diff -u --recursive --new-file v2.3.46/linux/CREDITS linux/CREDITS --- v2.3.46/linux/CREDITS Wed Feb 16 17:03:51 2000 +++ linux/CREDITS Fri Feb 18 14:51:22 2000 @@ -367,6 +367,13 @@ S: Orlando, Florida S: USA +N: Lennert Buytenhek +E: buytenh@gnu.org +D: Rewrite of the ethernet bridging code +S: Handelstraat 35 +S: 3131 EK Vlaardingen +S: The Netherlands + N: Michael Callahan E: callahan@maths.ox.ac.uk D: PPP for Linux @@ -1271,10 +1278,6 @@ S: L3R 8B2 S: Canada -N: Andrzej M. Krzysztofowicz -E: ankry@mif.pg.gda.pl -D: Some 8-bit XT disk driver and /devfs hacking - N: Andreas S. Krebs E: akrebs@altavista.net D: CYPRESS CY82C693 chipset IDE, Digital's PC-Alpha 164SX boards @@ -1289,7 +1292,7 @@ N: Andrzej M. Krzysztofowicz E: ankry@mif.pg.gda.pl -D: XT disk driver +D: Some 8-bit XT disk driver and devfs hacking D: Aladdin 1533/1543(C) chipset IDE D: PIIX chipset IDE S: ul. Matemblewska 1B/10 @@ -1528,6 +1531,13 @@ D: XF86_Mach8 D: XF86_8514 D: cfdisk (curses based disk partitioning program) + +N: Heinz Mauelshagen +E: mge@EZ-Darmstadt.Telekom.de +D: Logical Volume Manager +S: Bartningstr. 12 +S: 64289 Darmstadt +S: Germany N: Mike McLagan E: mike.mclagan@linux.org diff -u --recursive --new-file v2.3.46/linux/Documentation/Configure.help linux/Documentation/Configure.help --- v2.3.46/linux/Documentation/Configure.help Wed Feb 16 17:03:51 2000 +++ linux/Documentation/Configure.help Sun Feb 20 20:37:09 2000 @@ -65,7 +65,7 @@ Prompt for development and/or incomplete code/drivers CONFIG_EXPERIMENTAL Some of the various things that Linux supports (such as network - drivers, filesystems, network protocols, etc.) can be in a state + drivers, file systems, network protocols, etc.) can be in a state of development where the functionality, stability, or the level of testing is not yet high enough for general use. This is usually known as the "alpha-test" phase amongst developers. If a feature is @@ -224,7 +224,7 @@ RAM disk support CONFIG_BLK_DEV_RAM Saying Y here will allow you to use a portion of your RAM memory as - a block device, so that you can make filesystems on it, read and + a block device, so that you can make file systems on it, read and write to it and do all the other things that you can do with normal block devices (such as hard drives). It is usually used to load and store a copy of a minimal root file system off of a floppy into RAM @@ -260,7 +260,7 @@ burning the CD, or if you want to use floppy images without first writing them to floppy. - The loop device driver can also be used to "hide" a filesystem in a + The loop device driver can also be used to "hide" a file system in a disk partition, floppy, or regular file, either using encryption (scrambling the data) or steganography (hiding the data in the low bits of, say, a sound file). This is also safe if the file resides @@ -270,12 +270,12 @@ ftp://verden.pvv.org/pub/linux/kerneli/v2.1/ , and then you need to say Y to this option. - Note that alternative ways to use encrypted filesystems are provided + Note that alternative ways to use encrypted file systems are provided by the cfs package, which can be gotten from ftp://ftp.replay.com/pub/crypto/disk/ , and the newer tcfs package, available at http://tcfs.dia.unisa.it/ . You do not need to say Y here if you want to use one of these. However, using cfs requires - saying Y to "NFS filesystem support" below while using tcfs requires + saying Y to "NFS file system support" below while using tcfs requires applying a kernel patch. To use the loop device, you need the losetup utility and a recent @@ -297,7 +297,7 @@ CONFIG_BLK_DEV_NBD Saying Y here will allow your computer to be a client for network block devices, i.e. it will be able to use block devices exported by - servers (mount filesystems on them etc.). Communication between + servers (mount file systems on them etc.). Communication between client and server works over TCP/IP networking, but to the client program this is hidden: it looks like a regular local file access to a block device special file such as /dev/nd0. @@ -343,7 +343,7 @@ inserted in and removed from the running kernel whenever you want), say M here and read Documentation/modules.txt and Documentation/ide.txt. The module will be called ide.o. Do not - compile this driver as a module if your root filesystem (the one + compile this driver as a module if your root file system (the one containing the directory /) is located on an IDE device. If you have one or more IDE drives, say Y or M here. If your system @@ -400,7 +400,7 @@ inserted in and removed from the running kernel whenever you want), say M here and read Documentation/modules.txt. The module will be called ide-disk.o. Do not compile this driver as a module if your - root filesystem (the one containing the directory /) is located on + root file system (the one containing the directory /) is located on the IDE disk. If unsure, say Y. Use multi-mode by default @@ -424,7 +424,7 @@ along with other IDE devices, as "hdb" or "hdc", or something similar (check the boot messages with dmesg). If this is your only CDROM drive, you can say N to all other CDROM options, but be sure - to say Y or M to "ISO 9660 CDROM filesystem support". + to say Y or M to "ISO 9660 CDROM file system support". Read the CDROM-HOWTO, available from http://www.linuxdoc.org/docs.html#howto and the file @@ -631,7 +631,7 @@ DMA for IDE drives and chipsets which support it. Due to concerns about a couple of cases where buggy hardware may have caused damage, the default is now to NOT use DMA automatically. To revert to the - previous behaviour, say Y to this question. + previous behavior, say Y to this question. If you suspect your hardware is at all flakey, say N here. Do NOT email the IDE kernel people regarding this issue! @@ -1069,7 +1069,7 @@ system. Among the devices supported by this driver are the MicroSolutions backpack CD-ROM drives and the Freecom Power CD. If you have such a CD-ROM drive, you should also say Y or M to "ISO - 9660 CDROM filesystem support" below, because that's the filesystem + 9660 CDROM file system support" below, because that's the file system used on CDROMs. Parallel port ATAPI disks @@ -1260,6 +1260,30 @@ called on26.o. You must also have a high-level driver for the type of device that you want to support. +Logical Volume Manager (LVM) support +CONFIG_BLK_DEV_LVM + This driver lets you combine several hard disks, hard disk + partitions, multiple devices or even loop devices (for evaluation + purposes) into a volume group. Imagine a volume group as a kind of + virtual disk. Logical volumes, which can be thought of as virtual + partitions, can be created in the volume group. You can resize + volume groups and logical volumes after creation time, corresponding + to new capacity needs. Logical volumes are accessed as block + devices named /dev/VolumeGroupName/LogicalVolumeName. + + For details see /usr/src/linux/Documentaion/LVM-HOWTO. + + To get the newest software see . + +Logical Volume Manager /proc file system information +CONFIG_LVM_PROC_FS + If you say Y here, you are able to access overall Logical Volume + Manager, Volume Group, Logical and Physical Volume information in + /proc/lvm. + + To use this option, you have to check, that the "/proc file system + support" (CONFIG_PROC_FS) is enabled too. + Multiple devices driver support CONFIG_BLK_DEV_MD This driver lets you combine several hard disk partitions into one @@ -1496,7 +1520,7 @@ are completely invisible to the outside world, even though they can reach the outside and can receive replies. It is even possible to run globally visible servers from within a masqueraded local network - using a mechanism called portforwarding. Masquerading is also often + using a mechanism called port-forwarding. Masquerading is also often called NAT (Network Address Translation). Another use of Netfilter is in transparent proxying: if a machine on @@ -1506,7 +1530,7 @@ Various modules exist for netfilter which replace the previous masquerading (ipmasqadm), packet filtering (ipchains), transparent - proxying, and portforwarding mechanisms. More information is + proxying, and port-forwarding mechanisms. More information is available from http://netfilter.kernelnotes.org . Make sure to say N to "Fast switching" below if you intend to say Y @@ -1515,7 +1539,7 @@ Chances are that you should say Y here if you compile a kernel which will run as a router and N for regular hosts. If unsure, say N. -SYN flood protection +SIN flood protection CONFIG_SYN_COOKIES Normal TCP/IP networking is open to an attack known as "SYN flooding". This denial-of-service attack prevents legitimate remote @@ -1542,12 +1566,12 @@ them off. If you say Y here, note that SYN cookies aren't enabled by default; - you can enable them by saying Y to "/proc filesystem support" and + you can enable them by saying Y to "/proc file system support" and "Sysctl support" below and executing the command echo 1 >/proc/sys/net/ipv4/tcp_syncookies - at boot time after the proc filesystem has been mounted. + at boot time after the /proc file system has been mounted. If unsure, say Y. @@ -1855,7 +1879,7 @@ I2O /proc support CONFIG_I2O_PROC - If you say Y here and to "/proc filesystem support", you will be + If you say Y here and to "/proc file system support", you will be able to read I2O related information from the virtual directory /proc/i2o. @@ -1875,7 +1899,7 @@ Say Y here if you would like Linux to configure your Plug and Play devices. You should then also say Y to "ISA Plug and Play support", below. Alternatively, you can configure your PnP devices using the - user space utilities contained in the isapnptools package. + user space utilities contained in the ISAPNP tools package. This support is also available as a module ( = code which can be inserted in and removed from the running kernel whenever you want). @@ -1964,7 +1988,7 @@ certain kernel parameters and variables on the fly without requiring a recompile of the kernel or reboot of the system. The primary interface consists of a system call, but if you say Y to "/proc - filesystem support", a tree of modifiable sysctl entries will be + file system support", a tree of modifiable sysctl entries will be generated beneath the /proc/sys directory. They are explained in the files in Documentation/sysctl/. Note that enabling this option will enlarge the kernel by at least 8 KB. @@ -1975,7 +1999,7 @@ Kernel core (/proc/kcore) format CONFIG_KCORE_ELF - If you enabled support for /proc filesystem then the file /proc/kcore + If you enabled support for /proc file system then the file /proc/kcore will contain the kernel core image. This can be used in gdb: $ cd /usr/src/linux ; gdb vmlinux /proc/kcore @@ -2069,7 +2093,7 @@ Documentation/java.txt for information about how to include Java support. - You must say Y to "proc filesystem support" (CONFIG_PROC_FS) to + You must say Y to "/proc file system support" (CONFIG_PROC_FS) to use this part of the kernel. You may say M here for module support and later load the module when @@ -2381,7 +2405,7 @@ provided by the text console 80x50 (and higher) modes. Note this is a poor quality font. The VGA 8x16 font is quite a lot more readable. - Given the resolution provided by the frame buffer device, anwser N + Given the resolution provided by the frame buffer device, answer N here is safe. Backward compatibility mode for Xpmac @@ -2679,7 +2703,7 @@ Support IEEE1284 status readback CONFIG_PRINTER_READBACK - If you have a device on your parrallel port that support this protocol, + If you have a device on your parallel port that support this protocol, this option'll enable it to report its status. It is safe to say Y. @@ -2719,7 +2743,7 @@ Kernel module loader support CONFIG_KMOD - Normally when you have selected some drivers and/or filesystems to + Normally when you have selected some drivers and/or file systems to be created as loadable modules, you also have the responsibility to load the corresponding modules (using the programs insmod or modprobe) before you can use them. If you say Y here however, the @@ -2771,7 +2795,7 @@ Internet connected Unix computer; for more information, read http://www.bart.nl/~patrickr/term-howto/Term-HOWTO.html ). - If you say Y here and also to "/proc filesystem support" and "Sysctl + If you say Y here and also to "/proc file system support" and "Sysctl support" below, you can change various aspects of the behavior of the TCP/IP code by writing to the (virtual) files in /proc/sys/net/ipv4/*; the options are explained in the file @@ -2804,12 +2828,12 @@ Note that your box can only act as a router if you enable IP forwarding in your kernel; you can do that by saying Y to "/proc - filesystem support" and "Sysctl support" below and executing the + file system support" and "Sysctl support" below and executing the line echo "1" > /proc/sys/net/ipv4/ip_forward - at boot time after the /proc filesystem has been mounted. + at boot time after the /proc file system has been mounted. If you turn on IP forwarding, you will also get the rp_filter, which automatically rejects incoming packets if the routing table entry @@ -2903,12 +2927,12 @@ Note that your box can only act as a router if you enable IP forwarding in your kernel; you can do that by saying Y to "/proc - filesystem support" and "Sysctl support" below and executing the + file system support" and "Sysctl support" below and executing the line echo "1" > /proc/sys/net/ipv4/ip_forward - at boot time after the /proc filesystem has been mounted. You can do + at boot time after the /proc file system has been mounted. You can do that even if you say N here. If unsure, say N here. @@ -2925,7 +2949,7 @@ BOOTP support CONFIG_IP_PNP_BOOTP - If you want your Linux box to mount its whole root filesystem (the + If you want your Linux box to mount its whole root file system (the one containing the directory /) from some other computer over the net via NFS and you want the IP address of your computer to be discovered automatically at boot time using the BOOTP protocol (a @@ -2938,7 +2962,7 @@ RARP support CONFIG_IP_PNP_RARP - If you want your Linux box to mount its whole root filesystem (the + If you want your Linux box to mount its whole root file system (the one containing the directory /) from some other computer over the net via NFS and you want the IP address of your computer to be discovered automatically at boot time using the RARP protocol (an @@ -3166,7 +3190,7 @@ ftp://metalab.unc.edu/pub/Linux/system/filesystems/ ) or from within the Linux DOS emulator DOSEMU (read the DOSEMU-HOWTO, available from http://www.linuxdoc.org/docs.html#howto ). In order to do the - former, you'll also have to say Y to "NCP filesystem support", + former, you'll also have to say Y to "NCP file systems support", below. IPX is similar in scope to IP, while SPX, which runs on top of IPX, @@ -3225,7 +3249,7 @@ Note that Novell NetWare file sharing does not use SPX; it uses a protocol called NCP, for which separate Linux support is available - ("NCP filesystem support" below for the client side, and the user + ("NCP file systems support" below for the client side, and the user space programs lwared or mars_nwe for the server side). Say Y here if you have use for SPX; read the IPX-HOWTO at @@ -3250,7 +3274,7 @@ More detailed documentation is available in the Documentation/networking/decnet.txt file. - Be sure to say Y to "/proc filesystem support" and "Sysctl support" + Be sure to say Y to "/proc file systems support" and "Sysctl support" below when using DECnet, since you will need sysctl support to aid in configuration at run time. @@ -3797,25 +3821,25 @@ This is a Logical Link Layer protocol used for X.25 connections over Ethernet, using ordinary Ethernet cards. -Bridging (EXPERIMENTAL) +802.1d Ethernet Bridging CONFIG_BRIDGE If you say Y here, then your Linux box will be able to act as an Ethernet bridge, which means that the different Ethernet segments it is connected to will appear as one Ethernet to the participants. Several such bridges can work together to create even larger - networks of Ethernets using the IEEE802.1 spanning tree algorithm. + networks of Ethernets using the IEEE 802.1d spanning tree protocol. As this is a standard, Linux bridges will interwork properly with other third party bridge products. - In order to use this, you'll need the bridge configuration tools - available from ftp://shadow.cabi.net/pub/Linux . Please read the - Bridge mini-HOWTO for more information. Note that if your box acts - as a bridge, it probably contains several Ethernet devices, but the - kernel is not able to recognize more than one at boot time without - help; for details read the Ethernet-HOWTO, available from + In order to use the ethernet bridge, you'll need the bridge + configuration tools available from ftp://openrock.net/bridge. Please + read the Bridge mini-HOWTO for more information. Note that if your + box acts as a bridge, it probably contains several Ethernet devices, + but the kernel is not able to recognize more than one at boot time + without help; for details read the Ethernet-HOWTO, available from in http://www.linuxdoc.org/docs.html#howto . - The Bridging code is still in test. If unsure, say N. + If unsure, say N. Packet socket CONFIG_PACKET @@ -3896,13 +3920,13 @@ ATMARP. Typically you will either use LAN Emulation (LANE) or Classical IP to communicate with other IP hosts on your ATM network. -Do NOT send ICMP if no neighbour +Do NOT send ICMP if no neighbor CONFIG_ATM_CLIP_NO_ICMP - Normally, an "ICMP host unreachable" message is sent if a neighbour + Normally, an "ICMP host unreachable" message is sent if a neighbor cannot be reached because there is no VC to it in the kernel's ATMARP table. This may cause problems when ATMARP table entries are briefly removed during revalidation. If you say Y here, packets to - such neighbours are silently discarded instead. + such neighbors are silently discarded instead. LAN Emulation (LANE) support CONFIG_ATM_LANE @@ -4141,7 +4165,7 @@ The module will be called scsi_mod.o. If you want to compile it as a module, say M here and read Documentation/modules.txt and Documentation/scsi.txt. However, do not compile this as a module if - your root filesystem (the one containing the directory /) is located + your root file systems (the one containing the directory /) is located on a SCSI device. SCSI disk support @@ -4157,7 +4181,7 @@ The module will be called sd_mod.o. If you want to compile it as a module, say M here and read Documentation/modules.txt and Documentation/scsi.txt. Do not compile this driver as a module if - your root filesystem (the one containing the directory /) is located + your root file systems (the one containing the directory /) is located on a SCSI disk. In this case, do not compile the driver for your SCSI host adapter (below) as a module either. @@ -4204,7 +4228,7 @@ If you want to use a SCSI CDROM under Linux, say Y and read the SCSI-HOWTO and the CDROM-HOWTO at http://www.linuxdoc.org/docs.html#howto . Also make sure to say Y - or M to "ISO 9660 CDROM filesystem support" later. + or M to "ISO 9660 CDROM file systems support" later. This driver is also available as a module ( = code which can be inserted in and removed from the running kernel whenever you want). @@ -4284,12 +4308,12 @@ of SCSI related problems. If you say Y here, no logging output will appear by default, but you - can enable logging by saying Y to "/proc filesystem support" and + can enable logging by saying Y to "/proc file systems support" and "Sysctl support" below and executing the command echo "scsi log token [level]" > /proc/scsi/scsi - at boot time after the /proc filesystem has been mounted. + at boot time after the /proc file systems has been mounted. There are a number of things that can be used for 'token' (you can find them in the source: drivers/scsi/scsi.c), and this allows you @@ -4452,7 +4476,7 @@ small amount of overhead to each and every SCSI command the aic7xxx driver handles, so if you aren't really interested in this information, it is best to leave it disabled. This will only work if - you also say Y to "/proc filesystem support", below. + you also say Y to "/proc file system support", below. If unsure, say N. @@ -5702,16 +5726,16 @@ This configuration option enables common code for all devices (PCI, ISA, PCMCIA) module is aironet4500_core - quickconfig parameters: + quick config parameters: SSID=tsunami - "The Password" adhoc=1 there are no Access Points around master=1 Adhoc master (the one who creates network sync) slave=1 Adhoc slave(btw, it is still forming own net sometimes) channel=1..? meaningful in adhoc mode - all other parameters can be set via proc interface + all other parameters can be set via /proc interface These parameters belong to .._card module, but alas, they are here - if you have problems with screwin up card, both_bap_lock=1 is conservative + if you have problems with screwing up card, both_bap_lock=1 is conservative value (performance hit 15%) for any other configuration options look at ..._proc module @@ -5747,7 +5771,7 @@ Aironet 4500/4800 I365 broken support (EXPERIMENTAL) CONFIG_AIRONET4500_I365 This option enables support for PCMCIA cards on i365 controller - _without_ cardservices. Doesnt have much sense and is not working + _without_ cardservices. Doesn't have much sense and is not working properly. Comes from times where there was no PCMCIA support in kernel main source tree @@ -5760,7 +5784,7 @@ The same option is both on: 1. PCMCIA netdevices configuring panel 2. Wireless netdevices configuring panel - Possibility to change this option depeds on options set in 2. + Possibility to change this option depends on options set in 2. Aironet 4500/4800 PROC interface CONFIG_AIRONET4500_PROC @@ -6187,9 +6211,9 @@ That package also contains some documentation; for more, check out http://snafu.freedom.org/linux2.2/iproute-notes.html . - If you say Y here and to "/proc filesystem" below, you will be able - to read status information about packet schedulers from the file - /proc/net/psched. + If you say Y here and to "/proc file system support" below, you will + be able to read status information about packet schedulers from the + file /proc/net/psched. The available schedulers are listed in the following questions; you can say Y to as many as you like. If unsure, say N now. @@ -6392,7 +6416,7 @@ Network code profiler CONFIG_NET_PROFILE - If you say Y here and to "/proc filesystem support" below, some + If you say Y here and to "/proc file system support" below, some obscure and undocumented information about the network code's performance will be written to /proc/net/profile. If you don't know what it is about, you don't need it: say N. @@ -6747,17 +6771,29 @@ module, say M here and read Documentation/modules.txt as well as Documentation/networking/net-modules.txt. -RealTek 8129/8139 (not 8019/8029!) support -CONFIG_RTL8139 +RealTek 8129 (not 8019/8029!) support (EXPERIMENTAL) +CONFIG_RTL8129 + This is a driver for the Fast Ethernet PCI network cards based on + the RTL8129 chip. If you have one of those, say Y and + read the Ethernet-HOWTO, available from + http://www.linuxdoc.org/docs.html#howto . + + If you want to compile this driver as a module ( = code which can be + inserted in and removed from the running kernel whenever you want), + say M here and read Documentation/modules.txt. This is recommended. + The module will be called rtl8129.o. + +RealTek RTL-8139 PCI Fast Ethernet Adapter support +CONFIG_8139TOO This is a driver for the Fast Ethernet PCI network cards based on - the RTL8129 and RTL8139 chips. If you have one of those, say Y and + the RTL8139 chip. If you have one of those, say Y and read the Ethernet-HOWTO, available from http://www.linuxdoc.org/docs.html#howto . If you want to compile this driver as a module ( = code which can be inserted in and removed from the running kernel whenever you want), say M here and read Documentation/modules.txt. This is recommended. - The module will be called rtl8139.o. + The module will be called 8139too.o. SiS 900 PCI Fast Ethernet Adapter support CONFIG_SIS900 @@ -6850,7 +6886,7 @@ The dual link adapters support a link-failover feature. Read Documentation/networking/sk98lin.txt for information about optional driver parameters. - Questions concerning this driver may be addresse to: + Questions concerning this driver may be addressed to: linux@syskonnect.de If you want to compile this driver as a module ( = code which can be @@ -7307,7 +7343,7 @@ Documentation/networking/net-modules.txt. EISA, VLB, PCI and on board controllers -CONFIG_NET_EISA +CONFIG_NET_PCI This is another class of network cards which attach directly to the bus. If you have one of those, say Y and read the Ethernet-HOWTO, available from http://www.linuxdoc.org/docs.html#howto . @@ -7428,7 +7464,7 @@ Documentation/networking/net-modules.txt. EtherExpress PRO/100 support -CONFIG_EEXPRESS_PRO100 +CONFIG_EEPRO100 If you have an Intel EtherExpress PRO/100 PCI network (Ethernet) card, say Y and read the Ethernet-HOWTO, available from http://www.linuxdoc.org/docs.html#howto . @@ -7643,7 +7679,7 @@ Compaq 4/16 PCI, Thomas-Conrad TC4048 4/16 PCI, and several Madge adapters. If selected, you will be asked to select which cards to support below. If you're using modules, each - class of card will be supported by a seperate module. + class of card will be supported by a separate module. If you have such an adapter and would like to use it, say Y or M and read the Token-Ring mini-HOWTO, available from @@ -7716,6 +7752,36 @@ This is support for the DIGITAL series of EISA (DEFEA) and PCI (DEFPA) controllers which can connect you to a local FDDI network. +SysKonnect FDDI PCI support +CONFIG_SKFP + Say Y here if you have a SysKonnect FDDI PCI adapter. + The following adapters are supported by this driver: + - SK-5521 (SK-NET FDDI-UP) + - SK-5522 (SK-NET FDDI-UP DAS) + - SK-5541 (SK-NET FDDI-FP) + - SK-5543 (SK-NET FDDI-LP) + - SK-5544 (SK-NET FDDI-LP DAS) + - SK-5821 (SK-NET FDDI-UP64) + - SK-5822 (SK-NET FDDI-UP64 DAS) + - SK-5841 (SK-NET FDDI-FP64) + - SK-5843 (SK-NET FDDI-LP64) + - SK-5844 (SK-NET FDDI-LP64 DAS) + - Netelligent 100 FDDI DAS Fibre SC + - Netelligent 100 FDDI SAS Fibre SC + - Netelligent 100 FDDI DAS UTP + - Netelligent 100 FDDI SAS UTP + - Netelligent 100 FDDI SAS Fibre MIC + Read Documentation/networking/skfp.txt for information about + the driver. + WARNING: this driver does currently not support 64 bit systems! + Questions concerning this driver can be addressed to: + linux@syskonnect.de + + If you want to compile this driver as a module ( = code which can be + inserted in and removed from the running kernel whenever you want), + say M here and read Documentation/modules.txt. This is recommended. + The module will be called skfp.o. + HIgh Performance Parallel Interface support (EXPERIMENTAL) CONFIG_HIPPI HIgh Performance Parallel Interface (HIPPI) is a 800Mbit/sec and @@ -7789,7 +7855,7 @@ read Documentation/modules.txt. If you want to use any of these CDROM drivers, you also have to - answer Y or M to "ISO 9660 CDROM filesystem support" below (this + answer Y or M to "ISO 9660 CDROM file systems support" below (this answer will get "defaulted" for you if you enable any of the Linux CDROM drivers). @@ -7806,7 +7872,7 @@ explained in the SCSI-HOWTO. If you say Y here, you should also say Y or M to "ISO 9660 CDROM - filesystem support" below, because that's the filesystem used on + file systems support" below, because that's the file systems used on CDROMs. This driver is also available as a module ( = code which can be @@ -7828,7 +7894,7 @@ this. If you want that one, say N here. If you say Y here, you should also say Y or M to "ISO 9660 CDROM - filesystem support" below, because that's the filesystem used on + file systems support" below, because that's the file systems used on CDROMs. This driver is also available as a module ( = code which can be @@ -7861,7 +7927,7 @@ Documentation/cdrom/mcdx. If you say Y here, you should also say Y or M to "ISO 9660 CDROM - filesystem support" below, because that's the filesystem used on + file systems support" below, because that's the file systems used on CDROMs. This driver is also available as a module ( = code which can be @@ -7899,7 +7965,7 @@ usable. If you say Y here, you should also say Y or M to "ISO 9660 CDROM - filesystem support" below, because that's the filesystem used on + file systems support" below, because that's the file systems used on CDROMs. This driver is also available as a module ( = code which can be @@ -7924,7 +7990,7 @@ CDA269-031SE. Please read the file Documentation/cdrom/aztcd. If you say Y here, you should also say Y or M to "ISO 9660 CDROM - filesystem support" below, because that's the filesystem used on + file systems support" below, because that's the file systems used on CDROMs. This driver is also available as a module ( = code which can be @@ -7938,7 +8004,7 @@ drives. Please read the file Documentation/cdrom/sonycd535. If you say Y here, you should also say Y or M to "ISO 9660 CDROM - filesystem support" below, because that's the filesystem used on + file system support" below, because that's the file system used on CDROMs. This driver is also available as a module ( = code which can be @@ -7954,7 +8020,7 @@ kernel. Please read the file Documentation/cdrom/gscd. If you say Y here, you should also say Y or M to "ISO 9660 CDROM - filesystem support" below, because that's the filesystem used on + file system support" below, because that's the file system used on CDROMs. This driver is also available as a module ( = code which can be @@ -7969,7 +8035,7 @@ Documentation/cdrom/cm206. If you say Y here, you should also say Y or M to "ISO 9660 CDROM - filesystem support" below, because that's the filesystem used on + file system support" below, because that's the file system used on CDROMs. This driver is also available as a module ( = code which can be @@ -7986,7 +8052,7 @@ one. Please read the file Documentation/cdrom/optcd. If you say Y here, you should also say Y or M to "ISO 9660 CDROM - filesystem support" below, because that's the filesystem used on + file system support" below, because that's the file system used on CDROMs. This driver is also available as a module ( = code which can be @@ -7998,8 +8064,8 @@ CONFIG_SJCD If this is your CDROM drive, say Y here and read the file Documentation/cdrom/sjcd. You should then also say Y or M to - "ISO 9660 CDROM filesystem support" below, because that's the - filesystem used on CDROMs. + "ISO 9660 CDROM file system support" below, because that's the + file system used on CDROMs. This driver is also available as a module ( = code which can be inserted in and removed from the running kernel whenever you want). @@ -8034,7 +8100,7 @@ CONFIG_QUOTA If you say Y here, you will be able to set per user limits for disk usage (also called disk quotas). Currently, it works only for the - ext2 filesystem. You need additional software in order to use quota + ext2 file system. You need additional software in order to use quota support; for details, read the Quota mini-HOWTO, available from http://www.linuxdoc.org/docs.html#howto . Probably the quota support is only useful for multi user systems. If unsure, say N. @@ -8376,7 +8442,7 @@ The module will be called uss720.o. If you want to compile it as a module, say M here and read Documentation/modules.txt. -USB device filesystem +USB device file system CONFIG_USB_DEVICEFS This file system implements a "devices" file, that lists the currently connected to your USB busses, a "drivers" file @@ -8416,10 +8482,10 @@ Minix fs support CONFIG_MINIX_FS Minix is a simple operating system used in many classes about OS's. - The minix filesystem (method to organize files on a hard disk - partition or a floppy disk) was the original filesystem for Linux, - but has been superseded by the second extended filesystem ext2fs. - You don't want to use the minix filesystem on your hard disk because + The minix file system (method to organize files on a hard disk + partition or a floppy disk) was the original file system for Linux, + but has been superseded by the second extended file system ext2fs. + You don't want to use the minix file system on your hard disk because of certain built-in restrictions, but it is sometimes found on older Linux floppy disks. This option will enlarge your kernel by about 28 kB. If unsure, say N. @@ -8427,16 +8493,16 @@ If you want to compile this as a module ( = code which can be inserted in and removed from the running kernel whenever you want), say M here and read Documentation/modules.txt. The module will be - called minix.o. Note that the filesystem of your root partition (the + called minix.o. Note that the file system of your root partition (the one containing the directory /) cannot be compiled as a module. Second extended fs support CONFIG_EXT2_FS - This is the de facto standard Linux filesystem (method to organize + This is the de facto standard Linux file system (method to organize files on a storage device) for hard disks. You want to say Y here, unless you intend to use Linux exclusively - from inside a DOS partition using the umsdos filesystem. The + from inside a DOS partition using the umsdos file system. The advantage of the latter is that you can get away without repartitioning your hard drive (which often implies backing everything up and restoring afterwards); the disadvantage is that @@ -8447,16 +8513,16 @@ Linux partition later. Another (rare) case which doesn't require ext2fs is a diskless Linux box which mounts all files over the network using NFS (in this case it's sufficient to say Y to "NFS - filesystem support" below). Saying Y here will enlarge your kernel + file system support" below). Saying Y here will enlarge your kernel by about 44 kB. The Ext2fs-Undeletion mini-HOWTO, available from http://www.linuxdoc.org/docs.html#howto , gives information about - how to retrieve deleted files on ext2fs filesystems. + how to retrieve deleted files on ext2fs file systems. - To change the behavior of ext2 filesystems, you can use the tune2fs + To change the behavior of ext2 file systems, you can use the tune2fs utility ("man tune2fs"). To modify attributes of files and - directories on ext2 filesystems, use chattr ("man chattr"). + directories on ext2 file systems, use chattr ("man chattr"). Ext2fs partitions can be read from within DOS using the ext2tool command line tool package (available via FTP (user: anonymous) from @@ -8467,35 +8533,35 @@ NT and includes experimental write support; it is available from http://jnewbigin-pc.it.swin.edu.au/Linux/Explore2fs.htm . - If you want to compile this filesystem as a module ( = code which + If you want to compile this file system as a module ( = code which can be inserted in and removed from the running kernel whenever you want), say M here and read Documentation/modules.txt. The module - will be called ext2.o. Be aware however that the filesystem of your + will be called ext2.o. Be aware however that the file system of your root partition (the one containing the directory /) cannot be compiled as a module, and so this could be dangerous. Most everyone wants to say Y here. -SCO UnixWare BFS Support +BFS file system support (EXPERIMENTAL) CONFIG_BFS_FS - Boot Filesystem (BFS) is a filesystem used under SCO UnixWare to + Boot File System (BFS) is a file system used under SCO UnixWare to allow bootloader access the kernel image and other important files during the boot process. It is usually mounted under /stand and corresponds to the slice marked as "STAND" in the UnixWare partition. This is useful if you want to access files on your /stand - slice from Linux. More information on this filesystem can be found in + slice from Linux. More information on this file system can be found in Documentation/filesystems/bfs.txt file. If you do not know what it is, say N. If you want to compile this as a module ( = code which can be inserted in and removed from the running kernel whenever you want), say M here and read Documentation/modules.txt. The module will be - called bfs.o. Note that the filesystem of your root partition (the + called bfs.o. Note that the file system of your root partition (the one containing the directory /) cannot be compiled as a module. -ISO 9660 CDROM filesystem support +ISO 9660 CDROM file system support CONFIG_ISO9660_FS - This is the standard filesystem used on CDROMs. It was previously - known as "High Sierra Filesystem" and is called "hsfs" on other Unix + This is the standard file system used on CDROMs. It was previously + known as "High Sierra File System" and is called "hsfs" on other Unix systems. The so-called Rock-Ridge extensions which allow for long Unix filenames and symbolic links are also supported by this driver. If you have a CDROM drive and want to do more with it than just @@ -8511,21 +8577,21 @@ Microsoft Joliet CDROM extensions CONFIG_JOLIET - Joliet is a Microsoft extension for the ISO 9660 CDROM filesystem + Joliet is a Microsoft extension for the ISO 9660 CDROM file system which allows for long filenames in unicode format (unicode is the new 16 bit character code, successor to ASCII, which encodes the characters of almost all languages of the world; see http://www.unicode.org for more information). Say Y here if you want to be able to read Joliet CDROMs under Linux. -UDF Filesystem support (read only) +UDF file system support (read only) CONFIG_UDF_FS - This is the new filesystem used by some CDROMS and DVD drivers. Say + This is the new file system used by some CDROMS and DVD drivers. Say Y if you intend to mount DVD discs or CDRW's written in packet mode, or if written to by other UDF utilities, such as DirectCD. Please read Documentation/filesystems/udf.txt. - This filesystem support is also available as a module ( = code which + This file system support is also available as a module ( = code which can be inserted in and removed from the running kernel whenever you want). The module is called udf.o. If you want to compile it as a module, say M here and read Documentation/modules.txt. @@ -8534,32 +8600,32 @@ UDF write support (DANGEROUS) CONFIG_UDF_RW - Say Y if you want to test write support for UDF filesystems. + Say Y if you want to test write support for UDF file systems. Due to lack of support for writing to CDR/CDRW's, this option is only supported for Hard Discs, DVD-RAM, and loopback files. DOS FAT fs support CONFIG_FAT_FS - If you want to use one of the FAT-based filesystems (the MS-DOS, + If you want to use one of the FAT-based file systems (the MS-DOS, VFAT (Windows 95) and UMSDOS (used to run Linux on top of an - ordinary DOS partition) filesystems), then you must say Y or M here + ordinary DOS partition) file systems), then you must say Y or M here to include FAT support. You will then be able to mount partitions or - diskettes with FAT-based filesystems and transparently access the + diskettes with FAT-based file systems and transparently access the files on them, i.e. MSDOS files will look and behave just like all other Unix files. - This FAT support is not a filesystem in itself, it only provides the - foundation for the other filesystems. You will have to say Y or M to + This FAT support is not a file system in itself, it only provides the + foundation for the other file systems. You will have to say Y or M to at least one of "msdos fs support" or "vfat fs support" in order to make use of it. Another way to read and write MSDOS floppies and hard drive partitions from within Linux (but not transparently) is with the mtools ("man mtools") program suite. This doesn't require the FAT - filesystem support. + file system support. It is now also becoming possible to read and write compressed FAT - filesystems; read Documentation/filesystems/fat_cvf.txt for details. + file systems; read Documentation/filesystems/fat_cvf.txt for details. The FAT support will enlarge your kernel by about 37 KB. If unsure, say Y. @@ -8568,11 +8634,11 @@ be inserted in and removed from the running kernel whenever you want), say M here and read Documentation/modules.txt. The module will be called fat.o. Note that if you compile the FAT support as a - module, you cannot compile any of the FAT-based filesystems into the - kernel -- they will have to be modules as well. The filesystem of + module, you cannot compile any of the FAT-based file systems into the + kernel -- they will have to be modules as well. The file system of your root partition (the one containing the directory /) cannot be a module, so don't say M here if you intend to use UMSDOS as your root - filesystem. + file system. MSDOS fs support CONFIG_MSDOS_FS @@ -8587,12 +8653,12 @@ transparent, i.e. the MSDOS files look and behave just like all other Unix files. - If you want to use umsdos, the Unix-like filesystem on top of DOS, + If you want to use umsdos, the Unix-like file system on top of DOS, which allows you to run Linux from within a DOS partition without repartitioning, you'll have to say Y or M here. If you have Windows 95 or Windows NT installed on your MSDOS - partitions, you should use the VFAT filesystem (say Y to "vfat fs + partitions, you should use the VFAT file system (say Y to "vfat fs support" below), or you will not be able to see the long filenames generated by Windows 95 / Windows NT. @@ -8605,11 +8671,11 @@ VFAT (Windows-95) fs support CONFIG_VFAT_FS - This option provides support for normal Windows filesystems with - long filenames. That includes non-compressed FAT-based filesystems + This option provides support for normal Windows file systems with + long filenames. That includes non-compressed FAT-based file systems used by Windows 95, Windows 98, Windows NT 4.0, and mtools. - You cannot use the VFAT filesystem for your Linux root partition + You cannot use the VFAT file system for your Linux root partition (the one containing the directory /); use UMSDOS instead if you want to run Linux from within a DOS partition (i.e. say Y to "umsdos: Unix like fs on top of std MSDOS fs", below). @@ -8624,7 +8690,7 @@ say M here and read Documentation/modules.txt. The module will be called vfat.o. -UMSDOS: Unix-like filesystem on top of standard MSDOS filesystem +UMSDOS: Unix-like file system on top of standard MSDOS fs CONFIG_UMSDOS_FS Say Y here if you want to run Linux from within an existing DOS partition of your hard drive. The advantage of this is that you can @@ -8634,11 +8700,11 @@ disadvantage is that Linux becomes susceptible to DOS viruses and that UMSDOS is somewhat slower than ext2fs. Another use of UMSDOS is to write files with long unix filenames to MSDOS floppies; it - also allows Unix-style softlinks and owner/permissions of files on + also allows Unix-style soft-links and owner/permissions of files on MSDOS floppies. You will need a program called umssync in order to make use of umsdos; read Documentation/filesystems/umsdos.txt. - To get utilities for initializing/checking UMSDOS filesystem, or + To get utilities for initializing/checking UMSDOS file system, or latest patches and/or information, visit UMSDOS homepage at http://www.voyager.hr/~mnalis/umsdos/ . @@ -8647,13 +8713,13 @@ you want to compile this as a module ( = code which can be inserted in and removed from the running kernel whenever you want), say M here and read Documentation/modules.txt. The module will be called - umsdos.o. Note that the filesystem of your root partition (the one + umsdos.o. Note that the file system of your root partition (the one containing the directory /) cannot be a module, so saying M could be dangerous. If unsure, say N. -/proc filesystem support +/proc file system support CONFIG_PROC_FS - This is a virtual filesystem providing information about the status + This is a virtual file system providing information about the status of the system. "Virtual" means that it doesn't take up any space on your hard disk: the files are created on the fly by the kernel when you try to access them. Also, you cannot read the files with older @@ -8666,32 +8732,34 @@ often a source of trouble if two devices are mistakenly configured to use the same IRQ). - The /proc filesystem is explained in the file + The /proc file system is explained in the file Documentation/filesystems/proc.txt and on the proc(5) manpage ("man 5 proc"). This option will enlarge your kernel by about 67 KB. Several programs depend on this, so everyone should say Y here. -/dev filesystem support (EXPERIMENTAL) +/dev file system support (EXPERIMENTAL) CONFIG_DEVFS_FS - This is another virtual filesystem (like /proc) which provides the - filesystem interface to device drivers, normally found in /dev. + This is another virtual file system (like /proc) which provides the + file system interface to device drivers, normally found in /dev. Devfs does not depend on major and minor number allocations. Device drivers register entries in /dev which appear automagically. Without devfs you need to populate /dev with hundreds, even thousands of inodes. This is work in progress. If you want to use this you *must* read Documentation/filesystems/devfs/README + In particular, make sure you install devfsd. If you don't, expect to + spend time patching broken code and updating configuration files. -Enable devfs debugging output +Debug devfs CONFIG_DEVFS_DEBUG This option appears if you have CONFIG_DEVFS_FS enabled. Setting this to 'Y' enables devfs debugging output. See the file Documentation/filesystems/devfs/boot-options for more details. The default is 'N'. -NFS filesystem support +NFS file system support CONFIG_NFS_FS If you are connected to some other (usually local) Unix computer (using SLIP, PLIP, PPP or Ethernet) and want to mount files residing @@ -8699,25 +8767,25 @@ protocol, say Y. "Mounting files" means that the client can access the files with usual UNIX commands as if they were sitting on the client's hard disk. For this to work, the server must run the - programs nfsd and mountd (but does not need to have NFS filesystem + programs nfsd and mountd (but does not need to have NFS file system support enabled in its kernel). NFS is explained in the Network Administrator's Guide, available from http://metalab.unc.edu/mdw/linux.html#guide , on its man page: "man nfs", and in the NFS-HOWTO. A superior but less widely used alternative to NFS is provided by - the Coda filesystem; see "Coda filesystem support" below. + the Coda file system; see "Coda file system support" below. If you say Y here, you should have said Y to TCP/IP networking also. This option would enlarge your kernel by about 27 KB. - This filesystem is also available as a module ( = code which can be + This file system is also available as a module ( = code which can be inserted in and removed from the running kernel whenever you want). The module is called nfs.o. If you want to compile it as a module, say M here and read Documentation/modules.txt. If you are configuring a diskless machine which will mount its root - filesystem over NFS at boot time, say Y here and to "IP: kernel + file system over NFS at boot time, say Y here and to "IP: kernel level autoconfiguration" above and to "Root file system on NFS" below. You cannot compile this driver as a module in this case. There are two packages designed for booting diskless machines over @@ -8728,7 +8796,7 @@ Root file system on NFS CONFIG_ROOT_NFS - If you want your Linux box to mount its whole root filesystem (the + If you want your Linux box to mount its whole root file system (the one containing the directory /) from some other computer over the net via NFS (presumably because your box doesn't have a hard disk), say Y. Read Documentation/nfsroot.txt for details. It is likely that @@ -8764,24 +8832,24 @@ Provide NFSv3 server support (EXPERIMENTAL) CONFIG_NFSD_V3 If you would like to include the NFSv3 server was well as the NFSv2 - server, say Y here. File locking, via the NLMv4 protocol, is not - supported yet. If unsure, say N. + server, say Y here. File locking, via the NLMv4 protocol, is also + supported. If unsure, say N. -OS/2 HPFS filesystem support +OS/2 HPFS file system support CONFIG_HPFS_FS OS/2 is IBM's operating system for PC's, the same as Warp, and HPFS - is the filesystem used for organizing files on OS/2 hard disk + is the file system used for organizing files on OS/2 hard disk partitions. Say Y if you want to be able to read files from an OS/2 HPFS partition of your hard drive. OS/2 floppies however are in regular MSDOS format, so you don't need this option in order to be able to read them. Read Documentation/filesystems/hpfs.txt. - This filesystem is also available as a module ( = code which can be + This file system is also available as a module ( = code which can be inserted in and removed from the running kernel whenever you want). The module is called hpfs.o. If you want to compile it as a module, say M here and read Documentation/modules.txt. If unsure, say N. -Windows NT NTFS support (read only) +NTFS file system support (read only) CONFIG_NTFS_FS NTFS is the file system of Microsoft Windows NT. Say Y if you want to get read access to files on NTFS partitions of your hard drive. @@ -8804,7 +8872,7 @@ If unsure, say N. -System V and Coherent filesystem support (read only) +System V and Coherent file system support (read only) CONFIG_SYSV_FS SCO, Xenix and Coherent are commercial Unix systems for Intel machines. Saying Y here would allow you to read from their floppies @@ -8820,15 +8888,15 @@ ftp://tsx-11.mit.edu/pub/linux/BETA ). If you only intend to mount files from some other Unix over the - network using NFS, you don't need the System V filesystem support - (but you need NFS filesystem support obviously). + network using NFS, you don't need the System V file system support + (but you need NFS file system support obviously). Note that this option is generally not needed for floppies, since a good portable way to transport files and directories between unixes (and even other operating systems) is given by the tar program ("man tar" or preferably "info tar"). Note also that this option has nothing whatsoever to do with the option "System V IPC". Read about - the System V filesystem in Documentation/filesystems/sysv-fs.txt. + the System V file system in Documentation/filesystems/sysv-fs.txt. Saying Y here will enlarge your kernel by about 27 kB. If you want to compile this as a module ( = code which can be @@ -8838,7 +8906,7 @@ If you haven't heard about all of this before, it's safe to say N. -SYSV filesystem write support (DANGEROUS) +SYSV file system write support (DANGEROUS) CONFIG_SYSV_FS_WRITE If you say Y here, you will (hopefully) be able to write to System V and Coherent file systems as well as read from them. The read-write @@ -8847,9 +8915,9 @@ If unsure, say N. -Amiga FFS filesystem support +Amiga FFS file system support CONFIG_AFFS_FS - The Fast File System (FFS) is the common filesystem used on hard + The Fast File System (FFS) is the common file system used on hard disks by Amiga(tm) systems since AmigaOS Version 1.3 (34.20). Say Y if you want to be able to read and write files from and to an Amiga FFS partition on your hard drive. Amiga floppies however cannot be @@ -8863,31 +8931,31 @@ If you want to do this, you will also need to say Y or M to "Loop device support", above. - This filesystem is also available as a module ( = code which can be + This file system is also available as a module ( = code which can be inserted in and removed from the running kernel whenever you want). The module is called affs.o. If you want to compile it as a module, say M here and read Documentation/modules.txt. If unsure, say N. -Apple Macintosh filesystem support (EXPERIMENTAL) +Apple Macintosh file system support (EXPERIMENTAL) CONFIG_HFS_FS If you say Y here, you will be able to mount Macintosh-formatted floppy disks and hard drive partitions with full read-write access. Please read fs/hfs/HFS.txt to learn about the available mount options. - This filesystem support is also available as a module ( = code which + This file system support is also available as a module ( = code which can be inserted in and removed from the running kernel whenever you want). The module is called hfs.o. If you want to compile it as a module, say M here and read Documentation/modules.txt. -ROM filesystem support +ROM file system support CONFIG_ROMFS_FS - This is a very small read-only filesystem mainly intended for + This is a very small read-only file system mainly intended for initial ram disks of installation disks, but it could be used for other read-only media as well. Read Documentation/filesystems/romfs.txt for details. - This filesystem support is also available as a module ( = code which + This file system support is also available as a module ( = code which can be inserted in and removed from the running kernel whenever you want). The module is called romfs.o. If you want to compile it as a module, say M here and read Documentation/modules.txt. @@ -8895,14 +8963,14 @@ If you don't know whether you need it, then you don't need it: answer N. -QNX4 filesystem support (read only) (EXPERIMENTAL) +QNX4 file system support (read only) (EXPERIMENTAL) CONFIG_QNX4FS_FS - This is the filesystem used by the operating system QNX 4. Say Y if + This is the file system used by the operating system QNX 4. Say Y if you intend to mount QNX hard disks or floppies. Unless you say Y to "QNX4FS write support" below, you will only be able to read - these filesystems. + these file systems. - This filesystem support is also available as a module ( = code which + This file system support is also available as a module ( = code which can be inserted in and removed from the running kernel whenever you want). The module is called qnx4.o. If you want to compile it as a module, say M here and read Documentation/modules.txt. @@ -8912,18 +8980,18 @@ QNX4FS write support (DANGEROUS) CONFIG_QNX4FS_RW - Say Y if you want to test write support for QNX4 filesystems. + Say Y if you want to test write support for QNX4 file systems. Kernel automounter support CONFIG_AUTOFS_FS - The automounter is a tool to automatically mount remote filesystems + The automounter is a tool to automatically mount remote file systems on demand. This implementation is partially kernel-based to reduce overhead in the already-mounted case; this is unlike the BSD automounter (amd), which is a pure user space daemon. To use the automounter you need the user-space tools from ftp://ftp.kernel.org/pub/linux/daemons/autofs ; you also want to - answer Y to "NFS filesystem support", below. + answer Y to "NFS file system support", below. If you want to compile this as a module ( = code which can be inserted in and removed from the running kernel whenever you want), @@ -8936,16 +9004,16 @@ If you want to use the newer version of autofs with more features, say N here and select automounter v4. -Kernel automounter v4 support +Kernel automounter version 4 support (also supports v3) CONFIG_AUTOFS4_FS - The automounter is a tool to automatically mount remote filesystems + The automounter is a tool to automatically mount remote file systems on demand. This implementation is partially kernel-based to reduce overhead in the already-mounted case; this is unlike the BSD automounter (amd), which is a pure user space daemon. To use the automounter you need the user-space tools from ftp://ftp.kernel.org/pub/linux/daemons/autofs/testing-v4 ; you also - want to answer Y to "NFS filesystem support", below. + want to answer Y to "NFS file system support", below. If you want to compile this as a module ( = code which can be inserted in and removed from the running kernel whenever you want), @@ -8957,17 +9025,17 @@ have a laptop which needs to dynamically reconfigure to the local network, you probably do not need an automounter, and can say N here. -EFS filesystem support (read only) (EXPERIMENTAL) +EFS file system support (read only) (EXPERIMENTAL) CONFIG_EFS_FS - EFS is an older filesystem used for non-ISO9660 CDROMs and hard disk + EFS is an older file system used for non-ISO9660 CDROMs and hard disk partitions by SGI's IRIX operating system (IRIX 6.0 and newer uses - the XFS filesystem for hard disk partitions however). + the XFS file system for hard disk partitions however). This implementation only offers read-only access. If you don't know what all this is about, it's safe to say N. For more information about EFS see its home page at http://aeschi.ch.eu.org/efs/ . - If you want to compile the EFS filesystem support as a module ( = + If you want to compile the EFS file system support as a module ( = code which can be inserted in and removed from the running kernel whenever you want), say M here and read Documentation/modules.txt. The module will be called efs.o. @@ -8977,19 +9045,19 @@ Say Y to this only if you plan on mounting disks with SGI disklabels. This is not required to mount EFS-format CDROMs. -UFS filesystem support (read only) +UFS file system support (read only) CONFIG_UFS_FS BSD and derivate versions of Unix (such as SunOS, FreeBSD, NetBSD, - OpenBSD and NeXTstep) use a filesystem called UFS. Some System V + OpenBSD and NeXTstep) use a file system called UFS. Some System V Unixes can create and mount hard disk partitions and diskettes using - this filesystem as well. Saying Y here will allow you to read from + this file system as well. Saying Y here will allow you to read from these partitions; if you also want to write to them, say Y to the - experimental "UFS filesystem write support", below. Please read the + experimental "UFS file system write support", below. Please read the file Documentation/filesystems/ufs.txt for more information. If you only intend to mount files from some other Unix over the - network using NFS, you don't need the UFS filesystem support (but - you need NFS filesystem support obviously). + network using NFS, you don't need the UFS file system support (but + you need NFS file system support obviously). Note that this option is generally not needed for floppies, since a good portable way to transport files and directories between unixes @@ -9000,14 +9068,14 @@ NeXT character set to the Latin1 character set; use the program recode ("info recode") for this purpose. - If you want to compile the UFS filesystem support as a module ( = + If you want to compile the UFS file system support as a module ( = code which can be inserted in and removed from the running kernel whenever you want), say M here and read Documentation/modules.txt. The module will be called ufs.o. If you haven't heard about all of this before, it's safe to say N. -UFS filesystem write support (DANGEROUS) +UFS file system write support (DANGEROUS) CONFIG_UFS_FS_WRITE Say Y here if you want to try writing to UFS partitions. This is experimental, so you should back up your UFS partitions beforehand. @@ -9045,7 +9113,7 @@ first sector a new partition table in BSD disklabel format. Saying Y here allows you to read these disklabels and further mount FreeBSD partitions from within Linux if you have also said Y to "UFS - filesystem support", above. If you don't know what all this is + file system support", above. If you don't know what all this is about, say N. Sun partition tables support @@ -9053,7 +9121,7 @@ Like most systems, SunOS uses its own hard disk partition table format, incompatible with all others. Saying Y here allows you to read these partition tables and further mount SunOS partitions from - within Linux if you have also said Y to "UFS filesystem support", + within Linux if you have also said Y to "UFS file system support", above. This is mainly used to carry data from a SPARC under SunOS to your Linux box via a removable medium like magneto-optical or ZIP drives; note however that a good portable way to transport files and @@ -9067,16 +9135,16 @@ table format, incompatible with all others. Saying Y here allows you to read these partition tables and further mount Solaris x86 partitions from within Linux if you have also said Y to "UFS - filesystem support", above. + file system support", above. SGI partition support CONFIG_SGI_PARTITION Say Y here if you would like to be able to read the hard disk partition table format used by SGI machines. -ADFS filesystem support (read only) (EXPERIMENTAL) +ADFS file system support (read only) (EXPERIMENTAL) CONFIG_ADFS_FS - The Acorn Disc Filing System is the standard filesystem of the + The Acorn Disc Filing System is the standard file system of the RiscOS operating system which runs on Acorn's ARM-based Risc PC systems and the Acorn Archimedes range of machines. If you say Y here, Linux will be able to read from ADFS partitions on hard drives @@ -9093,10 +9161,10 @@ If unsure, say N. -/dev/pts filesystem for Unix98 PTYs +/dev/pts file system for Unix98 PTYs CONFIG_DEVPTS_FS You should say Y here if you said Y to "Unix98 PTY support" above. - You'll then get a virtual filesystem which can be mounted on + You'll then get a virtual file system which can be mounted on /dev/pts with "mount -t devpts". This, together with the pseudo terminal master multiplexer /dev/ptmx, is used for pseudo terminal support as described in The Open Group's Unix98 standard: in order @@ -9117,8 +9185,9 @@ partition (VTOC - Virtual Table of Contents). Its format is incompatible with all other OSes. Saying Y here allows you to read VTOC and further mount UnixWare partitions read-only from within - Linux if you have also said Y to "UFS filesystem support" or "System - V and Coherent filesystem support", above. + Linux if you have also said Y to "UFS file system support", "System + V and Coherent file system support" or "BFS file system support", + above. This is mainly used to carry data from a UnixWare box to your Linux box via a removable medium like magneto-optical, ZIP or @@ -9129,12 +9198,12 @@ If you don't know what all this is about, say N. -SMB filesystem support (to mount Windows shares etc.) +SMB file system support (to mount Windows shares etc.) CONFIG_SMB_FS SMB (Server Message Block) is the protocol Windows for Workgroups (WfW), Windows 95/98, Windows NT and OS/2 Lan Manager use to share files and printers over local networks. Saying Y here allows you to - mount their filesystems (often called "shares" in this context) and + mount their file systems (often called "shares" in this context) and access them just like any other Unix directory. Currently, this works only if the Windows machines use TCP/IP as the underlying transport protocol, and not NetBEUI. For details, read @@ -9155,10 +9224,10 @@ want), say M here and read Documentation/modules.txt. The module will be called smbfs.o. Most people say N, however. -Coda filesystem support (advanced network fs) +Coda file system support (advanced network fs) CONFIG_CODA_FS - Coda is an advanced network filesystem, similar to NFS in that it - enables you to mount filesystems of a remote server and access them + Coda is an advanced network file system, similar to NFS in that it + enables you to mount file systems of a remote server and access them with regular Unix commands as if they were sitting on your hard disk. Coda has several advantages over NFS: support for disconnected operation (e.g. for laptops), read/write server replication, @@ -9176,7 +9245,7 @@ whenever you want), say M here and read Documentation/modules.txt. The module will be called coda.o. -NCP filesystem support (to mount NetWare volumes) +NCP file system support (to mount NetWare volumes) CONFIG_NCP_FS NCP (NetWare Core Protocol) is a protocol that runs over IPX and is used by Novell NetWare clients to talk to file servers. It is to IPX @@ -9284,7 +9353,7 @@ nls codepage 437 CONFIG_NLS_CODEPAGE_437 - The Microsoft fat filesystem family can deal with filenames in + The Microsoft fat file system family can deal with filenames in native language character sets. These character sets are stored in so-called DOS codepages. You need to include the appropriate codepage if you want to be able to read/write these filenames on @@ -9295,7 +9364,7 @@ nls codepage 737 CONFIG_NLS_CODEPAGE_737 - The Microsoft fat filesystem family can deal with filenames in + The Microsoft fat file system family can deal with filenames in native language character sets. These character sets are stored in so-called DOS codepages. You need to include the appropriate codepage if you want to be able to read/write these filenames on @@ -9306,7 +9375,7 @@ nls codepage 775 CONFIG_NLS_CODEPAGE_775 - The Microsoft fat filesystem family can deal with filenames in + The Microsoft fat file system family can deal with filenames in native language character sets. These character sets are stored in so-called DOS codepages. You need to include the appropriate codepage if you want to be able to read/write these filenames on @@ -9317,7 +9386,7 @@ nls codepage 850 CONFIG_NLS_CODEPAGE_850 - The Microsoft fat filesystem family can deal with filenames in + The Microsoft fat file system family can deal with filenames in native language character sets. These character sets are stored in so-called DOS codepages. You need to include the appropriate codepage if you want to be able to read/write these filenames on @@ -9332,7 +9401,7 @@ nls codepage 852 CONFIG_NLS_CODEPAGE_852 - The Microsoft fat filesystem family can deal with filenames in + The Microsoft fat file system family can deal with filenames in native language character sets. These character sets are stored in so-called DOS codepages. You need to include the appropriate codepage if you want to be able to read/write these filenames on @@ -9346,7 +9415,7 @@ nls codepage 855 CONFIG_NLS_CODEPAGE_855 - The Microsoft fat filesystem family can deal with filenames in + The Microsoft fat file system family can deal with filenames in native language character sets. These character sets are stored in so-called DOS codepages. You need to include the appropriate codepage if you want to be able to read/write these filenames on @@ -9356,7 +9425,7 @@ nls codepage 857 CONFIG_NLS_CODEPAGE_857 - The Microsoft fat filesystem family can deal with filenames in + The Microsoft fat file system family can deal with filenames in native language character sets. These character sets are stored in so-called DOS codepages. You need to include the appropriate codepage if you want to be able to read/write these filenames on @@ -9366,7 +9435,7 @@ nls codepage 860 CONFIG_NLS_CODEPAGE_860 - The Microsoft fat filesystem family can deal with filenames in + The Microsoft fat file system family can deal with filenames in native language character sets. These character sets are stored in so-called DOS codepages. You need to include the appropriate codepage if you want to be able to read/write these filenames on @@ -9376,7 +9445,7 @@ nls codepage 861 CONFIG_NLS_CODEPAGE_861 - The Microsoft fat filesystem family can deal with filenames in + The Microsoft fat file system family can deal with filenames in native language character sets. These character sets are stored in so-called DOS codepages. You need to include the appropriate codepage if you want to be able to read/write these filenames on @@ -9386,7 +9455,7 @@ nls codepage 862 CONFIG_NLS_CODEPAGE_862 - The Microsoft fat filesystem family can deal with filenames in + The Microsoft fat file system family can deal with filenames in native language character sets. These character sets are stored in so-called DOS codepages. You need to include the appropriate codepage if you want to be able to read/write these filenames on @@ -9396,7 +9465,7 @@ nls codepage 863 CONFIG_NLS_CODEPAGE_863 - The Microsoft fat filesystem family can deal with filenames in + The Microsoft fat file system family can deal with filenames in native language character sets. These character sets are stored in so-called DOS codepages. You need to include the appropriate codepage if you want to be able to read/write these filenames on @@ -9407,7 +9476,7 @@ nls codepage 864 CONFIG_NLS_CODEPAGE_864 - The Microsoft fat filesystem family can deal with filenames in + The Microsoft fat file system family can deal with filenames in native language character sets. These character sets are stored in so-called DOS codepages. You need to include the appropriate codepage if you want to be able to read/write these filenames on @@ -9417,7 +9486,7 @@ nls codepage 865 CONFIG_NLS_CODEPAGE_865 - The Microsoft fat filesystem family can deal with filenames in + The Microsoft fat file system family can deal with filenames in native language character sets. These character sets are stored in so-called DOS codepages. You need to include the appropriate codepage if you want to be able to read/write these filenames on @@ -9428,7 +9497,7 @@ nls codepage 866 CONFIG_NLS_CODEPAGE_866 - The Microsoft fat filesystem family can deal with filenames in + The Microsoft fat file system family can deal with filenames in native language character sets. These character sets are stored in so-called DOS codepages. You need to include the appropriate codepage if you want to be able to read/write these filenames on @@ -9439,7 +9508,7 @@ nls codepage 869 CONFIG_NLS_CODEPAGE_869 - The Microsoft fat filesystem family can deal with filenames in + The Microsoft fat file system family can deal with filenames in native language character sets. These character sets are stored in so-called DOS codepages. You need to include the appropriate codepage if you want to be able to read/write these filenames on @@ -9452,7 +9521,7 @@ nls codepage 874 CONFIG_NLS_CODEPAGE_874 - The Microsoft fat filesystem family can deal with filenames in + The Microsoft fat file system family can deal with filenames in native language character sets. These character sets are stored in so-called DOS codepages. You need to include the appropriate codepage if you want to be able to read/write these filenames on @@ -9463,7 +9532,7 @@ nls iso8859-1 CONFIG_NLS_ISO8859_1 If you want to display filenames with native language characters - from the Microsoft fat filesystem family or from JOLIET CDROMs + from the Microsoft fat file system family or from JOLIET CDROMs correctly on the screen, you need to include the appropriate input/output character sets. Say Y here for the Latin 1 character set, which covers most West European languages such as Albanian, @@ -9474,7 +9543,7 @@ nls iso8859-2 CONFIG_NLS_ISO8859_2 If you want to display filenames with native language characters - from the Microsoft fat filesystem family or from JOLIET CDROMs + from the Microsoft fat file system family or from JOLIET CDROMs correctly on the screen, you need to include the appropriate input/output character sets. Say Y here for the Latin 2 character set, which works for most Latin-written Slavic and Central European @@ -9484,7 +9553,7 @@ nls iso8859-3 CONFIG_NLS_ISO8859_3 If you want to display filenames with native language characters - from the Microsoft fat filesystem family or from JOLIET CDROMs + from the Microsoft fat file system family or from JOLIET CDROMs correctly on the screen, you need to include the appropriate input/output character sets. Say Y here for the Latin 3 character set, which is popular with authors of Esperanto, Galician, Maltese, @@ -9493,7 +9562,7 @@ nls iso8859-4 CONFIG_NLS_ISO8859_4 If you want to display filenames with native language characters - from the Microsoft fat filesystem family or from JOLIET CDROMs + from the Microsoft fat file system family or from JOLIET CDROMs correctly on the screen, you need to include the appropriate input/output character sets. Say Y here for the Latin 4 character set which introduces letters for Estonian, Latvian, and @@ -9502,7 +9571,7 @@ nls iso8859-5 CONFIG_NLS_ISO8859_5 If you want to display filenames with native language characters - from the Microsoft fat filesystem family or from JOLIET CDROMs + from the Microsoft fat file system family or from JOLIET CDROMs correctly on the screen, you need to include the appropriate input/output character sets. Say Y here for ISO8859-5, a Cyrillic character set with which you can type Bulgarian, Byelorussian, @@ -9512,7 +9581,7 @@ nls iso8859-6 CONFIG_NLS_ISO8859_6 If you want to display filenames with native language characters - from the Microsoft fat filesystem family or from JOLIET CDROMs + from the Microsoft fat file system family or from JOLIET CDROMs correctly on the screen, you need to include the appropriate input/output character sets. Say Y here for ISO8859-6, the Arabic character set. @@ -9520,7 +9589,7 @@ nls iso8859-7 CONFIG_NLS_ISO8859_7 If you want to display filenames with native language characters - from the Microsoft fat filesystem family or from JOLIET CDROMs + from the Microsoft fat file system family or from JOLIET CDROMs correctly on the screen, you need to include the appropriate input/output character sets. Say Y here for ISO8859-7, the Modern Greek character set. @@ -9528,7 +9597,7 @@ nls iso8859-8 CONFIG_NLS_ISO8859_8 If you want to display filenames with native language characters - from the Microsoft fat filesystem family or from JOLIET CDROMs + from the Microsoft fat file system family or from JOLIET CDROMs correctly on the screen, you need to include the appropriate input/output character sets. Say Y here for ISO8859-8, the Hebrew character set. @@ -9536,7 +9605,7 @@ nls iso8859-9 CONFIG_NLS_ISO8859_9 If you want to display filenames with native language characters - from the Microsoft fat filesystem family or from JOLIET CDROMs + from the Microsoft fat file system family or from JOLIET CDROMs correctly on the screen, you need to include the appropriate input/output character sets. Say Y here for the Latin 5 character set, and it replaces the rarely needed Icelandic letters in Latin 1 @@ -9545,7 +9614,7 @@ nls iso8859-10 CONFIG_NLS_ISO8859_10 If you want to display filenames with native language characters - from the Microsoft fat filesystem family or from JOLIET CDROMs + from the Microsoft fat file system family or from JOLIET CDROMs correctly on the screen, you need to include the appropriate input/output character sets. Say Y here for the Latin 6 character set, which adds the last Inuit (Greenlandic) and Sami (Lappish) @@ -9555,7 +9624,7 @@ NLS ISO 8859-14 (Latin 8; Celtic) CONFIG_NLS_ISO8859_14 If you want to display filenames with native language characters - from the Microsoft fat filesystem family or from JOLIET CDROMs + from the Microsoft fat file system family or from JOLIET CDROMs correctly on the screen, you need to include the appropriate input/output character sets. Say Y here for the Latin 8 character set, which adds the last accented vowels for Welsh (aka Cymraeg) @@ -9565,7 +9634,7 @@ nls iso8859-15 CONFIG_NLS_ISO8859_15 If you want to display filenames with native language characters - from the Microsoft fat filesystem family or from JOLIET CDROMs + from the Microsoft fat file system family or from JOLIET CDROMs correctly on the screen, you need to include the appropriate input/output character sets. Say Y here for the Latin 9 character set, which covers most West European languages such as Albanian, @@ -9580,7 +9649,7 @@ nls koi8-r CONFIG_NLS_KOI8_R If you want to display filenames with native language characters - from the Microsoft fat filesystem family or from JOLIET CDROMs + from the Microsoft fat file system family or from JOLIET CDROMs correctly on the screen, you need to include the appropriate input/output character sets. Say Y here for the preferred Russian character set. @@ -9915,8 +9984,8 @@ traditionally /dev/ttyp2 will then be /dev/pts/2, for example. The entries in /dev/pts/ are created on the fly by a virtual - filesystem; therefore, if you say Y here you should say Y to - "/dev/pts filesystem for Unix98 PTYs" as well. + file system; therefore, if you say Y here you should say Y to + "/dev/pts file system for Unix98 PTYs" as well. If you want to say Y here, you need to have the C library glibc 2.1 or later (equal to libc-6.1, check with "ls -l /lib/libc.so.*"). @@ -9969,7 +10038,7 @@ option "console=lp" to the kernel at boot time. Note that kernel messages can get lost if the printer is out of - paper (or off, or unplugged, or too busy..), but this behaviour + paper (or off, or unplugged, or too busy..), but this behavior can be changed. See drivers/char/lp.c (do this at your own risk). If unsure, say N. @@ -10238,7 +10307,7 @@ Procfs entry for ftape CONFIG_FT_PROC_FS Optional. Saying Y will result in creation of a directory - `/proc/ftape' under the proc file system. The files can be viewed + `/proc/ftape' under the /proc file system. The files can be viewed with your favorite pager (i.e. use "more /proc/ftape/history" or "less /proc/ftape/history" or simply "cat /proc/ftape/history"). The file will contain some status information about the inserted @@ -10248,9 +10317,10 @@ by approximately 2 KB. WARNING: When compiling ftape as a module (i.e. saying M to - "Floppy tape drive") it is dangerous to use ftape's proc file system - interface. Accessing `/proc/ftape' while the module is unloaded will - result in a kernel Oops. This cannot be fixed from inside ftape. + "Floppy tape drive") it is dangerous to use ftape's /proc file + system interface. Accessing `/proc/ftape' while the module is + unloaded will result in a kernel Oops. This cannot be fixed from + inside ftape. Controlling the amount of debugging output of ftape CONFIG_FT_NORMAL_DEBUG @@ -10579,6 +10649,11 @@ 11) exchange RAM chips 12) exchange the motherboard. + To compile this driver as a module ( = code which can be inserted in + and removed from the running kernel whenever you want), say M here + and read Documentation/modules.txt. The module will be called + apm.o. + Ignore USER SUSPEND CONFIG_APM_IGNORE_USER_SUSPEND This option will ignore USER SUSPEND requests. On machines with a @@ -10660,14 +10735,6 @@ many of the newer IBM Thinkpads. If you experience hangs when you suspend, try setting this to Y. Otherwise, say N. -Entry point offset fix (some Acer laptops) -CONFIG_APM_BAD_ENTRY_OFFSET - Some implementations of the APM BIOS provide the driver with a bad - entry point offset. If you set this option to Y, then the upper - sixteen bits of the offset will be set to zero. This is usually - unnecessary but harmless. This is required for the Acer Travelmate - 510DX, Travelmate 510T and Extensa 503T. For others, say N. - Use real mode APM BIOS call to power off CONFIG_APM_REAL_MODE_POWER_OFF Use real mode APM BIOS calls to switch off the computer. This is @@ -10699,7 +10766,7 @@ Disable watchdog shutdown on close CONFIG_WATCHDOG_NOWAYOUT - The default watchdog behaviour (which you get if you say N here) is + The default watchdog behavior (which you get if you say N here) is to stop the timer if the process managing it closes the file /dev/watchdog. It's always remotely possible that this process might get killed. If you say Y here, the watchdog cannot be stopped once @@ -10799,7 +10866,7 @@ Every PC has such a clock built in. It can be used to generate signals from as low as 1Hz up to 8192Hz, and can also be used as a 24 hour alarm. It reports status information via the file - /proc/driver/rtc and its behaviour is set by various ioctls on + /proc/driver/rtc and its behavior is set by various ioctls on /dev/rtc. If you run Linux on a multiprocessor machine and said Y to @@ -10992,7 +11059,7 @@ row. Do not hold the button down for too long, as the driver does not - alter the behaviour of the hardware reset circuitry attached to the + alter the behavior of the hardware reset circuitry attached to the button; it will still execute a hard reset if the button is held down for longer than approximately five seconds. @@ -12335,7 +12402,7 @@ Say Y if you want your expansion cards to be identified on bootup; it will enlarge your kernel by about 10 KB. The identification information is also available through /proc/zorro (say Y to - "/proc filesystem support"!). + "/proc file system support"!). Note that even if you say N here, you can still use your expansion cards. If in doubt, say Y. @@ -13114,7 +13181,7 @@ Colour QuickCam Video For Linux CONFIG_VIDEO_CQCAM - This is the video4linux driver for the colour version of the + This is the video4linux driver for the color version of the Connectix Quickcam. If you have one of these cameras, say Y here, otherwise say N. This driver does not work with the original monochrome Quickcam, Quickcam VC or QuickClip. It is also available @@ -13167,7 +13234,7 @@ megs due to kernel allocation issues), you could use PCI accesses and have up to a couple gigs of texture space. - Note that this is the only meas to have get XFree4/GLX use + Note that this is the only mean to have get XFree4/GLX use write-combining with MTRR support on AGP bus. Without, OpenGL direct rendering will be a lot slower but still faster than PIO. @@ -13306,7 +13373,7 @@ Say Y to include the NWFPE floating point emulator in the kernel. This is necessary to run most binaries. Linux does not currently support floating point hardware so you need to say Y here even if - your machine has an FPA or floating point co-processor podule. + your machine has an FPA or floating point co-processor module. It is also possible to say M to build the emulator as a module (nwfpe.o) or indeed to leave it out altogether. However, unless you @@ -13363,12 +13430,12 @@ time and disk space needed for compilation of the kernel. If in doubt say N. -Split initialisation functions into discardable section +Split initialization functions into discardable section CONFIG_TEXT_SECTIONS If you say Y here, kernel code that is only used during - initialisation is collected into a special area of the kernel so + initialization is collected into a special area of the kernel so that it can be discarded and the memory reclaimed when - initialisation is complete. In addition, if the kernel you wish to + initialization is complete. In addition, if the kernel you wish to build is able to run on multiple architectures, it allows the unused code to be discarded. Some versions of binutils, however, have a bug that causes the kernel to crash during startup when this option is @@ -13429,7 +13496,7 @@ MFM hard disk support CONFIG_BLK_DEV_MFM Support the MFM hard drives on the Acorn Archimedes both - on-board the A4x0 motherboards and via the Acorn MFM podules. + on-board the A4x0 motherboards and via the Acorn MFM modules. Drives up to 64MB are supported. If you haven't got one of these machines or drives just say N. @@ -13748,7 +13815,7 @@ CONFIG_KHTTPD The kernel httpd acceleration daemon (kHTTPd) is a (limited) web server build into the kernel. It is limited since it can only - serve files from the filesystem. Saying "M" here builds the + serve files from the file system. Saying "M" here builds the kHTTPd module; this is NOT enough to have a working kHTTPd. For safety reasons, the module has to be activated by doing a "echo 1 > /proc/sys/net/khttpd/start" after inserting the module. @@ -13824,7 +13891,7 @@ # LocalWords: CONFIG coprocessor DX Pentium SX lilo loadlin HOWTO ftp metalab # LocalWords: unc edu docs emu README kB BLK DEV FD Thinkpad fd MFM RLL IDE gz # LocalWords: cdrom diskless netboot nfs xzvf ATAPI MB ide pavia rubini pl pd -# LocalWords: HD CDROMs IDECD NEC MITSUMI filesystem XT XD PCI BIOS cezar ATEN +# LocalWords: HD CDROMs IDECD NEC MITSUMI XT XD PCI BIOS cezar ATEN # LocalWords: ISA EISA Microchannel VESA BIOSes IPC SYSVIPC ipc Ctrl dmesg hlt # LocalWords: BINFMT Linkable http ac uk jo html GCC SPARC AVANTI CABRIOLET EB # LocalWords: netscape gcc LD CC toplevel MODVERSIONS insmod rmmod modprobe IP @@ -13854,7 +13921,7 @@ # LocalWords: readprofile diskdrives org com masq EtherTalk tcp netrom sunacm # LocalWords: misc AIC aic pio scc Portmaster eql GIS PhotoCDs MCDX Perell PG # LocalWords: mcdx gscd optcd sjcd ISP hdparm Workgroups Lan samba PARIDE PCD -# LocalWords: filesystems smbfs ATA ppp PCTech RZ www powerquest txt CMD ESDI +# LocalWords: smbfs ATA ppp PCTech RZ www powerquest txt CMD ESDI # LocalWords: chipset FB multicast MROUTE appletalk ifconfig IBMTR multiport # LocalWords: Multisession STALDRV EasyIO EC EasyConnection ISTALLION ONboard # LocalWords: Brumby pci TNC cis ohio faq usenet NETLINK dev hydra ca Tyne mem @@ -13876,7 +13943,7 @@ # LocalWords: AlphaPC mca AOUT OUTput PPro sipx gwdg lo nwe FourPort Boca unm # LocalWords: Keepalive linefill RELCOM keepalive analogue CDR conf CDI INIT # LocalWords: OPTi isp irq noisp VFAT vfat NTFS losetup dmsdosfs dosfs ISDN MP -# LocalWords: NOWAYOUT behaviour dialin isdn callback BTX Teles ICN EDSS Cisco +# LocalWords: NOWAYOUT behavior dialin isdn callback BTX Teles ICN EDSS Cisco # LocalWords: ipppd syncppp RFC MPP VJ downloaded icn NICCY Creatix shmem ufr # LocalWords: ibp md ARCnet ether encap NDIS arcether ODI Amigas AmiTCP NetBSD # LocalWords: initrd tue util DES funet des OnNet BIOSP smc Travan Iomega CMS @@ -13981,7 +14048,7 @@ # LocalWords: struct APIC realtime OSs LynxOS CNC tmp cvf HFS hfs ADFS Risc os # LocalWords: adfs ncpmount namespace SUBDIR reexport NDS kcore FT SPX spx DAT # LocalWords: interserver BLKSZ NUMBUFFERS apmd Tadpole ANA roestock QuickCam -# LocalWords: isapnptools Colour CQCAM colour Connectix QuickClip prive mentre +# LocalWords: isapnptools Colour CQCAM color Connectix QuickClip prive mentre # LocalWords: KMOD kmod conformant utexas kharker UnixWare Mwave cgi cl ts ibm # LocalWords: eXchange threepio oakland simtel pre ULTRAMCA EtherLink isa luik # LocalWords: EtherLink OpenBSD pts DEVPTS devpts ptmx ttyp glibc readback SA @@ -14045,7 +14112,7 @@ # LocalWords: VROOTHUB KBD ARRs MCRs NWBUTTON nwbutton NUM WaveArtist APNE cpu # LocalWords: apne blackhawke PlanB lu mlan planb NWFPE FPA nwfpe unbootable # LocalWords: FPEmulator ds vmlinux initialisation discardable pgtable PGT mdw -# LocalWords: quicklist pagetable arthur StrongARM podule podules Autodetect +# LocalWords: quicklist pagetable arthur StrongARM module modules Autodetect # LocalWords: dodgy IrPORT irport Litelink litelink SuSE rtfm internet hda CY # LocalWords: multmode DriveReady SeekComplete DriveStatusError miscompile AEC # LocalWords: mainboard's Digital's alim FastTrak aec PIIXn piix Gayle Eyetech diff -u --recursive --new-file v2.3.46/linux/Documentation/DMA-mapping.txt linux/Documentation/DMA-mapping.txt --- v2.3.46/linux/Documentation/DMA-mapping.txt Wed Feb 16 17:03:51 2000 +++ linux/Documentation/DMA-mapping.txt Fri Feb 18 15:07:20 2000 @@ -28,19 +28,126 @@ #include -is in your driver. This file defines a dma_addr_t type which should be -used everywhere you hold a DMA (bus) address returned from the DMA mapping -functions. +is in your driver. This file will obtain for you the definition of +the dma_addr_t type which should be used everywhere you hold a DMA +(bus) address returned from the DMA mapping functions. + + DMA addressing limitations + +Does your device have any DMA addressing limitations? For example, is +your device only capable of driving the low order 24-bits of address +on the PCI bus for DMA transfers? If your device can handle any PCI +dma address fully, then please skip to the next section, the rest of +this section does not concern your device. + +For correct operation, you must interrogate the PCI layer in your +device probe routine to see if the PCI controller on the machine can +properly support the DMA addressing limitation your device has. This +query is performed via a call to pci_dma_supported(): + + int pci_dma_supported(struct pci_dev *pdev, dma_addr_t device_mask) + +Here, pdev is a pointer to the PCI device struct of your device, and +device_mask is a bit mask describing which bits of a PCI address your +device supports. It returns non-zero if your card can perform DMA +properly on the machine. If it returns zero, your device can not +perform DMA properly on this platform, and attempting to do so will +result in undefined behavior. + +In the failure case, you have two options: + +1) Use some non-DMA mode for data transfer, if possible. +2) Ignore this device and do not initialize it. + +It is recommended that your driver print a kernel KERN_WARN message +when you do one of these two things. In this manner, if a user of +your driver reports that performance is bad or that the device is not +even detected, you can ask him for the kernel messages to find out +exactly why. + +So if, for example, you device can only drive the low 24-bits of +address during PCI bus mastering you might do something like: + + if (! pci_dma_supported(pdev, 0x00ffffff)) + goto ignore_this_device; + +There is a case which we are aware of at this time, which is worth +mentioning in this documentation. If your device supports multiple +functions (for example a sound card provides playback and record +functions) and the various different functions have _different_ +DMA addressing limitations, you may wish to probe each mask and +only provide the functionality which the machine can handle. +Here is pseudo-code showing how this might be done: + + #define PLAYBACK_ADDRESS_BITS 0xffffffff + #define RECORD_ADDRESS_BITS 0x00ffffff + + struct my_sound_card *card; + struct pci_dev *pdev; + + ... + if (pci_dma_supported(pdev, PLAYBACK_ADDRESS_BITS)) { + card->playback_enabled = 1; + } else { + card->playback_enabled = 0; + printk(KERN_WARN "%s: Playback disabled due to DMA limitations.\n", + card->name); + } + if (pci_dma_supported(pdev, RECORD_ADDRESS_BITS)) { + card->record_enabled = 1; + } else { + card->record_enabled = 0; + printk(KERN_WARN "%s: Record disabled due to DMA limitations.\n", + card->name); + } + +A sound card was used as an example here because this genre of PCI +devices seems to be littered with ISA chips given a PCI front end, +and thus retaining the 16MB DMA addressing limitations of ISA. + + Types of DMA mappings There are two types of DMA mappings: -- static DMA mappings which are usually mapped at driver initialization, - unmapped at the end and for which the hardware should not assume - sequential accesses (from both the DMA engine in the card and CPU). -- streaming DMA mappings which are usually mapped for one DMA transfer, + +- Consistent DMA mappings which are usually mapped at driver + initialization, unmapped at the end and for which the hardware should + guarentee that the device and the cpu can access the data + in parallel and will see updates made by each other without any + explicit software flushing. + + Think of "consistent" as "synchronous" or "coherent". + + Good examples of what to use consistent mappings for are: + + - Network card DMA ring descriptors. + - SCSI adapter mailbox command data structures. + - Device firmware microcode executed out of + main memory. + + The invariant these examples all require is that any cpu store + to memory is immediately visible to the device, and vice + versa. Consistent mappings guarentee this. + +- Streaming DMA mappings which are usually mapped for one DMA transfer, unmapped right after it (unless you use pci_dma_sync below) and for which hardware can optimize for sequential accesses. -To allocate and map a static DMA region, you should do: + This of "streaming" as "asynchronous" or "outside the coherency + domain". + + Good examples of what to use streaming mappings for are: + + - Networking buffers transmitted/received by a device. + - Filesystem buffers written/read by a SCSI device. + + The interfaces for using this type of mapping were designed in + such a way that an implementation can make whatever performance + optimizations the hardware allows. To this end, when using + such mappings you must be explicit about what you want to happen. + + Using Consistent DMA mappings. + +To allocate and map a consistent DMA region, you should do: dma_addr_t dma_handle; @@ -48,13 +155,18 @@ where dev is a struct pci_dev *. You should pass NULL for PCI like buses where devices don't have struct pci_dev (like ISA, EISA). + This argument is needed because the DMA translations may be bus -specific (and often is private to the bus which the device is attached to). +specific (and often is private to the bus which the device is attached +to). + Size is the length of the region you want to allocate. + This routine will allocate RAM for that region, so it acts similarly to -__get_free_pages (but takes size instead of page order). -It returns two values: the virtual address which you can use to access it -from the CPU and dma_handle which you pass to the card. +__get_free_pages (but takes size instead of a page order). + +It returns two values: the virtual address which you can use to access +it from the CPU and dma_handle which you pass to the card. The cpu return address and the DMA bus master address are both guaranteed to be aligned to the smallest PAGE_SIZE order which @@ -68,7 +180,66 @@ pci_free_consistent(dev, size, cpu_addr, dma_handle); where dev, size are the same as in the above call and cpu_addr and -dma_handle are the values pci_alloc_consistent returned. +dma_handle are the values pci_alloc_consistent returned to you. + + DMA Direction + +The interfaces described in subsequent portions of this document +take a DMA direction argument, which is an integer and takes on +one of the following values: + + PCI_DMA_BIDIRECTIONAL + PCI_DMA_TODEVICE + PCI_DMA_FROMDEVICE + PCI_DMA_NONE + +One should provide the exact DMA direction if you know it. + +PCI_DMA_TODEVICE means "from main memory to the PCI device" +PCI_DMA_FROMDEVICE means "from the PCI device to main memory" + +Cou are _strongly_ encouraged to specify this as precisely +as you possibly can. + +If you absolutely cannot know the direction of the DMA transfer, +specify PCI_DMA_BIDIRECTIONAL. It means that the DMA can go in +either direction. The platform guarentees that you may legally +specify this, and that it will work, but this may be at the +cost of performance for example. + +The value PCI_DMA_NONE is to be used for debugging. One can +hold this in a data structure before you come to know the +precise direction, and this will help catch cases where your +direction tracking logic has failed to set things up properly. + +Another advantage of specifying this value precisely (outside +of potential platform-specific optimizations of such) is for +debugging. Some platforms actually have a write permission +boolean which DMA mappings can be marked with, much like page +protections in a user program can have. Such platforms can +and do report errors in the kernel logs when the PCI controller +hardware detects violation of the permission setting. + +Only streaming mappings specify a direction, consistent mappings +implicitly have a direction attribute setting of +PCI_DMA_BIDIRECTIONAL. + +The SCSI subsystem provides mechanisms for you to easily obtain +the direction to use, in the SCSI command: + + scsi_to_pci_dma_dir(SCSI_DIRECTION) + +Where SCSI_DIRECTION is obtained from the 'sc_data_direction' +member of the SCSI command your driver is working on. The +mentioned interface above returns a value suitable for passing +into the streaming DMA mapping interfaces below. + +For Networking drivers, it's a rather simple affair. For transmit +packets, map/unmap them with the PCI_DMA_TODEVICE direction +specifier. For receive packets, just the opposite, map/unmap them +with the PCI_DMA_FROMDEVICE direction specifier. + + Using Streaming DMA mappings The streaming DMA mapping routines can be called from interrupt context. There are two versions of each map/unmap, one which map/unmap a single @@ -78,18 +249,18 @@ dma_addr_t dma_handle; - dma_handle = pci_map_single(dev, addr, size); + dma_handle = pci_map_single(dev, addr, size, direction); and to unmap it: - pci_unmap_single(dev, dma_handle, size); + pci_unmap_single(dev, dma_handle, size, direction); You should call pci_unmap_single when the DMA activity is finished, e.g. from interrupt which told you the DMA transfer is done. Similarly with scatterlists, you map a region gathered from several regions by: - int i, count = pci_map_sg(dev, sglist, nents); + int i, count = pci_map_sg(dev, sglist, nents, direction); struct scatterlist *sg; for (i = 0, sg = sglist; i < count; i++, sg++) { @@ -98,13 +269,15 @@ } where nents is the number of entries in the sglist. + The implementation is free to merge several consecutive sglist entries into one (e.g. if DMA mapping is done with PAGE_SIZE granularity, any consecutive sglist entries can be merged into one provided the first one ends and the second one starts on a page boundary - in fact this is a huge advantage for cards which either cannot do scatter-gather or have very limited number of scatter-gather entries) and returns the actual number -of sg entries it mapped them too. +of sg entries it mapped them to. + Then you should loop count times (note: this can be less than nents times) and use sg_dma_address() and sg_dma_length() macros where you previously accessed sg->address and sg->length as shown above. @@ -114,6 +287,12 @@ pci_unmap_sg(dev, sglist, nents); Again, make sure DMA activity finished. + +PLEASE NOTE: The 'nents' argument to the pci_unmap_sg call must be + the _same_ one you passed into the pci_map_sg call, + it should _NOT_ be the 'count' value _returned_ from the + pci_map_sg call. + Every pci_map_{single,sg} call should have its pci_unmap_{single,sg} counterpart, because the bus address space is a shared resource (although in some ports the mapping is per each BUS so less devices contend for the @@ -124,15 +303,64 @@ the data in between the DMA transfers, just map it with pci_map_{single,sg}, after each DMA transfer call either: - pci_dma_sync_single(dev, dma_handle, size); + pci_dma_sync_single(dev, dma_handle, size, direction); or: - pci_dma_sync_sg(dev, sglist, nents); + pci_dma_sync_sg(dev, sglist, nents, direction); and after the last DMA transfer call one of the DMA unmap routines pci_unmap_{single,sg}. If you don't touch the data from the first pci_map_* -call till pci_unmap_*, then you don't have to call pci_sync_* routines. +call till pci_unmap_*, then you don't have to call the pci_sync_* +routines at all. + +Here is pseudo code which shows a situation in which you would need +to use the pci_dma_sync_*() interfaces. + + my_card_setup_receive_buffer(struct my_card *cp, char *buffer, int len) + { + dma_addr_t mapping; + + mapping = pci_map_single(cp->pdev, buffer, len, PCI_DMA_FROMDEVICE); + + cp->rx_buf = buffer; + cp->rx_len = len; + cp->rx_dma = mapping; + + give_rx_buf_to_card(cp); + } + + ... + + my_card_interrupt_handler(int irq, void *devid, struct pt_regs *regs) + { + struct my_card *cp = devid; + + ... + if (read_card_status(cp) == RX_BUF_TRANSFERRED) { + struct my_card_header *hp; + + /* Examine the header to see if we wish + * to except the data. But synchronize + * the DMA transfer with the CPU first + * so that we see updated contents. + */ + pci_dma_sync_single(cp->pdev, cp->rx_buf, cp->rx_len, + PCI_DMA_FROMDEVICE); + + /* Now it is safe to examine the buffer. */ + hp = (struct my_card_header *) cp->rx_buf; + if (header_is_ok(hp)) { + pci_unmap_single(cp->pdev, cp->rx_buf, cp->rx_len, + PCI_DMA_FROMDEVICE); + pass_to_upper_layers(cp->rx_buf); + make_and_setup_new_rx_buf(cp); + } else { + /* Just give the buffer back to the card. */ + give_rx_buf_to_card(cp); + } + } + } Drivers converted fully to this interface should not use virt_to_bus any longer, nor should they use bus_to_virt. Some drivers have to be changed a @@ -142,8 +370,14 @@ stores them in the scatterlist itself if the platform supports dynamic DMA mapping in hardware) in your driver structures and/or in the card registers. -For PCI cards which recognize fewer address lines than 32 in Single -Address Cycle, you should set corresponding pci_dev's dma_mask field to a -different mask. The dma mapping routines then should either honour your request -and allocate the DMA only with the bus address with bits set in your -dma_mask or should complain that the device is not supported on that platform. +This document, and the API itself, would not be in it's current +form without the feedback and suggestions from numerous individuals. +We would like to specifically mention, in no particular order, the +following people: + + Russell King + Leo Dagum + Ralf Baechle + Grant Grundler + Jay Estabrook + Thomas Sailer diff -u --recursive --new-file v2.3.46/linux/Documentation/LVM-HOWTO linux/Documentation/LVM-HOWTO --- v2.3.46/linux/Documentation/LVM-HOWTO Wed Dec 31 16:00:00 1969 +++ linux/Documentation/LVM-HOWTO Thu Feb 17 16:13:04 2000 @@ -0,0 +1,119 @@ +Heinz Mauelshagen's LVM (Logical Volume Manager) howto. 02/10/1999 + + +Abstract: +--------- +The LVM adds a kind of virtual disks and virtual partitions functionality +to the Linux operating system. + +It achieves this by adding an additional layer between the physical peripherals +and the i/o interface in the kernel. + +This allows the concatenation of several disk partitions or total disks +(so-called physical volumes or PVs) or even multiple devices +to form a storage pool (so-called Volume Group or VG) with +allocation units called physical extents (called PE). +You can think of the volume group as a virtual disk. +Please see scenario below. + +Some or all PEs of this VG then can be allocated to so-called Logical Volumes +or LVs in units called logical extents or LEs. +Each LE is mapped to a corresponding PE. +LEs and PEs are equal in size. +Logical volumes are a kind of virtual partitions. + + +The LVs can be used through device special files similar to the known +/dev/sd[a-z]* or /dev/hd[a-z]* named /dev/VolumeGroupName/LogicalVolumeName. + +But going beyond this, you are able to extend or reduce +VGs _AND_ LVs at runtime! + +So... +If for example the capacity of a LV gets too small and your VG containing +this LV is full, you could add another PV to that VG and simply extend +the LV afterwards. +If you reduce or delete a LV you can use the freed capacity for different +LVs in the same VG. + + +The above scenario looks like this: + + /------------------------------------------\ + | /--PV2---\ VG 1 /--PVn---\ | + | |-VGDA---| |-VGDA-- | | + | |PE1PE2..| |PE1PE2..| | + | | | ...... | | | + | | | | | | + | | /-----------------------\ | | + | | \-------LV 1------------/ | | + | | ..PEn| | ..PEn| | + | \--------/ \--------/ | + \------------------------------------------/ + +PV 1 could be /dev/sdc1 sized 3GB +PV n could be /dev/sde1 sized 4GB +VG 1 could be test_vg +LV 1 could be /dev/test_vg/test_lv +VGDA is the volume group descriptor area holding the LVM metadata +PE1 up to PEn is the number of physical extents on each disk(partition) + + + +Installation steps see INSTALL and insmod(1)/modprobe(1), kmod/kerneld(8) +to load the logical volume manager module if you did not bind it +into the kernel. + + +Configuration steps for getting the above scenario: + +1. Set the partition system id to 0x8e on /dev/sdc1 and /dev/sde1. + +2. do a "pvcreate /dev/sd[ce]1" + For testing purposes you can use more than one partition on a disk. + You should not use more than one partition because in the case of + a striped LV you'll have a performance breakdown. + +3. do a "vgcreate test_vg /dev/sd[ce]1" to create the new VG named "test_vg" + which has the total capacity of both partitions. + vgcreate activates (transfers the metadata into the LVM driver in the kernel) + the new volume group too to be able to create LVs in the next step. + +4. do a "lvcreate -L1500 -ntest_lv test_vg" to get a 1500MB linear LV named + "test_lv" and it's block device special "/dev/test_vg/test_lv". + + Or do a "lvcreate -i2 -I4 -l1500 -nanother_test_lv test_vg" to get a 100 LE + large logical volume with 2 stripes and stripesize 4 KB. + +5. For example generate a filesystem in one LV with + "mke2fs /dev/test_vg/test_lv" and mount it. + +6. extend /dev/test_vg/test_lv to 1600MB with relative size by + "lvextend -L+100 /dev/test_vg/test_lv" + or with absolute size by + "lvextend -L1600 /dev/test_vg/test_lv" + +7. reduce /dev/test_vg/test_lv to 900 logical extents with relative extents by + "lvreduce -l-700 /dev/test_vg/test_lv" + or with absolute extents by + "lvreduce -l900 /dev/test_vg/test_lv" + +9. rename a VG by deactivating it with + "vgchange -an test_vg" # only VGs with _no_ open LVs can be deactivated! + "vgrename test_vg whatever" + and reactivate it again by + "vgchange -ay whatever" + +9. rename a LV after closing it by + "lvchange -an /dev/whatever/test_lv" # only closed LVs can be deactivated + "lvrename /dev/whatever/test_lv /dev/whatever/whatvolume" + or by + "lvrename whatever test_lv whatvolume" + and reactivate it again by + "lvchange -ay /dev/whatever/whatvolume" + +10. if you own Ted Tso's/Powerquest's resize2fs program, you are able to + resize the ext2 type filesystems contained in logical volumes without + destroyiing the data by + "e2fsadm -L+100 /dev/test_vg/another_test_lv" + diff -u --recursive --new-file v2.3.46/linux/Documentation/filesystems/devfs/ChangeLog linux/Documentation/filesystems/devfs/ChangeLog --- v2.3.46/linux/Documentation/filesystems/devfs/ChangeLog Wed Feb 16 17:03:51 2000 +++ linux/Documentation/filesystems/devfs/ChangeLog Sun Feb 20 20:23:20 2000 @@ -913,7 +913,7 @@ Changes for patch v105 - Unregister SCSI host from in - Thanks to Zoltan BOSZORMENYI + Thanks to Zoltán Böszörményi - Don't save /dev/log in rc.devfs @@ -1438,3 +1438,28 @@ Work sponsored by SGI - Ported to kernel 2.3.46-pre2 +=============================================================================== +Changes for patch v159 + +Work sponsored by SGI + +- Fixed drivers/block/md.c + Thanks to Mike Galbraith + +- Documentation fixes + +- Moved device registration from to + Thanks to Tim Waugh +=============================================================================== +Changes for patch v160 + +Work sponsored by SGI + +- Fixed drivers/char/joystick/joystick.c + Thanks to Vojtech Pavlik + +- Documentation updates + +- Fixed arch/i386/kernel/mtrr.c if procfs and devfs not enabled + +- Fixed drivers/char/stallion.c diff -u --recursive --new-file v2.3.46/linux/Documentation/filesystems/devfs/README linux/Documentation/filesystems/devfs/README --- v2.3.46/linux/Documentation/filesystems/devfs/README Wed Feb 16 17:03:51 2000 +++ linux/Documentation/filesystems/devfs/README Sun Feb 20 20:23:20 2000 @@ -472,6 +472,29 @@ will require this. Note that the kernel creates a compatibility entry for the root device, so you don't need initrd. +Note that you no longer need to mount devpts if you use Unix98 PTYs, +as devfs can manage /dev/pts itself. This saves you some RAM, as you +don't need to compile and install devpts. Note that some versions of +glibc have a bug with Unix98 pty handling on devfs systems. Contact +the glibc maintainers for a fix. + +Note also that apart from editing /etc/fstab, other things will need +to be changed if you *don't* install devfsd. Some software (like the X +server) hard-wire device names in their source. It really is much +easier to install devfsd so that compatibility entries are created. +You can then slowly migrate your system to using the new device names +(for example, by starting with /etc/fstab), and then limiting the +compatibility entries that devfsd creates. +MAKE SURE YOU INSTALL DEVFSD BEFORE YOU BOOT A DEVFS-ENABLED KERNEL! + +Now that devfs has gone into the 2.3.46 kernel, I'm getting a lot of +reports back. Many of these are because people are trying to run +without devfsd, and hence some things break. Please just run devfsd if +things break. I want to concentrate on real bugs rather than +misconfiguration problems at the moment. If people are willing to fix +bugs/false assumptions in other code (i.e. glibc, X server) and submit +that to the respective maintainers, that would be great. + Fail-safe Approach with real /dev inodes ---------------------------------------- This method involves more work, and is no longer recommended now that @@ -614,25 +637,25 @@ - TTY devices (console, serial ports, terminals and pseudo-terminals) Thanks to C. Scott Ananian -- SCSI tapes (/dev/st*) +- SCSI tapes (/dev/scsi and /dev/tapes) -- SCSI CD-ROMs (/dev/sr*) +- SCSI CD-ROMs (/dev/scsi and /dev/cdroms) -- SCSI generic devices (/dev/sg*) +- SCSI generic devices (/dev/scsi) - RAMDISCS (/dev/ram?) - Meta Devices (/dev/md*) -- Floppy discs (/dev/fd?*) +- Floppy discs (/dev/floppy) -- Parallel port printers (/dev/lp*) +- Parallel port printers (/dev/printers) -- Sound devices +- Sound devices (/dev/sound) Thanks to Eric Dumas and C. Scott Ananian -- Joysticks (/dev/js*) +- Joysticks (/dev/joysticks) - Sparc keyboard (/dev/kbd) @@ -642,12 +665,12 @@ - Coda network file system (/dev/cfs*) -- Virtual console capture devices (/dev/vcs*) +- Virtual console capture devices (/dev/vcc) Thanks to Dennis Hou -- Frame buffer devices (/dev/fb*) +- Frame buffer devices (/dev/fb) -- Video capture devices (/dev/video? /dev/vbi?) +- Video capture devices (/dev/v4l) Naming Scheme
@@ -751,6 +774,7 @@ /dev/tts/{0,1,...} /dev/ttyS{0,1,...} Serial ports /dev/cua/{0,1,...} /dev/cua{0,1,...} Call out devices /dev/vc/{0,1,...} /dev/tty{1...63} Virtual consoles + /dev/vcc/{0,1,...} /dev/vcs{1...63} Virtual consoles /dev/pty/m{0,1,...} /dev/ptyp?? PTY masters /dev/pty/s{0,1,...} /dev/ttyp?? PTY slaves @@ -848,6 +872,13 @@ simultaneous xterms and remote logins). Note that the device number is limited to the range 36864-61439 (majors 144-239), in order to avoid any possible conflicts with existing official allocations. + +Please note that using dynamically allocated block device numbers may +break the NFS daemons (both user and kernel mode), which expect dev_t +for a given device to be constant over reboots. A simple reboot, with +no change in your hardware layout, would result in the same device +numbers being allocated, and hence will not cause a problem for NFS +daemons. A final note on this scheme: since it doesn't increase the size of device numbers, there are no compatibility issues with userspace. diff -u --recursive --new-file v2.3.46/linux/Documentation/filesystems/devfs/ToDo linux/Documentation/filesystems/devfs/ToDo --- v2.3.46/linux/Documentation/filesystems/devfs/ToDo Wed Feb 16 17:03:51 2000 +++ linux/Documentation/filesystems/devfs/ToDo Thu Feb 17 15:24:52 2000 @@ -2,7 +2,7 @@ Richard Gooch - 5-DEC-1999 + 18-FEB-2000 This is a list of things to be done for better devfs support in the Linux kernel. If you'd like to contribute to the devfs, please have a @@ -37,4 +37,6 @@ - I2O block device (drivers/i2o/i2o_block.c) - ST-RAM device (arch/m68k/atari/stram.c) + +- Raw devices diff -u --recursive --new-file v2.3.46/linux/Documentation/kbuild/config-language.txt linux/Documentation/kbuild/config-language.txt --- v2.3.46/linux/Documentation/kbuild/config-language.txt Wed Oct 27 16:34:12 1999 +++ linux/Documentation/kbuild/config-language.txt Sun Feb 20 20:13:10 2000 @@ -120,6 +120,7 @@ Dependent statements: dep_bool /prompt/ /symbol/ /dep/ ... + dep_mbool /prompt/ /symbol/ /dep/ ... dep_hex /prompt/ /symbol/ /word/ /dep/ ... dep_int /prompt/ /symbol/ /word/ /dep/ ... dep_string /prompt/ /symbol/ /word/ /dep/ ... @@ -386,8 +387,8 @@ Example: - # Not from the corpus - define_int CONFIG_UID_TORVALDS 2026 + # drivers/char/ftape/Config.in + define_int CONFIG_FT_ALPHA_CLOCK 0 @@ -424,10 +425,15 @@ Example: - # not from the corpus - if [ "$CONFIG_ZFTAPE" != "n" ]; then - comment 'The compressor will be built as a module only!' - define_tristate CONFIG_ZFT_COMPRESSOR m + # drivers/video/Config.in + if [ "$CONFIG_FB_AMIGA" = "y" ]; then + define_tristate CONFIG_FBCON_AFB y + define_tristate CONFIG_FBCON_ILBM y + else + if [ "$CONFIG_FB_AMIGA" = "m" ]; then + define_tristate CONFIG_FBCON_AFB m + define_tristate CONFIG_FBCON_ILBM m + fi fi @@ -438,6 +444,36 @@ Any dependency which has a value of "y" does not restrict the input range. Any dependency which has an empty value is ignored. Any dependency which has a value of "n", or which has some other value, +(like "m") restricts the input range to "n". Quoting dependencies is not +allowed. Using dependencies with an empty value possible is not +recommended. See also dep_mbool below. + +If the input range is restricted to the single choice "n", dep_bool +silently assigns "n" to /symbol/. If the input range has more than +one choice, dep_bool displays /prompt/ to the user, accepts a value +from the user, and assigns that value to /symbol/. + +Configure: implemented +Menuconfig: implemented +XConfig: implemented +mconfig: implemented + +Example: + + # drivers/net/Config.in + dep_bool 'Aironet 4500/4800 PCI support 'CONFIG_AIRONET4500_PCI $CONFIG_PCI + +Known bugs: +- Xconfig does not write "# foo is not set" to .config (as well as + "#unset foo" to autoconf.h) if command is disabled by its dependencies. + + +=== dep_mbool /prompt/ /symbol/ /dep/ ... + +This verb evaluates all of the dependencies in the dependency list. +Any dependency which has a value of "y" or "m" does not restrict the +input range. Any dependency which has an empty value is ignored. +Any dependency which has a value of "n", or which has some other value, restricts the input range to "n". Quoting dependencies is not allowed. Using dependencies with an empty value possible is not recommended. @@ -446,13 +482,18 @@ one choice, dep_bool displays /prompt/ to the user, accepts a value from the user, and assigns that value to /symbol/. +Notice that the only difference between dep_bool and dep_mbool +is in the way of treating the "m" value as a dependency. + Configure: implemented Menuconfig: implemented XConfig: implemented -mconfig: implemented +mconfig: not implemented - # not from the corpus - dep_bool 'RZ1000 chipset bugfix/support' CONFIG_BLK_DEV_RZ1000 $CONFIG_PCI +Example: + + # Not from the corpus + dep_mbool 'Packet socket: mmapped IO' CONFIG_PACKET_MMAP $CONFIG_PACKET Known bugs: - Xconfig does not write "# foo is not set" to .config (as well as @@ -492,6 +533,11 @@ Xconfig: implemented mconfig: implemented +Example: + + # drivers/char/Config.in + dep_tristate 'Parallel printer support' CONFIG_PRINTER $CONFIG_PARPORT + Known bugs: - Xconfig does not write "# foo is not set" to .config (as well as "#unset foo" to autoconf.h) if command is disabled by its dependencies. @@ -508,6 +554,13 @@ Xconfig: implemented (with bugs) mconfig: implemented +Example: + + # arch/mips/config.in + unset CONFIG_PCI + unset CONFIG_MIPS_JAZZ + unset CONFIG_VIDEO_G364 + === choice /prompt/ /word/ /word/ @@ -538,6 +591,14 @@ Xconfig: implemented mconfig: implemented +Example: + + # arch/i386/config.in + choice ' PCI access mode' \ + "BIOS CONFIG_PCI_GOBIOS \ + Direct CONFIG_PCI_GODIRECT \ + Any CONFIG_PCI_GOANY" Any + === nchoice /prompt/ /symbol/ /prompt/ /symbol/ ... @@ -602,9 +663,6 @@ Xconfig has some known bugs, and probably some unknown bugs too: - literals with an empty "" value are not properly handled. - -- tkparse gives the wrong precedence to -o, -a, and !. Don't use both - -o and -a in an expression. Don't use ! at all. diff -u --recursive --new-file v2.3.46/linux/Documentation/magic-number.txt linux/Documentation/magic-number.txt --- v2.3.46/linux/Documentation/magic-number.txt Sun Aug 9 12:15:49 1998 +++ linux/Documentation/magic-number.txt Sun Feb 20 20:37:09 2000 @@ -48,7 +48,7 @@ PG_MAGIC 'P' pg_{read,write}_hdr include/linux/pg.h MKISS_DRIVER_MAGIC 0x04bf mkiss_channel drivers/net/mkiss.h RISCOM8_MAGIC 0x0907 riscom_port drivers/char/riscom8.h -APM_BIOS_MAGIC 0x4101 apm_bios_struct include/linux/apm_bios.h +APM_BIOS_MAGIC 0x4101 apm_user arch/i386/kernel/apm.c CYCLADES_MAGIC 0x4359 cyclades_port include/linux/cyclades.h FASYNC_MAGIC 0x4601 fasync_struct include/linux/fs.h PTY_MAGIC 0x5001 (none at the moment) diff -u --recursive --new-file v2.3.46/linux/Documentation/networking/bridge.txt linux/Documentation/networking/bridge.txt --- v2.3.46/linux/Documentation/networking/bridge.txt Wed Dec 31 16:00:00 1969 +++ linux/Documentation/networking/bridge.txt Fri Feb 18 14:51:22 2000 @@ -0,0 +1,11 @@ +In order to use the ethernet bridging functionality you'll need the +userspace tools available at ftp://openrock.net/bridge. The tarball +available there contains extensive documentation, but if you still have +questions, don't hesitate to post to the mailing list (more info at +http://openrock.net/mailman/listinfo/bridge). You can also mail me at +buytenh@openrock.net. + + + +Lennert Buytenhek + diff -u --recursive --new-file v2.3.46/linux/Documentation/networking/decnet.txt linux/Documentation/networking/decnet.txt --- v2.3.46/linux/Documentation/networking/decnet.txt Thu Feb 10 17:11:02 2000 +++ linux/Documentation/networking/decnet.txt Thu Feb 17 17:26:36 2000 @@ -24,7 +24,7 @@ Be sure to turn on the following options: CONFIG_DECNET (obviously) - CONFIG_PROCFS (to see what's going on) + CONFIG_PROC_FS (to see what's going on) CONFIG_SYSCTL (for easy configuration) if you want to try out router support (not properly debugged yet) diff -u --recursive --new-file v2.3.46/linux/Documentation/networking/skfp.txt linux/Documentation/networking/skfp.txt --- v2.3.46/linux/Documentation/networking/skfp.txt Wed Dec 31 16:00:00 1969 +++ linux/Documentation/networking/skfp.txt Fri Feb 18 14:55:53 2000 @@ -0,0 +1,214 @@ +(C)Copyright 1998-2000 SysKonnect, +=========================================================================== + +skfp.txt created 17-Feb-2000 + +Readme File for skfp.o v2.05 + + +This file contains +(1) OVERVIEW +(2) SUPPORTED ADAPTERS +(3) GENERAL INFORMATION +(4) INSTALLATION +(5) INCLUSION OF THE ADAPTER IN SYSTEM START +(6) TROUBLESHOOTING +(7) FUNCTION OF THE ADAPTER LEDS +(8) HISTORY + +=========================================================================== + + + +(1) OVERVIEW +============ + +This README explains how to use the driver 'skfp' for Linux with your +network adapter. + +Chapter 2: Contains a list of all network adapters that are supported by + this driver. + +Chapter 3: Gives some general information. + +Chapter 4: Describes common problems and solutions. + +Chapter 5: Shows the changed functionality of the adapter LEDs. + +Chapter 6: History of development. + +*** + + +(2) SUPPORTED ADAPTERS +====================== + +The network driver 'skfp' supports the following network adapters: +SysKonnect adapters: + - SK-5521 (SK-NET FDDI-UP) + - SK-5522 (SK-NET FDDI-UP DAS) + - SK-5541 (SK-NET FDDI-FP) + - SK-5543 (SK-NET FDDI-LP) + - SK-5544 (SK-NET FDDI-LP DAS) + - SK-5821 (SK-NET FDDI-UP64) + - SK-5822 (SK-NET FDDI-UP64 DAS) + - SK-5841 (SK-NET FDDI-FP64) + - SK-5843 (SK-NET FDDI-LP64) + - SK-5844 (SK-NET FDDI-LP64 DAS) +Compaq adapters (not tested): + - Netelligent 100 FDDI DAS Fibre SC + - Netelligent 100 FDDI SAS Fibre SC + - Netelligent 100 FDDI DAS UTP + - Netelligent 100 FDDI SAS UTP + - Netelligent 100 FDDI SAS Fibre MIC +*** + + +(3) GENERAL INFORMATION +======================= + +From v2.01 on, the driver is integrated in the linux kernel sources. +Therefor, the installation is the same as for any other adapter +supported by the kernel. +Refer to the manual of your distribution about the installation +of network adapters. +Makes my life much easier :-) +*** + + +(4) TROUBLESHOOTING +=================== + +If you run into problems during installation, check those items: + +Problem: The FDDI adapter can not be found by the driver. +Reason: Look in /proc/pci for the following entry: + 'FDDI network controller: SysKonnect SK-FDDI-PCI ...' + If this entry exists, then the FDDI adapter has been + found by the system and should be able to be used. + If this entry does not exist or if the file '/proc/pci' + is not there, then you may have a hardware problem or PCI + support may not be enabled in your kernel. + The adapter can be checked using the diagnostic program + which is available from the SysKonnect web site: + www.syskonnect.de + Some COMPAQ machines have a problem with PCI under + Linux. This is described in the 'PCI howto' document + (included in some distributions or available from the + www, e.g. at 'www.linux.org') and no workaround is available. + +Problem: You want to use your computer as a router between + multiple IP subnetworks (using multiple adapters), but + you can not reach computers in other subnetworks. +Reason: Either the router's kernel is not configured for IP + forwarding or there is a problem with the routing table + and gateway configuration in at least one of the + computers. + +If your problem is not listed here, please contact our +technical support for help. +You can send email to: + linux@syskonnect.de +When contacting our technical support, +please ensure that the following information is available: +- System Manufacturer and Model +- Boards in your system +- Distribution +- Kernel version + +*** + + +(5) FUNCTION OF THE ADAPTER LEDS +================================ + + The functionality of the LED's on the FDDI network adapters was + changed in SMT version v2.82. With this new SMT version, the yellow + LED works as a ring operational indicator. An active yellow LED + indicates that the ring is down. The green LED on the adapter now + works as a link indicator where an active GREEN LED indicates that + the respective port has a physical connection. + + With versions of SMT prior to v2.82 a ring up was indicated if the + yellow LED was off while the green LED(s) showed the connection + status of the adapter. During a ring down the green LED was off and + the yellow LED was on. + + All implementations indicate that a driver is not loaded if + all LEDs are off. + +*** + + +(6) HISTORY +=========== + +v2.05 (20000217) (In-Kernel version) + New features: + - Changes for 2.3.45 kernel + +v2.04 (20000207) (Standalone version) + New features: + - Added rx/tx byte counter + +v2.03 (20000111) (Standalone version) + Problems fixed: + - Fixed printk statements from v2.02 + +v2.02 (991215) (Standalone version) + Problems fixed: + - Removed unnecessary output + - Fixed path for "printver.sh" in makefile + +v2.01 (991122) (In-Kernel version) + New features: + - Integration in Linux kernel sources + - Support for memory mapped I/O. + +v2.00 (991112) + New features: + - Full source released under GPL + +v1.05 (991023) + Problems fixed: + - Compilation with kernel version 2.2.13 failed + +v1.04 (990427) + Changes: + - New SMT module included, changing LED functionality + Problems fixed: + - Synchronization on SMP machines was buggy + +v1.03 (990325) + Problems fixed: + - Interrupt routing on SMP machines could be incorrect + +v1.02 (990310) + New features: + - Support for kernel versions 2.2.x added + - Kernel patch instead of private duplicate of kernel functions + +v1.01 (980812) + Problems fixed: + Connection hangup with telnet + Slow telnet connection + +v1.00 beta 01 (980507) + New features: + None. + Problems fixed: + None. + Known limitations: + - tar archive instead of standard package format (rpm). + - FDDI statistic is empty. + - not tested with 2.1.xx kernels + - integration in kernel not tested + - not tested simultaneously with FDDI adapters from other vendors. + - only X86 processors supported. + - SBA (Synchronous Bandwidth Allocator) parameters can + not be configured. + - does not work on some COMPAQ machines. See the PCI howto + document for details about this problem. + - data corruption with kernel versions below 2.0.33. + +*** End of information file *** diff -u --recursive --new-file v2.3.46/linux/MAINTAINERS linux/MAINTAINERS --- v2.3.46/linux/MAINTAINERS Wed Feb 16 17:03:51 2000 +++ linux/MAINTAINERS Fri Feb 18 14:51:22 2000 @@ -330,6 +330,13 @@ L: linux-net@vger.rutgers.edu S: Maintained +ETHERNET BRIDGE +P: Lennert Buytenhek +M: buytenh@openrock.net +L: bridge@openrock.net +W: http://openrock.net/bridge +S: Maintained + ETHERTEAM 16I DRIVER P: Mika Kuoppala M: miku@iki.fi @@ -397,6 +404,13 @@ M: oe1kib@oe1kib.ampr.org L: linux-hams@vger.rutgers.edu S: Maintained + +LOGICAL VOLUME MANAGER +P: Heinz Mauelshagen +M: linux-LVM@EZ-Darmstadt.Telekom.de +L: linux-LVM@msede.com +W: http://linux.msede.com/lvm +S: Maintained HIPPI P: Jes Sorensen diff -u --recursive --new-file v2.3.46/linux/Makefile linux/Makefile --- v2.3.46/linux/Makefile Wed Feb 16 17:03:51 2000 +++ linux/Makefile Sun Feb 20 20:14:55 2000 @@ -1,6 +1,6 @@ VERSION = 2 PATCHLEVEL = 3 -SUBLEVEL = 46 +SUBLEVEL = 47 EXTRAVERSION = ARCH := $(shell uname -m | sed -e s/i.86/i386/ -e s/sun4u/sparc64/ -e s/arm.*/arm/ -e s/sa110/arm/) @@ -206,6 +206,10 @@ DRIVERS := $(DRIVERS) drivers/macintosh/macintosh.a endif +ifdef CONFIG_MAC +DRIVERS := $(DRIVERS) drivers/macintosh/macintosh.a +endif + ifeq ($(CONFIG_ISAPNP),y) DRIVERS := $(DRIVERS) drivers/pnp/pnp.o endif @@ -267,8 +271,8 @@ $(LD) $(LINKFLAGS) $(HEAD) init/main.o init/version.o \ --start-group \ $(CORE_FILES) \ - $(NETWORKS) \ $(DRIVERS) \ + $(NETWORKS) \ $(LIBS) \ --end-group \ -o vmlinux @@ -400,6 +404,7 @@ if [ -f FC4_MODULES ]; then inst_mod FC4_MODULES fc4; fi; \ if [ -f IRDA_MODULES ]; then inst_mod IRDA_MODULES net; fi; \ if [ -f SK98LIN_MODULES ]; then inst_mod SK98LIN_MODULES net; fi; \ + if [ -f SKFP_MODULES ]; then inst_mod SKFP_MODULES net; fi; \ if [ -f USB_MODULES ]; then inst_mod USB_MODULES usb; fi; \ if [ -f IEEE1394_MODULES ]; then inst_mod IEEE1394_MODULES ieee1394; fi; \ if [ -f PCMCIA_MODULES ]; then inst_mod PCMCIA_MODULES pcmcia; fi; \ diff -u --recursive --new-file v2.3.46/linux/arch/alpha/kernel/Makefile linux/arch/alpha/kernel/Makefile --- v2.3.46/linux/arch/alpha/kernel/Makefile Thu Feb 10 17:11:02 2000 +++ linux/arch/alpha/kernel/Makefile Sun Feb 20 08:13:56 2000 @@ -14,7 +14,7 @@ O_TARGET := kernel.o O_OBJS := entry.o traps.o process.o osf_sys.o irq.o signal.o setup.o \ - ptrace.o time.o semaphore.o + ptrace.o time.o semaphore.o i8259.o OX_OBJS := alpha_ksyms.o diff -u --recursive --new-file v2.3.46/linux/arch/alpha/kernel/alpha_ksyms.c linux/arch/alpha/kernel/alpha_ksyms.c --- v2.3.46/linux/arch/alpha/kernel/alpha_ksyms.c Thu Feb 10 17:11:02 2000 +++ linux/arch/alpha/kernel/alpha_ksyms.c Fri Feb 18 10:01:32 2000 @@ -36,6 +36,7 @@ extern struct hwrpb_struct *hwrpb; extern void dump_thread(struct pt_regs *, struct user *); extern int dump_fpu(struct pt_regs *, elf_fpregset_t *); +extern spinlock_t kernel_flag; /* these are C runtime functions with special calling conventions: */ extern void __divl (void); @@ -51,6 +52,7 @@ EXPORT_SYMBOL(enable_irq); EXPORT_SYMBOL(disable_irq); EXPORT_SYMBOL(disable_irq_nosync); +EXPORT_SYMBOL(probe_irq_mask); EXPORT_SYMBOL(screen_info); EXPORT_SYMBOL(perf_irq); @@ -96,6 +98,13 @@ EXPORT_SYMBOL(__memsetw); EXPORT_SYMBOL(__constant_c_memset); +EXPORT_SYMBOL(pci_alloc_consistent); +EXPORT_SYMBOL(pci_free_consistent); +EXPORT_SYMBOL(pci_map_single); +EXPORT_SYMBOL(pci_unmap_single); +EXPORT_SYMBOL(pci_map_sg); +EXPORT_SYMBOL(pci_unmap_sg); + EXPORT_SYMBOL(dump_thread); EXPORT_SYMBOL(dump_fpu); EXPORT_SYMBOL(hwrpb); @@ -158,13 +167,16 @@ */ #ifdef __SMP__ +EXPORT_SYMBOL(kernel_flag); EXPORT_SYMBOL(synchronize_irq); EXPORT_SYMBOL(flush_tlb_all); EXPORT_SYMBOL(flush_tlb_mm); EXPORT_SYMBOL(flush_tlb_page); EXPORT_SYMBOL(flush_tlb_range); +EXPORT_SYMBOL(smp_imb); EXPORT_SYMBOL(cpu_data); EXPORT_SYMBOL(__cpu_number_map); +EXPORT_SYMBOL(smp_num_cpus); EXPORT_SYMBOL(global_irq_holder); EXPORT_SYMBOL(__global_cli); EXPORT_SYMBOL(__global_sti); diff -u --recursive --new-file v2.3.46/linux/arch/alpha/kernel/core_mcpcia.c linux/arch/alpha/kernel/core_mcpcia.c --- v2.3.46/linux/arch/alpha/kernel/core_mcpcia.c Thu Feb 10 17:11:02 2000 +++ linux/arch/alpha/kernel/core_mcpcia.c Sun Feb 20 08:13:56 2000 @@ -45,12 +45,6 @@ #define MCPCIA_MAX_HOSES 4 -/* Dodge has PCI0 and PCI1 at MID 4 and 5 respectively. Durango adds - PCI2 and PCI3 at MID 6 and 7 respectively. */ - -#define hose2mid(h) ((h) + 4) - - /* * Given a bus, device, and function number, compute resulting * configuration space address and setup the MCPCIA_HAXR2 register @@ -98,7 +92,7 @@ struct pci_controler *hose) { unsigned long flags; - unsigned long mid = hose2mid(hose->index); + unsigned long mid = MCPCIA_HOSE2MID(hose->index); unsigned int stat0, value, temp, cpu; cpu = smp_processor_id(); @@ -146,7 +140,7 @@ struct pci_controler *hose) { unsigned long flags; - unsigned long mid = hose2mid(hose->index); + unsigned long mid = MCPCIA_HOSE2MID(hose->index); unsigned int stat0, temp, cpu; cpu = smp_processor_id(); @@ -297,7 +291,7 @@ mcpcia_pci_tbi(struct pci_controler *hose, dma_addr_t start, dma_addr_t end) { wmb(); - BUG(); + *(vuip)MCPCIA_SG_TBIA(MCPCIA_HOSE2MID(hose->index)) = 0; mb(); } @@ -305,7 +299,7 @@ mcpcia_probe_hose(int h) { int cpu = smp_processor_id(); - int mid = hose2mid(h); + int mid = MCPCIA_HOSE2MID(h); unsigned int pci_rev; /* Gotta be REAL careful. If hose is absent, we get an mcheck. */ @@ -340,7 +334,7 @@ { struct pci_controler *hose; struct resource *io, *mem, *hae_mem; - int mid = hose2mid(h); + int mid = MCPCIA_HOSE2MID(h); hose = alloc_pci_controler(); io = alloc_resource(); @@ -387,7 +381,7 @@ static void __init mcpcia_startup_hose(struct pci_controler *hose) { - int mid = hose2mid(hose->index); + int mid = MCPCIA_HOSE2MID(hose->index); unsigned int tmp; mcpcia_pci_clr_err(mid); @@ -578,7 +572,7 @@ error was on? */ struct pci_controler *hose; for (hose = hose_head; hose; hose = hose->next) - mcpcia_pci_clr_err(hose2mid(hose->index)); + mcpcia_pci_clr_err(MCPCIA_HOSE2MID(hose->index)); break; } case 1: diff -u --recursive --new-file v2.3.46/linux/arch/alpha/kernel/core_polaris.c linux/arch/alpha/kernel/core_polaris.c --- v2.3.46/linux/arch/alpha/kernel/core_polaris.c Thu Feb 10 17:11:02 2000 +++ linux/arch/alpha/kernel/core_polaris.c Sun Feb 20 08:13:56 2000 @@ -107,7 +107,7 @@ return PCIBIOS_SUCCESSFUL; } -static int +int polaris_read_config_dword(struct pci_dev *dev, int where, u32 *value) { unsigned long pci_addr; @@ -150,7 +150,7 @@ return PCIBIOS_SUCCESSFUL; } -static int +int polaris_write_config_dword(struct pci_dev *dev, int where, u32 value) { unsigned long pci_addr; diff -u --recursive --new-file v2.3.46/linux/arch/alpha/kernel/core_pyxis.c linux/arch/alpha/kernel/core_pyxis.c --- v2.3.46/linux/arch/alpha/kernel/core_pyxis.c Thu Feb 10 17:11:02 2000 +++ linux/arch/alpha/kernel/core_pyxis.c Sun Feb 20 08:13:56 2000 @@ -23,6 +23,7 @@ #include #include "proto.h" +#include "irq_impl.h" #include "pci_impl.h" @@ -286,6 +287,108 @@ write_dword: pyxis_write_config_dword }; +/* Note mask bit is true for ENABLED irqs. */ +static unsigned long cached_irq_mask; + +static inline void +pyxis_update_irq_hw(unsigned long mask) +{ + *(vulp)PYXIS_INT_MASK = mask; + mb(); + *(vulp)PYXIS_INT_MASK; +} + +static inline void +pyxis_enable_irq(unsigned int irq) +{ + pyxis_update_irq_hw(cached_irq_mask |= 1UL << (irq - 16)); +} + +static inline void +pyxis_disable_irq(unsigned int irq) +{ + pyxis_update_irq_hw(cached_irq_mask &= ~(1UL << (irq - 16))); +} + +static unsigned int +pyxis_startup_irq(unsigned int irq) +{ + pyxis_enable_irq(irq); + return 0; +} + +static void +pyxis_mask_and_ack_irq(unsigned int irq) +{ + unsigned long bit = 1UL << (irq - 16); + unsigned long mask = cached_irq_mask &= ~bit; + + /* Disable the interrupt. */ + *(vulp)PYXIS_INT_MASK = mask; + wmb(); + /* Ack PYXIS PCI interrupt. */ + *(vulp)PYXIS_INT_REQ = bit; + mb(); + /* Re-read to force both writes. */ + *(vulp)PYXIS_INT_MASK; +} + +static struct hw_interrupt_type pyxis_irq_type = { + typename: "PYXIS", + startup: pyxis_startup_irq, + shutdown: pyxis_disable_irq, + enable: pyxis_enable_irq, + disable: pyxis_disable_irq, + ack: pyxis_mask_and_ack_irq, + end: pyxis_enable_irq, +}; + +void +pyxis_device_interrupt(unsigned long vector, struct pt_regs *regs) +{ + unsigned long pld; + unsigned int i; + + /* Read the interrupt summary register of PYXIS */ + pld = *(vulp)PYXIS_INT_REQ; + pld &= cached_irq_mask; + + /* + * Now for every possible bit set, work through them and call + * the appropriate interrupt handler. + */ + while (pld) { + i = ffz(~pld); + pld &= pld - 1; /* clear least bit set */ + if (i == 7) + isa_device_interrupt(vector, regs); + else + handle_irq(16+i, regs); + } +} + +void __init +init_pyxis_irqs(unsigned long ignore_mask) +{ + long i; + + *(vulp)PYXIS_INT_MASK = 0; /* disable all */ + *(vulp)PYXIS_INT_REQ = -1; /* flush all */ + mb(); + + /* Send -INTA pulses to clear any pending interrupts ...*/ + *(vuip) PYXIS_IACK_SC; + + for (i = 16; i < 48; ++i) { + if ((ignore_mask >> i) & 1) + continue; + irq_desc[i].status = IRQ_DISABLED; + irq_desc[i].handler = &pyxis_irq_type; + } + + setup_irq(16+7, &isa_cascade_irqaction); +} + void pyxis_pci_tbi(struct pci_controler *hose, dma_addr_t start, dma_addr_t end) { @@ -342,7 +445,7 @@ __restore_flags(flags); } -static void +static void __init pyxis_enable_broken_tbi(struct pci_iommu_arena *arena) { void *page; diff -u --recursive --new-file v2.3.46/linux/arch/alpha/kernel/core_tsunami.c linux/arch/alpha/kernel/core_tsunami.c --- v2.3.46/linux/arch/alpha/kernel/core_tsunami.c Thu Feb 10 17:11:02 2000 +++ linux/arch/alpha/kernel/core_tsunami.c Sun Feb 20 08:13:56 2000 @@ -224,7 +224,7 @@ } #ifdef NXM_MACHINE_CHECKS_ON_TSUNAMI -static long +static long __init tsunami_probe_read(volatile unsigned long *vaddr) { long dont_care, probe_result; @@ -246,7 +246,7 @@ return probe_result; } -static long +static long __init tsunami_probe_write(volatile unsigned long *vaddr) { long true_contents, probe_result = 1; diff -u --recursive --new-file v2.3.46/linux/arch/alpha/kernel/i8259.c linux/arch/alpha/kernel/i8259.c --- v2.3.46/linux/arch/alpha/kernel/i8259.c Wed Dec 31 16:00:00 1969 +++ linux/arch/alpha/kernel/i8259.c Sun Feb 20 08:13:56 2000 @@ -0,0 +1,95 @@ +/* + * linux/arch/alpha/kernel/i8259.c + * + * This is the 'legacy' 8259A Programmable Interrupt Controller, + * present in the majority of PC/AT boxes. + * + * Started hacking from linux-2.3.30pre6/arch/i386/kernel/i8259.c. + */ + +#include +#include +#include +#include +#include + +#include + +#include "proto.h" +#include "irq_impl.h" + + +/* Note mask bit is true for DISABLED irqs. */ +static unsigned int cached_irq_mask = 0xffff; + +static inline void +i8259_update_irq_hw(unsigned int irq, unsigned long mask) +{ + int port = 0x21; + if (irq & 8) mask >>= 8; + if (irq & 8) port = 0xA1; + outb(mask, port); +} + +inline void +i8259a_enable_irq(unsigned int irq) +{ + i8259_update_irq_hw(irq, cached_irq_mask &= ~(1 << irq)); +} + +inline void +i8259a_disable_irq(unsigned int irq) +{ + i8259_update_irq_hw(irq, cached_irq_mask |= 1 << irq); +} + +void +i8259a_mask_and_ack_irq(unsigned int irq) +{ + i8259a_disable_irq(irq); + + /* Ack the interrupt making it the lowest priority. */ + if (irq >= 8) { + outb(0xE0 | (irq - 8), 0xa0); /* ack the slave */ + irq = 2; + } + outb(0xE0 | irq, 0x20); /* ack the master */ +} + +unsigned int +i8259a_startup_irq(unsigned int irq) +{ + i8259a_enable_irq(irq); + return 0; /* never anything pending */ +} + +struct hw_interrupt_type i8259a_irq_type = { + typename: "XT-PIC", + startup: i8259a_startup_irq, + shutdown: i8259a_disable_irq, + enable: i8259a_enable_irq, + disable: i8259a_disable_irq, + ack: i8259a_mask_and_ack_irq, + end: i8259a_enable_irq, +}; + +void __init +init_i8259a_irqs(void) +{ + static struct irqaction cascade = { + handler: no_action, + name: "cascade", + }; + + long i; + + outb(0xff, 0x21); /* mask all of 8259A-1 */ + outb(0xff, 0xA1); /* mask all of 8259A-2 */ + + for (i = 0; i < 16; i++) { + irq_desc[i].status = IRQ_DISABLED; + irq_desc[i].handler = &i8259a_irq_type; + } + + setup_irq(2, &cascade); +} diff -u --recursive --new-file v2.3.46/linux/arch/alpha/kernel/irq.c linux/arch/alpha/kernel/irq.c --- v2.3.46/linux/arch/alpha/kernel/irq.c Thu Feb 10 17:11:02 2000 +++ linux/arch/alpha/kernel/irq.c Sun Feb 20 08:13:56 2000 @@ -17,32 +17,29 @@ #include #include #include -#include #include #include #include #include -#include #include #include +#include #include #include #include "proto.h" +#include "irq_impl.h" #define vulp volatile unsigned long * #define vuip volatile unsigned int * /* Only uniprocessor needs this IRQ/BH locking depth, on SMP it lives in the per-cpu structure for cache reasons. */ -#ifndef __SMP__ +#ifndef CONFIG_SMP int __local_irq_count; int __local_bh_count; -#endif - -#if NR_IRQS > 128 -# error Unable to handle more than 128 irq levels. +unsigned long __irq_attempt[NR_IRQS]; #endif #ifdef CONFIG_ALPHA_GENERIC @@ -51,39 +48,13 @@ #define ACTUAL_NR_IRQS NR_IRQS #endif -/* Reserved interrupts. These must NEVER be requested by any driver! - IRQ 2 used by hw cascade */ -#define IS_RESERVED_IRQ(irq) ((irq)==2) - - /* - * Shadow-copy of masked interrupts. + * Performance counter hook. A module can override this to + * do something useful. */ -unsigned long _alpha_irq_masks[2] = { ~0UL, ~0UL }; - -/* - * The ack_irq routine used by 80% of the systems. - */ - -void -common_ack_irq(unsigned long irq) -{ - if (irq < 16) { - /* Ack the interrupt making it the lowest priority */ - /* First the slave .. */ - if (irq > 7) { - outb(0xE0 | (irq - 8), 0xa0); - irq = 2; - } - /* .. then the master */ - outb(0xE0 | irq, 0x20); - } -} - - - -static void dummy_perf(unsigned long vector, struct pt_regs *regs) +static void +dummy_perf(unsigned long vector, struct pt_regs *regs) { printk(KERN_CRIT "Performance counter interrupt!\n"); } @@ -94,7 +65,9 @@ * Dispatch device interrupts. */ -/* Handle ISA interrupt via the PICs. */ +/* + * Handle ISA interrupt via the PICs. + */ #if defined(CONFIG_ALPHA_GENERIC) # define IACK_SC alpha_mv.iack_sc @@ -112,15 +85,12 @@ # define IACK_SC POLARIS_IACK_SC #elif defined(CONFIG_ALPHA_IRONGATE) # define IACK_SC IRONGATE_IACK_SC -#else - /* This is bogus but necessary to get it to compile on all platforms. */ -# define IACK_SC 1L #endif +#if defined(IACK_SC) void -isa_device_interrupt(unsigned long vector, struct pt_regs * regs) +isa_device_interrupt(unsigned long vector, struct pt_regs *regs) { -#if 1 /* * Generate a PCI interrupt acknowledge cycle. The PIC will * respond with the interrupt vector of the highest priority @@ -135,8 +105,13 @@ return; } } - handle_irq(j, j, regs); -#else + handle_irq(j, regs); +} +#endif +#if defined(CONFIG_ALPHA_GENERIC) || !defined(IACK_SC) +void +isa_no_iack_sc_device_interrupt(unsigned long vector, struct pt_regs *regs) +{ unsigned long pic; /* @@ -153,131 +128,341 @@ * write only. This is not true. */ pic = inb(0x20) | (inb(0xA0) << 8); /* read isr */ - pic &= ~alpha_irq_mask; /* apply mask */ pic &= 0xFFFB; /* mask out cascade & hibits */ while (pic) { int j = ffz(~pic); pic &= pic - 1; - handle_irq(j, j, regs); + handle_irq(j, regs); } +} #endif + +/* + * Handle interrupts from the SRM, assuming no additional weirdness. + */ + +static inline void +srm_enable_irq(unsigned int irq) +{ + cserve_ena(irq - 16); } -/* Handle interrupts from the SRM, assuming no additional weirdness. */ +static void +srm_disable_irq(unsigned int irq) +{ + cserve_dis(irq - 16); +} + +static unsigned int +srm_startup_irq(unsigned int irq) +{ + srm_enable_irq(irq); + return 0; +} + +static struct hw_interrupt_type srm_irq_type = { + typename: "SRM", + startup: srm_startup_irq, + shutdown: srm_disable_irq, + enable: srm_enable_irq, + disable: srm_disable_irq, + ack: srm_disable_irq, + end: srm_enable_irq, +}; void srm_device_interrupt(unsigned long vector, struct pt_regs * regs) { - int irq, ack; + int irq = (vector - 0x800) >> 4; + handle_irq(irq, regs); +} + +void __init +init_srm_irqs(long max, unsigned long ignore_mask) +{ + long i; + + for (i = 16; i < max; ++i) { + if (i < 64 && ((ignore_mask >> i) & 1)) + continue; + irq_desc[i].status = IRQ_DISABLED; + irq_desc[i].handler = &srm_irq_type; + } +} + +/* + * The not-handled irq handler. + */ + +static void +noirq_enable_disable(unsigned int irq) +{ +} + +static unsigned int +noirq_startup(unsigned int irq) +{ + return 0; +} - ack = irq = (vector - 0x800) >> 4; - handle_irq(irq, ack, regs); +static void +noirq_ack(unsigned int irq) +{ + printk(KERN_CRIT "Unexpected IRQ %u\n", irq); } +static struct hw_interrupt_type no_irq_type = { + typename: "none", + startup: noirq_startup, + shutdown: noirq_enable_disable, + enable: noirq_enable_disable, + disable: noirq_enable_disable, + ack: noirq_ack, + end: noirq_enable_disable, +}; /* - * Initial irq handlers. + * The special RTC interrupt type. The interrupt itself was + * processed by PALcode, and comes in via entInt vector 1. */ -static struct irqaction timer_irq = { NULL, 0, 0, NULL, NULL, NULL}; -spinlock_t irq_controller_lock = SPIN_LOCK_UNLOCKED; -irq_desc_t irq_desc[NR_IRQS] __cacheline_aligned = { [0 ... NR_IRQS-1] = {0,} }; +static struct hw_interrupt_type rtc_irq_type = { + typename: "RTC", + startup: noirq_startup, + shutdown: noirq_enable_disable, + enable: noirq_enable_disable, + disable: noirq_enable_disable, + ack: noirq_enable_disable, + end: noirq_enable_disable, +}; + +void __init +init_rtc_irq(void) +{ + irq_desc[RTC_IRQ].status = IRQ_DISABLED; + irq_desc[RTC_IRQ].handler = &rtc_irq_type; +} +/* + * Special irq handlers. + */ -static inline void -mask_irq(unsigned long irq) +void +no_action(int cpl, void *dev_id, struct pt_regs *regs) { - set_bit(irq, _alpha_irq_masks); - alpha_mv.update_irq_hw(irq, alpha_irq_mask, 0); } -static inline void -unmask_irq(unsigned long irq) +/* + * Common irq handlers. + */ + +struct irqaction isa_cascade_irqaction = { + handler: no_action, + name: "isa-cascade" +}; + +struct irqaction timer_cascade_irqaction = { + handler: no_action, + name: "timer-cascade" +}; + +struct irqaction halt_switch_irqaction = { + handler: no_action, + name: "halt-switch" +}; + + +spinlock_t irq_controller_lock = SPIN_LOCK_UNLOCKED; +irq_desc_t irq_desc[NR_IRQS] __cacheline_aligned = { + [0 ... NR_IRQS-1] = { 0, &no_irq_type, } +}; + +int +handle_IRQ_event(unsigned int irq, struct pt_regs *regs, + struct irqaction *action) { - clear_bit(irq, _alpha_irq_masks); - alpha_mv.update_irq_hw(irq, alpha_irq_mask, 1); + int status, cpu = smp_processor_id(); + unsigned long ipl; + + kstat.irqs[cpu][irq]++; + irq_enter(cpu, irq); + + status = 1; /* Force the "do bottom halves" bit */ + ipl = rdps() & 7; + + do { + unsigned long newipl = (action->flags & SA_INTERRUPT ? 7 : 0); + if (newipl != ipl) { + swpipl(newipl); + ipl = newipl; + } + + status |= action->flags; + action->handler(irq, action->dev_id, regs); + action = action->next; + } while (action); + if (status & SA_SAMPLE_RANDOM) + add_interrupt_randomness(irq); + if (ipl == 0) + __cli(); + + irq_exit(cpu, irq); + + return status; } +/* + * Generic enable/disable code: this just calls + * down into the PIC-specific version for the actual + * hardware disable after having gotten the irq + * controller lock. + */ void -disable_irq_nosync(unsigned int irq_nr) +disable_irq_nosync(unsigned int irq) { unsigned long flags; - save_and_cli(flags); - mask_irq(irq_nr); - restore_flags(flags); + spin_lock_irqsave(&irq_controller_lock, flags); + if (!irq_desc[irq].depth++) { + irq_desc[irq].status |= IRQ_DISABLED; + irq_desc[irq].handler->disable(irq); + } + spin_unlock_irqrestore(&irq_controller_lock, flags); } +/* + * Synchronous version of the above, making sure the IRQ is + * no longer running on any other IRQ.. + */ void -disable_irq(unsigned int irq_nr) +disable_irq(unsigned int irq) { - /* This works non-SMP, and SMP until we write code to distribute - interrupts to more that cpu 0. */ - disable_irq_nosync(irq_nr); + disable_irq_nosync(irq); + + if (!local_irq_count(smp_processor_id())) { + do { + barrier(); + } while (irq_desc[irq].status & IRQ_INPROGRESS); + } } void -enable_irq(unsigned int irq_nr) +enable_irq(unsigned int irq) { unsigned long flags; - save_and_cli(flags); - unmask_irq(irq_nr); - restore_flags(flags); + spin_lock_irqsave(&irq_controller_lock, flags); + switch (irq_desc[irq].depth) { + case 1: + { + unsigned int status = irq_desc[irq].status & ~IRQ_DISABLED; + irq_desc[irq].status = status; + if ((status & (IRQ_PENDING | IRQ_REPLAY)) == IRQ_PENDING) { + irq_desc[irq].status = status | IRQ_REPLAY; + + /* ??? We can't re-send on (most?) alpha hw. + hw_resend_irq(irq_desc[irq].handler,irq); */ + } + irq_desc[irq].handler->enable(irq); + /* fall-through */ + } + default: + irq_desc[irq].depth--; + break; + case 0: + printk(KERN_ERR "enable_irq() unbalanced from %p\n", + __builtin_return_address(0)); + } + spin_unlock_irqrestore(&irq_controller_lock, flags); } int -check_irq(unsigned int irq) +setup_irq(unsigned int irq, struct irqaction * new) { - return irq_desc[irq].action ? -EBUSY : 0; + int shared = 0; + struct irqaction *old, **p; + unsigned long flags; + + /* + * Some drivers like serial.c use request_irq() heavily, + * so we have to be careful not to interfere with a + * running system. + */ + if (new->flags & SA_SAMPLE_RANDOM) { + /* + * This function might sleep, we want to call it first, + * outside of the atomic block. + * Yes, this might clear the entropy pool if the wrong + * driver is attempted to be loaded, without actually + * installing a new handler, but is this really a problem, + * only the sysadmin is able to do this. + */ + rand_initialize_irq(irq); + } + + /* + * The following block of code has to be executed atomically + */ + spin_lock_irqsave(&irq_controller_lock,flags); + p = &irq_desc[irq].action; + if ((old = *p) != NULL) { + /* Can't share interrupts unless both agree to */ + if (!(old->flags & new->flags & SA_SHIRQ)) { + spin_unlock_irqrestore(&irq_controller_lock,flags); + return -EBUSY; + } + + /* add new interrupt at end of irq queue */ + do { + p = &old->next; + old = *p; + } while (old); + shared = 1; + } + + *p = new; + + if (!shared) { + irq_desc[irq].depth = 0; + irq_desc[irq].status &= ~IRQ_DISABLED; + irq_desc[irq].handler->startup(irq); + } + spin_unlock_irqrestore(&irq_controller_lock,flags); + return 0; } int request_irq(unsigned int irq, void (*handler)(int, void *, struct pt_regs *), unsigned long irqflags, const char * devname, void *dev_id) { - int shared = 0; - struct irqaction * action, **p; - unsigned long flags; + int retval; + struct irqaction * action; if (irq >= ACTUAL_NR_IRQS) return -EINVAL; - if (IS_RESERVED_IRQ(irq)) - return -EINVAL; if (!handler) return -EINVAL; - p = &irq_desc[irq].action; - action = *p; - if (action) { - /* Can't share interrupts unless both agree to */ - if (!(action->flags & irqflags & SA_SHIRQ)) - return -EBUSY; - - /* Can't share interrupts unless both are same type */ - if ((action->flags ^ irqflags) & SA_INTERRUPT) - return -EBUSY; - - /* Add new interrupt at end of irq queue */ - do { - p = &action->next; - action = *p; - } while (action); - shared = 1; +#if 1 + /* + * Sanity-check: shared interrupts should REALLY pass in + * a real dev-ID, otherwise we'll have trouble later trying + * to figure out which interrupt is which (messes up the + * interrupt freeing logic etc). + */ + if ((irqflags & SA_SHIRQ) && !dev_id) { + printk(KERN_ERR + "Bad boy: %s (at %p) called us without a dev_id!\n", + devname, __builtin_return_address(0)); } +#endif - action = &timer_irq; - if (irq != TIMER_IRQ) { - action = (struct irqaction *) + action = (struct irqaction *) kmalloc(sizeof(struct irqaction), GFP_KERNEL); - } if (!action) return -ENOMEM; - if (irqflags & SA_SAMPLE_RANDOM) - rand_initialize_irq(irq); - action->handler = handler; action->flags = irqflags; action->mask = 0; @@ -285,56 +470,66 @@ action->next = NULL; action->dev_id = dev_id; - save_and_cli(flags); - *p = action; - - if (!shared) - unmask_irq(irq); - - restore_flags(flags); - return 0; + retval = setup_irq(irq, action); + if (retval) + kfree(action); + return retval; } - + void free_irq(unsigned int irq, void *dev_id) { - struct irqaction * action, **p; + struct irqaction **p; unsigned long flags; if (irq >= ACTUAL_NR_IRQS) { - printk("Trying to free IRQ%d\n",irq); - return; - } - if (IS_RESERVED_IRQ(irq)) { - printk("Trying to free reserved IRQ %d\n", irq); + printk(KERN_CRIT "Trying to free IRQ%d\n", irq); return; } - for (p = &irq_desc[irq].action; (action = *p) != NULL; p = &action->next) { - if (action->dev_id != dev_id) - continue; - /* Found it - now free it */ - save_and_cli(flags); - *p = action->next; - if (!irq_desc[irq].action) - mask_irq(irq); - restore_flags(flags); - kfree(action); + spin_lock_irqsave(&irq_controller_lock,flags); + p = &irq_desc[irq].action; + for (;;) { + struct irqaction * action = *p; + if (action) { + struct irqaction **pp = p; + p = &action->next; + if (action->dev_id != dev_id) + continue; + + /* Found - now remove it from the list of entries. */ + *pp = action->next; + if (!irq_desc[irq].action) { + irq_desc[irq].status |= IRQ_DISABLED; + irq_desc[irq].handler->shutdown(irq); + } + spin_unlock_irqrestore(&irq_controller_lock,flags); + + /* Wait to make sure it's not being used on + another CPU. */ + while (irq_desc[irq].status & IRQ_INPROGRESS) + barrier(); + kfree(action); + return; + } + printk(KERN_ERR "Trying to free free IRQ%d\n",irq); + spin_unlock_irqrestore(&irq_controller_lock,flags); return; } - printk("Trying to free free IRQ%d\n",irq); } int get_irq_list(char *buf) { - int i; + int i, j; struct irqaction * action; char *p = buf; -#ifdef __SMP__ +#ifdef CONFIG_SMP p += sprintf(p, " "); for (i = 0; i < smp_num_cpus; i++) p += sprintf(p, "CPU%d ", i); + for (i = 0; i < smp_num_cpus; i++) + p += sprintf(p, "TRY%d ", i); *p++ = '\n'; #endif @@ -343,16 +538,17 @@ if (!action) continue; p += sprintf(p, "%3d: ",i); -#ifndef __SMP__ +#ifndef CONFIG_SMP p += sprintf(p, "%10u ", kstat_irqs(i)); #else - { - int j; - for (j = 0; j < smp_num_cpus; j++) - p += sprintf(p, "%10u ", - kstat.irqs[cpu_logical_map(j)][i]); - } + for (j = 0; j < smp_num_cpus; j++) + p += sprintf(p, "%10u ", + kstat.irqs[cpu_logical_map(j)][i]); + for (j = 0; j < smp_num_cpus; j++) + p += sprintf(p, "%10lu ", + irq_attempt(cpu_logical_map(j), i)); #endif + p += sprintf(p, " %14s", irq_desc[i].handler->typename); p += sprintf(p, " %c%s", (action->flags & SA_INTERRUPT)?'+':' ', action->name); @@ -364,10 +560,17 @@ } *p++ = '\n'; } +#if CONFIG_SMP + p += sprintf(p, "LOC: "); + for (j = 0; j < smp_num_cpus; j++) + p += sprintf(p, "%10lu ", + cpu_data[cpu_logical_map(j)].smp_local_irq_count); + p += sprintf(p, "\n"); +#endif return p - buf; } -#ifdef __SMP__ +#ifdef CONFIG_SMP /* Who has global_irq_lock. */ int global_irq_holder = NO_PROC_ID; @@ -527,7 +730,7 @@ __sti(); break; default: - printk("global_restore_flags: %08lx (%p)\n", + printk(KERN_ERR "global_restore_flags: %08lx (%p)\n", flags, __builtin_return_address(0)); } } @@ -603,141 +806,195 @@ } #endif } -#endif /* __SMP__ */ - -static void -unexpected_irq(int irq, struct pt_regs * regs) -{ -#if 0 -#if 1 - printk("device_interrupt: unexpected interrupt %d\n", irq); -#else - struct irqaction *action; - int i; - - printk("IO device interrupt, irq = %d\n", irq); - printk("PC = %016lx PS=%04lx\n", regs->pc, regs->ps); - printk("Expecting: "); - for (i = 0; i < ACTUAL_NR_IRQS; i++) - if ((action = irq_desc[i].action)) - while (action->handler) { - printk("[%s:%d] ", action->name, i); - action = action->next; - } - printk("\n"); -#endif -#endif - -#if defined(CONFIG_ALPHA_JENSEN) - /* ??? Is all this just debugging, or are the inb's and outb's - necessary to make things work? */ - printk("64=%02x, 60=%02x, 3fa=%02x 2fa=%02x\n", - inb(0x64), inb(0x60), inb(0x3fa), inb(0x2fa)); - outb(0x0c, 0x3fc); - outb(0x0c, 0x2fc); - outb(0,0x61); - outb(0,0x461); -#endif -} +#endif /* CONFIG_SMP */ +/* + * do_IRQ handles all normal device IRQ's (the special + * SMP cross-CPU interrupts have their own specific + * handlers). + */ void -handle_irq(int irq, int ack, struct pt_regs * regs) -{ - struct irqaction * action; +handle_irq(int irq, struct pt_regs * regs) +{ + /* + * We ack quickly, we don't want the irq controller + * thinking we're snobs just because some other CPU has + * disabled global interrupts (we have already done the + * INT_ACK cycles, it's too late to try to pretend to the + * controller that we aren't taking the interrupt). + * + * 0 return value means that this irq is already being + * handled by some other CPU. (or is disabled) + */ int cpu = smp_processor_id(); + irq_desc_t *desc; + struct irqaction * action; + unsigned int status; if ((unsigned) irq > ACTUAL_NR_IRQS) { - printk("device_interrupt: illegal interrupt %d\n", irq); + printk(KERN_CRIT "device_interrupt: illegal interrupt %d\n", + irq); return; } -#if 0 - /* A useful bit of code to find out if an interrupt is going wild. */ - { - static unsigned int last_msg, last_cc; - static int last_irq, count; - unsigned int cc; - - __asm __volatile("rpcc %0" : "=r"(cc)); - ++count; - if (cc - last_msg > 150000000 || irq != last_irq) { - printk("handle_irq: irq %d count %d cc %u @ %p\n", - irq, count, cc-last_cc, regs->pc); - count = 0; - last_msg = cc; - last_irq = irq; - } - last_cc = cc; + irq_attempt(cpu, irq)++; + desc = irq_desc + irq; + spin_lock_irq(&irq_controller_lock); /* mask also the RTC */ + desc->handler->ack(irq); + + /* + * REPLAY is when Linux resends an IRQ that was dropped earlier. + * WAITING is used by probe to mark irqs that are being tested. + */ + status = desc->status & ~(IRQ_REPLAY | IRQ_WAITING); + status |= IRQ_PENDING; /* we _want_ to handle it */ + + /* + * If the IRQ is disabled for whatever reason, we cannot + * use the action we have. + */ + action = NULL; + if (!(status & (IRQ_DISABLED | IRQ_INPROGRESS))) { + action = desc->action; + status &= ~IRQ_PENDING; /* we commit to handling */ + status |= IRQ_INPROGRESS; /* we are handling it */ } -#endif + desc->status = status; + spin_unlock(&irq_controller_lock); - irq_enter(cpu, irq); - kstat.irqs[cpu][irq] += 1; - action = irq_desc[irq].action; + /* + * If there is no IRQ handler or it was disabled, exit early. + * Since we set PENDING, if another processor is handling + * a different instance of this same irq, the other processor + * will take care of it. + */ + if (!action) + return; /* - * For normal interrupts, we mask it out, and then ACK it. - * This way another (more timing-critical) interrupt can - * come through while we're doing this one. - * - * Note! An irq without a handler gets masked and acked, but - * never unmasked. The autoirq stuff depends on this (it looks - * at the masks before and after doing the probing). - */ - if (ack >= 0) { - mask_irq(ack); - alpha_mv.ack_irq(ack); - } - if (action) { - if (action->flags & SA_SAMPLE_RANDOM) - add_interrupt_randomness(irq); - do { - action->handler(irq, action->dev_id, regs); - action = action->next; - } while (action); - if (ack >= 0) - unmask_irq(ack); - } else { - unexpected_irq(irq, regs); + * Edge triggered interrupts need to remember pending events. + * This applies to any hw interrupts that allow a second + * instance of the same irq to arrive while we are in do_IRQ + * or in the handler. But the code here only handles the _second_ + * instance of the irq, not the third or fourth. So it is mostly + * useful for irq hardware that does not mask cleanly in an + * SMP environment. + */ + for (;;) { + handle_IRQ_event(irq, regs, action); + spin_lock(&irq_controller_lock); + + if (!(desc->status & IRQ_PENDING) + || (desc->status & IRQ_LEVEL)) + break; + desc->status &= ~IRQ_PENDING; + spin_unlock(&irq_controller_lock); } - irq_exit(cpu, irq); + desc->status &= ~IRQ_INPROGRESS; + if (!(desc->status & IRQ_DISABLED)) + desc->handler->end(irq); + spin_unlock(&irq_controller_lock); } - /* - * Start listening for interrupts.. + * IRQ autodetection code.. + * + * This depends on the fact that any interrupt that + * comes in on to an unassigned handler will get stuck + * with "IRQ_WAITING" cleared and the interrupt + * disabled. */ - unsigned long probe_irq_on(void) { - struct irqaction * action; - unsigned long irqs = 0; + int i; unsigned long delay; - unsigned int i; + unsigned long val; - /* Handle only the first 64 IRQs here. This is enough for - [E]ISA, which is the only thing that needs probing anyway. */ - for (i = (ACTUAL_NR_IRQS - 1) & 63; i > 0; i--) { - if (!(PROBE_MASK & (1UL << i))) { - continue; - } - action = irq_desc[i].action; - if (!action) { - enable_irq(i); - irqs |= (1UL << i); + /* Something may have generated an irq long ago and we want to + flush such a longstanding irq before considering it as spurious. */ + spin_lock_irq(&irq_controller_lock); + for (i = NR_IRQS-1; i >= 0; i--) + if (!irq_desc[i].action) + if(irq_desc[i].handler->startup(i)) + irq_desc[i].status |= IRQ_PENDING; + spin_unlock_irq(&irq_controller_lock); + + /* Wait for longstanding interrupts to trigger. */ + for (delay = jiffies + HZ/50; time_after(delay, jiffies); ) + /* about 20ms delay */ synchronize_irq(); + + /* enable any unassigned irqs (we must startup again here because + if a longstanding irq happened in the previous stage, it may have + masked itself) first, enable any unassigned irqs. */ + spin_lock_irq(&irq_controller_lock); + for (i = NR_IRQS-1; i >= 0; i--) { + if (!irq_desc[i].action) { + irq_desc[i].status |= IRQ_AUTODETECT | IRQ_WAITING; + if(irq_desc[i].handler->startup(i)) + irq_desc[i].status |= IRQ_PENDING; } } + spin_unlock_irq(&irq_controller_lock); /* - * Wait about 100ms for spurious interrupts to mask themselves - * out again... + * Wait for spurious interrupts to trigger */ - for (delay = jiffies + HZ/10; time_before(jiffies, delay); ) - barrier(); + for (delay = jiffies + HZ/10; time_after(delay, jiffies); ) + /* about 100ms delay */ synchronize_irq(); + + /* + * Now filter out any obviously spurious interrupts + */ + val = 0; + spin_lock_irq(&irq_controller_lock); + for (i=0; ishutdown(i); + continue; + } + + if (i < 64) + val |= 1 << i; + } + spin_unlock_irq(&irq_controller_lock); + + return val; +} + +/* + * Return a mask of triggered interrupts (this + * can handle only legacy ISA interrupts). + */ +unsigned int probe_irq_mask(unsigned long val) +{ + int i; + unsigned int mask; + + mask = 0; + spin_lock_irq(&irq_controller_lock); + for (i = 0; i < 16; i++) { + unsigned int status = irq_desc[i].status; + + if (!(status & IRQ_AUTODETECT)) + continue; - /* Now filter out any obviously spurious interrupts. */ - return irqs & ~alpha_irq_mask; + if (!(status & IRQ_WAITING)) + mask |= 1 << i; + + irq_desc[i].status = status & ~IRQ_AUTODETECT; + irq_desc[i].handler->shutdown(i); + } + spin_unlock_irq(&irq_controller_lock); + + return mask & val; } /* @@ -747,19 +1004,32 @@ */ int -probe_irq_off(unsigned long irqs) +probe_irq_off(unsigned long val) { - int i; - - /* Handle only the first 64 IRQs here. This is enough for - [E]ISA, which is the only thing that needs probing anyway. */ - irqs &= alpha_irq_mask; - if (!irqs) - return 0; - i = ffz(~irqs); - if (irqs != (1UL << i)) - i = -i; - return i; + int i, irq_found, nr_irqs; + + nr_irqs = 0; + irq_found = 0; + spin_lock_irq(&irq_controller_lock); + for (i=0; ishutdown(i); + } + spin_unlock_irq(&irq_controller_lock); + + if (nr_irqs > 1) + irq_found = -irq_found; + return irq_found; } @@ -774,15 +1044,21 @@ { switch (type) { case 0: -#ifdef __SMP__ +#ifdef CONFIG_SMP handle_ipi(®s); return; #else - printk("Interprocessor interrupt? You must be kidding\n"); + printk(KERN_CRIT "Interprocessor interrupt? " + "You must be kidding!\n"); #endif break; case 1: - handle_irq(RTC_IRQ, -1, ®s); +#ifdef CONFIG_SMP + cpu_data[smp_processor_id()].smp_local_irq_count++; + smp_percpu_timer_interrupt(®s); + if (smp_processor_id() == smp_boot_cpuid) +#endif + handle_irq(RTC_IRQ, ®s); return; case 2: alpha_mv.machine_check(vector, la_ptr, ®s); @@ -794,12 +1070,22 @@ perf_irq(vector, ®s); return; default: - printk("Hardware intr %ld %lx? Huh?\n", type, vector); + printk(KERN_CRIT "Hardware intr %ld %lx? Huh?\n", + type, vector); } printk("PC = %016lx PS=%04lx\n", regs.pc, regs.ps); } void __init +common_init_isa_dma(void) +{ + outb(0, DMA1_RESET_REG); + outb(0, DMA2_RESET_REG); + outb(0, DMA1_CLR_MASK_REG); + outb(0, DMA2_CLR_MASK_REG); +} + +void __init init_IRQ(void) { wrent(entInt, 0); @@ -817,7 +1103,7 @@ #define MCHK_K_OS_BUGCHECK 0x008A #define MCHK_K_PAL_BUGCHECK 0x0090 -#ifndef __SMP__ +#ifndef CONFIG_SMP struct mcheck_info __mcheck_info; #endif diff -u --recursive --new-file v2.3.46/linux/arch/alpha/kernel/irq_impl.h linux/arch/alpha/kernel/irq_impl.h --- v2.3.46/linux/arch/alpha/kernel/irq_impl.h Wed Dec 31 16:00:00 1969 +++ linux/arch/alpha/kernel/irq_impl.h Sun Feb 20 08:13:56 2000 @@ -0,0 +1,59 @@ +/* + * linux/arch/alpha/kernel/irq_impl.h + * + * Copyright (C) 1995 Linus Torvalds + * Copyright (C) 1998, 2000 Richard Henderson + * + * This file contains declarations and inline functions for interfacing + * with the IRQ handling routines in irq.c. + */ + +#include +#include + + +#define RTC_IRQ 8 + +extern void isa_device_interrupt(unsigned long, struct pt_regs *); +extern void isa_no_iack_sc_device_interrupt(unsigned long, struct pt_regs *); +extern void srm_device_interrupt(unsigned long, struct pt_regs *); +extern void pyxis_device_interrupt(unsigned long, struct pt_regs *); + +extern struct irqaction isa_cascade_irqaction; +extern struct irqaction timer_cascade_irqaction; +extern struct irqaction halt_switch_irqaction; + +extern void init_srm_irqs(long, unsigned long); +extern void init_pyxis_irqs(unsigned long); +extern void init_rtc_irq(void); + +extern void common_init_isa_dma(void); + +extern void i8259a_enable_irq(unsigned int); +extern void i8259a_disable_irq(unsigned int); +extern void i8259a_mask_and_ack_irq(unsigned int); +extern unsigned int i8259a_startup_irq(unsigned int); +extern struct hw_interrupt_type i8259a_irq_type; +extern void init_i8259a_irqs(void); + +extern void no_action(int cpl, void *dev_id, struct pt_regs *regs); +extern void handle_irq(int irq, struct pt_regs * regs); + +static inline void +alpha_do_profile(unsigned long pc) +{ + if (prof_buffer && current->pid) { + extern char _stext; + + pc -= (unsigned long) &_stext; + pc >>= prof_shift; + /* + * Don't ignore out-of-bounds PC values silently, + * put them into the last histogram slot, so if + * present, they will show up as a sharp peak. + */ + if (pc > prof_len - 1) + pc = prof_len - 1; + atomic_inc((atomic_t *)&prof_buffer[pc]); + } +} diff -u --recursive --new-file v2.3.46/linux/arch/alpha/kernel/pci.c linux/arch/alpha/kernel/pci.c --- v2.3.46/linux/arch/alpha/kernel/pci.c Thu Feb 10 17:11:02 2000 +++ linux/arch/alpha/kernel/pci.c Sun Feb 20 08:13:56 2000 @@ -109,7 +109,7 @@ void pcibios_align_resource(void *data, struct resource *res, unsigned long size) { - struct pci_dev * dev = data; + struct pci_dev *dev = data; unsigned long alignto; unsigned long start = res->start; @@ -325,10 +325,10 @@ ranges->mem_end -= bus->resource[1]->start; } -int __init +int pcibios_enable_device(struct pci_dev *dev) { - /* Not needed, since we enable all devices at startup. */ + /* Nothing to do, since we enable all devices at startup. */ return 0; } diff -u --recursive --new-file v2.3.46/linux/arch/alpha/kernel/pci_iommu.c linux/arch/alpha/kernel/pci_iommu.c --- v2.3.46/linux/arch/alpha/kernel/pci_iommu.c Wed Feb 16 17:03:51 2000 +++ linux/arch/alpha/kernel/pci_iommu.c Fri Feb 18 15:07:20 2000 @@ -121,10 +121,10 @@ /* Map a single buffer of the indicate size for PCI DMA in streaming mode. The 32-bit PCI bus mastering address to use is returned. Once the device is given the dma address, the device owns this memory - until either pci_unmap_single or pci_sync_single is performed. */ + until either pci_unmap_single or pci_dma_sync_single is performed. */ dma_addr_t -pci_map_single(struct pci_dev *pdev, void *cpu_addr, long size) +pci_map_single(struct pci_dev *pdev, void *cpu_addr, long size, int direction) { struct pci_controler *hose = pdev ? pdev->sysdata : pci_isa_hose; dma_addr_t max_dma = pdev ? pdev->dma_mask : 0x00ffffff; @@ -186,7 +186,7 @@ wrote there. */ void -pci_unmap_single(struct pci_dev *pdev, dma_addr_t dma_addr, long size) +pci_unmap_single(struct pci_dev *pdev, dma_addr_t dma_addr, long size, int direction) { struct pci_controler *hose = pdev ? pdev->sysdata : pci_isa_hose; struct pci_iommu_arena *arena; @@ -247,7 +247,7 @@ } memset(cpu_addr, 0, size); - *dma_addrp = pci_map_single(pdev, cpu_addr, size); + *dma_addrp = pci_map_single(pdev, cpu_addr, size, PCI_DMA_BIDIRECTIONAL); if (*dma_addrp == 0) { free_pages((unsigned long)cpu_addr, order); return NULL; @@ -270,7 +270,7 @@ pci_free_consistent(struct pci_dev *pdev, long size, void *cpu_addr, dma_addr_t dma_addr) { - pci_unmap_single(pdev, dma_addr, size); + pci_unmap_single(pdev, dma_addr, size, PCI_DMA_BIDIRECTIONAL); free_pages((unsigned long)cpu_addr, get_order(size)); DBGA2("pci_free_consistent: [%x,%lx] from %p\n", @@ -424,7 +424,7 @@ } int -pci_map_sg(struct pci_dev *pdev, struct scatterlist *sg, int nents) +pci_map_sg(struct pci_dev *pdev, struct scatterlist *sg, int nents, int direction) { struct scatterlist *start, *end, *out; struct pci_controler *hose; @@ -435,7 +435,7 @@ if (nents == 1) { sg->dma_length = sg->length; sg->dma_address - = pci_map_single(pdev, sg->address, sg->length); + = pci_map_single(pdev, sg->address, sg->length, direction); return sg->dma_address != 0; } @@ -472,6 +472,10 @@ out++; } + /* Mark the end of the list for pci_unmap_sg. */ + if (out < end) + out->dma_length = 0; + if (out - start == 0) printk(KERN_INFO "pci_map_sg failed: no entries?\n"); DBGA("pci_map_sg: %ld entries\n", out - start); @@ -485,7 +489,7 @@ /* Some allocation failed while mapping the scatterlist entries. Unmap them now. */ if (out > start) - pci_unmap_sg(pdev, start, out - start); + pci_unmap_sg(pdev, start, out - start, direction); return 0; } @@ -495,7 +499,7 @@ above. */ void -pci_unmap_sg(struct pci_dev *pdev, struct scatterlist *sg, int nents) +pci_unmap_sg(struct pci_dev *pdev, struct scatterlist *sg, int nents, int direction) { struct pci_controler *hose; struct pci_iommu_arena *arena; @@ -512,8 +516,6 @@ if (!arena || arena->dma_base + arena->size > max_dma) arena = hose->sg_isa; - DBGA("pci_unmap_sg: %d entries\n", nents); - fstart = -1; fend = 0; for (end = sg + nents; sg < end; ++sg) { @@ -522,6 +524,9 @@ addr = sg->dma_address; size = sg->dma_length; + if (!size) + break; + if (addr >= __direct_map_base && addr < __direct_map_base + __direct_map_size) { /* Nothing to do. */ @@ -531,6 +536,9 @@ long npages, ofs; dma_addr_t tend; + DBGA(" (%ld) sg [%lx,%lx]\n", + sg - end + nents, addr, size); + npages = calc_npages((addr & ~PAGE_MASK) + size); ofs = (addr - arena->dma_base) >> PAGE_SHIFT; iommu_arena_free(arena, ofs, npages); @@ -540,11 +548,10 @@ fstart = addr; if (fend < tend) fend = tend; - - DBGA(" (%ld) sg [%lx,%lx]\n", - sg - end + nents, addr, size); } } if (fend) alpha_mv.mv_pci_tbi(hose, fstart, fend); + + DBGA("pci_unmap_sg: %d entries\n", nents - (end - sg)); } diff -u --recursive --new-file v2.3.46/linux/arch/alpha/kernel/process.c linux/arch/alpha/kernel/process.c --- v2.3.46/linux/arch/alpha/kernel/process.c Tue Dec 7 09:32:39 1999 +++ linux/arch/alpha/kernel/process.c Sun Feb 20 08:13:56 2000 @@ -30,10 +30,6 @@ #include #include -#ifdef CONFIG_RTC -#include -#endif - #include #include #include @@ -138,11 +134,6 @@ take_over_console(&dummy_con, 0, MAX_NR_CONSOLES-1, 1); #endif } - -#ifdef CONFIG_RTC - /* Reset rtc to defaults. */ - rtc_kill_pit(); -#endif if (alpha_mv.kill_arch) alpha_mv.kill_arch(mode); diff -u --recursive --new-file v2.3.46/linux/arch/alpha/kernel/proto.h linux/arch/alpha/kernel/proto.h --- v2.3.46/linux/arch/alpha/kernel/proto.h Thu Feb 10 17:11:02 2000 +++ linux/arch/alpha/kernel/proto.h Sun Feb 20 08:13:56 2000 @@ -10,6 +10,7 @@ struct task_struct; struct pci_dev; struct pci_controler; +struct irqaction; /* core_apecs.c */ extern struct pci_ops apecs_pci_ops; @@ -46,6 +47,8 @@ /* core_polaris.c */ extern struct pci_ops polaris_pci_ops; +extern int polaris_read_config_dword(struct pci_dev *, int, u32 *); +extern int polaris_write_config_dword(struct pci_dev *, int, u32); extern void polaris_init_arch(void); extern void polaris_machine_check(u64, u64, struct pt_regs *); #define polaris_pci_tbi ((void *)0) @@ -84,9 +87,7 @@ /* time.c */ extern void timer_interrupt(int irq, void *dev, struct pt_regs * regs); -extern void rtc_init_pit(void); -extern void rtc_kill_pit(void); -extern void common_init_pit(void); +extern void common_init_rtc(struct irqaction *); extern unsigned long est_cycle_freq; /* smc37c93x.c */ @@ -101,7 +102,7 @@ /* ns87312.c */ extern void ns87312_enable_ide(long ide_base); -/* fpregs.c */ +/* ../lib/fpreg.c */ extern void alpha_write_fp_reg (unsigned long reg, unsigned long val); extern unsigned long alpha_read_fp_reg (unsigned long reg); @@ -134,7 +135,7 @@ /* ../mm/init.c */ void srm_paging_stop(void); -/* irq.h */ +/* irq.c */ #ifdef __SMP__ #define mcheck_expected(cpu) (cpu_data[cpu].mcheck_expected) diff -u --recursive --new-file v2.3.46/linux/arch/alpha/kernel/setup.c linux/arch/alpha/kernel/setup.c --- v2.3.46/linux/arch/alpha/kernel/setup.c Thu Feb 10 17:11:02 2000 +++ linux/arch/alpha/kernel/setup.c Sun Feb 20 08:13:56 2000 @@ -30,9 +30,6 @@ #include #include -#ifdef CONFIG_RTC -#include -#endif #ifdef CONFIG_BLK_DEV_INITRD #include #endif @@ -452,16 +449,6 @@ /* Reserve standard resources. */ reserve_std_resources(); - - /* Initialize the timers. */ - /* ??? There is some circumstantial evidence that this needs - to be done now rather than later in time_init, which would - be more natural. Someone please explain or refute. */ -#if defined(CONFIG_RTC) - rtc_init_pit(); -#else - alpha_mv.init_pit(); -#endif /* * Give us a default console. TGA users will see nothing until diff -u --recursive --new-file v2.3.46/linux/arch/alpha/kernel/smp.c linux/arch/alpha/kernel/smp.c --- v2.3.46/linux/arch/alpha/kernel/smp.c Thu Feb 10 17:11:02 2000 +++ linux/arch/alpha/kernel/smp.c Sun Feb 20 08:13:56 2000 @@ -33,6 +33,7 @@ #include #include "proto.h" +#include "irq_impl.h" #define DEBUG_SMP 0 @@ -62,6 +63,7 @@ static unsigned long smp_secondary_alive; unsigned long cpu_present_mask; /* Which cpus ids came online. */ +static unsigned long __cpu_present_mask __initdata = 0; /* cpu reported in the hwrpb */ static int max_cpus = -1; /* Command-line limitation. */ int smp_boot_cpuid; /* Which processor we booted from. */ @@ -506,7 +508,7 @@ if ((cpu->flags & 0x1cc) == 0x1cc) { smp_num_probed++; /* Assume here that "whami" == index */ - cpu_present_mask |= (1L << i); + __cpu_present_mask |= (1L << i); cpu->pal_revision = boot_cpu_palrev; } @@ -517,11 +519,12 @@ } } else { smp_num_probed = 1; - cpu_present_mask = (1L << smp_boot_cpuid); + __cpu_present_mask = (1L << smp_boot_cpuid); } + cpu_present_mask = 1L << smp_boot_cpuid; printk(KERN_INFO "SMP: %d CPUs probed -- cpu_present_mask = %lx\n", - smp_num_probed, cpu_present_mask); + smp_num_probed, __cpu_present_mask); } /* @@ -565,12 +568,13 @@ if (i == smp_boot_cpuid) continue; - if (((cpu_present_mask >> i) & 1) == 0) + if (((__cpu_present_mask >> i) & 1) == 0) continue; if (smp_boot_one_cpu(i, cpu_count)) continue; + cpu_present_mask |= 1L << i; cpu_count++; } @@ -623,7 +627,7 @@ /* We need to make like a normal interrupt -- otherwise timer interrupts ignore the global interrupt lock, which would be a Bad Thing. */ - irq_enter(cpu, TIMER_IRQ); + irq_enter(cpu, RTC_IRQ); update_one_process(current, 1, user, !user, cpu); if (current->pid) { @@ -647,7 +651,7 @@ } data->prof_counter = data->prof_multiplier; - irq_exit(cpu, TIMER_IRQ); + irq_exit(cpu, RTC_IRQ); } } @@ -865,6 +869,22 @@ } return 0; +} + +static void +ipi_imb(void *ignored) +{ + imb(); +} + +void +smp_imb(void) +{ + /* Must wait other processors to flush their icache before continue. */ + if (smp_call_function(ipi_imb, NULL, 1, 1)) + printk(KERN_CRIT "smp_imb: timed out\n"); + + imb(); } static void diff -u --recursive --new-file v2.3.46/linux/arch/alpha/kernel/sys_alcor.c linux/arch/alpha/kernel/sys_alcor.c --- v2.3.46/linux/arch/alpha/kernel/sys_alcor.c Tue Dec 7 09:32:39 1999 +++ linux/arch/alpha/kernel/sys_alcor.c Sun Feb 20 08:13:56 2000 @@ -27,50 +27,71 @@ #include #include "proto.h" -#include +#include "irq_impl.h" #include "pci_impl.h" #include "machvec_impl.h" -static void -alcor_update_irq_hw(unsigned long irq, unsigned long mask, int unmask_p) +/* Note mask bit is true for ENABLED irqs. */ +static unsigned long cached_irq_mask; + +static inline void +alcor_update_irq_hw(unsigned long mask) { - if (irq >= 16) { - /* On Alcor, at least, lines 20..30 are not connected and can - generate spurrious interrupts if we turn them on while IRQ - probing. So explicitly mask them out. */ - mask |= 0x7ff000000000UL; + *(vuip)GRU_INT_MASK = mask; + mb(); +} - /* Note inverted sense of mask bits: */ - *(vuip)GRU_INT_MASK = ~(mask >> 16); - mb(); - } - else if (irq >= 8) - outb(mask >> 8, 0xA1); /* ISA PIC2 */ - else - outb(mask, 0x21); /* ISA PIC1 */ +static inline void +alcor_enable_irq(unsigned int irq) +{ + alcor_update_irq_hw(cached_irq_mask |= 1UL << (irq - 16)); +} + +static inline void +alcor_disable_irq(unsigned int irq) +{ + alcor_update_irq_hw(cached_irq_mask &= ~(1UL << (irq - 16))); } static void -alcor_ack_irq(unsigned long irq) +alcor_mask_and_ack_irq(unsigned int irq) { - if (irq < 16) { - /* Ack the interrupt making it the lowest priority */ - /* First the slave .. */ - if (irq > 7) { - outb(0xE0 | (irq - 8), 0xa0); - irq = 2; - } - /* .. then the master */ - outb(0xE0 | irq, 0x20); + alcor_disable_irq(irq); - /* On ALCOR/XLT, need to dismiss interrupt via GRU. */ - *(vuip)GRU_INT_CLEAR = 0x80000000; mb(); - *(vuip)GRU_INT_CLEAR = 0x00000000; mb(); - } + /* On ALCOR/XLT, need to dismiss interrupt via GRU. */ + *(vuip)GRU_INT_CLEAR = 1 << (irq - 16); mb(); + *(vuip)GRU_INT_CLEAR = 0; mb(); +} + +static unsigned int +alcor_startup_irq(unsigned int irq) +{ + alcor_enable_irq(irq); + return 0; } static void +alcor_isa_mask_and_ack_irq(unsigned int irq) +{ + i8259a_mask_and_ack_irq(irq); + + /* On ALCOR/XLT, need to dismiss interrupt via GRU. */ + *(vuip)GRU_INT_CLEAR = 0x80000000; mb(); + *(vuip)GRU_INT_CLEAR = 0; mb(); +} + +static struct hw_interrupt_type alcor_irq_type = { + typename: "ALCOR", + startup: alcor_startup_irq, + shutdown: alcor_disable_irq, + enable: alcor_enable_irq, + disable: alcor_disable_irq, + ack: alcor_mask_and_ack_irq, + end: alcor_enable_irq, +}; + +static void alcor_device_interrupt(unsigned long vector, struct pt_regs *regs) { unsigned long pld; @@ -89,26 +110,40 @@ if (i == 31) { isa_device_interrupt(vector, regs); } else { - handle_irq(16 + i, 16 + i, regs); + handle_irq(16 + i, regs); } } } -static void +static void __init alcor_init_irq(void) { - STANDARD_INIT_IRQ_PROLOG; + long i; if (alpha_using_srm) alpha_mv.device_interrupt = srm_device_interrupt; - *(vuip)GRU_INT_MASK = ~(alpha_irq_mask >> 16); mb(); /* invert */ - *(vuip)GRU_INT_EDGE = 0U; mb(); /* all are level */ + *(vuip)GRU_INT_MASK = 0; mb(); /* all disabled */ + *(vuip)GRU_INT_EDGE = 0; mb(); /* all are level */ *(vuip)GRU_INT_HILO = 0x80000000U; mb(); /* ISA only HI */ - *(vuip)GRU_INT_CLEAR = 0UL; mb(); /* all clear */ + *(vuip)GRU_INT_CLEAR = 0; mb(); /* all clear */ + + for (i = 16; i < 48; ++i) { + /* On Alcor, at least, lines 20..30 are not connected + and can generate spurrious interrupts if we turn them + on while IRQ probing. */ + if (i >= 16+20 && i <= 16+30) + continue; + irq_desc[i].status = IRQ_DISABLED; + irq_desc[i].handler = &alcor_irq_type; + } + i8259a_irq_type.ack = alcor_isa_mask_and_ack_irq; + + init_i8259a_irqs(); + init_rtc_irq(); + common_init_isa_dma(); - enable_irq(16 + 31); /* enable (E)ISA PIC cascade */ - enable_irq(2); /* enable cascade */ + setup_irq(16+31, &isa_cascade_irqaction); } @@ -203,14 +238,11 @@ min_mem_address: CIA_DEFAULT_MEM_BASE, nr_irqs: 48, - irq_probe_mask: ALCOR_PROBE_MASK, - update_irq_hw: alcor_update_irq_hw, - ack_irq: alcor_ack_irq, device_interrupt: alcor_device_interrupt, init_arch: cia_init_arch, init_irq: alcor_init_irq, - init_pit: common_init_pit, + init_rtc: common_init_rtc, init_pci: common_init_pci, kill_arch: alcor_kill_arch, pci_map_irq: alcor_map_irq, @@ -236,14 +268,11 @@ min_mem_address: CIA_DEFAULT_MEM_BASE, nr_irqs: 48, - irq_probe_mask: ALCOR_PROBE_MASK, - update_irq_hw: alcor_update_irq_hw, - ack_irq: alcor_ack_irq, device_interrupt: alcor_device_interrupt, init_arch: cia_init_arch, init_irq: alcor_init_irq, - init_pit: common_init_pit, + init_rtc: common_init_rtc, init_pci: common_init_pci, kill_arch: alcor_kill_arch, pci_map_irq: alcor_map_irq, diff -u --recursive --new-file v2.3.46/linux/arch/alpha/kernel/sys_cabriolet.c linux/arch/alpha/kernel/sys_cabriolet.c --- v2.3.46/linux/arch/alpha/kernel/sys_cabriolet.c Tue Dec 7 09:32:39 1999 +++ linux/arch/alpha/kernel/sys_cabriolet.c Sun Feb 20 08:13:56 2000 @@ -31,42 +31,50 @@ #include #include "proto.h" -#include +#include "irq_impl.h" #include "pci_impl.h" #include "machvec_impl.h" -static void -cabriolet_update_irq_hw(unsigned long irq, unsigned long mask, int unmask_p) +/* Note mask bit is true for DISABLED irqs. */ +static unsigned long cached_irq_mask = ~0UL; + +static inline void +cabriolet_update_irq_hw(unsigned int irq, unsigned long mask) { - if (irq >= 16) - outl(alpha_irq_mask >> 16, 0x804); - else if (irq >= 8) - outb(mask >> 8, 0xA1); - else - outb(mask, 0x21); + int ofs = (irq - 16) / 8; + outb(mask >> (16 + ofs*3), 0x804 + ofs); } - -/* Under SRM console, we must use the CSERVE PALcode routine to manage - the interrupt mask for us. Otherwise, the kernel/HW get out of - sync with what the PALcode thinks it needs to deliver/ignore. */ +static inline void +cabriolet_enable_irq(unsigned int irq) +{ + cabriolet_update_irq_hw(irq, cached_irq_mask &= ~(1UL << irq)); +} static void -cabriolet_srm_update_irq_hw(unsigned long irq, unsigned long mask, int unmaskp) +cabriolet_disable_irq(unsigned int irq) { - if (irq >= 16) { - if (unmaskp) - cserve_ena(irq - 16); - else - cserve_dis(irq - 16); - } - else if (irq >= 8) - outb(mask >> 8, 0xA1); - else - outb(mask, 0x21); + cabriolet_update_irq_hw(irq, cached_irq_mask |= 1UL << irq); } +static unsigned int +cabriolet_startup_irq(unsigned int irq) +{ + cabriolet_enable_irq(irq); + return 0; /* never anything pending */ +} + +static struct hw_interrupt_type cabriolet_irq_type = { + typename: "CABRIOLET", + startup: cabriolet_startup_irq, + shutdown: cabriolet_disable_irq, + enable: cabriolet_enable_irq, + disable: cabriolet_disable_irq, + ack: cabriolet_disable_irq, + end: cabriolet_enable_irq, +}; + static void cabriolet_device_interrupt(unsigned long v, struct pt_regs *r) { @@ -86,26 +94,36 @@ if (i == 4) { isa_device_interrupt(v, r); } else { - handle_irq(16 + i, 16 + i, r); + handle_irq(16 + i, r); } } } -static void +static void __init cabriolet_init_irq(void) { - STANDARD_INIT_IRQ_PROLOG; + init_i8259a_irqs(); + init_rtc_irq(); if (alpha_using_srm) { - alpha_mv.update_irq_hw = cabriolet_srm_update_irq_hw; alpha_mv.device_interrupt = srm_device_interrupt; + init_srm_irqs(35, 0); } else { - outl(alpha_irq_mask >> 16, 0x804); + long i; + + outb(0xff, 0x804); + outb(0xff, 0x805); + outb(0xff, 0x806); + + for (i = 16; i < 35; ++i) { + irq_desc[i].status = IRQ_DISABLED; + irq_desc[i].handler = &cabriolet_irq_type; + } } - enable_irq(16 + 4); /* enable SIO cascade */ - enable_irq(2); /* enable cascade */ + common_init_isa_dma(); + setup_irq(16+4, &isa_cascade_irqaction); } @@ -260,14 +278,11 @@ min_mem_address: APECS_AND_LCA_DEFAULT_MEM_BASE, nr_irqs: 35, - irq_probe_mask: _PROBE_MASK(35), - update_irq_hw: cabriolet_update_irq_hw, - ack_irq: common_ack_irq, device_interrupt: cabriolet_device_interrupt, init_arch: apecs_init_arch, init_irq: cabriolet_init_irq, - init_pit: common_init_pit, + init_rtc: common_init_rtc, init_pci: cabriolet_init_pci, kill_arch: NULL, pci_map_irq: cabriolet_map_irq, @@ -289,14 +304,11 @@ min_mem_address: CIA_DEFAULT_MEM_BASE, nr_irqs: 35, - irq_probe_mask: _PROBE_MASK(35), - update_irq_hw: cabriolet_update_irq_hw, - ack_irq: common_ack_irq, device_interrupt: cabriolet_device_interrupt, init_arch: cia_init_arch, init_irq: cabriolet_init_irq, - init_pit: common_init_pit, + init_rtc: common_init_rtc, init_pci: cabriolet_init_pci, pci_map_irq: cabriolet_map_irq, pci_swizzle: common_swizzle, @@ -317,14 +329,11 @@ min_mem_address: APECS_AND_LCA_DEFAULT_MEM_BASE, nr_irqs: 35, - irq_probe_mask: _PROBE_MASK(35), - update_irq_hw: cabriolet_update_irq_hw, - ack_irq: common_ack_irq, device_interrupt: cabriolet_device_interrupt, init_arch: lca_init_arch, init_irq: cabriolet_init_irq, - init_pit: common_init_pit, + init_rtc: common_init_rtc, init_pci: cabriolet_init_pci, pci_map_irq: eb66p_map_irq, pci_swizzle: common_swizzle, @@ -345,14 +354,11 @@ min_mem_address: DEFAULT_MEM_BASE, nr_irqs: 35, - irq_probe_mask: _PROBE_MASK(35), - update_irq_hw: cabriolet_update_irq_hw, - ack_irq: common_ack_irq, device_interrupt: cabriolet_device_interrupt, init_arch: pyxis_init_arch, init_irq: cabriolet_init_irq, - init_pit: common_init_pit, + init_rtc: common_init_rtc, init_pci: alphapc164_init_pci, pci_map_irq: alphapc164_map_irq, pci_swizzle: common_swizzle, @@ -373,14 +379,11 @@ min_mem_address: CIA_DEFAULT_MEM_BASE, nr_irqs: 35, - irq_probe_mask: _PROBE_MASK(35), - update_irq_hw: cabriolet_update_irq_hw, - ack_irq: common_ack_irq, device_interrupt: cabriolet_device_interrupt, init_arch: cia_init_arch, init_irq: cabriolet_init_irq, - init_pit: common_init_pit, + init_rtc: common_init_rtc, init_pci: alphapc164_init_pci, pci_map_irq: alphapc164_map_irq, pci_swizzle: common_swizzle, diff -u --recursive --new-file v2.3.46/linux/arch/alpha/kernel/sys_dp264.c linux/arch/alpha/kernel/sys_dp264.c --- v2.3.46/linux/arch/alpha/kernel/sys_dp264.c Tue Dec 7 09:32:39 1999 +++ linux/arch/alpha/kernel/sys_dp264.c Sun Feb 20 08:13:56 2000 @@ -8,6 +8,7 @@ * Code supporting the DP264 (EV6+TSUNAMI). */ +#include #include #include #include @@ -27,72 +28,150 @@ #include #include "proto.h" -#include +#include "irq_impl.h" #include "pci_impl.h" #include "machvec_impl.h" -/* - * HACK ALERT! only the boot cpu is used for interrupts. - */ +static unsigned long cached_irq_mask; + + +#define TSUNAMI_SET_IRQ_MASK(cpu, value) \ +do { \ + volatile unsigned long *csr; \ + csr = &TSUNAMI_cchip->dim##cpu##.csr; \ + *csr = (value); \ + mb(); \ + *csr; \ +} while(0) + +static inline void +do_flush_irq_mask(unsigned long value) +{ + switch (TSUNAMI_bootcpu) { + case 0: + TSUNAMI_SET_IRQ_MASK(0, value); + break; + case 1: + TSUNAMI_SET_IRQ_MASK(1, value); + break; + case 2: + TSUNAMI_SET_IRQ_MASK(2, value); + break; + case 3: + TSUNAMI_SET_IRQ_MASK(3, value); + break; + } +} + +#ifdef CONFIG_SMP +static inline void +do_flush_smp_irq_mask(unsigned long value) +{ + extern unsigned long cpu_present_mask; + unsigned long other_cpus = cpu_present_mask & ~(1L << TSUNAMI_bootcpu); + + if (other_cpus & 1) + TSUNAMI_SET_IRQ_MASK(0, value); + if (other_cpus & 2) + TSUNAMI_SET_IRQ_MASK(1, value); + if (other_cpus & 4) + TSUNAMI_SET_IRQ_MASK(2, value); + if (other_cpus & 8) + TSUNAMI_SET_IRQ_MASK(3, value); +} +#endif static void -dp264_update_irq_hw(unsigned long irq, unsigned long mask, int unmask_p) +dp264_flush_irq_mask(unsigned long mask) { - volatile unsigned long *csr; + unsigned long value; - if (TSUNAMI_bootcpu < 2) { - if (!TSUNAMI_bootcpu) - csr = &TSUNAMI_cchip->dim0.csr; - else - csr = &TSUNAMI_cchip->dim1.csr; - } else { - if (TSUNAMI_bootcpu == 2) - csr = &TSUNAMI_cchip->dim2.csr; - else - csr = &TSUNAMI_cchip->dim3.csr; - } +#ifdef CONFIG_SMP + do_flush_smp_irq_mask(mask); +#endif - *csr = ~mask; - mb(); - *csr; - - if (irq < 16) { - if (irq >= 8) - outb(mask >> 8, 0xA1); /* ISA PIC2 */ - else - outb(mask, 0x21); /* ISA PIC1 */ - } + value = mask | (1UL << 55) | 0xffff; /* isa irqs always enabled */ + do_flush_irq_mask(value); } static void -clipper_update_irq_hw(unsigned long irq, unsigned long mask, int unmask_p) +clipper_flush_irq_mask(unsigned long mask) { - if (irq >= 16) { - volatile unsigned long *csr; + unsigned long value; - if (TSUNAMI_bootcpu < 2) - if (!TSUNAMI_bootcpu) - csr = &TSUNAMI_cchip->dim0.csr; - else - csr = &TSUNAMI_cchip->dim1.csr; - else - if (TSUNAMI_bootcpu == 2) - csr = &TSUNAMI_cchip->dim2.csr; - else - csr = &TSUNAMI_cchip->dim3.csr; - - *csr = (~mask >> 16) | (1UL << 55); /* master ISA enable */ - mb(); - *csr; - } - else if (irq >= 8) - outb(mask >> 8, 0xA1); /* ISA PIC2 */ - else - outb(mask, 0x21); /* ISA PIC1 */ + value = mask >> 16; +#ifdef CONFIG_SMP + do_flush_smp_irq_mask(value); +#endif + + value = value | (1UL << 55); /* master ISA enable */ + do_flush_irq_mask(value); +} + +static inline void +dp264_enable_irq(unsigned int irq) +{ + cached_irq_mask |= 1UL << irq; + dp264_flush_irq_mask(cached_irq_mask); } static void +dp264_disable_irq(unsigned int irq) +{ + cached_irq_mask &= ~(1UL << irq); + dp264_flush_irq_mask(cached_irq_mask); +} + +static unsigned int +dp264_startup_irq(unsigned int irq) +{ + dp264_enable_irq(irq); + return 0; /* never anything pending */ +} + +static inline void +clipper_enable_irq(unsigned int irq) +{ + cached_irq_mask |= 1UL << irq; + clipper_flush_irq_mask(cached_irq_mask); +} + +static void +clipper_disable_irq(unsigned int irq) +{ + cached_irq_mask &= ~(1UL << irq); + clipper_flush_irq_mask(cached_irq_mask); +} + +static unsigned int +clipper_startup_irq(unsigned int irq) +{ + clipper_enable_irq(irq); + return 0; /* never anything pending */ +} + +static struct hw_interrupt_type dp264_irq_type = { + typename: "DP264", + startup: dp264_startup_irq, + shutdown: dp264_disable_irq, + enable: dp264_enable_irq, + disable: dp264_disable_irq, + ack: dp264_disable_irq, + end: dp264_enable_irq, +}; + +static struct hw_interrupt_type clipper_irq_type = { + typename: "CLIPPER", + startup: clipper_startup_irq, + shutdown: clipper_disable_irq, + enable: clipper_enable_irq, + disable: clipper_disable_irq, + ack: clipper_disable_irq, + end: clipper_enable_irq, +}; + +static void dp264_device_interrupt(unsigned long vector, struct pt_regs * regs) { #if 1 @@ -126,9 +205,9 @@ static void dp264_srm_device_interrupt(unsigned long vector, struct pt_regs * regs) { - int irq, ack; + int irq; - ack = irq = (vector - 0x800) >> 4; + irq = (vector - 0x800) >> 4; /* * The SRM console reports PCI interrupts with a vector calculated by: @@ -142,17 +221,17 @@ * so we don't count them. */ if (irq >= 32) - ack = irq = irq - 16; + irq -= 16; - handle_irq(irq, ack, regs); + handle_irq(irq, regs); } static void clipper_srm_device_interrupt(unsigned long vector, struct pt_regs * regs) { - int irq, ack; + int irq; - ack = irq = (vector - 0x800) >> 4; + irq = (vector - 0x800) >> 4; /* * The SRM console reports PCI interrupts with a vector calculated by: @@ -166,7 +245,19 @@ * * Eg IRQ 24 is DRIR bit 8, etc, etc */ - handle_irq(irq, ack, regs); + handle_irq(irq, regs); +} + +static void __init +init_tsunami_irqs(struct hw_interrupt_type * ops) +{ + long i; + + /* Only irqs between 16 and 47 are tsunami irqs. */ + for (i = 16; i < 48; ++i) { + irq_desc[i].status = IRQ_DISABLED | IRQ_LEVEL; + irq_desc[i].handler = ops; + } } static void __init @@ -180,10 +271,11 @@ if (alpha_using_srm) alpha_mv.device_interrupt = dp264_srm_device_interrupt; - dp264_update_irq_hw(16, alpha_irq_mask, 0); + dp264_flush_irq_mask(0UL); - enable_irq(55); /* Enable ISA interrupt controller. */ - enable_irq(2); + init_i8259a_irqs(); + init_rtc_irq(); + init_tsunami_irqs(&dp264_irq_type); } static void __init @@ -197,10 +289,11 @@ if (alpha_using_srm) alpha_mv.device_interrupt = clipper_srm_device_interrupt; - clipper_update_irq_hw(16, alpha_irq_mask, 0); + clipper_flush_irq_mask(0UL); - enable_irq(55); /* Enable ISA interrupt controller. */ - enable_irq(2); + init_i8259a_irqs(); + init_rtc_irq(); + init_tsunami_irqs(&clipper_irq_type); } @@ -431,14 +524,11 @@ min_mem_address: DEFAULT_MEM_BASE, nr_irqs: 64, - irq_probe_mask: TSUNAMI_PROBE_MASK, - update_irq_hw: dp264_update_irq_hw, - ack_irq: common_ack_irq, device_interrupt: dp264_device_interrupt, init_arch: tsunami_init_arch, init_irq: dp264_init_irq, - init_pit: common_init_pit, + init_rtc: common_init_rtc, init_pci: dp264_init_pci, kill_arch: tsunami_kill_arch, pci_map_irq: dp264_map_irq, @@ -458,14 +548,11 @@ min_mem_address: DEFAULT_MEM_BASE, nr_irqs: 64, - irq_probe_mask: TSUNAMI_PROBE_MASK, - update_irq_hw: dp264_update_irq_hw, - ack_irq: common_ack_irq, device_interrupt: dp264_device_interrupt, init_arch: tsunami_init_arch, init_irq: dp264_init_irq, - init_pit: common_init_pit, + init_rtc: common_init_rtc, init_pci: monet_init_pci, kill_arch: tsunami_kill_arch, pci_map_irq: monet_map_irq, @@ -484,14 +571,11 @@ min_mem_address: DEFAULT_MEM_BASE, nr_irqs: 64, - irq_probe_mask: TSUNAMI_PROBE_MASK, - update_irq_hw: dp264_update_irq_hw, - ack_irq: common_ack_irq, device_interrupt: dp264_device_interrupt, init_arch: tsunami_init_arch, init_irq: dp264_init_irq, - init_pit: common_init_pit, + init_rtc: common_init_rtc, init_pci: common_init_pci, kill_arch: tsunami_kill_arch, pci_map_irq: webbrick_map_irq, @@ -510,14 +594,11 @@ min_mem_address: DEFAULT_MEM_BASE, nr_irqs: 64, - irq_probe_mask: TSUNAMI_PROBE_MASK, - update_irq_hw: clipper_update_irq_hw, - ack_irq: common_ack_irq, device_interrupt: dp264_device_interrupt, init_arch: tsunami_init_arch, init_irq: clipper_init_irq, - init_pit: common_init_pit, + init_rtc: common_init_rtc, init_pci: common_init_pci, kill_arch: tsunami_kill_arch, pci_map_irq: clipper_map_irq, diff -u --recursive --new-file v2.3.46/linux/arch/alpha/kernel/sys_eb64p.c linux/arch/alpha/kernel/sys_eb64p.c --- v2.3.46/linux/arch/alpha/kernel/sys_eb64p.c Tue Dec 7 09:32:39 1999 +++ linux/arch/alpha/kernel/sys_eb64p.c Sun Feb 20 08:13:56 2000 @@ -28,25 +28,49 @@ #include #include "proto.h" -#include +#include "irq_impl.h" #include "pci_impl.h" #include "machvec_impl.h" -static void -eb64p_update_irq_hw(unsigned long irq, unsigned long mask, int unmask_p) +/* Note mask bit is true for DISABLED irqs. */ +static unsigned int cached_irq_mask = -1; + +static inline void +eb64p_update_irq_hw(unsigned int irq, unsigned long mask) { - if (irq >= 16) - if (irq >= 24) - outb(mask >> 24, 0x27); - else - outb(mask >> 16, 0x26); - else if (irq >= 8) - outb(mask >> 8, 0xA1); - else - outb(mask, 0x21); + outb(mask >> (irq >= 24 ? 24 : 16), (irq >= 24 ? 0x27 : 0x26)); } +static inline void +eb64p_enable_irq(unsigned int irq) +{ + eb64p_update_irq_hw(irq, cached_irq_mask &= ~(1 << irq)); +} + +static inline void +eb64p_disable_irq(unsigned int irq) +{ + eb64p_update_irq_hw(irq, cached_irq_mask |= 1 << irq); +} + +static unsigned int +eb64p_startup_irq(unsigned int irq) +{ + eb64p_enable_irq(irq); + return 0; /* never anything pending */ +} + +static struct hw_interrupt_type eb64p_irq_type = { + typename: "EB64P", + startup: eb64p_startup_irq, + shutdown: eb64p_disable_irq, + enable: eb64p_enable_irq, + disable: eb64p_disable_irq, + ack: eb64p_disable_irq, + end: eb64p_enable_irq, +}; + static void eb64p_device_interrupt(unsigned long vector, struct pt_regs *regs) { @@ -55,6 +79,7 @@ /* Read the interrupt summary registers */ pld = inb(0x26) | (inb(0x27) << 8); + /* * Now, for every possible bit set, work through * them and call the appropriate interrupt handler. @@ -66,7 +91,7 @@ if (i == 5) { isa_device_interrupt(vector, regs); } else { - handle_irq(16 + i, 16 + i, regs); + handle_irq(16 + i, regs); } } } @@ -74,6 +99,8 @@ static void __init eb64p_init_irq(void) { + long i; + #ifdef CONFIG_ALPHA_GENERIC /* * CABRIO SRM may not set variation correctly, so here we test @@ -82,21 +109,25 @@ */ if (inw(0x806) != 0xffff) { extern struct alpha_machine_vector cabriolet_mv; -#if 1 - printk("eb64p_init_irq: resetting for CABRIO\n"); -#endif alpha_mv = cabriolet_mv; alpha_mv.init_irq(); return; } #endif /* GENERIC */ - STANDARD_INIT_IRQ_PROLOG; + outb(0xff, 0x26); + outb(0xff, 0x27); + + init_i8259a_irqs(); + init_rtc_irq(); + + for (i = 16; i < 32; ++i) { + irq_desc[i].status = IRQ_DISABLED; + irq_desc[i].handler = &eb64p_irq_type; + } - outb(alpha_irq_mask >> 16, 0x26); - outb(alpha_irq_mask >> 24, 0x27); - enable_irq(16 + 5); /* enable SIO cascade */ - enable_irq(2); /* enable cascade */ + common_init_isa_dma(); + setup_irq(16+5, &isa_cascade_irqaction); } /* @@ -112,7 +143,7 @@ * 3 Interrupt Line B from slot 1 * 4 Interrupt Line C from slot 0 * 5 Interrupt line from the two ISA PICs - * 6 Tulip (slot + * 6 Tulip * 7 NCR SCSI * * Summary @ 0x27 @@ -174,14 +205,11 @@ min_mem_address: APECS_AND_LCA_DEFAULT_MEM_BASE, nr_irqs: 32, - irq_probe_mask: _PROBE_MASK(32), - update_irq_hw: eb64p_update_irq_hw, - ack_irq: common_ack_irq, device_interrupt: eb64p_device_interrupt, init_arch: apecs_init_arch, init_irq: eb64p_init_irq, - init_pit: common_init_pit, + init_rtc: common_init_rtc, init_pci: common_init_pci, kill_arch: NULL, pci_map_irq: eb64p_map_irq, @@ -203,14 +231,11 @@ min_mem_address: APECS_AND_LCA_DEFAULT_MEM_BASE, nr_irqs: 32, - irq_probe_mask: _PROBE_MASK(32), - update_irq_hw: eb64p_update_irq_hw, - ack_irq: common_ack_irq, device_interrupt: eb64p_device_interrupt, init_arch: lca_init_arch, init_irq: eb64p_init_irq, - init_pit: common_init_pit, + init_rtc: common_init_rtc, init_pci: common_init_pci, pci_map_irq: eb64p_map_irq, pci_swizzle: common_swizzle, diff -u --recursive --new-file v2.3.46/linux/arch/alpha/kernel/sys_eiger.c linux/arch/alpha/kernel/sys_eiger.c --- v2.3.46/linux/arch/alpha/kernel/sys_eiger.c Tue Dec 7 09:32:39 1999 +++ linux/arch/alpha/kernel/sys_eiger.c Sun Feb 20 08:13:56 2000 @@ -29,7 +29,7 @@ #include #include "proto.h" -#include +#include "irq_impl.h" #include "pci_impl.h" #include "machvec_impl.h" @@ -38,29 +38,54 @@ * HACK ALERT! only the boot cpu is used for interrupts. */ -static void -eiger_update_irq_hw(unsigned long irq, unsigned long unused, int unmask_p) +/* Note that this interrupt code is identical to TAKARA. */ + +/* Note mask bit is true for DISABLED irqs. */ +static unsigned long cached_irq_mask[2] = { -1, -1 }; + +static inline void +eiger_update_irq_hw(unsigned long irq, unsigned long mask) { - unsigned int regaddr; - unsigned long mask; + int regaddr; - if (irq <= 15) { - if (irq <= 7) - outb(alpha_irq_mask, 0x21); /* ISA PIC1 */ - else - outb(alpha_irq_mask >> 8, 0xA1); /* ISA PIC2 */ - } else { - if (irq > 63) - mask = _alpha_irq_masks[1] << 16; - else - mask = _alpha_irq_masks[0] >> ((irq - 16) & 0x30); + mask = (irq >= 64 ? mask << 16 : mask >> ((irq - 16) & 0x30)); + regaddr = 0x510 + (((irq - 16) >> 2) & 0x0c); + outl(mask & 0xffff0000UL, regaddr); +} - regaddr = 0x510 + (((irq - 16) >> 2) & 0x0c); +static inline void +eiger_enable_irq(unsigned int irq) +{ + unsigned long mask; + mask = (cached_irq_mask[irq >= 64] &= ~(1UL << (irq & 63))); + eiger_update_irq_hw(irq, mask); +} - outl(mask & 0xffff0000UL, regaddr); - } +static void +eiger_disable_irq(unsigned int irq) +{ + unsigned long mask; + mask = (cached_irq_mask[irq >= 64] |= 1UL << (irq & 63)); + eiger_update_irq_hw(irq, mask); } +static unsigned int +eiger_startup_irq(unsigned int irq) +{ + eiger_enable_irq(irq); + return 0; /* never anything pending */ +} + +static struct hw_interrupt_type eiger_irq_type = { + typename: "EIGER", + startup: eiger_startup_irq, + shutdown: eiger_disable_irq, + enable: eiger_enable_irq, + disable: eiger_disable_irq, + ack: eiger_disable_irq, + end: eiger_enable_irq, +}; + static void eiger_device_interrupt(unsigned long vector, struct pt_regs * regs) { @@ -89,25 +114,27 @@ * despatch an interrupt if it's set. */ - if (intstatus & 8) handle_irq(16+3, 16+3, regs); - if (intstatus & 4) handle_irq(16+2, 16+2, regs); - if (intstatus & 2) handle_irq(16+1, 16+1, regs); - if (intstatus & 1) handle_irq(16+0, 16+0, regs); + if (intstatus & 8) handle_irq(16+3, regs); + if (intstatus & 4) handle_irq(16+2, regs); + if (intstatus & 2) handle_irq(16+1, regs); + if (intstatus & 1) handle_irq(16+0, regs); } else { - isa_device_interrupt (vector, regs); + isa_device_interrupt(vector, regs); } } static void eiger_srm_device_interrupt(unsigned long vector, struct pt_regs * regs) { - int irq = (vector - 0x800) >> 4; - handle_irq(irq, irq, regs); + int irq = (vector - 0x800) >> 4; + handle_irq(irq, regs); } static void __init eiger_init_irq(void) { + long i; + outb(0, DMA1_RESET_REG); outb(0, DMA2_RESET_REG); outb(DMA_MODE_CASCADE, DMA2_MODE_REG); @@ -116,9 +143,16 @@ if (alpha_using_srm) alpha_mv.device_interrupt = eiger_srm_device_interrupt; - eiger_update_irq_hw(16, alpha_irq_mask, 0); + for (i = 16; i < 128; i += 16) + eiger_update_irq_hw(i, -1); - enable_irq(2); + init_i8259a_irqs(); + init_rtc_irq(); + + for (i = 16; i < 128; ++i) { + irq_desc[i].status = IRQ_DISABLED; + irq_desc[i].handler = &eiger_irq_type; + } } static int __init @@ -199,14 +233,11 @@ min_mem_address: DEFAULT_MEM_BASE, nr_irqs: 128, - irq_probe_mask: TSUNAMI_PROBE_MASK, - update_irq_hw: eiger_update_irq_hw, - ack_irq: common_ack_irq, device_interrupt: eiger_device_interrupt, init_arch: tsunami_init_arch, init_irq: eiger_init_irq, - init_pit: common_init_pit, + init_rtc: common_init_rtc, init_pci: common_init_pci, kill_arch: tsunami_kill_arch, pci_map_irq: eiger_map_irq, diff -u --recursive --new-file v2.3.46/linux/arch/alpha/kernel/sys_jensen.c linux/arch/alpha/kernel/sys_jensen.c --- v2.3.46/linux/arch/alpha/kernel/sys_jensen.c Thu Feb 10 17:11:02 2000 +++ linux/arch/alpha/kernel/sys_jensen.c Sun Feb 20 08:13:56 2000 @@ -28,19 +28,10 @@ #include #include "proto.h" -#include +#include "irq_impl.h" #include "machvec_impl.h" -static void -jensen_update_irq_hw(unsigned long irq, unsigned long mask, int unmask_p) -{ - if (irq >= 8) - outb(mask >> 8, 0xA1); - else - outb(mask, 0x21); -} - /* * Jensen is special: the vector is 0x8X0 for EISA interrupt X, and * 0x9X0 for the local motherboard interrupts.. @@ -66,51 +57,71 @@ */ static void -handle_nmi(struct pt_regs * regs) +jensen_local_ack(unsigned int irq) { - printk("Whee.. NMI received. Probable hardware error\n"); - printk("61=%02x, 461=%02x\n", inb(0x61), inb(0x461)); -} + /* irq1 is supposed to be the keyboard, silly Jensen. */ + if (irq == 7) + i8259a_mask_and_ack_irq(1); +} + +static struct hw_interrupt_type jensen_local_irq_type = { + typename: "LOCAL", + startup: i8259a_startup_irq, + shutdown: i8259a_disable_irq, + enable: i8259a_enable_irq, + disable: i8259a_disable_irq, + ack: jensen_local_ack, + end: i8259a_enable_irq, +}; static void jensen_device_interrupt(unsigned long vector, struct pt_regs * regs) { - int irq, ack; - - ack = irq = (vector - 0x800) >> 4; + int irq; switch (vector) { - case 0x660: handle_nmi(regs); return; + case 0x660: + printk("Whee.. NMI received. Probable hardware error\n"); + printk("61=%02x, 461=%02x\n", inb(0x61), inb(0x461)); + return; /* local device interrupts: */ - case 0x900: irq = 4, ack = -1; break; /* com1 -> irq 4 */ - case 0x920: irq = 3, ack = -1; break; /* com2 -> irq 3 */ - case 0x980: irq = 1, ack = -1; break; /* kbd -> irq 1 */ - case 0x990: irq = 9, ack = -1; break; /* mouse -> irq 9 */ + case 0x900: irq = 4; break; /* com1 -> irq 4 */ + case 0x920: irq = 3; break; /* com2 -> irq 3 */ + case 0x980: irq = 1; break; /* kbd -> irq 1 */ + case 0x990: irq = 9; break; /* mouse -> irq 9 */ + default: if (vector > 0x900) { printk("Unknown local interrupt %lx\n", vector); + return; } - /* irq1 is supposed to be the keyboard, silly Jensen - (is this really needed??) */ + irq = (vector - 0x800) >> 4; if (irq == 1) irq = 7; break; } - handle_irq(irq, ack, regs); + handle_irq(irq, regs); } -static void +static void __init jensen_init_irq(void) { - STANDARD_INIT_IRQ_PROLOG; + init_i8259a_irqs(); + init_rtc_irq(); - enable_irq(2); /* enable cascade */ + irq_desc[1].handler = &jensen_local_irq_type; + irq_desc[4].handler = &jensen_local_irq_type; + irq_desc[3].handler = &jensen_local_irq_type; + irq_desc[7].handler = &jensen_local_irq_type; + irq_desc[9].handler = &jensen_local_irq_type; + + common_init_isa_dma(); } -static void +static void __init jensen_init_arch(void) { __direct_map_base = 0; @@ -140,14 +151,11 @@ rtc_port: 0x170, nr_irqs: 16, - irq_probe_mask: _PROBE_MASK(16), - update_irq_hw: jensen_update_irq_hw, - ack_irq: common_ack_irq, device_interrupt: jensen_device_interrupt, init_arch: jensen_init_arch, init_irq: jensen_init_irq, - init_pit: common_init_pit, + init_rtc: common_init_rtc, init_pci: NULL, kill_arch: NULL, }; diff -u --recursive --new-file v2.3.46/linux/arch/alpha/kernel/sys_miata.c linux/arch/alpha/kernel/sys_miata.c --- v2.3.46/linux/arch/alpha/kernel/sys_miata.c Tue Dec 7 09:32:40 1999 +++ linux/arch/alpha/kernel/sys_miata.c Sun Feb 20 08:13:56 2000 @@ -25,71 +25,17 @@ #include #include "proto.h" -#include +#include "irq_impl.h" #include "pci_impl.h" #include "machvec_impl.h" static void -miata_update_irq_hw(unsigned long irq, unsigned long mask, int unmask_p) -{ - if (irq >= 16) { - /* Make CERTAIN none of the bogus ints get enabled... */ - *(vulp)PYXIS_INT_MASK = - ~((long)mask >> 16) & ~0x400000000000063bUL; - mb(); - /* ... and read it back to make sure it got written. */ - *(vulp)PYXIS_INT_MASK; - } - else if (irq >= 8) - outb(mask >> 8, 0xA1); /* ISA PIC2 */ - else - outb(mask, 0x21); /* ISA PIC1 */ -} - -static void -miata_device_interrupt(unsigned long vector, struct pt_regs *regs) -{ - unsigned long pld, tmp; - unsigned int i; - - /* Read the interrupt summary register of PYXIS */ - pld = *(vulp)PYXIS_INT_REQ; - - /* - * For now, AND off any bits we are not interested in: - * HALT (2), timer (6), ISA Bridge (7), 21142/3 (8) - * then all the PCI slots/INTXs (12-31). - */ - /* Maybe HALT should only be used for SRM console boots? */ - pld &= 0x00000000fffff9c4UL; - - /* - * Now for every possible bit set, work through them and call - * the appropriate interrupt handler. - */ - while (pld) { - i = ffz(~pld); - pld &= pld - 1; /* clear least bit set */ - if (i == 7) { - isa_device_interrupt(vector, regs); - } else if (i == 6) { - continue; - } else { - /* if not timer int */ - handle_irq(16 + i, 16 + i, regs); - } - *(vulp)PYXIS_INT_REQ = 1UL << i; mb(); - tmp = *(vulp)PYXIS_INT_REQ; - } -} - -static void miata_srm_device_interrupt(unsigned long vector, struct pt_regs * regs) { - int irq, ack; + int irq; - ack = irq = (vector - 0x800) >> 4; + irq = (vector - 0x800) >> 4; /* * I really hate to do this, but the MIATA SRM console ignores the @@ -106,34 +52,36 @@ * So, here's this grotty hack... :-( */ if (irq >= 16) - ack = irq = irq + 8; + irq = irq + 8; - handle_irq(irq, ack, regs); + handle_irq(irq, regs); } static void __init miata_init_irq(void) { - STANDARD_INIT_IRQ_PROLOG; - if (alpha_using_srm) alpha_mv.device_interrupt = miata_srm_device_interrupt; - /* Note invert on MASK bits. */ - *(vulp)PYXIS_INT_MASK = - ~((long)alpha_irq_mask >> 16) & ~0x400000000000063bUL; mb(); #if 0 /* These break on MiataGL so we'll try not to do it at all. */ *(vulp)PYXIS_INT_HILO = 0x000000B2UL; mb(); /* ISA/NMI HI */ *(vulp)PYXIS_RT_COUNT = 0UL; mb(); /* clear count */ #endif - /* Clear upper timer. */ - *(vulp)PYXIS_INT_REQ = 0x4000000000000180UL; mb(); - enable_irq(16 + 2); /* enable HALT switch - SRM only? */ - enable_irq(16 + 6); /* enable timer */ - enable_irq(16 + 7); /* enable ISA PIC cascade */ - enable_irq(2); /* enable cascade */ + init_i8259a_irqs(); + init_rtc_irq(); + + /* Not interested in the bogus interrupts (3,10), Fan Fault (0), + NMI (1), or EIDE (9). + + We also disable the risers (4,5), since we don't know how to + route the interrupts behind the bridge. */ + init_pyxis_irqs(0x63b0000); + + common_init_isa_dma(); + setup_irq(16+2, &halt_switch_irqaction); /* SRM only? */ + setup_irq(16+6, &timer_cascade_irqaction); } @@ -300,14 +248,11 @@ min_mem_address: DEFAULT_MEM_BASE, nr_irqs: 48, - irq_probe_mask: _PROBE_MASK(48), - update_irq_hw: miata_update_irq_hw, - ack_irq: common_ack_irq, - device_interrupt: miata_device_interrupt, + device_interrupt: pyxis_device_interrupt, init_arch: pyxis_init_arch, init_irq: miata_init_irq, - init_pit: common_init_pit, + init_rtc: common_init_rtc, init_pci: miata_init_pci, kill_arch: miata_kill_arch, pci_map_irq: miata_map_irq, diff -u --recursive --new-file v2.3.46/linux/arch/alpha/kernel/sys_mikasa.c linux/arch/alpha/kernel/sys_mikasa.c --- v2.3.46/linux/arch/alpha/kernel/sys_mikasa.c Tue Dec 7 09:32:40 1999 +++ linux/arch/alpha/kernel/sys_mikasa.c Sun Feb 20 08:13:56 2000 @@ -28,21 +28,49 @@ #include #include "proto.h" -#include +#include "irq_impl.h" #include "pci_impl.h" #include "machvec_impl.h" -static void -mikasa_update_irq_hw(unsigned long irq, unsigned long mask, int unmask_p) + +/* Note mask bit is true for ENABLED irqs. */ +static int cached_irq_mask; + +static inline void +mikasa_update_irq_hw(int mask) +{ + outw(mask, 0x536); +} + +static inline void +mikasa_enable_irq(unsigned int irq) +{ + mikasa_update_irq_hw(cached_irq_mask |= 1 << (irq - 16)); +} + +static inline void +mikasa_disable_irq(unsigned int irq) { - if (irq >= 16) - outw(~(mask >> 16), 0x536); /* note invert */ - else if (irq >= 8) - outb(mask >> 8, 0xA1); - else - outb(mask, 0x21); + mikasa_update_irq_hw(cached_irq_mask &= ~(1 << (irq - 16))); } +static unsigned int +mikasa_startup_irq(unsigned int irq) +{ + mikasa_enable_irq(irq); + return 0; +} + +static struct hw_interrupt_type mikasa_irq_type = { + typename: "MIKASA", + startup: mikasa_startup_irq, + shutdown: mikasa_disable_irq, + enable: mikasa_enable_irq, + disable: mikasa_disable_irq, + ack: mikasa_disable_irq, + end: mikasa_enable_irq, +}; + static void mikasa_device_interrupt(unsigned long vector, struct pt_regs *regs) { @@ -50,9 +78,9 @@ unsigned int i; /* Read the interrupt summary registers */ - pld = (((unsigned long) (~inw(0x534)) & 0x0000ffffUL) << 16) | - (((unsigned long) inb(0xa0)) << 8) | - ((unsigned long) inb(0x20)); + pld = (((~inw(0x534) & 0x0000ffffUL) << 16) + | (((unsigned long) inb(0xa0)) << 8) + | inb(0x20)); /* * Now for every possible bit set, work through them and call @@ -64,7 +92,7 @@ if (i < 16) { isa_device_interrupt(vector, regs); } else { - handle_irq(i, i, regs); + handle_irq(i, regs); } } } @@ -72,13 +100,21 @@ static void __init mikasa_init_irq(void) { - STANDARD_INIT_IRQ_PROLOG; + long i; if (alpha_using_srm) alpha_mv.device_interrupt = srm_device_interrupt; - outw(~(alpha_irq_mask >> 16), 0x536); /* note invert */ - enable_irq(2); /* enable cascade */ + mikasa_update_irq_hw(0); + + for (i = 16; i < 32; ++i) { + irq_desc[i].status = IRQ_DISABLED; + irq_desc[i].handler = &mikasa_irq_type; + } + + init_i8259a_irqs(); + init_rtc_irq(); + common_init_isa_dma(); } @@ -185,14 +221,11 @@ min_mem_address: APECS_AND_LCA_DEFAULT_MEM_BASE, nr_irqs: 32, - irq_probe_mask: _PROBE_MASK(32), - update_irq_hw: mikasa_update_irq_hw, - ack_irq: common_ack_irq, device_interrupt: mikasa_device_interrupt, init_arch: apecs_init_arch, init_irq: mikasa_init_irq, - init_pit: common_init_pit, + init_rtc: common_init_rtc, init_pci: common_init_pci, kill_arch: NULL, pci_map_irq: mikasa_map_irq, @@ -214,14 +247,11 @@ min_mem_address: CIA_DEFAULT_MEM_BASE, nr_irqs: 32, - irq_probe_mask: _PROBE_MASK(32), - update_irq_hw: mikasa_update_irq_hw, - ack_irq: common_ack_irq, device_interrupt: mikasa_device_interrupt, init_arch: cia_init_arch, init_irq: mikasa_init_irq, - init_pit: common_init_pit, + init_rtc: common_init_rtc, init_pci: common_init_pci, pci_map_irq: mikasa_map_irq, pci_swizzle: common_swizzle, diff -u --recursive --new-file v2.3.46/linux/arch/alpha/kernel/sys_nautilus.c linux/arch/alpha/kernel/sys_nautilus.c --- v2.3.46/linux/arch/alpha/kernel/sys_nautilus.c Wed Dec 15 10:43:16 1999 +++ linux/arch/alpha/kernel/sys_nautilus.c Sun Feb 20 08:13:56 2000 @@ -45,34 +45,17 @@ #include #include "proto.h" -#include +#include "irq_impl.h" #include "pci_impl.h" #include "machvec_impl.h" -#define dev2hose(d) (bus2hose[(d)->bus->number]->pci_hose_index) - -static void -nautilus_update_irq_hw(unsigned long irq, unsigned long mask, int unmask_p) -{ - /* The timer is connected to PIC interrupt line also on Nautilus. - The timer interrupt handler enables the PIC line, so in order - not to get multiple timer interrupt sources, we mask it out - at all times. */ - - mask |= 0x100; - if (irq >= 8) - outb(mask >> 8, 0xA1); - else - outb(mask, 0x21); -} static void __init nautilus_init_irq(void) { - STANDARD_INIT_IRQ_PROLOG; - - enable_irq(2); /* enable cascade */ - disable_irq(8); + init_i8259a_irqs(); + init_rtc_irq(); + common_init_isa_dma(); } static int __init @@ -534,14 +517,11 @@ min_mem_address: DEFAULT_MEM_BASE, nr_irqs: 16, - irq_probe_mask: (_PROBE_MASK(16) & ~0x101UL), - update_irq_hw: nautilus_update_irq_hw, - ack_irq: common_ack_irq, device_interrupt: isa_device_interrupt, init_arch: irongate_init_arch, init_irq: nautilus_init_irq, - init_pit: common_init_pit, + init_rtc: common_init_rtc, init_pci: common_init_pci, kill_arch: nautilus_kill_arch, pci_map_irq: nautilus_map_irq, diff -u --recursive --new-file v2.3.46/linux/arch/alpha/kernel/sys_noritake.c linux/arch/alpha/kernel/sys_noritake.c --- v2.3.46/linux/arch/alpha/kernel/sys_noritake.c Tue Dec 7 09:32:40 1999 +++ linux/arch/alpha/kernel/sys_noritake.c Sun Feb 20 08:13:56 2000 @@ -29,25 +29,51 @@ #include #include "proto.h" -#include +#include "irq_impl.h" #include "pci_impl.h" #include "machvec_impl.h" +/* Note mask bit is true for ENABLED irqs. */ +static int cached_irq_mask; -static void -noritake_update_irq_hw(unsigned long irq, unsigned long mask, int unmask_p) +static inline void +noritake_update_irq_hw(int irq, int mask) { - if (irq <= 15) - if (irq <= 7) - outb(mask, 0x21); /* ISA PIC1 */ - else - outb(mask >> 8, 0xA1); /* ISA PIC2 */ - else if (irq <= 31) - outw(~(mask >> 16), 0x54a); - else - outw(~(mask >> 32), 0x54c); + int port = 0x54a; + if (irq >= 16) mask >>= 16; + if (irq >= 16) port = 0x54c; + outw(mask, port); +} + +static inline void +noritake_enable_irq(unsigned int irq) +{ + noritake_update_irq_hw(irq, cached_irq_mask |= 1 << (irq - 16)); +} + +static inline void +noritake_disable_irq(unsigned int irq) +{ + noritake_update_irq_hw(irq, cached_irq_mask &= ~(1 << (irq - 16))); } +static unsigned int +noritake_startup_irq(unsigned int irq) +{ + noritake_enable_irq(irq); + return 0; +} + +static struct hw_interrupt_type noritake_irq_type = { + typename: "NORITAKE", + startup: noritake_startup_irq, + shutdown: noritake_disable_irq, + enable: noritake_enable_irq, + disable: noritake_disable_irq, + ack: noritake_disable_irq, + end: noritake_enable_irq, +}; + static void noritake_device_interrupt(unsigned long vector, struct pt_regs *regs) { @@ -55,10 +81,10 @@ unsigned int i; /* Read the interrupt summary registers of NORITAKE */ - pld = ((unsigned long) inw(0x54c) << 32) | - ((unsigned long) inw(0x54a) << 16) | - ((unsigned long) inb(0xa0) << 8) | - ((unsigned long) inb(0x20)); + pld = (((unsigned long) inw(0x54c) << 32) + | ((unsigned long) inw(0x54a) << 16) + | ((unsigned long) inb(0xa0) << 8) + | inb(0x20)); /* * Now for every possible bit set, work through them and call @@ -70,7 +96,7 @@ if (i < 16) { isa_device_interrupt(vector, regs); } else { - handle_irq(i, i, regs); + handle_irq(i, regs); } } } @@ -78,36 +104,44 @@ static void noritake_srm_device_interrupt(unsigned long vector, struct pt_regs * regs) { - int irq, ack; + int irq; - ack = irq = (vector - 0x800) >> 4; + irq = (vector - 0x800) >> 4; /* * I really hate to do this, too, but the NORITAKE SRM console also - * reports PCI vectors *lower* than I expected from the bit numbers - * in the documentation. + * reports PCI vectors *lower* than I expected from the bit numbers + * in the documentation. * But I really don't want to change the fixup code for allocation - * of IRQs, nor the alpha_irq_mask maintenance stuff, both of which - * look nice and clean now. + * of IRQs, nor the alpha_irq_mask maintenance stuff, both of which + * look nice and clean now. * So, here's this additional grotty hack... :-( */ if (irq >= 16) - ack = irq = irq + 1; + irq = irq + 1; - handle_irq(irq, ack, regs); + handle_irq(irq, regs); } static void __init noritake_init_irq(void) { - STANDARD_INIT_IRQ_PROLOG; + long i; if (alpha_using_srm) alpha_mv.device_interrupt = noritake_srm_device_interrupt; - outw(~(alpha_irq_mask >> 16), 0x54a); /* note invert */ - outw(~(alpha_irq_mask >> 32), 0x54c); /* note invert */ - enable_irq(2); /* enable cascade */ + outw(0, 0x54a); + outw(0, 0x54c); + + for (i = 16; i < 48; ++i) { + irq_desc[i].status = IRQ_DISABLED; + irq_desc[i].handler = &noritake_irq_type; + } + + init_i8259a_irqs(); + init_rtc_irq(); + common_init_isa_dma(); } @@ -245,14 +279,11 @@ min_mem_address: APECS_AND_LCA_DEFAULT_MEM_BASE, nr_irqs: 48, - irq_probe_mask: _PROBE_MASK(48), - update_irq_hw: noritake_update_irq_hw, - ack_irq: common_ack_irq, device_interrupt: noritake_device_interrupt, init_arch: apecs_init_arch, init_irq: noritake_init_irq, - init_pit: common_init_pit, + init_rtc: common_init_rtc, init_pci: common_init_pci, kill_arch: NULL, pci_map_irq: noritake_map_irq, @@ -274,14 +305,11 @@ min_mem_address: CIA_DEFAULT_MEM_BASE, nr_irqs: 48, - irq_probe_mask: _PROBE_MASK(48), - update_irq_hw: noritake_update_irq_hw, - ack_irq: common_ack_irq, device_interrupt: noritake_device_interrupt, init_arch: cia_init_arch, init_irq: noritake_init_irq, - init_pit: common_init_pit, + init_rtc: common_init_rtc, init_pci: common_init_pci, pci_map_irq: noritake_map_irq, pci_swizzle: noritake_swizzle, diff -u --recursive --new-file v2.3.46/linux/arch/alpha/kernel/sys_rawhide.c linux/arch/alpha/kernel/sys_rawhide.c --- v2.3.46/linux/arch/alpha/kernel/sys_rawhide.c Tue Dec 7 09:32:40 1999 +++ linux/arch/alpha/kernel/sys_rawhide.c Sun Feb 20 08:13:56 2000 @@ -25,53 +25,77 @@ #include #include "proto.h" -#include +#include "irq_impl.h" #include "pci_impl.h" #include "machvec_impl.h" + +/* + * HACK ALERT! only the boot cpu is used for interrupts. + */ + + +/* Note mask bit is true for ENABLED irqs. */ + static unsigned int hose_irq_masks[4] = { 0xff0000, 0xfe0000, 0xff0000, 0xff0000 }; +static unsigned int cached_irq_masks[4]; +static inline void +rawhide_update_irq_hw(int hose, int mask) +{ + *(vuip)MCPCIA_INT_MASK0(MCPCIA_HOSE2MID(hose)) = mask; + mb(); + *(vuip)MCPCIA_INT_MASK0(MCPCIA_HOSE2MID(hose)); +} -/* Note that `mask' initially contains only the low 64 bits. */ - -static void -rawhide_update_irq_hw(unsigned long irq, unsigned long mask, int unmask_p) +static void +rawhide_enable_irq(unsigned int irq) { - unsigned int saddle, hose, new_irq; + unsigned int mask, hose; - if (irq < 16) { - if (irq < 8) - outb(mask, 0x21); /* ISA PIC1 */ - else - outb(mask >> 8, 0xA1); /* ISA PIC2 */ - return; - } + irq -= 16; + hose = irq / 24; + irq -= hose * 24; + + mask = cached_irq_masks[hose] |= 1 << irq; + mask |= hose_irq_masks[hose]; + rawhide_update_irq_hw(hose, mask); +} - saddle = (irq > 63); - mask = _alpha_irq_masks[saddle]; +static void +rawhide_disable_irq(unsigned int irq) +{ + unsigned int mask, hose; - if (saddle == 0) { - /* Saddle 0 includes EISA interrupts. */ - mask >>= 16; - new_irq = irq - 16; - } else { - new_irq = irq - 64; - } + irq -= 16; + hose = irq / 24; + irq -= hose * 24; + + mask = cached_irq_masks[hose] &= ~(1 << irq); + mask |= hose_irq_masks[hose]; + rawhide_update_irq_hw(hose, mask); +} - hose = saddle << 1; - if (new_irq >= 24) { - mask >>= 24; - hose += 1; - } - *(vuip)MCPCIA_INT_MASK0(hose) = - (~mask & 0x00ffffff) | hose_irq_masks[hose]; - mb(); - *(vuip)MCPCIA_INT_MASK0(hose); +static unsigned int +rawhide_startup_irq(unsigned int irq) +{ + rawhide_enable_irq(irq); + return 0; } +static struct hw_interrupt_type rawhide_irq_type = { + typename: "RAWHIDE", + startup: rawhide_startup_irq, + shutdown: rawhide_disable_irq, + enable: rawhide_enable_irq, + disable: rawhide_disable_irq, + ack: rawhide_disable_irq, + end: rawhide_enable_irq, +}; + static void rawhide_srm_device_interrupt(unsigned long vector, struct pt_regs * regs) { @@ -97,28 +121,30 @@ /* Adjust by which hose it is from. */ irq -= ((irq + 16) >> 2) & 0x38; - handle_irq(irq, irq, regs); + handle_irq(irq, regs); } static void __init rawhide_init_irq(void) { struct pci_controler *hose; + long i; mcpcia_init_hoses(); - STANDARD_INIT_IRQ_PROLOG; - - /* HACK ALERT! Routing is only to CPU #0. */ for (hose = hose_head; hose; hose = hose->next) { int h = hose->index; + rawhide_update_irq_hw(h, hose_irq_masks[h]); + } - *(vuip)MCPCIA_INT_MASK0(h) = hose_irq_masks[h]; - mb(); - *(vuip)MCPCIA_INT_MASK0(h); + for (i = 16; i < 128; ++i) { + irq_desc[i].status = IRQ_DISABLED; + irq_desc[i].handler = &rawhide_irq_type; } - enable_irq(2); + init_i8259a_irqs(); + init_rtc_irq(); + common_init_isa_dma(); } /* @@ -191,14 +217,11 @@ min_mem_address: MCPCIA_DEFAULT_MEM_BASE, nr_irqs: 128, - irq_probe_mask: _PROBE_MASK(128), - update_irq_hw: rawhide_update_irq_hw, - ack_irq: common_ack_irq, device_interrupt: rawhide_srm_device_interrupt, init_arch: mcpcia_init_arch, init_irq: rawhide_init_irq, - init_pit: common_init_pit, + init_rtc: common_init_rtc, init_pci: common_init_pci, kill_arch: NULL, pci_map_irq: rawhide_map_irq, diff -u --recursive --new-file v2.3.46/linux/arch/alpha/kernel/sys_ruffian.c linux/arch/alpha/kernel/sys_ruffian.c --- v2.3.46/linux/arch/alpha/kernel/sys_ruffian.c Tue Dec 7 09:32:40 1999 +++ linux/arch/alpha/kernel/sys_ruffian.c Sun Feb 20 08:13:56 2000 @@ -26,117 +26,17 @@ #include #include "proto.h" -#include +#include "irq_impl.h" #include "pci_impl.h" #include "machvec_impl.h" -static void -ruffian_update_irq_hw(unsigned long irq, unsigned long mask, int unmask_p) -{ - if (irq >= 16) { - /* Note inverted sense of mask bits: */ - /* Make CERTAIN none of the bogus ints get enabled... */ - *(vulp)PYXIS_INT_MASK = - ~((long)mask >> 16) & 0x00000000ffffffbfUL; - mb(); - /* ... and read it back to make sure it got written. */ - *(vulp)PYXIS_INT_MASK; - } - else if (irq >= 8) - outb(mask >> 8, 0xA1); /* ISA PIC2 */ - else - outb(mask, 0x21); /* ISA PIC1 */ -} - -static void -ruffian_ack_irq(unsigned long irq) -{ - if (irq < 16) { - /* Ack PYXIS ISA interrupt. */ - *(vulp)PYXIS_INT_REQ = 1L << 7; mb(); - /* ... and read it back to make sure it got written. */ - *(vulp)PYXIS_INT_REQ; - if (irq > 7) { - outb(0x20, 0xa0); - } - outb(0x20, 0x20); - } else { - /* Ack PYXIS PCI interrupt. */ - *(vulp)PYXIS_INT_REQ = (1UL << (irq - 16)); mb(); - /* ... and read it back to make sure it got written. */ - *(vulp)PYXIS_INT_REQ; - } -} - -static void -ruffian_device_interrupt(unsigned long vector, struct pt_regs *regs) -{ - unsigned long pld; - unsigned int i; - - /* Read the interrupt summary register of PYXIS */ - pld = *(vulp)PYXIS_INT_REQ; - - /* For now, AND off any bits we are not interested in: - * HALT (2), timer (6), ISA Bridge (7), 21142 (8) - * then all the PCI slots/INTXs (12-31) - * flash(5) :DWH: - */ - pld &= 0x00000000ffffff9fUL; /* was ffff7f */ - - /* - * Now for every possible bit set, work through them and call - * the appropriate interrupt handler. - */ - while (pld) { - i = ffz(~pld); - pld &= pld - 1; /* clear least bit set */ - if (i == 7) { /* if ISA int */ - /* Ruffian does not have the RTC connected to - the CPU timer interrupt. Instead, it uses the - PIT connected to IRQ 0. So we must detect that - and route that specifically to where we expected - to find the timer interrupt come in. */ - - /* Copy this code from isa_device_interrupt because - we need to hook into int 0 for the timer. I - refuse to soil device_interrupt with ifdefs. */ - - /* Generate a PCI interrupt acknowledge cycle. - The PIC will respond with the interrupt - vector of the highest priority interrupt - that is pending. The PALcode sets up the - interrupts vectors such that irq level L - generates vector L. */ - - unsigned int j = *(vuip)PYXIS_IACK_SC & 0xff; - if (j == 7 && !(inb(0x20) & 0x80)) { - /* It's only a passive release... */ - } else if (j == 0) { - handle_irq(TIMER_IRQ, -1, regs); - ruffian_ack_irq(0); - } else { - handle_irq(j, j, regs); - } - } else { /* if not an ISA int */ - handle_irq(16 + i, 16 + i, regs); - } - - *(vulp)PYXIS_INT_REQ = 1UL << i; mb(); - *(vulp)PYXIS_INT_REQ; /* read to force the write */ - } -} static void __init ruffian_init_irq(void) { - STANDARD_INIT_IRQ_PROLOG; - /* Invert 6&7 for i82371 */ *(vulp)PYXIS_INT_HILO = 0x000000c0UL; mb(); *(vulp)PYXIS_INT_CNFG = 0x00002064UL; mb(); /* all clear */ - *(vulp)PYXIS_INT_MASK = 0x00000000UL; mb(); - *(vulp)PYXIS_INT_REQ = 0xffffffffUL; mb(); outb(0x11,0xA0); outb(0x08,0xA1); @@ -150,17 +50,54 @@ outb(0x01,0x21); outb(0xFF,0x21); - /* Send -INTA pulses to clear any pending interrupts ...*/ - *(vuip) PYXIS_IACK_SC; - /* Finish writing the 82C59A PIC Operation Control Words */ outb(0x20,0xA0); outb(0x20,0x20); - /* Turn on the interrupt controller, the timer interrupt */ - enable_irq(16 + 7); /* enable ISA PIC cascade */ - enable_irq(0); /* enable timer */ - enable_irq(2); /* enable 2nd PIC cascade */ + init_i8259a_irqs(); + + /* Not interested in the bogus interrupts (0,3,4,6), + NMI (1), HALT (2), flash (5), or 21142 (8). */ + init_pyxis_irqs(0x17f0000); + + common_init_isa_dma(); +} + +static void __init +ruffian_init_rtc(struct irqaction *action) +{ + /* Ruffian does not have the RTC connected to the CPU timer + interrupt. Instead, it uses the PIT connected to IRQ 0. */ + + /* Setup interval timer. */ + outb(0x34, 0x43); /* binary, mode 2, LSB/MSB, ch 0 */ + outb(LATCH & 0xff, 0x40); /* LSB */ + outb(LATCH >> 8, 0x40); /* MSB */ + + outb(0xb6, 0x43); /* pit counter 2: speaker */ + outb(0x31, 0x42); + outb(0x13, 0x42); + + setup_irq(0, action); +} + +static void +ruffian_kill_arch (int mode) +{ +#if 0 + /* This only causes re-entry to ARCSBIOS */ + /* Perhaps this works for other PYXIS as well? */ + *(vuip) PYXIS_RESET = 0x0000dead; + mb(); +#endif +} + +static int __init +ruffian_map_irq(struct pci_dev *dev, u8 slot, u8 pin) +{ + /* We don't know anything about the PCI routing, so leave + the IRQ unchanged. */ + return dev->irq; } @@ -203,34 +140,6 @@ } #endif /* BUILDING_FOR_MILO */ -static void -ruffian_init_pit (void) -{ - outb(0xb6, 0x43); /* pit counter 2: speaker */ - outb(0x31, 0x42); - outb(0x13, 0x42); -} - -static void -ruffian_kill_arch (int mode) -{ -#if 0 - /* This only causes re-entry to ARCSBIOS */ - /* Perhaps this works for other PYXIS as well? */ - *(vuip) PYXIS_RESET = 0x0000dead; - mb(); -#endif -} - -static int __init -ruffian_map_irq(struct pci_dev *dev, u8 slot, u8 pin) -{ - /* We don't know anything about the PCI routing, so leave - the IRQ unchanged. */ - return dev->irq; -} - - /* * The System Vector */ @@ -247,14 +156,11 @@ min_mem_address: DEFAULT_MEM_BASE, nr_irqs: 48, - irq_probe_mask: RUFFIAN_PROBE_MASK, - update_irq_hw: ruffian_update_irq_hw, - ack_irq: ruffian_ack_irq, - device_interrupt: ruffian_device_interrupt, + device_interrupt: pyxis_device_interrupt, init_arch: pyxis_init_arch, init_irq: ruffian_init_irq, - init_pit: ruffian_init_pit, + init_rtc: ruffian_init_rtc, init_pci: common_init_pci, kill_arch: ruffian_kill_arch, pci_map_irq: ruffian_map_irq, diff -u --recursive --new-file v2.3.46/linux/arch/alpha/kernel/sys_rx164.c linux/arch/alpha/kernel/sys_rx164.c --- v2.3.46/linux/arch/alpha/kernel/sys_rx164.c Tue Dec 7 09:32:40 1999 +++ linux/arch/alpha/kernel/sys_rx164.c Sun Feb 20 08:13:56 2000 @@ -26,121 +26,103 @@ #include #include "proto.h" -#include +#include "irq_impl.h" #include "pci_impl.h" #include "machvec_impl.h" -static void -rx164_update_irq_hw(unsigned long irq, unsigned long mask, int unmask_p) +/* Note mask bit is true for ENABLED irqs. */ +static unsigned long cached_irq_mask; + +/* Bus 0, Device 0. Nothing else matters, since we invoke the + POLARIS routines directly. */ +static struct pci_dev rx164_system; + +static inline void +rx164_update_irq_hw(unsigned long mask) { - if (irq >= 16) { - unsigned int temp; - pcibios_write_config_dword(0, 0, 0x74, ~mask >> 16); - pcibios_read_config_dword(0, 0, 0x74, &temp); - } - else if (irq >= 8) - outb(mask >> 8, 0xA1); /* ISA PIC2 */ - else - outb(mask, 0x21); /* ISA PIC1 */ + unsigned int temp; + polaris_write_config_dword(&rx164_system, 0x74, mask); + polaris_read_config_dword(&rx164_system, 0x74, &temp); } -#if 0 -static void -rx164_srm_update_irq_hw(unsigned long irq, unsigned long mask, int unmask_p) +static inline void +rx164_enable_irq(unsigned int irq) { - if (irq >= 16) { - if (unmask_p) - cserve_ena(irq - 16); - else - cserve_dis(irq - 16); - } - else if (irq >= 8) - outb(mask >> 8, 0xA1); /* ISA PIC2 */ - else - outb(mask, 0x21); /* ISA PIC1 */ + rx164_update_irq_hw(cached_irq_mask |= 1UL << (irq - 16)); } -#endif static void -rx164_isa_device_interrupt(unsigned long vector, struct pt_regs * regs) +rx164_disable_irq(unsigned int irq) { - unsigned long pic; + rx164_update_irq_hw(cached_irq_mask &= ~(1UL << (irq - 16))); +} - /* - * It seems to me that the probability of two or more *device* - * interrupts occurring at almost exactly the same time is - * pretty low. So why pay the price of checking for - * additional interrupts here if the common case can be - * handled so much easier? - */ - /* - * The first read of the PIC gives you *all* interrupting lines. - * Therefore, read the mask register and and out those lines - * not enabled. Note that some documentation has 21 and a1 - * write only. This is not true. - */ - pic = inb(0x20) | (inb(0xA0) << 8); /* read isr */ - pic &= ~alpha_irq_mask; /* apply mask */ - pic &= 0xFFFB; /* mask out cascade & hibits */ - - while (pic) { - int j = ffz(~pic); - pic &= pic - 1; - handle_irq(j, j, regs); - } +static unsigned int +rx164_startup_irq(unsigned int irq) +{ + rx164_enable_irq(irq); + return 0; } +static struct hw_interrupt_type rx164_irq_type = { + typename: "RX164", + startup: rx164_startup_irq, + shutdown: rx164_disable_irq, + enable: rx164_enable_irq, + disable: rx164_disable_irq, + ack: rx164_disable_irq, + end: rx164_enable_irq, +}; + static void rx164_device_interrupt(unsigned long vector, struct pt_regs *regs) { + unsigned int temp; unsigned long pld; - int i; - - /* Read the interrupt summary register. On Polaris, - * this is the DIRR register in PCI config space (offset 0x84) - */ - pld = 0; - pcibios_read_config_dword(0, 0, 0x84, (unsigned int *)&pld); - -#if 0 - printk("PLD 0x%lx\n", pld); -#endif - - if (pld & 0xffffffff00000000UL) - pld &= 0x00000000ffffffffUL; + long i; - /* - * Now for every possible bit set, work through them and call - * the appropriate interrupt handler. - */ - while (pld) { - i = ffz(~pld); - pld &= pld - 1; /* clear least bit set */ - if (i == 20) { - rx164_isa_device_interrupt(vector, regs); - } else { - handle_irq(16+i, 16+i, regs); - } - } + /* Read the interrupt summary register. On Polaris, this is + the DIRR register in PCI config space (offset 0x84). */ + polaris_read_config_dword(&rx164_system, 0x84, &temp); + pld = temp; + + /* + * Now for every possible bit set, work through them and call + * the appropriate interrupt handler. + */ + while (pld) { + i = ffz(~pld); + pld &= pld - 1; /* clear least bit set */ + if (i == 20) { + isa_no_iack_sc_device_interrupt(vector, regs); + } else { + handle_irq(16+i, regs); + } + } } -static void +static void __init rx164_init_irq(void) { - unsigned int temp; + long i; - STANDARD_INIT_IRQ_PROLOG; + rx164_update_irq_hw(0); + for (i = 16; i < 40; ++i) { + irq_desc[i].status = IRQ_DISABLED; + irq_desc[i].handler = &rx164_irq_type; + } - pcibios_write_config_dword(0, 0, 0x74, (~alpha_irq_mask >> 16)); - pcibios_read_config_dword(0, 0, 0x74, &temp); + init_i8259a_irqs(); + init_rtc_irq(); + common_init_isa_dma(); - enable_irq(16 + 20); /* enable ISA interrupts */ - enable_irq(2); /* enable cascade */ + setup_irq(16+20, &isa_cascade_irqaction); } -/* The RX164 changed its interrupt routing between pass1 and pass2... +/* + * The RX164 changed its interrupt routing between pass1 and pass2... * * PASS1: * @@ -176,29 +158,29 @@ rx164_map_irq(struct pci_dev *dev, u8 slot, u8 pin) { #if 0 - char irq_tab_pass1[6][5] = { - /*INT INTA INTB INTC INTD */ - { 16+3, 16+3, 16+8, 16+13, 16+18}, /* IdSel 5, slot 2 */ - { 16+5, 16+5, 16+10, 16+15, 16+20}, /* IdSel 6, slot 0 */ - { 16+4, 16+4, 16+9, 16+14, 16+19}, /* IdSel 7, slot 1 */ - { -1, -1, -1, -1, -1}, /* IdSel 8, PCI/ISA bridge */ - { 16+2, 16+2, 16+7, 16+12, 16+17}, /* IdSel 9, slot 3 */ - { 16+1, 16+1, 16+6, 16+11, 16+16}, /* IdSel 10, slot 4 */ - }; + static char irq_tab_pass1[6][5] __initlocaldata = { + /*INT INTA INTB INTC INTD */ + { 16+3, 16+3, 16+8, 16+13, 16+18}, /* IdSel 5, slot 2 */ + { 16+5, 16+5, 16+10, 16+15, 16+20}, /* IdSel 6, slot 0 */ + { 16+4, 16+4, 16+9, 16+14, 16+19}, /* IdSel 7, slot 1 */ + { -1, -1, -1, -1, -1}, /* IdSel 8, PCI/ISA bridge */ + { 16+2, 16+2, 16+7, 16+12, 16+17}, /* IdSel 9, slot 3 */ + { 16+1, 16+1, 16+6, 16+11, 16+16}, /* IdSel 10, slot 4 */ + }; #else - char irq_tab[6][5] = { - /*INT INTA INTB INTC INTD */ - { 16+0, 16+0, 16+6, 16+11, 16+16}, /* IdSel 5, slot 0 */ - { 16+1, 16+1, 16+7, 16+12, 16+17}, /* IdSel 6, slot 1 */ - { -1, -1, -1, -1, -1}, /* IdSel 7, PCI/ISA bridge */ - { 16+2, 16+2, 16+8, 16+13, 16+18}, /* IdSel 8, slot 2 */ - { 16+3, 16+3, 16+9, 16+14, 16+19}, /* IdSel 9, slot 3 */ - { 16+4, 16+4, 16+10, 16+15, 16+5}, /* IdSel 10, PCI-PCI */ - }; + static char irq_tab[6][5] __initlocaldata = { + /*INT INTA INTB INTC INTD */ + { 16+0, 16+0, 16+6, 16+11, 16+16}, /* IdSel 5, slot 0 */ + { 16+1, 16+1, 16+7, 16+12, 16+17}, /* IdSel 6, slot 1 */ + { -1, -1, -1, -1, -1}, /* IdSel 7, PCI/ISA bridge */ + { 16+2, 16+2, 16+8, 16+13, 16+18}, /* IdSel 8, slot 2 */ + { 16+3, 16+3, 16+9, 16+14, 16+19}, /* IdSel 9, slot 3 */ + { 16+4, 16+4, 16+10, 16+15, 16+5}, /* IdSel 10, PCI-PCI */ + }; #endif const long min_idsel = 5, max_idsel = 10, irqs_per_slot = 5; - /* JRP - Need to figure out how to distinguish pass1 from pass2, + /* JRP - Need to figure out how to distinguish pass1 from pass2, and use the correct table. */ return COMMON_TABLE_LOOKUP; } @@ -220,14 +202,11 @@ min_mem_address: DEFAULT_MEM_BASE, nr_irqs: 40, - irq_probe_mask: _PROBE_MASK(40), - update_irq_hw: rx164_update_irq_hw, - ack_irq: common_ack_irq, device_interrupt: rx164_device_interrupt, init_arch: polaris_init_arch, init_irq: rx164_init_irq, - init_pit: common_init_pit, + init_rtc: common_init_rtc, init_pci: common_init_pci, kill_arch: NULL, pci_map_irq: rx164_map_irq, diff -u --recursive --new-file v2.3.46/linux/arch/alpha/kernel/sys_sable.c linux/arch/alpha/kernel/sys_sable.c --- v2.3.46/linux/arch/alpha/kernel/sys_sable.c Tue Dec 7 09:32:40 1999 +++ linux/arch/alpha/kernel/sys_sable.c Sun Feb 20 08:13:56 2000 @@ -26,7 +26,7 @@ #include #include "proto.h" -#include +#include "irq_impl.h" #include "pci_impl.h" #include "machvec_impl.h" @@ -38,15 +38,43 @@ * 0-7 (char at 536) * 8-15 (char at 53a) * 16-23 (char at 53c) + * + * Summary Registers (536/53a/53c): + * + * Bit Meaning Kernel IRQ + *------------------------------------------ + * 0 PCI slot 0 34 + * 1 NCR810 (builtin) 33 + * 2 TULIP (builtin) 32 + * 3 mouse 12 + * 4 PCI slot 1 35 + * 5 PCI slot 2 36 + * 6 keyboard 1 + * 7 floppy 6 + * 8 COM2 3 + * 9 parallel port 7 + *10 EISA irq 3 - + *11 EISA irq 4 - + *12 EISA irq 5 5 + *13 EISA irq 6 - + *14 EISA irq 7 - + *15 COM1 4 + *16 EISA irq 9 9 + *17 EISA irq 10 10 + *18 EISA irq 11 11 + *19 EISA irq 12 - + *20 EISA irq 13 - + *21 EISA irq 14 14 + *22 NC 15 + *23 IIC - */ -/* Note that the vector reported by the SRM PALcode corresponds to the - interrupt mask bits, but we have to manage via more normal IRQs. */ - static struct { char irq_to_mask[40]; char mask_to_irq[40]; + + /* Note mask bit is true for DISABLED irqs. */ unsigned long shadow_mask; } sable_irq_swizzle = { { @@ -54,61 +82,103 @@ -1, 16, 17, 18, 3, -1, 21, 22, /* pseudo PIC 8-15 */ -1, -1, -1, -1, -1, -1, -1, -1, /* pseudo EISA 0-7 */ -1, -1, -1, -1, -1, -1, -1, -1, /* pseudo EISA 8-15 */ - 2, 1, 0, 4, 5, -1, -1, -1, /* pseudo PCI */ + 2, 1, 0, 4, 5, -1, -1, -1, /* pseudo PCI */ }, { 34, 33, 32, 12, 35, 36, 1, 6, /* mask 0-7 */ - 3, 7, -1, -1, 5, -1, -1, 4, /* mask 8-15 */ - 9, 10, 11, -1, -1, 14, 15, -1, /* mask 16-23 */ + 3, 7, -1, -1, 5, -1, -1, 4, /* mask 8-15 */ + 9, 10, 11, -1, -1, 14, 15, -1, /* mask 16-23 */ }, - 0 + -1 }; +static inline void +sable_update_irq_hw(unsigned long bit, unsigned long mask) +{ + int port = 0x536; -static void -sable_update_irq_hw(unsigned long irq, unsigned long unused_mask, int unmask_p) + if (bit >= 16) { + port = 0x53d; + mask >>= 16; + } else if (bit >= 8) { + port = 0x53b; + mask >>= 8; + } + + outb(mask, port); +} + +static inline void +sable_ack_irq_hw(unsigned long bit) +{ + int port, val1, val2; + + if (bit >= 16) { + port = 0x53c; + val1 = 0xE0 | (bit - 16); + val2 = 0xE0 | 4; + } else if (bit >= 8) { + port = 0x53a; + val1 = 0xE0 | (bit - 8); + val2 = 0xE0 | 2; + } else { + port = 0x536; + val1 = 0xE0 | (bit - 0); + val2 = 0xE0 | 1; + } + + outb(val1, port); /* ack the slave */ + outb(val2, 0x534); /* ack the master */ +} + +static inline void +sable_enable_irq(unsigned int irq) +{ + unsigned long bit, mask; + + bit = sable_irq_swizzle.irq_to_mask[irq]; + mask = sable_irq_swizzle.shadow_mask &= ~(1UL << bit); + sable_update_irq_hw(bit, mask); +} + +static void +sable_disable_irq(unsigned int irq) { unsigned long bit, mask; - /* The "irq" argument is really the irq, but we need it to - be the mask bit number. Convert it now. */ + bit = sable_irq_swizzle.irq_to_mask[irq]; + mask = sable_irq_swizzle.shadow_mask |= 1UL << bit; + sable_update_irq_hw(bit, mask); +} - irq = sable_irq_swizzle.irq_to_mask[irq]; - bit = 1UL << irq; - mask = sable_irq_swizzle.shadow_mask | bit; - if (unmask_p) - mask &= ~bit; - sable_irq_swizzle.shadow_mask = mask; - - /* The "irq" argument is now really the mask bit number. */ - if (irq <= 7) - outb(mask, 0x537); - else if (irq <= 15) - outb(mask >> 8, 0x53b); - else - outb(mask >> 16, 0x53d); +static unsigned int +sable_startup_irq(unsigned int irq) +{ + sable_enable_irq(irq); + return 0; } static void -sable_ack_irq(unsigned long irq) +sable_mask_and_ack_irq(unsigned int irq) { - /* Note that the "irq" here is really the mask bit number */ - switch (irq) { - case 0 ... 7: - outb(0xE0 | (irq - 0), 0x536); - outb(0xE0 | 1, 0x534); /* slave 0 */ - break; - case 8 ... 15: - outb(0xE0 | (irq - 8), 0x53a); - outb(0xE0 | 3, 0x534); /* slave 1 */ - break; - case 16 ... 24: - outb(0xE0 | (irq - 16), 0x53c); - outb(0xE0 | 4, 0x534); /* slave 2 */ - break; - } + unsigned long bit, mask; + + bit = sable_irq_swizzle.irq_to_mask[irq]; + mask = sable_irq_swizzle.shadow_mask |= 1UL << bit; + sable_update_irq_hw(bit, mask); + sable_ack_irq_hw(bit); } +static struct hw_interrupt_type sable_irq_type = { + typename: "SABLE", + startup: sable_startup_irq, + shutdown: sable_disable_irq, + enable: sable_enable_irq, + disable: sable_disable_irq, + ack: sable_mask_and_ack_irq, + end: sable_enable_irq, +}; + static void sable_srm_device_interrupt(unsigned long vector, struct pt_regs * regs) { @@ -116,64 +186,36 @@ to the interrupt mask bits, but we have to manage via more normal IRQs. */ - int irq, ack; + int bit, irq; - ack = irq = (vector - 0x800) >> 4; - - irq = sable_irq_swizzle.mask_to_irq[(ack)]; -#if 0 - if (irq == 5 || irq == 9 || irq == 10 || irq == 11 || - irq == 14 || irq == 15) - printk("srm_device_interrupt: vector=0x%lx ack=0x%x" - " irq=0x%x\n", vector, ack, irq); -#endif - - handle_irq(irq, ack, regs); + bit = (vector - 0x800) >> 4; + irq = sable_irq_swizzle.mask_to_irq[bit]; + handle_irq(irq, regs); } static void __init sable_init_irq(void) { - STANDARD_INIT_IRQ_PROLOG; + long i; - outb(alpha_irq_mask , 0x537); /* slave 0 */ - outb(alpha_irq_mask >> 8, 0x53b); /* slave 1 */ - outb(alpha_irq_mask >> 16, 0x53d); /* slave 2 */ - outb(0x44, 0x535); /* enable cascades in master */ + outb(-1, 0x537); /* slave 0 */ + outb(-1, 0x53b); /* slave 1 */ + outb(-1, 0x53d); /* slave 2 */ + outb(0x44, 0x535); /* enable cascades in master */ + + for (i = 0; i < 40; ++i) { + irq_desc[i].status = IRQ_DISABLED; + irq_desc[i].handler = &sable_irq_type; + } + + init_rtc_irq(); + common_init_isa_dma(); } /* * PCI Fixup configuration for ALPHA SABLE (2100) - 2100A is different ?? * - * Summary Registers (536/53a/53c): - * Bit Meaning - *----------------- - * 0 PCI slot 0 - * 1 NCR810 (builtin) - * 2 TULIP (builtin) - * 3 mouse - * 4 PCI slot 1 - * 5 PCI slot 2 - * 6 keyboard - * 7 floppy - * 8 COM2 - * 9 parallel port - *10 EISA irq 3 - *11 EISA irq 4 - *12 EISA irq 5 - *13 EISA irq 6 - *14 EISA irq 7 - *15 COM1 - *16 EISA irq 9 - *17 EISA irq 10 - *18 EISA irq 11 - *19 EISA irq 12 - *20 EISA irq 13 - *21 EISA irq 14 - *22 NC - *23 IIC - * * The device to slot mapping looks like: * * Slot Device @@ -239,14 +281,11 @@ min_mem_address: DEFAULT_MEM_BASE, nr_irqs: 40, - irq_probe_mask: _PROBE_MASK(40), - update_irq_hw: sable_update_irq_hw, - ack_irq: sable_ack_irq, device_interrupt: sable_srm_device_interrupt, init_arch: t2_init_arch, init_irq: sable_init_irq, - init_pit: common_init_pit, + init_rtc: common_init_rtc, init_pci: common_init_pci, kill_arch: NULL, pci_map_irq: sable_map_irq, @@ -274,14 +313,11 @@ min_mem_address: DEFAULT_MEM_BASE, nr_irqs: 40, - irq_probe_mask: _PROBE_MASK(40), - update_irq_hw: sable_update_irq_hw, - ack_irq: sable_ack_irq, device_interrupt: sable_srm_device_interrupt, init_arch: t2_init_arch, init_irq: sable_init_irq, - init_pit: common_init_pit, + init_rtc: common_init_rtc, init_pci: common_init_pci, pci_map_irq: sable_map_irq, pci_swizzle: common_swizzle, diff -u --recursive --new-file v2.3.46/linux/arch/alpha/kernel/sys_sio.c linux/arch/alpha/kernel/sys_sio.c --- v2.3.46/linux/arch/alpha/kernel/sys_sio.c Thu Feb 10 17:11:02 2000 +++ linux/arch/alpha/kernel/sys_sio.c Sun Feb 20 08:13:56 2000 @@ -30,28 +30,20 @@ #include #include "proto.h" -#include +#include "irq_impl.h" #include "pci_impl.h" #include "machvec_impl.h" -static void -sio_update_irq_hw(unsigned long irq, unsigned long mask, int unmask_p) -{ - if (irq >= 8) - outb(mask >> 8, 0xA1); - else - outb(mask, 0x21); -} static void __init sio_init_irq(void) { - STANDARD_INIT_IRQ_PROLOG; - if (alpha_using_srm) alpha_mv.device_interrupt = srm_device_interrupt; - - enable_irq(2); /* enable cascade */ + + init_i8259a_irqs(); + init_rtc_irq(); + common_init_isa_dma(); } static inline void __init @@ -270,14 +262,11 @@ min_mem_address: APECS_AND_LCA_DEFAULT_MEM_BASE, nr_irqs: 16, - irq_probe_mask: _PROBE_MASK(16), - update_irq_hw: sio_update_irq_hw, - ack_irq: common_ack_irq, device_interrupt: isa_device_interrupt, init_arch: alphabook1_init_arch, init_irq: sio_init_irq, - init_pit: common_init_pit, + init_rtc: common_init_rtc, init_pci: alphabook1_init_pci, kill_arch: NULL, pci_map_irq: noname_map_irq, @@ -304,14 +293,11 @@ min_mem_address: APECS_AND_LCA_DEFAULT_MEM_BASE, nr_irqs: 16, - irq_probe_mask: _PROBE_MASK(16), - update_irq_hw: sio_update_irq_hw, - ack_irq: common_ack_irq, device_interrupt: isa_device_interrupt, init_arch: apecs_init_arch, init_irq: sio_init_irq, - init_pit: common_init_pit, + init_rtc: common_init_rtc, init_pci: noname_init_pci, pci_map_irq: noname_map_irq, pci_swizzle: common_swizzle, @@ -336,14 +322,11 @@ min_mem_address: APECS_AND_LCA_DEFAULT_MEM_BASE, nr_irqs: 16, - irq_probe_mask: _PROBE_MASK(16), - update_irq_hw: sio_update_irq_hw, - ack_irq: common_ack_irq, device_interrupt: srm_device_interrupt, init_arch: lca_init_arch, init_irq: sio_init_irq, - init_pit: common_init_pit, + init_rtc: common_init_rtc, init_pci: noname_init_pci, pci_map_irq: noname_map_irq, pci_swizzle: common_swizzle, @@ -377,14 +360,11 @@ min_mem_address: APECS_AND_LCA_DEFAULT_MEM_BASE, nr_irqs: 16, - irq_probe_mask: P2K_PROBE_MASK, - update_irq_hw: sio_update_irq_hw, - ack_irq: common_ack_irq, device_interrupt: srm_device_interrupt, init_arch: lca_init_arch, init_irq: sio_init_irq, - init_pit: common_init_pit, + init_rtc: common_init_rtc, init_pci: noname_init_pci, pci_map_irq: p2k_map_irq, pci_swizzle: common_swizzle, @@ -409,14 +389,11 @@ min_mem_address: XL_DEFAULT_MEM_BASE, nr_irqs: 16, - irq_probe_mask: _PROBE_MASK(16), - update_irq_hw: sio_update_irq_hw, - ack_irq: common_ack_irq, device_interrupt: isa_device_interrupt, init_arch: lca_init_arch, init_irq: sio_init_irq, - init_pit: common_init_pit, + init_rtc: common_init_rtc, init_pci: noname_init_pci, pci_map_irq: noname_map_irq, pci_swizzle: common_swizzle, diff -u --recursive --new-file v2.3.46/linux/arch/alpha/kernel/sys_sx164.c linux/arch/alpha/kernel/sys_sx164.c --- v2.3.46/linux/arch/alpha/kernel/sys_sx164.c Tue Dec 7 09:32:40 1999 +++ linux/arch/alpha/kernel/sys_sx164.c Sun Feb 20 08:13:56 2000 @@ -26,81 +26,12 @@ #include #include "proto.h" -#include +#include "irq_impl.h" #include "pci_impl.h" #include "machvec_impl.h" -static void -sx164_update_irq_hw(unsigned long irq, unsigned long mask, int unmask_p) -{ - if (irq >= 16) { - /* Make CERTAIN none of the bogus ints get enabled */ - *(vulp)PYXIS_INT_MASK = - ~((long)mask >> 16) & ~0x000000000000003bUL; - mb(); - /* ... and read it back to make sure it got written. */ - *(vulp)PYXIS_INT_MASK; - } - else if (irq >= 8) - outb(mask >> 8, 0xA1); /* ISA PIC2 */ - else - outb(mask, 0x21); /* ISA PIC1 */ -} - -static void -sx164_srm_update_irq_hw(unsigned long irq, unsigned long mask, int unmask_p) -{ - if (irq >= 16) { - if (unmask_p) - cserve_ena(irq - 16); - else - cserve_dis(irq - 16); - } - else if (irq >= 8) - outb(mask >> 8, 0xA1); /* ISA PIC2 */ - else - outb(mask, 0x21); /* ISA PIC1 */ -} - -static void -sx164_device_interrupt(unsigned long vector, struct pt_regs *regs) -{ - unsigned long pld, tmp; - unsigned int i; - - /* Read the interrupt summary register of PYXIS */ - pld = *(vulp)PYXIS_INT_REQ; - - /* - * For now, AND off any bits we are not interested in: - * HALT (2), timer (6), ISA Bridge (7) - * then all the PCI slots/INTXs (8-23) - */ - /* Maybe HALT should only be used for SRM console boots? */ - pld &= 0x0000000000ffffc0UL; - - /* - * Now for every possible bit set, work through them and call - * the appropriate interrupt handler. - */ - while (pld) { - i = ffz(~pld); - pld &= pld - 1; /* clear least bit set */ - if (i == 7) { - isa_device_interrupt(vector, regs); - } else if (i == 6) { - continue; - } else { - /* if not timer int */ - handle_irq(16 + i, 16 + i, regs); - } - *(vulp)PYXIS_INT_REQ = 1UL << i; mb(); - tmp = *(vulp)PYXIS_INT_REQ; - } -} - -static void +static void __init sx164_init_irq(void) { outb(0, DMA1_RESET_REG); @@ -108,20 +39,20 @@ outb(DMA_MODE_CASCADE, DMA2_MODE_REG); outb(0, DMA2_MASK_REG); - if (alpha_using_srm) { - alpha_mv.update_irq_hw = sx164_srm_update_irq_hw; + if (alpha_using_srm) alpha_mv.device_interrupt = srm_device_interrupt; - } - else { - /* Note invert on MASK bits. */ - *(vulp)PYXIS_INT_MASK = ~((long)alpha_irq_mask >> 16); - mb(); - *(vulp)PYXIS_INT_MASK; - } - - enable_irq(16 + 6); /* enable timer */ - enable_irq(16 + 7); /* enable ISA PIC cascade */ - enable_irq(2); /* enable cascade */ + + init_i8259a_irqs(); + init_rtc_irq(); + + /* Not interested in the bogus interrupts (0,3,4,5,40-47), + NMI (1), or HALT (2). */ + if (alpha_using_srm) + init_srm_irqs(40, 0x3f0000); + else + init_pyxis_irqs(0xff00003f0000); + + setup_irq(16+6, &timer_cascade_irqaction); } /* @@ -160,7 +91,6 @@ * 7 64 bit PCI option slot 1 * 8 Cypress I/O * 9 32 bit PCI option slot 3 - * */ static int __init @@ -201,15 +131,12 @@ min_io_address: DEFAULT_IO_BASE, min_mem_address: DEFAULT_MEM_BASE, - nr_irqs: 40, - irq_probe_mask: _PROBE_MASK(40), - update_irq_hw: sx164_update_irq_hw, - ack_irq: common_ack_irq, - device_interrupt: sx164_device_interrupt, + nr_irqs: 48, + device_interrupt: pyxis_device_interrupt, init_arch: pyxis_init_arch, init_irq: sx164_init_irq, - init_pit: common_init_pit, + init_rtc: common_init_rtc, init_pci: sx164_init_pci, kill_arch: NULL, pci_map_irq: sx164_map_irq, diff -u --recursive --new-file v2.3.46/linux/arch/alpha/kernel/sys_takara.c linux/arch/alpha/kernel/sys_takara.c --- v2.3.46/linux/arch/alpha/kernel/sys_takara.c Tue Dec 7 09:32:40 1999 +++ linux/arch/alpha/kernel/sys_takara.c Sun Feb 20 08:13:56 2000 @@ -25,31 +25,57 @@ #include #include "proto.h" -#include +#include "irq_impl.h" #include "pci_impl.h" #include "machvec_impl.h" -static void -takara_update_irq_hw(unsigned long irq, unsigned long mask, int unmask_p) +/* Note mask bit is true for DISABLED irqs. */ +static unsigned long cached_irq_mask[2] = { -1, -1 }; + +static inline void +takara_update_irq_hw(unsigned long irq, unsigned long mask) { - unsigned int regaddr; + int regaddr; - if (irq <= 15) { - if (irq <= 7) - outb(mask, 0x21); /* ISA PIC1 */ - else - outb(mask >> 8, 0xA1); /* ISA PIC2 */ - } else { - if (irq > 63) - mask = _alpha_irq_masks[1] << 16; - else - mask = mask >> ((irq - 16) & 0x30); - regaddr = 0x510 + (((irq - 16) >> 2) & 0x0c); - outl(mask & 0xffff0000UL, regaddr); - } + mask = (irq >= 64 ? mask << 16 : mask >> ((irq - 16) & 0x30)); + regaddr = 0x510 + (((irq - 16) >> 2) & 0x0c); + outl(mask & 0xffff0000UL, regaddr); +} + +static inline void +takara_enable_irq(unsigned int irq) +{ + unsigned long mask; + mask = (cached_irq_mask[irq >= 64] &= ~(1UL << (irq & 63))); + takara_update_irq_hw(irq, mask); +} + +static void +takara_disable_irq(unsigned int irq) +{ + unsigned long mask; + mask = (cached_irq_mask[irq >= 64] |= 1UL << (irq & 63)); + takara_update_irq_hw(irq, mask); } +static unsigned int +takara_startup_irq(unsigned int irq) +{ + takara_enable_irq(irq); + return 0; /* never anything pending */ +} + +static struct hw_interrupt_type takara_irq_type = { + typename: "TAKARA", + startup: takara_startup_irq, + shutdown: takara_disable_irq, + enable: takara_enable_irq, + disable: takara_disable_irq, + ack: takara_disable_irq, + end: takara_enable_irq, +}; + static void takara_device_interrupt(unsigned long vector, struct pt_regs *regs) { @@ -78,10 +104,10 @@ * despatch an interrupt if it's set. */ - if (intstatus & 8) handle_irq(16+3, 16+3, regs); - if (intstatus & 4) handle_irq(16+2, 16+2, regs); - if (intstatus & 2) handle_irq(16+1, 16+1, regs); - if (intstatus & 1) handle_irq(16+0, 16+0, regs); + if (intstatus & 8) handle_irq(16+3, regs); + if (intstatus & 4) handle_irq(16+2, regs); + if (intstatus & 2) handle_irq(16+1, regs); + if (intstatus & 1) handle_irq(16+0, regs); } else { isa_device_interrupt (vector, regs); } @@ -91,13 +117,16 @@ takara_srm_device_interrupt(unsigned long vector, struct pt_regs * regs) { int irq = (vector - 0x800) >> 4; - handle_irq(irq, irq, regs); + handle_irq(irq, regs); } static void __init takara_init_irq(void) { - STANDARD_INIT_IRQ_PROLOG; + long i; + + init_i8259a_irqs(); + init_rtc_irq(); if (alpha_using_srm) { alpha_mv.device_interrupt = takara_srm_device_interrupt; @@ -113,9 +142,18 @@ outl(ctlreg, 0x500); } - enable_irq(2); + for (i = 16; i < 128; i += 16) + takara_update_irq_hw(i, -1); + + for (i = 16; i < 128; ++i) { + irq_desc[i].status = IRQ_DISABLED; + irq_desc[i].handler = &takara_irq_type; + } + + common_init_isa_dma(); } + /* * The Takara has PCI devices 1, 2, and 3 configured to slots 20, * 19, and 18 respectively, in the default configuration. They can @@ -235,14 +273,11 @@ min_mem_address: CIA_DEFAULT_MEM_BASE, nr_irqs: 128, - irq_probe_mask: _PROBE_MASK(48), - update_irq_hw: takara_update_irq_hw, - ack_irq: common_ack_irq, device_interrupt: takara_device_interrupt, init_arch: cia_init_arch, init_irq: takara_init_irq, - init_pit: common_init_pit, + init_rtc: common_init_rtc, init_pci: takara_init_pci, kill_arch: NULL, pci_map_irq: takara_map_irq, diff -u --recursive --new-file v2.3.46/linux/arch/alpha/kernel/time.c linux/arch/alpha/kernel/time.c --- v2.3.46/linux/arch/alpha/kernel/time.c Tue Dec 7 09:32:40 1999 +++ linux/arch/alpha/kernel/time.c Sun Feb 20 08:13:56 2000 @@ -31,6 +31,8 @@ #include #include #include +#include +#include #include #include @@ -40,7 +42,7 @@ #include #include "proto.h" -#include +#include "irq_impl.h" extern rwlock_t xtime_lock; extern volatile unsigned long lost_ticks; /* kernel/sched.c */ @@ -88,13 +90,7 @@ __u32 now; long nticks; -#ifdef __SMP__ - /* When SMP, do this for *all* CPUs, but only do the rest for - the boot CPU. */ - smp_percpu_timer_interrupt(regs); - if (smp_processor_id() != smp_boot_cpuid) - return; -#else +#ifndef __SMP__ /* Not SMP, do kernel PC profiling here. */ if (!user_mode(regs)) alpha_do_profile(regs->pc); @@ -167,55 +163,8 @@ )*60 + sec; /* finally seconds */ } -/* - * Initialize Programmable Interval Timers with standard values. Some - * drivers depend on them being initialized (e.g., joystick driver). - */ - -#ifdef CONFIG_RTC -void -rtc_init_pit(void) -{ - unsigned char control; - - /* Turn off RTC interrupts before /dev/rtc is initialized */ - control = CMOS_READ(RTC_CONTROL); - control &= ~(RTC_PIE | RTC_AIE | RTC_UIE); - CMOS_WRITE(control, RTC_CONTROL); - (void) CMOS_READ(RTC_INTR_FLAGS); - - /* Setup interval timer. */ - outb(0x34, 0x43); /* binary, mode 2, LSB/MSB, ch 0 */ - outb(LATCH & 0xff, 0x40); /* LSB */ - outb(LATCH >> 8, 0x40); /* MSB */ - - outb(0xb6, 0x43); /* pit counter 2: speaker */ - outb(0x31, 0x42); - outb(0x13, 0x42); -} - void -rtc_kill_pit(void) -{ - unsigned char control; - - cli(); - - /* Reset periodic interrupt frequency. */ - CMOS_WRITE(0x26, RTC_FREQ_SELECT); - - /* Turn on periodic interrupts. */ - control = CMOS_READ(RTC_CONTROL); - control |= RTC_PIE; - CMOS_WRITE(control, RTC_CONTROL); - CMOS_READ(RTC_INTR_FLAGS); - - sti(); -} -#endif - -void -common_init_pit (void) +common_init_rtc(struct irqaction *action) { unsigned char x; @@ -243,12 +192,19 @@ outb(0xb6, 0x43); /* pit counter 2: speaker */ outb(0x31, 0x42); outb(0x13, 0x42); + + setup_irq(RTC_IRQ, action); } void time_init(void) { - void (*irq_handler)(int, void *, struct pt_regs *); + static struct irqaction timer_irqaction = { + handler: timer_interrupt, + flags: SA_INTERRUPT, + name: "timer", + }; + unsigned int year, mon, day, hour, min, sec, cc1, cc2; unsigned long cycle_freq, one_percent; long diff; @@ -336,10 +292,8 @@ state.last_rtc_update = 0; state.partial_tick = 0L; - /* setup timer */ - irq_handler = timer_interrupt; - if (request_irq(TIMER_IRQ, irq_handler, 0, "timer", NULL)) - panic("Could not allocate timer IRQ!"); + /* Startup the timer source. */ + alpha_mv.init_rtc(&timer_irqaction); } /* diff -u --recursive --new-file v2.3.46/linux/arch/alpha/lib/csum_ipv6_magic.S linux/arch/alpha/lib/csum_ipv6_magic.S --- v2.3.46/linux/arch/alpha/lib/csum_ipv6_magic.S Tue Feb 1 01:35:43 2000 +++ linux/arch/alpha/lib/csum_ipv6_magic.S Thu Feb 17 09:18:46 2000 @@ -18,7 +18,7 @@ ldq $0,0($16) # e0 : load src & dst addr words zapnot $20,15,$20 # .. e1 : zero extend incoming csum - extqh $18,7,$4 # e0 : byte swap len & proto while we wait + extqh $18,1,$4 # e0 : byte swap len & proto while we wait ldq $1,8($16) # .. e1 : extbl $18,1,$5 # e0 : diff -u --recursive --new-file v2.3.46/linux/arch/arm/mm/init.c linux/arch/arm/mm/init.c --- v2.3.46/linux/arch/arm/mm/init.c Thu Feb 10 17:11:03 2000 +++ linux/arch/arm/mm/init.c Thu Feb 17 23:34:46 2000 @@ -163,7 +163,7 @@ void __init paging_init(void) { void *zero_page, *bad_page, *bad_table; - unsigned int zone_size[MAX_NR_ZONES]; + unsigned long zone_size[MAX_NR_ZONES]; int i; #ifdef CONFIG_CPU_32 diff -u --recursive --new-file v2.3.46/linux/arch/arm/mm/proc-arm6,7.S linux/arch/arm/mm/proc-arm6,7.S --- v2.3.46/linux/arch/arm/mm/proc-arm6,7.S Sun Feb 13 19:29:03 2000 +++ linux/arch/arm/mm/proc-arm6,7.S Thu Feb 17 23:34:46 2000 @@ -30,6 +30,8 @@ ENTRY(cpu_arm7_flush_cache_entry) ENTRY(cpu_arm6_flush_icache_area) ENTRY(cpu_arm7_flush_icache_area) +ENTRY(cpu_arm6_flush_icache_page) +ENTRY(cpu_arm7_flush_icache_page) ENTRY(cpu_arm6_cache_wback_area) ENTRY(cpu_arm7_cache_wback_area) ENTRY(cpu_arm6_cache_purge_area) @@ -465,6 +467,7 @@ .word cpu_arm6_cache_purge_area .word cpu_arm6_flush_tlb_page .word cpu_arm6_do_idle + .word cpu_arm6_flush_icache_page .size arm6_processor_functions, . - arm6_processor_functions /* @@ -493,6 +496,7 @@ .word cpu_arm7_cache_purge_area .word cpu_arm7_flush_tlb_page .word cpu_arm7_do_idle + .word cpu_arm7_flush_icache_page .size arm7_processor_functions, . - arm7_processor_functions .type cpu_arm6_info, #object diff -u --recursive --new-file v2.3.46/linux/arch/arm/mm/proc-sa110.S linux/arch/arm/mm/proc-sa110.S --- v2.3.46/linux/arch/arm/mm/proc-sa110.S Fri Jan 21 18:19:16 2000 +++ linux/arch/arm/mm/proc-sa110.S Thu Feb 17 23:34:46 2000 @@ -287,6 +287,12 @@ mcr p15, 0, r0, c7, c5, 0 @ flush I cache mov pc, lr + .align 5 +ENTRY(cpu_sa110_flush_icache_page) +ENTRY(cpu_sa1100_flush_icache_page) + mcr p15, 0, r0, c7, c5, 0 @ flush I cache + mov pc, lr + /* * Function: sa110_data_abort () * Params : r0 = address of aborted instruction @@ -504,6 +510,7 @@ .word cpu_sa110_cache_purge_area .word cpu_sa110_flush_tlb_page .word cpu_sa110_do_idle + .word cpu_sa110_flush_icache_page .size sa110_processor_functions, . - sa110_processor_functions .type cpu_sa110_info, #object @@ -535,6 +542,7 @@ .word cpu_sa1100_cache_purge_area .word cpu_sa1100_flush_tlb_page .word cpu_sa1100_do_idle + .word cpu_sa1100_flush_icache_page .size sa1100_processor_functions, . - sa1100_processor_functions cpu_sa1100_info: diff -u --recursive --new-file v2.3.46/linux/arch/i386/boot/setup.S linux/arch/i386/boot/setup.S --- v2.3.46/linux/arch/i386/boot/setup.S Thu Jan 6 12:57:47 2000 +++ linux/arch/i386/boot/setup.S Sun Feb 20 20:37:09 2000 @@ -436,7 +436,7 @@ movw $0xAA, (0x1ff) # device present no_psmouse: -#ifdef CONFIG_APM +#if defined(CONFIG_APM) || defined(CONFIG_APM_MODULE) # Then check for an APM BIOS... # %ds points to the bootsector movw $0, 0x40 # version = 0 means no APM BIOS @@ -455,7 +455,11 @@ xorw %bx, %bx int $0x15 # ignore return code movw $0x05303, %ax # 32 bit connect - xorw %bx, %bx + xorl %ebx, %ebx + xorw %cx, %cx # paranoia :-) + xorw %dx, %dx # ... + xorl %esi, %esi # ... + xorw %di, %di # ... int $0x15 jc no_32_apm_bios # Ack, error. @@ -463,12 +467,13 @@ movl %ebx, (68) # BIOS entry point offset movw %cx, (72) # BIOS 16 bit code segment movw %dx, (74) # BIOS data segment - movl %esi, (78) # BIOS code segment length + movl %esi, (78) # BIOS code segment lengths movw %di, (82) # BIOS data segment length # Redo the installation check as the 32 bit connect # modifies the flags returned on some BIOSs movw $0x05300, %ax # APM BIOS installation check xorw %bx, %bx + xorw %cx, %cx # paranoia int $0x15 jc apm_disconnect # error -> shouldn't happen diff -u --recursive --new-file v2.3.46/linux/arch/i386/config.in linux/arch/i386/config.in --- v2.3.46/linux/arch/i386/config.in Wed Feb 16 17:03:51 2000 +++ linux/arch/i386/config.in Sun Feb 20 20:37:09 2000 @@ -49,7 +49,7 @@ define_bool CONFIG_X86_USE_3DNOW y fi -if [ "$CONFIG_M686" = "y" -a "$CONFIG_PROC_FS" = "y" ]; then +if [ "$CONFIG_PROC_FS" = "y" ]; then tristate '/proc/driver/microcode - Intel P6 CPU microcode support' CONFIG_MICROCODE fi @@ -148,7 +148,7 @@ fi fi -bool 'Advanced Power Management BIOS support' CONFIG_APM +tristate 'Advanced Power Management BIOS support' CONFIG_APM if [ "$CONFIG_APM" != "n" ]; then bool ' Ignore USER SUSPEND' CONFIG_APM_IGNORE_USER_SUSPEND bool ' Enable PM at boot time' CONFIG_APM_DO_ENABLE @@ -158,7 +158,6 @@ bool ' Ignore multiple suspend/resume cycles' CONFIG_APM_IGNORE_SUSPEND_BOUNCE bool ' RTC stores time in GMT' CONFIG_APM_RTC_IS_GMT bool ' Allow interrupts during APM BIOS calls' CONFIG_APM_ALLOW_INTS - bool ' Entry point offset fix (some Acer laptops)' CONFIG_APM_BAD_ENTRY_OFFSET bool ' Use real mode APM BIOS call to power off' CONFIG_APM_REAL_MODE_POWER_OFF fi diff -u --recursive --new-file v2.3.46/linux/arch/i386/defconfig linux/arch/i386/defconfig --- v2.3.46/linux/arch/i386/defconfig Wed Feb 16 17:03:51 2000 +++ linux/arch/i386/defconfig Sun Feb 20 20:46:42 2000 @@ -281,7 +281,7 @@ # CONFIG_DE4X5 is not set # CONFIG_TULIP is not set # CONFIG_DGRS is not set -CONFIG_EEXPRESS_PRO100=y +CONFIG_EEPRO100=y # CONFIG_NE2K_PCI is not set # CONFIG_8139TOO is not set # CONFIG_SIS900 is not set @@ -427,7 +427,7 @@ # # -# Filesystems +# File systems # # CONFIG_QUOTA is not set # CONFIG_AUTOFS_FS is not set @@ -446,19 +446,17 @@ # CONFIG_JOLIET is not set # CONFIG_MINIX_FS is not set # CONFIG_NTFS_FS is not set -# CONFIG_NTFS_RW is not set # CONFIG_HPFS_FS is not set CONFIG_PROC_FS=y +# CONFIG_DEVFS_FS is not set +# CONFIG_DEVFS_DEBUG is not set CONFIG_DEVPTS_FS=y # CONFIG_QNX4FS_FS is not set -# CONFIG_QNX4FS_RW is not set # CONFIG_ROMFS_FS is not set CONFIG_EXT2_FS=y # CONFIG_SYSV_FS is not set -# CONFIG_SYSV_FS_WRITE is not set # CONFIG_UDF_FS is not set # CONFIG_UFS_FS is not set -# CONFIG_UFS_FS_WRITE is not set # # Network File Systems diff -u --recursive --new-file v2.3.46/linux/arch/i386/kernel/apm.c linux/arch/i386/kernel/apm.c --- v2.3.46/linux/arch/i386/kernel/apm.c Wed Feb 16 17:03:51 2000 +++ linux/arch/i386/kernel/apm.c Sun Feb 20 20:37:09 2000 @@ -1,6 +1,6 @@ /* -*- linux-c -*- * APM BIOS driver for Linux - * Copyright 1994-1999 Stephen Rothwell (sfr@linuxcare.com) + * Copyright 1994-2000 Stephen Rothwell (sfr@linuxcare.com) * * Initial development of this driver was funded by NEC Australia P/L * and NEC Corporation @@ -35,6 +35,8 @@ * Jan 1999, Version 1.9 * Oct 1999, Version 1.10 * Nov 1999, Version 1.11 + * Jan 2000, Version 1.12 + * Feb 2000, Version 1.13 * * History: * 0.6b: first version in official kernel, Linux 1.3.46 @@ -54,7 +56,7 @@ * The new replacment for it is, but Linux doesn't yet support this. * Alan Cox Linux 2.1.55 * 1.3: Set up a valid data descriptor 0x40 for buggy BIOS's - * 1.4: Upgraded to support APM 1.2. Integrated ThinkPad suspend patch by + * 1.4: Upgraded to support APM 1.2. Integrated ThinkPad suspend patch by * Dean Gaudet . * C. Scott Ananian Linux 2.1.87 * 1.5: Fix segment register reloading (in case of bad segments saved @@ -110,6 +112,26 @@ * (reported by Panos Katsaloulis ). * Real mode power off patch (Walter Hofmann * ). + * 1.12: Remove CONFIG_SMP as the compiler will optimize + * the code away anyway (smp_num_cpus == 1 in UP) + * noted by Artur Skawina . + * Make power off under SMP work again. + * Fix thinko with initial engaging of BIOS. + * Make sure power off only happens on CPU 0 + * (Paul "Rusty" Russell ). + * Do error notification to user mode if BIOS calls fail. + * Move entrypoint offset fix to ...boot/setup.S + * where it belongs (Cosmos ). + * Remove smp-power-off. SMP users must now specify + * "apm=power-off" on the kernel command line. Suggested + * by Jim Avera , modified by Alan Cox + * . + * Register the /proc/apm entry even on SMP so that + * scripts that check for it before doing power off + * work (Jim Avera ). + * 1.13: Changes for new pm_ interfaces (Andy Henroid + * ). + * Modularize the code. * * APM 1.1 Reference: * @@ -145,13 +167,12 @@ #include #include #include +#include #include #include #include -#include - extern unsigned long get_cmos_time(void); extern void machine_real_restart(unsigned char *, int); @@ -172,10 +193,10 @@ * See Documentation/Config.help for the configuration options. * * Various options can be changed at boot time as follows: + * (We allow underscores for compatibility with the modules code) * apm=on/off enable/disable APM * [no-]debug log some debugging messages - * [no-]power-off power off on shutdown - * [no-]smp-power-off allow power off even for SMP + * [no-]power[-_]off power off on shutdown */ /* KNOWN PROBLEM MACHINES: @@ -219,8 +240,8 @@ /* * Define to re-initialize the interrupt 0 timer to 100 Hz after a suspend. - * This patched by Chad Miller , orig code by David - * Chen + * This patched by Chad Miller , original code by + * David Chen */ #undef INIT_TIMER_AFTER_SUSPEND @@ -237,7 +258,7 @@ /* * If CONFIG_APM_IGNORE_SUSPEND_BOUNCE is defined then - * ignore suspend events for this amount of time + * ignore suspend events for this amount of time after a resume */ #define BOUNCE_INTERVAL (3 * HZ) @@ -248,14 +269,40 @@ __asm__ __volatile__("movl %%" #seg ",%0" : "=m" (where)) /* + * Maximum number of events stored + */ +#define APM_MAX_EVENTS 20 + +/* + * The per-file APM data + */ +struct apm_user { + int magic; + struct apm_user * next; + int suser: 1; + int suspend_wait: 1; + int suspend_result; + int suspends_pending; + int standbys_pending; + int suspends_read; + int standbys_read; + int event_head; + int event_tail; + apm_event_t events[APM_MAX_EVENTS]; +}; + +/* + * The magic number in apm_user + */ +#define APM_BIOS_MAGIC 0x4101 + +/* * Local variables */ static struct { unsigned long offset; unsigned short segment; } apm_bios_entry; -static int apm_enabled = 0; -static int smp_hack = 0; #ifdef CONFIG_APM_CPU_IDLE static int clock_slowed = 0; #endif @@ -274,12 +321,19 @@ #endif static int debug = 0; static int apm_disabled = 0; -static int power_off_enabled = 1; +#ifdef CONFIG_SMP +static int power_off = 0; +#else +static int power_off = 1; +#endif +static int exit_kapmd = 0; +static int kapmd_running = 0; static DECLARE_WAIT_QUEUE_HEAD(apm_waitqueue); -static struct apm_bios_struct * user_list = NULL; +static DECLARE_WAIT_QUEUE_HEAD(apm_suspend_waitqueue); +static struct apm_user * user_list = NULL; -static char driver_version[] = "1.11"; /* no spaces */ +static char driver_version[] = "1.12"; /* no spaces */ static char * apm_event_name[] = { "system standby", @@ -380,6 +434,10 @@ __save_flags(flags); APM_DO_CLI; APM_DO_SAVE_SEGS; + /* + * N.B. We do NOT need a cld after the BIOS call + * because we always save and restore the flags. + */ __asm__ __volatile__(APM_DO_ZERO_SEGS "pushl %%edi\n\t" "pushl %%ebp\n\t" @@ -413,10 +471,14 @@ { int cx, dx, si; + /* + * N.B. We do NOT need a cld after the BIOS call + * because we always save and restore the flags. + */ __asm__ __volatile__(APM_DO_ZERO_SEGS "pushl %%edi\n\t" "pushl %%ebp\n\t" - "lcall %%cs:" SYMBOL_NAME_STR(apm_bios_entry)"\n\t" + "lcall %%cs:" SYMBOL_NAME_STR(apm_bios_entry) "\n\t" "setc %%bl\n\t" "popl %%ebp\n\t" "popl %%edi\n\t" @@ -499,6 +561,7 @@ } } +#if 0 extern int hlt_counter; /* @@ -543,48 +606,63 @@ } } #endif +#endif + +#ifdef CONFIG_SMP +static int apm_magic(void * unused) +{ + while (1) + schedule(); +} +#endif static void apm_power_off(void) { +#ifdef CONFIG_APM_REAL_MODE_POWER_OFF + unsigned char po_bios_call[] = { + 0xb8, 0x00, 0x10, /* movw $0x1000,ax */ + 0x8e, 0xd0, /* movw ax,ss */ + 0xbc, 0x00, 0xf0, /* movw $0xf000,sp */ + 0xb8, 0x07, 0x53, /* movw $0x5307,ax */ + 0xbb, 0x01, 0x00, /* movw $0x0001,bx */ + 0xb9, 0x03, 0x00, /* movw $0x0003,cx */ + 0xcd, 0x15 /* int $0x15 */ + }; +#endif + /* - * smp_hack == 2 means that we would have enabled APM support - * except there is more than one processor and so most of - * the APM stuff is unsafe. We will still try power down - * because is is useful to some people and they know what - * they are doing because they booted with the smp-power-off - * kernel option. + * This may be called on an SMP machine. */ - if (apm_enabled || (smp_hack == 2)) { +#ifdef CONFIG_SMP + /* Some bioses don't like being called from CPU != 0 */ + while (cpu_number_map[smp_processor_id()] != 0) { + kernel_thread(apm_magic, NULL, + CLONE_FS | CLONE_FILES | CLONE_SIGHAND | SIGCHLD); + schedule(); + } +#endif #ifdef CONFIG_APM_REAL_MODE_POWER_OFF - unsigned char po_bios_call[] = { - 0xb8, 0x00, 0x10, /* movw $0x1000,ax */ - 0x8e, 0xd0, /* movw ax,ss */ - 0xbc, 0x00, 0xf0, /* movw $0xf000,sp */ - 0xb8, 0x07, 0x53, /* movw $0x5307,ax */ - 0xbb, 0x01, 0x00, /* movw $0x0001,bx */ - 0xb9, 0x03, 0x00, /* movw $0x0003,cx */ - 0xcd, 0x15 /* int $0x15 */ - }; - - machine_real_restart(po_bios_call, sizeof(po_bios_call)); + machine_real_restart(po_bios_call, sizeof(po_bios_call)); #else - (void) apm_set_power_state(APM_STATE_OFF); + (void) apm_set_power_state(APM_STATE_OFF); #endif - } } -#ifdef CONFIG_APM_DO_ENABLE -static int __init apm_enable_power_management(void) +static int apm_enable_power_management(int enable) { u32 eax; + if ((enable == 0) && (apm_bios_info.flags & APM_BIOS_DISENGAGED)) + return APM_NOT_ENGAGED; if (apm_bios_call_simple(APM_FUNC_ENABLE_PM, APM_DEVICE_BALL, - 1, &eax)) + enable, &eax)) return (eax >> 8) & 0xff; - apm_bios_info.flags &= ~APM_BIOS_DISABLED; + if (enable) + apm_bios_info.flags &= ~APM_BIOS_DISABLED; + else + apm_bios_info.flags |= APM_BIOS_DISABLED; return APM_SUCCESS; } -#endif static int apm_get_power_status(u_short *status, u_short *bat, u_short *life) { @@ -632,12 +710,21 @@ } #endif -static int __init apm_engage_power_management(u_short device) +static int apm_engage_power_management(u_short device, int enable) { u32 eax; - if (apm_bios_call_simple(APM_FUNC_ENGAGE_PM, device, 1, &eax)) + if ((enable == 0) && (device == APM_DEVICE_ALL) + && (apm_bios_info.flags & APM_BIOS_DISABLED)) + return APM_DISABLED; + if (apm_bios_call_simple(APM_FUNC_ENGAGE_PM, device, enable, &eax)) return (eax >> 8) & 0xff; + if (device == APM_DEVICE_ALL) { + if (enable) + apm_bios_info.flags &= ~APM_BIOS_DISENGAGED; + else + apm_bios_info.flags |= APM_BIOS_DISENGAGED; + } return APM_SUCCESS; } @@ -655,7 +742,6 @@ } #if defined(CONFIG_APM_DISPLAY_BLANK) && defined(CONFIG_VT) -/* Called from console driver -- must make sure apm_enabled. */ static int apm_console_blank(int blank) { int error; @@ -664,9 +750,13 @@ state = blank ? APM_STATE_STANDBY : APM_STATE_READY; /* Blank the first display device */ error = set_power_state(0x100, state); - if (error != APM_SUCCESS) + if ((error != APM_SUCCESS) && (error != APM_NO_ERROR)) { /* try to blank them all instead */ error = set_power_state(0x1ff, state); + if ((error != APM_SUCCESS) && (error != APM_NO_ERROR)) + /* try to blank device one instead */ + error = set_power_state(0x101, state); + } if ((error == APM_SUCCESS) || (error == APM_NO_ERROR)) return 1; apm_error("set display", error); @@ -674,20 +764,20 @@ } #endif -static int queue_empty(struct apm_bios_struct * as) +static int queue_empty(struct apm_user *as) { return as->event_head == as->event_tail; } -static apm_event_t get_queued_event(struct apm_bios_struct * as) +static apm_event_t get_queued_event(struct apm_user *as) { as->event_tail = (as->event_tail + 1) % APM_MAX_EVENTS; return as->events[as->event_tail]; } -static void queue_event(apm_event_t event, struct apm_bios_struct *sender) +static void queue_event(apm_event_t event, struct apm_user *sender) { - struct apm_bios_struct * as; + struct apm_user * as; if (user_list == NULL) return; @@ -751,18 +841,11 @@ #endif } -static void suspend(void) +static void reinit_timer(void) { - int err; #ifdef INIT_TIMER_AFTER_SUSPEND unsigned long flags; -#endif - get_time_diff(); - err = apm_set_power_state(APM_STATE_SUSPEND); - if ((err != APM_SUCCESS) && (err != APM_NO_ERROR)) - apm_error("suspend", err); -#ifdef INIT_TIMER_AFTER_SUSPEND save_flags(flags); cli(); /* set the clock to 100 Hz */ @@ -774,7 +857,27 @@ udelay(10); restore_flags(flags); #endif +} + +static int suspend(void) +{ + int err; + int ret; + struct apm_user *as; + + get_time_diff(); + err = apm_set_power_state(APM_STATE_SUSPEND); + reinit_timer(); set_time(); + ret = (err == APM_SUCCESS) || (err == APM_NO_ERROR); + if (!ret) + apm_error("suspend", err); + for (as = user_list; as != NULL; as = as->next) { + as->suspend_wait = 0; + as->suspend_result = (ret ? 0 : -EIO); + } + wake_up_interruptible(&apm_suspend_waitqueue); + return ret; } static void standby(void) @@ -806,15 +909,14 @@ return 0; } -static int send_event(apm_event_t event, apm_event_t undo, - struct apm_bios_struct *sender) +static int send_event(apm_event_t event, struct apm_user *sender) { switch (event) { case APM_SYS_SUSPEND: case APM_CRITICAL_SUSPEND: case APM_USER_SUSPEND: /* map all suspends to ACPI D3 */ - if (pm_send_request(PM_SUSPEND, (void*) 3)) { + if (pm_send_request(PM_SUSPEND, (void *)3)) { if (apm_bios_info.version > 0x100) apm_set_power_state(APM_STATE_REJECT); return 0; @@ -823,11 +925,7 @@ case APM_NORMAL_RESUME: case APM_CRITICAL_RESUME: /* map all resumes to ACPI D0 */ - if (pm_send_request(PM_RESUME, 0)) { - if (apm_bios_info.version > 0x100) - apm_set_power_state(APM_STATE_REJECT); - return 0; - } + (void) pm_send_request(PM_RESUME, (void *)0); break; } @@ -864,7 +962,7 @@ if (waiting_for_resume) break; #endif - if (send_event(event, APM_STANDBY_RESUME, NULL)) { + if (send_event(event, NULL)) { #ifdef CONFIG_APM_IGNORE_MULTIPLE_SUSPEND waiting_for_resume = 1; #endif @@ -888,12 +986,12 @@ if (waiting_for_resume) break; #endif - if (send_event(event, APM_NORMAL_RESUME, NULL)) { + if (send_event(event, NULL)) { #ifdef CONFIG_APM_IGNORE_MULTIPLE_SUSPEND waiting_for_resume = 1; #endif if (suspends_pending <= 0) - suspend(); + (void) suspend(); } break; @@ -908,13 +1006,13 @@ ignore_bounce = 1; #endif set_time(); - send_event(event, 0, NULL); + send_event(event, NULL); break; case APM_CAPABILITY_CHANGE: case APM_LOW_BATTERY: case APM_POWER_STATUS_CHANGE: - send_event(event, 0, NULL); + send_event(event, NULL); break; case APM_UPDATE_TIME: @@ -922,7 +1020,7 @@ break; case APM_CRITICAL_SUSPEND: - suspend(); + (void) suspend(); break; } } @@ -930,18 +1028,18 @@ static void apm_event_handler(void) { - static int pending_count = 0; + static int pending_count = 4; int err; if ((standbys_pending > 0) || (suspends_pending > 0)) { - if ((apm_bios_info.version > 0x100) && (pending_count-- <= 0)) { + if ((apm_bios_info.version > 0x100) && (pending_count-- < 0)) { pending_count = 4; err = apm_set_power_state(APM_STATE_BUSY); if (err) apm_error("busy", err); } } else - pending_count = 0; + pending_count = 4; check_events(); } @@ -957,13 +1055,17 @@ static void apm_mainloop(void) { DECLARE_WAITQUEUE(wait, current); - apm_enabled = 1; + + if (smp_num_cpus > 1) + return; add_wait_queue(&apm_waitqueue, &wait); current->state = TASK_INTERRUPTIBLE; for (;;) { /* Nothing to do, just sleep for the timeout */ schedule_timeout(APM_CHECK_TIMEOUT); + if (exit_kapmd) + break; /* * Ok, check all events, check for idle (and mark us sleeping @@ -976,11 +1078,11 @@ continue; if (apm_do_idle()) { unsigned long start = jiffies; - do { + while (system_idle()) { apm_do_idle(); if (jiffies - start > APM_CHECK_TIMEOUT) break; - } while (system_idle()); + } apm_do_busy(); apm_event_handler(); } @@ -988,7 +1090,7 @@ } } -static int check_apm_bios_struct(struct apm_bios_struct *as, const char *func) +static int check_apm_user(struct apm_user *as, const char *func) { if ((as == NULL) || (as->magic != APM_BIOS_MAGIC)) { printk(KERN_ERR "apm: %s passed bad filp", func); @@ -999,13 +1101,13 @@ static ssize_t do_read(struct file *fp, char *buf, size_t count, loff_t *ppos) { - struct apm_bios_struct * as; + struct apm_user * as; int i; apm_event_t event; DECLARE_WAITQUEUE(wait, current); as = fp->private_data; - if (check_apm_bios_struct(as, "read")) + if (check_apm_user(as, "read")) return -EIO; if (count < sizeof(apm_event_t)) return -EINVAL; @@ -1053,10 +1155,10 @@ static unsigned int do_poll(struct file *fp, poll_table * wait) { - struct apm_bios_struct * as; + struct apm_user * as; as = fp->private_data; - if (check_apm_bios_struct(as, "select")) + if (check_apm_user(as, "poll")) return 0; poll_wait(fp, &apm_waitqueue, wait); if (!queue_empty(as)) @@ -1067,11 +1169,11 @@ static int do_ioctl(struct inode * inode, struct file *filp, u_int cmd, u_long arg) { - struct apm_bios_struct * as; - int send_ok = 1; + struct apm_user * as; + DECLARE_WAITQUEUE(wait, current); as = filp->private_data; - if (check_apm_bios_struct(as, "ioctl")) + if (check_apm_user(as, "ioctl")) return -EIO; if (!as->suser) return -EPERM; @@ -1081,11 +1183,9 @@ as->standbys_read--; as->standbys_pending--; standbys_pending--; - } - else - send_ok = send_event(APM_USER_STANDBY, - APM_STANDBY_RESUME, as); - if (send_ok && (standbys_pending <= 0)) + } else if (!send_event(APM_USER_STANDBY, as)) + return -EAGAIN; + if (standbys_pending <= 0) standby(); break; case APM_IOC_SUSPEND: @@ -1093,12 +1193,25 @@ as->suspends_read--; as->suspends_pending--; suspends_pending--; + } else if (!send_event(APM_USER_SUSPEND, as)) + return -EAGAIN; + if (suspends_pending <= 0) { + if (!suspend()) + return -EIO; + } else { + as->suspend_wait = 1; + add_wait_queue(&apm_suspend_waitqueue, &wait); + while (1) { + set_current_state(TASK_INTERRUPTIBLE); + if ((as->suspend_wait == 0) + || signal_pending(current)) + break; + schedule(); + } + current->state = TASK_RUNNING; + remove_wait_queue(&apm_suspend_waitqueue, &wait); + return as->suspend_result; } - else - send_ok = send_event(APM_USER_SUSPEND, - APM_NORMAL_RESUME, as); - if (send_ok && (suspends_pending <= 0)) - suspend(); break; default: return -EINVAL; @@ -1108,10 +1221,10 @@ static int do_release(struct inode * inode, struct file * filp) { - struct apm_bios_struct * as; + struct apm_user * as; as = filp->private_data; - if (check_apm_bios_struct(as, "release")) + if (check_apm_user(as, "release")) return 0; filp->private_data = NULL; if (as->standbys_pending > 0) { @@ -1122,12 +1235,12 @@ if (as->suspends_pending > 0) { suspends_pending -= as->suspends_pending; if (suspends_pending <= 0) - suspend(); + (void) suspend(); } if (user_list == as) user_list = as->next; else { - struct apm_bios_struct * as1; + struct apm_user * as1; for (as1 = user_list; (as1 != NULL) && (as1->next != as); @@ -1139,17 +1252,21 @@ as1->next = as->next; } kfree_s(as, sizeof(*as)); + MOD_DEC_USE_COUNT; return 0; } static int do_open(struct inode * inode, struct file * filp) { - struct apm_bios_struct * as; + struct apm_user * as; - as = (struct apm_bios_struct *)kmalloc(sizeof(*as), GFP_KERNEL); + MOD_INC_USE_COUNT; + + as = (struct apm_user *)kmalloc(sizeof(*as), GFP_KERNEL); if (as == NULL) { printk(KERN_ERR "apm: cannot allocate struct of size %d bytes", sizeof(*as)); + MOD_DEC_USE_COUNT; return -ENOMEM; } as->magic = APM_BIOS_MAGIC; @@ -1184,11 +1301,10 @@ int time_units = -1; char *units = "?"; - if (!apm_enabled) - return 0; p = buf; - if (!(error = apm_get_power_status(&bx, &cx, &dx))) { + if ((smp_num_cpus == 1) && + !(error = apm_get_power_status(&bx, &cx, &dx))) { ac_line_status = (bx >> 8) & 0xff; battery_status = bx & 0xff; if ((cx & 0xff) != 0xff) @@ -1264,6 +1380,11 @@ char * power_stat; char * bat_stat; + kapmd_running = 1; + + exit_files(current); /* daemonize doesn't do exit_files */ + daemonize(); + strcpy(current->comm, "kapmd"); sigfillset(¤t->blocked); @@ -1278,7 +1399,7 @@ apm_bios_info.version = 0x100; } } - if (debug) { + if (debug && (smp_num_cpus == 1)) { printk(KERN_INFO "apm: Connection version %d.%d\n", (apm_bios_info.version >> 8) & 0xff, apm_bios_info.version & 0xff); @@ -1328,32 +1449,51 @@ * is booted with PM disabled but not in the docking station. * Unfortunate ... */ - error = apm_enable_power_management(); + error = apm_enable_power_management(1); if (error) { apm_error("enable power management", error); return -1; } } #endif - if (((apm_bios_info.flags & APM_BIOS_DISENGAGED) == 0) + if ((apm_bios_info.flags & APM_BIOS_DISENGAGED) && (apm_bios_info.version > 0x0100)) { - if (apm_engage_power_management(0x0001) == APM_SUCCESS) - apm_bios_info.flags &= ~APM_BIOS_DISENGAGED; + error = apm_engage_power_management(APM_DEVICE_ALL, 1); + if (error) { + apm_error("engage power management", error); + return -1; + } } /* Install our power off handler.. */ - if (power_off_enabled) + if (power_off) pm_power_off = apm_power_off; #ifdef CONFIG_MAGIC_SYSRQ sysrq_power_off = apm_power_off; #endif #if defined(CONFIG_APM_DISPLAY_BLANK) && defined(CONFIG_VT) - console_blank_hook = apm_console_blank; + if (smp_num_cpus == 1) + console_blank_hook = apm_console_blank; #endif pm_active = 1; apm_mainloop(); + + pm_active = 0; + +#if defined(CONFIG_APM_DISPLAY_BLANK) && defined(CONFIG_VT) + if (smp_num_cpus == 1) + console_blank_hook = NULL; +#endif +#ifdef CONFIG_MAGIC_SYSRQ + sysrq_power_off = NULL; +#endif + if (power_off) + pm_power_off = NULL; + + kapmd_running = 0; + return 0; } @@ -1371,10 +1511,9 @@ str += 3; if (strncmp(str, "debug", 5) == 0) debug = !invert; - if (strncmp(str, "power-off", 9) == 0) - power_off_enabled = !invert; - if (strncmp(str, "smp-power-off", 13) == 0) - smp_hack = !invert; + if ((strncmp(str, "power-off", 9) == 0) || + (strncmp(str, "power_off", 9) == 0)) + power_off = !invert; str = strchr(str, ','); if (str != NULL) str += strspn(str, ", \t"); @@ -1455,7 +1594,10 @@ printk(KERN_NOTICE "apm: disabled on user request.\n"); APM_INIT_ERROR_RETURN; } - + if ((smp_num_cpus > 1) && !power_off) { + printk(KERN_NOTICE "apm: disabled - APM is not SMP safe.\n"); + APM_INIT_ERROR_RETURN; + } if (PM_IS_ACTIVE()) { printk(KERN_NOTICE "apm: overridden by ACPI.\n"); APM_INIT_ERROR_RETURN; @@ -1472,9 +1614,6 @@ _set_limit((char *)&gdt[APM_40 >> 3], 4095 - (0x40 << 4)); apm_bios_entry.offset = apm_bios_info.offset; -#ifdef CONFIG_APM_BAD_ENTRY_OFFSET - apm_bios_entry.offset &= 0xffff; -#endif apm_bios_entry.segment = APM_CS; set_base(gdt[APM_CS >> 3], __va((unsigned long)apm_bios_info.cseg << 4)); @@ -1483,18 +1622,16 @@ set_base(gdt[APM_DS >> 3], __va((unsigned long)apm_bios_info.dseg << 4)); #ifndef APM_RELAX_SEGMENTS - if (apm_bios_info.version == 0x100) + if (apm_bios_info.version == 0x100) { #endif - { /* For ASUS motherboard, Award BIOS rev 110 (and others?) */ _set_limit((char *)&gdt[APM_CS >> 3], 64 * 1024 - 1); /* For some unknown machine. */ _set_limit((char *)&gdt[APM_CS_16 >> 3], 64 * 1024 - 1); /* For the DEC Hinote Ultra CT475 (and others?) */ _set_limit((char *)&gdt[APM_DS >> 3], 64 * 1024 - 1); - } #ifndef APM_RELAX_SEGMENTS - else { + } else { _set_limit((char *)&gdt[APM_CS >> 3], (apm_bios_info.cseg_len - 1) & 0xffff); _set_limit((char *)&gdt[APM_CS_16 >> 3], @@ -1504,21 +1641,36 @@ } #endif -#ifdef CONFIG_SMP + create_proc_info_entry("apm", 0, NULL, apm_get_info); + + kernel_thread(apm, NULL, CLONE_FS | CLONE_FILES | CLONE_SIGHAND | SIGCHLD); + if (smp_num_cpus > 1) { - printk(KERN_NOTICE "apm: disabled - APM is not SMP safe.\n"); - if (smp_hack) - smp_hack = 2; + printk(KERN_NOTICE + "apm: disabled - APM is not SMP safe (power off active).\n"); APM_INIT_ERROR_RETURN; } -#endif - - create_proc_info_entry("apm", 0, 0, apm_get_info); misc_register(&apm_device); - kernel_thread(apm, NULL, CLONE_FS | CLONE_FILES | CLONE_SIGHAND | SIGCHLD); return 0; } -__initcall(apm_init); +static void __exit apm_exit(void) +{ + misc_deregister(&apm_device); + remove_proc_entry("apm", NULL); + exit_kapmd = 1; + while (kapmd_running) + schedule(); +} + +module_init(apm_init); +module_exit(apm_exit); + +MODULE_AUTHOR("Stephen Rothwell"); +MODULE_DESCRIPTION("Advanced Power Management"); +MODULE_PARM(debug, "i"); +MODULE_PARM_DESC(debug, "Enable debug mode"); + +EXPORT_NO_SYMBOLS; diff -u --recursive --new-file v2.3.46/linux/arch/i386/kernel/i386_ksyms.c linux/arch/i386/kernel/i386_ksyms.c --- v2.3.46/linux/arch/i386/kernel/i386_ksyms.c Thu Feb 10 17:11:03 2000 +++ linux/arch/i386/kernel/i386_ksyms.c Sun Feb 20 20:37:09 2000 @@ -10,6 +10,7 @@ #include #include #include +#include #include #include @@ -20,6 +21,7 @@ #include #include #include +#include extern void dump_thread(struct pt_regs *, struct user *); extern int dump_fpu(elf_fpregset_t *); @@ -34,6 +36,8 @@ EXPORT_SYMBOL(drive_info); #endif +extern unsigned long get_cmos_time(void); + /* platform dependent support */ EXPORT_SYMBOL(boot_cpu_data); EXPORT_SYMBOL(EISA_bus); @@ -51,6 +55,9 @@ EXPORT_SYMBOL(kernel_thread); EXPORT_SYMBOL(pm_idle); EXPORT_SYMBOL(pm_power_off); +EXPORT_SYMBOL(get_cmos_time); +EXPORT_SYMBOL(apm_bios_info); +EXPORT_SYMBOL(gdt); EXPORT_SYMBOL_NOVERS(__down_failed); EXPORT_SYMBOL_NOVERS(__down_failed_interruptible); diff -u --recursive --new-file v2.3.46/linux/arch/i386/kernel/irq.c linux/arch/i386/kernel/irq.c --- v2.3.46/linux/arch/i386/kernel/irq.c Thu Feb 10 17:11:03 2000 +++ linux/arch/i386/kernel/irq.c Fri Feb 18 08:15:52 2000 @@ -713,6 +713,7 @@ if (!(status & IRQ_WAITING)) { irq_desc[i].status = status & ~IRQ_AUTODETECT; irq_desc[i].handler->shutdown(i); + continue; } if (i < 32) diff -u --recursive --new-file v2.3.46/linux/arch/i386/kernel/microcode.c linux/arch/i386/kernel/microcode.c --- v2.3.46/linux/arch/i386/kernel/microcode.c Wed Feb 16 17:03:51 2000 +++ linux/arch/i386/kernel/microcode.c Fri Feb 18 15:11:13 2000 @@ -18,6 +18,8 @@ * * 1.0 16 February 2000, Tigran Aivazian * Initial release. + * 1.01 18 February 2000, Tigran Aivazian + * Added read() support + cleanups. */ #include @@ -31,7 +33,7 @@ #include #include -#define MICROCODE_VERSION "1.0" +#define MICROCODE_VERSION "1.01" MODULE_DESCRIPTION("CPU (P6) microcode update driver"); MODULE_AUTHOR("Tigran Aivazian "); @@ -40,11 +42,12 @@ /* VFS interface */ static int microcode_open(struct inode *, struct file *); static int microcode_release(struct inode *, struct file *); +static ssize_t microcode_read(struct file *, char *, size_t, loff_t *); static ssize_t microcode_write(struct file *, const char *, size_t, loff_t *); /* internal helpers to do the work */ -static void do_microcode_update(void); +static int do_microcode_update(void); static void do_update_one(void *); /* @@ -56,8 +59,10 @@ /* the actual array of microcode blocks, each 2048 bytes */ static struct microcode * microcode = NULL; static unsigned int microcode_num = 0; +static char *mc_applied = NULL; /* holds an array of applied microcode blocks */ static struct file_operations microcode_fops = { + read: microcode_read, write: microcode_write, open: microcode_open, release: microcode_release, @@ -71,21 +76,32 @@ static int __init microcode_init(void) { - /* write-only /proc/driver/microcode file, one day may become read-write.. */ - proc_microcode = create_proc_entry("microcode", S_IWUSR, proc_root_driver); + int size; + + proc_microcode = create_proc_entry("microcode", S_IWUSR|S_IRUSR, proc_root_driver); if (!proc_microcode) { - printk(KERN_ERR "microcode: can't create /proc/driver/microcode entry\n"); + printk(KERN_ERR "microcode: can't create /proc/driver/microcode\n"); return -ENOMEM; } proc_microcode->ops = µcode_inops; - printk(KERN_ERR "P6 Microcode Update Driver v%s registered\n", MICROCODE_VERSION); + size = smp_num_cpus * sizeof(struct microcode); + mc_applied = kmalloc(size, GFP_KERNEL); + if (!mc_applied) { + remove_proc_entry("microcode", proc_root_driver); + printk(KERN_ERR "microcode: can't allocate memory for saved microcode\n"); + return -ENOMEM; + } + memset(mc_applied, 0, size); /* so that reading from offsets corresponding to failed + update makes this obvious */ + printk(KERN_INFO "P6 Microcode Update Driver v%s registered\n", MICROCODE_VERSION); return 0; } static void __exit microcode_exit(void) { remove_proc_entry("microcode", proc_root_driver); - printk(KERN_ERR "P6 Microcode Update Driver v%s unregistered\n", MICROCODE_VERSION); + kfree(mc_applied); + printk(KERN_INFO "P6 Microcode Update Driver v%s unregistered\n", MICROCODE_VERSION); } module_init(microcode_init); @@ -116,23 +132,46 @@ return 0; } +/* a pointer to 'struct update_req' is passed to the IPI hanlder = do_update_one() + * update_req[cpu].err is set to 1 if update failed on 'cpu', 0 otherwise + * if err==0, microcode[update_req[cpu].slot] points to applied block of microcode + */ +struct update_req { + int err; + int slot; +} update_req[NR_CPUS]; -static void do_microcode_update(void) +static int do_microcode_update(void) { - if (smp_call_function(do_update_one, NULL, 1, 0) != 0) + int i, error = 0, err; + struct microcode *m; + + if (smp_call_function(do_update_one, (void *)update_req, 1, 1) != 0) panic("do_microcode_update(): timed out waiting for other CPUs\n"); - do_update_one(NULL); + do_update_one((void *)update_req); + + for (i=0; ierr = 1; /* be pessimistic */ if (c->x86_vendor != X86_VENDOR_INTEL || c->x86 < 6) return; @@ -153,7 +192,7 @@ if (microcode[i].rev <= rev) { printk(KERN_ERR "microcode: CPU%d not 'upgrading' to earlier revision" - " %d (current=%d)\n", id, microcode[i].rev, rev); + " %d (current=%d)\n", cpu_num, microcode[i].rev, rev); } else { int sum = 0; struct microcode *m = µcode[i]; @@ -163,29 +202,47 @@ sum += *sump; if (sum != 0) { printk(KERN_ERR "microcode: CPU%d aborting, " - "bad checksum\n", id); + "bad checksum\n", cpu_num); break; } + wrmsr(0x79, (unsigned int)(m->bits), 0); __asm__ __volatile__ ("cpuid"); rdmsr(0x8B, val[0], val[1]); + + req->err = 0; + req->slot = i; printk(KERN_ERR "microcode: CPU%d microcode updated " - "from revision %d to %d\n", id, rev, val[1]); + "from revision %d to %d, date=%08x\n", + cpu_num, rev, val[1], m->date); } break; } } +static ssize_t microcode_read(struct file *file, char *buf, size_t len, loff_t *ppos) +{ + size_t fsize = smp_num_cpus * sizeof(struct microcode); + + if (!proc_microcode->size || *ppos >= fsize) + return 0; /* EOF */ + if (*ppos + len > fsize) + len = fsize - *ppos; + if (copy_to_user(buf, mc_applied + *ppos, len)) + return -EFAULT; + *ppos += len; + return len; +} + static ssize_t microcode_write(struct file *file, const char *buf, size_t len, loff_t *ppos) { + ssize_t ret; + if (len % sizeof(struct microcode) != 0) { printk(KERN_ERR "microcode: can only write in N*%d bytes units\n", sizeof(struct microcode)); return -EINVAL; - return -EINVAL; } - if (!capable(CAP_SYS_RAWIO)) - return -EPERM; lock_kernel(); microcode_num = len/sizeof(struct microcode); microcode = vmalloc(len); @@ -198,8 +255,12 @@ unlock_kernel(); return -EFAULT; } - do_microcode_update(); + ret = do_microcode_update(); + if (!ret) { + proc_microcode->size = smp_num_cpus * sizeof(struct microcode); + ret = (ssize_t)len; + } vfree(microcode); unlock_kernel(); - return len; + return ret; } diff -u --recursive --new-file v2.3.46/linux/arch/i386/kernel/mtrr.c linux/arch/i386/kernel/mtrr.c --- v2.3.46/linux/arch/i386/kernel/mtrr.c Wed Feb 16 17:03:51 2000 +++ linux/arch/i386/kernel/mtrr.c Sun Feb 20 20:23:20 2000 @@ -1,6 +1,6 @@ /* Generic MTRR (Memory Type Range Register) driver. - Copyright (C) 1997-1999 Richard Gooch + Copyright (C) 1997-2000 Richard Gooch This library is free software; you can redistribute it and/or modify it under the terms of the GNU Library General Public @@ -224,6 +224,10 @@ success. 19991008 Manfred Spraul replaced spin_lock_reschedule() with a normal semaphore. + v1.36 + 20000221 Richard Gooch + Compile fix if procfs and devfs not enabled. + Formatting changes. */ #include #include @@ -261,7 +265,7 @@ #include #include -#define MTRR_VERSION "1.35 (19990512)" +#define MTRR_VERSION "1.36 (20000221)" #define TRUE 1 #define FALSE 0 @@ -484,8 +488,9 @@ unsigned long dummy, mask_lo, base_lo; rdmsr (MTRRphysMask_MSR(reg), mask_lo, dummy); - if ((mask_lo & 0x800) == 0) { - /* Invalid (i.e. free) range. */ + if ( (mask_lo & 0x800) == 0 ) + { + /* Invalid (i.e. free) range */ *base = 0; *size = 0; *type = 0; @@ -541,22 +546,26 @@ *size = 0; /* Bit 0 is Cache Enable on ARR7, Cache Disable on ARR0-ARR6 */ - if (reg < 7) { - switch (rcr) { - case 1: *type = MTRR_TYPE_UNCACHABLE; break; - case 8: *type = MTRR_TYPE_WRBACK; break; - case 9: *type = MTRR_TYPE_WRCOMB; break; - case 24: - default: *type = MTRR_TYPE_WRTHROUGH; break; - } - } else { - switch (rcr) { - case 0: *type = MTRR_TYPE_UNCACHABLE; break; - case 8: *type = MTRR_TYPE_WRCOMB; break; - case 9: *type = MTRR_TYPE_WRBACK; break; - case 25: - default: *type = MTRR_TYPE_WRTHROUGH; break; - } + if (reg < 7) + { + switch (rcr) + { + case 1: *type = MTRR_TYPE_UNCACHABLE; break; + case 8: *type = MTRR_TYPE_WRBACK; break; + case 9: *type = MTRR_TYPE_WRCOMB; break; + case 24: + default: *type = MTRR_TYPE_WRTHROUGH; break; + } + } else + { + switch (rcr) + { + case 0: *type = MTRR_TYPE_UNCACHABLE; break; + case 8: *type = MTRR_TYPE_WRCOMB; break; + case 9: *type = MTRR_TYPE_WRBACK; break; + case 25: + default: *type = MTRR_TYPE_WRTHROUGH; break; + } } } /* End Function cyrix_get_arr */ @@ -657,20 +666,24 @@ size &= 0x7fff; /* make sure arr_size <= 14 */ for(arr_size = 0; size; arr_size++, size >>= 1); - if (reg<7) { - switch (type) { - case MTRR_TYPE_UNCACHABLE: arr_type = 1; break; - case MTRR_TYPE_WRCOMB: arr_type = 9; break; - case MTRR_TYPE_WRTHROUGH: arr_type = 24; break; - default: arr_type = 8; break; - } - } else { - switch (type) { - case MTRR_TYPE_UNCACHABLE: arr_type = 0; break; - case MTRR_TYPE_WRCOMB: arr_type = 8; break; - case MTRR_TYPE_WRTHROUGH: arr_type = 25; break; - default: arr_type = 9; break; - } + if (reg<7) + { + switch (type) { + case MTRR_TYPE_UNCACHABLE: arr_type = 1; break; + case MTRR_TYPE_WRCOMB: arr_type = 9; break; + case MTRR_TYPE_WRTHROUGH: arr_type = 24; break; + default: arr_type = 8; break; + } + } + else + { + switch (type) + { + case MTRR_TYPE_UNCACHABLE: arr_type = 0; break; + case MTRR_TYPE_WRCOMB: arr_type = 8; break; + case MTRR_TYPE_WRTHROUGH: arr_type = 25; break; + default: arr_type = 9; break; + } } if (do_safe) set_mtrr_prepare (&ctxt); @@ -783,16 +796,18 @@ int changed = FALSE; rdmsr(MTRRphysBase_MSR(index), lo, hi); - if ((vr->base_lo & 0xfffff0ffUL) != (lo & 0xfffff0ffUL) - || (vr->base_hi & 0xfUL) != (hi & 0xfUL)) { - wrmsr(MTRRphysBase_MSR(index), vr->base_lo, vr->base_hi); + if ( (vr->base_lo & 0xfffff0ffUL) != (lo & 0xfffff0ffUL) + || (vr->base_hi & 0xfUL) != (hi & 0xfUL) ) + { + wrmsr (MTRRphysBase_MSR(index), vr->base_lo, vr->base_hi); changed = TRUE; } - rdmsr(MTRRphysMask_MSR(index), lo, hi); + rdmsr (MTRRphysMask_MSR(index), lo, hi); - if ((vr->mask_lo & 0xfffff800UL) != (lo & 0xfffff800UL) - || (vr->mask_hi & 0xfUL) != (hi & 0xfUL)) { + if ( (vr->mask_lo & 0xfffff800UL) != (lo & 0xfffff800UL) + || (vr->mask_hi & 0xfUL) != (hi & 0xfUL) ) + { wrmsr(MTRRphysMask_MSR(index), vr->mask_lo, vr->mask_hi); changed = TRUE; } @@ -820,22 +835,27 @@ unsigned long lo, hi; rdmsr(MTRRfix64K_00000_MSR, lo, hi); - if (p[0] != lo || p[1] != hi) { - wrmsr(MTRRfix64K_00000_MSR, p[0], p[1]); + if (p[0] != lo || p[1] != hi) + { + wrmsr (MTRRfix64K_00000_MSR, p[0], p[1]); changed = TRUE; } - for (i = 0; i < 2; i++) { - rdmsr(MTRRfix16K_80000_MSR + i, lo, hi); - if (p[2 + i*2] != lo || p[3 + i*2] != hi) { - wrmsr(MTRRfix16K_80000_MSR + i, p[2 + i*2], p[3 + i*2]); + for (i = 0; i < 2; i++) + { + rdmsr (MTRRfix16K_80000_MSR + i, lo, hi); + if (p[2 + i*2] != lo || p[3 + i*2] != hi) + { + wrmsr (MTRRfix16K_80000_MSR + i, p[2 + i*2], p[3 + i*2]); changed = TRUE; } } - for (i = 0; i < 8; i++) { - rdmsr(MTRRfix4K_C0000_MSR + i, lo, hi); - if (p[6 + i*2] != lo || p[7 + i*2] != hi) { + for (i = 0; i < 8; i++) + { + rdmsr (MTRRfix4K_C0000_MSR + i, lo, hi); + if (p[6 + i*2] != lo || p[7 + i*2] != hi) + { wrmsr(MTRRfix4K_C0000_MSR + i, p[6 + i*2], p[7 + i*2]); changed = TRUE; } @@ -903,8 +923,8 @@ change_mask |= MTRR_CHANGE_MASK_FIXED; /* Set_mtrr_restore restores the old value of MTRRdefType, so to set it we fiddle with the saved value */ - if ((ctxt->deftype_lo & 0xff) != state->def_type - || ((ctxt->deftype_lo & 0xc00) >> 10) != state->enabled) + if ( (ctxt->deftype_lo & 0xff) != state->def_type + || ( (ctxt->deftype_lo & 0xc00) >> 10 ) != state->enabled) { ctxt->deftype_lo |= (state->def_type | state->enabled << 10); change_mask |= MTRR_CHANGE_MASK_DEFTYPE; @@ -1057,11 +1077,14 @@ unsigned long lbase, lsize; /* If we are to set up a region >32M then look at ARR7 immediately */ - if (size > 0x2000000UL) { + if (size > 0x2000000UL) + { cyrix_get_arr (7, &lbase, &lsize, <ype); if (lsize < 1) return 7; - /* else try ARR0-ARR6 first */ - } else { + /* Else try ARR0-ARR6 first */ + } + else + { for (i = 0; i < 7; i++) { cyrix_get_arr (i, &lbase, &lsize, <ype); @@ -1099,29 +1122,32 @@ switch (boot_cpu_data.x86_vendor) { case X86_VENDOR_AMD: - if (boot_cpu_data.x86 < 6) { /* pre-Athlon CPUs */ - /* Apply the K6 block alignment and size rules + if (boot_cpu_data.x86 < 6) + { /* pre-Athlon CPUs */ + /* Apply the K6 block alignment and size rules In order o Uncached or gathering only o 128K or bigger block o Power of 2 block o base suitably aligned to the power */ - if (type > MTRR_TYPE_WRCOMB || size < (1 << 17) || - (size & ~(size-1))-size || (base & (size-1))) - return -EINVAL; + if ( type > MTRR_TYPE_WRCOMB || size < (1 << 17) || + (size & ~(size-1))-size || ( base & (size-1) ) ) + return -EINVAL; break; - } /* else fall through */ + } + /* Else fall through */ case X86_VENDOR_INTEL: - /* Double check for Intel, we may run on Athlon. */ - if (boot_cpu_data.x86_vendor == X86_VENDOR_INTEL) { - /* For Intel PPro stepping <= 7, must be 4 MiB aligned */ - if ( (boot_cpu_data.x86 == 6) && (boot_cpu_data.x86_model == 1) && - (boot_cpu_data.x86_mask <= 7) && ( base & ( (1 << 22) - 1 ) ) ) - { - printk ("mtrr: base(0x%lx) is not 4 MiB aligned\n", base); - return -EINVAL; - } + /* Double check for Intel, we may run on Athlon */ + if (boot_cpu_data.x86_vendor == X86_VENDOR_INTEL) + { + /* For Intel PPro stepping <= 7, must be 4 MiB aligned */ + if ( (boot_cpu_data.x86 == 6) && (boot_cpu_data.x86_model == 1) && + (boot_cpu_data.x86_mask <= 7) && ( base & ( (1 << 22) -1 ) ) ) + { + printk ("mtrr: base(0x%lx) is not 4 MiB aligned\n", base); + return -EINVAL; + } } /* Fall through */ case X86_VENDOR_CYRIX: @@ -1236,7 +1262,7 @@ if ( !(boot_cpu_data.x86_capability & X86_FEATURE_MTRR) ) return -ENODEV; max = get_num_var_ranges (); - down(&main_lock); + down (&main_lock); if (reg < 0) { /* Search for existing MTRR */ @@ -1258,15 +1284,15 @@ } if (reg >= max) { - up(&main_lock); + up (&main_lock); printk ("mtrr: register: %d too big\n", reg); return -EINVAL; } if (boot_cpu_data.x86_vendor == X86_VENDOR_CYRIX) { - if ((reg == 3) && arr3_protected) + if ( (reg == 3) && arr3_protected ) { - up(&main_lock); + up (&main_lock); printk ("mtrr: ARR3 cannot be changed\n"); return -EINVAL; } @@ -1274,19 +1300,19 @@ (*get_mtrr) (reg, &lbase, &lsize, <ype); if (lsize < 1) { - up(&main_lock); + up (&main_lock); printk ("mtrr: MTRR %d not used\n", reg); return -EINVAL; } if (usage_table[reg] < 1) { - up(&main_lock); + up (&main_lock); printk ("mtrr: reg: %d has count=0\n", reg); return -EINVAL; } if (--usage_table[reg] < 1) set_mtrr (reg, 0, 0, 0); compute_ascii (); - up(&main_lock); + up (&main_lock); return reg; } /* End Function mtrr_del */ @@ -1473,16 +1499,17 @@ static struct file_operations mtrr_fops = { - read: mtrr_read, - write: mtrr_write, - ioctl: mtrr_ioctl, - release: mtrr_close, + read: mtrr_read, + write: mtrr_write, + ioctl: mtrr_ioctl, + release: mtrr_close, }; # ifdef CONFIG_PROC_FS -static struct inode_operations proc_mtrr_inode_operations = { - &mtrr_fops, /* default property file-ops */ +static struct inode_operations proc_mtrr_inode_operations = +{ + &mtrr_fops, /* default property file-ops */ }; static struct proc_dir_entry *proc_root_mtrr; @@ -1538,15 +1565,17 @@ #ifdef __SMP__ -typedef struct { - unsigned long base; - unsigned long size; - mtrr_type type; +typedef struct +{ + unsigned long base; + unsigned long size; + mtrr_type type; } arr_state_t; -arr_state_t arr_state[8] __initdata = { - {0UL,0UL,0UL}, {0UL,0UL,0UL}, {0UL,0UL,0UL}, {0UL,0UL,0UL}, - {0UL,0UL,0UL}, {0UL,0UL,0UL}, {0UL,0UL,0UL}, {0UL,0UL,0UL} +arr_state_t arr_state[8] __initdata = +{ + {0UL,0UL,0UL}, {0UL,0UL,0UL}, {0UL,0UL,0UL}, {0UL,0UL,0UL}, + {0UL,0UL,0UL}, {0UL,0UL,0UL}, {0UL,0UL,0UL}, {0UL,0UL,0UL} }; unsigned char ccr_state[7] __initdata = { 0, 0, 0, 0, 0, 0, 0 }; @@ -1604,31 +1633,35 @@ ccr[5] = getCx86 (CX86_CCR5); ccr[6] = getCx86 (CX86_CCR6); - if (ccr[3] & 1) { - ccrc[3] = 1; - arr3_protected = 1; - } else { - /* Disable SMM mode (bit 1), access to SMM memory (bit 2) and - * access to SMM memory through ARR3 (bit 7). - */ - if (ccr[1] & 0x80) { ccr[1] &= 0x7f; ccrc[1] |= 0x80; } - if (ccr[1] & 0x04) { ccr[1] &= 0xfb; ccrc[1] |= 0x04; } - if (ccr[1] & 0x02) { ccr[1] &= 0xfd; ccrc[1] |= 0x02; } - arr3_protected = 0; - if (ccr[6] & 0x02) { - ccr[6] &= 0xfd; ccrc[6] = 1; /* Disable write protection of ARR3. */ - setCx86 (CX86_CCR6, ccr[6]); - } - /* Disable ARR3. This is safe now that we disabled SMM. */ - /* cyrix_set_arr_up (3, 0, 0, 0, FALSE); */ + if (ccr[3] & 1) + { + ccrc[3] = 1; + arr3_protected = 1; + } + else + { + /* Disable SMM mode (bit 1), access to SMM memory (bit 2) and + * access to SMM memory through ARR3 (bit 7). + */ + if (ccr[1] & 0x80) { ccr[1] &= 0x7f; ccrc[1] |= 0x80; } + if (ccr[1] & 0x04) { ccr[1] &= 0xfb; ccrc[1] |= 0x04; } + if (ccr[1] & 0x02) { ccr[1] &= 0xfd; ccrc[1] |= 0x02; } + arr3_protected = 0; + if (ccr[6] & 0x02) { + ccr[6] &= 0xfd; ccrc[6] = 1; /* Disable write protection of ARR3 */ + setCx86 (CX86_CCR6, ccr[6]); + } + /* Disable ARR3. This is safe now that we disabled SMM. */ + /* cyrix_set_arr_up (3, 0, 0, 0, FALSE); */ } /* If we changed CCR1 in memory, change it in the processor, too. */ if (ccrc[1]) setCx86 (CX86_CCR1, ccr[1]); /* Enable ARR usage by the processor */ - if (!(ccr[5] & 0x20)) { - ccr[5] |= 0x20; ccrc[5] = 1; - setCx86 (CX86_CCR5, ccr[5]); + if (!(ccr[5] & 0x20)) + { + ccr[5] |= 0x20; ccrc[5] = 1; + setCx86 (CX86_CCR5, ccr[5]); } #ifdef __SMP__ @@ -1680,11 +1713,14 @@ switch (boot_cpu_data.x86_vendor) { case X86_VENDOR_AMD: - if (boot_cpu_data.x86 < 6) { /* pre-Athlon CPUs */ - get_mtrr = amd_get_mtrr; - set_mtrr_up = amd_set_mtrr_up; - break; - } /* else fall through */ + if (boot_cpu_data.x86 < 6) + { + /* pre-Athlon CPUs */ + get_mtrr = amd_get_mtrr; + set_mtrr_up = amd_set_mtrr_up; + break; + } + /* Else fall through */ case X86_VENDOR_INTEL: get_mtrr = intel_get_mtrr; set_mtrr_up = intel_set_mtrr_up; @@ -1713,7 +1749,7 @@ switch (boot_cpu_data.x86_vendor) { case X86_VENDOR_AMD: - if (boot_cpu_data.x86 < 6) break; /* pre-Athlon CPUs */ + if (boot_cpu_data.x86 < 6) break; /* Pre-Athlon CPUs */ case X86_VENDOR_INTEL: get_mtrr_state (&smp_mtrr_state); break; @@ -1751,7 +1787,7 @@ switch (boot_cpu_data.x86_vendor) { case X86_VENDOR_AMD: - /* Just for robustness: pre-Athlon CPUs cannot do SMP. */ + /* Just for robustness: pre-Athlon CPUs cannot do SMP */ if (boot_cpu_data.x86 < 6) break; case X86_VENDOR_INTEL: intel_mtrr_init_secondary_cpu (); @@ -1775,17 +1811,17 @@ int __init mtrr_init(void) { if ( !(boot_cpu_data.x86_capability & X86_FEATURE_MTRR) ) return 0; -# ifdef __SMP__ +#ifdef __SMP__ switch (boot_cpu_data.x86_vendor) { case X86_VENDOR_AMD: - if (boot_cpu_data.x86 < 6) break; /* pre-Athlon CPUs */ + if (boot_cpu_data.x86 < 6) break; /* Pre-Athlon CPUs */ case X86_VENDOR_INTEL: finalize_mtrr_state (&smp_mtrr_state); mtrr_state_warn (smp_changes_mask); break; } -# else /* __SMP__ */ +#else /* __SMP__ */ mtrr_setup (); switch (boot_cpu_data.x86_vendor) { @@ -1796,15 +1832,17 @@ centaur_mcr_init (); break; } -# endif /* !__SMP__ */ +#endif /* !__SMP__ */ -# ifdef CONFIG_PROC_FS +#ifdef CONFIG_PROC_FS proc_root_mtrr = create_proc_entry ("mtrr", S_IWUSR | S_IRUGO, &proc_root); proc_root_mtrr->ops = &proc_mtrr_inode_operations; -#endif +#endif +#ifdev CONFIG_DEVFS_FS devfs_handle = devfs_register (NULL, "cpu/mtrr", 0, DEVFS_FL_DEFAULT, 0, 0, S_IFREG | S_IRUGO | S_IWUSR, 0, 0, &mtrr_fops, NULL); +#endif init_table (); return 0; } /* End Function mtrr_init */ diff -u --recursive --new-file v2.3.46/linux/arch/i386/kernel/process.c linux/arch/i386/kernel/process.c --- v2.3.46/linux/arch/i386/kernel/process.c Thu Feb 10 17:11:03 2000 +++ linux/arch/i386/kernel/process.c Sun Feb 20 20:37:09 2000 @@ -48,16 +48,6 @@ int hlt_counter=0; -void disable_hlt(void) -{ - hlt_counter++; -} - -void enable_hlt(void) -{ - hlt_counter--; -} - /* * Powermanagement idle function, if any.. */ @@ -68,6 +58,16 @@ */ void (*pm_power_off)(void) = NULL; +void disable_hlt(void) +{ + hlt_counter++; +} + +void enable_hlt(void) +{ + hlt_counter--; +} + /* * We use this if we don't have any better * idle routine.. @@ -293,7 +293,7 @@ void machine_restart(char * __unused) { -#if __SMP__ +#if CONFIG_SMP /* * Stop all CPUs and turn off local APICs and the IO-APIC, so * other OSs see a clean IRQ state. diff -u --recursive --new-file v2.3.46/linux/arch/sparc/defconfig linux/arch/sparc/defconfig --- v2.3.46/linux/arch/sparc/defconfig Thu Feb 10 17:11:05 2000 +++ linux/arch/sparc/defconfig Fri Feb 18 14:51:22 2000 @@ -259,18 +259,17 @@ # CONFIG_JOLIET is not set CONFIG_MINIX_FS=m # CONFIG_NTFS_FS is not set -# CONFIG_NTFS_RW is not set CONFIG_HPFS_FS=m CONFIG_PROC_FS=y +# CONFIG_DEVFS_FS is not set +# CONFIG_DEVFS_DEBUG is not set CONFIG_DEVPTS_FS=y # CONFIG_QNX4FS_FS is not set -# CONFIG_QNX4FS_RW is not set CONFIG_ROMFS_FS=m CONFIG_EXT2_FS=y CONFIG_SYSV_FS=m # CONFIG_SYSV_FS_WRITE is not set # CONFIG_UDF_FS is not set -# CONFIG_UDF_RW is not set CONFIG_UFS_FS=m # CONFIG_UFS_FS_WRITE is not set diff -u --recursive --new-file v2.3.46/linux/arch/sparc/kernel/ioport.c linux/arch/sparc/kernel/ioport.c --- v2.3.46/linux/arch/sparc/kernel/ioport.c Wed Feb 16 17:03:51 2000 +++ linux/arch/sparc/kernel/ioport.c Fri Feb 18 15:07:20 2000 @@ -1,4 +1,4 @@ -/* $Id: ioport.c,v 1.32 2000/02/12 03:04:48 zaitcev Exp $ +/* $Id: ioport.c,v 1.34 2000/02/18 13:48:48 davem Exp $ * ioport.c: Simple io mapping allocator. * * Copyright (C) 1995 David S. Miller (davem@caip.rutgers.edu) @@ -348,7 +348,7 @@ * CPU view of this memory may be inconsistent with * a device view and explicit flushing is necessary. */ -u32 sbus_map_single(struct sbus_dev *sdev, void *va, long len) +u32 sbus_map_single(struct sbus_dev *sdev, void *va, long len, int direction) { #if 0 /* This is the version that abuses consistent space */ unsigned long len_total = (len + PAGE_SIZE-1) & PAGE_MASK; @@ -395,7 +395,7 @@ #endif } -void sbus_unmap_single(struct sbus_dev *sdev, u32 ba, long n) +void sbus_unmap_single(struct sbus_dev *sdev, u32 ba, long n, int direction) { #if 0 /* This is the version that abuses consistent space */ struct resource *res; @@ -424,7 +424,7 @@ #endif } -int sbus_map_sg(struct sbus_dev *sdev, struct scatterlist *sg, int n) +int sbus_map_sg(struct sbus_dev *sdev, struct scatterlist *sg, int n, int direction) { mmu_get_scsi_sgl(sg, n, sdev->bus); @@ -435,14 +435,14 @@ return n; } -void sbus_unmap_sg(struct sbus_dev *sdev, struct scatterlist *sg, int n) +void sbus_unmap_sg(struct sbus_dev *sdev, struct scatterlist *sg, int n, int direction) { mmu_release_scsi_sgl(sg, n, sdev->bus); } /* */ -void sbus_dma_sync_single(struct sbus_dev *sdev, u32 ba, long size) +void sbus_dma_sync_single(struct sbus_dev *sdev, u32 ba, long size, int direction) { unsigned long va; struct resource *res; @@ -456,7 +456,7 @@ mmu_inval_dma_area(va, (size + PAGE_SIZE-1) & PAGE_MASK); } -void sbus_dma_sync_sg(struct sbus_dev *sdev, struct scatterlist *sg, int n) +void sbus_dma_sync_sg(struct sbus_dev *sdev, struct scatterlist *sg, int n, int direction) { printk("sbus_dma_sync_sg: not implemented yet\n"); } @@ -577,8 +577,10 @@ * Once the device is given the dma address, the device owns this memory * until either pci_unmap_single or pci_dma_sync_single is performed. */ -dma_addr_t pci_map_single(struct pci_dev *hwdev, void *ptr, size_t size) +dma_addr_t pci_map_single(struct pci_dev *hwdev, void *ptr, size_t size, int direction) { + if (direction == PCI_DMA_NONE) + BUG(); return virt_to_bus(ptr); } @@ -589,8 +591,10 @@ * After this call, reads by the cpu to the buffer are guarenteed to see * whatever the device wrote there. */ -void pci_unmap_single(struct pci_dev *hwdev, dma_addr_t dma_addr, size_t size) +void pci_unmap_single(struct pci_dev *hwdev, dma_addr_t dma_addr, size_t size, int direction) { + if (direction == PCI_DMA_NONE) + BUG(); /* Nothing to do... */ } @@ -609,9 +613,13 @@ * Device ownership issues as mentioned above for pci_map_single are * the same here. */ -int pci_map_sg(struct pci_dev *hwdev, struct scatterlist *sg, int nents) +int pci_map_sg(struct pci_dev *hwdev, struct scatterlist *sg, int nents, int direction) { int n; + + if (direction == PCI_DMA_NONE) + BUG(); + for (n = 0; n < nents; n++) { sg->dvma_address = virt_to_bus(sg->address); sg->dvma_length = sg->length; @@ -624,8 +632,10 @@ * Again, cpu read rules concerning calls here are the same as for * pci_unmap_single() above. */ -void pci_unmap_sg(struct pci_dev *hwdev, struct scatterlist *sg, int nhwents) +void pci_unmap_sg(struct pci_dev *hwdev, struct scatterlist *sg, int nhwents, int direction) { + if (direction == PCI_DMA_NONE) + BUG(); /* Nothing to do... */ } @@ -638,8 +648,10 @@ * next point you give the PCI dma address back to the card, the * device again owns the buffer. */ -void pci_dma_sync_single(struct pci_dev *hwdev, dma_addr_t ba, size_t size) +void pci_dma_sync_single(struct pci_dev *hwdev, dma_addr_t ba, size_t size, int direction) { + if (direction == PCI_DMA_NONE) + BUG(); mmu_inval_dma_area((unsigned long)bus_to_virt(ba), (size + PAGE_SIZE-1) & PAGE_MASK); } @@ -650,8 +662,10 @@ * The same as pci_dma_sync_single but for a scatter-gather list, * same rules and usage. */ -void pci_dma_sync_sg(struct pci_dev *hwdev, struct scatterlist *sg, int nents) +void pci_dma_sync_sg(struct pci_dev *hwdev, struct scatterlist *sg, int nents, int direction) { + if (direction == PCI_DMA_NONE) + BUG(); while (nents) { --nents; mmu_inval_dma_area((unsigned long)sg->address, diff -u --recursive --new-file v2.3.46/linux/arch/sparc/kernel/sparc_ksyms.c linux/arch/sparc/kernel/sparc_ksyms.c --- v2.3.46/linux/arch/sparc/kernel/sparc_ksyms.c Wed Feb 16 17:03:51 2000 +++ linux/arch/sparc/kernel/sparc_ksyms.c Sun Feb 20 08:48:45 2000 @@ -1,4 +1,4 @@ -/* $Id: sparc_ksyms.c,v 1.90 2000/02/13 09:52:54 anton Exp $ +/* $Id: sparc_ksyms.c,v 1.91 2000/02/18 20:23:24 davem Exp $ * arch/sparc/kernel/ksyms.c: Sparc specific ksyms support. * * Copyright (C) 1996 David S. Miller (davem@caip.rutgers.edu) @@ -190,6 +190,8 @@ EXPORT_SYMBOL(sbus_unmap_sg); EXPORT_SYMBOL(sbus_dma_sync_single); EXPORT_SYMBOL(sbus_dma_sync_sg); +EXPORT_SYMBOL(sbus_iounmap); +EXPORT_SYMBOL(sbus_ioremap); #endif #if CONFIG_PCI /* We do not have modular drivers for PCI devices yet. */ diff -u --recursive --new-file v2.3.46/linux/arch/sparc/kernel/sys_sparc.c linux/arch/sparc/kernel/sys_sparc.c --- v2.3.46/linux/arch/sparc/kernel/sys_sparc.c Wed Feb 16 17:03:51 2000 +++ linux/arch/sparc/kernel/sys_sparc.c Thu Feb 17 09:26:30 2000 @@ -1,4 +1,4 @@ -/* $Id: sys_sparc.c,v 1.60 2000/02/08 20:24:18 davem Exp $ +/* $Id: sys_sparc.c,v 1.61 2000/02/16 07:31:29 davem Exp $ * linux/arch/sparc/kernel/sys_sparc.c * * This file contains various random system calls that diff -u --recursive --new-file v2.3.46/linux/arch/sparc/kernel/sys_sunos.c linux/arch/sparc/kernel/sys_sunos.c --- v2.3.46/linux/arch/sparc/kernel/sys_sunos.c Wed Feb 16 17:03:51 2000 +++ linux/arch/sparc/kernel/sys_sunos.c Thu Feb 17 09:26:30 2000 @@ -1,4 +1,4 @@ -/* $Id: sys_sunos.c,v 1.112 2000/01/29 07:40:11 davem Exp $ +/* $Id: sys_sunos.c,v 1.113 2000/02/16 07:31:29 davem Exp $ * sys_sunos.c: SunOS specific syscall compatibility support. * * Copyright (C) 1995 David S. Miller (davem@caip.rutgers.edu) diff -u --recursive --new-file v2.3.46/linux/arch/sparc/kernel/systbls.S linux/arch/sparc/kernel/systbls.S --- v2.3.46/linux/arch/sparc/kernel/systbls.S Wed Feb 16 17:03:51 2000 +++ linux/arch/sparc/kernel/systbls.S Thu Feb 17 09:26:30 2000 @@ -1,4 +1,4 @@ -/* $Id: systbls.S,v 1.93 2000/01/29 16:41:18 jj Exp $ +/* $Id: systbls.S,v 1.94 2000/02/16 07:31:30 davem Exp $ * systbls.S: System call entry point tables for OS compatibility. * The native Linux system call table lives here also. * diff -u --recursive --new-file v2.3.46/linux/arch/sparc/mm/fault.c linux/arch/sparc/mm/fault.c --- v2.3.46/linux/arch/sparc/mm/fault.c Fri Jan 28 15:09:07 2000 +++ linux/arch/sparc/mm/fault.c Thu Feb 17 09:26:30 2000 @@ -1,4 +1,4 @@ -/* $Id: fault.c,v 1.113 2000/01/21 11:38:47 jj Exp $ +/* $Id: fault.c,v 1.114 2000/02/14 04:52:36 jj Exp $ * fault.c: Page fault handlers for the Sparc. * * Copyright (C) 1995 David S. Miller (davem@caip.rutgers.edu) @@ -342,7 +342,6 @@ { extern void sun4c_update_mmu_cache(struct vm_area_struct *, unsigned long,pte_t); - extern pgd_t *sun4c_pgd_offset(struct mm_struct *,unsigned long); extern pte_t *sun4c_pte_offset(pmd_t *,unsigned long); struct task_struct *tsk = current; struct mm_struct *mm = tsk->mm; @@ -362,7 +361,7 @@ } } - pgdp = sun4c_pgd_offset(mm, address); + pgdp = pgd_offset(mm, address); ptep = sun4c_pte_offset((pmd_t *) pgdp, address); if (pgd_val(*pgdp)) { diff -u --recursive --new-file v2.3.46/linux/arch/sparc/mm/nosun4c.c linux/arch/sparc/mm/nosun4c.c --- v2.3.46/linux/arch/sparc/mm/nosun4c.c Tue Aug 31 17:29:13 1999 +++ linux/arch/sparc/mm/nosun4c.c Thu Feb 17 09:26:30 2000 @@ -1,4 +1,4 @@ -/* $Id: nosun4c.c,v 1.2 1999/08/31 06:54:36 davem Exp $ +/* $Id: nosun4c.c,v 1.3 2000/02/14 04:52:36 jj Exp $ * nosun4c.c: This file is a bunch of dummies for SMP compiles, * so that it does not need sun4c and avoid ifdefs. * @@ -50,11 +50,6 @@ void sun4c_complete_all_stores(void) { -} - -pgd_t *sun4c_pgd_offset(struct mm_struct * mm, unsigned long address) -{ - return NULL; } pte_t *sun4c_pte_offset(pmd_t * dir, unsigned long address) diff -u --recursive --new-file v2.3.46/linux/arch/sparc/mm/srmmu.c linux/arch/sparc/mm/srmmu.c --- v2.3.46/linux/arch/sparc/mm/srmmu.c Wed Feb 16 17:03:51 2000 +++ linux/arch/sparc/mm/srmmu.c Thu Feb 17 09:26:30 2000 @@ -1,4 +1,4 @@ -/* $Id: srmmu.c,v 1.207 2000/02/14 02:51:53 davem Exp $ +/* $Id: srmmu.c,v 1.208 2000/02/14 04:52:33 jj Exp $ * srmmu.c: SRMMU specific routines for memory management. * * Copyright (C) 1995 David S. Miller (davem@caip.rutgers.edu) @@ -201,7 +201,7 @@ } /* to find an entry in a top-level page table... */ -static inline pgd_t *srmmu_pgd_offset(struct mm_struct * mm, unsigned long address) +extern inline pgd_t *srmmu_pgd_offset(struct mm_struct * mm, unsigned long address) { return mm->pgd + (address >> SRMMU_PGDIR_SHIFT); } @@ -2337,7 +2337,6 @@ BTFIXUPSET_CALL(pgd_set, srmmu_pgd_set, BTFIXUPCALL_NORM); BTFIXUPSET_INT(pte_modify_mask, SRMMU_CHG_MASK); - BTFIXUPSET_CALL(pgd_offset, srmmu_pgd_offset, BTFIXUPCALL_NORM); BTFIXUPSET_CALL(pmd_offset, srmmu_pmd_offset, BTFIXUPCALL_NORM); BTFIXUPSET_CALL(pte_offset, srmmu_pte_offset, BTFIXUPCALL_NORM); BTFIXUPSET_CALL(pte_free_kernel, srmmu_pte_free, BTFIXUPCALL_NORM); diff -u --recursive --new-file v2.3.46/linux/arch/sparc/mm/sun4c.c linux/arch/sparc/mm/sun4c.c --- v2.3.46/linux/arch/sparc/mm/sun4c.c Wed Feb 16 17:03:51 2000 +++ linux/arch/sparc/mm/sun4c.c Thu Feb 17 09:26:30 2000 @@ -1,4 +1,4 @@ -/* $Id: sun4c.c,v 1.189 2000/02/14 02:51:55 davem Exp $ +/* $Id: sun4c.c,v 1.190 2000/02/14 04:52:34 jj Exp $ * sun4c.c: Doing in software what should be done in hardware. * * Copyright (C) 1996 David S. Miller (davem@caip.rutgers.edu) @@ -2185,7 +2185,7 @@ } /* to find an entry in a page-table-directory */ -pgd_t *sun4c_pgd_offset(struct mm_struct * mm, unsigned long address) +extern inline pgd_t *sun4c_pgd_offset(struct mm_struct * mm, unsigned long address) { return mm->pgd + (address >> SUN4C_PGDIR_SHIFT); } @@ -2273,7 +2273,7 @@ ret = (unsigned long *)__get_free_page(GFP_KERNEL); memset (ret, 0, (KERNBASE / SUN4C_PGDIR_SIZE) * sizeof(pgd_t)); - init = pgd_offset(&init_mm, 0); + init = sun4c_pgd_offset(&init_mm, 0); memcpy (((pgd_t *)ret) + USER_PTRS_PER_PGD, init + USER_PTRS_PER_PGD, (PTRS_PER_PGD - USER_PTRS_PER_PGD) * sizeof(pgd_t)); } @@ -2696,7 +2696,6 @@ BTFIXUPSET_CALL(mk_pte_io, sun4c_mk_pte_io, BTFIXUPCALL_NORM); BTFIXUPSET_INT(pte_modify_mask, _SUN4C_PAGE_CHG_MASK); - BTFIXUPSET_CALL(pgd_offset, sun4c_pgd_offset, BTFIXUPCALL_NORM); BTFIXUPSET_CALL(pmd_offset, sun4c_pmd_offset, BTFIXUPCALL_NORM); BTFIXUPSET_CALL(pte_offset, sun4c_pte_offset, BTFIXUPCALL_NORM); BTFIXUPSET_CALL(pte_free_kernel, sun4c_pte_free_kernel, BTFIXUPCALL_NORM); diff -u --recursive --new-file v2.3.46/linux/arch/sparc64/config.in linux/arch/sparc64/config.in --- v2.3.46/linux/arch/sparc64/config.in Thu Feb 10 17:11:05 2000 +++ linux/arch/sparc64/config.in Sun Feb 20 20:15:01 2000 @@ -226,9 +226,9 @@ if [ "$CONFIG_PCI" = "y" ]; then tristate 'Generic DECchip & DIGITAL EtherWORKS PCI/EISA' CONFIG_DE4X5 tristate '3c590/3c900 series (592/595/597) "Vortex/Boomerang" support' CONFIG_VORTEX - tristate 'RealTek 8129/8139 (not 8019/8029!) support' CONFIG_RTL8139 + tristate 'RealTek RTL-8139 support' CONFIG_8139TOO tristate 'PCI NE2000 support' CONFIG_NE2K_PCI - tristate 'EtherExpressPro/100 support' CONFIG_EEXPRESS_PRO100 + tristate 'EtherExpressPro/100 support' CONFIG_EEPRO100 tristate 'Adaptec Starfire support' CONFIG_ADAPTEC_STARFIRE fi endmenu diff -u --recursive --new-file v2.3.46/linux/arch/sparc64/defconfig linux/arch/sparc64/defconfig --- v2.3.46/linux/arch/sparc64/defconfig Thu Feb 10 17:11:05 2000 +++ linux/arch/sparc64/defconfig Fri Feb 18 14:51:22 2000 @@ -318,12 +318,12 @@ # CONFIG_JOLIET is not set CONFIG_MINIX_FS=m # CONFIG_NTFS_FS is not set -# CONFIG_NTFS_RW is not set CONFIG_HPFS_FS=m CONFIG_PROC_FS=y +# CONFIG_DEVFS_FS is not set +# CONFIG_DEVFS_DEBUG is not set CONFIG_DEVPTS_FS=y # CONFIG_QNX4FS_FS is not set -# CONFIG_QNX4FS_RW is not set CONFIG_ROMFS_FS=m CONFIG_EXT2_FS=y CONFIG_SYSV_FS=m diff -u --recursive --new-file v2.3.46/linux/arch/sparc64/kernel/ioctl32.c linux/arch/sparc64/kernel/ioctl32.c --- v2.3.46/linux/arch/sparc64/kernel/ioctl32.c Thu Feb 10 17:11:06 2000 +++ linux/arch/sparc64/kernel/ioctl32.c Thu Feb 17 09:26:30 2000 @@ -1,7 +1,7 @@ -/* $Id: ioctl32.c,v 1.79 2000/02/08 20:24:25 davem Exp $ +/* $Id: ioctl32.c,v 1.80 2000/02/17 06:45:09 jj Exp $ * ioctl32.c: Conversion between 32bit and 64bit native ioctls. * - * Copyright (C) 1997 Jakub Jelinek (jj@sunsite.mff.cuni.cz) + * Copyright (C) 1997-2000 Jakub Jelinek (jakub@redhat.com) * Copyright (C) 1998 Eddie C. Dost (ecd@skynet.be) * * These routines maintain argument size conversion between 32bit and 64bit @@ -42,6 +42,7 @@ #include #include #include +#include #include /* Ugly hack. */ @@ -435,7 +436,7 @@ __kernel_caddr_t32 ifcbuf; }; -static int dev_ifname32(unsigned int fd, unsigned long arg) +static int dev_ifname32(unsigned int fd, unsigned int cmd, unsigned long arg) { struct net_device *dev; struct ifreq32 ifr32; @@ -454,7 +455,7 @@ return (err ? -EFAULT : 0); } -static inline int dev_ifconf(unsigned int fd, unsigned long arg) +static inline int dev_ifconf(unsigned int fd, unsigned int cmd, unsigned long arg) { struct ifconf32 ifc32; struct ifconf ifc; @@ -671,7 +672,7 @@ u32 start; }; -static inline int hdio_getgeo(unsigned int fd, unsigned long arg) +static inline int hdio_getgeo(unsigned int fd, unsigned int cmd, unsigned long arg) { mm_segment_t old_fs = get_fs(); struct hd_geometry geo; @@ -1024,8 +1025,8 @@ unsigned int badness; }; -#define FDSETPRM32 _IOW(2, 0x42, struct floppy_struct32) -#define FDDEFPRM32 _IOW(2, 0x43, struct floppy_struct32) +#define FDSETPRM32 _IOW(2, 0x42, struct floppy_struct32) +#define FDDEFPRM32 _IOW(2, 0x43, struct floppy_struct32) #define FDGETPRM32 _IOR(2, 0x04, struct floppy_struct32) #define FDSETDRVPRM32 _IOW(2, 0x90, struct floppy_drive_params32) #define FDGETDRVPRM32 _IOR(2, 0x11, struct floppy_drive_params32) @@ -1648,7 +1649,7 @@ u32 chardata; /* font data in expanded form */ }; -static int do_fontx_ioctl(struct file *file, int cmd, struct consolefontdesc32 *user_cfd) +static int do_fontx_ioctl(unsigned int fd, int cmd, struct consolefontdesc32 *user_cfd, struct file *file) { struct consolefontdesc cfdarg; struct console_font_op op; @@ -1657,7 +1658,7 @@ perm = vt_check(file); if (perm < 0) return perm; - if (copy_from_user(&cfdarg, user_cfd, sizeof(struct consolefontdesc32))) + if (copy_from_user(&cfdarg, user_cfd, sizeof(struct consolefontdesc32))) return -EFAULT; cfdarg.chardata = (unsigned char *)A(((struct consolefontdesc32 *)&cfdarg)->chardata); @@ -1703,7 +1704,7 @@ u32 data; /* font data with height fixed to 32 */ }; -static int do_kdfontop_ioctl(struct file *file, struct console_font_op32 *fontop) +static int do_kdfontop_ioctl(unsigned int fd, unsigned int cmd, struct console_font_op32 *fontop, struct file *file) { struct console_font_op op; int perm = vt_check(file), i; @@ -1731,7 +1732,7 @@ u32 entries; }; -static int do_unimap_ioctl(struct file *file, int cmd, struct unimapdesc32 *user_ud) +static int do_unimap_ioctl(unsigned int fd, unsigned int cmd, struct unimapdesc32 *user_ud, struct file *file) { struct unimapdesc32 tmp; int perm = vt_check(file); @@ -1978,768 +1979,813 @@ return -EINVAL; } -asmlinkage int sys32_ioctl(unsigned int fd, unsigned int cmd, unsigned long arg) +static int ret_einval(unsigned int fd, unsigned int cmd, unsigned long arg) { - struct file * filp; - int error = -EBADF; - - lock_kernel(); - filp = fget(fd); - if(!filp) - goto out2; + return -EINVAL; +} - if (!filp->f_op || !filp->f_op->ioctl) { - error = sys_ioctl (fd, cmd, arg); - goto out; - } - switch (cmd) { - case SIOCGIFNAME: - error = dev_ifname32(fd, arg); - goto out; +static int broken_blkgetsize(unsigned int fd, unsigned int cmd, unsigned long arg) +{ + /* The mkswap binary hard codes it to Intel value :-((( */ + return w_long(fd, BLKGETSIZE, arg); +} - case SIOCGIFCONF: - error = dev_ifconf(fd, arg); - goto out; - - case SIOCGIFFLAGS: - case SIOCSIFFLAGS: - case SIOCGIFMETRIC: - case SIOCSIFMETRIC: - case SIOCGIFMTU: - case SIOCSIFMTU: - case SIOCGIFMEM: - case SIOCSIFMEM: - case SIOCGIFHWADDR: - case SIOCSIFHWADDR: - case SIOCADDMULTI: - case SIOCDELMULTI: - case SIOCGIFINDEX: - case SIOCGIFMAP: - case SIOCSIFMAP: - case SIOCGIFADDR: - case SIOCSIFADDR: - case SIOCGIFBRDADDR: - case SIOCSIFBRDADDR: - case SIOCGIFDSTADDR: - case SIOCSIFDSTADDR: - case SIOCGIFNETMASK: - case SIOCSIFNETMASK: - case SIOCSIFPFLAGS: - case SIOCGIFPFLAGS: - case SIOCGPPPSTATS: - case SIOCGPPPCSTATS: - case SIOCGPPPVER: - case SIOCGIFTXQLEN: - case SIOCSIFTXQLEN: - case SIOCETHTOOL: - error = dev_ifsioc(fd, cmd, arg); - goto out; - - case SIOCADDRT: - case SIOCDELRT: - error = routing_ioctl(fd, cmd, arg); - goto out; +struct blkpg_ioctl_arg32 { + int op; + int flags; + int datalen; + u32 data; +}; + +static int blkpg_ioctl_trans(unsigned int fd, unsigned int cmd, struct blkpg_ioctl_arg32 *arg) +{ + struct blkpg_ioctl_arg a; + struct blkpg_partition p; + int err; + mm_segment_t old_fs = get_fs(); + + err = get_user(a.op, &arg->op); + err |= __get_user(a.flags, &arg->flags); + err |= __get_user(a.datalen, &arg->datalen); + err |= __get_user((long)a.data, &arg->data); + if (err) return err; + switch (a.op) { + case BLKPG_ADD_PARTITION: + case BLKPG_DEL_PARTITION: + if (a.datalen < sizeof(struct blkpg_partition)) + return -EINVAL; + if (copy_from_user(&p, a.data, sizeof(struct blkpg_partition))) + return -EFAULT; + a.data = &p; + set_fs (KERNEL_DS); + err = sys_ioctl(fd, cmd, (unsigned long)&a); + set_fs (old_fs); + default: + return -EINVAL; + } + return err; +} - case SIOCRTMSG: /* Note SIOCRTMSG is no longer, so this is safe and - * the user would have seen just an -EINVAL anyways. - */ - error = -EINVAL; - goto out; +static int ioc_settimeout(unsigned int fd, unsigned int cmd, unsigned long arg) +{ + return rw_long(fd, AUTOFS_IOC_SETTIMEOUT, arg); +} - case SIOCGSTAMP: - /* Sorry, timeval in the kernel is different now. */ - error = do_siocgstamp(fd, cmd, arg); - goto out; +struct ioctl_trans { + unsigned int cmd; + unsigned int handler; + unsigned int next; +}; - case HDIO_GETGEO: - error = hdio_getgeo(fd, arg); - goto out; - - case BLKRAGET: - case BLKGETSIZE: - case 0x1260: - /* The mkswap binary hard codes it to Intel value :-((( */ - if(cmd == 0x1260) - cmd = BLKGETSIZE; - error = w_long(fd, cmd, arg); - goto out; - - case FBIOPUTCMAP32: - case FBIOGETCMAP32: - error = fbiogetputcmap(fd, cmd, arg); - goto out; - - case FBIOSCURSOR32: - error = fbiogscursor(fd, cmd, arg); - goto out; +#define COMPATIBLE_IOCTL(cmd) asm volatile(".word %0, sys_ioctl, 0" : : "i" (cmd)); +#define HANDLE_IOCTL(cmd,handler) asm volatile(".word %0, %1, 0" : : "i" (cmd), "i" (handler)); +#define IOCTL_TABLE_START void ioctl32_foo(void) { asm volatile(".data\nioctl_translations:"); +#define IOCTL_TABLE_END asm volatile("\nioctl_translations_end:\n\t.previous"); } - case FBIOGET_FSCREENINFO: - case FBIOGETCMAP: - case FBIOPUTCMAP: - error = fb_ioctl_trans(fd, cmd, arg); - goto out; +IOCTL_TABLE_START +/* List here exlicitly which ioctl's are known to have + * compatable types passed or none at all... + */ +/* Big T */ +COMPATIBLE_IOCTL(TCGETA) +COMPATIBLE_IOCTL(TCSETA) +COMPATIBLE_IOCTL(TCSETAW) +COMPATIBLE_IOCTL(TCSETAF) +COMPATIBLE_IOCTL(TCSBRK) +COMPATIBLE_IOCTL(TCXONC) +COMPATIBLE_IOCTL(TCFLSH) +COMPATIBLE_IOCTL(TCGETS) +COMPATIBLE_IOCTL(TCSETS) +COMPATIBLE_IOCTL(TCSETSW) +COMPATIBLE_IOCTL(TCSETSF) +COMPATIBLE_IOCTL(TIOCLINUX) +/* Little t */ +COMPATIBLE_IOCTL(TIOCGETD) +COMPATIBLE_IOCTL(TIOCSETD) +COMPATIBLE_IOCTL(TIOCEXCL) +COMPATIBLE_IOCTL(TIOCNXCL) +COMPATIBLE_IOCTL(TIOCCONS) +COMPATIBLE_IOCTL(TIOCGSOFTCAR) +COMPATIBLE_IOCTL(TIOCSSOFTCAR) +COMPATIBLE_IOCTL(TIOCSWINSZ) +COMPATIBLE_IOCTL(TIOCGWINSZ) +COMPATIBLE_IOCTL(TIOCMGET) +COMPATIBLE_IOCTL(TIOCMBIC) +COMPATIBLE_IOCTL(TIOCMBIS) +COMPATIBLE_IOCTL(TIOCMSET) +COMPATIBLE_IOCTL(TIOCPKT) +COMPATIBLE_IOCTL(TIOCNOTTY) +COMPATIBLE_IOCTL(TIOCSTI) +COMPATIBLE_IOCTL(TIOCOUTQ) +COMPATIBLE_IOCTL(TIOCSPGRP) +COMPATIBLE_IOCTL(TIOCGPGRP) +COMPATIBLE_IOCTL(TIOCSCTTY) +COMPATIBLE_IOCTL(TIOCGPTN) +COMPATIBLE_IOCTL(TIOCSPTLCK) +COMPATIBLE_IOCTL(TIOCGSERIAL) +COMPATIBLE_IOCTL(TIOCSSERIAL) +COMPATIBLE_IOCTL(TIOCSERGETLSR) +/* Big F */ +COMPATIBLE_IOCTL(FBIOGTYPE) +COMPATIBLE_IOCTL(FBIOSATTR) +COMPATIBLE_IOCTL(FBIOGATTR) +COMPATIBLE_IOCTL(FBIOSVIDEO) +COMPATIBLE_IOCTL(FBIOGVIDEO) +COMPATIBLE_IOCTL(FBIOGCURSOR32) /* This is not implemented yet. Later it should be converted... */ +COMPATIBLE_IOCTL(FBIOSCURPOS) +COMPATIBLE_IOCTL(FBIOGCURPOS) +COMPATIBLE_IOCTL(FBIOGCURMAX) +COMPATIBLE_IOCTL(FBIOGET_VSCREENINFO) +COMPATIBLE_IOCTL(FBIOPUT_VSCREENINFO) +COMPATIBLE_IOCTL(FBIOPAN_DISPLAY) +COMPATIBLE_IOCTL(FBIOGET_FCURSORINFO) +COMPATIBLE_IOCTL(FBIOGET_VCURSORINFO) +COMPATIBLE_IOCTL(FBIOPUT_VCURSORINFO) +COMPATIBLE_IOCTL(FBIOGET_CURSORSTATE) +COMPATIBLE_IOCTL(FBIOPUT_CURSORSTATE) +COMPATIBLE_IOCTL(FBIOGET_CON2FBMAP) +COMPATIBLE_IOCTL(FBIOPUT_CON2FBMAP) +/* Little f */ +COMPATIBLE_IOCTL(FIOCLEX) +COMPATIBLE_IOCTL(FIONCLEX) +COMPATIBLE_IOCTL(FIOASYNC) +COMPATIBLE_IOCTL(FIONBIO) +COMPATIBLE_IOCTL(FIONREAD) /* This is also TIOCINQ */ +/* 0x00 */ +COMPATIBLE_IOCTL(FIBMAP) +COMPATIBLE_IOCTL(FIGETBSZ) +/* 0x03 -- HD/IDE ioctl's used by hdparm and friends. + * Some need translations, these do not. + */ +COMPATIBLE_IOCTL(HDIO_GET_IDENTITY) +COMPATIBLE_IOCTL(HDIO_SET_DMA) +COMPATIBLE_IOCTL(HDIO_SET_KEEPSETTINGS) +COMPATIBLE_IOCTL(HDIO_SET_UNMASKINTR) +COMPATIBLE_IOCTL(HDIO_SET_NOWERR) +COMPATIBLE_IOCTL(HDIO_SET_32BIT) +COMPATIBLE_IOCTL(HDIO_SET_MULTCOUNT) +COMPATIBLE_IOCTL(HDIO_DRIVE_CMD) +COMPATIBLE_IOCTL(HDIO_SET_PIO_MODE) +COMPATIBLE_IOCTL(HDIO_SCAN_HWIF) +COMPATIBLE_IOCTL(HDIO_SET_NICE) +/* 0x02 -- Floppy ioctls */ +COMPATIBLE_IOCTL(FDMSGON) +COMPATIBLE_IOCTL(FDMSGOFF) +COMPATIBLE_IOCTL(FDSETEMSGTRESH) +COMPATIBLE_IOCTL(FDFLUSH) +COMPATIBLE_IOCTL(FDWERRORCLR) +COMPATIBLE_IOCTL(FDSETMAXERRS) +COMPATIBLE_IOCTL(FDGETMAXERRS) +COMPATIBLE_IOCTL(FDGETDRVTYP) +COMPATIBLE_IOCTL(FDEJECT) +COMPATIBLE_IOCTL(FDCLRPRM) +COMPATIBLE_IOCTL(FDFMTBEG) +COMPATIBLE_IOCTL(FDFMTEND) +COMPATIBLE_IOCTL(FDRESET) +COMPATIBLE_IOCTL(FDTWADDLE) +COMPATIBLE_IOCTL(FDFMTTRK) +COMPATIBLE_IOCTL(FDRAWCMD) +/* 0x12 */ +COMPATIBLE_IOCTL(BLKROSET) +COMPATIBLE_IOCTL(BLKROGET) +COMPATIBLE_IOCTL(BLKRRPART) +COMPATIBLE_IOCTL(BLKFLSBUF) +COMPATIBLE_IOCTL(BLKRASET) +COMPATIBLE_IOCTL(BLKFRASET) +COMPATIBLE_IOCTL(BLKSECTSET) +COMPATIBLE_IOCTL(BLKSSZGET) - case HDIO_GET_KEEPSETTINGS: - case HDIO_GET_UNMASKINTR: - case HDIO_GET_DMA: - case HDIO_GET_32BIT: - case HDIO_GET_MULTCOUNT: - case HDIO_GET_NOWERR: - case HDIO_GET_NICE: - error = hdio_ioctl_trans(fd, cmd, arg); - goto out; - case FDSETPRM32: - case FDDEFPRM32: - case FDGETPRM32: - case FDSETDRVPRM32: - case FDGETDRVPRM32: - case FDGETDRVSTAT32: - case FDPOLLDRVSTAT32: - case FDGETFDCSTAT32: - case FDWERRORGET32: - error = fd_ioctl_trans(fd, cmd, arg); - goto out; +#if 0 /* New RAID code is being merged, fix up to handle + * new RAID ioctls when fully merged in 2.3.x -DaveM + */ +/* 0x09 */ +COMPATIBLE_IOCTL(REGISTER_DEV) +COMPATIBLE_IOCTL(REGISTER_DEV_NEW) +COMPATIBLE_IOCTL(START_MD) +COMPATIBLE_IOCTL(STOP_MD) +#endif + +/* Big K */ +COMPATIBLE_IOCTL(PIO_FONT) +COMPATIBLE_IOCTL(GIO_FONT) +COMPATIBLE_IOCTL(KDSIGACCEPT) +COMPATIBLE_IOCTL(KDGETKEYCODE) +COMPATIBLE_IOCTL(KDSETKEYCODE) +COMPATIBLE_IOCTL(KIOCSOUND) +COMPATIBLE_IOCTL(KDMKTONE) +COMPATIBLE_IOCTL(KDGKBTYPE) +COMPATIBLE_IOCTL(KDSETMODE) +COMPATIBLE_IOCTL(KDGETMODE) +COMPATIBLE_IOCTL(KDSKBMODE) +COMPATIBLE_IOCTL(KDGKBMODE) +COMPATIBLE_IOCTL(KDSKBMETA) +COMPATIBLE_IOCTL(KDGKBMETA) +COMPATIBLE_IOCTL(KDGKBENT) +COMPATIBLE_IOCTL(KDSKBENT) +COMPATIBLE_IOCTL(KDGKBSENT) +COMPATIBLE_IOCTL(KDSKBSENT) +COMPATIBLE_IOCTL(KDGKBDIACR) +COMPATIBLE_IOCTL(KDSKBDIACR) +COMPATIBLE_IOCTL(KDGKBLED) +COMPATIBLE_IOCTL(KDSKBLED) +COMPATIBLE_IOCTL(KDGETLED) +COMPATIBLE_IOCTL(KDSETLED) +COMPATIBLE_IOCTL(GIO_SCRNMAP) +COMPATIBLE_IOCTL(PIO_SCRNMAP) +COMPATIBLE_IOCTL(GIO_UNISCRNMAP) +COMPATIBLE_IOCTL(PIO_UNISCRNMAP) +COMPATIBLE_IOCTL(PIO_FONTRESET) +COMPATIBLE_IOCTL(PIO_UNIMAPCLR) +/* Little k */ +COMPATIBLE_IOCTL(KIOCTYPE) +COMPATIBLE_IOCTL(KIOCLAYOUT) +COMPATIBLE_IOCTL(KIOCGTRANS) +COMPATIBLE_IOCTL(KIOCTRANS) +COMPATIBLE_IOCTL(KIOCCMD) +COMPATIBLE_IOCTL(KIOCSDIRECT) +COMPATIBLE_IOCTL(KIOCSLED) +COMPATIBLE_IOCTL(KIOCGLED) +COMPATIBLE_IOCTL(KIOCSRATE) +COMPATIBLE_IOCTL(KIOCGRATE) +/* Big S */ +COMPATIBLE_IOCTL(SCSI_IOCTL_GET_IDLUN) +COMPATIBLE_IOCTL(SCSI_IOCTL_DOORLOCK) +COMPATIBLE_IOCTL(SCSI_IOCTL_DOORUNLOCK) +COMPATIBLE_IOCTL(SCSI_IOCTL_TEST_UNIT_READY) +COMPATIBLE_IOCTL(SCSI_IOCTL_TAGGED_ENABLE) +COMPATIBLE_IOCTL(SCSI_IOCTL_TAGGED_DISABLE) +COMPATIBLE_IOCTL(SCSI_IOCTL_GET_BUS_NUMBER) +COMPATIBLE_IOCTL(SCSI_IOCTL_SEND_COMMAND) +/* Big V */ +COMPATIBLE_IOCTL(VT_SETMODE) +COMPATIBLE_IOCTL(VT_GETMODE) +COMPATIBLE_IOCTL(VT_GETSTATE) +COMPATIBLE_IOCTL(VT_OPENQRY) +COMPATIBLE_IOCTL(VT_ACTIVATE) +COMPATIBLE_IOCTL(VT_WAITACTIVE) +COMPATIBLE_IOCTL(VT_RELDISP) +COMPATIBLE_IOCTL(VT_DISALLOCATE) +COMPATIBLE_IOCTL(VT_RESIZE) +COMPATIBLE_IOCTL(VT_RESIZEX) +COMPATIBLE_IOCTL(VT_LOCKSWITCH) +COMPATIBLE_IOCTL(VT_UNLOCKSWITCH) +/* Little v */ +COMPATIBLE_IOCTL(VUIDSFORMAT) +COMPATIBLE_IOCTL(VUIDGFORMAT) +/* Little v, the video4linux ioctls */ +COMPATIBLE_IOCTL(VIDIOCGCAP) +COMPATIBLE_IOCTL(VIDIOCGCHAN) +COMPATIBLE_IOCTL(VIDIOCSCHAN) +COMPATIBLE_IOCTL(VIDIOCGPICT) +COMPATIBLE_IOCTL(VIDIOCSPICT) +COMPATIBLE_IOCTL(VIDIOCCAPTURE) +COMPATIBLE_IOCTL(VIDIOCKEY) +COMPATIBLE_IOCTL(VIDIOCGAUDIO) +COMPATIBLE_IOCTL(VIDIOCSAUDIO) +COMPATIBLE_IOCTL(VIDIOCSYNC) +COMPATIBLE_IOCTL(VIDIOCMCAPTURE) +COMPATIBLE_IOCTL(VIDIOCGMBUF) +COMPATIBLE_IOCTL(VIDIOCGUNIT) +COMPATIBLE_IOCTL(VIDIOCGCAPTURE) +COMPATIBLE_IOCTL(VIDIOCSCAPTURE) +/* BTTV specific... */ +COMPATIBLE_IOCTL(_IOW('v', BASE_VIDIOCPRIVATE+0, char [256])) +COMPATIBLE_IOCTL(_IOR('v', BASE_VIDIOCPRIVATE+1, char [256])) +COMPATIBLE_IOCTL(_IOR('v' , BASE_VIDIOCPRIVATE+2, unsigned int)) +COMPATIBLE_IOCTL(_IOW('v' , BASE_VIDIOCPRIVATE+3, char [16])) /* struct bttv_pll_info */ +COMPATIBLE_IOCTL(_IOR('v' , BASE_VIDIOCPRIVATE+4, int)) +COMPATIBLE_IOCTL(_IOR('v' , BASE_VIDIOCPRIVATE+5, int)) +COMPATIBLE_IOCTL(_IOR('v' , BASE_VIDIOCPRIVATE+6, int)) +COMPATIBLE_IOCTL(_IOR('v' , BASE_VIDIOCPRIVATE+7, int)) +/* Little p (/dev/rtc, /dev/envctrl, etc.) */ +COMPATIBLE_IOCTL(RTCGET) +COMPATIBLE_IOCTL(RTCSET) +COMPATIBLE_IOCTL(I2CIOCSADR) +COMPATIBLE_IOCTL(I2CIOCGADR) +/* Little m */ +COMPATIBLE_IOCTL(MTIOCTOP) +/* OPENPROMIO, SunOS/Solaris only, the NetBSD one's have + * embedded pointers in the arg which we'd need to clean up... + */ +COMPATIBLE_IOCTL(OPROMGETOPT) +COMPATIBLE_IOCTL(OPROMSETOPT) +COMPATIBLE_IOCTL(OPROMNXTOPT) +COMPATIBLE_IOCTL(OPROMSETOPT2) +COMPATIBLE_IOCTL(OPROMNEXT) +COMPATIBLE_IOCTL(OPROMCHILD) +COMPATIBLE_IOCTL(OPROMGETPROP) +COMPATIBLE_IOCTL(OPROMNXTPROP) +COMPATIBLE_IOCTL(OPROMU2P) +COMPATIBLE_IOCTL(OPROMGETCONS) +COMPATIBLE_IOCTL(OPROMGETFBNAME) +COMPATIBLE_IOCTL(OPROMGETBOOTARGS) +COMPATIBLE_IOCTL(OPROMSETCUR) +COMPATIBLE_IOCTL(OPROMPCI2NODE) +COMPATIBLE_IOCTL(OPROMPATH2NODE) +/* Socket level stuff */ +COMPATIBLE_IOCTL(FIOSETOWN) +COMPATIBLE_IOCTL(SIOCSPGRP) +COMPATIBLE_IOCTL(FIOGETOWN) +COMPATIBLE_IOCTL(SIOCGPGRP) +COMPATIBLE_IOCTL(SIOCATMARK) +COMPATIBLE_IOCTL(SIOCSIFLINK) +COMPATIBLE_IOCTL(SIOCSIFENCAP) +COMPATIBLE_IOCTL(SIOCGIFENCAP) +COMPATIBLE_IOCTL(SIOCSIFBR) +COMPATIBLE_IOCTL(SIOCGIFBR) +COMPATIBLE_IOCTL(SIOCSARP) +COMPATIBLE_IOCTL(SIOCGARP) +COMPATIBLE_IOCTL(SIOCDARP) +#if 0 /* XXX No longer exist in new routing code. XXX */ +COMPATIBLE_IOCTL(OLD_SIOCSARP) +COMPATIBLE_IOCTL(OLD_SIOCGARP) +COMPATIBLE_IOCTL(OLD_SIOCDARP) +#endif +COMPATIBLE_IOCTL(SIOCSRARP) +COMPATIBLE_IOCTL(SIOCGRARP) +COMPATIBLE_IOCTL(SIOCDRARP) +COMPATIBLE_IOCTL(SIOCADDDLCI) +COMPATIBLE_IOCTL(SIOCDELDLCI) +/* SG stuff */ +COMPATIBLE_IOCTL(SG_SET_TIMEOUT) +COMPATIBLE_IOCTL(SG_GET_TIMEOUT) +COMPATIBLE_IOCTL(SG_EMULATED_HOST) +COMPATIBLE_IOCTL(SG_SET_TRANSFORM) +COMPATIBLE_IOCTL(SG_GET_TRANSFORM) +/* PPP stuff */ +COMPATIBLE_IOCTL(PPPIOCGFLAGS) +COMPATIBLE_IOCTL(PPPIOCSFLAGS) +COMPATIBLE_IOCTL(PPPIOCGASYNCMAP) +COMPATIBLE_IOCTL(PPPIOCSASYNCMAP) +COMPATIBLE_IOCTL(PPPIOCGUNIT) +COMPATIBLE_IOCTL(PPPIOCGRASYNCMAP) +COMPATIBLE_IOCTL(PPPIOCSRASYNCMAP) +COMPATIBLE_IOCTL(PPPIOCGMRU) +COMPATIBLE_IOCTL(PPPIOCSMRU) +COMPATIBLE_IOCTL(PPPIOCSMAXCID) +COMPATIBLE_IOCTL(PPPIOCGXASYNCMAP) +COMPATIBLE_IOCTL(PPPIOCSXASYNCMAP) +COMPATIBLE_IOCTL(PPPIOCXFERUNIT) +COMPATIBLE_IOCTL(PPPIOCGNPMODE) +COMPATIBLE_IOCTL(PPPIOCSNPMODE) +COMPATIBLE_IOCTL(PPPIOCGDEBUG) +COMPATIBLE_IOCTL(PPPIOCSDEBUG) +COMPATIBLE_IOCTL(PPPIOCNEWUNIT) +COMPATIBLE_IOCTL(PPPIOCATTACH) +COMPATIBLE_IOCTL(PPPIOCDETACH) +/* CDROM stuff */ +COMPATIBLE_IOCTL(CDROMPAUSE) +COMPATIBLE_IOCTL(CDROMRESUME) +COMPATIBLE_IOCTL(CDROMPLAYMSF) +COMPATIBLE_IOCTL(CDROMPLAYTRKIND) +COMPATIBLE_IOCTL(CDROMREADTOCHDR) +COMPATIBLE_IOCTL(CDROMREADTOCENTRY) +COMPATIBLE_IOCTL(CDROMSTOP) +COMPATIBLE_IOCTL(CDROMSTART) +COMPATIBLE_IOCTL(CDROMEJECT) +COMPATIBLE_IOCTL(CDROMVOLCTRL) +COMPATIBLE_IOCTL(CDROMSUBCHNL) +COMPATIBLE_IOCTL(CDROMEJECT_SW) +COMPATIBLE_IOCTL(CDROMMULTISESSION) +COMPATIBLE_IOCTL(CDROM_GET_MCN) +COMPATIBLE_IOCTL(CDROMRESET) +COMPATIBLE_IOCTL(CDROMVOLREAD) +COMPATIBLE_IOCTL(CDROMSEEK) +COMPATIBLE_IOCTL(CDROMPLAYBLK) +COMPATIBLE_IOCTL(CDROMCLOSETRAY) +COMPATIBLE_IOCTL(CDROM_SET_OPTIONS) +COMPATIBLE_IOCTL(CDROM_CLEAR_OPTIONS) +COMPATIBLE_IOCTL(CDROM_SELECT_SPEED) +COMPATIBLE_IOCTL(CDROM_SELECT_DISC) +COMPATIBLE_IOCTL(CDROM_MEDIA_CHANGED) +COMPATIBLE_IOCTL(CDROM_DRIVE_STATUS) +COMPATIBLE_IOCTL(CDROM_DISC_STATUS) +COMPATIBLE_IOCTL(CDROM_CHANGER_NSLOTS) +COMPATIBLE_IOCTL(CDROM_LOCKDOOR) +COMPATIBLE_IOCTL(CDROM_DEBUG) +COMPATIBLE_IOCTL(CDROM_GET_CAPABILITY) +/* Big L */ +COMPATIBLE_IOCTL(LOOP_SET_FD) +COMPATIBLE_IOCTL(LOOP_CLR_FD) +/* Big A */ +COMPATIBLE_IOCTL(AUDIO_GETINFO) +COMPATIBLE_IOCTL(AUDIO_SETINFO) +COMPATIBLE_IOCTL(AUDIO_DRAIN) +COMPATIBLE_IOCTL(AUDIO_GETDEV) +COMPATIBLE_IOCTL(AUDIO_GETDEV_SUNOS) +COMPATIBLE_IOCTL(AUDIO_FLUSH) +/* Big Q for sound/OSS */ +COMPATIBLE_IOCTL(SNDCTL_SEQ_RESET) +COMPATIBLE_IOCTL(SNDCTL_SEQ_SYNC) +COMPATIBLE_IOCTL(SNDCTL_SYNTH_INFO) +COMPATIBLE_IOCTL(SNDCTL_SEQ_CTRLRATE) +COMPATIBLE_IOCTL(SNDCTL_SEQ_GETOUTCOUNT) +COMPATIBLE_IOCTL(SNDCTL_SEQ_GETINCOUNT) +COMPATIBLE_IOCTL(SNDCTL_SEQ_PERCMODE) +COMPATIBLE_IOCTL(SNDCTL_FM_LOAD_INSTR) +COMPATIBLE_IOCTL(SNDCTL_SEQ_TESTMIDI) +COMPATIBLE_IOCTL(SNDCTL_SEQ_RESETSAMPLES) +COMPATIBLE_IOCTL(SNDCTL_SEQ_NRSYNTHS) +COMPATIBLE_IOCTL(SNDCTL_SEQ_NRMIDIS) +COMPATIBLE_IOCTL(SNDCTL_MIDI_INFO) +COMPATIBLE_IOCTL(SNDCTL_SEQ_THRESHOLD) +COMPATIBLE_IOCTL(SNDCTL_SYNTH_MEMAVL) +COMPATIBLE_IOCTL(SNDCTL_FM_4OP_ENABLE) +COMPATIBLE_IOCTL(SNDCTL_SEQ_PANIC) +COMPATIBLE_IOCTL(SNDCTL_SEQ_OUTOFBAND) +COMPATIBLE_IOCTL(SNDCTL_SEQ_GETTIME) +COMPATIBLE_IOCTL(SNDCTL_SYNTH_ID) +COMPATIBLE_IOCTL(SNDCTL_SYNTH_CONTROL) +COMPATIBLE_IOCTL(SNDCTL_SYNTH_REMOVESAMPLE) +/* Big T for sound/OSS */ +COMPATIBLE_IOCTL(SNDCTL_TMR_TIMEBASE) +COMPATIBLE_IOCTL(SNDCTL_TMR_START) +COMPATIBLE_IOCTL(SNDCTL_TMR_STOP) +COMPATIBLE_IOCTL(SNDCTL_TMR_CONTINUE) +COMPATIBLE_IOCTL(SNDCTL_TMR_TEMPO) +COMPATIBLE_IOCTL(SNDCTL_TMR_SOURCE) +COMPATIBLE_IOCTL(SNDCTL_TMR_METRONOME) +COMPATIBLE_IOCTL(SNDCTL_TMR_SELECT) +/* Little m for sound/OSS */ +COMPATIBLE_IOCTL(SNDCTL_MIDI_PRETIME) +COMPATIBLE_IOCTL(SNDCTL_MIDI_MPUMODE) +COMPATIBLE_IOCTL(SNDCTL_MIDI_MPUCMD) +/* Big P for sound/OSS */ +COMPATIBLE_IOCTL(SNDCTL_DSP_RESET) +COMPATIBLE_IOCTL(SNDCTL_DSP_SYNC) +COMPATIBLE_IOCTL(SNDCTL_DSP_SPEED) +COMPATIBLE_IOCTL(SNDCTL_DSP_STEREO) +COMPATIBLE_IOCTL(SNDCTL_DSP_GETBLKSIZE) +COMPATIBLE_IOCTL(SNDCTL_DSP_CHANNELS) +COMPATIBLE_IOCTL(SOUND_PCM_WRITE_FILTER) +COMPATIBLE_IOCTL(SNDCTL_DSP_POST) +COMPATIBLE_IOCTL(SNDCTL_DSP_SUBDIVIDE) +COMPATIBLE_IOCTL(SNDCTL_DSP_SETFRAGMENT) +COMPATIBLE_IOCTL(SNDCTL_DSP_GETFMTS) +COMPATIBLE_IOCTL(SNDCTL_DSP_SETFMT) +COMPATIBLE_IOCTL(SNDCTL_DSP_GETOSPACE) +COMPATIBLE_IOCTL(SNDCTL_DSP_GETISPACE) +COMPATIBLE_IOCTL(SNDCTL_DSP_NONBLOCK) +COMPATIBLE_IOCTL(SNDCTL_DSP_GETCAPS) +COMPATIBLE_IOCTL(SNDCTL_DSP_GETTRIGGER) +COMPATIBLE_IOCTL(SNDCTL_DSP_SETTRIGGER) +COMPATIBLE_IOCTL(SNDCTL_DSP_GETIPTR) +COMPATIBLE_IOCTL(SNDCTL_DSP_GETOPTR) +/* SNDCTL_DSP_MAPINBUF, XXX needs translation */ +/* SNDCTL_DSP_MAPOUTBUF, XXX needs translation */ +COMPATIBLE_IOCTL(SNDCTL_DSP_SETSYNCRO) +COMPATIBLE_IOCTL(SNDCTL_DSP_SETDUPLEX) +COMPATIBLE_IOCTL(SNDCTL_DSP_GETODELAY) +COMPATIBLE_IOCTL(SNDCTL_DSP_PROFILE) +COMPATIBLE_IOCTL(SOUND_PCM_READ_RATE) +COMPATIBLE_IOCTL(SOUND_PCM_READ_CHANNELS) +COMPATIBLE_IOCTL(SOUND_PCM_READ_BITS) +COMPATIBLE_IOCTL(SOUND_PCM_READ_FILTER) +/* Big C for sound/OSS */ +COMPATIBLE_IOCTL(SNDCTL_COPR_RESET) +COMPATIBLE_IOCTL(SNDCTL_COPR_LOAD) +COMPATIBLE_IOCTL(SNDCTL_COPR_RDATA) +COMPATIBLE_IOCTL(SNDCTL_COPR_RCODE) +COMPATIBLE_IOCTL(SNDCTL_COPR_WDATA) +COMPATIBLE_IOCTL(SNDCTL_COPR_WCODE) +COMPATIBLE_IOCTL(SNDCTL_COPR_RUN) +COMPATIBLE_IOCTL(SNDCTL_COPR_HALT) +COMPATIBLE_IOCTL(SNDCTL_COPR_SENDMSG) +COMPATIBLE_IOCTL(SNDCTL_COPR_RCVMSG) +/* Big M for sound/OSS */ +COMPATIBLE_IOCTL(SOUND_MIXER_READ_VOLUME) +COMPATIBLE_IOCTL(SOUND_MIXER_READ_BASS) +COMPATIBLE_IOCTL(SOUND_MIXER_READ_TREBLE) +COMPATIBLE_IOCTL(SOUND_MIXER_READ_SYNTH) +COMPATIBLE_IOCTL(SOUND_MIXER_READ_PCM) +COMPATIBLE_IOCTL(SOUND_MIXER_READ_SPEAKER) +COMPATIBLE_IOCTL(SOUND_MIXER_READ_LINE) +COMPATIBLE_IOCTL(SOUND_MIXER_READ_MIC) +COMPATIBLE_IOCTL(SOUND_MIXER_READ_CD) +COMPATIBLE_IOCTL(SOUND_MIXER_READ_IMIX) +COMPATIBLE_IOCTL(SOUND_MIXER_READ_ALTPCM) +COMPATIBLE_IOCTL(SOUND_MIXER_READ_RECLEV) +COMPATIBLE_IOCTL(SOUND_MIXER_READ_IGAIN) +COMPATIBLE_IOCTL(SOUND_MIXER_READ_OGAIN) +COMPATIBLE_IOCTL(SOUND_MIXER_READ_LINE1) +COMPATIBLE_IOCTL(SOUND_MIXER_READ_LINE2) +COMPATIBLE_IOCTL(SOUND_MIXER_READ_LINE3) +COMPATIBLE_IOCTL(SOUND_MIXER_READ_MUTE) +/* SOUND_MIXER_READ_ENHANCE, same value as READ_MUTE */ +/* SOUND_MIXER_READ_LOUD, same value as READ_MUTE */ +COMPATIBLE_IOCTL(SOUND_MIXER_READ_RECSRC) +COMPATIBLE_IOCTL(SOUND_MIXER_READ_DEVMASK) +COMPATIBLE_IOCTL(SOUND_MIXER_READ_RECMASK) +COMPATIBLE_IOCTL(SOUND_MIXER_READ_STEREODEVS) +COMPATIBLE_IOCTL(SOUND_MIXER_READ_CAPS) +COMPATIBLE_IOCTL(SOUND_MIXER_WRITE_VOLUME) +COMPATIBLE_IOCTL(SOUND_MIXER_WRITE_BASS) +COMPATIBLE_IOCTL(SOUND_MIXER_WRITE_TREBLE) +COMPATIBLE_IOCTL(SOUND_MIXER_WRITE_SYNTH) +COMPATIBLE_IOCTL(SOUND_MIXER_WRITE_PCM) +COMPATIBLE_IOCTL(SOUND_MIXER_WRITE_SPEAKER) +COMPATIBLE_IOCTL(SOUND_MIXER_WRITE_LINE) +COMPATIBLE_IOCTL(SOUND_MIXER_WRITE_MIC) +COMPATIBLE_IOCTL(SOUND_MIXER_WRITE_CD) +COMPATIBLE_IOCTL(SOUND_MIXER_WRITE_IMIX) +COMPATIBLE_IOCTL(SOUND_MIXER_WRITE_ALTPCM) +COMPATIBLE_IOCTL(SOUND_MIXER_WRITE_RECLEV) +COMPATIBLE_IOCTL(SOUND_MIXER_WRITE_IGAIN) +COMPATIBLE_IOCTL(SOUND_MIXER_WRITE_OGAIN) +COMPATIBLE_IOCTL(SOUND_MIXER_WRITE_LINE1) +COMPATIBLE_IOCTL(SOUND_MIXER_WRITE_LINE2) +COMPATIBLE_IOCTL(SOUND_MIXER_WRITE_LINE3) +COMPATIBLE_IOCTL(SOUND_MIXER_WRITE_MUTE) +/* SOUND_MIXER_WRITE_ENHANCE, same value as WRITE_MUTE */ +/* SOUND_MIXER_WRITE_LOUD, same value as WRITE_MUTE */ +COMPATIBLE_IOCTL(SOUND_MIXER_WRITE_RECSRC) +COMPATIBLE_IOCTL(SOUND_MIXER_INFO) +COMPATIBLE_IOCTL(SOUND_OLD_MIXER_INFO) +COMPATIBLE_IOCTL(SOUND_MIXER_ACCESS) +COMPATIBLE_IOCTL(SOUND_MIXER_PRIVATE1) +COMPATIBLE_IOCTL(SOUND_MIXER_PRIVATE2) +COMPATIBLE_IOCTL(SOUND_MIXER_PRIVATE3) +COMPATIBLE_IOCTL(SOUND_MIXER_PRIVATE4) +COMPATIBLE_IOCTL(SOUND_MIXER_PRIVATE5) +COMPATIBLE_IOCTL(SOUND_MIXER_GETLEVELS) +COMPATIBLE_IOCTL(SOUND_MIXER_SETLEVELS) +COMPATIBLE_IOCTL(OSS_GETVERSION) +/* AUTOFS */ +COMPATIBLE_IOCTL(AUTOFS_IOC_READY) +COMPATIBLE_IOCTL(AUTOFS_IOC_FAIL) +COMPATIBLE_IOCTL(AUTOFS_IOC_CATATONIC) +COMPATIBLE_IOCTL(AUTOFS_IOC_PROTOVER) +COMPATIBLE_IOCTL(AUTOFS_IOC_EXPIRE) +/* Raw devices */ +COMPATIBLE_IOCTL(RAW_SETBIND) +COMPATIBLE_IOCTL(RAW_GETBIND) +/* SMB ioctls which do not need any translations */ +COMPATIBLE_IOCTL(SMB_IOC_NEWCONN) +/* Little a */ +COMPATIBLE_IOCTL(ATMSIGD_CTRL) +COMPATIBLE_IOCTL(ATMARPD_CTRL) +COMPATIBLE_IOCTL(ATMLEC_CTRL) +COMPATIBLE_IOCTL(ATMLEC_MCAST) +COMPATIBLE_IOCTL(ATMLEC_DATA) +COMPATIBLE_IOCTL(ATM_SETSC) +COMPATIBLE_IOCTL(SIOCSIFATMTCP) +COMPATIBLE_IOCTL(SIOCMKCLIP) +COMPATIBLE_IOCTL(ATMARP_MKIP) +COMPATIBLE_IOCTL(ATMARP_SETENTRY) +COMPATIBLE_IOCTL(ATMARP_ENCAP) +COMPATIBLE_IOCTL(ATMTCP_CREATE) +COMPATIBLE_IOCTL(ATMTCP_REMOVE) +COMPATIBLE_IOCTL(ATMMPC_CTRL) +COMPATIBLE_IOCTL(ATMMPC_DATA) +/* And these ioctls need translation */ +HANDLE_IOCTL(SIOCGIFNAME, dev_ifname32) +HANDLE_IOCTL(SIOCGIFCONF, dev_ifconf) +HANDLE_IOCTL(SIOCGIFFLAGS, dev_ifsioc) +HANDLE_IOCTL(SIOCSIFFLAGS, dev_ifsioc) +HANDLE_IOCTL(SIOCGIFMETRIC, dev_ifsioc) +HANDLE_IOCTL(SIOCSIFMETRIC, dev_ifsioc) +HANDLE_IOCTL(SIOCGIFMTU, dev_ifsioc) +HANDLE_IOCTL(SIOCSIFMTU, dev_ifsioc) +HANDLE_IOCTL(SIOCGIFMEM, dev_ifsioc) +HANDLE_IOCTL(SIOCSIFMEM, dev_ifsioc) +HANDLE_IOCTL(SIOCGIFHWADDR, dev_ifsioc) +HANDLE_IOCTL(SIOCSIFHWADDR, dev_ifsioc) +HANDLE_IOCTL(SIOCADDMULTI, dev_ifsioc) +HANDLE_IOCTL(SIOCDELMULTI, dev_ifsioc) +HANDLE_IOCTL(SIOCGIFINDEX, dev_ifsioc) +HANDLE_IOCTL(SIOCGIFMAP, dev_ifsioc) +HANDLE_IOCTL(SIOCSIFMAP, dev_ifsioc) +HANDLE_IOCTL(SIOCGIFADDR, dev_ifsioc) +HANDLE_IOCTL(SIOCSIFADDR, dev_ifsioc) +HANDLE_IOCTL(SIOCGIFBRDADDR, dev_ifsioc) +HANDLE_IOCTL(SIOCSIFBRDADDR, dev_ifsioc) +HANDLE_IOCTL(SIOCGIFDSTADDR, dev_ifsioc) +HANDLE_IOCTL(SIOCSIFDSTADDR, dev_ifsioc) +HANDLE_IOCTL(SIOCGIFNETMASK, dev_ifsioc) +HANDLE_IOCTL(SIOCSIFNETMASK, dev_ifsioc) +HANDLE_IOCTL(SIOCSIFPFLAGS, dev_ifsioc) +HANDLE_IOCTL(SIOCGIFPFLAGS, dev_ifsioc) +HANDLE_IOCTL(SIOCGPPPSTATS, dev_ifsioc) +HANDLE_IOCTL(SIOCGPPPCSTATS, dev_ifsioc) +HANDLE_IOCTL(SIOCGPPPVER, dev_ifsioc) +HANDLE_IOCTL(SIOCGIFTXQLEN, dev_ifsioc) +HANDLE_IOCTL(SIOCSIFTXQLEN, dev_ifsioc) +HANDLE_IOCTL(SIOCETHTOOL, dev_ifsioc) +HANDLE_IOCTL(SIOCADDRT, routing_ioctl) +HANDLE_IOCTL(SIOCDELRT, routing_ioctl) +/* Note SIOCRTMSG is no longer, so this is safe and * the user would have seen just an -EINVAL anyways. */ +HANDLE_IOCTL(SIOCRTMSG, ret_einval) +HANDLE_IOCTL(SIOCGSTAMP, do_siocgstamp) +HANDLE_IOCTL(HDIO_GETGEO, hdio_getgeo) +HANDLE_IOCTL(BLKRAGET, w_long) +HANDLE_IOCTL(BLKGETSIZE, w_long) +HANDLE_IOCTL(0x1260, broken_blkgetsize) +HANDLE_IOCTL(BLKFRAGET, w_long) +HANDLE_IOCTL(BLKSECTGET, w_long) +HANDLE_IOCTL(BLKPG, blkpg_ioctl_trans) +HANDLE_IOCTL(FBIOPUTCMAP32, fbiogetputcmap) +HANDLE_IOCTL(FBIOGETCMAP32, fbiogetputcmap) +HANDLE_IOCTL(FBIOSCURSOR32, fbiogscursor) +HANDLE_IOCTL(FBIOGET_FSCREENINFO, fb_ioctl_trans) +HANDLE_IOCTL(FBIOGETCMAP, fb_ioctl_trans) +HANDLE_IOCTL(FBIOPUTCMAP, fb_ioctl_trans) +HANDLE_IOCTL(HDIO_GET_KEEPSETTINGS, hdio_ioctl_trans) +HANDLE_IOCTL(HDIO_GET_UNMASKINTR, hdio_ioctl_trans) +HANDLE_IOCTL(HDIO_GET_DMA, hdio_ioctl_trans) +HANDLE_IOCTL(HDIO_GET_32BIT, hdio_ioctl_trans) +HANDLE_IOCTL(HDIO_GET_MULTCOUNT, hdio_ioctl_trans) +HANDLE_IOCTL(HDIO_GET_NOWERR, hdio_ioctl_trans) +HANDLE_IOCTL(HDIO_GET_NICE, hdio_ioctl_trans) +HANDLE_IOCTL(FDSETPRM32, fd_ioctl_trans) +HANDLE_IOCTL(FDDEFPRM32, fd_ioctl_trans) +HANDLE_IOCTL(FDGETPRM32, fd_ioctl_trans) +HANDLE_IOCTL(FDSETDRVPRM32, fd_ioctl_trans) +HANDLE_IOCTL(FDGETDRVPRM32, fd_ioctl_trans) +HANDLE_IOCTL(FDGETDRVSTAT32, fd_ioctl_trans) +HANDLE_IOCTL(FDPOLLDRVSTAT32, fd_ioctl_trans) +HANDLE_IOCTL(FDGETFDCSTAT32, fd_ioctl_trans) +HANDLE_IOCTL(FDWERRORGET32, fd_ioctl_trans) +HANDLE_IOCTL(PPPIOCGIDLE32, ppp_ioctl_trans) +HANDLE_IOCTL(PPPIOCSCOMPRESS32, ppp_ioctl_trans) +HANDLE_IOCTL(MTIOCGET32, mt_ioctl_trans) +HANDLE_IOCTL(MTIOCPOS32, mt_ioctl_trans) +HANDLE_IOCTL(MTIOCGETCONFIG32, mt_ioctl_trans) +HANDLE_IOCTL(MTIOCSETCONFIG32, mt_ioctl_trans) +HANDLE_IOCTL(CDROMREADMODE2, cdrom_ioctl_trans) +HANDLE_IOCTL(CDROMREADMODE1, cdrom_ioctl_trans) +HANDLE_IOCTL(CDROMREADRAW, cdrom_ioctl_trans) +HANDLE_IOCTL(CDROMREADCOOKED, cdrom_ioctl_trans) +HANDLE_IOCTL(CDROMREADAUDIO, cdrom_ioctl_trans) +HANDLE_IOCTL(CDROMREADALL, cdrom_ioctl_trans) +HANDLE_IOCTL(CDROM_SEND_PACKET, cdrom_ioctl_trans) +HANDLE_IOCTL(LOOP_SET_STATUS, loop_status) +HANDLE_IOCTL(LOOP_GET_STATUS, loop_status) +#define AUTOFS_IOC_SETTIMEOUT32 _IOWR(0x93,0x64,unsigned int) +HANDLE_IOCTL(AUTOFS_IOC_SETTIMEOUT32, ioc_settimeout) +HANDLE_IOCTL(PIO_FONTX, do_fontx_ioctl) +HANDLE_IOCTL(GIO_FONTX, do_fontx_ioctl) +HANDLE_IOCTL(PIO_UNIMAP, do_unimap_ioctl) +HANDLE_IOCTL(GIO_UNIMAP, do_unimap_ioctl) +HANDLE_IOCTL(KDFONTOP, do_kdfontop_ioctl) +HANDLE_IOCTL(EXT2_IOC32_GETFLAGS, do_ext2_ioctl) +HANDLE_IOCTL(EXT2_IOC32_SETFLAGS, do_ext2_ioctl) +HANDLE_IOCTL(EXT2_IOC32_GETVERSION, do_ext2_ioctl) +HANDLE_IOCTL(EXT2_IOC32_SETVERSION, do_ext2_ioctl) +HANDLE_IOCTL(VIDIOCGTUNER32, do_video_ioctl) +HANDLE_IOCTL(VIDIOCSTUNER32, do_video_ioctl) +HANDLE_IOCTL(VIDIOCGWIN32, do_video_ioctl) +HANDLE_IOCTL(VIDIOCSWIN32, do_video_ioctl) +HANDLE_IOCTL(VIDIOCGFBUF32, do_video_ioctl) +HANDLE_IOCTL(VIDIOCSFBUF32, do_video_ioctl) +HANDLE_IOCTL(VIDIOCGFREQ32, do_video_ioctl) +HANDLE_IOCTL(VIDIOCSFREQ32, do_video_ioctl) +/* One SMB ioctl needs translations. */ +#define SMB_IOC_GETMOUNTUID_32 _IOR('u', 1, __kernel_uid_t32) +HANDLE_IOCTL(SMB_IOC_GETMOUNTUID_32, do_smb_getmountuid) +HANDLE_IOCTL(ATM_GETLINKRATE32, do_atm_ioctl) +HANDLE_IOCTL(ATM_GETNAMES32, do_atm_ioctl) +HANDLE_IOCTL(ATM_GETTYPE32, do_atm_ioctl) +HANDLE_IOCTL(ATM_GETESI32, do_atm_ioctl) +HANDLE_IOCTL(ATM_GETADDR32, do_atm_ioctl) +HANDLE_IOCTL(ATM_RSTADDR32, do_atm_ioctl) +HANDLE_IOCTL(ATM_ADDADDR32, do_atm_ioctl) +HANDLE_IOCTL(ATM_DELADDR32, do_atm_ioctl) +HANDLE_IOCTL(ATM_GETCIRANGE32, do_atm_ioctl) +HANDLE_IOCTL(ATM_SETCIRANGE32, do_atm_ioctl) +HANDLE_IOCTL(ATM_SETESI32, do_atm_ioctl) +HANDLE_IOCTL(ATM_SETESIF32, do_atm_ioctl) +HANDLE_IOCTL(ATM_GETSTAT32, do_atm_ioctl) +HANDLE_IOCTL(ATM_GETSTATZ32, do_atm_ioctl) +HANDLE_IOCTL(SUNI_GETLOOP, do_atm_ioctl) +HANDLE_IOCTL(SUNI_SETLOOP, do_atm_ioctl) +HANDLE_IOCTL(SONET_GETSTAT, do_atm_ioctl) +HANDLE_IOCTL(SONET_GETSTATZ, do_atm_ioctl) +HANDLE_IOCTL(SONET_GETDIAG, do_atm_ioctl) +HANDLE_IOCTL(SONET_SETDIAG, do_atm_ioctl) +HANDLE_IOCTL(SONET_CLRDIAG, do_atm_ioctl) +HANDLE_IOCTL(SONET_SETFRAMING, do_atm_ioctl) +HANDLE_IOCTL(SONET_GETFRAMING, do_atm_ioctl) +HANDLE_IOCTL(SONET_GETFRSENSE, do_atm_ioctl) +IOCTL_TABLE_END + +unsigned int ioctl32_hash_table[1024]; + +extern inline unsigned long ioctl32_hash(unsigned long cmd) +{ + return ((cmd >> 6) ^ (cmd >> 4) ^ cmd) & 0x3ff; +} + +static void ioctl32_insert_translation(struct ioctl_trans *trans) +{ + unsigned long hash; + struct ioctl_trans *t; + + hash = ioctl32_hash (trans->cmd); + if (!ioctl32_hash_table[hash]) + ioctl32_hash_table[hash] = (u32)(long)trans; + else { + t = (struct ioctl_trans *)(long)ioctl32_hash_table[hash]; + while (t->next) + t = (struct ioctl_trans *)(long)t->next; + trans->next = 0; + t->next = (u32)(long)trans; + } +} - case PPPIOCGIDLE32: - case PPPIOCSCOMPRESS32: - error = ppp_ioctl_trans(fd, cmd, arg); - goto out; +static int __init init_sys32_ioctl(void) +{ + int i; + extern struct ioctl_trans ioctl_translations[], ioctl_translations_end[]; - case MTIOCGET32: - case MTIOCPOS32: - case MTIOCGETCONFIG32: - case MTIOCSETCONFIG32: - error = mt_ioctl_trans(fd, cmd, arg); - goto out; + for (i = 0; &ioctl_translations[i] < &ioctl_translations_end[0]; i++) + ioctl32_insert_translation(&ioctl_translations[i]); + return 0; +} - case CDROMREADMODE2: - case CDROMREADMODE1: - case CDROMREADRAW: - case CDROMREADCOOKED: - case CDROMREADAUDIO: - case CDROMREADALL: - case CDROM_SEND_PACKET: - error = cdrom_ioctl_trans(fd, cmd, arg); - goto out; - - case LOOP_SET_STATUS: - case LOOP_GET_STATUS: - error = loop_status(fd, cmd, arg); - goto out; +__initcall(init_sys32_ioctl); -#define AUTOFS_IOC_SETTIMEOUT32 _IOWR(0x93,0x64,unsigned int) - case AUTOFS_IOC_SETTIMEOUT32: - error = rw_long(fd, AUTOFS_IOC_SETTIMEOUT, arg); - goto out; - - case PIO_FONTX: - case GIO_FONTX: - error = do_fontx_ioctl(filp, cmd, (struct consolefontdesc32 *)arg); - goto out; - - case PIO_UNIMAP: - case GIO_UNIMAP: - error = do_unimap_ioctl(filp, cmd, (struct unimapdesc32 *)arg); - goto out; +static struct ioctl_trans *additional_ioctls; - case KDFONTOP: - error = do_kdfontop_ioctl(filp, (struct console_font_op32 *)arg); - goto out; - - case EXT2_IOC32_GETFLAGS: - case EXT2_IOC32_SETFLAGS: - case EXT2_IOC32_GETVERSION: - case EXT2_IOC32_SETVERSION: - error = do_ext2_ioctl(fd, cmd, arg); - goto out; - - case VIDIOCGTUNER32: - case VIDIOCSTUNER32: - case VIDIOCGWIN32: - case VIDIOCSWIN32: - case VIDIOCGFBUF32: - case VIDIOCSFBUF32: - case VIDIOCGFREQ32: - case VIDIOCSFREQ32: - error = do_video_ioctl(fd, cmd, arg); - goto out; +/* Always call these with kernel lock held! */ - /* One SMB ioctl needs translations. */ - case _IOR('u', 1, __kernel_uid_t32): /* SMB_IOC_GETMOUNTUID */ - error = do_smb_getmountuid(fd, cmd, arg); - goto out; +int register_ioctl32_conversion(unsigned int cmd, int (*handler)(unsigned int, unsigned int, unsigned long, struct file *)) +{ + int i; + if (!additional_ioctls) { + additional_ioctls = module_map(PAGE_SIZE); + if (!additional_ioctls) return -ENOMEM; + } + for (i = 0; i < PAGE_SIZE/sizeof(struct ioctl_trans); i++) + if (!additional_ioctls[i].cmd) + break; + if (i == PAGE_SIZE/sizeof(struct ioctl_trans)) + return -ENOMEM; + additional_ioctls[i].cmd = cmd; + if (!handler) + additional_ioctls[i].handler = (u32)(long)sys_ioctl; + else + additional_ioctls[i].handler = (u32)(long)handler; + ioctl32_insert_translation(&additional_ioctls[i]); + return 0; +} - case ATM_GETLINKRATE32: - case ATM_GETNAMES32: - case ATM_GETTYPE32: - case ATM_GETESI32: - case ATM_GETADDR32: - case ATM_RSTADDR32: - case ATM_ADDADDR32: - case ATM_DELADDR32: - case ATM_GETCIRANGE32: - case ATM_SETCIRANGE32: - case ATM_SETESI32: - case ATM_SETESIF32: - case ATM_GETSTAT32: - case ATM_GETSTATZ32: - case SUNI_GETLOOP: - case SUNI_SETLOOP: - case SONET_GETSTAT: - case SONET_GETSTATZ: - case SONET_GETDIAG: - case SONET_SETDIAG: - case SONET_CLRDIAG: - case SONET_SETFRAMING: - case SONET_GETFRAMING: - case SONET_GETFRSENSE: - error = do_atm_ioctl(fd, cmd, arg); - goto out; - - /* List here exlicitly which ioctl's are known to have - * compatable types passed or none at all... - */ +int unregister_ioctl32_conversion(unsigned int cmd) +{ + unsigned long hash = ioctl32_hash(cmd); + struct ioctl_trans *t, *t1; - /* Big T */ - case TCGETA: - case TCSETA: - case TCSETAW: - case TCSETAF: - case TCSBRK: - case TCXONC: - case TCFLSH: - case TCGETS: - case TCSETS: - case TCSETSW: - case TCSETSF: - case TIOCLINUX: - - /* Little t */ - case TIOCGETD: - case TIOCSETD: - case TIOCEXCL: - case TIOCNXCL: - case TIOCCONS: - case TIOCGSOFTCAR: - case TIOCSSOFTCAR: - case TIOCSWINSZ: - case TIOCGWINSZ: - case TIOCMGET: - case TIOCMBIC: - case TIOCMBIS: - case TIOCMSET: - case TIOCPKT: - case TIOCNOTTY: - case TIOCSTI: - case TIOCOUTQ: - case TIOCSPGRP: - case TIOCGPGRP: - case TIOCSCTTY: - case TIOCGPTN: - case TIOCSPTLCK: - case TIOCGSERIAL: - case TIOCSSERIAL: - case TIOCSERGETLSR: - - /* Big F */ - case FBIOGTYPE: - case FBIOSATTR: - case FBIOGATTR: - case FBIOSVIDEO: - case FBIOGVIDEO: - case FBIOGCURSOR32: /* This is not implemented yet. Later it should be converted... */ - case FBIOSCURPOS: - case FBIOGCURPOS: - case FBIOGCURMAX: - - case FBIOGET_VSCREENINFO: - case FBIOPUT_VSCREENINFO: - case FBIOPAN_DISPLAY: - case FBIOGET_FCURSORINFO: - case FBIOGET_VCURSORINFO: - case FBIOPUT_VCURSORINFO: - case FBIOGET_CURSORSTATE: - case FBIOPUT_CURSORSTATE: - case FBIOGET_CON2FBMAP: - case FBIOPUT_CON2FBMAP: - - /* Little f */ - case FIOCLEX: - case FIONCLEX: - case FIOASYNC: - case FIONBIO: - case FIONREAD: /* This is also TIOCINQ */ - - /* 0x00 */ - case FIBMAP: - case FIGETBSZ: - - /* 0x03 -- HD/IDE ioctl's used by hdparm and friends. - * Some need translations, these do not. - */ - case HDIO_GET_IDENTITY: - case HDIO_SET_DMA: - case HDIO_SET_KEEPSETTINGS: - case HDIO_SET_UNMASKINTR: - case HDIO_SET_NOWERR: - case HDIO_SET_32BIT: - case HDIO_SET_MULTCOUNT: - case HDIO_DRIVE_CMD: - case HDIO_SET_PIO_MODE: - case HDIO_SCAN_HWIF: - case HDIO_SET_NICE: - case BLKROSET: - case BLKROGET: - - /* 0x02 -- Floppy ioctls */ - case FDMSGON: - case FDMSGOFF: - case FDSETEMSGTRESH: - case FDFLUSH: - case FDWERRORCLR: - case FDSETMAXERRS: - case FDGETMAXERRS: - case FDGETDRVTYP: - case FDEJECT: - case FDCLRPRM: - case FDFMTBEG: - case FDFMTEND: - case FDRESET: - case FDTWADDLE: - case FDFMTTRK: - case FDRAWCMD: - - /* 0x12 */ - case BLKRRPART: - case BLKFLSBUF: - case BLKRASET: + t = (struct ioctl_trans *)(long)ioctl32_hash_table[hash]; + if (!t) return -EINVAL; + if (t->cmd == cmd && t >= additional_ioctls && + (unsigned long)t < ((unsigned long)additional_ioctls) + PAGE_SIZE) { + ioctl32_hash_table[hash] = t->next; + t->cmd = 0; + return 0; + } else while (t->next) { + t1 = (struct ioctl_trans *)(long)t->next; + if (t1->cmd == cmd && t1 >= additional_ioctls && + (unsigned long)t1 < ((unsigned long)additional_ioctls) + PAGE_SIZE) { + t1->cmd = 0; + t->next = t1->next; + return 0; + } + t = t1; + } + return -EINVAL; +} -#if 0 /* New RAID code is being merged, fix up to handle - * new RAID ioctls when fully merged in 2.3.x -DaveM - */ - /* 0x09 */ - case REGISTER_DEV: - case REGISTER_DEV_NEW: - case START_MD: - case STOP_MD: -#endif - - /* Big K */ - case PIO_FONT: - case GIO_FONT: - case KDSIGACCEPT: - case KDGETKEYCODE: - case KDSETKEYCODE: - case KIOCSOUND: - case KDMKTONE: - case KDGKBTYPE: - case KDSETMODE: - case KDGETMODE: - case KDSKBMODE: - case KDGKBMODE: - case KDSKBMETA: - case KDGKBMETA: - case KDGKBENT: - case KDSKBENT: - case KDGKBSENT: - case KDSKBSENT: - case KDGKBDIACR: - case KDSKBDIACR: - case KDGKBLED: - case KDSKBLED: - case KDGETLED: - case KDSETLED: - case GIO_SCRNMAP: - case PIO_SCRNMAP: - case GIO_UNISCRNMAP: - case PIO_UNISCRNMAP: - case PIO_FONTRESET: - case PIO_UNIMAPCLR: - - /* Little k */ - case KIOCTYPE: - case KIOCLAYOUT: - case KIOCGTRANS: - case KIOCTRANS: - case KIOCCMD: - case KIOCSDIRECT: - case KIOCSLED: - case KIOCGLED: - case KIOCSRATE: - case KIOCGRATE: - - /* Big S */ - case SCSI_IOCTL_GET_IDLUN: - case SCSI_IOCTL_DOORLOCK: - case SCSI_IOCTL_DOORUNLOCK: - case SCSI_IOCTL_TEST_UNIT_READY: - case SCSI_IOCTL_TAGGED_ENABLE: - case SCSI_IOCTL_TAGGED_DISABLE: - case SCSI_IOCTL_GET_BUS_NUMBER: - case SCSI_IOCTL_SEND_COMMAND: - - /* Big V */ - case VT_SETMODE: - case VT_GETMODE: - case VT_GETSTATE: - case VT_OPENQRY: - case VT_ACTIVATE: - case VT_WAITACTIVE: - case VT_RELDISP: - case VT_DISALLOCATE: - case VT_RESIZE: - case VT_RESIZEX: - case VT_LOCKSWITCH: - case VT_UNLOCKSWITCH: - - /* Little v */ - case VUIDSFORMAT: - case VUIDGFORMAT: - - /* Little v, the video4linux ioctls */ - case VIDIOCGCAP: - case VIDIOCGCHAN: - case VIDIOCSCHAN: - case VIDIOCGPICT: - case VIDIOCSPICT: - case VIDIOCCAPTURE: - case VIDIOCKEY: - case VIDIOCGAUDIO: - case VIDIOCSAUDIO: - case VIDIOCSYNC: - case VIDIOCMCAPTURE: - case VIDIOCGMBUF: - case VIDIOCGUNIT: - case VIDIOCGCAPTURE: - case VIDIOCSCAPTURE: - - /* BTTV specific... */ - case _IOW('v', BASE_VIDIOCPRIVATE+0, char [256]): - case _IOR('v', BASE_VIDIOCPRIVATE+1, char [256]): - case _IOR('v' , BASE_VIDIOCPRIVATE+2, unsigned int): - case _IOW('v' , BASE_VIDIOCPRIVATE+3, char [16]): /* struct bttv_pll_info */ - case _IOR('v' , BASE_VIDIOCPRIVATE+4, int): - case _IOR('v' , BASE_VIDIOCPRIVATE+5, int): - case _IOR('v' , BASE_VIDIOCPRIVATE+6, int): - case _IOR('v' , BASE_VIDIOCPRIVATE+7, int): - - /* Little p (/dev/rtc, /dev/envctrl, etc.) */ - case RTCGET: - case RTCSET: - case I2CIOCSADR: - case I2CIOCGADR: +asmlinkage int sys32_ioctl(unsigned int fd, unsigned int cmd, unsigned long arg) +{ + struct file * filp; + int error = -EBADF; + int (*handler)(unsigned int, unsigned int, unsigned long, struct file * filp); + struct ioctl_trans *t; - /* Little m */ - case MTIOCTOP: + lock_kernel(); + filp = fget(fd); + if(!filp) + goto out2; - /* OPENPROMIO, SunOS/Solaris only, the NetBSD one's have - * embedded pointers in the arg which we'd need to clean up... - */ - case OPROMGETOPT: - case OPROMSETOPT: - case OPROMNXTOPT: - case OPROMSETOPT2: - case OPROMNEXT: - case OPROMCHILD: - case OPROMGETPROP: - case OPROMNXTPROP: - case OPROMU2P: - case OPROMGETCONS: - case OPROMGETFBNAME: - case OPROMGETBOOTARGS: - case OPROMSETCUR: - case OPROMPCI2NODE: - case OPROMPATH2NODE: - - /* Socket level stuff */ - case FIOSETOWN: - case SIOCSPGRP: - case FIOGETOWN: - case SIOCGPGRP: - case SIOCATMARK: - case SIOCSIFLINK: - case SIOCSIFENCAP: - case SIOCGIFENCAP: - case SIOCSIFBR: - case SIOCGIFBR: - case SIOCSARP: - case SIOCGARP: - case SIOCDARP: -#if 0 /* XXX No longer exist in new routing code. XXX */ - case OLD_SIOCSARP: - case OLD_SIOCGARP: - case OLD_SIOCDARP: -#endif - case SIOCSRARP: - case SIOCGRARP: - case SIOCDRARP: - case SIOCADDDLCI: - case SIOCDELDLCI: - - /* SG stuff */ - case SG_SET_TIMEOUT: - case SG_GET_TIMEOUT: - case SG_EMULATED_HOST: - case SG_SET_TRANSFORM: - case SG_GET_TRANSFORM: - - /* PPP stuff */ - case PPPIOCGFLAGS: - case PPPIOCSFLAGS: - case PPPIOCGASYNCMAP: - case PPPIOCSASYNCMAP: - case PPPIOCGUNIT: - case PPPIOCGRASYNCMAP: - case PPPIOCSRASYNCMAP: - case PPPIOCGMRU: - case PPPIOCSMRU: - case PPPIOCSMAXCID: - case PPPIOCGXASYNCMAP: - case PPPIOCSXASYNCMAP: - case PPPIOCXFERUNIT: - case PPPIOCGNPMODE: - case PPPIOCSNPMODE: - case PPPIOCGDEBUG: - case PPPIOCSDEBUG: - case PPPIOCNEWUNIT: - case PPPIOCATTACH: - case PPPIOCDETACH: - - /* CDROM stuff */ - case CDROMPAUSE: - case CDROMRESUME: - case CDROMPLAYMSF: - case CDROMPLAYTRKIND: - case CDROMREADTOCHDR: - case CDROMREADTOCENTRY: - case CDROMSTOP: - case CDROMSTART: - case CDROMEJECT: - case CDROMVOLCTRL: - case CDROMSUBCHNL: - case CDROMEJECT_SW: - case CDROMMULTISESSION: - case CDROM_GET_MCN: - case CDROMRESET: - case CDROMVOLREAD: - case CDROMSEEK: - case CDROMPLAYBLK: - case CDROMCLOSETRAY: - case CDROM_SET_OPTIONS: - case CDROM_CLEAR_OPTIONS: - case CDROM_SELECT_SPEED: - case CDROM_SELECT_DISC: - case CDROM_MEDIA_CHANGED: - case CDROM_DRIVE_STATUS: - case CDROM_DISC_STATUS: - case CDROM_CHANGER_NSLOTS: - case CDROM_LOCKDOOR: - case CDROM_DEBUG: - case CDROM_GET_CAPABILITY: - - /* Big L */ - case LOOP_SET_FD: - case LOOP_CLR_FD: - - /* Big A */ - case AUDIO_GETINFO: - case AUDIO_SETINFO: - case AUDIO_DRAIN: - case AUDIO_GETDEV: - case AUDIO_GETDEV_SUNOS: - case AUDIO_FLUSH: - - /* Big Q for sound/OSS */ - case SNDCTL_SEQ_RESET: - case SNDCTL_SEQ_SYNC: - case SNDCTL_SYNTH_INFO: - case SNDCTL_SEQ_CTRLRATE: - case SNDCTL_SEQ_GETOUTCOUNT: - case SNDCTL_SEQ_GETINCOUNT: - case SNDCTL_SEQ_PERCMODE: - case SNDCTL_FM_LOAD_INSTR: - case SNDCTL_SEQ_TESTMIDI: - case SNDCTL_SEQ_RESETSAMPLES: - case SNDCTL_SEQ_NRSYNTHS: - case SNDCTL_SEQ_NRMIDIS: - case SNDCTL_MIDI_INFO: - case SNDCTL_SEQ_THRESHOLD: - case SNDCTL_SYNTH_MEMAVL: - case SNDCTL_FM_4OP_ENABLE: - case SNDCTL_SEQ_PANIC: - case SNDCTL_SEQ_OUTOFBAND: - case SNDCTL_SEQ_GETTIME: - case SNDCTL_SYNTH_ID: - case SNDCTL_SYNTH_CONTROL: - case SNDCTL_SYNTH_REMOVESAMPLE: - - /* Big T for sound/OSS */ - case SNDCTL_TMR_TIMEBASE: - case SNDCTL_TMR_START: - case SNDCTL_TMR_STOP: - case SNDCTL_TMR_CONTINUE: - case SNDCTL_TMR_TEMPO: - case SNDCTL_TMR_SOURCE: - case SNDCTL_TMR_METRONOME: - case SNDCTL_TMR_SELECT: - - /* Little m for sound/OSS */ - case SNDCTL_MIDI_PRETIME: - case SNDCTL_MIDI_MPUMODE: - case SNDCTL_MIDI_MPUCMD: - - /* Big P for sound/OSS */ - case SNDCTL_DSP_RESET: - case SNDCTL_DSP_SYNC: - case SNDCTL_DSP_SPEED: - case SNDCTL_DSP_STEREO: - case SNDCTL_DSP_GETBLKSIZE: - case SNDCTL_DSP_CHANNELS: - case SOUND_PCM_WRITE_FILTER: - case SNDCTL_DSP_POST: - case SNDCTL_DSP_SUBDIVIDE: - case SNDCTL_DSP_SETFRAGMENT: - case SNDCTL_DSP_GETFMTS: - case SNDCTL_DSP_SETFMT: - case SNDCTL_DSP_GETOSPACE: - case SNDCTL_DSP_GETISPACE: - case SNDCTL_DSP_NONBLOCK: - case SNDCTL_DSP_GETCAPS: - case SNDCTL_DSP_GETTRIGGER: - case SNDCTL_DSP_SETTRIGGER: - case SNDCTL_DSP_GETIPTR: - case SNDCTL_DSP_GETOPTR: - /* case SNDCTL_DSP_MAPINBUF: XXX needs translation */ - /* case SNDCTL_DSP_MAPOUTBUF: XXX needs translation */ - case SNDCTL_DSP_SETSYNCRO: - case SNDCTL_DSP_SETDUPLEX: - case SNDCTL_DSP_GETODELAY: - case SNDCTL_DSP_PROFILE: - - case SOUND_PCM_READ_RATE: - case SOUND_PCM_READ_CHANNELS: - case SOUND_PCM_READ_BITS: - case SOUND_PCM_READ_FILTER: - - /* Big C for sound/OSS */ - case SNDCTL_COPR_RESET: - case SNDCTL_COPR_LOAD: - case SNDCTL_COPR_RDATA: - case SNDCTL_COPR_RCODE: - case SNDCTL_COPR_WDATA: - case SNDCTL_COPR_WCODE: - case SNDCTL_COPR_RUN: - case SNDCTL_COPR_HALT: - case SNDCTL_COPR_SENDMSG: - case SNDCTL_COPR_RCVMSG: - - /* Big M for sound/OSS */ - case SOUND_MIXER_READ_VOLUME: - case SOUND_MIXER_READ_BASS: - case SOUND_MIXER_READ_TREBLE: - case SOUND_MIXER_READ_SYNTH: - case SOUND_MIXER_READ_PCM: - case SOUND_MIXER_READ_SPEAKER: - case SOUND_MIXER_READ_LINE: - case SOUND_MIXER_READ_MIC: - case SOUND_MIXER_READ_CD: - case SOUND_MIXER_READ_IMIX: - case SOUND_MIXER_READ_ALTPCM: - case SOUND_MIXER_READ_RECLEV: - case SOUND_MIXER_READ_IGAIN: - case SOUND_MIXER_READ_OGAIN: - case SOUND_MIXER_READ_LINE1: - case SOUND_MIXER_READ_LINE2: - case SOUND_MIXER_READ_LINE3: - case SOUND_MIXER_READ_MUTE: - /* case SOUND_MIXER_READ_ENHANCE: same value as READ_MUTE */ - /* case SOUND_MIXER_READ_LOUD: same value as READ_MUTE */ - case SOUND_MIXER_READ_RECSRC: - case SOUND_MIXER_READ_DEVMASK: - case SOUND_MIXER_READ_RECMASK: - case SOUND_MIXER_READ_STEREODEVS: - case SOUND_MIXER_READ_CAPS: - - case SOUND_MIXER_WRITE_VOLUME: - case SOUND_MIXER_WRITE_BASS: - case SOUND_MIXER_WRITE_TREBLE: - case SOUND_MIXER_WRITE_SYNTH: - case SOUND_MIXER_WRITE_PCM: - case SOUND_MIXER_WRITE_SPEAKER: - case SOUND_MIXER_WRITE_LINE: - case SOUND_MIXER_WRITE_MIC: - case SOUND_MIXER_WRITE_CD: - case SOUND_MIXER_WRITE_IMIX: - case SOUND_MIXER_WRITE_ALTPCM: - case SOUND_MIXER_WRITE_RECLEV: - case SOUND_MIXER_WRITE_IGAIN: - case SOUND_MIXER_WRITE_OGAIN: - case SOUND_MIXER_WRITE_LINE1: - case SOUND_MIXER_WRITE_LINE2: - case SOUND_MIXER_WRITE_LINE3: - case SOUND_MIXER_WRITE_MUTE: - /* case SOUND_MIXER_WRITE_ENHANCE: same value as WRITE_MUTE */ - /* case SOUND_MIXER_WRITE_LOUD: same value as WRITE_MUTE */ - case SOUND_MIXER_WRITE_RECSRC: - - case SOUND_MIXER_INFO: - case SOUND_OLD_MIXER_INFO: - case SOUND_MIXER_ACCESS: - case SOUND_MIXER_PRIVATE1: - case SOUND_MIXER_PRIVATE2: - case SOUND_MIXER_PRIVATE3: - case SOUND_MIXER_PRIVATE4: - case SOUND_MIXER_PRIVATE5: - case SOUND_MIXER_GETLEVELS: - case SOUND_MIXER_SETLEVELS: - - case OSS_GETVERSION: - - /* AUTOFS */ - case AUTOFS_IOC_READY: - case AUTOFS_IOC_FAIL: - case AUTOFS_IOC_CATATONIC: - case AUTOFS_IOC_PROTOVER: - case AUTOFS_IOC_EXPIRE: - - /* Raw devices */ - case RAW_SETBIND: - case RAW_GETBIND: - - /* SMB ioctls which do not need any translations */ - case SMB_IOC_NEWCONN: - - /* Little a */ - case ATMSIGD_CTRL: - case ATMARPD_CTRL: - case ATMLEC_CTRL: - case ATMLEC_MCAST: - case ATMLEC_DATA: - case ATM_SETSC: - case SIOCSIFATMTCP: - case SIOCMKCLIP: - case ATMARP_MKIP: - case ATMARP_SETENTRY: - case ATMARP_ENCAP: - case ATMTCP_CREATE: - case ATMTCP_REMOVE: - case ATMMPC_CTRL: - case ATMMPC_DATA: - + if (!filp->f_op || !filp->f_op->ioctl) { error = sys_ioctl (fd, cmd, arg); goto out; + } - default: - do { - static int count = 0; - if (++count <= 20) - printk("sys32_ioctl: Unknown cmd fd(%d) " - "cmd(%08x) arg(%08x)\n", - (int)fd, (unsigned int)cmd, (unsigned int)arg); - } while(0); + t = (struct ioctl_trans *)(long)ioctl32_hash_table [ioctl32_hash (cmd)]; + + while (t && t->cmd != cmd) + t = (struct ioctl_trans *)(long)t->next; + if (t) { + handler = (void *)(long)t->handler; + error = handler(fd, cmd, arg, filp); + } else { + static int count = 0; + if (++count <= 20) + printk("sys32_ioctl: Unknown cmd fd(%d) " + "cmd(%08x) arg(%08x)\n", + (int)fd, (unsigned int)cmd, (unsigned int)arg); error = -EINVAL; - break; } out: fput(filp); diff -u --recursive --new-file v2.3.46/linux/arch/sparc64/kernel/pci_iommu.c linux/arch/sparc64/kernel/pci_iommu.c --- v2.3.46/linux/arch/sparc64/kernel/pci_iommu.c Wed Feb 16 17:03:51 2000 +++ linux/arch/sparc64/kernel/pci_iommu.c Fri Feb 18 15:07:20 2000 @@ -1,4 +1,4 @@ -/* $Id: pci_iommu.c,v 1.8 2000/01/28 13:41:59 jj Exp $ +/* $Id: pci_iommu.c,v 1.10 2000/02/18 13:48:54 davem Exp $ * pci_iommu.c: UltraSparc PCI controller IOM/STC support. * * Copyright (C) 1999 David S. Miller (davem@redhat.com) @@ -99,13 +99,12 @@ return NULL; } -#define IOPTE_CONSISTANT(CTX, PADDR) \ - (IOPTE_VALID | IOPTE_CACHE | IOPTE_WRITE | \ - (((CTX) << 47) & IOPTE_CONTEXT) | \ - ((PADDR) & IOPTE_PAGE)) +#define IOPTE_CONSISTENT(CTX) \ + (IOPTE_VALID | IOPTE_CACHE | \ + (((CTX) << 47) & IOPTE_CONTEXT)) -#define IOPTE_STREAMING(CTX, PADDR) \ - (IOPTE_CONSISTANT(CTX, PADDR) | IOPTE_STBUF) +#define IOPTE_STREAMING(CTX) \ + (IOPTE_CONSISTENT(CTX) | IOPTE_STBUF) #define IOPTE_INVALID 0UL @@ -127,11 +126,6 @@ if (order >= 10) return NULL; - /* We still don't support devices which don't recognize at least 30 bits - of bus address. Bug me to code it (is pretty easy actually). -jj */ - if ((pdev->dma_mask & 0x3fffffff) != 0x3fffffff) - BUG(); - first_page = __get_free_pages(GFP_ATOMIC, order); if (first_page == 0UL) return NULL; @@ -157,7 +151,9 @@ ctx = iommu->iommu_cur_ctx++; first_page = __pa(first_page); while (npages--) { - iopte_val(*iopte) = IOPTE_CONSISTANT(ctx, first_page); + iopte_val(*iopte) = (IOPTE_CONSISTENT(ctx) | + IOPTE_WRITE | + (first_page & IOPTE_PAGE)); iopte++; first_page += PAGE_SIZE; } @@ -215,7 +211,7 @@ /* Map a single buffer at PTR of SZ bytes for PCI DMA * in streaming mode. */ -dma_addr_t pci_map_single(struct pci_dev *pdev, void *ptr, size_t sz) +dma_addr_t pci_map_single(struct pci_dev *pdev, void *ptr, size_t sz, int direction) { struct pcidev_cookie *pcp; struct pci_iommu *iommu; @@ -224,14 +220,13 @@ unsigned long flags, npages, oaddr; unsigned long i, base_paddr, ctx; u32 bus_addr, ret; + unsigned long iopte_protection; pcp = pdev->sysdata; iommu = &pcp->pbm->parent->iommu; strbuf = &pcp->pbm->stc; - /* We still don't support devices which don't recognize at least 30 bits - of bus address. Bug me to code it (is pretty easy actually). -jj */ - if ((pdev->dma_mask & 0x3fffffff) != 0x3fffffff) + if (direction == PCI_DMA_NONE) BUG(); oaddr = (unsigned long)ptr; @@ -248,13 +243,15 @@ ctx = 0; if (iommu->iommu_ctxflush) ctx = iommu->iommu_cur_ctx++; - if (strbuf->strbuf_enabled) { - for (i = 0; i < npages; i++, base++, base_paddr += PAGE_SIZE) - iopte_val(*base) = IOPTE_STREAMING(ctx, base_paddr); - } else { - for (i = 0; i < npages; i++, base++, base_paddr += PAGE_SIZE) - iopte_val(*base) = IOPTE_CONSISTANT(ctx, base_paddr); - } + if (strbuf->strbuf_enabled) + iopte_protection = IOPTE_STREAMING(ctx); + else + iopte_protection = IOPTE_CONSISTENT(ctx); + if (direction != PCI_DMA_TODEVICE) + iopte_protection |= IOPTE_WRITE; + + for (i = 0; i < npages; i++, base++, base_paddr += PAGE_SIZE) + iopte_val(*base) = iopte_protection | base_paddr; /* Flush the IOMMU TLB. */ if (iommu->iommu_ctxflush) { @@ -270,7 +267,7 @@ } /* Unmap a single streaming mode DMA translation. */ -void pci_unmap_single(struct pci_dev *pdev, dma_addr_t bus_addr, size_t sz) +void pci_unmap_single(struct pci_dev *pdev, dma_addr_t bus_addr, size_t sz, int direction) { struct pcidev_cookie *pcp; struct pci_iommu *iommu; @@ -278,6 +275,9 @@ iopte_t *base; unsigned long flags, npages, i, ctx; + if (direction == PCI_DMA_NONE) + BUG(); + pcp = pdev->sysdata; iommu = &pcp->pbm->parent->iommu; strbuf = &pcp->pbm->stc; @@ -335,7 +335,7 @@ spin_unlock_irqrestore(&iommu->lock, flags); } -static inline void fill_sg(iopte_t *iopte, struct scatterlist *sg, int nused, unsigned long ctx, int streaming) +static inline void fill_sg(iopte_t *iopte, struct scatterlist *sg, int nused, unsigned long iopte_protection) { struct scatterlist *dma_sg = sg; int i; @@ -375,10 +375,7 @@ sg++; } - if (streaming) - pteval = IOPTE_STREAMING(ctx, pteval); - else - pteval = IOPTE_CONSISTANT(ctx, pteval); + pteval = iopte_protection | (pteval & IOPTE_PAGE); while (len > 0) { *iopte++ = __iopte(pteval); pteval += PAGE_SIZE; @@ -413,12 +410,12 @@ * When making changes here, inspect the assembly output. I was having * hard time to kepp this routine out of using stack slots for holding variables. */ -int pci_map_sg(struct pci_dev *pdev, struct scatterlist *sglist, int nelems) +int pci_map_sg(struct pci_dev *pdev, struct scatterlist *sglist, int nelems, int direction) { struct pcidev_cookie *pcp; struct pci_iommu *iommu; struct pci_strbuf *strbuf; - unsigned long flags, ctx, i, npages; + unsigned long flags, ctx, i, npages, iopte_protection; iopte_t *base; u32 dma_base; struct scatterlist *sgtmp; @@ -426,7 +423,7 @@ /* Fast path single entry scatterlists. */ if (nelems == 1) { - sglist->dvma_address = pci_map_single(pdev, sglist->address, sglist->length); + sglist->dvma_address = pci_map_single(pdev, sglist->address, sglist->length, direction); sglist->dvma_length = sglist->length; return 1; } @@ -435,9 +432,7 @@ iommu = &pcp->pbm->parent->iommu; strbuf = &pcp->pbm->stc; - /* We still don't support devices which don't recognize at least 30 bits - of bus address. Bug me to code it (is pretty easy actually). -jj */ - if ((pdev->dma_mask & 0x3fffffff) != 0x3fffffff) + if (direction == PCI_DMA_NONE) BUG(); /* Step 1: Prepare scatter list. */ @@ -468,7 +463,13 @@ ctx = iommu->iommu_cur_ctx++; /* Step 5: Create the mappings. */ - fill_sg (base, sglist, used, ctx, strbuf->strbuf_enabled); + if (strbuf->strbuf_enabled) + iopte_protection = IOPTE_STREAMING(ctx); + else + iopte_protection = IOPTE_CONSISTENT(ctx); + if (direction != PCI_DMA_TODEVICE) + iopte_protection |= IOPTE_WRITE; + fill_sg (base, sglist, used, iopte_protection); #ifdef VERIFY_SG verify_sglist(sglist, nelems, base, npages); #endif @@ -487,7 +488,7 @@ } /* Unmap a set of streaming mode DMA translations. */ -void pci_unmap_sg(struct pci_dev *pdev, struct scatterlist *sglist, int nelems) +void pci_unmap_sg(struct pci_dev *pdev, struct scatterlist *sglist, int nelems, int direction) { struct pcidev_cookie *pcp; struct pci_iommu *iommu; @@ -496,6 +497,9 @@ unsigned long flags, ctx, i, npages; u32 bus_addr; + if (direction == PCI_DMA_NONE) + BUG(); + pcp = pdev->sysdata; iommu = &pcp->pbm->parent->iommu; strbuf = &pcp->pbm->stc; @@ -562,7 +566,7 @@ /* Make physical memory consistent for a single * streaming mode DMA translation after a transfer. */ -void pci_dma_sync_single(struct pci_dev *pdev, dma_addr_t bus_addr, size_t sz) +void pci_dma_sync_single(struct pci_dev *pdev, dma_addr_t bus_addr, size_t sz, int direction) { struct pcidev_cookie *pcp; struct pci_iommu *iommu; @@ -623,7 +627,7 @@ /* Make physical memory consistent for a set of streaming * mode DMA translations after a transfer. */ -void pci_dma_sync_sg(struct pci_dev *pdev, struct scatterlist *sglist, int nelems) +void pci_dma_sync_sg(struct pci_dev *pdev, struct scatterlist *sglist, int nelems, int direction) { struct pcidev_cookie *pcp; struct pci_iommu *iommu; @@ -683,4 +687,20 @@ membar("#LoadLoad"); spin_unlock_irqrestore(&iommu->lock, flags); +} + +int pci_dma_supported(struct pci_dev *pdev, dma_addr_t device_mask) +{ + struct pcidev_cookie *pcp = pdev->sysdata; + u32 dma_addr_mask; + + if (pdev == NULL) { + dma_addr_mask = 0xffffffff; + } else { + struct pci_iommu *iommu = &pcp->pbm->parent->iommu; + + dma_addr_mask = iommu->dma_addr_mask; + } + + return (device_mask & dma_addr_mask) == dma_addr_mask; } diff -u --recursive --new-file v2.3.46/linux/arch/sparc64/kernel/pci_psycho.c linux/arch/sparc64/kernel/pci_psycho.c --- v2.3.46/linux/arch/sparc64/kernel/pci_psycho.c Thu Feb 10 17:11:06 2000 +++ linux/arch/sparc64/kernel/pci_psycho.c Fri Feb 18 15:07:20 2000 @@ -1,4 +1,4 @@ -/* $Id: pci_psycho.c,v 1.11 2000/02/08 05:11:32 jj Exp $ +/* $Id: pci_psycho.c,v 1.13 2000/02/18 13:48:54 davem Exp $ * pci_psycho.c: PSYCHO/U2P specific PCI controller support. * * Copyright (C) 1997, 1998, 1999 David S. Miller (davem@caipfs.rutgers.edu) @@ -1264,6 +1264,7 @@ p->iommu.page_table = (iopte_t *)tsbbase; p->iommu.page_table_sz_bits = 17; p->iommu.page_table_map_base = 0xc0000000; + p->iommu.dma_addr_mask = 0xffffffff; memset((char *)tsbbase, 0, PAGE_SIZE << 7); /* Make sure DMA address 0 is never returned just to allow catching @@ -1344,9 +1345,7 @@ int is_pbm_a) { unsigned long base = p->controller_regs; - - /* Currently we don't even use it. */ - pbm->stc.strbuf_enabled = 0; + u64 control; if (is_pbm_a) { pbm->stc.strbuf_control = base + PSYCHO_STRBUF_CONTROL_A; @@ -1368,14 +1367,29 @@ pbm->stc.strbuf_flushflag_pa = (unsigned long) __pa(pbm->stc.strbuf_flushflag); -#if 0 - /* And when we do enable it, these are the sorts of things - * we'll do. + /* Enable the streaming buffer. We have to be careful + * just in case OBP left it with LRU locking enabled. + * + * It is possible to control if PBM will be rerun on + * line misses. Currently I just retain whatever setting + * OBP left us with. All checks so far show it having + * a value of zero. */ +#undef PSYCHO_STRBUF_RERUN_ENABLE +#undef PSYCHO_STRBUF_RERUN_DISABLE control = psycho_read(pbm->stc.strbuf_control); - control |= PSYCHO_SBUFCTRL_SB_EN; - psycho_write(pbm->stc.strbuf_control, control); + control |= PSYCHO_STRBUF_CTRL_ENAB; + control &= ~(PSYCHO_STRBUF_CTRL_LENAB | PSYCHO_STRBUF_CTRL_LPTR); +#ifdef PSYCHO_STRBUF_RERUN_ENABLE + control &= ~(PSYCHO_STRBUF_CTRL_RRDIS); +#else +#ifdef PSYCHO_STRBUF_RERUN_DISABLE + control |= PSYCHO_STRBUF_CTRL_RRDIS; #endif +#endif + psycho_write(pbm->stc.strbuf_control, control); + + pbm->stc.strbuf_enabled = 1; } #define PSYCHO_IOSPACE_A 0x002000000UL diff -u --recursive --new-file v2.3.46/linux/arch/sparc64/kernel/pci_sabre.c linux/arch/sparc64/kernel/pci_sabre.c --- v2.3.46/linux/arch/sparc64/kernel/pci_sabre.c Wed Feb 16 17:03:51 2000 +++ linux/arch/sparc64/kernel/pci_sabre.c Fri Feb 18 15:07:20 2000 @@ -1,4 +1,4 @@ -/* $Id: pci_sabre.c,v 1.12 2000/02/08 05:11:33 jj Exp $ +/* $Id: pci_sabre.c,v 1.14 2000/02/18 13:48:55 davem Exp $ * pci_sabre.c: Sabre specific PCI controller support. * * Copyright (C) 1997, 1998, 1999 David S. Miller (davem@caipfs.rutgers.edu) @@ -1105,7 +1105,8 @@ } static void __init sabre_iommu_init(struct pci_controller_info *p, - int tsbsize, unsigned long dvma_offset) + int tsbsize, unsigned long dvma_offset, + u32 dma_mask) { unsigned long tsbbase, i, order; u64 control; @@ -1140,6 +1141,7 @@ } p->iommu.page_table = (iopte_t *)tsbbase; p->iommu.page_table_map_base = dvma_offset; + p->iommu.dma_addr_mask = dma_mask; memset((char *)tsbbase, 0, PAGE_SIZE << order); /* Make sure DMA address 0 is never returned just to allow catching @@ -1312,7 +1314,7 @@ int tsbsize, err; u32 busrange[2]; u32 vdma[2]; - u32 upa_portid; + u32 upa_portid, dma_mask; int bus; p = kmalloc(sizeof(*p), GFP_ATOMIC); @@ -1372,12 +1374,19 @@ prom_halt(); } + dma_mask = vdma[0]; switch(vdma[1]) { case 0x20000000: + dma_mask |= 0x1fffffff; tsbsize = 64; break; case 0x40000000: + dma_mask |= 0x3fffffff; + tsbsize = 128; + break; + case 0x80000000: + dma_mask |= 0x7fffffff; tsbsize = 128; break; default: @@ -1385,7 +1394,7 @@ prom_halt(); } - sabre_iommu_init(p, tsbsize, vdma[0]); + sabre_iommu_init(p, tsbsize, vdma[0], dma_mask); printk("SABRE: DVMA at %08x [%08x]\n", vdma[0], vdma[1]); diff -u --recursive --new-file v2.3.46/linux/arch/sparc64/kernel/sbus.c linux/arch/sparc64/kernel/sbus.c --- v2.3.46/linux/arch/sparc64/kernel/sbus.c Wed Feb 16 17:03:51 2000 +++ linux/arch/sparc64/kernel/sbus.c Fri Feb 18 15:07:20 2000 @@ -1,4 +1,4 @@ -/* $Id: sbus.c,v 1.7 2000/01/28 13:41:58 jj Exp $ +/* $Id: sbus.c,v 1.9 2000/02/18 13:48:57 davem Exp $ * sbus.c: UltraSparc SBUS controller support. * * Copyright (C) 1999 David S. Miller (davem@redhat.com) @@ -308,12 +308,16 @@ free_pages((unsigned long)cpu, order); } -dma_addr_t sbus_map_single(struct sbus_dev *sdev, void *ptr, size_t size) +dma_addr_t sbus_map_single(struct sbus_dev *sdev, void *ptr, size_t size, int dir) { struct sbus_iommu *iommu = sdev->bus->iommu; unsigned long npages, phys_base, flags; iopte_t *iopte; u32 dma_base, offset; + unsigned long iopte_bits; + + if (dir == SBUS_DMA_NONE) + BUG(); phys_base = (unsigned long) ptr; offset = (u32) (phys_base & ~PAGE_MASK); @@ -325,10 +329,11 @@ iopte = alloc_streaming_cluster(iommu, npages); dma_base = MAP_BASE + ((iopte - iommu->page_table) << PAGE_SHIFT); npages = size >> PAGE_SHIFT; + iopte_bits = IOPTE_VALID | IOPTE_STBUF | IOPTE_CACHE; + if (dir != SBUS_DMA_TODEVICE) + iopte_bits |= IOPTE_WRITE; while (npages--) { - *iopte++ = __iopte(IOPTE_VALID | IOPTE_STBUF | - IOPTE_CACHE | IOPTE_WRITE | - (phys_base & IOPTE_PAGE)); + *iopte++ = __iopte(iopte_bits | (phys_base & IOPTE_PAGE)); phys_base += PAGE_SIZE; } npages = size >> PAGE_SHIFT; @@ -338,7 +343,7 @@ return (dma_base | offset); } -void sbus_unmap_single(struct sbus_dev *sdev, dma_addr_t dma_addr, size_t size) +void sbus_unmap_single(struct sbus_dev *sdev, dma_addr_t dma_addr, size_t size, int direction) { struct sbus_iommu *iommu = sdev->bus->iommu; u32 dma_base = dma_addr & PAGE_MASK; @@ -352,7 +357,7 @@ spin_unlock_irqrestore(&iommu->lock, flags); } -static inline void fill_sg(iopte_t *iopte, struct scatterlist *sg, int nused) +static inline void fill_sg(iopte_t *iopte, struct scatterlist *sg, int nused, unsigned long iopte_bits) { struct scatterlist *dma_sg = sg; int i; @@ -392,9 +397,7 @@ sg++; } - pteval = ((pteval & IOPTE_PAGE) | - IOPTE_VALID | IOPTE_STBUF | - IOPTE_CACHE | IOPTE_WRITE); + pteval = ((pteval & IOPTE_PAGE) | iopte_bits); while (len > 0) { *iopte++ = __iopte(pteval); pteval += PAGE_SIZE; @@ -424,7 +427,7 @@ } } -int sbus_map_sg(struct sbus_dev *sdev, struct scatterlist *sg, int nents) +int sbus_map_sg(struct sbus_dev *sdev, struct scatterlist *sg, int nents, int dir) { struct sbus_iommu *iommu = sdev->bus->iommu; unsigned long flags, npages; @@ -432,10 +435,14 @@ u32 dma_base; struct scatterlist *sgtmp; int used; + unsigned long iopte_bits; + + if (dir == SBUS_DMA_NONE) + BUG(); /* Fast path single entry scatterlists. */ if (nents == 1) { - sg->dvma_address = sbus_map_single(sdev, sg->address, sg->length); + sg->dvma_address = sbus_map_single(sdev, sg->address, sg->length, dir); sg->dvma_length = sg->length; return 1; } @@ -457,7 +464,11 @@ } used = nents - used; - fill_sg(iopte, sg, used); + iopte_bits = IOPTE_VALID | IOPTE_STBUF | IOPTE_CACHE; + if (dir != SBUS_DMA_TODEVICE) + iopte_bits |= IOPTE_WRITE; + + fill_sg(iopte, sg, used, iopte_bits); #ifdef VERIFY_SG verify_sglist(sg, nents, iopte, npages); #endif @@ -467,7 +478,7 @@ return used; } -void sbus_unmap_sg(struct sbus_dev *sdev, struct scatterlist *sg, int nents) +void sbus_unmap_sg(struct sbus_dev *sdev, struct scatterlist *sg, int nents, int direction) { unsigned long size, flags; struct sbus_iommu *iommu; @@ -476,7 +487,7 @@ /* Fast path single entry scatterlists. */ if (nents == 1) { - sbus_unmap_single(sdev, sg->dvma_address, sg->dvma_length); + sbus_unmap_single(sdev, sg->dvma_address, sg->dvma_length, direction); return; } @@ -495,7 +506,7 @@ spin_unlock_irqrestore(&iommu->lock, flags); } -void sbus_dma_sync_single(struct sbus_dev *sdev, dma_addr_t base, size_t size) +void sbus_dma_sync_single(struct sbus_dev *sdev, dma_addr_t base, size_t size, int direction) { struct sbus_iommu *iommu = sdev->bus->iommu; unsigned long flags; @@ -507,7 +518,7 @@ spin_unlock_irqrestore(&iommu->lock, flags); } -void sbus_dma_sync_sg(struct sbus_dev *sdev, struct scatterlist *sg, int nents) +void sbus_dma_sync_sg(struct sbus_dev *sdev, struct scatterlist *sg, int nents, int direction) { struct sbus_iommu *iommu = sdev->bus->iommu; unsigned long flags, size; diff -u --recursive --new-file v2.3.46/linux/arch/sparc64/kernel/sys_sparc.c linux/arch/sparc64/kernel/sys_sparc.c --- v2.3.46/linux/arch/sparc64/kernel/sys_sparc.c Wed Feb 16 17:03:51 2000 +++ linux/arch/sparc64/kernel/sys_sparc.c Thu Feb 17 09:26:30 2000 @@ -1,4 +1,4 @@ -/* $Id: sys_sparc.c,v 1.35 2000/01/29 07:40:12 davem Exp $ +/* $Id: sys_sparc.c,v 1.36 2000/02/16 07:31:35 davem Exp $ * linux/arch/sparc64/kernel/sys_sparc.c * * This file contains various random system calls that diff -u --recursive --new-file v2.3.46/linux/arch/sparc64/kernel/sys_sparc32.c linux/arch/sparc64/kernel/sys_sparc32.c --- v2.3.46/linux/arch/sparc64/kernel/sys_sparc32.c Wed Feb 16 17:03:51 2000 +++ linux/arch/sparc64/kernel/sys_sparc32.c Thu Feb 17 09:26:31 2000 @@ -1,4 +1,4 @@ -/* $Id: sys_sparc32.c,v 1.131 2000/01/21 11:38:54 jj Exp $ +/* $Id: sys_sparc32.c,v 1.132 2000/02/16 07:31:35 davem Exp $ * sys_sparc32.c: Conversion between 32bit and 64bit native syscalls. * * Copyright (C) 1997,1998 Jakub Jelinek (jj@sunsite.mff.cuni.cz) diff -u --recursive --new-file v2.3.46/linux/arch/sparc64/kernel/sys_sunos32.c linux/arch/sparc64/kernel/sys_sunos32.c --- v2.3.46/linux/arch/sparc64/kernel/sys_sunos32.c Wed Feb 16 17:03:51 2000 +++ linux/arch/sparc64/kernel/sys_sunos32.c Thu Feb 17 09:26:31 2000 @@ -1,4 +1,4 @@ -/* $Id: sys_sunos32.c,v 1.38 2000/01/29 07:40:13 davem Exp $ +/* $Id: sys_sunos32.c,v 1.39 2000/02/16 07:31:37 davem Exp $ * sys_sunos32.c: SunOS binary compatability layer on sparc64. * * Copyright (C) 1995, 1996, 1997 David S. Miller (davem@caip.rutgers.edu) diff -u --recursive --new-file v2.3.46/linux/arch/sparc64/kernel/systbls.S linux/arch/sparc64/kernel/systbls.S --- v2.3.46/linux/arch/sparc64/kernel/systbls.S Wed Feb 16 17:03:51 2000 +++ linux/arch/sparc64/kernel/systbls.S Thu Feb 17 09:26:31 2000 @@ -1,4 +1,4 @@ -/* $Id: systbls.S,v 1.67 2000/01/29 16:41:21 jj Exp $ +/* $Id: systbls.S,v 1.68 2000/02/16 07:31:38 davem Exp $ * systbls.S: System call entry point tables for OS compatibility. * The native Linux system call table lives here also. * diff -u --recursive --new-file v2.3.46/linux/arch/sparc64/solaris/misc.c linux/arch/sparc64/solaris/misc.c --- v2.3.46/linux/arch/sparc64/solaris/misc.c Wed Feb 16 17:03:51 2000 +++ linux/arch/sparc64/solaris/misc.c Thu Feb 17 09:26:31 2000 @@ -1,4 +1,4 @@ -/* $Id: misc.c,v 1.21 2000/01/29 07:40:15 davem Exp $ +/* $Id: misc.c,v 1.22 2000/02/16 07:31:41 davem Exp $ * misc.c: Miscelaneous syscall emulation for Solaris * * Copyright (C) 1997,1998 Jakub Jelinek (jj@sunsite.mff.cuni.cz) diff -u --recursive --new-file v2.3.46/linux/arch/sparc64/solaris/socksys.c linux/arch/sparc64/solaris/socksys.c --- v2.3.46/linux/arch/sparc64/solaris/socksys.c Wed Feb 16 17:03:51 2000 +++ linux/arch/sparc64/solaris/socksys.c Thu Feb 17 09:26:31 2000 @@ -1,4 +1,4 @@ -/* $Id: socksys.c,v 1.11 2000/02/09 22:32:17 davem Exp $ +/* $Id: socksys.c,v 1.12 2000/02/17 05:50:11 davem Exp $ * socksys.c: /dev/inet/ stuff for Solaris emulation. * * Copyright (C) 1997 Jakub Jelinek (jj@sunsite.mff.cuni.cz) diff -u --recursive --new-file v2.3.46/linux/drivers/Makefile linux/drivers/Makefile --- v2.3.46/linux/drivers/Makefile Tue Feb 1 01:35:43 2000 +++ linux/drivers/Makefile Thu Feb 17 09:57:13 2000 @@ -52,7 +52,7 @@ MOD_SUB_DIRS += video endif -ifdef CONFIG_PPC +ifdef CONFIG_MAC SUB_DIRS += macintosh MOD_SUB_DIRS += macintosh endif diff -u --recursive --new-file v2.3.46/linux/drivers/acorn/net/ether1.c linux/drivers/acorn/net/ether1.c --- v2.3.46/linux/drivers/acorn/net/ether1.c Fri Oct 22 13:21:47 1999 +++ linux/drivers/acorn/net/ether1.c Thu Feb 17 23:34:46 2000 @@ -1,7 +1,7 @@ /* * linux/arch/arm/drivers/net/ether1.c * - * (C) Copyright 1996,1997,1998 Russell King + * (C) Copyright 1996-2000 Russell King * * Acorn ether1 driver (82586 chip) * for Acorn machines @@ -28,6 +28,7 @@ * TDR now only reports failure when chip reports non-zero * TDR time-distance. * 1.05 RMK 31/12/1997 Removed calls to dev_tint for 2.1 + * 1.06 RMK 10/02/2000 Updated for 2.3.43 */ #include @@ -64,9 +65,16 @@ #define RX_AREA_START 0x05000 #define RX_AREA_END 0x0fc00 -#define tx_done(dev) 0 +static int ether1_open(struct net_device *dev); +static int ether1_sendpacket(struct sk_buff *skb, struct net_device *dev); +static void ether1_interrupt(int irq, void *dev_id, struct pt_regs *regs); +static int ether1_close(struct net_device *dev); +static struct enet_statistics *ether1_getstats(struct net_device *dev); +static void ether1_setmulticastlist(struct net_device *dev); +static void ether1_timeout(struct net_device *dev); + /* ------------------------------------------------------------------------- */ -static char *version = "ether1 ethernet driver (c) 1995 Russell King v1.05\n"; +static char *version = "ether1 ethernet driver (c) 2000 Russell King v1.06\n"; #define BUS_16 16 #define BUS_8 8 @@ -636,12 +644,12 @@ if (net_debug && version_printed++ == 0) printk (KERN_INFO "%s", version); - printk (KERN_INFO "%s: ether1 found [%d, %04lx, %d]", dev->name, priv->bus_type, - dev->base_addr, dev->irq); - request_region (dev->base_addr, 16, "ether1"); request_region (dev->base_addr + 0x800, 4096, "ether1(ram)"); + printk (KERN_INFO "%s: ether1 at %lx, IRQ%d, ether address ", + dev->name, dev->base_addr, dev->irq); + for (i = 0; i < 6; i++) printk (i==0?" %02x":i==5?":%02x\n":":%02x", dev->dev_addr[i]); @@ -650,11 +658,13 @@ return 1; } - dev->open = ether1_open; - dev->stop = ether1_close; + dev->open = ether1_open; + dev->stop = ether1_close; dev->hard_start_xmit = ether1_sendpacket; - dev->get_stats = ether1_getstats; + dev->get_stats = ether1_getstats; dev->set_multicast_list = ether1_setmulticastlist; + dev->tx_timeout = ether1_timeout; + dev->watchdog_timeo = 5 * HZ / 100; /* Fill in the fields of the device structure with ethernet values */ ether_setup (dev); @@ -727,38 +737,18 @@ return start; } -static void -ether1_restart (struct net_device *dev, char *reason) -{ - struct ether1_priv *priv = (struct ether1_priv *)dev->priv; - priv->stats.tx_errors ++; - - if (reason) - printk (KERN_WARNING "%s: %s - resetting device\n", dev->name, reason); - else - printk (" - resetting device\n"); - - ether1_reset (dev); - - dev->start = 0; - dev->tbusy = 0; - - if (ether1_init_for_open (dev)) - printk (KERN_ERR "%s: unable to restart interface\n", dev->name); - - dev->start = 1; -} - static int ether1_open (struct net_device *dev) { struct ether1_priv *priv = (struct ether1_priv *)dev->priv; - if (request_irq (dev->irq, ether1_interrupt, 0, "ether1", dev)) - return -EAGAIN; - MOD_INC_USE_COUNT; + if (request_irq(dev->irq, ether1_interrupt, 0, "ether1", dev)) { + MOD_DEC_USE_COUNT; + return -EAGAIN; + } + memset (&priv->stats, 0, sizeof (struct enet_statistics)); if (ether1_init_for_open (dev)) { @@ -767,95 +757,94 @@ return -EAGAIN; } - dev->tbusy = 0; - dev->interrupt = 0; - dev->start = 1; + netif_start_queue(dev); return 0; } +static void +ether1_timeout(struct net_device *dev) +{ + struct ether1_priv *priv = (struct ether1_priv *)dev->priv; + + printk(KERN_WARNING "%s: transmit timeout, network cable problem?\n", + dev->name); + printk(KERN_WARNING "%s: resetting device\n", dev->name); + + ether1_reset (dev); + + if (ether1_init_for_open (dev)) + printk (KERN_ERR "%s: unable to restart interface\n", dev->name); + + priv->stats.tx_errors++; + netif_wake_queue(dev); +} + static int ether1_sendpacket (struct sk_buff *skb, struct net_device *dev) { struct ether1_priv *priv = (struct ether1_priv *)dev->priv; + int len = (ETH_ZLEN < skb->len) ? skb->len : ETH_ZLEN; + int tmp, tst, nopaddr, txaddr, tbdaddr, dataddr; + unsigned long flags; + tx_t tx; + tbd_t tbd; + nop_t nop; - if (priv->restart) - ether1_restart (dev, NULL); - - if (dev->tbusy) { - /* - * If we get here, some higher level has decided that we are broken. - * There should really be a "kick me" function call instead. - */ - int tickssofar = jiffies - dev->trans_start; + if (priv->restart) { + printk(KERN_WARNING "%s: resetting device\n", dev->name); - if (tickssofar < 5) - return 1; + ether1_reset(dev); - /* Try to restart the adapter. */ - ether1_restart (dev, "transmit timeout, network cable problem?"); - dev->trans_start = jiffies; + if (ether1_init_for_open(dev)) + printk(KERN_ERR "%s: unable to restart interface\n", dev->name); } /* - * Block a timer-based transmit from overlapping. This could better be - * done with atomic_swap(1, dev->tbusy), but set_bit() works as well. + * insert packet followed by a nop */ - if (test_and_set_bit (0, (void *)&dev->tbusy) != 0) - printk (KERN_WARNING "%s: transmitter access conflict.\n", dev->name); - else { - int len = (ETH_ZLEN < skb->len) ? skb->len : ETH_ZLEN; - int tmp, tst, nopaddr, txaddr, tbdaddr, dataddr; - unsigned long flags; - tx_t tx; - tbd_t tbd; - nop_t nop; - - /* - * insert packet followed by a nop - */ - txaddr = ether1_txalloc (dev, TX_SIZE); - tbdaddr = ether1_txalloc (dev, TBD_SIZE); - dataddr = ether1_txalloc (dev, len); - nopaddr = ether1_txalloc (dev, NOP_SIZE); - - tx.tx_status = 0; - tx.tx_command = CMD_TX | CMD_INTR; - tx.tx_link = nopaddr; - tx.tx_tbdoffset = tbdaddr; - tbd.tbd_opts = TBD_EOL | len; - tbd.tbd_link = I82586_NULL; - tbd.tbd_bufl = dataddr; - tbd.tbd_bufh = 0; - nop.nop_status = 0; - nop.nop_command = CMD_NOP; - nop.nop_link = nopaddr; - - save_flags_cli (flags); - ether1_writebuffer (dev, &tx, txaddr, TX_SIZE); - ether1_writebuffer (dev, &tbd, tbdaddr, TBD_SIZE); - ether1_writebuffer (dev, skb->data, dataddr, len); - ether1_writebuffer (dev, &nop, nopaddr, NOP_SIZE); - tmp = priv->tx_link; - priv->tx_link = nopaddr; + txaddr = ether1_txalloc (dev, TX_SIZE); + tbdaddr = ether1_txalloc (dev, TBD_SIZE); + dataddr = ether1_txalloc (dev, len); + nopaddr = ether1_txalloc (dev, NOP_SIZE); + + tx.tx_status = 0; + tx.tx_command = CMD_TX | CMD_INTR; + tx.tx_link = nopaddr; + tx.tx_tbdoffset = tbdaddr; + tbd.tbd_opts = TBD_EOL | len; + tbd.tbd_link = I82586_NULL; + tbd.tbd_bufl = dataddr; + tbd.tbd_bufh = 0; + nop.nop_status = 0; + nop.nop_command = CMD_NOP; + nop.nop_link = nopaddr; + + save_flags_cli(flags); + ether1_writebuffer (dev, &tx, txaddr, TX_SIZE); + ether1_writebuffer (dev, &tbd, tbdaddr, TBD_SIZE); + ether1_writebuffer (dev, skb->data, dataddr, len); + ether1_writebuffer (dev, &nop, nopaddr, NOP_SIZE); + tmp = priv->tx_link; + priv->tx_link = nopaddr; + + /* now reset the previous nop pointer */ + ether1_outw (dev, txaddr, tmp, nop_t, nop_link, NORMALIRQS); - /* now reset the previous nop pointer */ - ether1_outw (dev, txaddr, tmp, nop_t, nop_link, NORMALIRQS); + restore_flags(flags); - restore_flags (flags); - - /* handle transmit */ - dev->trans_start = jiffies; + /* handle transmit */ + dev->trans_start = jiffies; - /* check to see if we have room for a full sized ether frame */ - tmp = priv->tx_head; - tst = ether1_txalloc (dev, TX_SIZE + TBD_SIZE + NOP_SIZE + ETH_FRAME_LEN); - priv->tx_head = tmp; - if (tst != -1) - dev->tbusy = 0; - } + /* check to see if we have room for a full sized ether frame */ + tmp = priv->tx_head; + tst = ether1_txalloc (dev, TX_SIZE + TBD_SIZE + NOP_SIZE + ETH_FRAME_LEN); + priv->tx_head = tmp; dev_kfree_skb (skb); + if (tst == -1) + netif_stop_queue(dev); + return 0; } @@ -957,9 +946,7 @@ tst = ether1_txalloc (dev, TX_SIZE + TBD_SIZE + NOP_SIZE + ETH_FRAME_LEN); priv->tx_head = caddr; if (tst != -1) - dev->tbusy = 0; - - mark_bh (NET_BH); + netif_wake_queue(dev); } static void @@ -1024,8 +1011,6 @@ struct ether1_priv *priv = (struct ether1_priv *)dev->priv; int status; - dev->interrupt = 1; - status = ether1_inw (dev, SCB_ADDR, scb_t, scb_status, NORMALIRQS); if (status) { @@ -1065,8 +1050,6 @@ } } else outb (CTRL_ACK, REG_CONTROL); - - dev->interrupt = 0; } static int @@ -1076,9 +1059,6 @@ free_irq(dev->irq, dev); - dev->start = 0; - dev->tbusy = 0; - MOD_DEC_USE_COUNT; return 0; @@ -1110,7 +1090,7 @@ static struct ether_dev { struct expansion_card *ec; char name[9]; - struct net_device dev; + struct net_device dev; } ether_devs[MAX_ECARDS]; int diff -u --recursive --new-file v2.3.46/linux/drivers/acorn/net/ether1.h linux/drivers/acorn/net/ether1.h --- v2.3.46/linux/drivers/acorn/net/ether1.h Wed Aug 18 11:38:59 1999 +++ linux/drivers/acorn/net/ether1.h Thu Feb 17 23:34:46 2000 @@ -43,13 +43,6 @@ unsigned char restart : 1; }; -static int ether1_open (struct net_device *dev); -static int ether1_sendpacket (struct sk_buff *skb, struct net_device *dev); -static void ether1_interrupt (int irq, void *dev_id, struct pt_regs *regs); -static int ether1_close (struct net_device *dev); -static struct enet_statistics *ether1_getstats (struct net_device *dev); -static void ether1_setmulticastlist (struct net_device *dev); - #define I82586_NULL (-1) typedef struct { /* tdr */ diff -u --recursive --new-file v2.3.46/linux/drivers/acorn/net/ether3.c linux/drivers/acorn/net/ether3.c --- v2.3.46/linux/drivers/acorn/net/ether3.c Tue Aug 31 17:29:13 1999 +++ linux/drivers/acorn/net/ether3.c Thu Feb 17 23:34:46 2000 @@ -36,9 +36,10 @@ * 1.14 RMK 07/01/1998 Added initial code for ETHERB addressing. * 1.15 RMK 30/04/1999 More fixes to the transmit routine for buggy * hardware. + * 1.16 RMK 10/02/2000 Updated for 2.3.43 */ -static char *version = "ether3 ethernet driver (c) 1995-1999 R.M.King v1.15\n"; +static char *version = "ether3 ethernet driver (c) 1995-2000 R.M.King v1.16\n"; #include #include @@ -74,9 +75,17 @@ { 0xffff, 0xffff } }; -static void ether3_setmulticastlist(struct net_device *dev); -static int ether3_rx(struct net_device *dev, struct dev_priv *priv, unsigned int maxcnt); -static void ether3_tx(struct net_device *dev, struct dev_priv *priv); +static void ether3_setmulticastlist(struct net_device *dev); +static int ether3_rx(struct net_device *dev, struct dev_priv *priv, unsigned int maxcnt); +static void ether3_tx(struct net_device *dev, struct dev_priv *priv); +static int ether3_probe1 (struct net_device *dev); +static int ether3_open (struct net_device *dev); +static int ether3_sendpacket (struct sk_buff *skb, struct net_device *dev); +static void ether3_interrupt (int irq, void *dev_id, struct pt_regs *regs); +static int ether3_close (struct net_device *dev); +static struct enet_statistics *ether3_getstats (struct net_device *dev); +static void ether3_setmulticastlist (struct net_device *dev); +static void ether3_timeout(struct net_device *dev); #define BUS_16 2 #define BUS_8 1 @@ -406,6 +415,7 @@ static unsigned version_printed = 0; struct dev_priv *priv; unsigned int i, bus_type, error = ENODEV; + const char *name = "ether3"; if (net_debug && version_printed++ == 0) printk(version); @@ -421,7 +431,7 @@ priv = (struct dev_priv *) dev->priv; memset(priv, 0, sizeof(struct dev_priv)); - request_region(dev->base_addr, 128, "ether3"); + request_region(dev->base_addr, 128, name); /* Reset card... */ @@ -443,33 +453,38 @@ switch (bus_type) { case BUS_UNKNOWN: - printk(KERN_ERR "%s: unable to identify podule bus width\n", dev->name); + printk(KERN_ERR "%s: unable to identify bus width\n", dev->name); goto failed; case BUS_8: - printk(KERN_ERR "%s: ether3 found, but is an unsupported 8-bit card\n", dev->name); + printk(KERN_ERR "%s: %s found, but is an unsupported " + "8-bit card\n", dev->name, name); goto failed; default: break; } - printk("%s: ether3 found at %lx, IRQ%d, ether address ", dev->name, dev->base_addr, dev->irq); + printk("%s: %s at %lx, IRQ%d, ether address ", + dev->name, name, dev->base_addr, dev->irq); for (i = 0; i < 6; i++) printk(i == 5 ? "%2.2x\n" : "%2.2x:", dev->dev_addr[i]); - if (!ether3_init_2(dev)) { - dev->open = ether3_open; - dev->stop = ether3_close; - dev->hard_start_xmit = ether3_sendpacket; - dev->get_stats = ether3_getstats; - dev->set_multicast_list = ether3_setmulticastlist; + if (ether3_init_2(dev)) + goto failed; - /* Fill in the fields of the device structure with ethernet values. */ - ether_setup(dev); + dev->open = ether3_open; + dev->stop = ether3_close; + dev->hard_start_xmit = ether3_sendpacket; + dev->get_stats = ether3_getstats; + dev->set_multicast_list = ether3_setmulticastlist; + dev->tx_timeout = ether3_timeout; + dev->watchdog_timeo = 5 * HZ / 100; - return 0; - } + /* Fill in the fields of the device structure with ethernet values. */ + ether_setup(dev); + + return 0; failed: kfree(dev->priv); @@ -535,12 +550,10 @@ return -EAGAIN; } - dev->tbusy = 0; - dev->interrupt = 0; - dev->start = 1; - ether3_init_for_open(dev); + netif_start_queue(dev); + return 0; } @@ -552,8 +565,7 @@ { struct dev_priv *priv = (struct dev_priv *)dev->priv; - dev->tbusy = 1; - dev->start = 0; + netif_stop_queue(dev); disable_irq(dev->irq); @@ -602,6 +614,34 @@ ether3_outw(priv->regs.config1 | CFG1_LOCBUFMEM, REG_CONFIG1); } +static void +ether3_timeout(struct net_device *dev) +{ + struct dev_priv *priv = (struct dev_priv *)dev->priv; + unsigned long flags; + + del_timer(&priv->timer); + + save_flags_cli(flags); + printk(KERN_ERR "%s: transmit timed out, network cable problem?\n", dev->name); + printk(KERN_ERR "%s: state: { status=%04X cfg1=%04X cfg2=%04X }\n", dev->name, + ether3_inw(REG_STATUS), ether3_inw(REG_CONFIG1), ether3_inw(REG_CONFIG2)); + printk(KERN_ERR "%s: { rpr=%04X rea=%04X tpr=%04X }\n", dev->name, + ether3_inw(REG_RECVPTR), ether3_inw(REG_RECVEND), ether3_inw(REG_TRANSMITPTR)); + printk(KERN_ERR "%s: tx head=%X tx tail=%X\n", dev->name, + priv->tx_head, priv->tx_tail); + ether3_setbuffer(dev, buffer_read, priv->tx_tail); + printk(KERN_ERR "%s: packet status = %08X\n", dev->name, ether3_readlong(dev)); + restore_flags(flags); + + priv->regs.config2 |= CFG2_CTRLO; + priv->stats.tx_errors += 1; + ether3_outw(priv->regs.config2, REG_CONFIG2); + priv->tx_head = priv->tx_tail = 0; + + netif_wake_queue(dev); +} + /* * Transmit a packet */ @@ -609,102 +649,61 @@ ether3_sendpacket(struct sk_buff *skb, struct net_device *dev) { struct dev_priv *priv = (struct dev_priv *)dev->priv; -retry: - if (!dev->tbusy) { - /* Block a timer-based transmit from overlapping. This could better be - * done with atomic_swap(1, dev->tbusy), but set_bit() works as well. - */ - if (!test_and_set_bit(0, (void *)&dev->tbusy)) { - unsigned long flags; - unsigned int length = ETH_ZLEN < skb->len ? skb->len : ETH_ZLEN; - unsigned int ptr, next_ptr; - - length = (length + 1) & ~1; - - if (priv->broken) { - dev_kfree_skb(skb); - priv->stats.tx_dropped ++; - dev->tbusy = 0; - return 0; - } + unsigned long flags; + unsigned int length = ETH_ZLEN < skb->len ? skb->len : ETH_ZLEN; + unsigned int ptr, next_ptr; + + length = (length + 1) & ~1; + + if (priv->broken) { + dev_kfree_skb(skb); + priv->stats.tx_dropped ++; + netif_start_queue(dev); + return 0; + } - next_ptr = (priv->tx_head + 1) & 15; + next_ptr = (priv->tx_head + 1) & 15; - save_flags_cli(flags); + save_flags_cli(flags); - if (priv->tx_tail == next_ptr) { - restore_flags(flags); - return 1; /* unable to queue */ - } + if (priv->tx_tail == next_ptr) { + restore_flags(flags); + return 1; /* unable to queue */ + } - dev->trans_start = jiffies; - ptr = 0x600 * priv->tx_head; - priv->tx_head = next_ptr; - next_ptr *= 0x600; + dev->trans_start = jiffies; + ptr = 0x600 * priv->tx_head; + priv->tx_head = next_ptr; + next_ptr *= 0x600; #define TXHDR_FLAGS (TXHDR_TRANSMIT|TXHDR_CHAINCONTINUE|TXHDR_DATAFOLLOWS|TXHDR_ENSUCCESS) - ether3_setbuffer(dev, buffer_write, next_ptr); - ether3_writelong(dev, 0); - ether3_setbuffer(dev, buffer_write, ptr); - ether3_writelong(dev, 0); - ether3_writebuffer(dev, skb->data, length); - ether3_writeword(dev, htons(next_ptr)); - ether3_writeword(dev, TXHDR_CHAINCONTINUE >> 16); - ether3_setbuffer(dev, buffer_write, ptr); - ether3_writeword(dev, htons((ptr + length + 4))); - ether3_writeword(dev, TXHDR_FLAGS >> 16); - ether3_ledon(dev, priv); - - if (!(ether3_inw(REG_STATUS) & STAT_TXON)) { - ether3_outw(ptr, REG_TRANSMITPTR); - ether3_outw(priv->regs.command | CMD_TXON, REG_COMMAND); - } - - next_ptr = (priv->tx_head + 1) & 15; - if (priv->tx_tail != next_ptr) - dev->tbusy = 0; - - restore_flags(flags); + ether3_setbuffer(dev, buffer_write, next_ptr); + ether3_writelong(dev, 0); + ether3_setbuffer(dev, buffer_write, ptr); + ether3_writelong(dev, 0); + ether3_writebuffer(dev, skb->data, length); + ether3_writeword(dev, htons(next_ptr)); + ether3_writeword(dev, TXHDR_CHAINCONTINUE >> 16); + ether3_setbuffer(dev, buffer_write, ptr); + ether3_writeword(dev, htons((ptr + length + 4))); + ether3_writeword(dev, TXHDR_FLAGS >> 16); + ether3_ledon(dev, priv); - dev_kfree_skb(skb); + if (!(ether3_inw(REG_STATUS) & STAT_TXON)) { + ether3_outw(ptr, REG_TRANSMITPTR); + ether3_outw(priv->regs.command | CMD_TXON, REG_COMMAND); + } - return 0; - } else { - printk("%s: transmitter access conflict.\n", dev->name); - return 1; - } - } else { - /* If we get here, some higher level has decided we are broken. - * There should really be a "kick me" function call instead. - */ - int tickssofar = jiffies - dev->trans_start; - unsigned long flags; + next_ptr = (priv->tx_head + 1) & 15; + restore_flags(flags); - if (tickssofar < 5) - return 1; - del_timer(&priv->timer); + dev_kfree_skb(skb); - save_flags_cli(flags); - printk(KERN_ERR "%s: transmit timed out, network cable problem?\n", dev->name); - printk(KERN_ERR "%s: state: { status=%04X cfg1=%04X cfg2=%04X }\n", dev->name, - ether3_inw(REG_STATUS), ether3_inw(REG_CONFIG1), ether3_inw(REG_CONFIG2)); - printk(KERN_ERR "%s: { rpr=%04X rea=%04X tpr=%04X }\n", dev->name, - ether3_inw(REG_RECVPTR), ether3_inw(REG_RECVEND), ether3_inw(REG_TRANSMITPTR)); - printk(KERN_ERR "%s: tx head=%X tx tail=%X\n", dev->name, - priv->tx_head, priv->tx_tail); - ether3_setbuffer(dev, buffer_read, priv->tx_tail); - printk(KERN_ERR "%s: packet status = %08X\n", dev->name, ether3_readlong(dev)); - restore_flags(flags); + if (priv->tx_tail == next_ptr) + netif_stop_queue(dev); - dev->tbusy = 0; - priv->regs.config2 |= CFG2_CTRLO; - priv->stats.tx_errors += 1; - ether3_outw(priv->regs.config2, REG_CONFIG2); - dev->trans_start = jiffies; - priv->tx_head = priv->tx_tail = 0; - goto retry; - } + return 0; } static void @@ -721,8 +720,6 @@ priv = (struct dev_priv *)dev->priv; - dev->interrupt = 1; - status = ether3_inw(REG_STATUS); if (status & STAT_INTRX) { @@ -735,8 +732,6 @@ ether3_tx(dev, priv); } - dev->interrupt = 0; - #if NET_DEBUG > 1 if(net_debug & DEBUG_INT) printk("done\n"); @@ -904,8 +899,7 @@ if (priv->tx_tail != tx_tail) { priv->tx_tail = tx_tail; - dev->tbusy = 0; - mark_bh(NET_BH); /* Inform upper layers. */ + netif_wake_queue(dev); } } @@ -914,7 +908,7 @@ static struct ether_dev { struct expansion_card *ec; char name[9]; - struct net_device dev; + struct net_device dev; } ether_devs[MAX_ECARDS]; int diff -u --recursive --new-file v2.3.46/linux/drivers/acorn/net/ether3.h linux/drivers/acorn/net/ether3.h --- v2.3.46/linux/drivers/acorn/net/ether3.h Wed Aug 18 11:38:59 1999 +++ linux/drivers/acorn/net/ether3.h Thu Feb 17 23:34:46 2000 @@ -159,13 +159,4 @@ int broken; /* 0 = ok, 1 = something went wrong */ }; -extern int ether3_probe (struct net_device *dev); -static int ether3_probe1 (struct net_device *dev); -static int ether3_open (struct net_device *dev); -static int ether3_sendpacket (struct sk_buff *skb, struct net_device *dev); -static void ether3_interrupt (int irq, void *dev_id, struct pt_regs *regs); -static int ether3_close (struct net_device *dev); -static struct enet_statistics *ether3_getstats (struct net_device *dev); -static void ether3_setmulticastlist (struct net_device *dev); - #endif diff -u --recursive --new-file v2.3.46/linux/drivers/acorn/net/etherh.c linux/drivers/acorn/net/etherh.c --- v2.3.46/linux/drivers/acorn/net/etherh.c Tue Aug 31 17:29:13 1999 +++ linux/drivers/acorn/net/etherh.c Thu Feb 17 23:34:46 2000 @@ -13,6 +13,7 @@ * RMK 1.03 Added support for EtherLan500 cards * 23-11-1997 RMK 1.04 Added media autodetection * 16-04-1998 RMK 1.05 Improved media autodetection + * 10-02-2000 RMK 1.06 Updated for 2.3.43 * * Insmod Module Parameters * ------------------------ @@ -61,7 +62,7 @@ MODULE_AUTHOR("Russell King"); MODULE_DESCRIPTION("i3 EtherH driver"); -static char *version = "etherh [500/600/600A] ethernet driver (c) 1998 R.M.King v1.05\n"; +static char *version = "etherh [500/600/600A] ethernet driver (c) 2000 R.M.King v1.06\n"; #define ETHERH500_DATAPORT 0x200 /* MEMC */ #define ETHERH500_NS8390 0x000 /* MEMC */ @@ -190,8 +191,8 @@ if (ei_status.dmaing) { printk ("%s: DMAing conflict in etherh_block_input: " - " DMAstat %d irqlock %d intr %ld\n", dev->name, - ei_status.dmaing, ei_status.irqlock, dev->interrupt); + " DMAstat %d irqlock %d\n", dev->name, + ei_status.dmaing, ei_status.irqlock); return; } @@ -248,8 +249,8 @@ if (ei_status.dmaing) { printk ("%s: DMAing conflict in etherh_block_input: " - " DMAstat %d irqlock %d intr %ld\n", dev->name, - ei_status.dmaing, ei_status.irqlock, dev->interrupt); + " DMAstat %d irqlock %d\n", dev->name, + ei_status.dmaing, ei_status.irqlock); return; } @@ -287,8 +288,8 @@ if (ei_status.dmaing) { printk ("%s: DMAing conflict in etherh_get_header: " - " DMAstat %d irqlock %d intr %ld\n", dev->name, - ei_status.dmaing, ei_status.irqlock, dev->interrupt); + " DMAstat %d irqlock %d\n", dev->name, + ei_status.dmaing, ei_status.irqlock); return; } @@ -359,6 +360,7 @@ unsigned int addr, i, reg0, tmp; const char *dev_type; const char *if_type; + const char *name = "etherh"; addr = dev->base_addr; @@ -367,13 +369,13 @@ switch (dev->mem_end) { case PROD_I3_ETHERLAN500: - dev_type = "500 "; + dev_type = "500"; break; case PROD_I3_ETHERLAN600: - dev_type = "600 "; + dev_type = "600"; break; case PROD_I3_ETHERLAN600A: - dev_type = "600A "; + dev_type = "600A"; break; default: dev_type = ""; @@ -382,7 +384,8 @@ reg0 = inb (addr); if (reg0 == 0xff) { if (net_debug & DEBUG_INIT) - printk ("%s: etherh error: NS8390 command register wrong\n", dev->name); + printk("%s: %s error: NS8390 command register wrong\n", + dev->name, name); return -ENODEV; } @@ -393,34 +396,35 @@ inb (addr + EN0_COUNTER0); if (inb (addr + EN0_COUNTER0) != 0) { if (net_debug & DEBUG_INIT) - printk ("%s: etherh error: NS8390 not found\n", dev->name); + printk("%s: %s error: NS8390 not found\n", + dev->name, name); outb (reg0, addr); outb (tmp, addr + 13); return -ENODEV; } - if (ethdev_init (dev)) + if (ethdev_init(dev)) return -ENOMEM; - request_region (addr, 16, "etherh"); + request_region(addr, 16, name); - printk("%s: etherh %sfound at %lx, IRQ%d, ether address ", - dev->name, dev_type, dev->base_addr, dev->irq); + printk("%s: %s %s at %lx, IRQ%d, ether address ", + dev->name, name, dev_type, dev->base_addr, dev->irq); for (i = 0; i < 6; i++) printk (i == 5 ? "%2.2x " : "%2.2x:", dev->dev_addr[i]); - ei_status.name = "etherh"; - ei_status.word16 = 1; - ei_status.tx_start_page = ETHERH_TX_START_PAGE; - ei_status.rx_start_page = ei_status.tx_start_page + TX_PAGES; - ei_status.stop_page = ETHERH_STOP_PAGE; - ei_status.reset_8390 = etherh_reset; - ei_status.block_input = etherh_block_input; - ei_status.block_output = etherh_block_output; - ei_status.get_8390_hdr = etherh_get_header; - dev->open = etherh_open; - dev->stop = etherh_close; + ei_status.name = name; + ei_status.word16 = 1; + ei_status.tx_start_page = ETHERH_TX_START_PAGE; + ei_status.rx_start_page = ei_status.tx_start_page + TX_PAGES; + ei_status.stop_page = ETHERH_STOP_PAGE; + ei_status.reset_8390 = etherh_reset; + ei_status.block_input = etherh_block_input; + ei_status.block_output = etherh_block_output; + ei_status.get_8390_hdr = etherh_get_header; + dev->open = etherh_open; + dev->stop = etherh_close; /* select 10bT */ ei_status.interface_num = 0; @@ -567,7 +571,8 @@ my_ethers[i] = dev; if (register_netdev(dev) != 0) { - printk (KERN_WARNING "No etherh card found at %08lX\n", dev->base_addr); + printk(KERN_ERR "No etherh card found at %08lX\n", + dev->base_addr); if (ec[i]) { ecard_release(ec[i]); ec[i] = NULL; diff -u --recursive --new-file v2.3.46/linux/drivers/block/DAC960.c linux/drivers/block/DAC960.c --- v2.3.46/linux/drivers/block/DAC960.c Wed Feb 16 17:03:51 2000 +++ linux/drivers/block/DAC960.c Thu Feb 17 09:26:31 2000 @@ -2589,8 +2589,8 @@ (long *) Argument); case BLKRAGET: /* Get Read-Ahead. */ - if ((int *) Argument == NULL) return -EINVAL; - return put_user(read_ahead[MAJOR(Inode->i_rdev)], (int *) Argument); + if ((long *) Argument == NULL) return -EINVAL; + return put_user(read_ahead[MAJOR(Inode->i_rdev)], (long *) Argument); case BLKRASET: /* Set Read-Ahead. */ if (!capable(CAP_SYS_ADMIN)) return -EACCES; diff -u --recursive --new-file v2.3.46/linux/drivers/block/Makefile linux/drivers/block/Makefile --- v2.3.46/linux/drivers/block/Makefile Thu Feb 10 17:11:06 2000 +++ linux/drivers/block/Makefile Thu Feb 17 16:13:04 2000 @@ -326,6 +326,14 @@ endif endif +ifeq ($(CONFIG_BLK_DEV_LVM),y) +L_OBJS += lvm.o lvm-snap.o +else + ifeq ($(CONFIG_BLK_DEV_LVM),m) + M_OBJS += lvm-mod.o + endif +endif + ifeq ($(CONFIG_BLK_DEV_MD),y) LX_OBJS += md.o @@ -354,13 +362,9 @@ endif ifeq ($(CONFIG_MD_RAID5),y) -LX_OBJS += xor.o -CFLAGS_xor.o := $(PROFILING) -fomit-frame-pointer L_OBJS += raid5.o else ifeq ($(CONFIG_MD_RAID5),m) - LX_OBJS += xor.o - CFLAGS_xor.o := $(PROFILING) -fomit-frame-pointer M_OBJS += raid5.o endif endif @@ -407,3 +411,6 @@ ide-probe-mod.o: ide-probe.o ide-geometry.o $(LD) $(LD_RFLAG) -r -o $@ ide-probe.o ide-geometry.o + +lvm-mod.o: lvm.o lvm-snap.o + $(LD) -r -o $@ lvm.o lvm-snap.o diff -u --recursive --new-file v2.3.46/linux/drivers/block/README.lvm linux/drivers/block/README.lvm --- v2.3.46/linux/drivers/block/README.lvm Wed Dec 31 16:00:00 1969 +++ linux/drivers/block/README.lvm Thu Feb 17 16:13:04 2000 @@ -0,0 +1,8 @@ + +This is the Logical Volume Manager driver for Linux, + +Tools, library that manage logical volumes can be found +at . + +There you can obtain actual driver versions too. + diff -u --recursive --new-file v2.3.46/linux/drivers/block/icside.c linux/drivers/block/icside.c --- v2.3.46/linux/drivers/block/icside.c Fri Jan 28 15:09:07 2000 +++ linux/drivers/block/icside.c Thu Feb 17 23:34:46 2000 @@ -24,6 +24,8 @@ #include #include +extern char *ide_xfer_verbose (byte xfer_rate); + /* * Maximum number of interfaces per card */ diff -u --recursive --new-file v2.3.46/linux/drivers/block/ide-dma.c linux/drivers/block/ide-dma.c --- v2.3.46/linux/drivers/block/ide-dma.c Fri Jan 28 15:09:07 2000 +++ linux/drivers/block/ide-dma.c Fri Feb 18 15:07:20 2000 @@ -214,6 +214,10 @@ struct scatterlist *sg = hwif->sg_table; int nents = 0; + if (rq->cmd == READ) + hwif->sg_dma_direction = PCI_DMA_FROMDEVICE; + else + hwif->sg_dma_direction = PCI_DMA_TODEVICE; bh = rq->bh; do { unsigned char *virt_addr = bh->b_data; @@ -230,7 +234,7 @@ nents++; } while (bh != NULL); - return pci_map_sg(hwif->pci_dev, sg, nents); + return pci_map_sg(hwif->pci_dev, sg, nents, hwif->sg_dma_direction); } /* @@ -265,7 +269,8 @@ printk("%s: DMA table too small\n", drive->name); pci_unmap_sg(HWIF(drive)->pci_dev, HWIF(drive)->sg_table, - HWIF(drive)->sg_nents); + HWIF(drive)->sg_nents, + HWIF(drive)->sg_dma_direction); return 0; /* revert to PIO for this request */ } else { u32 xcount, bcount = 0x10000 - (cur_addr & 0xffff); @@ -301,7 +306,7 @@ struct scatterlist *sg = HWIF(drive)->sg_table; int nents = HWIF(drive)->sg_nents; - pci_unmap_sg(dev, sg, nents); + pci_unmap_sg(dev, sg, nents, HWIF(drive)->sg_dma_direction); } /* diff -u --recursive --new-file v2.3.46/linux/drivers/block/ide-probe.c linux/drivers/block/ide-probe.c --- v2.3.46/linux/drivers/block/ide-probe.c Wed Feb 16 17:03:51 2000 +++ linux/drivers/block/ide-probe.c Thu Feb 17 23:59:57 2000 @@ -406,7 +406,7 @@ ide_ioreg_t ide_control_reg = hwif->io_ports[IDE_CONTROL_OFFSET]; ide_ioreg_t region_low = hwif->io_ports[IDE_DATA_OFFSET]; ide_ioreg_t region_high = region_low; - ide_ioreg_t region_request = 8; + unsigned int region_request = 8; int i; if (hwif->noprobe) diff -u --recursive --new-file v2.3.46/linux/drivers/block/ll_rw_blk.c linux/drivers/block/ll_rw_blk.c --- v2.3.46/linux/drivers/block/ll_rw_blk.c Wed Feb 16 17:03:51 2000 +++ linux/drivers/block/ll_rw_blk.c Sun Feb 20 20:26:10 2000 @@ -253,7 +253,7 @@ INIT_LIST_HEAD(&q->queue_head); q->elevator = ELEVATOR_DEFAULTS; q->request_fn = rfn; - q->back_merges_fn = ll_back_merge_fn; + q->back_merge_fn = ll_back_merge_fn; q->front_merge_fn = ll_front_merge_fn; q->merge_requests_fn = ll_merge_requests_fn; q->make_request_fn = NULL; @@ -469,22 +469,17 @@ #define elevator_merge_after(q, req, lat) __elevator_merge((q), (req), (lat), 1) static inline void __elevator_merge(request_queue_t * q, struct request * req, int latency, int after) { -#ifdef DEBUG_ELEVATOR int sequence = elevator_sequence(&q->elevator, latency); if (after) sequence -= req->nr_segments; if (elevator_sequence_before(sequence, req->elevator_sequence)) { - static int warned = 0; - if (!warned) { + if (!after) printk(KERN_WARNING __FUNCTION__ ": req latency %d req latency %d\n", req->elevator_sequence - q->elevator.sequence, sequence - q->elevator.sequence); - warned = 1; - } req->elevator_sequence = sequence; } -#endif } static inline void elevator_queue(request_queue_t * q, @@ -679,7 +674,7 @@ int rw_ahead, max_req, max_sectors; unsigned long flags; int orig_latency, latency, __latency, starving, __starving, empty; - struct list_head * entry, * __entry; + struct list_head * entry, * __entry = NULL; count = bh->b_size >> 9; sector = bh->b_rsector; @@ -1241,4 +1236,5 @@ EXPORT_SYMBOL(blk_cleanup_queue); EXPORT_SYMBOL(blk_queue_headactive); EXPORT_SYMBOL(blk_queue_pluggable); +EXPORT_SYMBOL(blk_queue_make_request); EXPORT_SYMBOL(generic_make_request); diff -u --recursive --new-file v2.3.46/linux/drivers/block/loop.c linux/drivers/block/loop.c --- v2.3.46/linux/drivers/block/loop.c Wed Feb 16 17:03:51 2000 +++ linux/drivers/block/loop.c Sun Feb 20 13:11:38 2000 @@ -377,13 +377,13 @@ spin_lock_irq(&io_request_lock); current_request->sector += current_request->current_nr_sectors; current_request->nr_sectors -= current_request->current_nr_sectors; - list_add(¤t_request->queue, ¤t_request->q->queue_head); + list_add(¤t_request->queue, &q->queue_head); end_request(1); goto repeat; error_out_lock: spin_lock_irq(&io_request_lock); error_out: - list_add(¤t_request->queue, ¤t_request->q->queue_head); + list_add(¤t_request->queue, &q->queue_head); end_request(0); goto repeat; } diff -u --recursive --new-file v2.3.46/linux/drivers/block/lvm-snap.c linux/drivers/block/lvm-snap.c --- v2.3.46/linux/drivers/block/lvm-snap.c Wed Dec 31 16:00:00 1969 +++ linux/drivers/block/lvm-snap.c Thu Feb 17 16:13:05 2000 @@ -0,0 +1,434 @@ +/* + * kernel/lvm-snap.c + * + * Copyright (C) 2000 Andrea Arcangeli SuSE + * + * LVM snapshot driver is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2, or (at your option) + * any later version. + * + * LVM driver is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with GNU CC; see the file COPYING. If not, write to + * the Free Software Foundation, 59 Temple Place - Suite 330, + * Boston, MA 02111-1307, USA. + * + */ + +#include +#include +#include +#include +#include +#include +#include + + +static char *lvm_snap_version = "LVM 0.8final (15/02/2000)\n"; + +extern const char *const lvm_name; +extern int lvm_blocksizes[]; + +void lvm_snapshot_release(lv_t *); + +#define hashfn(dev,block,mask,chunk_size) \ + ((HASHDEV(dev)^((block)/(chunk_size))) & (mask)) + +static inline lv_block_exception_t * +lvm_find_exception_table(kdev_t org_dev, unsigned long org_start, lv_t * lv) +{ + struct list_head * hash_table = lv->lv_snapshot_hash_table, * next; + unsigned long mask = lv->lv_snapshot_hash_mask; + int chunk_size = lv->lv_chunk_size; + lv_block_exception_t * ret; + int i = 0; + + hash_table = &hash_table[hashfn(org_dev, org_start, mask, chunk_size)]; + ret = NULL; + for (next = hash_table->next; next != hash_table; next = next->next) + { + lv_block_exception_t * exception; + + exception = list_entry(next, lv_block_exception_t, hash); + if (exception->rsector_org == org_start && + exception->rdev_org == org_dev) + { + if (i) + { + /* fun, isn't it? :) */ + list_del(next); + list_add(next, hash_table); + } + ret = exception; + break; + } + i++; + } + return ret; +} + +static inline void lvm_hash_link(lv_block_exception_t * exception, + kdev_t org_dev, unsigned long org_start, + lv_t * lv) +{ + struct list_head * hash_table = lv->lv_snapshot_hash_table; + unsigned long mask = lv->lv_snapshot_hash_mask; + int chunk_size = lv->lv_chunk_size; + + hash_table = &hash_table[hashfn(org_dev, org_start, mask, chunk_size)]; + list_add(&exception->hash, hash_table); +} + +int lvm_snapshot_remap_block(kdev_t * org_dev, unsigned long * org_sector, + unsigned long pe_start, lv_t * lv) +{ + int ret; + unsigned long pe_off, pe_adjustment, __org_start; + kdev_t __org_dev; + int chunk_size = lv->lv_chunk_size; + lv_block_exception_t * exception; + + pe_off = pe_start % chunk_size; + pe_adjustment = (*org_sector-pe_off) % chunk_size; + __org_start = *org_sector - pe_adjustment; + __org_dev = *org_dev; + + ret = 0; + exception = lvm_find_exception_table(__org_dev, __org_start, lv); + if (exception) + { + *org_dev = exception->rdev_new; + *org_sector = exception->rsector_new + pe_adjustment; + ret = 1; + } + return ret; +} + +static void lvm_drop_snapshot(lv_t * lv_snap, const char * reason) +{ + kdev_t last_dev; + int i; + + /* no exception storage space available for this snapshot + or error on this snapshot --> release it */ + invalidate_buffers(lv_snap->lv_dev); + + for (i = last_dev = 0; i < lv_snap->lv_remap_ptr; i++) { + if ( lv_snap->lv_block_exception[i].rdev_new != last_dev) { + last_dev = lv_snap->lv_block_exception[i].rdev_new; + invalidate_buffers(last_dev); + } + } + + lvm_snapshot_release(lv_snap); + + printk(KERN_INFO + "%s -- giving up to snapshot %s on %s due %s\n", + lvm_name, lv_snap->lv_snapshot_org->lv_name, lv_snap->lv_name, + reason); +} + +static inline void lvm_snapshot_prepare_blocks(unsigned long * blocks, + unsigned long start, + int nr_sectors, + int blocksize) +{ + int i, sectors_per_block, nr_blocks; + + sectors_per_block = blocksize >> 9; + nr_blocks = nr_sectors / sectors_per_block; + start /= sectors_per_block; + + for (i = 0; i < nr_blocks; i++) + blocks[i] = start++; +} + +static inline int get_blksize(kdev_t dev) +{ + int correct_size = BLOCK_SIZE, i, major; + + major = MAJOR(dev); + if (blksize_size[major]) + { + i = blksize_size[major][MINOR(dev)]; + if (i) + correct_size = i; + } + return correct_size; +} + +#ifdef DEBUG_SNAPSHOT +static inline void invalidate_snap_cache(unsigned long start, unsigned long nr, + kdev_t dev) +{ + struct buffer_head * bh; + int sectors_per_block, i, blksize, minor; + + minor = MINOR(dev); + blksize = lvm_blocksizes[minor]; + sectors_per_block = blksize >> 9; + nr /= sectors_per_block; + start /= sectors_per_block; + + for (i = 0; i < nr; i++) + { + bh = get_hash_table(dev, start++, blksize); + if (bh) + bforget(bh); + } +} +#endif + +/* + * copy on write handler for one snapshot logical volume + * + * read the original blocks and store it/them on the new one(s). + * if there is no exception storage space free any longer --> release snapshot. + * + * this routine gets called for each _first_ write to a physical chunk. + */ +int lvm_snapshot_COW(kdev_t org_phys_dev, + unsigned long org_phys_sector, + unsigned long org_pe_start, + unsigned long org_virt_sector, + lv_t * lv_snap) +{ + const char * reason; + unsigned long org_start, snap_start, snap_phys_dev, virt_start, pe_off; + int idx = lv_snap->lv_remap_ptr, chunk_size = lv_snap->lv_chunk_size; + struct kiobuf * iobuf; + unsigned long blocks[KIO_MAX_SECTORS]; + int blksize_snap, blksize_org, min_blksize, max_blksize; + int max_sectors, nr_sectors; + + /* check if we are out of snapshot space */ + if (idx >= lv_snap->lv_remap_end) + goto fail_out_of_space; + + /* calculate physical boundaries of source chunk */ + pe_off = org_pe_start % chunk_size; + org_start = org_phys_sector - ((org_phys_sector-pe_off) % chunk_size); + virt_start = org_virt_sector - (org_phys_sector - org_start); + + /* calculate physical boundaries of destination chunk */ + snap_phys_dev = lv_snap->lv_block_exception[idx].rdev_new; + snap_start = lv_snap->lv_block_exception[idx].rsector_new; + +#ifdef DEBUG_SNAPSHOT + printk(KERN_INFO + "%s -- COW: " + "org %02d:%02d faulting %lu start %lu, " + "snap %02d:%02d start %lu, " + "size %d, pe_start %lu pe_off %lu, virt_sec %lu\n", + lvm_name, + MAJOR(org_phys_dev), MINOR(org_phys_dev), org_phys_sector, + org_start, + MAJOR(snap_phys_dev), MINOR(snap_phys_dev), snap_start, + chunk_size, + org_pe_start, pe_off, + org_virt_sector); +#endif + + iobuf = lv_snap->lv_iobuf; + + blksize_org = get_blksize(org_phys_dev); + blksize_snap = get_blksize(snap_phys_dev); + max_blksize = max(blksize_org, blksize_snap); + min_blksize = min(blksize_org, blksize_snap); + max_sectors = KIO_MAX_SECTORS * (min_blksize>>9); + + if (chunk_size % (max_blksize>>9)) + goto fail_blksize; + + while (chunk_size) + { + nr_sectors = min(chunk_size, max_sectors); + chunk_size -= nr_sectors; + + iobuf->length = nr_sectors << 9; + + lvm_snapshot_prepare_blocks(blocks, org_start, + nr_sectors, blksize_org); + if (brw_kiovec(READ, 1, &iobuf, org_phys_dev, + blocks, blksize_org) != (nr_sectors<<9)) + goto fail_raw_read; + + lvm_snapshot_prepare_blocks(blocks, snap_start, + nr_sectors, blksize_snap); + if (brw_kiovec(WRITE, 1, &iobuf, snap_phys_dev, + blocks, blksize_snap) != (nr_sectors<<9)) + goto fail_raw_write; + } + +#ifdef DEBUG_SNAPSHOT + /* invalidate the logcial snapshot buffer cache */ + invalidate_snap_cache(virt_start, lv_snap->lv_chunk_size, + lv_snap->lv_dev); +#endif + + /* the original chunk is now stored on the snapshot volume + so update the execption table */ + lv_snap->lv_block_exception[idx].rdev_org = org_phys_dev; + lv_snap->lv_block_exception[idx].rsector_org = org_start; + lvm_hash_link(lv_snap->lv_block_exception + idx, + org_phys_dev, org_start, lv_snap); + lv_snap->lv_remap_ptr = idx + 1; + return 0; + + /* slow path */ + out: + lvm_drop_snapshot(lv_snap, reason); + return 1; + + fail_out_of_space: + reason = "out of space"; + goto out; + fail_raw_read: + reason = "read error"; + goto out; + fail_raw_write: + reason = "write error"; + goto out; + fail_blksize: + reason = "blocksize error"; + goto out; +} + +static int lvm_snapshot_alloc_iobuf_pages(struct kiobuf * iobuf, int sectors) +{ + int bytes, nr_pages, err, i; + + bytes = sectors << 9; + nr_pages = (bytes + ~PAGE_MASK) >> PAGE_SHIFT; + err = expand_kiobuf(iobuf, nr_pages); + if (err) + goto out; + + err = -ENOMEM; + iobuf->locked = 1; + iobuf->nr_pages = 0; + for (i = 0; i < nr_pages; i++) + { + struct page * page; + +#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,3,27) + page = alloc_page(GFP_KERNEL); + if (!page) + goto out; +#else + { + unsigned long addr = __get_free_page(GFP_USER); + if (!addr) + goto out; + iobuf->pagelist[i] = addr; + page = mem_map + MAP_NR(addr); + } +#endif + + iobuf->maplist[i] = page; + /* the only point to lock the page here is to be allowed + to share unmap_kiobuf() in the fail-path */ +#ifndef LockPage +#define LockPage(map) set_bit(PG_locked, &(map)->flags) +#endif + LockPage(page); + iobuf->nr_pages++; + } + iobuf->offset = 0; + + err = 0; + out: + return err; +} + +static int calc_max_buckets(void) +{ + unsigned long mem; + + mem = num_physpages << PAGE_SHIFT; + mem /= 100; + mem *= 2; + mem /= sizeof(struct list_head); + + return mem; +} + +static int lvm_snapshot_alloc_hash_table(lv_t * lv) +{ + int err; + unsigned long buckets, max_buckets, size; + struct list_head * hash; + + buckets = lv->lv_remap_end; + max_buckets = calc_max_buckets(); + buckets = min(buckets, max_buckets); + while (buckets & (buckets-1)) + buckets &= (buckets-1); + + size = buckets * sizeof(struct list_head); + + err = -ENOMEM; + hash = vmalloc(size); + lv->lv_snapshot_hash_table = hash; + + if (!hash) + goto out; + + lv->lv_snapshot_hash_mask = buckets-1; + while (buckets--) + INIT_LIST_HEAD(hash+buckets); + err = 0; + out: + return err; +} + +int lvm_snapshot_alloc(lv_t * lv_snap) +{ + int err, blocksize, max_sectors; + + err = alloc_kiovec(1, &lv_snap->lv_iobuf); + if (err) + goto out; + + blocksize = lvm_blocksizes[MINOR(lv_snap->lv_dev)]; + max_sectors = KIO_MAX_SECTORS << (PAGE_SHIFT-9); + + err = lvm_snapshot_alloc_iobuf_pages(lv_snap->lv_iobuf, max_sectors); + if (err) + goto out_free_kiovec; + + err = lvm_snapshot_alloc_hash_table(lv_snap); + if (err) + goto out_free_kiovec; + out: + return err; + + out_free_kiovec: + unmap_kiobuf(lv_snap->lv_iobuf); + free_kiovec(1, &lv_snap->lv_iobuf); + goto out; +} + +void lvm_snapshot_release(lv_t * lv) +{ + if (lv->lv_block_exception) + { + vfree(lv->lv_block_exception); + lv->lv_block_exception = NULL; + } + if (lv->lv_snapshot_hash_table) + { + vfree(lv->lv_snapshot_hash_table); + lv->lv_snapshot_hash_table = NULL; + } + if (lv->lv_iobuf) + { + free_kiovec(1, &lv->lv_iobuf); + lv->lv_iobuf = NULL; + } +} diff -u --recursive --new-file v2.3.46/linux/drivers/block/lvm.c linux/drivers/block/lvm.c --- v2.3.46/linux/drivers/block/lvm.c Wed Dec 31 16:00:00 1969 +++ linux/drivers/block/lvm.c Thu Feb 17 16:13:05 2000 @@ -0,0 +1,2556 @@ +/* + * kernel/lvm.c + * + * Copyright (C) 1997 - 2000 Heinz Mauelshagen, Germany + * + * February-November 1997 + * April-May,July-August,November 1998 + * January-March,May,July,September,October 1999 + * January,February 2000 + * + * + * LVM driver is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2, or (at your option) + * any later version. + * + * LVM driver is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with GNU CC; see the file COPYING. If not, write to + * the Free Software Foundation, 59 Temple Place - Suite 330, + * Boston, MA 02111-1307, USA. + * + */ + +/* + * Changelog + * + * 09/11/1997 - added chr ioctls VG_STATUS_GET_COUNT + * and VG_STATUS_GET_NAMELIST + * 18/01/1998 - change lvm_chr_open/close lock handling + * 30/04/1998 - changed LV_STATUS ioctl to LV_STATUS_BYNAME and + * - added LV_STATUS_BYINDEX ioctl + * - used lvm_status_byname_req_t and + * lvm_status_byindex_req_t vars + * 04/05/1998 - added multiple device support + * 08/05/1998 - added support to set/clear extendable flag in volume group + * 09/05/1998 - changed output of lvm_proc_get_info() because of + * support for free (eg. longer) logical volume names + * 12/05/1998 - added spin_locks (thanks to Pascal van Dam + * ) + * 25/05/1998 - fixed handling of locked PEs in lvm_map() and lvm_chr_ioctl() + * 26/05/1998 - reactivated verify_area by access_ok + * 07/06/1998 - used vmalloc/vfree instead of kmalloc/kfree to go + * beyond 128/256 KB max allocation limit per call + * - #ifdef blocked spin_lock calls to avoid compile errors + * with 2.0.x + * 11/06/1998 - another enhancement to spinlock code in lvm_chr_open() + * and use of LVM_VERSION_CODE instead of my own macros + * (thanks to Michael Marxmeier ) + * 07/07/1998 - added statistics in lvm_map() + * 08/07/1998 - saved statistics in lvm_do_lv_extend_reduce() + * 25/07/1998 - used __initfunc macro + * 02/08/1998 - changes for official char/block major numbers + * 07/08/1998 - avoided init_module() and cleanup_module() to be static + * 30/08/1998 - changed VG lv_open counter from sum of LV lv_open counters + * to sum of LVs open (no matter how often each is) + * 01/09/1998 - fixed lvm_gendisk.part[] index error + * 07/09/1998 - added copying of lv_current_pe-array + * in LV_STATUS_BYINDEX ioctl + * 17/11/1998 - added KERN_* levels to printk + * 13/01/1999 - fixed LV index bug in lvm_do_lv_create() which hit lvrename + * 07/02/1999 - fixed spinlock handling bug in case of LVM_RESET + * by moving spinlock code from lvm_chr_open() + * to lvm_chr_ioctl() + * - added LVM_LOCK_LVM ioctl to lvm_chr_ioctl() + * - allowed LVM_RESET and retrieval commands to go ahead; + * only other update ioctls are blocked now + * - fixed pv->pe to NULL for pv_status + * - using lv_req structure in lvm_chr_ioctl() now + * - fixed NULL ptr reference bug in lvm_do_lv_extend_reduce() + * caused by uncontiguous PV array in lvm_chr_ioctl(VG_REDUCE) + * 09/02/1999 - changed BLKRASET and BLKRAGET in lvm_chr_ioctl() to + * handle lgoical volume private read ahead sector + * - implemented LV read_ahead handling with lvm_blk_read() + * and lvm_blk_write() + * 10/02/1999 - implemented 2.[12].* support function lvm_hd_name() + * to be used in drivers/block/genhd.c by disk_name() + * 12/02/1999 - fixed index bug in lvm_blk_ioctl(), HDIO_GETGEO + * - enhanced gendisk insert/remove handling + * 16/02/1999 - changed to dynamic block minor number allocation to + * have as much as 99 volume groups with 256 logical volumes + * as the grand total; this allows having 1 volume group with + * up to 256 logical volumes in it + * 21/02/1999 - added LV open count information to proc filesystem + * - substituted redundant LVM_RESET code by calls + * to lvm_do_vg_remove() + * 22/02/1999 - used schedule_timeout() to be more responsive + * in case of lvm_do_vg_remove() with lots of logical volumes + * 19/03/1999 - fixed NULL pointer bug in module_init/lvm_init + * 17/05/1999 - used DECLARE_WAIT_QUEUE_HEAD macro (>2.3.0) + * - enhanced lvm_hd_name support + * 03/07/1999 - avoided use of KERNEL_VERSION macro based ifdefs and + * memcpy_tofs/memcpy_fromfs macro redefinitions + * 06/07/1999 - corrected reads/writes statistic counter copy in case + * of striped logical volume + * 28/07/1999 - implemented snapshot logical volumes + * - lvm_chr_ioctl + * - LV_STATUS_BYINDEX + * - LV_STATUS_BYNAME + * - lvm_do_lv_create + * - lvm_do_lv_remove + * - lvm_map + * - new lvm_snapshot_remap_block + * - new lvm_snapshot_remap_new_block + * 08/10/1999 - implemented support for multiple snapshots per + * original logical volume + * 12/10/1999 - support for 2.3.19 + * 11/11/1999 - support for 2.3.28 + * 21/11/1999 - changed lvm_map() interface to buffer_head based + * 19/12/1999 - support for 2.3.33 + * 01/01/2000 - changed locking concept in lvm_map(), + * lvm_do_vg_create() and lvm_do_lv_remove() + * 15/01/2000 - fixed PV_FLUSH bug in lvm_chr_ioctl() + * 24/01/2000 - ported to 2.3.40 including Alan Cox's pointer changes etc. + * 29/01/2000 - used kmalloc/kfree again for all small structures + * 20/01/2000 - cleaned up lvm_chr_ioctl by moving code + * to seperated functions + * - avoided "/dev/" in proc filesystem output + * - avoided inline strings functions lvm_strlen etc. + * 14/02/2000 - support for 2.3.43 + * - integrated Andrea Arcagnelli's snapshot code + * + */ + + +static char *lvm_version = "LVM version 0.8final by Heinz Mauelshagen (15/02/2000)\n"; +static char *lvm_short_version = "version 0.8final (15/02/2000)"; + +#define MAJOR_NR LVM_BLK_MAJOR +#define DEVICE_OFF(device) + +#include +#include + +#ifdef MODVERSIONS +#undef MODULE +#define MODULE +#include +#endif + +#include + +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#ifdef CONFIG_KERNELD +#include +#endif + +#include +#include + +#include +#include + +#define LVM_CORRECT_READ_AHEAD( a) \ + if ( a < LVM_MIN_READ_AHEAD || \ + a > LVM_MAX_READ_AHEAD) a = LVM_MAX_READ_AHEAD; + +#ifndef WRITEA +# define WRITEA WRITE +#endif + +/* + * External function prototypes + */ +#ifdef MODULE +int init_module(void); +void cleanup_module(void); +#else +extern int lvm_init(void); +#endif + +static void lvm_dummy_device_request(request_queue_t *); +#define DEVICE_REQUEST lvm_dummy_device_request + +static void lvm_make_request_fn(int, struct buffer_head*); + +static int lvm_blk_ioctl(struct inode *, struct file *, uint, ulong); +static int lvm_blk_open(struct inode *, struct file *); + +static ssize_t lvm_blk_read(struct file *, char *, size_t, loff_t *); +static ssize_t lvm_blk_write(struct file *, const char *, size_t, loff_t *); + +static int lvm_chr_open(struct inode *, struct file *); + +static int lvm_chr_close(struct inode *, struct file *); +static int lvm_blk_close(struct inode *, struct file *); + +static int lvm_chr_ioctl(struct inode *, struct file *, uint, ulong); + +#if defined CONFIG_LVM_PROC_FS && defined CONFIG_PROC_FS +static int lvm_proc_get_info(char *, char **, off_t, int); +static int (*lvm_proc_get_info_ptr) (char *, char **, off_t, int) = +&lvm_proc_get_info; +#endif + +#ifdef LVM_HD_NAME +void lvm_hd_name(char *, int); +#endif +/* End external function prototypes */ + + +/* + * Internal function prototypes + */ +static void lvm_init_vars(void); + +/* external snapshot calls */ +int lvm_snapshot_remap_block(kdev_t *, ulong *, ulong, lv_t *); +int lvm_snapshot_COW(kdev_t, ulong, ulong, ulong, lv_t *); +int lvm_snapshot_alloc(lv_t *); +void lvm_snapshot_release(lv_t *); + +#ifdef LVM_HD_NAME +extern void (*lvm_hd_name_ptr) (char *, int); +#endif +static int lvm_map(struct buffer_head *, int); +static int lvm_do_lock_lvm(void); +static int lvm_do_le_remap(vg_t *, void *); +static int lvm_do_pe_lock_unlock(vg_t *r, void *); +static int lvm_do_vg_create(int, void *); +static int lvm_do_vg_extend(vg_t *, void *); +static int lvm_do_vg_reduce(vg_t *, void *); +static int lvm_do_vg_remove(int); +static int lvm_do_lv_create(int, char *, lv_t *); +static int lvm_do_lv_remove(int, char *, int); +static int lvm_do_lv_extend_reduce(int, char *, lv_t *); +static int lvm_do_lv_status_byname(vg_t *r, void *); +static int lvm_do_lv_status_byindex(vg_t *, void *arg); +static int lvm_do_pv_change(vg_t*, void*); +static int lvm_do_pv_status(vg_t *, void *); +static void lvm_geninit(struct gendisk *); +#ifdef LVM_GET_INODE +static struct inode *lvm_get_inode(int); +void lvm_clear_inode(struct inode *); +#endif +/* END Internal function prototypes */ + + +/* volume group descriptor area pointers */ +static vg_t *vg[ABS_MAX_VG]; +static pv_t *pvp = NULL; +static lv_t *lvp = NULL; +static pe_t *pep = NULL; +static pe_t *pep1 = NULL; + + +/* map from block minor number to VG and LV numbers */ +typedef struct { + int vg_number; + int lv_number; +} vg_lv_map_t; +static vg_lv_map_t vg_lv_map[ABS_MAX_LV]; + + +/* Request structures (lvm_chr_ioctl()) */ +static pv_change_req_t pv_change_req; +static pv_flush_req_t pv_flush_req; +static pv_status_req_t pv_status_req; +static pe_lock_req_t pe_lock_req; +static le_remap_req_t le_remap_req; +static lv_req_t lv_req; + +#ifdef LVM_TOTAL_RESET +static int lvm_reset_spindown = 0; +#endif + +static char pv_name[NAME_LEN]; +/* static char rootvg[NAME_LEN] = { 0, }; */ +static uint lv_open = 0; +static const char *const lvm_name = LVM_NAME; +static int lock = 0; +static int loadtime = 0; +static uint vg_count = 0; +static long lvm_chr_open_count = 0; +static ushort lvm_iop_version = LVM_DRIVER_IOP_VERSION; +static DECLARE_WAIT_QUEUE_HEAD(lvm_snapshot_wait); +static DECLARE_WAIT_QUEUE_HEAD(lvm_wait); +static DECLARE_WAIT_QUEUE_HEAD(lvm_map_wait); + +static spinlock_t lvm_lock = SPIN_LOCK_UNLOCKED; +static spinlock_t lvm_snapshot_lock = SPIN_LOCK_UNLOCKED; + +static struct file_operations lvm_chr_fops = +{ + open: lvm_chr_open, + release: lvm_chr_close, + ioctl: lvm_chr_ioctl, +}; + +static struct file_operations lvm_blk_fops = +{ + open: lvm_blk_open, + release: blkdev_close, + read: lvm_blk_read, + write: lvm_blk_write, + ioctl: lvm_blk_ioctl, + fsync: block_fsync, +}; + +#define BLOCK_DEVICE_OPERATIONS +/* block device operations structure needed for 2.3.38? and above */ +static struct block_device_operations lvm_blk_dops = +{ + open: lvm_blk_open, + release: lvm_blk_close, + ioctl: lvm_blk_ioctl +}; + +/* gendisk structures */ +static struct hd_struct lvm_hd_struct[MAX_LV]; +static int lvm_blocksizes[MAX_LV] = +{0,}; +static int lvm_size[MAX_LV] = +{0,}; +static struct gendisk lvm_gendisk = +{ + MAJOR_NR, /* major # */ + LVM_NAME, /* name of major */ + 0, /* number of times minor is shifted + to get real minor */ + 1, /* maximum partitions per device */ + lvm_hd_struct, /* partition table */ + lvm_size, /* device size in blocks, copied + to block_size[] */ + MAX_LV, /* number or real devices */ + NULL, /* internal */ + NULL, /* pointer to next gendisk struct (internal) */ +}; + + +#ifdef MODULE +/* + * Module initialization... + */ +int init_module(void) +#else +/* + * Driver initialization... + */ +#ifdef __initfunc +__initfunc(int lvm_init(void)) +#else +int __init lvm_init(void) +#endif +#endif /* #ifdef MODULE */ +{ + struct gendisk *gendisk_ptr = NULL; + + if (register_chrdev(LVM_CHAR_MAJOR, lvm_name, &lvm_chr_fops) < 0) { + printk(KERN_ERR "%s -- register_chrdev failed\n", lvm_name); + return -EIO; + } +#ifdef BLOCK_DEVICE_OPERATIONS + if (register_blkdev(MAJOR_NR, lvm_name, &lvm_blk_dops) < 0) +#else + if (register_blkdev(MAJOR_NR, lvm_name, &lvm_blk_fops) < 0) +#endif + { + printk("%s -- register_blkdev failed\n", lvm_name); + if (unregister_chrdev(LVM_CHAR_MAJOR, lvm_name) < 0) + printk(KERN_ERR "%s -- unregister_chrdev failed\n", lvm_name); + return -EIO; + } +#if defined CONFIG_LVM_PROC_FS && defined CONFIG_PROC_FS + create_proc_info_entry(LVM_NAME, S_IFREG | S_IRUGO, + &proc_root, lvm_proc_get_info_ptr); +#endif + + lvm_init_vars(); + lvm_geninit(&lvm_gendisk); + + /* insert our gendisk at the corresponding major */ + if (gendisk_head != NULL) { + gendisk_ptr = gendisk_head; + while (gendisk_ptr->next != NULL && + gendisk_ptr->major > lvm_gendisk.major) { + gendisk_ptr = gendisk_ptr->next; + } + lvm_gendisk.next = gendisk_ptr->next; + gendisk_ptr->next = &lvm_gendisk; + } else { + gendisk_head = &lvm_gendisk; + lvm_gendisk.next = NULL; + } + +#ifdef LVM_HD_NAME + /* reference from drivers/block/genhd.c */ + lvm_hd_name_ptr = lvm_hd_name; +#endif + + blk_init_queue(BLK_DEFAULT_QUEUE(MAJOR_NR), DEVICE_REQUEST); + blk_queue_make_request(BLK_DEFAULT_QUEUE(MAJOR_NR), lvm_make_request_fn); + /* optional read root VGDA */ +/* + if ( *rootvg != 0) vg_read_with_pv_and_lv ( rootvg, &vg); +*/ + + printk(KERN_INFO + "%s%s -- " +#ifdef MODULE + "Module" +#else + "Driver" +#endif + " successfully initialized\n", + lvm_version, lvm_name); + + return 0; +} /* init_module() / lvm_init() */ + + +#ifdef MODULE +/* + * Module cleanup... + */ +void cleanup_module(void) +{ + struct gendisk *gendisk_ptr = NULL, *gendisk_ptr_prev = NULL; + + if (unregister_chrdev(LVM_CHAR_MAJOR, lvm_name) < 0) { + printk(KERN_ERR "%s -- unregister_chrdev failed\n", lvm_name); + } + if (unregister_blkdev(MAJOR_NR, lvm_name) < 0) { + printk(KERN_ERR "%s -- unregister_blkdev failed\n", lvm_name); + } + blk_cleanup_queue(BLK_DEFAULT_QUEUE(MAJOR_NR)); + + gendisk_ptr = gendisk_ptr_prev = gendisk_head; + while (gendisk_ptr != NULL) { + if (gendisk_ptr == &lvm_gendisk) + break; + gendisk_ptr_prev = gendisk_ptr; + gendisk_ptr = gendisk_ptr->next; + } + /* delete our gendisk from chain */ + if (gendisk_ptr == &lvm_gendisk) + gendisk_ptr_prev->next = gendisk_ptr->next; + + blk_size[MAJOR_NR] = NULL; + blksize_size[MAJOR_NR] = NULL; + +#if defined CONFIG_LVM_PROC_FS && defined CONFIG_PROC_FS + remove_proc_entry(LVM_NAME, &proc_root); +#endif + +#ifdef LVM_HD_NAME + /* reference from linux/drivers/block/genhd.c */ + lvm_hd_name_ptr = NULL; +#endif + + printk(KERN_INFO "%s -- Module successfully deactivated\n", lvm_name); + + return; +} /* void cleanup_module() */ +#endif /* #ifdef MODULE */ + + +/* + * support function to initialize lvm variables + */ +#ifdef __initfunc +__initfunc(void lvm_init_vars(void)) +#else +void __init lvm_init_vars(void) +#endif +{ + int v; + + loadtime = CURRENT_TIME; + + lvm_lock = lvm_snapshot_lock = SPIN_LOCK_UNLOCKED; + + pe_lock_req.lock = UNLOCK_PE; + pe_lock_req.data.lv_dev = \ + pe_lock_req.data.pv_dev = \ + pe_lock_req.data.pv_offset = 0; + + /* Initialize VG pointers */ + for (v = 0; v < ABS_MAX_VG; v++) vg[v] = NULL; + + /* Initialize LV -> VG association */ + for (v = 0; v < ABS_MAX_LV; v++) { + /* index ABS_MAX_VG never used for real VG */ + vg_lv_map[v].vg_number = ABS_MAX_VG; + vg_lv_map[v].lv_number = -1; + } + + return; +} /* lvm_init_vars() */ + + +/******************************************************************** + * + * Character device functions + * + ********************************************************************/ + +/* + * character device open routine + */ +static int lvm_chr_open(struct inode *inode, + struct file *file) +{ + int minor = MINOR(inode->i_rdev); + +#ifdef DEBUG + printk(KERN_DEBUG + "%s -- lvm_chr_open MINOR: %d VG#: %d mode: 0x%X lock: %d\n", + lvm_name, minor, VG_CHR(minor), file->f_mode, lock); +#endif + + /* super user validation */ + if (!capable(CAP_SYS_ADMIN)) return -EACCES; + + /* Group special file open */ + if (VG_CHR(minor) > MAX_VG) return -ENXIO; + + MOD_INC_USE_COUNT; + + lvm_chr_open_count++; + return 0; +} /* lvm_chr_open() */ + + +/* + * character device i/o-control routine + * + * Only one changing process can do changing ioctl at one time, + * others will block. + * + */ +static int lvm_chr_ioctl(struct inode *inode, struct file *file, + uint command, ulong a) +{ + int minor = MINOR(inode->i_rdev); + uint extendable, l, v; + void *arg = (void *) a; + lv_t lv; + vg_t* vg_ptr = vg[VG_CHR(minor)]; + + /* otherwise cc will complain about unused variables */ + (void) lvm_lock; + + +#ifdef DEBUG_IOCTL + printk(KERN_DEBUG + "%s -- lvm_chr_ioctl: command: 0x%X MINOR: %d " + "VG#: %d mode: 0x%X\n", + lvm_name, command, minor, VG_CHR(minor), file->f_mode); +#endif + +#ifdef LVM_TOTAL_RESET + if (lvm_reset_spindown > 0) return -EACCES; +#endif + + /* Main command switch */ + switch (command) { + case LVM_LOCK_LVM: + /* lock the LVM */ + return lvm_do_lock_lvm(); + + case LVM_GET_IOP_VERSION: + /* check lvm version to ensure driver/tools+lib + interoperability */ + if (copy_to_user(arg, &lvm_iop_version, sizeof(ushort)) != 0) + return -EFAULT; + return 0; + +#ifdef LVM_TOTAL_RESET + case LVM_RESET: + /* lock reset function */ + lvm_reset_spindown = 1; + for (v = 0; v < ABS_MAX_VG; v++) { + if (vg[v] != NULL) lvm_do_vg_remove(v); + } + +#ifdef MODULE + while (GET_USE_COUNT(&__this_module) < 1) + MOD_INC_USE_COUNT; + while (GET_USE_COUNT(&__this_module) > 1) + MOD_DEC_USE_COUNT; +#endif /* MODULE */ + lock = 0; /* release lock */ + wake_up_interruptible(&lvm_wait); + return 0; +#endif /* LVM_TOTAL_RESET */ + + + case LE_REMAP: + /* remap a logical extent (after moving the physical extent) */ + return lvm_do_le_remap(vg_ptr,arg); + + case PE_LOCK_UNLOCK: + /* lock/unlock i/o to a physical extent to move it to another + physical volume (move's done in user space's pvmove) */ + return lvm_do_pe_lock_unlock(vg_ptr,arg); + + case VG_CREATE: + /* create a VGDA */ + return lvm_do_vg_create(minor, arg); + + case VG_REMOVE: + /* remove an inactive VGDA */ + return lvm_do_vg_remove(minor); + + case VG_EXTEND: + /* extend a volume group */ + return lvm_do_vg_extend(vg_ptr,arg); + + case VG_REDUCE: + /* reduce a volume group */ + return lvm_do_vg_reduce(vg_ptr,arg); + + + case VG_SET_EXTENDABLE: + /* set/clear extendability flag of volume group */ + if (vg_ptr == NULL) return -ENXIO; + if (copy_from_user(&extendable, arg, sizeof(extendable)) != 0) + return -EFAULT; + + if (extendable == VG_EXTENDABLE || + extendable == ~VG_EXTENDABLE) { + if (extendable == VG_EXTENDABLE) + vg_ptr->vg_status |= VG_EXTENDABLE; + else + vg_ptr->vg_status &= ~VG_EXTENDABLE; + } else return -EINVAL; + return 0; + + + case VG_STATUS: + /* get volume group data (only the vg_t struct) */ + if (vg_ptr == NULL) return -ENXIO; + if (copy_to_user(arg, vg_ptr, sizeof(vg_t)) != 0) + return -EFAULT; + return 0; + + + case VG_STATUS_GET_COUNT: + /* get volume group count */ + if (copy_to_user(arg, &vg_count, sizeof(vg_count)) != 0) + return -EFAULT; + return 0; + + + case VG_STATUS_GET_NAMELIST: + /* get volume group count */ + for (l = v = 0; v < ABS_MAX_VG; v++) { + if (vg[v] != NULL) { + if (copy_to_user(arg + l++ * NAME_LEN, + vg[v]->vg_name, + NAME_LEN) != 0) + return -EFAULT; + } + } + return 0; + + + case LV_CREATE: + case LV_REMOVE: + case LV_EXTEND: + case LV_REDUCE: + /* create, remove, extend or reduce a logical volume */ + if (vg_ptr == NULL) return -ENXIO; + if (copy_from_user(&lv_req, arg, sizeof(lv_req)) != 0) + return -EFAULT; + + if (command != LV_REMOVE) { + if (copy_from_user(&lv, lv_req.lv, sizeof(lv_t)) != 0) + return -EFAULT; + } + switch (command) { + case LV_CREATE: + return lvm_do_lv_create(minor, lv_req.lv_name, &lv); + + case LV_REMOVE: + return lvm_do_lv_remove(minor, lv_req.lv_name, -1); + + case LV_EXTEND: + case LV_REDUCE: + return lvm_do_lv_extend_reduce(minor, lv_req.lv_name, &lv); + } + + + case LV_STATUS_BYNAME: + /* get status of a logical volume by name */ + return lvm_do_lv_status_byname(vg_ptr,arg); + + case LV_STATUS_BYINDEX: + /* get status of a logical volume by index */ + return lvm_do_lv_status_byindex(vg_ptr,arg); + + case PV_CHANGE: + /* change a physical volume */ + return lvm_do_pv_change(vg_ptr,arg); + + case PV_STATUS: + /* get physical volume data (pv_t structure only) */ + return lvm_do_pv_status(vg_ptr,arg); + + case PV_FLUSH: + /* physical volume buffer flush/invalidate */ + if (copy_from_user(&pv_flush_req, arg, + sizeof(pv_flush_req)) != 0) + return -EFAULT; + + fsync_dev(pv_flush_req.pv_dev); + invalidate_buffers(pv_flush_req.pv_dev); + return 0; + + default: + printk(KERN_WARNING + "%s -- lvm_chr_ioctl: unknown command %x\n", + lvm_name, command); + return -EINVAL; + } + + return 0; +} /* lvm_chr_ioctl */ + + +/* + * character device close routine + */ +static int lvm_chr_close(struct inode *inode, struct file *file) +{ +#ifdef DEBUG + int minor = MINOR(inode->i_rdev); + printk(KERN_DEBUG + "%s -- lvm_chr_close VG#: %d\n", lvm_name, VG_CHR(minor)); +#endif + +#ifdef LVM_TOTAL_RESET + if (lvm_reset_spindown > 0) { + lvm_reset_spindown = 0; + lvm_chr_open_count = 1; + } +#endif + + if (lvm_chr_open_count > 0) lvm_chr_open_count--; + if (lock == current->pid) { + lock = 0; /* release lock */ + wake_up_interruptible(&lvm_wait); + } + +#ifdef MODULE + if (GET_USE_COUNT(&__this_module) > 0) MOD_DEC_USE_COUNT; +#endif + + return 0; +} /* lvm_chr_close() */ + + + +/******************************************************************** + * + * Block device functions + * + ********************************************************************/ + +/* + * block device open routine + */ +static int lvm_blk_open(struct inode *inode, struct file *file) +{ + int minor = MINOR(inode->i_rdev); + lv_t *lv_ptr; + vg_t *vg_ptr = vg[VG_BLK(minor)]; + +#ifdef DEBUG_LVM_BLK_OPEN + printk(KERN_DEBUG + "%s -- lvm_blk_open MINOR: %d VG#: %d LV#: %d mode: 0x%X\n", + lvm_name, minor, VG_BLK(minor), LV_BLK(minor), file->f_mode); +#endif + +#ifdef LVM_TOTAL_RESET + if (lvm_reset_spindown > 0) + return -EPERM; +#endif + + if (vg_ptr != NULL && + (vg_ptr->vg_status & VG_ACTIVE) && + (lv_ptr = vg_ptr->lv[LV_BLK(minor)]) != NULL && + LV_BLK(minor) >= 0 && + LV_BLK(minor) < vg_ptr->lv_max) { + + /* Check parallel LV spindown (LV remove) */ + if (lv_ptr->lv_status & LV_SPINDOWN) return -EPERM; + + /* Check inactive LV and open for read/write */ + if (file->f_mode & O_RDWR) { + if (!(lv_ptr->lv_status & LV_ACTIVE)) return -EPERM; + if (!(lv_ptr->lv_access & LV_WRITE)) return -EACCES; + } + +#ifdef BLOCK_DEVICE_OPERATIONS + file->f_op = &lvm_blk_fops; +#endif + + /* be sure to increment VG counter */ + if (lv_ptr->lv_open == 0) vg_ptr->lv_open++; + lv_ptr->lv_open++; + + MOD_INC_USE_COUNT; + +#ifdef DEBUG_LVM_BLK_OPEN + printk(KERN_DEBUG + "%s -- lvm_blk_open MINOR: %d VG#: %d LV#: %d size: %d\n", + lvm_name, minor, VG_BLK(minor), LV_BLK(minor), + lv_ptr->lv_size); +#endif + + return 0; + } + return -ENXIO; +} /* lvm_blk_open() */ + + +/* + * block device read + */ +static ssize_t lvm_blk_read(struct file *file, char *buffer, + size_t size, loff_t * offset) +{ + int minor = MINOR(file->f_dentry->d_inode->i_rdev); + + read_ahead[MAJOR(file->f_dentry->d_inode->i_rdev)] = + vg[VG_BLK(minor)]->lv[LV_BLK(minor)]->lv_read_ahead; + return block_read(file, buffer, size, offset); +} + + +/* + * block device write + */ +static ssize_t lvm_blk_write(struct file *file, const char *buffer, + size_t size, loff_t * offset) +{ + int minor = MINOR(file->f_dentry->d_inode->i_rdev); + + read_ahead[MAJOR(file->f_dentry->d_inode->i_rdev)] = + vg[VG_BLK(minor)]->lv[LV_BLK(minor)]->lv_read_ahead; + return block_write(file, buffer, size, offset); +} + + +/* + * block device i/o-control routine + */ +static int lvm_blk_ioctl(struct inode *inode, struct file *file, + uint command, ulong a) +{ + int minor = MINOR(inode->i_rdev); + vg_t *vg_ptr = vg[VG_BLK(minor)]; + lv_t *lv_ptr = vg_ptr->lv[LV_BLK(minor)]; + void *arg = (void *) a; + struct hd_geometry *hd = (struct hd_geometry *) a; + +#ifdef DEBUG_IOCTL + printk(KERN_DEBUG + "%s -- lvm_blk_ioctl MINOR: %d command: 0x%X arg: %X " + "VG#: %dl LV#: %d\n", + lvm_name, minor, command, (ulong) arg, + VG_BLK(minor), LV_BLK(minor)); +#endif + + switch (command) { + case BLKGETSIZE: + /* return device size */ +#ifdef DEBUG_IOCTL + printk(KERN_DEBUG + "%s -- lvm_blk_ioctl -- BLKGETSIZE: %u\n", + lvm_name, lv_ptr->lv_size); +#endif + copy_to_user((long *) arg, &lv_ptr->lv_size, + sizeof(lv_ptr->lv_size)); + break; + + + case BLKFLSBUF: + /* flush buffer cache */ + if (!capable(CAP_SYS_ADMIN)) return -EACCES; + +#ifdef DEBUG_IOCTL + printk(KERN_DEBUG + "%s -- lvm_blk_ioctl -- BLKFLSBUF\n", lvm_name); +#endif + fsync_dev(inode->i_rdev); + break; + + + case BLKRASET: + /* set read ahead for block device */ + if (!capable(CAP_SYS_ADMIN)) return -EACCES; + +#ifdef DEBUG_IOCTL + printk(KERN_DEBUG + "%s -- lvm_blk_ioctl -- BLKRASET: %d sectors for %02X:%02X\n", + lvm_name, (long) arg, MAJOR(inode->i_rdev), minor); +#endif + if ((long) arg < LVM_MIN_READ_AHEAD || + (long) arg > LVM_MAX_READ_AHEAD) + return -EINVAL; + lv_ptr->lv_read_ahead = (long) arg; + break; + + + case BLKRAGET: + /* get current read ahead setting */ +#ifdef DEBUG_IOCTL + printk(KERN_DEBUG + "%s -- lvm_blk_ioctl -- BLKRAGET\n", lvm_name); +#endif + copy_to_user((long *) arg, &lv_ptr->lv_read_ahead, + sizeof(lv_ptr->lv_read_ahead)); + break; + + + case HDIO_GETGEO: + /* get disk geometry */ +#ifdef DEBUG_IOCTL + printk(KERN_DEBUG + "%s -- lvm_blk_ioctl -- HDIO_GETGEO\n", lvm_name); +#endif + if (hd == NULL) + return -EINVAL; + { + unsigned char heads = 64; + unsigned char sectors = 32; + long start = 0; + short cylinders = lv_ptr->lv_size / heads / sectors; + + if (copy_to_user((char *) &hd->heads, &heads, + sizeof(heads)) != 0 || + copy_to_user((char *) &hd->sectors, §ors, + sizeof(sectors)) != 0 || + copy_to_user((short *) &hd->cylinders, + &cylinders, sizeof(cylinders)) != 0 || + copy_to_user((long *) &hd->start, &start, + sizeof(start)) != 0) + return -EFAULT; + } + +#ifdef DEBUG_IOCTL + printk(KERN_DEBUG + "%s -- lvm_blk_ioctl -- cylinders: %d\n", + lvm_name, lv_ptr->lv_size / heads / sectors); +#endif + break; + + + case LV_SET_ACCESS: + /* set access flags of a logical volume */ + if (!capable(CAP_SYS_ADMIN)) return -EACCES; + lv_ptr->lv_access = (ulong) arg; + break; + + + case LV_SET_STATUS: + /* set status flags of a logical volume */ + if (!capable(CAP_SYS_ADMIN)) return -EACCES; + if (!((ulong) arg & LV_ACTIVE) && lv_ptr->lv_open > 1) + return -EPERM; + lv_ptr->lv_status = (ulong) arg; + break; + + + case LV_SET_ALLOCATION: + /* set allocation flags of a logical volume */ + if (!capable(CAP_SYS_ADMIN)) return -EACCES; + lv_ptr->lv_allocation = (ulong) arg; + break; + + + default: + printk(KERN_WARNING + "%s -- lvm_blk_ioctl: unknown command %d\n", + lvm_name, command); + return -EINVAL; + } + + return 0; +} /* lvm_blk_ioctl() */ + + +/* + * block device close routine + */ +static int lvm_blk_close(struct inode *inode, struct file *file) +{ + int minor = MINOR(inode->i_rdev); + vg_t *vg_ptr = vg[VG_BLK(minor)]; + lv_t *lv_ptr = vg_ptr->lv[LV_BLK(minor)]; + +#ifdef DEBUG + printk(KERN_DEBUG + "%s -- lvm_blk_close MINOR: %d VG#: %d LV#: %d\n", + lvm_name, minor, VG_BLK(minor), LV_BLK(minor)); +#endif + + sync_dev(inode->i_rdev); + if (lv_ptr->lv_open == 1) vg_ptr->lv_open--; + lv_ptr->lv_open--; + + MOD_DEC_USE_COUNT; + + return 0; +} /* lvm_blk_close() */ + + +#if defined CONFIG_LVM_PROC_FS && defined CONFIG_PROC_FS +/* + * Support function /proc-Filesystem + */ +#define LVM_PROC_BUF ( i == 0 ? dummy_buf : &buf[sz]) + +static int lvm_proc_get_info(char *page, char **start, off_t pos, int count) +{ + int c, i, l, p, v, vg_counter, pv_counter, lv_counter, lv_open_counter, + lv_open_total, pe_t_bytes, lv_block_exception_t_bytes, seconds; + static off_t sz; + off_t sz_last; + char allocation_flag, inactive_flag, rw_flag, stripes_flag; + char *lv_name, *pv_name; + static char *buf = NULL; + static char dummy_buf[160]; /* sized for 2 lines */ + vg_t *vg_ptr; + lv_t *lv_ptr; + pv_t *pv_ptr; + + +#ifdef DEBUG_LVM_PROC_GET_INFO + printk(KERN_DEBUG + "%s - lvm_proc_get_info CALLED pos: %lu count: %d whence: %d\n", + lvm_name, pos, count, whence); +#endif + + if (pos == 0 || buf == NULL) { + sz_last = vg_counter = pv_counter = lv_counter = lv_open_counter = \ + lv_open_total = pe_t_bytes = lv_block_exception_t_bytes = 0; + + /* search for activity */ + for (v = 0; v < ABS_MAX_VG; v++) { + if ((vg_ptr = vg[v]) != NULL) { + vg_counter++; + pv_counter += vg_ptr->pv_cur; + lv_counter += vg_ptr->lv_cur; + if (vg_ptr->lv_cur > 0) { + for (l = 0; l < vg[v]->lv_max; l++) { + if ((lv_ptr = vg_ptr->lv[l]) != NULL) { + pe_t_bytes += lv_ptr->lv_allocated_le; + if (lv_ptr->lv_block_exception != NULL) + lv_block_exception_t_bytes += lv_ptr->lv_remap_end; + if (lv_ptr->lv_open > 0) { + lv_open_counter++; + lv_open_total += lv_ptr->lv_open; + } + } + } + } + } + } + pe_t_bytes *= sizeof(pe_t); + lv_block_exception_t_bytes *= sizeof(lv_block_exception_t); + + if (buf != NULL) { +#ifdef DEBUG_KFREE + printk(KERN_DEBUG + "%s -- kfree %d\n", lvm_name, __LINE__); +#endif + kfree(buf); + buf = NULL; + } + /* 2 times: first to get size to allocate buffer, + 2nd to fill the malloced buffer */ + for (i = 0; i < 2; i++) { + sz = 0; + sz += sprintf(LVM_PROC_BUF, + "LVM " +#ifdef MODULE + "module" +#else + "driver" +#endif + " %s\n\n" + "Total: %d VG%s %d PV%s %d LV%s ", + lvm_short_version, + vg_counter, vg_counter == 1 ? "" : "s", + pv_counter, pv_counter == 1 ? "" : "s", + lv_counter, lv_counter == 1 ? "" : "s"); + sz += sprintf(LVM_PROC_BUF, + "(%d LV%s open", + lv_open_counter, + lv_open_counter == 1 ? "" : "s"); + if (lv_open_total > 0) + sz += sprintf(LVM_PROC_BUF, + " %d times)\n", + lv_open_total); + else + sz += sprintf(LVM_PROC_BUF, ")"); + sz += sprintf(LVM_PROC_BUF, + "\nGlobal: %lu bytes malloced IOP version: %d ", + vg_counter * sizeof(vg_t) + + pv_counter * sizeof(pv_t) + + lv_counter * sizeof(lv_t) + + pe_t_bytes + lv_block_exception_t_bytes + sz_last, + lvm_iop_version); + + seconds = CURRENT_TIME - loadtime; + if (seconds < 0) + loadtime = CURRENT_TIME + seconds; + if (seconds / 86400 > 0) { + sz += sprintf(LVM_PROC_BUF, "%d day%s ", + seconds / 86400, + seconds / 86400 == 0 || + seconds / 86400 > 1 ? "s" : ""); + } + sz += sprintf(LVM_PROC_BUF, "%d:%02d:%02d active\n", + (seconds % 86400) / 3600, + (seconds % 3600) / 60, + seconds % 60); + + if (vg_counter > 0) { + for (v = 0; v < ABS_MAX_VG; v++) { + /* volume group */ + if ((vg_ptr = vg[v]) != NULL) { + inactive_flag = ' '; + if (!(vg_ptr->vg_status & VG_ACTIVE)) inactive_flag = 'I'; + sz += sprintf(LVM_PROC_BUF, + "\nVG: %c%s [%d PV, %d LV/%d open] " + " PE Size: %d KB\n" + " Usage [KB/PE]: %d /%d total " + "%d /%d used %d /%d free", + inactive_flag, + vg_ptr->vg_name, + vg_ptr->pv_cur, + vg_ptr->lv_cur, + vg_ptr->lv_open, + vg_ptr->pe_size >> 1, + vg_ptr->pe_size * vg_ptr->pe_total >> 1, + vg_ptr->pe_total, + vg_ptr->pe_allocated * vg_ptr->pe_size >> 1, + vg_ptr->pe_allocated, + (vg_ptr->pe_total - vg_ptr->pe_allocated) * + vg_ptr->pe_size >> 1, + vg_ptr->pe_total - vg_ptr->pe_allocated); + + /* physical volumes */ + sz += sprintf(LVM_PROC_BUF, + "\n PV%s ", + vg_ptr->pv_cur == 1 ? ": " : "s:"); + c = 0; + for (p = 0; p < vg_ptr->pv_max; p++) { + if ((pv_ptr = vg_ptr->pv[p]) != NULL) { + inactive_flag = 'A'; + if (!(pv_ptr->pv_status & PV_ACTIVE)) + inactive_flag = 'I'; + allocation_flag = 'A'; + if (!(pv_ptr->pv_allocatable & PV_ALLOCATABLE)) + allocation_flag = 'N'; + pv_name = strchr(pv_ptr->pv_name+1,'/'); + if ( pv_name == 0) pv_name = pv_ptr->pv_name; + else pv_name++; + sz += sprintf(LVM_PROC_BUF, + "[%c%c] %-21s %8d /%-6d " + "%8d /%-6d %8d /%-6d", + inactive_flag, + allocation_flag, + pv_name, + pv_ptr->pe_total * + pv_ptr->pe_size >> 1, + pv_ptr->pe_total, + pv_ptr->pe_allocated * + pv_ptr->pe_size >> 1, + pv_ptr->pe_allocated, + (pv_ptr->pe_total - + pv_ptr->pe_allocated) * + pv_ptr->pe_size >> 1, + pv_ptr->pe_total - + pv_ptr->pe_allocated); + c++; + if (c < vg_ptr->pv_cur) + sz += sprintf(LVM_PROC_BUF, + "\n "); + } + } + + /* logical volumes */ + sz += sprintf(LVM_PROC_BUF, + "\n LV%s ", + vg_ptr->lv_cur == 1 ? ": " : "s:"); + c = 0; + for (l = 0; l < vg[v]->lv_max; l++) { + if ((lv_ptr = vg_ptr->lv[l]) != NULL) { + inactive_flag = 'A'; + if (!(lv_ptr->lv_status & LV_ACTIVE)) + inactive_flag = 'I'; + rw_flag = 'R'; + if (lv_ptr->lv_access & LV_WRITE) + rw_flag = 'W'; + allocation_flag = 'D'; + if (lv_ptr->lv_allocation & LV_CONTIGUOUS) + allocation_flag = 'C'; + stripes_flag = 'L'; + if (lv_ptr->lv_stripes > 1) + stripes_flag = 'S'; + sz += sprintf(LVM_PROC_BUF, + "[%c%c%c%c", + inactive_flag, + rw_flag, + allocation_flag, + stripes_flag); + if (lv_ptr->lv_stripes > 1) + sz += sprintf(LVM_PROC_BUF, "%-2d", + lv_ptr->lv_stripes); + else + sz += sprintf(LVM_PROC_BUF, " "); + lv_name = strrchr(lv_ptr->lv_name, '/'); + if ( lv_name == 0) lv_name = lv_ptr->lv_name; + else lv_name++; + sz += sprintf(LVM_PROC_BUF, "] %-25s", lv_name); + if (strlen(lv_name) > 25) + sz += sprintf(LVM_PROC_BUF, + "\n "); + sz += sprintf(LVM_PROC_BUF, "%9d /%-6d ", + lv_ptr->lv_size >> 1, + lv_ptr->lv_size / vg[v]->pe_size); + + if (lv_ptr->lv_open == 0) + sz += sprintf(LVM_PROC_BUF, "close"); + else + sz += sprintf(LVM_PROC_BUF, "%dx open", + lv_ptr->lv_open); + c++; + if (c < vg_ptr->lv_cur) + sz += sprintf(LVM_PROC_BUF, + "\n "); + } + } + if (vg_ptr->lv_cur == 0) sz += sprintf(LVM_PROC_BUF, "none"); + sz += sprintf(LVM_PROC_BUF, "\n"); + } + } + } + if (buf == NULL) { + if ((buf = vmalloc(sz)) == NULL) { + sz = 0; + return sprintf(page, "%s - vmalloc error at line %d\n", + lvm_name, __LINE__); + } + } + sz_last = sz; + } + } + if (pos > sz - 1) { + vfree(buf); + buf = NULL; + return 0; + } + *start = &buf[pos]; + if (sz - pos < count) + return sz - pos; + else + return count; +} /* lvm_proc_get_info() */ +#endif /* #if defined CONFIG_LVM_PROC_FS && defined CONFIG_PROC_FS */ + + +/* + * block device support function for /usr/src/linux/drivers/block/ll_rw_blk.c + * (see init_module/lvm_init) + */ +static int lvm_map(struct buffer_head *bh, int rw) +{ + int minor = MINOR(bh->b_dev); + int ret = 0; + ulong index; + ulong pe_start; + ulong size = bh->b_size >> 9; + ulong rsector_tmp = bh->b_blocknr * size; + ulong rsector_sav; + kdev_t rdev_tmp = bh->b_dev; + kdev_t rdev_sav; + lv_t *lv = vg[VG_BLK(minor)]->lv[LV_BLK(minor)]; + + + if (!(lv->lv_status & LV_ACTIVE)) { + printk(KERN_ALERT + "%s - lvm_map: ll_rw_blk for inactive LV %s\n", + lvm_name, lv->lv_name); + return -1; + } +/* + if ( lv->lv_access & LV_SNAPSHOT) + printk ( "%s -- %02d:%02d block: %lu rw: %d\n", lvm_name, MAJOR ( bh->b_dev), MINOR ( bh->b_dev), bh->b_blocknr, rw); + */ + + /* take care of snapshot chunk writes before + check for writable logical volume */ + if ((lv->lv_access & LV_SNAPSHOT) && + MAJOR(bh->b_rdev) != 0 && + MAJOR(bh->b_rdev) != MAJOR_NR && + (rw == WRITEA || rw == WRITE)) + { + printk ( "%s -- doing snapshot write for %02d:%02d[%02d:%02d] b_blocknr: %lu b_rsector: %lu\n", lvm_name, MAJOR ( bh->b_dev), MINOR ( bh->b_dev), MAJOR ( bh->b_rdev), MINOR ( bh->b_rdev), bh->b_blocknr, bh->b_rsector); + return 0; + } + + if ((rw == WRITE || rw == WRITEA) && + !(lv->lv_access & LV_WRITE)) { + printk(KERN_CRIT + "%s - lvm_map: ll_rw_blk write for readonly LV %s\n", + lvm_name, lv->lv_name); + return -1; + } +#ifdef DEBUG_MAP + printk(KERN_DEBUG + "%s - lvm_map minor:%d *rdev: %02d:%02d *rsector: %lu " + "size:%lu\n", + lvm_name, minor, + MAJOR(rdev_tmp), + MINOR(rdev_tmp), + rsector_tmp, size); +#endif + + if (rsector_tmp + size > lv->lv_size) { + printk(KERN_ALERT + "%s - lvm_map *rsector: %lu or size: %lu wrong for" + " minor: %2d\n", lvm_name, rsector_tmp, size, minor); + return -1; + } + rsector_sav = rsector_tmp; + rdev_sav = rdev_tmp; + +lvm_second_remap: + /* linear mapping */ + if (lv->lv_stripes < 2) { + /* get the index */ + index = rsector_tmp / vg[VG_BLK(minor)]->pe_size; + pe_start = lv->lv_current_pe[index].pe; + rsector_tmp = lv->lv_current_pe[index].pe + + (rsector_tmp % vg[VG_BLK(minor)]->pe_size); + rdev_tmp = lv->lv_current_pe[index].dev; + +#ifdef DEBUG_MAP + printk(KERN_DEBUG + "lv_current_pe[%ld].pe: %ld rdev: %02d:%02d rsector:%ld\n", + index, + lv->lv_current_pe[index].pe, + MAJOR(rdev_tmp), + MINOR(rdev_tmp), + rsector_tmp); +#endif + + /* striped mapping */ + } else { + ulong stripe_index; + ulong stripe_length; + + stripe_length = vg[VG_BLK(minor)]->pe_size * lv->lv_stripes; + stripe_index = (rsector_tmp % stripe_length) / lv->lv_stripesize; + index = rsector_tmp / stripe_length + + (stripe_index % lv->lv_stripes) * + (lv->lv_allocated_le / lv->lv_stripes); + pe_start = lv->lv_current_pe[index].pe; + rsector_tmp = lv->lv_current_pe[index].pe + + (rsector_tmp % stripe_length) - + (stripe_index % lv->lv_stripes) * lv->lv_stripesize - + stripe_index / lv->lv_stripes * + (lv->lv_stripes - 1) * lv->lv_stripesize; + rdev_tmp = lv->lv_current_pe[index].dev; + } + +#ifdef DEBUG_MAP + printk(KERN_DEBUG + "lv_current_pe[%ld].pe: %ld rdev: %02d:%02d rsector:%ld\n" + "stripe_length: %ld stripe_index: %ld\n", + index, + lv->lv_current_pe[index].pe, + MAJOR(rdev_tmp), + MINOR(rdev_tmp), + rsector_tmp, + stripe_length, + stripe_index); +#endif + + /* handle physical extents on the move */ + if (pe_lock_req.lock == LOCK_PE) { + if (rdev_tmp == pe_lock_req.data.pv_dev && + rsector_tmp >= pe_lock_req.data.pv_offset && + rsector_tmp < (pe_lock_req.data.pv_offset + + vg[VG_BLK(minor)]->pe_size)) { + sleep_on(&lvm_map_wait); + rsector_tmp = rsector_sav; + rdev_tmp = rdev_sav; + goto lvm_second_remap; + } + } + /* statistic */ + if (rw == WRITE || rw == WRITEA) + lv->lv_current_pe[index].writes++; + else + lv->lv_current_pe[index].reads++; + + /* snapshot volume exception handling on physical device address base */ + if (lv->lv_access & (LV_SNAPSHOT | LV_SNAPSHOT_ORG)) { + /* original logical volume */ + if (lv->lv_access & LV_SNAPSHOT_ORG) { + if (rw == WRITE || rw == WRITEA) + { + lv_t *lv_ptr; + + /* start with first snapshot and loop thrugh all of them */ + for (lv_ptr = lv->lv_snapshot_next; + lv_ptr != NULL; + lv_ptr = lv_ptr->lv_snapshot_next) { + down(&lv->lv_snapshot_org->lv_snapshot_sem); + /* do we still have exception storage for this snapshot free? */ + if (lv_ptr->lv_block_exception != NULL) { + rdev_sav = rdev_tmp; + rsector_sav = rsector_tmp; + if (!lvm_snapshot_remap_block(&rdev_tmp, + &rsector_tmp, + pe_start, + lv_ptr)) { + /* create a new mapping */ + ret = lvm_snapshot_COW(rdev_tmp, + rsector_tmp, + pe_start, + rsector_sav, + lv_ptr); + } + rdev_tmp = rdev_sav; + rsector_tmp = rsector_sav; + } + up(&lv->lv_snapshot_org->lv_snapshot_sem); + } + } + } else { + /* remap snapshot logical volume */ + down(&lv->lv_snapshot_sem); + if (lv->lv_block_exception != NULL) + lvm_snapshot_remap_block(&rdev_tmp, &rsector_tmp, pe_start, lv); + up(&lv->lv_snapshot_sem); + } + } + bh->b_rdev = rdev_tmp; + bh->b_rsector = rsector_tmp; + + return ret; +} /* lvm_map() */ + + +/* + * internal support functions + */ + +#ifdef LVM_HD_NAME +/* + * generate "hard disk" name + */ +void lvm_hd_name(char *buf, int minor) +{ + int len = 0; + lv_t *lv_ptr; + + if (vg[VG_BLK(minor)] == NULL || + (lv_ptr = vg[VG_BLK(minor)]->lv[LV_BLK(minor)]) == NULL) + return; + len = strlen(lv_ptr->lv_name) - 5; + memcpy(buf, &lv_ptr->lv_name[5], len); + buf[len] = 0; + return; +} +#endif + + +/* + * this one never should be called... + */ +static void lvm_dummy_device_request(request_queue_t * t) +{ + printk(KERN_EMERG + "%s -- oops, got lvm request for %02d:%02d [sector: %lu]\n", + lvm_name, + MAJOR(CURRENT->rq_dev), + MINOR(CURRENT->rq_dev), + CURRENT->sector); + return; +} + + +/* + * make request function + */ +static void lvm_make_request_fn(int rw, struct buffer_head *bh) +{ + lvm_map(bh, rw); + if (bh->b_rdev != MD_MAJOR) generic_make_request(rw, bh); + return; +} + + +/******************************************************************** + * + * Character device support functions + * + ********************************************************************/ +/* + * character device support function logical volume manager lock + */ +static int lvm_do_lock_lvm(void) +{ +lock_try_again: + spin_lock(&lvm_lock); + if (lock != 0 && lock != current->pid) { +#ifdef DEBUG_IOCTL + printk(KERN_INFO "lvm_do_lock_lvm: %s is locked by pid %d ...\n", + lvm_name, lock); +#endif + spin_unlock(&lvm_lock); + interruptible_sleep_on(&lvm_wait); + if (current->sigpending != 0) + return -EINTR; +#ifdef LVM_TOTAL_RESET + if (lvm_reset_spindown > 0) + return -EACCES; +#endif + goto lock_try_again; + } + lock = current->pid; + spin_unlock(&lvm_lock); + return 0; +} /* lvm_do_lock_lvm */ + + +/* + * character device support function lock/unlock physical extend + */ +static int lvm_do_pe_lock_unlock(vg_t *vg_ptr, void *arg) +{ + uint p; + + if (vg_ptr == NULL) return -ENXIO; + if (copy_from_user(&pe_lock_req, arg, + sizeof(pe_lock_req_t)) != 0) return -EFAULT; + + switch (pe_lock_req.lock) { + case LOCK_PE: + for (p = 0; p < vg_ptr->pv_max; p++) { + if (vg_ptr->pv[p] != NULL && + pe_lock_req.data.pv_dev == + vg_ptr->pv[p]->pv_dev) + break; + } + if (p == vg_ptr->pv_max) return -ENXIO; + + pe_lock_req.lock = UNLOCK_PE; + fsync_dev(pe_lock_req.data.lv_dev); + pe_lock_req.lock = LOCK_PE; + break; + + case UNLOCK_PE: + pe_lock_req.lock = UNLOCK_PE; + pe_lock_req.data.lv_dev = \ + pe_lock_req.data.pv_dev = \ + pe_lock_req.data.pv_offset = 0; + wake_up(&lvm_map_wait); + break; + + default: + return -EINVAL; + } + return 0; +} + + +/* + * character device support function logical extend remap + */ +static int lvm_do_le_remap(vg_t *vg_ptr, void *arg) +{ + uint l, le; + lv_t *lv_ptr; + + if (vg_ptr == NULL) return -ENXIO; + if (copy_from_user(&le_remap_req, arg, + sizeof(le_remap_req_t)) != 0) + return -EFAULT; + + for (l = 0; l < vg_ptr->lv_max; l++) { + lv_ptr = vg_ptr->lv[l]; + if (lv_ptr != NULL && + strcmp(lv_ptr->lv_name, + le_remap_req.lv_name) == 0) { + for (le = 0; le < lv_ptr->lv_allocated_le; + le++) { + if (lv_ptr->lv_current_pe[le].dev == + le_remap_req.old_dev && + lv_ptr->lv_current_pe[le].pe == + le_remap_req.old_pe) { + lv_ptr->lv_current_pe[le].dev = + le_remap_req.new_dev; + lv_ptr->lv_current_pe[le].pe = + le_remap_req.new_pe; + return 0; + } + } + return -EINVAL; + } + } + return -ENXIO; +} /* lvm_do_le_remap() */ + + +/* + * character device support function VGDA create + */ +int lvm_do_vg_create(int minor, void *arg) +{ + int snaporg_minor = 0; + ulong l, p; + lv_t lv; + vg_t *vg_ptr; + pv_t *pv_ptr; + lv_t *lv_ptr; + + if (vg[VG_CHR(minor)] != NULL) return -EPERM; + + if ((vg_ptr = kmalloc(sizeof(vg_t),GFP_KERNEL)) == NULL) { + printk(KERN_CRIT + "%s -- VG_CREATE: kmalloc error VG at line %d\n", + lvm_name, __LINE__); + return -ENOMEM; + } + /* get the volume group structure */ + if (copy_from_user(vg_ptr, arg, sizeof(vg_t)) != 0) { + kfree(vg_ptr); + return -EFAULT; + } + /* we are not that active so far... */ + vg_ptr->vg_status &= ~VG_ACTIVE; + vg[VG_CHR(minor)] = vg_ptr; + + vg[VG_CHR(minor)]->pe_allocated = 0; + if (vg_ptr->pv_max > ABS_MAX_PV) { + printk(KERN_WARNING + "%s -- Can't activate VG: ABS_MAX_PV too small\n", + lvm_name); + kfree(vg_ptr); + vg[VG_CHR(minor)] = NULL; + return -EPERM; + } + if (vg_ptr->lv_max > ABS_MAX_LV) { + printk(KERN_WARNING + "%s -- Can't activate VG: ABS_MAX_LV too small for %u\n", + lvm_name, vg_ptr->lv_max); + kfree(vg_ptr); + vg_ptr = NULL; + return -EPERM; + } + /* get the physical volume structures */ + vg_ptr->pv_act = vg_ptr->pv_cur = 0; + for (p = 0; p < vg_ptr->pv_max; p++) { + /* user space address */ + if ((pvp = vg_ptr->pv[p]) != NULL) { + pv_ptr = vg_ptr->pv[p] = kmalloc(sizeof(pv_t),GFP_KERNEL); + if (pv_ptr == NULL) { + printk(KERN_CRIT + "%s -- VG_CREATE: kmalloc error PV at line %d\n", + lvm_name, __LINE__); + lvm_do_vg_remove(minor); + return -ENOMEM; + } + if (copy_from_user(pv_ptr, pvp, sizeof(pv_t)) != 0) { + lvm_do_vg_remove(minor); + return -EFAULT; + } + /* We don't need the PE list + in kernel space as with LVs pe_t list (see below) */ + pv_ptr->pe = NULL; + pv_ptr->pe_allocated = 0; + pv_ptr->pv_status = PV_ACTIVE; + vg_ptr->pv_act++; + vg_ptr->pv_cur++; + +#ifdef LVM_GET_INODE + /* insert a dummy inode for fs_may_mount */ + pv_ptr->inode = lvm_get_inode(pv_ptr->pv_dev); +#endif + } + } + + /* get the logical volume structures */ + vg_ptr->lv_cur = 0; + for (l = 0; l < vg_ptr->lv_max; l++) { + /* user space address */ + if ((lvp = vg_ptr->lv[l]) != NULL) { + if (copy_from_user(&lv, lvp, sizeof(lv_t)) != 0) { + lvm_do_vg_remove(minor); + return -EFAULT; + } + vg_ptr->lv[l] = NULL; + if (lvm_do_lv_create(minor, lv.lv_name, &lv) != 0) { + lvm_do_vg_remove(minor); + return -EFAULT; + } + } + } + + /* Second path to correct snapshot logical volumes which are not + in place during first path above */ + for (l = 0; l < vg_ptr->lv_max; l++) { + if ((lv_ptr = vg_ptr->lv[l]) != NULL && + vg_ptr->lv[l]->lv_access & LV_SNAPSHOT) { + snaporg_minor = lv_ptr->lv_snapshot_minor; + if (vg_ptr->lv[LV_BLK(snaporg_minor)] != NULL) { + /* get pointer to original logical volume */ + lv_ptr = vg_ptr->lv[l]->lv_snapshot_org = + vg_ptr->lv[LV_BLK(snaporg_minor)]; + + /* set necessary fields of original logical volume */ + lv_ptr->lv_access |= LV_SNAPSHOT_ORG; + lv_ptr->lv_snapshot_minor = 0; + lv_ptr->lv_snapshot_org = lv_ptr; + lv_ptr->lv_snapshot_prev = NULL; + + /* find last snapshot logical volume in the chain */ + while (lv_ptr->lv_snapshot_next != NULL) + lv_ptr = lv_ptr->lv_snapshot_next; + + /* set back pointer to this last one in our new logical volume */ + vg_ptr->lv[l]->lv_snapshot_prev = lv_ptr; + + /* last logical volume now points to our new snapshot volume */ + lv_ptr->lv_snapshot_next = vg_ptr->lv[l]; + + /* now point to the new one */ + lv_ptr = lv_ptr->lv_snapshot_next; + + /* set necessary fields of new snapshot logical volume */ + lv_ptr->lv_snapshot_next = NULL; + lv_ptr->lv_current_pe = + vg_ptr->lv[LV_BLK(snaporg_minor)]->lv_current_pe; + lv_ptr->lv_allocated_le = + vg_ptr->lv[LV_BLK(snaporg_minor)]->lv_allocated_le; + lv_ptr->lv_current_le = + vg_ptr->lv[LV_BLK(snaporg_minor)]->lv_current_le; + lv_ptr->lv_size = + vg_ptr->lv[LV_BLK(snaporg_minor)]->lv_size; + } + } + } + + vg_count++; + + /* let's go active */ + vg_ptr->vg_status |= VG_ACTIVE; + + MOD_INC_USE_COUNT; + + return 0; +} /* lvm_do_vg_create() */ + + +/* + * character device support function VGDA extend + */ +static int lvm_do_vg_extend(vg_t *vg_ptr, void *arg) +{ + uint p; + pv_t *pv_ptr; + + if (vg_ptr == NULL) return -ENXIO; + if (vg_ptr->pv_cur < vg_ptr->pv_max) { + for (p = 0; p < vg_ptr->pv_max; p++) { + if (vg_ptr->pv[p] == NULL) { + if ((pv_ptr = vg_ptr->pv[p] = kmalloc(sizeof(pv_t),GFP_KERNEL)) == NULL) { + printk(KERN_CRIT + "%s -- VG_EXTEND: kmalloc error PV at line %d\n", + lvm_name, __LINE__); + return -ENOMEM; + } + if (copy_from_user(pv_ptr, arg, sizeof(pv_t)) != 0) { + kfree(pv_ptr); + vg_ptr->pv[p] = NULL; + return -EFAULT; + } + + pv_ptr->pv_status = PV_ACTIVE; + /* We don't need the PE list + in kernel space like LVs pe_t list */ + pv_ptr->pe = NULL; + vg_ptr->pv_cur++; + vg_ptr->pv_act++; + vg_ptr->pe_total += + pv_ptr->pe_total; +#ifdef LVM_GET_INODE + /* insert a dummy inode for fs_may_mount */ + pv_ptr->inode = lvm_get_inode(pv_ptr->pv_dev); +#endif + return 0; + } + } + } +return -EPERM; +} /* lvm_do_vg_extend() */ + + +/* + * character device support function VGDA reduce + */ +static int lvm_do_vg_reduce(vg_t *vg_ptr, void *arg) +{ + uint p; + pv_t *pv_ptr; + + if (vg_ptr == NULL) return -ENXIO; + if (copy_from_user(pv_name, arg, sizeof(pv_name)) != 0) + return -EFAULT; + + for (p = 0; p < vg_ptr->pv_max; p++) { + pv_ptr = vg_ptr->pv[p]; + if (pv_ptr != NULL && + strcmp(pv_ptr->pv_name, + pv_name) == 0) { + if (pv_ptr->lv_cur > 0) return -EPERM; + vg_ptr->pe_total -= + pv_ptr->pe_total; + vg_ptr->pv_cur--; + vg_ptr->pv_act--; +#ifdef LVM_GET_INODE + lvm_clear_inode(pv_ptr->inode); +#endif + kfree(pv_ptr); + /* Make PV pointer array contiguous */ + for (; p < vg_ptr->pv_max - 1; p++) + vg_ptr->pv[p] = vg_ptr->pv[p + 1]; + vg_ptr->pv[p + 1] = NULL; + return 0; + } + } + return -ENXIO; +} /* lvm_do_vg_reduce */ + + +/* + * character device support function VGDA remove + */ +static int lvm_do_vg_remove(int minor) +{ + int i; + vg_t *vg_ptr = vg[VG_CHR(minor)]; + pv_t *pv_ptr; + + if (vg_ptr == NULL) return -ENXIO; + +#ifdef LVM_TOTAL_RESET + if (vg_ptr->lv_open > 0 && lvm_reset_spindown == 0) +#else + if (vg_ptr->lv_open > 0) +#endif + return -EPERM; + + /* let's go inactive */ + vg_ptr->vg_status &= ~VG_ACTIVE; + + /* free LVs */ + /* first free snapshot logical volumes */ + for (i = 0; i < vg_ptr->lv_max; i++) { + if (vg_ptr->lv[i] != NULL && + vg_ptr->lv[i]->lv_access & LV_SNAPSHOT) { + lvm_do_lv_remove(minor, NULL, i); + current->state = TASK_UNINTERRUPTIBLE; + schedule_timeout(1); + } + } + /* then free the rest of the LVs */ + for (i = 0; i < vg_ptr->lv_max; i++) { + if (vg_ptr->lv[i] != NULL) { + lvm_do_lv_remove(minor, NULL, i); + current->state = TASK_UNINTERRUPTIBLE; + schedule_timeout(1); + } + } + + /* free PVs */ + for (i = 0; i < vg_ptr->pv_max; i++) { + if ((pv_ptr = vg_ptr->pv[i]) != NULL) { +#ifdef DEBUG_KFREE + printk(KERN_DEBUG + "%s -- kfree %d\n", lvm_name, __LINE__); +#endif +#ifdef LVM_GET_INODE + lvm_clear_inode(pv_ptr->inode); +#endif + kfree(pv_ptr); + vg[VG_CHR(minor)]->pv[i] = NULL; + } + } + +#ifdef DEBUG_KFREE + printk(KERN_DEBUG "%s -- kfree %d\n", lvm_name, __LINE__); +#endif + kfree(vg_ptr); + vg[VG_CHR(minor)] = NULL; + + vg_count--; + + MOD_DEC_USE_COUNT; + + return 0; +} /* lvm_do_vg_remove() */ + + +/* + * character device support function logical volume create + */ +static int lvm_do_lv_create(int minor, char *lv_name, lv_t *lv) +{ + int l, le, l_new, p, size; + ulong lv_status_save; + lv_block_exception_t *lvbe = lv->lv_block_exception; + vg_t *vg_ptr = vg[VG_CHR(minor)]; + lv_t *lv_ptr = NULL; + + if ((pep = lv->lv_current_pe) == NULL) return -EINVAL; + if (lv->lv_chunk_size > LVM_SNAPSHOT_MAX_CHUNK) + return -EINVAL; + + for (l = 0; l < vg_ptr->lv_max; l++) { + if (vg_ptr->lv[l] != NULL && + strcmp(vg_ptr->lv[l]->lv_name, lv_name) == 0) + return -EEXIST; + } + + /* in case of lv_remove(), lv_create() pair; for eg. lvrename does this */ + l_new = -1; + if (vg_ptr->lv[lv->lv_number] == NULL) + l_new = lv->lv_number; + else { + for (l = 0; l < vg_ptr->lv_max; l++) { + if (vg_ptr->lv[l] == NULL) + if (l_new == -1) l_new = l; + } + } + if (l_new == -1) return -EPERM; + else l = l_new; + + if ((lv_ptr = kmalloc(sizeof(lv_t),GFP_KERNEL)) == NULL) {; + printk(KERN_CRIT "%s -- LV_CREATE: kmalloc error LV at line %d\n", + lvm_name, __LINE__); + return -ENOMEM; + } + /* copy preloaded LV */ + memcpy((char *) lv_ptr, (char *) lv, sizeof(lv_t)); + + lv_status_save = lv_ptr->lv_status; + lv_ptr->lv_status &= ~LV_ACTIVE; + lv_ptr->lv_snapshot_org = \ + lv_ptr->lv_snapshot_prev = \ + lv_ptr->lv_snapshot_next = NULL; + lv_ptr->lv_block_exception = NULL; + init_MUTEX(&lv_ptr->lv_snapshot_sem); + vg_ptr->lv[l] = lv_ptr; + + /* get the PE structures from user space if this + is no snapshot logical volume */ + if (!(lv_ptr->lv_access & LV_SNAPSHOT)) { + size = lv_ptr->lv_allocated_le * sizeof(pe_t); + if ((lv_ptr->lv_current_pe = vmalloc(size)) == NULL) { + printk(KERN_CRIT + "%s -- LV_CREATE: vmalloc error LV_CURRENT_PE of %d Byte " + "at line %d\n", + lvm_name, size, __LINE__); +#ifdef DEBUG_KFREE + printk(KERN_DEBUG "%s -- kfree %d\n", lvm_name, __LINE__); +#endif + kfree(lv_ptr); + vg[VG_CHR(minor)]->lv[l] = NULL; + return -ENOMEM; + } + if (copy_from_user(lv_ptr->lv_current_pe, pep, size)) { + vfree(lv_ptr->lv_current_pe); + kfree(lv_ptr); + vg_ptr->lv[l] = NULL; + return -EFAULT; + } + /* correct the PE count in PVs */ + for (le = 0; le < lv_ptr->lv_allocated_le; le++) { + vg_ptr->pe_allocated++; + for (p = 0; p < vg_ptr->pv_cur; p++) { + if (vg_ptr->pv[p]->pv_dev == + lv_ptr->lv_current_pe[le].dev) + vg_ptr->pv[p]->pe_allocated++; + } + } + } else { + /* Get snapshot exception data and block list */ + if (lvbe != NULL) { + lv_ptr->lv_snapshot_org = + vg_ptr->lv[LV_BLK(lv_ptr->lv_snapshot_minor)]; + if (lv_ptr->lv_snapshot_org != NULL) { + size = lv_ptr->lv_remap_end * sizeof(lv_block_exception_t); + if ((lv_ptr->lv_block_exception = vmalloc(size)) == NULL) { + printk(KERN_CRIT + "%s -- lvm_do_lv_create: vmalloc error LV_BLOCK_EXCEPTION " + "of %d byte at line %d\n", + lvm_name, size, __LINE__); +#ifdef DEBUG_KFREE + printk(KERN_DEBUG "%s -- kfree %d\n", lvm_name, __LINE__); +#endif + kfree(lv_ptr); + vg_ptr->lv[l] = NULL; + return -ENOMEM; + } + if (copy_from_user(lv_ptr->lv_block_exception, lvbe, size)) { + vfree(lv_ptr->lv_block_exception); + kfree(lv_ptr); + vg[VG_CHR(minor)]->lv[l] = NULL; + return -EFAULT; + } + /* get pointer to original logical volume */ + lv_ptr = lv_ptr->lv_snapshot_org; + + lv_ptr->lv_snapshot_minor = 0; + lv_ptr->lv_snapshot_org = lv_ptr; + lv_ptr->lv_snapshot_prev = NULL; + /* walk thrugh the snapshot list */ + while (lv_ptr->lv_snapshot_next != NULL) + lv_ptr = lv_ptr->lv_snapshot_next; + /* now lv_ptr points to the last existing snapshot in the chain */ + vg_ptr->lv[l]->lv_snapshot_prev = lv_ptr; + /* our new one now back points to the previous last in the chain */ + lv_ptr = vg_ptr->lv[l]; + /* now lv_ptr points to our new last snapshot logical volume */ + lv_ptr->lv_snapshot_org = lv_ptr->lv_snapshot_prev->lv_snapshot_org; + lv_ptr->lv_snapshot_next = NULL; + lv_ptr->lv_current_pe = lv_ptr->lv_snapshot_org->lv_current_pe; + lv_ptr->lv_allocated_le = lv_ptr->lv_snapshot_org->lv_allocated_le; + lv_ptr->lv_current_le = lv_ptr->lv_snapshot_org->lv_current_le; + lv_ptr->lv_size = lv_ptr->lv_snapshot_org->lv_size; + lv_ptr->lv_stripes = lv_ptr->lv_snapshot_org->lv_stripes; + lv_ptr->lv_stripesize = lv_ptr->lv_snapshot_org->lv_stripesize; + { + int err = lvm_snapshot_alloc(lv_ptr); + if (err) + { + vfree(lv_ptr->lv_block_exception); + kfree(lv_ptr); + vg[VG_CHR(minor)]->lv[l] = NULL; + return err; + } + } + } else { + vfree(lv_ptr->lv_block_exception); + kfree(lv_ptr); + vg_ptr->lv[l] = NULL; + return -EFAULT; + } + } else { + kfree(vg_ptr->lv[l]); + vg_ptr->lv[l] = NULL; + return -EINVAL; + } + } /* if ( vg[VG_CHR(minor)]->lv[l]->lv_access & LV_SNAPSHOT) */ + + lv_ptr = vg_ptr->lv[l]; + lvm_gendisk.part[MINOR(lv_ptr->lv_dev)].start_sect = 0; + lvm_gendisk.part[MINOR(lv_ptr->lv_dev)].nr_sects = lv_ptr->lv_size; + lvm_size[MINOR(lv_ptr->lv_dev)] = lv_ptr->lv_size >> 1; + vg_lv_map[MINOR(lv_ptr->lv_dev)].vg_number = vg_ptr->vg_number; + vg_lv_map[MINOR(lv_ptr->lv_dev)].lv_number = lv_ptr->lv_number; + LVM_CORRECT_READ_AHEAD(lv_ptr->lv_read_ahead); + vg_ptr->lv_cur++; + lv_ptr->lv_status = lv_status_save; + + /* optionally add our new snapshot LV */ + if (lv_ptr->lv_access & LV_SNAPSHOT) { + /* sync the original logical volume */ + fsync_dev(lv_ptr->lv_snapshot_org->lv_dev); + /* put ourselve into the chain */ + lv_ptr->lv_snapshot_prev->lv_snapshot_next = lv_ptr; + lv_ptr->lv_snapshot_org->lv_access |= LV_SNAPSHOT_ORG; + } + return 0; +} /* lvm_do_lv_create() */ + + +/* + * character device support function logical volume remove + */ +static int lvm_do_lv_remove(int minor, char *lv_name, int l) +{ + uint le, p; + vg_t *vg_ptr = vg[VG_CHR(minor)]; + lv_t *lv_ptr; + + if (l == -1) { + for (l = 0; l < vg_ptr->lv_max; l++) { + if (vg_ptr->lv[l] != NULL && + strcmp(vg_ptr->lv[l]->lv_name, lv_name) == 0) { + break; + } + } + } + if (l == vg_ptr->lv_max) return -ENXIO; + + lv_ptr = vg_ptr->lv[l]; +#ifdef LVM_TOTAL_RESET + if (lv_ptr->lv_open > 0 && lvm_reset_spindown == 0) +#else + if (lv_ptr->lv_open > 0) +#endif + return -EBUSY; + + /* check for deletion of snapshot source while + snapshot volume still exists */ + if ((lv_ptr->lv_access & LV_SNAPSHOT_ORG) && + lv_ptr->lv_snapshot_next != NULL) + return -EPERM; + + lv_ptr->lv_status |= LV_SPINDOWN; + + /* sync the buffers */ + fsync_dev(lv_ptr->lv_dev); + + lv_ptr->lv_status &= ~LV_ACTIVE; + + /* invalidate the buffers */ + invalidate_buffers(lv_ptr->lv_dev); + + /* reset generic hd */ + lvm_gendisk.part[MINOR(lv_ptr->lv_dev)].start_sect = -1; + lvm_gendisk.part[MINOR(lv_ptr->lv_dev)].nr_sects = 0; + lvm_size[MINOR(lv_ptr->lv_dev)] = 0; + + /* reset VG/LV mapping */ + vg_lv_map[MINOR(lv_ptr->lv_dev)].vg_number = ABS_MAX_VG; + vg_lv_map[MINOR(lv_ptr->lv_dev)].lv_number = -1; + + /* correct the PE count in PVs if this is no snapshot logical volume */ + if (!(lv_ptr->lv_access & LV_SNAPSHOT)) { + /* only if this is no snapshot logical volume because + we share the lv_current_pe[] structs with the + original logical volume */ + for (le = 0; le < lv_ptr->lv_allocated_le; le++) { + vg_ptr->pe_allocated--; + for (p = 0; p < vg_ptr->pv_cur; p++) { + if (vg_ptr->pv[p]->pv_dev == + lv_ptr->lv_current_pe[le].dev) + vg_ptr->pv[p]->pe_allocated--; + } + } + vfree(lv_ptr->lv_current_pe); + /* LV_SNAPSHOT */ + } else { + /* remove this snapshot logical volume from the chain */ + lv_ptr->lv_snapshot_prev->lv_snapshot_next = lv_ptr->lv_snapshot_next; + if (lv_ptr->lv_snapshot_next != NULL) { + lv_ptr->lv_snapshot_next->lv_snapshot_prev = + lv_ptr->lv_snapshot_prev; + } + /* no more snapshots? */ + if (lv_ptr->lv_snapshot_org->lv_snapshot_next == NULL) + lv_ptr->lv_snapshot_org->lv_access &= ~LV_SNAPSHOT_ORG; + lvm_snapshot_release(lv_ptr); + } + +#ifdef DEBUG_KFREE + printk(KERN_DEBUG "%s -- kfree %d\n", lvm_name, __LINE__); +#endif + kfree(lv_ptr); + vg_ptr->lv[l] = NULL; + vg_ptr->lv_cur--; + return 0; +} /* lvm_do_lv_remove() */ + + +/* + * character device support function logical volume extend / reduce + */ +static int lvm_do_lv_extend_reduce(int minor, char *lv_name, lv_t *lv) +{ + int l, le, p, size, old_allocated_le; + uint32_t end, lv_status_save; + vg_t *vg_ptr = vg[VG_CHR(minor)]; + lv_t *lv_ptr; + pe_t *pe; + + if ((pep = lv->lv_current_pe) == NULL) return -EINVAL; + + for (l = 0; l < vg_ptr->lv_max; l++) { + if (vg_ptr->lv[l] != NULL && + strcmp(vg_ptr->lv[l]->lv_name, lv_name) == 0) + break; + } + if (l == vg_ptr->lv_max) return -ENXIO; + lv_ptr = vg_ptr->lv[l]; + + /* check for active snapshot */ + if (lv->lv_access & (LV_SNAPSHOT | LV_SNAPSHOT_ORG)) return -EPERM; + + if ((pe = vmalloc(size = lv->lv_current_le * sizeof(pe_t))) == NULL) { + printk(KERN_CRIT + "%s -- lvm_do_lv_extend_reduce: vmalloc error LV_CURRENT_PE " + "of %d Byte at line %d\n", + lvm_name, size, __LINE__); + return -ENOMEM; + } + /* get the PE structures from user space */ + if (copy_from_user(pe, pep, size)) { + vfree(pe); + return -EFAULT; + } + +#ifdef DEBUG + printk(KERN_DEBUG + "%s -- fsync_dev and " + "invalidate_buffers for %s [%s] in %s\n", + lvm_name, lv_ptr->lv_name, + kdevname(lv_ptr->lv_dev), + vg_ptr->vg_name); +#endif + + lv_ptr->lv_status |= LV_SPINDOWN; + fsync_dev(lv_ptr->lv_dev); + lv_ptr->lv_status &= ~LV_ACTIVE; + invalidate_buffers(lv_ptr->lv_dev); + + /* reduce allocation counters on PV(s) */ + for (le = 0; le < lv_ptr->lv_allocated_le; le++) { + vg_ptr->pe_allocated--; + for (p = 0; p < vg_ptr->pv_cur; p++) { + if (vg_ptr->pv[p]->pv_dev == + lv_ptr->lv_current_pe[le].dev) { + vg_ptr->pv[p]->pe_allocated--; + break; + } + } + } + + + /* save pointer to "old" lv/pe pointer array */ + pep1 = lv_ptr->lv_current_pe; + end = lv_ptr->lv_current_le; + + /* save open counter */ + lv_open = lv_ptr->lv_open; + + /* save # of old allocated logical extents */ + old_allocated_le = lv_ptr->lv_allocated_le; + + /* copy preloaded LV */ + lv_status_save = lv->lv_status; + lv->lv_status |= LV_SPINDOWN; + lv->lv_status &= ~LV_ACTIVE; + memcpy((char *) lv_ptr, (char *) lv, sizeof(lv_t)); + lv_ptr->lv_current_pe = pe; + lv_ptr->lv_open = lv_open; + + /* save availiable i/o statistic data */ + /* linear logical volume */ + if (lv_ptr->lv_stripes < 2) { + /* Check what last LE shall be used */ + if (end > lv_ptr->lv_current_le) end = lv_ptr->lv_current_le; + for (le = 0; le < end; le++) { + lv_ptr->lv_current_pe[le].reads = pep1[le].reads; + lv_ptr->lv_current_pe[le].writes = pep1[le].writes; + } + /* striped logical volume */ + } else { + uint i, j, source, dest, end, old_stripe_size, new_stripe_size; + + old_stripe_size = old_allocated_le / lv_ptr->lv_stripes; + new_stripe_size = lv_ptr->lv_allocated_le / lv_ptr->lv_stripes; + end = old_stripe_size; + if (end > new_stripe_size) end = new_stripe_size; + for (i = source = dest = 0; + i < lv_ptr->lv_stripes; i++) { + for (j = 0; j < end; j++) { + lv_ptr->lv_current_pe[dest + j].reads = + pep1[source + j].reads; + lv_ptr->lv_current_pe[dest + j].writes = + pep1[source + j].writes; + } + source += old_stripe_size; + dest += new_stripe_size; + } + } + vfree(pep1); + pep1 = NULL; + + + /* extend the PE count in PVs */ + for (le = 0; le < lv_ptr->lv_allocated_le; le++) { + vg_ptr->pe_allocated++; + for (p = 0; p < vg_ptr->pv_cur; p++) { + if (vg_ptr->pv[p]->pv_dev == + vg_ptr->lv[l]->lv_current_pe[le].dev) { + vg_ptr->pv[p]->pe_allocated++; + break; + } + } + } + + lvm_gendisk.part[MINOR(lv_ptr->lv_dev)].start_sect = 0; + lvm_gendisk.part[MINOR(lv_ptr->lv_dev)].nr_sects = lv_ptr->lv_size; + lvm_size[MINOR(lv_ptr->lv_dev)] = lv_ptr->lv_size >> 1; + /* vg_lv_map array doesn't have to be changed here */ + + LVM_CORRECT_READ_AHEAD(lv_ptr->lv_read_ahead); + lv_ptr->lv_status = lv_status_save; + + return 0; +} /* lvm_do_lv_extend_reduce() */ + + +/* + * character device support function logical volume status by name + */ +static int lvm_do_lv_status_byname(vg_t *vg_ptr, void *arg) +{ + uint l; + ulong size; + lv_t lv; + lv_t *lv_ptr; + lv_status_byname_req_t lv_status_byname_req; + + if (vg_ptr == NULL) return -ENXIO; + if (copy_from_user(&lv_status_byname_req, arg, + sizeof(lv_status_byname_req_t)) != 0) + return -EFAULT; + + if (lv_status_byname_req.lv == NULL) return -EINVAL; + if (copy_from_user(&lv, lv_status_byname_req.lv, + sizeof(lv_t)) != 0) + return -EFAULT; + + for (l = 0; l < vg_ptr->lv_max; l++) { + lv_ptr = vg_ptr->lv[l]; + if (lv_ptr != NULL && + strcmp(lv_ptr->lv_name, + lv_status_byname_req.lv_name) == 0) { + if (copy_to_user(lv_status_byname_req.lv, + lv_ptr, + sizeof(lv_t)) != 0) + return -EFAULT; + + if (lv.lv_current_pe != NULL) { + size = lv_ptr->lv_allocated_le * + sizeof(pe_t); + if (copy_to_user(lv.lv_current_pe, + lv_ptr->lv_current_pe, + size) != 0) + return -EFAULT; + } + return 0; + } + } + return -ENXIO; +} /* lvm_do_lv_status_byname() */ + + +/* + * character device support function logical volume status by index + */ +static int lvm_do_lv_status_byindex(vg_t *vg_ptr,void *arg) +{ + ulong size; + lv_t lv; + lv_t *lv_ptr; + lv_status_byindex_req_t lv_status_byindex_req; + + if (vg_ptr == NULL) return -ENXIO; + if (copy_from_user(&lv_status_byindex_req, arg, + sizeof(lv_status_byindex_req)) != 0) + return -EFAULT; + + if ((lvp = lv_status_byindex_req.lv) == NULL) + return -EINVAL; + if ( ( lv_ptr = vg_ptr->lv[lv_status_byindex_req.lv_index]) == NULL) + return -ENXIO; + + if (copy_from_user(&lv, lvp, sizeof(lv_t)) != 0) + return -EFAULT; + + if (copy_to_user(lvp, lv_ptr, sizeof(lv_t)) != 0) + return -EFAULT; + + if (lv.lv_current_pe != NULL) { + size = lv_ptr->lv_allocated_le * sizeof(pe_t); + if (copy_to_user(lv.lv_current_pe, + lv_ptr->lv_current_pe, + size) != 0) + return -EFAULT; + } + return 0; +} /* lvm_do_lv_status_byindex() */ + + +/* + * character device support function physical volume change + */ +static int lvm_do_pv_change(vg_t *vg_ptr, void *arg) +{ + uint p; + pv_t *pv_ptr; +#ifdef LVM_GET_INODE + struct inode *inode_sav; +#endif + + if (vg_ptr == NULL) return -ENXIO; + if (copy_from_user(&pv_change_req, arg, + sizeof(pv_change_req)) != 0) + return -EFAULT; + + for (p = 0; p < vg_ptr->pv_max; p++) { + pv_ptr = vg_ptr->pv[p]; + if (pv_ptr != NULL && + strcmp(pv_ptr->pv_name, + pv_change_req.pv_name) == 0) { +#ifdef LVM_GET_INODE + inode_sav = pv_ptr->inode; +#endif + if (copy_from_user(pv_ptr, + pv_change_req.pv, + sizeof(pv_t)) != 0) + return -EFAULT; + + /* We don't need the PE list + in kernel space as with LVs pe_t list */ + pv_ptr->pe = NULL; +#ifdef LVM_GET_INODE + pv_ptr->inode = inode_sav; +#endif + return 0; + } + } + return -ENXIO; +} /* lvm_do_pv_change() */ + +/* + * character device support function get physical volume status + */ +static int lvm_do_pv_status(vg_t *vg_ptr, void *arg) +{ + uint p; + pv_t *pv_ptr; + + if (vg_ptr == NULL) return -ENXIO; + if (copy_from_user(&pv_status_req, arg, + sizeof(pv_status_req)) != 0) + return -EFAULT; + + for (p = 0; p < vg_ptr->pv_max; p++) { + pv_ptr = vg_ptr->pv[p]; + if (pv_ptr != NULL && + strcmp(pv_ptr->pv_name, + pv_status_req.pv_name) == 0) { + if (copy_to_user(pv_status_req.pv, + pv_ptr, + sizeof(pv_t)) != 0) + return -EFAULT; + return 0; + } + } + return -ENXIO; +} /* lvm_do_pv_status() */ + + +/* + * support function initialize gendisk variables + */ +#ifdef __initfunc +__initfunc(void lvm_geninit(struct gendisk *lvm_gdisk)) +#else +void __init + lvm_geninit(struct gendisk *lvm_gdisk) +#endif +{ + int i = 0; + +#ifdef DEBUG_GENDISK + printk(KERN_DEBUG "%s -- lvm_gendisk\n", lvm_name); +#endif + + for (i = 0; i < MAX_LV; i++) { + lvm_gendisk.part[i].start_sect = -1; /* avoid partition check */ + lvm_size[i] = lvm_gendisk.part[i].nr_sects = 0; + lvm_blocksizes[i] = BLOCK_SIZE; + } + + blksize_size[MAJOR_NR] = lvm_blocksizes; + blk_size[MAJOR_NR] = lvm_size; + + return; +} /* lvm_gen_init() */ + + +#ifdef LVM_GET_INODE +/* + * support function to get an empty inode + * + * Gets an empty inode to be inserted into the inode hash, + * so that a physical volume can't be mounted. + * This is analog to drivers/block/md.c + * + * Is this the real thing? + * + */ +struct inode *lvm_get_inode(int dev) +{ + struct inode *inode_this = NULL; + + /* Lock the device by inserting a dummy inode. */ + inode_this = get_empty_inode(); + inode_this->i_dev = dev; + insert_inode_hash(inode_this); + return inode_this; +} + + +/* + * support function to clear an inode + * + */ +void lvm_clear_inode(struct inode *inode) +{ +#ifdef I_FREEING + inode->i_state |= I_FREEING; +#endif + clear_inode(inode); + return; +} +#endif /* #ifdef LVM_GET_INODE */ diff -u --recursive --new-file v2.3.46/linux/drivers/block/md.c linux/drivers/block/md.c --- v2.3.46/linux/drivers/block/md.c Wed Feb 16 17:03:51 2000 +++ linux/drivers/block/md.c Thu Feb 17 15:24:52 2000 @@ -3314,7 +3314,7 @@ return (-1); } devfs_handle = devfs_mk_dir (NULL, "md", 0, NULL); - devfs_register_series (devfs_handle, "%u", MAX_MD_DEV,DEVFS_FL_DEFAULT, + devfs_register_series (devfs_handle, "%u",MAX_MD_DEVS,DEVFS_FL_DEFAULT, MAJOR_NR, 0, S_IFBLK | S_IRUSR | S_IWUSR, 0, 0, &md_fops, NULL); diff -u --recursive --new-file v2.3.46/linux/drivers/block/nbd.c linux/drivers/block/nbd.c --- v2.3.46/linux/drivers/block/nbd.c Wed Feb 16 17:03:51 2000 +++ linux/drivers/block/nbd.c Thu Feb 17 09:09:27 2000 @@ -248,7 +248,6 @@ void nbd_clear_que(struct nbd_device *lo) { struct request *req; - unsigned long flags; while (!list_empty(&lo->queue_head)) { req = blkdev_entry_prev_request(&lo->queue_head); @@ -405,8 +404,8 @@ return 0; #ifdef PARANOIA case NBD_PRINT_DEBUG: - printk(KERN_INFO "NBD device %d: queue_head = %p. Global: in %d, out %d\n", - dev, lo->queue_head, requests_in, requests_out); + printk(KERN_INFO "NBD device %d: next = %p, prev = %p. Global: in %d, out %d\n", + dev, lo->queue_head.next, lo->queue_head.prev, requests_in, requests_out); return 0; #endif case BLKGETSIZE: diff -u --recursive --new-file v2.3.46/linux/drivers/block/raid1.c linux/drivers/block/raid1.c --- v2.3.46/linux/drivers/block/raid1.c Thu Aug 12 10:16:28 1999 +++ linux/drivers/block/raid1.c Sun Feb 20 20:23:20 2000 @@ -211,7 +211,11 @@ while (!( /* FIXME: now we are rather fault tolerant than nice */ r1_bh = kmalloc (sizeof (struct raid1_bh), GFP_KERNEL) ) ) + { printk ("raid1_make_request(#1): out of memory\n"); + current->policy |= SCHED_YIELD; + schedule(); + } memset (r1_bh, 0, sizeof (struct raid1_bh)); /* @@ -298,7 +302,11 @@ while (!( /* FIXME: now we are rather fault tolerant than nice */ mirror_bh[i] = kmalloc (sizeof (struct buffer_head), GFP_KERNEL) ) ) + { printk ("raid1_make_request(#2): out of memory\n"); + current->policy |= SCHED_YIELD; + schedule(); + } memset (mirror_bh[i], 0, sizeof (struct buffer_head)); /* @@ -710,7 +718,11 @@ while (!( /* FIXME: now we are rather fault tolerant than nice */ mddev->private = kmalloc (sizeof (struct raid1_data), GFP_KERNEL) ) ) + { printk ("raid1_run(): out of memory\n"); + current->policy |= SCHED_YIELD; + schedule(); + } raid_conf = mddev->private; memset(raid_conf, 0, sizeof(*raid_conf)); diff -u --recursive --new-file v2.3.46/linux/drivers/char/Makefile linux/drivers/char/Makefile --- v2.3.46/linux/drivers/char/Makefile Wed Feb 16 17:03:51 2000 +++ linux/drivers/char/Makefile Sun Feb 20 20:37:09 2000 @@ -36,7 +36,7 @@ # All of the (potential) objects that export symbols. # This list comes from 'grep -l EXPORT_SYMBOL *.[hc]'. -export-objs := busmouse.o console.o i2c-old.o keyboard.o \ +export-objs := busmouse.o console.o i2c-old.o keyboard.o sysrq.o \ misc.o pty.o random.o selection.o serial.o videodev.o \ tty_io.o @@ -144,13 +144,14 @@ obj-$(CONFIG_MIXCOMWD) += mixcomwd.o obj-$(CONFIG_AMIGAMOUSE) += amigamouse.o obj-$(CONFIG_ATARIMOUSE) += atarimouse.o -obj-$(CONFIG_ADBMOUSE) += adbmouse.o +obj-$(CONFIG_ADBMOUSE) += adbmouse.o busmouse.o obj-$(CONFIG_PC110_PAD) += pc110pad.o obj-$(CONFIG_WDT) += wdt.o obj-$(CONFIG_RTC) += rtc.o ifeq ($(CONFIG_PPC),) obj-$(CONFIG_NVRAM) += nvram.o endif +obj-$(CONFIG_I810_RNG) += i810_rng.o obj-$(CONFIG_VIDEO_DEV) += videodev.o diff -u --recursive --new-file v2.3.46/linux/drivers/char/console.c linux/drivers/char/console.c --- v2.3.46/linux/drivers/char/console.c Wed Feb 16 17:03:51 2000 +++ linux/drivers/char/console.c Sun Feb 20 20:37:09 2000 @@ -1816,6 +1816,8 @@ unsigned long draw_from = 0, draw_to = 0; struct vt_struct *vt = (struct vt_struct *)tty->driver_data; u16 himask, charmask; + const unsigned char *orig_buf = NULL; + int orig_count; currcons = vt->vc_num; if (!vc_cons_allocated(currcons)) { @@ -1828,9 +1830,13 @@ return 0; } - down(&con_buf_sem); + orig_buf = buf; + orig_count = count; if (from_user) { + down(&con_buf_sem); + +again: if (count > CON_BUF_SIZE) count = CON_BUF_SIZE; if (copy_from_user(con_buf, buf, count)) { @@ -1969,7 +1975,21 @@ spin_unlock_irq(&console_lock); out: - up(&con_buf_sem); + if (from_user) { + /* If the user requested something larger than + * the CON_BUF_SIZE, and the tty is not stopped, + * keep going. + */ + if ((orig_count > CON_BUF_SIZE) && !tty->stopped) { + orig_count -= CON_BUF_SIZE; + orig_buf += CON_BUF_SIZE; + count = orig_count; + buf = orig_buf; + goto again; + } + + up(&con_buf_sem); + } return n; #undef FLUSH @@ -2911,6 +2931,7 @@ EXPORT_SYMBOL(video_scan_lines); EXPORT_SYMBOL(vc_resize); EXPORT_SYMBOL(fg_console); +EXPORT_SYMBOL(console_blank_hook); #ifndef VT_SINGLE_DRIVER EXPORT_SYMBOL(take_over_console); diff -u --recursive --new-file v2.3.46/linux/drivers/char/ftape/zftape/zftape-init.c linux/drivers/char/ftape/zftape/zftape-init.c --- v2.3.46/linux/drivers/char/ftape/zftape/zftape-init.c Wed Feb 16 17:03:51 2000 +++ linux/drivers/char/ftape/zftape/zftape-init.c Thu Feb 17 09:56:46 2000 @@ -436,7 +436,7 @@ TRACE_CATCH(devfs_register_chrdev(QIC117_TAPE_MAJOR, "zft", &zft_cdev),); for (i = 0; i < 4; i++) { - char devname[8]; + char devname[9]; sprintf (devname, "qft%i", i); devfs_register (NULL, devname, 0, DEVFS_FL_NONE, @@ -510,7 +510,7 @@ void cleanup_module(void) { int i; - char devname[8]; + char devname[9]; TRACE_FUN(ft_t_flow); diff -u --recursive --new-file v2.3.46/linux/drivers/char/h8.c linux/drivers/char/h8.c --- v2.3.46/linux/drivers/char/h8.c Fri Jan 28 15:09:07 2000 +++ linux/drivers/char/h8.c Sun Feb 20 14:14:16 2000 @@ -260,7 +260,7 @@ return; } else if (data_reg == H8_SYNC_BYTE) { h8_state = H8_IDLE; - if (!QUEUE_EMPTY(&h8_actq, link)) + if (!QUEUE_IS_EMPTY(&h8_actq, link)) h8_send_next_cmd_byte(); } else { Dprintk ("h8_intr: resync unknown data 0x%x \n", data_reg); @@ -279,7 +279,7 @@ QUEUE_REMOVE(&h8_actq, qp, link); h8_cmd_done (qp); /* More commands to send over? */ - if (!QUEUE_EMPTY(&h8_cmdq, link)) + if (!QUEUE_IS_EMPTY(&h8_cmdq, link)) h8_start_new_cmd(); } return; @@ -458,7 +458,7 @@ /* get cmd buf */ save_flags(flags); cli(); - while (QUEUE_EMPTY(&h8_freeq, link)) { + while (QUEUE_IS_EMPTY(&h8_freeq, link)) { Dprintk("H8: need to allocate more cmd buffers\n"); restore_flags(flags); h8_alloc_queues(); @@ -500,13 +500,13 @@ return; } - if (!QUEUE_EMPTY(&h8_actq, link)) { + if (!QUEUE_IS_EMPTY(&h8_actq, link)) { Dprintk("h8_start_new_cmd: inconsistency: IDLE with non-empty active queue!\n"); restore_flags(flags); return; } - if (QUEUE_EMPTY(&h8_cmdq, link)) { + if (QUEUE_IS_EMPTY(&h8_cmdq, link)) { Dprintk("h8_start_new_cmd: no command to dequeue\n"); restore_flags(flags); return; diff -u --recursive --new-file v2.3.46/linux/drivers/char/joystick/joystick.c linux/drivers/char/joystick/joystick.c --- v2.3.46/linux/drivers/char/joystick/joystick.c Wed Feb 16 17:03:52 2000 +++ linux/drivers/char/joystick/joystick.c Sun Feb 20 20:23:20 2000 @@ -738,12 +738,6 @@ curd->name = all += axes * sizeof(struct js_corr); strcpy(curd->name, name); - sprintf (devfs_name, "analogue%d", number); - curd->devfs_handle = devfs_register (devfs_handle, devfs_name, 0, - DEVFS_FL_DEFAULT, - JOYSTICK_MAJOR, number, - S_IFCHR | S_IRUGO | S_IWUSR, 0, 0, - &js_fops, NULL); port->devs[number] = curd; port->axes[number] = curd->new.axes; @@ -757,6 +751,13 @@ spin_unlock_irqrestore(&js_lock, flags); + sprintf(devfs_name, "js%d", i); + curd->devfs_handle = devfs_register(devfs_handle, devfs_name, 0, + DEVFS_FL_DEFAULT, + JOYSTICK_MAJOR, i, + S_IFCHR | S_IRUGO | S_IWUSR, 0, 0, + &js_fops, NULL); + return i; } @@ -772,7 +773,7 @@ spin_unlock_irqrestore(&js_lock, flags); - devfs_unregister (dev->devfs_handle); + devfs_unregister(dev->devfs_handle); kfree(dev); } @@ -805,7 +806,7 @@ printk(KERN_ERR "js: unable to get major %d for joystick\n", JOYSTICK_MAJOR); return -EBUSY; } - devfs_handle = devfs_mk_dir (NULL, "joysticks", 9, NULL); + devfs_handle = devfs_mk_dir(NULL, "joysticks", 9, NULL); printk(KERN_INFO "js: Joystick driver v%d.%d.%d (c) 1999 Vojtech Pavlik \n", JS_VERSION >> 16 & 0xff, JS_VERSION >> 8 & 0xff, JS_VERSION & 0xff); @@ -885,9 +886,9 @@ void cleanup_module(void) { del_timer(&js_timer); - devfs_unregister (devfs_handle); + devfs_unregister(devfs_handle); if (devfs_unregister_chrdev(JOYSTICK_MAJOR, "js")) - printk(KERN_ERR "js: can't unregister device\n"); + printk(KERN_ERR "js: can't unregister device\n"); } #endif diff -u --recursive --new-file v2.3.46/linux/drivers/char/lp.c linux/drivers/char/lp.c --- v2.3.46/linux/drivers/char/lp.c Wed Feb 16 17:03:52 2000 +++ linux/drivers/char/lp.c Thu Feb 17 15:24:52 2000 @@ -237,7 +237,6 @@ ssize_t retv = 0; ssize_t written; size_t copy_size = count; - long old_to; #ifdef LP_STATS if (jiffies-lp_table[minor].lastcall > LP_TIME(minor)) @@ -263,8 +262,8 @@ /* Go to compatibility mode. */ parport_negotiate (port, IEEE1284_MODE_COMPAT); - old_to = parport_set_timeout (lp_table[minor].dev, - lp_table[minor].timeout); + parport_set_timeout (lp_table[minor].dev, + lp_table[minor].timeout); do { /* Write the data. */ @@ -310,9 +309,6 @@ } } while (count > 0); - /* Not really necessary, but polite. */ - parport_set_timeout (lp_table[minor].dev, old_to); - parport_release (lp_table[minor].dev); up (&lp_table[minor].port_mutex); @@ -564,13 +560,12 @@ struct pardevice *dev = lp_table[CONSOLE_LP].dev; struct parport *port = dev->port; ssize_t written; - signed long old_to; if (parport_claim (dev)) /* Nothing we can do. */ return; - old_to = parport_set_timeout (dev, 0); + parport_set_timeout (dev, 0); /* Go to compatibility mode. */ parport_negotiate (port, IEEE1284_MODE_COMPAT); @@ -608,7 +603,6 @@ } } while (count > 0 && (CONSOLE_LP_STRICT || written > 0)); - parport_set_timeout (dev, old_to); parport_release (dev); } @@ -680,6 +674,8 @@ static int lp_register(int nr, struct parport *port) { + char name[8]; + lp_table[nr].dev = parport_register_device(port, "lp", NULL, NULL, NULL, 0, (void *) &lp_table[nr]); @@ -690,6 +686,12 @@ if (reset) lp_reset(nr); + sprintf (name, "%d", nr); + devfs_register (devfs_handle, name, 0, + DEVFS_FL_DEFAULT, LP_MAJOR, nr, + S_IFCHR | S_IRUGO | S_IWUGO, 0, 0, + &lp_fops, NULL); + printk(KERN_INFO "lp%d: using %s (%s).\n", nr, port->name, (port->irq == PARPORT_IRQ_NONE)?"polling":"interrupt-driven"); @@ -787,26 +789,12 @@ } devfs_handle = devfs_mk_dir (NULL, "printers", 0, NULL); - if (lp_count) { - for (i = 0; i < LP_NO; ++i) - { - char name[8]; - - if (!(lp_table[i].flags & LP_EXIST)) - continue; /* skip this entry: it doesn't exist. */ - sprintf (name, "%d", i); - devfs_register (devfs_handle, name, 0, - DEVFS_FL_DEFAULT, LP_MAJOR, i, - S_IFCHR | S_IRUGO | S_IWUGO, 0, 0, - &lp_fops, NULL); - } - } if (!lp_count) { printk (KERN_INFO "lp: driver loaded but no devices found\n"); -#ifndef CONFIG_PARPORT_12843 +#ifndef CONFIG_PARPORT_1284 if (parport_nr[0] == LP_PARPORT_AUTO) - printk (KERN_INFO "lp: (is IEEE 1284.3 support enabled?)\n"); + printk (KERN_INFO "lp: (is IEEE 1284 support enabled?)\n"); #endif } diff -u --recursive --new-file v2.3.46/linux/drivers/char/ppdev.c linux/drivers/char/ppdev.c --- v2.3.46/linux/drivers/char/ppdev.c Wed Feb 16 17:03:52 2000 +++ linux/drivers/char/ppdev.c Thu Feb 17 15:29:44 2000 @@ -45,7 +45,6 @@ #include #include #include -#include #include #include #include diff -u --recursive --new-file v2.3.46/linux/drivers/char/pty.c linux/drivers/char/pty.c --- v2.3.46/linux/drivers/char/pty.c Wed Feb 16 17:03:52 2000 +++ linux/drivers/char/pty.c Thu Feb 17 15:29:44 2000 @@ -10,7 +10,6 @@ #include #include /* For EXPORT_SYMBOL */ -#include #include #include #include diff -u --recursive --new-file v2.3.46/linux/drivers/char/rtc.c linux/drivers/char/rtc.c --- v2.3.46/linux/drivers/char/rtc.c Thu Feb 10 17:11:08 2000 +++ linux/drivers/char/rtc.c Thu Feb 17 09:44:11 2000 @@ -97,14 +97,18 @@ static int rtc_ioctl(struct inode *inode, struct file *file, unsigned int cmd, unsigned long arg); +#ifndef __alpha__ static unsigned int rtc_poll(struct file *file, poll_table *wait); +#endif static void get_rtc_time (struct rtc_time *rtc_tm); static void get_rtc_alm_time (struct rtc_time *alm_tm); +#ifndef __alpha__ static void rtc_dropped_irq(unsigned long data); static void set_rtc_irq_bit(unsigned char bit); static void mask_rtc_irq_bit(unsigned char bit); +#endif static inline unsigned char rtc_is_updating(void); @@ -132,6 +136,7 @@ static const unsigned char days_in_mo[] = {0, 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31}; +#ifndef __alpha__ /* * A very tiny interrupt handler. It runs with SA_INTERRUPT set, * so that there is no possibility of conflicting with the @@ -162,6 +167,7 @@ if (atomic_read(&rtc_status) & RTC_TIMER_ON) mod_timer(&rtc_irq_timer, jiffies + HZ/rtc_freq + 2*HZ/100); } +#endif /* * Now all the various file operations that we export. @@ -175,6 +181,9 @@ static ssize_t rtc_read(struct file *file, char *buf, size_t count, loff_t *ppos) { +#ifdef __alpha__ + return -EIO; +#else DECLARE_WAITQUEUE(wait, current); unsigned long data; ssize_t retval; @@ -206,6 +215,7 @@ remove_wait_queue(&rtc_wait, &wait); return retval; +#endif } static int rtc_ioctl(struct inode *inode, struct file *file, unsigned int cmd, @@ -216,6 +226,7 @@ struct rtc_time wtime; switch (cmd) { +#ifndef __alpha__ case RTC_AIE_OFF: /* Mask alarm int. enab. bit */ { mask_rtc_irq_bit(RTC_AIE); @@ -265,6 +276,7 @@ set_rtc_irq_bit(RTC_UIE); return 0; } +#endif case RTC_ALM_READ: /* Read the present alarm time */ { /* @@ -398,6 +410,7 @@ spin_unlock_irqrestore(&rtc_lock, flags); return 0; } +#ifndef __alpha__ case RTC_IRQP_READ: /* Read the periodic IRQ rate. */ { return put_user(rtc_freq, (unsigned long *)arg); @@ -437,7 +450,7 @@ spin_unlock_irqrestore(&rtc_lock, flags); return 0; } -#ifdef __alpha__ +#else case RTC_EPOCH_READ: /* Read the epoch. */ { return put_user (epoch, (unsigned long *)arg); @@ -494,13 +507,14 @@ static int rtc_release(struct inode *inode, struct file *file) { + unsigned long flags; +#ifndef __alpha__ /* * Turn off all interrupts once the device is no longer * in use, and clear the data. */ unsigned char tmp; - unsigned long flags; spin_lock_irqsave(&rtc_lock, flags); tmp = CMOS_READ(RTC_CONTROL); @@ -520,6 +534,7 @@ rtc_fasync (-1, file, 0); } +#endif MOD_DEC_USE_COUNT; spin_lock_irqsave (&rtc_lock, flags); @@ -529,6 +544,7 @@ return 0; } +#ifndef __alpha__ static unsigned int rtc_poll(struct file *file, poll_table *wait) { unsigned long l, flags; @@ -543,6 +559,7 @@ return POLLIN | POLLRDNORM; return 0; } +#endif /* * The various file operations we support. @@ -551,7 +568,9 @@ static struct file_operations rtc_fops = { llseek: rtc_llseek, read: rtc_read, +#ifndef __alpha__ poll: rtc_poll, +#endif ioctl: rtc_ioctl, open: rtc_open, release: rtc_release, @@ -612,12 +631,14 @@ return -EIO; } +#ifndef __alpha__ if(request_irq(RTC_IRQ, rtc_interrupt, SA_INTERRUPT, "rtc", NULL)) { /* Yeah right, seeing as irq 8 doesn't even hit the bus. */ printk(KERN_ERR "rtc: IRQ %d is not free.\n", RTC_IRQ); return -EIO; } +#endif request_region(RTC_PORT(0), RTC_IO_EXTENT, "rtc"); #endif /* __sparc__ vs. others */ @@ -654,12 +675,14 @@ if (guess) printk("rtc: %s epoch (%lu) detected\n", guess, epoch); #endif +#ifndef __alpha__ init_timer(&rtc_irq_timer); rtc_irq_timer.function = rtc_dropped_irq; spin_lock_irqsave(&rtc_lock, flags); /* Initialize periodic freq. to CMOS reset default, which is 1024Hz */ CMOS_WRITE(((CMOS_READ(RTC_FREQ_SELECT) & 0xF0) | 0x06), RTC_FREQ_SELECT); spin_unlock_irqrestore(&rtc_lock, flags); +#endif rtc_freq = 1024; printk(KERN_INFO "Real Time Clock Driver v" RTC_VERSION "\n"); @@ -689,6 +712,7 @@ module_exit(rtc_exit); EXPORT_NO_SYMBOLS; +#ifndef __alpha__ /* * At IRQ rates >= 4096Hz, an interrupt may get lost altogether. * (usually during an IDE disk interrupt, with IRQ unmasking off) @@ -714,6 +738,7 @@ rtc_irq_data |= (CMOS_READ(RTC_INTR_FLAGS) & 0xF0); /* restart */ spin_unlock_irqrestore(&rtc_lock, flags); } +#endif /* * Info exported via "/proc/driver/rtc". @@ -902,6 +927,7 @@ } } +#ifndef __alpha__ /* * Used to disable/enable interrupts for any one of UIE, AIE, PIE. * Rumour has it that if you frob the interrupt enable/disable @@ -939,3 +965,4 @@ rtc_irq_data = 0; spin_unlock_irqrestore(&rtc_lock, flags); } +#endif diff -u --recursive --new-file v2.3.46/linux/drivers/char/stallion.c linux/drivers/char/stallion.c --- v2.3.46/linux/drivers/char/stallion.c Wed Feb 16 17:03:52 2000 +++ linux/drivers/char/stallion.c Sun Feb 20 20:23:20 2000 @@ -751,6 +751,8 @@ /*****************************************************************************/ +static devfs_handle_t devfs_handle = NULL; + #ifdef MODULE /* @@ -774,8 +776,6 @@ } /*****************************************************************************/ - -static devfs_handle_t devfs_handle = NULL; void cleanup_module() { diff -u --recursive --new-file v2.3.46/linux/drivers/char/sysrq.c linux/drivers/char/sysrq.c --- v2.3.46/linux/drivers/char/sysrq.c Sun Nov 7 16:37:34 1999 +++ linux/drivers/char/sysrq.c Sun Feb 20 20:37:09 2000 @@ -21,6 +21,7 @@ #include #include #include +#include #include @@ -31,6 +32,8 @@ /* Machine specific power off function */ void (*sysrq_power_off)(void) = NULL; + +EXPORT_SYMBOL(sysrq_power_off); /* Send a signal to all user processes */ diff -u --recursive --new-file v2.3.46/linux/drivers/char/vc_screen.c linux/drivers/char/vc_screen.c --- v2.3.46/linux/drivers/char/vc_screen.c Wed Feb 16 17:03:52 2000 +++ linux/drivers/char/vc_screen.c Sun Feb 20 20:19:12 2000 @@ -21,6 +21,7 @@ * - making it shorter - scr_readw are macros which expand in PRETTY long code */ +#include #include #include #include @@ -37,6 +38,7 @@ #include #include #include +#include #undef attr #undef org @@ -175,71 +177,58 @@ con_buf0[1] = (char) video_num_columns; getconsxy(currcons, con_buf0 + 2); - tmp_count = HEADER_SIZE - p; + con_buf_start += p; + this_round += p; + if (this_round > CON_BUF_SIZE) { + this_round = CON_BUF_SIZE; + orig_count = this_round - p; + } + + tmp_count = HEADER_SIZE; if (tmp_count > this_round) tmp_count = this_round; /* Advance state pointers and move on. */ this_round -= tmp_count; - con_buf_start += p; - orig_count -= p; - p += tmp_count; - con_buf0 = con_buf + p; + p = HEADER_SIZE; + con_buf0 = con_buf + HEADER_SIZE; + /* If this_round >= 0, then p is even... */ + } else if (p & 1) { + /* Skip first byte for output if start address is odd + * Update region sizes up/down depending on free + * space in buffer. + */ + con_buf_start++; + if (this_round < CON_BUF_SIZE) + this_round++; + else + orig_count--; } - p -= HEADER_SIZE; - col = (p/2) % maxcol; if (this_round > 0) { - char tmp_byte; - - org = screen_pos(currcons, p/2, viewed); - if ((p & 1) && this_round > 0) { -#ifdef __BIG_ENDIAN - tmp_byte = vcs_scr_readw(currcons, org++) & 0xff; -#else - tmp_byte = vcs_scr_readw(currcons, org++) >> 8; -#endif - - *con_buf0++ = tmp_byte; + unsigned short *tmp_buf = (unsigned short *)con_buf0; - this_round--; - p++; - if (++col == maxcol) { - org = screen_pos(currcons, p/2, viewed); - col = 0; - } - } + p -= HEADER_SIZE; p /= 2; + col = p % maxcol; + + org = screen_pos(currcons, p, viewed); p += maxcol - col; - } - if (this_round > 1) { - size_t tmp_count = this_round; - unsigned short *tmp_buf = (unsigned short *)con_buf0; + /* Buffer has even length, so we can always copy + * character + attribute. We do not copy last byte + * to userspace if this_round is odd. + */ + this_round = (this_round + 1) >> 1; - while (tmp_count > 1) { + while (this_round) { *tmp_buf++ = vcs_scr_readw(currcons, org++); - tmp_count -= 2; + this_round --; if (++col == maxcol) { org = screen_pos(currcons, p, viewed); col = 0; p += maxcol; } } - - /* Advance pointers, and move on. */ - this_round = tmp_count; - con_buf0 = (char*)tmp_buf; - } - if (this_round > 0) { - char tmp_byte; - -#ifdef __BIG_ENDIAN - tmp_byte = vcs_scr_readw(currcons, org) >> 8; -#else - tmp_byte = vcs_scr_readw(currcons, org) & 0xff; -#endif - - *con_buf0++ = tmp_byte; } } @@ -415,7 +404,7 @@ while (this_round > 1) { unsigned short w; - w = *((const unsigned short *)con_buf0); + w = get_unaligned(((const unsigned short *)con_buf0)); vcs_scr_writew(currcons, w, org++); con_buf0 += 2; this_round -= 2; diff -u --recursive --new-file v2.3.46/linux/drivers/char/vt.c linux/drivers/char/vt.c --- v2.3.46/linux/drivers/char/vt.c Wed Feb 16 17:03:52 2000 +++ linux/drivers/char/vt.c Sun Feb 20 08:48:45 2000 @@ -106,12 +106,13 @@ { static struct timer_list sound_timer = { NULL, NULL, 0, 0, kd_nosound }; - unsigned int count = 0; + unsigned long flags; if (hz > 20 && hz < 32767) count = 1193180 / hz; + save_flags(flags); cli(); del_timer(&sound_timer); if (count) { @@ -129,7 +130,7 @@ } } else kd_nosound(0); - sti(); + restore_flags(flags); return; } diff -u --recursive --new-file v2.3.46/linux/drivers/fc4/fc.c linux/drivers/fc4/fc.c --- v2.3.46/linux/drivers/fc4/fc.c Fri Jan 28 15:09:07 2000 +++ linux/drivers/fc4/fc.c Fri Feb 18 15:07:20 2000 @@ -56,17 +56,21 @@ #ifdef __sparc__ #define dma_alloc_consistent(d,s,p) sbus_alloc_consistent(d,s,p) #define dma_free_consistent(d,s,v,h) sbus_free_consistent(d,s,v,h) -#define dma_map_single(d,v,s) sbus_map_single(d,v,s) -#define dma_unmap_single(d,h,s) sbus_unmap_single(d,h,s) -#define dma_map_sg(d,s,n) sbus_map_sg(d,s,n) -#define dma_unmap_sg(d,s,n) sbus_unmap_sg(d,s,n) +#define dma_map_single(d,v,s,dir) sbus_map_single(d,v,s,dir) +#define dma_unmap_single(d,h,s,dir) sbus_unmap_single(d,h,s,dir) +#define dma_map_sg(d,s,n,dir) sbus_map_sg(d,s,n,dir) +#define dma_unmap_sg(d,s,n,dir) sbus_unmap_sg(d,s,n,dir) +#define scsi_to_fc_dma_dir(dir) scsi_to_sbus_dma_dir(dir) +#define FC_DMA_BIDIRECTIONAL SBUS_DMA_BIDIRECTIONAL #else #define dma_alloc_consistent(d,s,p) pci_alloc_consistent(d,s,p) #define dma_free_consistent(d,s,v,h) pci_free_consistent(d,s,v,h) -#define dma_map_single(d,v,s) pci_map_single(d,v,s) -#define dma_unmap_single(d,h,s) pci_unmap_single(d,h,s) -#define dma_map_sg(d,s,n) pci_map_sg(d,s,n) -#define dma_unmap_sg(d,s,n) pci_unmap_sg(d,s,n) +#define dma_map_single(d,v,s,dir) pci_map_single(d,v,s,dir) +#define dma_unmap_single(d,h,s,dir) pci_unmap_single(d,h,s,dir) +#define dma_map_sg(d,s,n,dir) pci_map_sg(d,s,n,dir) +#define dma_unmap_sg(d,s,n,dir) pci_unmap_sg(d,s,n,dir) +#define scsi_to_fc_dma_dir(dir) scsi_to_pci_dma_dir(dir) +#define FC_DMA_BIDIRECTIONAL PCI_DMA_BIDIRECTIONAL #endif #define FCP_CMND(SCpnt) ((fcp_cmnd *)&(SCpnt->SCp)) @@ -163,7 +167,8 @@ fc->state = FC_STATE_FPORT_OK; fcmd = l->fcmds + i; plogi = l->logi + 3 * i; - dma_unmap_single (fc->dev, fcmd->cmd, 3 * sizeof(logi)); + dma_unmap_single (fc->dev, fcmd->cmd, 3 * sizeof(logi), + FC_DMA_BIDIRECTIONAL); plogi->code = LS_PLOGI; memcpy (&plogi->nport_wwn, &fc->wwn_nport, sizeof(fc_wwn)); memcpy (&plogi->node_wwn, &fc->wwn_node, sizeof(fc_wwn)); @@ -183,7 +188,8 @@ printk ("\n"); } #endif - fcmd->cmd = dma_map_single (fc->dev, plogi, 3 * sizeof(logi)); + fcmd->cmd = dma_map_single (fc->dev, plogi, 3 * sizeof(logi), + FC_DMA_BIDIRECTIONAL); fcmd->rsp = fcmd->cmd + 2 * sizeof(logi); if (fc->hw_enque (fc, fcmd)) printk ("FC: Cannot enque PLOGI packet on %s\n", fc->name); @@ -206,7 +212,8 @@ switch (status) { case FC_STATUS_OK: plogi = l->logi + 3 * i; - dma_unmap_single (fc->dev, l->fcmds[i].cmd, 3 * sizeof(logi)); + dma_unmap_single (fc->dev, l->fcmds[i].cmd, 3 * sizeof(logi), + FC_DMA_BIDIRECTIONAL); if (!fc->wwn_dest.lo && !fc->wwn_dest.hi) { memcpy (&fc->wwn_dest, &plogi[1].node_wwn, sizeof(fc_wwn)); FCD(("Dest WWN %08x%08x\n", *(u32 *)&fc->wwn_dest, fc->wwn_dest.lo)) @@ -224,7 +231,8 @@ break; case FC_STATUS_ERR_OFFLINE: fc->state = FC_STATE_OFFLINE; - dma_unmap_single (fc->dev, l->fcmds[i].cmd, 3 * sizeof(logi)); + dma_unmap_single (fc->dev, l->fcmds[i].cmd, 3 * sizeof(logi), + FC_DMA_BIDIRECTIONAL); printk ("%s: FC is offline\n", fc->name); if (atomic_dec_and_test (&l->todo)) up(&l->sem); @@ -248,7 +256,8 @@ FCD(("Report map done %d %d\n", i, status)) switch (status) { case FC_STATUS_OK: /* Ok, let's have a fun on a loop */ - dma_unmap_single (fc->dev, l->fcmds[i].cmd, 3 * sizeof(logi)); + dma_unmap_single (fc->dev, l->fcmds[i].cmd, 3 * sizeof(logi), + FC_DMA_BIDIRECTIONAL); p = (fc_al_posmap *)(l->logi + 3 * i); #ifdef FCDEBUG { @@ -297,7 +306,8 @@ case FC_STATUS_POINTTOPOINT: /* We're Point-to-Point, no AL... */ FCD(("SID %d DID %d\n", fc->sid, fc->did)) fcmd = l->fcmds + i; - dma_unmap_single(fc->dev, fcmd->cmd, 3 * sizeof(logi)); + dma_unmap_single(fc->dev, fcmd->cmd, 3 * sizeof(logi), + FC_DMA_BIDIRECTIONAL); fch = &fcmd->fch; memset(l->logi + 3 * i, 0, 3 * sizeof(logi)); FILL_FCHDR_RCTL_DID(fch, R_CTL_ELS_REQ, FS_FABRIC_F_PORT); @@ -307,7 +317,8 @@ FILL_FCHDR_OXRX(fch, 0xffff, 0xffff); fch->param = 0; l->logi [3 * i].code = LS_FLOGI; - fcmd->cmd = dma_map_single (fc->dev, l->logi + 3 * i, 3 * sizeof(logi)); + fcmd->cmd = dma_map_single (fc->dev, l->logi + 3 * i, 3 * sizeof(logi), + FC_DMA_BIDIRECTIONAL); fcmd->rsp = fcmd->cmd + sizeof(logi); fcmd->cmdlen = sizeof(logi); fcmd->rsplen = sizeof(logi); @@ -424,9 +435,11 @@ if (fcmd->data) { if (SCpnt->use_sg) - dma_unmap_sg(fc->dev, (struct scatterlist *)SCpnt->buffer, SCpnt->use_sg); + dma_unmap_sg(fc->dev, (struct scatterlist *)SCpnt->buffer, SCpnt->use_sg, + scsi_to_fc_dma_dir(SCpnt->sc_data_direction)); else - dma_unmap_single(fc->dev, fcmd->data, SCpnt->request_bufflen); + dma_unmap_single(fc->dev, fcmd->data, SCpnt->request_bufflen, + scsi_to_fc_dma_dir(SCpnt->sc_data_direction)); } break; default: @@ -565,7 +578,8 @@ fc->login = fcmd; fc->ls = (void *)l; /* Assumes sizeof(fc_al_posmap) < 3 * sizeof(logi), which is true */ - fcmd->cmd = dma_map_single (fc->dev, l->logi + 3 * i, 3 * sizeof(logi)); + fcmd->cmd = dma_map_single (fc->dev, l->logi + 3 * i, 3 * sizeof(logi), + FC_DMA_BIDIRECTIONAL); fcmd->proto = PROTO_REPORT_AL_MAP; fcmd->token = i; fcmd->fc = fc; @@ -584,7 +598,7 @@ } else { fc->state = FC_STATE_OFFLINE; enable_irq(fc->irq); - dma_unmap_single (fc->dev, l->fcmds[i].cmd, 3 * sizeof(logi)); + dma_unmap_single (fc->dev, l->fcmds[i].cmd, 3 * sizeof(logi), FC_DMA_BIDIRECTIONAL); if (atomic_dec_and_test (&l->todo)) goto all_done; } @@ -601,7 +615,7 @@ FCD(("SID %d DID %d\n", fc->sid, fc->did)) fcmd = l->fcmds + i; - dma_unmap_single(fc->dev, fcmd->cmd, 3 * sizeof(logi)); + dma_unmap_single(fc->dev, fcmd->cmd, 3 * sizeof(logi), FC_DMA_BIDIRECTIONAL); fch = &fcmd->fch; FILL_FCHDR_RCTL_DID(fch, R_CTL_ELS_REQ, FS_FABRIC_F_PORT); FILL_FCHDR_SID(fch, 0); @@ -610,7 +624,7 @@ FILL_FCHDR_OXRX(fch, 0xffff, 0xffff); fch->param = 0; l->logi [3 * i].code = LS_FLOGI; - fcmd->cmd = dma_map_single (fc->dev, l->logi + 3 * i, 3 * sizeof(logi)); + fcmd->cmd = dma_map_single (fc->dev, l->logi + 3 * i, 3 * sizeof(logi), FC_DMA_BIDIRECTIONAL); fcmd->rsp = fcmd->cmd + sizeof(logi); fcmd->cmdlen = sizeof(logi); fcmd->rsplen = sizeof(logi); @@ -638,7 +652,7 @@ switch (fc->state) { case FC_STATE_ONLINE: break; case FC_STATE_OFFLINE: break; - default: dma_unmap_single (fc->dev, l->fcmds[i].cmd, 3 * sizeof(logi)); + default: dma_unmap_single (fc->dev, l->fcmds[i].cmd, 3 * sizeof(logi), FC_DMA_BIDIRECTIONAL); break; } } @@ -801,13 +815,15 @@ if (!SCpnt->use_sg) { cmd->fcp_data_len = SCpnt->request_bufflen; fcmd->data = dma_map_single (fc->dev, (char *)SCpnt->request_buffer, - SCpnt->request_bufflen); + SCpnt->request_bufflen, + scsi_to_fc_dma_dir(SCpnt->sc_data_direction)); } else { struct scatterlist *sg = (struct scatterlist *)SCpnt->buffer; int nents; FCD(("XXX: Use_sg %d %d\n", SCpnt->use_sg, sg->length)) - nents = dma_map_sg (fc->dev, sg, SCpnt->use_sg); + nents = dma_map_sg (fc->dev, sg, SCpnt->use_sg, + scsi_to_fc_dma_dir(SCpnt->sc_data_direction)); if (nents > 1) printk ("%s: SG for nents %d (use_sg %d) not handled yet\n", fc->name, nents, SCpnt->use_sg); fcmd->data = sg_dma_address(sg); cmd->fcp_data_len = sg_dma_len(sg); @@ -1048,7 +1064,7 @@ FILL_FCHDR_SEQ_DF_SEQ(fch, 0, 0, 0); FILL_FCHDR_OXRX(fch, 0xffff, 0xffff); fch->param = 0; - fcmd->cmd = dma_map_single (fc->dev, data, 2 * len); + fcmd->cmd = dma_map_single (fc->dev, data, 2 * len, FC_DMA_BIDIRECTIONAL); fcmd->rsp = fcmd->cmd + len; fcmd->cmdlen = len; fcmd->rsplen = len; @@ -1083,7 +1099,7 @@ clear_bit(fcmd->token, fc->scsi_bitmap); fc->scsi_free++; - dma_unmap_single (fc->dev, fcmd->cmd, 2 * len); + dma_unmap_single (fc->dev, fcmd->cmd, 2 * len, FC_DMA_BIDIRECTIONAL); return l.status; } diff -u --recursive --new-file v2.3.46/linux/drivers/ieee1394/hosts.c linux/drivers/ieee1394/hosts.c --- v2.3.46/linux/drivers/ieee1394/hosts.c Fri Jan 21 18:19:16 2000 +++ linux/drivers/ieee1394/hosts.c Sun Feb 20 20:32:50 2000 @@ -23,31 +23,6 @@ static struct hpsb_host_template *templates = NULL; spinlock_t templates_lock = SPIN_LOCK_UNLOCKED; - -/* - * The following function is exported for module usage. It will - * be called from high-level drivers such as the raw driver. - */ -int hpsb_get_host_list(struct hpsb_host *list[], int list_size) -{ - struct hpsb_host *host, **ptr; - struct hpsb_host_template *tmpl; - int count=0; - - ptr = list; - - for (tmpl = templates ; tmpl != NULL; tmpl = tmpl->next) { - for (host = tmpl->hosts; (host != NULL) && (count < list_size); - host = host->next) { - *ptr = host; - ptr++; - count++; - } - } - - return count; -} - /* * This function calls the add_host/remove_host hooks for every host currently * registered. Init == TRUE means add_host. @@ -131,7 +106,7 @@ h->timeout_tq.data = h; h->topology_map = h->csr.topology_map + 3; - h->speed_map = h->csr.speed_map + 2; + h->speed_map = (u8 *)(h->csr.speed_map + 2); h->template = tmpl; if (hd_size) { diff -u --recursive --new-file v2.3.46/linux/drivers/ieee1394/hosts.h linux/drivers/ieee1394/hosts.h --- v2.3.46/linux/drivers/ieee1394/hosts.h Fri Jan 21 18:19:16 2000 +++ linux/drivers/ieee1394/hosts.h Sun Feb 20 20:32:50 2000 @@ -27,7 +27,8 @@ wait_queue_head_t tlabel_wait; int reset_retries; - quadlet_t *topology_map, *speed_map; + quadlet_t *topology_map; + u8 *speed_map; struct csr_control csr; unsigned char iso_listen_count[64]; @@ -172,14 +173,6 @@ */ struct hpsb_host *hpsb_get_host(struct hpsb_host_template *tmpl, size_t hostdata_size); - -/* - * Write pointers to all available hpsb_hosts into list. - * Return number of host adapters (i.e. elements in list). - * - * DEPRECATED - register with highlevel instead. - */ -int hpsb_get_host_list(struct hpsb_host *list[], int max_list_size); /* * Increase / decrease host usage counter. Increase function will return true diff -u --recursive --new-file v2.3.46/linux/drivers/ieee1394/ieee1394_core.c linux/drivers/ieee1394/ieee1394_core.c --- v2.3.46/linux/drivers/ieee1394/ieee1394_core.c Fri Jan 21 18:19:16 2000 +++ linux/drivers/ieee1394/ieee1394_core.c Sun Feb 20 20:32:50 2000 @@ -4,7 +4,7 @@ * Core support: hpsb_packet management, packet handling and forwarding to * csr or lowlevel code * - * Copyright (C) 1999 Andreas E. Bombe + * Copyright (C) 1999, 2000 Andreas E. Bombe */ #include @@ -191,6 +191,74 @@ return nodeid + 1; } +static void build_speed_map(struct hpsb_host *host, int nodecount) +{ + char speedcap[nodecount]; + char cldcnt[nodecount]; + u8 *map = host->speed_map; + quadlet_t *sidp; + int i, j, n; + + for (i = 0; i < (nodecount * 64); i += 64) { + for (j = 0; j < nodecount; j++) { + map[i+j] = SPEED_400; + } + } + + for (i = 0; i < nodecount; i++) { + cldcnt[i] = 0; + } + + /* find direct children count and speed */ + for (sidp = &host->topology_map[host->selfid_count-1], + n = nodecount - 1; + sidp >= host->topology_map; sidp--) { + if (*sidp & 0x00800000 /* extended */) { + for (i = 2; i < 18; i += 2) { + if ((*sidp & (0x3 << i)) == (0x3 << i)) { + cldcnt[n]++; + } + } + } else { + for (i = 2; i < 8; i += 2) { + if ((*sidp & (0x3 << i)) == (0x3 << i)) { + cldcnt[n]++; + } + } + speedcap[n] = (*sidp >> 14) & 0x3; + n--; + } + } + + /* set self mapping */ + for (i = nodecount - 1; i; i--) { + map[64*i + i] = speedcap[i]; + } + + /* fix up direct children count to total children count; + * also fix up speedcaps for sibling and parent communication */ + for (i = 1; i < nodecount; i++) { + for (j = cldcnt[i], n = i - 1; j > 0; j--) { + cldcnt[i] += cldcnt[n]; + speedcap[n] = MIN(speedcap[n], speedcap[i]); + n -= cldcnt[n] + 1; + } + } + + for (n = 0; n < nodecount; n++) { + for (i = n - cldcnt[n]; i <= n; i++) { + for (j = 0; j < (n - cldcnt[n]); j++) { + map[j*64 + i] = map[i*64 + j] = + MIN(map[i*64 + j], speedcap[n]); + } + for (j = n + 1; j < nodecount; j++) { + map[j*64 + i] = map[i*64 + j] = + MIN(map[i*64 + j], speedcap[n]); + } + } + } +} + void hpsb_selfid_received(struct hpsb_host *host, quadlet_t sid) { if (host->in_bus_reset) { @@ -204,8 +272,6 @@ void hpsb_selfid_complete(struct hpsb_host *host, int phyid, int isroot) { - - host->node_id = 0xffc0 | phyid; host->in_bus_reset = 0; host->is_root = isroot; @@ -219,9 +285,11 @@ return; } else { HPSB_NOTICE("stopping out-of-control reset loop"); - HPSB_NOTICE("warning - topology map will therefore not " - "be valid"); + HPSB_NOTICE("warning - topology map and speed map will " + "therefore not be valid"); } + } else { + build_speed_map(host, host->node_count); } /* irm_id is kept up to date by check_selfids() */ @@ -275,8 +343,22 @@ } packet->state = queued; + packet->speed_code = host->speed_map[(host->node_id & NODE_MASK) * 64 + + (packet->node_id & NODE_MASK)]; - dump_packet("send packet:", packet->header, packet->header_size); + switch (packet->speed_code) { + case 2: + dump_packet("send packet 400:", packet->header, + packet->header_size); + break; + case 1: + dump_packet("send packet 200:", packet->header, + packet->header_size); + break; + default: + dump_packet("send packet 100:", packet->header, + packet->header_size); + } return host->template->transmit_packet(host, packet); } diff -u --recursive --new-file v2.3.46/linux/drivers/ieee1394/ieee1394_syms.c linux/drivers/ieee1394/ieee1394_syms.c --- v2.3.46/linux/drivers/ieee1394/ieee1394_syms.c Tue Feb 1 01:35:43 2000 +++ linux/drivers/ieee1394/ieee1394_syms.c Sun Feb 20 20:32:50 2000 @@ -19,7 +19,6 @@ EXPORT_SYMBOL(hpsb_register_lowlevel); EXPORT_SYMBOL(hpsb_unregister_lowlevel); EXPORT_SYMBOL(hpsb_get_host); -EXPORT_SYMBOL(hpsb_get_host_list); EXPORT_SYMBOL(hpsb_inc_host_usage); EXPORT_SYMBOL(hpsb_dec_host_usage); @@ -53,8 +52,3 @@ EXPORT_SYMBOL(highlevel_write); EXPORT_SYMBOL(highlevel_lock); EXPORT_SYMBOL(highlevel_lock64); - -/* -EXPORT_SYMBOL(hpsb_dispatch_event); -EXPORT_SYMBOL(hpsb_reg_event_handler); -*/ diff -u --recursive --new-file v2.3.46/linux/drivers/ieee1394/ohci1394.c linux/drivers/ieee1394/ohci1394.c --- v2.3.46/linux/drivers/ieee1394/ohci1394.c Tue Feb 1 01:35:43 2000 +++ linux/drivers/ieee1394/ohci1394.c Sun Feb 20 20:32:50 2000 @@ -18,6 +18,28 @@ * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ +/* + * Things known to be working: + * . Async Request Transmit + * . Async Response Receive + * . Async Request Receive + * . Async Response Transmit + * . Iso Receive + * + * Things not implemented: + * . Iso Transmit + * . DMA to user's space in iso receive mode + * . DMA error recovery + * + * Things to be fixed: + * . Config ROM + * + * Known bugs: + * . Self-id are not received properly if card + * is initialized with no other nodes on the + * bus. + */ + #include #include #include @@ -35,12 +57,31 @@ #include #include +#include +#include +#include +#include +#include +#include +#include + #include "ieee1394.h" #include "ieee1394_types.h" #include "hosts.h" #include "ieee1394_core.h" #include "ohci1394.h" +#ifdef DBGMSG +#undef DBGMSG +#endif + +#if OHCI1394_DEBUG +#define DBGMSG(card, fmt, args...) \ +printk(KERN_INFO "ohci1394_%d: " fmt "\n" , card , ## args) +#else +#define DBGMSG(card, fmt, args...) +#endif + /* print general (card independent) information */ #define PRINT_G(level, fmt, args...) \ printk(level "ohci1394: " fmt "\n" , ## args) @@ -49,11 +90,18 @@ #define PRINT(level, card, fmt, args...) \ printk(level "ohci1394_%d: " fmt "\n" , card , ## args) +#define FAIL(fmt, args...) \ + PRINT_G(KERN_ERR, fmt , ## args); \ + num_of_cards--; \ + remove_card(ohci); \ + return 1; + int supported_chips[][2] = { - { PCI_VENDOR_ID_TI, PCI_DEVICE_ID_TI_OHCI1394 }, - { PCI_VENDOR_ID_TI, PCI_DEVICE_ID_TI_OHCI1394_2 }, - { PCI_VENDOR_ID_VIA, PCI_DEVICE_ID_VIA_OHCI1394 }, - { -1, -1 } + { PCI_VENDOR_ID_TI, PCI_DEVICE_ID_TI_OHCI1394 }, + { PCI_VENDOR_ID_TI, PCI_DEVICE_ID_TI_OHCI1394_2 }, + { PCI_VENDOR_ID_VIA, PCI_DEVICE_ID_VIA_OHCI1394 }, + { PCI_VENDOR_ID_SONY, PCI_DEVICE_ID_SONY_CXD3222 }, + { -1, -1 } }; static struct ti_ohci cards[MAX_OHCI1394_CARDS]; @@ -62,6 +110,8 @@ static int add_card(struct pci_dev *dev); static void remove_card(struct ti_ohci *ohci); static int init_driver(void); +static void dma_trm_bh(void *data); +static void dma_trm_reset(struct dma_trm_ctx *d); /*********************************** * IEEE-1394 functionality section * @@ -87,7 +137,7 @@ /* wait */ while (!(reg_read(ohci, OHCI1394_PhyControl)&0x80000000) && timeout) - timeout--; + timeout--; if (!timeout) { @@ -120,7 +170,7 @@ /* wait */ while (!(reg_read(ohci, OHCI1394_PhyControl)&0x80000000) && timeout) - timeout--; + timeout--; spin_unlock(&ohci->phy_reg_lock); @@ -150,31 +200,34 @@ if ((self_id_count&0x80000000) || ((self_id_count&0x00FF0000) != (q[0]&0x00FF0000))) { PRINT(KERN_ERR, ohci->id, - "Error in reception of self-id packets"); + "Error in reception of self-id packets" + "Self-id count: %08x q[0]: %08x", + self_id_count, q[0]); return -1; - } - + } + size = ((self_id_count&0x0000EFFC)>>2) - 1; q++; while (size > 0) { if (q[0] == ~q[1]) { - printk("-%d- selfid packet 0x%x rcvd\n", - ohci->id, q[0]); + PRINT(KERN_INFO, ohci->id, "selfid packet 0x%x rcvd", + q[0]); hpsb_selfid_received(host, q[0]); if (((q[0]&0x3f000000)>>24)==phyid) { lsid=q[0]; - printk("This node self-id is 0x%08x\n",lsid); + PRINT(KERN_INFO, ohci->id, + "This node self-id is 0x%08x", lsid); } } else { - printk("-%d- inconsistent selfid 0x%x/0x%x\n", ohci->id, - q[0], q[1]); + PRINT(KERN_ERR, ohci->id, + "inconsistent selfid 0x%x/0x%x", q[0], q[1]); } q += 2; size -= 2; } - printk(" calling self-id complete\n"); + PRINT(KERN_INFO, ohci->id, "calling self-id complete"); hpsb_selfid_complete(host, phyid, isroot); return 0; @@ -206,7 +259,7 @@ reg_write(ohci, OHCI1394_HCControlSet, 0x00010000); while ((reg_read(ohci, OHCI1394_HCControlSet)&0x00010000) && timeout) - timeout--; + timeout--; if (!timeout) { PRINT(KERN_ERR, ohci->id, "soft reset timeout !!!"); return -EFAULT; @@ -215,6 +268,108 @@ return 0; } +static int run_context(struct ti_ohci *ohci, int reg, char *msg) +{ + u32 nodeId; + + /* check that the node id is valid */ + nodeId = reg_read(ohci, OHCI1394_NodeID); + if (!(nodeId&0x80000000)) { + PRINT(KERN_ERR, ohci->id, + "Running dma failed because Node ID not valid"); + return -1; + } + + /* check that the node number != 63 */ + if ((nodeId&0x3f)==63) { + PRINT(KERN_ERR, ohci->id, + "Running dma failed because Node ID == 63"); + return -1; + } + + /* Run the dma context */ + reg_write(ohci, reg, 0x8000); + + if (msg) PRINT(KERN_INFO, ohci->id, "%s", msg); + + return 0; +} + +static void stop_context(struct ti_ohci *ohci, int reg, char *msg) +{ + int i=0; + + /* stop the channel program if it's still running */ + reg_write(ohci, reg, 0x8000); + + /* Wait until it effectively stops */ + while (reg_read(ohci, reg) & 0x400) { + i++; + if (i>5000) { + PRINT(KERN_ERR, ohci->id, + "runaway loop while stopping context..."); + break; + } + } + if (msg) PRINT(KERN_ERR, ohci->id, "%s\n dma prg stopped\n", msg); +} + +/* Generate the dma receive prgs and start the context */ +static void initialize_dma_rcv_ctx(struct dma_rcv_ctx *d) +{ + struct ti_ohci *ohci = (struct ti_ohci*)(d->ohci); + int i; + + stop_context(ohci, d->ctrlClear, NULL); + + for (i=0; inum_desc; i++) { + + /* end of descriptor list? */ + if ((i+1) < d->num_desc) { + d->prg[i]->control = (0x283C << 16) | d->buf_size; + d->prg[i]->branchAddress = + (virt_to_bus(d->prg[i+1]) & 0xfffffff0) | 0x1; + } else { + d->prg[i]->control = (0x283C << 16) | d->buf_size; + d->prg[i]->branchAddress = + (virt_to_bus(d->prg[0]) & 0xfffffff0); + } + + d->prg[i]->address = virt_to_bus(d->buf[i]); + d->prg[i]->status = d->buf_size; + } + + d->buf_ind = 0; + d->buf_offset = 0; + + /* Tell the controller where the first AR program is */ + reg_write(ohci, d->cmdPtr, virt_to_bus(d->prg[0]) | 0x1); + + /* Run AR context */ + reg_write(ohci, d->ctrlSet, 0x00008000); + + PRINT(KERN_INFO, ohci->id, "Receive DMA ctx=%d initialized", d->ctx); +} + +/* Initialize the dma transmit context */ +static void initialize_dma_trm_ctx(struct dma_trm_ctx *d) +{ + struct ti_ohci *ohci = (struct ti_ohci*)(d->ohci); + + /* Stop the context */ + stop_context(ohci, d->ctrlClear, NULL); + + d->prg_ind = 0; + d->sent_ind = 0; + d->free_prgs = d->num_desc; + d->branchAddrPtr = NULL; + d->first = NULL; + d->last = NULL; + + PRINT(KERN_INFO, ohci->id, "AT dma ctx=%d initialized", d->ctx); +} + +/* Global initialization */ static int ohci_initialize(struct hpsb_host *host) { struct ti_ohci *ohci=host->hostdata; @@ -255,109 +410,64 @@ reg_write(ohci, OHCI1394_ConfigROMmap, virt_to_bus(ohci->csr_config_rom)); -#if 1 /* Why is this step necessary ? */ /* Write the config ROM header */ - reg_write(ohci, OHCI1394_ConfigROMhdr,0x04040000); + reg_write(ohci, OHCI1394_ConfigROMhdr, ohci->csr_config_rom[0]); /* Set bus options */ - reg_write(ohci, OHCI1394_BusOptions, 0xf064A002); -#endif + reg_write(ohci, OHCI1394_BusOptions, ohci->csr_config_rom[2]); -#if 1 - /* Accept phy packets into AR request context */ - reg_write(ohci, OHCI1394_LinkControlSet, 0x00000400); -#endif + /* Write the GUID into the csr config rom */ + ohci->csr_config_rom[3] = reg_read(ohci, OHCI1394_GUIDHi); + ohci->csr_config_rom[4] = reg_read(ohci, OHCI1394_GUIDLo); + + /* Don't accept phy packets into AR request context */ + reg_write(ohci, OHCI1394_LinkControlClear, 0x00000400); /* Enable link */ reg_write(ohci, OHCI1394_HCControlSet, 0x00020000); /* Initialize IR dma */ + for (i=0;i<4;i++) { /* FIXME : how many contexts are available ? */ + reg_write(ohci, OHCI1394_IrRcvContextControlClear+32*i, + 0xffffffff); + reg_write(ohci, OHCI1394_IrRcvContextMatch+32*i, 0); + reg_write(ohci, OHCI1394_IrRcvCommandPtr+32*i, 0); + } + + /* Set bufferFill, isochHeader, multichannel for IR context */ + reg_write(ohci, OHCI1394_IrRcvContextControlSet, 0xd0000000); + + /* Set the context match register to match on all tags */ + reg_write(ohci, OHCI1394_IrRcvContextMatch, 0xf0000000); + + /* Clear the multi channel mask high and low registers */ + reg_write(ohci, OHCI1394_IRMultiChanMaskHiClear, 0xffffffff); + reg_write(ohci, OHCI1394_IRMultiChanMaskLoClear, 0xffffffff); + + /* Clear the interrupt mask */ + reg_write(ohci, OHCI1394_IsoRecvIntMaskClear, 0xffffffff); + + /* Set up isoRecvIntMask to generate interrupts for context 0 + (thanks to Michael Greger for seeing that I forgot this) */ + reg_write(ohci, OHCI1394_IsoRecvIntMaskSet, 0x00000001); - /* make sure the context isn't running, dead, or active */ - if (!(reg_read(ohci, OHCI1394_IrRcvContextControlSet) & 0x00008F00)) { - - /* initialize IR program */ - for (i= 0; i < IR_NUM_DESC; i++) { - - /* end of descriptor list? */ - if ((i + 1) < IR_NUM_DESC) { - ohci->IR_recv_prg[i]->control= - (0x283C << 16) | IR_RECV_BUF_SIZE; - ohci->IR_recv_prg[i]->branchAddress= - (virt_to_bus(ohci->IR_recv_prg[i + 1]) - & 0xfffffff0) | 0x1; - } else { - ohci->IR_recv_prg[i]->control= - (0x283C << 16) | IR_RECV_BUF_SIZE; - ohci->IR_recv_prg[i]->branchAddress= - (virt_to_bus(ohci->IR_recv_prg[0]) - & 0xfffffff0) | 0x1; - } - - ohci->IR_recv_prg[i]->address= - virt_to_bus(ohci->IR_recv_buf[i]); - ohci->IR_recv_prg[i]->status= IR_RECV_BUF_SIZE; - } - - /* Tell the controller where the first IR program is */ - reg_write(ohci, OHCI1394_IrRcvCommandPtr, - virt_to_bus(ohci->IR_recv_prg[0]) | 0x1 ); - - /* Set bufferFill, isochHeader, multichannel for IR context */ - reg_write(ohci, OHCI1394_IrRcvContextControlSet, 0xd0000000); - - /* Set the context match register to match on all tags */ - reg_write(ohci, OHCI1394_IrRcvContextMatch, 0xf0000000); - - /* Clear the multi channel mask high and low registers */ - reg_write(ohci, OHCI1394_IRMultiChanMaskHiClear, 0xffffffff); - reg_write(ohci, OHCI1394_IRMultiChanMaskLoClear, 0xffffffff); - - /* Set up isoRecvIntMask to generate interrupts for context 0 - (thanks to Michael Greger for seeing that I forgot this) */ - reg_write(ohci, OHCI1394_IsoRecvIntMaskSet, 0x00000001); - - /* Run IR context */ - reg_write(ohci, OHCI1394_IrRcvContextControlSet, 0x00008000); - } + initialize_dma_rcv_ctx(ohci->ir_context); /* Initialize AR dma */ - /* make sure the context isn't running, dead, or active */ - if (!(reg_read(ohci, OHCI1394_AsRspRcvContextControlSet) & 0x00008F00)) { - - /* initialize AR program */ - for (i= 0; i < AR_RESP_NUM_DESC; i++) { - - /* end of descriptor list? */ - if ((i + 1) < AR_RESP_NUM_DESC) { - ohci->AR_resp_prg[i]->control= - (0x283C << 16) | AR_RESP_BUF_SIZE; - ohci->AR_resp_prg[i]->branchAddress= - (virt_to_bus(ohci->AR_resp_prg[i + 1]) - & 0xfffffff0) | 0x1; - } else { - ohci->AR_resp_prg[i]->control= - (0x283C << 16) | AR_RESP_BUF_SIZE; - ohci->AR_resp_prg[i]->branchAddress= - (virt_to_bus(ohci->AR_resp_prg[0]) - & 0xfffffff0) | 0x1; - } + initialize_dma_rcv_ctx(ohci->ar_req_context); + initialize_dma_rcv_ctx(ohci->ar_resp_context); - ohci->AR_resp_prg[i]->address= - virt_to_bus(ohci->AR_resp_buf[i]); - ohci->AR_resp_prg[i]->status= AR_RESP_BUF_SIZE; - } - - /* Tell the controller where the first AR program is */ - reg_write(ohci, OHCI1394_AsRspRcvCommandPtr, - virt_to_bus(ohci->AR_resp_prg[0]) | 0x1 ); - - /* Accept phy packets into AR request context */ - reg_write(ohci, OHCI1394_LinkControlSet, 0x00000400); - - /* Run AR context */ - reg_write(ohci, OHCI1394_AsRspRcvContextControlSet, 0x00008000); - } + /* Initialize AT dma */ + initialize_dma_trm_ctx(ohci->at_req_context); + initialize_dma_trm_ctx(ohci->at_resp_context); + + /* + * Accept AT requests from all nodes. This probably + * will have to be controlled from the subsystem + * on a per node basis. + * (Tip by Emilie Chung ) + */ + reg_write(ohci,OHCI1394_AsReqFilterHiSet, 0x80000000); /* Specify AT retries */ reg_write(ohci, OHCI1394_ATRetries, @@ -384,7 +494,7 @@ OHCI1394_respTxComplete | OHCI1394_reqTxComplete | OHCI1394_isochRx - ); + ); return 1; } @@ -399,126 +509,144 @@ } } - -/* This must be called with the async_queue_lock held. */ -static void send_next_async(struct ti_ohci *ohci) +/* Insert a packet in the AT DMA fifo and generate the DMA prg */ +static void insert_packet(struct ti_ohci *ohci, + struct dma_trm_ctx *d, struct hpsb_packet *packet) { - int i=0; - struct hpsb_packet *packet = ohci->async_queue; - struct dma_cmd prg; -#if 0 - quadlet_t *ptr = (quadlet_t *)ohci->AT_req_prg; -#endif - //HPSB_TRACE(); - - /* stop the channel program if it's still running */ - reg_write(ohci, OHCI1394_AsReqTrContextControlClear, 0x8000); - - /* Wait until it effectively stops */ - while (reg_read(ohci, OHCI1394_AsReqTrContextControlSet) - & 0x400) { - i++; - if (i>5000) { - PRINT(KERN_ERR, ohci->id, - "runaway loop in DmaAT. bailing out..."); - break; - } - }; + u32 cycleTimer; + int idx = d->prg_ind; - if (packet->type == async) - { - - /* re-format packet header according to ohci specification */ - packet->header[1] = (packet->header[1] & 0xFFFF) | - (packet->header[0] & 0xFFFF0000); - packet->header[0] = DMA_SPEED_200 | - (packet->header[0] & 0xFFFF); - - if (packet->data_size) { /* block transmit */ - prg.control = OUTPUT_MORE_IMMEDIATE | 0x10; - prg.address = 0; - prg.branchAddress = 0; - prg.status = 0; - memcpy(ohci->AT_req_prg, &prg, 16); - memcpy(ohci->AT_req_prg + 1, packet->header, 16); - prg.control = OUTPUT_LAST | packet->data_size; - prg.address = virt_to_bus(packet->data); - memcpy(ohci->AT_req_prg + 2, &prg, 16); - - reg_write(ohci, OHCI1394_AsReqTrCommandPtr, - virt_to_bus(ohci->AT_req_prg)|0x3); - } - else { /* quadlet transmit */ - prg.control = OUTPUT_LAST_IMMEDIATE | - packet->header_size; - prg.address = 0; - prg.branchAddress = 0; - prg.status = 0; - memcpy(ohci->AT_req_prg, &prg, 16); - memcpy(ohci->AT_req_prg + 1, packet->header, 16); -#if 0 - PRINT(KERN_INFO, ohci->id, - "dma_cmd: %08x %08x %08x %08x", - *ptr, *(ptr+1), *(ptr+2), *(ptr+3)); - PRINT(KERN_INFO, ohci->id, - "header: %08x %08x %08x %08x", - *(ptr+4), *(ptr+5), *(ptr+6), *(ptr+7)); -#endif - reg_write(ohci, OHCI1394_AsReqTrCommandPtr, - virt_to_bus(ohci->AT_req_prg)|0x2); - } - - } - else if (packet->type == raw) - { - prg.control = OUTPUT_LAST | packet->data_size; - prg.address = virt_to_bus(packet->data); - prg.branchAddress = 0; - prg.status = 0; - memcpy(ohci->AT_req_prg, &prg, 16); -#if 0 - PRINT(KERN_INFO, ohci->id, - "dma_cmd: %08x %08x %08x %08x", - *ptr, *(ptr+1), *(ptr+2), *(ptr+3)); -#endif - reg_write(ohci, OHCI1394_AsReqTrCommandPtr, - virt_to_bus(ohci->AT_req_prg)|0x2); - } - - /* run program */ - reg_write(ohci, OHCI1394_AsReqTrContextControlSet, 0x00008000); + d->prg[idx].begin.address = 0; + d->prg[idx].begin.branchAddress = 0; + if (d->ctx==1) { + /* + * For response packets, we need to put a timeout value in + * the 16 lower bits of the status... let's try 1 sec timeout + */ + cycleTimer = reg_read(ohci, OHCI1394_IsochronousCycleTimer); + d->prg[idx].begin.status = + (((((cycleTimer>>25)&0x7)+1)&0x7)<<13) | + ((cycleTimer&0x01fff000)>>12); + + DBGMSG(ohci->id, "cycleTimer: %08x timeStamp: %08x", + cycleTimer, d->prg[idx].begin.status); + } + else + d->prg[idx].begin.status = 0; + + d->prg[idx].data[0] = packet->speed_code<<16 | + (packet->header[0] & 0xFFFF); + d->prg[idx].data[1] = (packet->header[1] & 0xFFFF) | + (packet->header[0] & 0xFFFF0000); + d->prg[idx].data[2] = packet->header[2]; + d->prg[idx].data[3] = packet->header[3]; + + if (packet->data_size) { /* block transmit */ + d->prg[idx].begin.control = OUTPUT_MORE_IMMEDIATE | 0x10; + d->prg[idx].end.control = OUTPUT_LAST | packet->data_size; + d->prg[idx].end.address = virt_to_bus(packet->data); + d->prg[idx].end.branchAddress = 0; + d->prg[idx].end.status = 0x4000; + if (d->branchAddrPtr) + *(d->branchAddrPtr) = virt_to_bus(d->prg+idx) | 0x3; + d->branchAddrPtr = &(d->prg[idx].end.branchAddress); + } + else { /* quadlet transmit */ + d->prg[idx].begin.control = + OUTPUT_LAST_IMMEDIATE | packet->header_size; + if (d->branchAddrPtr) + *(d->branchAddrPtr) = virt_to_bus(d->prg+idx) | 0x2; + d->branchAddrPtr = &(d->prg[idx].begin.branchAddress); + } + d->free_prgs--; + + /* queue the packet in the appropriate context queue */ + if (d->last) { + d->last->xnext = packet; + d->last = packet; + } + else { + d->first = packet; + d->last = packet; + } } static int ohci_transmit(struct hpsb_host *host, struct hpsb_packet *packet) { struct ti_ohci *ohci = host->hostdata; - struct hpsb_packet *p; - unsigned long flags; + struct dma_trm_ctx *d; + unsigned char tcode; + int i=50; if (packet->data_size >= 4096) { PRINT(KERN_ERR, ohci->id, "transmit packet data too big (%d)", packet->data_size); return 0; } - - //HPSB_TRACE(); packet->xnext = NULL; - - spin_lock_irqsave(&ohci->async_queue_lock, flags); - if (ohci->async_queue == NULL) { - ohci->async_queue = packet; - send_next_async(ohci); - } else { - p = ohci->async_queue; - while (p->xnext != NULL) { - p = p->xnext; + /* Decide wether we have a request or a response packet */ + tcode = (packet->header[0]>>4)&0xf; + if ((tcode==TCODE_READQ)|| + (tcode==TCODE_WRITEQ)|| + (tcode==TCODE_READB)|| + (tcode==TCODE_WRITEB)|| + (tcode==TCODE_LOCK_REQUEST)) + d = ohci->at_req_context; + + else if ((tcode==TCODE_WRITE_RESPONSE)|| + (tcode==TCODE_READQ_RESPONSE)|| + (tcode==TCODE_READB_RESPONSE)|| + (tcode==TCODE_LOCK_RESPONSE)) + d = ohci->at_resp_context; + + else { + PRINT(KERN_ERR, ohci->id, + "Unexpected packet tcode=%d in AT DMA", tcode); + return 0; + } + + spin_lock(&d->lock); + + if (d->free_prgs<1) { + PRINT(KERN_INFO, ohci->id, + "AT DMA ctx=%d Running out of prgs... waiting",d->ctx); + } + while (d->free_prgs<1) { + spin_unlock(&d->lock); + schedule(); + if (i-- <0) { + stop_context(ohci, d->ctrlClear, + "AT DMA runaway loop... bailing out"); + return 0; } - - p->xnext = packet; + spin_lock(&d->lock); + } + + insert_packet(ohci, d, packet); + + /* Is the context running ? (should be unless it is + the first packet to be sent in this context) */ + if (!(reg_read(ohci, d->ctrlSet) & 0x8000)) { + DBGMSG(ohci->id,"Starting AT DMA ctx=%d",d->ctx); + if (packet->data_size) + reg_write(ohci, d->cmdPtr, + virt_to_bus(&(d->prg[d->prg_ind])) | 0x3); + else + reg_write(ohci, d->cmdPtr, + virt_to_bus(&(d->prg[d->prg_ind])) | 0x2); + + run_context(ohci, d->ctrlSet, NULL); + } + else { + DBGMSG(ohci->id,"Waking AT DMA ctx=%d",d->ctx); + /* wake up the dma context if necessary */ + if (!(reg_read(ohci, d->ctrlSet) & 0x400)) + reg_write(ohci, d->ctrlSet, 0x1000); } - - spin_unlock_irqrestore(&ohci->async_queue_lock, flags); + + d->prg_ind = (d->prg_ind+1)%d->num_desc; + spin_unlock(&d->lock); return 1; } @@ -528,31 +656,29 @@ struct ti_ohci *ohci = host->hostdata; int retval = 0; unsigned long flags; - struct hpsb_packet *packet, *lastpacket; - u32 r; switch (cmd) { - case RESET_BUS: + case RESET_BUS: PRINT(KERN_INFO, ohci->id, "resetting bus on request%s", (host->attempt_root ? " and attempting to become root" : "")); - r = (host->attempt_root) ? 0x000041ff : 0x0000417f; - reg_write(ohci, OHCI1394_PhyControl, r); + reg_write(ohci, OHCI1394_PhyControl, + (host->attempt_root) ? 0x000041ff : 0x0000417f); break; - case GET_CYCLE_COUNTER: + case GET_CYCLE_COUNTER: retval = reg_read(ohci, OHCI1394_IsochronousCycleTimer); break; - case SET_CYCLE_COUNTER: + case SET_CYCLE_COUNTER: reg_write(ohci, OHCI1394_IsochronousCycleTimer, arg); break; - case SET_BUS_ID: + case SET_BUS_ID: PRINT(KERN_ERR, ohci->id, "devctl command SET_BUS_ID err"); break; - case ACT_CYCLE_MASTER: + case ACT_CYCLE_MASTER: #if 0 if (arg) { /* enable cycleTimer, cycleMaster, cycleSource */ @@ -564,23 +690,13 @@ #endif break; - case CANCEL_REQUESTS: - spin_lock_irqsave(&ohci->async_queue_lock, flags); - /* stop any chip activity */ - reg_write(ohci, OHCI1394_HCControlClear, 0x00020000); - packet = ohci->async_queue; - ohci->async_queue = NULL; - spin_unlock_irqrestore(&ohci->async_queue_lock, flags); - - while (packet != NULL) { - lastpacket = packet; - packet = packet->xnext; - hpsb_packet_sent(host, lastpacket, ACKX_ABORTED); - } - + case CANCEL_REQUESTS: + DBGMSG(ohci->id, "Cancel request received"); + dma_trm_reset(ohci->at_req_context); + dma_trm_reset(ohci->at_resp_context); break; - case MODIFY_USAGE: + case MODIFY_USAGE: if (arg) { MOD_INC_USE_COUNT; } else { @@ -588,7 +704,7 @@ } break; - case ISO_LISTEN_CHANNEL: + case ISO_LISTEN_CHANNEL: spin_lock_irqsave(&ohci->IR_channel_lock, flags); @@ -614,7 +730,7 @@ spin_unlock_irqrestore(&ohci->IR_channel_lock, flags); break; - case ISO_UNLISTEN_CHANNEL: + case ISO_UNLISTEN_CHANNEL: spin_lock_irqsave(&ohci->IR_channel_lock, flags); @@ -642,7 +758,7 @@ spin_unlock_irqrestore(&ohci->IR_channel_lock, flags); break; - default: + default: PRINT_G(KERN_ERR, "ohci_devctl cmd %d not implemented yet\n", cmd); break; @@ -659,160 +775,118 @@ * Global stuff (interrupt handler, init/shutdown code) * ********************************************************/ -static void stop_ar_resp_context(struct ti_ohci *ohci, char *msg) +static void dma_trm_reset(struct dma_trm_ctx *d) { - int i=0; + struct ti_ohci *ohci; - /* stop the channel program if it's still running */ - reg_write(ohci, OHCI1394_AsRspRcvContextControlClear, 0x8000); - - /* Wait until it effectively stops */ - while (reg_read(ohci, OHCI1394_AsRspRcvContextControlSet) - & 0x400) { - i++; - if (i>5000) { - PRINT(KERN_ERR, ohci->id, - "runaway loop in Dma Ar Resp. bailing out..."); - break; - } - } - PRINT(KERN_ERR, ohci->id, "%s\n async response receive dma stopped\n", msg); + if (d==NULL) { + PRINT_G(KERN_ERR, "dma_trm_reset called with NULL arg"); + return; + } + ohci = (struct ti_ohci *)(d->ohci); + stop_context(ohci, d->ctrlClear, NULL); + + spin_lock(&d->lock); + + /* is there still any packet pending ? */ + while(d->first) { + PRINT(KERN_INFO, ohci->id, + "AT dma reset ctx=%d, aborting transmission", + d->ctx); + hpsb_packet_sent(ohci->host, d->first, ACKX_ABORTED); + d->first = d->first->xnext; + } + d->first = d->last = NULL; + d->branchAddrPtr=NULL; + d->sent_ind = d->prg_ind; + d->free_prgs = d->num_desc; + spin_unlock(&d->lock); } static void ohci_irq_handler(int irq, void *dev_id, struct pt_regs *regs_are_unused) { - //int i; - static quadlet_t event,node_id; + quadlet_t event,node_id; struct ti_ohci *ohci = (struct ti_ohci *)dev_id; struct hpsb_host *host = ohci->host; int phyid = -1, isroot = 0; event=reg_read(ohci, OHCI1394_IntEventSet); - /* Clear the interrupt register */ - reg_write(ohci, OHCI1394_IntEventClear, event); - - /* PRINT(KERN_INFO, ohci->id, "int event %08X mask %08X", - event,reg_read(ohci, OHCI1394_IntMaskSet)); */ - if (event & OHCI1394_busReset) { -#if 0 - PRINT(KERN_INFO, ohci->id, "bus reset interrupt"); -#endif if (!host->in_bus_reset) { - hpsb_bus_reset(host); + PRINT(KERN_INFO, ohci->id, "Bus reset"); + + /* Wait for the AT fifo to be flushed */ + dma_trm_reset(ohci->at_req_context); + dma_trm_reset(ohci->at_resp_context); + + /* Subsystem call */ + hpsb_bus_reset(ohci->host); + + ohci->NumBusResets++; } - ohci->NumBusResets++; } - if (event & OHCI1394_RQPkt) { - PRINT(KERN_INFO, ohci->id, "RQPkt int received"); + /* + * Problem: How can I ensure that the AT bottom half will be + * executed before the AR bottom half (both events may have + * occured within a single irq event) + * Quick hack: just launch it within the IRQ handler + */ + if (event & OHCI1394_reqTxComplete) { + struct dma_trm_ctx *d = ohci->at_req_context; + DBGMSG(ohci->id, "Got reqTxComplete interrupt status=0x%08X", + reg_read(ohci, d->ctrlSet)); + if (reg_read(ohci, d->ctrlSet) & 0x800) + stop_context(ohci, d->ctrlClear, "reqTxComplete"); + else + dma_trm_bh((void *)d); + } + if (event & OHCI1394_respTxComplete) { + struct dma_trm_ctx *d = ohci->at_resp_context; + DBGMSG(ohci->id, "Got respTxComplete interrupt status=0x%08X", + reg_read(ohci, d->ctrlSet)); + if (reg_read(ohci, d->ctrlSet) & 0x800) + stop_context(ohci, d->ctrlClear, "respTxComplete"); + else + dma_trm_bh((void *)d); } if (event & OHCI1394_RQPkt) { - PRINT(KERN_INFO, ohci->id, "ControlContext: %08X", - reg_read(ohci, OHCI1394_AsReqRcvContextControlSet)); + struct dma_rcv_ctx *d = ohci->ar_req_context; + DBGMSG(ohci->id, "Got RQPkt interrupt status=0x%08X", + reg_read(ohci, d->ctrlSet)); + if (reg_read(ohci, d->ctrlSet) & 0x800) + stop_context(ohci, d->ctrlClear, "RQPkt"); + else { + queue_task(&d->task, &tq_immediate); + mark_bh(IMMEDIATE_BH); + } } if (event & OHCI1394_RSPkt) { - unsigned int idx,offset,rescount; - - spin_lock(&ohci->AR_resp_lock); - - idx = ohci->AR_resp_buf_th_ind; - offset = ohci->AR_resp_buf_th_offset; - - rescount = ohci->AR_resp_prg[idx]->status&0xffff; - ohci->AR_resp_bytes_left += AR_RESP_BUF_SIZE - rescount - offset; - offset = AR_RESP_BUF_SIZE - rescount; - - if (!rescount) { /* We cross a buffer boundary */ - idx = (idx+1) % AR_RESP_NUM_DESC; - -#if 0 - /* This bit of code does not work */ - /* Let's see how many bytes were written in the async response - receive buf since last interrupt. This is done by finding - the next active context (See OHCI Spec p91) */ - while (ohci->AR_resp_bytes_left <= AR_RESP_TOTAL_BUF_SIZE) { - if (ohci->AR_resp_prg[idx]->status&0x04000000) break; - idx = (idx+1) % AR_RESP_NUM_DESC; - PRINT(KERN_INFO,ohci->id,"crossing more than one buffer boundary !!!"); - ohci->AR_resp_bytes_left += AR_RESP_BUF_SIZE; - } -#endif - /* ASSUMPTION: only one buffer boundary is crossed */ - rescount = ohci->AR_resp_prg[idx]->status&0xffff; - offset = AR_RESP_BUF_SIZE - rescount; - ohci->AR_resp_bytes_left += offset; - } - if (offset==AR_RESP_BUF_SIZE) { - offset=0; - idx = (idx+1) % AR_RESP_NUM_DESC; - } - ohci->AR_resp_buf_th_ind = idx; - ohci->AR_resp_buf_th_offset = offset; - - /* is buffer processing too slow? (all buffers used) */ - if (ohci->AR_resp_bytes_left > AR_RESP_TOTAL_BUF_SIZE) { - stop_ar_resp_context(ohci,"async response receive processing too slow"); - spin_unlock(&ohci->AR_resp_lock); - return; + struct dma_rcv_ctx *d = ohci->ar_resp_context; + DBGMSG(ohci->id, "Got RSPkt interrupt status=0x%08X", + reg_read(ohci, d->ctrlSet)); + if (reg_read(ohci, d->ctrlSet) & 0x800) + stop_context(ohci, d->ctrlClear, "RSPkt"); + else { + queue_task(&d->task, &tq_immediate); + mark_bh(IMMEDIATE_BH); } - spin_unlock(&ohci->AR_resp_lock); - - /* queue bottom half in immediate queue */ - queue_task(&ohci->AR_resp_pdl_task, &tq_immediate); - mark_bh(IMMEDIATE_BH); } if (event & OHCI1394_isochRx) { quadlet_t isoRecvIntEvent; - - /* ASSUMPTION: We assume there is only one context for now. */ - - spin_lock(&ohci->IR_recv_lock); - - /* Clear the isoRecvIntEvent register (very important!) */ - isoRecvIntEvent= reg_read(ohci, OHCI1394_IsoRecvIntEventSet); + struct dma_rcv_ctx *d = ohci->ir_context; + isoRecvIntEvent = reg_read(ohci, OHCI1394_IsoRecvIntEventSet); reg_write(ohci, OHCI1394_IsoRecvIntEventClear, isoRecvIntEvent); - - ohci->IR_buf_used++; - ohci->IR_buf_next_ind= - (ohci->IR_buf_next_ind + 1) % IR_NUM_DESC; - - /* is buffer processing too slow? (all buffers used) */ - if (ohci->IR_buf_next_ind == ohci->IR_buf_last_ind) { - int i= 0; - - /* stop the context */ - reg_write(ohci, - OHCI1394_IrRcvContextControlClear, 0x8000); - - while (reg_read(ohci, OHCI1394_IrRcvContextControlSet) - & 0x400) { - i++; - - if (i>5000) { - PRINT(KERN_ERR, ohci->id, "runaway loop in DmaIR. bailing out..."); - break; - } - - } - - spin_unlock(&ohci->IR_recv_lock); - PRINT(KERN_ERR, ohci->id, - "iso receive processing too slow... stopped"); - return; + DBGMSG(ohci->id, "Got reqTxComplete interrupt status=0x%08X", + reg_read(ohci, d->ctrlSet)); + if (reg_read(ohci, d->ctrlSet) & 0x800) + stop_context(ohci, d->ctrlClear, "isochRx"); + else { + queue_task(&d->task, &tq_immediate); + mark_bh(IMMEDIATE_BH); } - - /* reset status field of next descriptor */ - ohci->IR_recv_prg[ohci->IR_buf_next_ind]->status= - IR_RECV_BUF_SIZE; - - spin_unlock(&ohci->IR_recv_lock); - - /* queue bottom half in immediate queue */ - queue_task(&ohci->IR_pdl_task, &tq_immediate); - mark_bh(IMMEDIATE_BH); } if (event & OHCI1394_selfIDComplete) { if (host->in_bus_reset) { @@ -828,9 +902,13 @@ handle_selfid(ohci, host, phyid, isroot); } else - PRINT(KERN_ERR, ohci->id, - "SelfID process finished but NodeID" - " not valid: %08X",node_id); + PRINT(KERN_ERR, ohci->id, + "SelfID process finished but NodeID" + " not valid: %08X",node_id); + + /* Accept Physical requests from all nodes. */ + reg_write(ohci,OHCI1394_AsReqFilterHiSet, 0xffffffff); + reg_write(ohci,OHCI1394_AsReqFilterLoSet, 0xffffffff); } else PRINT(KERN_INFO, ohci->id, "phy reg received without reset\n"); @@ -840,316 +918,424 @@ if (host->in_bus_reset) { PRINT(KERN_INFO, ohci->id, "PhyControl: %08X", reg_read(ohci, OHCI1394_PhyControl)); - } else printk("-%d- phy reg received without reset\n", - ohci->id); + } else + PRINT(KERN_ERR, ohci->id, + "phy reg received without reset"); #endif } - if (event & OHCI1394_reqTxComplete) { - /* async packet sent - transmitter ready */ - u32 ack; - struct hpsb_packet *packet; - - if (ohci->async_queue) { - - spin_lock(&ohci->async_queue_lock); - - ack=reg_read(ohci, OHCI1394_AsReqTrContextControlSet) - & 0xF; - - packet = ohci->async_queue; - ohci->async_queue = packet->xnext; - - if (ohci->async_queue != NULL) { - send_next_async(ohci); - } - spin_unlock(&ohci->async_queue_lock); -#if 0 - PRINT(KERN_INFO,ohci->id, - "packet sent with ack code %d",ack); -#endif - hpsb_packet_sent(host, packet, ack); - } else - PRINT(KERN_INFO,ohci->id, - "packet sent without async_queue (self-id?)"); - ohci->TxRdy++; + /* clear the interrupt event register */ + reg_write(ohci, OHCI1394_IntEventClear, event); +} + +/* Put the buffer back into the dma context */ +static void insert_dma_buffer(struct dma_rcv_ctx *d, int idx) +{ + struct ti_ohci *ohci = (struct ti_ohci*)(d->ohci); + DBGMSG(ohci->id, "Inserting dma buf ctx=%d idx=%d", d->ctx, idx); + + d->prg[idx]->status = d->buf_size; + d->prg[idx]->branchAddress &= 0xfffffff0; + idx = (idx + d->num_desc - 1 ) % d->num_desc; + d->prg[idx]->branchAddress |= 0x1; + + /* wake up the dma context if necessary */ + if (!(reg_read(ohci, d->ctrlSet) & 0x400)) { + PRINT(KERN_INFO, ohci->id, + "Waking dma cxt=%d ... processing is probably too slow", + d->ctx); + reg_write(ohci, d->ctrlSet, 0x1000); } +} - ohci->NumInterrupts++; +static int block_length(struct dma_rcv_ctx *d, int idx, + quadlet_t *buf_ptr, int offset) +{ + int length=0; + + /* Where is the data length ? */ + if (offset+12>=d->buf_size) + length = (d->buf[(idx+1)%d->num_desc] + [3-(d->buf_size-offset)/4]>>16); + else + length = (buf_ptr[3]>>16); + if (length % 4) length += 4 - (length % 4); + return length; } +static int packet_length(struct dma_rcv_ctx *d, int idx, + quadlet_t *buf_ptr, int offset) +{ + unsigned char tcode; + int length; + + /* Let's see what kind of packet is in there */ + tcode = (buf_ptr[0]>>4)&0xf; -/* This is the bottom half that processes async response receive descriptor buffers. */ -static void ohci_ar_resp_proc_desc(void *data) + if (d->ctx==0) { /* Async Receive Request */ + if (tcode==TCODE_READQ) return 16; + else if (tcode==TCODE_WRITEQ || + tcode==TCODE_READB) return 20; + else if (tcode==TCODE_WRITEB || + tcode==TCODE_LOCK_REQUEST) { + return block_length(d, idx, buf_ptr, offset) + 20; + } + else if (tcode==0xE) { /* Phy packet */ + return 16; + } + else return -1; + } + else if (d->ctx==1) { /* Async Receive Response */ + if (tcode==TCODE_WRITE_RESPONSE) return 16; + else if (tcode==TCODE_READQ_RESPONSE) return 20; + else if (tcode==TCODE_READB_RESPONSE || + tcode==TCODE_LOCK_RESPONSE) { + return block_length(d, idx, buf_ptr, offset) + 20; + } + else return -1; + } + else if (d->ctx==2) { /* Iso receive */ + /* Assumption: buffer fill mode with header/trailer */ + length = (buf_ptr[0]>>16); + if (length % 4) length += 4 - (length % 4); + return length+8; + } + return -1; +} + +/* Bottom half that processes dma receive buffers */ +static void dma_rcv_bh(void *data) { + struct dma_rcv_ctx *d = (struct dma_rcv_ctx*)data; + struct ti_ohci *ohci = (struct ti_ohci*)(d->ohci); + unsigned int split_left, idx, offset, rescount; + unsigned char tcode; + int length, bytes_left; quadlet_t *buf_ptr; char *split_ptr; - unsigned int split_left; - struct ti_ohci *ohci= (struct ti_ohci*)data; - unsigned int packet_length; - unsigned int idx,offset,tcode; - unsigned long flags; char msg[256]; - spin_lock_irqsave(&ohci->AR_resp_lock, flags); + spin_lock(&d->lock); - idx = ohci->AR_resp_buf_bh_ind; - offset = ohci->AR_resp_buf_bh_offset; + idx = d->buf_ind; + offset = d->buf_offset; + buf_ptr = d->buf[idx] + offset/4; - buf_ptr = ohci->AR_resp_buf[idx]; - buf_ptr += offset/4; + rescount = d->prg[idx]->status&0xffff; + bytes_left = d->buf_size - rescount - offset; - while(ohci->AR_resp_bytes_left > 0) { - - /* check to see if a fatal error occurred */ - if ((ohci->AR_resp_prg[idx]->status >> 16) & 0x800) { - sprintf(msg,"fatal async response receive error -- status is %d", - ohci->AR_resp_prg[idx]->status & 0x1F); - stop_ar_resp_context(ohci, msg); - spin_unlock_irqrestore(&ohci->AR_resp_lock, flags); - return; - } - - spin_unlock_irqrestore(&ohci->AR_resp_lock, flags); - - /* Let's see what kind of packet is in there */ + while (bytes_left>0) { tcode = (buf_ptr[0]>>4)&0xf; - if (tcode==2) /* no-data receive */ - packet_length=16; - else if (tcode==6) /* quadlet receive */ - packet_length=20; - else if (tcode==7) { /* block receive */ - /* Where is the data length ? */ - if (offset+12>=AR_RESP_BUF_SIZE) - packet_length=(ohci->AR_resp_buf[(idx+1)%AR_RESP_NUM_DESC] - [3-(AR_RESP_BUF_SIZE-offset)/4]>>16)+20; - else - packet_length=(buf_ptr[3]>>16)+20; - if (packet_length % 4) - packet_length += 4 - (packet_length % 4); - } - else /* something is wrong */ { - sprintf(msg,"unexpected packet tcode %d in async response receive buffer",tcode); - stop_ar_resp_context(ohci,msg); + length = packet_length(d, idx, buf_ptr, offset); + + if (length<4) { /* something is wrong */ + sprintf(msg,"unexpected tcode 0x%X in AR ctx=%d", + tcode, d->ctx); + stop_context(ohci, d->ctrlClear, msg); + spin_unlock(&d->lock); return; } - if ((offset+packet_length)>AR_RESP_BUF_SIZE) { - /* we have a split packet */ - if (packet_length>AR_RESP_SPLIT_PACKET_BUF_SIZE) { - sprintf(msg,"packet size %d bytes exceed split packet buffer size %d bytes", - packet_length,AR_RESP_SPLIT_PACKET_BUF_SIZE); - stop_ar_resp_context(ohci, msg); + + if ((offset+length)>d->buf_size) { /* Split packet */ + if (length>d->split_buf_size) { + stop_context(ohci, d->ctrlClear, + "split packet size exceeded"); + d->buf_ind = idx; + d->buf_offset = offset; + spin_unlock(&d->lock); return; } - split_left = packet_length; - split_ptr = (char *)ohci->AR_resp_spb; - while (split_left>0) { - memcpy(split_ptr,buf_ptr,AR_RESP_BUF_SIZE-offset); - split_left -= AR_RESP_BUF_SIZE-offset; - split_ptr += AR_RESP_BUF_SIZE-offset; - ohci->AR_resp_prg[idx]->status = AR_RESP_BUF_SIZE; - idx = (idx+1) % AR_RESP_NUM_DESC; - buf_ptr = ohci->AR_resp_buf[idx]; - offset=0; - while (split_left >= AR_RESP_BUF_SIZE) { - memcpy(split_ptr,buf_ptr,AR_RESP_BUF_SIZE); - split_ptr += AR_RESP_BUF_SIZE; - split_left -= AR_RESP_BUF_SIZE; - ohci->AR_resp_prg[idx]->status = AR_RESP_BUF_SIZE; - idx = (idx+1) % AR_RESP_NUM_DESC; - buf_ptr = ohci->AR_resp_buf[idx]; - } - if (split_left>0) { - memcpy(split_ptr,buf_ptr,split_left); - offset = split_left; - split_left=0; - buf_ptr += split_left/4; - } + if (d->prg[(idx+1)%d->num_desc]->status==d->buf_size) { + /* other part of packet not written yet */ + /* this should never happen I think */ + /* anyway we'll get it on the next call */ + PRINT(KERN_INFO, ohci->id, + "Got only half a packet !!!"); + d->buf_ind = idx; + d->buf_offset = offset; + spin_unlock(&d->lock); + return; } -#if 0 - PRINT(KERN_INFO,ohci->id,"AR resp: received split packet tcode=%d length=%d", - tcode,packet_length); -#endif - hpsb_packet_received(ohci->host, ohci->AR_resp_spb, packet_length); - ohci->AR_resp_bytes_left -= packet_length; + split_left = length; + split_ptr = (char *)d->spb; + memcpy(split_ptr,buf_ptr,d->buf_size-offset); + split_left -= d->buf_size-offset; + split_ptr += d->buf_size-offset; + insert_dma_buffer(d, idx); + idx = (idx+1) % d->num_desc; + buf_ptr = d->buf[idx]; + offset=0; + while (split_left >= d->buf_size) { + memcpy(split_ptr,buf_ptr,d->buf_size); + split_ptr += d->buf_size; + split_left -= d->buf_size; + insert_dma_buffer(d, idx); + idx = (idx+1) % d->num_desc; + buf_ptr = d->buf[idx]; + } + if (split_left>0) { + memcpy(split_ptr, buf_ptr, split_left); + offset = split_left; + buf_ptr += offset/4; + } + + /* + * We get one phy packet for each bus reset. + * we know that from now on the bus topology may + * have changed. Just ignore it for the moment + */ + if (tcode != 0xE) { + DBGMSG(ohci->id, "Split packet received from" + " node %d ack=0x%02X spd=%d tcode=0x%X" + " length=%d data=0x%08x ctx=%d", + (d->spb[1]>>16)&0x3f, + (d->spb[length/4-1]>>16)&0x1f, + (d->spb[length/4-1]>>21)&0x3, + tcode, length, d->spb[3], d->ctx); + hpsb_packet_received(ohci->host, d->spb, + length); + } + else + PRINT(KERN_INFO, ohci->id, + "Got phy packet ctx=%d ... discarded", + d->ctx); } else { -#if 0 - PRINT(KERN_INFO,ohci->id,"AR resp: received packet tcode=%d length=%d", - tcode,packet_length); -#endif - hpsb_packet_received(ohci->host, buf_ptr, packet_length); - offset += packet_length; - buf_ptr += packet_length/4; - ohci->AR_resp_bytes_left -= packet_length; - if (offset==AR_RESP_BUF_SIZE) { - ohci->AR_resp_prg[idx]->status = AR_RESP_BUF_SIZE; - idx = (idx+1) % AR_RESP_NUM_DESC; - buf_ptr = ohci->AR_resp_buf[idx]; + /* + * We get one phy packet for each bus reset. + * we know that from now on the bus topology may + * have changed. Just ignore it for the moment + */ + if (tcode != 0xE) { + DBGMSG(ohci->id, "Packet received from node" + " %d ack=0x%02X spd=%d tcode=0x%X" + " length=%d data=0x%08x ctx=%d", + (buf_ptr[1]>>16)&0x3f, + (buf_ptr[length/4-1]>>16)&0x1f, + (buf_ptr[length/4-1]>>21)&0x3, + tcode, length, buf_ptr[3], d->ctx); + hpsb_packet_received(ohci->host, buf_ptr, + length); + } + else + PRINT(KERN_INFO, ohci->id, + "Got phy packet ctx=%d ... discarded", + d->ctx); + offset += length; + buf_ptr += length/4; + if (offset==d->buf_size) { + insert_dma_buffer(d, idx); + idx = (idx+1) % d->num_desc; + buf_ptr = d->buf[idx]; offset=0; } } - + rescount = d->prg[idx]->status & 0xffff; + bytes_left = d->buf_size - rescount - offset; + } + + d->buf_ind = idx; + d->buf_offset = offset; + + spin_unlock(&d->lock); +} + +/* Bottom half that processes sent packets */ +static void dma_trm_bh(void *data) +{ + struct dma_trm_ctx *d = (struct dma_trm_ctx*)data; + struct ti_ohci *ohci = (struct ti_ohci*)(d->ohci); + struct hpsb_packet *packet; + u32 ack; + + spin_lock(&d->lock); + + if (d->first==NULL) { + stop_context(ohci, d->ctrlClear, + "Packet sent ack received but queue is empty"); + spin_unlock(&d->lock); + return; + } + packet = d->first; + d->first = d->first->xnext; + if (d->first==NULL) d->last=NULL; + if (packet->data_size) + ack = d->prg[d->sent_ind].end.status>>16; + else + ack = d->prg[d->sent_ind].begin.status>>16; + d->sent_ind = (d->sent_ind+1)%d->num_desc; + d->free_prgs++; + spin_unlock(&d->lock); - if (ohci->AR_resp_bytes_left<0) - stop_ar_resp_context(ohci, "Sync problem in AR resp dma buffer"); + DBGMSG(ohci->id, "Packet sent to node %d ack=0x%X spd=%d ctx=%d", + (packet->header[0]>>16)&0x3f, ack&0x1f, (ack>>5)&0x3, d->ctx); + hpsb_packet_sent(ohci->host, packet, ack&0xf); +} + +static int free_dma_rcv_ctx(struct dma_rcv_ctx *d) +{ + int i; - ohci->AR_resp_buf_bh_ind = idx; - ohci->AR_resp_buf_bh_offset = offset; + if (d==NULL) return -1; - spin_unlock_irqrestore(&ohci->AR_resp_lock, flags); + if (d->buf) { + for (i=0; inum_desc; i++) + if (d->buf[i]) kfree(d->buf[i]); + kfree(d->buf); + } + if (d->prg) { + for (i=0; inum_desc; i++) + if (d->prg[i]) kfree(d->prg[i]); + kfree(d->prg); + } + if (d->spb) kfree(d->spb); + + kfree(d); + + return 0; } -/* This is the bottom half that processes iso receive descriptor buffers. */ -static void ohci_ir_proc_desc(void *data) +static struct dma_rcv_ctx * +alloc_dma_rcv_ctx(struct ti_ohci *ohci, int ctx, int num_desc, + int buf_size, int split_buf_size, + int ctrlSet, int ctrlClear, int cmdPtr) { - quadlet_t *buf_ptr; - struct ti_ohci *ohci= (struct ti_ohci*)data; - int bytes_left, data_length; - unsigned int idx; - unsigned long flags; - - spin_lock_irqsave(&ohci->IR_recv_lock, flags); - - while(ohci->IR_buf_used > 0) - { - idx= ohci->IR_buf_last_ind; - - /* check to see if a fatal error occurred */ - if ((ohci->IR_recv_prg[idx]->status >> 16) & 0x800) { - int i= 0; - - /* stop the context */ - reg_write(ohci, OHCI1394_IrRcvContextControlClear, - 0x8000); - - while (reg_read(ohci, OHCI1394_IrRcvContextControlSet) - & 0x400) { - i++; - - if (i > 5000) { - PRINT(KERN_ERR, ohci->id, "runaway loop in DmaIR. bailing out..."); - break; - } + struct dma_rcv_ctx *d=NULL; + int i; - } + d = (struct dma_rcv_ctx *)kmalloc(sizeof(struct dma_rcv_ctx), + GFP_KERNEL); - spin_unlock_irqrestore(&ohci->IR_recv_lock, flags); - PRINT(KERN_ERR, ohci->id, - "fatal iso receive error -- status is %d", - ohci->IR_recv_prg[idx]->status & 0x1F); - return; - } + if (d==NULL) { + PRINT(KERN_ERR, ohci->id, "failed to allocate dma_rcv_ctx"); + return NULL; + } - spin_unlock_irqrestore(&ohci->IR_recv_lock, flags); + d->ohci = (void *)ohci; + d->ctx = ctx; - buf_ptr= bus_to_virt(ohci->IR_recv_prg[idx]->address); - bytes_left= IR_RECV_BUF_SIZE; + d->num_desc = num_desc; + d->buf_size = buf_size; + d->split_buf_size = split_buf_size; + d->ctrlSet = ctrlSet; + d->ctrlClear = ctrlClear; + d->cmdPtr = cmdPtr; - /* are we processing a split packet from last buffer */ - if (ohci->IR_sp_bytes_left) { + d->buf = NULL; + d->prg = NULL; + d->spb = NULL; - if (!ohci->IR_spb_bytes_used) { - /* packet is in process of being dropped */ - if (ohci->IR_sp_bytes_left > bytes_left) { - ohci->IR_sp_bytes_left-= bytes_left; - bytes_left= 0; - } else { - buf_ptr= bus_to_virt((unsigned long) - &((quadlet_t*)ohci->IR_recv_prg - [idx]->address) - [ohci->IR_sp_bytes_left / 4]); - bytes_left-= ohci->IR_sp_bytes_left; - ohci->IR_sp_bytes_left= 0; - } + d->buf = kmalloc(d->num_desc * sizeof(quadlet_t*), GFP_KERNEL); - } else { - /* packet is being assembled */ - if (ohci->IR_sp_bytes_left > bytes_left) { - memcpy(&ohci->IR_spb - [ohci->IR_spb_bytes_used / 4], - buf_ptr, bytes_left); - ohci->IR_spb_bytes_used+= bytes_left; - ohci->IR_sp_bytes_left-= bytes_left; - bytes_left= 0; - } else { - memcpy(&ohci->IR_spb - [ohci->IR_spb_bytes_used / 4], - buf_ptr, - ohci->IR_sp_bytes_left); - ohci->IR_spb_bytes_used+= - ohci->IR_sp_bytes_left; - hpsb_packet_received(ohci->host, - ohci->IR_spb, - ohci->IR_spb_bytes_used); - buf_ptr= - bus_to_virt((unsigned long) - &((quadlet_t*)ohci->IR_recv_prg - [idx]->address) - [ohci->IR_sp_bytes_left / 4]); - bytes_left-= ohci->IR_sp_bytes_left; - ohci->IR_sp_bytes_left= 0; - ohci->IR_spb_bytes_used= 0; - } + if (d->buf == NULL) { + PRINT(KERN_ERR, ohci->id, "failed to allocate dma buffer"); + free_dma_rcv_ctx(d); + return NULL; + } + memset(d->buf, 0, d->num_desc * sizeof(quadlet_t*)); - } + d->prg = kmalloc(d->num_desc * sizeof(struct dma_cmd*), GFP_KERNEL); - } + if (d->prg == NULL) { + PRINT(KERN_ERR, ohci->id, "failed to allocate dma prg"); + free_dma_rcv_ctx(d); + return NULL; + } + memset(d->prg, 0, d->num_desc * sizeof(struct dma_cmd*)); - while(bytes_left > 0) { - data_length= (int)((buf_ptr[0] >> 16) & 0xffff); + d->spb = kmalloc(d->split_buf_size, GFP_KERNEL); + + if (d->spb == NULL) { + PRINT(KERN_ERR, ohci->id, "failed to allocate split buffer"); + free_dma_rcv_ctx(d); + return NULL; + } - if (data_length % 4) - data_length+= 4 - (data_length % 4); + for (i=0; inum_desc; i++) { + d->buf[i] = kmalloc(d->buf_size, GFP_KERNEL); + + if (d->buf[i] != NULL) { + memset(d->buf[i], 0, d->buf_size); + } else { + PRINT(KERN_ERR, ohci->id, + "failed to allocate dma buffer"); + free_dma_rcv_ctx(d); + return NULL; + } - /* is this a split packet? */ - if ( (bytes_left - (data_length + 8)) < 0 ) { + d->prg[i]= kmalloc(sizeof(struct dma_cmd), GFP_KERNEL); - if ( (data_length + 8) <= - IR_SPLIT_PACKET_BUF_SIZE ) { - memcpy(ohci->IR_spb, buf_ptr, - bytes_left); - ohci->IR_spb_bytes_used= bytes_left; - } else { - PRINT(KERN_ERR, ohci->id, "Packet too large for split packet buffer... dropping it"); - PRINT(KERN_DEBUG, ohci->id, "Header: %8.8x\n", buf_ptr[0]); - ohci->IR_spb_bytes_used= 0; - } + if (d->prg[i] != NULL) { + memset(d->prg[i], 0, sizeof(struct dma_cmd)); + } else { + PRINT(KERN_ERR, ohci->id, + "failed to allocate dma prg"); + free_dma_rcv_ctx(d); + return NULL; + } + } - ohci->IR_sp_bytes_left= - (data_length + 8) - bytes_left; - } else { - hpsb_packet_received(ohci->host, buf_ptr, - (data_length + 8)); - buf_ptr= bus_to_virt((unsigned long) - &((quadlet_t*)ohci->IR_recv_prg - [idx]->address) - [(IR_RECV_BUF_SIZE - bytes_left - + data_length + 8) / 4]); - } + spin_lock_init(&d->lock); - bytes_left-= (data_length + 8); - } + /* initialize bottom handler */ + d->task.routine = dma_rcv_bh; + d->task.data = (void*)d; - spin_lock_irqsave(&ohci->IR_recv_lock, flags); - ohci->IR_buf_last_ind= (idx + 1) % IR_NUM_DESC; - ohci->IR_buf_used--; - } + return d; +} - spin_unlock_irqrestore(&ohci->IR_recv_lock, flags); +static int free_dma_trm_ctx(struct dma_trm_ctx *d) +{ + if (d==NULL) return -1; + if (d->prg) kfree(d->prg); + kfree(d); + return 0; } -static int add_card(struct pci_dev *dev) +static struct dma_trm_ctx * +alloc_dma_trm_ctx(struct ti_ohci *ohci, int ctx, int num_desc, + int ctrlSet, int ctrlClear, int cmdPtr) { -#define FAIL(fmt, args...) \ - PRINT_G(KERN_ERR, fmt , ## args); \ - num_of_cards--; \ - remove_card(ohci); \ - return 1; + struct dma_trm_ctx *d=NULL; + d = (struct dma_trm_ctx *)kmalloc(sizeof(struct dma_trm_ctx), + GFP_KERNEL); + + if (d==NULL) { + PRINT(KERN_ERR, ohci->id, "failed to allocate dma_trm_ctx"); + return NULL; + } + + d->ohci = (void *)ohci; + d->ctx = ctx; + d->num_desc = num_desc; + d->ctrlSet = ctrlSet; + d->ctrlClear = ctrlClear; + d->cmdPtr = cmdPtr; + d->prg = NULL; + + d->prg = kmalloc(d->num_desc * sizeof(struct at_dma_prg), GFP_KERNEL); + + if (d->prg == NULL) { + PRINT(KERN_ERR, ohci->id, "failed to allocate at dma prg"); + free_dma_trm_ctx(d); + return NULL; + } + memset(d->prg, 0, d->num_desc * sizeof(struct at_dma_prg)); + + spin_lock_init(&d->lock); + + /* initialize bottom handler */ + d->task.routine = dma_trm_bh; + d->task.data = (void*)d; + + return d; +} + +static int add_card(struct pci_dev *dev) +{ struct ti_ohci *ohci; /* shortcut to currently handled device */ - int i; if (num_of_cards == MAX_OHCI1394_CARDS) { PRINT_G(KERN_WARNING, "cannot handle more than %d cards. " @@ -1185,124 +1371,51 @@ FAIL("failed to allocate DMA buffer for self-id packets"); } - /* AR dma buffer and program allocation */ - ohci->AR_resp_buf= - kmalloc(AR_RESP_NUM_DESC * sizeof(quadlet_t*), - GFP_KERNEL); - - if (ohci->AR_resp_buf == NULL) { - FAIL("failed to allocate AR response receive DMA buffer"); - } - - ohci->AR_resp_prg= - kmalloc(AR_RESP_NUM_DESC * sizeof(struct dma_cmd*), - GFP_KERNEL); - - if (ohci->AR_resp_prg == NULL) { - FAIL("failed to allocate AR response receive DMA program"); - } - - ohci->AR_resp_spb= kmalloc(AR_RESP_SPLIT_PACKET_BUF_SIZE, GFP_KERNEL); - - if (ohci->AR_resp_spb == NULL) { - FAIL("failed to allocate AR response split packet buffer"); - } - - for (i= 0; i < AR_RESP_NUM_DESC; i++) { - ohci->AR_resp_buf[i]= kmalloc(AR_RESP_BUF_SIZE, GFP_KERNEL); - - if (ohci->AR_resp_buf[i] != NULL) { - memset(ohci->AR_resp_buf[i], 0, AR_RESP_BUF_SIZE); - } else { - FAIL("failed to allocate AR response DMA buffer"); - } - - ohci->AR_resp_prg[i]= kmalloc(sizeof(struct dma_cmd), - GFP_KERNEL); - - if (ohci->AR_resp_prg[i] != NULL) { - memset(ohci->AR_resp_prg[i], 0, - sizeof(struct dma_cmd)); - } else { - FAIL("failed to allocate AR response DMA buffer"); - } - - } - - ohci->AR_resp_buf_th_ind = 0; - ohci->AR_resp_buf_th_offset = 0; - ohci->AR_resp_buf_bh_ind = 0; - ohci->AR_resp_buf_bh_offset = 0; - ohci->AR_resp_bytes_left = 0; - spin_lock_init(&ohci->AR_resp_lock); - - /* initialize AR response receive task */ - ohci->AR_resp_pdl_task.routine= ohci_ar_resp_proc_desc; - ohci->AR_resp_pdl_task.data= (void*)ohci; - - /* AT dma program allocation */ - ohci->AT_req_prg = (struct dma_cmd *) kmalloc(AT_REQ_PRG_SIZE, - GFP_KERNEL); - if (ohci->AT_req_prg != NULL) { - memset(ohci->AT_req_prg, 0, AT_REQ_PRG_SIZE); - } else { - FAIL("failed to allocate AT request DMA program"); - } - - /* IR dma buffer and program allocation */ - ohci->IR_recv_buf= - kmalloc(IR_NUM_DESC * sizeof(quadlet_t*), - GFP_KERNEL); - - if (ohci->IR_recv_buf == NULL) { - FAIL("failed to allocate IR receive DMA buffer"); - } - - ohci->IR_recv_prg= - kmalloc(IR_NUM_DESC * sizeof(struct dma_cmd*), - GFP_KERNEL); - - if (ohci->IR_recv_prg == NULL) { - FAIL("failed to allocate IR receive DMA program"); - } - - ohci->IR_spb= kmalloc(IR_SPLIT_PACKET_BUF_SIZE, GFP_KERNEL); - - if (ohci->IR_spb == NULL) { - FAIL("failed to allocate IR split packet buffer"); - } - - for (i= 0; i < IR_NUM_DESC; i++) { - ohci->IR_recv_buf[i]= kmalloc(IR_RECV_BUF_SIZE, GFP_KERNEL); - - if (ohci->IR_recv_buf[i] != NULL) { - memset(ohci->IR_recv_buf[i], 0, IR_RECV_BUF_SIZE); - } else { - FAIL("failed to allocate IR DMA buffer"); - } + ohci->ar_req_context = + alloc_dma_rcv_ctx(ohci, 0, AR_REQ_NUM_DESC, + AR_REQ_BUF_SIZE, AR_REQ_SPLIT_BUF_SIZE, + OHCI1394_AsReqRcvContextControlSet, + OHCI1394_AsReqRcvContextControlClear, + OHCI1394_AsReqRcvCommandPtr); + + if (ohci->ar_req_context == NULL) return 1; + + ohci->ar_resp_context = + alloc_dma_rcv_ctx(ohci, 1, AR_RESP_NUM_DESC, + AR_RESP_BUF_SIZE, AR_RESP_SPLIT_BUF_SIZE, + OHCI1394_AsRspRcvContextControlSet, + OHCI1394_AsRspRcvContextControlClear, + OHCI1394_AsRspRcvCommandPtr); + + if (ohci->ar_resp_context == NULL) return 1; - ohci->IR_recv_prg[i]= kmalloc(sizeof(struct dma_cmd), - GFP_KERNEL); + ohci->at_req_context = + alloc_dma_trm_ctx(ohci, 0, AT_REQ_NUM_DESC, + OHCI1394_AsReqTrContextControlSet, + OHCI1394_AsReqTrContextControlClear, + OHCI1394_AsReqTrCommandPtr); + + if (ohci->at_req_context == NULL) return 1; - if (ohci->IR_recv_prg[i] != NULL) { - memset(ohci->IR_recv_prg[i], 0, - sizeof(struct dma_cmd)); - } else { - FAIL("failed to allocate IR DMA buffer"); - } + ohci->at_resp_context = + alloc_dma_trm_ctx(ohci, 1, AT_RESP_NUM_DESC, + OHCI1394_AsRspTrContextControlSet, + OHCI1394_AsRspTrContextControlClear, + OHCI1394_AsRspTrCommandPtr); + + if (ohci->at_resp_context == NULL) return 1; + + ohci->ir_context = + alloc_dma_rcv_ctx(ohci, 2, IR_NUM_DESC, + IR_BUF_SIZE, IR_SPLIT_BUF_SIZE, + OHCI1394_IrRcvContextControlSet, + OHCI1394_IrRcvContextControlClear, + OHCI1394_IrRcvCommandPtr); - } + if (ohci->ir_context == NULL) return 1; - ohci->IR_buf_used= 0; - ohci->IR_buf_last_ind= 0; - ohci->IR_buf_next_ind= 0; - spin_lock_init(&ohci->IR_recv_lock); - spin_lock_init(&ohci->IR_channel_lock); ohci->IR_channel_usage= 0x0000000000000000; - - /* initialize iso receive task */ - ohci->IR_pdl_task.routine= ohci_ir_proc_desc; - ohci->IR_pdl_task.data= (void*)ohci; + spin_lock_init(&ohci->IR_channel_lock); #if LINUX_VERSION_CODE < KERNEL_VERSION(2,3,13) ohci->registers = ioremap_nocache(dev->base_address[0], @@ -1342,6 +1455,8 @@ //unsigned char phyreg; //int i, nports; int i; + struct dma_rcv_ctx *d=NULL; + struct dma_trm_ctx *dt=NULL; p += sprintf(p,"IEEE-1394 OHCI Driver status report:\n"); p += sprintf(p," bus number: 0x%x Node ID: 0x%x\n", @@ -1370,22 +1485,93 @@ host->is_busmgr ? "bus_mgr" : ""); p += sprintf(p,"\n---Iso Receive DMA---\n"); - for (i= 0; i < IR_NUM_DESC; i++) { - p += sprintf(p, "IR_recv_buf[%d] : %p IR_recv_prg[%d]: %p\n", - i, ohci->IR_recv_buf[i], i, ohci->IR_recv_prg[i]); + d = ohci->ir_context; +#if 0 + for (i=0; inum_desc; i++) { + p += sprintf(p, "IR buf[%d] : %p prg[%d]: %p\n", + i, d->buf[i], i, d->prg[i]); } +#endif + p += sprintf(p, "Current buf: %d offset: %d\n", + d->buf_ind,d->buf_offset); + + p += sprintf(p,"\n---Async Receive DMA---\n"); + d = ohci->ar_req_context; +#if 0 + for (i=0; inum_desc; i++) { + p += sprintf(p, "AR req buf[%d] : %p prg[%d]: %p\n", + i, d->buf[i], i, d->prg[i]); + } +#endif + p += sprintf(p, "Ar req current buf: %d offset: %d\n", + d->buf_ind,d->buf_offset); + + d = ohci->ar_resp_context; +#if 0 + for (i=0; inum_desc; i++) { + p += sprintf(p, "AR resp buf[%d] : %p prg[%d]: %p\n", + i, d->buf[i], i, d->prg[i]); + } +#endif + p += sprintf(p, "AR resp current buf: %d offset: %d\n", + d->buf_ind,d->buf_offset); + + p += sprintf(p,"\n---Async Transmit DMA---\n"); + dt = ohci->at_req_context; + p += sprintf(p, "AT req prg: %d sent: %d free: %d branchAddrPtr: %p\n", + dt->prg_ind, dt->sent_ind, dt->free_prgs, + dt->branchAddrPtr); + p += sprintf(p, "AT req queue: first: %p last: %p\n", + dt->first, dt->last); + dt = ohci->at_resp_context; +#if 0 + for (i=0; inum_desc; i++) { + p += sprintf(p, "------- AT resp prg[%02d] ------\n",i); + p += sprintf(p, "%p: control : %08x\n", + &(dt->prg[i].begin.control), + dt->prg[i].begin.control); + p += sprintf(p, "%p: address : %08x\n", + &(dt->prg[i].begin.address), + dt->prg[i].begin.address); + p += sprintf(p, "%p: brancAddr: %08x\n", + &(dt->prg[i].begin.branchAddress), + dt->prg[i].begin.branchAddress); + p += sprintf(p, "%p: status : %08x\n", + &(dt->prg[i].begin.status), + dt->prg[i].begin.status); + p += sprintf(p, "%p: header[0]: %08x\n", + &(dt->prg[i].data[0]), + dt->prg[i].data[0]); + p += sprintf(p, "%p: header[1]: %08x\n", + &(dt->prg[i].data[1]), + dt->prg[i].data[1]); + p += sprintf(p, "%p: header[2]: %08x\n", + &(dt->prg[i].data[2]), + dt->prg[i].data[2]); + p += sprintf(p, "%p: header[3]: %08x\n", + &(dt->prg[i].data[3]), + dt->prg[i].data[3]); + p += sprintf(p, "%p: control : %08x\n", + &(dt->prg[i].end.control), + dt->prg[i].end.control); + p += sprintf(p, "%p: address : %08x\n", + &(dt->prg[i].end.address), + dt->prg[i].end.address); + p += sprintf(p, "%p: brancAddr: %08x\n", + &(dt->prg[i].end.branchAddress), + dt->prg[i].end.branchAddress); + p += sprintf(p, "%p: status : %08x\n", + &(dt->prg[i].end.status), + dt->prg[i].end.status); + } +#endif + p += sprintf(p, "AR resp prg: %d sent: %d free: %d" + " branchAddrPtr: %p\n", + dt->prg_ind, dt->sent_ind, dt->free_prgs, + dt->branchAddrPtr); + p += sprintf(p, "AT resp queue: first: %p last: %p\n", + dt->first, dt->last); - - p += sprintf(p,"\n---Async Reponse Receive DMA---\n"); - for (i= 0; i < AR_RESP_NUM_DESC; i++) { - p += sprintf(p, "AR_resp_buf[%d] : %p AR_resp_prg[%d]: %p\n", - i, ohci->AR_resp_buf[i], i, ohci->AR_resp_prg[i]); - } - p += sprintf(p, "Current AR resp buf in irq handler: %d offset: %d\n", - ohci->AR_resp_buf_th_ind,ohci->AR_resp_buf_th_offset); - p += sprintf(p, "Current AR resp buf in bottom half: %d offset: %d\n", - ohci->AR_resp_buf_bh_ind,ohci->AR_resp_buf_bh_offset); - /* ----- Register Dump ----- */ p += sprintf(p,"\n### HC Register dump ###\n"); SR("Version : %08x GUID_ROM : %08x ATRetries : %08x\n", @@ -1427,20 +1613,32 @@ SR("AsRsRvCtxCtl: %08x AsRsRvCmdPtr: %08x IntEvent : %08x\n", OHCI1394_AsRspRcvContextControlSet, OHCI1394_AsRspRcvCommandPtr, OHCI1394_IntEventSet); - + for (i=0;i<4;i++) { + p += sprintf(p,"IsoRCtxCtl%02d: %08x IsoRCmdPtr%02d: %08x" + " IsoRCxtMch%02d: %08x\n", i, + reg_read(ohci, + OHCI1394_IrRcvContextControlSet+32*i), + i,reg_read(ohci, OHCI1394_IrRcvCommandPtr+32*i), + i,reg_read(ohci, + OHCI1394_IrRcvContextMatch+32*i)); + } + #if 0 p += sprintf(p,"\n### Phy Register dump ###\n"); phyreg=get_phy_reg(ohci,1); - p += sprintf(p,"offset: %d val: 0x%02x -> RHB: %d IBR: %d Gap_count: %d\n", - 1,phyreg,(phyreg&0x80) != 0, (phyreg&0x40) !=0, phyreg&0x3f); + p += sprintf(p,"offset: %d val: 0x%02x -> RHB: %d" + "IBR: %d Gap_count: %d\n", + 1,phyreg,(phyreg&0x80) != 0, + (phyreg&0x40) !=0, phyreg&0x3f); phyreg=get_phy_reg(ohci,2); nports=phyreg&0x1f; - p += sprintf(p,"offset: %d val: 0x%02x -> SPD: %d E : %d Ports : %2d\n", - 2,phyreg, - (phyreg&0xC0)>>6, (phyreg&0x20) !=0, nports); + p += sprintf(p,"offset: %d val: 0x%02x -> SPD: %d" + " E : %d Ports : %2d\n", + 2,phyreg, (phyreg&0xC0)>>6, (phyreg&0x20) !=0, nports); for (i=0;i [port %d] TPA: %d TPB: %d | %s %s\n", + p += sprintf(p,"offset: %d val: 0x%02x -> [port %d]" + " TPA: %d TPB: %d | %s %s\n", 3+i,phyreg, i, (phyreg&0xC0)>>6, (phyreg&0x30)>>4, (phyreg&0x08) ? "child" : "parent", @@ -1454,11 +1652,6 @@ phyreg&0x3f); #endif -#if 0 - p += sprintf(p,"AR_resp_prg ctrl: %08x\n",ohci->AR_resp_prg->control); - p += sprintf(p,"AR_resp_prg status: %08x\n",ohci->AR_resp_prg->status); -#endif - return p - buf; } @@ -1494,53 +1687,26 @@ static void remove_card(struct ti_ohci *ohci) { if (ohci->registers) - iounmap(ohci->registers); + iounmap(ohci->registers); - /* Free AR response buffers and programs */ - if (ohci->AR_resp_buf) { - int i; - for (i= 0; i < AR_RESP_NUM_DESC; i++) { - kfree(ohci->AR_resp_buf[i]); - } - kfree(ohci->AR_resp_buf); - } - if (ohci->AR_resp_prg) { - int i; - for (i= 0; i < AR_RESP_NUM_DESC; i++) { - kfree(ohci->AR_resp_prg[i]); - } - kfree(ohci->AR_resp_prg); - } - kfree(ohci->AR_resp_spb); + /* Free AR dma */ + free_dma_rcv_ctx(ohci->ar_req_context); + free_dma_rcv_ctx(ohci->ar_resp_context); + + /* Free AT dma */ + free_dma_trm_ctx(ohci->at_req_context); + free_dma_trm_ctx(ohci->at_resp_context); - /* Free AT request buffer and program */ - if (ohci->AT_req_prg) - kfree(ohci->AT_req_prg); - - /* Free Iso receive buffers and programs */ - if (ohci->IR_recv_buf) { - int i; - for (i= 0; i < IR_NUM_DESC; i++) { - kfree(ohci->IR_recv_buf[i]); - } - kfree(ohci->IR_recv_buf); - } - if (ohci->IR_recv_prg) { - int i; - for (i= 0; i < IR_NUM_DESC; i++) { - kfree(ohci->IR_recv_prg[i]); - } - kfree(ohci->IR_recv_prg); - } - kfree(ohci->IR_spb); + /* Free IR dma */ + free_dma_rcv_ctx(ohci->ir_context); /* Free self-id buffer */ if (ohci->self_id_buffer) - kfree(ohci->self_id_buffer); + kfree(ohci->self_id_buffer); /* Free config rom */ if (ohci->csr_config_rom) - kfree(ohci->csr_config_rom); + kfree(ohci->csr_config_rom); /* Free the IRQ */ free_irq(ohci->dev->irq, ohci); @@ -1562,13 +1728,13 @@ PRINT_G(KERN_INFO, "looking for Ohci1394 cards"); for (i = 0; supported_chips[i][0] != -1; i++) { - while ((dev = pci_find_device(supported_chips[i][0], - supported_chips[i][1], dev)) - != NULL) { - if (add_card(dev) == 0) { - success = 1; + while ((dev = pci_find_device(supported_chips[i][0], + supported_chips[i][1], dev)) + != NULL) { + if (add_card(dev) == 0) { + success = 1; + } } - } } if (success == 0) { @@ -1593,10 +1759,8 @@ { struct ti_ohci *ohci=host->hostdata; -#if 0 - PRINT(KERN_INFO, ohci->id, "request csr_rom address: %08X", - (u32)ohci->csr_config_rom); -#endif + DBGMSG(ohci->id, "request csr_rom address: %08X", + (u32)ohci->csr_config_rom); *ptr = ohci->csr_config_rom; return sizeof(ohci_csr_rom); diff -u --recursive --new-file v2.3.46/linux/drivers/ieee1394/ohci1394.h linux/drivers/ieee1394/ohci1394.h --- v2.3.46/linux/drivers/ieee1394/ohci1394.h Tue Feb 1 01:35:43 2000 +++ linux/drivers/ieee1394/ohci1394.h Sun Feb 20 20:32:50 2000 @@ -4,6 +4,8 @@ #include "ieee1394_types.h" +#define OHCI1394_DEBUG 1 + #define OHCI1394_DRIVER_NAME "ohci1394" #ifndef PCI_DEVICE_ID_TI_OHCI1394 @@ -18,21 +20,34 @@ #define PCI_DEVICE_ID_VIA_OHCI1394 0x3044 #endif +#ifndef PCI_VENDOR_ID_SONY +#define PCI_VENDOR_ID_SONY 0x104d +#endif + +#ifndef PCI_DEVICE_ID_SONY_CXD3222 +#define PCI_DEVICE_ID_SONY_CXD3222 0x8039 +#endif + #define MAX_OHCI1394_CARDS 4 -#define OHCI1394_MAX_AT_REQ_RETRIES 1 -#define OHCI1394_MAX_AT_RESP_RETRIES 1 -#define OHCI1394_MAX_PHYS_RESP_RETRIES 4 +#define OHCI1394_MAX_AT_REQ_RETRIES 0x2 +#define OHCI1394_MAX_AT_RESP_RETRIES 0x2 +#define OHCI1394_MAX_PHYS_RESP_RETRIES 0x8 + +#define AR_REQ_NUM_DESC 4 /* number of AR req descriptors */ +#define AR_REQ_BUF_SIZE 4096 /* size of AR req buffers */ +#define AR_REQ_SPLIT_BUF_SIZE 4096 /* split packet buffer */ #define AR_RESP_NUM_DESC 4 /* number of AR resp descriptors */ #define AR_RESP_BUF_SIZE 4096 /* size of AR resp buffers */ -#define AR_RESP_SPLIT_PACKET_BUF_SIZE 256 /* split packet buffer */ -#define AR_RESP_TOTAL_BUF_SIZE (AR_RESP_BUF_SIZE * AR_RESP_NUM_DESC) -#define AT_REQ_PRG_SIZE 256 - -#define IR_RECV_BUF_SIZE 4096 /* 4096 bytes/buffer */ -#define IR_SPLIT_PACKET_BUF_SIZE 8192 /* size of buffer for split packets */ -#define IR_NUM_DESC 16 /* number of ISO recv descriptors */ +#define AR_RESP_SPLIT_BUF_SIZE 4096 /* split packet buffer */ + +#define IR_NUM_DESC 16 /* number of IR descriptors */ +#define IR_BUF_SIZE 6480 /* 6480 bytes/buffer */ +#define IR_SPLIT_BUF_SIZE 8192 /* split packet buffer */ + +#define AT_REQ_NUM_DESC 32 /* number of AT req descriptors */ +#define AT_RESP_NUM_DESC 32 /* number of AT resp descriptors */ struct dma_cmd { u32 control; @@ -41,6 +56,50 @@ u32 status; }; +struct at_dma_prg { + struct dma_cmd begin; + quadlet_t data[4]; + struct dma_cmd end; +}; + +/* DMA receive context */ +struct dma_rcv_ctx { + void *ohci; + int ctx; + unsigned int num_desc; + unsigned int buf_size; + unsigned int split_buf_size; + struct dma_cmd **prg; + quadlet_t **buf; + unsigned int buf_ind; + unsigned int buf_offset; + quadlet_t *spb; + spinlock_t lock; + struct tq_struct task; + int ctrlClear; + int ctrlSet; + int cmdPtr; +}; + +/* DMA transmit context */ +struct dma_trm_ctx { + void *ohci; + int ctx; + unsigned int num_desc; + struct at_dma_prg *prg; + unsigned int prg_ind; + unsigned int sent_ind; + int free_prgs; + quadlet_t *branchAddrPtr; + struct hpsb_packet *first; + struct hpsb_packet *last; + spinlock_t lock; + struct tq_struct task; + int ctrlClear; + int ctrlSet; + int cmdPtr; +}; + struct ti_ohci { int id; /* sequential card number */ @@ -54,42 +113,18 @@ quadlet_t *self_id_buffer; /* dma buffer for self-id packets */ quadlet_t *csr_config_rom; /* buffer for csr config rom */ - /* asynchronous receive */ - struct dma_cmd **AR_resp_prg; - quadlet_t **AR_resp_buf; - unsigned int AR_resp_buf_bh_ind; - unsigned int AR_resp_buf_bh_offset; - unsigned int AR_resp_buf_th_ind; - unsigned int AR_resp_buf_th_offset; - int AR_resp_bytes_left; - quadlet_t *AR_resp_spb; - spinlock_t AR_resp_lock; - - /* async receive task */ - struct tq_struct AR_resp_pdl_task; - - /* asynchronous transmit */ - struct dma_cmd *AT_req_prg; - - /* isochronous receive */ - struct dma_cmd **IR_recv_prg; - quadlet_t **IR_recv_buf; - unsigned int IR_buf_used; - unsigned int IR_buf_last_ind; - unsigned int IR_buf_next_ind; - spinlock_t IR_recv_lock; - - /* iso recv split packet handling */ - quadlet_t *IR_spb; - unsigned int IR_sp_bytes_left; - unsigned int IR_spb_bytes_used; + /* async receive */ + struct dma_rcv_ctx *ar_resp_context; + struct dma_rcv_ctx *ar_req_context; + + /* async transmit */ + struct dma_trm_ctx *at_resp_context; + struct dma_trm_ctx *at_req_context; - /* iso receive channel usage */ - spinlock_t IR_channel_lock; + /* iso receive */ + struct dma_rcv_ctx *ir_context; u64 IR_channel_usage; - - /* iso receive task */ - struct tq_struct IR_pdl_task; + spinlock_t IR_channel_lock; /* IEEE-1394 part follows */ struct hpsb_host *host; @@ -98,16 +133,9 @@ spinlock_t phy_reg_lock; - struct hpsb_packet *async_queue; - spinlock_t async_queue_lock; - - int AR_resp_active; int NumBusResets; - int TxRdy; - int NumInterrupts; }; - /* * Register read and write helper functions. */ @@ -129,9 +157,9 @@ /* bus info block */ 0x04040000, /* info/CRC length, CRC */ 0x31333934, /* 1394 magic number */ - 0xf064a000, /* misc. settings - FIXME */ - 0x08002856, /* vendor ID, chip ID high */ - 0x0000083E, /* chip ID low */ + 0xf07da002, /* cyc_clk_acc = 125us, max_rec = 1024 */ + 0x00000000, /* vendor ID, chip ID high (written from card info) */ + 0x00000000, /* chip ID low (written from card info) */ /* root directory - FIXME */ 0x00090000, /* CRC length, CRC */ 0x03080028, /* vendor ID (Texas Instr.) */ diff -u --recursive --new-file v2.3.46/linux/drivers/ieee1394/pcilynx.h linux/drivers/ieee1394/pcilynx.h --- v2.3.46/linux/drivers/ieee1394/pcilynx.h Fri Jan 21 18:19:16 2000 +++ linux/drivers/ieee1394/pcilynx.h Sun Feb 20 20:32:50 2000 @@ -348,8 +348,8 @@ struct { u32 control; u32 pointer; - } buffer[13]; -}; + } buffer[13] __attribute__ ((packed)); +} __attribute__ ((packed)); #include #define pcloffs(MEMBER) (offsetof(struct ti_pcl, MEMBER)) @@ -383,7 +383,11 @@ inline static u32 pcl_bus(const struct ti_lynx *lynx, pcl_t pclid) { +#if LINUX_VERSION_CODE < KERNEL_VERSION(2,3,13) + return lynx->dev->base_address[1] + pclid * sizeof(struct ti_pcl); +#else return lynx->dev->resource[1].start + pclid * sizeof(struct ti_pcl); +#endif } #else /* CONFIG_IEEE1394_PCILYNX_LOCALRAM */ diff -u --recursive --new-file v2.3.46/linux/drivers/ieee1394/raw1394.c linux/drivers/ieee1394/raw1394.c --- v2.3.46/linux/drivers/ieee1394/raw1394.c Tue Feb 1 01:35:43 2000 +++ linux/drivers/ieee1394/raw1394.c Sun Feb 20 20:32:50 2000 @@ -3,7 +3,7 @@ * * Raw interface to the bus * - * Copyright (C) 1999 Andreas E. Bombe + * Copyright (C) 1999, 2000 Andreas E. Bombe */ #include @@ -30,6 +30,9 @@ static struct hpsb_highlevel *hl_handle = NULL; +static atomic_t iso_buffer_size; +static const int iso_buffer_max = 4 * 1024 * 1024; /* 4 MB */ + static void queue_complete_cb(struct pending_request *req); static struct pending_request *__alloc_pending_request(int flags) @@ -56,6 +59,7 @@ { if (req->ibs) { if (atomic_dec_and_test(&req->ibs->refcount)) { + atomic_sub((req->data[0] >> 16) + 4, &iso_buffer_size); kfree(req->ibs); } } else if (req->free_data) { @@ -210,6 +214,10 @@ struct iso_block_store *ibs = NULL; LIST_HEAD(reqs); + if ((atomic_read(&iso_buffer_size) + length) > iso_buffer_max) { + return; + } + spin_lock_irqsave(&host_info_lock, flags); hi = find_host_info(host); @@ -227,6 +235,7 @@ + length, SLAB_ATOMIC); if (!ibs) break; + atomic_add(length, &iso_buffer_size); atomic_set(&ibs->refcount, 0); memcpy(ibs->data, data, length); } diff -u --recursive --new-file v2.3.46/linux/drivers/isdn/isdn_net.c linux/drivers/isdn/isdn_net.c --- v2.3.46/linux/drivers/isdn/isdn_net.c Wed Feb 16 17:03:52 2000 +++ linux/drivers/isdn/isdn_net.c Thu Feb 17 09:18:47 2000 @@ -483,7 +483,7 @@ * Instead I chose to add isdn_net_started() which gives the state of the * master in case of slaves. * I'm still not sure if this is how it's supposed to be done this way - * because it uses test_bit(LINK_STATE_START, &dev->state) which might be + * because it uses netif_running(dev) which might be * considered private to the network layer. However, it works for now. * Alternative: set a flag in _open() and clear it in _close() * @@ -506,7 +506,7 @@ dev = lp->master; else dev = &n->dev; - return test_bit(LINK_STATE_START, &dev->state); + return netif_running(dev); } /* diff -u --recursive --new-file v2.3.46/linux/drivers/net/3c505.c linux/drivers/net/3c505.c --- v2.3.46/linux/drivers/net/3c505.c Wed Feb 16 17:03:52 2000 +++ linux/drivers/net/3c505.c Thu Feb 17 09:18:47 2000 @@ -361,7 +361,8 @@ static inline void prime_rx(struct net_device *dev) { elp_device *adapter = dev->priv; - while (adapter->rx_active < ELP_RX_PCBS && test_bit(LINK_STATE_START, &dev->state)) { + while (adapter->rx_active < ELP_RX_PCBS && + netif_running(dev->state)) { if (!start_receive(dev, &adapter->itx_pcb)) break; } @@ -722,7 +723,7 @@ case 0xff: case CMD_RECEIVE_PACKET_COMPLETE: /* if the device isn't open, don't pass packets up the stack */ - if (test_bit(LINK_STATE_START, &dev->state) == 0) + if (!netif_running(dev)) break; len = adapter->irx_pcb.data.rcv_resp.pkt_len; dlen = adapter->irx_pcb.data.rcv_resp.buf_len; @@ -806,7 +807,7 @@ case CMD_TRANSMIT_PACKET_COMPLETE: if (elp_debug >= 3) printk("%s: interrupt - packet sent\n", dev->name); - if (test_bit(LINK_STATE_START, &dev->state) == 0) + if (!netif_running(dev)) break; switch (adapter->irx_pcb.data.xmit_resp.c_stat) { case 0xffff: @@ -1121,7 +1122,7 @@ /* If the device is closed, just return the latest stats we have, - we cannot ask from the adapter without interrupts */ - if (!test_bit(LINK_STATE_START, &dev->state)) + if (!netif_running(dev)) return &adapter->stats; /* send a get statistics command to the board */ diff -u --recursive --new-file v2.3.46/linux/drivers/net/3c507.c linux/drivers/net/3c507.c --- v2.3.46/linux/drivers/net/3c507.c Sat Feb 12 11:22:10 2000 +++ linux/drivers/net/3c507.c Thu Feb 17 09:18:47 2000 @@ -576,8 +576,7 @@ /* Acknowledge the interrupt sources. */ ack_cmd = status & 0xf000; - if ((status & 0x0700) != 0x0200 && - (test_bit(LINK_STATE_START, &dev->state))) { + if ((status & 0x0700) != 0x0200 && netif_running(dev)) { if (net_debug) printk("%s: Command unit stopped, status %04x, restarting.\n", dev->name, status); @@ -587,9 +586,7 @@ ack_cmd |= CUC_RESUME; } - if ((status & 0x0070) != 0x0040 && - (test_bit(LINK_STATE_START, &dev->state))) - { + if ((status & 0x0070) != 0x0040 && netif_running(dev)) { static void init_rx_bufs(struct net_device *); /* The Rx unit is not ready, it must be hung. Restart the receiver by initializing the rx buffers, and issuing an Rx start command. */ diff -u --recursive --new-file v2.3.46/linux/drivers/net/3c515.c linux/drivers/net/3c515.c --- v2.3.46/linux/drivers/net/3c515.c Sat Feb 12 11:22:10 2000 +++ linux/drivers/net/3c515.c Thu Feb 17 09:18:47 2000 @@ -1081,8 +1081,7 @@ other interrupt problems. */ if (donedidthis++ > 100) { printk(KERN_ERR "%s: Bogus interrupt, bailing. Status %4.4x, start=%d.\n", - dev->name, status, - test_bit(LINK_STATE_START, &dev->state)); + dev->name, status, netif_running(dev)); free_irq(dev->irq, dev); } } @@ -1426,7 +1425,7 @@ (struct corkscrew_private *) dev->priv; unsigned long flags; - if (test_bit(LINK_STATE_START, &dev->state)) { + if (netif_running(dev)) { save_flags(flags); cli(); update_stats(dev->base_addr, dev); diff -u --recursive --new-file v2.3.46/linux/drivers/net/3c523.c linux/drivers/net/3c523.c --- v2.3.46/linux/drivers/net/3c523.c Sat Feb 12 11:22:10 2000 +++ linux/drivers/net/3c523.c Thu Feb 17 09:18:47 2000 @@ -869,7 +869,7 @@ if (dev == NULL) { printk(KERN_ERR "elmc-interrupt: irq %d for unknown device.\n", (int) -(((struct pt_regs *) reg_ptr)->orig_eax + 2)); return; - } else if (!test_bit(LINK_STATE_START, &dev->state)) { + } else if (!netif_running(dev)) { /* The 3c523 has this habit of generating interrupts during the reset. I'm not sure if the ni52 has this same problem, but it's really annoying if we haven't finished initializing it. I was @@ -902,7 +902,7 @@ #ifndef NO_NOPCOMMANDS if (stat & STAT_CNA) { /* CU went 'not ready' */ - if (test_bit(LINK_STATE_START, &dev->state)) { + if (netif_running(dev->state)) { printk(KERN_WARNING "%s: oops! CU has left active state. stat: %04x/%04x.\n", dev->name, (int) stat, (int) p->scb->status); } } diff -u --recursive --new-file v2.3.46/linux/drivers/net/3c59x.c linux/drivers/net/3c59x.c --- v2.3.46/linux/drivers/net/3c59x.c Sun Feb 13 19:29:04 2000 +++ linux/drivers/net/3c59x.c Fri Feb 18 15:07:20 2000 @@ -1085,7 +1085,7 @@ break; /* Bad news! */ skb->dev = dev; /* Mark as being used by this device. */ skb_reserve(skb, 2); /* Align IP on 16 byte boundaries */ - vp->rx_ring[i].addr = cpu_to_le32(pci_map_single(vp->pdev, skb->tail, PKT_BUF_SZ)); + vp->rx_ring[i].addr = cpu_to_le32(pci_map_single(vp->pdev, skb->tail, PKT_BUF_SZ, PCI_DMA_FROMDEVICE)); } /* Wrap the ring. */ vp->rx_ring[i-1].next = cpu_to_le32(vp->rx_ring_dma); @@ -1407,7 +1407,7 @@ if (vp->bus_master) { /* Set the bus-master controller to transfer the packet. */ int len = (skb->len + 3) & ~3; - outl(vp->tx_skb_dma = pci_map_single(vp->pdev, skb->data, len), ioaddr + Wn7_MasterAddr); + outl(vp->tx_skb_dma = pci_map_single(vp->pdev, skb->data, len, PCI_DMA_TODEVICE), ioaddr + Wn7_MasterAddr); outw(len, ioaddr + Wn7_MasterLen); vp->tx_skb = skb; outw(StartDMADown, ioaddr + EL3_CMD); @@ -1479,7 +1479,7 @@ } vp->tx_skbuff[entry] = skb; vp->tx_ring[entry].next = 0; - vp->tx_ring[entry].addr = cpu_to_le32(pci_map_single(vp->pdev, skb->data, skb->len)); + vp->tx_ring[entry].addr = cpu_to_le32(pci_map_single(vp->pdev, skb->data, skb->len, PCI_DMA_TODEVICE)); vp->tx_ring[entry].length = cpu_to_le32(skb->len | LAST_FRAG); vp->tx_ring[entry].status = cpu_to_le32(skb->len | TxIntrUploaded); @@ -1559,7 +1559,7 @@ if (vp->tx_skbuff[entry]) { struct sk_buff *skb = vp->tx_skbuff[entry]; - pci_unmap_single(vp->pdev, le32_to_cpu(vp->tx_ring[entry].addr), skb->len); + pci_unmap_single(vp->pdev, le32_to_cpu(vp->tx_ring[entry].addr), skb->len, PCI_DMA_TODEVICE); dev_kfree_skb_irq(vp->tx_skbuff[entry]); vp->tx_skbuff[entry] = 0; } @@ -1576,7 +1576,7 @@ if (status & DMADone) { if (inw(ioaddr + Wn7_MasterStatus) & 0x1000) { outw(0x1000, ioaddr + Wn7_MasterStatus); /* Ack the event. */ - pci_unmap_single(vp->pdev, vp->tx_skb_dma, (vp->tx_skb->len + 3) & ~3); + pci_unmap_single(vp->pdev, vp->tx_skb_dma, (vp->tx_skb->len + 3) & ~3, PCI_DMA_TODEVICE); dev_kfree_skb_irq(vp->tx_skb); /* Release the transfered buffer */ if (inw(ioaddr + TxFree) > 1536) { netif_wake_queue(dev); @@ -1657,13 +1657,13 @@ if (vp->bus_master && ! (inw(ioaddr + Wn7_MasterStatus) & 0x8000)) { dma_addr_t dma = pci_map_single(vp->pdev, skb_put(skb, pkt_len), - pkt_len); + pkt_len, PCI_DMA_FROMDEVICE); outl(dma, ioaddr + Wn7_MasterAddr); outw((skb->len + 3) & ~3, ioaddr + Wn7_MasterLen); outw(StartDMAUp, ioaddr + EL3_CMD); while (inw(ioaddr + Wn7_MasterStatus) & 0x8000) ; - pci_unmap_single(vp->pdev, dma, pkt_len); + pci_unmap_single(vp->pdev, dma, pkt_len, PCI_DMA_FROMDEVICE); } else { insl(ioaddr + RX_FIFO, skb_put(skb, pkt_len), (pkt_len + 3) >> 2); @@ -1737,7 +1737,7 @@ && (skb = dev_alloc_skb(pkt_len + 2)) != 0) { skb->dev = dev; skb_reserve(skb, 2); /* Align IP on 16 byte boundaries */ - pci_dma_sync_single(vp->pdev, dma, PKT_BUF_SZ); + pci_dma_sync_single(vp->pdev, dma, PKT_BUF_SZ, PCI_DMA_FROMDEVICE); /* 'skb_put()' points to the start of sk_buff data area. */ memcpy(skb_put(skb, pkt_len), vp->rx_skbuff[entry]->tail, @@ -1748,7 +1748,7 @@ skb = vp->rx_skbuff[entry]; vp->rx_skbuff[entry] = NULL; skb_put(skb, pkt_len); - pci_unmap_single(vp->pdev, dma, PKT_BUF_SZ); + pci_unmap_single(vp->pdev, dma, PKT_BUF_SZ, PCI_DMA_FROMDEVICE); rx_nocopy++; } skb->protocol = eth_type_trans(skb, dev); @@ -1777,7 +1777,7 @@ break; /* Bad news! */ skb->dev = dev; /* Mark as being used by this device. */ skb_reserve(skb, 2); /* Align IP on 16 byte boundaries */ - vp->rx_ring[entry].addr = cpu_to_le32(pci_map_single(vp->pdev, skb->tail, PKT_BUF_SZ)); + vp->rx_ring[entry].addr = cpu_to_le32(pci_map_single(vp->pdev, skb->tail, PKT_BUF_SZ, PCI_DMA_FROMDEVICE)); vp->rx_skbuff[entry] = skb; } vp->rx_ring[entry].status = 0; /* Clear complete bit. */ @@ -1825,7 +1825,7 @@ outl(0, ioaddr + UpListPtr); for (i = 0; i < RX_RING_SIZE; i++) if (vp->rx_skbuff[i]) { - pci_unmap_single(vp->pdev, le32_to_cpu(vp->rx_ring[i].addr), PKT_BUF_SZ); + pci_unmap_single(vp->pdev, le32_to_cpu(vp->rx_ring[i].addr), PKT_BUF_SZ, PCI_DMA_FROMDEVICE); DEV_FREE_SKB(vp->rx_skbuff[i]); vp->rx_skbuff[i] = 0; } @@ -1836,7 +1836,7 @@ if (vp->tx_skbuff[i]) { struct sk_buff *skb = vp->tx_skbuff[i]; - pci_unmap_single(vp->pdev, le32_to_cpu(vp->tx_ring[i].addr), skb->len); + pci_unmap_single(vp->pdev, le32_to_cpu(vp->tx_ring[i].addr), skb->len, PCI_DMA_TODEVICE); DEV_FREE_SKB(skb); vp->tx_skbuff[i] = 0; } @@ -1852,7 +1852,7 @@ struct vortex_private *vp = (struct vortex_private *)dev->priv; unsigned long flags; - if (test_bit(LINK_STATE_START, &dev->state)) { + if (netif_running(dev)) { save_flags(flags); cli(); update_stats(dev->base_addr, dev); diff -u --recursive --new-file v2.3.46/linux/drivers/net/8139too.c linux/drivers/net/8139too.c --- v2.3.46/linux/drivers/net/8139too.c Wed Feb 16 17:03:52 2000 +++ linux/drivers/net/8139too.c Sun Feb 20 09:06:14 2000 @@ -87,7 +87,7 @@ #include -#define RTL8139_VERSION "0.9.2" +#define RTL8139_VERSION "0.9.3" #define RTL8139_MODULE_NAME "8139too" #define RTL8139_DRIVER_NAME RTL8139_MODULE_NAME " Fast Ethernet driver " RTL8139_VERSION #define PFX RTL8139_MODULE_NAME ": " @@ -154,7 +154,7 @@ HAS_LNK_CHNG = 0x040000, }; -#define RTL_IO_SIZE 256 +#define RTL_IO_SIZE 0x80 #define RTL8139_CAPS HAS_CHIP_XCVR|HAS_LNK_CHNG @@ -163,8 +163,6 @@ RTL8139_CB, SMC1211TX, /*MPX5030,*/ - SIS900, - SIS7016, DELTA8139, ADDTRON8139, } chip_t; @@ -178,8 +176,6 @@ { RTL8139_CB, "RealTek RTL8139B PCI/CardBus"}, { SMC1211TX, "SMC1211TX EZCard 10/100 (RealTek RTL8139)"}, /* { MPX5030, "Accton MPX5030 (RealTek RTL8139)"},*/ - { SIS900, "SiS 900 (RealTek RTL8139) Fast Ethernet"}, - { SIS7016, "SiS 7016 (RealTek RTL8139) Fast Ethernet"}, { DELTA8139, "Delta Electronics 8139 10/100BaseTX"}, { ADDTRON8139, "Addtron Technolgy 8139 10/100BaseTX"}, {0,}, @@ -191,8 +187,6 @@ {0x10ec, 0x8138, PCI_ANY_ID, PCI_ANY_ID, 0, 0, RTL8139_CB }, {0x1113, 0x1211, PCI_ANY_ID, PCI_ANY_ID, 0, 0, SMC1211TX }, /* {0x1113, 0x1211, PCI_ANY_ID, PCI_ANY_ID, 0, 0, MPX5030 },*/ - {0x1039, 0x0900, PCI_ANY_ID, PCI_ANY_ID, 0, 0, SIS900 }, - {0x1039, 0x7016, PCI_ANY_ID, PCI_ANY_ID, 0, 0, SIS7016 }, {0x1500, 0x1360, PCI_ANY_ID, PCI_ANY_ID, 0, 0, DELTA8139 }, {0x4033, 0x1360, PCI_ANY_ID, PCI_ANY_ID, 0, 0, ADDTRON8139 }, {0,}, @@ -1202,7 +1196,7 @@ tp->stats.tx_dropped++; } if (rp->mapping != 0) { - pci_unmap_single (tp->pci_dev, rp->mapping, rp->skb->len); + pci_unmap_single (tp->pci_dev, rp->mapping, rp->skb->len, PCI_DMA_TODEVICE); rp->mapping = 0; } } @@ -1258,7 +1252,7 @@ RTL_W32 (TxAddr0 + entry * 4, tp->tx_bufs_dma + (tp->tx_buf[entry] - tp->tx_bufs)); } else { tp->tx_info[entry].mapping = - pci_map_single(tp->pci_dev, skb->data, skb->len); + pci_map_single(tp->pci_dev, skb->data, skb->len, PCI_DMA_TODEVICE); assert (tp->tx_info[entry].mapping > 0); RTL_W32 (TxAddr0 + entry * 4, tp->tx_info[entry].mapping); @@ -1334,7 +1328,8 @@ if (tp->tx_info[entry].mapping != 0) { pci_unmap_single (tp->pci_dev, tp->tx_info[entry].mapping, - tp->tx_info[entry].skb->len); + tp->tx_info[entry].skb->len, + PCI_DMA_TODEVICE); tp->tx_info[entry].mapping = 0; } /* Free the original skb. */ @@ -1675,7 +1670,7 @@ if (skb) { if (mapping) - pci_unmap_single (tp->pci_dev, mapping, skb->len); + pci_unmap_single (tp->pci_dev, mapping, skb->len, PCI_DMA_TODEVICE); dev_kfree_skb (skb); } tp->tx_info[i].skb = NULL; @@ -1738,7 +1733,7 @@ assert (tp != NULL); - if (test_bit(LINK_STATE_START, &dev->state)) { + if (netif_running(dev)) { tp->stats.rx_missed_errors += RTL_R32 (RxMissed); RTL_W32 (RxMissed, 0); } @@ -1865,6 +1860,8 @@ printk (KERN_INFO RTL8139_DRIVER_NAME " loaded (%d device%s registered)\n", rc, rc > 1 ? "s" : ""); + } else { + pci_unregister_driver (&rtl8139_pci_driver); } DPRINTK ("EXIT\n"); diff -u --recursive --new-file v2.3.46/linux/drivers/net/82596.c linux/drivers/net/82596.c --- v2.3.46/linux/drivers/net/82596.c Sat Feb 12 11:22:10 2000 +++ linux/drivers/net/82596.c Thu Feb 17 09:18:47 2000 @@ -1251,7 +1251,7 @@ } if ((lp->cmd_head != (struct i596_cmd *) I596_NULL) && - (test_bit(LINK_STATE_START, &dev->state))) + netif_running(dev)) ack_cmd |= CUC_START; lp->scb.cmd = WSWAPcmd(lp->cmd_head); } @@ -1260,7 +1260,7 @@ printk("%s: i596 interrupt received a frame.\n", dev->name); /* Only RX_START if stopped - RGH 07-07-96 */ if (status & 0x1000) { - if (test_bit(LINK_STATE_START, &dev->state)) + if (netif_running(dev)) ack_cmd |= RX_START; if (i596_debug > 1) printk("%s: i596 interrupt receive unit inactive %x.\n", dev->name, status & 0x00f0); diff -u --recursive --new-file v2.3.46/linux/drivers/net/8390.c linux/drivers/net/8390.c --- v2.3.46/linux/drivers/net/8390.c Sat Feb 12 11:22:10 2000 +++ linux/drivers/net/8390.c Thu Feb 17 09:18:47 2000 @@ -167,7 +167,6 @@ NS8390_init(dev, 1); /* Set the flag before we drop the lock, That way the IRQ arrives after its set and we get no silly warnings */ - clear_bit(LINK_STATE_RXSEM, &dev->state); netif_start_queue(dev); spin_unlock_irqrestore(&ei_local->page_lock, flags); ei_local->irqlock = 0; @@ -203,8 +202,8 @@ * board has died and kick it. */ - if (test_bit(LINK_STATE_XOFF, &dev->state)) - { /* Do timeouts, just like the 8003 driver. */ + if (netif_queue_stopped(dev)) { + /* Do timeouts, just like the 8003 driver. */ int txsr; int isr; int tickssofar = jiffies - dev->trans_start; @@ -224,8 +223,7 @@ ei_local->stat.tx_errors++; isr = inb(e8390_base+EN0_ISR); - if (!test_bit(LINK_STATE_START, &dev->state)) - { + if (!netif_running(dev)) { spin_unlock_irqrestore(&ei_local->page_lock, flags); printk(KERN_WARNING "%s: xmit on stopped card\n", dev->name); return 1; @@ -430,8 +428,6 @@ return; } - set_bit(LINK_STATE_RXSEM, &dev->state); - /* Change to page 0 and read the intr status reg. */ outb_p(E8390_NODMA+E8390_PAGE0, e8390_base + E8390_CMD); if (ei_debug > 3) @@ -442,8 +438,7 @@ while ((interrupts = inb_p(e8390_base + EN0_ISR)) != 0 && ++nr_serviced < MAX_SERVICE) { - if (!test_bit(LINK_STATE_START, &dev->state)) - { + if (!netif_running(dev)) { printk(KERN_WARNING "%s: interrupt from stopped card\n", dev->name); interrupts = 0; break; @@ -491,7 +486,6 @@ outb_p(0xff, e8390_base + EN0_ISR); /* Ack. all intrs. */ } } - clear_bit(LINK_STATE_RXSEM, &dev->state); spin_unlock(&ei_local->page_lock); return; } @@ -837,7 +831,7 @@ unsigned long flags; /* If the card is stopped, just return the present stats. */ - if (!test_bit(LINK_STATE_START, &dev->state)) + if (!netif_running(dev)) return &ei_local->stat; spin_lock_irqsave(&ei_local->page_lock,flags); @@ -933,7 +927,7 @@ * Ultra32 EISA) appears to have this bug fixed. */ - if (test_bit(LINK_STATE_START, &dev->state)) + if (netif_running(dev)) outb_p(E8390_RXCONFIG, e8390_base + EN0_RXCR); outb_p(E8390_NODMA + E8390_PAGE1, e8390_base + E8390_CMD); for(i = 0; i < 8; i++) diff -u --recursive --new-file v2.3.46/linux/drivers/net/Config.in linux/drivers/net/Config.in --- v2.3.46/linux/drivers/net/Config.in Sun Feb 13 19:29:04 2000 +++ linux/drivers/net/Config.in Sun Feb 20 20:14:55 2000 @@ -136,8 +136,11 @@ if [ "$CONFIG_EXPERIMENTAL" = "y" ]; then tristate ' DM9102 PCI Fast Ethernet Adapter support (EXPERIMENTAL)' CONFIG_DM9102 fi - tristate ' EtherExpressPro/100 support' CONFIG_EEXPRESS_PRO100 + tristate ' EtherExpressPro/100 support' CONFIG_EEPRO100 if [ "$CONFIG_EXPERIMENTAL" = "y" ]; then + if [ "$CONFIG_EEPRO100" = "y" -o "$CONFIG_EEPRO100" = "m" ]; then + bool ' Enable Power Management (EXPERIMENTAL)' CONFIG_EEPRO100_PM + fi tristate ' Mylex EISA LNE390A/B support (EXPERIMENTAL)' CONFIG_LNE390 tristate ' Novell/Eagle/Microdyne NE3210 EISA support (EXPERIMENTAL)' CONFIG_NE3210 fi @@ -189,6 +192,7 @@ bool 'FDDI driver support' CONFIG_FDDI if [ "$CONFIG_FDDI" = "y" ]; then bool ' Digital DEFEA and DEFPA adapter support' CONFIG_DEFXX + tristate ' SysKonnect FDDI PCI support' CONFIG_SKFP fi if [ "$CONFIG_EXPERIMENTAL" = "y" ]; then diff -u --recursive --new-file v2.3.46/linux/drivers/net/Makefile linux/drivers/net/Makefile --- v2.3.46/linux/drivers/net/Makefile Sun Feb 13 19:29:04 2000 +++ linux/drivers/net/Makefile Sun Feb 20 20:14:55 2000 @@ -17,7 +17,8 @@ SUB_DIRS := MOD_SUB_DIRS := MOD_IN_SUB_DIRS := -ALL_SUB_DIRS := $(SUB_DIRS) fc hamradio irda pcmcia tokenring wan sk98lin arcnet +ALL_SUB_DIRS := $(SUB_DIRS) fc hamradio irda pcmcia tokenring wan sk98lin \ + arcnet skfp O_TARGET := net.o MOD_LIST_NAME := NET_MODULES @@ -119,7 +120,7 @@ obj-$(CONFIG_VORTEX) += 3c59x.o obj-$(CONFIG_NE2K_PCI) += ne2k-pci.o 8390.o obj-$(CONFIG_PCNET32) += pcnet32.o -obj-$(CONFIG_EEXPRESS_PRO100) += eepro100.o +obj-$(CONFIG_EEPRO100) += eepro100.o obj-$(CONFIG_TLAN) += tlan.o obj-$(CONFIG_TULIP) += tulip.o obj-$(CONFIG_EPIC100) += epic100.o @@ -134,6 +135,15 @@ else ifeq ($(CONFIG_SK98LIN),m) MOD_IN_SUB_DIRS += sk98lin + endif +endif + +ifeq ($(CONFIG_SKFP),y) + SUB_DIRS += skfp + obj-y += skfp/skfp.o +else + ifeq ($(CONFIG_SKFP),m) + MOD_IN_SUB_DIRS += skfp endif endif diff -u --recursive --new-file v2.3.46/linux/drivers/net/Space.c linux/drivers/net/Space.c --- v2.3.46/linux/drivers/net/Space.c Thu Feb 10 17:11:10 2000 +++ linux/drivers/net/Space.c Fri Feb 18 14:55:53 2000 @@ -120,6 +120,7 @@ /* FDDI adapters */ extern int dfx_probe(struct net_device *dev); extern int apfddi_init(struct net_device *dev); +extern int skfp_probe(struct net_device *dev); /* Fibre Channel adapters */ extern int iph5526_probe(struct net_device *dev); @@ -469,6 +470,9 @@ #endif #ifdef CONFIG_APFDDI && apfddi_init(dev) +#endif +#ifdef CONFIG_SKFP + && skfp_probe(dev) #endif && 1 ) { return 1; /* -ENODEV or -EAGAIN would be more accurate. */ diff -u --recursive --new-file v2.3.46/linux/drivers/net/a2065.c linux/drivers/net/a2065.c --- v2.3.46/linux/drivers/net/a2065.c Sun Feb 13 19:29:04 2000 +++ linux/drivers/net/a2065.c Thu Feb 17 09:18:47 2000 @@ -467,8 +467,7 @@ ll->rdp = LE_C0_STRT; } - if (test_bit(LINK_STATE_XOFF, &dev->state) && - TX_BUFFS_AVAIL > 0) + if (netif_queue_stopped(dev) && TX_BUFFS_AVAIL > 0) netif_wake_queue(dev); ll->rap = LE_CSR0; @@ -687,7 +686,7 @@ volatile struct lance_init_block *ib = lp->init_block; volatile struct lance_regs *ll = lp->ll; - if (!test_bit(LINK_STATE_START, &dev->state)) + if (!netif_running(dev)) return; if (lp->tx_old != lp->tx_new) { diff -u --recursive --new-file v2.3.46/linux/drivers/net/acenic.c linux/drivers/net/acenic.c --- v2.3.46/linux/drivers/net/acenic.c Sat Feb 12 11:22:10 2000 +++ linux/drivers/net/acenic.c Fri Feb 18 15:07:20 2000 @@ -27,6 +27,8 @@ * with 'testing the tx_ret_csm and setting tx_full' * David S. Miller : conversion to new PCI dma mapping * infrastructure and Sparc support + * Pierrick Pinasseau (CERN): For lending me an Ultra 5 to test the + * driver under Linux/Sparc64 */ #include @@ -59,6 +61,7 @@ #include #include + #ifdef CONFIG_ACENIC_OMIT_TIGON_I #define ACE_IS_TIGON_I(ap) 0 #else @@ -118,8 +121,8 @@ return virt_ptr; } #define pci_free_consistent(cookie, size, ptr, dma_ptr) kfree(ptr) -#define pci_map_single(cookie, address, size) virt_to_bus(address) -#define pci_unmap_single(cookie, address, size) +#define pci_map_single(cookie, address, size, dir) virt_to_bus(address) +#define pci_unmap_single(cookie, address, size, dir) #endif #if (LINUX_VERSION_CODE < 0x02032b) @@ -144,8 +147,8 @@ #else #define NET_BH 0 #define ace_mark_net_bh(foo) {do{} while(0);} -#define ace_if_busy(dev) test_bit(LINK_STATE_XOFF, &dev->state) -#define ace_if_running(dev) test_bit(LINK_STATE_START, &dev->state) +#define ace_if_busy(dev) netif_queue_stopped(dev) +#define ace_if_running(dev) netif_running(dev) #define ace_if_down(dev) {do{} while(0);} #endif @@ -334,10 +337,14 @@ #define ACE_JUMBO_BUFSIZE (ACE_JUMBO_MTU + ETH_HLEN + 2+4+16) #define DEF_TX_RATIO 24 -#define DEF_TX_COAL 1000 +/* + * There seems to be a magic difference in the effect between 995 and 996 + * but little difference between 900 and 995 ... no idea why. + */ +#define DEF_TX_COAL 996 #define DEF_TX_MAX_DESC 40 #define DEF_RX_COAL 1000 -#define DEF_RX_MAX_DESC 20 +#define DEF_RX_MAX_DESC 25 #define TX_COAL_INTS_ONLY 0 /* seems not worth it */ #define DEF_TRACE 0 #define DEF_STAT 2 * TICKS_PER_SEC @@ -352,7 +359,7 @@ static int dis_pci_mem_inval[8] = {1, 1, 1, 1, 1, 1, 1, 1}; static const char __initdata *version = - "acenic.c: v0.39 02/11/2000 Jes Sorensen, linux-acenic@SunSITE.auc.dk\n" + "acenic.c: v0.41 02/16/2000 Jes Sorensen, linux-acenic@SunSITE.auc.dk\n" " http://home.cern.ch/~jes/gige/acenic.html\n"; static struct net_device *root_dev = NULL; @@ -421,7 +428,6 @@ ap->pdev = pdev; dev->irq = pdev->irq; - dev->open = &ace_open; dev->hard_start_xmit = &ace_start_xmit; dev->stop = &ace_close; @@ -523,8 +529,12 @@ break; } ap->name [sizeof (ap->name) - 1] = '\0'; - printk("Gigabit Ethernet at 0x%08lx, irq %i\n", - dev->base_addr, dev->irq); + printk("Gigabit Ethernet at 0x%08lx, ", dev->base_addr); +#ifdef __sparc__ + printk("irq %s\n", __irq_itoa(dev->irq)); +#else + printk("irq %i\n", dev->irq); +#endif #ifdef CONFIG_ACENIC_OMIT_TIGON_I if ((readl(&ap->regs->HostCtrl) >> 28) == 4) { @@ -598,7 +608,7 @@ /* * This clears any pending interrupts */ - writel(0, ®s->Mb0Lo); + writel(1, ®s->Mb0Lo); /* * Make sure no other CPUs are processing interrupts @@ -622,7 +632,8 @@ ap->rx_std_ring[i].size = 0; ap->skb->rx_std_skbuff[i].skb = NULL; pci_unmap_single(ap->pdev, mapping, - ACE_STD_BUFSIZE - (2 + 16)); + ACE_STD_BUFSIZE - (2 + 16), + PCI_DMA_FROMDEVICE); dev_kfree_skb(skb); } } @@ -637,7 +648,8 @@ ap->rx_mini_ring[i].size = 0; ap->skb->rx_mini_skbuff[i].skb = NULL; pci_unmap_single(ap->pdev, mapping, - ACE_MINI_BUFSIZE - (2 + 16)); + ACE_MINI_BUFSIZE - (2 + 16), + PCI_DMA_FROMDEVICE); dev_kfree_skb(skb); } } @@ -652,7 +664,8 @@ ap->rx_jumbo_ring[i].size = 0; ap->skb->rx_jumbo_skbuff[i].skb = NULL; pci_unmap_single(ap->pdev, mapping, - ACE_JUMBO_BUFSIZE - (2 + 16)); + ACE_JUMBO_BUFSIZE - (2 + 16), + PCI_DMA_FROMDEVICE); dev_kfree_skb(skb); } } @@ -668,8 +681,8 @@ kfree(ap->skb); if (root_dev->irq) free_irq(root_dev->irq, root_dev); - iounmap(regs); unregister_netdev(root_dev); + iounmap(regs); kfree(root_dev); root_dev = next; @@ -677,20 +690,6 @@ } -#if (LINUX_VERSION_CODE < 0x02032b) -int init_module(void) -{ - return ace_module_init(); -} - - -void cleanup_module(void) -{ - ace_module_cleanup(); -} -#endif -#endif - int __init ace_module_init(void) { int cards; @@ -706,7 +705,22 @@ } -#if (LINUX_VERSION_CODE >= 0x02032b) +#if (LINUX_VERSION_CODE < 0x02032a) +int init_module(void) +{ + return ace_module_init(); +} + + +void cleanup_module(void) +{ + ace_module_cleanup(); +} +#endif +#endif + + +#if (LINUX_VERSION_CODE >= 0x02032a) module_init(ace_module_init); module_exit(ace_module_cleanup); #endif @@ -726,6 +740,7 @@ pci_free_consistent(ap->pdev, size, ap->rx_std_ring, ap->rx_ring_base_dma); + ap->rx_std_ring = NULL; ap->rx_jumbo_ring = NULL; ap->rx_mini_ring = NULL; ap->rx_return_ring = NULL; @@ -759,7 +774,7 @@ { struct ace_private *ap = dev->priv; int size; - + size = (sizeof(struct rx_desc) * (RX_STD_RING_ENTRIES + RX_JUMBO_RING_ENTRIES + @@ -843,7 +858,7 @@ * address the `Firmware not running' problem subsequent * to any crashes involving the NIC */ - writel(HW_RESET, ®s->HostCtrl); + writel(HW_RESET | (HW_RESET << 24), ®s->HostCtrl); wmb(); /* @@ -854,7 +869,7 @@ * This will most likely need BYTE_SWAP once we switch * to using __raw_writel() */ - writel(((WORD_SWAP | CLR_INT) | + writel((WORD_SWAP | CLR_INT | ((WORD_SWAP | CLR_INT) << 24)), ®s->HostCtrl); #else @@ -888,7 +903,7 @@ writel(readl(®s->CpuBCtrl) | CPU_HALT, ®s->CpuBCtrl); /* * The SRAM bank size does _not_ indicate the amount - * of memory on the card, it controls the bank size! + * of memory on the card, it controls the _bank_ size! * Ie. a 1MB AceNIC will have two banks of 512KB. */ writel(SRAM_BANK_512K, ®s->LocalCtrl); @@ -909,13 +924,14 @@ * value a second time works as well. This is what caused the * `Firmware not running' problem on the Tigon II. */ -#ifdef __LITTLE_ENDIAN - writel(ACE_BYTE_SWAP_DATA | ACE_WARN | ACE_FATAL | - ACE_WORD_SWAP | ACE_NO_JUMBO_FRAG, ®s->ModeStat); +#ifdef __BIG_ENDIAN + writel(ACE_BYTE_SWAP_DMA | ACE_WARN | ACE_FATAL | ACE_BYTE_SWAP_BD | + ACE_WORD_SWAP_BD | ACE_NO_JUMBO_FRAG, ®s->ModeStat); #else - writel(ACE_BYTE_SWAP_DATA | ACE_WARN | ACE_FATAL | ACE_BYTE_SWAP | - ACE_WORD_SWAP | ACE_NO_JUMBO_FRAG, ®s->ModeStat); + writel(ACE_BYTE_SWAP_DMA | ACE_WARN | ACE_FATAL | + ACE_WORD_SWAP_BD | ACE_NO_JUMBO_FRAG, ®s->ModeStat); #endif + mb(); mac1 = 0; for(i = 0; i < 4; i++) { @@ -1007,6 +1023,21 @@ } } } +#ifdef __sparc__ + /* On this platform, we know what the best dma settings + * are. We use 64-byte maximum bursts, because if we + * burst larger than the cache line size (or even cross + * a 64byte boundry in a single burst) the UltraSparc + * PCI controller will disconnect at 64-byte multiples. + * + * Read-multiple will be properly enabled above, and when + * set will give the PCI controller proper hints about + * prefetching. + */ + tmp = (tmp & ~(0xfc)); + tmp |= DMA_READ_MAX_64; + tmp |= DMA_WRITE_MAX_64; +#endif writel(tmp, ®s->PciState); /* @@ -1301,8 +1332,10 @@ */ myjif = jiffies + 3 * HZ; while (time_before(jiffies, myjif) && !ap->fw_running); + if (!ap->fw_running) { printk(KERN_ERR "%s: Firmware NOT running!\n", dev->name); + ace_dump_trace(ap); writel(readl(®s->CpuCtrl) | CPU_HALT, ®s->CpuCtrl); @@ -1344,6 +1377,8 @@ } return 0; init_error: + iounmap(ap->regs); + unregister_netdev(dev); if (ap->skb) { kfree(ap->skb); ap->skb = NULL; @@ -1460,7 +1495,8 @@ */ skb_reserve(skb, 2 + 16); mapping = pci_map_single(ap->pdev, skb->data, - ACE_STD_BUFSIZE - (2 + 16)); + ACE_STD_BUFSIZE - (2 + 16), + PCI_DMA_FROMDEVICE); ap->skb->rx_std_skbuff[idx].skb = skb; ap->skb->rx_std_skbuff[idx].mapping = mapping; @@ -1521,7 +1557,8 @@ */ skb_reserve(skb, 2 + 16); mapping = pci_map_single(ap->pdev, skb->data, - ACE_MINI_BUFSIZE - (2 + 16)); + ACE_MINI_BUFSIZE - (2 + 16), + PCI_DMA_FROMDEVICE); ap->skb->rx_mini_skbuff[idx].skb = skb; ap->skb->rx_mini_skbuff[idx].mapping = mapping; @@ -1579,7 +1616,8 @@ */ skb_reserve(skb, 2 + 16); mapping = pci_map_single(ap->pdev, skb->data, - ACE_JUMBO_BUFSIZE - (2 + 16)); + ACE_JUMBO_BUFSIZE - (2 + 16), + PCI_DMA_FROMDEVICE); ap->skb->rx_jumbo_skbuff[idx].skb = skb; ap->skb->rx_jumbo_skbuff[idx].mapping = mapping; @@ -1634,6 +1672,7 @@ printk(KERN_INFO "%s: Firmware up and running\n", dev->name); ap->fw_running = 1; + wmb(); break; case E_STATS_UPDATED: break; @@ -1756,8 +1795,7 @@ skb = rip->skb; rip->skb = NULL; - pci_unmap_single(ap->pdev, rip->mapping, mapsize); - rxdesc->size = 0; + pci_unmap_single(ap->pdev, rip->mapping, mapsize, PCI_DMA_FROMDEVICE); skb_put(skb, retdesc->size); #if 0 /* unncessary */ @@ -1864,7 +1902,7 @@ ap->stats.tx_packets++; ap->stats.tx_bytes += skb->len; - pci_unmap_single(ap->pdev, mapping, skb->len); + pci_unmap_single(ap->pdev, mapping, skb->len, PCI_DMA_TODEVICE); dev_kfree_skb_irq(skb); ap->skb->tx_skbuff[idx].skb = NULL; @@ -2105,7 +2143,7 @@ writel(0, &ap->tx_ring[i].addr.addrhi); writel(0, &ap->tx_ring[i].addr.addrlo); writel(0, &ap->tx_ring[i].flagsize); - pci_unmap_single(ap->pdev, mapping, skb->len); + pci_unmap_single(ap->pdev, mapping, skb->len, PCI_DMA_TODEVICE); dev_kfree_skb(skb); ap->skb->tx_skbuff[i].skb = NULL; } @@ -2155,7 +2193,7 @@ ap->skb->tx_skbuff[idx].skb = skb; ap->skb->tx_skbuff[idx].mapping = - pci_map_single(ap->pdev, skb->data, skb->len); + pci_map_single(ap->pdev, skb->data, skb->len, PCI_DMA_TODEVICE); addr = (unsigned long) ap->skb->tx_skbuff[idx].mapping; #if (BITS_PER_LONG == 64) writel(addr >> 32, &ap->tx_ring[idx].addr.addrhi); diff -u --recursive --new-file v2.3.46/linux/drivers/net/acenic.h linux/drivers/net/acenic.h --- v2.3.46/linux/drivers/net/acenic.h Sat Feb 12 11:22:10 2000 +++ linux/drivers/net/acenic.h Thu Feb 17 09:18:47 2000 @@ -245,10 +245,10 @@ * Mode status */ -#define ACE_BYTE_SWAP_DATA 0x10 +#define ACE_BYTE_SWAP_BD 0x02 +#define ACE_WORD_SWAP_BD 0x04 /* not actually used */ #define ACE_WARN 0x08 -#define ACE_WORD_SWAP 0x04 -#define ACE_BYTE_SWAP 0x02 +#define ACE_BYTE_SWAP_DMA 0x10 #define ACE_NO_JUMBO_FRAG 0x200 #define ACE_FATAL 0x40000000 @@ -298,7 +298,7 @@ #define EVT_RING_SIZE (EVT_RING_ENTRIES * sizeof(struct event)) struct event { -#ifdef __LITTLE_ENDIAN +#ifdef __LITTLE_ENDIAN_BITFIELD u32 idx:12; u32 code:12; u32 evt:8; @@ -344,7 +344,7 @@ #define CMD_RING_ENTRIES 64 struct cmd { -#ifdef __LITTLE_ENDIAN +#ifdef __LITTLE_ENDIAN_BITFIELD u32 idx:12; u32 code:12; u32 evt:8; @@ -594,7 +594,8 @@ { struct ace_skb *skb; struct ace_regs *regs; /* register base */ - int version, fw_running, fw_up, link; + volatile int fw_running; + int version, fw_up, link; int promisc, mcast_all; /* * The send ring is located in the shared memory window @@ -648,17 +649,19 @@ static inline void set_aceaddr(aceaddr *aa, dma_addr_t addr) { + unsigned long baddr = (unsigned long) addr; #if (BITS_PER_LONG == 64) - aa->addrlo = addr & 0xffffffff; - aa->addrhi = addr >> 32; + aa->addrlo = baddr & 0xffffffff; + aa->addrhi = baddr >> 32; #else - /* Don't bother setting zero every time */ - aa->addrlo = addr; + /* Don't bother setting zero every time */ + aa->addrlo = baddr; #endif mb(); } +#if 0 static inline void *get_aceaddr(aceaddr *aa) { unsigned long addr; @@ -668,21 +671,9 @@ #else addr = aa->addrlo; #endif - return bus_to_virt(addr); -} - - -static inline void *get_aceaddr_bus(aceaddr *aa) -{ - unsigned long addr; - mb(); -#if (BITS_PER_LONG == 64) - addr = (u64)aa->addrhi << 32 | aa->addrlo; -#else - addr = aa->addrlo; -#endif return (void *)addr; } +#endif static inline void ace_set_txprd(struct ace_regs *regs, diff -u --recursive --new-file v2.3.46/linux/drivers/net/arcnet/arcnet.c linux/drivers/net/arcnet/arcnet.c --- v2.3.46/linux/drivers/net/arcnet/arcnet.c Sun Feb 13 19:29:04 2000 +++ linux/drivers/net/arcnet/arcnet.c Thu Feb 17 09:18:47 2000 @@ -723,7 +723,7 @@ * RESET flag was enabled - if device is not running, we must clear it right * away (but nothing else). */ - if (!test_bit(LINK_STATE_START, &dev->state)) { + if (!netif_running(dev)) { if (ASTATUS() & RESETflag) ACOMMAND(CFLAGScmd | RESETclear); AINTMASK(0); diff -u --recursive --new-file v2.3.46/linux/drivers/net/cs89x0.c linux/drivers/net/cs89x0.c --- v2.3.46/linux/drivers/net/cs89x0.c Sat Feb 12 11:22:10 2000 +++ linux/drivers/net/cs89x0.c Thu Feb 17 09:18:47 2000 @@ -941,7 +941,7 @@ static int set_mac_address(struct net_device *dev, void *addr) { int i; - if (test_bit(LINK_STATE_START, &dev->state)) + if (netif_running(dev)) return -EBUSY; printk("%s: Setting MAC address to ", dev->name); for (i = 0; i < 6; i++) diff -u --recursive --new-file v2.3.46/linux/drivers/net/de4x5.c linux/drivers/net/de4x5.c --- v2.3.46/linux/drivers/net/de4x5.c Sun Feb 13 19:29:04 2000 +++ linux/drivers/net/de4x5.c Fri Feb 18 15:07:20 2000 @@ -1561,15 +1561,14 @@ return -1; /* Transmit descriptor ring full or stale skb */ - if (test_bit(LINK_STATE_XOFF, &dev->state) || - (u_long) lp->tx_skb[lp->tx_new] > 1) { + if (netif_queue_stopped(dev) || (u_long) lp->tx_skb[lp->tx_new] > 1) { if (lp->interrupt) { de4x5_putb_cache(dev, skb); /* Requeue the buffer */ } else { de4x5_put_cache(dev, skb); } if (de4x5_debug & DEBUG_TX) { - printk("%s: transmit busy, lost media or stale skb found:\n STS:%08x\n tbusy:%d\n IMR:%08x\n OMR:%08x\n Stale skb: %s\n",dev->name, inl(DE4X5_STS), test_bit(LINK_STATE_XOFF, &dev->state), inl(DE4X5_IMR), inl(DE4X5_OMR), ((u_long) lp->tx_skb[lp->tx_new] > 1) ? "YES" : "NO"); + printk("%s: transmit busy, lost media or stale skb found:\n STS:%08x\n tbusy:%d\n IMR:%08x\n OMR:%08x\n Stale skb: %s\n",dev->name, inl(DE4X5_STS), netif_queue_stopped(dev), inl(DE4X5_IMR), inl(DE4X5_OMR), ((u_long) lp->tx_skb[lp->tx_new] > 1) ? "YES" : "NO"); } } else if (skb->len > 0) { /* If we already have stuff queued locally, use that first */ @@ -1578,7 +1577,8 @@ skb = de4x5_get_cache(dev); } - while (skb && !test_bit(LINK_STATE_XOFF, &dev->state) && (u_long) lp->tx_skb[lp->tx_new] <= 1) { + while (skb && !netif_queue_stopped(dev) && + (u_long) lp->tx_skb[lp->tx_new] <= 1) { spin_lock_irqsave(&lp->lock, flags); netif_stop_queue(dev); load_packet(dev, skb->data, TD_IC | TD_LS | TD_FS | skb->len, skb); @@ -1666,7 +1666,7 @@ /* Load the TX ring with any locally stored packets */ if (!test_and_set_bit(0, (void *)&lp->cache.lock)) { - while (lp->cache.skb && !test_bit(LINK_STATE_XOFF, &dev->state) && lp->tx_enable) { + while (lp->cache.skb && !netif_queue_stopped(dev) && lp->tx_enable) { de4x5_queue_pkt(de4x5_get_cache(dev), dev); } lp->cache.lock = 0; @@ -1759,7 +1759,8 @@ de4x5_free_tx_buff(struct de4x5_private *lp, int entry) { pci_unmap_single(lp->pdev, le32_to_cpu(lp->tx_ring[entry].buf), - le32_to_cpu(lp->tx_ring[entry].des1) & TD_TBS1); + le32_to_cpu(lp->tx_ring[entry].des1) & TD_TBS1, + PCI_DMA_TODEVICE); if ((u_long) lp->tx_skb[entry] > 1) dev_kfree_skb_irq(lp->tx_skb[entry]); lp->tx_skb[entry] = NULL; @@ -1810,7 +1811,7 @@ } /* Any resources available? */ - if (TX_BUFFS_AVAIL && test_bit(LINK_STATE_XOFF, &dev->state)) { + if (TX_BUFFS_AVAIL && netif_queue_stopped(dev)) { if (lp->interrupt) netif_wake_queue(dev); else @@ -1980,7 +1981,7 @@ { struct de4x5_private *lp = (struct de4x5_private *)dev->priv; int entry = (lp->tx_new ? lp->tx_new-1 : lp->txRingSize-1); - dma_addr_t buf_dma = pci_map_single(lp->pdev, buf, flags & TD_TBS1); + dma_addr_t buf_dma = pci_map_single(lp->pdev, buf, flags & TD_TBS1, PCI_DMA_TODEVICE); lp->tx_ring[lp->tx_new].buf = cpu_to_le32(buf_dma); lp->tx_ring[lp->tx_new].des1 &= cpu_to_le32(TD_TER); @@ -5606,18 +5607,19 @@ case DE4X5_SET_HWADDR: /* Set the hardware address */ if (!capable(CAP_NET_ADMIN)) return -EPERM; if (copy_from_user(tmp.addr, ioc->data, ETH_ALEN)) return -EFAULT; + if (netif_queue_stopped(dev)) + return -EBUSY; + netif_stop_queue(dev); for (i=0; idev_addr[i] = tmp.addr[i]; } build_setup_frame(dev, PHYS_ADDR_ONLY); /* Set up the descriptor and give ownership to the card */ - while (test_and_set_bit(LINK_STATE_XOFF, &dev->state) != 0) - barrier(); load_packet(dev, lp->setup_frame, TD_IC | PERFECT_F | TD_SET | SETUP_FRAME_LEN, (struct sk_buff *)1); lp->tx_new = (++lp->tx_new) % lp->txRingSize; outl(POLL_DEMAND, DE4X5_TPD); /* Start the TX */ - netif_start_queue(dev); /* Unlock the TX ring */ + netif_wake_queue(dev); /* Unlock the TX ring */ break; case DE4X5_SET_PROM: /* Set Promiscuous Mode */ @@ -5769,7 +5771,7 @@ } tmp.addr[j++] = lp->txRingSize; - tmp.addr[j++] = test_bit(LINK_STATE_XOFF, &dev->state); + tmp.addr[j++] = netif_queue_stopped(dev); ioc->len = j; if (copy_to_user(ioc->data, tmp.addr, ioc->len)) return -EFAULT; diff -u --recursive --new-file v2.3.46/linux/drivers/net/de600.c linux/drivers/net/de600.c --- v2.3.46/linux/drivers/net/de600.c Sat Feb 12 11:22:10 2000 +++ linux/drivers/net/de600.c Thu Feb 17 09:18:47 2000 @@ -368,7 +368,7 @@ de600_put_command(0); select_prn(); - if (test_bit(LINK_STATE_START, &dev->state)) { /* perhaps not needed? */ + if (netif_running(dev)) { /* perhaps not needed? */ free_irq(DE600_IRQ, dev); MOD_DEC_USE_COUNT; } diff -u --recursive --new-file v2.3.46/linux/drivers/net/depca.c linux/drivers/net/depca.c --- v2.3.46/linux/drivers/net/depca.c Sat Feb 12 11:22:10 2000 +++ linux/drivers/net/depca.c Thu Feb 17 09:18:47 2000 @@ -905,7 +905,8 @@ if (csr0 & TINT) /* Tx interrupt (packet sent) */ depca_tx (dev); - if ((TX_BUFFS_AVAIL >= 0) && (test_bit (LINK_STATE_XOFF, &dev->flags))) { /* any resources available? */ + /* Any resources available? */ + if ((TX_BUFFS_AVAIL >= 0) && netif_queue_stopped(dev)) { netif_wake_queue (dev); /* Unmask the DEPCA board interrupts and turn off the LED */ diff -u --recursive --new-file v2.3.46/linux/drivers/net/eepro.c linux/drivers/net/eepro.c --- v2.3.46/linux/drivers/net/eepro.c Sat Feb 12 11:22:10 2000 +++ linux/drivers/net/eepro.c Thu Feb 17 09:18:47 2000 @@ -1409,7 +1409,7 @@ lp->tx_last = last; lp->tx_end = end; - if (test_bit(LINK_STATE_XOFF, &dev->flags)) + if (netif_queue_stopped(dev)) netif_wake_queue(dev); /* Enable RX and TX interrupts */ diff -u --recursive --new-file v2.3.46/linux/drivers/net/eepro100.c linux/drivers/net/eepro100.c --- v2.3.46/linux/drivers/net/eepro100.c Wed Feb 16 17:03:52 2000 +++ linux/drivers/net/eepro100.c Sun Feb 20 20:14:55 2000 @@ -188,10 +188,8 @@ /* 'options' is used to pass a transceiver override or full-duplex flag e.g. "options=16" for FD, "options=32" for 100mbps-only. */ -#if MODULE_SETUP_FIXED static int full_duplex[] = {-1, -1, -1, -1, -1, -1, -1, -1}; static int options[] = {-1, -1, -1, -1, -1, -1, -1, -1}; -#endif static int debug = -1; /* The debug level */ /* A few values that may be tweaked. */ @@ -214,7 +212,8 @@ #error You must compile this driver with "-O". #endif -#include + +#include #include #include #include @@ -237,12 +236,8 @@ MODULE_AUTHOR("Donald Becker "); MODULE_DESCRIPTION("Intel i82557/i82558 PCI EtherExpressPro driver"); MODULE_PARM(debug, "i"); - -#if MODULE_OPTIONS_FIXED MODULE_PARM(options, "1-" __MODULE_STRING(8) "i"); MODULE_PARM(full_duplex, "1-" __MODULE_STRING(8) "i"); -#endif - MODULE_PARM(congenb, "i"); MODULE_PARM(txfifo, "i"); MODULE_PARM(rxfifo, "i"); @@ -257,6 +252,21 @@ #define RUN_AT(x) (jiffies + (x)) +/* ACPI power states don't universally work (yet) */ +#ifndef CONFIG_EEPRO100_PM +#undef pci_set_power_state +#define pci_set_power_state null_set_power_state +static inline int null_set_power_state(struct pci_dev *dev, int state) +{ + return 0; +} +#endif /* CONFIG_EEPRO100_PM */ + + +/* compile-time switch to en/disable slow PIO */ +#undef USE_IO + + int speedo_debug = 1; @@ -522,6 +532,7 @@ u16 eeprom[0x100]; int acpi_idle_state = 0, pm, irq; unsigned long ioaddr; + static int card_idx = -1; static int did_version = 0; /* Already printed version info. */ @@ -531,6 +542,8 @@ ioaddr = pci_resource_start (pdev, 1); #endif irq = pdev->irq; + + card_idx++; if (!request_region (pci_resource_start (pdev, 1), pci_resource_len (pdev, 1), @@ -578,10 +591,8 @@ if (dev->mem_start > 0) option = dev->mem_start; -#if MODULE_SETUP_FIXED else if (card_idx >= 0 && options[card_idx] >= 0) option = options[card_idx]; -#endif else option = 0; @@ -735,12 +746,10 @@ sp->full_duplex = option >= 0 && (option & 0x10) ? 1 : 0; -#if MODULE_SETUP_FIXED if (card_idx >= 0) { if (full_duplex[card_idx] >= 0) sp->full_duplex = full_duplex[card_idx]; } -#endif sp->default_port = option >= 0 ? (option & 0x0f) : 0; @@ -773,8 +782,8 @@ err_out_iounmap: #ifndef USE_IO iounmap ((void *)ioaddr); -#endif err_out_free_mmio_region: +#endif release_mem_region (pci_resource_start (pdev, 0), pci_resource_len (pdev, 0)); err_out_free_pio_region: @@ -903,7 +912,6 @@ /* Fire up the hardware. */ speedo_resume(dev); - clear_bit(LINK_STATE_RXSEM, &dev->state); netif_start_queue(dev); /* Setup the chip and configure the multicast list. */ @@ -1093,7 +1101,7 @@ rxf = (struct RxFD *)skb->tail; sp->rx_ringp[i] = rxf; sp->rx_ring_dma[i] = - pci_map_single(sp->pdev, rxf, PKT_BUF_SZ + sizeof(struct RxFD)); + pci_map_single(sp->pdev, rxf, PKT_BUF_SZ + sizeof(struct RxFD), PCI_DMA_FROMDEVICE); skb_reserve(skb, sizeof(struct RxFD)); if (last_rxf) last_rxf->link = cpu_to_le32(sp->rx_ring_dma[i]); @@ -1194,7 +1202,7 @@ sp->tx_ring[entry].count = cpu_to_le32(sp->tx_threshold); sp->tx_ring[entry].tx_buf_addr0 = cpu_to_le32(pci_map_single(sp->pdev, skb->data, - skb->len)); + skb->len, PCI_DMA_TODEVICE)); sp->tx_ring[entry].tx_buf_size0 = cpu_to_le32(skb->len); /* Todo: perhaps leave the interrupt bit set if the Tx queue is more than half full. Argument against: we should be receiving packets @@ -1289,19 +1297,18 @@ /* Free the original skb. */ if (sp->tx_skbuff[entry]) { sp->stats.tx_packets++; /* Count only user packets. */ -#if LINUX_VERSION_CODE > 0x20127 sp->stats.tx_bytes += sp->tx_skbuff[entry]->len; -#endif pci_unmap_single(sp->pdev, le32_to_cpu(sp->tx_ring[entry].tx_buf_addr0), - sp->tx_skbuff[entry]->len); + sp->tx_skbuff[entry]->len, PCI_DMA_TODEVICE); dev_kfree_skb_irq(sp->tx_skbuff[entry]); sp->tx_skbuff[entry] = 0; } else if ((status & 0x70000) == CmdNOp) { if (sp->mc_setup_busy) pci_unmap_single(sp->pdev, sp->mc_setup_dma, - sp->mc_setup_frm_len); + sp->mc_setup_frm_len, + PCI_DMA_TODEVICE); sp->mc_setup_busy = 0; } dirty_tx++; @@ -1386,7 +1393,7 @@ skb_reserve(skb, 2); /* Align IP on 16 byte boundaries */ /* 'skb_put()' points to the start of sk_buff data area. */ pci_dma_sync_single(sp->pdev, sp->rx_ring_dma[entry], - PKT_BUF_SZ + sizeof(struct RxFD)); + PKT_BUF_SZ + sizeof(struct RxFD), PCI_DMA_FROMDEVICE); #if 1 || USE_IP_CSUM /* Packet is in one chunk -- we can copy + cksum. */ eth_copy_and_sum(skb, sp->rx_skbuff[entry]->tail, pkt_len, 0); @@ -1408,14 +1415,12 @@ temp = skb_put(skb, pkt_len); sp->rx_ringp[entry] = NULL; pci_unmap_single(sp->pdev, sp->rx_ring_dma[entry], - PKT_BUF_SZ + sizeof(struct RxFD)); + PKT_BUF_SZ + sizeof(struct RxFD), PCI_DMA_FROMDEVICE); } skb->protocol = eth_type_trans(skb, dev); netif_rx(skb); sp->stats.rx_packets++; -#if LINUX_VERSION_CODE > 0x20127 sp->stats.rx_bytes += pkt_len; -#endif } entry = (++sp->cur_rx) % RX_RING_SIZE; } @@ -1436,7 +1441,7 @@ rxf = sp->rx_ringp[entry] = (struct RxFD *)skb->tail; sp->rx_ring_dma[entry] = pci_map_single(sp->pdev, rxf, PKT_BUF_SZ - + sizeof(struct RxFD)); + + sizeof(struct RxFD), PCI_DMA_FROMDEVICE); skb->dev = dev; skb_reserve(skb, sizeof(struct RxFD)); rxf->rx_buf_addr = 0xffffffff; @@ -1485,10 +1490,7 @@ if (skb) { pci_unmap_single(sp->pdev, sp->rx_ring_dma[i], - PKT_BUF_SZ + sizeof(struct RxFD)); -#if LINUX_VERSION_CODE < 0x20100 - skb->free = 1; -#endif + PKT_BUF_SZ + sizeof(struct RxFD), PCI_DMA_FROMDEVICE); dev_kfree_skb(skb); } } @@ -1501,7 +1503,7 @@ if (skb) { pci_unmap_single(sp->pdev, le32_to_cpu(sp->tx_ring[i].tx_buf_addr0), - skb->len); + skb->len, PCI_DMA_TODEVICE); dev_kfree_skb(skb); } } @@ -1554,7 +1556,7 @@ sp->stats.rx_fifo_errors += le32_to_cpu(sp->lstats->rx_overrun_errs); sp->stats.rx_length_errors += le32_to_cpu(sp->lstats->rx_runt_errs); sp->lstats->done_marker = 0x0000; - if (test_bit(LINK_STATE_START, &dev->state)) { + if (netif_running(dev)) { wait_for_cmd_done(ioaddr + SCBCmd); outw(CUDumpStats, ioaddr + SCBCmd); } @@ -1746,7 +1748,7 @@ /* Change the command to a NoOp, pointing to the CmdMulti command. */ sp->tx_skbuff[entry] = 0; sp->tx_ring[entry].status = cpu_to_le32(CmdNOp); - sp->mc_setup_dma = pci_map_single(sp->pdev, mc_setup_frm, sp->mc_setup_frm_len); + sp->mc_setup_dma = pci_map_single(sp->pdev, mc_setup_frm, sp->mc_setup_frm_len, PCI_DMA_TODEVICE); sp->tx_ring[entry].link = cpu_to_le32(sp->mc_setup_dma); /* Set the link in the setup frame. */ @@ -1773,7 +1775,7 @@ struct net_device *dev = pdev->driver_data; long ioaddr = dev->base_addr; - netif_stop_queue (dev); + netif_device_detach(dev); outl(PortPartialReset, ioaddr + SCBPort); /* XXX call pci_set_power_state ()? */ @@ -1785,6 +1787,7 @@ struct net_device *dev = pdev->driver_data; struct speedo_private *np = (struct speedo_private *)dev->priv; + netif_device_attach(dev); speedo_resume(dev); np->rx_mode = -1; np->flow_ctrl = np->partner = 0; @@ -1810,6 +1813,10 @@ pci_set_power_state (pdev, sp->acpi_pwr); + pci_free_consistent(pdev, TX_RING_SIZE * sizeof(struct TxFD) + + sizeof(struct speedo_stats), + sp->tx_ring, sp->tx_ring_dma); + kfree (dev); } @@ -1846,6 +1853,7 @@ cards_found = pci_register_driver (&eepro100_driver); if (cards_found <= 0) { printk(KERN_INFO PFX "No cards found, driver not installed.\n"); + pci_unregister_driver (&eepro100_driver); return -ENODEV; } diff -u --recursive --new-file v2.3.46/linux/drivers/net/eexpress.c linux/drivers/net/eexpress.c --- v2.3.46/linux/drivers/net/eexpress.c Sat Feb 12 11:22:10 2000 +++ linux/drivers/net/eexpress.c Thu Feb 17 09:18:47 2000 @@ -543,7 +543,7 @@ else { unsigned short txstatus = eexp_hw_lasttxstat(dev); - if (test_bit(LINK_STATE_XOFF, &dev->state) && !txstatus) + if (netif_queue_stopped(dev) && !txstatus) { printk(KERN_WARNING "%s: CU wedged, status %04x %04x, resetting...\n", dev->name,status,txstatus); @@ -1204,7 +1204,7 @@ unsigned short tx_block = lp->tx_reap; unsigned short status; - if (!test_bit(LINK_STATE_XOFF, &dev->state) && lp->tx_head==lp->tx_reap) + if (!netif_queue_stopped(dev) && lp->tx_head==lp->tx_reap) return 0x0000; do diff -u --recursive --new-file v2.3.46/linux/drivers/net/epic100.c linux/drivers/net/epic100.c --- v2.3.46/linux/drivers/net/epic100.c Wed Feb 16 17:03:52 2000 +++ linux/drivers/net/epic100.c Sun Feb 20 09:06:14 2000 @@ -775,7 +775,7 @@ #endif if (ep->tx_full && - test_bit(LINK_STATE_XOFF, &dev->flags) && + netif_queue_stopped(dev) && dirty_tx > ep->cur_tx - TX_RING_SIZE + 2) { /* The ring is no longer full, clear tbusy. */ ep->tx_full = 0; @@ -970,7 +970,7 @@ struct epic_private *ep = (struct epic_private *)dev->priv; long ioaddr = dev->base_addr; - if (test_bit(LINK_STATE_START, &dev->state)) { + if (netif_running(dev)) { /* Update the error counts. */ ep->stats.rx_missed_errors += inb(ioaddr + MPCNT); ep->stats.rx_frame_errors += inb(ioaddr + ALICNT); @@ -1058,12 +1058,12 @@ data[0] = ((struct epic_private *)dev->priv)->phys[0] & 0x1f; /* Fall Through */ case SIOCDEVPRIVATE+1: /* Read the specified MII register. */ - if (! test_bit(LINK_STATE_START, &dev->state)) { + if (! netif_running(dev)) { outl(0x0200, ioaddr + GENCTL); outl((inl(ioaddr + NVCTL) & ~0x003C) | 0x4800, ioaddr + NVCTL); } data[3] = mdio_read(ioaddr, data[0] & 0x1f, data[1] & 0x1f); - if (! test_bit(LINK_STATE_START, &dev->state)) { + if (! netif_running(dev)) { #ifdef notdef outl(0x0008, ioaddr + GENCTL); outl((inl(ioaddr + NVCTL) & ~0x483C) | 0x0000, ioaddr + NVCTL); @@ -1073,12 +1073,12 @@ case SIOCDEVPRIVATE+2: /* Write the specified MII register */ if (!suser()) return -EPERM; - if (! test_bit(LINK_STATE_START, &dev->state)) { + if (! netif_running(dev)) { outl(0x0200, ioaddr + GENCTL); outl((inl(ioaddr + NVCTL) & ~0x003C) | 0x4800, ioaddr + NVCTL); } mdio_write(ioaddr, data[0] & 0x1f, data[1] & 0x1f, data[2]); - if (! test_bit(LINK_STATE_START, &dev->state)) { + if (! netif_running(dev)) { #ifdef notdef outl(0x0008, ioaddr + GENCTL); outl((inl(ioaddr + NVCTL) & ~0x483C) | 0x0000, ioaddr + NVCTL); @@ -1285,6 +1285,7 @@ if (pci_register_driver (&epic100_driver) > 0) return 0; + pci_unregister_driver (&epic100_driver); return -ENODEV; } diff -u --recursive --new-file v2.3.46/linux/drivers/net/hamradio/6pack.c linux/drivers/net/hamradio/6pack.c --- v2.3.46/linux/drivers/net/hamradio/6pack.c Wed Feb 16 17:03:52 2000 +++ linux/drivers/net/hamradio/6pack.c Thu Feb 17 09:18:47 2000 @@ -283,7 +283,8 @@ struct sixpack *sp = (struct sixpack *) tty->disc_data; /* First make sure we're connected. */ - if (!sp || sp->magic != SIXPACK_MAGIC || !test_bit(LINK_STATE_START, &sp->dev->state)) { + if (!sp || sp->magic != SIXPACK_MAGIC || + !netif_running(sp->dev)) { return; } @@ -477,7 +478,8 @@ struct sixpack *sp = (struct sixpack *) tty->disc_data; - if (!sp || sp->magic != SIXPACK_MAGIC || !test_bit(LINK_STATE_START, &sp->dev->state) || !count) + if (!sp || sp->magic != SIXPACK_MAGIC || + !netif_running(sp->dev) || !count) return; save_flags(flags); @@ -750,7 +752,7 @@ * VSV = if dev->start==0, then device * unregistered while close proc. */ - if (test_bit(LINK_STATE_START, &sixpack_ctrls[i]->dev.state)) + if (netif_running(sixpack_ctrls[i]->dev)) unregister_netdev(&(sixpack_ctrls[i]->dev)); kfree(sixpack_ctrls[i]); diff -u --recursive --new-file v2.3.46/linux/drivers/net/hamradio/baycom_epp.c linux/drivers/net/hamradio/baycom_epp.c --- v2.3.46/linux/drivers/net/hamradio/baycom_epp.c Sat Feb 12 11:22:10 2000 +++ linux/drivers/net/hamradio/baycom_epp.c Thu Feb 17 09:18:47 2000 @@ -1275,7 +1275,7 @@ break; case HDLCDRVCTL_SETMODEMPAR: - if ((!suser()) || test_bit(LINK_STATE_START, &dev->state)) + if ((!suser()) || netif_running(dev)) return -EACCES; dev->base_addr = hi.data.mp.iobase; dev->irq = /*hi.data.mp.irq*/0; @@ -1314,7 +1314,7 @@ break; case HDLCDRVCTL_SETMODE: - if (!suser() || test_bit(LINK_STATE_START, &dev->state)) + if (!suser() || netif_running(dev)) return -EACCES; hi.data.modename[sizeof(hi.data.modename)-1] = '\0'; return baycom_setmode(bc, hi.data.modename); diff -u --recursive --new-file v2.3.46/linux/drivers/net/hamradio/baycom_par.c linux/drivers/net/hamradio/baycom_par.c --- v2.3.46/linux/drivers/net/hamradio/baycom_par.c Sat Feb 12 11:22:10 2000 +++ linux/drivers/net/hamradio/baycom_par.c Thu Feb 17 09:18:47 2000 @@ -445,7 +445,7 @@ return 0; case HDLCDRVCTL_SETMODE: - if (test_bit(LINK_STATE_START, &dev->state) || !suser()) + if (netif_running(dev) || !suser()) return -EACCES; hi->data.modename[sizeof(hi->data.modename)-1] = '\0'; return baycom_setmode(bc, hi->data.modename); diff -u --recursive --new-file v2.3.46/linux/drivers/net/hamradio/baycom_ser_fdx.c linux/drivers/net/hamradio/baycom_ser_fdx.c --- v2.3.46/linux/drivers/net/hamradio/baycom_ser_fdx.c Sat Feb 12 11:22:10 2000 +++ linux/drivers/net/hamradio/baycom_ser_fdx.c Thu Feb 17 09:18:47 2000 @@ -555,7 +555,7 @@ return 0; case HDLCDRVCTL_SETMODE: - if (test_bit(LINK_STATE_START, &dev->state) || !suser()) + if (netif_running(dev) || !suser()) return -EACCES; hi->data.modename[sizeof(hi->data.modename)-1] = '\0'; return baycom_setmode(bc, hi->data.modename); diff -u --recursive --new-file v2.3.46/linux/drivers/net/hamradio/baycom_ser_hdx.c linux/drivers/net/hamradio/baycom_ser_hdx.c --- v2.3.46/linux/drivers/net/hamradio/baycom_ser_hdx.c Sat Feb 12 11:22:10 2000 +++ linux/drivers/net/hamradio/baycom_ser_hdx.c Thu Feb 17 09:18:47 2000 @@ -598,7 +598,7 @@ return 0; case HDLCDRVCTL_SETMODE: - if (test_bit(LINK_STATE_START, &dev->state) || !suser()) + if (netif_running(dev) || !suser()) return -EACCES; hi->data.modename[sizeof(hi->data.modename)-1] = '\0'; return baycom_setmode(bc, hi->data.modename); diff -u --recursive --new-file v2.3.46/linux/drivers/net/hamradio/bpqether.c linux/drivers/net/hamradio/bpqether.c --- v2.3.46/linux/drivers/net/hamradio/bpqether.c Wed Feb 16 17:03:52 2000 +++ linux/drivers/net/hamradio/bpqether.c Thu Feb 17 09:18:47 2000 @@ -222,7 +222,7 @@ dev = bpq_get_ax25_dev(dev); - if (dev == NULL || !test_bit(LINK_STATE_START, &dev->state)) { + if (dev == NULL || !netif_running(dev)) { kfree_skb(skb); return 0; } @@ -275,8 +275,7 @@ * Just to be *really* sure not to send anything if the interface * is down, the ethernet device may have gone. */ - if (!test_bit(LINK_STATE_START, &dev->state)) - { + if (!netif_running(dev)) { bpq_check_devices(dev); kfree_skb(skb); return -ENODEV; diff -u --recursive --new-file v2.3.46/linux/drivers/net/hamradio/dmascc.c linux/drivers/net/hamradio/dmascc.c --- v2.3.46/linux/drivers/net/hamradio/dmascc.c Sun Feb 13 19:29:04 2000 +++ linux/drivers/net/hamradio/dmascc.c Thu Feb 17 09:18:47 2000 @@ -784,7 +784,7 @@ case SIOCSSCCPARAM: if (!capable(CAP_NET_ADMIN)) return -EPERM; - if (test_bit(LINK_STATE_START, &dev->state)) + if (netif_running(dev)) return -EAGAIN; if(copy_from_user(&priv->param, ifr->ifr_data, sizeof(struct scc_param))) return -EFAULT; diff -u --recursive --new-file v2.3.46/linux/drivers/net/hamradio/hdlcdrv.c linux/drivers/net/hamradio/hdlcdrv.c --- v2.3.46/linux/drivers/net/hamradio/hdlcdrv.c Wed Feb 16 17:03:52 2000 +++ linux/drivers/net/hamradio/hdlcdrv.c Thu Feb 17 09:18:47 2000 @@ -656,7 +656,7 @@ break; case HDLCDRVCTL_SETMODEMPAR: - if ((!suser()) || test_bit(LINK_STATE_START, &dev->state)) + if ((!suser()) || netif_running(dev)) return -EACCES; dev->base_addr = bi.data.mp.iobase; dev->irq = bi.data.mp.irq; diff -u --recursive --new-file v2.3.46/linux/drivers/net/hamradio/soundmodem/sm.c linux/drivers/net/hamradio/soundmodem/sm.c --- v2.3.46/linux/drivers/net/hamradio/soundmodem/sm.c Sat Feb 12 11:22:10 2000 +++ linux/drivers/net/hamradio/soundmodem/sm.c Thu Feb 17 09:18:47 2000 @@ -509,7 +509,7 @@ return 0; case HDLCDRVCTL_SETMODE: - if (test_bit(LINK_STATE_START, &dev->state) || !suser()) + if (netif_running(dev) || !suser()) return -EACCES; hi->data.modename[sizeof(hi->data.modename)-1] = '\0'; return sethw(dev, sm, hi->data.modename); diff -u --recursive --new-file v2.3.46/linux/drivers/net/hamradio/yam.c linux/drivers/net/hamradio/yam.c --- v2.3.46/linux/drivers/net/hamradio/yam.c Sun Feb 13 19:29:04 2000 +++ linux/drivers/net/hamradio/yam.c Thu Feb 17 09:18:47 2000 @@ -649,7 +649,7 @@ for (i = 0; i < NR_PORTS; i++) { struct net_device *dev = &yam_ports[i].dev; - if (test_bit(LINK_STATE_START, &dev->state)) + if (netif_running(dev)) yam_arbitrate(dev); } yam_timer.expires = jiffies + HZ / 100; @@ -748,7 +748,7 @@ yp = &yam_ports[i]; dev = &yp->dev; - if (!test_bit(LINK_STATE_START, &dev->state)) + if (!netif_running(dev)) continue; while ((iir = IIR_MASK & inb(IIR(dev->base_addr))) != IIR_NOPEND) { @@ -794,7 +794,7 @@ if (yam_ports[i].iobase == 0 || yam_ports[i].irq == 0) continue; len += sprintf(buffer + len, "Device %s\n", yam_ports[i].name); - len += sprintf(buffer + len, " Up %d\n", test_bit(LINK_STATE_START, &yam_ports[i].dev.state)); + len += sprintf(buffer + len, " Up %d\n", netif_running(&yam_ports[i].dev)); len += sprintf(buffer + len, " Speed %u\n", yam_ports[i].bitrate); len += sprintf(buffer + len, " IoBase 0x%x\n", yam_ports[i].iobase); len += sprintf(buffer + len, " BaudRate %u\n", yam_ports[i].baudrate); @@ -974,7 +974,7 @@ return -EINVAL; /* unused */ case SIOCYAMSMCS: - if (test_bit(LINK_STATE_START, &dev->state)) + if (netif_running(dev)) return -EINVAL; /* Cannot change this parameter when up */ ym = kmalloc(sizeof(struct yamdrv_ioctl_mcs), GFP_ATOMIC); ym->bitrate = 9600; @@ -990,13 +990,13 @@ if (copy_from_user(&yi, ifr->ifr_data, sizeof(struct yamdrv_ioctl_cfg))) return -EFAULT; - if ((yi.cfg.mask & YAM_IOBASE) && test_bit(LINK_STATE_START, &dev->state)) + if ((yi.cfg.mask & YAM_IOBASE) && netif_running(dev)) return -EINVAL; /* Cannot change this parameter when up */ - if ((yi.cfg.mask & YAM_IRQ) && test_bit(LINK_STATE_START, &dev->state)) + if ((yi.cfg.mask & YAM_IRQ) && netif_running(dev)) return -EINVAL; /* Cannot change this parameter when up */ - if ((yi.cfg.mask & YAM_BITRATE) && test_bit(LINK_STATE_START, &dev->state)) + if ((yi.cfg.mask & YAM_BITRATE) && netif_running(dev)) return -EINVAL; /* Cannot change this parameter when up */ - if ((yi.cfg.mask & YAM_BAUDRATE) && test_bit(LINK_STATE_START, &dev->state)) + if ((yi.cfg.mask & YAM_BAUDRATE) && netif_running(dev)) return -EINVAL; /* Cannot change this parameter when up */ if (yi.cfg.mask & YAM_IOBASE) { @@ -1210,7 +1210,7 @@ struct net_device *dev = &yam_ports[i].dev; if (!dev->priv) continue; - if (test_bit(LINK_STATE_START, &dev->state)) + if (netif_running(dev)) yam_close(dev); unregister_netdev(dev); } diff -u --recursive --new-file v2.3.46/linux/drivers/net/lance.c linux/drivers/net/lance.c --- v2.3.46/linux/drivers/net/lance.c Sat Feb 12 11:22:10 2000 +++ linux/drivers/net/lance.c Thu Feb 17 09:18:47 2000 @@ -1043,7 +1043,7 @@ #endif if (lp->tx_full && - (test_bit(LINK_STATE_XOFF, &dev->flags)) && + (netif_queue_stopped(dev)) && dirty_tx > lp->cur_tx - TX_RING_SIZE + 2) { /* The ring is no longer full, clear tbusy. */ lp->tx_full = 0; diff -u --recursive --new-file v2.3.46/linux/drivers/net/myri_sbus.c linux/drivers/net/myri_sbus.c --- v2.3.46/linux/drivers/net/myri_sbus.c Thu Feb 10 17:11:10 2000 +++ linux/drivers/net/myri_sbus.c Fri Feb 18 15:07:20 2000 @@ -256,7 +256,7 @@ u32 dma_addr; dma_addr = sbus_readl(&rxd->myri_scatters[0].addr); - sbus_unmap_single(mp->myri_sdev, dma_addr, RX_ALLOC_SIZE); + sbus_unmap_single(mp->myri_sdev, dma_addr, RX_ALLOC_SIZE, SBUS_DMA_FROMDEVICE); dev_kfree_skb(mp->rx_skbs[i]); mp->rx_skbs[i] = NULL; } @@ -272,7 +272,7 @@ u32 dma_addr; dma_addr = sbus_readl(&txd->myri_gathers[0].addr); - sbus_unmap_single(mp->myri_sdev, dma_addr, (skb->len + 3) & ~3); + sbus_unmap_single(mp->myri_sdev, dma_addr, (skb->len + 3) & ~3, SBUS_DMA_TODEVICE); dev_kfree_skb(mp->tx_skbs[i]); mp->tx_skbs[i] = NULL; } @@ -301,7 +301,7 @@ skb->dev = dev; skb_put(skb, RX_ALLOC_SIZE); - dma_addr = sbus_map_single(mp->myri_sdev, skb->data, RX_ALLOC_SIZE); + dma_addr = sbus_map_single(mp->myri_sdev, skb->data, RX_ALLOC_SIZE, SBUS_DMA_FROMDEVICE); sbus_writel(dma_addr, &rxd[i].myri_scatters[0].addr); sbus_writel(RX_ALLOC_SIZE, &rxd[i].myri_scatters[0].len); sbus_writel(i, &rxd[i].ctx); @@ -363,7 +363,7 @@ DTX(("SKB[%d] ", entry)); dma_addr = sbus_readl(&sq->myri_txd[entry].myri_gathers[0].addr); - sbus_unmap_single(mp->myri_sdev, dma_addr, skb->len); + sbus_unmap_single(mp->myri_sdev, dma_addr, skb->len, SBUS_DMA_TODEVICE); dev_kfree_skb(skb); mp->tx_skbs[entry] = NULL; mp->enet_stats.tx_packets++; @@ -444,7 +444,7 @@ DRX(("rxd[%d]: %p len[%d] csum[%08x] ", entry, rxd, len, csum)); sbus_dma_sync_single(mp->myri_sdev, sbus_readl(&rxd->myri_scatters[0].addr), - RX_ALLOC_SIZE); + RX_ALLOC_SIZE, SBUS_DMA_FROMDEVICE); if (len < (ETH_HLEN + MYRI_PAD_LEN) || (skb->data[0] != MYRI_PAD_LEN)) { DRX(("ERROR[")); mp->enet_stats.rx_errors++; @@ -481,13 +481,15 @@ } sbus_unmap_single(mp->myri_sdev, sbus_readl(&rxd->myri_scatters[0].addr), - RX_ALLOC_SIZE); + RX_ALLOC_SIZE, + SBUS_DMA_FROMDEVICE); mp->rx_skbs[index] = new_skb; new_skb->dev = dev; skb_put(new_skb, RX_ALLOC_SIZE); dma_addr = sbus_map_single(mp->myri_sdev, new_skb->data, - RX_ALLOC_SIZE); + RX_ALLOC_SIZE, + SBUS_DMA_FROMDEVICE); sbus_writel(dma_addr, &rxd->myri_scatters[0].addr); sbus_writel(RX_ALLOC_SIZE, &rxd->myri_scatters[0].len); sbus_writel(index, &rxd->ctx); @@ -650,7 +652,7 @@ sbus_writew((skb->data[4] << 8) | skb->data[5], &txd->addr[3]); } - dma_addr = sbus_map_single(mp->myri_sdev, skb->data, len); + dma_addr = sbus_map_single(mp->myri_sdev, skb->data, len, SBUS_DMA_TODEVICE); sbus_writel(dma_addr, &txd->myri_gathers[0].addr); sbus_writel(len, &txd->myri_gathers[0].len); sbus_writel(1, &txd->num_sg); diff -u --recursive --new-file v2.3.46/linux/drivers/net/net_init.c linux/drivers/net/net_init.c --- v2.3.46/linux/drivers/net/net_init.c Thu Feb 10 17:11:10 2000 +++ linux/drivers/net/net_init.c Thu Feb 17 09:18:47 2000 @@ -153,7 +153,7 @@ static int eth_mac_addr(struct net_device *dev, void *p) { struct sockaddr *addr=p; - if(test_bit(LINK_STATE_START, &dev->state)) + if (netif_running(dev)) return -EBUSY; memcpy(dev->dev_addr, addr->sa_data,dev->addr_len); return 0; @@ -200,7 +200,7 @@ static int hippi_mac_addr(struct net_device *dev, void *p) { struct sockaddr *addr = p; - if(test_bit(LINK_STATE_START, &dev->state)) + if (netif_running(dev)) return -EBUSY; memcpy(dev->dev_addr, addr->sa_data, dev->addr_len); return 0; diff -u --recursive --new-file v2.3.46/linux/drivers/net/ni52.c linux/drivers/net/ni52.c --- v2.3.46/linux/drivers/net/ni52.c Sat Feb 12 11:22:10 2000 +++ linux/drivers/net/ni52.c Thu Feb 17 09:18:47 2000 @@ -858,7 +858,7 @@ #ifndef NO_NOPCOMMANDS if(stat & STAT_CNA) /* CU went 'not ready' */ { - if(test_bit(LINK_STATE_START, &dev->state)) + if(netif_running(dev)) printk("%s: oops! CU has left active state. stat: %04x/%02x.\n",dev->name,(int) stat,(int) p->scb->cus); } #endif diff -u --recursive --new-file v2.3.46/linux/drivers/net/pcmcia/3c574_cs.c linux/drivers/net/pcmcia/3c574_cs.c --- v2.3.46/linux/drivers/net/pcmcia/3c574_cs.c Wed Feb 16 17:03:52 2000 +++ linux/drivers/net/pcmcia/3c574_cs.c Thu Feb 17 09:18:47 2000 @@ -627,8 +627,7 @@ case CS_EVENT_CARD_REMOVAL: link->state &= ~DEV_PRESENT; if (link->state & DEV_CONFIG) { - netif_stop_queue (dev); - clear_bit(LINK_STATE_START, &dev->state); + netif_device_detach(dev); link->release.expires = jiffies + HZ/20; add_timer(&link->release); } @@ -642,10 +641,9 @@ /* Fall through... */ case CS_EVENT_RESET_PHYSICAL: if (link->state & DEV_CONFIG) { - if (link->open) { - netif_stop_queue (dev); - clear_bit(LINK_STATE_START, &dev->state); - } + if (link->open) + netif_device_detach(dev); + CardServices(ReleaseConfiguration, link->handle); } break; @@ -657,8 +655,7 @@ CardServices(RequestConfiguration, link->handle, &link->conf); if (link->open) { tc574_reset(dev); - set_bit(LINK_STATE_START, &dev->state); - netif_start_queue (dev); + netif_device_attach(dev); } } break; @@ -953,7 +950,7 @@ ioaddr_t ioaddr, status; int work_budget = max_interrupt_work; - if (!test_bit(LINK_STATE_START, &dev->state)) + if (!netif_device_present(dev)) return; spin_lock (&lp->lock); @@ -966,8 +963,7 @@ while ((status = inw(ioaddr + EL3_STATUS)) & (IntLatch | RxComplete | RxEarly | StatsFull)) { - if (!test_bit(LINK_STATE_START, &dev->state) || - ((status & 0xe000) != 0x2000)) { + if (!netif_device_present(dev) || ((status & 0xe000) != 0x2000)) { DEBUG(1, "%s: Interrupt from dead card\n", dev->name); break; } @@ -1047,7 +1043,7 @@ u_long flags; u_short /* cable, */ media, partner; - if (!test_bit(LINK_STATE_START, &dev->state)) + if (!netif_device_present(dev)) goto reschedule; /* Check for pending interrupt with expired latency timer: with @@ -1118,7 +1114,7 @@ { struct el3_private *lp = (struct el3_private *)dev->priv; - if (test_bit(LINK_STATE_START, &dev->state)) + if (netif_device_present(dev)) update_stats(dev); return &lp->stats; } diff -u --recursive --new-file v2.3.46/linux/drivers/net/pcmcia/3c575_cb.c linux/drivers/net/pcmcia/3c575_cb.c --- v2.3.46/linux/drivers/net/pcmcia/3c575_cb.c Sun Feb 13 19:29:04 2000 +++ linux/drivers/net/pcmcia/3c575_cb.c Thu Feb 17 09:18:47 2000 @@ -1845,7 +1845,7 @@ long ioaddr = dev->base_addr; int i; - if (test_bit(LINK_STATE_START, &dev->state)) + if (netif_device_present(dev)) vortex_down(dev); if (vortex_debug > 1) { @@ -1883,7 +1883,7 @@ struct vortex_private *vp = (struct vortex_private *)dev->priv; unsigned long flags; - if (test_bit(LINK_STATE_START, &dev->state)) { + if (netif_device_present(dev)) { spin_lock_irqsave (&vp->lock, flags); update_stats(dev->base_addr, dev); spin_unlock_irqrestore (&vp->lock, flags); diff -u --recursive --new-file v2.3.46/linux/drivers/net/pcmcia/3c589_cs.c linux/drivers/net/pcmcia/3c589_cs.c --- v2.3.46/linux/drivers/net/pcmcia/3c589_cs.c Wed Feb 16 17:03:52 2000 +++ linux/drivers/net/pcmcia/3c589_cs.c Thu Feb 17 09:18:47 2000 @@ -512,8 +512,7 @@ case CS_EVENT_CARD_REMOVAL: link->state &= ~DEV_PRESENT; if (link->state & DEV_CONFIG) { - netif_stop_queue (dev); - clear_bit(LINK_STATE_START, &dev->state); + netif_device_detach(dev); link->release.expires = jiffies + HZ/20; add_timer(&link->release); } @@ -527,10 +526,9 @@ /* Fall through... */ case CS_EVENT_RESET_PHYSICAL: if (link->state & DEV_CONFIG) { - if (link->open) { - netif_stop_queue (dev); - clear_bit(LINK_STATE_START, &dev->state); - } + if (link->open) + netif_device_detach(dev); + CardServices(ReleaseConfiguration, link->handle); } break; @@ -542,8 +540,7 @@ CardServices(RequestConfiguration, link->handle, &link->conf); if (link->open) { tc589_reset(dev); - set_bit(LINK_STATE_START, &dev->state); - netif_start_queue (dev); + netif_device_attach(dev); } } break; @@ -782,7 +779,7 @@ ioaddr_t ioaddr, status; int i = 0; - if (!test_bit(LINK_STATE_START, &dev->state)) + if (!netif_device_present(dev)) return; ioaddr = dev->base_addr; @@ -791,7 +788,7 @@ while ((status = inw(ioaddr + EL3_STATUS)) & (IntLatch | RxComplete | StatsFull)) { - if (!test_bit(LINK_STATE_START, &dev->state) || + if (!netif_device_present(dev)) || ((status & 0xe000) != 0x2000)) { DEBUG(1, "%s: interrupt from dead card\n", dev->name); break; @@ -865,7 +862,7 @@ u_short media, errs; u_long flags; - if (!test_bit(LINK_STATE_START, &dev->state)) + if (!netif_device_present(dev)) goto reschedule; EL3WINDOW(1); diff -u --recursive --new-file v2.3.46/linux/drivers/net/pcmcia/aironet4500_cs.c linux/drivers/net/pcmcia/aironet4500_cs.c --- v2.3.46/linux/drivers/net/pcmcia/aironet4500_cs.c Sun Feb 13 19:29:04 2000 +++ linux/drivers/net/pcmcia/aironet4500_cs.c Thu Feb 17 09:18:47 2000 @@ -566,7 +566,7 @@ case CS_EVENT_CARD_REMOVAL: link->state &= ~DEV_PRESENT; if (link->state & DEV_CONFIG) { - netif_stop_queue (dev); + netif_device_detach(dev); link->release.expires = RUN_AT( HZ/20 ); add_timer(&link->release); } @@ -580,9 +580,9 @@ /* Fall through... */ case CS_EVENT_RESET_PHYSICAL: if (link->state & DEV_CONFIG) { - if (link->open) { - netif_stop_queue (dev); - } + if (link->open) + netif_device_detach(dev); + CardServices(ReleaseConfiguration, link->handle); } break; @@ -594,7 +594,7 @@ CardServices(RequestConfiguration, link->handle, &link->conf); if (link->open) { // awc_reset(dev); - netif_start_queue (dev); + netif_device_attach(dev); } } break; @@ -636,4 +636,4 @@ // awc_detach(dev_list); } - \ No newline at end of file + diff -u --recursive --new-file v2.3.46/linux/drivers/net/pcmcia/fmvj18x_cs.c linux/drivers/net/pcmcia/fmvj18x_cs.c --- v2.3.46/linux/drivers/net/pcmcia/fmvj18x_cs.c Wed Feb 16 17:03:52 2000 +++ linux/drivers/net/pcmcia/fmvj18x_cs.c Thu Feb 17 09:18:47 2000 @@ -593,8 +593,7 @@ case CS_EVENT_CARD_REMOVAL: link->state &= ~DEV_PRESENT; if (link->state & DEV_CONFIG) { - netif_stop_queue (dev); - clear_bit(LINK_STATE_START, &dev->state); + netif_device_detach(dev); link->release.expires = jiffies + HZ/20; add_timer(&link->release); } @@ -608,10 +607,9 @@ /* Fall through... */ case CS_EVENT_RESET_PHYSICAL: if (link->state & DEV_CONFIG) { - if (link->open) { - netif_stop_queue (dev); - clear_bit(LINK_STATE_START, &dev->state); - } + if (link->open) + netif_device_detach(dev); + CardServices(ReleaseConfiguration, link->handle); } break; @@ -623,8 +621,7 @@ CardServices(RequestConfiguration, link->handle, &link->conf); if (link->open) { fjn_reset(dev); - set_bit(LINK_STATE_START, &dev->state); - netif_start_queue (dev); + netif_device_attach(dev); } } break; diff -u --recursive --new-file v2.3.46/linux/drivers/net/pcmcia/netwave_cs.c linux/drivers/net/pcmcia/netwave_cs.c --- v2.3.46/linux/drivers/net/pcmcia/netwave_cs.c Wed Feb 16 17:03:52 2000 +++ linux/drivers/net/pcmcia/netwave_cs.c Thu Feb 17 09:18:47 2000 @@ -1019,8 +1019,7 @@ case CS_EVENT_CARD_REMOVAL: link->state &= ~DEV_PRESENT; if (link->state & DEV_CONFIG) { - netif_stop_queue (dev); - clear_bit(LINK_STATE_START, &dev->state); + netif_device_detach(dev); link->release.expires = jiffies + 5; add_timer(&link->release); } @@ -1034,10 +1033,9 @@ /* Fall through... */ case CS_EVENT_RESET_PHYSICAL: if (link->state & DEV_CONFIG) { - if (link->open) { - netif_stop_queue (dev); - clear_bit(LINK_STATE_START, &dev->state); - } + if (link->open) + netif_device_detach(dev); + CardServices(ReleaseConfiguration, link->handle); } break; @@ -1049,8 +1047,7 @@ CardServices(RequestConfiguration, link->handle, &link->conf); if (link->open) { netwave_reset(dev); - set_bit(LINK_STATE_START, &dev->state); - netif_start_queue (dev); + netif_device_attach(dev); } } break; @@ -1299,7 +1296,7 @@ dev_link_t *link = &priv->link; int i; - if ((dev == NULL) || !test_bit(LINK_STATE_START, &dev->state)) + if ((dev == NULL) || !netif_device_present(dev)) return; spin_lock (&priv->lock); diff -u --recursive --new-file v2.3.46/linux/drivers/net/pcmcia/nmclan_cs.c linux/drivers/net/pcmcia/nmclan_cs.c --- v2.3.46/linux/drivers/net/pcmcia/nmclan_cs.c Wed Feb 16 17:03:52 2000 +++ linux/drivers/net/pcmcia/nmclan_cs.c Thu Feb 17 09:18:47 2000 @@ -870,7 +870,7 @@ case CS_EVENT_CARD_REMOVAL: link->state &= ~DEV_PRESENT; if (link->state & DEV_CONFIG) { - netif_stop_queue (dev); + netif_device_detach(dev); link->release.expires = jiffies + HZ/20; add_timer(&link->release); } @@ -884,9 +884,9 @@ /* Fall through... */ case CS_EVENT_RESET_PHYSICAL: if (link->state & DEV_CONFIG) { - if (link->open) { - netif_stop_queue (dev); - } + if (link->open) + netif_device_detach(dev); + CardServices(ReleaseConfiguration, link->handle); } break; @@ -898,7 +898,7 @@ CardServices(RequestConfiguration, link->handle, &link->conf); if (link->open) { nmclan_reset(dev); - netif_start_queue (dev); + netif_device_attach(dev); } } break; @@ -1153,7 +1153,7 @@ return; } - if (!test_bit(LINK_STATE_START, &dev->state)) { + if (!netif_device_present(dev)) { DEBUG(2, "%s: interrupt from dead card\n", dev->name); goto exception; } diff -u --recursive --new-file v2.3.46/linux/drivers/net/pcmcia/pcnet_cs.c linux/drivers/net/pcmcia/pcnet_cs.c --- v2.3.46/linux/drivers/net/pcmcia/pcnet_cs.c Wed Feb 16 17:03:52 2000 +++ linux/drivers/net/pcmcia/pcnet_cs.c Thu Feb 17 09:18:47 2000 @@ -812,8 +812,7 @@ case CS_EVENT_CARD_REMOVAL: link->state &= ~DEV_PRESENT; if (link->state & DEV_CONFIG) { - netif_stop_queue(&info->dev); - clear_bit(LINK_STATE_START, &info->dev.state); + netif_device_detach(&info->dev); link->release.expires = jiffies + HZ/20; link->state |= DEV_RELEASE_PENDING; add_timer(&link->release); @@ -828,10 +827,9 @@ /* Fall through... */ case CS_EVENT_RESET_PHYSICAL: if (link->state & DEV_CONFIG) { - if (link->open) { - netif_stop_queue(&info->dev); - clear_bit(LINK_STATE_START, &info->dev.state); - } + if (link->open) + netif_device_detach(&info->dev); + CardServices(ReleaseConfiguration, link->handle); } break; @@ -844,8 +842,7 @@ if (link->open) { pcnet_reset_8390(&info->dev); NS8390_init(&info->dev, 1); - netif_start_queue(&info->dev); - set_bit(LINK_STATE_START, &info->dev.state); + netif_device_attach(&info->dev); } } break; @@ -988,7 +985,7 @@ struct net_device *dev = &info->dev; ioaddr_t nic_base = dev->base_addr; - if (!test_bit(LINK_STATE_START, &dev->state)) + if (!netif_device_present(dev)) goto reschedule; /* Check for pending interrupt with expired latency timer: with diff -u --recursive --new-file v2.3.46/linux/drivers/net/pcmcia/ray_cs.c linux/drivers/net/pcmcia/ray_cs.c --- v2.3.46/linux/drivers/net/pcmcia/ray_cs.c Thu Feb 10 17:11:11 2000 +++ linux/drivers/net/pcmcia/ray_cs.c Thu Feb 17 09:18:47 2000 @@ -926,8 +926,7 @@ switch (event) { case CS_EVENT_CARD_REMOVAL: link->state &= ~DEV_PRESENT; - netif_stop_queue(dev); - clear_bit(LINK_STATE_START, &dev->state); + netif_device_detach(dev); if (link->state & DEV_CONFIG) { link->release.expires = jiffies + HZ/20; add_timer(&link->release); @@ -943,10 +942,9 @@ /* Fall through... */ case CS_EVENT_RESET_PHYSICAL: if (link->state & DEV_CONFIG) { - if (link->open) { - netif_stop_queue(dev); - clear_bit(LINK_STATE_START, &dev->state); - } + if (link->open) + netif_device_detach(dev); + pcmcia_release_configuration(link->handle); } break; @@ -958,8 +956,7 @@ pcmcia_request_configuration(link->handle, &link->conf); if (link->open) { ray_reset(dev); - netif_start_queue(dev); - set_bit(LINK_STATE_START, &dev->state); + netif_device_attach(dev); } } break; diff -u --recursive --new-file v2.3.46/linux/drivers/net/pcmcia/smc91c92_cs.c linux/drivers/net/pcmcia/smc91c92_cs.c --- v2.3.46/linux/drivers/net/pcmcia/smc91c92_cs.c Wed Feb 16 17:03:52 2000 +++ linux/drivers/net/pcmcia/smc91c92_cs.c Thu Feb 17 09:18:47 2000 @@ -1112,8 +1112,7 @@ case CS_EVENT_CARD_REMOVAL: link->state &= ~DEV_PRESENT; if (link->state & DEV_CONFIG) { - netif_stop_queue (dev); - clear_bit(LINK_STATE_START, &dev->state); + netif_device_detach(dev); link->release.expires = jiffies + HZ/20; link->state |= DEV_RELEASE_PENDING; add_timer(&link->release); @@ -1128,10 +1127,9 @@ /* Fall through... */ case CS_EVENT_RESET_PHYSICAL: if (link->state & DEV_CONFIG) { - if (link->open) { - netif_stop_queue (dev); - clear_bit(LINK_STATE_START, &dev->state); - } + if (link->open) + netif_device_detach(dev); + CardServices(ReleaseConfiguration, link->handle); } break; @@ -1154,8 +1152,7 @@ } if (link->open) { smc_reset(dev); - set_bit(LINK_STATE_START, &dev->state); - netif_start_queue (dev); + netif_device_attach(dev); } } break; @@ -1506,7 +1503,7 @@ u_short saved_bank, saved_pointer, mask, status; char bogus_cnt = INTR_WORK; /* Work we are willing to do. */ - if ((smc == NULL) || !test_bit(LINK_STATE_START, &dev->state)) + if ((smc == NULL) || !netif_device_present(dev)) return; ioaddr = dev->base_addr; @@ -1910,7 +1907,7 @@ ioaddr_t ioaddr = dev->base_addr; u_short i, media, saved_bank; - if (!test_bit(LINK_STATE_START, &dev->state)) + if (!netif_device_present(dev)) goto reschedule; saved_bank = inw(ioaddr + BANK_SELECT); diff -u --recursive --new-file v2.3.46/linux/drivers/net/pcmcia/tulip_cb.c linux/drivers/net/pcmcia/tulip_cb.c --- v2.3.46/linux/drivers/net/pcmcia/tulip_cb.c Sun Feb 13 19:29:04 2000 +++ linux/drivers/net/pcmcia/tulip_cb.c Fri Feb 18 11:50:34 2000 @@ -2713,8 +2713,6 @@ long ioaddr = dev->base_addr; struct tulip_private *tp = (struct tulip_private *)dev->priv; - netif_stop_queue (dev); - /* Disable interrupts by clearing the interrupt mask. */ outl(0x00000000, ioaddr + CSR7); /* Stop the chip's Tx and Rx processes. */ @@ -2726,8 +2724,6 @@ if (inl(ioaddr + CSR6) != 0xffffffff) tp->stats.rx_missed_errors += inl(ioaddr + CSR8) & 0xffff; - del_timer(&tp->timer); - dev->if_port = tp->saved_if_port; } @@ -2742,9 +2738,13 @@ printk(KERN_DEBUG "%s: Shutting down ethercard, status was %2.2x.\n", dev->name, inl(ioaddr + CSR5)); - if (test_bit(LINK_STATE_START, &dev->state)) + netif_stop_queue(dev); + + if (netif_device_present(dev)) tulip_down(dev); + del_timer(&tp->timer); + free_irq(dev->irq, dev); /* Free all the skbuffs in the Rx queue. */ @@ -2774,7 +2774,7 @@ struct tulip_private *tp = (struct tulip_private *)dev->priv; long ioaddr = dev->base_addr; - if (test_bit(LINK_STATE_START, &dev->state)) + if (netif_device_present(dev)) tp->stats.rx_missed_errors += inl(ioaddr + CSR8) & 0xffff; return &tp->stats; diff -u --recursive --new-file v2.3.46/linux/drivers/net/pcmcia/wavelan_cs.c linux/drivers/net/pcmcia/wavelan_cs.c --- v2.3.46/linux/drivers/net/pcmcia/wavelan_cs.c Wed Feb 16 17:03:52 2000 +++ linux/drivers/net/pcmcia/wavelan_cs.c Thu Feb 17 09:18:47 2000 @@ -1001,7 +1001,7 @@ lp->reconfig_82593 = FALSE; wv_82593_config (dev); - netif_start_queue (dev); + netif_wake_queue (dev); } } @@ -4360,7 +4360,7 @@ MOD_DEC_USE_COUNT; /* If the card is still present */ - if (test_bit(LINK_STATE_START, &dev->state)) + if (netif_device_present(dev)) { netif_stop_queue (dev); @@ -4662,8 +4662,7 @@ if(link->state & DEV_CONFIG) { /* Accept no more transmissions */ - netif_stop_queue (dev); - clear_bit(LINK_STATE_START, &dev->state); + netif_device_detach(dev); /* Release the card */ wv_pcmcia_release((u_long) link); @@ -4700,10 +4699,8 @@ if(link->state & DEV_CONFIG) { if(link->open) - { - netif_stop_queue (dev); - clear_bit(LINK_STATE_START, &dev->state); - } + netif_device_detach(dev); + CardServices(ReleaseConfiguration, link->handle); } break; @@ -4718,8 +4715,7 @@ if(link->open) /* If RESET -> True, If RESUME -> False ??? */ { wv_hw_reset(dev); - set_bit(LINK_STATE_START, &dev->state); - netif_start_queue (dev); + netif_device_attach(dev); } } break; diff -u --recursive --new-file v2.3.46/linux/drivers/net/pcmcia/xirc2ps_cs.c linux/drivers/net/pcmcia/xirc2ps_cs.c --- v2.3.46/linux/drivers/net/pcmcia/xirc2ps_cs.c Wed Feb 16 17:03:52 2000 +++ linux/drivers/net/pcmcia/xirc2ps_cs.c Thu Feb 17 09:18:47 2000 @@ -1340,8 +1340,7 @@ case CS_EVENT_CARD_REMOVAL: link->state &= ~DEV_PRESENT; if (link->state & DEV_CONFIG) { - netif_stop_queue(dev); - clear_bit(LINK_STATE_START, &dev->state); + netif_device_detach(dev); link->release.expires = jiffies + HZ / 20; add_timer(&link->release); } @@ -1356,8 +1355,7 @@ case CS_EVENT_RESET_PHYSICAL: if (link->state & DEV_CONFIG) { if (link->open) { - netif_stop_queue(dev); - clear_bit(LINK_STATE_START, &dev->state); + netif_device_detach(dev); lp->suspended=1; do_powerdown(dev); } @@ -1373,8 +1371,7 @@ if (link->open) { do_reset(dev,1); lp->suspended=0; - set_bit(LINK_STATE_START, &dev->state); - netif_start_queue(dev); + netif_device_attach(dev); } } break; @@ -1403,7 +1400,7 @@ */ spin_lock (&lp->lock); - if (!test_bit(LINK_STATE_START, &dev->state)) + if (!netif_device_present(dev)) return; ioaddr = dev->base_addr; diff -u --recursive --new-file v2.3.46/linux/drivers/net/pcnet32.c linux/drivers/net/pcnet32.c --- v2.3.46/linux/drivers/net/pcnet32.c Sat Feb 12 11:22:10 2000 +++ linux/drivers/net/pcnet32.c Thu Feb 17 09:18:47 2000 @@ -1153,8 +1153,8 @@ } #endif if (lp->tx_full && - test_bit(LINK_STATE_XOFF, &dev->flags) && - dirty_tx > lp->cur_tx - TX_RING_SIZE + 2) { + netif_queue_stopped(dev) && + dirty_tx > lp->cur_tx - TX_RING_SIZE + 2) { /* The ring is no longer full, clear tbusy. */ lp->tx_full = 0; netif_wake_queue (dev); diff -u --recursive --new-file v2.3.46/linux/drivers/net/plip.c linux/drivers/net/plip.c --- v2.3.46/linux/drivers/net/plip.c Sat Feb 12 11:22:10 2000 +++ linux/drivers/net/plip.c Thu Feb 17 09:18:47 2000 @@ -965,7 +965,7 @@ struct net_local *nl = (struct net_local *)dev->priv; struct plip_local *snd = &nl->snd_data; - if (test_bit(LINK_STATE_XOFF, &dev->flags)) + if (netif_queue_stopped(dev)) return 1; /* We may need to grab the bus */ diff -u --recursive --new-file v2.3.46/linux/drivers/net/rtl8129.c linux/drivers/net/rtl8129.c --- v2.3.46/linux/drivers/net/rtl8129.c Wed Feb 16 17:03:52 2000 +++ linux/drivers/net/rtl8129.c Fri Feb 18 15:07:20 2000 @@ -787,7 +787,7 @@ rtl8129_interrupt(dev->irq, dev, 0); } } - if (test_bit(LINK_STATE_XOFF, &dev->state) && + if (netif_queue_stopped(dev) && (jiffies - dev->trans_start) >= 2*TX_TIMEOUT) rtl8129_tx_timeout(dev); @@ -908,7 +908,7 @@ saved_skb[j] = rp->skb; if (rp->mapping != 0) { - pci_unmap_single(tp->pdev, rp->mapping, rp->skb->len); + pci_unmap_single(tp->pdev, rp->mapping, rp->skb->len, PCI_DMA_TODEVICE); rp->mapping = 0; } } @@ -922,7 +922,7 @@ ioaddr + TxAddr0 + i*4); } else { tp->tx_info[i].mapping = - pci_map_single(tp->pdev, skb->data, skb->len); + pci_map_single(tp->pdev, skb->data, skb->len, PCI_DMA_TODEVICE); outl(tp->tx_info[i].mapping, ioaddr + TxAddr0 + i*4); } /* Note: the chip doesn't have auto-pad! */ @@ -991,7 +991,7 @@ ioaddr + TxAddr0 + entry*4); } else { tp->tx_info[entry].mapping = - pci_map_single(tp->pdev, skb->data, skb->len); + pci_map_single(tp->pdev, skb->data, skb->len, PCI_DMA_TODEVICE); outl(tp->tx_info[entry].mapping, ioaddr + TxAddr0 + entry*4); } /* Note: the chip doesn't have auto-pad! */ @@ -1085,7 +1085,8 @@ if (tp->tx_info[entry].mapping != 0) { pci_unmap_single(tp->pdev, tp->tx_info[entry].mapping, - tp->tx_info[entry].skb->len); + tp->tx_info[entry].skb->len, + PCI_DMA_TODEVICE); tp->tx_info[entry].mapping = 0; } @@ -1315,7 +1316,7 @@ if (skb) { if (mapping) - pci_unmap_single(tp->pdev, mapping, skb->len); + pci_unmap_single(tp->pdev, mapping, skb->len, PCI_DMA_TODEVICE); dev_kfree_skb(skb); } tp->tx_info[i].skb = NULL; @@ -1366,7 +1367,7 @@ struct rtl8129_private *tp = (struct rtl8129_private *)dev->priv; long ioaddr = dev->base_addr; - if (test_bit(LINK_STATE_START, &dev->state)) { + if (netif_running(dev)) { tp->stats.rx_missed_errors += inl(ioaddr + RxMissed); outl(0, ioaddr + RxMissed); } diff -u --recursive --new-file v2.3.46/linux/drivers/net/sis900.c linux/drivers/net/sis900.c --- v2.3.46/linux/drivers/net/sis900.c Sun Feb 13 19:29:04 2000 +++ linux/drivers/net/sis900.c Thu Feb 17 09:18:47 2000 @@ -1066,7 +1066,7 @@ sis_priv->tx_ring[entry].cmdsts = 0; } - if (sis_priv->tx_full && test_bit(LINK_STATE_XOFF, &net_dev->flags) && + if (sis_priv->tx_full && netif_queue_stopped(net_dev) && sis_priv->cur_tx - sis_priv->dirty_tx < NUM_TX_DESC - 4) { /* The ring is no longer full, clear tx_full and schedule more transmission by netif_wake_queue(net_dev) */ diff -u --recursive --new-file v2.3.46/linux/drivers/net/sk98lin/skge.c linux/drivers/net/sk98lin/skge.c --- v2.3.46/linux/drivers/net/sk98lin/skge.c Thu Feb 10 17:11:11 2000 +++ linux/drivers/net/sk98lin/skge.c Fri Feb 18 15:07:20 2000 @@ -276,7 +276,9 @@ // #define RLMT_MODE {"CheckLink", } -#define DEV_KFREE_SKB(skb) dev_kfree_skb(skb); +#define DEV_KFREE_SKB(skb) dev_kfree_skb(skb) +#define DEV_KFREE_SKB_IRQ(skb) dev_kfree_skb_irq(skb) +#define DEV_KFREE_SKB_ANY(skb) dev_kfree_skb_any(skb) /* function prototypes ******************************************************/ static void FreeResources(struct net_device *dev); @@ -410,6 +412,21 @@ pci_set_master(pdev); +#ifdef __sparc__ + /* Set the proper cache line size value, plus enable + * write-invalidate and fast back-to-back on Sparc. + */ + { + SK_U16 pci_command; + + SkPciWriteCfgByte(pAC, PCI_CACHE_LINE_SIZE, 0x10); + + SkPciReadCfgWord(pAC, PCI_COMMAND, &pci_command); + pci_command |= (PCI_COMMAND_INVALIDATE | PCI_COMMAND_FAST_BACK); + SkPciWriteCfgWord(pAC, PCI_COMMAND, pci_command); + } +#endif + base_address = pdev->resource[0].start; #ifdef SK_BIG_ENDIAN @@ -1507,13 +1524,16 @@ Rc = XmitFrame(pAC, &pAC->TxPort[pAC->ActivePort][TX_PRIO_LOW], skb); - if (Rc == 0) { - /* transmitter out of resources */ + /* Transmitter out of resources? */ + if (Rc <= 0) netif_stop_queue(dev); - /* give buffer ownership back to the queueing layer */ + /* If not taken, give buffer ownership back to the + * queueing layer. + */ + if (Rc < 0) return (1); - } + dev->trans_start = jiffies; return (0); } /* SkGeXmit */ @@ -1539,7 +1559,7 @@ * > 0 - on succes: the number of bytes in the message * = 0 - on resource shortage: this frame sent or dropped, now * the ring is full ( -> set tbusy) - * < 0 - on failure: other problems (not used) + * < 0 - on failure: other problems ( -> return failure to upper layers) */ static int XmitFrame( SK_AC *pAC, /* pointer to adapter context */ @@ -1566,7 +1586,7 @@ SK_DBGCAT_DRV_TX_PROGRESS, ("XmitFrame failed\n")); /* this message can not be sent now */ - return (0); + return (-1); } } /* advance head counter behind descriptor needed for this frame */ @@ -1586,7 +1606,8 @@ /* set up descriptor and CONTROL dword */ PhysAddr = (SK_U64) pci_map_single(&pAC->PciDev, pMessage->data, - pMessage->len); + pMessage->len, + PCI_DMA_TODEVICE); pTxd->VDataLow = (SK_U32) (PhysAddr & 0xffffffff); pTxd->VDataHigh = (SK_U32) (PhysAddr >> 32); pTxd->pMBuf = pMessage; @@ -1679,9 +1700,11 @@ PhysAddr = ((SK_U64) pTxd->VDataHigh) << (SK_U64) 32; PhysAddr |= (SK_U64) pTxd->VDataLow; pci_unmap_single(&pAC->PciDev, PhysAddr, - pTxd->pMBuf->len); + pTxd->pMBuf->len, + PCI_DMA_TODEVICE); - DEV_KFREE_SKB(pTxd->pMBuf); /* free message */ + /* free message */ + DEV_KFREE_SKB_ANY(pTxd->pMBuf); pTxPort->TxdRingFree++; pTxd->TBControl &= ~TX_CTRL_SOFTWARE; pTxd = pTxd->pNextTxd; /* point behind fragment with EOF */ @@ -1759,7 +1782,8 @@ Length = pAC->RxBufSize; PhysAddr = (SK_U64) pci_map_single(&pAC->PciDev, pMsgBlock->data, - pAC->RxBufSize - 2); + pAC->RxBufSize - 2, + PCI_DMA_FROMDEVICE); pRxd->VDataLow = (SK_U32) (PhysAddr & 0xffffffff); pRxd->VDataHigh = (SK_U32) (PhysAddr >> 32); pRxd->pMBuf = pMsgBlock; @@ -1882,7 +1906,8 @@ skb_put(pNewMsg, FrameLength); pci_dma_sync_single(&pAC->PciDev, (dma_addr_t) PhysAddr, - FrameLength); + FrameLength, + PCI_DMA_FROMDEVICE); eth_copy_and_sum(pNewMsg, pMsg->data, FrameLength, 0); ReQueueRxBuffer(pAC, pRxPort, pMsg, @@ -1902,15 +1927,16 @@ /* release the DMA mapping */ pci_unmap_single(&pAC->PciDev, PhysAddr, - pAC->RxBufSize - 2); + pAC->RxBufSize - 2, + PCI_DMA_FROMDEVICE); /* set length in message */ skb_put(pMsg, FrameLength); /* hardware checksum */ Type = ntohs(*((short*)&pMsg->data[12])); if (Type == 0x800) { - Csum1= pRxd->TcpSums & 0xffff; - Csum2=(pRxd->TcpSums >> 16) & 0xffff; + Csum1=le16_to_cpu(pRxd->TcpSums & 0xffff); + Csum2=le16_to_cpu((pRxd->TcpSums >> 16) & 0xffff); if ((Csum1 & 0xfffe) && (Csum2 & 0xfffe)) { Result = SkCsGetReceiveInfo(pAC, &pMsg->data[14], @@ -1980,7 +2006,7 @@ SK_DBG_MSG(NULL, SK_DBGMOD_DRV, SK_DBGCAT_DRV_RX_PROGRESS, ("D")); - DEV_KFREE_SKB(pMsg); + DEV_KFREE_SKB_IRQ(pMsg); } } /* if not for rlmt */ else { @@ -2016,7 +2042,7 @@ pAC->dev->last_rx = jiffies; } else { - DEV_KFREE_SKB(pMsg); + DEV_KFREE_SKB_IRQ(pMsg); } } /* if packet for rlmt */ @@ -2040,7 +2066,7 @@ ("skge: Error in received frame, dropped!\n" "Control: %x\nRxStat: %x\n", Control, FrameStat)); - DEV_KFREE_SKB(pMsg); + DEV_KFREE_SKB_IRQ(pMsg); } } /* while */ FillRxRing(pAC, pRxPort); @@ -2060,8 +2086,9 @@ PhysAddr |= (SK_U64) pRxd->VDataLow; pci_unmap_single(&pAC->PciDev, PhysAddr, - pAC->RxBufSize - 2); - DEV_KFREE_SKB(pRxd->pMBuf); + pAC->RxBufSize - 2, + PCI_DMA_FROMDEVICE); + DEV_KFREE_SKB_IRQ(pRxd->pMBuf); pRxd->pMBuf = NULL; pRxPort->RxdRingFree++; pRxPort->pRxdRingHead = pRxd->pNextRxd; @@ -2139,7 +2166,8 @@ PhysAddr |= (SK_U64) pRxd->VDataLow; pci_unmap_single(&pAC->PciDev, PhysAddr, - pAC->RxBufSize - 2); + pAC->RxBufSize - 2, + PCI_DMA_FROMDEVICE); DEV_KFREE_SKB(pRxd->pMBuf); pRxd->pMBuf = NULL; } @@ -2276,7 +2304,7 @@ SK_DBG_MSG(NULL, SK_DBGMOD_DRV, SK_DBGCAT_DRV_ENTRY, ("SkGeSetMacAddr starts now...\n")); - if(test_bit(LINK_STATE_START, &dev->state)) { + if(netif_running(dev)) { return -EBUSY; } memcpy(dev->dev_addr, addr->sa_data,dev->addr_len); @@ -3120,7 +3148,7 @@ pFreeMbuf = pMbuf; do { pNextMbuf = pFreeMbuf->pNext; - DEV_KFREE_SKB(pFreeMbuf->pOs); + DEV_KFREE_SKB_ANY(pFreeMbuf->pOs); pFreeMbuf = pNextMbuf; } while ( pFreeMbuf != NULL ); } /* SkDrvFreeRlmtMbuf */ @@ -3489,8 +3517,9 @@ pRlmtMbuf = (SK_MBUF*) Param.pParaPtr; pMsg = (struct sk_buff*) pRlmtMbuf->pOs; skb_put(pMsg, pRlmtMbuf->Length); - XmitFrame(pAC, &pAC->TxPort[pRlmtMbuf->PortIdx][TX_PRIO_LOW], - pMsg); + if (XmitFrame(pAC, &pAC->TxPort[pRlmtMbuf->PortIdx][TX_PRIO_LOW], + pMsg) < 0) + DEV_KFREE_SKB_ANY(pMsg); break; default: break; diff -u --recursive --new-file v2.3.46/linux/drivers/net/skeleton.c linux/drivers/net/skeleton.c --- v2.3.46/linux/drivers/net/skeleton.c Thu Feb 10 17:11:11 2000 +++ linux/drivers/net/skeleton.c Thu Feb 17 09:18:47 2000 @@ -416,7 +416,7 @@ spin_lock_irq(&np->lock); add_to_tx_ring(np, skb, length); - dev->trans_start = jiffied; + dev->trans_start = jiffies; /* If we just used up the very last entry in the * TX ring on this device, tell the queueing @@ -482,8 +482,7 @@ * condition, and space has now been made available, * wake up the queue. */ - if (test_bit(LINK_STATE_XOFF, &dev->state) && - ! tx_full(dev)) + if (netif_queue_stopped(dev) && ! tx_full(dev)) netif_wake_queue(dev); spin_unlock(&np->lock); diff -u --recursive --new-file v2.3.46/linux/drivers/net/skfp/Makefile linux/drivers/net/skfp/Makefile --- v2.3.46/linux/drivers/net/skfp/Makefile Wed Dec 31 16:00:00 1969 +++ linux/drivers/net/skfp/Makefile Fri Feb 18 14:55:53 2000 @@ -0,0 +1,39 @@ +# +# Makefile for the SysKonnect FDDI PCI adapter driver +# + +ifeq ($(CONFIG_SKFP),y) + O_TARGET := skfp.o + O_OBJS = skfddi.o hwmtm.o fplustm.o smt.o cfm.o \ + ecm.o pcmplc.o pmf.o queue.o rmt.o \ + smtdef.o smtinit.o smttimer.o srf.o lnkstat.o \ + smtparse.o hwt.o drvfbi.o ess.o +else + ifeq ($(CONFIG_SKFP),m) + MOD_LIST_NAME := SKFP_MODULES + M_OBJS := skfp.o + O_TARGET := skfp.o + O_OBJS = skfddi.o hwmtm.o fplustm.o smt.o cfm.o \ + ecm.o pcmplc.o pmf.o queue.o rmt.o \ + smtdef.o smtinit.o smttimer.o srf.o lnkstat.o \ + smtparse.o hwt.o drvfbi.o ess.o + endif +endif + +# NOTE: +# Compiling this driver produces some warnings (and some more are +# switched off below), but I did not fix this, because the Hardware +# Module source (see skfddi.c for details) is used for different +# drivers, and fixing it for Linux might bring problems on other +# projects. To keep the source common for all those drivers (and +# thus simplify fixes to it), please do not clean it up! + +EXTRA_CFLAGS += -I. -DPCI -DMEM_MAPPED_IO -Wno-strict-prototypes + +include $(TOPDIR)/Rules.make + +clean: + rm -f core *.o *.a *.s + + + diff -u --recursive --new-file v2.3.46/linux/drivers/net/skfp/can.c linux/drivers/net/skfp/can.c --- v2.3.46/linux/drivers/net/skfp/can.c Wed Dec 31 16:00:00 1969 +++ linux/drivers/net/skfp/can.c Fri Feb 18 14:55:53 2000 @@ -0,0 +1,83 @@ +/****************************************************************************** + * + * (C)Copyright 1998,1999 SysKonnect, + * a business unit of Schneider & Koch & Co. Datensysteme GmbH. + * + * See the file "skfddi.c" for further information. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * The information in this file is provided "AS IS" without warranty. + * + ******************************************************************************/ + +#ifndef lint +static const char xID_sccs[] = "@(#)can.c 1.5 97/04/07 (C) SK " ; +#endif + +/* + * canonical bit order + */ +const u_char canonical[256] = { + 0x00,0x80,0x40,0xc0,0x20,0xa0,0x60,0xe0, + 0x10,0x90,0x50,0xd0,0x30,0xb0,0x70,0xf0, + 0x08,0x88,0x48,0xc8,0x28,0xa8,0x68,0xe8, + 0x18,0x98,0x58,0xd8,0x38,0xb8,0x78,0xf8, + 0x04,0x84,0x44,0xc4,0x24,0xa4,0x64,0xe4, + 0x14,0x94,0x54,0xd4,0x34,0xb4,0x74,0xf4, + 0x0c,0x8c,0x4c,0xcc,0x2c,0xac,0x6c,0xec, + 0x1c,0x9c,0x5c,0xdc,0x3c,0xbc,0x7c,0xfc, + 0x02,0x82,0x42,0xc2,0x22,0xa2,0x62,0xe2, + 0x12,0x92,0x52,0xd2,0x32,0xb2,0x72,0xf2, + 0x0a,0x8a,0x4a,0xca,0x2a,0xaa,0x6a,0xea, + 0x1a,0x9a,0x5a,0xda,0x3a,0xba,0x7a,0xfa, + 0x06,0x86,0x46,0xc6,0x26,0xa6,0x66,0xe6, + 0x16,0x96,0x56,0xd6,0x36,0xb6,0x76,0xf6, + 0x0e,0x8e,0x4e,0xce,0x2e,0xae,0x6e,0xee, + 0x1e,0x9e,0x5e,0xde,0x3e,0xbe,0x7e,0xfe, + 0x01,0x81,0x41,0xc1,0x21,0xa1,0x61,0xe1, + 0x11,0x91,0x51,0xd1,0x31,0xb1,0x71,0xf1, + 0x09,0x89,0x49,0xc9,0x29,0xa9,0x69,0xe9, + 0x19,0x99,0x59,0xd9,0x39,0xb9,0x79,0xf9, + 0x05,0x85,0x45,0xc5,0x25,0xa5,0x65,0xe5, + 0x15,0x95,0x55,0xd5,0x35,0xb5,0x75,0xf5, + 0x0d,0x8d,0x4d,0xcd,0x2d,0xad,0x6d,0xed, + 0x1d,0x9d,0x5d,0xdd,0x3d,0xbd,0x7d,0xfd, + 0x03,0x83,0x43,0xc3,0x23,0xa3,0x63,0xe3, + 0x13,0x93,0x53,0xd3,0x33,0xb3,0x73,0xf3, + 0x0b,0x8b,0x4b,0xcb,0x2b,0xab,0x6b,0xeb, + 0x1b,0x9b,0x5b,0xdb,0x3b,0xbb,0x7b,0xfb, + 0x07,0x87,0x47,0xc7,0x27,0xa7,0x67,0xe7, + 0x17,0x97,0x57,0xd7,0x37,0xb7,0x77,0xf7, + 0x0f,0x8f,0x4f,0xcf,0x2f,0xaf,0x6f,0xef, + 0x1f,0x9f,0x5f,0xdf,0x3f,0xbf,0x7f,0xff +} ; + +#ifdef MAKE_TABLE +int byte_reverse(x) +int x ; +{ + int y = 0 ; + + if (x & 0x01) + y |= 0x80 ; + if (x & 0x02) + y |= 0x40 ; + if (x & 0x04) + y |= 0x20 ; + if (x & 0x08) + y |= 0x10 ; + if (x & 0x10) + y |= 0x08 ; + if (x & 0x20) + y |= 0x04 ; + if (x & 0x40) + y |= 0x02 ; + if (x & 0x80) + y |= 0x01 ; + return(y) ; +} +#endif diff -u --recursive --new-file v2.3.46/linux/drivers/net/skfp/cfm.c linux/drivers/net/skfp/cfm.c --- v2.3.46/linux/drivers/net/skfp/cfm.c Wed Dec 31 16:00:00 1969 +++ linux/drivers/net/skfp/cfm.c Fri Feb 18 14:55:53 2000 @@ -0,0 +1,642 @@ +/****************************************************************************** + * + * (C)Copyright 1998,1999 SysKonnect, + * a business unit of Schneider & Koch & Co. Datensysteme GmbH. + * + * See the file "skfddi.c" for further information. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * The information in this file is provided "AS IS" without warranty. + * + ******************************************************************************/ + +/* + SMT CFM + Configuration Management + DAS with single MAC +*/ + +/* + * Hardware independant state machine implemantation + * The following external SMT functions are referenced : + * + * queue_event() + * + * The following external HW dependant functions are referenced : + * config_mux() + * + * The following HW dependant events are required : + * NONE + */ + +#include "h/types.h" +#include "h/fddi.h" +#include "h/smc.h" + +#define KERNEL +#include "h/smtstate.h" + +#ifndef lint +static const char ID_sccs[] = "@(#)cfm.c 2.18 98/10/06 (C) SK " ; +#endif + +/* + * FSM Macros + */ +#define AFLAG 0x10 +#define GO_STATE(x) (smc->mib.fddiSMTCF_State = (x)|AFLAG) +#define ACTIONS_DONE() (smc->mib.fddiSMTCF_State &= ~AFLAG) +#define ACTIONS(x) (x|AFLAG) + +#ifdef DEBUG +/* + * symbolic state names + */ +static const char * const cfm_states[] = { + "SC0_ISOLATED","CF1","CF2","CF3","CF4", + "SC1_WRAP_A","SC2_WRAP_B","SC5_TRHU_B","SC7_WRAP_S", + "SC9_C_WRAP_A","SC10_C_WRAP_B","SC11_C_WRAP_S","SC4_THRU_A" +} ; + +/* + * symbolic event names + */ +static const char * const cfm_events[] = { + "NONE","CF_LOOP_A","CF_LOOP_B","CF_JOIN_A","CF_JOIN_B" +} ; +#endif + +/* + * map from state to downstream port type + */ +static const u_char cf_to_ptype[] = { + TNONE,TNONE,TNONE,TNONE,TNONE, + TNONE,TB,TB,TS, + TA,TB,TS,TB +} ; + +/* + * CEM port states + */ +#define CEM_PST_DOWN 0 +#define CEM_PST_UP 1 +#define CEM_PST_HOLD 2 +/* define portstate array only for A and B port */ +/* Do this within the smc structure (use in multiple cards) */ + +/* + * all Globals are defined in smc.h + * struct s_cfm + */ + +/* + * function declarations + */ +static void cfm_fsm() ; + +/* + init CFM state machine + clear all CFM vars and flags +*/ +void cfm_init(smc) +struct s_smc *smc ; +{ + smc->mib.fddiSMTCF_State = ACTIONS(SC0_ISOLATED) ; + smc->r.rm_join = 0 ; + smc->r.rm_loop = 0 ; + smc->y[PA].scrub = 0 ; + smc->y[PB].scrub = 0 ; + smc->y[PA].cem_pst = CEM_PST_DOWN ; + smc->y[PB].cem_pst = CEM_PST_DOWN ; +} + +/* Some terms conditions used by the selection criteria */ +#define THRU_ENABLED(smc) (smc->y[PA].pc_mode != PM_TREE && \ + smc->y[PB].pc_mode != PM_TREE) +/* Selection criteria for the ports */ +static void selection_criteria (smc,phy) +struct s_smc *smc ; +struct s_phy *phy ; +{ + + switch (phy->mib->fddiPORTMy_Type) { + case TA: + if ( !THRU_ENABLED(smc) && smc->y[PB].cf_join ) { + phy->wc_flag = TRUE ; + } else { + phy->wc_flag = FALSE ; + } + + break; + case TB: + /* take precedence over PA */ + phy->wc_flag = FALSE ; + break; + case TS: + phy->wc_flag = FALSE ; + break; + case TM: + phy->wc_flag = FALSE ; + break; + } + +} + +void all_selection_criteria (smc) +struct s_smc *smc ; +{ + struct s_phy *phy ; + int p ; + + for ( p = 0,phy = smc->y ; p < NUMPHYS; p++, phy++ ) { + /* Do the selection criteria */ + selection_criteria (smc,phy); + } +} + +static void cem_priv_state (smc, event) +struct s_smc *smc ; +int event ; +/* State machine for private PORT states: used to optimize dual homing */ +{ + int np; /* Number of the port */ + int i; + + /* Do this only in a DAS */ + if (smc->s.sas != SMT_DAS ) + return ; + + np = event - CF_JOIN; + + if (np != PA && np != PB) { + return ; + } + /* Change the port state according to the event (portnumber) */ + if (smc->y[np].cf_join) { + smc->y[np].cem_pst = CEM_PST_UP ; + } else if (!smc->y[np].wc_flag) { + /* set the port to done only if it is not withheld */ + smc->y[np].cem_pst = CEM_PST_DOWN ; + } + + /* Don't set an hold port to down */ + + /* Check all ports of restart conditions */ + for (i = 0 ; i < 2 ; i ++ ) { + /* Check all port for PORT is on hold and no withhold is done */ + if ( smc->y[i].cem_pst == CEM_PST_HOLD && !smc->y[i].wc_flag ) { + smc->y[i].cem_pst = CEM_PST_DOWN; + queue_event(smc,(int)(EVENT_PCM+i),PC_START) ; + } + if ( smc->y[i].cem_pst == CEM_PST_UP && smc->y[i].wc_flag ) { + smc->y[i].cem_pst = CEM_PST_HOLD; + queue_event(smc,(int)(EVENT_PCM+i),PC_START) ; + } + if ( smc->y[i].cem_pst == CEM_PST_DOWN && smc->y[i].wc_flag ) { + /* + * The port must be restarted when the wc_flag + * will be reset. So set the port on hold. + */ + smc->y[i].cem_pst = CEM_PST_HOLD; + } + } + return ; +} + +/* + CFM state machine + called by dispatcher + + do + display state change + process event + until SM is stable +*/ +void cfm(smc,event) +struct s_smc *smc ; +int event ; +{ + int state ; /* remember last state */ + int cond ; + int oldstate ; + + /* We will do the following: */ + /* - compute the variable WC_Flag for every port (This is where */ + /* we can extend the requested path checking !!) */ + /* - do the old (SMT 6.2 like) state machine */ + /* - do the resulting station states */ + + all_selection_criteria (smc); + + /* We will check now whether a state transition is allowed or not */ + /* - change the portstates */ + cem_priv_state (smc, event); + + oldstate = smc->mib.fddiSMTCF_State ; + do { + DB_CFM("CFM : state %s%s", + (smc->mib.fddiSMTCF_State & AFLAG) ? "ACTIONS " : "", + cfm_states[smc->mib.fddiSMTCF_State & ~AFLAG]) ; + DB_CFM(" event %s\n",cfm_events[event],0) ; + state = smc->mib.fddiSMTCF_State ; + cfm_fsm(smc,event) ; + event = 0 ; + } while (state != smc->mib.fddiSMTCF_State) ; + +#ifndef SLIM_SMT + /* + * check peer wrap condition + */ + cond = FALSE ; + if ( (smc->mib.fddiSMTCF_State == SC9_C_WRAP_A && + smc->y[PA].pc_mode == PM_PEER) || + (smc->mib.fddiSMTCF_State == SC10_C_WRAP_B && + smc->y[PB].pc_mode == PM_PEER) || + (smc->mib.fddiSMTCF_State == SC11_C_WRAP_S && + smc->y[PS].pc_mode == PM_PEER && + smc->y[PS].mib->fddiPORTNeighborType != TS ) ) { + cond = TRUE ; + } + if (cond != smc->mib.fddiSMTPeerWrapFlag) + smt_srf_event(smc,SMT_COND_SMT_PEER_WRAP,0,cond) ; + +#if 0 + /* + * Don't send ever MAC_PATH_CHANGE events. Our MAC is hard-wired + * to the primary path. + */ + /* + * path change + */ + if (smc->mib.fddiSMTCF_State != oldstate) { + smt_srf_event(smc,SMT_EVENT_MAC_PATH_CHANGE,INDEX_MAC,0) ; + } +#endif +#endif /* no SLIM_SMT */ + + /* + * set MAC port type + */ + smc->mib.m[MAC0].fddiMACDownstreamPORTType = + cf_to_ptype[smc->mib.fddiSMTCF_State] ; + cfm_state_change(smc,(int)smc->mib.fddiSMTCF_State) ; +} + +/* + process CFM event +*/ +/*ARGSUSED1*/ +static void cfm_fsm(smc,cmd) +struct s_smc *smc ; +int cmd ; +{ + switch(smc->mib.fddiSMTCF_State) { + case ACTIONS(SC0_ISOLATED) : + smc->mib.p[PA].fddiPORTCurrentPath = MIB_PATH_ISOLATED ; + smc->mib.p[PB].fddiPORTCurrentPath = MIB_PATH_ISOLATED ; + smc->mib.p[PA].fddiPORTMACPlacement = 0 ; + smc->mib.p[PB].fddiPORTMACPlacement = 0 ; + smc->mib.fddiSMTStationStatus = MIB_SMT_STASTA_SEPA ; + config_mux(smc,MUX_ISOLATE) ; /* configure PHY Mux */ + smc->r.rm_loop = FALSE ; + smc->r.rm_join = FALSE ; + queue_event(smc,EVENT_RMT,RM_JOIN) ;/* signal RMT */ + /* Don't do the WC-Flag changing here */ + ACTIONS_DONE() ; + DB_CFMN(1,"CFM : %s\n",cfm_states[smc->mib.fddiSMTCF_State],0) ; + break; + case SC0_ISOLATED : + /*SC07*/ + /*SAS port can be PA or PB ! */ + if (smc->s.sas && (smc->y[PA].cf_join || smc->y[PA].cf_loop || + smc->y[PB].cf_join || smc->y[PB].cf_loop)) { + GO_STATE(SC11_C_WRAP_S) ; + break ; + } + /*SC01*/ + if ((smc->y[PA].cem_pst == CEM_PST_UP && smc->y[PA].cf_join && + !smc->y[PA].wc_flag) || smc->y[PA].cf_loop) { + GO_STATE(SC9_C_WRAP_A) ; + break ; + } + /*SC02*/ + if ((smc->y[PB].cem_pst == CEM_PST_UP && smc->y[PB].cf_join && + !smc->y[PB].wc_flag) || smc->y[PB].cf_loop) { + GO_STATE(SC10_C_WRAP_B) ; + break ; + } + break ; + case ACTIONS(SC9_C_WRAP_A) : + smc->mib.p[PA].fddiPORTCurrentPath = MIB_PATH_CONCATENATED ; + smc->mib.p[PB].fddiPORTCurrentPath = MIB_PATH_ISOLATED ; + smc->mib.p[PA].fddiPORTMACPlacement = INDEX_MAC ; + smc->mib.p[PB].fddiPORTMACPlacement = 0 ; + smc->mib.fddiSMTStationStatus = MIB_SMT_STASTA_CON ; + config_mux(smc,MUX_WRAPA) ; /* configure PHY mux */ + if (smc->y[PA].cf_loop) { + smc->r.rm_join = FALSE ; + smc->r.rm_loop = TRUE ; + queue_event(smc,EVENT_RMT,RM_LOOP) ;/* signal RMT */ + } + if (smc->y[PA].cf_join) { + smc->r.rm_loop = FALSE ; + smc->r.rm_join = TRUE ; + queue_event(smc,EVENT_RMT,RM_JOIN) ;/* signal RMT */ + } + ACTIONS_DONE() ; + DB_CFMN(1,"CFM : %s\n",cfm_states[smc->mib.fddiSMTCF_State],0) ; + break ; + case SC9_C_WRAP_A : + /*SC10*/ + if ( (smc->y[PA].wc_flag || !smc->y[PA].cf_join) && + !smc->y[PA].cf_loop ) { + GO_STATE(SC0_ISOLATED) ; + break ; + } + /*SC12*/ + else if ( (smc->y[PB].cf_loop && smc->y[PA].cf_join && + smc->y[PA].cem_pst == CEM_PST_UP) || + ((smc->y[PB].cf_loop || + (smc->y[PB].cf_join && + smc->y[PB].cem_pst == CEM_PST_UP)) && + (smc->y[PA].pc_mode == PM_TREE || + smc->y[PB].pc_mode == PM_TREE))) { + smc->y[PA].scrub = TRUE ; + GO_STATE(SC10_C_WRAP_B) ; + break ; + } + /*SC14*/ + else if (!smc->s.attach_s && + smc->y[PA].cf_join && + smc->y[PA].cem_pst == CEM_PST_UP && + smc->y[PA].pc_mode == PM_PEER && smc->y[PB].cf_join && + smc->y[PB].cem_pst == CEM_PST_UP && + smc->y[PB].pc_mode == PM_PEER) { + smc->y[PA].scrub = TRUE ; + smc->y[PB].scrub = TRUE ; + GO_STATE(SC4_THRU_A) ; + break ; + } + /*SC15*/ + else if ( smc->s.attach_s && + smc->y[PA].cf_join && + smc->y[PA].cem_pst == CEM_PST_UP && + smc->y[PA].pc_mode == PM_PEER && + smc->y[PB].cf_join && + smc->y[PB].cem_pst == CEM_PST_UP && + smc->y[PB].pc_mode == PM_PEER) { + smc->y[PA].scrub = TRUE ; + smc->y[PB].scrub = TRUE ; + GO_STATE(SC5_THRU_B) ; + break ; + } + break ; + case ACTIONS(SC10_C_WRAP_B) : + smc->mib.p[PA].fddiPORTCurrentPath = MIB_PATH_ISOLATED ; + smc->mib.p[PB].fddiPORTCurrentPath = MIB_PATH_CONCATENATED ; + smc->mib.p[PA].fddiPORTMACPlacement = 0 ; + smc->mib.p[PB].fddiPORTMACPlacement = INDEX_MAC ; + smc->mib.fddiSMTStationStatus = MIB_SMT_STASTA_CON ; + config_mux(smc,MUX_WRAPB) ; /* configure PHY mux */ + if (smc->y[PB].cf_loop) { + smc->r.rm_join = FALSE ; + smc->r.rm_loop = TRUE ; + queue_event(smc,EVENT_RMT,RM_LOOP) ;/* signal RMT */ + } + if (smc->y[PB].cf_join) { + smc->r.rm_loop = FALSE ; + smc->r.rm_join = TRUE ; + queue_event(smc,EVENT_RMT,RM_JOIN) ;/* signal RMT */ + } + ACTIONS_DONE() ; + DB_CFMN(1,"CFM : %s\n",cfm_states[smc->mib.fddiSMTCF_State],0) ; + break ; + case SC10_C_WRAP_B : + /*SC20*/ + if ( !smc->y[PB].cf_join && !smc->y[PB].cf_loop ) { + GO_STATE(SC0_ISOLATED) ; + break ; + } + /*SC21*/ + else if ( smc->y[PA].cf_loop && smc->y[PA].pc_mode == PM_PEER && + smc->y[PB].cf_join && smc->y[PB].pc_mode == PM_PEER) { + smc->y[PB].scrub = TRUE ; + GO_STATE(SC9_C_WRAP_A) ; + break ; + } + /*SC24*/ + else if (!smc->s.attach_s && + smc->y[PA].cf_join && smc->y[PA].pc_mode == PM_PEER && + smc->y[PB].cf_join && smc->y[PB].pc_mode == PM_PEER) { + smc->y[PA].scrub = TRUE ; + smc->y[PB].scrub = TRUE ; + GO_STATE(SC4_THRU_A) ; + break ; + } + /*SC25*/ + else if ( smc->s.attach_s && + smc->y[PA].cf_join && smc->y[PA].pc_mode == PM_PEER && + smc->y[PB].cf_join && smc->y[PB].pc_mode == PM_PEER) { + smc->y[PA].scrub = TRUE ; + smc->y[PB].scrub = TRUE ; + GO_STATE(SC5_THRU_B) ; + break ; + } + break ; + case ACTIONS(SC4_THRU_A) : + smc->mib.p[PA].fddiPORTCurrentPath = MIB_PATH_THRU ; + smc->mib.p[PB].fddiPORTCurrentPath = MIB_PATH_THRU ; + smc->mib.p[PA].fddiPORTMACPlacement = 0 ; + smc->mib.p[PB].fddiPORTMACPlacement = INDEX_MAC ; + smc->mib.fddiSMTStationStatus = MIB_SMT_STASTA_THRU ; + config_mux(smc,MUX_THRUA) ; /* configure PHY mux */ + smc->r.rm_loop = FALSE ; + smc->r.rm_join = TRUE ; + queue_event(smc,EVENT_RMT,RM_JOIN) ;/* signal RMT */ + ACTIONS_DONE() ; + DB_CFMN(1,"CFM : %s\n",cfm_states[smc->mib.fddiSMTCF_State],0) ; + break ; + case SC4_THRU_A : + /*SC41*/ + if (smc->y[PB].wc_flag || !smc->y[PB].cf_join) { + smc->y[PA].scrub = TRUE ; + GO_STATE(SC9_C_WRAP_A) ; + break ; + } + /*SC42*/ + else if (!smc->y[PA].cf_join || smc->y[PA].wc_flag) { + smc->y[PB].scrub = TRUE ; + GO_STATE(SC10_C_WRAP_B) ; + break ; + } + /*SC45*/ + else if (smc->s.attach_s) { + smc->y[PB].scrub = TRUE ; + GO_STATE(SC5_THRU_B) ; + break ; + } + break ; + case ACTIONS(SC5_THRU_B) : + smc->mib.p[PA].fddiPORTCurrentPath = MIB_PATH_THRU ; + smc->mib.p[PB].fddiPORTCurrentPath = MIB_PATH_THRU ; + smc->mib.p[PA].fddiPORTMACPlacement = INDEX_MAC ; + smc->mib.p[PB].fddiPORTMACPlacement = 0 ; + smc->mib.fddiSMTStationStatus = MIB_SMT_STASTA_THRU ; + config_mux(smc,MUX_THRUB) ; /* configure PHY mux */ + smc->r.rm_loop = FALSE ; + smc->r.rm_join = TRUE ; + queue_event(smc,EVENT_RMT,RM_JOIN) ;/* signal RMT */ + ACTIONS_DONE() ; + DB_CFMN(1,"CFM : %s\n",cfm_states[smc->mib.fddiSMTCF_State],0) ; + break ; + case SC5_THRU_B : + /*SC51*/ + if (!smc->y[PB].cf_join || smc->y[PB].wc_flag) { + smc->y[PA].scrub = TRUE ; + GO_STATE(SC9_C_WRAP_A) ; + break ; + } + /*SC52*/ + else if (!smc->y[PA].cf_join || smc->y[PA].wc_flag) { + smc->y[PB].scrub = TRUE ; + GO_STATE(SC10_C_WRAP_B) ; + break ; + } + /*SC54*/ + else if (!smc->s.attach_s) { + smc->y[PA].scrub = TRUE ; + GO_STATE(SC4_THRU_A) ; + break ; + } + break ; + case ACTIONS(SC11_C_WRAP_S) : + smc->mib.p[PS].fddiPORTCurrentPath = MIB_PATH_CONCATENATED ; + smc->mib.p[PS].fddiPORTMACPlacement = INDEX_MAC ; + smc->mib.fddiSMTStationStatus = MIB_SMT_STASTA_CON ; + config_mux(smc,MUX_WRAPS) ; /* configure PHY mux */ + if (smc->y[PA].cf_loop || smc->y[PB].cf_loop) { + smc->r.rm_join = FALSE ; + smc->r.rm_loop = TRUE ; + queue_event(smc,EVENT_RMT,RM_LOOP) ;/* signal RMT */ + } + if (smc->y[PA].cf_join || smc->y[PB].cf_join) { + smc->r.rm_loop = FALSE ; + smc->r.rm_join = TRUE ; + queue_event(smc,EVENT_RMT,RM_JOIN) ;/* signal RMT */ + } + ACTIONS_DONE() ; + DB_CFMN(1,"CFM : %s\n",cfm_states[smc->mib.fddiSMTCF_State],0) ; + break ; + case SC11_C_WRAP_S : + /*SC70*/ + if ( !smc->y[PA].cf_join && !smc->y[PA].cf_loop && + !smc->y[PB].cf_join && !smc->y[PB].cf_loop) { + GO_STATE(SC0_ISOLATED) ; + break ; + } + break ; + default: + SMT_PANIC(smc,SMT_E0106, SMT_E0106_MSG) ; + break; + } +} + +/* + * get MAC's input Port + * return : + * PA or PB + */ +int cfm_get_mac_input(smc) +struct s_smc *smc ; +{ + return((smc->mib.fddiSMTCF_State == SC10_C_WRAP_B || + smc->mib.fddiSMTCF_State == SC5_THRU_B) ? PB : PA) ; +} + +/* + * get MAC's output Port + * return : + * PA or PB + */ +int cfm_get_mac_output(smc) +struct s_smc *smc ; +{ + return((smc->mib.fddiSMTCF_State == SC10_C_WRAP_B || + smc->mib.fddiSMTCF_State == SC4_THRU_A) ? PB : PA) ; +} + +static char path_iso[] = { + 0,0, 0,RES_PORT, 0,PA + INDEX_PORT, 0,PATH_ISO, + 0,0, 0,RES_MAC, 0,INDEX_MAC, 0,PATH_ISO, + 0,0, 0,RES_PORT, 0,PB + INDEX_PORT, 0,PATH_ISO +} ; + +static char path_wrap_a[] = { + 0,0, 0,RES_PORT, 0,PA + INDEX_PORT, 0,PATH_PRIM, + 0,0, 0,RES_MAC, 0,INDEX_MAC, 0,PATH_PRIM, + 0,0, 0,RES_PORT, 0,PB + INDEX_PORT, 0,PATH_ISO +} ; + +static char path_wrap_b[] = { + 0,0, 0,RES_PORT, 0,PB + INDEX_PORT, 0,PATH_PRIM, + 0,0, 0,RES_MAC, 0,INDEX_MAC, 0,PATH_PRIM, + 0,0, 0,RES_PORT, 0,PA + INDEX_PORT, 0,PATH_ISO +} ; + +static char path_thru[] = { + 0,0, 0,RES_PORT, 0,PA + INDEX_PORT, 0,PATH_PRIM, + 0,0, 0,RES_MAC, 0,INDEX_MAC, 0,PATH_PRIM, + 0,0, 0,RES_PORT, 0,PB + INDEX_PORT, 0,PATH_PRIM +} ; + +static char path_wrap_s[] = { + 0,0, 0,RES_PORT, 0,PS + INDEX_PORT, 0,PATH_PRIM, + 0,0, 0,RES_MAC, 0,INDEX_MAC, 0,PATH_PRIM, +} ; + +static char path_iso_s[] = { + 0,0, 0,RES_PORT, 0,PS + INDEX_PORT, 0,PATH_ISO, + 0,0, 0,RES_MAC, 0,INDEX_MAC, 0,PATH_ISO, +} ; + +int cem_build_path(smc,to,path_index) +struct s_smc *smc ; +char *to ; +int path_index ; +{ + char *path ; + int len ; + + switch (smc->mib.fddiSMTCF_State) { + default : + case SC0_ISOLATED : + path = smc->s.sas ? path_iso_s : path_iso ; + len = smc->s.sas ? sizeof(path_iso_s) : sizeof(path_iso) ; + break ; + case SC9_C_WRAP_A : + path = path_wrap_a ; + len = sizeof(path_wrap_a) ; + break ; + case SC10_C_WRAP_B : + path = path_wrap_b ; + len = sizeof(path_wrap_b) ; + break ; + case SC4_THRU_A : + path = path_thru ; + len = sizeof(path_thru) ; + break ; + case SC11_C_WRAP_S : + path = path_wrap_s ; + len = sizeof(path_wrap_s) ; + break ; + } + memcpy(to,path,len) ; + + LINT_USE(path_index); + + return(len) ; +} diff -u --recursive --new-file v2.3.46/linux/drivers/net/skfp/drvfbi.c linux/drivers/net/skfp/drvfbi.c --- v2.3.46/linux/drivers/net/skfp/drvfbi.c Wed Dec 31 16:00:00 1969 +++ linux/drivers/net/skfp/drvfbi.c Fri Feb 18 14:55:53 2000 @@ -0,0 +1,1612 @@ +/****************************************************************************** + * + * (C)Copyright 1998,1999 SysKonnect, + * a business unit of Schneider & Koch & Co. Datensysteme GmbH. + * + * See the file "skfddi.c" for further information. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * The information in this file is provided "AS IS" without warranty. + * + ******************************************************************************/ + +/* + * FBI board dependent Driver for SMT and LLC + */ + +#include "h/types.h" +#include "h/fddi.h" +#include "h/smc.h" +#include "h/supern_2.h" +#include "h/skfbiinc.h" + +#ifndef lint +static const char ID_sccs[] = "@(#)drvfbi.c 1.63 99/02/11 (C) SK " ; +#endif + +/* + * PCM active state + */ +#define PC8_ACTIVE 8 + +#define LED_Y_ON 0x11 /* Used for ring up/down indication */ +#define LED_Y_OFF 0x10 + + +#define MS2BCLK(x) ((x)*12500L) + +/* + * valid configuration values are: + */ +#ifdef ISA +const int opt_ints[] = {8, 3, 4, 5, 9, 10, 11, 12, 15} ; +const int opt_iops[] = {8, + 0x100, 0x120, 0x180, 0x1a0, 0x220, 0x240, 0x320, 0x340}; +const int opt_dmas[] = {4, 3, 5, 6, 7} ; +const int opt_eproms[] = {15, 0xc0, 0xc2, 0xc4, 0xc6, 0xc8, 0xca, 0xcc, 0xce, + 0xd0, 0xd2, 0xd4, 0xd6, 0xd8, 0xda, 0xdc} ; +#endif +#ifdef EISA +const int opt_ints[] = {5, 9, 10, 11} ; +const int opt_dmas[] = {0, 5, 6, 7} ; +const int opt_eproms[] = {0xc0, 0xc2, 0xc4, 0xc6, 0xc8, 0xca, 0xcc, 0xce, + 0xd0, 0xd2, 0xd4, 0xd6, 0xd8, 0xda, 0xdc} ; +#endif + +#ifdef MCA +int opt_ints[] = {3, 11, 10, 9} ; /* FM1 */ +int opt_eproms[] = {0, 0xc4, 0xc8, 0xcc, 0xd0, 0xd4, 0xd8, 0xdc} ; +#endif /* MCA */ + +/* + * xPOS_ID:xxxx + * | \ / + * | \/ + * | --------------------- the patched POS_ID of the Adapter + * | xxxx = (Vendor ID low byte, + * | Vendor ID high byte, + * | Device ID low byte, + * | Device ID high byte) + * +------------------------------ the patched oem_id must be + * 'S' for SK or 'I' for IBM + * this is a short id for the driver. + */ +#ifndef MULT_OEM +#ifndef OEM_CONCEPT +#ifndef MCA +const u_char oem_id[] = "xPOS_ID:xxxx" ; +#else +const u_char oem_id[] = "xPOSID1:xxxx" ; /* FM1 card id. */ +#endif +#else /* OEM_CONCEPT */ +#ifndef MCA +const u_char oem_id[] = OEM_ID ; +#else +const u_char oem_id[] = OEM_ID1 ; /* FM1 card id. */ +#endif /* MCA */ +#endif /* OEM_CONCEPT */ +#define ID_BYTE0 8 +#define OEMID(smc,i) oem_id[ID_BYTE0 + i] +#else /* MULT_OEM */ +const struct s_oem_ids oem_ids[] = { +#include "oemids.h" +{0} +}; +#define OEMID(smc,i) smc->hw.oem_id->oi_id[i] +#endif /* MULT_OEM */ + +/* Prototypes of external functions */ +extern void hwt_restart() ; +#ifdef AIX +extern int AIX_vpdReadByte() ; +#endif + + +/* Prototypes of local functions. */ +void smt_stop_watchdog() ; + +#ifdef MCA +static int read_card_id() ; +static void DisableSlotAccess() ; +static void EnableSlotAccess() ; +#ifdef AIX +extern int attach_POS_addr() ; +extern int detach_POS_addr() ; +extern u_char read_POS() ; +extern void write_POS() ; +extern int AIX_vpdReadByte() ; +#else +#define read_POS(smc,a1,a2) ((u_char) inp(a1)) +#define write_POS(smc,a1,a2,a3) outp((a1),(a3)) +#endif +#endif /* MCA */ + + +/* + * FDDI card reset + */ +void card_start(smc) +struct s_smc *smc ; +{ + int i ; +#ifdef PCI + u_char rev_id ; + u_short word; +#endif + + smt_stop_watchdog(smc) ; + +#ifdef ISA + outpw(CSR_A,0) ; /* reset for all chips */ + for (i = 10 ; i ; i--) /* delay for PLC's */ + (void)inpw(ISR_A) ; + OUT_82c54_TIMER(3,COUNT(2) | RW_OP(3) | TMODE(2)) ; + /* counter 2, mode 2 */ + OUT_82c54_TIMER(2,97) ; /* LSB */ + OUT_82c54_TIMER(2,0) ; /* MSB ( 15.6 us ) */ + outpw(CSR_A,CS_CRESET) ; +#endif +#ifdef EISA + outpw(CSR_A,0) ; /* reset for all chips */ + for (i = 10 ; i ; i--) /* delay for PLC's */ + (void)inpw(ISR_A) ; + outpw(CSR_A,CS_CRESET) ; + smc->hw.led = (2<<6) ; + outpw(CSR_A,CS_CRESET | smc->hw.led) ; +#endif +#ifdef MCA + outp(ADDR(CARD_DIS),0) ; /* reset for all chips */ + for (i = 10 ; i ; i--) /* delay for PLC's */ + (void)inpw(ISR_A) ; + outp(ADDR(CARD_EN),0) ; + /* first I/O after reset must not be a access to FORMAC or PLC */ + + /* + * bus timeout (MCA) + */ + OUT_82c54_TIMER(3,COUNT(2) | RW_OP(3) | TMODE(3)) ; + /* counter 2, mode 3 */ + OUT_82c54_TIMER(2,(2*24)) ; /* 3.9 us * 2 square wave */ + OUT_82c54_TIMER(2,0) ; /* MSB */ + + /* POS 102 indicated an activ Check Line or Buss Error monitoring */ + if (inpw(CSA_A) & (POS_EN_CHKINT | POS_EN_BUS_ERR)) { + outp(ADDR(IRQ_CHCK_EN),0) ; + } + + if (!((i = inpw(CSR_A)) & CS_SAS)) { + if (!(i & CS_BYSTAT)) { + outp(ADDR(BYPASS(STAT_INS)),0) ;/* insert station */ + } + } + outpw(LEDR_A,LED_1) ; /* yellow */ +#endif /* MCA */ +#ifdef PCI + /* + * make sure no transfer activity is pending + */ + outpw(FM_A(FM_MDREG1),FM_MINIT) ; + outp(ADDR(B0_CTRL), CTRL_HPI_SET) ; + hwt_wait_time(smc,hwt_quick_read(smc),MS2BCLK(10)) ; + /* + * now reset everything + */ + outp(ADDR(B0_CTRL),CTRL_RST_SET) ; /* reset for all chips */ + i = (int) inp(ADDR(B0_CTRL)) ; /* do dummy read */ + SK_UNUSED(i) ; /* Make LINT happy. */ + outp(ADDR(B0_CTRL), CTRL_RST_CLR) ; + + /* + * Reset all bits in the PCI STATUS register + */ + outp(ADDR(B0_TST_CTRL), TST_CFG_WRITE_ON) ; /* enable for writes */ + word = inpw(PCI_C(PCI_STATUS)) ; + outpw(PCI_C(PCI_STATUS), word | PCI_ERRBITS) ; + outp(ADDR(B0_TST_CTRL), TST_CFG_WRITE_OFF) ; /* disable writes */ + + /* + * Release the reset of all the State machines + * Release Master_Reset + * Release HPI_SM_Reset + */ + outp(ADDR(B0_CTRL), CTRL_MRST_CLR|CTRL_HPI_CLR) ; + + /* + * determine the adapter type + * Note: Do it here, because some drivers may call card_start() once + * at very first before any other initialization functions is + * executed. + */ + rev_id = inp(PCI_C(PCI_REV_ID)) ; + if ((rev_id & 0xf0) == SK_ML_ID_1 || (rev_id & 0xf0) == SK_ML_ID_2) { + smc->hw.hw_is_64bit = TRUE ; + } else { + smc->hw.hw_is_64bit = FALSE ; + } + + /* + * Watermark initialization + */ + if (!smc->hw.hw_is_64bit) { + outpd(ADDR(B4_R1_F), RX_WATERMARK) ; + outpd(ADDR(B5_XA_F), TX_WATERMARK) ; + outpd(ADDR(B5_XS_F), TX_WATERMARK) ; + } + + outp(ADDR(B0_CTRL),CTRL_RST_CLR) ; /* clear the reset chips */ + outp(ADDR(B0_LED),LED_GA_OFF|LED_MY_ON|LED_GB_OFF) ; /* ye LED on */ + + /* init the timer value for the watch dog 2,5 minutes */ + outpd(ADDR(B2_WDOG_INI),0x6FC23AC0) ; + + /* initialize the ISR mask */ + smc->hw.is_imask = ISR_MASK ; + smc->hw.hw_state = STOPPED ; +#endif + GET_PAGE(0) ; /* necessary for BOOT */ +} + +void card_stop(smc) +struct s_smc *smc ; +{ + smt_stop_watchdog(smc) ; + smc->hw.mac_ring_is_up = 0 ; /* ring down */ +#ifdef ISA + outpw(CSR_A,0) ; /* reset for all chips */ +#endif +#ifdef EISA + outpw(CSR_A,0) ; /* reset for all chips */ +#endif +#ifdef MCA + outp(ADDR(CARD_DIS),0) ; /* reset for all chips */ +#endif +#ifdef PCI + /* + * make sure no transfer activity is pending + */ + outpw(FM_A(FM_MDREG1),FM_MINIT) ; + outp(ADDR(B0_CTRL), CTRL_HPI_SET) ; + hwt_wait_time(smc,hwt_quick_read(smc),MS2BCLK(10)) ; + /* + * now reset everything + */ + outp(ADDR(B0_CTRL),CTRL_RST_SET) ; /* reset for all chips */ + outp(ADDR(B0_CTRL),CTRL_RST_CLR) ; /* reset for all chips */ + outp(ADDR(B0_LED),LED_GA_OFF|LED_MY_OFF|LED_GB_OFF) ; /* all LEDs off */ + smc->hw.hw_state = STOPPED ; +#endif +} +/*--------------------------- ISR handling ----------------------------------*/ + +#ifndef PCI +void mac1_irq(smc,stu, stl) +struct s_smc *smc ; +u_short stu; +u_short stl; +{ + int restart_tx = 0 ; +again: +#ifndef ISA +/* + * FORMAC+ bug modified the queue pointer if many read/write accesses happens!? + */ + if (stl & (FM_SPCEPDS | /* parit/coding err. syn.q.*/ + FM_SPCEPDA0 | /* parit/coding err. a.q.0 */ + FM_SPCEPDA1 | /* parit/coding err. a.q.1 */ + FM_SPCEPDA2)) { /* parit/coding err. a.q.2 */ + SMT_PANIC(smc,SMT_E0132, SMT_E0132_MSG) ; + } + if (stl & (FM_STBURS | /* tx buffer underrun syn.q.*/ + FM_STBURA0 | /* tx buffer underrun a.q.0 */ + FM_STBURA1 | /* tx buffer underrun a.q.1 */ + FM_STBURA2)) { /* tx buffer underrun a.q.2 */ + SMT_PANIC(smc,SMT_E0133, SMT_E0133_MSG) ; + } +#endif + if ( (stu & (FM_SXMTABT | /* transmit abort */ +#ifdef SYNC + FM_STXABRS | /* syn. tx abort */ +#endif /* SYNC */ + FM_STXABRA0)) || /* asyn. tx abort */ + (stl & (FM_SQLCKS | /* lock for syn. q. */ + FM_SQLCKA0)) ) { /* lock for asyn. q. */ + formac_tx_restart(smc) ; /* init tx */ + restart_tx = 1 ; + stu = inpw(FM_A(FM_ST1U)) ; + stl = inpw(FM_A(FM_ST1L)) ; + stu &= ~ (FM_STECFRMA0 | FM_STEFRMA0 | FM_STEFRMS) ; + if (stu || stl) + goto again ; + } + +#ifndef SYNC + if (stu & (FM_STECFRMA0 | /* end of chain asyn tx */ + FM_STEFRMA0)) { /* end of frame asyn tx */ + /* free tx_queue */ + smc->hw.n_a_send = 0 ; + if (++smc->hw.fp.tx_free < smc->hw.fp.tx_max) { + start_next_send(smc); + } + restart_tx = 1 ; + } +#else /* SYNC */ + if (stu & (FM_STEFRMA0 | /* end of asyn tx */ + FM_STEFRMS)) { /* end of sync tx */ + restart_tx = 1 ; + } +#endif /* SYNC */ + if (restart_tx) + llc_restart_tx(smc) ; +} +#else /* PCI */ + +void mac1_irq(smc,stu, stl) +struct s_smc *smc ; +u_short stu; +u_short stl; +{ + int restart_tx = 0 ; +again: + + /* + * parity error: note encoding error is not possible in tag mode + */ + if (stl & (FM_SPCEPDS | /* parity err. syn.q.*/ + FM_SPCEPDA0 | /* parity err. a.q.0 */ + FM_SPCEPDA1)) { /* parity err. a.q.1 */ + SMT_PANIC(smc,SMT_E0134, SMT_E0134_MSG) ; + } + /* + * buffer underrun: can only occur if a tx threshold is specified + */ + if (stl & (FM_STBURS | /* tx buffer underrun syn.q.*/ + FM_STBURA0 | /* tx buffer underrun a.q.0 */ + FM_STBURA1)) { /* tx buffer underrun a.q.2 */ + SMT_PANIC(smc,SMT_E0133, SMT_E0133_MSG) ; + } + + if ( (stu & (FM_SXMTABT | /* transmit abort */ + FM_STXABRS | /* syn. tx abort */ + FM_STXABRA0)) || /* asyn. tx abort */ + (stl & (FM_SQLCKS | /* lock for syn. q. */ + FM_SQLCKA0)) ) { /* lock for asyn. q. */ + formac_tx_restart(smc) ; /* init tx */ + restart_tx = 1 ; + stu = inpw(FM_A(FM_ST1U)) ; + stl = inpw(FM_A(FM_ST1L)) ; + stu &= ~ (FM_STECFRMA0 | FM_STEFRMA0 | FM_STEFRMS) ; + if (stu || stl) + goto again ; + } + + if (stu & (FM_STEFRMA0 | /* end of asyn tx */ + FM_STEFRMS)) { /* end of sync tx */ + restart_tx = 1 ; + } + + if (restart_tx) + llc_restart_tx(smc) ; +} +#endif /* PCI */ +/* + * interrupt source= plc1 + * this function is called in nwfbisr.asm + */ +void plc1_irq(smc) +struct s_smc *smc ; +{ + u_short st = inpw(PLC(PB,PL_INTR_EVENT)) ; + +#if (defined(ISA) || defined(EISA)) + /* reset PLC Int. bits */ + outpw(PLC1_I,inpw(PLC1_I)) ; +#endif + plc_irq(smc,PB,st) ; +} + +/* + * interrupt source= plc2 + * this function is called in nwfbisr.asm + */ +void plc2_irq(smc) +struct s_smc *smc ; +{ + u_short st = inpw(PLC(PA,PL_INTR_EVENT)) ; + +#if (defined(ISA) || defined(EISA)) + /* reset PLC Int. bits */ + outpw(PLC2_I,inpw(PLC2_I)) ; +#endif + plc_irq(smc,PA,st) ; +} + + +/* + * interrupt source= timer + */ +void timer_irq(smc) +struct s_smc *smc ; +{ + hwt_restart(smc); + smc->hw.t_stop = smc->hw.t_start; + smt_timer_done(smc) ; +} + +/* + * return S-port (PA or PB) + */ +int pcm_get_s_port(smc) +struct s_smc *smc ; +{ + SK_UNUSED(smc) ; + return(PS) ; +} + +/* + * Station Label = "FDDI-XYZ" where + * + * X = connector type + * Y = PMD type + * Z = port type + */ +#define STATION_LABEL_CONNECTOR_OFFSET 5 +#define STATION_LABEL_PMD_OFFSET 6 +#define STATION_LABEL_PORT_OFFSET 7 + +void read_address(smc,mac_addr) +struct s_smc *smc ; +u_char *mac_addr ; +{ + char ConnectorType ; + char PmdType ; + int i ; + + extern const u_char canonical[256] ; + +#if (defined(ISA) || defined(MCA)) + for (i = 0; i < 4 ;i++) { /* read mac address from board */ + smc->hw.fddi_phys_addr.a[i] = + canonical[(inpw(PR_A(i+SA_MAC))&0xff)] ; + } + for (i = 4; i < 6; i++) { + smc->hw.fddi_phys_addr.a[i] = + canonical[(inpw(PR_A(i+SA_MAC+PRA_OFF))&0xff)] ; + } +#endif +#ifdef EISA + /* + * Note: We get trouble on an Alpha machine if we make a inpw() + * instead of inp() + */ + for (i = 0; i < 4 ;i++) { /* read mac address from board */ + smc->hw.fddi_phys_addr.a[i] = + canonical[inp(PR_A(i+SA_MAC))] ; + } + for (i = 4; i < 6; i++) { + smc->hw.fddi_phys_addr.a[i] = + canonical[inp(PR_A(i+SA_MAC+PRA_OFF))] ; + } +#endif +#ifdef PCI + for (i = 0; i < 6; i++) { /* read mac address from board */ + smc->hw.fddi_phys_addr.a[i] = + canonical[inp(ADDR(B2_MAC_0+i))] ; + } +#endif +#ifndef PCI + ConnectorType = inpw(PR_A(SA_PMD_TYPE)) & 0xff ; + PmdType = inpw(PR_A(SA_PMD_TYPE+1)) & 0xff ; +#else + ConnectorType = inp(ADDR(B2_CONN_TYP)) ; + PmdType = inp(ADDR(B2_PMD_TYP)) ; +#endif + + smc->y[PA].pmd_type[PMD_SK_CONN] = + smc->y[PB].pmd_type[PMD_SK_CONN] = ConnectorType ; + smc->y[PA].pmd_type[PMD_SK_PMD ] = + smc->y[PB].pmd_type[PMD_SK_PMD ] = PmdType ; + + if (mac_addr) { + for (i = 0; i < 6 ;i++) { + smc->hw.fddi_canon_addr.a[i] = mac_addr[i] ; + smc->hw.fddi_home_addr.a[i] = canonical[mac_addr[i]] ; + } + return ; + } + smc->hw.fddi_home_addr = smc->hw.fddi_phys_addr ; + + for (i = 0; i < 6 ;i++) { + smc->hw.fddi_canon_addr.a[i] = + canonical[smc->hw.fddi_phys_addr.a[i]] ; + } +} + +/* + * FDDI card soft reset + */ +void init_board(smc,mac_addr) +struct s_smc *smc ; +u_char *mac_addr ; +{ + card_start(smc) ; + read_address(smc,mac_addr) ; + +#ifndef PCI + if (inpw(CSR_A) & CS_SAS) +#else + if (!(inp(ADDR(B0_DAS)) & DAS_AVAIL)) +#endif + smc->s.sas = SMT_SAS ; /* Single att. station */ + else + smc->s.sas = SMT_DAS ; /* Dual att. station */ + +#ifndef PCI + if (inpw(CSR_A) & CS_BYSTAT) +#else + if (!(inp(ADDR(B0_DAS)) & DAS_BYP_ST)) +#endif + smc->mib.fddiSMTBypassPresent = 0 ; + /* without opt. bypass */ + else + smc->mib.fddiSMTBypassPresent = 1 ; + /* with opt. bypass */ +} + +/* + * insert or deinsert optical bypass (called by ECM) + */ +void sm_pm_bypass_req(smc,mode) +struct s_smc *smc ; +int mode; +{ +#if (defined(ISA) || defined(EISA)) + int csra_v ; +#endif + + DB_ECMN(1,"ECM : sm_pm_bypass_req(%s)\n",(mode == BP_INSERT) ? + "BP_INSERT" : "BP_DEINSERT",0) ; + + if (smc->s.sas != SMT_DAS) + return ; + +#if (defined(ISA) || defined(EISA)) + + csra_v = inpw(CSR_A) & ~CS_BYPASS ; +#ifdef EISA + csra_v |= smc->hw.led ; +#endif + + switch(mode) { + case BP_INSERT : + outpw(CSR_A,csra_v | CS_BYPASS) ; + break ; + case BP_DEINSERT : + outpw(CSR_A,csra_v) ; + break ; + } +#endif /* ISA / EISA */ +#ifdef MCA + switch(mode) { + case BP_INSERT : + outp(ADDR(BYPASS(STAT_INS)),0) ;/* insert station */ + break ; + case BP_DEINSERT : + outp(ADDR(BYPASS(STAT_BYP)),0) ; /* bypass station */ + break ; + } +#endif +#ifdef PCI + switch(mode) { + case BP_INSERT : + outp(ADDR(B0_DAS),DAS_BYP_INS) ; /* insert station */ + break ; + case BP_DEINSERT : + outp(ADDR(B0_DAS),DAS_BYP_RMV) ; /* bypass station */ + break ; + } +#endif +} + +/* + * check if bypass connected + */ +int sm_pm_bypass_present(smc) +struct s_smc *smc ; +{ +#ifndef PCI + return( (inpw(CSR_A) & CS_BYSTAT) ? FALSE : TRUE ) ; +#else + return( (inp(ADDR(B0_DAS)) & DAS_BYP_ST) ? TRUE: FALSE) ; +#endif +} + +void plc_clear_irq(smc,p) +struct s_smc *smc ; +int p ; +{ + SK_UNUSED(p) ; + +#if (defined(ISA) || defined(EISA)) + switch (p) { + case PA : + /* reset PLC Int. bits */ + outpw(PLC2_I,inpw(PLC2_I)) ; + break ; + case PB : + /* reset PLC Int. bits */ + outpw(PLC1_I,inpw(PLC1_I)) ; + break ; + } +#else + SK_UNUSED(smc) ; +#endif +} + + +/* + * led_indication called by rmt_indication() and + * pcm_state_change() + * + * Input: + * smc: SMT context + * led_event: + * 0 Only switch green LEDs according to their respective PCM state + * LED_Y_OFF just switch yellow LED off + * LED_Y_ON just switch yello LED on + */ +void led_indication(smc,led_event) +struct s_smc *smc ; +int led_event; +{ + /* use smc->hw.mac_ring_is_up == TRUE + * as indication for Ring Operational + */ + u_short led_state ; + struct s_phy *phy ; + struct fddi_mib_p *mib_a ; + struct fddi_mib_p *mib_b ; + + phy = &smc->y[PA] ; + mib_a = phy->mib ; + phy = &smc->y[PB] ; + mib_b = phy->mib ; + +#ifdef EISA + /* Ring up = yellow led OFF*/ + if (led_event == LED_Y_ON) { + smc->hw.led |= CS_LED_1 ; + } + else if (led_event == LED_Y_OFF) { + smc->hw.led &= ~CS_LED_1 ; + } + else { + /* Link at Port A or B = green led ON */ + if (mib_a->fddiPORTPCMState == PC8_ACTIVE || + mib_b->fddiPORTPCMState == PC8_ACTIVE) { + smc->hw.led |= CS_LED_0 ; + } + else { + smc->hw.led &= ~CS_LED_0 ; + } + } +#endif +#ifdef MCA + led_state = inpw(LEDR_A) ; + + /* Ring up = yellow led OFF*/ + if (led_event == LED_Y_ON) { + led_state |= LED_1 ; + } + else if (led_event == LED_Y_OFF) { + led_state &= ~LED_1 ; + } + else { + led_state &= ~(LED_2|LED_0) ; + + /* Link at Port A = green led A ON */ + if (mib_a->fddiPORTPCMState == PC8_ACTIVE) { + led_state |= LED_2 ; + } + + /* Link at Port B/S = green led B ON */ + if (mib_b->fddiPORTPCMState == PC8_ACTIVE) { + led_state |= LED_0 ; + } + } + + outpw(LEDR_A, led_state) ; +#endif /* MCA */ +#ifdef PCI + led_state = 0 ; + + /* Ring up = yellow led OFF*/ + if (led_event == LED_Y_ON) { + led_state |= LED_MY_ON ; + } + else if (led_event == LED_Y_OFF) { + led_state |= LED_MY_OFF ; + } + else { /* PCM state changed */ + /* Link at Port A/S = green led A ON */ + if (mib_a->fddiPORTPCMState == PC8_ACTIVE) { + led_state |= LED_GA_ON ; + } + else { + led_state |= LED_GA_OFF ; + } + + /* Link at Port B = green led B ON */ + if (mib_b->fddiPORTPCMState == PC8_ACTIVE) { + led_state |= LED_GB_ON ; + } + else { + led_state |= LED_GB_OFF ; + } + } + + outp(ADDR(B0_LED), led_state) ; +#endif /* PCI */ + +} + + +void pcm_state_change(smc,plc,p_state) +struct s_smc *smc; +int plc; +int p_state; +{ + /* + * the current implementation of pcm_state_change() in the driver + * parts must be renamed to drv_pcm_state_change() which will be called + * now after led_indication. + */ + DRV_PCM_STATE_CHANGE(smc,plc,p_state) ; + + led_indication(smc,0) ; +} + + +void rmt_indication(smc,i) +struct s_smc *smc ; +int i; +{ + /* Call a driver special function if defined */ + DRV_RMT_INDICATION(smc,i) ; + + led_indication(smc, i ? LED_Y_OFF : LED_Y_ON) ; +} + + +/* + * llc_recover_tx called by init_tx (fplus.c) + */ +void llc_recover_tx(smc) +struct s_smc *smc ; +{ +#ifdef LOAD_GEN + extern int load_gen_flag ; + + load_gen_flag = 0 ; +#endif +#ifndef SYNC + smc->hw.n_a_send= 0 ; +#else + SK_UNUSED(smc) ; +#endif +} + +/*--------------------------- DMA init ----------------------------*/ +#ifdef ISA + +/* + * init DMA + */ +void init_dma(smc,dma) +struct s_smc *smc; +int dma; +{ + SK_UNUSED(smc) ; + + /* + * set cascade mode, + * clear mask bit (enable DMA cannal) + */ + if (dma > 3) { + outp(0xd6,(dma & 0x03) | 0xc0) ; + outp(0xd4, dma & 0x03) ; + } + else { + outp(0x0b,(dma & 0x03) | 0xc0) ; + outp(0x0a,dma & 0x03) ; + } +} + +/* + * disable DMA + */ +void dis_dma(smc,dma) +struct s_smc *smc ; +int dma; +{ + SK_UNUSED(smc) ; + + /* + * set mask bit (disable DMA cannal) + */ + if (dma > 3) { + outp(0xd4,(dma & 0x03) | 0x04) ; + } + else { + outp(0x0a,(dma & 0x03) | 0x04) ; + } +} + +#endif /* ISA */ + +#ifdef EISA + +/*arrays with io adresses of dma controller length and adress registers*/ +static const int cntr[8] = { 0x001,0x003,0x005,0x007,0,0x0c6,0x0ca,0x0ce } ; +static const int base[8] = { 0x000,0x002,0x004,0x006,0,0x0c4,0x0c8,0x0cc } ; +static const int page[8] = { 0x087,0x083,0x081,0x082,0,0x08b,0x089,0x08a } ; + +void init_dma(smc,dma) +struct s_smc *smc ; +int dma; +{ + /* + * extended mode register + * 32 bit IO + * type c + * TC output + * disable stop + */ + + /* mode read (write) demand */ + smc->hw.dma_rmode = (dma & 3) | 0x08 | 0x0 ; + smc->hw.dma_wmode = (dma & 3) | 0x04 | 0x0 ; + + /* 32 bit IO's, burst DMA mode (type "C") */ + smc->hw.dma_emode = (dma & 3) | 0x08 | 0x30 ; + + outp((dma < 4) ? 0x40b : 0x4d6,smc->hw.dma_emode) ; + + /* disable chaining */ + outp((dma < 4) ? 0x40a : 0x4d4,(dma&3)) ; + + /*load dma controller addresses for fast access during set dma*/ + smc->hw.dma_base_word_count = cntr[smc->hw.dma]; + smc->hw.dma_base_address = base[smc->hw.dma]; + smc->hw.dma_base_address_page = page[smc->hw.dma]; + +} + +void dis_dma(smc,dma) +struct s_smc *smc ; +int dma; +{ + SK_UNUSED(smc) ; + + outp((dma < 4) ? 0x0a : 0xd4,(dma&3)|4) ;/* mask bit */ +} +#endif /* EISA */ + +#ifdef MCA +void init_dma(smc,dma) +struct s_smc *smc; +int dma; +{ + SK_UNUSED(smc) ; + SK_UNUSED(dma) ; +} +void dis_dma(smc,dma) +struct s_smc *smc; +int dma; +{ + SK_UNUSED(smc) ; + SK_UNUSED(dma) ; +} +#endif + +#ifdef PCI +void init_dma(smc,dma) +struct s_smc *smc; +int dma; +{ + SK_UNUSED(smc) ; + SK_UNUSED(dma) ; +} +void dis_dma(smc,dma) +struct s_smc *smc; +int dma; +{ + SK_UNUSED(smc) ; + SK_UNUSED(dma) ; +} +#endif + +#ifdef MULT_OEM +static int is_equal_num(comp1,comp2,num) +char comp1[] ; +char comp2[] ; +int num ; +{ + int i ; + + for (i = 0 ; i < num ; i++) { + if (comp1[i] != comp2[i]) + return (0) ; + } + return (1) ; +} /* is_equal_num */ + + +/* + * set the OEM ID defaults, and test the contents of the OEM data base + * The default OEM is the first ACTIVE entry in the OEM data base + * + * returns: 0 success + * 1 error in data base + * 2 data base empty + * 3 no active entry + */ +int set_oi_id_def(smc) +struct s_smc *smc ; +{ + int sel_id ; + int i ; + int act_entries ; + + i = 0 ; + sel_id = -1 ; + act_entries = FALSE ; + smc->hw.oem_id = 0 ; + smc->hw.oem_min_status = OI_STAT_ACTIVE ; + + /* check OEM data base */ + while (oem_ids[i].oi_status) { + switch (oem_ids[i].oi_status) { + case OI_STAT_ACTIVE: + act_entries = TRUE ; /* we have active IDs */ + if (sel_id == -1) + sel_id = i ; /* save the first active ID */ + case OI_STAT_VALID: + case OI_STAT_PRESENT: + i++ ; + break ; /* entry ok */ + default: + return (1) ; /* invalid oi_status */ + } + } + + if (i == 0) + return (2) ; + if (!act_entries) + return (3) ; + + /* ok, we have a valid OEM data base with an active entry */ + smc->hw.oem_id = (struct s_oem_ids *) &oem_ids[sel_id] ; + return (0) ; +} +#endif /* MULT_OEM */ + + +#ifdef MCA +/************************ + * + * BEGIN_MANUAL_ENTRY() + * + * exist_board + * + * Check if an MCA board is present in the specified slot. + * + * int exist_board( + * struct s_smc *smc, + * int slot) ; + * In + * smc - A pointer to the SMT Context struct. + * + * slot - The number of the slot to inspect. + * Out + * 0 = No adapter present. + * 1 = Found FM1 adapter. + * + * Pseudo + * Read MCA ID + * for all valid OEM_IDs + * compare with ID read + * if equal, return 1 + * return(0 + * + * Note + * The smc pointer must be valid now. + * + * END_MANUAL_ENTRY() + * + ************************/ +#define LONG_CARD_ID(lo, hi) ((((hi) & 0xff) << 8) | ((lo) & 0xff)) +int exist_board(smc,slot) +struct s_smc *smc ; +int slot ; +{ +#ifdef MULT_OEM + SK_LOC_DECL(u_char,id[2]) ; + int idi ; +#endif /* MULT_OEM */ + + /* No longer valid. */ + if (smc == NULL) + return(0) ; + +#ifndef MULT_OEM + if (read_card_id(smc, slot) + == LONG_CARD_ID(OEMID(smc,0), OEMID(smc,1))) + return (1) ; /* Found FM adapter. */ + +#else /* MULT_OEM */ + idi = read_card_id(smc, slot) ; + id[0] = idi & 0xff ; + id[1] = idi >> 8 ; + + smc->hw.oem_id = (struct s_oem_ids *) &oem_ids[0] ; + for (; smc->hw.oem_id->oi_status != OI_STAT_LAST; smc->hw.oem_id++) { + if (smc->hw.oem_id->oi_status < smc->hw.oem_min_status) + continue ; + + if (is_equal_num(&id[0],&OEMID(smc,0),2)) + return (1) ; + } +#endif /* MULT_OEM */ + return (0) ; /* No adapter found. */ +} + +/************************ + * + * read_card_id + * + * Read the MCA card id from the specified slot. + * In + * smc - A pointer to the SMT Context struct. + * CAVEAT: This pointer may be NULL and *must not* be used within this + * function. It's only purpose is for drivers that need some information + * for the inp() and outp() macros. + * + * slot - The number of the slot for which the card id is returned. + * Out + * Returns the card id read from the specified slot. If an illegal slot + * number is specified, the function returns zero. + * + ************************/ +static int read_card_id(smc,slot) +struct s_smc *smc ; /* Do not use. */ +int slot ; +{ + int card_id ; + + SK_UNUSED(smc) ; /* Make LINT happy. */ + if ((slot < 1) || (slot > 15)) /* max 16 slots, 0 = motherboard */ + return (0) ; /* Illegal slot number specified. */ + + EnableSlotAccess(smc, slot) ; + + card_id = ((read_POS(smc,POS_ID_HIGH,slot - 1) & 0xff) << 8) | + (read_POS(smc,POS_ID_LOW,slot - 1) & 0xff) ; + + DisableSlotAccess(smc) ; + + return (card_id) ; +} + +/************************ + * + * BEGIN_MANUAL_ENTRY() + * + * get_board_para + * + * Get adapter configuration information. Fill all board specific + * parameters within the 'smc' structure. + * + * int get_board_para( + * struct s_smc *smc, + * int slot) ; + * In + * smc - A pointer to the SMT Context struct, to which this function will + * write some adapter configuration data. + * + * slot - The number of the slot, in which the adapter is installed. + * Out + * 0 = No adapter present. + * 1 = Ok. + * 2 = Adapter present, but card enable bit not set. + * + * END_MANUAL_ENTRY() + * + ************************/ +int get_board_para(smc,slot) +struct s_smc *smc ; +int slot ; +{ + int val ; + int i ; + + /* Check if adapter present & get type of adapter. */ + switch (exist_board(smc, slot)) { + case 0: /* Adapter not present. */ + return (0) ; + case 1: /* FM Rev. 1 */ + smc->hw.rev = FM1_REV ; + smc->hw.VFullRead = 0x0a ; + smc->hw.VFullWrite = 0x05 ; + smc->hw.DmaWriteExtraBytes = 8 ; /* 2 extra words. */ + break ; + } + smc->hw.slot = slot ; + + EnableSlotAccess(smc, slot) ; + + if (!(read_POS(smc,POS_102, slot - 1) & POS_CARD_EN)) { + DisableSlotAccess(smc) ; + return (2) ; /* Card enable bit not set. */ + } + + val = read_POS(smc,POS_104, slot - 1) ; /* I/O, IRQ */ + +#ifndef MEM_MAPPED_IO /* is defined by the operating system */ + i = val & POS_IOSEL ; /* I/O base addr. (0x0200 .. 0xfe00) */ + smc->hw.iop = (i + 1) * 0x0400 - 0x200 ; +#endif + i = ((val & POS_IRQSEL) >> 6) & 0x03 ; /* IRQ <0, 1> */ + smc->hw.irq = opt_ints[i] ; + + /* FPROM base addr. */ + i = ((read_POS(smc,POS_103, slot - 1) & POS_MSEL) >> 4) & 0x07 ; + smc->hw.eprom = opt_eproms[i] ; + + DisableSlotAccess(smc) ; + + /* before this, the smc->hw.iop must be set !!! */ + smc->hw.slot_32 = inpw(CSF_A) & SLOT_32 ; + + return (1) ; +} + +/* Enable access to specified MCA slot. */ +static void EnableSlotAccess(smc,slot) +struct s_smc *smc ; +int slot ; +{ + SK_UNUSED(slot) ; + +#ifndef AIX + SK_UNUSED(smc) ; + + /* System mode. */ + outp(POS_SYS_SETUP, POS_SYSTEM) ; + + /* Select slot. */ + outp(POS_CHANNEL_POS, POS_CHANNEL_BIT | (slot-1)) ; +#else + attach_POS_addr (smc) ; +#endif +} + +/* Disable access to MCA slot formerly enabled via EnableSlotAccess(). */ +static void DisableSlotAccess(smc) +struct s_smc *smc ; +{ +#ifndef AIX + SK_UNUSED(smc) ; + + outp(POS_CHANNEL_POS, 0) ; +#else + detach_POS_addr (smc) ; +#endif +} +#endif /* MCA */ + +#ifdef EISA +#ifndef MEM_MAPPED_IO +#define SADDR(slot) (((slot)<<12)&0xf000) +#else /* MEM_MAPPED_IO */ +#define SADDR(slot) (smc->hw.iop) +#endif /* MEM_MAPPED_IO */ + +/************************ + * + * BEGIN_MANUAL_ENTRY() + * + * exist_board + * + * Check if an EISA board is present in the specified slot. + * + * int exist_board( + * struct s_smc *smc, + * int slot) ; + * In + * smc - A pointer to the SMT Context struct. + * + * slot - The number of the slot to inspect. + * Out + * 0 = No adapter present. + * 1 = Found adapter. + * + * Pseudo + * Read EISA ID + * for all valid OEM_IDs + * compare with ID read + * if equal, return 1 + * return(0 + * + * Note + * The smc pointer must be valid now. + * + ************************/ +int exist_board(smc,slot) +struct s_smc *smc ; +int slot ; +{ + int i ; +#ifdef MULT_OEM + SK_LOC_DECL(u_char,id[4]) ; +#endif /* MULT_OEM */ + + /* No longer valid. */ + if (smc == NULL) + return(0); + + SK_UNUSED(slot) ; + +#ifndef MULT_OEM + for (i = 0 ; i < 4 ; i++) { + if (inp(SADDR(slot)+PRA(i)) != OEMID(smc,i)) + return(0) ; + } + return(1) ; +#else /* MULT_OEM */ + for (i = 0 ; i < 4 ; i++) + id[i] = inp(SADDR(slot)+PRA(i)) ; + + smc->hw.oem_id = (struct s_oem_ids *) &oem_ids[0] ; + + for (; smc->hw.oem_id->oi_status != OI_STAT_LAST; smc->hw.oem_id++) { + if (smc->hw.oem_id->oi_status < smc->hw.oem_min_status) + continue ; + + if (is_equal_num(&id[0],&OEMID(smc,0),4)) + return (1) ; + } + return (0) ; /* No adapter found. */ +#endif /* MULT_OEM */ +} + + +int get_board_para(smc,slot) +struct s_smc *smc ; +int slot ; +{ + int i ; + + if (!exist_board(smc,slot)) + return(0) ; + + smc->hw.slot = slot ; +#ifndef MEM_MAPPED_IO /* if defined by the operating system */ + smc->hw.iop = SADDR(slot) ; +#endif + + if (!(inp(C0_A(0))&CFG_CARD_EN)) { + return(2) ; /* CFG_CARD_EN bit not set! */ + } + + smc->hw.irq = opt_ints[(inp(C1_A(0)) & CFG_IRQ_SEL)] ; + smc->hw.dma = opt_dmas[((inp(C1_A(0)) & CFG_DRQ_SEL)>>3)] ; + + if ((i = inp(C2_A(0)) & CFG_EPROM_SEL) != 0x0f) + smc->hw.eprom = opt_eproms[i] ; + else + smc->hw.eprom = 0 ; + + smc->hw.DmaWriteExtraBytes = 8 ; + + return(1) ; +} +#endif /* EISA */ + +#ifdef ISA +#ifndef MULT_OEM +const u_char sklogo[6] = SKLOGO_STR ; +#define SIZE_SKLOGO(smc) sizeof(sklogo) +#define SKLOGO(smc,i) sklogo[i] +#else /* MULT_OEM */ +#define SIZE_SKLOGO(smc) smc->hw.oem_id->oi_logo_len +#define SKLOGO(smc,i) smc->hw.oem_id->oi_logo[i] +#endif /* MULT_OEM */ + + +int exist_board(smc,port) +struct s_smc *smc ; +HW_PTR port ; +{ + int i ; +#ifdef MULT_OEM + int bytes_read ; + u_char board_logo[15] ; + SK_LOC_DECL(u_char,id[4]) ; +#endif /* MULT_OEM */ + + /* No longer valid. */ + if (smc == NULL) + return(0); + + SK_UNUSED(smc) ; +#ifndef MULT_OEM + for (i = SADDRL ; i < (signed) (SADDRL+SIZE_SKLOGO(smc)) ; i++) { + if ((u_char)inpw((PRA(i)+port)) != SKLOGO(smc,i-SADDRL)) { + return(0) ; + } + } + + /* check MAC address (S&K or other) */ + for (i = 0 ; i < 3 ; i++) { + if ((u_char)inpw((PRA(i)+port)) != OEMID(smc,i)) + return(0) ; + } + return(1) ; +#else /* MULT_OEM */ + smc->hw.oem_id = (struct s_oem_ids *) &oem_ids[0] ; + board_logo[0] = (u_char)inpw((PRA(SADDRL)+port)) ; + bytes_read = 1 ; + + for (; smc->hw.oem_id->oi_status != OI_STAT_LAST; smc->hw.oem_id++) { + if (smc->hw.oem_id->oi_status < smc->hw.oem_min_status) + continue ; + + /* Test all read bytes with current OEM_entry */ + /* for (i=0; (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 -u --recursive --new-file v2.3.46/linux/drivers/net/skfp/ecm.c linux/drivers/net/skfp/ecm.c --- v2.3.46/linux/drivers/net/skfp/ecm.c Wed Dec 31 16:00:00 1969 +++ linux/drivers/net/skfp/ecm.c Fri Feb 18 14:55:53 2000 @@ -0,0 +1,547 @@ +/****************************************************************************** + * + * (C)Copyright 1998,1999 SysKonnect, + * a business unit of Schneider & Koch & Co. Datensysteme GmbH. + * + * See the file "skfddi.c" for further information. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * The information in this file is provided "AS IS" without warranty. + * + ******************************************************************************/ + +/* + SMT ECM + Entity Coordination Management + Hardware independant state machine +*/ + +/* + * Hardware independant state machine implemantation + * The following external SMT functions are referenced : + * + * queue_event() + * smt_timer_start() + * smt_timer_stop() + * + * The following external HW dependant functions are referenced : + * sm_pm_bypass_req() + * sm_pm_ls_latch() + * sm_pm_get_ls() + * + * The following HW dependant events are required : + * NONE + * + */ + +#include "h/types.h" +#include "h/fddi.h" +#include "h/smc.h" + +#define KERNEL +#include "h/smtstate.h" + +#ifndef lint +static const char ID_sccs[] = "@(#)ecm.c 2.7 99/08/05 (C) SK " ; +#endif + +/* + * FSM Macros + */ +#define AFLAG 0x10 +#define GO_STATE(x) (smc->mib.fddiSMTECMState = (x)|AFLAG) +#define ACTIONS_DONE() (smc->mib.fddiSMTECMState &= ~AFLAG) +#define ACTIONS(x) (x|AFLAG) + +#define EC0_OUT 0 /* not inserted */ +#define EC1_IN 1 /* inserted */ +#define EC2_TRACE 2 /* tracing */ +#define EC3_LEAVE 3 /* leaving the ring */ +#define EC4_PATH_TEST 4 /* performing path test */ +#define EC5_INSERT 5 /* bypass being turned on */ +#define EC6_CHECK 6 /* checking bypass */ +#define EC7_DEINSERT 7 /* bypass being turnde off */ + +#ifdef DEBUG +/* + * symbolic state names + */ +static const char * const ecm_states[] = { + "EC0_OUT","EC1_IN","EC2_TRACE","EC3_LEAVE","EC4_PATH_TEST", + "EC5_INSERT","EC6_CHECK","EC7_DEINSERT" +} ; + +/* + * symbolic event names + */ +static const char * const ecm_events[] = { + "NONE","EC_CONNECT","EC_DISCONNECT","EC_TRACE_PROP","EC_PATH_TEST", + "EC_TIMEOUT_TD","EC_TIMEOUT_TMAX", + "EC_TIMEOUT_IMAX","EC_TIMEOUT_INMAX","EC_TEST_DONE" +} ; +#endif + +/* + * all Globals are defined in smc.h + * struct s_ecm + */ + +/* + * function declarations + */ + +static void ecm_fsm() ; +static void start_ecm_timer() ; +static void stop_ecm_timer() ; +static void prop_actions() ; + +/* + init ECM state machine + clear all ECM vars and flags +*/ +void ecm_init(smc) +struct s_smc *smc ; +{ + smc->e.path_test = PT_PASSED ; + smc->e.trace_prop = 0 ; + smc->e.sb_flag = 0 ; + smc->mib.fddiSMTECMState = ACTIONS(EC0_OUT) ; + smc->e.ecm_line_state = FALSE ; +} + +/* + ECM state machine + called by dispatcher + + do + display state change + process event + until SM is stable +*/ +void ecm(smc,event) +struct s_smc *smc ; +int event ; +{ + int state ; + + do { + DB_ECM("ECM : state %s%s", + (smc->mib.fddiSMTECMState & AFLAG) ? "ACTIONS " : "", + ecm_states[smc->mib.fddiSMTECMState & ~AFLAG]) ; + DB_ECM(" event %s\n",ecm_events[event],0) ; + state = smc->mib.fddiSMTECMState ; + ecm_fsm(smc,event) ; + event = 0 ; + } while (state != smc->mib.fddiSMTECMState) ; + ecm_state_change(smc,(int)smc->mib.fddiSMTECMState) ; +} + +/* + process ECM event +*/ +static void ecm_fsm(smc,cmd) +struct s_smc *smc ; +int cmd ; +{ + int ls_a ; /* current line state PHY A */ + int ls_b ; /* current line state PHY B */ + int p ; /* ports */ + + + smc->mib.fddiSMTBypassPresent = sm_pm_bypass_present(smc) ; + if (cmd == EC_CONNECT) + smc->mib.fddiSMTRemoteDisconnectFlag = FALSE ; + + /* For AIX event notification: */ + /* Is a disconnect command remotely issued ? */ + if (cmd == EC_DISCONNECT && + smc->mib.fddiSMTRemoteDisconnectFlag == TRUE) + AIX_EVENT (smc, (u_long) CIO_HARD_FAIL, (u_long) + FDDI_REMOTE_DISCONNECT, smt_get_event_word(smc), + smt_get_error_word(smc) ); + + /*jd 05-Aug-1999 Bug #10419 "Port Disconnect fails at Dup MAc Cond."*/ + if (cmd == EC_CONNECT) { + smc->e.DisconnectFlag = FALSE ; + } + else if (cmd == EC_DISCONNECT) { + smc->e.DisconnectFlag = TRUE ; + } + + switch(smc->mib.fddiSMTECMState) { + case ACTIONS(EC0_OUT) : + /* + * We do not perform a path test + */ + smc->e.path_test = PT_PASSED ; + smc->e.ecm_line_state = FALSE ; + stop_ecm_timer(smc) ; + ACTIONS_DONE() ; + break ; + case EC0_OUT: + /*EC01*/ + if (cmd == EC_CONNECT && !smc->mib.fddiSMTBypassPresent + && smc->e.path_test==PT_PASSED) { + GO_STATE(EC1_IN) ; + break ; + } + /*EC05*/ + else if (cmd == EC_CONNECT && (smc->e.path_test==PT_PASSED) && + smc->mib.fddiSMTBypassPresent && + (smc->s.sas == SMT_DAS)) { + GO_STATE(EC5_INSERT) ; + break ; + } + break; + case ACTIONS(EC1_IN) : + stop_ecm_timer(smc) ; + smc->e.trace_prop = 0 ; + sm_ma_control(smc,MA_TREQ) ; + for (p = 0 ; p < NUMPHYS ; p++) + if (smc->mib.p[p].fddiPORTHardwarePresent) + queue_event(smc,EVENT_PCMA+p,PC_START) ; + ACTIONS_DONE() ; + break ; + case EC1_IN: + /*EC12*/ + if (cmd == EC_TRACE_PROP) { + prop_actions(smc) ; + GO_STATE(EC2_TRACE) ; + break ; + } + /*EC13*/ + else if (cmd == EC_DISCONNECT) { + GO_STATE(EC3_LEAVE) ; + break ; + } + break; + case ACTIONS(EC2_TRACE) : + start_ecm_timer(smc,MIB2US(smc->mib.fddiSMTTrace_MaxExpiration), + EC_TIMEOUT_TMAX) ; + ACTIONS_DONE() ; + break ; + case EC2_TRACE : + /*EC22*/ + if (cmd == EC_TRACE_PROP) { + prop_actions(smc) ; + GO_STATE(EC2_TRACE) ; + break ; + } + /*EC23a*/ + else if (cmd == EC_DISCONNECT) { + smc->e.path_test = PT_EXITING ; + GO_STATE(EC3_LEAVE) ; + break ; + } + /*EC23b*/ + else if (smc->e.path_test == PT_PENDING) { + GO_STATE(EC3_LEAVE) ; + break ; + } + /*EC23c*/ + else if (cmd == EC_TIMEOUT_TMAX) { + /* Trace_Max is expired */ + /* -> send AIX_EVENT */ + AIX_EVENT(smc, (u_long) FDDI_RING_STATUS, + (u_long) FDDI_SMT_ERROR, (u_long) + FDDI_TRACE_MAX, smt_get_error_word(smc)); + smc->e.path_test = PT_PENDING ; + GO_STATE(EC3_LEAVE) ; + break ; + } + break ; + case ACTIONS(EC3_LEAVE) : + start_ecm_timer(smc,smc->s.ecm_td_min,EC_TIMEOUT_TD) ; + for (p = 0 ; p < NUMPHYS ; p++) + queue_event(smc,EVENT_PCMA+p,PC_STOP) ; + ACTIONS_DONE() ; + break ; + case EC3_LEAVE: + /*EC30*/ + if (cmd == EC_TIMEOUT_TD && !smc->mib.fddiSMTBypassPresent && + (smc->e.path_test != PT_PENDING)) { + GO_STATE(EC0_OUT) ; + break ; + } + /*EC34*/ + else if (cmd == EC_TIMEOUT_TD && + (smc->e.path_test == PT_PENDING)) { + GO_STATE(EC4_PATH_TEST) ; + break ; + } + /*EC31*/ + else if (cmd == EC_CONNECT && smc->e.path_test == PT_PASSED) { + GO_STATE(EC1_IN) ; + break ; + } + /*EC33*/ + else if (cmd == EC_DISCONNECT && + smc->e.path_test == PT_PENDING) { + smc->e.path_test = PT_EXITING ; + /* + * stay in state - state will be left via timeout + */ + } + /*EC37*/ + else if (cmd == EC_TIMEOUT_TD && + smc->mib.fddiSMTBypassPresent && + smc->e.path_test != PT_PENDING) { + GO_STATE(EC7_DEINSERT) ; + break ; + } + break ; + case ACTIONS(EC4_PATH_TEST) : + stop_ecm_timer(smc) ; + smc->e.path_test = PT_TESTING ; + start_ecm_timer(smc,smc->s.ecm_test_done,EC_TEST_DONE) ; + /* now perform path test ... just a simulation */ + ACTIONS_DONE() ; + break ; + case EC4_PATH_TEST : + /* path test done delay */ + if (cmd == EC_TEST_DONE) + smc->e.path_test = PT_PASSED ; + + if (smc->e.path_test == PT_FAILED) + RS_SET(smc,RS_PATHTEST) ; + + /*EC40a*/ + if (smc->e.path_test == PT_FAILED && + !smc->mib.fddiSMTBypassPresent) { + GO_STATE(EC0_OUT) ; + break ; + } + /*EC40b*/ + else if (cmd == EC_DISCONNECT && + !smc->mib.fddiSMTBypassPresent) { + GO_STATE(EC0_OUT) ; + break ; + } + /*EC41*/ + else if (smc->e.path_test == PT_PASSED) { + GO_STATE(EC1_IN) ; + break ; + } + /*EC47a*/ + else if (smc->e.path_test == PT_FAILED && + smc->mib.fddiSMTBypassPresent) { + GO_STATE(EC7_DEINSERT) ; + break ; + } + /*EC47b*/ + else if (cmd == EC_DISCONNECT && + smc->mib.fddiSMTBypassPresent) { + GO_STATE(EC7_DEINSERT) ; + break ; + } + break ; + case ACTIONS(EC5_INSERT) : + sm_pm_bypass_req(smc,BP_INSERT); + start_ecm_timer(smc,smc->s.ecm_in_max,EC_TIMEOUT_INMAX) ; + ACTIONS_DONE() ; + break ; + case EC5_INSERT : + /*EC56*/ + if (cmd == EC_TIMEOUT_INMAX) { + GO_STATE(EC6_CHECK) ; + break ; + } + /*EC57*/ + else if (cmd == EC_DISCONNECT) { + GO_STATE(EC7_DEINSERT) ; + break ; + } + break ; + case ACTIONS(EC6_CHECK) : + /* + * in EC6_CHECK, we *POLL* the line state ! + * check whether both bypass switches have switched. + */ + start_ecm_timer(smc,smc->s.ecm_check_poll,0) ; + smc->e.ecm_line_state = TRUE ; /* flag to pcm: report Q/HLS */ + (void) sm_pm_ls_latch(smc,PA,1) ; /* enable line state latch */ + (void) sm_pm_ls_latch(smc,PB,1) ; /* enable line state latch */ + ACTIONS_DONE() ; + break ; + case EC6_CHECK : + ls_a = sm_pm_get_ls(smc,PA) ; + ls_b = sm_pm_get_ls(smc,PB) ; + + /*EC61*/ + if (((ls_a == PC_QLS) || (ls_a == PC_HLS)) && + ((ls_b == PC_QLS) || (ls_b == PC_HLS)) ) { + smc->e.sb_flag = FALSE ; + smc->e.ecm_line_state = FALSE ; + GO_STATE(EC1_IN) ; + break ; + } + /*EC66*/ + else if (!smc->e.sb_flag && + (((ls_a == PC_ILS) && (ls_b == PC_QLS)) || + ((ls_a == PC_QLS) && (ls_b == PC_ILS)))){ + smc->e.sb_flag = TRUE ; + DB_ECMN(1,"ECM : EC6_CHECK - stuck bypass\n",0,0) ; + AIX_EVENT(smc, (u_long) FDDI_RING_STATUS, (u_long) + FDDI_SMT_ERROR, (u_long) FDDI_BYPASS_STUCK, + smt_get_error_word(smc)); + } + /*EC67*/ + else if (cmd == EC_DISCONNECT) { + smc->e.ecm_line_state = FALSE ; + GO_STATE(EC7_DEINSERT) ; + break ; + } + else { + /* + * restart poll + */ + start_ecm_timer(smc,smc->s.ecm_check_poll,0) ; + } + break ; + case ACTIONS(EC7_DEINSERT) : + sm_pm_bypass_req(smc,BP_DEINSERT); + start_ecm_timer(smc,smc->s.ecm_i_max,EC_TIMEOUT_IMAX) ; + ACTIONS_DONE() ; + break ; + case EC7_DEINSERT: + /*EC70*/ + if (cmd == EC_TIMEOUT_IMAX) { + GO_STATE(EC0_OUT) ; + break ; + } + /*EC75*/ + else if (cmd == EC_CONNECT && smc->e.path_test == PT_PASSED) { + GO_STATE(EC5_INSERT) ; + break ; + } + break; + default: + SMT_PANIC(smc,SMT_E0107, SMT_E0107_MSG) ; + break; + } +} + +#ifndef CONCENTRATOR +/* + * trace propagation actions for SAS & DAS + */ +static void prop_actions(smc) +struct s_smc *smc ; +{ + int port_in ; + int port_out ; + + RS_SET(smc,RS_EVENT) ; + switch (smc->s.sas) { + case SMT_SAS : + port_in = port_out = pcm_get_s_port(smc) ; + break ; + case SMT_DAS : + port_in = cfm_get_mac_input(smc) ; /* PA or PB */ + port_out = cfm_get_mac_output(smc) ; /* PA or PB */ + break ; + case SMT_NAC : + SMT_PANIC(smc,SMT_E0108, SMT_E0108_MSG) ; + return ; + } + + DB_ECM("ECM : prop_actions - trace_prop %d\n", smc->e.trace_prop,0) ; + DB_ECM("ECM : prop_actions - in %d out %d\n", port_in,port_out) ; + + if (smc->e.trace_prop & ENTITY_BIT(ENTITY_MAC)) { + /* trace initiatior */ + DB_ECM("ECM : initiate TRACE on PHY %c\n",'A'+port_in-PA,0) ; + queue_event(smc,EVENT_PCM+port_in,PC_TRACE) ; + } + else if ((smc->e.trace_prop & ENTITY_BIT(ENTITY_PHY(PA))) && + port_out != PA) { + /* trace propagate upstream */ + DB_ECM("ECM : propagate TRACE on PHY B\n",0,0) ; + queue_event(smc,EVENT_PCMB,PC_TRACE) ; + } + else if ((smc->e.trace_prop & ENTITY_BIT(ENTITY_PHY(PB))) && + port_out != PB) { + /* trace propagate upstream */ + DB_ECM("ECM : propagate TRACE on PHY A\n",0,0) ; + queue_event(smc,EVENT_PCMA,PC_TRACE) ; + } + else { + /* signal trace termination */ + DB_ECM("ECM : TRACE terminated\n",0,0) ; + smc->e.path_test = PT_PENDING ; + } + smc->e.trace_prop = 0 ; +} +#else +/* + * trace propagation actions for Concentrator + */ +static void prop_actions(smc) +struct s_smc *smc ; +{ + int initiator ; + int upstream ; + int p ; + + RS_SET(smc,RS_EVENT) ; + while (smc->e.trace_prop) { + DB_ECM("ECM : prop_actions - trace_prop %d\n", + smc->e.trace_prop,0) ; + + if (smc->e.trace_prop & ENTITY_BIT(ENTITY_MAC)) { + initiator = ENTITY_MAC ; + smc->e.trace_prop &= ~ENTITY_BIT(ENTITY_MAC) ; + DB_ECM("ECM: MAC initiates trace\n",0,0) ; + } + else { + for (p = NUMPHYS-1 ; p >= 0 ; p--) { + if (smc->e.trace_prop & + ENTITY_BIT(ENTITY_PHY(p))) + break ; + } + initiator = ENTITY_PHY(p) ; + smc->e.trace_prop &= ~ENTITY_BIT(ENTITY_PHY(p)) ; + } + upstream = cem_get_upstream(smc,initiator) ; + + if (upstream == ENTITY_MAC) { + /* signal trace termination */ + DB_ECM("ECM : TRACE terminated\n",0,0) ; + smc->e.path_test = PT_PENDING ; + } + else { + /* trace propagate upstream */ + DB_ECM("ECM : propagate TRACE on PHY %d\n",upstream,0) ; + queue_event(smc,EVENT_PCM+upstream,PC_TRACE) ; + } + } +} +#endif + + +/* + * SMT timer interface + * start ECM timer + */ +static void start_ecm_timer(smc,value,event) +struct s_smc *smc ; +u_long value; +int event ; +{ + smt_timer_start(smc,&smc->e.ecm_timer,value,EV_TOKEN(EVENT_ECM,event)); +} + +/* + * SMT timer interface + * stop ECM timer + */ +static void stop_ecm_timer(smc) +struct s_smc *smc ; +{ + if (smc->e.ecm_timer.tm_active) + smt_timer_stop(smc,&smc->e.ecm_timer) ; +} diff -u --recursive --new-file v2.3.46/linux/drivers/net/skfp/ess.c linux/drivers/net/skfp/ess.c --- v2.3.46/linux/drivers/net/skfp/ess.c Wed Dec 31 16:00:00 1969 +++ linux/drivers/net/skfp/ess.c Fri Feb 18 14:55:53 2000 @@ -0,0 +1,732 @@ +/****************************************************************************** + * + * (C)Copyright 1998,1999 SysKonnect, + * a business unit of Schneider & Koch & Co. Datensysteme GmbH. + * + * See the file "skfddi.c" for further information. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * The information in this file is provided "AS IS" without warranty. + * + ******************************************************************************/ + +/* + * ******************************************************************* + * This SBA code implements the Synchronous Bandwidth Allocation + * functions described in the "FDDI Synchronous Forum Implementer's + * Agreement" dated December 1th, 1993. + * ******************************************************************* + * + * PURPOSE: The purpose of this function is to control + * synchronous allocations on a single FDDI segment. + * Allocations are limited to the primary FDDI ring. + * The SBM provides recovery mechanisms to recover + * unused bandwidth also resolves T_Neg and + * reconfiguration changes. Many of the SBM state + * machine inputs are sourced by the underlying + * FDDI sub-system supporting the SBA application. + * + * ******************************************************************* + */ + +#include "h/types.h" +#include "h/fddi.h" +#include "h/smc.h" +#include "h/smt_p.h" + + +#ifndef SLIM_SMT + +#ifdef ESS + +#ifndef lint +static const char ID_sccs[] = "@(#)ess.c 1.10 96/02/23 (C) SK" ; +#define LINT_USE(x) +#else +#define LINT_USE(x) (x)=(x) +#endif +#define MS2BCLK(x) ((x)*12500L) + +/* + ------------------------------------------------------------- + LOCAL VARIABLES: + ------------------------------------------------------------- +*/ + +static const u_short plist_raf_alc_res[] = { SMT_P0012, SMT_P320B, SMT_P320F, + SMT_P3210, SMT_P0019, SMT_P001A, + SMT_P001D, 0 } ; + +static const u_short plist_raf_chg_req[] = { SMT_P320B, SMT_P320F, SMT_P3210, + SMT_P001A, 0 } ; + +static const struct fddi_addr smt_sba_da = {0x80,0x01,0x43,0x00,0x80,0x0C} ; +static const struct fddi_addr null_addr = {0,0,0,0,0,0} ; + +/* + ------------------------------------------------------------- + GLOBAL VARIABLES: + ------------------------------------------------------------- +*/ + + +/* + ------------------------------------------------------------- + LOCAL FUNCTIONS: + ------------------------------------------------------------- +*/ + +static void ess_send_response(), ess_config_fifo(), + ess_send_alc_req(), ess_send_frame() ; + +/* + ------------------------------------------------------------- + EXTERNAL FUNCTIONS: + ------------------------------------------------------------- +*/ + +extern void *sm_to_para() ; + +extern void smt_send_frame(), smt_free_mbuf(), + set_formac_tsync(), formac_reinit_tx() ; + +extern int smt_check_para() ; + +extern SMbuf *smt_get_mbuf(), *smt_build_frame() ; + +extern u_long smt_get_tid() ; + +/* + ------------------------------------------------------------- + PUBLIC FUNCTIONS: + ------------------------------------------------------------- +*/ + + void ess_timer_poll(), ess_para_change() ; + + int ess_raf_received_pack(), process_bw_alloc() ; + + +/* + * -------------------------------------------------------------------------- + * End Station Support (ESS) + * -------------------------------------------------------------------------- + */ + +/* + * evaluate the RAF frame + */ +int ess_raf_received_pack(smc,mb,sm,fs) +struct s_smc *smc ; +SMbuf *mb ; +struct smt_header *sm ; +int fs ; +{ + void *p ; /* universal pointer */ + struct smt_p_0016 *cmd ; /* para: command for the ESS */ + SMbuf *db ; + u_long msg_res_type ; /* recource type */ + u_long payload, overhead ; + int local ; + int i ; + + /* + * Message Processing Code + */ + local = ((fs & L_INDICATOR) != 0) ; + + /* + * get the resource type + */ + if (!(p = (void *) sm_to_para(smc,sm,SMT_P0015))) { + DB_ESS("ESS: RAF frame error, parameter type not found\n",0,0) ; + return(fs) ; + } + msg_res_type = ((struct smt_p_0015 *)p)->res_type ; + + /* + * get the pointer to the ESS command + */ + if (!(cmd = (struct smt_p_0016 *) sm_to_para(smc,sm,SMT_P0016))) { + /* + * error in frame: para ESS command was not found + */ + DB_ESS("ESS: RAF frame error, parameter command not found\n",0,0); + return(fs) ; + } + + DB_ESSN(2,"fc %x ft %x\n",sm->smt_class,sm->smt_type) ; + DB_ESSN(2,"ver %x tran %lx\n",sm->smt_version,sm->smt_tid) ; + DB_ESSN(2,"stn_id %s\n",addr_to_string(&sm->smt_source),0) ; + + DB_ESSN(2,"infolen %x res %x\n",sm->smt_len, msg_res_type) ; + DB_ESSN(2,"sbacmd %x\n",cmd->sba_cmd,0) ; + + /* + * evaluate the ESS command + */ + switch (cmd->sba_cmd) { + + /* + * Process an ESS Allocation Request + */ + case REQUEST_ALLOCATION : + /* + * check for an RAF Request (Allocation Request) + */ + if (sm->smt_type == SMT_REQUEST) { + /* + * process the Allocation request only if the frame is + * local and no static allocation is used + */ + if (!local || smc->mib.fddiESSPayload) + return(fs) ; + + p = (void *) sm_to_para(smc,sm,SMT_P0019) ; + for (i = 0; i < 5; i++) { + if (((struct smt_p_0019 *)p)->alloc_addr.a[i]) { + return(fs) ; + } + } + + /* + * Note: The Application should send a LAN_LOC_FRAME. + * The ESS do not send the Frame to the network! + */ + smc->ess.alloc_trans_id = sm->smt_tid ; + DB_ESS("ESS: save Alloc Req Trans ID %lx\n",sm->smt_tid,0); + p = (void *) sm_to_para(smc,sm,SMT_P320F) ; + ((struct smt_p_320f *)p)->mib_payload = + smc->mib.a[PATH0].fddiPATHSbaPayload ; + p = (void *) sm_to_para(smc,sm,SMT_P3210) ; + ((struct smt_p_3210 *)p)->mib_overhead = + smc->mib.a[PATH0].fddiPATHSbaOverhead ; + sm->smt_dest = smt_sba_da ; + + if (smc->ess.local_sba_active) + return(fs | I_INDICATOR) ; + + if (!(db = smt_get_mbuf(smc))) + return(fs) ; + + db->sm_len = mb->sm_len ; + db->sm_off = mb->sm_off ; + memcpy(((char *)(db->sm_data+db->sm_off)),(char *)sm, + (int)db->sm_len) ; + dump_smt(smc, + (struct smt_header *)(db->sm_data+db->sm_off), + "RAF") ; + smt_send_frame(smc,db,FC_SMT_INFO,0) ; + return(fs) ; + } + + /* + * The RAF frame is an Allocation Response ! + * check the parameters + */ + if (smt_check_para(smc,sm,plist_raf_alc_res)) { + DB_ESS("ESS: RAF with para problem, ignoring\n",0,0) ; + return(fs) ; + } + + /* + * VERIFY THE FRAME IS WELL BUILT: + * + * 1. path index = primary ring only + * 2. resource type = sync bw only + * 3. trans action id = alloc_trans_id + * 4. reason code = success + * + * If any are violated, discard the RAF frame + */ + if ((((struct smt_p_320b *)sm_to_para(smc,sm,SMT_P320B))->path_index + != PRIMARY_RING) || + (msg_res_type != SYNC_BW) || + (((struct smt_p_reason *)sm_to_para(smc,sm,SMT_P0012))->rdf_reason + != SMT_RDF_SUCCESS) || + (sm->smt_tid != smc->ess.alloc_trans_id)) { + + DB_ESS("ESS: Allocation Responce not accepted\n",0,0) ; + return(fs) ; + } + + /* + * Extract message parameters + */ + p = (void *) sm_to_para(smc,sm,SMT_P320F) ; + payload = ((struct smt_p_320f *)p)->mib_payload ; + p = (void *) sm_to_para(smc,sm,SMT_P3210) ; + overhead = ((struct smt_p_3210 *)p)->mib_overhead ; + + DB_ESSN(2,"payload= %lx overhead= %lx\n",payload,overhead) ; + + /* + * process the bandwidth allocation + */ + (void)process_bw_alloc(smc,(long)payload,(long)overhead) ; + + return(fs) ; + /* end of Process Allocation Request */ + + /* + * Process an ESS Change Request + */ + case CHANGE_ALLOCATION : + /* + * except only replies + */ + if (sm->smt_type != SMT_REQUEST) { + DB_ESS("ESS: Do not process Change Responses\n",0,0) ; + return(fs) ; + } + + /* + * check the para for the Change Request + */ + if (smt_check_para(smc,sm,plist_raf_chg_req)) { + DB_ESS("ESS: RAF with para problem, ignoring\n",0,0) ; + return(fs) ; + } + + /* + * Verify the path index and resource + * type are correct. If any of + * these are false, don't process this + * change request frame. + */ + if ((((struct smt_p_320b *)sm_to_para(smc,sm,SMT_P320B))->path_index + != PRIMARY_RING) || (msg_res_type != SYNC_BW)) { + DB_ESS("ESS: RAF frame with para problem, ignoring\n",0,0) ; + return(fs) ; + } + + /* + * Extract message queue parameters + */ + p = (void *) sm_to_para(smc,sm,SMT_P320F) ; + payload = ((struct smt_p_320f *)p)->mib_payload ; + p = (void *) sm_to_para(smc,sm,SMT_P3210) ; + overhead = ((struct smt_p_3210 *)p)->mib_overhead ; + + DB_ESSN(2,"ESS: Change Request from %s\n", + addr_to_string(&sm->smt_source),0) ; + DB_ESSN(2,"payload= %lx overhead= %lx\n",payload,overhead) ; + + /* + * process the bandwidth allocation + */ + if(!process_bw_alloc(smc,(long)payload,(long)overhead)) + return(fs) ; + + /* + * send an RAF Change Reply + */ + ess_send_response(smc,sm,CHANGE_ALLOCATION) ; + + return(fs) ; + /* end of Process Change Request */ + + /* + * Process Report Response + */ + case REPORT_ALLOCATION : + /* + * except only requests + */ + if (sm->smt_type != SMT_REQUEST) { + DB_ESS("ESS: Do not process a Report Reply\n",0,0) ; + return(fs) ; + } + + DB_ESSN(2,"ESS: Report Request from %s\n", + addr_to_string(&(sm->smt_source)),0) ; + + /* + * verify that the resource type is sync bw only + */ + if (msg_res_type != SYNC_BW) { + DB_ESS("ESS: ignoring RAF with para problem\n",0,0) ; + return(fs) ; + } + + /* + * send an RAF Change Reply + */ + ess_send_response(smc,sm,REPORT_ALLOCATION) ; + + return(fs) ; + /* end of Process Report Request */ + + default: + /* + * error in frame + */ + DB_ESS("ESS: ignoring RAF with bad sba_cmd\n",0,0) ; + break ; + } + + return(fs) ; +} + +/* + * determines the synchronous bandwidth, set the TSYNC register and the + * mib variables SBAPayload, SBAOverhead and fddiMACT-NEG. + */ +int process_bw_alloc(smc,payload,overhead) +struct s_smc *smc ; +long payload ; +long overhead ; +{ + /* + * determine the synchronous bandwidth (sync_bw) in bytes per T-NEG, + * if the payload is greater than zero. + * For the SBAPayload and the SBAOverhead we have the following + * unite quations + * _ _ + * | bytes | + * SBAPayload = | 8000 ------ | + * | s | + * - - + * _ _ + * | bytes | + * SBAOverhead = | ------ | + * | T-NEG | + * - - + * + * T-NEG is discribed by the equation: + * + * (-) fddiMACT-NEG + * T-NEG = ------------------- + * 12500000 1/s + * + * The number of bytes we are able to send is the payload + * plus the overhead. + * + * bytes T-NEG SBAPayload 8000 bytes/s + * sync_bw = SBAOverhead ------ + ----------------------------- + * T-NEG T-NEG + * + * + * 1 + * sync_bw = SBAOverhead + ---- (-)fddiMACT-NEG * SBAPayload + * 1562 + * + */ + + /* + * set the mib attributes fddiPATHSbaOverhead, fddiPATHSbaPayload + */ +/* if (smt_set_obj(smc,SMT_P320F,payload,S_SET)) { + DB_ESS("ESS: SMT does not accept the payload value\n",0,0) ; + return(FALSE) ; + } + if (smt_set_obj(smc,SMT_P3210,overhead,S_SET)) { + DB_ESS("ESS: SMT does not accept the overhead value\n",0,0) ; + return(FALSE) ; + } */ + + /* premliminary */ + if (payload > MAX_PAYLOAD || overhead > 5000) { + DB_ESS("ESS: payload / overhead not accepted\n",0,0) ; + return(FALSE) ; + } + + /* + * start the iterative allocation process if the payload or the overhead + * are smaller than the parsed values + */ + if (smc->mib.fddiESSPayload && + ((u_long)payload != smc->mib.fddiESSPayload || + (u_long)overhead != smc->mib.fddiESSOverhead)) { + smc->ess.raf_act_timer_poll = TRUE ; + smc->ess.timer_count = 0 ; + } + + /* + * evulate the Payload + */ + if (payload) { + DB_ESSN(2,"ESS: turn SMT_ST_SYNC_SERVICE bit on\n",0,0) ; + smc->ess.sync_bw_available = TRUE ; + + smc->ess.sync_bw = overhead - + (long)smc->mib.m[MAC0].fddiMACT_Neg * + payload / 1562 ; + } + else { + DB_ESSN(2,"ESS: turn SMT_ST_SYNC_SERVICE bit off\n",0,0) ; + smc->ess.sync_bw_available = FALSE ; + smc->ess.sync_bw = 0 ; + overhead = 0 ; + } + + smc->mib.a[PATH0].fddiPATHSbaPayload = payload ; + smc->mib.a[PATH0].fddiPATHSbaOverhead = overhead ; + + + DB_ESSN(2,"tsync = %lx\n",smc->ess.sync_bw,0) ; + + ess_config_fifo(smc) ; + set_formac_tsync(smc,smc->ess.sync_bw) ; + return(TRUE) ; +} + +static void ess_send_response(smc,sm,sba_cmd) +struct s_smc *smc ; +struct smt_header *sm ; +int sba_cmd ; +{ + struct smt_sba_chg *chg ; + SMbuf *mb ; + void *p ; + + /* + * get and initialize the responce frame + */ + if (sba_cmd == CHANGE_ALLOCATION) { + if (!(mb=smt_build_frame(smc,SMT_RAF,SMT_REPLY, + sizeof(struct smt_sba_chg)))) + return ; + } + else { + if (!(mb=smt_build_frame(smc,SMT_RAF,SMT_REPLY, + sizeof(struct smt_sba_rep_res)))) + return ; + } + + chg = smtod(mb,struct smt_sba_chg *) ; + chg->smt.smt_tid = sm->smt_tid ; + chg->smt.smt_dest = sm->smt_source ; + + /* set P15 */ + chg->s_type.para.p_type = SMT_P0015 ; + chg->s_type.para.p_len = sizeof(struct smt_p_0015) - PARA_LEN ; + chg->s_type.res_type = SYNC_BW ; + + /* set P16 */ + chg->cmd.para.p_type = SMT_P0016 ; + chg->cmd.para.p_len = sizeof(struct smt_p_0016) - PARA_LEN ; + chg->cmd.sba_cmd = sba_cmd ; + + /* set P320B */ + chg->path.para.p_type = SMT_P320B ; + chg->path.para.p_len = sizeof(struct smt_p_320b) - PARA_LEN ; + chg->path.mib_index = SBAPATHINDEX ; + chg->path.path_pad = (u_short)NULL ; + chg->path.path_index = PRIMARY_RING ; + + /* set P320F */ + chg->payload.para.p_type = SMT_P320F ; + chg->payload.para.p_len = sizeof(struct smt_p_320f) - PARA_LEN ; + chg->payload.mib_index = SBAPATHINDEX ; + chg->payload.mib_payload = smc->mib.a[PATH0].fddiPATHSbaPayload ; + + /* set P3210 */ + chg->overhead.para.p_type = SMT_P3210 ; + chg->overhead.para.p_len = sizeof(struct smt_p_3210) - PARA_LEN ; + chg->overhead.mib_index = SBAPATHINDEX ; + chg->overhead.mib_overhead = smc->mib.a[PATH0].fddiPATHSbaOverhead ; + + if (sba_cmd == CHANGE_ALLOCATION) { + /* set P1A */ + chg->cat.para.p_type = SMT_P001A ; + chg->cat.para.p_len = sizeof(struct smt_p_001a) - PARA_LEN ; + p = (void *) sm_to_para(smc,sm,SMT_P001A) ; + chg->cat.category = ((struct smt_p_001a *)p)->category ; + } + dump_smt(smc,(struct smt_header *)chg,"RAF") ; + ess_send_frame(smc,mb) ; +} + + +void ess_timer_poll(smc) +struct s_smc *smc ; +{ + if (!smc->ess.raf_act_timer_poll) + return ; + + DB_ESSN(2,"ESS: timer_poll\n",0,0) ; + + smc->ess.timer_count++ ; + if (smc->ess.timer_count == 10) { + smc->ess.timer_count = 0 ; + ess_send_alc_req(smc) ; + } +} + +static void ess_send_alc_req(smc) +struct s_smc *smc ; +{ + struct smt_sba_alc_req *req ; + SMbuf *mb ; + + /* + * send never allocation request where the requested payload and + * overhead is zero or deallocate bandwidht when no bandwidth is + * parsed + */ + if (!smc->mib.fddiESSPayload) { + smc->mib.fddiESSOverhead = 0 ; + } + else { + if (!smc->mib.fddiESSOverhead) + smc->mib.fddiESSOverhead = DEFAULT_OV ; + } + + if (smc->mib.fddiESSOverhead == + smc->mib.a[PATH0].fddiPATHSbaOverhead && + smc->mib.fddiESSPayload == + smc->mib.a[PATH0].fddiPATHSbaPayload){ + smc->ess.raf_act_timer_poll = FALSE ; + smc->ess.timer_count = 7 ; /* next RAF alc req after 3 s */ + return ; + } + + /* + * get and initialize the responce frame + */ + if (!(mb=smt_build_frame(smc,SMT_RAF,SMT_REQUEST, + sizeof(struct smt_sba_alc_req)))) + return ; + req = smtod(mb,struct smt_sba_alc_req *) ; + req->smt.smt_tid = smc->ess.alloc_trans_id = smt_get_tid(smc) ; + req->smt.smt_dest = smt_sba_da ; + + /* set P15 */ + req->s_type.para.p_type = SMT_P0015 ; + req->s_type.para.p_len = sizeof(struct smt_p_0015) - PARA_LEN ; + req->s_type.res_type = SYNC_BW ; + + /* set P16 */ + req->cmd.para.p_type = SMT_P0016 ; + req->cmd.para.p_len = sizeof(struct smt_p_0016) - PARA_LEN ; + req->cmd.sba_cmd = REQUEST_ALLOCATION ; + + /* + * set the parameter type and parameter lenght of all used + * parameters + */ + + /* set P320B */ + req->path.para.p_type = SMT_P320B ; + req->path.para.p_len = sizeof(struct smt_p_320b) - PARA_LEN ; + req->path.mib_index = SBAPATHINDEX ; + req->path.path_pad = (u_short)NULL ; + req->path.path_index = PRIMARY_RING ; + + /* set P0017 */ + req->pl_req.para.p_type = SMT_P0017 ; + req->pl_req.para.p_len = sizeof(struct smt_p_0017) - PARA_LEN ; + req->pl_req.sba_pl_req = smc->mib.fddiESSPayload - + smc->mib.a[PATH0].fddiPATHSbaPayload ; + + /* set P0018 */ + req->ov_req.para.p_type = SMT_P0018 ; + req->ov_req.para.p_len = sizeof(struct smt_p_0018) - PARA_LEN ; + req->ov_req.sba_ov_req = smc->mib.fddiESSOverhead - + smc->mib.a[PATH0].fddiPATHSbaOverhead ; + + /* set P320F */ + req->payload.para.p_type = SMT_P320F ; + req->payload.para.p_len = sizeof(struct smt_p_320f) - PARA_LEN ; + req->payload.mib_index = SBAPATHINDEX ; + req->payload.mib_payload = smc->mib.a[PATH0].fddiPATHSbaPayload ; + + /* set P3210 */ + req->overhead.para.p_type = SMT_P3210 ; + req->overhead.para.p_len = sizeof(struct smt_p_3210) - PARA_LEN ; + req->overhead.mib_index = SBAPATHINDEX ; + req->overhead.mib_overhead = smc->mib.a[PATH0].fddiPATHSbaOverhead ; + + /* set P19 */ + req->a_addr.para.p_type = SMT_P0019 ; + req->a_addr.para.p_len = sizeof(struct smt_p_0019) - PARA_LEN ; + req->a_addr.sba_pad = (u_short)NULL ; + req->a_addr.alloc_addr = null_addr ; + + /* set P1A */ + req->cat.para.p_type = SMT_P001A ; + req->cat.para.p_len = sizeof(struct smt_p_001a) - PARA_LEN ; + req->cat.category = smc->mib.fddiESSCategory ; + + /* set P1B */ + req->tneg.para.p_type = SMT_P001B ; + req->tneg.para.p_len = sizeof(struct smt_p_001b) - PARA_LEN ; + req->tneg.max_t_neg = smc->mib.fddiESSMaxTNeg ; + + /* set P1C */ + req->segm.para.p_type = SMT_P001C ; + req->segm.para.p_len = sizeof(struct smt_p_001c) - PARA_LEN ; + req->segm.min_seg_siz = smc->mib.fddiESSMinSegmentSize ; + + dump_smt(smc,(struct smt_header *)req,"RAF") ; + ess_send_frame(smc,mb) ; +} + +static void ess_send_frame(smc,mb) +struct s_smc *smc ; +SMbuf *mb ; +{ + /* + * check if the frame must be send to the own ESS + */ + if (smc->ess.local_sba_active) { + /* + * Send the Change Reply to the local SBA + */ + DB_ESS("ESS:Send to the local SBA\n",0,0) ; + if (!smc->ess.sba_reply_pend) + smc->ess.sba_reply_pend = mb ; + else { + DB_ESS("Frame is lost - another frame was pending\n",0,0); + smt_free_mbuf(smc,mb) ; + } + } + else { + /* + * Send the SBA RAF Change Reply to the network + */ + DB_ESS("ESS:Send to the network\n",0,0) ; + smt_send_frame(smc,mb,FC_SMT_INFO,0) ; + } +} + +void ess_para_change(smc) +struct s_smc *smc ; +{ + (void)process_bw_alloc(smc,(long)smc->mib.a[PATH0].fddiPATHSbaPayload, + (long)smc->mib.a[PATH0].fddiPATHSbaOverhead) ; +} + +static void ess_config_fifo(smc) +struct s_smc *smc ; +{ + /* + * if nothing to do exit + */ + if (smc->mib.a[PATH0].fddiPATHSbaPayload) { + if (smc->hw.fp.fifo.fifo_config_mode & SYNC_TRAFFIC_ON && + (smc->hw.fp.fifo.fifo_config_mode&SEND_ASYNC_AS_SYNC) == + smc->mib.fddiESSSynchTxMode) { + return ; + } + } + else { + if (!(smc->hw.fp.fifo.fifo_config_mode & SYNC_TRAFFIC_ON)) { + return ; + } + } + + /* + * split up the FIFO and reinitialize the queues + */ + formac_reinit_tx(smc) ; +} + +#endif /* ESS */ + +#endif /* no SLIM_SMT */ diff -u --recursive --new-file v2.3.46/linux/drivers/net/skfp/fplustm.c linux/drivers/net/skfp/fplustm.c --- v2.3.46/linux/drivers/net/skfp/fplustm.c Wed Dec 31 16:00:00 1969 +++ linux/drivers/net/skfp/fplustm.c Fri Feb 18 14:55:53 2000 @@ -0,0 +1,1645 @@ +/****************************************************************************** + * + * (C)Copyright 1998,1999 SysKonnect, + * a business unit of Schneider & Koch & Co. Datensysteme GmbH. + * + * See the file "skfddi.c" for further information. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * The information in this file is provided "AS IS" without warranty. + * + ******************************************************************************/ + +/* + * FORMAC+ Driver for tag mode + */ + +#include "h/types.h" +#include "h/fddi.h" +#include "h/smc.h" +#include "h/supern_2.h" +#include "can.c" + +#ifndef lint +static const char ID_sccs[] = "@(#)fplustm.c 1.32 99/02/23 (C) SK " ; +#endif + +#ifndef UNUSED +#ifdef lint +#define UNUSED(x) (x) = (x) +#else +#define UNUSED(x) +#endif +#endif + +#define FM_ADDRX (FM_ADDET|FM_EXGPA0|FM_EXGPA1) +#define MS2BCLK(x) ((x)*12500L) +#define US2BCLK(x) ((x)*1250L) + +/* + * prototypes for static function + */ +static void build_claim_beacon() ; +static int init_mac() ; +static void rtm_init() ; +static void smt_split_up_fifo() ; + +#if (!defined(NO_SMT_PANIC) || defined(DEBUG)) +static char write_mdr_warning [] = "E350 write_mdr() FM_SNPPND is set\n"; +static char cam_warning [] = "E_SMT_004: CAM still busy\n"; +#endif + +#define DUMMY_READ() smc->hw.mc_dummy = (u_short) inp(ADDR(B0_RAP)) + +#define CHECK_NPP() { unsigned k = 10000 ;\ + while ((inpw(FM_A(FM_STMCHN)) & FM_SNPPND) && k) k--;\ + if (!k) { \ + SMT_PANIC(smc,SMT_E0130, SMT_E0130_MSG) ; \ + } \ + } + +#define CHECK_CAM() { unsigned k = 10 ;\ + while (!(inpw(FM_A(FM_AFSTAT)) & FM_DONE) && k) k--;\ + if (!k) { \ + SMT_PANIC(smc,SMT_E0131, SMT_E0131_MSG) ; \ + } \ + } + +const struct fddi_addr fddi_broadcast = {0xff,0xff,0xff,0xff,0xff,0xff}; +static const struct fddi_addr null_addr = {0,0,0,0,0,0} ; +static const struct fddi_addr dbeacon_multi = {0x01,0x80,0xc2,0x00,0x01,0x00}; + +static const u_short my_said = 0xffff ; /* short address (n.u.) */ +static const u_short my_sagp = 0xffff ; /* short group address (n.u.) */ + +/* + * define my address + */ +#ifdef USE_CAN_ADDR +#define MA smc->hw.fddi_canon_addr +#else +#define MA smc->hw.fddi_home_addr +#endif + + +/* + * usefull interrupt bits + */ +static int mac_imsk1u = FM_STXABRS | FM_STXABRA0 | FM_SXMTABT ; +static int mac_imsk1l = FM_SQLCKS | FM_SQLCKA0 | FM_SPCEPDS | FM_SPCEPDA0| + FM_STBURS | FM_STBURA0 ; + + /* delete FM_SRBFL after tests */ +static int mac_imsk2u = FM_SERRSF | FM_SNFSLD | FM_SRCVOVR | FM_SRBFL | + FM_SMYCLM ; +static int mac_imsk2l = FM_STRTEXR | FM_SDUPCLM | FM_SFRMCTR | + FM_SERRCTR | FM_SLSTCTR | + FM_STRTEXP | FM_SMULTDA | FM_SRNGOP ; + +static int mac_imsk3u = FM_SRCVOVR2 | FM_SRBFL2 ; +static int mac_imsk3l = FM_SRPERRQ2 | FM_SRPERRQ1 ; + +static int mac_beacon_imsk2u = FM_SOTRBEC | FM_SMYBEC | FM_SBEC | + FM_SLOCLM | FM_SHICLM | FM_SMYCLM | FM_SCLM ; + + +static u_long mac_get_tneg(smc) +struct s_smc *smc ; +{ + u_long tneg ; + + tneg = (u_long)((long)inpw(FM_A(FM_TNEG))<<5) ; + return((u_long)((tneg + ((inpw(FM_A(FM_TMRS))>>10)&0x1f)) | + 0xffe00000L)) ; +} + +void mac_update_counter(smc) +struct s_smc *smc ; +{ + smc->mib.m[MAC0].fddiMACFrame_Ct = + (smc->mib.m[MAC0].fddiMACFrame_Ct & 0xffff0000L) + + (u_short) inpw(FM_A(FM_FCNTR)) ; + smc->mib.m[MAC0].fddiMACLost_Ct = + (smc->mib.m[MAC0].fddiMACLost_Ct & 0xffff0000L) + + (u_short) inpw(FM_A(FM_LCNTR)) ; + smc->mib.m[MAC0].fddiMACError_Ct = + (smc->mib.m[MAC0].fddiMACError_Ct & 0xffff0000L) + + (u_short) inpw(FM_A(FM_ECNTR)) ; + smc->mib.m[MAC0].fddiMACT_Neg = mac_get_tneg(smc) ; +#ifdef SMT_REAL_TOKEN_CT + /* + * If the token counter is emulated it is updated in smt_event. + */ + TBD +#else + smt_emulate_token_ct( smc, MAC0 ); +#endif +} + +/* + * write long value into buffer memory over memory data register (MDR), + */ +void write_mdr(smc,val) +struct s_smc *smc ; +u_long val; +{ + CHECK_NPP() ; + MDRW(val) ; +} + +/* + * read long value from buffer memory over memory data register (MDR), + */ +u_long read_mdr(smc,addr) +struct s_smc *smc ; +unsigned int addr; +{ + long p ; + CHECK_NPP() ; + MARR(addr) ; + outpw(FM_A(FM_CMDREG1),FM_IRMEMWO) ; + CHECK_NPP() ; /* needed for PCI to prevent from timeing violations */ +/* p = MDRR() ; */ /* bad read values if the workaround */ + /* smc->hw.mc_dummy = *((short volatile far *)(addr)))*/ + /* is used */ + p = (u_long)inpw(FM_A(FM_MDRU))<<16 ; + p += (u_long)inpw(FM_A(FM_MDRL)) ; + return(p) ; +} +/* + * clear buffer memory + */ +static void init_ram(smc) +struct s_smc *smc ; +{ + u_short i ; + + smc->hw.fp.fifo.rbc_ram_start = 0 ; + smc->hw.fp.fifo.rbc_ram_end = + smc->hw.fp.fifo.rbc_ram_start + RBC_MEM_SIZE ; + CHECK_NPP() ; + MARW(smc->hw.fp.fifo.rbc_ram_start) ; + for (i = smc->hw.fp.fifo.rbc_ram_start; + i < (u_short) (smc->hw.fp.fifo.rbc_ram_end-1); i++) + write_mdr(smc,0L) ; + /* Erase the last byte too */ + write_mdr(smc,0L) ; +} + +/* + * set receive FIFO pointer + */ +static void set_recvptr(smc) +struct s_smc *smc ; +{ + /* + * initialize the pointer for receive queue 1 + */ + outpw(FM_A(FM_RPR1),smc->hw.fp.fifo.rx1_fifo_start) ; /* RPR1 */ + outpw(FM_A(FM_SWPR1),smc->hw.fp.fifo.rx1_fifo_start) ; /* SWPR1 */ + outpw(FM_A(FM_WPR1),smc->hw.fp.fifo.rx1_fifo_start) ; /* WPR1 */ + outpw(FM_A(FM_EARV1),smc->hw.fp.fifo.tx_s_start-1) ; /* EARV1 */ + + /* + * initialize the pointer for receive queue 2 + */ + if (smc->hw.fp.fifo.rx2_fifo_size) { + outpw(FM_A(FM_RPR2),smc->hw.fp.fifo.rx2_fifo_start) ; + outpw(FM_A(FM_SWPR2),smc->hw.fp.fifo.rx2_fifo_start) ; + outpw(FM_A(FM_WPR2),smc->hw.fp.fifo.rx2_fifo_start) ; + outpw(FM_A(FM_EARV2),smc->hw.fp.fifo.rbc_ram_end-1) ; + } + else { + outpw(FM_A(FM_RPR2),smc->hw.fp.fifo.rbc_ram_end-1) ; + outpw(FM_A(FM_SWPR2),smc->hw.fp.fifo.rbc_ram_end-1) ; + outpw(FM_A(FM_WPR2),smc->hw.fp.fifo.rbc_ram_end-1) ; + outpw(FM_A(FM_EARV2),smc->hw.fp.fifo.rbc_ram_end-1) ; + } +} + +/* + * set transmit FIFO pointer + */ +static void set_txptr(smc) +struct s_smc *smc ; +{ + outpw(FM_A(FM_CMDREG2),FM_IRSTQ) ; /* reset transmit queues */ + + /* + * initialize the pointer for asynchronous transmit queue + */ + outpw(FM_A(FM_RPXA0),smc->hw.fp.fifo.tx_a0_start) ; /* RPXA0 */ + outpw(FM_A(FM_SWPXA0),smc->hw.fp.fifo.tx_a0_start) ; /* SWPXA0 */ + outpw(FM_A(FM_WPXA0),smc->hw.fp.fifo.tx_a0_start) ; /* WPXA0 */ + outpw(FM_A(FM_EAA0),smc->hw.fp.fifo.rx2_fifo_start-1) ; /* EAA0 */ + + /* + * initialize the pointer for synchronous transmit queue + */ + if (smc->hw.fp.fifo.tx_s_size) { + outpw(FM_A(FM_RPXS),smc->hw.fp.fifo.tx_s_start) ; + outpw(FM_A(FM_SWPXS),smc->hw.fp.fifo.tx_s_start) ; + outpw(FM_A(FM_WPXS),smc->hw.fp.fifo.tx_s_start) ; + outpw(FM_A(FM_EAS),smc->hw.fp.fifo.tx_a0_start-1) ; + } + else { + outpw(FM_A(FM_RPXS),smc->hw.fp.fifo.tx_a0_start-1) ; + outpw(FM_A(FM_SWPXS),smc->hw.fp.fifo.tx_a0_start-1) ; + outpw(FM_A(FM_WPXS),smc->hw.fp.fifo.tx_a0_start-1) ; + outpw(FM_A(FM_EAS),smc->hw.fp.fifo.tx_a0_start-1) ; + } +} + +/* + * init memory buffer management registers + */ +static void init_rbc(smc) +struct s_smc *smc ; +{ + u_short rbc_ram_addr ; + + /* + * set unused pointers or permanent pointers + */ + rbc_ram_addr = smc->hw.fp.fifo.rx2_fifo_start - 1 ; + + outpw(FM_A(FM_RPXA1),rbc_ram_addr) ; /* a1-send pointer */ + outpw(FM_A(FM_WPXA1),rbc_ram_addr) ; + outpw(FM_A(FM_SWPXA1),rbc_ram_addr) ; + outpw(FM_A(FM_EAA1),rbc_ram_addr) ; + + set_recvptr(smc) ; + set_txptr(smc) ; +} + +/* + * init rx pointer + */ +static void init_rx(smc) +struct s_smc *smc ; +{ + struct s_smt_rx_queue *queue ; + + /* + * init all tx data structures for receive queue 1 + */ + smc->hw.fp.rx[QUEUE_R1] = queue = &smc->hw.fp.rx_q[QUEUE_R1] ; + queue->rx_bmu_ctl = (HW_PTR) ADDR(B0_R1_CSR) ; + queue->rx_bmu_dsc = (HW_PTR) ADDR(B4_R1_DA) ; + + /* + * init all tx data structures for receive queue 2 + */ + smc->hw.fp.rx[QUEUE_R2] = queue = &smc->hw.fp.rx_q[QUEUE_R2] ; + queue->rx_bmu_ctl = (HW_PTR) ADDR(B0_R2_CSR) ; + queue->rx_bmu_dsc = (HW_PTR) ADDR(B4_R2_DA) ; +} + +/* + * set the TSYNC register of the FORMAC to regulate synchronous transmission + */ +void set_formac_tsync(smc,sync_bw) +struct s_smc *smc ; +long sync_bw ; +{ + outpw(FM_A(FM_TSYNC),(unsigned int) (((-sync_bw) >> 5) & 0xffff) ) ; +} + +/* + * init all tx data structures + */ +static void init_tx(smc) +struct s_smc *smc ; +{ + struct s_smt_tx_queue *queue ; + + /* + * init all tx data structures for the synchronous queue + */ + smc->hw.fp.tx[QUEUE_S] = queue = &smc->hw.fp.tx_q[QUEUE_S] ; + queue->tx_bmu_ctl = (HW_PTR) ADDR(B0_XS_CSR) ; + queue->tx_bmu_dsc = (HW_PTR) ADDR(B5_XS_DA) ; + +#ifdef ESS + set_formac_tsync(smc,smc->ess.sync_bw) ; +#endif + + /* + * init all tx data structures for the asynchronous queue 0 + */ + smc->hw.fp.tx[QUEUE_A0] = queue = &smc->hw.fp.tx_q[QUEUE_A0] ; + queue->tx_bmu_ctl = (HW_PTR) ADDR(B0_XA_CSR) ; + queue->tx_bmu_dsc = (HW_PTR) ADDR(B5_XA_DA) ; + + + llc_recover_tx(smc) ; +} + +static void mac_counter_init(smc) +struct s_smc *smc ; +{ + int i ; + u_long *ec ; + + /* + * clear FORMAC+ frame-, lost- and error counter + */ + outpw(FM_A(FM_FCNTR),0) ; + outpw(FM_A(FM_LCNTR),0) ; + outpw(FM_A(FM_ECNTR),0) ; + /* + * clear internal error counter stucture + */ + ec = (u_long *)&smc->hw.fp.err_stats ; + for (i = (sizeof(struct err_st)/sizeof(long)) ; i ; i--) + *ec++ = 0L ; + smc->mib.m[MAC0].fddiMACRingOp_Ct = 0 ; +} + +/* + * set FORMAC address, and t_request + */ +static void set_formac_addr(smc) +struct s_smc *smc ; +{ + long t_requ = smc->mib.m[MAC0].fddiMACT_Req ; + + outpw(FM_A(FM_SAID),my_said) ; /* set short address */ + outpw(FM_A(FM_LAIL),(unsigned)((smc->hw.fddi_home_addr.a[4]<<8) + + smc->hw.fddi_home_addr.a[5])) ; + outpw(FM_A(FM_LAIC),(unsigned)((smc->hw.fddi_home_addr.a[2]<<8) + + smc->hw.fddi_home_addr.a[3])) ; + outpw(FM_A(FM_LAIM),(unsigned)((smc->hw.fddi_home_addr.a[0]<<8) + + smc->hw.fddi_home_addr.a[1])) ; + + outpw(FM_A(FM_SAGP),my_sagp) ; /* set short group address */ + + outpw(FM_A(FM_LAGL),(unsigned)((smc->hw.fp.group_addr.a[4]<<8) + + smc->hw.fp.group_addr.a[5])) ; + outpw(FM_A(FM_LAGC),(unsigned)((smc->hw.fp.group_addr.a[2]<<8) + + smc->hw.fp.group_addr.a[3])) ; + outpw(FM_A(FM_LAGM),(unsigned)((smc->hw.fp.group_addr.a[0]<<8) + + smc->hw.fp.group_addr.a[1])) ; + + /* set r_request regs. (MSW & LSW of TRT ) */ + outpw(FM_A(FM_TREQ1),(unsigned)(t_requ>>16)) ; + outpw(FM_A(FM_TREQ0),(unsigned)t_requ) ; +} + +void set_long(p,l) +char *p; +long l; +{ + p[0] = (char)(l >> 24) ; + p[1] = (char)(l >> 16) ; + p[2] = (char)(l >> 8) ; + p[3] = (char)(l >> 0) ; +} + +/* + * copy TX descriptor to buffer mem + * append FC field and MAC frame + * if more bit is set in descr + * append pointer to descriptor (endless loop) + * else + * append 'end of chain' pointer + */ +static void copy_tx_mac(smc,td,mac,off,len) +struct s_smc *smc ; +u_long td; /* transmit descriptor */ +struct fddi_mac *mac; /* mac frame pointer */ +unsigned off; /* start address within buffer memory */ +int len ; /* lenght of the frame including the FC */ +{ + int i ; + u_long *p ; + + CHECK_NPP() ; + MARW(off) ; /* set memory address reg for writes */ + + p = (u_long *) mac ; + for (i = (len + 3)/4 ; i ; i--) { + if (i == 1) { + /* last word, set the tag bit */ + outpw(FM_A(FM_CMDREG2),FM_ISTTB) ; + } + write_mdr(smc,MDR_REVERSE(*p)) ; + p++ ; + } + + outpw(FM_A(FM_CMDREG2),FM_ISTTB) ; /* set the tag bit */ + write_mdr(smc,td) ; /* write over memory data reg to buffer */ +} + +/* + BEGIN_MANUAL_ENTRY(module;tests;3) + How to test directed beacon frames + ---------------------------------------------------------------- + + o Insert a break point in the function build_claim_beacon() + before calling copy_tx_mac() for building the claim frame. + o Modify the RM3_DETECT case so that the RM6_DETECT state + will always entered from the RM3_DETECT state (function rmt_fsm(), + rmt.c) + o Compile the driver. + o Set the parameter TREQ in the protocol.ini or net.cfg to a + small value to make sure your station will win the claim + process. + o Start the driver. + o When you reach the break point, modify the SA and DA address + of the claim frame (e.g. SA = DA = 10005affffff). + o When you see RM3_DETECT and RM6_DETECT, observe the direct + beacon frames on the UPPSLANA. + + END_MANUAL_ENTRY + */ +static void directed_beacon(smc) +struct s_smc *smc ; +{ + SK_LOC_DECL(u_long,a[2]) ; + + /* + * set UNA in frame + * enable FORMAC to send endless queue of directed beacon + * important: the UNA starts at byte 1 (not at byte 0) + */ + * (char *) a = (char) ((long)DBEACON_INFO<<24L) ; + a[1] = 0 ; + memcpy((char *)a+1,(char *) &smc->mib.m[MAC0].fddiMACUpstreamNbr,6) ; + + CHECK_NPP() ; + /* set memory address reg for writes */ + MARW(smc->hw.fp.fifo.rbc_ram_start+DBEACON_FRAME_OFF+4) ; + write_mdr(smc,MDR_REVERSE(a[0])) ; + outpw(FM_A(FM_CMDREG2),FM_ISTTB) ; /* set the tag bit */ + write_mdr(smc,MDR_REVERSE(a[1])) ; + + outpw(FM_A(FM_SABC),smc->hw.fp.fifo.rbc_ram_start + DBEACON_FRAME_OFF) ; +} + +/* + setup claim & beacon pointer + NOTE : + special frame packets end with a pointer to their own + descriptor, and the MORE bit is set in the descriptor +*/ +static void build_claim_beacon(smc,t_request) +struct s_smc *smc ; +u_long t_request; +{ + u_long td ; + int len ; + struct fddi_mac_sf *mac ; + + /* + * build claim packet + */ + len = 17 ; + td = TX_DESCRIPTOR | ((((u_long)len-1)&3)<<27) ; + mac = &smc->hw.fp.mac_sfb ; + mac->mac_fc = FC_CLAIM ; + /* DA == SA in claim frame */ + mac->mac_source = mac->mac_dest = MA ; + /* 2's complement */ + set_long((char *)mac->mac_info,(long)t_request) ; + + copy_tx_mac(smc,td,(struct fddi_mac *)mac, + smc->hw.fp.fifo.rbc_ram_start + CLAIM_FRAME_OFF,len) ; + /* set CLAIM start pointer */ + outpw(FM_A(FM_SACL),smc->hw.fp.fifo.rbc_ram_start + CLAIM_FRAME_OFF) ; + + /* + * build beacon packet + */ + len = 17 ; + td = TX_DESCRIPTOR | ((((u_long)len-1)&3)<<27) ; + mac->mac_fc = FC_BEACON ; + mac->mac_source = MA ; + mac->mac_dest = null_addr ; /* DA == 0 in beacon frame */ + set_long((char *) mac->mac_info,((long)BEACON_INFO<<24L) + 0 ) ; + + copy_tx_mac(smc,td,(struct fddi_mac *)mac, + smc->hw.fp.fifo.rbc_ram_start + BEACON_FRAME_OFF,len) ; + /* set beacon start pointer */ + outpw(FM_A(FM_SABC),smc->hw.fp.fifo.rbc_ram_start + BEACON_FRAME_OFF) ; + + /* + * build directed beacon packet + * contains optional UNA + */ + len = 23 ; + td = TX_DESCRIPTOR | ((((u_long)len-1)&3)<<27) ; + mac->mac_fc = FC_BEACON ; + mac->mac_source = MA ; + mac->mac_dest = dbeacon_multi ; /* multicast */ + set_long((char *) mac->mac_info,((long)DBEACON_INFO<<24L) + 0 ) ; + set_long((char *) mac->mac_info+4,0L) ; + set_long((char *) mac->mac_info+8,0L) ; + + copy_tx_mac(smc,td,(struct fddi_mac *)mac, + smc->hw.fp.fifo.rbc_ram_start + DBEACON_FRAME_OFF,len) ; + + /* end of claim/beacon queue */ + outpw(FM_A(FM_EACB),smc->hw.fp.fifo.rx1_fifo_start-1) ; + + outpw(FM_A(FM_WPXSF),0) ; + outpw(FM_A(FM_RPXSF),0) ; +} + +void formac_rcv_restart(smc) +struct s_smc *smc ; +{ + /* enable receive function */ + SETMASK(FM_A(FM_MDREG1),smc->hw.fp.rx_mode,FM_ADDRX) ; + + outpw(FM_A(FM_CMDREG1),FM_ICLLR) ; /* clear receive lock */ +} + +void formac_tx_restart(smc) +struct s_smc *smc ; +{ + outpw(FM_A(FM_CMDREG1),FM_ICLLS) ; /* clear s-frame lock */ + outpw(FM_A(FM_CMDREG1),FM_ICLLA0) ; /* clear a-frame lock */ +} + +static void enable_formac(smc) +struct s_smc *smc ; +{ + /* set formac IMSK : 0 enables irq */ + outpw(FM_A(FM_IMSK1U),~mac_imsk1u) ; + outpw(FM_A(FM_IMSK1L),~mac_imsk1l) ; + outpw(FM_A(FM_IMSK2U),~mac_imsk2u) ; + outpw(FM_A(FM_IMSK2L),~mac_imsk2l) ; + outpw(FM_A(FM_IMSK3U),~mac_imsk3u) ; + outpw(FM_A(FM_IMSK3L),~mac_imsk3l) ; +} + +#if 0 /* Removed because the driver should use the ASICs TX complete IRQ. */ + /* The FORMACs tx complete IRQ should be used any longer */ + +/* + BEGIN_MANUAL_ENTRY(if,func;others;4) + + void enable_tx_irq(smc, queue) + struct s_smc *smc ; + u_short queue ; + +Function DOWNCALL (SMT, fplustm.c) + enable_tx_irq() enables the FORMACs transmit complete + interrupt of the queue. + +Para queue = QUEUE_S: synchronous queue + = QUEUE_A0: asynchronous queue + +Note After any ring operational change the transmit complete + interrupts are disabled. + The operating system dependent module must enable + the transmit complete interrupt of a queue, + - when it queues the first frame, + because of no transmit resources are beeing + available and + - when it escapes from the function llc_restart_tx + while some frames are still queued. + + END_MANUAL_ENTRY + */ +void enable_tx_irq(smc, queue) +struct s_smc *smc ; +u_short queue ; /* 0 = synchronous queue, 1 = asynchronous queue 0 */ +{ + u_short imask ; + + imask = ~(inpw(FM_A(FM_IMSK1U))) ; + + if (queue == 0) { + outpw(FM_A(FM_IMSK1U),~(imask|FM_STEFRMS)) ; + } + if (queue == 1) { + outpw(FM_A(FM_IMSK1U),~(imask|FM_STEFRMA0)) ; + } +} + +/* + BEGIN_MANUAL_ENTRY(if,func;others;4) + + void disable_tx_irq(smc, queue) + struct s_smc *smc ; + u_short queue ; + +Function DOWNCALL (SMT, fplustm.c) + disable_tx_irq disables the FORMACs transmit complete + interrupt of the queue + +Para queue = QUEUE_S: synchronous queue + = QUEUE_A0: asynchronous queue + +Note The operating system dependent module should disable + the transmit complete interrupts if it escapes from the + function llc_restart_tx and no frames are queued. + + END_MANUAL_ENTRY + */ +void disable_tx_irq(smc, queue) +struct s_smc *smc ; +u_short queue ; /* 0 = synchronous queue, 1 = asynchronous queue 0 */ +{ + u_short imask ; + + imask = ~(inpw(FM_A(FM_IMSK1U))) ; + + if (queue == 0) { + outpw(FM_A(FM_IMSK1U),~(imask&~FM_STEFRMS)) ; + } + if (queue == 1) { + outpw(FM_A(FM_IMSK1U),~(imask&~FM_STEFRMA0)) ; + } +} +#endif + +static void disable_formac(smc) +struct s_smc *smc ; +{ + /* clear formac IMSK : 1 disables irq */ + outpw(FM_A(FM_IMSK1U),MW) ; + outpw(FM_A(FM_IMSK1L),MW) ; + outpw(FM_A(FM_IMSK2U),MW) ; + outpw(FM_A(FM_IMSK2L),MW) ; + outpw(FM_A(FM_IMSK3U),MW) ; + outpw(FM_A(FM_IMSK3L),MW) ; +} + + +static void mac_ring_up(smc,up) +struct s_smc *smc ; +int up; +{ + if (up) { + formac_rcv_restart(smc) ; /* enable receive function */ + smc->hw.mac_ring_is_up = TRUE ; + llc_restart_tx(smc) ; /* TX queue */ + } + else { + /* disable receive function */ + SETMASK(FM_A(FM_MDREG1),FM_MDISRCV,FM_ADDET) ; + + /* abort current transmit activity */ + outpw(FM_A(FM_CMDREG2),FM_IACTR) ; + + smc->hw.mac_ring_is_up = FALSE ; + } +} + +/*--------------------------- ISR handling ----------------------------------*/ +/* + * mac1_irq is in drvfbi.c + */ + +/* + * mac2_irq: status bits for the receive queue 1, and ring status + * ring status indication bits + */ +void mac2_irq(smc,code_s2u,code_s2l) +struct s_smc *smc ; +u_short code_s2u ; +u_short code_s2l ; +{ + u_short change_s2l ; + u_short change_s2u ; + + /* (jd) 22-Feb-1999 + * Restart 2_DMax Timer after end of claiming or beaconing + */ + if (code_s2u & (FM_SCLM|FM_SHICLM|FM_SBEC|FM_SOTRBEC)) { + queue_event(smc,EVENT_RMT,RM_TX_STATE_CHANGE) ; + } + else if (code_s2l & (FM_STKISS)) { + queue_event(smc,EVENT_RMT,RM_TX_STATE_CHANGE) ; + } + + /* + * XOR current st bits with the last to avoid useless RMT event queuing + */ + change_s2l = smc->hw.fp.s2l ^ code_s2l ; + change_s2u = smc->hw.fp.s2u ^ code_s2u ; + + if ((change_s2l & FM_SRNGOP) || + (!smc->hw.mac_ring_is_up && ((code_s2l & FM_SRNGOP)))) { + if (code_s2l & FM_SRNGOP) { + mac_ring_up(smc,1) ; + queue_event(smc,EVENT_RMT,RM_RING_OP) ; + smc->mib.m[MAC0].fddiMACRingOp_Ct++ ; + } + else { + mac_ring_up(smc,0) ; + queue_event(smc,EVENT_RMT,RM_RING_NON_OP) ; + } + goto mac2_end ; + } + if (code_s2l & FM_SMISFRM) { /* missed frame */ + smc->mib.m[MAC0].fddiMACNotCopied_Ct++ ; + } + if (code_s2u & (FM_SRCVOVR | /* recv. FIFO overflow */ + FM_SRBFL)) { /* recv. buffer full */ + smc->hw.mac_ct.mac_r_restart_counter++ ; +/* formac_rcv_restart(smc) ; */ + smt_stat_counter(smc,1) ; +/* goto mac2_end ; */ + } + if (code_s2u & FM_SOTRBEC) + queue_event(smc,EVENT_RMT,RM_OTHER_BEACON) ; + if (code_s2u & FM_SMYBEC) + queue_event(smc,EVENT_RMT,RM_MY_BEACON) ; + if (change_s2u & code_s2u & FM_SLOCLM) { + DB_RMTN(2,"RMT : lower claim received\n",0,0) ; + } + if ((code_s2u & FM_SMYCLM) && !(code_s2l & FM_SDUPCLM)) { + /* + * This is my claim and that claim is not detected as a + * duplicate one. + */ + queue_event(smc,EVENT_RMT,RM_MY_CLAIM) ; + } + if (code_s2l & FM_SDUPCLM) { + /* + * If a duplicate claim frame (same SA but T_Bid != T_Req) + * this flag will be set. + * In the RMT state machine we need a RM_VALID_CLAIM event + * to do the appropriate state change. + * RM(34c) + */ + queue_event(smc,EVENT_RMT,RM_VALID_CLAIM) ; + } + if (change_s2u & code_s2u & FM_SHICLM) { + DB_RMTN(2,"RMT : higher claim received\n",0,0) ; + } + if ( (code_s2l & FM_STRTEXP) || + (code_s2l & FM_STRTEXR) ) + queue_event(smc,EVENT_RMT,RM_TRT_EXP) ; + if (code_s2l & FM_SMULTDA) { + /* + * The MAC has found a 2. MAC with the same address. + * Signal dup_addr_test = failed to RMT state machine. + * RM(25) + */ + smc->r.dup_addr_test = DA_FAILED ; + queue_event(smc,EVENT_RMT,RM_DUP_ADDR) ; + } + if (code_s2u & FM_SBEC) + smc->hw.fp.err_stats.err_bec_stat++ ; + if (code_s2u & FM_SCLM) + smc->hw.fp.err_stats.err_clm_stat++ ; + if (code_s2l & FM_STVXEXP) + smc->mib.m[MAC0].fddiMACTvxExpired_Ct++ ; + if ((code_s2u & (FM_SBEC|FM_SCLM))) { + if (!(change_s2l & FM_SRNGOP) && (smc->hw.fp.s2l & FM_SRNGOP)) { + mac_ring_up(smc,0) ; + queue_event(smc,EVENT_RMT,RM_RING_NON_OP) ; + + mac_ring_up(smc,1) ; + queue_event(smc,EVENT_RMT,RM_RING_OP) ; + smc->mib.m[MAC0].fddiMACRingOp_Ct++ ; + } + } + if (code_s2l & FM_SPHINV) + smc->hw.fp.err_stats.err_phinv++ ; + if (code_s2l & FM_SSIFG) + smc->hw.fp.err_stats.err_sifg_det++ ; + if (code_s2l & FM_STKISS) + smc->hw.fp.err_stats.err_tkiss++ ; + if (code_s2l & FM_STKERR) + smc->hw.fp.err_stats.err_tkerr++ ; + if (code_s2l & FM_SFRMCTR) + smc->mib.m[MAC0].fddiMACFrame_Ct += 0x10000L ; + if (code_s2l & FM_SERRCTR) + smc->mib.m[MAC0].fddiMACError_Ct += 0x10000L ; + if (code_s2l & FM_SLSTCTR) + smc->mib.m[MAC0].fddiMACLost_Ct += 0x10000L ; + if (code_s2u & FM_SERRSF) { + SMT_PANIC(smc,SMT_E0114, SMT_E0114_MSG) ; + } +mac2_end: + /* notice old status */ + smc->hw.fp.s2l = code_s2l ; + smc->hw.fp.s2u = code_s2u ; + outpw(FM_A(FM_IMSK2U),~mac_imsk2u) ; +} + +/* + * mac3_irq: receive queue 2 bits and address detection bits + */ +void mac3_irq(smc,code_s3u,code_s3l) +struct s_smc *smc ; +u_short code_s3u ; +u_short code_s3l ; +{ + UNUSED(code_s3l) ; + + if (code_s3u & (FM_SRCVOVR2 | /* recv. FIFO overflow */ + FM_SRBFL2)) { /* recv. buffer full */ + smc->hw.mac_ct.mac_r_restart_counter++ ; + smt_stat_counter(smc,1); + } + + + if (code_s3u & FM_SRPERRQ2) { /* parity error receive queue 2 */ + SMT_PANIC(smc,SMT_E0115, SMT_E0115_MSG) ; + } + if (code_s3u & FM_SRPERRQ1) { /* parity error receive queue 2 */ + SMT_PANIC(smc,SMT_E0116, SMT_E0116_MSG) ; + } +} + + +/* + * take formac offline + */ +static void formac_offline(smc) +struct s_smc *smc ; +{ + outpw(FM_A(FM_CMDREG2),FM_IACTR) ;/* abort current transmit activity */ + + /* disable receive function */ + SETMASK(FM_A(FM_MDREG1),FM_MDISRCV,FM_ADDET) ; + + /* FORMAC+ 'Initialize Mode' */ + SETMASK(FM_A(FM_MDREG1),FM_MINIT,FM_MMODE) ; + + disable_formac(smc) ; + smc->hw.mac_ring_is_up = FALSE ; + smc->hw.hw_state = STOPPED ; +} + +/* + * bring formac online + */ +static void formac_online(smc) +struct s_smc *smc ; +{ + enable_formac(smc) ; + SETMASK(FM_A(FM_MDREG1),FM_MONLINE | FM_SELRA | MDR1INIT | + smc->hw.fp.rx_mode, FM_MMODE | FM_SELRA | FM_ADDRX) ; +} + +/* + * FORMAC+ full init. (tx, rx, timer, counter, claim & beacon) + */ +int init_fplus(smc) +struct s_smc *smc ; +{ + smc->hw.fp.nsa_mode = FM_MRNNSAFNMA ; + smc->hw.fp.rx_mode = FM_MDAMA ; + smc->hw.fp.group_addr = fddi_broadcast ; + smc->hw.fp.func_addr = 0 ; + smc->hw.fp.frselreg_init = 0 ; + + init_driver_fplus(smc) ; + if (smc->s.sas == SMT_DAS) + smc->hw.fp.mdr3init |= FM_MENDAS ; + + smc->hw.mac_ct.mac_nobuf_counter = 0 ; + smc->hw.mac_ct.mac_r_restart_counter = 0 ; + + smc->hw.fp.fm_st1u = (HW_PTR) ADDR(B0_ST1U) ; + smc->hw.fp.fm_st1l = (HW_PTR) ADDR(B0_ST1L) ; + smc->hw.fp.fm_st2u = (HW_PTR) ADDR(B0_ST2U) ; + smc->hw.fp.fm_st2l = (HW_PTR) ADDR(B0_ST2L) ; + smc->hw.fp.fm_st3u = (HW_PTR) ADDR(B0_ST3U) ; + smc->hw.fp.fm_st3l = (HW_PTR) ADDR(B0_ST3L) ; + + smc->hw.fp.s2l = smc->hw.fp.s2u = 0 ; + smc->hw.mac_ring_is_up = 0 ; + + mac_counter_init(smc) ; + + /* convert BCKL units to symbol time */ + smc->hw.mac_pa.t_neg = (u_long)0 ; + smc->hw.mac_pa.t_pri = (u_long)0 ; + + /* make sure all PCI settings are correct */ + mac_do_pci_fix(smc) ; + + return(init_mac(smc,1)) ; + /* enable_formac(smc) ; */ +} + +static int init_mac(smc,all) +struct s_smc *smc ; +int all ; +{ + u_short t_max,x ; + u_long time=0 ; + + /* + * clear memory + */ + outpw(FM_A(FM_MDREG1),FM_MINIT) ; /* FORMAC+ init mode */ + set_formac_addr(smc) ; + outpw(FM_A(FM_MDREG1),FM_MMEMACT) ; /* FORMAC+ memory activ mode */ + /* Note: Mode register 2 is set here, incase parity is enabled. */ + outpw(FM_A(FM_MDREG2),smc->hw.fp.mdr2init) ; + + if (all) { + init_ram(smc) ; + } + else { + /* + * reset the HPI, the Master and the BMUs + */ + outp(ADDR(B0_CTRL), CTRL_HPI_SET) ; + time = hwt_quick_read(smc) ; + } + + /* + * set all pointers, frames etc + */ + smt_split_up_fifo(smc) ; + + init_tx(smc) ; + init_rx(smc) ; + init_rbc(smc) ; + + build_claim_beacon(smc,smc->mib.m[MAC0].fddiMACT_Req) ; + + /* set RX threshold */ + /* see Errata #SN2 Phantom receive overflow */ + outpw(FM_A(FM_FRMTHR),14<<12) ; /* switch on */ + + /* set formac work mode */ + outpw(FM_A(FM_MDREG1),MDR1INIT | FM_SELRA | smc->hw.fp.rx_mode) ; + outpw(FM_A(FM_MDREG2),smc->hw.fp.mdr2init) ; + outpw(FM_A(FM_MDREG3),smc->hw.fp.mdr3init) ; + outpw(FM_A(FM_FRSELREG),smc->hw.fp.frselreg_init) ; + + /* set timer */ + /* + * errata #22 fplus: + * T_MAX must not be FFFE + * or one of FFDF, FFB8, FF91 (-0x27 etc..) + */ + t_max = (u_short)(smc->mib.m[MAC0].fddiMACT_Max/32) ; + x = t_max/0x27 ; + x *= 0x27 ; + if ((t_max == 0xfffe) || (t_max - x == 0x16)) + t_max-- ; + outpw(FM_A(FM_TMAX),(u_short)t_max) ; + + /* BugFix for report #10204 */ + if (smc->mib.m[MAC0].fddiMACTvxValue < (u_long) (- US2BCLK(52))) { + outpw(FM_A(FM_TVX), (u_short) (- US2BCLK(52))/255 & MB) ; + } else { + outpw(FM_A(FM_TVX), + (u_short)((smc->mib.m[MAC0].fddiMACTvxValue/255) & MB)) ; + } + + outpw(FM_A(FM_CMDREG1),FM_ICLLS) ; /* clear s-frame lock */ + outpw(FM_A(FM_CMDREG1),FM_ICLLA0) ; /* clear a-frame lock */ + outpw(FM_A(FM_CMDREG1),FM_ICLLR); /* clear receive lock */ + + /* Auto unlock receice threshold for receive queue 1 and 2 */ + outpw(FM_A(FM_UNLCKDLY),(0xff|(0xff<<8))) ; + + rtm_init(smc) ; /* RT-Monitor */ + + if (!all) { + /* + * after 10ms, reset the BMUs and repair the rings + */ + hwt_wait_time(smc,time,MS2BCLK(10)) ; + outpd(ADDR(B0_R1_CSR),CSR_SET_RESET) ; + outpd(ADDR(B0_XA_CSR),CSR_SET_RESET) ; + outpd(ADDR(B0_XS_CSR),CSR_SET_RESET) ; + outp(ADDR(B0_CTRL), CTRL_HPI_CLR) ; + outpd(ADDR(B0_R1_CSR),CSR_CLR_RESET) ; + outpd(ADDR(B0_XA_CSR),CSR_CLR_RESET) ; + outpd(ADDR(B0_XS_CSR),CSR_CLR_RESET) ; + if (!smc->hw.hw_is_64bit) { + outpd(ADDR(B4_R1_F), RX_WATERMARK) ; + outpd(ADDR(B5_XA_F), TX_WATERMARK) ; + outpd(ADDR(B5_XS_F), TX_WATERMARK) ; + } + smc->hw.hw_state = STOPPED ; + mac_drv_repair_descr(smc) ; + } + smc->hw.hw_state = STARTED ; + + return(0) ; +} + + +/* + * called by CFM + */ +void config_mux(smc,mux) +struct s_smc *smc ; +int mux; +{ + plc_config_mux(smc,mux) ; + + SETMASK(FM_A(FM_MDREG1),FM_SELRA,FM_SELRA) ; +} + +/* + * called by RMT + * enable CLAIM/BEACON interrupts + * (only called if these events are of interest, e.g. in DETECT state + * the interrupt must not be permanently enabled + * RMT calls this function periodically (timer driven polling) + */ +void sm_mac_check_beacon_claim(smc) +struct s_smc *smc ; +{ + /* set formac IMSK : 0 enables irq */ + outpw(FM_A(FM_IMSK2U),~(mac_imsk2u | mac_beacon_imsk2u)) ; + /* the driver must receive the directed beacons */ + formac_rcv_restart(smc) ; + process_receive(smc) ; +} + +/*-------------------------- interface functions ----------------------------*/ +/* + * control ODL output + */ +void sm_pm_control(smc,mode) +struct s_smc *smc ; +int mode; +{ + SK_UNUSED(smc) ; + + /* + * if PCM logic has set LS_REQUEST = Transmit QUIET Line State + * /FOTOFF signal turn activ -> ODL disable + */ + switch(mode) { + case PM_TRANSMIT_DISABLE : + break ; + case PM_TRANSMIT_ENABLE : + break ; + } +} + +/* + * control MAC layer (called by RMT) + */ +void sm_ma_control(smc,mode) +struct s_smc *smc ; +int mode; +{ + switch(mode) { + case MA_OFFLINE : + /* Add to make the MAC offline in RM0_ISOLATED state */ + formac_offline(smc) ; + break ; + case MA_RESET : + (void)init_mac(smc,0) ; + break ; + case MA_BEACON : + formac_online(smc) ; + break ; + case MA_DIRECTED : + directed_beacon(smc) ; + break ; + case MA_TREQ : + /* + * no actions necessary, TREQ is already set + */ + break ; + } +} + +int sm_mac_get_tx_state(smc) +struct s_smc *smc ; +{ + return((inpw(FM_A(FM_STMCHN))>>4)&7) ; +} + +/* + * multicast functions + */ + +static struct s_fpmc *mac_get_mc_table(smc,user,own,del,can) +struct s_smc *smc ; +struct fddi_addr *user ; +struct fddi_addr *own ; +int del ; +int can ; +{ + struct s_fpmc *tb ; + struct s_fpmc *slot ; + u_char *p ; + int i ; + + /* + * set own = can(user) + */ + *own = *user ; + if (can) { + p = own->a ; + for (i = 0 ; i < 6 ; i++, p++) + *p = canonical[*p] ; + } + slot = 0 ; + for (i = 0, tb = smc->hw.fp.mc.table ; i < FPMAX_MULTICAST ; i++, tb++){ + if (!tb->n) { /* not used */ + if (!del && !slot) /* if !del save first free */ + slot = tb ; + continue ; + } + if (memcmp((char *)&tb->a,(char *)own,6)) + continue ; + return(tb) ; + } + return(slot) ; /* return first free or NULL */ +} + +/* + BEGIN_MANUAL_ENTRY(if,func;others;2) + + void mac_clear_multicast(smc) + struct s_smc *smc ; + +Function DOWNCALL (SMT, fplustm.c) + Clear all multicast entries + + END_MANUAL_ENTRY() + */ +void mac_clear_multicast(smc) +struct s_smc *smc ; +{ + struct s_fpmc *tb ; + int i ; + + smc->hw.fp.os_slots_used = 0 ; /* note the SMT addresses */ + /* will not be deleted */ + for (i = 0, tb = smc->hw.fp.mc.table ; i < FPMAX_MULTICAST ; i++, tb++){ + if (!tb->perm) { + tb->n = 0 ; + } + } +} + +/* + BEGIN_MANUAL_ENTRY(if,func;others;2) + + int mac_set_func_addr(smc,f_addr) + struct s_smc *smc ; + u_long f_addr ; + +Function DOWNCALL (SMT, fplustm.c) + Set a Token-Ring functional address, the address will + be activated after calling mac_update_multicast() + +Para f_addr functional bits in non-canonical format + +Returns 0: always success + + END_MANUAL_ENTRY() + */ +int mac_set_func_addr(smc,f_addr) +struct s_smc *smc ; +u_long f_addr ; +{ + smc->hw.fp.func_addr = f_addr ; + return(0) ; +} + + +/* + BEGIN_MANUAL_ENTRY(if,func;others;2) + + int mac_add_multicast(smc,addr,can) + struct s_smc *smc ; + struct fddi_addr *addr ; + int can ; + +Function DOWNCALL (SMC, fplustm.c) + Add an entry to the multicast table + +Para addr pointer to a multicast address + can = 0: the multicast address has the physical format + = 1: the multicast address has the canonical format + | 0x80 permanent + +Returns 0: success + 1: address table full + +Note After a 'driver reset' or a 'station set address' all + entries of the multicast table are cleared. + In this case the driver has to fill the multicast table again. + After the operating system dependent module filled + the multicast table it must call mac_update_multicast + to activate the new multicast addresses! + + END_MANUAL_ENTRY() + */ +int mac_add_multicast(smc,addr,can) +struct s_smc *smc ; +struct fddi_addr *addr ; +int can ; +{ + SK_LOC_DECL(struct fddi_addr,own) ; + struct s_fpmc *tb ; + + /* + * check if there are free table entries + */ + if (can & 0x80) { + if (smc->hw.fp.smt_slots_used >= SMT_MAX_MULTI) { + return(1) ; + } + } + else { + if (smc->hw.fp.os_slots_used >= FPMAX_MULTICAST-SMT_MAX_MULTI) { + return(1) ; + } + } + + /* + * find empty slot + */ + if (!(tb = mac_get_mc_table(smc,addr,&own,0,can & ~0x80))) + return(1) ; + tb->n++ ; + tb->a = own ; + tb->perm = (can & 0x80) ? 1 : 0 ; + + if (can & 0x80) + smc->hw.fp.smt_slots_used++ ; + else + smc->hw.fp.os_slots_used++ ; + + return(0) ; +} + +/* + BEGIN_MANUAL_ENTRY(if,func;others;2) + + void mac_del_multicast(smc,addr,can) + struct s_smc *smc ; + struct fddi_addr *addr ; + int can ; + +Function DOWNCALL (SMT, fplustm.c) + Delete an entry from the multicast table + +Para addr pointer to a multicast address + can = 0: the multicast address has the physical format + = 1: the multicast address has the canonical format + | 0x80 permanent + + END_MANUAL_ENTRY() + */ +void mac_del_multicast(smc,addr,can) +struct s_smc *smc ; +struct fddi_addr *addr ; +int can ; +{ + SK_LOC_DECL(struct fddi_addr,own) ; + struct s_fpmc *tb ; + + if (!(tb = mac_get_mc_table(smc,addr,&own,1,can & ~0x80))) + return ; + /* + * permanent addresses must be deleted with perm bit + * and vice versa + */ + if (( tb->perm && (can & 0x80)) || + (!tb->perm && !(can & 0x80))) { + /* + * delete it + */ + if (tb->n) { + tb->n-- ; + if (tb->perm) { + smc->hw.fp.smt_slots_used-- ; + } + else { + smc->hw.fp.os_slots_used-- ; + } + } + } +} + +/* + * mode + */ + +#define RX_MODE_PROM 0x1 +#define RX_MODE_ALL_MULTI 0x2 + +/* + BEGIN_MANUAL_ENTRY(if,func;others;2) + + void mac_update_multicast(smc) + struct s_smc *smc ; + +Function DOWNCALL (SMT, fplustm.c) + Update FORMAC multicast registers + + END_MANUAL_ENTRY() + */ +void mac_update_multicast(smc) +struct s_smc *smc ; +{ + struct s_fpmc *tb ; + u_char *fu ; + int i ; + + /* + * invalidate the CAM + */ + outpw(FM_A(FM_AFCMD),FM_IINV_CAM) ; + + /* + * set the functional address + */ + if (smc->hw.fp.func_addr) { + fu = (u_char *) &smc->hw.fp.func_addr ; + outpw(FM_A(FM_AFMASK2),0xffff) ; + outpw(FM_A(FM_AFMASK1),(u_short) ~((fu[0] << 8) + fu[1])) ; + outpw(FM_A(FM_AFMASK0),(u_short) ~((fu[2] << 8) + fu[3])) ; + outpw(FM_A(FM_AFPERS),FM_VALID|FM_DA) ; + outpw(FM_A(FM_AFCOMP2), 0xc000) ; + outpw(FM_A(FM_AFCOMP1), 0x0000) ; + outpw(FM_A(FM_AFCOMP0), 0x0000) ; + outpw(FM_A(FM_AFCMD),FM_IWRITE_CAM) ; + } + + /* + * set the mask and the personality register(s) + */ + outpw(FM_A(FM_AFMASK0),0xffff) ; + outpw(FM_A(FM_AFMASK1),0xffff) ; + outpw(FM_A(FM_AFMASK2),0xffff) ; + outpw(FM_A(FM_AFPERS),FM_VALID|FM_DA) ; + + for (i = 0, tb = smc->hw.fp.mc.table; i < FPMAX_MULTICAST; i++, tb++) { + if (tb->n) { + CHECK_CAM() ; + + /* + * wirte the multicast addres into the CAM + */ + outpw(FM_A(FM_AFCOMP2), + (u_short)((tb->a.a[0]<<8)+tb->a.a[1])) ; + outpw(FM_A(FM_AFCOMP1), + (u_short)((tb->a.a[2]<<8)+tb->a.a[3])) ; + outpw(FM_A(FM_AFCOMP0), + (u_short)((tb->a.a[4]<<8)+tb->a.a[5])) ; + outpw(FM_A(FM_AFCMD),FM_IWRITE_CAM) ; + } + } +} + +/* + BEGIN_MANUAL_ENTRY(if,func;others;3) + + void mac_set_rx_mode(smc,mode) + struct s_smc *smc ; + int mode ; + +Function DOWNCALL/INTERN (SMT, fplustm.c) + This function enables / disables the selected receive. + Don't call this function if the hardware module is + used -- use mac_drv_rx_mode() instead of. + +Para mode = 1 RX_ENABLE_ALLMULTI enable all multicasts + 2 RX_DISABLE_ALLMULTI disable "enable all multicasts" + 3 RX_ENABLE_PROMISC enable promiscous + 4 RX_DISABLE_PROMISC disable promiscous + 5 RX_ENABLE_NSA enable reception of NSA frames + 6 RX_DISABLE_NSA disable reception of NSA frames + +Note The selected receive modes will be lost after 'driver reset' + or 'set station address' + + END_MANUAL_ENTRY + */ +void mac_set_rx_mode(smc,mode) +struct s_smc *smc ; +int mode ; +{ + switch (mode) { + case RX_ENABLE_ALLMULTI : + smc->hw.fp.rx_prom |= RX_MODE_ALL_MULTI ; + break ; + case RX_DISABLE_ALLMULTI : + smc->hw.fp.rx_prom &= ~RX_MODE_ALL_MULTI ; + break ; + case RX_ENABLE_PROMISC : + smc->hw.fp.rx_prom |= RX_MODE_PROM ; + break ; + case RX_DISABLE_PROMISC : + smc->hw.fp.rx_prom &= ~RX_MODE_PROM ; + break ; + case RX_ENABLE_NSA : + smc->hw.fp.nsa_mode = FM_MDAMA ; + smc->hw.fp.rx_mode = (smc->hw.fp.rx_mode & ~FM_ADDET) | + smc->hw.fp.nsa_mode ; + break ; + case RX_DISABLE_NSA : + smc->hw.fp.nsa_mode = FM_MRNNSAFNMA ; + smc->hw.fp.rx_mode = (smc->hw.fp.rx_mode & ~FM_ADDET) | + smc->hw.fp.nsa_mode ; + break ; + } + if (smc->hw.fp.rx_prom & RX_MODE_PROM) { + smc->hw.fp.rx_mode = FM_MLIMPROM ; + } + else if (smc->hw.fp.rx_prom & RX_MODE_ALL_MULTI) { + smc->hw.fp.rx_mode = smc->hw.fp.nsa_mode | FM_EXGPA0 ; + } + else + smc->hw.fp.rx_mode = smc->hw.fp.nsa_mode ; + SETMASK(FM_A(FM_MDREG1),smc->hw.fp.rx_mode,FM_ADDRX) ; + mac_update_multicast(smc) ; +} + +/* + BEGIN_MANUAL_ENTRY(module;tests;3) + How to test the Restricted Token Monitor + ---------------------------------------------------------------- + + o Insert a break point in the function rtm_irq() + o Remove all stations with a restricted token monitor from the + network. + o Connect a UPPS ISA or EISA station to the network. + o Give the FORMAC of UPPS station the command to send + restricted tokens until the ring becomes instable. + o Now connect your test test client. + o The restricted token monitor should detect the restricted token, + and your break point will be reached. + o You can ovserve how the station will clean the ring. + + END_MANUAL_ENTRY + */ +void rtm_irq(smc) +struct s_smc *smc ; +{ + outpw(ADDR(B2_RTM_CRTL),TIM_CL_IRQ) ; /* clear IRQ */ + if (inpw(ADDR(B2_RTM_CRTL)) & TIM_RES_TOK) { + outpw(FM_A(FM_CMDREG1),FM_ICL) ; /* force claim */ + DB_RMT("RMT: fddiPATHT_Rmode expired\n",0,0) ; + AIX_EVENT(smc, (u_long) FDDI_RING_STATUS, + (u_long) FDDI_SMT_EVENT, + (u_long) FDDI_RTT, smt_get_event_word(smc)); + } + outpw(ADDR(B2_RTM_CRTL),TIM_START) ; /* enable RTM monitoring */ +} + +static void rtm_init(smc) +struct s_smc *smc ; +{ + outpd(ADDR(B2_RTM_INI),0) ; /* timer = 0 */ + outpw(ADDR(B2_RTM_CRTL),TIM_START) ; /* enable IRQ */ +} + +void rtm_set_timer(smc) +struct s_smc *smc ; +{ + /* + * MIB timer and hardware timer have the same resolution of 80nS + */ + DB_RMT("RMT: setting new fddiPATHT_Rmode, t = %d ns \n", + (int) smc->mib.a[PATH0].fddiPATHT_Rmode,0) ; + outpd(ADDR(B2_RTM_INI),smc->mib.a[PATH0].fddiPATHT_Rmode) ; +} + +static void smt_split_up_fifo(smc) +struct s_smc *smc ; +{ + +/* + BEGIN_MANUAL_ENTRY(module;mem;1) + ------------------------------------------------------------- + RECEIVE BUFFER MEMORY DIVERSION + ------------------------------------------------------------- + + R1_RxD == SMT_R1_RXD_COUNT + R2_RxD == SMT_R2_RXD_COUNT + + SMT_R1_RXD_COUNT must be unequal zero + + | R1_RxD R2_RxD |R1_RxD R2_RxD | R1_RxD R2_RxD + | x 0 | x 1-3 | x < 3 + ---------------------------------------------------------------------- + | 63,75 kB | 54,75 | R1_RxD + rx queue 1 | RX_FIFO_SPACE | RX_LARGE_FIFO| ------------- * 63,75 kB + | | | R1_RxD+R2_RxD + ---------------------------------------------------------------------- + | | 9 kB | R2_RxD + rx queue 2 | 0 kB | RX_SMALL_FIFO| ------------- * 63,75 kB + | (not used) | | R1_RxD+R2_RxD + + END_MANUAL_ENTRY +*/ + + if (SMT_R1_RXD_COUNT == 0) { + SMT_PANIC(smc,SMT_E0117, SMT_E0117_MSG) ; + } + + switch(SMT_R2_RXD_COUNT) { + case 0: + smc->hw.fp.fifo.rx1_fifo_size = RX_FIFO_SPACE ; + smc->hw.fp.fifo.rx2_fifo_size = 0 ; + break ; + case 1: + case 2: + case 3: + smc->hw.fp.fifo.rx1_fifo_size = RX_LARGE_FIFO ; + smc->hw.fp.fifo.rx2_fifo_size = RX_SMALL_FIFO ; + break ; + default: /* this is not the real defaule */ + smc->hw.fp.fifo.rx1_fifo_size = RX_FIFO_SPACE * + SMT_R1_RXD_COUNT/(SMT_R1_RXD_COUNT+SMT_R2_RXD_COUNT) ; + smc->hw.fp.fifo.rx2_fifo_size = RX_FIFO_SPACE * + SMT_R2_RXD_COUNT/(SMT_R1_RXD_COUNT+SMT_R2_RXD_COUNT) ; + break ; + } + +/* + BEGIN_MANUAL_ENTRY(module;mem;1) + ------------------------------------------------------------- + TRANSMIT BUFFER MEMORY DIVERSION + ------------------------------------------------------------- + + + | no sync bw | sync bw available and | sync bw available and + | available | SynchTxMode = SPLIT | SynchTxMode = ALL + ----------------------------------------------------------------------- + sync tx | 0 kB | 32 kB | 55 kB + queue | | TX_MEDIUM_FIFO | TX_LARGE_FIFO + ----------------------------------------------------------------------- + async tx | 64 kB | 32 kB | 9 k + queue | TX_FIFO_SPACE| TX_MEDIUM_FIFO | TX_SMALL_FIFO + + END_MANUAL_ENTRY +*/ + + /* + * set the tx mode bits + */ + if (smc->mib.a[PATH0].fddiPATHSbaPayload) { +#ifdef ESS + smc->hw.fp.fifo.fifo_config_mode |= + smc->mib.fddiESSSynchTxMode | SYNC_TRAFFIC_ON ; +#endif + } + else { + smc->hw.fp.fifo.fifo_config_mode &= + ~(SEND_ASYNC_AS_SYNC|SYNC_TRAFFIC_ON) ; + } + + /* + * split up the FIFO + */ + if (smc->hw.fp.fifo.fifo_config_mode & SYNC_TRAFFIC_ON) { + if (smc->hw.fp.fifo.fifo_config_mode & SEND_ASYNC_AS_SYNC) { + smc->hw.fp.fifo.tx_s_size = TX_LARGE_FIFO ; + smc->hw.fp.fifo.tx_a0_size = TX_SMALL_FIFO ; + } + else { + smc->hw.fp.fifo.tx_s_size = TX_MEDIUM_FIFO ; + smc->hw.fp.fifo.tx_a0_size = TX_MEDIUM_FIFO ; + } + } + else { + smc->hw.fp.fifo.tx_s_size = 0 ; + smc->hw.fp.fifo.tx_a0_size = TX_FIFO_SPACE ; + } + + smc->hw.fp.fifo.rx1_fifo_start = smc->hw.fp.fifo.rbc_ram_start + + RX_FIFO_OFF ; + smc->hw.fp.fifo.tx_s_start = smc->hw.fp.fifo.rx1_fifo_start + + smc->hw.fp.fifo.rx1_fifo_size ; + smc->hw.fp.fifo.tx_a0_start = smc->hw.fp.fifo.tx_s_start + + smc->hw.fp.fifo.tx_s_size ; + smc->hw.fp.fifo.rx2_fifo_start = smc->hw.fp.fifo.tx_a0_start + + smc->hw.fp.fifo.tx_a0_size ; + + DB_SMT("FIFO split: mode = %x\n",smc->hw.fp.fifo.fifo_config_mode,0) ; + DB_SMT("rbc_ram_start = %x rbc_ram_end = %x\n", + smc->hw.fp.fifo.rbc_ram_start, smc->hw.fp.fifo.rbc_ram_end) ; + DB_SMT("rx1_fifo_start = %x tx_s_start = %x\n", + smc->hw.fp.fifo.rx1_fifo_start, smc->hw.fp.fifo.tx_s_start) ; + DB_SMT("tx_a0_start = %x rx2_fifo_start = %x\n", + smc->hw.fp.fifo.tx_a0_start, smc->hw.fp.fifo.rx2_fifo_start) ; +} + +void formac_reinit_tx(smc) +struct s_smc *smc ; +{ + /* + * Split up the FIFO and reinitialize the MAC if synchronous + * bandwidth becomes available but no synchronous queue is + * configured. + */ + if (!smc->hw.fp.fifo.tx_s_size && smc->mib.a[PATH0].fddiPATHSbaPayload){ + (void)init_mac(smc,0) ; + } +} + + diff -u --recursive --new-file v2.3.46/linux/drivers/net/skfp/h/cmtdef.h linux/drivers/net/skfp/h/cmtdef.h --- v2.3.46/linux/drivers/net/skfp/h/cmtdef.h Wed Dec 31 16:00:00 1969 +++ linux/drivers/net/skfp/h/cmtdef.h Fri Feb 18 14:55:53 2000 @@ -0,0 +1,801 @@ +/****************************************************************************** + * + * (C)Copyright 1998,1999 SysKonnect, + * a business unit of Schneider & Koch & Co. Datensysteme GmbH. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * The information in this file is provided "AS IS" without warranty. + * + ******************************************************************************/ + +#ifndef _CMTDEF_ +#define _CMTDEF_ + +/* **************************************************************** */ + +/* + * implementation specific constants + * MODIIFY THE FOLLWOING THREE DEFINES + */ +#define AMDPLC /* if Amd PLC chip used */ +#ifdef CONC +#define NUMPHYS 12 /* 2 for SAS or DAS, more for Concentrator */ +#else +#ifdef CONC_II +#define NUMPHYS 24 /* 2 for SAS or DAS, more for Concentrator */ +#else +#define NUMPHYS 2 /* 2 for SAS or DAS, more for Concentrator */ +#endif +#endif +#define NUMMACS 1 /* only 1 supported at the moment */ +#define NUMPATHS 2 /* primary and secondary path supported */ + +/* + * DO NOT MODIFY BEYOND THIS POINT + */ + +/* **************************************************************** */ + +#if NUMPHYS > 2 +#define CONCENTRATOR +#endif + +/* + * Definitions for comfortable LINT usage + */ +#ifdef lint +#define LINT_USE(x) (x)=(x) +#else +#define LINT_USE(x) +#endif + +#ifdef DEBUG +#define DB_PR(flag,a,b,c) { if (flag) printf(a,b,c) ; } +#else +#define DB_PR(flag,a,b,c) +#endif + +#ifdef DEBUG_BRD +#define DB_ECM(a,b,c) DB_PR((smc->debug.d_smt&1),a,b,c) +#define DB_ECMN(n,a,b,c) DB_PR((smc->debug.d_ecm >=(n)),a,b,c) +#define DB_RMT(a,b,c) DB_PR((smc->debug.d_smt&2),a,b,c) +#define DB_RMTN(n,a,b,c) DB_PR((smc->debug.d_rmt >=(n)),a,b,c) +#define DB_CFM(a,b,c) DB_PR((smc->debug.d_smt&4),a,b,c) +#define DB_CFMN(n,a,b,c) DB_PR((smc->debug.d_cfm >=(n)),a,b,c) +#define DB_PCM(a,b,c) DB_PR((smc->debug.d_smt&8),a,b,c) +#define DB_PCMN(n,a,b,c) DB_PR((smc->debug.d_pcm >=(n)),a,b,c) +#define DB_SMT(a,b,c) DB_PR((smc->debug.d_smtf),a,b,c) +#define DB_SMTN(n,a,b,c) DB_PR((smc->debug.d_smtf >=(n)),a,b,c) +#define DB_SBA(a,b,c) DB_PR((smc->debug.d_sba),a,b,c) +#define DB_SBAN(n,a,b,c) DB_PR((smc->debug.d_sba >=(n)),a,b,c) +#define DB_ESS(a,b,c) DB_PR((smc->debug.d_ess),a,b,c) +#define DB_ESSN(n,a,b,c) DB_PR((smc->debug.d_ess >=(n)),a,b,c) +#else +#define DB_ECM(a,b,c) DB_PR((debug.d_smt&1),a,b,c) +#define DB_ECMN(n,a,b,c) DB_PR((debug.d_ecm >=(n)),a,b,c) +#define DB_RMT(a,b,c) DB_PR((debug.d_smt&2),a,b,c) +#define DB_RMTN(n,a,b,c) DB_PR((debug.d_rmt >=(n)),a,b,c) +#define DB_CFM(a,b,c) DB_PR((debug.d_smt&4),a,b,c) +#define DB_CFMN(n,a,b,c) DB_PR((debug.d_cfm >=(n)),a,b,c) +#define DB_PCM(a,b,c) DB_PR((debug.d_smt&8),a,b,c) +#define DB_PCMN(n,a,b,c) DB_PR((debug.d_pcm >=(n)),a,b,c) +#define DB_SMT(a,b,c) DB_PR((debug.d_smtf),a,b,c) +#define DB_SMTN(n,a,b,c) DB_PR((debug.d_smtf >=(n)),a,b,c) +#define DB_SBA(a,b,c) DB_PR((debug.d_sba),a,b,c) +#define DB_SBAN(n,a,b,c) DB_PR((debug.d_sba >=(n)),a,b,c) +#define DB_ESS(a,b,c) DB_PR((debug.d_ess),a,b,c) +#define DB_ESSN(n,a,b,c) DB_PR((debug.d_ess >=(n)),a,b,c) +#endif + +#ifndef SS_NOT_DS +#define SK_LOC_DECL(type,var) type var +#else +#define SK_LOC_DECL(type,var) static type var +#endif +/* + * PHYs and PORTS + * Note: Don't touch the definition of PA and PB. Those might be used + * by some "for" loops. + */ +#define PA 0 +#define PB 1 +#if defined(SUPERNET_3) || defined(CONC_II) +/* + * The port indices have to be different, + * because the MAC output goes through the 2. PLC + * Conc II: It has to be the first port in the row. + */ +#define PS 0 /* Internal PLC which is the same as PA */ +#else +#define PS 1 +#endif +#define PM 2 /* PM .. PA+NUM_PHYS-1 */ + +/* + * PHY types - as in path descriptor 'fddiPHYType' + */ +#define TA 0 /* A port */ +#define TB 1 /* B port */ +#define TS 2 /* S port */ +#define TM 3 /* M port */ +#define TNONE 4 + + +/* + * indexes in MIB + */ +#define INDEX_MAC 1 +#define INDEX_PATH 1 +#define INDEX_PORT 1 + + +/* + * policies + */ +#define POLICY_AA (1<<0) /* reject AA */ +#define POLICY_AB (1<<1) /* reject AB */ +#define POLICY_AS (1<<2) /* reject AS */ +#define POLICY_AM (1<<3) /* reject AM */ +#define POLICY_BA (1<<4) /* reject BA */ +#define POLICY_BB (1<<5) /* reject BB */ +#define POLICY_BS (1<<6) /* reject BS */ +#define POLICY_BM (1<<7) /* reject BM */ +#define POLICY_SA (1<<8) /* reject SA */ +#define POLICY_SB (1<<9) /* reject SB */ +#define POLICY_SS (1<<10) /* reject SS */ +#define POLICY_SM (1<<11) /* reject SM */ +#define POLICY_MA (1<<12) /* reject MA */ +#define POLICY_MB (1<<13) /* reject MB */ +#define POLICY_MS (1<<14) /* reject MS */ +#define POLICY_MM (1<<15) /* reject MM */ + +/* + * commands + */ + +/* + * EVENTS + * event classes + */ +#define EVENT_ECM 1 /* event class ECM */ +#define EVENT_CFM 2 /* event class CFM */ +#define EVENT_RMT 3 /* event class RMT */ +#define EVENT_SMT 4 /* event class SMT */ +#define EVENT_PCM 5 /* event class PCM */ +#define EVENT_PCMA 5 /* event class PCMA */ +#define EVENT_PCMB 6 /* event class PCMB */ + +/* WARNING : + * EVENT_PCM* must be last in the above list + * if more then two ports are used, EVENT_PCM .. EVENT_PCMA+NUM_PHYS-1 + * are used ! + */ + +#define EV_TOKEN(class,event) (((u_long)(class)<<16L)|((u_long)(event))) +#define EV_T_CLASS(token) ((int)((token)>>16)&0xffff) +#define EV_T_EVENT(token) ((int)(token)&0xffff) + +/* + * ECM events + */ +#define EC_CONNECT 1 /* connect request */ +#define EC_DISCONNECT 2 /* disconnect request */ +#define EC_TRACE_PROP 3 /* trace propagation */ +#define EC_PATH_TEST 4 /* path test */ +#define EC_TIMEOUT_TD 5 /* timer TD_min */ +#define EC_TIMEOUT_TMAX 6 /* timer trace_max */ +#define EC_TIMEOUT_IMAX 7 /* timer I_max */ +#define EC_TIMEOUT_INMAX 8 /* timer IN_max */ +#define EC_TEST_DONE 9 /* path test done */ + +/* + * CFM events + */ +#define CF_LOOP 1 /* cf_loop flag from PCM */ +#define CF_LOOP_A 1 /* cf_loop flag from PCM */ +#define CF_LOOP_B 2 /* cf_loop flag from PCM */ +#define CF_JOIN 3 /* cf_join flag from PCM */ +#define CF_JOIN_A 3 /* cf_join flag from PCM */ +#define CF_JOIN_B 4 /* cf_join flag from PCM */ + +/* + * PCM events + */ +#define PC_START 1 +#define PC_STOP 2 +#define PC_LOOP 3 +#define PC_JOIN 4 +#define PC_SIGNAL 5 +#define PC_REJECT 6 +#define PC_MAINT 7 +#define PC_TRACE 8 +#define PC_PDR 9 +#define PC_ENABLE 10 +#define PC_DISABLE 11 + +/* + * must be ordered as in LineStateType + */ +#define PC_QLS 12 +#define PC_ILS 13 +#define PC_MLS 14 +#define PC_HLS 15 +#define PC_LS_PDR 16 +#define PC_LS_NONE 17 +#define LS2MIB(x) ((x)-PC_QLS) +#define MIB2LS(x) ((x)+PC_QLS) + +#define PC_TIMEOUT_TB_MAX 18 /* timer TB_max */ +#define PC_TIMEOUT_TB_MIN 19 /* timer TB_min */ +#define PC_TIMEOUT_C_MIN 20 /* timer C_Min */ +#define PC_TIMEOUT_T_OUT 21 /* timer T_Out */ +#define PC_TIMEOUT_TL_MIN 22 /* timer TL_Min */ +#define PC_TIMEOUT_T_NEXT 23 /* timer t_next[] */ +#define PC_TIMEOUT_LCT 24 +#define PC_NSE 25 /* NOISE hardware timer */ +#define PC_LEM 26 /* LEM done */ + +/* + * RMT events meaning from + */ +#define RM_RING_OP 1 /* ring operational MAC */ +#define RM_RING_NON_OP 2 /* ring not operational MAC */ +#define RM_MY_BEACON 3 /* recvd my beacon MAC */ +#define RM_OTHER_BEACON 4 /* recvd other beacon MAC */ +#define RM_MY_CLAIM 5 /* recvd my claim MAC */ +#define RM_TRT_EXP 6 /* TRT exp MAC */ +#define RM_VALID_CLAIM 7 /* claim from dup addr MAC */ +#define RM_JOIN 8 /* signal rm_join CFM */ +#define RM_LOOP 9 /* signal rm_loop CFM */ +#define RM_DUP_ADDR 10 /* dup_addr_test hange SMT-NIF */ +#define RM_ENABLE_FLAG 11 /* enable flag */ + +#define RM_TIMEOUT_NON_OP 12 /* timeout T_Non_OP */ +#define RM_TIMEOUT_T_STUCK 13 /* timeout T_Stuck */ +#define RM_TIMEOUT_ANNOUNCE 14 /* timeout T_Announce */ +#define RM_TIMEOUT_T_DIRECT 15 /* timeout T_Direct */ +#define RM_TIMEOUT_D_MAX 16 /* timeout D_Max */ +#define RM_TIMEOUT_POLL 17 /* claim/beacon poller */ +#define RM_TX_STATE_CHANGE 18 /* To restart timer for D_Max */ + +/* + * SMT events + */ +#define SM_TIMER 1 /* timer */ +#define SM_FAST 2 /* smt_force_irq */ + +/* PC modes */ +#define PM_NONE 0 +#define PM_PEER 1 +#define PM_TREE 2 + +/* + * PCM withhold codes + * MIB PC-WithholdType ENUM + */ +#define PC_WH_NONE 0 /* ok */ +#define PC_WH_M_M 1 /* M to M */ +#define PC_WH_OTHER 2 /* other incompatible phys */ +#define PC_WH_PATH 3 /* path not available */ +/* + * LCT duration + */ +#define LC_SHORT 1 /* short LCT */ +#define LC_MEDIUM 2 /* medium LCT */ +#define LC_LONG 3 /* long LCT */ +#define LC_EXTENDED 4 /* extended LCT */ + +/* + * path_test values + */ +#define PT_NONE 0 +#define PT_TESTING 1 /* test is running */ +#define PT_PASSED 2 /* test passed */ +#define PT_FAILED 3 /* test failed */ +#define PT_PENDING 4 /* path test follows */ +#define PT_EXITING 5 /* disconnected while in trace/leave */ + +/* + * duplicate address test + * MIB DupAddressTest ENUM + */ +#define DA_NONE 0 /* */ +#define DA_PASSED 1 /* test passed */ +#define DA_FAILED 2 /* test failed */ + + +/* + * optical bypass + */ +#define BP_DEINSERT 0 /* disable bypass */ +#define BP_INSERT 1 /* enable bypass */ + +/* + * ODL enable/disable + */ +#define PM_TRANSMIT_DISABLE 0 /* disable xmit */ +#define PM_TRANSMIT_ENABLE 1 /* enable xmit */ + +/* + * parameter for config_mux + * note : number is index in config_endec table ! + */ +#define MUX_THRUA 0 /* through A */ +#define MUX_THRUB 1 /* through B */ +#define MUX_WRAPA 2 /* wrap A */ +#define MUX_WRAPB 3 /* wrap B */ +#define MUX_ISOLATE 4 /* isolated */ +#define MUX_WRAPS 5 /* SAS */ + +/* + * MAC control + */ +#define MA_RESET 0 +#define MA_BEACON 1 +#define MA_CLAIM 2 +#define MA_DIRECTED 3 /* directed beacon */ +#define MA_TREQ 4 /* change T_Req */ +#define MA_OFFLINE 5 /* switch MAC to offline */ + + +/* + * trace prop + * bit map for trace propagation + */ +#define ENTITY_MAC (NUMPHYS) +#define ENTITY_PHY(p) (p) +#define ENTITY_BIT(m) (1<<(m)) + +/* + * Resource Tag Types + */ +#define PATH_ISO 0 /* isolated */ +#define PATH_PRIM 3 /* primary path */ +#define PATH_THRU 5 /* through path */ + +#define RES_MAC 2 /* resource type MAC */ +#define RES_PORT 4 /* resource type PORT */ + + +/* + * CFM state + * oops: MUST MATCH CF-StateType in SMT7.2 ! + */ +#define SC0_ISOLATED 0 /* isolated */ +#define SC1_WRAP_A 5 /* wrap A (not used) */ +#define SC2_WRAP_B 6 /* wrap B (not used) */ +#define SC4_THRU_A 12 /* through A */ +#define SC5_THRU_B 7 /* through B (used in SMT 6.2) */ +#define SC7_WRAP_S 8 /* SAS (not used) */ +#define SC9_C_WRAP_A 9 /* c wrap A */ +#define SC10_C_WRAP_B 10 /* c wrap B */ +#define SC11_C_WRAP_S 11 /* c wrap S */ + +/* + * convert MIB time in units of 80nS to uS + */ +#define MIB2US(t) ((t)/12) +#define SEC2MIB(s) ((s)*12500000L) +/* + * SMT timer + */ +struct smt_timer { + struct smt_timer *tm_next ; /* linked list */ + struct s_smc *tm_smc ; /* pointer to context */ + u_long tm_delta ; /* delta time */ + u_long tm_token ; /* token value */ + u_short tm_active ; /* flag : active/inactive */ + u_short tm_pad ; /* pad field */ +} ; + +/* + * communication structures + */ +struct mac_parameter { + u_long t_neg ; /* T_Neg parameter */ + u_long t_pri ; /* T_Pri register in MAC */ +} ; + +/* + * MAC counters + */ +struct mac_counter { + u_long mac_nobuf_counter ; /* MAC SW counter: no buffer */ + u_long mac_r_restart_counter ; /* MAC SW counter: rx restarted */ +} ; + +/* + * para struct context for SMT parameters + */ +struct s_pcon { + int pc_len ; + int pc_err ; + int pc_badset ; + void *pc_p ; +} ; + + +/* + * link error monitor + */ +#define LEM_AVG 5 +struct lem_counter { +#ifdef AM29K + int lem_on ; + u_long lem_errors ; + u_long lem_symbols ; + u_long lem_tsymbols ; + int lem_s_count ; + int lem_n_s ; + int lem_values ; + int lem_index ; + int lem_avg_ber[LEM_AVG] ; + int lem_sum ; +#else + u_short lem_float_ber ; /* 10E-nn bit error rate */ + u_long lem_errors ; /* accumulated error count */ + u_short lem_on ; +#endif +} ; + +#define NUMBITS 10 + + +#ifdef AMDPLC + +/* + * PLC state table + */ +struct s_plc { + u_short p_state ; /* current state */ + u_short p_bits ; /* number of bits to send */ + u_short p_start ; /* first bit pos */ + u_short p_pad ; /* padding for alignment */ + u_long soft_err ; /* error counter */ + u_long parity_err ; /* error counter */ + u_long ebuf_err ; /* error counter */ + u_long ebuf_cont ; /* continous error counter */ + u_long phyinv ; /* error counter */ + u_long vsym_ctr ; /* error counter */ + u_long mini_ctr ; /* error counter */ + u_long tpc_exp ; /* error counter */ + u_long np_err ; /* error counter */ + u_long b_pcs ; /* error counter */ + u_long b_tpc ; /* error counter */ + u_long b_tne ; /* error counter */ + u_long b_qls ; /* error counter */ + u_long b_ils ; /* error counter */ + u_long b_hls ; /* error counter */ +} ; +#endif + +#ifdef PROTOTYP_INC +#include "fddi/driver.pro" +#else /* PROTOTYP_INC */ +/* + * function prototypes + */ +#include "h/mbuf.h" /* Type definitions for MBUFs */ +void hwt_restart( /* hwt.c */ +#ifdef ANSIC + struct s_smc *smc +#endif + ) ; + +SMbuf *smt_build_frame( /* smt.c */ +#ifdef ANSIC + struct s_smc *smc, + int class, + int type, + int length +#endif + ) ; + +SMbuf *smt_get_mbuf( /* drvsr.c */ +#ifdef ANSIC + struct s_smc *smc +#endif + ) ; + +void *sm_to_para( /* smt.c */ +#ifdef ANSIC + struct s_smc *smc, + struct smt_header *sm, + int para +#endif + ) ; + +#ifndef SK_UNUSED +#define SK_UNUSED(var) (void)(var) +#endif + +void queue_event() ; +void ecm() ; +void ecm_init() ; +void rmt() ; +void rmt_init() ; +void pcm() ; +void pcm_init() ; +void cfm() ; +void cfm_init() ; +void smt_timer_start() ; +void smt_timer_stop() ; +void pcm_status_state() ; +void plc_config_mux() ; +void sm_lem_evaluate() ; +void smt_clear_una_dna() ; +void mac_status_para() ; +void mac_update_counter() ; +void sm_pm_ls_latch() ; +void sm_ma_control() ; +void sm_mac_check_beacon_claim() ; +void config_mux() ; +void smt_agent_init() ; +void smt_timer_init() ; +void smt_received_pack() ; +void smt_add_para() ; +void smt_swap_para() ; +void ev_init() ; +void hwt_init() ; +u_long hwt_read() ; +void hwt_stop() ; +void hwt_start() ; +void smt_send_mbuf() ; +void smt_free_mbuf() ; +void sm_pm_bypass_req() ; +void rmt_indication() ; +void cfm_state_change() ; +void rx_indication() ; +void tx_indication() ; +#ifndef NO_SMT_PANIC +void smt_panic() ; +#else +#ifdef DEBUG +void smt_panic() ; +#else +#define smt_panic(smc,text) +#endif /* DEBUG */ +#endif /* NO_SMT_PANIC */ +void smt_stat_counter() ; +void smt_timer_poll() ; +u_long smt_get_time() ; +u_long smt_get_tid() ; +void smt_timer_done() ; +void smt_set_defaults() ; +void smt_fixup_mib() ; +void smt_reset_defaults() ; +void smt_agent_task() ; +void smt_please_reconnect() ; +int smt_check_para() ; +void driver_get_bia() ; +#ifdef SUPERNET_3 +void drv_reset_indication() ; +#endif /* SUPERNET_3 */ +void smt_start_watchdog() ; + +void smt_event() ; +void pcm_event() ; +void rmt_event() ; +void cfm_event() ; +void timer_event() ; +void ev_dispatcher() ; + +void smt_get_state() ; +void ecm_get_state() ; +void pcm_get_state() ; +void rmt_get_state() ; + +void ecm_state_change() ; +int sm_pm_bypass_present() ; +void pcm_state_change() ; +void rmt_state_change() ; +int sm_pm_get_ls() ; +int pcm_get_s_port() ; +int pcm_rooted_station() ; +int cfm_get_mac_input() ; +int cfm_get_mac_output() ; +int port_to_mib() ; +int cem_build_path() ; +int sm_mac_get_tx_state() ; +int is_individual() ; +int is_my_addr() ; +int is_broadcast() ; +int is_equal() ; +char *get_pcmstate() ; + +int smt_action() ; +u_short smt_online() ; +void smt_force_irq() ; +void smt_pmf_received_pack() ; +void smt_send_frame() ; +void smt_set_timestamp() ; +void mac_set_rx_mode() ; +int mac_add_multicast() ; +int mac_set_func_addr() ; +void mac_del_multicast() ; +void mac_update_multicast() ; +void mac_clear_multicast() ; +void mac_rx_directed_beacon() ; +void set_formac_tsync() ; +void formac_reinit_tx() ; +void formac_tx_restart() ; +void process_receive() ; +void init_driver_fplus() ; + +void rtm_irq() ; +void rtm_set_timer() ; +void ring_status_indication() ; +void llc_recover_tx() ; +void llc_restart_tx() ; +void plc_clear_irq() ; +void plc_irq() ; +int smt_set_mac_opvalues() ; +#ifdef TAG_MODE +void mac_drv_pci_fix() ; +void mac_do_pci_fix() ; +void mac_drv_clear_tx_queue() ; +void mac_drv_repair_descr() ; +u_long hwt_quick_read() ; +void hwt_wait_time() ; +#endif + +#ifdef SMT_PNMI +#ifdef ANSIC +int pnmi_init (struct s_smc* smc); +int pnmi_process_ndis_id (struct s_smc* smc, u_long ndis_oid, void* buf, + int len, int* BytesAccessed, int* BytesNeeded, u_char action); +#else +int pnmi_init (); +int pnmi_process_ndis_id (); +#endif +#endif + +#ifdef SBA +#ifndef _H2INC +void sba() ; +#endif +void sba_raf_received_pack() ; +void sba_timer_poll() ; +void smt_init_sba() ; +#endif +#ifdef ESS +int ess_raf_received_pack() ; +void ess_timer_poll() ; +void ess_para_change() ; +#endif + +#ifdef BOOT +#define smt_srf_event(a,b,c,d) +#define smt_init_evc(a) +#else +void smt_init_evc() ; +void smt_srf_event() ; +#endif + +#ifndef SMT_REAL_TOKEN_CT +void smt_emulate_token_ct(); +#endif + +#if defined(DEBUG) && !defined(BOOT) +void dump_smt() ; +#else +#define dump_smt(smc,sm,text) +#endif + +#ifdef DEBUG +char *addr_to_string() ; +void dump_hex() ; +#endif +#endif /* PROTOTYP_INC */ + +/* PNMI default defines */ +#ifndef PNMI_INIT +#define PNMI_INIT(smc) /* Nothing */ +#endif +#ifndef PNMI_GET_ID +#define PNMI_GET_ID( smc, ndis_oid, buf, len, BytesWritten, BytesNeeded ) \ + ( 1 ? (-1) : (-1) ) +#endif +#ifndef PNMI_SET_ID +#define PNMI_SET_ID( smc, ndis_oid, buf, len, BytesRead, BytesNeeded, \ + set_type) ( 1 ? (-1) : (-1) ) +#endif + +/* + * SMT_PANIC defines + */ +#ifndef SMT_PANIC +#define SMT_PANIC(smc,nr,msg) smt_panic (smc, msg) +#endif + +#ifndef SMT_ERR_LOG +#define SMT_ERR_LOG(smc,nr,msg) SMT_PANIC (smc, nr, msg) +#endif + +#ifndef SMT_EBASE +#define SMT_EBASE 100 +#endif + +#define SMT_E0100 SMT_EBASE + 0 +#define SMT_E0100_MSG "cfm FSM: illegal ce_type" +#define SMT_E0101 SMT_EBASE + 1 +#define SMT_E0101_MSG "CEM: case ???" +#define SMT_E0102 SMT_EBASE + 2 +#define SMT_E0102_MSG "CEM A: illegal state" +#define SMT_E0103 SMT_EBASE + 3 +#define SMT_E0103_MSG "CEM B: illegal state" +#define SMT_E0104 SMT_EBASE + 4 +#define SMT_E0104_MSG "CEM M: illegal state" +#define SMT_E0105 SMT_EBASE + 5 +#define SMT_E0105_MSG "CEM S: illegal state" +#define SMT_E0106 SMT_EBASE + 6 +#define SMT_E0106_MSG "CFM : illegal state" +#define SMT_E0107 SMT_EBASE + 7 +#define SMT_E0107_MSG "ECM : illegal state" +#define SMT_E0108 SMT_EBASE + 8 +#define SMT_E0108_MSG "prop_actions : NAC in DAS CFM" +#define SMT_E0109 SMT_EBASE + 9 +#define SMT_E0109_MSG "ST2U.FM_SERRSF error in special frame" +#define SMT_E0110 SMT_EBASE + 10 +#define SMT_E0110_MSG "ST2U.FM_SRFRCTOV recv. count. overflow" +#define SMT_E0111 SMT_EBASE + 11 +#define SMT_E0111_MSG "ST2U.FM_SNFSLD NP & FORMAC simult. load" +#define SMT_E0112 SMT_EBASE + 12 +#define SMT_E0112_MSG "ST2U.FM_SRCVFRM single-frame recv.-mode" +#define SMT_E0113 SMT_EBASE + 13 +#define SMT_E0113_MSG "FPLUS: Buffer Memory Error" +#define SMT_E0114 SMT_EBASE + 14 +#define SMT_E0114_MSG "ST2U.FM_SERRSF error in special frame" +#define SMT_E0115 SMT_EBASE + 15 +#define SMT_E0115_MSG "ST3L: parity error in receive queue 2" +#define SMT_E0116 SMT_EBASE + 16 +#define SMT_E0116_MSG "ST3L: parity error in receive queue 1" +#define SMT_E0117 SMT_EBASE + 17 +#define SMT_E0117_MSG "E_SMT_001: RxD count for receive queue 1 = 0" +#define SMT_E0118 SMT_EBASE + 18 +#define SMT_E0118_MSG "PCM : illegal state" +#define SMT_E0119 SMT_EBASE + 19 +#define SMT_E0119_MSG "smt_add_para" +#define SMT_E0120 SMT_EBASE + 20 +#define SMT_E0120_MSG "smt_set_para" +#define SMT_E0121 SMT_EBASE + 21 +#define SMT_E0121_MSG "illegal event in dispatcher" +#define SMT_E0122 SMT_EBASE + 22 +#define SMT_E0122_MSG "RMT : illegal state" +#define SMT_E0123 SMT_EBASE + 23 +#define SMT_E0123_MSG "SBA: state machine has illegal state" +#define SMT_E0124 SMT_EBASE + 24 +#define SMT_E0124_MSG "sba_free_session() called with NULL pointer" +#define SMT_E0125 SMT_EBASE + 25 +#define SMT_E0125_MSG "SBA : illegal session pointer" +#define SMT_E0126 SMT_EBASE + 26 +#define SMT_E0126_MSG "smt_free_mbuf() called with NULL pointer\n" +#define SMT_E0127 SMT_EBASE + 27 +#define SMT_E0127_MSG "sizeof evcs" +#define SMT_E0128 SMT_EBASE + 28 +#define SMT_E0128_MSG "evc->evc_cond_state = 0" +#define SMT_E0129 SMT_EBASE + 29 +#define SMT_E0129_MSG "evc->evc_multiple = 0" +#define SMT_E0130 SMT_EBASE + 30 +#define SMT_E0130_MSG write_mdr_warning +#define SMT_E0131 SMT_EBASE + 31 +#define SMT_E0131_MSG cam_warning +#define SMT_E0132 SMT_EBASE + 32 +#define SMT_E0132_MSG "ST1L.FM_SPCEPDx parity/coding error" +#define SMT_E0133 SMT_EBASE + 33 +#define SMT_E0133_MSG "ST1L.FM_STBURx tx buffer underrun" +#define SMT_E0134 SMT_EBASE + 34 +#define SMT_E0134_MSG "ST1L.FM_SPCEPDx parity error" +#define SMT_E0135 SMT_EBASE + 35 +#define SMT_E0135_MSG "RMT: duplicate MAC address detected. Ring left!" +#define SMT_E0136 SMT_EBASE + 36 +#define SMT_E0136_MSG "Elasticity Buffer hang-up" +#define SMT_E0137 SMT_EBASE + 37 +#define SMT_E0137_MSG "SMT: queue overrun" +#define SMT_E0138 SMT_EBASE + 38 +#define SMT_E0138_MSG "RMT: duplicate MAC address detected. Ring NOT left!" +#endif /* _CMTDEF_ */ diff -u --recursive --new-file v2.3.46/linux/drivers/net/skfp/h/fddi.h linux/drivers/net/skfp/h/fddi.h --- v2.3.46/linux/drivers/net/skfp/h/fddi.h Wed Dec 31 16:00:00 1969 +++ linux/drivers/net/skfp/h/fddi.h Fri Feb 18 14:55:53 2000 @@ -0,0 +1,69 @@ +/****************************************************************************** + * + * (C)Copyright 1998,1999 SysKonnect, + * a business unit of Schneider & Koch & Co. Datensysteme GmbH. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * The information in this file is provided "AS IS" without warranty. + * + ******************************************************************************/ + +#ifndef _FDDI_ +#define _FDDI_ + +struct fddi_addr { + u_char a[6] ; +} ; + +#define GROUP_ADDR 0x80 /* MSB in a[0] */ + +struct fddi_mac { + struct fddi_addr mac_dest ; + struct fddi_addr mac_source ; + u_char mac_info[4478] ; +} ; + +#define FDDI_MAC_SIZE (12) +#define FDDI_RAW_MTU (4500-5) /* exl. Pr,SD, ED/FS */ +#define FDDI_RAW (4500) + +/* + * FC values + */ +#define FC_VOID 0x40 /* void frame */ +#define FC_TOKEN 0x80 /* token */ +#define FC_RES_TOKEN 0xc0 /* restricted token */ +#define FC_SMT_INFO 0x41 /* SMT Info frame */ +/* + * FC_SMT_LAN_LOC && FC_SMT_LOC are SK specific ! + */ +#define FC_SMT_LAN_LOC 0x42 /* local SMT Info frame */ +#define FC_SMT_LOC 0x43 /* local SMT Info frame */ +#define FC_SMT_NSA 0x4f /* SMT NSA frame */ +#define FC_MAC 0xc0 /* MAC frame */ +#define FC_BEACON 0xc2 /* MAC beacon frame */ +#define FC_CLAIM 0xc3 /* MAC claim frame */ +#define FC_SYNC_LLC 0xd0 /* sync. LLC frame */ +#define FC_ASYNC_LLC 0x50 /* async. LLC frame */ +#define FC_SYNC_BIT 0x80 /* sync. bit in FC */ + +#define FC_LLC_PRIOR 0x07 /* priority bits */ + +#define BEACON_INFO 0 /* beacon type */ +#define DBEACON_INFO 1 /* beacon type DIRECTED */ + + +/* + * indicator bits + */ +#define C_INDICATOR (1<<0) +#define A_INDICATOR (1<<1) +#define E_INDICATOR (1<<2) +#define I_INDICATOR (1<<6) /* SK specific */ +#define L_INDICATOR (1<<7) /* SK specific */ + +#endif /* _FDDI_ */ diff -u --recursive --new-file v2.3.46/linux/drivers/net/skfp/h/fddimib.h linux/drivers/net/skfp/h/fddimib.h --- v2.3.46/linux/drivers/net/skfp/h/fddimib.h Wed Dec 31 16:00:00 1969 +++ linux/drivers/net/skfp/h/fddimib.h Fri Feb 18 14:55:53 2000 @@ -0,0 +1,349 @@ +/****************************************************************************** + * + * (C)Copyright 1998,1999 SysKonnect, + * a business unit of Schneider & Koch & Co. Datensysteme GmbH. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * The information in this file is provided "AS IS" without warranty. + * + ******************************************************************************/ + +/* + * FDDI MIB + */ + +/* + * typedefs + */ + +typedef u_long Counter ; +typedef u_char TimeStamp[8] ; +typedef struct fddi_addr LongAddr ; +typedef u_long Timer_2 ; +typedef u_long Timer ; +typedef u_short ResId ; +typedef u_short SMTEnum ; +typedef u_char SMTFlag ; + +typedef struct { + Counter count ; + TimeStamp timestamp ; +} SetCountType ; + +/* + * bits for bit string "available_path" + */ +#define MIB_PATH_P (1<<0) +#define MIB_PATH_S (1<<1) +#define MIB_PATH_L (1<<2) + +/* + * bits for bit string PermittedPaths & RequestedPaths (SIZE(8)) + */ +#define MIB_P_PATH_LOCAL (1<<0) +#define MIB_P_PATH_SEC_ALTER (1<<1) +#define MIB_P_PATH_PRIM_ALTER (1<<2) +#define MIB_P_PATH_CON_ALTER (1<<3) +#define MIB_P_PATH_SEC_PREFER (1<<4) +#define MIB_P_PATH_PRIM_PREFER (1<<5) +#define MIB_P_PATH_CON_PREFER (1<<6) +#define MIB_P_PATH_THRU (1<<7) + +/* + * enum current path + */ +#define MIB_PATH_ISOLATED 0 +#define MIB_PATH_LOCAL 1 +#define MIB_PATH_SECONDARY 2 +#define MIB_PATH_PRIMARY 3 +#define MIB_PATH_CONCATENATED 4 +#define MIB_PATH_THRU 5 + +/* + * enum PMDClass + */ +#define MIB_PMDCLASS_MULTI 0 +#define MIB_PMDCLASS_SINGLE1 1 +#define MIB_PMDCLASS_SINGLE2 2 +#define MIB_PMDCLASS_SONET 3 +#define MIB_PMDCLASS_LCF 4 +#define MIB_PMDCLASS_TP 5 +#define MIB_PMDCLASS_UNKNOWN 6 +#define MIB_PMDCLASS_UNSPEC 7 + +/* + * enum SMTStationStatus + */ +#define MIB_SMT_STASTA_CON 0 +#define MIB_SMT_STASTA_SEPA 1 +#define MIB_SMT_STASTA_THRU 2 + + +struct fddi_mib { + /* + * private + */ + u_char fddiPRPMFPasswd[8] ; + struct smt_sid fddiPRPMFStation ; + +#ifdef ESS + /* + * private variables for static allocation of the + * End Station Support + */ + u_long fddiESSPayload ; /* payload for static alloc */ + u_long fddiESSOverhead ; /* frame ov for static alloc */ + u_long fddiESSMaxTNeg ; /* maximum of T-NEG */ + u_long fddiESSMinSegmentSize ; /* min size of the sync frames */ + u_long fddiESSCategory ; /* category for the Alloc req */ + short fddiESSSynchTxMode ; /* send all LLC frames as sync */ +#endif /* ESS */ +#ifdef SBA + /* + * private variables for the Synchronous Bandwidth Allocator + */ + char fddiSBACommand ; /* holds the parsed SBA cmd */ + u_char fddiSBAAvailable ; /* SBA allocatable value */ +#endif /* SBA */ + + /* + * SMT standard mib + */ + struct smt_sid fddiSMTStationId ; + u_short fddiSMTOpVersionId ; + u_short fddiSMTHiVersionId ; + u_short fddiSMTLoVersionId ; + u_char fddiSMTManufacturerData[32] ; + u_char fddiSMTUserData[32] ; + u_short fddiSMTMIBVersionId ; + + /* + * ConfigGrp + */ + u_char fddiSMTMac_Ct ; + u_char fddiSMTNonMaster_Ct ; + u_char fddiSMTMaster_Ct ; + u_char fddiSMTAvailablePaths ; + u_short fddiSMTConfigCapabilities ; + u_short fddiSMTConfigPolicy ; + u_short fddiSMTConnectionPolicy ; + u_short fddiSMTTT_Notify ; + u_char fddiSMTStatRptPolicy ; + u_long fddiSMTTrace_MaxExpiration ; + u_short fddiSMTPORTIndexes[NUMPHYS] ; + u_short fddiSMTMACIndexes ; + u_char fddiSMTBypassPresent ; + + /* + * StatusGrp + */ + SMTEnum fddiSMTECMState ; + SMTEnum fddiSMTCF_State ; + SMTEnum fddiSMTStationStatus ; + u_char fddiSMTRemoteDisconnectFlag ; + u_char fddiSMTPeerWrapFlag ; + + /* + * MIBOperationGrp + */ + TimeStamp fddiSMTTimeStamp ; + TimeStamp fddiSMTTransitionTimeStamp ; + SetCountType fddiSMTSetCount ; + struct smt_sid fddiSMTLastSetStationId ; + + struct fddi_mib_m { + u_short fddiMACFrameStatusFunctions ; + Timer_2 fddiMACT_MaxCapabilitiy ; + Timer_2 fddiMACTVXCapabilitiy ; + + /* ConfigGrp */ + u_char fddiMACMultiple_N ; /* private */ + u_char fddiMACMultiple_P ; /* private */ + u_char fddiMACDuplicateAddressCond ;/* private */ + u_char fddiMACAvailablePaths ; + u_short fddiMACCurrentPath ; + LongAddr fddiMACUpstreamNbr ; + LongAddr fddiMACDownstreamNbr ; + LongAddr fddiMACOldUpstreamNbr ; + LongAddr fddiMACOldDownstreamNbr ; + SMTEnum fddiMACDupAddressTest ; + u_short fddiMACRequestedPaths ; + SMTEnum fddiMACDownstreamPORTType ; + ResId fddiMACIndex ; + + /* AddressGrp */ + LongAddr fddiMACSMTAddress ; + + /* OperationGrp */ + Timer_2 fddiMACT_Min ; /* private */ + Timer_2 fddiMACT_ReqMIB ; + Timer_2 fddiMACT_Req ; /* private */ + Timer_2 fddiMACT_Neg ; + Timer_2 fddiMACT_MaxMIB ; + Timer_2 fddiMACT_Max ; /* private */ + Timer_2 fddiMACTvxValueMIB ; + Timer_2 fddiMACTvxValue ; /* private */ + Timer_2 fddiMACT_Pri0 ; + Timer_2 fddiMACT_Pri1 ; + Timer_2 fddiMACT_Pri2 ; + Timer_2 fddiMACT_Pri3 ; + Timer_2 fddiMACT_Pri4 ; + Timer_2 fddiMACT_Pri5 ; + Timer_2 fddiMACT_Pri6 ; + + /* CountersGrp */ + Counter fddiMACFrame_Ct ; + Counter fddiMACCopied_Ct ; + Counter fddiMACTransmit_Ct ; + Counter fddiMACToken_Ct ; + Counter fddiMACError_Ct ; + Counter fddiMACLost_Ct ; + Counter fddiMACTvxExpired_Ct ; + Counter fddiMACNotCopied_Ct ; + Counter fddiMACRingOp_Ct ; + + Counter fddiMACSMTCopied_Ct ; /* private */ + Counter fddiMACSMTTransmit_Ct ; /* private */ + + /* private for delta ratio */ + Counter fddiMACOld_Frame_Ct ; + Counter fddiMACOld_Copied_Ct ; + Counter fddiMACOld_Error_Ct ; + Counter fddiMACOld_Lost_Ct ; + Counter fddiMACOld_NotCopied_Ct ; + + /* FrameErrorConditionGrp */ + u_short fddiMACFrameErrorThreshold ; + u_short fddiMACFrameErrorRatio ; + + /* NotCopiedConditionGrp */ + u_short fddiMACNotCopiedThreshold ; + u_short fddiMACNotCopiedRatio ; + + /* StatusGrp */ + SMTEnum fddiMACRMTState ; + SMTFlag fddiMACDA_Flag ; + SMTFlag fddiMACUNDA_Flag ; + SMTFlag fddiMACFrameErrorFlag ; + SMTFlag fddiMACNotCopiedFlag ; + SMTFlag fddiMACMA_UnitdataAvailable ; + SMTFlag fddiMACHardwarePresent ; + SMTFlag fddiMACMA_UnitdataEnable ; + + } m[NUMMACS] ; +#define MAC0 0 + + struct fddi_mib_a { + ResId fddiPATHIndex ; + u_long fddiPATHSbaPayload ; + u_long fddiPATHSbaOverhead ; + /* fddiPATHConfiguration is built on demand */ + /* u_long fddiPATHConfiguration ; */ + Timer fddiPATHT_Rmode ; + u_long fddiPATHSbaAvailable ; + Timer_2 fddiPATHTVXLowerBound ; + Timer_2 fddiPATHT_MaxLowerBound ; + Timer_2 fddiPATHMaxT_Req ; + } a[NUMPATHS] ; +#define PATH0 0 + + struct fddi_mib_p { + /* ConfigGrp */ + SMTEnum fddiPORTMy_Type ; + SMTEnum fddiPORTNeighborType ; + u_char fddiPORTConnectionPolicies ; + struct { + u_char T_val ; + u_char R_val ; + } fddiPORTMacIndicated ; + SMTEnum fddiPORTCurrentPath ; + /* must be 4: is 32 bit in SMT format + * indices : + * 1 none + * 2 tree + * 3 peer + */ + u_char fddiPORTRequestedPaths[4] ; + u_short fddiPORTMACPlacement ; + u_char fddiPORTAvailablePaths ; + u_char fddiPORTConnectionCapabilities ; + SMTEnum fddiPORTPMDClass ; + ResId fddiPORTIndex ; + + /* OperationGrp */ + SMTEnum fddiPORTMaint_LS ; + SMTEnum fddiPORTPC_LS ; + u_char fddiPORTBS_Flag ; + + /* ErrorCtrsGrp */ + Counter fddiPORTLCTFail_Ct ; + Counter fddiPORTEBError_Ct ; + Counter fddiPORTOldEBError_Ct ; + + /* LerGrp */ + Counter fddiPORTLem_Reject_Ct ; + Counter fddiPORTLem_Ct ; + u_char fddiPORTLer_Estimate ; + u_char fddiPORTLer_Cutoff ; + u_char fddiPORTLer_Alarm ; + + /* StatusGrp */ + SMTEnum fddiPORTConnectState ; + SMTEnum fddiPORTPCMState ; /* real value */ + SMTEnum fddiPORTPCMStateX ; /* value for MIB */ + SMTEnum fddiPORTPC_Withhold ; + SMTFlag fddiPORTHardwarePresent ; + u_char fddiPORTLerFlag ; + + u_char fddiPORTMultiple_U ; /* private */ + u_char fddiPORTMultiple_P ; /* private */ + u_char fddiPORTEB_Condition ; /* private */ + } p[NUMPHYS] ; + struct { + Counter fddiPRIVECF_Req_Rx ; /* ECF req received */ + Counter fddiPRIVECF_Reply_Rx ; /* ECF repl received */ + Counter fddiPRIVECF_Req_Tx ; /* ECF req transm */ + Counter fddiPRIVECF_Reply_Tx ; /* ECF repl transm */ + Counter fddiPRIVPMF_Get_Rx ; /* PMF Get rec */ + Counter fddiPRIVPMF_Set_Rx ; /* PMF Set rec */ + Counter fddiPRIVRDF_Rx ; /* RDF received */ + Counter fddiPRIVRDF_Tx ; /* RDF transmitted */ + } priv ; +} ; + +/* + * OIDs for statistics + */ +#define SMT_OID_CF_STATE 1 /* fddiSMTCF_State */ +#define SMT_OID_PCM_STATE_A 2 /* fddiPORTPCMState port A */ +#define SMT_OID_PCM_STATE_B 17 /* fddiPORTPCMState port B */ +#define SMT_OID_RMT_STATE 3 /* fddiMACRMTState */ +#define SMT_OID_UNA 4 /* fddiMACUpstreamNbr */ +#define SMT_OID_DNA 5 /* fddiMACOldDownstreamNbr */ +#define SMT_OID_ERROR_CT 6 /* fddiMACError_Ct */ +#define SMT_OID_LOST_CT 7 /* fddiMACLost_Ct */ +#define SMT_OID_LEM_CT 8 /* fddiPORTLem_Ct */ +#define SMT_OID_LEM_CT_A 11 /* fddiPORTLem_Ct port A */ +#define SMT_OID_LEM_CT_B 12 /* fddiPORTLem_Ct port B */ +#define SMT_OID_LCT_FAIL_CT 9 /* fddiPORTLCTFail_Ct */ +#define SMT_OID_LCT_FAIL_CT_A 13 /* fddiPORTLCTFail_Ct port A */ +#define SMT_OID_LCT_FAIL_CT_B 14 /* fddiPORTLCTFail_Ct port B */ +#define SMT_OID_LEM_REJECT_CT 10 /* fddiPORTLem_Reject_Ct */ +#define SMT_OID_LEM_REJECT_CT_A 15 /* fddiPORTLem_Reject_Ct port A */ +#define SMT_OID_LEM_REJECT_CT_B 16 /* fddiPORTLem_Reject_Ct port B */ + +/* + * SK MIB + */ +#define SMT_OID_ECF_REQ_RX 20 /* ECF requests received */ +#define SMT_OID_ECF_REPLY_RX 21 /* ECF replies received */ +#define SMT_OID_ECF_REQ_TX 22 /* ECF requests transmitted */ +#define SMT_OID_ECF_REPLY_TX 23 /* ECF replies transmitted */ +#define SMT_OID_PMF_GET_RX 24 /* PMF get requests received */ +#define SMT_OID_PMF_SET_RX 25 /* PMF set requests received */ +#define SMT_OID_RDF_RX 26 /* RDF received */ +#define SMT_OID_RDF_TX 27 /* RDF transmitted */ diff -u --recursive --new-file v2.3.46/linux/drivers/net/skfp/h/fplustm.h linux/drivers/net/skfp/h/fplustm.h --- v2.3.46/linux/drivers/net/skfp/h/fplustm.h Wed Dec 31 16:00:00 1969 +++ linux/drivers/net/skfp/h/fplustm.h Fri Feb 18 14:55:53 2000 @@ -0,0 +1,274 @@ +/****************************************************************************** + * + * (C)Copyright 1998,1999 SysKonnect, + * a business unit of Schneider & Koch & Co. Datensysteme GmbH. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * The information in this file is provided "AS IS" without warranty. + * + ******************************************************************************/ + +/* + * AMD Fplus in tag mode data structs + * defs for fplustm.c + */ + +#ifndef _FPLUS_ +#define _FPLUS_ + +#ifndef HW_PTR +#ifdef MEM_MAPPED_IO +#define HW_PTR u_long +#else +#define HW_PTR u_short +#endif +#endif + +/* + * fplus error statistic structure + */ +struct err_st { + u_long err_valid ; /* memory status valid */ + u_long err_abort ; /* memory status receive abort */ + u_long err_e_indicator ; /* error indicator */ + u_long err_crc ; /* error detected (CRC or length) */ + u_long err_llc_frame ; /* LLC frame */ + u_long err_mac_frame ; /* MAC frame */ + u_long err_smt_frame ; /* SMT frame */ + u_long err_imp_frame ; /* implementer frame */ + u_long err_no_buf ; /* no buffer available */ + u_long err_too_long ; /* longer than max. buffer */ + u_long err_bec_stat ; /* beacon state entered */ + u_long err_clm_stat ; /* claim state entered */ + u_long err_sifg_det ; /* short interframe gap detect */ + u_long err_phinv ; /* PHY invalid */ + u_long err_tkiss ; /* token issued */ + u_long err_tkerr ; /* token error */ +} ; + +/* + * Transmit Descriptor struct + */ +struct s_smt_fp_txd { + u_long txd_tbctrl ; /* transmit buffer control */ + u_long txd_txdscr ; /* transmit frame status word */ + u_long txd_tbadr ; /* physical tx buffer address */ + u_long txd_ntdadr ; /* physical pointer to the next TxD */ +#ifdef ENA_64BIT_SUP + u_long txd_tbadr_hi ; /* physical tx buffer addr (high dword)*/ +#endif + char far *txd_virt ; /* virtual pointer to the data frag */ + /* virt pointer to the next TxD */ + struct s_smt_fp_txd volatile far *txd_next ; + struct s_txd_os txd_os ; /* OS - specific struct */ +} ; + +/* + * Receive Descriptor struct + */ +struct s_smt_fp_rxd { + u_long rxd_rbctrl ; /* receive buffer control */ + u_long rxd_rfsw ; /* receive frame status word */ + u_long rxd_rbadr ; /* physical rx buffer address */ + u_long rxd_nrdadr ; /* physical pointer to the next RxD */ +#ifdef ENA_64BIT_SUP + u_long rxd_rbadr_hi ; /* physical tx buffer addr (high dword)*/ +#endif + char far *rxd_virt ; /* virtual pointer to the data frag */ + /* virt pointer to the next RxD */ + struct s_smt_fp_rxd volatile far *rxd_next ; + struct s_rxd_os rxd_os ; /* OS - specific struct */ +} ; + +/* + * Descriptor Union Definition + */ +union s_fp_descr { + struct s_smt_fp_txd t ; /* pointer to the TxD */ + struct s_smt_fp_rxd r ; /* pointer to the RxD */ +} ; + +/* + * TxD Ring Control struct + */ +struct s_smt_tx_queue { + struct s_smt_fp_txd volatile *tx_curr_put ; /* next free TxD */ + struct s_smt_fp_txd volatile *tx_prev_put ; /* shadow put pointer */ + struct s_smt_fp_txd volatile *tx_curr_get ; /* next TxD to release*/ + u_short tx_free ; /* count of free TxD's */ + u_short tx_used ; /* count of used TxD's */ + HW_PTR tx_bmu_ctl ; /* BMU addr for tx start */ + HW_PTR tx_bmu_dsc ; /* BMU addr for curr dsc. */ +} ; + +/* + * RxD Ring Control struct + */ +struct s_smt_rx_queue { + struct s_smt_fp_rxd volatile *rx_curr_put ; /* next RxD to queue into */ + struct s_smt_fp_rxd volatile *rx_prev_put ; /* shadow put pointer */ + struct s_smt_fp_rxd volatile *rx_curr_get ; /* next RxD to fill */ + u_short rx_free ; /* count of free RxD's */ + u_short rx_used ; /* count of used RxD's */ + HW_PTR rx_bmu_ctl ; /* BMU addr for rx start */ + HW_PTR rx_bmu_dsc ; /* BMU addr for curr dsc. */ +} ; + +#define VOID_FRAME_OFF 0x00 +#define CLAIM_FRAME_OFF 0x08 +#define BEACON_FRAME_OFF 0x10 +#define DBEACON_FRAME_OFF 0x18 +#define RX_FIFO_OFF 0x21 /* to get a prime number for */ + /* the RX_FIFO_SPACE */ + +#define RBC_MEM_SIZE 0x8000 +#define SEND_ASYNC_AS_SYNC 0x1 +#define SYNC_TRAFFIC_ON 0x2 + +/* big FIFO memory */ +#define RX_FIFO_SPACE 0x4000 - RX_FIFO_OFF +#define TX_FIFO_SPACE 0x4000 + +#define TX_SMALL_FIFO 0x0900 +#define TX_MEDIUM_FIFO TX_FIFO_SPACE / 2 +#define TX_LARGE_FIFO TX_FIFO_SPACE - TX_SMALL_FIFO + +#define RX_SMALL_FIFO 0x0900 +#define RX_LARGE_FIFO RX_FIFO_SPACE - RX_SMALL_FIFO + +struct s_smt_fifo_conf { + u_short rbc_ram_start ; /* FIFO start address */ + u_short rbc_ram_end ; /* FIFO size */ + u_short rx1_fifo_start ; /* rx queue start address */ + u_short rx1_fifo_size ; /* rx queue size */ + u_short rx2_fifo_start ; /* rx queue start address */ + u_short rx2_fifo_size ; /* rx queue size */ + u_short tx_s_start ; /* sync queue start address */ + u_short tx_s_size ; /* sync queue size */ + u_short tx_a0_start ; /* async queue A0 start address */ + u_short tx_a0_size ; /* async queue A0 size */ + u_short fifo_config_mode ; /* FIFO configuration mode */ +} ; + +#define FM_ADDRX (FM_ADDET|FM_EXGPA0|FM_EXGPA1) + +struct s_smt_fp { + u_short mdr2init ; /* mode register 2 init value */ + u_short mdr3init ; /* mode register 3 init value */ + u_short frselreg_init ; /* frame selection register init val */ + u_short rx_mode ; /* address mode broad/multi/promisc */ + u_short nsa_mode ; + u_short rx_prom ; + u_short exgpa ; + + struct err_st err_stats ; /* error statistics */ + + /* + * MAC buffers + */ + struct fddi_mac_sf { /* special frame build buffer */ + u_char mac_fc ; + struct fddi_addr mac_dest ; + struct fddi_addr mac_source ; + u_char mac_info[0x20] ; + } mac_sfb ; + + + /* + * queues + */ +#define QUEUE_S 0 +#define QUEUE_A0 1 +#define QUEUE_R1 0 +#define QUEUE_R2 1 +#define USED_QUEUES 2 + + /* + * queue pointers; points to the queue dependent variables + */ + struct s_smt_tx_queue *tx[USED_QUEUES] ; + struct s_smt_rx_queue *rx[USED_QUEUES] ; + + /* + * queue dependent variables + */ + struct s_smt_tx_queue tx_q[USED_QUEUES] ; + struct s_smt_rx_queue rx_q[USED_QUEUES] ; + + /* + * FIFO configuration struct + */ + struct s_smt_fifo_conf fifo ; + + /* last formac status */ + u_short s2u ; + u_short s2l ; + + /* calculated FORMAC+ reg.addr. */ + HW_PTR fm_st1u ; + HW_PTR fm_st1l ; + HW_PTR fm_st2u ; + HW_PTR fm_st2l ; + HW_PTR fm_st3u ; + HW_PTR fm_st3l ; + + + /* + * multicast table + */ +#define FPMAX_MULTICAST 32 +#define SMT_MAX_MULTI 4 + struct { + struct s_fpmc { + struct fddi_addr a ; /* mc address */ + u_char n ; /* usage counter */ + u_char perm ; /* flag: permanent */ + } table[FPMAX_MULTICAST] ; + } mc ; + struct fddi_addr group_addr ; + u_long func_addr ; /* functional address */ + int smt_slots_used ; /* count of table entries for the SMT */ + int os_slots_used ; /* count of table entries */ + /* used by the os-specific module */ +} ; + +/* + * modes for mac_set_rx_mode() + */ +#define RX_ENABLE_ALLMULTI 1 /* enable all multicasts */ +#define RX_DISABLE_ALLMULTI 2 /* disable "enable all multicasts" */ +#define RX_ENABLE_PROMISC 3 /* enable promiscous */ +#define RX_DISABLE_PROMISC 4 /* disable promiscous */ +#define RX_ENABLE_NSA 5 /* enable reception of NSA frames */ +#define RX_DISABLE_NSA 6 /* disable reception of NSA frames */ + + +/* + * support for byte reversal in AIX + * (descriptors and pointers must be byte reversed in memory + * CPU is big endian; M-Channel is little endian) + */ +#ifdef AIX +#define MDR_REV +#define AIX_REVERSE(x) ((((x)<<24L)&0xff000000L) + \ + (((x)<< 8L)&0x00ff0000L) + \ + (((x)>> 8L)&0x0000ff00L) + \ + (((x)>>24L)&0x000000ffL)) +#else +#define AIX_REVERSE(x) (x) +#endif + +#ifdef MDR_REV +#define MDR_REVERSE(x) ((((x)<<24L)&0xff000000L) + \ + (((x)<< 8L)&0x00ff0000L) + \ + (((x)>> 8L)&0x0000ff00L) + \ + (((x)>>24L)&0x000000ffL)) +#else +#define MDR_REVERSE(x) (x) +#endif + +#endif diff -u --recursive --new-file v2.3.46/linux/drivers/net/skfp/h/hwmtm.h linux/drivers/net/skfp/h/hwmtm.h --- v2.3.46/linux/drivers/net/skfp/h/hwmtm.h Wed Dec 31 16:00:00 1969 +++ linux/drivers/net/skfp/h/hwmtm.h Fri Feb 18 14:55:53 2000 @@ -0,0 +1,424 @@ +/****************************************************************************** + * + * (C)Copyright 1998,1999 SysKonnect, + * a business unit of Schneider & Koch & Co. Datensysteme GmbH. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * The information in this file is provided "AS IS" without warranty. + * + ******************************************************************************/ + +#ifndef _HWM_ +#define _HWM_ + +#include "h/mbuf.h" + +/* + * MACRO for DMA synchronization: + * The descriptor 'desc' is flushed for the device 'flag'. + * Devices are the CPU (DDI_DMA_SYNC_FORCPU) and the + * adapter (DDI_DMA_SYNC_FORDEV). + * + * 'desc' Pointer to a Rx or Tx descriptor. + * 'flag' Flag for direction (view for CPU or DEVICE) that + * should be synchronized. + * + * Empty macros and defines are specified here. The real macro + * is os-specific and should be defined in osdef1st.h. + */ +#ifndef DRV_BUF_FLUSH +#define DRV_BUF_FLUSH(desc,flag) +#define DDI_DMA_SYNC_FORCPU +#define DDI_DMA_SYNC_FORDEV +#endif + + /* + * hardware modul dependent receive modes + */ +#define RX_ENABLE_PASS_SMT 21 +#define RX_DISABLE_PASS_SMT 22 +#define RX_ENABLE_PASS_NSA 23 +#define RX_DISABLE_PASS_NSA 24 +#define RX_ENABLE_PASS_DB 25 +#define RX_DISABLE_PASS_DB 26 +#define RX_DISABLE_PASS_ALL 27 +#define RX_DISABLE_LLC_PROMISC 28 +#define RX_ENABLE_LLC_PROMISC 29 + + +#ifndef DMA_RD +#define DMA_RD 1 /* memory -> hw */ +#endif +#ifndef DMA_WR +#define DMA_WR 2 /* hw -> memory */ +#endif +#define SMT_BUF 0x80 + + /* + * bits of the frame status byte + */ +#define EN_IRQ_EOF 0x02 /* get IRQ after end of frame transmission */ +#define LOC_TX 0x04 /* send frame to the local SMT */ +#define LAST_FRAG 0x08 /* last TxD of the frame */ +#define FIRST_FRAG 0x10 /* first TxD of the frame */ +#define LAN_TX 0x20 /* send frame to network if set */ +#define RING_DOWN 0x40 /* error: unable to send, ring down */ +#define OUT_OF_TXD 0x80 /* error: not enough TxDs available */ + + +#ifndef NULL +#define NULL 0 +#endif + +#ifdef LITTLE_ENDIAN +#define HWM_REVERSE(x) (x) +#else +#define HWM_REVERSE(x) ((((x)<<24L)&0xff000000L) + \ + (((x)<< 8L)&0x00ff0000L) + \ + (((x)>> 8L)&0x0000ff00L) + \ + (((x)>>24L)&0x000000ffL)) +#endif + +#define C_INDIC (1L<<25) +#define A_INDIC (1L<<26) +#define RD_FS_LOCAL 0x80 + + /* + * DEBUG FLAGS + */ +#define DEBUG_SMTF 1 +#define DEBUG_SMT 2 +#define DEBUG_ECM 3 +#define DEBUG_RMT 4 +#define DEBUG_CFM 5 +#define DEBUG_PCM 6 +#define DEBUG_SBA 7 +#define DEBUG_ESS 8 + +#define DB_HWM_RX 10 +#define DB_HWM_TX 11 +#define DB_HWM_GEN 12 + +struct s_mbuf_pool { +#ifndef MB_OUTSIDE_SMC + SMbuf mb[MAX_MBUF] ; /* mbuf pool */ +#endif + SMbuf *mb_start ; /* points to the first mb */ + SMbuf *mb_free ; /* free queue */ +} ; + +struct hwm_r { + /* + * hardware modul specific receive variables + */ + u_int len ; /* length of the whole frame */ + char *mb_pos ; /* SMbuf receive position */ +} ; + +struct hw_modul { + /* + * All hardware modul specific variables + */ + struct s_mbuf_pool mbuf_pool ; + struct hwm_r r ; + + union s_fp_descr volatile *descr_p ; /* points to the desriptor area */ + + u_short pass_SMT ; /* pass SMT frames */ + u_short pass_NSA ; /* pass all NSA frames */ + u_short pass_DB ; /* pass Direct Beacon Frames */ + u_short pass_llc_promisc ; /* pass all llc frames (default ON) */ + + SMbuf *llc_rx_pipe ; /* points to the first queued llc fr */ + SMbuf *llc_rx_tail ; /* points to the last queued llc fr */ + int queued_rx_frames ; /* number of queued frames */ + + SMbuf *txd_tx_pipe ; /* points to first mb in the txd ring */ + SMbuf *txd_tx_tail ; /* points to last mb in the txd ring */ + int queued_txd_mb ; /* number of SMT MBufs in txd ring */ + + int rx_break ; /* rev. was breaked because ind. off */ + int leave_isr ; /* leave fddi_isr immedeately if set */ + int isr_flag ; /* set, when HWM is entered from isr */ + /* + * varaibles for the current transmit frame + */ + struct s_smt_tx_queue *tx_p ; /* pointer to the transmit queue */ + u_long tx_descr ; /* tx descriptor for FORMAC+ */ + int tx_len ; /* tx frame length */ + SMbuf *tx_mb ; /* SMT tx MBuf pointer */ + char *tx_data ; /* data pointer to the SMT tx Mbuf */ + + int detec_count ; /* counter for out of RxD condition */ + u_long rx_len_error ; /* rx len FORMAC != sum of fragments */ +} ; + + +/* + * DEBUG structs and macros + */ + +#ifdef DEBUG +struct os_debug { + int hwm_rx ; + int hwm_tx ; + int hwm_gen ; +} ; +#endif + +#ifdef DEBUG +#ifdef DEBUG_BRD +#define DB_P smc->debug +#else +#define DB_P debug +#endif + +#define DB_RX(a,b,c,lev) if (DB_P.d_os.hwm_rx >= (lev)) printf(a,b,c) +#define DB_TX(a,b,c,lev) if (DB_P.d_os.hwm_tx >= (lev)) printf(a,b,c) +#define DB_GEN(a,b,c,lev) if (DB_P.d_os.hwm_gen >= (lev)) printf(a,b,c) +#else /* DEBUG */ +#define DB_RX(a,b,c,lev) +#define DB_TX(a,b,c,lev) +#define DB_GEN(a,b,c,lev) +#endif /* DEBUG */ + +#ifndef SK_BREAK +#define SK_BREAK() +#endif + + +/* + * HWM Macros + */ + +/* + * BEGIN_MANUAL_ENTRY(HWM_GET_TX_PHYS) + * u_long HWM_GET_TX_PHYS(txd) + * + * function MACRO (hardware module, hwmtm.h) + * This macro may be invoked by the OS-specific module to read + * the physical address of the specified TxD. + * + * para txd pointer to the TxD + * + * END_MANUAL_ENTRY + */ +#define HWM_GET_TX_PHYS(txd) (u_long)AIX_REVERSE((txd)->txd_tbadr) + +/* + * BEGIN_MANUAL_ENTRY(HWM_GET_TX_LEN) + * int HWM_GET_TX_LEN(txd) + * + * function MACRO (hardware module, hwmtm.h) + * This macro may be invoked by the OS-specific module to read + * the fragment length of the specified TxD + * + * para rxd pointer to the TxD + * + * return the length of the fragment in bytes + * + * END_MANUAL_ENTRY + */ +#define HWM_GET_TX_LEN(txd) ((int)AIX_REVERSE((txd)->txd_tbctrl)& RD_LENGTH) + +/* + * BEGIN_MANUAL_ENTRY(HWM_GET_TX_USED) + * txd *HWM_GET_TX_USED(smc,queue) + * + * function MACRO (hardware module, hwmtm.h) + * This macro may be invoked by the OS-specific module to get the + * number of used TxDs for the queue, specified by the index. + * + * para queue the number of the send queue: Can be specified by + * QUEUE_A0, QUEUE_S or (frame_status & QUEUE_A0) + * + * return number of used TxDs for this send queue + * + * END_MANUAL_ENTRY + */ +#define HWM_GET_TX_USED(smc,queue) (int) (smc)->hw.fp.tx_q[queue].tx_used + +/* + * BEGIN_MANUAL_ENTRY(HWM_GET_CURR_TXD) + * txd *HWM_GET_CURR_TXD(smc,queue) + * + * function MACRO (hardware module, hwmtm.h) + * This macro may be invoked by the OS-specific module to get the + * pointer to the TxD which points to the current queue put + * position. + * + * para queue the number of the send queue: Can be specified by + * QUEUE_A0, QUEUE_S or (frame_status & QUEUE_A0) + * + * return pointer to the current TxD + * + * END_MANUAL_ENTRY + */ +#define HWM_GET_CURR_TXD(smc,queue) (struct s_smt_fp_txd volatile *)\ + (smc)->hw.fp.tx_q[queue].tx_curr_put + +/* + * BEGIN_MANUAL_ENTRY(HWM_TX_CHECK) + * void HWM_TX_CHECK(smc,frame_status,low_water) + * + * function MACRO (hardware module, hwmtm.h) + * This macro is invoked by the OS-specific before it left it's + * driver_send function. This macro calls mac_drv_clear_txd + * if the free TxDs of the current transmit queue is equal or + * lower than the given low water mark. + * + * para frame_status status of the frame, see design description + * low_water low water mark of free TxD's + * + * END_MANUAL_ENTRY + */ +#ifndef HWM_NO_FLOW_CTL +#define HWM_TX_CHECK(smc,frame_status,low_water) {\ + if ((low_water)>=(smc)->hw.fp.tx_q[(frame_status)&QUEUE_A0].tx_free) {\ + mac_drv_clear_txd(smc) ;\ + }\ +} +#else +#define HWM_TX_CHECK(smc,frame_status,low_water) mac_drv_clear_txd(smc) +#endif + +/* + * BEGIN_MANUAL_ENTRY(HWM_GET_RX_FRAG_LEN) + * int HWM_GET_RX_FRAG_LEN(rxd) + * + * function MACRO (hardware module, hwmtm.h) + * This macro may be invoked by the OS-specific module to read + * the fragment length of the specified RxD + * + * para rxd pointer to the RxD + * + * return the length of the fragment in bytes + * + * END_MANUAL_ENTRY + */ +#define HWM_GET_RX_FRAG_LEN(rxd) ((int)AIX_REVERSE((rxd)->rxd_rbctrl)& \ + RD_LENGTH) + +/* + * BEGIN_MANUAL_ENTRY(HWM_GET_RX_PHYS) + * u_long HWM_GET_RX_PHYS(rxd) + * + * function MACRO (hardware module, hwmtm.h) + * This macro may be invoked by the OS-specific module to read + * the physical address of the specified RxD. + * + * para rxd pointer to the RxD + * + * return the RxD's physical pointer to the data fragment + * + * END_MANUAL_ENTRY + */ +#define HWM_GET_RX_PHYS(rxd) (u_long)AIX_REVERSE((rxd)->rxd_rbadr) + +/* + * BEGIN_MANUAL_ENTRY(HWM_GET_RX_USED) + * int HWM_GET_RX_USED(smc) + * + * function MACRO (hardware module, hwmtm.h) + * This macro may be invoked by the OS-specific module to get + * the count of used RXDs in receive queue 1. + * + * return the used RXD count of receive queue 1 + * + * NOTE: Remember, because of an ASIC bug at least one RXD should be unused + * in the descriptor ring ! + * + * END_MANUAL_ENTRY + */ +#define HWM_GET_RX_USED(smc) ((int)(smc)->hw.fp.rx_q[QUEUE_R1].rx_used) + +/* + * BEGIN_MANUAL_ENTRY(HWM_GET_RX_FREE) + * int HWM_GET_RX_FREE(smc) + * + * function MACRO (hardware module, hwmtm.h) + * This macro may be invoked by the OS-specific module to get + * the rxd_free count of receive queue 1. + * + * return the rxd_free count of receive queue 1 + * + * END_MANUAL_ENTRY + */ +#define HWM_GET_RX_FREE(smc) ((int)(smc)->hw.fp.rx_q[QUEUE_R1].rx_free-1) + +/* + * BEGIN_MANUAL_ENTRY(HWM_GET_CURR_RXD) + * rxd *HWM_GET_CURR_RXD(smc) + * + * function MACRO (hardware module, hwmtm.h) + * This macro may be invoked by the OS-specific module to get the + * pointer to the RxD which points to the current queue put + * position. + * + * return pointer to the current RxD + * + * END_MANUAL_ENTRY + */ +#define HWM_GET_CURR_RXD(smc) (struct s_smt_fp_rxd volatile *)\ + (smc)->hw.fp.rx_q[QUEUE_R1].rx_curr_put + +/* + * BEGIN_MANUAL_ENTRY(HWM_RX_CHECK) + * void HWM_RX_CHECK(smc,low_water) + * + * function MACRO (hardware module, hwmtm.h) + * This macro is invoked by the OS-specific before it left the + * function mac_drv_rx_complete. This macro calls mac_drv_fill_rxd + * if the number of used RxDs is equal or lower than the + * the given low water mark. + * + * para low_water low water mark of used RxD's + * + * END_MANUAL_ENTRY + */ +#ifndef HWM_NO_FLOW_CTL +#define HWM_RX_CHECK(smc,low_water) {\ + if ((low_water) >= (smc)->hw.fp.rx_q[QUEUE_R1].rx_used) {\ + mac_drv_fill_rxd(smc) ;\ + }\ +} +#else +#define HWM_RX_CHECK(smc,low_water) mac_drv_fill_rxd(smc) +#endif + +#ifndef HWM_EBASE +#define HWM_EBASE 500 +#endif + +#define HWM_E0001 HWM_EBASE + 1 +#define HWM_E0001_MSG "HWM: Wrong size of s_rxd_os struct" +#define HWM_E0002 HWM_EBASE + 2 +#define HWM_E0002_MSG "HWM: Wrong size of s_txd_os struct" +#define HWM_E0003 HWM_EBASE + 3 +#define HWM_E0003_MSG "HWM: smt_free_mbuf() called with NULL pointer" +#define HWM_E0004 HWM_EBASE + 4 +#define HWM_E0004_MSG "HWM: Parity error rx queue 1" +#define HWM_E0005 HWM_EBASE + 5 +#define HWM_E0005_MSG "HWM: Encoding error rx queue 1" +#define HWM_E0006 HWM_EBASE + 6 +#define HWM_E0006_MSG "HWM: Encoding error async tx queue" +#define HWM_E0007 HWM_EBASE + 7 +#define HWM_E0007_MSG "HWM: Encoding error sync tx queue" +#define HWM_E0008 HWM_EBASE + 8 +#define HWM_E0008_MSG "" +#define HWM_E0009 HWM_EBASE + 9 +#define HWM_E0009_MSG "HWM: Out of RxD condition detected" +#define HWM_E0010 HWM_EBASE + 10 +#define HWM_E0010_MSG "HWM: A protocol layer has tried to send a frame with an invalid frame control" +#define HWM_E0011 HWM_EBASE + 11 +#define HWM_E0011_MSG "HWM: mac_drv_clear_tx_queue was called although the hardware wasn't stopped" +#define HWM_E0012 HWM_EBASE + 12 +#define HWM_E0012_MSG "HWM: mac_drv_clear_rx_queue was called although the hardware wasn't stopped" +#define HWM_E0013 HWM_EBASE + 13 +#define HWM_E0013_MSG "HWM: mac_drv_repair_descr was called although the hardware wasn't stopped" + +#endif diff -u --recursive --new-file v2.3.46/linux/drivers/net/skfp/h/lnkstat.h linux/drivers/net/skfp/h/lnkstat.h --- v2.3.46/linux/drivers/net/skfp/h/lnkstat.h Wed Dec 31 16:00:00 1969 +++ linux/drivers/net/skfp/h/lnkstat.h Fri Feb 18 14:55:53 2000 @@ -0,0 +1,84 @@ +/****************************************************************************** + * + * (C)Copyright 1998,1999 SysKonnect, + * a business unit of Schneider & Koch & Co. Datensysteme GmbH. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * The information in this file is provided "AS IS" without warranty. + * + ******************************************************************************/ + +/* + * Definition of the Error Log Structure + * This structure will be copied into the Error Log buffer + * during the NDIS General Request ReadErrorLog by the MAC Driver + */ + +struct s_error_log { + + /* + * place holder for token ring adapter error log (zeros) + */ + u_char reserved_0 ; /* byte 0 inside Error Log */ + u_char reserved_1 ; /* byte 1 */ + u_char reserved_2 ; /* byte 2 */ + u_char reserved_3 ; /* byte 3 */ + u_char reserved_4 ; /* byte 4 */ + u_char reserved_5 ; /* byte 5 */ + u_char reserved_6 ; /* byte 6 */ + u_char reserved_7 ; /* byte 7 */ + u_char reserved_8 ; /* byte 8 */ + u_char reserved_9 ; /* byte 9 */ + u_char reserved_10 ; /* byte 10 */ + u_char reserved_11 ; /* byte 11 */ + u_char reserved_12 ; /* byte 12 */ + u_char reserved_13 ; /* byte 13 */ + + /* + * FDDI link statistics + */ +/* + * smt error low + */ +#define SMT_ERL_AEB (1<<15) /* A elast. buffer */ +#define SMT_ERL_BLC (1<<14) /* B link error condition */ +#define SMT_ERL_ALC (1<<13) /* A link error condition */ +#define SMT_ERL_NCC (1<<12) /* not copied condition */ +#define SMT_ERL_FEC (1<<11) /* frame error condition */ + +/* + * smt event low + */ +#define SMT_EVL_NCE (1<<5) + + u_short smt_error_low ; /* byte 14/15 */ + u_short smt_error_high ; /* byte 16/17 */ + u_short smt_event_low ; /* byte 18/19 */ + u_short smt_event_high ; /* byte 20/21 */ + u_short connection_policy_violation ; /* byte 22/23 */ + u_short port_event ; /* byte 24/25 */ + u_short set_count_low ; /* byte 26/27 */ + u_short set_count_high ; /* byte 28/29 */ + u_short aci_id_code ; /* byte 30/31 */ + u_short purge_frame_counter ; /* byte 32/33 */ + + /* + * CMT and RMT state machines + */ + u_short ecm_state ; /* byte 34/35 */ + u_short pcm_a_state ; /* byte 36/37 */ + u_short pcm_b_state ; /* byte 38/39 */ + u_short cfm_state ; /* byte 40/41 */ + u_short rmt_state ; /* byte 42/43 */ + + u_short not_used[30] ; /* byte 44-103 */ + + u_short ucode_version_level ; /* byte 104/105 */ + + u_short not_used_1 ; /* byte 106/107 */ + u_short not_used_2 ; /* byte 108/109 */ +} ; diff -u --recursive --new-file v2.3.46/linux/drivers/net/skfp/h/mbuf.h linux/drivers/net/skfp/h/mbuf.h --- v2.3.46/linux/drivers/net/skfp/h/mbuf.h Wed Dec 31 16:00:00 1969 +++ linux/drivers/net/skfp/h/mbuf.h Fri Feb 18 14:55:53 2000 @@ -0,0 +1,54 @@ +/****************************************************************************** + * + * (C)Copyright 1998,1999 SysKonnect, + * a business unit of Schneider & Koch & Co. Datensysteme GmbH. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * The information in this file is provided "AS IS" without warranty. + * + ******************************************************************************/ + +#ifndef _MBUF_ +#define _MBUF_ + +#ifndef PCI +#define M_SIZE 4550 +#else +#define M_SIZE 4504 +#endif + +#ifndef MAX_MBUF +#define MAX_MBUF 4 +#endif + +#ifndef NO_STD_MBUF +#define sm_next m_next +#define sm_off m_off +#define sm_len m_len +#define sm_data m_data +#define SMbuf Mbuf +#define mtod smtod +#define mtodoff smtodoff +#endif + +struct s_mbuf { + struct s_mbuf *sm_next ; /* low level linked list */ + short sm_off ; /* offset in m_data */ + u_int sm_len ; /* len of data */ +#ifdef PCI + int sm_use_count ; +#endif + char sm_data[M_SIZE] ; +} ; + +typedef struct s_mbuf SMbuf ; + +/* mbuf head, to typed data */ +#define smtod(x,t) ((t)((x)->sm_data + (x)->sm_off)) +#define smtodoff(x,t,o) ((t)((x)->sm_data + (o))) + +#endif /* _MBUF_ */ diff -u --recursive --new-file v2.3.46/linux/drivers/net/skfp/h/osdef1st.h linux/drivers/net/skfp/h/osdef1st.h --- v2.3.46/linux/drivers/net/skfp/h/osdef1st.h Wed Dec 31 16:00:00 1969 +++ linux/drivers/net/skfp/h/osdef1st.h Fri Feb 18 14:55:53 2000 @@ -0,0 +1,118 @@ +/****************************************************************************** + * + * (C)Copyright 1998,1999 SysKonnect, + * a business unit of Schneider & Koch & Co. Datensysteme GmbH. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * The information in this file is provided "AS IS" without warranty. + * + ******************************************************************************/ + +/* + * Operating system-dependant definitions that have to be defined + * before any other header files are included. + */ + +// HWM (HardWare Module) Definitions +// ----------------------- + +#ifdef __LITTLE_ENDIAN +#define LITTLE_ENDIAN +#else +#define BIG_ENDIAN +#endif + +// this is set in the makefile +// #define PCI /* only PCI adapters supported by this driver */ +// #define MEM_MAPPED_IO /* use memory mapped I/O */ + + +#define USE_CAN_ADDR /* DA and SA in MAC header are canonical. */ + +#define MB_OUTSIDE_SMC /* SMT Mbufs outside of smc struct. */ + +// ----------------------- + + +// SMT Definitions +// ----------------------- +#define SYNC /* allow synchronous frames */ + +// #define SBA /* Synchronous Bandwidth Allocator support */ + /* not available as free source */ + +#define ESS /* SBA End Station Support */ + +#define SMT_PANIC(smc, nr, msg) printk(KERN_INFO "SMT PANIC: code: %d, msg: %s\n",nr,msg) + + +#ifdef DEBUG +#define printf(s,args...) printk(KERN_INFO s, ## args) +#endif + +// #define HW_PTR u_long +// ----------------------- + + + +// HWM and OS-specific buffer definitions +// ----------------------- + +// default number of receive buffers. +#define NUM_RECEIVE_BUFFERS 10 + +// default number of transmit buffers. +#define NUM_TRANSMIT_BUFFERS 10 + +// Number of SMT buffers (Mbufs). +#define NUM_SMT_BUF 4 + +// Number of TXDs for asynchronous transmit queue. +#define HWM_ASYNC_TXD_COUNT (NUM_TRANSMIT_BUFFERS + NUM_SMT_BUF) + +// Number of TXDs for synchronous transmit queue. +#define HWM_SYNC_TXD_COUNT HWM_ASYNC_TXD_COUNT + + +// Number of RXDs for receive queue #1. +// Note: Workaround for ASIC Errata #7: One extra RXD is required. +#if (NUM_RECEIVE_BUFFERS > 100) +#define SMT_R1_RXD_COUNT (1 + 100) +#else +#define SMT_R1_RXD_COUNT (1 + NUM_RECEIVE_BUFFERS) +#endif + +// Number of RXDs for receive queue #2. +#define SMT_R2_RXD_COUNT 0 // Not used. +// ----------------------- + + + +/* + * OS-specific part of the transmit/receive descriptor structure (TXD/RXD). + * + * Note: The size of these structures must follow this rule: + * + * size = 8 + n * 16, n >= 0 + * + * NOTE: The size of this structures may not be changed, because + * libskfddi.a depends on it. But the dummy fields can be + * used freely. + */ + +struct s_txd_os { // os-specific part of transmit descriptor + struct sk_buff *skb; + long dummy; +} ; + +struct s_rxd_os { // os-specific part of receive descriptor + struct sk_buff *skb; + long dummy; +} ; + + + diff -u --recursive --new-file v2.3.46/linux/drivers/net/skfp/h/sba.h linux/drivers/net/skfp/h/sba.h --- v2.3.46/linux/drivers/net/skfp/h/sba.h Wed Dec 31 16:00:00 1969 +++ linux/drivers/net/skfp/h/sba.h Fri Feb 18 14:55:53 2000 @@ -0,0 +1,142 @@ +/****************************************************************************** + * + * (C)Copyright 1998,1999 SysKonnect, + * a business unit of Schneider & Koch & Co. Datensysteme GmbH. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * The information in this file is provided "AS IS" without warranty. + * + ******************************************************************************/ + +/* + * Synchronous Bandwith Allocation (SBA) structs + */ + +#ifndef _SBA_ +#define _SBA_ + +#include "h/mbuf.h" +#include "h/sba_def.h" + +#ifdef SBA + +/* Timer Cell Template */ +struct timer_cell { + struct timer_cell *next_ptr ; + struct timer_cell *prev_ptr ; + u_long start_time ; + struct s_sba_node_vars *node_var ; +} ; + +/* + * Node variables + */ +struct s_sba_node_vars { + u_char change_resp_flag ; + u_char report_resp_flag ; + u_char change_req_flag ; + u_char report_req_flag ; + long change_amount ; + long node_overhead ; + long node_payload ; + u_long node_status ; + u_char deallocate_status ; + u_char timer_state ; + u_short report_cnt ; + long lastrep_req_tranid ; + struct fddi_addr mac_address ; + struct s_sba_sessions *node_sessions ; + struct timer_cell timer ; +} ; + +/* + * Session variables + */ +struct s_sba_sessions { + u_long deallocate_status ; + long session_overhead ; + u_long min_segment_size ; + long session_payload ; + u_long session_status ; + u_long sba_category ; + long lastchg_req_tranid ; + u_short session_id ; + u_char class ; + u_char fddi2 ; + u_long max_t_neg ; + struct s_sba_sessions *next_session ; +} ; + +struct s_sba { + + struct s_sba_node_vars node[MAX_NODES] ; + struct s_sba_sessions session[MAX_SESSIONS] ; + + struct s_sba_sessions *free_session ; /* points to the first */ + /* free session */ + + struct timer_cell *tail_timer ; /* points to the last timer cell */ + + /* + * variables for allocation actions + */ + long total_payload ; /* Total Payload */ + long total_overhead ; /* Total Overhead */ + long sba_allocatable ; /* allocatable sync bandwidth */ + + /* + * RAF message receive parameters + */ + long msg_path_index ; /* Path Type */ + long msg_sba_pl_req ; /* Payload Request */ + long msg_sba_ov_req ; /* Overhead Request */ + long msg_mib_pl ; /* Current Payload for this Path */ + long msg_mib_ov ; /* Current Overhead for this Path*/ + long msg_category ; /* Category of the Allocation */ + u_long msg_max_t_neg ; /* longest T_Neg acceptable */ + u_long msg_min_seg_siz ; /* minimum segement size */ + struct smt_header *sm ; /* points to the rec message */ + struct fddi_addr *msg_alloc_addr ; /* Allocation Address */ + + /* + * SBA variables + */ + u_long sba_t_neg ; /* holds the last T_NEG */ + long sba_max_alloc ; /* the parsed value of SBAAvailable */ + + /* + * SBA state machine variables + */ + short sba_next_state ; /* the next state of the SBA */ + char sba_command ; /* holds the execuded SBA cmd */ + u_char sba_available ; /* parsed value after possible check */ +} ; + +#endif /* SBA */ + + /* + * variables for the End Station Support + */ +struct s_ess { + + /* + * flags and counters + */ + u_char sync_bw_available ; /* is set if sync bw is allocated */ + u_char local_sba_active ; /* set when a local sba is available */ + char raf_act_timer_poll ; /* activate the timer to send allc req */ + char timer_count ; /* counts every timer function call */ + + SMbuf *sba_reply_pend ; /* local reply for the sba is pending */ + + /* + * variables for the ess bandwidth control + */ + long sync_bw ; /* holds the allocaed sync bw */ + u_long alloc_trans_id ; /* trans id of the last alloc req */ +} ; +#endif diff -u --recursive --new-file v2.3.46/linux/drivers/net/skfp/h/sba_def.h linux/drivers/net/skfp/h/sba_def.h --- v2.3.46/linux/drivers/net/skfp/h/sba_def.h Wed Dec 31 16:00:00 1969 +++ linux/drivers/net/skfp/h/sba_def.h Fri Feb 18 14:55:53 2000 @@ -0,0 +1,76 @@ +/****************************************************************************** + * + * (C)Copyright 1998,1999 SysKonnect, + * a business unit of Schneider & Koch & Co. Datensysteme GmbH. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * The information in this file is provided "AS IS" without warranty. + * + ******************************************************************************/ + +#define PHYS 0 /* physical addr */ +#define PERM_ADDR 0x80 /* permanet address */ +#define SB_STATIC 0x00000001 +#define MAX_PAYLOAD 1562 +#define PRIMARY_RING 0x00000001 +#ifndef NULL +#define NULL 0x00 +#endif + +/*********************** SB_Input Variable Values ***********************/ +/* may be needed when ever the SBA state machine is called */ + +#define UNKNOWN_SYNC_SOURCE 0x0001 +#define REQ_ALLOCATION 0x0002 +#define REPORT_RESP 0x0003 +#define CHANGE_RESP 0x0004 +#define TNEG 0x0005 +#define NIF 0x0006 +#define SB_STOP 0x0007 +#define SB_START 0x0008 +#define REPORT_TIMER 0x0009 +#define CHANGE_REQUIRED 0x000A + +#define DEFAULT_OV 50 + +#ifdef SBA +/**************************** SBA STATES *****************************/ + +#define SBA_STANDBY 0x00000000 +#define SBA_ACTIVE 0x00000001 +#define SBA_RECOVERY 0x00000002 +#define SBA_REPORT 0x00000003 +#define SBA_CHANGE 0x00000004 + +/**************************** OTHERS *********************************/ + +#define FIFTY_PERCENT 50 /* bytes per second */ +#define MAX_SESSIONS 150 +#define TWO_MINUTES 13079 /* 9.175 ms/tick */ +#define FIFTY_BYTES 50 +#define SBA_DENIED 0x0000000D +#define I_NEED_ONE 0x00000000 +#define MAX_NODES 50 +/*#define T_REPORT 0x59682F00L*/ /* 120s/80ns in Hex */ +#define TWO_MIN 120 /* seconds */ +#define SBA_ST_UNKNOWN 0x00000002 +#define SBA_ST_ACTIVE 0x00000001 +#define S_CLEAR 0x00000000L +#define ZERO 0x00000000 +#define FULL 0x00000000 /* old: 0xFFFFFFFFF */ +#define S_SET 0x00000001L +#define LOW_PRIO 0x02 /* ??????? */ +#define OK 0x01 /* ??????? */ +#define NOT_OK 0x00 /* ??????? */ + +/****************************************/ +/* deallocate_status[ni][si] values */ +/****************************************/ +#define TX_CHANGE 0X00000001L +#define PENDING 0x00000002L +#define NONE 0X00000000L +#endif diff -u --recursive --new-file v2.3.46/linux/drivers/net/skfp/h/skfbi.h linux/drivers/net/skfp/h/skfbi.h --- v2.3.46/linux/drivers/net/skfp/h/skfbi.h Wed Dec 31 16:00:00 1969 +++ linux/drivers/net/skfp/h/skfbi.h Fri Feb 18 14:55:53 2000 @@ -0,0 +1,1920 @@ +/****************************************************************************** + * + * (C)Copyright 1998,1999 SysKonnect, + * a business unit of Schneider & Koch & Co. Datensysteme GmbH. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * The information in this file is provided "AS IS" without warranty. + * + ******************************************************************************/ + +#ifndef _SKFBI_H_ +#define _SKFBI_H_ + +#ifdef SYNC +#define exist_board_far exist_board +#define get_board_para_far get_board_para +#endif + +/* + * physical address offset + IO-Port base address + */ +#ifndef PCI +#define ADDR(a) ((a)+smc->hw.iop) +#define ADDRS(smc,a) ((a)+(smc)->hw.iop) +#endif + +/* + * FDDI-Fx (x := {I(SA), E(ISA), M(CA), P(CI)}) + * address calculation & function defines + */ + +#ifdef EISA + +/* + * Configuration PROM: !! all 8-Bit IO's !! + * |<- MAC-Address ->| + * /-+--+--+--+--+-//-+--+--+--+--+-//-+--+--+--+--+-//-+--+--+--+--+-/ + * val: |PROD_ID0..3| | free | |00|00|5A|40| |nn|mm|00|00| + * /-+--+--+--+--+-//-+--+--+--+--+-//-+--+--+--+--+-//-+--+--+--+--+-/ + * IO- ^ ^ ^ ^ ^ + * port 0C80 0C83 0C88 0C90 0C98 + * | \ + * | \ + * | \______________________________________________ + * EISA Expansion Board Product ID: \ + * BIT: |7 6 5 4 3 2 1 0| \ + * | PROD_ID0 | PROD_ID1 | PROD_ID2 | PROD_ID3 | + * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + * |0| MAN_C0 | MAN_C1 | MAN_C2 | PROD1 | PROD0 | REV1 | REV0 | + * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + * ^=reserved | product numb. | revision numb | + * MAN_Cx = compressed manufacterer code (x:=0..2) + * ASCII : 'A'..'Z' : 0x41..0x5A -> compr.(c-0x40) : 0x01..0x1A (5Bits!) + */ + +#ifndef MULT_OEM +#ifndef OEM_CONCEPT +#define MAN_C0 ('S'-0x40) +#define MAN_C1 ('K'-0x40) +#define MAN_C2 ('D'-0x40) +#define PROD_ID0 (u_char)((MAN_C0<<2) | (MAN_C1>>3)) +#define PROD_ID1 (u_char)(((MAN_C1<<5) & 0xff) | MAN_C2) +#define PROD_ID2 (u_char)(1) /* prod. nr. */ +#define PROD_ID3 (u_char)(0) /* rev. nr. */ + +#ifndef OEM_USER_DATA +#define OEM_USER_DATA "SK-NET FDDI V2.0 Userdata" +#endif +#else /* OEM_CONCEPT */ + +/* MAN_C(0|1|2) no longer present (ra). */ +#define PROD_ID0 (u_char)OEM_PROD_ID0 +#define PROD_ID1 (u_char)OEM_PROD_ID1 +#define PROD_ID2 (u_char)OEM_PROD_ID2 +#define PROD_ID3 (u_char)OEM_PROD_ID3 +#endif /* OEM_CONCEPT */ + +#define SKLOGO PROD_ID0, PROD_ID1, PROD_ID2, PROD_ID3 +#endif /* MULT_OEM */ + +#define SADDRL (0) /* start address SKLOGO */ +#define SA_MAC (0x10) /* start addr. MAC_AD within the PROM */ +#define PRA_OFF (4) +#define SA_PMD_TYPE (8) /* start addr. PMD-Type */ + +#define SKFDDI_PSZ 32 /* address PROM size */ + +/* + * address transmision from logical to physical offset address on board + */ +#define FMA(a) (0x0400|((a)<<1)) /* FORMAC+ (r/w) */ +#define P1A(a) (0x0800|((a)<<1)) /* PLC1 (r/w) */ +#define P2A(a) (0x0840|((a)<<1)) /* PLC2 (r/w) */ +#define TIA(a) (0x0880|((a)<<1)) /* Timer (r/w) */ +#define PRA(a) (0x0c80| (a)) /* configuration PROM */ +#define C0A(a) (0x0c84| (a)) /* config. RAM */ +#define C1A(a) (0x0ca0| (a)) /* IRQ-, DMA-nr., EPROM type */ +#define C2A(a) (0x0ca4| (a)) /* EPROM and PAGE selector */ + +#define CONF C0A(0) /* config RAM (card enable bit port) */ +#define PGRA C2A(0) /* Flash page register */ +#define CDID PRA(0) /* Card ID I/O port addr. offset */ + + +/* + * physical address offset + slot specific IO-Port base address + */ +#define FM_A(a) (FMA(a)+smc->hw.iop) /* FORMAC Plus physical addr */ +#define P1_A(a) (P1A(a)+smc->hw.iop) /* PLC1 (r/w) */ +#define P2_A(a) (P2A(a)+smc->hw.iop) /* PLC2 (r/w) */ +#define TI_A(a) (TIA(a)+smc->hw.iop) /* Timer (r/w) */ +#define PR_A(a) (PRA(a)+smc->hw.iop) /* config. PROM */ +#define C0_A(a) (C0A(a)+smc->hw.iop) /* config. RAM */ +#define C1_A(a) (C1A(a)+smc->hw.iop) /* config. RAM */ +#define C2_A(a) (C2A(a)+smc->hw.iop) /* config. RAM */ + + +#define CSRA 0x0008 /* control/status register address (r/w) */ +#define ISRA 0x0008 /* int. source register address (upper 8Bits) */ +#define PLC1I 0x001a /* clear PLC1 interrupt (write only) */ +#define PLC2I 0x0020 /* clear PLC2 interrupt (write only) */ +#define CSFA 0x001c /* control/status FIFO BUSY flags (read only) */ +#define RQAA 0x001c /* Request reg. (write only) */ +#define WCTA 0x001e /* word counter (r/w) */ +#define FFLAG 0x005e /* FLAG/V_FULL (FIFO almost full, write only)*/ + +#define CSR_A (CSRA+smc->hw.iop) /* control/status register address (r/w) */ +#ifdef UNIX +#define CSR_AS(smc) (CSRA+(smc)->hw.iop) /* control/status register address (r/w) */ +#endif +#define ISR_A (ISRA+smc->hw.iop) /* int. source register address (upper 8Bits) */ +#define PLC1_I (PLC1I+smc->hw.iop) /* clear PLC1 internupt (write only) */ +#define PLC2_I (PLC2I+smc->hw.iop) /* clear PLC2 interrupt (write only) */ +#define CSF_A (CSFA+smc->hw.iop) /* control/status FIFO BUSY flags (r/w) */ +#define RQA_A (RQAA+smc->hw.iop) /* Request reg. (write only) */ +#define WCT_A (WCTA+smc->hw.iop) /* word counter (r/w) */ +#define FFLAG_A (FFLAG+smc->hw.iop) /* FLAG/V_FULL (FIFO almost full, write only)*/ + +/* + * control/status register CSRA bits + */ +/* write */ +#define CS_CRESET 0x01 /* Card reset (0=reset) */ +#define CS_RESET_FIFO 0x02 /* FIFO reset (0=reset) */ +#define CS_IMSK 0x04 /* enable IRQ (1=enable, 0=disable) */ +#define CS_EN_IRQ_TC 0x08 /* enable IRQ from transfer counter */ +#define CS_BYPASS 0x20 /* bypass switch (0=remove, 1=insert)*/ +#define CS_LED_0 0x40 /* switch LED 0 */ +#define CS_LED_1 0x80 /* switch LED 1 */ +/* read */ +#define CS_BYSTAT 0x40 /* 0=Bypass exist, 1= ..not */ +#define CS_SAS 0x80 /* single attachement station (=1) */ + +/* + * control/status register CSFA bits (FIFO) + */ +#define CSF_MUX0 0x01 +#define CSF_MUX1 0x02 +#define CSF_HSREQ0 0x04 +#define CSF_HSREQ1 0x08 +#define CSF_HSREQ2 0x10 +#define CSF_BUSY_DMA 0x40 +#define CSF_BUSY_FIFO 0x80 + +/* + * Interrupt source register ISRA (upper 8 data bits) read only & low activ. + */ +#define IS_MINTR1 0x0100 /* FORMAC ST1U/L & ~IMSK1U/L*/ +#define IS_MINTR2 0x0200 /* FORMAC ST2U/L & ~IMSK2U/L*/ +#define IS_PLINT1 0x0400 /* PLC1 */ +#define IS_PLINT2 0x0800 /* PLC2 */ +#define IS_TIMINT 0x1000 /* Timer 82C54-2 */ +#define IS_TC 0x2000 /* transf. counter */ + +#define ALL_IRSR (IS_MINTR1|IS_MINTR2|IS_PLINT1|IS_PLINT2|IS_TIMINT|IS_TC) + +/* + * CONFIG<0> RAM (C0_A()) + */ +#define CFG_CARD_EN 0x01 /* card enable */ + +/* + * CONFIG<1> RAM (C1_A()) + */ +#define CFG_IRQ_SEL 0x03 /* IRQ select (4 nr.) */ +#define CFG_IRQ_TT 0x04 /* IRQ trigger type (LEVEL/EDGE) */ +#define CFG_DRQ_SEL 0x18 /* DMA requ. (4 nr.) */ +#define CFG_BOOT_EN 0x20 /* 0=BOOT-, 1=Application Software */ +#define CFG_PROG_EN 0x40 /* V_Prog for FLASH_PROM (1=on) */ + +/* + * CONFIG<2> RAM (C2_A()) + */ +#define CFG_EPROM_SEL 0x0f /* FPROM start address selection */ +#define CFG_PAGE 0xf0 /* FPROM page selection */ + + +#define READ_PROM(a) ((u_char)inp(a)) +#define GET_PAGE(i) outp(C2_A(0),((int)(i)<<4) | (inp(C2_A(0)) & ~CFG_PAGE)) +#define FPROM_SW() (inp(C1_A(0)) & CFG_BOOT_EN) + +#define MAX_PAGES 16 /* 16 pages */ +#define MAX_FADDR 0x2000 /* 8K per page */ +#define VPP_ON() outp(C1_A(0),inp(C1_A(0)) | CFG_PROG_EN) +#define VPP_OFF() outp(C1_A(0),inp(C1_A(0)) & ~CFG_PROG_EN) + +#define DMA_BUSY() (inpw(CSF_A) & CSF_BUSY_DMA) +#define FIFO_BUSY() (inpw(CSF_A) & CSF_BUSY_FIFO) +#define DMA_FIFO_BUSY() (inpw(CSF_A) & (CSF_BUSY_DMA | CSF_BUSY_FIFO)) +#define BUS_CHECK() + +#ifdef UNISYS +/* For UNISYS use another macro with drv_usecewait function */ +#define CHECK_DMA() {u_long k = 1000000; \ + while (k && (DMA_BUSY())) { k--; drv_usecwait(20); } \ + if (!k) SMT_PANIC(smc,HWM_E0003,HWM_E0003_MSG) ; } +#else +#define CHECK_DMA() {u_long k = 1000000 ;\ + while (k && (DMA_BUSY())) k-- ;\ + if (!k) SMT_PANIC(smc,HWM_E0003,HWM_E0003_MSG) ; } +#endif + +#define CHECK_FIFO() {u_long k = 1000000 ;\ + while (k && (FIFO_BUSY())) k-- ;\ + if (!k) SMT_PANIC(smc,HWM_E0019,HWM_E0019_MSG) ; } + +#define CHECK_DMA_FIFO() {u_long k = 1000000 ;\ + while (k && (DMA_FIFO_BUSY())) k-- ;\ + if (!k) SMT_PANIC(smc,HWM_E0004,HWM_E0004_MSG) ; } + +#define GET_ISR() ~inpw(ISR_A) +#define CHECK_ISR() ~inpw(ISR_A) + +#ifndef UNIX +#ifndef WINNT +#define CLI_FBI() outpw(CSR_A,(inpw(CSR_A)&\ + (CS_CRESET|CS_BYPASS))|CS_RESET_FIFO|smc->hw.led) +#else /* WINNT */ +#define CLI_FBI() outpw(CSR_A,(l_inpw(CSR_A)&\ + (CS_CRESET|CS_BYPASS))|CS_RESET_FIFO|smc->hw.led) +#endif /* WINNT */ +#else /* UNIX */ +#define CLI_FBI(smc) outpw(CSR_AS(smc),(inpw(CSR_AS(smc))&\ + (CS_CRESET|CS_BYPASS))|CS_RESET_FIFO|(smc)->hw.led) +#endif + +#ifndef UNIX +#define STI_FBI() outpw(CSR_A,(inpw(CSR_A)&\ + (CS_CRESET|CS_BYPASS|CS_RESET_FIFO))|CS_IMSK|smc->hw.led) +#else +#define STI_FBI(smc) outpw(CSR_AS(smc),(inpw(CSR_AS(smc))&\ + (CS_CRESET|CS_BYPASS|CS_RESET_FIFO))|CS_IMSK|(smc)->hw.led) +#endif + +/* EISA DMA Controller */ +#define DMA_WRITE_SINGLE_MASK_BIT_M 0x0a /* Master DMA Controller */ +#define DMA_WRITE_SINGLE_MASK_BIT_S 0xd4 /* Slave DMA Controller */ +#define DMA_CLEAR_BYTE_POINTER_M 0x0c +#define DMA_CLEAR_BYTE_POINTER_S 0xd8 + +#endif /* EISA */ + +#ifdef MCA + +/* + * POS Register: !! all I/O's are 8-Bit !! + */ +#define POS_SYS_SETUP 0x94 /* system setup register */ +#define POS_SYSTEM 0xff /* system mode */ + +#define POS_CHANNEL_POS 0x96 /* register slot ID */ +#define POS_CHANNEL_BIT 0x08 /* mask for -"- */ + +#define POS_BASE 0x100 /* POS base address */ +#define POS_ID_LOW POS_BASE /* card ID low */ +#define POS_ID_HIGH (POS_BASE+1) /* card ID high */ +#define POS_102 (POS_BASE+2) /* card en., arbitration level .. */ +#define POS_103 (POS_BASE+3) /* FPROM addr, page */ +#define POS_104 (POS_BASE+4) /* I/O, IRQ */ +#define POS_105 (POS_BASE+5) /* POS_CHCK */ +#define POS_106 (POS_BASE+6) /* to read VPD */ +#define POS_107 (POS_BASE+7) /* added without function */ + +/* FM1 card IDs */ +#define FM1_CARD_ID0 0x83 +#define FM1_CARD_ID1 0 + +#define FM1_IBM_ID0 0x9c +#define FM1_IBM_ID1 0x8f + + +/* FM2 card IDs */ +#define FM2_CARD_ID0 0xab +#define FM2_CARD_ID1 0 + +#define FM2_IBM_ID0 0x7e +#define FM2_IBM_ID1 0x8f + +/* Board revision. */ +#define FM1_REV 0 +#define FM2_REV 1 + +#define MAX_SLOT 8 + +/* + * POS_102 + */ +#define POS_CARD_EN 0x01 /* card enable =1 */ +#define POS_SDAT_EN 0x02 /* enable 32-bit streaming data mode */ +#define POS_EN_CHKINT 0x04 /* enable int. from check line asserted */ +#define POS_EN_BUS_ERR 0x08 /* enable int. on invalid busmaster transf. */ +#define POS_FAIRNESS 0x10 /* fairnes on =1 */ +/* attention: arbitration level used with bit 0 POS 105 */ +#define POS_LARBIT 0xe0 /* arbitration level (0,0,0)->level = 0x8 + (1,1,1)->level = 0xf */ +/* + * POS_103 + */ +#define POS_PAGE 0x07 /* FPROM page selection */ +#define POS_BOOT_EN 0x08 /* boot PROM enable =1 */ +#define POS_MSEL 0x70 /* memory start address for FPROM mapping */ +#define PROG_EN 0x80 /* FM1: Vpp prog on/off */ +#define POS_SDR 0x80 /* FM2: Streaming data bit */ + +/* + * POS_104 + */ +#define POS_IOSEL 0x3f /* selected I/O base address */ +#define POS_IRQSEL 0xc0 /* selected interrupt */ + +/* + * POS_105 + */ +#define POS_CHCK 0x80 +#define POS_SYNC_ERR 0x20 /* FM2: synchronous error reporting */ +#define POS_PAR_DATA 0x10 /* FM2: data parity enable bit */ +#define POS_PAR_ADDR 0x08 /* FM2: address parity enable bit */ +#define POS_IRQHSEL 0x02 /* FM2: Highest bit for IRQ_selection */ +#define POS_HARBIT 0x01 /* Highest bit in Bus arbitration selection */ + +#define SA_MAC (0) /* start addr. MAC_AD within the PROM */ +#define PRA_OFF (0) +#define SA_PMD_TYPE (8) /* start addr. PMD-Type */ + +/* + * address transmision from logical to physical offset address on board + */ +#define FMA(a) (0x0100|((a)<<1)) /* FORMAC+ (r/w) */ +#define P2(a) (0x00c0|((a)<<1)) /* PLC2 (r/w) (DAS) */ +#define P1(a) (0x0080|((a)<<1)) /* PLC1 (r/w) */ +#define TI(a) (0x0060|((a)<<1)) /* Timer (r/w) */ +#define PR(a) (0x0040|((a)<<1)) /* configuration PROM */ +#define CS(a) (0x0020| (a)) /* control/status */ +#define FF(a) (0x0010|((a)<<1)) /* FIFO ASIC */ +#define CT(a) (0x0000|((a)<<1)) /* counter */ + +/* + * counter + */ +#define ACLA CT(0) /* address counter low */ +#define ACHA CT(1) /* address counter high */ +#define BCN CT(2) /* byte counter */ +#define MUX CT(3) /* MUX-register */ +#define WCN CT(0x08) /* word counter */ +#define FFLG CT(0x09) /* FIFO Flags */ + +/* + * test/control register (FM2 only) + */ +#define CNT_TST 0x018 /* Counter test control register */ +#define CNT_STP 0x01a /* Counter test step reg. (8 Bit) */ + +/* + * CS register (read only) + */ +#define CSRA CS(0) /* control/status register address */ +#define CSFA CS(2) /* control/status FIFO BUSY ... */ +#define ISRA CS(4) /* first int. source register address */ +#define ISR2 CS(6) /* second int. source register address */ +#define LEDR CS(0x0c) /* LED register r/w */ +#define CSIL CS(0x10) /* I/O mapped POS_ID_low (100) */ +#define CSIH CS(0x12) /* - " - POS_ID_HIGH (101) */ +#define CSA CS(0x14) /* - " - POS_102 */ +#define CSM CS(0x0e) /* - " - POS_103 */ +#define CSM_FM1 CS(0x16) /* - " - POS_103 (copy in FM1) */ +#define CSI CS(0x18) /* - " - POS_104 */ +#define CSS CS(0x1a) /* - " - POS_105 */ +#define CSP_06 CS(0x1c) /* - " - POS_106 */ +#define WDOG_ST 0x1c /* Watchdog status (FM2 only) */ +#define WDOG_EN 0x1c /* Watchdog enabling (FM2 only, 8Bit) */ +#define WDOG_DIS 0x1e /* Watchdog disabling (FM2 only, 8Bit) */ + +#define PGRA CSM /* Flash page register */ + + +#define WCTA FF(0) /* word counter */ +#define FFLAG FF(1) /* FLAG/V_FULL (FIFO almost full, write only)*/ + +/* + * Timer register (FM2 only) + */ +#define RTM_CNT 0x28 /* RTM Counter */ +#define TI_DIV 0x60 /* Timer Prescaler */ +#define TI_CH1 0x62 /* Timer channel 1 counter */ +#define TI_STOP 0x64 /* Stop timer on channel 1 */ +#define TI_STRT 0x66 /* Start timer on channel 1 */ +#define TI_INI2 0x68 /* Timer: Bus master preemption */ +#define TI_CNT2 0x6a /* Timer */ +#define TI_INI3 0x6c /* Timer: Streaming data */ +#define TI_CNT3 0x6e /* Timer */ +#define WDOG_LO 0x70 /* Watchdog counter low */ +#define WDOG_HI 0x72 /* Watchdog counter high */ +#define RTM_PRE 0x74 /* restr. token prescaler */ +#define RTM_TIM 0x76 /* restr. token timer */ + +/* + * Recommended Timeout values (for FM2 timer only) + */ +#define TOUT_BM_PRE 188 /* 3.76 usec */ +#define TOUT_S_DAT 374 /* 7.48 usec */ + +/* + * CS register (write only) + */ +#define HSR(p) CS(0x18|(p)) /* Host request register */ + +#define RTM_PUT 0x36 /* restr. token counter write */ +#define RTM_GET 0x28 /* - " - clear */ +#define RTM_CLEAR 0x34 /* - " - read */ + +/* + * BCN Bit definitions + */ +#define BCN_BUSY 0x8000 /* DMA Busy flag */ +#define BCN_AZERO 0x4000 /* Almost zero flag (BCN < 4) */ +#define BCN_STREAM 0x2000 /* Allow streaming data (BCN >= 8) */ + +/* + * WCN Bit definitions + */ +#define WCN_ZERO 0x2000 /* Zero flag (counted to zero) */ +#define WCN_AZERO 0x1000 /* Almost zero flag (BCN < 4) */ + +/* + * CNT_TST Bit definitions + */ +#define CNT_MODE 0x01 /* Go into test mode */ +#define CNT_D32 0x02 /* 16/32 BIT test mode */ + +/* + * FIFO Flag FIFO Flags/Vfull register + */ +#define FF_VFULL 0x003f /* V_full value mask */ +#define FFLG_FULL 0x2000 /* FULL flag */ +#define FFLG_A_FULL 0x1000 /* Almost full flag */ +#define FFLG_VFULL 0x0800 /* V_full Flag */ +#define FFLG_A_EMP 0x0400 /* almost empty flag */ +#define FFLG_EMP 0x0200 /* empty flag */ +#define FFLG_T_EMP 0x0100 /* totally empty flag */ + +/* + * WDOG Watchdog status register + */ +#define WDOG_ALM 0x01 /* Watchdog alarm Bit */ +#define WDOG_ACT 0x02 /* Watchdog active Bit */ + +/* + * CS(0) CONTROLS + */ +#define CS_CRESET 0x0001 +#define FIFO_RST 0x0002 +#define CS_IMSK 0x0004 +#define EN_IRQ_CHCK 0x0008 +#define EN_IRQ_TOKEN 0x0010 +#define EN_IRQ_TC 0x0020 +#define TOKEN_STATUS 0x0040 +#define RTM_CHANGE 0x0080 + +#define CS_SAS 0x0100 +#define CS_BYSTAT 0x0200 /* bypass connected (0=conn.) */ +#define CS_BYPASS 0x0400 /* bypass on/off indication */ + +/* + * CS(2) FIFOSTAT + */ +#define HSREQ 0x0007 +#define BIGDIR 0x0008 +#define CSF_BUSY_FIFO 0x0010 +#define CSF_BUSY_DMA 0x0020 +#define SLOT_32 0x0040 + +#define LED_0 0x0001 +#define LED_1 0x0002 +#define LED_2 0x0100 + +#define MAX_PAGES 8 /* pages */ +#define MAX_FADDR 0x4000 /* 16K per page */ + +/* + * IRQ = ISRA || ISR2 ; + * + * ISRA = IRQ_OTH_EN && (IS_LAN | IS_BUS) ; + * ISR2 = IRQ_TC_EN && IS_TC ; + * + * IS_LAN = (IS_MINTR1 | IS_MINTR2 | IS_PLINT1 | IS_PLINT2 | IS_TIMINT) || + * (IRQ_EN_TOKEN && IS_TOKEN) ; + * IS_BUS = IRQ_CHCK_EN && (IS_BUSERR | IS_CHCK_L) ; + */ +/* + * ISRA !!! activ high !!! + */ +#define IS_MINTR1 0x0001 /* FORMAC ST1U/L & ~IMSK1U/L*/ +#define IS_MINTR2 0x0002 /* FORMAC ST2U/L & ~IMSK2U/L*/ +#define IS_PLINT1 0x0004 /* PLC1 */ +#define IS_PLINT2 0x0008 /* PLC2 */ +#define IS_TIMINT 0x0010 /* Timer 82C54-2 */ +#define IS_TOKEN 0x0020 /* restrictet token monitoring */ +#define IS_CHCK_L 0x0040 /* check line asserted */ +#define IS_BUSERR 0x0080 /* bus error */ +/* + * ISR2 + */ +#define IS_TC 0x0001 /* terminal count irq */ +#define IS_SFDBKRTN 0x0002 /* selected feedback return */ +#define IS_D16 0x0004 /* DS16 */ +#define IS_D32 0x0008 /* DS32 */ +#define IS_DPEI 0x0010 /* Data Parity Indication */ + +#define ALL_IRSR 0x00ff + +#define FM_A(a) ADDR(FMA(a)) /* FORMAC Plus physical addr */ +#define P1_A(a) ADDR(P1(a)) /* PLC1 (r/w) */ +#define P2_A(a) ADDR(P2(a)) /* PLC2 (r/w) (DAS) */ +#define TI_A(a) ADDR(TI(a)) /* Timer (r/w) FM1 only! */ +#define PR_A(a) ADDR(PR(a)) /* config. PROM */ +#define CS_A(a) ADDR(CS(a)) /* control/status */ + +#define ISR1_A ADDR(ISRA) /* first int. source register address */ +#define ISR2_A ADDR(ISR2) /* second -"- */ +#define CSR_A ADDR(CSRA) /* control/status register address */ +#define CSF_A ADDR(CSFA) /* control/status FIFO BUSY flags (r/w) */ + +#define CSIL_A ADDR(CSIL) /* I/O mapped POS_ID_low (102) */ +#define CSIH_A ADDR(CSIH) /* - " - POS_ID_HIGH (101) */ +#define CSA_A ADDR(CSA) /* - " - POS_102 */ +#define CSI_A ADDR(CSI) /* - " - POS_104 */ +#define CSM_A ADDR(CSM) /* - " - POS_103 */ +#define CSM_FM1_A ADDR(CSM_FM1) /* - " - POS_103 (2nd copy, FM1) */ +#define CSP_06_A ADDR(CSP_06) /* - " - POS_106 */ + +#define WCT_A ADDR(WCTA) /* word counter (r/w) */ +#define FFLAG_A ADDR(FFLAG) /* FLAG/V_FULL (FIFO almost full, write only)*/ + +#define ACL_A ADDR(ACLA) /* address counter low */ +#define ACH_A ADDR(ACHA) /* address counter high */ +#define BCN_A ADDR(BCN) /* byte counter */ +#define MUX_A ADDR(MUX) /* MUX-register */ + +#define ISR_A ADDR(ISRA) /* Interrupt Source Register */ +#define FIFO_RESET_A ADDR(FIFO_RESET) /* reset the FIFO */ +#define FIFO_EN_A ADDR(FIFO_EN) /* enable the FIFO */ + +#define WDOG_EN_A ADDR(WDOG_EN) /* reset and start the WDOG */ +#define WDOG_DIS_A ADDR(WDOG_DIS) /* disable the WDOG */ +/* + * all control reg. (read!) are 8 bit (except PAGE_RG_A and LEDR_A) + */ +#define HSR_A(p) ADDR(HSR(p)) /* Host request register */ + +#define STAT_BYP 0 /* bypass station */ +#define STAT_INS 2 /* insert station */ +#define BYPASS(o) CS(0x10|(o)) /* o=STAT_BYP || STAT_INS */ + +#define IRQ_TC_EN CS(0x0b) /* enable/disable IRQ on TC */ +#define IRQ_TC_DIS CS(0x0a) +#define IRQ_TOKEN_EN CS(9) /* enable/disable IRQ on restr. Token */ +#define IRQ_TOKEN_DIS CS(8) +#define IRQ_CHCK_EN CS(7) /* -"- IRQ after CHCK line */ +#define IRQ_CHCK_DIS CS(6) +#define IRQ_OTH_EN CS(5) /* -"- other IRQ's */ +#define IRQ_OTH_DIS CS(4) +#define FIFO_EN CS(3) /* disable (reset), enable FIFO */ +#define FIFO_RESET CS(2) +#define CARD_EN CS(1) /* disable (reset), enable card */ +#define CARD_DIS CS(0) + +#define LEDR_A ADDR(LEDR) /* D0=green, D1=yellow, D8=L2 */ +#define PAGE_RG_A ADDR(CSM) /* D<2..0> */ +#define IRQ_CHCK_EN_A ADDR(IRQ_CHCK_EN) +#define IRQ_CHCK_DIS_A ADDR(IRQ_CHCK_DIS) + +#define GET_PAGE(bank) outpw(PAGE_RG_A,(inpw(PAGE_RG_A) &\ + (~POS_PAGE)) |(int) (bank)) +#define VPP_ON() if (smc->hw.rev == FM1_REV) { \ + outpw(PAGE_RG_A, \ + (inpw(PAGE_RG_A) & POS_PAGE) | PROG_EN); \ + } +#define VPP_OFF() if (smc->hw.rev == FM1_REV) { \ + outpw(PAGE_RG_A,(inpw(PAGE_RG_A) & POS_PAGE)); \ + } + +#define SKFDDI_PSZ 16 /* address PROM size */ + +#define READ_PROM(a) ((u_char)inp(a)) + +#define GET_ISR() ~inpw(ISR1_A) +#ifndef TCI +#define CHECK_ISR() ~inpw(ISR1_A) +#define CHECK_ISR_SMP(iop) ~inpw((iop)+ISRA) +#else +#define CHECK_ISR() (~inpw(ISR1_A) | ~inpw(ISR2_A)) +#define CHECK_ISR_SMP(iop) (~inpw((iop)+ISRA) | ~inpw((iop)+ISR2)) +#endif + +#define DMA_BUSY() (inpw(CSF_A) & CSF_BUSY_DMA) +#define FIFO_BUSY() (inpw(CSF_A) & CSF_BUSY_FIFO) +#define DMA_FIFO_BUSY() (inpw(CSF_A) & (CSF_BUSY_DMA | CSF_BUSY_FIFO)) +#define BUS_CHECK() { int i ; \ + if ((i = GET_ISR()) & IS_BUSERR) \ + SMT_PANIC(smc,HWM_E0020,HWM_E0020_MSG) ; \ + if (i & IS_CHCK_L) \ + SMT_PANIC(smc,HWM_E0014,HWM_E0014_MSG) ; \ + } + +#define CHECK_DMA() { u_long k = 10000 ; \ + while (k && (DMA_BUSY())) { \ + k-- ; \ + BUS_CHECK() ; \ + } \ + if (!k) SMT_PANIC(smc,HWM_E0003,HWM_E0003_MSG) ; } + +#define CHECK_FIFO() {u_long k = 1000000 ;\ + while (k && (FIFO_BUSY())) k-- ;\ + if (!k) SMT_PANIC(smc,HWM_E0019,HWM_E0019_MSG) ; } + +#define CHECK_DMA_FIFO() {u_long k = 1000000 ;\ + while (k && (DMA_FIFO_BUSY())) { \ + k-- ;\ + BUS_CHECK() ; \ + } \ + if (!k) SMT_PANIC(smc,HWM_E0004,HWM_E0004_MSG) ; } + +#ifndef UNIX +#define CLI_FBI() outp(ADDR(IRQ_OTH_DIS),0) +#else +#define CLI_FBI(smc) outp(ADDRS((smc),IRQ_OTH_DIS),0) +#endif + +#ifndef TCI +#define CLI_FBI_SMP(iop) outp((iop)+IRQ_OTH_DIS,0) +#else +#define CLI_FBI_SMP(iop) outp((iop)+IRQ_OTH_DIS,0) ;\ + outp((iop)+IRQ_TC_DIS,0) +#endif + +#ifndef UNIX +#define STI_FBI() outp(ADDR(IRQ_OTH_EN),0) +#else +#define STI_FBI(smc) outp(ADDRS((smc),IRQ_OTH_EN),0) +#endif + +/* + * Terminal count primitives + */ +#define CLI_TCI(smc) outp(ADDRS((smc),IRQ_TC_DIS),0) +#define STI_TCI(smc) outp(ADDRS((smc),IRQ_TC_EN),0) +#define CHECK_TC(smc,k) {(k) = 10000 ;\ + while ((k) && (~inpw(ISR2_A) & IS_TC)) (k)-- ;\ + if (!k) SMT_PANIC(smc,HWM_E0018,HWM_E0018_MSG) ; } + +#endif /* MCA */ + +#ifdef ISA + +/* + * address transmision from logic NPADDR6-0 to physical offset address on board + */ +#define FMA(a) (0x8000|(((a)&0x07)<<1)|(((a)&0x78)<<7)) /* FORMAC+ (r/w) */ +#define PRA(a) (0x1000|(((a)&0x07)<<1)|(((a)&0x18)<<7)) /* PROM (read only)*/ +#define P1A(a) (0x4000|(((a)&0x07)<<1)|(((a)&0x18)<<7)) /* PLC1 (r/w) */ +#define P2A(a) (0x5000|(((a)&0x07)<<1)|(((a)&0x18)<<7)) /* PLC2 (r/w) */ +#define TIA(a) (0x6000|(((a)&0x03)<<1)) /* Timer (r/w) */ + +#define ISRA 0x0000 /* int. source register address (read only) */ +#define ACLA 0x0000 /* address counter low address (write only) */ +#define ACHA 0x0002 /* address counter high address (write only) */ +#define TRCA 0x0004 /* transfer counter address (write only) */ +#define PGRA 0x0006 /* page register address (write only) */ +#define RQAA 0x2000 /* Request reg. (write only) */ +#define CSRA 0x3000 /* control/status register address (r/w) */ + +/* + * physical address offset + IO-Port base address + */ +#define FM_A(a) (FMA(a)+smc->hw.iop) /* FORMAC Plus physical addr */ +#define PR_A(a) (PRA(a)+smc->hw.iop) /* PROM (read only)*/ +#define P1_A(a) (P1A(a)+smc->hw.iop) /* PLC1 (r/w) */ +#define P2_A(a) (P2A(a)+smc->hw.iop) /* PLC2 (r/w) */ +#define TI_A(a) (TIA(a)+smc->hw.iop) /* Timer (r/w) */ + +#define ISR_A (0x0000+smc->hw.iop) /* int. source register address (read only) */ +#define ACL_A (0x0000+smc->hw.iop) /* address counter low address (write only) */ +#define ACH_A (0x0002+smc->hw.iop) /* address counter high address (write only)*/ +#define TRC_A (0x0004+smc->hw.iop) /* transfer counter address (write only) */ +#define PGR_A (0x0006+smc->hw.iop) /* page register address (write only) */ +#define RQA_A (0x2000+smc->hw.iop) /* Request reg. (write only) */ +#define CSR_A (0x3000+smc->hw.iop) /* control/status register address (r/w) */ +#ifdef UNIX +#define CSR_AS(smc) (0x3000+(smc)->hw.iop) /* control/status register address */ +#endif +#define PLC1_I (0x3400+smc->hw.iop) /* clear PLC1 interrupt bit */ +#define PLC2_I (0x3800+smc->hw.iop) /* clear PLC2 interrupt bit */ + +#ifndef MULT_OEM +#ifndef OEM_CONCEPT +#define SKLOGO_STR "SKFDDI" +#else /* OEM_CONCEPT */ +#define SKLOGO_STR OEM_FDDI_LOGO +#endif /* OEM_CONCEPT */ +#endif /* MULT_OEM */ +#define SADDRL (24) /* start address SKLOGO */ +#define SA_MAC (0) /* start addr. MAC_AD within the PROM */ +#define PRA_OFF (0) +#define SA_PMD_TYPE (8) /* start addr. PMD-Type */ + +#define CDID (PRA(SADDRL)) /* Card ID int/O port addr. offset */ +#define NEXT_CDID ((PRA(SADDRL+1)) - CDID) + +#define SKFDDI_PSZ 32 /* address PROM size */ + +#define READ_PROM(a) ((u_char)inpw(a)) +#define GET_PAGE(i) outpw(PGR_A,(int)(i)) + +#define MAX_PAGES 16 /* 16 pages */ +#define MAX_FADDR 0x2000 /* 8K per page */ +#define VPP_OFF() outpw(CSR_A,(inpw(CSR_A) & (CS_CRESET|CS_BYPASS))) +#define VPP_ON() outpw(CSR_A,(inpw(CSR_A) & (CS_CRESET|CS_BYPASS)) | \ + CS_VPPSW) + +/* + * control/status register CSRA bits (log. addr: 0x3000) + */ +/* write */ +#define CS_CRESET 0x01 /* Card reset (0=reset) */ +#define CS_IMSK 0x02 /* enable IRQ (1=enable, 0=disable) */ +#define CS_RESINT1 0x04 /* PLINT1 reset */ +#define CS_VPPSW 0x10 /* 12V power switch (0=off, 1=on) */ +#define CS_BYPASS 0x20 /* bypass switch (0=remove, 1=insert)*/ +#define CS_RESINT2 0x40 /* PLINT2 reset */ +/* read */ +#define CS_BUSY 0x04 /* master transfer activ (=1) */ +#define CS_SW_EPROM 0x08 /* 0=Application Soft. 1=BOOT-EPROM */ +#define CS_BYSTAT 0x40 /* 0=Bypass exist, 1= ..not */ +#define CS_SAS 0x80 /* single attachement station (=1) */ + +/* + * Interrupt source register ISRA (log. addr: 0x0000) read only & low activ. + */ +#define IS_MINTR1 0x01 /* FORMAC ST1U/L && ~IMSK1U/L*/ +#define IS_MINTR2 0x02 /* FORMAC ST2U/L && ~IMSK2U/L*/ +#define IS_PLINT1 0x04 /* PLC1 */ +#define IS_PLINT2 0x08 /* PLC2 */ +#define IS_TIMINT 0x10 /* Timer 82C54-2 */ + +#define ALL_IRSR (IS_MINTR1|IS_MINTR2|IS_PLINT1|IS_PLINT2|IS_TIMINT) + +#define FPROM_SW() (inpw(CSR_A)&CS_SW_EPROM) +#define DMA_BUSY() (inpw(CSR_A)&CS_BUSY) +#define CHECK_FIFO() +#define BUS_CHECK() + +/* + * set Host Request register (wr.) + */ +#define SET_HRQ(qup) outpw(RQA_A+((qup)<<1),0) + +#ifndef UNIX +#ifndef WINNT +#define CLI_FBI() outpw(CSR_A,(inpw(CSR_A)&(CS_CRESET|CS_BYPASS|CS_VPPSW))) +#else +#define CLI_FBI() outpw(CSR_A,(l_inpw(CSR_A) & \ + (CS_CRESET|CS_BYPASS|CS_VPPSW))) +#endif +#else +#define CLI_FBI(smc) outpw(CSR_AS(smc),(inpw(CSR_AS(smc))& \ + (CS_CRESET|CS_BYPASS|CS_VPPSW))) +#endif + +#ifndef UNIX +#define STI_FBI() outpw(CSR_A,(inpw(CSR_A) & \ + (CS_CRESET|CS_BYPASS|CS_VPPSW)) | CS_IMSK) +#else +#define STI_FBI(smc) outpw(CSR_AS(smc),(inpw(CSR_AS(smc)) & \ + (CS_CRESET|CS_BYPASS|CS_VPPSW)) | CS_IMSK) +#endif + +#define CHECK_DMA() {unsigned k = 10000 ;\ + while (k && (DMA_BUSY())) k-- ;\ + if (!k) SMT_PANIC(smc,HWM_E0003,HWM_E0003_MSG) ; } + +#define GET_ISR() ~inpw(ISR_A) + +#endif /* ISA */ + +/*--------------------------------------------------------------------------*/ +#ifdef PCI + +/* + * (DV) = only defined for Da Vinci + * (ML) = only defined for Monalisa + */ + +/* + * Configuration Space header + */ +#define PCI_VENDOR_ID 0x00 /* 16 bit Vendor ID */ +#define PCI_DEVICE_ID 0x02 /* 16 bit Device ID */ +#define PCI_COMMAND 0x04 /* 16 bit Command */ +#define PCI_STATUS 0x06 /* 16 bit Status */ +#define PCI_REV_ID 0x08 /* 8 bit Revision ID */ +#define PCI_CLASS_CODE 0x09 /* 24 bit Class Code */ +#define PCI_CACHE_LSZ 0x0c /* 8 bit Cache Line Size */ +#define PCI_LAT_TIM 0x0d /* 8 bit Latency Timer */ +#define PCI_HEADER_T 0x0e /* 8 bit Header Type */ +#define PCI_BIST 0x0f /* 8 bit Built-in selftest */ +#define PCI_BASE_1ST 0x10 /* 32 bit 1st Base address */ +#define PCI_BASE_2ND 0x14 /* 32 bit 2nd Base address */ +/* Byte 18..2b: Reserved */ +#define PCI_SUB_VID 0x2c /* 16 bit Subsystem Vendor ID */ +#define PCI_SUB_ID 0x2e /* 16 bit Subsystem ID */ +#define PCI_BASE_ROM 0x30 /* 32 bit Expansion ROM Base Address */ +/* Byte 34..33: Reserved */ +#define PCI_CAP_PTR 0x34 /* 8 bit (ML) Capabilities Ptr */ +/* Byte 35..3b: Reserved */ +#define PCI_IRQ_LINE 0x3c /* 8 bit Interrupt Line */ +#define PCI_IRQ_PIN 0x3d /* 8 bit Interrupt Pin */ +#define PCI_MIN_GNT 0x3e /* 8 bit Min_Gnt */ +#define PCI_MAX_LAT 0x3f /* 8 bit Max_Lat */ +/* Device Dependent Region */ +#define PCI_OUR_REG 0x40 /* 32 bit (DV) Our Register */ +#define PCI_OUR_REG_1 0x40 /* 32 bit (ML) Our Register 1 */ +#define PCI_OUR_REG_2 0x44 /* 32 bit (ML) Our Register 2 */ +/* Power Management Region */ +#define PCI_PM_CAP_ID 0x48 /* 8 bit (ML) Power Management Cap. ID */ +#define PCI_PM_NITEM 0x49 /* 8 bit (ML) Next Item Ptr */ +#define PCI_PM_CAP_REG 0x4a /* 16 bit (ML) Power Management Capabilities */ +#define PCI_PM_CTL_STS 0x4c /* 16 bit (ML) Power Manag. Control/Status */ +/* Byte 0x4e: Reserved */ +#define PCI_PM_DAT_REG 0x4f /* 8 bit (ML) Power Manag. Data Register */ +/* VPD Region */ +#define PCI_VPD_CAP_ID 0x50 /* 8 bit (ML) VPD Cap. ID */ +#define PCI_VPD_NITEM 0x51 /* 8 bit (ML) Next Item Ptr */ +#define PCI_VPD_ADR_REG 0x52 /* 16 bit (ML) VPD Address Register */ +#define PCI_VPD_DAT_REG 0x54 /* 32 bit (ML) VPD Data Register */ +/* Byte 58..ff: Reserved */ + +/* + * I2C Address (PCI Config) + * + * Note: The temperature and voltage sensors are relocated on a different + * I2C bus. + */ +#define I2C_ADDR_VPD 0xA0 /* I2C address for the VPD EEPROM */ + +/* + * Define Bits and Values of the registers + */ +/* PCI_VENDOR_ID 16 bit Vendor ID */ +/* PCI_DEVICE_ID 16 bit Device ID */ +/* Values for Vendor ID and Device ID shall be patched into the code */ +/* PCI_COMMAND 16 bit Command */ +#define PCI_FBTEN 0x0200 /* Bit 9: Fast Back-To-Back enable */ +#define PCI_SERREN 0x0100 /* Bit 8: SERR enable */ +#define PCI_ADSTEP 0x0080 /* Bit 7: Address Stepping */ +#define PCI_PERREN 0x0040 /* Bit 6: Parity Report Response enable */ +#define PCI_VGA_SNOOP 0x0020 /* Bit 5: VGA palette snoop */ +#define PCI_MWIEN 0x0010 /* Bit 4: Memory write an inv cycl ena */ +#define PCI_SCYCEN 0x0008 /* Bit 3: Special Cycle enable */ +#define PCI_BMEN 0x0004 /* Bit 2: Bus Master enable */ +#define PCI_MEMEN 0x0002 /* Bit 1: Memory Space Access enable */ +#define PCI_IOEN 0x0001 /* Bit 0: IO Space Access enable */ + +/* PCI_STATUS 16 bit Status */ +#define PCI_PERR 0x8000 /* Bit 15: Parity Error */ +#define PCI_SERR 0x4000 /* Bit 14: Signaled SERR */ +#define PCI_RMABORT 0x2000 /* Bit 13: Received Master Abort */ +#define PCI_RTABORT 0x1000 /* Bit 12: Received Target Abort */ +#define PCI_STABORT 0x0800 /* Bit 11: Sent Target Abort */ +#define PCI_DEVSEL 0x0600 /* Bit 10..9: DEVSEL Timing */ +#define PCI_DEV_FAST (0<<9) /* fast */ +#define PCI_DEV_MEDIUM (1<<9) /* medium */ +#define PCI_DEV_SLOW (2<<9) /* slow */ +#define PCI_DATAPERR 0x0100 /* Bit 8: DATA Parity error detected */ +#define PCI_FB2BCAP 0x0080 /* Bit 7: Fast Back-to-Back Capability */ +#define PCI_UDF 0x0040 /* Bit 6: User Defined Features */ +#define PCI_66MHZCAP 0x0020 /* Bit 5: 66 MHz PCI bus clock capable */ +#define PCI_NEWCAP 0x0010 /* Bit 4: New cap. list implemented */ + +#define PCI_ERRBITS (PCI_PERR|PCI_SERR|PCI_RMABORT|PCI_STABORT|PCI_DATAPERR) + +/* PCI_REV_ID 8 bit Revision ID */ +/* PCI_CLASS_CODE 24 bit Class Code */ +/* Byte 2: Base Class (02) */ +/* Byte 1: SubClass (02) */ +/* Byte 0: Programming Interface (00) */ + +/* PCI_CACHE_LSZ 8 bit Cache Line Size */ +/* Possible values: 0,2,4,8,16 */ + +/* PCI_LAT_TIM 8 bit Latency Timer */ + +/* PCI_HEADER_T 8 bit Header Type */ +#define PCI_HD_MF_DEV 0x80 /* Bit 7: 0= single, 1= multi-func dev */ +#define PCI_HD_TYPE 0x7f /* Bit 6..0: Header Layout 0= normal */ + +/* PCI_BIST 8 bit Built-in selftest */ +#define PCI_BIST_CAP 0x80 /* Bit 7: BIST Capable */ +#define PCI_BIST_ST 0x40 /* Bit 6: Start BIST */ +#define PCI_BIST_RET 0x0f /* Bit 3..0: Completion Code */ + +/* PCI_BASE_1ST 32 bit 1st Base address */ +#define PCI_MEMSIZE 0x800L /* use 2 kB Memory Base */ +#define PCI_MEMBASE_BITS 0xfffff800L /* Bit 31..11: Memory Base Address */ +#define PCI_MEMSIZE_BIIS 0x000007f0L /* Bit 10..4: Memory Size Req. */ +#define PCI_PREFEN 0x00000008L /* Bit 3: Prefetchable */ +#define PCI_MEM_TYP 0x00000006L /* Bit 2..1: Memory Type */ +#define PCI_MEM32BIT (0<<1) /* Base addr anywhere in 32 Bit range */ +#define PCI_MEM1M (1<<1) /* Base addr below 1 MegaByte */ +#define PCI_MEM64BIT (2<<1) /* Base addr anywhere in 64 Bit range */ +#define PCI_MEMSPACE 0x00000001L /* Bit 0: Memory Space Indic. */ + +/* PCI_BASE_2ND 32 bit 2nd Base address */ +#define PCI_IOBASE 0xffffff00L /* Bit 31..8: I/O Base address */ +#define PCI_IOSIZE 0x000000fcL /* Bit 7..2: I/O Size Requirements */ +#define PCI_IOSPACE 0x00000001L /* Bit 0: I/O Space Indicator */ + +/* PCI_SUB_VID 16 bit Subsystem Vendor ID */ +/* PCI_SUB_ID 16 bit Subsystem ID */ + +/* PCI_BASE_ROM 32 bit Expansion ROM Base Address */ +#define PCI_ROMBASE 0xfffe0000L /* Bit 31..17: ROM BASE addres (1st) */ +#define PCI_ROMBASZ 0x0001c000L /* Bit 16..14: Treat as BASE or SIZE */ +#define PCI_ROMSIZE 0x00003800L /* Bit 13..11: ROM Size Requirements */ +#define PCI_ROMEN 0x00000001L /* Bit 0: Address Decode enable */ + +/* PCI_CAP_PTR 8 bit New Capabilities Pointers */ +/* PCI_IRQ_LINE 8 bit Interrupt Line */ +/* PCI_IRQ_PIN 8 bit Interrupt Pin */ +/* PCI_MIN_GNT 8 bit Min_Gnt */ +/* PCI_MAX_LAT 8 bit Max_Lat */ +/* Device Dependent Region */ +/* PCI_OUR_REG (DV) 32 bit Our Register */ +/* PCI_OUR_REG_1 (ML) 32 bit Our Register 1 */ + /* Bit 31..29: reserved */ +#define PCI_PATCH_DIR (3L<<27) /*(DV) Bit 28..27: Ext Patchs direction */ +#define PCI_PATCH_DIR_0 (1L<<27) /*(DV) Type of the pins EXT_PATCHS<1..0> */ +#define PCI_PATCH_DIR_1 (1L<<28) /* 0 = input */ + /* 1 = output */ +#define PCI_EXT_PATCHS (3L<<25) /*(DV) Bit 26..25: Extended Patches */ +#define PCI_EXT_PATCH_0 (1L<<25) /*(DV) */ +#define PCI_EXT_PATCH_1 (1L<<26) /* CLK for MicroWire (ML) */ +#define PCI_VIO (1L<<25) /*(ML) */ +#define PCI_EN_BOOT (1L<<24) /* Bit 24: Enable BOOT via ROM */ + /* 1 = Don't boot with ROM */ + /* 0 = Boot with ROM */ +#define PCI_EN_IO (1L<<23) /* Bit 23: Mapping to IO space */ +#define PCI_EN_FPROM (1L<<22) /* Bit 22: FLASH mapped to mem? */ + /* 1 = Map Flash to Memory */ + /* 0 = Disable all addr. decoding */ +#define PCI_PAGESIZE (3L<<20) /* Bit 21..20: FLASH Page Size */ +#define PCI_PAGE_16 (0L<<20) /* 16 k pages */ +#define PCI_PAGE_32K (1L<<20) /* 32 k pages */ +#define PCI_PAGE_64K (2L<<20) /* 64 k pages */ +#define PCI_PAGE_128K (3L<<20) /* 128 k pages */ + /* Bit 19: reserved (ML) and (DV) */ +#define PCI_PAGEREG (7L<<16) /* Bit 18..16: Page Register */ + /* Bit 15: reserved */ +#define PCI_FORCE_BE (1L<<14) /* Bit 14: Assert all BEs on MR */ +#define PCI_DIS_MRL (1L<<13) /* Bit 13: Disable Mem R Line */ +#define PCI_DIS_MRM (1L<<12) /* Bit 12: Disable Mem R multip */ +#define PCI_DIS_MWI (1L<<11) /* Bit 11: Disable Mem W & inv */ +#define PCI_DISC_CLS (1L<<10) /* Bit 10: Disc: cacheLsz bound */ +#define PCI_BURST_DIS (1L<<9) /* Bit 9: Burst Disable */ +#define PCI_BYTE_SWAP (1L<<8) /*(DV) Bit 8: Byte Swap in DATA */ +#define PCI_SKEW_DAS (0xfL<<4) /* Bit 7..4: Skew Ctrl, DAS Ext */ +#define PCI_SKEW_BASE (0xfL<<0) /* Bit 3..0: Skew Ctrl, Base */ + +/* PCI_OUR_REG_2 (ML) 32 bit Our Register 2 (Monalisa only) */ +#define PCI_VPD_WR_TH (0xffL<<24) /* Bit 24..31 VPD Write Threshold */ +#define PCI_DEV_SEL (0x7fL<<17) /* Bit 17..23 EEPROM Device Select */ +#define PCI_VPD_ROM_SZ (7L<<14) /* Bit 14..16 VPD ROM Size */ + /* Bit 12..13 reserved */ +#define PCI_PATCH_DIR2 (0xfL<<8) /* Bit 8..11 Ext Patchs dir 2..5 */ +#define PCI_PATCH_DIR_2 (1L<<8) /* Bit 8 CS for MicroWire */ +#define PCI_PATCH_DIR_3 (1L<<9) +#define PCI_PATCH_DIR_4 (1L<<10) +#define PCI_PATCH_DIR_5 (1L<<11) +#define PCI_EXT_PATCHS2 (0xfL<<4) /* Bit 4..7 Extended Patches */ +#define PCI_EXT_PATCH_2 (1L<<4) /* Bit 4 CS for MicroWire */ +#define PCI_EXT_PATCH_3 (1L<<5) +#define PCI_EXT_PATCH_4 (1L<<6) +#define PCI_EXT_PATCH_5 (1L<<7) +#define PCI_EN_DUMMY_RD (1L<<3) /* Bit 3 Enable Dummy Read */ +#define PCI_REV_DESC (1L<<2) /* Bit 2 Reverse Desc. Bytes */ +#define PCI_USEADDR64 (1L<<1) /* Bit 1 Use 64 Bit Addresse */ +#define PCI_USEDATA64 (1L<<0) /* Bit 0 Use 64 Bit Data bus ext*/ + +/* Power Management Region */ +/* PCI_PM_CAP_ID 8 bit (ML) Power Management Cap. ID */ +/* PCI_PM_NITEM 8 bit (ML) Next Item Ptr */ +/* PCI_PM_CAP_REG 16 bit (ML) Power Management Capabilities*/ +#define PCI_PME_SUP (0x1f<<11) /* Bit 11..15 PM Manag. Event Support*/ +#define PCI_PM_D2_SUB (1<<10) /* Bit 10 D2 Support Bit */ +#define PCI_PM_D1_SUB (1<<9) /* Bit 9 D1 Support Bit */ + /* Bit 6..8 reserved */ +#define PCI_PM_DSI (1<<5) /* Bit 5 Device Specific Init.*/ +#define PCI_PM_APS (1<<4) /* Bit 4 Auxialiary Power Src */ +#define PCI_PME_CLOCK (1<<3) /* Bit 3 PM Event Clock */ +#define PCI_PM_VER (7<<0) /* Bit 0..2 PM PCI Spec. version */ + +/* PCI_PM_CTL_STS 16 bit (ML) Power Manag. Control/Status */ +#define PCI_PME_STATUS (1<<15) /* Bit 15 PFA doesn't sup. PME#*/ +#define PCI_PM_DAT_SCL (3<<13) /* Bit 13..14 dat reg Scaling factor */ +#define PCI_PM_DAT_SEL (0xf<<9) /* Bit 9..12 PM data selector field */ + /* Bit 7.. 2 reserved */ +#define PCI_PM_STATE (3<<0) /* Bit 0.. 1 Power Management State */ +#define PCI_PM_STATE_D0 (0<<0) /* D0: Operational (default) */ +#define PCI_PM_STATE_D1 (1<<0) /* D1: not supported */ +#define PCI_PM_STATE_D2 (2<<0) /* D2: not supported */ +#define PCI_PM_STATE_D3 (3<<0) /* D3: HOT, Power Down and Reset */ + +/* PCI_PM_DAT_REG 8 bit (ML) Power Manag. Data Register */ +/* VPD Region */ +/* PCI_VPD_CAP_ID 8 bit (ML) VPD Cap. ID */ +/* PCI_VPD_NITEM 8 bit (ML) Next Item Ptr */ +/* PCI_VPD_ADR_REG 16 bit (ML) VPD Address Register */ +#define PCI_VPD_FLAG (1<<15) /* Bit 15 starts VPD rd/wd cycle*/ +#define PCI_VPD_ADDR (0x3fff<<0) /* Bit 0..14 VPD address */ + +/* PCI_VPD_DAT_REG 32 bit (ML) VPD Data Register */ + +/* + * Control Register File: + * Bank 0 + */ +#define B0_RAP 0x0000 /* 8 bit register address port */ + /* 0x0001 - 0x0003: reserved */ +#define B0_CTRL 0x0004 /* 8 bit control register */ +#define B0_DAS 0x0005 /* 8 Bit control register (DAS) */ +#define B0_LED 0x0006 /* 8 Bit LED register */ +#define B0_TST_CTRL 0x0007 /* 8 bit test control register */ +#define B0_ISRC 0x0008 /* 32 bit Interrupt source register */ +#define B0_IMSK 0x000c /* 32 bit Interrupt mask register */ + +/* 0x0010 - 0x006b: formac+ (supernet_3) fequently used registers */ +#define B0_CMDREG1 0x0010 /* write command reg 1 instruction */ +#define B0_CMDREG2 0x0014 /* write command reg 2 instruction */ +#define B0_ST1U 0x0010 /* read upper 16-bit of status reg 1 */ +#define B0_ST1L 0x0014 /* read lower 16-bit of status reg 1 */ +#define B0_ST2U 0x0018 /* read upper 16-bit of status reg 2 */ +#define B0_ST2L 0x001c /* read lower 16-bit of status reg 2 */ + +#define B0_MARR 0x0020 /* r/w the memory read addr register */ +#define B0_MARW 0x0024 /* r/w the memory write addr register*/ +#define B0_MDRU 0x0028 /* r/w upper 16-bit of mem. data reg */ +#define B0_MDRL 0x002c /* r/w lower 16-bit of mem. data reg */ + +#define B0_MDREG3 0x0030 /* r/w Mode Register 3 */ +#define B0_ST3U 0x0034 /* read upper 16-bit of status reg 3 */ +#define B0_ST3L 0x0038 /* read lower 16-bit of status reg 3 */ +#define B0_IMSK3U 0x003c /* r/w upper 16-bit of IMSK reg 3 */ +#define B0_IMSK3L 0x0040 /* r/w lower 16-bit of IMSK reg 3 */ +#define B0_IVR 0x0044 /* read Interrupt Vector register */ +#define B0_IMR 0x0048 /* r/w Interrupt mask register */ +/* 0x4c Hidden */ + +#define B0_CNTRL_A 0x0050 /* control register A (r/w) */ +#define B0_CNTRL_B 0x0054 /* control register B (r/w) */ +#define B0_INTR_MASK 0x0058 /* interrupt mask (r/w) */ +#define B0_XMIT_VECTOR 0x005c /* transmit vector register (r/w) */ + +#define B0_STATUS_A 0x0060 /* status register A (read only) */ +#define B0_STATUS_B 0x0064 /* status register B (read only) */ +#define B0_CNTRL_C 0x0068 /* control register C (r/w) */ +#define B0_MDREG1 0x006c /* r/w Mode Register 1 */ + +#define B0_R1_CSR 0x0070 /* 32 bit BMU control/status reg (rec q 1) */ +#define B0_R2_CSR 0x0074 /* 32 bit BMU control/status reg (rec q 2)(DV)*/ +#define B0_XA_CSR 0x0078 /* 32 bit BMU control/status reg (a xmit q) */ +#define B0_XS_CSR 0x007c /* 32 bit BMU control/status reg (s xmit q) */ + +/* + * Bank 1 + * - completely empty (this is the RAP Block window) + * Note: if RAP = 1 this page is reserved + */ + +/* + * Bank 2 + */ +#define B2_MAC_0 0x0100 /* 8 bit MAC address Byte 0 */ +#define B2_MAC_1 0x0101 /* 8 bit MAC address Byte 1 */ +#define B2_MAC_2 0x0102 /* 8 bit MAC address Byte 2 */ +#define B2_MAC_3 0x0103 /* 8 bit MAC address Byte 3 */ +#define B2_MAC_4 0x0104 /* 8 bit MAC address Byte 4 */ +#define B2_MAC_5 0x0105 /* 8 bit MAC address Byte 5 */ +#define B2_MAC_6 0x0106 /* 8 bit MAC address Byte 6 (== 0) (DV) */ +#define B2_MAC_7 0x0107 /* 8 bit MAC address Byte 7 (== 0) (DV) */ + +#define B2_CONN_TYP 0x0108 /* 8 bit Connector type */ +#define B2_PMD_TYP 0x0109 /* 8 bit PMD type */ + /* 0x010a - 0x010b: reserved */ + /* Eprom registers are currently of no use */ +#define B2_E_0 0x010c /* 8 bit EPROM Byte 0 */ +#define B2_E_1 0x010d /* 8 bit EPROM Byte 1 */ +#define B2_E_2 0x010e /* 8 bit EPROM Byte 2 */ +#define B2_E_3 0x010f /* 8 bit EPROM Byte 3 */ +#define B2_FAR 0x0110 /* 32 bit Flash-Prom Address Register/Counter */ +#define B2_FDP 0x0114 /* 8 bit Flash-Prom Data Port */ + /* 0x0115 - 0x0117: reserved */ +#define B2_LD_CRTL 0x0118 /* 8 bit loader control */ +#define B2_LD_TEST 0x0119 /* 8 bit loader test */ + /* 0x011a - 0x011f: reserved */ +#define B2_TI_INI 0x0120 /* 32 bit Timer init value */ +#define B2_TI_VAL 0x0124 /* 32 bit Timer value */ +#define B2_TI_CRTL 0x0128 /* 8 bit Timer control */ +#define B2_TI_TEST 0x0129 /* 8 Bit Timer Test */ + /* 0x012a - 0x012f: reserved */ +#define B2_WDOG_INI 0x0130 /* 32 bit Watchdog init value */ +#define B2_WDOG_VAL 0x0134 /* 32 bit Watchdog value */ +#define B2_WDOG_CRTL 0x0138 /* 8 bit Watchdog control */ +#define B2_WDOG_TEST 0x0139 /* 8 Bit Watchdog Test */ + /* 0x013a - 0x013f: reserved */ +#define B2_RTM_INI 0x0140 /* 32 bit RTM init value */ +#define B2_RTM_VAL 0x0144 /* 32 bit RTM value */ +#define B2_RTM_CRTL 0x0148 /* 8 bit RTM control */ +#define B2_RTM_TEST 0x0149 /* 8 Bit RTM Test */ + +#define B2_TOK_COUNT 0x014c /* (ML) 32 bit Token Counter */ +#define B2_DESC_ADDR_H 0x0150 /* (ML) 32 bit Desciptor Base Addr Reg High */ +#define B2_CTRL_2 0x0154 /* (ML) 8 bit Control Register 2 */ +#define B2_IFACE_REG 0x0155 /* (ML) 8 bit Interface Register */ + /* 0x0156: reserved */ +#define B2_TST_CTRL_2 0x0157 /* (ML) 8 bit Test Control Register 2 */ +#define B2_I2C_CTRL 0x0158 /* (ML) 32 bit I2C Control Register */ +#define B2_I2C_DATA 0x015c /* (ML) 32 bit I2C Data Register */ + +#define B2_IRQ_MOD_INI 0x0160 /* (ML) 32 bit IRQ Moderation Timer Init Reg. */ +#define B2_IRQ_MOD_VAL 0x0164 /* (ML) 32 bit IRQ Moderation Timer Value */ +#define B2_IRQ_MOD_CTRL 0x0168 /* (ML) 8 bit IRQ Moderation Timer Control */ +#define B2_IRQ_MOD_TEST 0x0169 /* (ML) 8 bit IRQ Moderation Timer Test */ + /* 0x016a - 0x017f: reserved */ + +/* + * Bank 3 + */ +/* + * This is a copy of the Configuration register file (lower half) + */ +#define B3_CFG_SPC 0x180 + +/* + * Bank 4 + */ +#define B4_R1_D 0x0200 /* 4*32 bit current receive Descriptor */ +#define B4_R1_DA 0x0210 /* 32 bit current rec desc address */ +#define B4_R1_AC 0x0214 /* 32 bit current receive Address Count */ +#define B4_R1_BC 0x0218 /* 32 bit current receive Byte Counter */ +#define B4_R1_CSR 0x021c /* 32 bit BMU Control/Status Register */ +#define B4_R1_F 0x0220 /* 32 bit flag register */ +#define B4_R1_T1 0x0224 /* 32 bit Test Register 1 */ +#define B4_R1_T1_TR 0x0224 /* 8 bit Test Register 1 TR */ +#define B4_R1_T1_WR 0x0225 /* 8 bit Test Register 1 WR */ +#define B4_R1_T1_RD 0x0226 /* 8 bit Test Register 1 RD */ +#define B4_R1_T1_SV 0x0227 /* 8 bit Test Register 1 SV */ +#define B4_R1_T2 0x0228 /* 32 bit Test Register 2 */ +#define B4_R1_T3 0x022c /* 32 bit Test Register 3 */ +#define B4_R1_DA_H 0x0230 /* (ML) 32 bit Curr Rx Desc Address High */ +#define B4_R1_AC_H 0x0234 /* (ML) 32 bit Curr Addr Counter High dword */ + /* 0x0238 - 0x023f: reserved */ + /* Receive queue 2 is removed on Monalisa */ +#define B4_R2_D 0x0240 /* 4*32 bit current receive Descriptor (q2) */ +#define B4_R2_DA 0x0250 /* 32 bit current rec desc address (q2) */ +#define B4_R2_AC 0x0254 /* 32 bit current receive Address Count (q2) */ +#define B4_R2_BC 0x0258 /* 32 bit current receive Byte Counter (q2) */ +#define B4_R2_CSR 0x025c /* 32 bit BMU Control/Status Register (q2) */ +#define B4_R2_F 0x0260 /* 32 bit flag register (q2) */ +#define B4_R2_T1 0x0264 /* 32 bit Test Register 1 (q2) */ +#define B4_R2_T1_TR 0x0264 /* 8 bit Test Register 1 TR (q2) */ +#define B4_R2_T1_WR 0x0265 /* 8 bit Test Register 1 WR (q2) */ +#define B4_R2_T1_RD 0x0266 /* 8 bit Test Register 1 RD (q2) */ +#define B4_R2_T1_SV 0x0267 /* 8 bit Test Register 1 SV (q2) */ +#define B4_R2_T2 0x0268 /* 32 bit Test Register 2 (q2) */ +#define B4_R2_T3 0x026c /* 32 bit Test Register 3 (q2) */ + /* 0x0270 - 0x027c: reserved */ + +/* + * Bank 5 + */ +#define B5_XA_D 0x0280 /* 4*32 bit current transmit Descriptor (xa) */ +#define B5_XA_DA 0x0290 /* 32 bit current tx desc address (xa) */ +#define B5_XA_AC 0x0294 /* 32 bit current tx Address Count (xa) */ +#define B5_XA_BC 0x0298 /* 32 bit current tx Byte Counter (xa) */ +#define B5_XA_CSR 0x029c /* 32 bit BMU Control/Status Register (xa) */ +#define B5_XA_F 0x02a0 /* 32 bit flag register (xa) */ +#define B5_XA_T1 0x02a4 /* 32 bit Test Register 1 (xa) */ +#define B5_XA_T1_TR 0x02a4 /* 8 bit Test Register 1 TR (xa) */ +#define B5_XA_T1_WR 0x02a5 /* 8 bit Test Register 1 WR (xa) */ +#define B5_XA_T1_RD 0x02a6 /* 8 bit Test Register 1 RD (xa) */ +#define B5_XA_T1_SV 0x02a7 /* 8 bit Test Register 1 SV (xa) */ +#define B5_XA_T2 0x02a8 /* 32 bit Test Register 2 (xa) */ +#define B5_XA_T3 0x02ac /* 32 bit Test Register 3 (xa) */ +#define B5_XA_DA_H 0x02b0 /* (ML) 32 bit Curr Tx Desc Address High */ +#define B5_XA_AC_H 0x02b4 /* (ML) 32 bit Curr Addr Counter High dword */ + /* 0x02b8 - 0x02bc: reserved */ +#define B5_XS_D 0x02c0 /* 4*32 bit current transmit Descriptor (xs) */ +#define B5_XS_DA 0x02d0 /* 32 bit current tx desc address (xs) */ +#define B5_XS_AC 0x02d4 /* 32 bit current transmit Address Count(xs) */ +#define B5_XS_BC 0x02d8 /* 32 bit current transmit Byte Counter (xs) */ +#define B5_XS_CSR 0x02dc /* 32 bit BMU Control/Status Register (xs) */ +#define B5_XS_F 0x02e0 /* 32 bit flag register (xs) */ +#define B5_XS_T1 0x02e4 /* 32 bit Test Register 1 (xs) */ +#define B5_XS_T1_TR 0x02e4 /* 8 bit Test Register 1 TR (xs) */ +#define B5_XS_T1_WR 0x02e5 /* 8 bit Test Register 1 WR (xs) */ +#define B5_XS_T1_RD 0x02e6 /* 8 bit Test Register 1 RD (xs) */ +#define B5_XS_T1_SV 0x02e7 /* 8 bit Test Register 1 SV (xs) */ +#define B5_XS_T2 0x02e8 /* 32 bit Test Register 2 (xs) */ +#define B5_XS_T3 0x02ec /* 32 bit Test Register 3 (xs) */ +#define B5_XS_DA_H 0x02f0 /* (ML) 32 bit Curr Tx Desc Address High */ +#define B5_XS_AC_H 0x02f4 /* (ML) 32 bit Curr Addr Counter High dword */ + /* 0x02f8 - 0x02fc: reserved */ + +/* + * Bank 6 + */ +/* External PLC-S registers (SN2 compatibility for DV) */ +/* External registers (ML) */ +#define B6_EXT_REG 0x300 + +/* + * Bank 7 + */ +/* DAS PLC-S Registers */ + +/* + * Bank 8 - 15 + */ +/* IFCP registers */ + +/*---------------------------------------------------------------------------*/ +/* Definitions of the Bits in the registers */ + +/* B0_RAP 16 bit register address port */ +#define RAP_RAP 0x0f /* Bit 3..0: 0 = block0, .., f = block15 */ + +/* B0_CTRL 8 bit control register */ +#define CTRL_FDDI_CLR (1<<7) /* Bit 7: (ML) Clear FDDI Reset */ +#define CTRL_FDDI_SET (1<<6) /* Bit 6: (ML) Set FDDI Reset */ +#define CTRL_HPI_CLR (1<<5) /* Bit 5: Clear HPI SM reset */ +#define CTRL_HPI_SET (1<<4) /* Bit 4: Set HPI SM reset */ +#define CTRL_MRST_CLR (1<<3) /* Bit 3: Clear Master reset */ +#define CTRL_MRST_SET (1<<2) /* Bit 2: Set Master reset */ +#define CTRL_RST_CLR (1<<1) /* Bit 1: Clear Software reset */ +#define CTRL_RST_SET (1<<0) /* Bit 0: Set Software reset */ + +/* B0_DAS 8 Bit control register (DAS) */ +#define BUS_CLOCK (1<<7) /* Bit 7: (ML) Bus Clock 0/1 = 33/66MHz */ +#define BUS_SLOT_SZ (1<<6) /* Bit 6: (ML) Slot Size 0/1 = 32/64 bit slot*/ + /* Bit 5..4: reserved */ +#define DAS_AVAIL (1<<3) /* Bit 3: 1 = DAS, 0 = SAS */ +#define DAS_BYP_ST (1<<2) /* Bit 2: 1 = avail,SAS, 0 = not avail */ +#define DAS_BYP_INS (1<<1) /* Bit 1: 1 = insert Bypass */ +#define DAS_BYP_RMV (1<<0) /* Bit 0: 1 = remove Bypass */ + +/* B0_LED 8 Bit LED register */ + /* Bit 7..6: reserved */ +#define LED_2_ON (1<<5) /* Bit 5: 1 = switch LED_2 on (left,gn)*/ +#define LED_2_OFF (1<<4) /* Bit 4: 1 = switch LED_2 off */ +#define LED_1_ON (1<<3) /* Bit 3: 1 = switch LED_1 on (mid,yel)*/ +#define LED_1_OFF (1<<2) /* Bit 2: 1 = switch LED_1 off */ +#define LED_0_ON (1<<1) /* Bit 1: 1 = switch LED_0 on (rght,gn)*/ +#define LED_0_OFF (1<<0) /* Bit 0: 1 = switch LED_0 off */ +/* This hardware defines are very ugly therefore we define some others */ + +#define LED_GA_ON LED_2_ON /* S port = A port */ +#define LED_GA_OFF LED_2_OFF /* S port = A port */ +#define LED_MY_ON LED_1_ON +#define LED_MY_OFF LED_1_OFF +#define LED_GB_ON LED_0_ON +#define LED_GB_OFF LED_0_OFF + +/* B0_TST_CTRL 8 bit test control register */ +#define TST_FRC_DPERR_MR (1<<7) /* Bit 7: force DATAPERR on MST RE. */ +#define TST_FRC_DPERR_MW (1<<6) /* Bit 6: force DATAPERR on MST WR. */ +#define TST_FRC_DPERR_TR (1<<5) /* Bit 5: force DATAPERR on TRG RE. */ +#define TST_FRC_DPERR_TW (1<<4) /* Bit 4: force DATAPERR on TRG WR. */ +#define TST_FRC_APERR_M (1<<3) /* Bit 3: force ADDRPERR on MST */ +#define TST_FRC_APERR_T (1<<2) /* Bit 2: force ADDRPERR on TRG */ +#define TST_CFG_WRITE_ON (1<<1) /* Bit 1: ena configuration reg. WR */ +#define TST_CFG_WRITE_OFF (1<<0) /* Bit 0: dis configuration reg. WR */ + +/* B0_ISRC 32 bit Interrupt source register */ + /* Bit 31..28: reserved */ +#define IS_I2C_READY (1L<<27) /* Bit 27: (ML) IRQ on end of I2C tx */ +#define IS_IRQ_SW (1L<<26) /* Bit 26: (ML) SW forced IRQ */ +#define IS_EXT_REG (1L<<25) /* Bit 25: (ML) IRQ from external reg*/ +#define IS_IRQ_STAT (1L<<24) /* Bit 24: IRQ status execption */ + /* PERR, RMABORT, RTABORT DATAPERR */ +#define IS_IRQ_MST_ERR (1L<<23) /* Bit 23: IRQ master error */ + /* RMABORT, RTABORT, DATAPERR */ +#define IS_TIMINT (1L<<22) /* Bit 22: IRQ_TIMER */ +#define IS_TOKEN (1L<<21) /* Bit 21: IRQ_RTM */ +/* + * Note: The DAS is our First Port (!=PA) + */ +#define IS_PLINT1 (1L<<20) /* Bit 20: IRQ_PHY_DAS */ +#define IS_PLINT2 (1L<<19) /* Bit 19: IRQ_IFCP_4 */ +#define IS_MINTR3 (1L<<18) /* Bit 18: IRQ_IFCP_3/IRQ_PHY */ +#define IS_MINTR2 (1L<<17) /* Bit 17: IRQ_IFCP_2/IRQ_MAC_2 */ +#define IS_MINTR1 (1L<<16) /* Bit 16: IRQ_IFCP_1/IRQ_MAC_1 */ +/* Receive Queue 1 */ +#define IS_R1_P (1L<<15) /* Bit 15: Parity Error (q1) */ +#define IS_R1_B (1L<<14) /* Bit 14: End of Buffer (q1) */ +#define IS_R1_F (1L<<13) /* Bit 13: End of Frame (q1) */ +#define IS_R1_C (1L<<12) /* Bit 12: Encoding Error (q1) */ +/* Receive Queue 2 */ +#define IS_R2_P (1L<<11) /* Bit 11: (DV) Parity Error (q2) */ +#define IS_R2_B (1L<<10) /* Bit 10: (DV) End of Buffer (q2) */ +#define IS_R2_F (1L<<9) /* Bit 9: (DV) End of Frame (q2) */ +#define IS_R2_C (1L<<8) /* Bit 8: (DV) Encoding Error (q2) */ +/* Asynchronous Transmit queue */ + /* Bit 7: reserved */ +#define IS_XA_B (1L<<6) /* Bit 6: End of Buffer (xa) */ +#define IS_XA_F (1L<<5) /* Bit 5: End of Frame (xa) */ +#define IS_XA_C (1L<<4) /* Bit 4: Encoding Error (xa) */ +/* Synchronous Transmit queue */ + /* Bit 3: reserved */ +#define IS_XS_B (1L<<2) /* Bit 2: End of Buffer (xs) */ +#define IS_XS_F (1L<<1) /* Bit 1: End of Frame (xs) */ +#define IS_XS_C (1L<<0) /* Bit 0: Encoding Error (xs) */ + +/* + * Define all valid interrupt source Bits from GET_ISR () + */ +#define ALL_IRSR 0x01ffff77L /* (DV) */ +#define ALL_IRSR_ML 0x0ffff077L /* (ML) */ + + +/* B0_IMSK 32 bit Interrupt mask register */ +/* + * The Bit definnition of this register are the same as of the interrupt + * source register. These definition are directly derived from the Hardware + * spec. + */ + /* Bit 31..28: reserved */ +#define IRQ_I2C_READY (1L<<27) /* Bit 27: (ML) IRQ on end of I2C tx */ +#define IRQ_SW (1L<<26) /* Bit 26: (ML) SW forced IRQ */ +#define IRQ_EXT_REG (1L<<25) /* Bit 25: (ML) IRQ from external reg*/ +#define IRQ_STAT (1L<<24) /* Bit 24: IRQ status execption */ + /* PERR, RMABORT, RTABORT DATAPERR */ +#define IRQ_MST_ERR (1L<<23) /* Bit 23: IRQ master error */ + /* RMABORT, RTABORT, DATAPERR */ +#define IRQ_TIMER (1L<<22) /* Bit 22: IRQ_TIMER */ +#define IRQ_RTM (1L<<21) /* Bit 21: IRQ_RTM */ +#define IRQ_DAS (1L<<20) /* Bit 20: IRQ_PHY_DAS */ +#define IRQ_IFCP_4 (1L<<19) /* Bit 19: IRQ_IFCP_4 */ +#define IRQ_IFCP_3 (1L<<18) /* Bit 18: IRQ_IFCP_3/IRQ_PHY */ +#define IRQ_IFCP_2 (1L<<17) /* Bit 17: IRQ_IFCP_2/IRQ_MAC_2 */ +#define IRQ_IFCP_1 (1L<<16) /* Bit 16: IRQ_IFCP_1/IRQ_MAC_1 */ +/* Receive Queue 1 */ +#define IRQ_R1_P (1L<<15) /* Bit 15: Parity Error (q1) */ +#define IRQ_R1_B (1L<<14) /* Bit 14: End of Buffer (q1) */ +#define IRQ_R1_F (1L<<13) /* Bit 13: End of Frame (q1) */ +#define IRQ_R1_C (1L<<12) /* Bit 12: Encoding Error (q1) */ +/* Receive Queue 2 */ +#define IRQ_R2_P (1L<<11) /* Bit 11: (DV) Parity Error (q2) */ +#define IRQ_R2_B (1L<<10) /* Bit 10: (DV) End of Buffer (q2) */ +#define IRQ_R2_F (1L<<9) /* Bit 9: (DV) End of Frame (q2) */ +#define IRQ_R2_C (1L<<8) /* Bit 8: (DV) Encoding Error (q2) */ +/* Asynchronous Transmit queue */ + /* Bit 7: reserved */ +#define IRQ_XA_B (1L<<6) /* Bit 6: End of Buffer (xa) */ +#define IRQ_XA_F (1L<<5) /* Bit 5: End of Frame (xa) */ +#define IRQ_XA_C (1L<<4) /* Bit 4: Encoding Error (xa) */ +/* Synchronous Transmit queue */ + /* Bit 3: reserved */ +#define IRQ_XS_B (1L<<2) /* Bit 2: End of Buffer (xs) */ +#define IRQ_XS_F (1L<<1) /* Bit 1: End of Frame (xs) */ +#define IRQ_XS_C (1L<<0) /* Bit 0: Encoding Error (xs) */ + +/* 0x0010 - 0x006b: formac+ (supernet_3) fequently used registers */ +/* B0_R1_CSR 32 bit BMU control/status reg (rec q 1 ) */ +/* B0_R2_CSR 32 bit BMU control/status reg (rec q 2 ) */ +/* B0_XA_CSR 32 bit BMU control/status reg (a xmit q ) */ +/* B0_XS_CSR 32 bit BMU control/status reg (s xmit q ) */ +/* The registers are the same as B4_R1_CSR, B4_R2_CSR, B5_Xa_CSR, B5_XS_CSR */ + +/* B2_MAC_0 8 bit MAC address Byte 0 */ +/* B2_MAC_1 8 bit MAC address Byte 1 */ +/* B2_MAC_2 8 bit MAC address Byte 2 */ +/* B2_MAC_3 8 bit MAC address Byte 3 */ +/* B2_MAC_4 8 bit MAC address Byte 4 */ +/* B2_MAC_5 8 bit MAC address Byte 5 */ +/* B2_MAC_6 8 bit MAC address Byte 6 (== 0) (DV) */ +/* B2_MAC_7 8 bit MAC address Byte 7 (== 0) (DV) */ + +/* B2_CONN_TYP 8 bit Connector type */ +/* B2_PMD_TYP 8 bit PMD type */ +/* Values of connector and PMD type comply to SysKonnect internal std */ + +/* The EPROM register are currently of no use */ +/* B2_E_0 8 bit EPROM Byte 0 */ +/* B2_E_1 8 bit EPROM Byte 1 */ +/* B2_E_2 8 bit EPROM Byte 2 */ +/* B2_E_3 8 bit EPROM Byte 3 */ + +/* B2_FAR 32 bit Flash-Prom Address Register/Counter */ +#define FAR_ADDR 0x1ffffL /* Bit 16..0: FPROM Address mask */ + +/* B2_FDP 8 bit Flash-Prom Data Port */ + +/* B2_LD_CRTL 8 bit loader control */ +/* Bits are currently reserved */ + +/* B2_LD_TEST 8 bit loader test */ +#define LD_T_ON (1<<3) /* Bit 3: Loader Testmode on */ +#define LD_T_OFF (1<<2) /* Bit 2: Loader Testmode off */ +#define LD_T_STEP (1<<1) /* Bit 1: Decrement FPROM addr. Counter */ +#define LD_START (1<<0) /* Bit 0: Start loading FPROM */ + +/* B2_TI_INI 32 bit Timer init value */ +/* B2_TI_VAL 32 bit Timer value */ +/* B2_TI_CRTL 8 bit Timer control */ +/* B2_TI_TEST 8 Bit Timer Test */ +/* B2_WDOG_INI 32 bit Watchdog init value */ +/* B2_WDOG_VAL 32 bit Watchdog value */ +/* B2_WDOG_CRTL 8 bit Watchdog control */ +/* B2_WDOG_TEST 8 Bit Watchdog Test */ +/* B2_RTM_INI 32 bit RTM init value */ +/* B2_RTM_VAL 32 bit RTM value */ +/* B2_RTM_CRTL 8 bit RTM control */ +/* B2_RTM_TEST 8 Bit RTM Test */ +/* B2__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 -u --recursive --new-file v2.3.46/linux/drivers/net/skfp/h/skfbiinc.h linux/drivers/net/skfp/h/skfbiinc.h --- v2.3.46/linux/drivers/net/skfp/h/skfbiinc.h Wed Dec 31 16:00:00 1969 +++ linux/drivers/net/skfp/h/skfbiinc.h Fri Feb 18 14:55:53 2000 @@ -0,0 +1,123 @@ +/****************************************************************************** + * + * (C)Copyright 1998,1999 SysKonnect, + * a business unit of Schneider & Koch & Co. Datensysteme GmbH. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * The information in this file is provided "AS IS" without warranty. + * + ******************************************************************************/ + +#ifndef _SKFBIINC_ +#define _SKFBIINC_ + +#include "h/supern_2.h" + +/* + * special defines for use into .asm files + */ +#define ERR_FLAGS (FS_MSRABT | FS_SEAC2 | FS_SFRMERR | FS_SFRMTY1) + +#ifdef ISA +#define DMA_BUSY_CHECK CSRA +#define IMASK_FAST (IS_PLINT1 | IS_PLINT2 | IS_TIMINT) +#define HRQR (RQAA+(RQ_RRQ<<1)) +#define HRQW (RQAA+(RQ_WA2<<1)) +#define HRQA0 (RQAA+(RQ_WA0<<1)) +#define HRQSQ (RQAA+(RQ_WSQ<<1)) +#endif + +#ifdef EISA +#define DMA_BUSY_CHECK CSRA +#define DMA_HIGH_WORD 0x0400 +#define DMA_MASK_M 0x0a +#define DMA_MODE_M 0x0b +#define DMA_BYTE_PTR_M 0x0c +#define DMA_MASK_S 0x0d4 +#define DMA_MODE_S 0x0d6 +#define DMA_BYTE_PTR_S 0x0d8 +#define IMASK_FAST (IS_PLINT1 | IS_PLINT2 | IS_TIMINT | IS_TC) +#endif /* EISA */ + +#ifdef MCA +#define IMASK_FAST (IS_PLINT1 | IS_PLINT2 | IS_TIMINT | IS_TOKEN | \ + IS_CHCK_L | IS_BUSERR) +#endif + +#ifdef PCI +#define IMASK_FAST (IS_PLINT1 | IS_PLINT2 | IS_TIMINT | IS_TOKEN | \ + IS_MINTR2 | IS_MINTR3 | IS_R1_P | \ + IS_R1_C | IS_XA_C | IS_XS_C) +#endif + +#ifdef PCI +#define ISR_MASK (IS_MINTR1 | IS_R1_F | IS_XS_F| IS_XA_F | IMASK_FAST) +#else +#define ISR_MASK (IS_MINTR1 | IS_MINTR2 | IMASK_FAST) +#endif + +#define FMA_FM_CMDREG1 FMA(FM_CMDREG1) +#define FMA_FM_CMDREG2 FMA(FM_CMDREG2) +#define FMA_FM_STMCHN FMA(FM_STMCHN) +#define FMA_FM_RPR FMA(FM_RPR) +#define FMA_FM_WPXA0 FMA(FM_WPXA0) +#define FMA_FM_WPXA2 FMA(FM_WPXA2) +#define FMA_FM_MARR FMA(FM_MARR) +#define FMA_FM_MARW FMA(FM_MARW) +#define FMA_FM_MDRU FMA(FM_MDRU) +#define FMA_FM_MDRL FMA(FM_MDRL) +#define FMA_ST1L FMA(FM_ST1L) +#define FMA_ST1U FMA(FM_ST1U) +#define FMA_ST2L FMA(FM_ST2L) +#define FMA_ST2U FMA(FM_ST2U) +#ifdef SUPERNET_3 +#define FMA_ST3L FMA(FM_ST3L) +#define FMA_ST3U FMA(FM_ST3U) +#endif + +#define TMODE_RRQ RQ_RRQ +#define TMODE_WAQ2 RQ_WA2 +#define HSRA HSR(0) + + +#define FMA_FM_ST1L FMA_ST1L +#define FMA_FM_ST1U FMA_ST1U +#define FMA_FM_ST2L FMA_ST2L +#define FMA_FM_ST2U FMA_ST2U +#ifdef SUPERNET_3 +#define FMA_FM_ST3L FMA_ST3L +#define FMA_FM_ST3U FMA_ST3U +#endif + +#define FMA_FM_SWPR FMA(FM_SWPR) + +#define FMA_FM_RPXA0 FMA(FM_RPXA0) + +#define FMA_FM_RPXS FMA(FM_RPXS) +#define FMA_FM_WPXS FMA(FM_WPXS) + +#define FMA_FM_IMSK1U FMA(FM_IMSK1U) +#define FMA_FM_IMSK1L FMA(FM_IMSK1L) + +#define FMA_FM_EAS FMA(FM_EAS) +#define FMA_FM_EAA0 FMA(FM_EAA0) + +#define TMODE_WAQ0 RQ_WA0 +#define TMODE_WSQ RQ_WSQ + +/* Define default for DRV_PCM_STATE_CHANGE */ +#ifndef DRV_PCM_STATE_CHANGE +#define DRV_PCM_STATE_CHANGE(smc,plc,p_state) /* nothing */ +#endif + +/* Define default for DRV_RMT_INDICATION */ +#ifndef DRV_RMT_INDICATION +#define DRV_RMT_INDICATION(smc,i) /* nothing */ +#endif + +#endif /* n_SKFBIINC_ */ + diff -u --recursive --new-file v2.3.46/linux/drivers/net/skfp/h/smc.h linux/drivers/net/skfp/h/smc.h --- v2.3.46/linux/drivers/net/skfp/h/smc.h Wed Dec 31 16:00:00 1969 +++ linux/drivers/net/skfp/h/smc.h Fri Feb 18 14:55:53 2000 @@ -0,0 +1,471 @@ +/****************************************************************************** + * + * (C)Copyright 1998,1999 SysKonnect, + * a business unit of Schneider & Koch & Co. Datensysteme GmbH. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * The information in this file is provided "AS IS" without warranty. + * + ******************************************************************************/ + +#ifndef _SCMECM_ +#define _SCMECM_ + +#if defined(PCI) && !defined(OSDEF) +/* + * In the case of the PCI bus the file osdef1st.h must be present + */ +#define OSDEF +#endif + +#ifdef PCI +#ifndef SUPERNET_3 +#define SUPERNET_3 +#endif +#ifndef TAG_MODE +#define TAG_MODE +#endif +#endif + +/* + * include all other files in required order + * the following files must have been included before: + * types.h + * fddi.h + */ +#ifdef OSDEF +#include "h/osdef1st.h" +#endif /* OSDEF */ +#ifdef OEM_CONCEPT +#include "oemdef.h" +#endif /* OEM_CONCEPT */ +#include "h/smt.h" +#include "h/cmtdef.h" +#include "h/fddimib.h" +#include "h/targethw.h" /* all target hw dependencies */ +#include "h/targetos.h" /* all target os dependencies */ +#ifdef ESS +#include "h/sba.h" +#endif + +/* + * Event Queue + * queue.c + * events are class/value pairs + * class is addressee, e.g. RMT, PCM etc. + * value is command, e.g. line state change, ring op change etc. + */ +struct event_queue { + u_short class ; /* event class */ + u_short event ; /* event value */ +} ; + +/* + * define event queue as circular buffer + */ +#ifdef CONCENTRATOR +#define MAX_EVENT 128 +#else /* nCONCENTRATOR */ +#define MAX_EVENT 64 +#endif /* nCONCENTRATOR */ + +struct s_queue { + + struct event_queue ev_queue[MAX_EVENT]; + struct event_queue *ev_put ; + struct event_queue *ev_get ; +} ; + +/* + * ECM - Entity Coordination Management + * ecm.c + */ +struct s_ecm { + u_char path_test ; /* ECM path test variable */ + u_char sb_flag ; /* ECM stuck bypass */ + u_char DisconnectFlag ; /* jd 05-Aug-1999 Bug #10419 + * ECM disconnected */ + u_char ecm_line_state ; /* flag to dispatcher : line states */ + u_long trace_prop ; /* ECM Trace_Prop flag >= 16 bits !! */ + /* NUMPHYS note: + * this variable must have enough bits to hold all entiies in + * the station. So NUMPHYS may not be greater than 31. + */ + char ec_pad[2] ; + struct smt_timer ecm_timer ; /* timer */ +} ; + + +/* + * RMT - Ring Management + * rmt.c + */ +struct s_rmt { + u_char dup_addr_test ; /* state of dupl. addr. test */ + u_char da_flag ; /* flag : duplicate address det. */ + u_char loop_avail ; /* flag : MAC available for loopback */ + u_char sm_ma_avail ; /* flag : MAC available for SMT */ + u_char no_flag ; /* flag : ring not operational */ + u_char bn_flag ; /* flag : MAC reached beacon state */ + u_char jm_flag ; /* flag : jamming in NON_OP_DUP */ + u_char rm_join ; /* CFM flag RM_Join */ + u_char rm_loop ; /* CFM flag RM_Loop */ + + long fast_rm_join ; /* bit mask of active ports */ + /* + * timer and flags + */ + struct smt_timer rmt_timer0 ; /* timer 0 */ + struct smt_timer rmt_timer1 ; /* timer 1 */ + struct smt_timer rmt_timer2 ; /* timer 2 */ + u_char timer0_exp ; /* flag : timer 0 expired */ + u_char timer1_exp ; /* flag : timer 1 expired */ + u_char timer2_exp ; /* flag : timer 2 expired */ + + u_char rm_pad1[1] ; +} ; + +/* + * CFM - Configuration Management + * cfm.c + * used for SAS and DAS + */ +struct s_cfm { + u_char cf_state; /* CFM state machine current state */ + u_char cf_pad[3] ; +} ; + +/* + * CEM - Configuration Element Management + * cem.c + * used for Concentrator + */ +#ifdef CONCENTRATOR +struct s_cem { + int ce_state ; /* CEM state */ + int ce_port ; /* PA PB PM PM+1 .. */ + int ce_type ; /* TA TB TS TM */ +} ; + +/* + * linked list of CCEs in current token path + */ +struct s_c_ring { + struct s_c_ring *c_next ; + char c_entity ; +} ; + +struct mib_path_config { + u_long fddimibPATHConfigSMTIndex; + u_long fddimibPATHConfigPATHIndex; + u_long fddimibPATHConfigTokenOrder; + u_long fddimibPATHConfigResourceType; +#define SNMP_RES_TYPE_MAC 2 /* Resource is a MAC */ +#define SNMP_RES_TYPE_PORT 4 /* Resource is a PORT */ + u_long fddimibPATHConfigResourceIndex; + u_long fddimibPATHConfigCurrentPath; +#define SNMP_PATH_ISOLATED 1 /* Current path is isolated */ +#define SNMP_PATH_LOCAL 2 /* Current path is local */ +#define SNMP_PATH_SECONDARY 3 /* Current path is secondary */ +#define SNMP_PATH_PRIMARY 4 /* Current path is primary */ +#define SNMP_PATH_CONCATENATED 5 /* Current path is concatenated */ +#define SNMP_PATH_THRU 6 /* Current path is thru */ +}; + + +#endif + +/* + * PCM connect states + */ +#define PCM_DISABLED 0 +#define PCM_CONNECTING 1 +#define PCM_STANDBY 2 +#define PCM_ACTIVE 3 + +struct s_pcm { + u_char pcm_pad[3] ; +} ; + +/* + * PHY struct + * one per physical port + */ +struct s_phy { + /* Inter Module Globals */ + struct fddi_mib_p *mib ; + + u_char np ; /* index 0 .. NUMPHYS */ + u_char cf_join ; + u_char cf_loop ; + u_char wc_flag ; /* withhold connection flag */ + u_char pc_mode ; /* Holds the negotiated mode of the PCM */ + u_char pc_lem_fail ; /* flag : LCT failed */ + u_char lc_test ; + u_char scrub ; /* CFM flag Scrub -> PCM */ + char phy_name ; + u_char pmd_type[2] ; /* SK connector/transceiver type codes */ +#define PMD_SK_CONN 0 /* pmd_type[PMD_SK_CONN] = Connector */ +#define PMD_SK_PMD 1 /* pmd_type[PMD_SK_PMD] = Xver */ + u_char pmd_scramble ; /* scrambler on/off */ + + /* inner Module Globals */ + u_char curr_ls ; /* current line state */ + u_char ls_flag ; + u_char rc_flag ; + u_char tc_flag ; + u_char td_flag ; + u_char bitn ; + u_char tr_flag ; /* trace recvd while in active */ + u_char twisted ; /* flag to indicate an A-A or B-B connection */ + u_char t_val[NUMBITS] ; /* transmit bits for signaling */ + u_char r_val[NUMBITS] ; /* receive bits for signaling */ + u_long t_next[NUMBITS] ; + struct smt_timer pcm_timer0 ; + struct smt_timer pcm_timer1 ; + struct smt_timer pcm_timer2 ; + u_char timer0_exp ; + u_char timer1_exp ; + u_char timer2_exp ; + u_char pcm_pad1[1] ; + int cem_pst ; /* CEM privae state; used for dual homing */ + struct lem_counter lem ; +#ifdef AMDPLC + struct s_plc plc ; +#endif +} ; + +/* + * timer package + * smttimer.c + */ +struct s_timer { + struct smt_timer *st_queue ; + struct smt_timer st_fast ; +} ; + +/* + * SRF types and data + */ +#define SMT_EVENT_BASE 1 +#define SMT_EVENT_MAC_PATH_CHANGE (SMT_EVENT_BASE+0) +#define SMT_EVENT_MAC_NEIGHBOR_CHANGE (SMT_EVENT_BASE+1) +#define SMT_EVENT_PORT_PATH_CHANGE (SMT_EVENT_BASE+2) +#define SMT_EVENT_PORT_CONNECTION (SMT_EVENT_BASE+3) + +#define SMT_IS_CONDITION(x) ((x)>=SMT_COND_BASE) + +#define SMT_COND_BASE (SMT_EVENT_PORT_CONNECTION+1) +#define SMT_COND_SMT_PEER_WRAP (SMT_COND_BASE+0) +#define SMT_COND_SMT_HOLD (SMT_COND_BASE+1) +#define SMT_COND_MAC_FRAME_ERROR (SMT_COND_BASE+2) +#define SMT_COND_MAC_DUP_ADDR (SMT_COND_BASE+3) +#define SMT_COND_MAC_NOT_COPIED (SMT_COND_BASE+4) +#define SMT_COND_PORT_EB_ERROR (SMT_COND_BASE+5) +#define SMT_COND_PORT_LER (SMT_COND_BASE+6) + +#define SR0_WAIT 0 +#define SR1_HOLDOFF 1 +#define SR2_DISABLED 2 + +struct s_srf { + u_long SRThreshold ; /* threshold value */ + u_char RT_Flag ; /* report transmitted flag */ + u_char sr_state ; /* state-machine */ + u_char any_report ; /* any report required */ + u_long TSR ; /* timer */ + u_short ring_status ; /* IBM ring status */ +} ; + +/* + * IBM token ring status + */ +#define RS_RES15 (1<<15) /* reserved */ +#define RS_HARDERROR (1<<14) /* ring down */ +#define RS_SOFTERROR (1<<13) /* sent SRF */ +#define RS_BEACON (1<<12) /* transmitted beacon */ +#define RS_PATHTEST (1<<11) /* path test failed */ +#define RS_SELFTEST (1<<10) /* selftest required */ +#define RS_RES9 (1<< 9) /* reserved */ +#define RS_DISCONNECT (1<< 8) /* remote disconnect */ +#define RS_RES7 (1<< 7) /* reserved */ +#define RS_DUPADDR (1<< 6) /* duplicate address */ +#define RS_NORINGOP (1<< 5) /* no ring op */ +#define RS_VERSION (1<< 4) /* SMT version mismatch */ +#define RS_STUCKBYPASSS (1<< 3) /* stuck bypass */ +#define RS_EVENT (1<< 2) /* FDDI event occured */ +#define RS_RINGOPCHANGE (1<< 1) /* ring op changed */ +#define RS_RES0 (1<< 0) /* reserved */ + +#define RS_SET(smc,bit) \ + ring_status_indication(smc,smc->srf.ring_status |= bit) +#define RS_CLEAR(smc,bit) \ + ring_status_indication(smc,smc->srf.ring_status &= ~bit) + +#define RS_CLEAR_EVENT (0xffff & ~(RS_NORINGOP)) + +/* Define the AIX-event-Notification as null function if it isn't defined */ +/* in the targetos.h file */ +#ifndef AIX_EVENT +#define AIX_EVENT(smc,opt0,opt1,opt2,opt3) /* nothing */ +#endif + +struct s_srf_evc { + u_char evc_code ; /* event code type */ + u_char evc_index ; /* index for mult. instances */ + u_char evc_rep_required ; /* report required */ + u_short evc_para ; /* SMT Para Number */ + u_char *evc_cond_state ; /* condition state */ + u_char *evc_multiple ; /* multiple occurence */ +} ; + +/* + * Values used by frame based services + * smt.c + */ +#define SMT_MAX_TEST 5 +#define SMT_TID_NIF 0 /* pending NIF request */ +#define SMT_TID_NIF_TEST 1 /* pending NIF test */ +#define SMT_TID_ECF_UNA 2 /* pending ECF UNA test */ +#define SMT_TID_ECF_DNA 3 /* pending ECF DNA test */ +#define SMT_TID_ECF 4 /* pending ECF test */ + +struct smt_values { + u_long smt_tvu ; /* timer valid una */ + u_long smt_tvd ; /* timer valid dna */ + u_long smt_tid ; /* transaction id */ + u_long pend[SMT_MAX_TEST] ; /* TID of requests */ + u_long uniq_time ; /* unique time stamp */ + u_short uniq_ticks ; /* unique time stamp */ + u_short please_reconnect ; /* flag : reconnect */ + u_long smt_last_lem ; + u_long smt_last_notify ; + struct smt_timer smt_timer ; /* SMT NIF timer */ + u_long last_tok_time[NUMMACS]; /* token cnt emulation */ +} ; + +/* + * SMT/CMT configurable parameters + */ +#define SMT_DAS 0 /* dual attach */ +#define SMT_SAS 1 /* single attach */ +#define SMT_NAC 2 /* null attach concentrator */ + +struct smt_config { + u_char attach_s ; /* CFM attach to secondary path */ + u_char sas ; /* SMT_DAS/SAS/NAC */ + u_char build_ring_map ; /* build ringmap if TRUE */ + u_char numphys ; /* number of active phys */ + u_char sc_pad[1] ; + + u_long pcm_tb_min ; /* PCM : TB_Min timer value */ + u_long pcm_tb_max ; /* PCM : TB_Max timer value */ + u_long pcm_c_min ; /* PCM : C_Min timer value */ + u_long pcm_t_out ; /* PCM : T_Out timer value */ + u_long pcm_tl_min ; /* PCM : TL_min timer value */ + u_long pcm_lc_short ; /* PCM : LC_Short timer value */ + u_long pcm_lc_medium ; /* PCM : LC_Medium timer value */ + u_long pcm_lc_long ; /* PCM : LC_Long timer value */ + u_long pcm_lc_extended ; /* PCM : LC_Extended timer value */ + u_long pcm_t_next_9 ; /* PCM : T_Next[9] timer value */ + u_long pcm_ns_max ; /* PCM : NS_Max timer value */ + + u_long ecm_i_max ; /* ECM : I_Max timer value */ + u_long ecm_in_max ; /* ECM : IN_Max timer value */ + u_long ecm_td_min ; /* ECM : TD_Min timer */ + u_long ecm_test_done ; /* ECM : path test done timer */ + u_long ecm_check_poll ; /* ECM : check bypass poller */ + + u_long rmt_t_non_op ; /* RMT : T_Non_OP timer value */ + u_long rmt_t_stuck ; /* RMT : T_Stuck timer value */ + u_long rmt_t_direct ; /* RMT : T_Direct timer value */ + u_long rmt_t_jam ; /* RMT : T_Jam timer value */ + u_long rmt_t_announce ; /* RMT : T_Announce timer value */ + u_long rmt_t_poll ; /* RMT : claim/beacon poller */ + u_long rmt_dup_mac_behavior ; /* Flag for the beavior of SMT if + * a Duplicate MAC Address was detected. + * FALSE: SMT will leave finaly the ring + * TRUE: SMT will reinstert into the ring + */ + u_long mac_d_max ; /* MAC : D_Max timer value */ + + u_long lct_short ; /* LCT : error threshhold */ + u_long lct_medium ; /* LCT : error threshhold */ + u_long lct_long ; /* LCT : error threshhold */ + u_long lct_extended ; /* LCT : error threshhold */ +} ; + +#ifdef DEBUG +/* + * Debugging struct sometimes used in smc + */ +struct smt_debug { + int d_smtf ; + int d_smt ; + int d_ecm ; + int d_rmt ; + int d_cfm ; + int d_pcm ; + int d_plc ; +#ifdef ESS + int d_ess ; +#endif +#ifdef SBA + int d_sba ; +#endif + struct os_debug d_os; /* Include specific OS DEBUG struct */ +} ; + +#ifndef DEBUG_BRD +/* all boards shall be debugged with one debug struct */ +extern struct smt_debug debug; /* Declaration of debug struct */ +#endif /* DEBUG_BRD */ + +#endif /* DEBUG */ + +/* + * the SMT Context Struct SMC + * this struct contains ALL global variables of SMT + */ +struct s_smc { + struct s_smt_os os ; /* os specific */ + struct s_smt_hw hw ; /* hardware */ + +/* + * NOTE: os and hw MUST BE the first two structs + * anything beyond hw WILL BE SET TO ZERO in smt_set_defaults() + */ + struct smt_config s ; /* smt constants */ + struct smt_values sm ; /* smt variables */ + struct s_ecm e ; /* ecm */ + struct s_rmt r ; /* rmt */ + struct s_cfm cf ; /* cfm/cem */ +#ifdef CONCENTRATOR + struct s_cem ce[NUMPHYS] ; /* cem */ + struct s_c_ring cr[NUMPHYS+NUMMACS] ; +#endif + struct s_pcm p ; /* pcm */ + struct s_phy y[NUMPHYS] ; /* phy */ + struct s_queue q ; /* queue */ + struct s_timer t ; /* timer */ + struct s_srf srf ; /* SRF */ + struct s_srf_evc evcs[6+NUMPHYS*4] ; + struct fddi_mib mib ; /* __THE_MIB__ */ +#ifdef SBA + struct s_sba sba ; /* SBA variables */ +#endif +#ifdef ESS + struct s_ess ess ; /* Ess variables */ +#endif +#if defined(DEBUG) && defined(DEBUG_BRD) + /* If you want all single board to be debugged separately */ + struct smt_debug debug; /* Declaration of debug struct */ +#endif /* DEBUG_BRD && DEBUG */ +} ; + +#endif /* _SCMECM_ */ + diff -u --recursive --new-file v2.3.46/linux/drivers/net/skfp/h/smt.h linux/drivers/net/skfp/h/smt.h --- v2.3.46/linux/drivers/net/skfp/h/smt.h Wed Dec 31 16:00:00 1969 +++ linux/drivers/net/skfp/h/smt.h Fri Feb 18 14:55:53 2000 @@ -0,0 +1,882 @@ +/****************************************************************************** + * + * (C)Copyright 1998,1999 SysKonnect, + * a business unit of Schneider & Koch & Co. Datensysteme GmbH. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * The information in this file is provided "AS IS" without warranty. + * + ******************************************************************************/ + +/* + * SMT 7.2 frame definitions + */ + +#ifndef _SMT_ +#define _SMT_ + +/* #define SMT5_10 */ +#define SMT6_10 +#define SMT7_20 + +#define OPT_PMF /* if parameter management is supported */ +#define OPT_SRF /* if status report is supported */ + +/* + * SMT frame version 5.1 + */ + +#define SMT_VID 0x0001 /* V 5.1 .. 6.1 */ +#define SMT_VID_2 0x0002 /* V 7.2 */ + +struct smt_sid { + u_char sid_oem[2] ; /* implementation spec. */ + struct fddi_addr sid_node ; /* node address */ +} ; + +typedef u_char t_station_id[8] ; + +/* + * note on alignment : + * sizeof(struct smt_header) = 32 + * all parameters are long aligned + * if struct smt_header starts at offset 0, all longs are aligned correctly + * (FC starts at offset 3) + */ +_packed struct smt_header { + struct fddi_addr smt_dest ; /* destination address */ + struct fddi_addr smt_source ; /* source address */ + u_char smt_class ; /* NIF, SIF ... */ + u_char smt_type ; /* req., response .. */ + u_short smt_version ; /* version id */ + u_long smt_tid ; /* transaction ID */ + struct smt_sid smt_sid ; /* station ID */ + u_short smt_pad ; /* pad with 0 */ + u_short smt_len ; /* length of info field */ +} ; +#define SWAP_SMTHEADER "662sl8ss" + +#if 0 +/* + * MAC FC values + */ +#define FC_SMT_INFO 0x41 /* SMT info */ +#define FC_SMT_NSA 0x4f /* SMT Next Station Addressing */ +#endif + + +/* + * type codes + */ +#define SMT_ANNOUNCE 0x01 /* announcement */ +#define SMT_REQUEST 0x02 /* request */ +#define SMT_REPLY 0x03 /* reply */ + +/* + * class codes + */ +#define SMT_NIF 0x01 /* neighbor information frames */ +#define SMT_SIF_CONFIG 0x02 /* station information configuration */ +#define SMT_SIF_OPER 0x03 /* station information operation */ +#define SMT_ECF 0x04 /* echo frames */ +#define SMT_RAF 0x05 /* resource allocation */ +#define SMT_RDF 0x06 /* request denied */ +#define SMT_SRF 0x07 /* status report */ +#define SMT_PMF_GET 0x08 /* parameter management get */ +#define SMT_PMF_SET 0x09 /* parameter management set */ +#define SMT_ESF 0xff /* extended service */ + +#define SMT_MAX_ECHO_LEN 4458 /* max length of SMT Echo */ +#if defined(CONC) || defined(CONC_II) +#define SMT_TEST_ECHO_LEN 50 /* test length of SMT Echo */ +#else +#define SMT_TEST_ECHO_LEN SMT_MAX_ECHO_LEN /* test length */ +#endif + +#define SMT_MAX_INFO_LEN (4352-20) /* max length for SMT info */ + + +/* + * parameter types + */ + +struct smt_para { + u_short p_type ; /* type */ + u_short p_len ; /* length of parameter */ +} ; + +#define PARA_LEN (sizeof(struct smt_para)) + +#define SMTSETPARA(p,t) (p)->para.p_type = (t),\ + (p)->para.p_len = sizeof(*(p)) - PARA_LEN + +/* + * P01 : Upstream Neighbor Address, UNA + */ +#define SMT_P_UNA 0x0001 /* upstream neighbor address */ +#define SWAP_SMT_P_UNA "s6" + +struct smt_p_una { + struct smt_para para ; /* generic parameter header */ + u_short una_pad ; + struct fddi_addr una_node ; /* node address, zero if unknown */ +} ; + +/* + * P02 : Station Descriptor + */ +#define SMT_P_SDE 0x0002 /* station descriptor */ +#define SWAP_SMT_P_SDE "1111" + +#define SMT_SDE_STATION 0 /* end node */ +#define SMT_SDE_CONCENTRATOR 1 /* concentrator */ + +struct smt_p_sde { + struct smt_para para ; /* generic parameter header */ + u_char sde_type ; /* station type */ + u_char sde_mac_count ; /* number of MACs */ + u_char sde_non_master ; /* number of A,B or S ports */ + u_char sde_master ; /* number of S ports on conc. */ +} ; + +/* + * P03 : Station State + */ +#define SMT_P_STATE 0x0003 /* station state */ +#define SWAP_SMT_P_STATE "scc" + +struct smt_p_state { + struct smt_para para ; /* generic parameter header */ + u_short st_pad ; + u_char st_topology ; /* topology */ + u_char st_dupl_addr ; /* duplicate address detected */ +} ; +#define SMT_ST_WRAPPED (1<<0) /* station wrapped */ +#define SMT_ST_UNATTACHED (1<<1) /* unattached concentrator */ +#define SMT_ST_TWISTED_A (1<<2) /* A-A connection, twisted ring */ +#define SMT_ST_TWISTED_B (1<<3) /* B-B connection, twisted ring */ +#define SMT_ST_ROOTED_S (1<<4) /* rooted station */ +#define SMT_ST_SRF (1<<5) /* SRF protocol supported */ +#define SMT_ST_SYNC_SERVICE (1<<6) /* use synchronous bandwidth */ + +#define SMT_ST_MY_DUPA (1<<0) /* my station detected dupl. */ +#define SMT_ST_UNA_DUPA (1<<1) /* my UNA detected duplicate */ + +/* + * P04 : timestamp + */ +#define SMT_P_TIMESTAMP 0x0004 /* time stamp */ +#define SWAP_SMT_P_TIMESTAMP "8" +struct smt_p_timestamp { + struct smt_para para ; /* generic parameter header */ + u_char ts_time[8] ; /* time, resolution 80nS, unique */ +} ; + +/* + * P05 : station policies + */ +#define SMT_P_POLICY 0x0005 /* station policies */ +#define SWAP_SMT_P_POLICY "ss" + +struct smt_p_policy { + struct smt_para para ; /* generic parameter header */ + u_short pl_config ; + u_short pl_connect ; /* bit string POLICY_AA ... */ +} ; +#define SMT_PL_HOLD 1 /* hold policy supported (Dual MAC) */ + +/* + * P06 : latency equivalent + */ +#define SMT_P_LATENCY 0x0006 /* latency */ +#define SWAP_SMT_P_LATENCY "ssss" + +/* + * note: latency has two phy entries by definition + * for a SAS, the 2nd one is null + */ +struct smt_p_latency { + struct smt_para para ; /* generic parameter header */ + u_short lt_phyout_idx1 ; /* index */ + u_short lt_latency1 ; /* latency , unit : byte clock */ + u_short lt_phyout_idx2 ; /* 0 if SAS */ + u_short lt_latency2 ; /* 0 if SAS */ +} ; + +/* + * P07 : MAC neighbors + */ +#define SMT_P_NEIGHBORS 0x0007 /* MAC neighbor description */ +#define SWAP_SMT_P_NEIGHBORS "ss66" + +struct smt_p_neighbor { + struct smt_para para ; /* generic parameter header */ + u_short nb_mib_index ; /* MIB index */ + u_short nb_mac_index ; /* n+1 .. n+m, m = #MACs, n = #PHYs */ + struct fddi_addr nb_una ; /* UNA , 0 for unknown */ + struct fddi_addr nb_dna ; /* DNA , 0 for unknown */ +} ; + +/* + * PHY record + */ +#define SMT_PHY_A 0 /* A port */ +#define SMT_PHY_B 1 /* B port */ +#define SMT_PHY_S 2 /* slave port */ +#define SMT_PHY_M 3 /* master port */ + +#define SMT_CS_DISABLED 0 /* connect state : disabled */ +#define SMT_CS_CONNECTING 1 /* connect state : connecting */ +#define SMT_CS_STANDBY 2 /* connect state : stand by */ +#define SMT_CS_ACTIVE 3 /* connect state : active */ + +#define SMT_RM_NONE 0 +#define SMT_RM_MAC 1 + +struct smt_phy_rec { + u_short phy_mib_index ; /* MIB index */ + u_char phy_type ; /* A/B/S/M */ + u_char phy_connect_state ; /* disabled/connecting/active */ + u_char phy_remote_type ; /* A/B/S/M */ + u_char phy_remote_mac ; /* none/remote */ + u_short phy_resource_idx ; /* 1 .. n */ +} ; + +/* + * MAC record + */ +struct smt_mac_rec { + struct fddi_addr mac_addr ; /* MAC address */ + u_short mac_resource_idx ; /* n+1 .. n+m */ +} ; + +/* + * P08 : path descriptors + * should be really an array ; however our environment has a fixed number of + * PHYs and MACs + */ +#define SMT_P_PATH 0x0008 /* path descriptor */ +#define SWAP_SMT_P_PATH "[6s]" + +struct smt_p_path { + struct smt_para para ; /* generic parameter header */ + struct smt_phy_rec pd_phy[2] ; /* PHY A */ + struct smt_mac_rec pd_mac ; /* MAC record */ +} ; + +/* + * P09 : MAC status + */ +#define SMT_P_MAC_STATUS 0x0009 /* MAC status */ +#define SWAP_SMT_P_MAC_STATUS "sslllllllll" + +struct smt_p_mac_status { + struct smt_para para ; /* generic parameter header */ + u_short st_mib_index ; /* MIB index */ + u_short st_mac_index ; /* n+1 .. n+m */ + u_long st_t_req ; /* T_Req */ + u_long st_t_neg ; /* T_Neg */ + u_long st_t_max ; /* T_Max */ + u_long st_tvx_value ; /* TVX_Value */ + u_long st_t_min ; /* T_Min */ + u_long st_sba ; /* synchr. bandwidth alloc */ + u_long st_frame_ct ; /* frame counter */ + u_long st_error_ct ; /* error counter */ + u_long st_lost_ct ; /* lost frames counter */ +} ; + +/* + * P0A : PHY link error rate monitoring + */ +#define SMT_P_LEM 0x000a /* link error monitor */ +#define SWAP_SMT_P_LEM "ssccccll" +/* + * units of lem_cutoff,lem_alarm,lem_estimate : 10**-x + */ +struct smt_p_lem { + struct smt_para para ; /* generic parameter header */ + u_short lem_mib_index ; /* MIB index */ + u_short lem_phy_index ; /* 1 .. n */ + u_char lem_pad2 ; /* be nice and make it even . */ + u_char lem_cutoff ; /* 0x4 .. 0xf, default 0x7 */ + u_char lem_alarm ; /* 0x4 .. 0xf, default 0x8 */ + u_char lem_estimate ; /* 0x0 .. 0xff */ + u_long lem_reject_ct ; /* 0x00000000 .. 0xffffffff */ + u_long lem_ct ; /* 0x00000000 .. 0xffffffff */ +} ; + +/* + * P0B : MAC frame counters + */ +#define SMT_P_MAC_COUNTER 0x000b /* MAC frame counters */ +#define SWAP_SMT_P_MAC_COUNTER "ssll" + +struct smt_p_mac_counter { + struct smt_para para ; /* generic parameter header */ + u_short mc_mib_index ; /* MIB index */ + u_short mc_index ; /* mac index */ + u_long mc_receive_ct ; /* receive counter */ + u_long mc_transmit_ct ; /* transmit counter */ +} ; + +/* + * P0C : MAC frame not copied counter + */ +#define SMT_P_MAC_FNC 0x000c /* MAC frame not copied counter */ +#define SWAP_SMT_P_MAC_FNC "ssl" + +struct smt_p_mac_fnc { + struct smt_para para ; /* generic parameter header */ + u_short nc_mib_index ; /* MIB index */ + u_short nc_index ; /* mac index */ + u_long nc_counter ; /* not copied counter */ +} ; + + +/* + * P0D : MAC priority values + */ +#define SMT_P_PRIORITY 0x000d /* MAC priority values */ +#define SWAP_SMT_P_PRIORITY "ssl" + +struct smt_p_priority { + struct smt_para para ; /* generic parameter header */ + u_short pr_mib_index ; /* MIB index */ + u_short pr_index ; /* mac index */ + u_long pr_priority[7] ; /* priority values */ +} ; + +/* + * P0E : PHY elasticity buffer status + */ +#define SMT_P_EB 0x000e /* PHY EB status */ +#define SWAP_SMT_P_EB "ssl" + +struct smt_p_eb { + struct smt_para para ; /* generic parameter header */ + u_short eb_mib_index ; /* MIB index */ + u_short eb_index ; /* phy index */ + u_long eb_error_ct ; /* # of eb overflows */ +} ; + +/* + * P0F : manufacturer field + */ +#define SMT_P_MANUFACTURER 0x000f /* manufacturer field */ +#define SWAP_SMT_P_MANUFACTURER "" + +struct smp_p_manufacturer { + struct smt_para para ; /* generic parameter header */ + u_char mf_data[32] ; /* OUI + arbitrary data */ +} ; + +/* + * P10 : user field + */ +#define SMT_P_USER 0x0010 /* manufacturer field */ +#define SWAP_SMT_P_USER "" + +struct smp_p_user { + struct smt_para para ; /* generic parameter header */ + u_char us_data[32] ; /* arbitrary data */ +} ; + + + +/* + * P11 : echo data + */ +#define SMT_P_ECHODATA 0x0011 /* echo data */ +#define SWAP_SMT_P_ECHODATA "" + +struct smt_p_echo { + struct smt_para para ; /* generic parameter header */ + u_char ec_data[SMT_MAX_ECHO_LEN-4] ; /* echo data */ +} ; + +/* + * P12 : reason code + */ +#define SMT_P_REASON 0x0012 /* reason code */ +#define SWAP_SMT_P_REASON "l" + +struct smt_p_reason { + struct smt_para para ; /* generic parameter header */ + u_long rdf_reason ; /* CLASS/VERSION */ +} ; +#define SMT_RDF_CLASS 0x00000001 /* class not supported */ +#define SMT_RDF_VERSION 0x00000002 /* version not supported */ +#define SMT_RDF_SUCCESS 0x00000003 /* success (PMF) */ +#define SMT_RDF_BADSET 0x00000004 /* bad set count (PMF) */ +#define SMT_RDF_ILLEGAL 0x00000005 /* read only (PMF) */ +#define SMT_RDF_NOPARAM 0x6 /* paramter not supported (PMF) */ +#define SMT_RDF_RANGE 0x8 /* out of range */ +#define SMT_RDF_AUTHOR 0x9 /* not autohorized */ +#define SMT_RDF_LENGTH 0x0a /* length error */ +#define SMT_RDF_TOOLONG 0x0b /* length error */ +#define SMT_RDF_SBA 0x0d /* SBA denied */ + +/* + * P13 : refused frame beginning + */ +#define SMT_P_REFUSED 0x0013 /* refused frame beginning */ +#define SWAP_SMT_P_REFUSED "l" + +struct smt_p_refused { + struct smt_para para ; /* generic parameter header */ + u_long ref_fc ; /* 3 bytes 0 + FC */ + struct smt_header ref_header ; /* refused header */ +} ; + +/* + * P14 : supported SMT versions + */ +#define SMT_P_VERSION 0x0014 /* SMT supported versions */ +#define SWAP_SMT_P_VERSION "sccss" + +struct smt_p_version { + struct smt_para para ; /* generic parameter header */ + u_short v_pad ; + u_char v_n ; /* 1 .. 0xff, #versions */ + u_char v_index ; /* 1 .. 0xff, index of op. v. */ + u_short v_version[1] ; /* list of min. 1 version */ + u_short v_pad2 ; /* pad if necessary */ +} ; + +/* + * P15 : Resource Type + */ +#define SWAP_SMT_P0015 "l" + +struct smt_p_0015 { + struct smt_para para ; /* generic parameter header */ + u_long res_type ; /* recsource type */ +} ; + +#define SYNC_BW 0x00000001L /* Synchronous Bandwidth */ + +/* + * P16 : SBA Command + */ +#define SWAP_SMT_P0016 "l" + +struct smt_p_0016 { + struct smt_para para ; /* generic parameter header */ + u_long sba_cmd ; /* command for the SBA */ +} ; + +#define REQUEST_ALLOCATION 0x1 /* req allocation of sync bandwidth */ +#define REPORT_ALLOCATION 0x2 /* rep of sync bandwidth allocation */ +#define CHANGE_ALLOCATION 0x3 /* forces a station using sync band-*/ + /* width to change its current allo-*/ + /* cation */ + +/* + * P17 : SBA Payload Request + */ +#define SWAP_SMT_P0017 "l" + +struct smt_p_0017 { + struct smt_para para ; /* generic parameter header */ + long sba_pl_req ; /* total sync bandwidth measured in */ +} ; /* bytes per 125 us */ + +/* + * P18 : SBA Overhead Request + */ +#define SWAP_SMT_P0018 "l" + +struct smt_p_0018 { + struct smt_para para ; /* generic parameter header */ + long sba_ov_req ; /* total sync bandwidth req for overhead*/ +} ; /* measuered in bytes per T_Neg */ + +/* + * P19 : SBA Allocation Address + */ +#define SWAP_SMT_P0019 "s6" + +struct smt_p_0019 { + struct smt_para para ; /* generic parameter header */ + u_short sba_pad ; + struct fddi_addr alloc_addr ; /* Allocation Address */ +} ; + +/* + * P1A : SBA Category + */ +#define SWAP_SMT_P001A "l" + +struct smt_p_001a { + struct smt_para para ; /* generic parameter header */ + u_long category ; /* Allocator defined classification */ +} ; + +/* + * P1B : Maximum T_Neg + */ +#define SWAP_SMT_P001B "l" + +struct smt_p_001b { + struct smt_para para ; /* generic parameter header */ + u_long max_t_neg ; /* longest T_NEG for the sync service*/ +} ; + +/* + * P1C : Minimum SBA Segment Size + */ +#define SWAP_SMT_P001C "l" + +struct smt_p_001c { + struct smt_para para ; /* generic parameter header */ + u_long min_seg_siz ; /* smallest number of bytes per frame*/ +} ; + +/* + * P1D : SBA Allocatable + */ +#define SWAP_SMT_P001D "l" + +struct smt_p_001d { + struct smt_para para ; /* generic parameter header */ + u_long allocatable ; /* total sync bw availabel for alloc */ +} ; + +/* + * P20 0B : frame status capabilities + * NOTE: not in swap table, is used by smt.c AND PMF table + */ +#define SMT_P_FSC 0x200b +/* #define SWAP_SMT_P_FSC "ssss" */ + +struct smt_p_fsc { + struct smt_para para ; /* generic parameter header */ + u_short fsc_pad0 ; + u_short fsc_mac_index ; /* mac index 1 .. ff */ + u_short fsc_pad1 ; + u_short fsc_value ; /* FSC_TYPE[0-2] */ +} ; + +#define FSC_TYPE0 0 /* "normal" node (A/C handling) */ +#define FSC_TYPE1 1 /* Special A/C indicator forwarding */ +#define FSC_TYPE2 2 /* Special A/C indicator forwarding */ + +/* + * P00 21 : user defined authoriziation (see pmf.c) + */ +#define SMT_P_AUTHOR 0x0021 + +/* + * notification parameters + */ +#define SWAP_SMT_P1048 "ll" +struct smt_p_1048 { + u_long p1048_flag ; + u_long p1048_cf_state ; +} ; + +/* + * NOTE: all 2xxx 3xxx and 4xxx must include the INDEX in the swap string, + * even so the INDEX is NOT part of the struct. + * INDEX is already swapped in pmf.c, format in string is '4' + */ +#define SWAP_SMT_P208C "4lss66" +struct smt_p_208c { + u_long p208c_flag ; + u_short p208c_pad ; + u_short p208c_dupcondition ; + struct fddi_addr p208c_fddilong ; + struct fddi_addr p208c_fddiunalong ; +} ; + +#define SWAP_SMT_P208D "4lllll" +struct smt_p_208d { + u_long p208d_flag ; + u_long p208d_frame_ct ; + u_long p208d_error_ct ; + u_long p208d_lost_ct ; + u_long p208d_ratio ; +} ; + +#define SWAP_SMT_P208E "4llll" +struct smt_p_208e { + u_long p208e_flag ; + u_long p208e_not_copied ; + u_long p208e_copied ; + u_long p208e_not_copied_ratio ; +} ; + +#define SWAP_SMT_P208F "4ll6666s6" + +struct smt_p_208f { + u_long p208f_multiple ; + u_long p208f_nacondition ; + struct fddi_addr p208f_old_una ; + struct fddi_addr p208f_new_una ; + struct fddi_addr p208f_old_dna ; + struct fddi_addr p208f_new_dna ; + u_short p208f_curren_path ; + struct fddi_addr p208f_smt_address ; +} ; + +#define SWAP_SMT_P2090 "4lssl" + +struct smt_p_2090 { + u_long p2090_multiple ; + u_short p2090_availablepaths ; + u_short p2090_currentpath ; + u_long p2090_requestedpaths ; +} ; + +/* + * NOTE: + * special kludge for parameters 320b,320f,3210 + * these parameters are part of RAF frames + * RAF frames are parsed in SBA.C and must be swapped + * PMF.C has special code to avoid double swapping + */ +#ifdef LITTLE_ENDIAN +#define SBAPATHINDEX (0x01000000L) +#else +#define SBAPATHINDEX (0x01L) +#endif + +#define SWAP_SMT_P320B "42s" + +struct smt_p_320b { + struct smt_para para ; /* generic parameter header */ + u_long mib_index ; + u_short path_pad ; + u_short path_index ; +} ; + +#define SWAP_SMT_P320F "4l" + +struct smt_p_320f { + struct smt_para para ; /* generic parameter header */ + u_long mib_index ; + u_long mib_payload ; +} ; + +#define SWAP_SMT_P3210 "4l" + +struct smt_p_3210 { + struct smt_para para ; /* generic parameter header */ + u_long mib_index ; + u_long mib_overhead ; +} ; + +#define SWAP_SMT_P4050 "4l1111ll" + +struct smt_p_4050 { + u_long p4050_flag ; + u_char p4050_pad ; + u_char p4050_cutoff ; + u_char p4050_alarm ; + u_char p4050_estimate ; + u_long p4050_reject_ct ; + u_long p4050_ct ; +} ; + +#define SWAP_SMT_P4051 "4lssss" +struct smt_p_4051 { + u_long p4051_multiple ; + u_short p4051_porttype ; + u_short p4051_connectstate ; + u_short p4051_pc_neighbor ; + u_short p4051_pc_withhold ; +} ; + +#define SWAP_SMT_P4052 "4ll" +struct smt_p_4052 { + u_long p4052_flag ; + u_long p4052_eberrorcount ; +} ; + +#define SWAP_SMT_P4053 "4lsslss" + +struct smt_p_4053 { + u_long p4053_multiple ; + u_short p4053_availablepaths ; + u_short p4053_currentpath ; + u_long p4053_requestedpaths ; + u_short p4053_mytype ; + u_short p4053_neighbortype ; +} ; + + +#define SMT_P_SETCOUNT 0x1035 +#define SWAP_SMT_P_SETCOUNT "l8" + +struct smt_p_setcount { + struct smt_para para ; /* generic parameter header */ + u_long count ; + u_char timestamp[8] ; +} ; + +/* + * SMT FRAMES + */ + +/* + * NIF : neighbor information frames + */ +struct smt_nif { + struct smt_header smt ; /* generic header */ + struct smt_p_una una ; /* UNA */ + struct smt_p_sde sde ; /* station descriptor */ + struct smt_p_state state ; /* station state */ +#ifdef SMT6_10 + struct smt_p_fsc fsc ; /* frame status cap. */ +#endif +} ; + +/* + * SIF : station information frames + */ +struct smt_sif_config { + struct smt_header smt ; /* generic header */ + struct smt_p_timestamp ts ; /* time stamp */ + struct smt_p_sde sde ; /* station descriptor */ + struct smt_p_version version ; /* supported versions */ + struct smt_p_state state ; /* station state */ + struct smt_p_policy policy ; /* station policy */ + struct smt_p_latency latency ; /* path latency */ + struct smt_p_neighbor neighbor ; /* neighbors, we have only one*/ +#ifdef OPT_PMF + struct smt_p_setcount setcount ; /* Set Count mandatory */ +#endif + /* WARNING : path MUST BE LAST FIELD !!! (see smt.c:smt_fill_path) */ + struct smt_p_path path ; /* path descriptor */ +} ; +#define SIZEOF_SMT_SIF_CONFIG (sizeof(struct smt_sif_config)- \ + sizeof(struct smt_p_path)) + +struct smt_sif_operation { + struct smt_header smt ; /* generic header */ + struct smt_p_timestamp ts ; /* time stamp */ + struct smt_p_mac_status status ; /* mac status */ + struct smt_p_mac_counter mc ; /* MAC counter */ + struct smt_p_mac_fnc fnc ; /* MAC frame not copied */ + struct smp_p_manufacturer man ; /* manufacturer field */ + struct smp_p_user user ; /* user field */ +#ifdef OPT_PMF + struct smt_p_setcount setcount ; /* Set Count mandatory */ +#endif + /* must be last */ + struct smt_p_lem lem[1] ; /* phy lem status */ +} ; +#define SIZEOF_SMT_SIF_OPERATION (sizeof(struct smt_sif_operation)- \ + sizeof(struct smt_p_lem)) + +/* + * ECF : echo frame + */ +struct smt_ecf { + struct smt_header smt ; /* generic header */ + struct smt_p_echo ec_echo ; /* echo parameter */ +} ; +#define SMT_ECF_LEN (sizeof(struct smt_header)+sizeof(struct smt_para)) + +/* + * RDF : request denied frame + */ +struct smt_rdf { + struct smt_header smt ; /* generic header */ + struct smt_p_reason reason ; /* reason code */ + struct smt_p_version version ; /* supported versions */ + struct smt_p_refused refused ; /* refused frame fragment */ +} ; + +/* + * SBA Request Allocation Responce Frame + */ +struct smt_sba_alc_res { + struct smt_header smt ; /* generic header */ + struct smt_p_0015 s_type ; /* resource type */ + struct smt_p_0016 cmd ; /* SBA command */ + struct smt_p_reason reason ; /* reason code */ + struct smt_p_320b path ; /* path type */ + struct smt_p_320f payload ; /* current SBA payload */ + struct smt_p_3210 overhead ; /* current SBA overhead */ + struct smt_p_0019 a_addr ; /* Allocation Address */ + struct smt_p_001a cat ; /* Category - from the request */ + struct smt_p_001d alloc ; /* SBA Allocatable */ +} ; + +/* + * SBA Request Allocation Request Frame + */ +struct smt_sba_alc_req { + struct smt_header smt ; /* generic header */ + struct smt_p_0015 s_type ; /* resource type */ + struct smt_p_0016 cmd ; /* SBA command */ + struct smt_p_320b path ; /* path type */ + struct smt_p_0017 pl_req ; /* requested payload */ + struct smt_p_0018 ov_req ; /* requested SBA overhead */ + struct smt_p_320f payload ; /* current SBA payload */ + struct smt_p_3210 overhead ; /* current SBA overhead */ + struct smt_p_0019 a_addr ; /* Allocation Address */ + struct smt_p_001a cat ; /* Category - from the request */ + struct smt_p_001b tneg ; /* max T-NEG */ + struct smt_p_001c segm ; /* minimum segment size */ +} ; + +/* + * SBA Change Allocation Request Frame + */ +struct smt_sba_chg { + struct smt_header smt ; /* generic header */ + struct smt_p_0015 s_type ; /* resource type */ + struct smt_p_0016 cmd ; /* SBA command */ + struct smt_p_320b path ; /* path type */ + struct smt_p_320f payload ; /* current SBA payload */ + struct smt_p_3210 overhead ; /* current SBA overhead */ + struct smt_p_001a cat ; /* Category - from the request */ +} ; + +/* + * SBA Report Allocation Request Frame + */ +struct smt_sba_rep_req { + struct smt_header smt ; /* generic header */ + struct smt_p_0015 s_type ; /* resource type */ + struct smt_p_0016 cmd ; /* SBA command */ +} ; + +/* + * SBA Report Allocation Response Frame + */ +struct smt_sba_rep_res { + struct smt_header smt ; /* generic header */ + struct smt_p_0015 s_type ; /* resource type */ + struct smt_p_0016 cmd ; /* SBA command */ + struct smt_p_320b path ; /* path type */ + struct smt_p_320f payload ; /* current SBA payload */ + struct smt_p_3210 overhead ; /* current SBA overhead */ +} ; + +/* + * actions + */ +#define SMT_STATION_ACTION 1 +#define SMT_STATION_ACTION_CONNECT 0 +#define SMT_STATION_ACTION_DISCONNECT 1 +#define SMT_STATION_ACTION_PATHTEST 2 +#define SMT_STATION_ACTION_SELFTEST 3 +#define SMT_STATION_ACTION_DISABLE_A 4 +#define SMT_STATION_ACTION_DISABLE_B 5 +#define SMT_STATION_ACTION_DISABLE_M 6 + +#define SMT_PORT_ACTION 2 +#define SMT_PORT_ACTION_MAINT 0 +#define SMT_PORT_ACTION_ENABLE 1 +#define SMT_PORT_ACTION_DISABLE 2 +#define SMT_PORT_ACTION_START 3 +#define SMT_PORT_ACTION_STOP 4 + +#endif /* _SMT_ */ diff -u --recursive --new-file v2.3.46/linux/drivers/net/skfp/h/smt_p.h linux/drivers/net/skfp/h/smt_p.h --- v2.3.46/linux/drivers/net/skfp/h/smt_p.h Wed Dec 31 16:00:00 1969 +++ linux/drivers/net/skfp/h/smt_p.h Fri Feb 18 14:55:53 2000 @@ -0,0 +1,326 @@ +/****************************************************************************** + * + * (C)Copyright 1998,1999 SysKonnect, + * a business unit of Schneider & Koch & Co. Datensysteme GmbH. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * The information in this file is provided "AS IS" without warranty. + * + ******************************************************************************/ + +/* + * defines for all SMT attributes + */ + +/* + * this boring file was produced by perl + * thanks Larry ! + */ +#define SMT_P0012 0x0012 + +#define SMT_P0015 0x0015 +#define SMT_P0016 0x0016 +#define SMT_P0017 0x0017 +#define SMT_P0018 0x0018 +#define SMT_P0019 0x0019 + +#define SMT_P001A 0x001a +#define SMT_P001B 0x001b +#define SMT_P001C 0x001c +#define SMT_P001D 0x001d + +#define SMT_P100A 0x100a +#define SMT_P100B 0x100b +#define SMT_P100C 0x100c +#define SMT_P100D 0x100d +#define SMT_P100E 0x100e +#define SMT_P100F 0x100f +#define SMT_P1010 0x1010 +#define SMT_P1011 0x1011 +#define SMT_P1012 0x1012 +#define SMT_P1013 0x1013 +#define SMT_P1014 0x1014 +#define SMT_P1015 0x1015 +#define SMT_P1016 0x1016 +#define SMT_P1017 0x1017 +#define SMT_P1018 0x1018 +#define SMT_P1019 0x1019 +#define SMT_P101A 0x101a +#define SMT_P101B 0x101b +#define SMT_P101C 0x101c +#define SMT_P101D 0x101d +#define SMT_P101E 0x101e +#define SMT_P101F 0x101f +#define SMT_P1020 0x1020 +#define SMT_P1021 0x1021 +#define SMT_P1022 0x1022 +#define SMT_P1023 0x1023 +#define SMT_P1024 0x1024 +#define SMT_P1025 0x1025 +#define SMT_P1026 0x1026 +#define SMT_P1027 0x1027 +#define SMT_P1028 0x1028 +#define SMT_P1029 0x1029 +#define SMT_P102A 0x102a +#define SMT_P102B 0x102b +#define SMT_P102C 0x102c +#define SMT_P102D 0x102d +#define SMT_P102E 0x102e +#define SMT_P102F 0x102f +#define SMT_P1030 0x1030 +#define SMT_P1031 0x1031 +#define SMT_P1032 0x1032 +#define SMT_P1033 0x1033 +#define SMT_P1034 0x1034 +#define SMT_P1035 0x1035 +#define SMT_P1036 0x1036 +#define SMT_P1037 0x1037 +#define SMT_P1038 0x1038 +#define SMT_P1039 0x1039 +#define SMT_P103A 0x103a +#define SMT_P103B 0x103b +#define SMT_P103C 0x103c +#define SMT_P103D 0x103d +#define SMT_P103E 0x103e +#define SMT_P103F 0x103f +#define SMT_P1040 0x1040 +#define SMT_P1041 0x1041 +#define SMT_P1042 0x1042 +#define SMT_P1043 0x1043 +#define SMT_P1044 0x1044 +#define SMT_P1045 0x1045 +#define SMT_P1046 0x1046 +#define SMT_P1047 0x1047 +#define SMT_P1048 0x1048 +#define SMT_P1049 0x1049 +#define SMT_P104A 0x104a +#define SMT_P104B 0x104b +#define SMT_P104C 0x104c +#define SMT_P104D 0x104d +#define SMT_P104E 0x104e +#define SMT_P104F 0x104f +#define SMT_P1050 0x1050 +#define SMT_P1051 0x1051 +#define SMT_P1052 0x1052 +#define SMT_P1053 0x1053 +#define SMT_P1054 0x1054 + +#define SMT_P10F0 0x10f0 +#define SMT_P10F1 0x10f1 +#ifdef ESS +#define SMT_P10F2 0x10f2 +#define SMT_P10F3 0x10f3 +#define SMT_P10F4 0x10f4 +#define SMT_P10F5 0x10f5 +#define SMT_P10F6 0x10f6 +#define SMT_P10F7 0x10f7 +#endif +#ifdef SBA +#define SMT_P10F8 0x10f8 +#define SMT_P10F9 0x10f9 +#endif + +#define SMT_P200A 0x200a +#define SMT_P200B 0x200b +#define SMT_P200C 0x200c +#define SMT_P200D 0x200d +#define SMT_P200E 0x200e +#define SMT_P200F 0x200f +#define SMT_P2010 0x2010 +#define SMT_P2011 0x2011 +#define SMT_P2012 0x2012 +#define SMT_P2013 0x2013 +#define SMT_P2014 0x2014 +#define SMT_P2015 0x2015 +#define SMT_P2016 0x2016 +#define SMT_P2017 0x2017 +#define SMT_P2018 0x2018 +#define SMT_P2019 0x2019 +#define SMT_P201A 0x201a +#define SMT_P201B 0x201b +#define SMT_P201C 0x201c +#define SMT_P201D 0x201d +#define SMT_P201E 0x201e +#define SMT_P201F 0x201f +#define SMT_P2020 0x2020 +#define SMT_P2021 0x2021 +#define SMT_P2022 0x2022 +#define SMT_P2023 0x2023 +#define SMT_P2024 0x2024 +#define SMT_P2025 0x2025 +#define SMT_P2026 0x2026 +#define SMT_P2027 0x2027 +#define SMT_P2028 0x2028 +#define SMT_P2029 0x2029 +#define SMT_P202A 0x202a +#define SMT_P202B 0x202b +#define SMT_P202C 0x202c +#define SMT_P202D 0x202d +#define SMT_P202E 0x202e +#define SMT_P202F 0x202f +#define SMT_P2030 0x2030 +#define SMT_P2031 0x2031 +#define SMT_P2032 0x2032 +#define SMT_P2033 0x2033 +#define SMT_P2034 0x2034 +#define SMT_P2035 0x2035 +#define SMT_P2036 0x2036 +#define SMT_P2037 0x2037 +#define SMT_P2038 0x2038 +#define SMT_P2039 0x2039 +#define SMT_P203A 0x203a +#define SMT_P203B 0x203b +#define SMT_P203C 0x203c +#define SMT_P203D 0x203d +#define SMT_P203E 0x203e +#define SMT_P203F 0x203f +#define SMT_P2040 0x2040 +#define SMT_P2041 0x2041 +#define SMT_P2042 0x2042 +#define SMT_P2043 0x2043 +#define SMT_P2044 0x2044 +#define SMT_P2045 0x2045 +#define SMT_P2046 0x2046 +#define SMT_P2047 0x2047 +#define SMT_P2048 0x2048 +#define SMT_P2049 0x2049 +#define SMT_P204A 0x204a +#define SMT_P204B 0x204b +#define SMT_P204C 0x204c +#define SMT_P204D 0x204d +#define SMT_P204E 0x204e +#define SMT_P204F 0x204f +#define SMT_P2050 0x2050 +#define SMT_P2051 0x2051 +#define SMT_P2052 0x2052 +#define SMT_P2053 0x2053 +#define SMT_P2054 0x2054 +#define SMT_P2055 0x2055 +#define SMT_P2056 0x2056 +#define SMT_P2057 0x2057 +#define SMT_P2058 0x2058 +#define SMT_P2059 0x2059 +#define SMT_P205A 0x205a +#define SMT_P205B 0x205b +#define SMT_P205C 0x205c +#define SMT_P205D 0x205d +#define SMT_P205E 0x205e +#define SMT_P205F 0x205f +#define SMT_P2060 0x2060 +#define SMT_P2061 0x2061 +#define SMT_P2062 0x2062 +#define SMT_P2063 0x2063 +#define SMT_P2064 0x2064 +#define SMT_P2065 0x2065 +#define SMT_P2066 0x2066 +#define SMT_P2067 0x2067 +#define SMT_P2068 0x2068 +#define SMT_P2069 0x2069 +#define SMT_P206A 0x206a +#define SMT_P206B 0x206b +#define SMT_P206C 0x206c +#define SMT_P206D 0x206d +#define SMT_P206E 0x206e +#define SMT_P206F 0x206f +#define SMT_P2070 0x2070 +#define SMT_P2071 0x2071 +#define SMT_P2072 0x2072 +#define SMT_P2073 0x2073 +#define SMT_P2074 0x2074 +#define SMT_P2075 0x2075 +#define SMT_P2076 0x2076 + +#define SMT_P208C 0x208c +#define SMT_P208D 0x208d +#define SMT_P208E 0x208e +#define SMT_P208F 0x208f +#define SMT_P2090 0x2090 + +#define SMT_P20F0 0x20F0 +#define SMT_P20F1 0x20F1 + +#define SMT_P320A 0x320a +#define SMT_P320B 0x320b +#define SMT_P320C 0x320c +#define SMT_P320D 0x320d +#define SMT_P320E 0x320e +#define SMT_P320F 0x320f +#define SMT_P3210 0x3210 +#define SMT_P3211 0x3211 +#define SMT_P3212 0x3212 +#define SMT_P3213 0x3213 +#define SMT_P3214 0x3214 +#define SMT_P3215 0x3215 +#define SMT_P3216 0x3216 +#define SMT_P3217 0x3217 + +#define SMT_P400A 0x400a +#define SMT_P400B 0x400b +#define SMT_P400C 0x400c +#define SMT_P400D 0x400d +#define SMT_P400E 0x400e +#define SMT_P400F 0x400f +#define SMT_P4010 0x4010 +#define SMT_P4011 0x4011 +#define SMT_P4012 0x4012 +#define SMT_P4013 0x4013 +#define SMT_P4014 0x4014 +#define SMT_P4015 0x4015 +#define SMT_P4016 0x4016 +#define SMT_P4017 0x4017 +#define SMT_P4018 0x4018 +#define SMT_P4019 0x4019 +#define SMT_P401A 0x401a +#define SMT_P401B 0x401b +#define SMT_P401C 0x401c +#define SMT_P401D 0x401d +#define SMT_P401E 0x401e +#define SMT_P401F 0x401f +#define SMT_P4020 0x4020 +#define SMT_P4021 0x4021 +#define SMT_P4022 0x4022 +#define SMT_P4023 0x4023 +#define SMT_P4024 0x4024 +#define SMT_P4025 0x4025 +#define SMT_P4026 0x4026 +#define SMT_P4027 0x4027 +#define SMT_P4028 0x4028 +#define SMT_P4029 0x4029 +#define SMT_P402A 0x402a +#define SMT_P402B 0x402b +#define SMT_P402C 0x402c +#define SMT_P402D 0x402d +#define SMT_P402E 0x402e +#define SMT_P402F 0x402f +#define SMT_P4030 0x4030 +#define SMT_P4031 0x4031 +#define SMT_P4032 0x4032 +#define SMT_P4033 0x4033 +#define SMT_P4034 0x4034 +#define SMT_P4035 0x4035 +#define SMT_P4036 0x4036 +#define SMT_P4037 0x4037 +#define SMT_P4038 0x4038 +#define SMT_P4039 0x4039 +#define SMT_P403A 0x403a +#define SMT_P403B 0x403b +#define SMT_P403C 0x403c +#define SMT_P403D 0x403d +#define SMT_P403E 0x403e +#define SMT_P403F 0x403f +#define SMT_P4040 0x4040 +#define SMT_P4041 0x4041 +#define SMT_P4042 0x4042 +#define SMT_P4043 0x4043 +#define SMT_P4044 0x4044 +#define SMT_P4045 0x4045 +#define SMT_P4046 0x4046 + +#define SMT_P4050 0x4050 +#define SMT_P4051 0x4051 +#define SMT_P4052 0x4052 +#define SMT_P4053 0x4053 diff -u --recursive --new-file v2.3.46/linux/drivers/net/skfp/h/smtstate.h linux/drivers/net/skfp/h/smtstate.h --- v2.3.46/linux/drivers/net/skfp/h/smtstate.h Wed Dec 31 16:00:00 1969 +++ linux/drivers/net/skfp/h/smtstate.h Fri Feb 18 14:55:53 2000 @@ -0,0 +1,100 @@ +/****************************************************************************** + * + * (C)Copyright 1998,1999 SysKonnect, + * a business unit of Schneider & Koch & Co. Datensysteme GmbH. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * The information in this file is provided "AS IS" without warranty. + * + ******************************************************************************/ + +/* + * SMT state definitions + */ + +#ifndef KERNEL +/* + * PCM states + */ +#define PC0_OFF 0 +#define PC1_BREAK 1 +#define PC2_TRACE 2 +#define PC3_CONNECT 3 +#define PC4_NEXT 4 +#define PC5_SIGNAL 5 +#define PC6_JOIN 6 +#define PC7_VERIFY 7 +#define PC8_ACTIVE 8 +#define PC9_MAINT 9 + +/* + * PCM modes + */ +#define PM_NONE 0 +#define PM_PEER 1 +#define PM_TREE 2 + +/* + * PCM type + */ +#define TA 0 +#define TB 1 +#define TS 2 +#define TM 3 +#define TNONE 4 + +/* + * CFM states + */ +#define SC0_ISOLATED 0 /* isolated */ +#define SC1_WRAP_A 5 /* wrap A */ +#define SC2_WRAP_B 6 /* wrap B */ +#define SC4_THRU_A 12 /* through A */ +#define SC5_THRU_B 7 /* through B (SMt 6.2) */ +#define SC7_WRAP_S 8 /* SAS */ + +/* + * ECM states + */ +#define EC0_OUT 0 +#define EC1_IN 1 +#define EC2_TRACE 2 +#define EC3_LEAVE 3 +#define EC4_PATH_TEST 4 +#define EC5_INSERT 5 +#define EC6_CHECK 6 +#define EC7_DEINSERT 7 + +/* + * RMT states + */ +#define RM0_ISOLATED 0 +#define RM1_NON_OP 1 /* not operational */ +#define RM2_RING_OP 2 /* ring operational */ +#define RM3_DETECT 3 /* detect dupl addresses */ +#define RM4_NON_OP_DUP 4 /* dupl. addr detected */ +#define RM5_RING_OP_DUP 5 /* ring oper. with dupl. addr */ +#define RM6_DIRECTED 6 /* sending directed beacons */ +#define RM7_TRACE 7 /* trace initiated */ +#endif + +struct pcm_state { + unsigned char pcm_type ; /* TA TB TS TM */ + unsigned char pcm_state ; /* state PC[0-9]_* */ + unsigned char pcm_mode ; /* PM_{NONE,PEER,TREE} */ + unsigned char pcm_neighbor ; /* TA TB TS TM */ + unsigned char pcm_bsf ; /* flag bs : TRUE/FALSE */ + unsigned char pcm_lsf ; /* flag ls : TRUE/FALSE */ + unsigned char pcm_lct_fail ; /* counter lct_fail */ + unsigned char pcm_ls_rx ; /* rx line state */ + short pcm_r_val ; /* signaling bits */ + short pcm_t_val ; /* signaling bits */ +} ; + +struct smt_state { + struct pcm_state pcm_state[NUMPHYS] ; /* port A & port B */ +} ; diff -u --recursive --new-file v2.3.46/linux/drivers/net/skfp/h/supern_2.h linux/drivers/net/skfp/h/supern_2.h --- v2.3.46/linux/drivers/net/skfp/h/supern_2.h Wed Dec 31 16:00:00 1969 +++ linux/drivers/net/skfp/h/supern_2.h Fri Feb 18 14:55:53 2000 @@ -0,0 +1,1059 @@ +/****************************************************************************** + * + * (C)Copyright 1998,1999 SysKonnect, + * a business unit of Schneider & Koch & Co. Datensysteme GmbH. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * The information in this file is provided "AS IS" without warranty. + * + ******************************************************************************/ + +/* + defines for AMD Supernet II chip set + the chips are refered to as + FPLUS Formac Plus + PLC Physical Layer + + added defines for AMD Supernet III chip set + added comments on differences between Supernet II and Supernet III + added defines for the Motorola ELM (MOT_ELM) +*/ + +#ifndef _SUPERNET_ +#define _SUPERNET_ + +/* + * Define Supernet 3 when used + */ +#ifdef PCI +#ifndef SUPERNET_3 +#define SUPERNET_3 +#endif +#define TAG +#endif + +#define MB 0xff +#define MW 0xffff +#define MD 0xffffffff + +/* + * FORMAC frame status (rx_msext) + */ +#define FS_EI (1<<2) +#define FS_AI (1<<1) +#define FS_CI (1<<0) + +#define FS_MSVALID (1<<15) /* end of queue */ +#define FS_MSRABT (1<<14) /* frame was aborted during reception*/ +#define FS_SSRCRTG (1<<12) /* if SA has set MSB (source-routing)*/ +#define FS_SEAC2 (FS_EI<<9) /* error indicator */ +#define FS_SEAC1 (FS_AI<<9) /* address indicator */ +#define FS_SEAC0 (FS_CI<<9) /* copy indicator */ +#define FS_SFRMERR (1<<8) /* error detected (CRC or length) */ +#define FS_SADRRG (1<<7) /* address recognized */ +#define FS_SFRMTY2 (1<<6) /* frame-class bit */ +#define FS_SFRMTY1 (1<<5) /* frame-type bit (impementor) */ +#define FS_SFRMTY0 (1<<4) /* frame-type bit (LLC) */ +#define FS_ERFBB1 (1<<1) /* byte offset (depends on LSB bit) */ +#define FS_ERFBB0 (1<<0) /* - " - */ + +/* + * status frame type + */ +#define FRM_SMT (0) /* asynchr. frames */ +#define FRM_LLCA (1) +#define FRM_IMPA (2) +#define FRM_MAC (4) /* synchr. frames */ +#define FRM_LLCS (5) +#define FRM_IMPS (6) + +/* + * bits in rx_descr.i (receive frame status word) + */ +#define RX_MSVALID ((long)1<<31) /* memory status valid */ +#define RX_MSRABT ((long)1<<30) /* memory status receive abort */ +#define RX_FS_E ((long)FS_SEAC2<<16) /* error indicator */ +#define RX_FS_A ((long)FS_SEAC1<<16) /* address indicator */ +#define RX_FS_C ((long)FS_SEAC0<<16) /* copy indicator */ +#define RX_FS_CRC ((long)FS_SFRMERR<<16)/* error detected */ +#define RX_FS_ADDRESS ((long)FS_SADRRG<<16) /* address recognized */ +#define RX_FS_MAC ((long)FS_SFRMTY2<<16)/* MAC frame */ +#define RX_FS_SMT ((long)0<<16) /* SMT frame */ +#define RX_FS_IMPL ((long)FS_SFRMTY1<<16)/* implementer frame */ +#define RX_FS_LLC ((long)FS_SFRMTY0<<16)/* LLC frame */ + +/* + * receive frame descriptor + */ +union rx_descr { + struct { +#ifdef LITTLE_ENDIAN + unsigned rx_length :16 ; /* frame length lower/upper byte */ + unsigned rx_erfbb :2 ; /* received frame byte boundary */ + unsigned rx_reserv2:2 ; /* reserved */ + unsigned rx_sfrmty :3 ; /* frame type bits */ + unsigned rx_sadrrg :1 ; /* DA == MA or broad-/multicast */ + unsigned rx_sfrmerr:1 ; /* received frame not valid */ + unsigned rx_seac0 :1 ; /* frame-copied C-indicator */ + unsigned rx_seac1 :1 ; /* address-match A-indicator */ + unsigned rx_seac2 :1 ; /* frame-error E-indicator */ + unsigned rx_ssrcrtg:1 ; /* == 1 SA has MSB set */ + unsigned rx_reserv1:1 ; /* reserved */ + unsigned rx_msrabt :1 ; /* memory status receive abort */ + unsigned rx_msvalid:1 ; /* memory status valid */ +#else + unsigned rx_msvalid:1 ; /* memory status valid */ + unsigned rx_msrabt :1 ; /* memory status receive abort */ + unsigned rx_reserv1:1 ; /* reserved */ + unsigned rx_ssrcrtg:1 ; /* == 1 SA has MSB set */ + unsigned rx_seac2 :1 ; /* frame-error E-indicator */ + unsigned rx_seac1 :1 ; /* address-match A-indicator */ + unsigned rx_seac0 :1 ; /* frame-copied C-indicator */ + unsigned rx_sfrmerr:1 ; /* received frame not valid */ + unsigned rx_sadrrg :1 ; /* DA == MA or broad-/multicast */ + unsigned rx_sfrmty :3 ; /* frame type bits */ + unsigned rx_erfbb :2 ; /* received frame byte boundary */ + unsigned rx_reserv2:2 ; /* reserved */ + unsigned rx_length :16 ; /* frame length lower/upper byte */ +#endif + } r ; + long i ; +} ; + +/* defines for Receive Frame Descriptor access */ +#define RD_S_ERFBB 0x00030000L /* received frame byte boundary */ +#define RD_S_RES2 0x000c0000L /* reserved */ +#define RD_S_SFRMTY 0x00700000L /* frame type bits */ +#define RD_S_SADRRG 0x00800000L /* DA == MA or broad-/multicast */ +#define RD_S_SFRMERR 0x01000000L /* received frame not valid */ +#define RD_S_SEAC 0x0e000000L /* frame status indicators */ +#define RD_S_SEAC0 0x02000000L /* frame-copied case-indicator */ +#define RD_S_SEAC1 0x04000000L /* address-match A-indicator */ +#define RD_S_SEAC2 0x08000000L /* frame-error E-indicator */ +#define RD_S_SSRCRTG 0x10000000L /* == 1 SA has MSB set */ +#define RD_S_RES1 0x20000000L /* reserved */ +#define RD_S_MSRABT 0x40000000L /* memory status receive abort */ +#define RD_S_MSVALID 0x80000000L /* memory status valid */ + +#define RD_STATUS 0xffff0000L +#define RD_LENGTH 0x0000ffffL + +/* defines for Receive Frames Status Word values */ +/*RD_S_SFRMTY*/ +#define RD_FRM_SMT (unsigned long)(0<<20) /* asynchr. frames */ +#define RD_FRM_LLCA (unsigned long)(1<<20) +#define RD_FRM_IMPA (unsigned long)(2<<20) +#define RD_FRM_MAC (unsigned long)(4<<20) /* synchr. frames */ +#define RD_FRM_LLCS (unsigned long)(5<<20) +#define RD_FRM_IMPS (unsigned long)(6<<20) + +#define TX_DESCRIPTOR 0x40000000L +#define TX_OFFSET_3 0x18000000L + +#define TXP1 2 + +/* + * transmit frame descriptor + */ +union tx_descr { + struct { +#ifdef LITTLE_ENDIAN + unsigned tx_length:16 ; /* frame length lower/upper byte */ + unsigned tx_res :8 ; /* reserved (bit 16..23) */ + unsigned tx_xmtabt:1 ; /* transmit abort */ + unsigned tx_nfcs :1 ; /* no frame check sequence */ + unsigned tx_xdone :1 ; /* give up token */ + unsigned tx_rpxm :2 ; /* byte offset */ + unsigned tx_pat1 :2 ; /* must be TXP1 */ + unsigned tx_more :1 ; /* more frame in chain */ +#else + unsigned tx_more :1 ; /* more frame in chain */ + unsigned tx_pat1 :2 ; /* must be TXP1 */ + unsigned tx_rpxm :2 ; /* byte offset */ + unsigned tx_xdone :1 ; /* give up token */ + unsigned tx_nfcs :1 ; /* no frame check sequence */ + unsigned tx_xmtabt:1 ; /* transmit abort */ + unsigned tx_res :8 ; /* reserved (bit 16..23) */ + unsigned tx_length:16 ; /* frame length lower/upper byte */ +#endif + } t ; + long i ; +} ; + +/* defines for Transmit Descriptor access */ +#define TD_C_MORE 0x80000000L /* more frame in chain */ +#define TD_C_DESCR 0x60000000L /* must be TXP1 */ +#define TD_C_TXFBB 0x18000000L /* byte offset */ +#define TD_C_XDONE 0x04000000L /* give up token */ +#define TD_C_NFCS 0x02000000L /* no frame check sequence */ +#define TD_C_XMTABT 0x01000000L /* transmit abort */ + +#define TD_C_LNCNU 0x0000ff00L +#define TD_C_LNCNL 0x000000ffL +#define TD_C_LNCN 0x0000ffffL /* frame length lower/upper byte */ + +/* + * transmit pointer + */ +union tx_pointer { + struct t { +#ifdef LITTLE_ENDIAN + unsigned tp_pointer:16 ; /* pointer to tx_descr (low/high) */ + unsigned tp_res :8 ; /* reserved (bit 16..23) */ + unsigned tp_pattern:8 ; /* fixed pattern (bit 24..31) */ +#else + unsigned tp_pattern:8 ; /* fixed pattern (bit 24..31) */ + unsigned tp_res :8 ; /* reserved (bit 16..23) */ + unsigned tp_pointer:16 ; /* pointer to tx_descr (low/high) */ +#endif + } t ; + long i ; +} ; + +/* defines for Nontag Mode Pointer access */ +#define TD_P_CNTRL 0xff000000L +#define TD_P_RPXU 0x0000ff00L +#define TD_P_RPXL 0x000000ffL +#define TD_P_RPX 0x0000ffffL + + +#define TX_PATTERN 0xa0 +#define TX_POINTER_END 0xa0000000L +#define TX_INT_PATTERN 0xa0000000L + +struct tx_queue { + struct tx_queue *tq_next ; + u_short tq_pack_offset ; /* offset buffer memory */ + u_char tq_pad[2] ; +} ; + +/* + defines for FORMAC Plus (Am79C830) +*/ + +/* + * FORMAC+ read/write (r/w) registers + */ +#define FM_CMDREG1 0x00 /* write command reg 1 instruction */ +#define FM_CMDREG2 0x01 /* write command reg 2 instruction */ +#define FM_ST1U 0x00 /* read upper 16-bit of status reg 1 */ +#define FM_ST1L 0x01 /* read lower 16-bit of status reg 1 */ +#define FM_ST2U 0x02 /* read upper 16-bit of status reg 2 */ +#define FM_ST2L 0x03 /* read lower 16-bit of status reg 2 */ +#define FM_IMSK1U 0x04 /* r/w upper 16-bit of IMSK 1 */ +#define FM_IMSK1L 0x05 /* r/w lower 16-bit of IMSK 1 */ +#define FM_IMSK2U 0x06 /* r/w upper 16-bit of IMSK 2 */ +#define FM_IMSK2L 0x07 /* r/w lower 16-bit of IMSK 2 */ +#define FM_SAID 0x08 /* r/w short addr.-individual */ +#define FM_LAIM 0x09 /* r/w long addr.-ind. (MSW of LAID) */ +#define FM_LAIC 0x0a /* r/w long addr.-ind. (middle)*/ +#define FM_LAIL 0x0b /* r/w long addr.-ind. (LSW) */ +#define FM_SAGP 0x0c /* r/w short address-group */ +#define FM_LAGM 0x0d /* r/w long addr.-gr. (MSW of LAGP) */ +#define FM_LAGC 0x0e /* r/w long addr.-gr. (middle) */ +#define FM_LAGL 0x0f /* r/w long addr.-gr. (LSW) */ +#define FM_MDREG1 0x10 /* r/w 16-bit mode reg 1 */ +#define FM_STMCHN 0x11 /* read state-machine reg */ +#define FM_MIR1 0x12 /* read upper 16-bit of MAC Info Reg */ +#define FM_MIR0 0x13 /* read lower 16-bit of MAC Info Reg */ +#define FM_TMAX 0x14 /* r/w 16-bit TMAX reg */ +#define FM_TVX 0x15 /* write 8-bit TVX reg with NP7-0 + read TVX on NP7-0, timer on NP15-8*/ +#define FM_TRT 0x16 /* r/w upper 16-bit of TRT timer */ +#define FM_THT 0x17 /* r/w upper 16-bit of THT timer */ +#define FM_TNEG 0x18 /* read upper 16-bit of TNEG (TTRT) */ +#define FM_TMRS 0x19 /* read lower 5-bit of TNEG,TRT,THT */ + /* F E D C B A 9 8 7 6 5 4 3 2 1 0 + x |-TNEG4-0| |-TRT4-0-| |-THT4-0-| (x-late count) */ +#define FM_TREQ0 0x1a /* r/w 16-bit TREQ0 reg (LSW of TRT) */ +#define FM_TREQ1 0x1b /* r/w 16-bit TREQ1 reg (MSW of TRT) */ +#define FM_PRI0 0x1c /* r/w priority r. for asyn.-queue 0 */ +#define FM_PRI1 0x1d /* r/w priority r. for asyn.-queue 1 */ +#define FM_PRI2 0x1e /* r/w priority r. for asyn.-queue 2 */ +#define FM_TSYNC 0x1f /* r/w 16-bit of the TSYNC register */ +#define FM_MDREG2 0x20 /* r/w 16-bit mode reg 2 */ +#define FM_FRMTHR 0x21 /* r/w the frame threshold register */ +#define FM_EACB 0x22 /* r/w end addr of claim/beacon area */ +#define FM_EARV 0x23 /* r/w end addr of receive queue */ +/* Supernet 3 */ +#define FM_EARV1 FM_EARV + +#define FM_EAS 0x24 /* r/w end addr of synchr. queue */ +#define FM_EAA0 0x25 /* r/w end addr of asyn. queue 0 */ +#define FM_EAA1 0x26 /* r/w end addr of asyn. queue 1 */ +#define FM_EAA2 0x27 /* r/w end addr of asyn. queue 2 */ +#define FM_SACL 0x28 /* r/w start addr of claim frame */ +#define FM_SABC 0x29 /* r/w start addr of beacon frame */ +#define FM_WPXSF 0x2a /* r/w the write ptr. for special fr.*/ +#define FM_RPXSF 0x2b /* r/w the read ptr. for special fr. */ +#define FM_RPR 0x2d /* r/w the read ptr. for receive qu. */ +#define FM_WPR 0x2e /* r/w the write ptr. for receive qu.*/ +#define FM_SWPR 0x2f /* r/w the shadow wr.-ptr. for rec.q.*/ +/* Supernet 3 */ +#define FM_RPR1 FM_RPR +#define FM_WPR1 FM_WPR +#define FM_SWPR1 FM_SWPR + +#define FM_WPXS 0x30 /* r/w the write ptr. for synchr. qu.*/ +#define FM_WPXA0 0x31 /* r/w the write ptr. for asyn. qu.0 */ +#define FM_WPXA1 0x32 /* r/w the write ptr. for asyn. qu.1 */ +#define FM_WPXA2 0x33 /* r/w the write ptr. for asyn. qu.2 */ +#define FM_SWPXS 0x34 /* r/w the shadow wr.-ptr. for syn.q.*/ +#define FM_SWPXA0 0x35 /* r/w the shad. wr.-ptr. for asyn.q0*/ +#define FM_SWPXA1 0x36 /* r/w the shad. wr.-ptr. for asyn.q1*/ +#define FM_SWPXA2 0x37 /* r/w the shad. wr.-ptr. for asyn.q2*/ +#define FM_RPXS 0x38 /* r/w the read ptr. for synchr. qu. */ +#define FM_RPXA0 0x39 /* r/w the read ptr. for asyn. qu. 0 */ +#define FM_RPXA1 0x3a /* r/w the read ptr. for asyn. qu. 1 */ +#define FM_RPXA2 0x3b /* r/w the read ptr. for asyn. qu. 2 */ +#define FM_MARR 0x3c /* r/w the memory read addr register */ +#define FM_MARW 0x3d /* r/w the memory write addr register*/ +#define FM_MDRU 0x3e /* r/w upper 16-bit of mem. data reg */ +#define FM_MDRL 0x3f /* r/w lower 16-bit of mem. data reg */ + +/* following instructions relate to MAC counters and timer */ +#define FM_TMSYNC 0x40 /* r/w upper 16 bits of TMSYNC timer */ +#define FM_FCNTR 0x41 /* r/w the 16-bit frame counter */ +#define FM_LCNTR 0x42 /* r/w the 16-bit lost counter */ +#define FM_ECNTR 0x43 /* r/w the 16-bit error counter */ + +/* Supernet 3: extensions to old register block */ +#define FM_FSCNTR 0x44 /* r/? Frame Strip Counter */ +#define FM_FRSELREG 0x45 /* r/w Frame Selection Register */ + +/* Supernet 3: extensions for 2. receive queue etc. */ +#define FM_MDREG3 0x60 /* r/w Mode Register 3 */ +#define FM_ST3U 0x61 /* read upper 16-bit of status reg 3 */ +#define FM_ST3L 0x62 /* read lower 16-bit of status reg 3 */ +#define FM_IMSK3U 0x63 /* r/w upper 16-bit of IMSK reg 3 */ +#define FM_IMSK3L 0x64 /* r/w lower 16-bit of IMSK reg 3 */ +#define FM_IVR 0x65 /* read Interrupt Vector register */ +#define FM_IMR 0x66 /* r/w Interrupt mask register */ +/* 0x67 Hidden */ +#define FM_RPR2 0x68 /* r/w the read ptr. for rec. qu. 2 */ +#define FM_WPR2 0x69 /* r/w the write ptr. for rec. qu. 2 */ +#define FM_SWPR2 0x6a /* r/w the shadow wptr. for rec. q. 2 */ +#define FM_EARV2 0x6b /* r/w end addr of rec. qu. 2 */ +#define FM_UNLCKDLY 0x6c /* r/w Auto Unlock Delay register */ + /* Bit 15-8: RECV2 unlock threshold */ + /* Bit 7-0: RECV1 unlock threshold */ +/* 0x6f-0x73 Hidden */ +#define FM_LTDPA1 0x79 /* r/w Last Trans desc ptr for A1 qu. */ +/* 0x80-0x9a PLCS registers of built-in PLCS (Supernet 3 only) */ + +/* Supernet 3: Adderss Filter Registers */ +#define FM_AFCMD 0xb0 /* r/w Address Filter Command Reg */ +#define FM_AFSTAT 0xb2 /* r/w Address Filter Status Reg */ +#define FM_AFBIST 0xb4 /* r/w Address Filter BIST signature */ +#define FM_AFCOMP2 0xb6 /* r/w Address Filter Comparand 2 */ +#define FM_AFCOMP1 0xb8 /* r/w Address Filter Comparand 1 */ +#define FM_AFCOMP0 0xba /* r/w Address Filter Comparand 0 */ +#define FM_AFMASK2 0xbc /* r/w Address Filter Mask 2 */ +#define FM_AFMASK1 0xbe /* r/w Address Filter Mask 1 */ +#define FM_AFMASK0 0xc0 /* r/w Address Filter Mask 0 */ +#define FM_AFPERS 0xc2 /* r/w Address Filter Personality Reg */ + +/* Supernet 3: Orion (PDX?) Registers */ +#define FM_ORBIST 0xd0 /* r/w Orion BIST signature */ +#define FM_ORSTAT 0xd2 /* r/w Orion Status Register */ + + +/* + * Mode Register 1 (MDREG1) + */ +#define FM_RES0 0x0001 /* reserved */ + /* SN3: other definition */ +#define FM_XMTINH_HOLD 0x0002 /* transmit-inhibit/hold bit */ + /* SN3: other definition */ +#define FM_HOFLXI 0x0003 /* SN3: Hold / Flush / Inhibit */ +#define FM_FULL_HALF 0x0004 /* full-duplex/half-duplex bit */ +#define FM_LOCKTX 0x0008 /* lock-transmit-asynchr.-queues bit */ +#define FM_EXGPA0 0x0010 /* extended-group-addressing bit 0 */ +#define FM_EXGPA1 0x0020 /* extended-group-addressing bit 1 */ +#define FM_DISCRY 0x0040 /* disable-carry bit */ + /* SN3: reserved */ +#define FM_SELRA 0x0080 /* select input from PHY (1=RA,0=RB) */ + +#define FM_ADDET 0x0700 /* address detection */ +#define FM_MDAMA (0<<8) /* address detection : DA = MA */ +#define FM_MDASAMA (1<<8) /* address detection : DA=MA||SA=MA */ +#define FM_MRNNSAFNMA (2<<8) /* rec. non-NSA frames DA=MA&&SA!=MA */ +#define FM_MRNNSAF (3<<8) /* rec. non-NSA frames DA = MA */ +#define FM_MDISRCV (4<<8) /* disable receive function */ +#define FM_MRES0 (5<<8) /* reserve */ +#define FM_MLIMPROM (6<<8) /* limited-promiscuous mode */ +#define FM_MPROMISCOUS (7<<8) /* address detection : promiscous */ + +#define FM_SELSA 0x0800 /* select-short-address bit */ + +#define FM_MMODE 0x7000 /* mode select */ +#define FM_MINIT (0<<12) /* initialize */ +#define FM_MMEMACT (1<<12) /* memory activate */ +#define FM_MONLINESP (2<<12) /* on-line special */ +#define FM_MONLINE (3<<12) /* on-line (FDDI operational mode) */ +#define FM_MILOOP (4<<12) /* internal loopback */ +#define FM_MRES1 (5<<12) /* reserved */ +#define FM_MRES2 (6<<12) /* reserved */ +#define FM_MELOOP (7<<12) /* external loopback */ + +#define FM_SNGLFRM 0x8000 /* single-frame-receive mode */ + /* SN3: reserved */ + +#define MDR1INIT (FM_MINIT | FM_MDAMA) + +/* + * Mode Register 2 (MDREG2) + */ +#define FM_AFULL 0x000f /* 4-bit value (empty loc.in txqueue)*/ +#define FM_RCVERR 0x0010 /* rec.-errored-frames bit */ +#define FM_SYMCTL 0x0020 /* sysmbol-control bit */ + /* SN3: reserved */ +#define FM_SYNPRQ 0x0040 /* synchron.-NP-DMA-request bit */ +#define FM_ENNPRQ 0x0080 /* enable-NP-DMA-request bit */ +#define FM_ENHSRQ 0x0100 /* enable-host-request bit */ +#define FM_RXFBB01 0x0600 /* rec. frame byte boundary bit0 & 1 */ +#define FM_LSB 0x0800 /* determ. ordering of bytes in buffer*/ +#define FM_PARITY 0x1000 /* 1 = even, 0 = odd */ +#define FM_CHKPAR 0x2000 /* 1 = parity of 32-bit buffer BD-bus*/ +#define FM_STRPFCS 0x4000 /* 1 = strips FCS field of rec.frame */ +#define FM_BMMODE 0x8000 /* Buffer-Memory-Mode (1 = tag mode) */ + /* SN3: 1 = tag, 0 = modified tag */ + +/* + * Status Register 1, Upper 16 Bits (ST1U) + */ +#define FM_STEFRMS 0x0001 /* transmit end of frame: synchr. qu.*/ +#define FM_STEFRMA0 0x0002 /* transmit end of frame: asyn. qu.0 */ +#define FM_STEFRMA1 0x0004 /* transmit end of frame: asyn. qu.1 */ +#define FM_STEFRMA2 0x0008 /* transmit end of frame: asyn. qu.2 */ + /* SN3: reserved */ +#define FM_STECFRMS 0x0010 /* transmit end of chain of syn. qu. */ + /* SN3: reserved */ +#define FM_STECFRMA0 0x0020 /* transmit end of chain of asyn. q0 */ + /* SN3: reserved */ +#define FM_STECFRMA1 0x0040 /* transmit end of chain of asyn. q1 */ + /* SN3: STECMDA1 */ +#define FM_STECMDA1 0x0040 /* SN3: 'no description' */ +#define FM_STECFRMA2 0x0080 /* transmit end of chain of asyn. q2 */ + /* SN3: reserved */ +#define FM_STEXDONS 0x0100 /* transmit until XDONE in syn. qu. */ +#define FM_STBFLA 0x0200 /* asynchr.-queue trans. buffer full */ +#define FM_STBFLS 0x0400 /* synchr.-queue transm. buffer full */ +#define FM_STXABRS 0x0800 /* synchr. queue transmit-abort */ +#define FM_STXABRA0 0x1000 /* asynchr. queue 0 transmit-abort */ +#define FM_STXABRA1 0x2000 /* asynchr. queue 1 transmit-abort */ +#define FM_STXABRA2 0x4000 /* asynchr. queue 2 transmit-abort */ + /* SN3: reserved */ +#define FM_SXMTABT 0x8000 /* transmit abort */ + +/* + * Status Register 1, Lower 16 Bits (ST1L) + */ +#define FM_SQLCKS 0x0001 /* queue lock for synchr. queue */ +#define FM_SQLCKA0 0x0002 /* queue lock for asynchr. queue 0 */ +#define FM_SQLCKA1 0x0004 /* queue lock for asynchr. queue 1 */ +#define FM_SQLCKA2 0x0008 /* queue lock for asynchr. queue 2 */ + /* SN3: reserved */ +#define FM_STXINFLS 0x0010 /* transmit instruction full: syn. */ + /* SN3: reserved */ +#define FM_STXINFLA0 0x0020 /* transmit instruction full: asyn.0 */ + /* SN3: reserved */ +#define FM_STXINFLA1 0x0040 /* transmit instruction full: asyn.1 */ + /* SN3: reserved */ +#define FM_STXINFLA2 0x0080 /* transmit instruction full: asyn.2 */ + /* SN3: reserved */ +#define FM_SPCEPDS 0x0100 /* parity/coding error: syn. queue */ +#define FM_SPCEPDA0 0x0200 /* parity/coding error: asyn. queue0 */ +#define FM_SPCEPDA1 0x0400 /* parity/coding error: asyn. queue1 */ +#define FM_SPCEPDA2 0x0800 /* parity/coding error: asyn. queue2 */ + /* SN3: reserved */ +#define FM_STBURS 0x1000 /* transmit buffer underrun: syn. q. */ +#define FM_STBURA0 0x2000 /* transmit buffer underrun: asyn.0 */ +#define FM_STBURA1 0x4000 /* transmit buffer underrun: asyn.1 */ +#define FM_STBURA2 0x8000 /* transmit buffer underrun: asyn.2 */ + /* SN3: reserved */ + +/* + * Status Register 2, Upper 16 Bits (ST2U) + */ +#define FM_SOTRBEC 0x0001 /* other beacon received */ +#define FM_SMYBEC 0x0002 /* my beacon received */ +#define FM_SBEC 0x0004 /* beacon state entered */ +#define FM_SLOCLM 0x0008 /* low claim received */ +#define FM_SHICLM 0x0010 /* high claim received */ +#define FM_SMYCLM 0x0020 /* my claim received */ +#define FM_SCLM 0x0040 /* claim state entered */ +#define FM_SERRSF 0x0080 /* error in special frame */ +#define FM_SNFSLD 0x0100 /* NP and FORMAC+ simultaneous load */ +#define FM_SRFRCTOV 0x0200 /* receive frame counter overflow */ + /* SN3: reserved */ +#define FM_SRCVFRM 0x0400 /* receive frame */ + /* SN3: reserved */ +#define FM_SRCVOVR 0x0800 /* receive FIFO overflow */ +#define FM_SRBFL 0x1000 /* receive buffer full */ +#define FM_SRABT 0x2000 /* receive abort */ +#define FM_SRBMT 0x4000 /* receive buffer empty */ +#define FM_SRCOMP 0x8000 /* receive complete. Nontag mode */ + +/* + * Status Register 2, Lower 16 Bits (ST2L) + * Attention: SN3 docu shows these bits the other way around + */ +#define FM_SRES0 0x0001 /* reserved */ +#define FM_SESTRIPTK 0x0001 /* SN3: 'no description' */ +#define FM_STRTEXR 0x0002 /* TRT expired in claim | beacon st. */ +#define FM_SDUPCLM 0x0004 /* duplicate claim received */ +#define FM_SSIFG 0x0008 /* short interframe gap */ +#define FM_SFRMCTR 0x0010 /* frame counter overflow */ +#define FM_SERRCTR 0x0020 /* error counter overflow */ +#define FM_SLSTCTR 0x0040 /* lost counter overflow */ +#define FM_SPHINV 0x0080 /* PHY invalid */ +#define FM_SADET 0x0100 /* address detect */ +#define FM_SMISFRM 0x0200 /* missed frame */ +#define FM_STRTEXP 0x0400 /* TRT expired and late count > 0 */ +#define FM_STVXEXP 0x0800 /* TVX expired */ +#define FM_STKISS 0x1000 /* token issued */ +#define FM_STKERR 0x2000 /* token error */ +#define FM_SMULTDA 0x4000 /* multiple destination address */ +#define FM_SRNGOP 0x8000 /* ring operational */ + +/* + * Supernet 3: + * Status Register 3, Upper 16 Bits (ST3U) + */ +#define FM_SRQUNLCK1 0x0001 /* receive queue unlocked queue 1 */ +#define FM_SRQUNLCK2 0x0002 /* receive queue unlocked queue 2 */ +#define FM_SRPERRQ1 0x0004 /* receive parity error rx queue 1 */ +#define FM_SRPERRQ2 0x0008 /* receive parity error rx queue 2 */ + /* Bit 4-10: reserved */ +#define FM_SRCVOVR2 0x0800 /* receive FIFO overfull rx queue 2 */ +#define FM_SRBFL2 0x1000 /* receive buffer full rx queue 2 */ +#define FM_SRABT2 0x2000 /* receive abort rx queue 2 */ +#define FM_SRBMT2 0x4000 /* receive buf empty rx queue 2 */ +#define FM_SRCOMP2 0x8000 /* receive comp rx queue 2 */ + +/* + * Supernet 3: + * Status Register 3, Lower 16 Bits (ST3L) + */ +#define FM_AF_BIST_DONE 0x0001 /* Address Filter BIST is done */ +#define FM_PLC_BIST_DONE 0x0002 /* internal PLC Bist is done */ +#define FM_PDX_BIST_DONE 0x0004 /* PDX BIST is done */ + /* Bit 3: reserved */ +#define FM_SICAMDAMAT 0x0010 /* Status internal CAM DA match */ +#define FM_SICAMDAXACT 0x0020 /* Status internal CAM DA exact match */ +#define FM_SICAMSAMAT 0x0040 /* Status internal CAM SA match */ +#define FM_SICAMSAXACT 0x0080 /* Status internal CAM SA exact match */ + +/* + * MAC State-Machine Register FM_STMCHN + */ +#define FM_MDRTAG 0x0004 /* tag bit of long word read */ +#define FM_SNPPND 0x0008 /* r/w from buffer mem. is pending */ +#define FM_TXSTAT 0x0070 /* transmitter state machine state */ +#define FM_RCSTAT 0x0380 /* receiver state machine state */ +#define FM_TM01 0x0c00 /* indicate token mode */ +#define FM_SIM 0x1000 /* indicate send immediate-mode */ +#define FM_REV 0xe000 /* FORMAC Plus revision number */ + +/* + * Supernet 3 + * Mode Register 3 + */ +#define FM_MENRS 0x0001 /* Ena enhanced rec status encoding */ +#define FM_MENXS 0x0002 /* Ena enhanced xmit status encoding */ +#define FM_MENXCT 0x0004 /* Ena EXACT/INEXACT matching */ +#define FM_MENAFULL 0x0008 /* Ena enh QCTRL encoding for AFULL */ +#define FM_MEIND 0x0030 /* Ena enh A,C indicator settings */ +#define FM_MENQCTRL 0x0040 /* Ena enh QCTRL encoding */ +#define FM_MENRQAUNLCK 0x0080 /* Ena rec q auto unlock */ +#define FM_MENDAS 0x0100 /* Ena DAS connections by cntr MUX */ +#define FM_MENPLCCST 0x0200 /* Ena Counter Segm test in PLC blck */ +#define FM_MENSGLINT 0x0400 /* Ena Vectored Interrupt reading */ +#define FM_MENDRCV 0x0800 /* Ena dual receive queue operation */ +#define FM_MENFCLOC 0x3000 /* Ena FC location within frm data */ +#define FM_MENTRCMD 0x4000 /* Ena ASYNC1 xmit only after command */ +#define FM_MENTDLPBK 0x8000 /* Ena TDAT to RDAT lkoopback */ + +/* + * Supernet 3 + * Frame Selection Register + */ +#define FM_RECV1 0x000f /* options for receive queue 1 */ +#define FM_RCV1_ALL (0<<0) /* receive all frames */ +#define FM_RCV1_LLC (1<<0) /* rec all LLC frames */ +#define FM_RCV1_SMT (2<<0) /* rec all SMT frames */ +#define FM_RCV1_NSMT (3<<0) /* rec non-SMT frames */ +#define FM_RCV1_IMP (4<<0) /* rec Implementor frames */ +#define FM_RCV1_MAC (5<<0) /* rec all MAC frames */ +#define FM_RCV1_SLLC (6<<0) /* rec all sync LLC frames */ +#define FM_RCV1_ALLC (7<<0) /* rec all async LLC frames */ +#define FM_RCV1_VOID (8<<0) /* rec all void frames */ +#define FM_RCV1_ALSMT (9<<0) /* rec all async LLC & SMT frames */ +#define FM_RECV2 0x00f0 /* options for receive queue 2 */ +#define FM_RCV2_ALL (0<<4) /* receive all other frames */ +#define FM_RCV2_LLC (1<<4) /* rec all LLC frames */ +#define FM_RCV2_SMT (2<<4) /* rec all SMT frames */ +#define FM_RCV2_NSMT (3<<4) /* rec non-SMT frames */ +#define FM_RCV2_IMP (4<<4) /* rec Implementor frames */ +#define FM_RCV2_MAC (5<<4) /* rec all MAC frames */ +#define FM_RCV2_SLLC (6<<4) /* rec all sync LLC frames */ +#define FM_RCV2_ALLC (7<<4) /* rec all async LLC frames */ +#define FM_RCV2_VOID (8<<4) /* rec all void frames */ +#define FM_RCV2_ALSMT (9<<4) /* rec all async LLC & SMT frames */ +#define FM_ENXMTADSWAP 0x4000 /* enh rec addr swap (phys -> can) */ +#define FM_ENRCVADSWAP 0x8000 /* enh tx addr swap (can -> phys) */ + +/* + * Supernet 3: + * Address Filter Command Register (AFCMD) + */ +#define FM_INST 0x0007 /* Address Filter Operation */ +#define FM_IINV_CAM (0<<0) /* Invalidate CAM */ +#define FM_IWRITE_CAM (1<<0) /* Write CAM */ +#define FM_IREAD_CAM (2<<0) /* Read CAM */ +#define FM_IRUN_BIST (3<<0) /* Run BIST */ +#define FM_IFIND (4<<0) /* Find */ +#define FM_IINV (5<<0) /* Invalidate */ +#define FM_ISKIP (6<<0) /* Skip */ +#define FM_ICL_SKIP (7<<0) /* Clear all SKIP bits */ + +/* + * Supernet 3: + * Address Filter Status Register (AFSTAT) + */ + /* Bit 0-4: reserved */ +#define FM_REV_NO 0x00e0 /* Revision Number of Address Filter */ +#define FM_BIST_DONE 0x0100 /* BIST complete */ +#define FM_EMPTY 0x0200 /* CAM empty */ +#define FM_ERROR 0x0400 /* Error (improper operation) */ +#define FM_MULT 0x0800 /* Multiple Match */ +#define FM_EXACT 0x1000 /* Exact Match */ +#define FM_FOUND 0x2000 /* Comparand found in CAM */ +#define FM_FULL 0x4000 /* CAM full */ +#define FM_DONE 0x8000 /* DONE indicator */ + +/* + * Supernet 3: + * BIST Signature Register (AFBIST) + */ +#define AF_BIST_SIGNAT 0x0553 /* Address Filter BIST Signature */ + +/* + * Supernet 3: + * Personality Register (AFPERS) + */ +#define FM_VALID 0x0001 /* CAM Entry Valid */ +#define FM_DA 0x0002 /* Destination Address */ +#define FM_DAX 0x0004 /* Destination Address Exact */ +#define FM_SA 0x0008 /* Source Address */ +#define FM_SAX 0x0010 /* Source Address Exact */ +#define FM_SKIP 0x0020 /* Skip this entry */ + +/* + * instruction set for command register 1 (NPADDR6-0 = 0x00) + */ +#define FM_IRESET 0x01 /* software reset */ +#define FM_IRMEMWI 0x02 /* load Memory Data Reg., inc MARR */ +#define FM_IRMEMWO 0x03 /* load MDR from buffer memory, n.i. */ +#define FM_IIL 0x04 /* idle/listen */ +#define FM_ICL 0x05 /* claim/listen */ +#define FM_IBL 0x06 /* beacon/listen */ +#define FM_ILTVX 0x07 /* load TVX timer from TVX reg */ +#define FM_INRTM 0x08 /* nonrestricted token mode */ +#define FM_IENTM 0x09 /* enter nonrestricted token mode */ +#define FM_IERTM 0x0a /* enter restricted token mode */ +#define FM_IRTM 0x0b /* restricted token mode */ +#define FM_ISURT 0x0c /* send unrestricted token */ +#define FM_ISRT 0x0d /* send restricted token */ +#define FM_ISIM 0x0e /* enter send-immediate mode */ +#define FM_IESIM 0x0f /* exit send-immediate mode */ +#define FM_ICLLS 0x11 /* clear synchronous queue lock */ +#define FM_ICLLA0 0x12 /* clear asynchronous queue 0 lock */ +#define FM_ICLLA1 0x14 /* clear asynchronous queue 1 lock */ +#define FM_ICLLA2 0x18 /* clear asynchronous queue 2 lock */ + /* SN3: reserved */ +#define FM_ICLLR 0x20 /* clear receive queue (SN3:1) lock */ +#define FM_ICLLR2 0x21 /* SN3: clear receive queue 2 lock */ +#define FM_ITRXBUS 0x22 /* SN3: Tristate X-Bus (SAS only) */ +#define FM_IDRXBUS 0x23 /* SN3: drive X-Bus */ +#define FM_ICLLAL 0x3f /* clear all queue locks */ + +/* + * instruction set for command register 2 (NPADDR6-0 = 0x01) + */ +#define FM_ITRS 0x01 /* transmit synchronous queue */ + /* SN3: reserved */ +#define FM_ITRA0 0x02 /* transmit asynchronous queue 0 */ + /* SN3: reserved */ +#define FM_ITRA1 0x04 /* transmit asynchronous queue 1 */ + /* SN3: reserved */ +#define FM_ITRA2 0x08 /* transmit asynchronous queue 2 */ + /* SN3: reserved */ +#define FM_IACTR 0x10 /* abort current transmit activity */ +#define FM_IRSTQ 0x20 /* reset transmit queues */ +#define FM_ISTTB 0x30 /* set tag bit */ +#define FM_IERSF 0x40 /* enable receive single frame */ + /* SN3: reserved */ +#define FM_ITR 0x50 /* SN3: Transmit Command */ + + +/* + * defines for PLC (Am79C864) + */ + +/* + * PLC read/write (r/w) registers + */ +#define PL_CNTRL_A 0x00 /* control register A (r/w) */ +#define PL_CNTRL_B 0x01 /* control register B (r/w) */ +#define PL_INTR_MASK 0x02 /* interrupt mask (r/w) */ +#define PL_XMIT_VECTOR 0x03 /* transmit vector register (r/w) */ +#define PL_VECTOR_LEN 0x04 /* transmit vector length (r/w) */ +#define PL_LE_THRESHOLD 0x05 /* link error event threshold (r/w) */ +#define PL_C_MIN 0x06 /* minimum connect state time (r/w) */ +#define PL_TL_MIN 0x07 /* min. line state transmit t. (r/w) */ +#define PL_TB_MIN 0x08 /* minimum break time (r/w) */ +#define PL_T_OUT 0x09 /* signal timeout (r/w) */ +#define PL_CNTRL_C 0x0a /* control register C (r/w) */ +#define PL_LC_LENGTH 0x0b /* link confidence test time (r/w) */ +#define PL_T_SCRUB 0x0c /* scrub time = MAC TVX (r/w) */ +#define PL_NS_MAX 0x0d /* max. noise time before break (r/w)*/ +#define PL_TPC_LOAD_V 0x0e /* TPC timer load value (write only) */ +#define PL_TNE_LOAD_V 0x0f /* TNE timer load value (write only) */ +#define PL_STATUS_A 0x10 /* status register A (read only) */ +#define PL_STATUS_B 0x11 /* status register B (read only) */ +#define PL_TPC 0x12 /* timer for PCM (ro) [20.48 us] */ +#define PL_TNE 0x13 /* time of noise event [0.32 us] */ +#define PL_CLK_DIV 0x14 /* TNE clock divider (read only) */ +#define PL_BIST_SIGNAT 0x15 /* built in self test signature (ro)*/ +#define PL_RCV_VECTOR 0x16 /* receive vector reg. (read only) */ +#define PL_INTR_EVENT 0x17 /* interrupt event reg. (read only) */ +#define PL_VIOL_SYM_CTR 0x18 /* violation symbol count. (read o) */ +#define PL_MIN_IDLE_CTR 0x19 /* minimum idle counter (read only) */ +#define PL_LINK_ERR_CTR 0x1a /* link error event ctr.(read only) */ +#ifdef MOT_ELM +#define PL_T_FOT_ASS 0x1e /* FOTOFF Assert Timer */ +#define PL_T_FOT_DEASS 0x1f /* FOTOFF Deassert Timer */ +#endif /* MOT_ELM */ + +#ifdef MOT_ELM +/* + * Special Quad-Elm Registers. + * A Quad-ELM consists of for ELMs and these additional registers. + */ +#define QELM_XBAR_W 0x80 /* Crossbar Control ELM W */ +#define QELM_XBAR_X 0x81 /* Crossbar Control ELM X */ +#define QELM_XBAR_Y 0x82 /* Crossbar Control ELM Y */ +#define QELM_XBAR_Z 0x83 /* Crossbar Control ELM Z */ +#define QELM_XBAR_P 0x84 /* Crossbar Control Bus P */ +#define QELM_XBAR_S 0x85 /* Crossbar Control Bus S */ +#define QELM_XBAR_R 0x86 /* Crossbar Control Bus R */ +#define QELM_WR_XBAR 0x87 /* Write the Crossbar now (write) */ +#define QELM_CTR_W 0x88 /* Counter W */ +#define QELM_CTR_X 0x89 /* Counter X */ +#define QELM_CTR_Y 0x8a /* Counter Y */ +#define QELM_CTR_Z 0x8b /* Counter Z */ +#define QELM_INT_MASK 0x8c /* Interrupt mask register */ +#define QELM_INT_DATA 0x8d /* Interrupt data (event) register */ +#define QELM_ELMB 0x00 /* Elm base */ +#define QELM_ELM_SIZE 0x20 /* ELM size */ +#endif /* MOT_ELM */ +/* + * PLC control register A (PL_CNTRL_A: log. addr. 0x00) + * It is used for timer configuration, specification of PCM MAINT state option, + * counter interrupt frequency, PLC data path config. and Built In Self Test. + */ +#define PL_RUN_BIST 0x0001 /* begin running its Built In Self T.*/ +#define PL_RF_DISABLE 0x0002 /* disable the Repeat Filter state m.*/ +#define PL_SC_REM_LOOP 0x0004 /* remote loopback path */ +#define PL_SC_BYPASS 0x0008 /* by providing a physical bypass */ +#define PL_LM_LOC_LOOP 0x0010 /* loop path just after elastic buff.*/ +#define PL_EB_LOC_LOOP 0x0020 /* loop path just prior to PDT/PDR IF*/ +#define PL_FOT_OFF 0x0040 /* assertion of /FOTOFF pin of PLC */ +#define PL_LOOPBACK 0x0080 /* it cause the /LPBCK pin ass. low */ +#define PL_MINI_CTR_INT 0x0100 /* partially contr. when bit is ass. */ +#define PL_VSYM_CTR_INT 0x0200 /* controls when int bit is asserted */ +#define PL_ENA_PAR_CHK 0x0400 /* enable parity check */ +#define PL_REQ_SCRUB 0x0800 /* limited access to scrub capability*/ +#define PL_TPC_16BIT 0x1000 /* causes the TPC as a 16 bit timer */ +#define PL_TNE_16BIT 0x2000 /* causes the TNE as a 16 bit timer */ +#define PL_NOISE_TIMER 0x4000 /* allows the noise timing function */ + +/* + * PLC control register B (PL_CNTRL_B: log. addr. 0x01) + * It contains signals and requeste to direct the process of PCM and it is also + * used to control the Line State Match interrupt. + */ +#define PL_PCM_CNTRL 0x0003 /* control PCM state machine */ +#define PL_PCM_NAF (0) /* state is not affected */ +#define PL_PCM_START (1) /* goes to the BREAK state */ +#define PL_PCM_TRACE (2) /* goes to the TRACE state */ +#define PL_PCM_STOP (3) /* goes to the OFF state */ + +#define PL_MAINT 0x0004 /* if OFF state --> MAINT state */ +#define PL_LONG 0x0008 /* perf. a long Link Confid.Test(LCT)*/ +#define PL_PC_JOIN 0x0010 /* if NEXT state --> JOIN state */ + +#define PL_PC_LOOP 0x0060 /* loopback used in the LCT */ +#define PL_NOLCT (0<<5) /* no LCT is performed */ +#define PL_TPDR (1<<5) /* PCM asserts transmit PDR */ +#define PL_TIDLE (2<<5) /* PCM asserts transmit idle */ +#define PL_RLBP (3<<5) /* trans. PDR & remote loopb. path */ + +#define PL_CLASS_S 0x0080 /* signif. that single att. station */ + +#define PL_MAINT_LS 0x0700 /* line state while in the MAINT st. */ +#define PL_M_QUI0 (0<<8) /* transmit QUIET line state */ +#define PL_M_IDLE (1<<8) /* transmit IDLE line state */ +#define PL_M_HALT (2<<8) /* transmit HALT line state */ +#define PL_M_MASTR (3<<8) /* transmit MASTER line state */ +#define PL_M_QUI1 (4<<8) /* transmit QUIET line state */ +#define PL_M_QUI2 (5<<8) /* transmit QUIET line state */ +#define PL_M_TPDR (6<<8) /* tr. PHY_DATA requ.-symbol is tr.ed*/ +#define PL_M_QUI3 (7<<8) /* transmit QUIET line state */ + +#define PL_MATCH_LS 0x7800 /* line state to be comp. with curr.*/ +#define PL_I_ANY (0<<11) /* Int. on any change in *_LINE_ST */ +#define PL_I_IDLE (1<<11) /* Interrupt on IDLE line state */ +#define PL_I_HALT (2<<11) /* Interrupt on HALT line state */ +#define PL_I_MASTR (4<<11) /* Interrupt on MASTER line state */ +#define PL_I_QUIET (8<<11) /* Interrupt on QUIET line state */ + +#define PL_CONFIG_CNTRL 0x8000 /* control over scrub, byp. & loopb.*/ + +/* + * PLC control register C (PL_CNTRL_C: log. addr. 0x0a) + * It contains the scrambling control registers (PLC-S only) + */ +#define PL_C_CIPHER_ENABLE (1<<0) /* enable scrambler */ +#define PL_C_CIPHER_LPBCK (1<<1) /* loopback scrambler */ +#define PL_C_SDOFF_ENABLE (1<<6) /* enable SDOFF timer */ +#define PL_C_SDON_ENABLE (1<<7) /* enable SDON timer */ +#ifdef MOT_ELM +#define PL_C_FOTOFF_CTRL (3<<2) /* FOTOFF timer control */ +#define PL_C_FOTOFF_TIM (0<<2) /* FOTOFF use timer for (de)-assert */ +#define PL_C_FOTOFF_INA (2<<2) /* FOTOFF forced inactive */ +#define PL_C_FOTOFF_ACT (3<<2) /* FOTOFF forced active */ +#define PL_C_FOTOFF_SRCE (1<<4) /* FOTOFF source is PCM state != OFF */ +#define PL_C_RXDATA_EN (1<<5) /* Rec scr data forced to 0 */ +#define PL_C_SDNRZEN (1<<8) /* Monitor rec descr. data for act */ +#else /* nMOT_ELM */ +#define PL_C_FOTOFF_CTRL (3<<8) /* FOTOFF timer control */ +#define PL_C_FOTOFF_0 (0<<8) /* timer off */ +#define PL_C_FOTOFF_30 (1<<8) /* 30uS */ +#define PL_C_FOTOFF_50 (2<<8) /* 50uS */ +#define PL_C_FOTOFF_NEVER (3<<8) /* never */ +#define PL_C_SDON_TIMER (3<<10) /* SDON timer control */ +#define PL_C_SDON_084 (0<<10) /* 0.84 uS */ +#define PL_C_SDON_132 (1<<10) /* 1.32 uS */ +#define PL_C_SDON_252 (2<<10) /* 2.52 uS */ +#define PL_C_SDON_512 (3<<10) /* 5.12 uS */ +#define PL_C_SOFF_TIMER (3<<12) /* SDOFF timer control */ +#define PL_C_SOFF_076 (0<<12) /* 0.76 uS */ +#define PL_C_SOFF_132 (1<<12) /* 1.32 uS */ +#define PL_C_SOFF_252 (2<<12) /* 2.52 uS */ +#define PL_C_SOFF_512 (3<<12) /* 5.12 uS */ +#define PL_C_TSEL (3<<14) /* scrambler path select */ +#endif /* nMOT_ELM */ + +/* + * PLC status register A (PL_STATUS_A: log. addr. 0x10) + * It is used to report status information to the Node Processor about the + * Line State Machine (LSM). + */ +#ifdef MOT_ELM +#define PLC_INT_MASK 0xc000 /* ELM integration bits in status A */ +#define PLC_INT_C 0x0000 /* ELM Revision Band C */ +#define PLC_INT_CAMEL 0x4000 /* ELM integrated into CAMEL */ +#define PLC_INT_QE 0x8000 /* ELM integrated into Quad ELM */ +#define PLC_REV_MASK 0x3800 /* revision bits in status A */ +#define PLC_REVISION_B 0x0000 /* rev bits for ELM Rev B */ +#define PLC_REVISION_QA 0x0800 /* rev bits for ELM core in QELM-A */ +#else /* nMOT_ELM */ +#define PLC_REV_MASK 0xf800 /* revision bits in status A */ +#define PLC_REVISION_A 0x0000 /* revision bits for PLC */ +#define PLC_REVISION_S 0xf800 /* revision bits for PLC-S */ +#define PLC_REV_SN3 0x7800 /* revision bits for PLC-S in IFCP */ +#endif /* nMOT_ELM */ +#define PL_SYM_PR_CTR 0x0007 /* contains the LSM symbol pair Ctr. */ +#define PL_UNKN_LINE_ST 0x0008 /* unknown line state bit from LSM */ +#define PL_LSM_STATE 0x0010 /* state bit of LSM */ + +#define PL_LINE_ST 0x00e0 /* contains recogn. line state of LSM*/ +#define PL_L_NLS (0<<5) /* noise line state */ +#define PL_L_ALS (1<<5) /* activ line state */ +#define PL_L_UND (2<<5) /* undefined */ +#define PL_L_ILS4 (3<<5) /* idle l. s. (after 4 idle symbols) */ +#define PL_L_QLS (4<<5) /* quiet line state */ +#define PL_L_MLS (5<<5) /* master line state */ +#define PL_L_HLS (6<<5) /* halt line state */ +#define PL_L_ILS16 (7<<5) /* idle line state (after 16 idle s.)*/ + +#define PL_PREV_LINE_ST 0x0300 /* value of previous line state */ +#define PL_P_QLS (0<<8) /* quiet line state */ +#define PL_P_MLS (1<<8) /* master line state */ +#define PL_P_HLS (2<<8) /* halt line state */ +#define PL_P_ILS16 (3<<8) /* idle line state (after 16 idle s.)*/ + +#define PL_SIGNAL_DET 0x0400 /* 1=that signal detect is deasserted*/ + + +/* + * PLC status register B (PL_STATUS_B: log. addr. 0x11) + * It contains signals and status from the repeat filter and PCM state machine. + */ +#define PL_BREAK_REASON 0x0007 /* reason for PCM state mach.s to br.*/ +#define PL_B_NOT (0) /* PCM SM has not gone to BREAK state*/ +#define PL_B_PCS (1) /* PC_Start issued */ +#define PL_B_TPC (2) /* TPC timer expired after T_OUT */ +#define PL_B_TNE (3) /* TNE timer expired after NS_MAX */ +#define PL_B_QLS (4) /* quit line state detected */ +#define PL_B_ILS (5) /* idle line state detected */ +#define PL_B_HLS (6) /* halt line state detected */ + +#define PL_TCF 0x0008 /* transmit code flag (start exec.) */ +#define PL_RCF 0x0010 /* receive code flag (start exec.) */ +#define PL_LSF 0x0020 /* line state flag (l.s. has been r.)*/ +#define PL_PCM_SIGNAL 0x0040 /* indic. that XMIT_VECTOR hb.written*/ + +#define PL_PCM_STATE 0x0780 /* state bits of PCM state machine */ +#define PL_PC0 (0<<7) /* OFF - when /RST or PCM_CNTRL */ +#define PL_PC1 (1<<7) /* BREAK - entry point in start PCM*/ +#define PL_PC2 (2<<7) /* TRACE - to localize stuck Beacon*/ +#define PL_PC3 (3<<7) /* CONNECT - synchronize ends of conn*/ +#define PL_PC4 (4<<7) /* NEXT - to seperate the signalng*/ +#define PL_PC5 (5<<7) /* SIGNAL - PCM trans/rec. bit infos*/ +#define PL_PC6 (6<<7) /* JOIN - 1. state to activ conn. */ +#define PL_PC7 (7<<7) /* VERIFY - 2. - " - (3. ACTIVE) */ +#define PL_PC8 (8<<7) /* ACTIVE - PHY has been incorporated*/ +#define PL_PC9 (9<<7) /* MAINT - for test purposes or so + that PCM op. completely in softw. */ + +#define PL_PCI_SCRUB 0x0800 /* scrubbing function is being exec. */ + +#define PL_PCI_STATE 0x3000 /* Physical Connect. Insertion SM */ +#define PL_CI_REMV (0<<12) /* REMOVED */ +#define PL_CI_ISCR (1<<12) /* INSERT_SCRUB */ +#define PL_CI_RSCR (2<<12) /* REMOVE_SCRUB */ +#define PL_CI_INS (3<<12) /* INSERTED */ + +#define PL_RF_STATE 0xc000 /* state bit of repeate filter SM */ +#define PL_RF_REPT (0<<14) /* REPEAT */ +#define PL_RF_IDLE (1<<14) /* IDLE */ +#define PL_RF_HALT1 (2<<14) /* HALT1 */ +#define PL_RF_HALT2 (3<<14) /* HALT2 */ + + +/* + * PLC interrupt event register (PL_INTR_EVENT: log. addr. 0x17) + * It is read only and is clearde whenever it is read! + * It is used by the PLC to report events to the node processor. + */ +#define PL_PARITY_ERR 0x0001 /* p. error h.b.detected on TX9-0 inp*/ +#define PL_LS_MATCH 0x0002 /* l.s.== l.s. PLC_CNTRL_B's MATCH_LS*/ +#define PL_PCM_CODE 0x0004 /* transmit&receive | LCT complete */ +#define PL_TRACE_PROP 0x0008 /* master l.s. while PCM ACTIV|TRACE */ +#define PL_SELF_TEST 0x0010 /* QUIET|HALT while PCM in TRACE st. */ +#define PL_PCM_BREAK 0x0020 /* PCM has entered the BREAK state */ +#define PL_PCM_ENABLED 0x0040 /* asserted SC_JOIN, scrub. & ACTIV */ +#define PL_TPC_EXPIRED 0x0080 /* TPC timer reached zero */ +#define PL_TNE_EXPIRED 0x0100 /* TNE timer reached zero */ +#define PL_EBUF_ERR 0x0200 /* elastic buff. det. over-|underflow*/ +#define PL_PHYINV 0x0400 /* physical layer invalid signal */ +#define PL_VSYM_CTR 0x0800 /* violation symbol counter has incr.*/ +#define PL_MINI_CTR 0x1000 /* dep. on PLC_CNTRL_A's MINI_CTR_INT*/ +#define PL_LE_CTR 0x2000 /* link error event counter */ +#define PL_LSDO 0x4000 /* SDO input pin changed to a 1 */ +#define PL_NP_ERR 0x8000 /* NP has requested to r/w an inv. r.*/ + +/* + * The PLC interrupt mask register (PL_INTR_MASK: log. addr. 0x02) constr. is + * equal PL_INTR_EVENT register. + * For each set bit, the setting of corresponding bit generate an int to NP. + */ + +#ifdef MOT_ELM +/* + * Quad ELM Crosbar Control register values (QELM_XBAR_?) + */ +#define QELM_XOUT_IDLE 0x0000 /* Idles/Passthrough */ +#define QELM_XOUT_P 0x0001 /* Output to: Bus P */ +#define QELM_XOUT_S 0x0002 /* Output to: Bus S */ +#define QELM_XOUT_R 0x0003 /* Output to: Bus R */ +#define QELM_XOUT_W 0x0004 /* Output to: ELM W */ +#define QELM_XOUT_X 0x0005 /* Output to: ELM X */ +#define QELM_XOUT_Y 0x0006 /* Output to: ELM Y */ +#define QELM_XOUT_Z 0x0007 /* Output to: ELM Z */ + +/* + * Quad ELM Interrupt data and event registers. + */ +#define QELM_NP_ERR (1<<15) /* Node Processor Error */ +#define QELM_COUNT_Z (1<<7) /* Counter Z Interrupt */ +#define QELM_COUNT_Y (1<<6) /* Counter Y Interrupt */ +#define QELM_COUNT_X (1<<5) /* Counter X Interrupt */ +#define QELM_COUNT_W (1<<4) /* Counter W Interrupt */ +#define QELM_ELM_Z (1<<3) /* ELM Z Interrupt */ +#define QELM_ELM_Y (1<<2) /* ELM Y Interrupt */ +#define QELM_ELM_X (1<<1) /* ELM X Interrupt */ +#define QELM_ELM_W (1<<0) /* ELM W Interrupt */ +#endif /* MOT_ELM */ +/* + * PLC Timing Parameters + */ +#define TP_C_MIN 0xff9c /* 2 ms */ +#define TP_TL_MIN 0xfff0 /* 0.3 ms */ +#define TP_TB_MIN 0xff10 /* 5 ms */ +#define TP_T_OUT 0xd9db /* 200 ms */ +#define TP_LC_LENGTH 0xf676 /* 50 ms */ +#define TP_LC_LONGLN 0xa0a2 /* 500 ms */ +#define TP_T_SCRUB 0xff6d /* 3.5 ms */ +#define TP_NS_MAX 0xf021 /* 1.3 ms */ + +/* + * BIST values + */ +#define PLC_BIST 0x6ecd /* BIST signature for PLC */ +#define PLCS_BIST 0x5b6b /* BIST signature for PLC-S */ +#define PLC_ELM_B_BIST 0x6ecd /* BIST signature of ELM Rev. B */ +#define PLC_ELM_D_BIST 0x5b6b /* BIST signature of ELM Rev. D */ +#define PLC_CAM_A_BIST 0x9e75 /* BIST signature of CAMEL Rev. A */ +#define PLC_CAM_B_BIST 0x5b6b /* BIST signature of CAMEL Rev. B */ +#define PLC_IFD_A_BIST 0x9e75 /* BIST signature of IFDDI Rev. A */ +#define PLC_IFD_B_BIST 0x5b6b /* BIST signature of IFDDI Rev. B */ +#define PLC_QELM_A_BIST 0x5b6b /* BIST signature of QELM Rev. A */ + +/* + FDDI board recources + */ + +/* + * request register array (log. addr: RQA_A + a<<1 {a=0..7}) write only. + * It specifies to FORMAC+ the type of buffer memory access the host requires. + */ +#define RQ_NOT 0 /* not request */ +#define RQ_RES 1 /* reserved */ +#define RQ_SFW 2 /* special frame write */ +#define RQ_RRQ 3 /* read request: receive queue */ +#define RQ_WSQ 4 /* write request: synchronous queue */ +#define RQ_WA0 5 /* write requ.: asynchronous queue 0 */ +#define RQ_WA1 6 /* write requ.: asynchronous queue 1 */ +#define RQ_WA2 7 /* write requ.: asynchronous queue 2 */ + +#define SZ_LONG (sizeof(long)) + +/* + * FDDI defaults + * NOTE : In the ANSI docs, times are specified in units of "symbol time". + * AMD chips use BCLK as unit. 1 BCKL == 2 symbols + */ +#define COMPLREF ((u_long)32*256*256) /* two's complement 21 bit */ +#define MSTOBCLK(x) ((u_long)(x)*12500L) +#define MSTOTVX(x) (((u_long)(x)*1000L)/80/255) + +#endif /* _SUPERNET_ */ diff -u --recursive --new-file v2.3.46/linux/drivers/net/skfp/h/targethw.h linux/drivers/net/skfp/h/targethw.h --- v2.3.46/linux/drivers/net/skfp/h/targethw.h Wed Dec 31 16:00:00 1969 +++ linux/drivers/net/skfp/h/targethw.h Fri Feb 18 14:55:53 2000 @@ -0,0 +1,173 @@ +/****************************************************************************** + * + * (C)Copyright 1998,1999 SysKonnect, + * a business unit of Schneider & Koch & Co. Datensysteme GmbH. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * The information in this file is provided "AS IS" without warranty. + * + ******************************************************************************/ + +#ifndef _TARGETHW_ +#define _TARGETHW_ + + /* + * PCI Watermark definition + */ +#ifdef PCI +#define RX_WATERMARK 24 +#define TX_WATERMARK 24 +#define SK_ML_ID_1 0x20 +#define SK_ML_ID_2 0x30 +#endif + +#include "h/skfbi.h" +#ifndef TAG_MODE +#include "h/fplus.h" +#else +#include "h/fplustm.h" +#endif + +#ifndef HW_PTR +#ifdef MEM_MAPPED_IO +#define HW_PTR u_long +#else +#define HW_PTR u_short +#endif +#endif + +#ifdef MULT_OEM +#define OI_STAT_LAST 0 /* end of OEM data base */ +#define OI_STAT_PRESENT 1 /* entry present but not empty */ +#define OI_STAT_VALID 2 /* holds valid ID, but is not active */ +#define OI_STAT_ACTIVE 3 /* holds valid ID, entry is active */ + /* active = adapter is supported */ + +/* Memory representation of IDs must match representation in adapter. */ +struct s_oem_ids { + u_char oi_status ; /* Stat: last, present, valid, active */ + u_char oi_mark[5] ; /* "PID00" .. "PID07" .. */ + u_char oi_id[4] ; /* id bytes, representation as */ + /* defined by hardware, */ +#ifdef PCI + u_char oi_sub_id[4] ; /* sub id bytes, representation as */ + /* defined by hardware, */ +#endif +#ifdef ISA + u_char oi_logo_len ; /* the length of the adapter logo */ + u_char oi_logo[6] ; /* the adapter logo */ + u_char oi_reserved1 ; +#endif /* ISA */ +} ; +#endif /* MULT_OEM */ + + +struct s_smt_hw { + /* + * global + */ + HW_PTR iop ; /* IO base address */ + short dma ; /* DMA channel */ + short irq ; /* IRQ level */ + short eprom ; /* FLASH prom */ +#ifndef PCI + short DmaWriteExtraBytes ; /* add bytes for DMA write */ +#endif + +#ifndef SYNC + u_short n_a_send ; /* pending send requests */ +#endif + +#if (defined(EISA) || defined(MCA) || defined(PCI)) + short slot ; /* slot number */ + short max_slots ; /* maximum number of slots */ +#endif + +#if (defined(PCI) || defined(MCA)) + short wdog_used ; /* TRUE if the watch dog is used */ +#endif + +#ifdef MCA + short slot_32 ; /* 32bit slot (1) or 16bit slot (0) */ + short rev ; /* Board revision (FMx_REV). */ + short VFullRead ; /* V_full value for DMA read */ + short VFullWrite ; /* V_full value for DMA write */ +#endif + +#ifdef EISA + short led ; /* LED for FE card */ + + short dma_rmode ; /* read mode */ + short dma_wmode ; /* write mode */ + short dma_emode ; /* extend mode */ + + /* DMA controller channel dependent io addresses */ + u_short dma_base_word_count ; + u_short dma_base_address ; + u_short dma_base_address_page ; +#endif + +#ifdef PCI + u_short pci_handle ; /* handle to access the BIOS func */ + u_long is_imask ; /* int maske for the int source reg */ + u_long phys_mem_addr ; /* physical memory address */ + u_short mc_dummy ; /* work around for MC compiler bug */ + /* + * state of the hardware + */ + u_short hw_state ; /* started or stopped */ + +#define STARTED 1 +#define STOPPED 0 + + int hw_is_64bit ; /* does we have a 64 bit adapter */ +#endif + +#ifdef TAG_MODE + u_long pci_fix_value ; /* value parsed by PCIFIX */ +#endif + + /* + * hwt.c + */ + u_long t_start ; /* HWT start */ + u_long t_stop ; /* HWT stop */ + u_short timer_activ ; /* HWT timer active */ + + /* + * PIC + */ + u_char pic_a1 ; + u_char pic_21 ; + + /* + * GENERIC ; do not modify beyond this line + */ + + /* + * physical and canonical address + */ + struct fddi_addr fddi_home_addr ; + struct fddi_addr fddi_canon_addr ; + struct fddi_addr fddi_phys_addr ; + + /* + * mac variables + */ + struct mac_parameter mac_pa ; /* tmin, tmax, tvx, treq .. */ + struct mac_counter mac_ct ; /* recv., lost, error */ + u_short mac_ring_is_up ; /* ring is up flag */ + + struct s_smt_fp fp ; /* formac+ */ + +#ifdef MULT_OEM + struct s_oem_ids *oem_id ; /* pointer to selected id */ + int oem_min_status ; /* IDs to take care of */ +#endif /* MULT_OEM */ + +} ; +#endif diff -u --recursive --new-file v2.3.46/linux/drivers/net/skfp/h/targetos.h linux/drivers/net/skfp/h/targetos.h --- v2.3.46/linux/drivers/net/skfp/h/targetos.h Wed Dec 31 16:00:00 1969 +++ linux/drivers/net/skfp/h/targetos.h Fri Feb 18 14:55:53 2000 @@ -0,0 +1,163 @@ +/****************************************************************************** + * + * (C)Copyright 1998,1999 SysKonnect, + * a business unit of Schneider & Koch & Co. Datensysteme GmbH. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * The information in this file is provided "AS IS" without warranty. + * + ******************************************************************************/ + +/* + * Operating system specific definitions for driver and + * hardware module. + */ + +#ifndef TARGETOS_H +#define TARGETOS_H + + +//-------- those should go into include/linux/pci.h +#define PCI_VENDOR_ID_SK 0x1148 +#define PCI_DEVICE_ID_SK_FP 0x4000 +//-------- + + + +//-------- those should go into include/linux/if_fddi.h +#define FDDI_MAC_HDR_LEN 13 + +#define FDDI_RII 0x01 /* routing information bit */ +#define FDDI_RCF_DIR_BIT 0x80 +#define FDDI_RCF_LEN_MASK 0x1f +#define FDDI_RCF_BROADCAST 0x8000 +#define FDDI_RCF_LIMITED_BROADCAST 0xA000 +#define FDDI_RCF_FRAME2K 0x20 +#define FDDI_RCF_FRAME4K 0x30 +//-------- + + +#undef ADDR + +#include +#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 -u --recursive --new-file v2.3.46/linux/drivers/net/skfp/h/types.h linux/drivers/net/skfp/h/types.h --- v2.3.46/linux/drivers/net/skfp/h/types.h Wed Dec 31 16:00:00 1969 +++ linux/drivers/net/skfp/h/types.h Fri Feb 18 14:55:53 2000 @@ -0,0 +1,48 @@ +/****************************************************************************** + * + * (C)Copyright 1998,1999 SysKonnect, + * a business unit of Schneider & Koch & Co. Datensysteme GmbH. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * The information in this file is provided "AS IS" without warranty. + * + ******************************************************************************/ + +#include +/* + ---------------------- + Basic SMT system types + ---------------------- +*/ +#ifndef _TYPES_ +#define _TYPES_ + +#define _packed +#ifndef far +#define far +#endif +#ifndef _far +#define _far +#endif + +#ifndef MEM_MAPPED_IO // "normal" IO +#define inp(p) inb(p) +#define inpw(p) inw(p) +#define inpd(p) inl(p) +#define outp(p,c) outb(c,p) +#define outpw(p,s) outw(s,p) +#define outpd(p,l) outl(l,p) +#else // memory mapped io +#define inp(a) readb(a) +#define inpw(a) readw(a) +#define inpd(a) readl(a) +#define outp(a,v) writeb(v, a) +#define outpw(a,v) writew(v, a) +#define outpd(a,v) writel(v, a) +#endif + +#endif /* _TYPES_ */ diff -u --recursive --new-file v2.3.46/linux/drivers/net/skfp/hwmtm.c linux/drivers/net/skfp/hwmtm.c --- v2.3.46/linux/drivers/net/skfp/hwmtm.c Wed Dec 31 16:00:00 1969 +++ linux/drivers/net/skfp/hwmtm.c Fri Feb 18 14:55:53 2000 @@ -0,0 +1,2261 @@ +/****************************************************************************** + * + * (C)Copyright 1998,1999 SysKonnect, + * a business unit of Schneider & Koch & Co. Datensysteme GmbH. + * + * See the file "skfddi.c" for further information. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * The information in this file is provided "AS IS" without warranty. + * + ******************************************************************************/ + +#ifndef lint +static char const ID_sccs[] = "@(#)hwmtm.c 1.40 99/05/31 (C) SK" ; +#endif + +#define HWMTM + +#ifndef FDDI +#define FDDI +#endif + +#include "h/types.h" +#include "h/fddi.h" +#include "h/smc.h" +#include "h/supern_2.h" +#include "h/skfbiinc.h" + +/* + ------------------------------------------------------------- + DOCUMENTATION + ------------------------------------------------------------- + BEGIN_MANUAL_ENTRY(DOCUMENTATION) + + T B D + + END_MANUAL_ENTRY +*/ +/* + ------------------------------------------------------------- + LOCAL VARIABLES: + ------------------------------------------------------------- +*/ +#ifdef COMMON_MB_POOL +static SMbuf *mb_start = 0 ; +static SMbuf *mb_free = 0 ; +static int mb_init = FALSE ; +static int call_count = 0 ; +#endif + +/* + ------------------------------------------------------------- + EXTERNE VARIABLES: + ------------------------------------------------------------- +*/ + +#ifdef DEBUG +#ifndef DEBUG_BRD +extern struct smt_debug debug ; +#endif +#endif + +#ifdef NDIS_OS2 +extern u_char offDepth ; +extern u_char force_irq_pending ; +#endif + +/* + ------------------------------------------------------------- + LOCAL FUNCTIONS: + ------------------------------------------------------------- +*/ + +static void queue_llc_rx(), smt_to_llc(), + init_txd_ring(), init_rxd_ring(), + queue_txd_mb() ; + +static u_long init_descr_ring(), repair_txd_ring(), + repair_rxd_ring() ; + +static SMbuf *get_llc_rx(), *get_txd_mb() ; + + +/* + ------------------------------------------------------------- + EXTERNAL FUNCTIONS: + ------------------------------------------------------------- +*/ +/* The external SMT functions are listed in cmtdef.h */ + +extern void *mac_drv_get_space(), *mac_drv_get_desc_mem(), + init_board(), mac_drv_fill_rxd(), + plc1_irq(), mac_drv_tx_complete(), + plc2_irq(), mac1_irq(), + mac2_irq(), mac3_irq(), + timer_irq(), mac_drv_rx_complete(), + mac_drv_requeue_rxd(), init_plc(), + mac_drv_clear_rxd(), llc_restart_tx(), + ev_dispatcher(), smt_force_irq() ; + +#ifdef USE_OS_CPY +extern void hwm_cpy_rxd2mb(), hwm_cpy_txd2mb() ; +#endif +#ifdef ALL_RX_COMPLETE +extern void mac_drv_all_receives_complete() ; +#endif + +extern u_long mac_drv_virt2phys(), dma_master() ; + +#ifdef NDIS_OS2 +extern void post_proc() ; +#else +extern void dma_complete() ; +#endif + +extern int init_fplus(), mac_drv_rx_init() ; + +/* + ------------------------------------------------------------- + PUBLIC FUNCTIONS: + ------------------------------------------------------------- +*/ + void process_receive(), smt_send_mbuf(), + fddi_isr(), mac_drv_clear_txd(), + smt_free_mbuf(), init_driver_fplus(), + mac_drv_rx_mode(), init_fddi_driver(), + mac_drv_clear_tx_queue(), + mac_drv_clear_rx_queue(), + hwm_tx_frag(), hwm_rx_frag() ; + + int mac_drv_rx_frag(), mac_drv_init(), + hwm_tx_init() ; + + u_int mac_drv_check_space() ; + + SMbuf *smt_get_mbuf() ; + +#ifdef DEBUG + void mac_drv_debug_lev() ; +#endif + +/* + ------------------------------------------------------------- + MACROS: + ------------------------------------------------------------- +*/ +#ifndef UNUSED +#ifdef lint +#define UNUSED(x) (x) = (x) +#else +#define UNUSED(x) +#endif +#endif + +#ifdef USE_CAN_ADDR +#define MA smc->hw.fddi_canon_addr.a +#define GROUP_ADDR_BIT 0x01 +#else +#define MA smc->hw.fddi_home_addr.a +#define GROUP_ADDR_BIT 0x80 +#endif + +#define RXD_TXD_COUNT (HWM_ASYNC_TXD_COUNT+HWM_SYNC_TXD_COUNT+\ + SMT_R1_RXD_COUNT+SMT_R2_RXD_COUNT) + +#ifdef MB_OUTSIDE_SMC +#define EXT_VIRT_MEM ((RXD_TXD_COUNT+1)*sizeof(struct s_smt_fp_txd) +\ + MAX_MBUF*sizeof(SMbuf)) +#define EXT_VIRT_MEM_2 ((RXD_TXD_COUNT+1)*sizeof(struct s_smt_fp_txd)) +#else +#define EXT_VIRT_MEM ((RXD_TXD_COUNT+1)*sizeof(struct s_smt_fp_txd)) +#endif + + /* + * define critical read for 16 Bit drivers + */ +#if defined(NDIS_OS2) || defined(ODI2) +#define CR_READ(var) ((var) & 0xffff0000 | ((var) & 0xffff)) +#else +#define CR_READ(var) (u_long)(var) +#endif + +#define IMASK_SLOW (IS_PLINT1 | IS_PLINT2 | IS_TIMINT | IS_TOKEN | \ + IS_MINTR1 | IS_MINTR2 | IS_MINTR3 | IS_R1_P | \ + IS_R1_C | IS_XA_C | IS_XS_C) + +/* + ------------------------------------------------------------- + INIT- AND SMT FUNCTIONS: + ------------------------------------------------------------- +*/ + + +/* + * BEGIN_MANUAL_ENTRY(mac_drv_check_space) + * u_int mac_drv_check_space() + * + * function DOWNCALL (drvsr.c) + * This function calculates the needed non virtual + * memory for MBufs, RxD and TxD descriptors etc. + * needed by the driver. + * + * return u_int memory in bytes + * + * END_MANUAL_ENTRY + */ +u_int mac_drv_check_space() +{ +#ifdef MB_OUTSIDE_SMC +#ifdef COMMON_MB_POOL + call_count++ ; + if (call_count == 1) { + return(EXT_VIRT_MEM) ; + } + else { + return(EXT_VIRT_MEM_2) ; + } +#else + return (EXT_VIRT_MEM) ; +#endif +#else + return (0) ; +#endif +} + +/* + * BEGIN_MANUAL_ENTRY(mac_drv_init) + * void mac_drv_init(smc) + * + * function DOWNCALL (drvsr.c) + * In this function the hardware module allocates it's + * memory. + * The operating system dependent module should call + * mac_drv_init once, after the adatper is detected. + * END_MANUAL_ENTRY + */ +int mac_drv_init(smc) +struct s_smc *smc ; +{ + if (sizeof(struct s_smt_fp_rxd) % 16) { + SMT_PANIC(smc,HWM_E0001,HWM_E0001_MSG) ; + } + if (sizeof(struct s_smt_fp_txd) % 16) { + SMT_PANIC(smc,HWM_E0002,HWM_E0002_MSG) ; + } + + /* + * get the required memory for the RxDs and TxDs + */ + if (!(smc->os.hwm.descr_p = (union s_fp_descr volatile *) + mac_drv_get_desc_mem(smc,(u_int) + (RXD_TXD_COUNT+1)*sizeof(struct s_smt_fp_txd)))) { + return(1) ; /* no space the hwm modul can't work */ + } + + /* + * get the memory for the SMT MBufs + */ +#ifndef MB_OUTSIDE_SMC + smc->os.hwm.mbuf_pool.mb_start=(SMbuf *)(&smc->os.hwm.mbuf_pool.mb[0]) ; +#else +#ifndef COMMON_MB_POOL + if (!(smc->os.hwm.mbuf_pool.mb_start = (SMbuf *) mac_drv_get_space(smc, + MAX_MBUF*sizeof(SMbuf)))) { + return(1) ; /* no space the hwm modul can't work */ + } +#else + if (!mb_start) { + if (!(mb_start = (SMbuf *) mac_drv_get_space(smc, + MAX_MBUF*sizeof(SMbuf)))) { + return(1) ; /* no space the hwm modul can't work */ + } + } +#endif +#endif + return (0) ; +} + +/* + * BEGIN_MANUAL_ENTRY(init_driver_fplus) + * init_driver_fplus(smc) + * + * Sets hardware modul specific values for the mode register 2 + * (e.g. the byte alignment for the received frames, the position of the + * least significant byte etc.) + * END_MANUAL_ENTRY + */ +void init_driver_fplus(smc) +struct s_smc *smc ; +{ + smc->hw.fp.mdr2init = FM_LSB | FM_BMMODE | FM_ENNPRQ | FM_ENHSRQ | 3 ; + +#ifdef PCI + smc->hw.fp.mdr2init |= FM_CHKPAR | FM_PARITY ; +#endif + smc->hw.fp.mdr3init = FM_MENRQAUNLCK | FM_MENRS ; + +#ifdef USE_CAN_ADDR + /* enable address bit swapping */ + smc->hw.fp.frselreg_init = FM_ENXMTADSWAP | FM_ENRCVADSWAP ; +#endif +} + +static u_long init_descr_ring(smc,start,count) +struct s_smc *smc ; +union s_fp_descr volatile *start; +int count ; +{ + int i ; + union s_fp_descr volatile *d1 ; + union s_fp_descr volatile *d2 ; + u_long phys ; + + DB_GEN("descr ring starts at = %x ",(void *)start,0,3) ; + for (i=count-1, d1=start; i ; i--) { + d2 = d1 ; + d1++ ; /* descr is owned by the host */ + d2->r.rxd_rbctrl = AIX_REVERSE(BMU_CHECK) ; + d2->r.rxd_next = &d1->r ; + phys = mac_drv_virt2phys(smc,(void *)d1) ; + d2->r.rxd_nrdadr = AIX_REVERSE(phys) ; + } + DB_GEN("descr ring ends at = %x ",(void *)d1,0,3) ; + d1->r.rxd_rbctrl = AIX_REVERSE(BMU_CHECK) ; + d1->r.rxd_next = &start->r ; + phys = mac_drv_virt2phys(smc,(void *)start) ; + d1->r.rxd_nrdadr = AIX_REVERSE(phys) ; + + for (i=count, d1=start; i ; i--) { + DRV_BUF_FLUSH(&d1->r,DDI_DMA_SYNC_FORDEV) ; + d1++; + } + return(phys) ; +} + +static void init_txd_ring(smc) +struct s_smc *smc ; +{ + struct s_smt_fp_txd volatile *ds ; + struct s_smt_tx_queue *queue ; + u_long phys ; + + /* + * initialize the transmit descriptors + */ + ds = (struct s_smt_fp_txd volatile *) ((char *)smc->os.hwm.descr_p + + SMT_R1_RXD_COUNT*sizeof(struct s_smt_fp_rxd)) ; + queue = smc->hw.fp.tx[QUEUE_A0] ; + DB_GEN("Init async TxD ring, %d TxDs ",HWM_ASYNC_TXD_COUNT,0,3) ; + (void)init_descr_ring(smc,(union s_fp_descr volatile *)ds, + HWM_ASYNC_TXD_COUNT) ; + phys = AIX_REVERSE(ds->txd_ntdadr) ; + ds++ ; + queue->tx_curr_put = queue->tx_curr_get = ds ; + ds-- ; + queue->tx_free = HWM_ASYNC_TXD_COUNT ; + queue->tx_used = 0 ; + outpd(ADDR(B5_XA_DA),phys) ; + + ds = (struct s_smt_fp_txd volatile *) ((char *)ds + + HWM_ASYNC_TXD_COUNT*sizeof(struct s_smt_fp_txd)) ; + queue = smc->hw.fp.tx[QUEUE_S] ; + DB_GEN("Init sync TxD ring, %d TxDs ",HWM_SYNC_TXD_COUNT,0,3) ; + (void)init_descr_ring(smc,(union s_fp_descr volatile *)ds, + HWM_SYNC_TXD_COUNT) ; + phys = AIX_REVERSE(ds->txd_ntdadr) ; + ds++ ; + queue->tx_curr_put = queue->tx_curr_get = ds ; + queue->tx_free = HWM_SYNC_TXD_COUNT ; + queue->tx_used = 0 ; + outpd(ADDR(B5_XS_DA),phys) ; +} + +static void init_rxd_ring(smc) +struct s_smc *smc ; +{ + struct s_smt_fp_rxd volatile *ds ; + struct s_smt_rx_queue *queue ; + u_long phys ; + + /* + * initialize the receive descriptors + */ + ds = (struct s_smt_fp_rxd volatile *) smc->os.hwm.descr_p ; + queue = smc->hw.fp.rx[QUEUE_R1] ; + DB_GEN("Init RxD ring, %d RxDs ",SMT_R1_RXD_COUNT,0,3) ; + (void)init_descr_ring(smc,(union s_fp_descr volatile *)ds, + SMT_R1_RXD_COUNT) ; + phys = AIX_REVERSE(ds->rxd_nrdadr) ; + ds++ ; + queue->rx_curr_put = queue->rx_curr_get = ds ; + queue->rx_free = SMT_R1_RXD_COUNT ; + queue->rx_used = 0 ; + outpd(ADDR(B4_R1_DA),phys) ; +} + +/* + * BEGIN_MANUAL_ENTRY(init_fddi_driver) + * void init_fddi_driver(smc,mac_addr) + * + * initializes the driver and it's variables + * + * END_MANUAL_ENTRY + */ +void init_fddi_driver(smc,mac_addr) +struct s_smc *smc ; +u_char *mac_addr ; /* canonical address */ +{ + SMbuf *mb ; + int i ; + + init_board(smc,mac_addr) ; + (void)init_fplus(smc) ; + + /* + * initialize the SMbufs for the SMT + */ +#ifndef COMMON_MB_POOL + mb = smc->os.hwm.mbuf_pool.mb_start ; + smc->os.hwm.mbuf_pool.mb_free = (SMbuf *)NULL ; + for (i = 0; i < MAX_MBUF; i++) { + mb->sm_use_count = 1 ; + smt_free_mbuf(smc,mb) ; + mb++ ; + } +#else + mb = mb_start ; + if (!mb_init) { + mb_free = 0 ; + for (i = 0; i < MAX_MBUF; i++) { + mb->sm_use_count = 1 ; + smt_free_mbuf(smc,mb) ; + mb++ ; + } + mb_init = TRUE ; + } +#endif + + /* + * initialize the other variables + */ + smc->os.hwm.llc_rx_pipe = smc->os.hwm.llc_rx_tail = (SMbuf *)NULL ; + smc->os.hwm.txd_tx_pipe = smc->os.hwm.txd_tx_tail = NULL ; + smc->os.hwm.pass_SMT = smc->os.hwm.pass_NSA = smc->os.hwm.pass_DB = 0 ; + smc->os.hwm.pass_llc_promisc = TRUE ; + smc->os.hwm.queued_rx_frames = smc->os.hwm.queued_txd_mb = 0 ; + smc->os.hwm.detec_count = 0 ; + smc->os.hwm.rx_break = 0 ; + smc->os.hwm.rx_len_error = 0 ; + smc->os.hwm.isr_flag = FALSE ; + + /* + * make sure that the start pointer is 16 byte aligned + */ + i = 16 - ((int)smc->os.hwm.descr_p & 0xf) ; + if (i != 16) { + DB_GEN("i = %d",i,0,3) ; + smc->os.hwm.descr_p = (union s_fp_descr volatile *) + ((char *)smc->os.hwm.descr_p+i) ; + } + DB_GEN("pt to descr area = %x",(void *)smc->os.hwm.descr_p,0,3) ; + + init_txd_ring(smc) ; + init_rxd_ring(smc) ; + mac_drv_fill_rxd(smc) ; + + init_plc(smc) ; +} + + +SMbuf *smt_get_mbuf(smc) +struct s_smc *smc ; +{ + register SMbuf *mb ; + +#ifndef COMMON_MB_POOL + mb = smc->os.hwm.mbuf_pool.mb_free ; +#else + mb = mb_free ; +#endif + if (mb) { +#ifndef COMMON_MB_POOL + smc->os.hwm.mbuf_pool.mb_free = mb->sm_next ; +#else + mb_free = mb->sm_next ; +#endif + mb->sm_off = 8 ; + mb->sm_use_count = 1 ; + } + DB_GEN("get SMbuf: mb = %x",(void *)mb,0,3) ; + return (mb) ; /* May be NULL */ +} + +void smt_free_mbuf(smc, mb) +struct s_smc *smc ; +SMbuf *mb; +{ + + if (mb) { + mb->sm_use_count-- ; + DB_GEN("free_mbuf: sm_use_count = %d",mb->sm_use_count,0,3) ; + /* + * If the use_count is != zero the MBuf is queued + * more than once and must not queued into the + * free MBuf queue + */ + if (!mb->sm_use_count) { + DB_GEN("free SMbuf: mb = %x",(void *)mb,0,3) ; +#ifndef COMMON_MB_POOL + mb->sm_next = smc->os.hwm.mbuf_pool.mb_free ; + smc->os.hwm.mbuf_pool.mb_free = mb ; +#else + mb->sm_next = mb_free ; + mb_free = mb ; +#endif + } + } + else + SMT_PANIC(smc,HWM_E0003,HWM_E0003_MSG) ; +} + + +/* + * BEGIN_MANUAL_ENTRY(mac_drv_repair_descr) + * void mac_drv_repair_descr(smc) + * + * function called from SMT (HWM / hwmtm.c) + * The BMU is idle when this function is called. + * Mac_drv_repair_descr sets up the physical address + * for all receive and transmit queues where the BMU + * should continue. + * It may be that the BMU was reseted during a fragmented + * transfer. In this case there are some fragments which will + * never completed by the BMU. The OWN bit of this fragments + * must be switched to be owned by the host. + * + * Give a start command to the receive BMU. + * Start the transmit BMUs if transmit frames pending. + * + * END_MANUAL_ENTRY + */ +void mac_drv_repair_descr(smc) +struct s_smc *smc ; +{ + u_long phys ; + + if (smc->hw.hw_state != STOPPED) { + SK_BREAK() ; + SMT_PANIC(smc,HWM_E0013,HWM_E0013_MSG) ; + return ; + } + + /* + * repair tx queues: don't start + */ + phys = repair_txd_ring(smc,smc->hw.fp.tx[QUEUE_A0]) ; + outpd(ADDR(B5_XA_DA),phys) ; + if (smc->hw.fp.tx_q[QUEUE_A0].tx_used) { + outpd(ADDR(B0_XA_CSR),CSR_START) ; + } + phys = repair_txd_ring(smc,smc->hw.fp.tx[QUEUE_S]) ; + outpd(ADDR(B5_XS_DA),phys) ; + if (smc->hw.fp.tx_q[QUEUE_S].tx_used) { + outpd(ADDR(B0_XS_CSR),CSR_START) ; + } + + /* + * repair rx queues + */ + phys = repair_rxd_ring(smc,smc->hw.fp.rx[QUEUE_R1]) ; + outpd(ADDR(B4_R1_DA),phys) ; + outpd(ADDR(B0_R1_CSR),CSR_START) ; +} + +static u_long repair_txd_ring(smc,queue) +struct s_smc *smc ; +struct s_smt_tx_queue *queue ; +{ + int i ; + int tx_used ; + u_long phys ; + u_long tbctrl ; + struct s_smt_fp_txd volatile *t ; + + SK_UNUSED(smc) ; + + t = queue->tx_curr_get ; + tx_used = queue->tx_used ; + for (i = tx_used+queue->tx_free-1 ; i ; i-- ) { + t = t->txd_next ; + } + phys = AIX_REVERSE(t->txd_ntdadr) ; + + t = queue->tx_curr_get ; + while (tx_used) { + DRV_BUF_FLUSH(t,DDI_DMA_SYNC_FORCPU) ; + tbctrl = AIX_REVERSE(t->txd_tbctrl) ; + + if (tbctrl & BMU_OWN) { + if (tbctrl & BMU_STF) { + break ; /* exit the loop */ + } + else { + /* + * repair the descriptor + */ + t->txd_tbctrl &= AIX_REVERSE(~BMU_OWN) ; + } + } + phys = AIX_REVERSE(t->txd_ntdadr) ; + DRV_BUF_FLUSH(t,DDI_DMA_SYNC_FORDEV) ; + t = t->txd_next ; + tx_used-- ; + } + return(phys) ; +} + +/* + * Repairs the receive descriptor ring and returns the physical address + * where the BMU should continue working. + * + * o The physical address where the BMU was stopped has to be + * determined. This is the next RxD after rx_curr_get with an OWN + * bit set. + * o The BMU should start working at beginning of the next frame. + * RxDs with an OWN bit set but with a reset STF bit should be + * skipped and owned by the driver (OWN = 0). + */ +static u_long repair_rxd_ring(smc,queue) +struct s_smc *smc ; +struct s_smt_rx_queue *queue ; +{ + int i ; + int rx_used ; + u_long phys ; + u_long rbctrl ; + struct s_smt_fp_rxd volatile *r ; + + SK_UNUSED(smc) ; + + r = queue->rx_curr_get ; + rx_used = queue->rx_used ; + for (i = SMT_R1_RXD_COUNT-1 ; i ; i-- ) { + r = r->rxd_next ; + } + phys = AIX_REVERSE(r->rxd_nrdadr) ; + + r = queue->rx_curr_get ; + while (rx_used) { + DRV_BUF_FLUSH(r,DDI_DMA_SYNC_FORCPU) ; + rbctrl = AIX_REVERSE(r->rxd_rbctrl) ; + + if (rbctrl & BMU_OWN) { + if (rbctrl & BMU_STF) { + break ; /* exit the loop */ + } + else { + /* + * repair the descriptor + */ + r->rxd_rbctrl &= AIX_REVERSE(~BMU_OWN) ; + } + } + phys = AIX_REVERSE(r->rxd_nrdadr) ; + DRV_BUF_FLUSH(r,DDI_DMA_SYNC_FORDEV) ; + r = r->rxd_next ; + rx_used-- ; + } + return(phys) ; +} + + +/* + ------------------------------------------------------------- + INTERRUPT SERVICE ROUTINE: + ------------------------------------------------------------- +*/ + +/* + * BEGIN_MANUAL_ENTRY(fddi_isr) + * void fddi_isr(smc) + * + * function DOWNCALL (drvsr.c) + * interrupt service routine, handles the interrupt requests + * generated by the FDDI adapter. + * + * NOTE: The operating system dependent module must garantee that the + * interrupts of the adapter are disabled when it calls fddi_isr. + * + * About the USE_BREAK_ISR mechanismn: + * + * The main requirement of this mechanismn is to force an timer IRQ when + * leaving process_receive() with leave_isr set. process_receive() may + * be called at any time from anywhere! + * To be sure we don't miss such event we set 'force_irq' per default. + * We have to force and Timer IRQ if 'smc->os.hwm.leave_isr' AND + * 'force_irq' are set. 'force_irq' may be reset if a receive complete + * IRQ is pending. + * + * END_MANUAL_ENTRY + */ +void fddi_isr(smc) +struct s_smc *smc ; +{ + u_long is ; /* ISR source */ + u_short stu, stl ; + SMbuf *mb ; + +#ifdef USE_BREAK_ISR + int force_irq ; +#endif + +#ifdef ODI2 + if (smc->os.hwm.rx_break) { + mac_drv_fill_rxd(smc) ; + if (smc->hw.fp.rx_q[QUEUE_R1].rx_used > 0) { + smc->os.hwm.rx_break = 0 ; + process_receive(smc) ; + } + else { + smc->os.hwm.detec_count = 0 ; + smt_force_irq(smc) ; + } + } +#endif + smc->os.hwm.isr_flag = TRUE ; + +#ifdef USE_BREAK_ISR + force_irq = TRUE ; + if (smc->os.hwm.leave_isr) { + smc->os.hwm.leave_isr = FALSE ; + process_receive(smc) ; + } +#endif + + while ((is = GET_ISR() & ISR_MASK)) { + NDD_TRACE("CH0B",is,0,0) ; + DB_GEN("ISA = 0x%x",is,0,7) ; + + if (is & IMASK_SLOW) { + NDD_TRACE("CH1b",is,0,0) ; + if (is & IS_PLINT1) { /* PLC1 */ + plc1_irq(smc) ; + } + if (is & IS_PLINT2) { /* PLC2 */ + plc2_irq(smc) ; + } + if (is & IS_MINTR1) { /* FORMAC+ STU1(U/L) */ + stu = inpw(FM_A(FM_ST1U)) ; + stl = inpw(FM_A(FM_ST1L)) ; + DB_GEN("Slow transmit complete",0,0,6) ; + mac1_irq(smc,stu,stl) ; + } + if (is & IS_MINTR2) { /* FORMAC+ STU2(U/L) */ + stu= inpw(FM_A(FM_ST2U)) ; + stl= inpw(FM_A(FM_ST2L)) ; + DB_GEN("Slow receive complete",0,0,6) ; + DB_GEN("stl = %x : stu = %x",stl,stu,7) ; + mac2_irq(smc,stu,stl) ; + } + if (is & IS_MINTR3) { /* FORMAC+ STU3(U/L) */ + stu= inpw(FM_A(FM_ST3U)) ; + stl= inpw(FM_A(FM_ST3L)) ; + DB_GEN("FORMAC Mode Register 3",0,0,6) ; + mac3_irq(smc,stu,stl) ; + } + if (is & IS_TIMINT) { /* Timer 82C54-2 */ + timer_irq(smc) ; +#ifdef NDIS_OS2 + force_irq_pending = 0 ; +#endif + /* + * out of RxD detection + */ + if (++smc->os.hwm.detec_count > 4) { + /* + * check out of RxD condition + */ + process_receive(smc) ; + } + } + if (is & IS_TOKEN) { /* Restricted Token Monitor */ + rtm_irq(smc) ; + } + if (is & IS_R1_P) { /* Parity error rx queue 1 */ + /* clear IRQ */ + outpd(ADDR(B4_R1_CSR),CSR_IRQ_CL_P) ; + SMT_PANIC(smc,HWM_E0004,HWM_E0004_MSG) ; + } + if (is & IS_R1_C) { /* Encoding error rx queue 1 */ + /* clear IRQ */ + outpd(ADDR(B4_R1_CSR),CSR_IRQ_CL_C) ; + SMT_PANIC(smc,HWM_E0005,HWM_E0005_MSG) ; + } + if (is & IS_XA_C) { /* Encoding error async tx q */ + /* clear IRQ */ + outpd(ADDR(B5_XA_CSR),CSR_IRQ_CL_C) ; + SMT_PANIC(smc,HWM_E0006,HWM_E0006_MSG) ; + } + if (is & IS_XS_C) { /* Encoding error sync tx q */ + /* clear IRQ */ + outpd(ADDR(B5_XS_CSR),CSR_IRQ_CL_C) ; + SMT_PANIC(smc,HWM_E0007,HWM_E0007_MSG) ; + } + } + + /* + * Fast Tx complete Async/Sync Queue (BMU service) + */ + if (is & (IS_XS_F|IS_XA_F)) { + DB_GEN("Fast tx complete queue",0,0,6) ; + /* + * clear IRQ, Note: no IRQ is lost, because + * we always service both queues + */ + outpd(ADDR(B5_XS_CSR),CSR_IRQ_CL_F) ; + outpd(ADDR(B5_XA_CSR),CSR_IRQ_CL_F) ; + mac_drv_clear_txd(smc) ; + llc_restart_tx(smc) ; + } + + /* + * Fast Rx Complete (BMU service) + */ + if (is & IS_R1_F) { + DB_GEN("Fast receive complete",0,0,6) ; + /* clear IRQ */ +#ifndef USE_BREAK_ISR + outpd(ADDR(B4_R1_CSR),CSR_IRQ_CL_F) ; + process_receive(smc) ; +#else + process_receive(smc) ; + if (smc->os.hwm.leave_isr) { + force_irq = FALSE ; + } else { + outpd(ADDR(B4_R1_CSR),CSR_IRQ_CL_F) ; + process_receive(smc) ; + } +#endif + } + +#ifndef NDIS_OS2 + while ((mb = get_llc_rx(smc))) { + smt_to_llc(smc,mb) ; + } +#else + if (offDepth) + post_proc() ; + + while (!offDepth && (mb = get_llc_rx(smc))) { + smt_to_llc(smc,mb) ; + } + + if (!offDepth && smc->os.hwm.rx_break) { + process_receive(smc) ; + } +#endif + if (smc->q.ev_get != smc->q.ev_put) { + NDD_TRACE("CH2a",0,0,0) ; + ev_dispatcher(smc) ; + } +#ifdef NDIS_OS2 + post_proc() ; + if (offDepth) { /* leave fddi_isr because */ + break ; /* indications not allowed */ + } +#endif +#ifdef USE_BREAK_ISR + if (smc->os.hwm.leave_isr) { + break ; /* leave fddi_isr */ + } +#endif + + /* NOTE: when the isr is left, no rx is pending */ + } /* end of interrupt source polling loop */ + +#ifdef USE_BREAK_ISR + if (smc->os.hwm.leave_isr && force_irq) { + smt_force_irq(smc) ; + } +#endif + smc->os.hwm.isr_flag = FALSE ; + NDD_TRACE("CH0E",0,0,0) ; +} + + +/* + ------------------------------------------------------------- + RECEIVE FUNCTIONS: + ------------------------------------------------------------- +*/ + +#ifndef NDIS_OS2 +/* + * BEGIN_MANUAL_ENTRY(mac_drv_rx_mode) + * void mac_drv_rx_mode(smc,mode) + * + * function DOWNCALL (fplus.c) + * Corresponding to the parameter mode, the operating system + * dependent module can activate several receive modes. + * + * para mode = 1: RX_ENABLE_ALLMULTI enable all multicasts + * = 2: RX_DISABLE_ALLMULTI disable "enable all multicasts" + * = 3: RX_ENABLE_PROMISC enable promiscuous + * = 4: RX_DISABLE_PROMISC disable promiscuous + * = 5: RX_ENABLE_NSA enable rec. of all NSA frames + * (disabled after 'driver reset' & 'set station address') + * = 6: RX_DISABLE_NSA disable rec. of all NSA frames + * + * = 21: RX_ENABLE_PASS_SMT ( see description ) + * = 22: RX_DISABLE_PASS_SMT ( " " ) + * = 23: RX_ENABLE_PASS_NSA ( " " ) + * = 24: RX_DISABLE_PASS_NSA ( " " ) + * = 25: RX_ENABLE_PASS_DB ( " " ) + * = 26: RX_DISABLE_PASS_DB ( " " ) + * = 27: RX_DISABLE_PASS_ALL ( " " ) + * = 28: RX_DISABLE_LLC_PROMISC ( " " ) + * = 29: RX_ENABLE_LLC_PROMISC ( " " ) + * + * + * RX_ENABLE_PASS_SMT / RX_DISABLE_PASS_SMT + * + * If the operating system dependent module activates the + * mode RX_ENABLE_PASS_SMT, the hardware module + * duplicates all SMT frames with the frame control + * FC_SMT_INFO and passes them to the LLC receive channel + * by calling mac_drv_rx_init. + * The SMT Frames which are sent by the local SMT and the NSA + * frames whose A- and C-Indicator is not set are also duplicated + * and passed. + * The receive mode RX_DISABLE_PASS_SMT disables the passing + * of SMT frames. + * + * RX_ENABLE_PASS_NSA / RX_DISABLE_PASS_NSA + * + * If the operating system dependent module activates the + * mode RX_ENABLE_PASS_NSA, the hardware module + * duplicates all NSA frames with frame control FC_SMT_NSA + * and a set A-Indicator and passed them to the LLC + * receive channel by calling mac_drv_rx_init. + * All NSA Frames which are sent by the local SMT + * are also duplicated and passed. + * The receive mode RX_DISABLE_PASS_NSA disables the passing + * of NSA frames with the A- or C-Indicator set. + * + * NOTE: For fear that the hardware module receives NSA frames with + * a reset A-Indicator, the operating system dependent module + * has to call mac_drv_rx_mode with the mode RX_ENABLE_NSA + * before activate the RX_ENABLE_PASS_NSA mode and after every + * 'driver reset' and 'set station address'. + * + * RX_ENABLE_PASS_DB / RX_DISABLE_PASS_DB + * + * If the operating system dependent module activates the + * mode RX_ENABLE_PASS_DB, direct BEACON frames + * (FC_BEACON frame control) are passed to the LLC receive + * channel by mac_drv_rx_init. + * The receive mode RX_DISABLE_PASS_DB disables the passing + * of direct BEACON frames. + * + * RX_DISABLE_PASS_ALL + * + * Disables all special receives modes. It is equal to + * call mac_drv_set_rx_mode successively with the + * parameters RX_DISABLE_NSA, RX_DISABLE_PASS_SMT, + * RX_DISABLE_PASS_NSA and RX_DISABLE_PASS_DB. + * + * RX_ENABLE_LLC_PROMISC + * + * (default) all received LLC frames and all SMT/NSA/DBEACON + * frames depending on the attitude of the flags + * PASS_SMT/PASS_NSA/PASS_DBEACON will be delivered to the + * LLC layer + * + * RX_DISABLE_LLC_PROMISC + * + * all received SMT/NSA/DBEACON frames depending on the + * attitude of the flags PASS_SMT/PASS_NSA/PASS_DBEACON + * will be delivered to the LLC layer. + * all received LLC frames with a directed address, Multicast + * or Broadcast address will be delivered to the LLC + * layer too. + * + * END_MANUAL_ENTRY + */ +void mac_drv_rx_mode(smc,mode) +struct s_smc *smc ; +int mode ; +{ + switch(mode) { + case RX_ENABLE_PASS_SMT: + smc->os.hwm.pass_SMT = TRUE ; + break ; + case RX_DISABLE_PASS_SMT: + smc->os.hwm.pass_SMT = FALSE ; + break ; + case RX_ENABLE_PASS_NSA: + smc->os.hwm.pass_NSA = TRUE ; + break ; + case RX_DISABLE_PASS_NSA: + smc->os.hwm.pass_NSA = FALSE ; + break ; + case RX_ENABLE_PASS_DB: + smc->os.hwm.pass_DB = TRUE ; + break ; + case RX_DISABLE_PASS_DB: + smc->os.hwm.pass_DB = FALSE ; + break ; + case RX_DISABLE_PASS_ALL: + smc->os.hwm.pass_SMT = smc->os.hwm.pass_NSA = FALSE ; + smc->os.hwm.pass_DB = FALSE ; + smc->os.hwm.pass_llc_promisc = TRUE ; + mac_set_rx_mode(smc,RX_DISABLE_NSA) ; + break ; + case RX_DISABLE_LLC_PROMISC: + smc->os.hwm.pass_llc_promisc = FALSE ; + break ; + case RX_ENABLE_LLC_PROMISC: + smc->os.hwm.pass_llc_promisc = TRUE ; + break ; + case RX_ENABLE_ALLMULTI: + case RX_DISABLE_ALLMULTI: + case RX_ENABLE_PROMISC: + case RX_DISABLE_PROMISC: + case RX_ENABLE_NSA: + case RX_DISABLE_NSA: + default: + mac_set_rx_mode(smc,mode) ; + break ; + } +} +#endif /* ifndef NDIS_OS2 */ + +/* + * process receive queue + */ +void process_receive(smc) +struct s_smc *smc ; +{ + int i ; + int n ; + int frag_count ; /* number of RxDs of the curr rx buf */ + int used_frags ; /* number of RxDs of the curr frame */ + struct s_smt_rx_queue *queue ; /* points to the queue ctl struct */ + struct s_smt_fp_rxd volatile *r ; /* rxd pointer */ + struct s_smt_fp_rxd volatile *rxd ; /* first rxd of rx frame */ + u_long rbctrl ; /* receive buffer control word */ + u_long rfsw ; /* receive frame status word */ + u_short rx_used ; + u_char far *virt ; + char far *data ; + SMbuf *mb ; + u_char fc ; /* Frame control */ + int len ; /* Frame length */ + + smc->os.hwm.detec_count = 0 ; + queue = smc->hw.fp.rx[QUEUE_R1] ; + NDD_TRACE("RHxB",0,0,0) ; + for ( ; ; ) { + r = queue->rx_curr_get ; + rx_used = queue->rx_used ; + frag_count = 0 ; + +#ifdef USE_BREAK_ISR + if (smc->os.hwm.leave_isr) { + goto rx_end ; + } +#endif +#ifdef NDIS_OS2 + if (offDepth) { + smc->os.hwm.rx_break = 1 ; + goto rx_end ; + } + smc->os.hwm.rx_break = 0 ; +#endif +#ifdef ODI2 + if (smc->os.hwm.rx_break) { + goto rx_end ; + } +#endif + n = 0 ; + do { + DB_RX("Check RxD %x for OWN and EOF",(void *)r,0,5) ; + DRV_BUF_FLUSH(r,DDI_DMA_SYNC_FORCPU) ; + rbctrl = CR_READ(r->rxd_rbctrl) ; +#ifdef AIX + rbctrl = AIX_REVERSE(rbctrl) ; +#endif + if (rbctrl & BMU_OWN) { + NDD_TRACE("RHxE",r,rfsw,rbctrl) ; + DB_RX("End of RxDs",0,0,4) ; + goto rx_end ; + } + /* + * out of RxD detection + */ + if (!rx_used) { + SK_BREAK() ; + SMT_PANIC(smc,HWM_E0009,HWM_E0009_MSG) ; + /* Either we don't have an RxD or all + * RxDs are filled. Therefore it's allowed + * for to set the STOPPED flag */ + smc->hw.hw_state = STOPPED ; + mac_drv_clear_rx_queue(smc) ; + smc->hw.hw_state = STARTED ; + mac_drv_fill_rxd(smc) ; + smc->os.hwm.detec_count = 0 ; + goto rx_end ; + } + rfsw = AIX_REVERSE(r->rxd_rfsw) ; + if ((rbctrl & BMU_STF) != ((rbctrl & BMU_ST_BUF) <<5)) { + /* + * The BMU_STF bit is deleted, 1 frame is + * placed into more than 1 rx buffer + * + * skip frame by setting the rx len to 0 + * + * if fragment count == 0 + * The missing STF bit belongs to the + * current frame, search for the + * EOF bit to complete the frame + * else + * the fragment belongs to the next frame, + * exit the loop and process the frame + */ + SK_BREAK() ; + rfsw = 0 ; + if (frag_count) { + break ; + } + } + n += rbctrl & 0xffff ; + r = r->rxd_next ; + frag_count++ ; + rx_used-- ; + } while (!(rbctrl & BMU_EOF)) ; + used_frags = frag_count ; + DB_RX("EOF set in RxD, used_frags = %d ",used_frags,0,5) ; + + /* may be next 2 DRV_BUF_FLUSH() can be skipped, because */ + /* BMU_ST_BUF will not be changed by the ASIC */ + DRV_BUF_FLUSH(r,DDI_DMA_SYNC_FORCPU) ; + while (rx_used && !(r->rxd_rbctrl & AIX_REVERSE(BMU_ST_BUF))) { + DB_RX("Check STF bit in %x",(void *)r,0,5) ; + r = r->rxd_next ; + DRV_BUF_FLUSH(r,DDI_DMA_SYNC_FORCPU) ; + frag_count++ ; + rx_used-- ; + } + DB_RX("STF bit found",0,0,5) ; + + /* + * The received frame is finished for the process receive + */ + rxd = queue->rx_curr_get ; + queue->rx_curr_get = r ; + queue->rx_free += frag_count ; + queue->rx_used = rx_used ; + + /* + * ASIC Errata no. 7 (STF - Bit Bug) + */ + rxd->rxd_rbctrl &= AIX_REVERSE(~BMU_STF) ; + + for (r=rxd, i=frag_count ; i ; r=r->rxd_next, i--){ + DB_RX("dma_complete for RxD %x",(void *)r,0,5) ; + dma_complete(smc,(union s_fp_descr volatile *)r,DMA_WR); + } + smc->hw.fp.err_stats.err_valid++ ; + smc->mib.m[MAC0].fddiMACCopied_Ct++ ; + + /* the length of the data including the FC */ + len = (rfsw & RD_LENGTH) - 4 ; + + DB_RX("frame length = %d",len,0,4) ; + /* + * check the frame_lenght and all error flags + */ + if (rfsw & (RX_MSRABT|RX_FS_E|RX_FS_CRC|RX_FS_IMPL)){ + if (rfsw & RD_S_MSRABT) { + DB_RX("Frame aborted by the FORMAC",0,0,2) ; + smc->hw.fp.err_stats.err_abort++ ; + } + /* + * check frame status + */ + if (rfsw & RD_S_SEAC2) { + DB_RX("E-Indicator set",0,0,2) ; + smc->hw.fp.err_stats.err_e_indicator++ ; + } + if (rfsw & RD_S_SFRMERR) { + DB_RX("CRC error",0,0,2) ; + smc->hw.fp.err_stats.err_crc++ ; + } + if (rfsw & RX_FS_IMPL) { + DB_RX("Implementer frame",0,0,2) ; + smc->hw.fp.err_stats.err_imp_frame++ ; + } + goto abort_frame ; + } + if (len > FDDI_RAW_MTU-4) { + DB_RX("Frame to long error",0,0,2) ; + smc->hw.fp.err_stats.err_too_long++ ; + goto abort_frame ; + } + /* + * SUPERNET 3 Bug: FORMAC delivers status words + * of aborded frames to the BMU + */ + if (len <= 4) { + DB_RX("Frame length = 0",0,0,2) ; + goto abort_frame ; + } + + if (len != (n-4)) { + DB_RX("BMU: rx len differs: [%d:%d]",len,n,4); + smc->os.hwm.rx_len_error++ ; + goto abort_frame ; + } + + /* + * Check SA == MA + */ + virt = (u_char far *) rxd->rxd_virt ; + DB_RX("FC = %x",*virt,0,2) ; + if (virt[12] == MA[5] && + virt[11] == MA[4] && + virt[10] == MA[3] && + virt[9] == MA[2] && + virt[8] == MA[1] && + (virt[7] & ~GROUP_ADDR_BIT) == MA[0]) { + goto abort_frame ; + } + + /* + * test if LLC frame + */ + if (rfsw & RX_FS_LLC) { + /* + * if pass_llc_promisc is disable + * if DA != Multicast or Broadcast or DA!=MA + * abort the frame + */ + if (!smc->os.hwm.pass_llc_promisc) { + if(!(virt[1] & GROUP_ADDR_BIT)) { + if (virt[6] != MA[5] || + virt[5] != MA[4] || + virt[4] != MA[3] || + virt[3] != MA[2] || + virt[2] != MA[1] || + virt[1] != MA[0]) { + DB_RX("DA != MA and not multi- or broadcast",0,0,2) ; + goto abort_frame ; + } + } + } + + /* + * LLC frame received + */ + DB_RX("LLC - receive",0,0,4) ; + mac_drv_rx_complete(smc,rxd,frag_count,len) ; + } + else { + if (!(mb = smt_get_mbuf(smc))) { + smc->hw.fp.err_stats.err_no_buf++ ; + DB_RX("No SMbuf; receive terminated",0,0,4) ; + goto abort_frame ; + } + data = smtod(mb,char *) - 1 ; + + /* + * copy the frame into a SMT_MBuf + */ +#ifdef USE_OS_CPY + hwm_cpy_rxd2mb(rxd,data,len) ; +#else + for (r=rxd, i=used_frags ; i ; r=r->rxd_next, i--){ + n = AIX_REVERSE(r->rxd_rbctrl) & RD_LENGTH ; + DB_RX("cp SMT frame to mb: len = %d",n,0,6) ; + memcpy(data,r->rxd_virt,n) ; + data += n ; + } + data = smtod(mb,char *) - 1 ; +#endif + fc = *(char *)mb->sm_data = *data ; + mb->sm_len = len - 1 ; /* len - fc */ + data++ ; + + /* + * SMT frame received + */ + switch(fc) { + case FC_SMT_INFO : + smc->hw.fp.err_stats.err_smt_frame++ ; + DB_RX("SMT frame received ",0,0,5) ; + + if (smc->os.hwm.pass_SMT) { + DB_RX("pass SMT frame ",0,0,5) ; + mac_drv_rx_complete(smc, rxd, + frag_count,len) ; + } + else { + DB_RX("requeue RxD",0,0,5) ; + mac_drv_requeue_rxd(smc,rxd,frag_count); + } + + smt_received_pack(smc,mb,(int)(rfsw>>25)) ; + break ; + case FC_SMT_NSA : + smc->hw.fp.err_stats.err_smt_frame++ ; + DB_RX("SMT frame received ",0,0,5) ; + + /* if pass_NSA set pass the NSA frame or */ + /* pass_SMT set and the A-Indicator */ + /* is not set, pass the NSA frame */ + if (smc->os.hwm.pass_NSA || + (smc->os.hwm.pass_SMT && + !(rfsw & A_INDIC))) { + DB_RX("pass SMT frame ",0,0,5) ; + mac_drv_rx_complete(smc, rxd, + frag_count,len) ; + } + else { + DB_RX("requeue RxD",0,0,5) ; + mac_drv_requeue_rxd(smc,rxd,frag_count); + } + + smt_received_pack(smc,mb,(int)(rfsw>>25)) ; + break ; + case FC_BEACON : + if (smc->os.hwm.pass_DB) { + DB_RX("pass DB frame ",0,0,5) ; + mac_drv_rx_complete(smc, rxd, + frag_count,len) ; + } + else { + DB_RX("requeue RxD",0,0,5) ; + mac_drv_requeue_rxd(smc,rxd,frag_count); + } + smt_free_mbuf(smc,mb) ; + break ; + default : + /* + * unknown FC abord the frame + */ + DB_RX("unknown FC error",0,0,2) ; + smt_free_mbuf(smc,mb) ; + DB_RX("requeue RxD",0,0,5) ; + mac_drv_requeue_rxd(smc,rxd,frag_count) ; + if ((fc & 0xf0) == FC_MAC) + smc->hw.fp.err_stats.err_mac_frame++ ; + else + smc->hw.fp.err_stats.err_imp_frame++ ; + + break ; + } + } + + DB_RX("next RxD is %x ",queue->rx_curr_get,0,3) ; + NDD_TRACE("RHx1",queue->rx_curr_get,0,0) ; + + continue ; + /*--------------------------------------------------------------------*/ +abort_frame: + DB_RX("requeue RxD",0,0,5) ; + mac_drv_requeue_rxd(smc,rxd,frag_count) ; + + DB_RX("next RxD is %x ",queue->rx_curr_get,0,3) ; + NDD_TRACE("RHx2",queue->rx_curr_get,0,0) ; + } +rx_end: +#ifdef ALL_RX_COMPLETE + mac_drv_all_receives_complete(smc) ; +#endif + return ; /* lint bug: needs return detect end of function */ +} + +static void smt_to_llc(smc,mb) +struct s_smc *smc ; +SMbuf *mb ; +{ + u_char fc ; + + DB_RX("send a queued frame to the llc layer",0,0,4) ; + smc->os.hwm.r.len = mb->sm_len ; + smc->os.hwm.r.mb_pos = smtod(mb,char *) ; + fc = *smc->os.hwm.r.mb_pos ; + (void)mac_drv_rx_init(smc,(int)mb->sm_len,(int)fc, + smc->os.hwm.r.mb_pos,(int)mb->sm_len) ; + smt_free_mbuf(smc,mb) ; +} + +/* + * BEGIN_MANUAL_ENTRY(hwm_rx_frag) + * void hwm_rx_frag(smc,virt,phys,len,frame_status) + * + * function MACRO (hardware module, hwmtm.h) + * This function calls dma_master for preparing the + * system hardware for the DMA transfer and initializes + * the current RxD with the length and the physical and + * virtual address of the fragment. Furthermore, it sets the + * STF and EOF bits depending on the frame status byte, + * switches the OWN flag of the RxD, so that it is owned by the + * adapter and issues an rx_start. + * + * para virt virtual pointer to the fragment + * len the length of the fragment + * frame_status status of the frame, see design description + * + * NOTE: It is possible to call this function with a fragment length + * of zero. + * + * END_MANUAL_ENTRY + */ +void hwm_rx_frag(smc,virt,phys,len,frame_status) +struct s_smc *smc ; +char far *virt ; +u_long phys ; +int len ; +int frame_status ; +{ + struct s_smt_fp_rxd volatile *r ; +#ifdef AIX + u_long rbctrl ; +#endif + + NDD_TRACE("RHfB",virt,len,frame_status) ; + DB_RX("hwm_rx_frag: len = %d, frame_status = %x\n",len,frame_status,2) ; + r = smc->hw.fp.rx_q[QUEUE_R1].rx_curr_put ; + r->rxd_virt = virt ; + r->rxd_rbadr = AIX_REVERSE(phys) ; +#ifndef AIX + r->rxd_rbctrl = (((u_long)frame_status & (FIRST_FRAG|LAST_FRAG))<<26) | + (((u_long) frame_status & FIRST_FRAG) << 21) | + BMU_OWN | BMU_CHECK | BMU_EN_IRQ_EOF | len ; +#else + rbctrl = AIX_REVERSE( (((u_long)frame_status & + (FIRST_FRAG|LAST_FRAG))<<26) | + (((u_long) frame_status & FIRST_FRAG) << 21) | + BMU_OWN | BMU_CHECK | BMU_EN_IRQ_EOF | len) ; + r->rxd_rbctrl = rbctrl ; +#endif + DRV_BUF_FLUSH(r,DDI_DMA_SYNC_FORDEV) ; + outpd(ADDR(B0_R1_CSR),CSR_START) ; + smc->hw.fp.rx_q[QUEUE_R1].rx_free-- ; + smc->hw.fp.rx_q[QUEUE_R1].rx_used++ ; + smc->hw.fp.rx_q[QUEUE_R1].rx_curr_put = r->rxd_next ; + NDD_TRACE("RHfE",r,AIX_REVERSE(r->rxd_rbadr),0) ; +} + +#ifndef NDIS_OS2 +/* + * BEGIN_MANUAL_ENTRY(mac_drv_rx_frag) + * int mac_drv_rx_frag(smc,virt,len) + * + * function DOWNCALL (hwmtm.c) + * mac_drv_rx_frag fills the fragment with a part of the frame. + * + * para virt the virtual address of the fragment + * len the length in bytes of the fragment + * + * return 0: success code, no errors possible + * + * END_MANUAL_ENTRY + */ +int mac_drv_rx_frag(smc,virt,len) +struct s_smc *smc ; +void far *virt ; +int len ; +{ + NDD_TRACE("RHSB",virt,len,smc->os.hwm.r.mb_pos) ; + + DB_RX("receive from queue: len/virt: = %d/%x",len,virt,4) ; + memcpy((char far *)virt,smc->os.hwm.r.mb_pos,len) ; + smc->os.hwm.r.mb_pos += len ; + + NDD_TRACE("RHSE",smc->os.hwm.r.mb_pos,0,0) ; + return(0) ; +} +#endif + + +/* + * BEGINN_MANUAL_ENTRY(mac_drv_clear_rx_queue) + * + * void mac_drv_clear_rx_queue(smc) + * struct s_smc *smc ; + * + * function DOWNCALL (hardware module, hwmtm.c) + * mac_drv_clear_rx_queue is called by the OS-specific module + * after it has issued a card_stop. + * In this case, the frames in the receive queue are obsolete and + * should be removed. For removing mac_drv_clear_rx_queue + * calls dma_master for each RxD and mac_drv_clear_rxd for each + * receive buffer. + * + * NOTE: calling sequence card_stop: + * CLI_FBI(), card_stop(), + * mac_drv_clear_tx_queue(), mac_drv_clear_rx_queue(), + * + * NOTE: The caller is responsible that the BMUs are idle + * when this function is called. + * + * END_MANUAL_ENTRY + */ +void mac_drv_clear_rx_queue(smc) +struct s_smc *smc ; +{ + struct s_smt_fp_rxd volatile *r ; + struct s_smt_fp_rxd volatile *next_rxd ; + struct s_smt_rx_queue *queue ; + int frag_count ; + int i ; + + if (smc->hw.hw_state != STOPPED) { + SK_BREAK() ; + SMT_PANIC(smc,HWM_E0012,HWM_E0012_MSG) ; + return ; + } + + queue = smc->hw.fp.rx[QUEUE_R1] ; + DB_RX("clear_rx_queue",0,0,5) ; + + /* + * dma_complete and mac_drv_clear_rxd for all RxDs / receive buffers + */ + r = queue->rx_curr_get ; + while (queue->rx_used) { + DRV_BUF_FLUSH(r,DDI_DMA_SYNC_FORCPU) ; + DB_RX("switch OWN bit of RxD 0x%x ",r,0,5) ; + r->rxd_rbctrl &= AIX_REVERSE(~BMU_OWN) ; + frag_count = 1 ; + DRV_BUF_FLUSH(r,DDI_DMA_SYNC_FORDEV) ; + r = r->rxd_next ; + DRV_BUF_FLUSH(r,DDI_DMA_SYNC_FORCPU) ; + while (r != queue->rx_curr_put && + !(r->rxd_rbctrl & AIX_REVERSE(BMU_ST_BUF))) { + DB_RX("Check STF bit in %x",(void *)r,0,5) ; + r->rxd_rbctrl &= AIX_REVERSE(~BMU_OWN) ; + DRV_BUF_FLUSH(r,DDI_DMA_SYNC_FORDEV) ; + r = r->rxd_next ; + DRV_BUF_FLUSH(r,DDI_DMA_SYNC_FORCPU) ; + frag_count++ ; + } + DB_RX("STF bit found",0,0,5) ; + next_rxd = r ; + + for (r=queue->rx_curr_get,i=frag_count; i ; r=r->rxd_next,i--){ + DB_RX("dma_complete for RxD %x",(void *)r,0,5) ; + dma_complete(smc,(union s_fp_descr volatile *)r,DMA_WR); + } + + DB_RX("mac_drv_clear_rxd: RxD %x frag_count %d ", + (void *)queue->rx_curr_get,frag_count,5) ; + mac_drv_clear_rxd(smc,queue->rx_curr_get,frag_count) ; + + queue->rx_curr_get = next_rxd ; + queue->rx_used -= frag_count ; + queue->rx_free += frag_count ; + } +} + + +/* + ------------------------------------------------------------- + SEND FUNCTIONS: + ------------------------------------------------------------- +*/ + +/* + * BEGIN_MANUAL_ENTRY(hwm_tx_init) + * int hwm_tx_init(smc,fc,frag_count,frame_len,frame_status) + * + * function DOWN_CALL (hardware module, hwmtm.c) + * hwm_tx_init checks if the frame can be sent through the + * corresponding send queue. + * + * para fc the frame control. To determine through which + * send queue the frame should be transmitted. + * 0x50 - 0x57: asynchronous LLC frame + * 0xD0 - 0xD7: synchronous LLC frame + * 0x41, 0x4F: SMT frame to the network + * 0x42: SMT frame to the network and to the local SMT + * 0x43: SMT frame to the local SMT + * frag_count count of the fragments for this frame + * frame_len length of the frame + * frame_status status of the frame, the send queue bit is already + * specified + * + * return frame_status + * + * END_MANUAL_ENTRY + */ +int hwm_tx_init(smc,fc,frag_count,frame_len,frame_status) +struct s_smc *smc ; +u_char fc ; +int frag_count ; +int frame_len ; +int frame_status ; +{ + NDD_TRACE("THiB",fc,frag_count,frame_len) ; + smc->os.hwm.tx_p = smc->hw.fp.tx[frame_status & QUEUE_A0] ; + smc->os.hwm.tx_descr = TX_DESCRIPTOR | (((u_long)(frame_len-1)&3)<<27) ; + smc->os.hwm.tx_len = frame_len ; + DB_TX("hwm_tx_init: fc = %x, len = %d",fc,frame_len,3) ; + if ((fc & ~(FC_SYNC_BIT|FC_LLC_PRIOR)) == FC_ASYNC_LLC) { + frame_status |= LAN_TX ; + } + else { + switch (fc) { + case FC_SMT_INFO : + case FC_SMT_NSA : + frame_status |= LAN_TX ; + break ; + case FC_SMT_LOC : + frame_status |= LOC_TX ; + break ; + case FC_SMT_LAN_LOC : + frame_status |= LAN_TX | LOC_TX ; + break ; + default : + SMT_PANIC(smc,HWM_E0010,HWM_E0010_MSG) ; + } + } + if (!smc->hw.mac_ring_is_up) { + frame_status &= ~LAN_TX ; + frame_status |= RING_DOWN ; + DB_TX("Ring is down: terminate LAN_TX",0,0,2) ; + } + if (frag_count > smc->os.hwm.tx_p->tx_free) { +#ifndef NDIS_OS2 + mac_drv_clear_txd(smc) ; + if (frag_count > smc->os.hwm.tx_p->tx_free) { + DB_TX("Out of TxDs, terminate LAN_TX",0,0,2) ; + frame_status &= ~LAN_TX ; + frame_status |= OUT_OF_TXD ; + } +#else + DB_TX("Out of TxDs, terminate LAN_TX",0,0,2) ; + frame_status &= ~LAN_TX ; + frame_status |= OUT_OF_TXD ; +#endif + } + DB_TX("frame_status = %x",frame_status,0,3) ; + NDD_TRACE("THiE",frame_status,smc->os.hwm.tx_p->tx_free,0) ; + return(frame_status) ; +} + +/* + * BEGIN_MANUAL_ENTRY(hwm_tx_frag) + * void hwm_tx_frag(smc,virt,phys,len,frame_status) + * + * function DOWNCALL (hardware module, hwmtm.c) + * If the frame should be sent to the LAN, this function calls + * dma_master, fills the current TxD with the virtual and the + * physical address, sets the STF and EOF bits dependent on + * the frame status, and requests the BMU to start the + * transmit. + * If the frame should be sent to the local SMT, an SMT_MBuf + * is allocated if the FIRST_FRAG bit is set in the frame_status. + * The fragment of the frame is copied into the SMT MBuf. + * The function smt_received_pack is called if the LAST_FRAG + * bit is set in the frame_status word. + * + * para virt virtual pointer to the fragment + * len the length of the fragment + * frame_status status of the frame, see design description + * + * return nothing returned, no parameter is modified + * + * NOTE: It is possible to invoke this macro with a fragment length + * of zero. + * + * END_MANUAL_ENTRY + */ +void hwm_tx_frag(smc,virt,phys,len,frame_status) +struct s_smc *smc ; +char far *virt ; +u_long phys ; +int len ; +int frame_status ; +{ + struct s_smt_fp_txd volatile *t ; + struct s_smt_tx_queue *queue ; +#ifdef AIX + u_long tbctrl ; +#endif + + queue = smc->os.hwm.tx_p ; + + NDD_TRACE("THfB",virt,len,frame_status) ; + /* Bug fix: AF / May 31 1999 (#missing) + * snmpinfo problem reported by IBM is caused by invalid + * t-pointer (txd) if LAN_TX is not set but LOC_TX only. + * Set: t = queue->tx_curr_put here ! + */ + t = queue->tx_curr_put ; + + DB_TX("hwm_tx_frag: len = %d, frame_status = %x ",len,frame_status,2) ; + if (frame_status & LAN_TX) { + /* '*t' is already defined */ + DB_TX("LAN_TX: TxD = %x, virt = %x ",t,virt,3) ; + t->txd_virt = virt ; + t->txd_txdscr = AIX_REVERSE(smc->os.hwm.tx_descr) ; + t->txd_tbadr = AIX_REVERSE(phys) ; +#ifndef AIX + t->txd_tbctrl = (((u_long)frame_status & + (FIRST_FRAG|LAST_FRAG|EN_IRQ_EOF))<< 26) | + BMU_OWN|BMU_CHECK |len ; + DRV_BUF_FLUSH(t,DDI_DMA_SYNC_FORDEV) ; + outpd(queue->tx_bmu_ctl,CSR_START) ; + +#else /* ifndef AIX */ + tbctrl = AIX_REVERSE((((u_long)frame_status & + (FIRST_FRAG|LAST_FRAG|EN_IRQ_EOF))<< 26) | + BMU_OWN|BMU_CHECK |len) ; + t->txd_tbctrl = tbctrl ; + + DRV_BUF_FLUSH(t,DDI_DMA_SYNC_FORDEV) ; + if (frame_status & QUEUE_A0) { + outpd(ADDR(B0_XA_CSR),CSR_START) ; + } + else { + outpd(ADDR(B0_XS_CSR),CSR_START) ; + } +#endif + queue->tx_free-- ; + queue->tx_used++ ; + queue->tx_curr_put = t->txd_next ; + if (frame_status & LAST_FRAG) { + smc->mib.m[MAC0].fddiMACTransmit_Ct++ ; + } + } + if (frame_status & LOC_TX) { + DB_TX("LOC_TX: ",0,0,3) ; + if (frame_status & FIRST_FRAG) { + if(!(smc->os.hwm.tx_mb = smt_get_mbuf(smc))) { + smc->hw.fp.err_stats.err_no_buf++ ; + DB_TX("No SMbuf; transmit terminated",0,0,4) ; + } + else { + smc->os.hwm.tx_data = + smtod(smc->os.hwm.tx_mb,char *) - 1 ; +#ifdef USE_OS_CPY +#ifdef PASS_1ST_TXD_2_TX_COMP + hwm_cpy_txd2mb(t,smc->os.hwm.tx_data, + smc->os.hwm.tx_len) ; +#endif +#endif + } + } + if (smc->os.hwm.tx_mb) { +#ifndef USE_OS_CPY + DB_TX("copy fragment into MBuf ",0,0,3) ; + memcpy(smc->os.hwm.tx_data,virt,len) ; + smc->os.hwm.tx_data += len ; +#endif + if (frame_status & LAST_FRAG) { +#ifdef USE_OS_CPY +#ifndef PASS_1ST_TXD_2_TX_COMP + /* + * hwm_cpy_txd2mb(txd,data,len) copies 'len' + * bytes from the virtual pointer in 'rxd' + * to 'data'. The virtual pointer of the + * os-specific tx-buffer should be written + * in the LAST txd. + */ + hwm_cpy_txd2mb(t,smc->os.hwm.tx_data, + smc->os.hwm.tx_len) ; +#endif /* nPASS_1ST_TXD_2_TX_COMP */ +#endif /* USE_OS_CPY */ + smc->os.hwm.tx_data = + smtod(smc->os.hwm.tx_mb,char *) - 1 ; + *(char *)smc->os.hwm.tx_mb->sm_data = + *smc->os.hwm.tx_data ; + smc->os.hwm.tx_data++ ; + smc->os.hwm.tx_mb->sm_len = + smc->os.hwm.tx_len - 1 ; + DB_TX("pass LLC frame to SMT ",0,0,3) ; + smt_received_pack(smc,smc->os.hwm.tx_mb, + RD_FS_LOCAL) ; + } + } + } + NDD_TRACE("THfE",t,queue->tx_free,0) ; +} + + +/* + * queues a receive for later send + */ +static void queue_llc_rx(smc,mb) +struct s_smc *smc ; +SMbuf *mb ; +{ + DB_GEN("queue_llc_rx: mb = %x",(void *)mb,0,4) ; + smc->os.hwm.queued_rx_frames++ ; + mb->sm_next = (SMbuf *)NULL ; + if (smc->os.hwm.llc_rx_pipe == 0) { + smc->os.hwm.llc_rx_pipe = mb ; + } + else { + smc->os.hwm.llc_rx_tail->sm_next = mb ; + } + smc->os.hwm.llc_rx_tail = mb ; + + /* + * force an timer IRQ to receive the data + */ + if (!smc->os.hwm.isr_flag) { + smt_force_irq(smc) ; + } +} + +/* + * get a SMbuf from the llc_rx_queue + */ +static SMbuf *get_llc_rx(smc) +struct s_smc *smc ; +{ + SMbuf *mb ; + + if ((mb = smc->os.hwm.llc_rx_pipe)) { + smc->os.hwm.queued_rx_frames-- ; + smc->os.hwm.llc_rx_pipe = mb->sm_next ; + } + DB_GEN("get_llc_rx: mb = 0x%x",(void *)mb,0,4) ; + return(mb) ; +} + +/* + * queues a transmit SMT MBuf during the time were the MBuf is + * queued the TxD ring + */ +static void queue_txd_mb(smc,mb) +struct s_smc *smc ; +SMbuf *mb ; +{ + DB_GEN("_rx: queue_txd_mb = %x",(void *)mb,0,4) ; + smc->os.hwm.queued_txd_mb++ ; + mb->sm_next = (SMbuf *)NULL ; + if (smc->os.hwm.txd_tx_pipe == 0) { + smc->os.hwm.txd_tx_pipe = mb ; + } + else { + smc->os.hwm.txd_tx_tail->sm_next = mb ; + } + smc->os.hwm.txd_tx_tail = mb ; +} + +/* + * get a SMbuf from the txd_tx_queue + */ +static SMbuf *get_txd_mb(smc) +struct s_smc *smc ; +{ + SMbuf *mb ; + + if ((mb = smc->os.hwm.txd_tx_pipe)) { + smc->os.hwm.queued_txd_mb-- ; + smc->os.hwm.txd_tx_pipe = mb->sm_next ; + } + DB_GEN("get_txd_mb: mb = 0x%x",(void *)mb,0,4) ; + return(mb) ; +} + +/* + * SMT Send function + */ +void smt_send_mbuf(smc,mb,fc) +struct s_smc *smc; +SMbuf *mb; +int fc; +{ + char far *data ; + int len ; + int n ; + int i ; + int frag_count ; + int frame_status ; + SK_LOC_DECL(char far,*virt[3]) ; + int frag_len[3] ; + struct s_smt_tx_queue *queue ; + struct s_smt_fp_txd volatile *t ; + u_long phys ; +#ifdef AIX + u_long tbctrl ; +#endif + + NDD_TRACE("THSB",mb,fc,0) ; + DB_TX("smt_send_mbuf: mb = 0x%x, fc = 0x%x",mb,fc,4) ; + + mb->sm_off-- ; /* set to fc */ + mb->sm_len++ ; /* + fc */ + data = smtod(mb,char *) ; + *data = fc ; + if (fc == FC_SMT_LOC) + *data = FC_SMT_INFO ; + + /* + * determine the frag count and the virt addresses of the frags + */ + frag_count = 0 ; + len = mb->sm_len ; + while (len) { + n = SMT_PAGESIZE - ((int)data & (SMT_PAGESIZE-1)) ; + if (n >= len) { + n = len ; + } + DB_TX("frag: virt/len = 0x%x/%d ",(void *)data,n,5) ; + virt[frag_count] = data ; + frag_len[frag_count] = n ; + frag_count++ ; + len -= n ; + data += n ; + } + + /* + * determine the frame status + */ + queue = smc->hw.fp.tx[QUEUE_A0] ; + if (fc == FC_BEACON || fc == FC_SMT_LOC) { + frame_status = LOC_TX ; + } + else { + frame_status = LAN_TX ; + if ((smc->os.hwm.pass_NSA &&(fc == FC_SMT_NSA)) || + (smc->os.hwm.pass_SMT &&(fc == FC_SMT_INFO))) + frame_status |= LOC_TX ; + } + + if (!smc->hw.mac_ring_is_up || frag_count > queue->tx_free) { + if (frame_status &= ~LAN_TX) { + DB_TX("Ring is down: terminate LAN_TX",0,0,2) ; + } + else { + DB_TX("Ring is down: terminate transmission",0,0,2) ; + smt_free_mbuf(smc,mb) ; + return ; + } + } + DB_TX("frame_status = 0x%x ",frame_status,0,5) ; + + if ((frame_status & LAN_TX) && (frame_status & LOC_TX)) { + mb->sm_use_count = 2 ; + } + + if (frame_status & LAN_TX) { + t = queue->tx_curr_put ; + frame_status |= FIRST_FRAG ; + for (i = 0; i < frag_count; i++) { + DB_TX("init TxD = 0x%x",(void *)t,0,5) ; + if (i == frag_count-1) { + frame_status |= LAST_FRAG ; + t->txd_txdscr = AIX_REVERSE(TX_DESCRIPTOR | + (((u_long)(mb->sm_len-1)&3) << 27)) ; + } + t->txd_virt = virt[i] ; + phys = dma_master(smc, (void far *)virt[i], + frag_len[i], DMA_RD|SMT_BUF) ; + t->txd_tbadr = AIX_REVERSE(phys) ; +#ifndef AIX + t->txd_tbctrl = (((u_long) frame_status & + (FIRST_FRAG|LAST_FRAG)) << 26) | + BMU_OWN | BMU_CHECK | BMU_SMT_TX |frag_len[i] ; + DRV_BUF_FLUSH(t,DDI_DMA_SYNC_FORDEV) ; + outpd(queue->tx_bmu_ctl,CSR_START) ; +#else + tbctrl = AIX_REVERSE((((u_long) frame_status & + (FIRST_FRAG|LAST_FRAG)) << 26) | + BMU_OWN | BMU_CHECK | BMU_SMT_TX |frag_len[i]) ; + t->txd_tbctrl = tbctrl ; + DRV_BUF_FLUSH(t,DDI_DMA_SYNC_FORDEV) ; + outpd(ADDR(B0_XA_CSR),CSR_START) ; +#endif + frame_status &= ~FIRST_FRAG ; + queue->tx_curr_put = t = t->txd_next ; + queue->tx_free-- ; + queue->tx_used++ ; + } + smc->mib.m[MAC0].fddiMACTransmit_Ct++ ; + queue_txd_mb(smc,mb) ; + } + + if (frame_status & LOC_TX) { + DB_TX("pass Mbuf to LLC queue",0,0,5) ; + queue_llc_rx(smc,mb) ; + } + + /* + * We need to unqueue the free SMT_MBUFs here, because it may + * be that the SMT want's to send more than 1 frame for one down call + */ + mac_drv_clear_txd(smc) ; + NDD_TRACE("THSE",t,queue->tx_free,frag_count) ; +} + +/* BEGIN_MANUAL_ENTRY(mac_drv_clear_txd) + * void mac_drv_clear_txd(smc) + * + * function DOWNCALL (hardware module, hwmtm.c) + * mac_drv_clear_txd searches in both send queues for TxD's + * which were finished by the adapter. It calls dma_complete + * for each TxD. If the last fragment of an LLC frame is + * reached, it calls mac_drv_tx_complete to release the + * send buffer. + * + * return nothing + * + * END_MANUAL_ENTRY + */ +void mac_drv_clear_txd(smc) +struct s_smc *smc ; +{ + struct s_smt_tx_queue *queue ; + struct s_smt_fp_txd volatile *t1 ; + struct s_smt_fp_txd volatile *t2=0 ; + SMbuf *mb ; + u_long tbctrl ; + int i ; + int frag_count ; + int n ; + + NDD_TRACE("THcB",0,0,0) ; + for (i = QUEUE_S; i <= QUEUE_A0; i++) { + queue = smc->hw.fp.tx[i] ; + t1 = queue->tx_curr_get ; + DB_TX("clear_txd: QUEUE = %d (0=sync/1=async)",i,0,5) ; + + for ( ; ; ) { + frag_count = 0 ; + + do { + DRV_BUF_FLUSH(t1,DDI_DMA_SYNC_FORCPU) ; + DB_TX("check OWN/EOF bit of TxD 0x%x",t1,0,5) ; + tbctrl = CR_READ(t1->txd_tbctrl) ; +#ifdef AIX + tbctrl = AIX_REVERSE(tbctrl) ; +#endif + if (tbctrl & BMU_OWN || !queue->tx_used){ + DB_TX("End of TxDs queue %d",i,0,4) ; + goto free_next_queue ; /* next queue */ + } + t1 = t1->txd_next ; + frag_count++ ; + } while (!(tbctrl & BMU_EOF)) ; + + t1 = queue->tx_curr_get ; + for (n = frag_count; n; n--) { + tbctrl = AIX_REVERSE(t1->txd_tbctrl) ; + dma_complete(smc, + (union s_fp_descr volatile *) t1, + (int) (DMA_RD | + ((tbctrl & BMU_SMT_TX) >> 18))) ; + t2 = t1 ; + t1 = t1->txd_next ; + } + + if (tbctrl & BMU_SMT_TX) { + mb = get_txd_mb(smc) ; + smt_free_mbuf(smc,mb) ; + } + else { +#ifndef PASS_1ST_TXD_2_TX_COMP + DB_TX("mac_drv_tx_comp for TxD 0x%x",t2,0,4) ; + mac_drv_tx_complete(smc,t2) ; +#else + DB_TX("mac_drv_tx_comp for TxD 0x%x", + queue->tx_curr_get,0,4) ; + mac_drv_tx_complete(smc,queue->tx_curr_get) ; +#endif + } + queue->tx_curr_get = t1 ; + queue->tx_free += frag_count ; + queue->tx_used -= frag_count ; + } +free_next_queue: ; + } + NDD_TRACE("THcE",0,0,0) ; +} + +/* + * BEGINN_MANUAL_ENTRY(mac_drv_clear_tx_queue) + * + * void mac_drv_clear_tx_queue(smc) + * struct s_smc *smc ; + * + * function DOWNCALL (hardware module, hwmtm.c) + * mac_drv_clear_tx_queue is called from the SMT when + * the RMT state machine has entered the ISOLATE state. + * This function is also called by the os-specific module + * after it has called the function card_stop(). + * In this case, the frames in the send queues are obsolete and + * should be removed. + * + * note calling sequence: + * CLI_FBI(), card_stop(), + * mac_drv_clear_tx_queue(), mac_drv_clear_rx_queue(), + * + * NOTE: The caller is responsible that the BMUs are idle + * when this function is called. + * + * END_MANUAL_ENTRY + */ +void mac_drv_clear_tx_queue(smc) +struct s_smc *smc ; +{ + struct s_smt_fp_txd volatile *t ; + struct s_smt_tx_queue *queue ; + int tx_used ; + int i ; + + if (smc->hw.hw_state != STOPPED) { + SK_BREAK() ; + SMT_PANIC(smc,HWM_E0011,HWM_E0011_MSG) ; + return ; + } + + for (i = QUEUE_S; i <= QUEUE_A0; i++) { + queue = smc->hw.fp.tx[i] ; + DB_TX("clear_tx_queue: QUEUE = %d (0=sync/1=async)",i,0,5) ; + + /* + * switch the OWN bit of all pending frames to the host + */ + t = queue->tx_curr_get ; + tx_used = queue->tx_used ; + while (tx_used) { + DRV_BUF_FLUSH(t,DDI_DMA_SYNC_FORCPU) ; + DB_TX("switch OWN bit of TxD 0x%x ",t,0,5) ; + t->txd_tbctrl &= AIX_REVERSE(~BMU_OWN) ; + DRV_BUF_FLUSH(t,DDI_DMA_SYNC_FORDEV) ; + t = t->txd_next ; + tx_used-- ; + } + } + + /* + * release all TxD's for both send queues + */ + mac_drv_clear_txd(smc) ; + + for (i = QUEUE_S; i <= QUEUE_A0; i++) { + queue = smc->hw.fp.tx[i] ; + t = queue->tx_curr_get ; + + /* + * write the phys pointer of the NEXT descriptor into the + * BMU's current address descriptor pointer and set + * tx_curr_get and tx_curr_put to this position + */ + if (i == QUEUE_S) { + outpd(ADDR(B5_XS_DA),AIX_REVERSE(t->txd_ntdadr)) ; + } + else { + outpd(ADDR(B5_XA_DA),AIX_REVERSE(t->txd_ntdadr)) ; + } + + queue->tx_curr_put = queue->tx_curr_get->txd_next ; + queue->tx_curr_get = queue->tx_curr_put ; + } +} + + +/* + ------------------------------------------------------------- + TEST FUNCTIONS: + ------------------------------------------------------------- +*/ + +#ifdef DEBUG +/* + * BEGIN_MANUAL_ENTRY(mac_drv_debug_lev) + * void mac_drv_debug_lev(smc,flag,lev) + * + * function DOWNCALL (drvsr.c) + * To get a special debug info the user can assign a debug level + * to any debug flag. + * + * para flag debug flag, possible values are: + * = 0: reset all debug flags (the defined level is + * ignored) + * = 1: debug.d_smtf + * = 2: debug.d_smt + * = 3: debug.d_ecm + * = 4: debug.d_rmt + * = 5: debug.d_cfm + * = 6: debug.d_pcm + * + * = 10: debug.d_os.hwm_rx (hardware module receive path) + * = 11: debug.d_os.hwm_tx(hardware module transmit path) + * = 12: debug.d_os.hwm_gen(hardware module general flag) + * + * lev debug level + * + * END_MANUAL_ENTRY + */ +void mac_drv_debug_lev(smc,flag,lev) +struct s_smc *smc ; +int flag ; +int lev ; +{ + switch(flag) { + case (int)NULL: + DB_P.d_smtf = DB_P.d_smt = DB_P.d_ecm = DB_P.d_rmt = 0 ; + DB_P.d_cfm = 0 ; + DB_P.d_os.hwm_rx = DB_P.d_os.hwm_tx = DB_P.d_os.hwm_gen = 0 ; +#ifdef SBA + DB_P.d_sba = 0 ; +#endif +#ifdef ESS + DB_P.d_ess = 0 ; +#endif + break ; + case DEBUG_SMTF: + DB_P.d_smtf = lev ; + break ; + case DEBUG_SMT: + DB_P.d_smt = lev ; + break ; + case DEBUG_ECM: + DB_P.d_ecm = lev ; + break ; + case DEBUG_RMT: + DB_P.d_rmt = lev ; + break ; + case DEBUG_CFM: + DB_P.d_cfm = lev ; + break ; + case DEBUG_PCM: + DB_P.d_pcm = lev ; + break ; + case DEBUG_SBA: +#ifdef SBA + DB_P.d_sba = lev ; +#endif + break ; + case DEBUG_ESS: +#ifdef ESS + DB_P.d_ess = lev ; +#endif + break ; + case DB_HWM_RX: + DB_P.d_os.hwm_rx = lev ; + break ; + case DB_HWM_TX: + DB_P.d_os.hwm_tx = lev ; + break ; + case DB_HWM_GEN: + DB_P.d_os.hwm_gen = lev ; + break ; + default: + break ; + } +} +#endif diff -u --recursive --new-file v2.3.46/linux/drivers/net/skfp/hwt.c linux/drivers/net/skfp/hwt.c --- v2.3.46/linux/drivers/net/skfp/hwt.c Wed Dec 31 16:00:00 1969 +++ linux/drivers/net/skfp/hwt.c Fri Feb 18 14:55:53 2000 @@ -0,0 +1,314 @@ +/****************************************************************************** + * + * (C)Copyright 1998,1999 SysKonnect, + * a business unit of Schneider & Koch & Co. Datensysteme GmbH. + * + * See the file "skfddi.c" for further information. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * The information in this file is provided "AS IS" without warranty. + * + ******************************************************************************/ + +/* + * Timer Driver for FBI board (timer chip 82C54) + */ + +/* + * Modifications: + * + * 28-Jun-1994 sw Edit v1.6. + * MCA: Added support for the SK-NET FDDI-FM2 adapter. The + * following functions have been added(+) or modified(*): + * hwt_start(*), hwt_stop(*), hwt_restart(*), hwt_read(*) + */ + +#include "h/types.h" +#include "h/fddi.h" +#include "h/smc.h" + +#ifndef lint +static const char ID_sccs[] = "@(#)hwt.c 1.13 97/04/23 (C) SK " ; +#endif + +/* + * Prototypes of local functions. + */ +/* 28-Jun-1994 sw - Note: hwt_restart() is also used in module 'drvfbi.c'. */ +/*static*/ void hwt_restart() ; + +/************************ + * + * hwt_start + * + * Start hardware timer (clock ticks are 16us). + * + * void hwt_start( + * struct s_smc *smc, + * u_long time) ; + * In + * smc - A pointer to the SMT Context structure. + * + * time - The time in units of 16us to load the timer with. + * Out + * Nothing. + * + ************************/ +#define HWT_MAX (65000) + +void hwt_start(smc, time) +struct s_smc *smc ; +u_long time ; +{ + u_short cnt ; + + if (time > HWT_MAX) + time = HWT_MAX ; + + smc->hw.t_start = time ; + smc->hw.t_stop = 0L ; + + cnt = (u_short)time ; + /* + * if time < 16 us + * time = 16 us + */ + if (!cnt) + cnt++ ; +#ifndef PCI + /* + * 6.25MHz -> CLK0 : T0 (cnt0 = 16us) -> OUT0 + * OUT0 -> CLK1 : T1 (cnt1) OUT1 -> ISRA(IS_TIMINT) + */ + OUT_82c54_TIMER(3,1<<6 | 3<<4 | 0<<1) ; /* counter 1, mode 0 */ + OUT_82c54_TIMER(1,cnt & 0xff) ; /* LSB */ + OUT_82c54_TIMER(1,(cnt>>8) & 0xff) ; /* MSB */ + /* + * start timer by switching counter 0 to mode 3 + * T0 resolution 16 us (CLK0=0.16us) + */ + OUT_82c54_TIMER(3,0<<6 | 3<<4 | 3<<1) ; /* counter 0, mode 3 */ + OUT_82c54_TIMER(0,100) ; /* LSB */ + OUT_82c54_TIMER(0,0) ; /* MSB */ +#else /* PCI */ + outpd(ADDR(B2_TI_INI), (u_long) cnt * 200) ; /* Load timer value. */ + outpw(ADDR(B2_TI_CRTL), TIM_START) ; /* Start timer. */ +#endif /* PCI */ + smc->hw.timer_activ = TRUE ; +} + +/************************ + * + * hwt_stop + * + * Stop hardware timer. + * + * void hwt_stop( + * struct s_smc *smc) ; + * In + * smc - A pointer to the SMT Context structure. + * Out + * Nothing. + * + ************************/ +void hwt_stop(smc) +struct s_smc *smc ; +{ +#ifndef PCI + /* stop counter 0 by switching to mode 0 */ + OUT_82c54_TIMER(3,0<<6 | 3<<4 | 0<<1) ; /* counter 0, mode 0 */ + OUT_82c54_TIMER(0,0) ; /* LSB */ + OUT_82c54_TIMER(0,0) ; /* MSB */ +#else /* PCI */ + outpw(ADDR(B2_TI_CRTL), TIM_STOP) ; + outpw(ADDR(B2_TI_CRTL), TIM_CL_IRQ) ; +#endif /* PCI */ + + smc->hw.timer_activ = FALSE ; +} + +/************************ + * + * hwt_init + * + * Initialize hardware timer. + * + * void hwt_init( + * struct s_smc *smc) ; + * In + * smc - A pointer to the SMT Context structure. + * Out + * Nothing. + * + ************************/ +void hwt_init(smc) +struct s_smc *smc ; +{ + smc->hw.t_start = 0 ; + smc->hw.t_stop = 0 ; + smc->hw.timer_activ = FALSE ; + + hwt_restart(smc) ; +} + +/************************ + * + * hwt_restart + * + * Clear timer interrupt. + * + * void hwt_restart( + * struct s_smc *smc) ; + * In + * smc - A pointer to the SMT Context structure. + * Out + * Nothing. + * + ************************/ +void hwt_restart(smc) +struct s_smc *smc ; +{ + hwt_stop(smc) ; +#ifndef PCI + OUT_82c54_TIMER(3,1<<6 | 3<<4 | 0<<1) ; /* counter 1, mode 0 */ + OUT_82c54_TIMER(1,1 ) ; /* LSB */ + OUT_82c54_TIMER(1,0 ) ; /* MSB */ +#endif +} + +/************************ + * + * hwt_read + * + * Stop hardware timer and read time elapsed since last start. + * + * u_long hwt_read(smc) ; + * In + * smc - A pointer to the SMT Context structure. + * Out + * The elapsed time since last start in units of 16us. + * + ************************/ +u_long hwt_read(smc) +struct s_smc *smc ; +{ + u_short tr ; +#ifndef PCI + u_short is ; +#else + u_long is ; +#endif + + if (smc->hw.timer_activ) { + hwt_stop(smc) ; +#ifndef PCI + OUT_82c54_TIMER(3,1<<6) ; /* latch command */ + tr = IN_82c54_TIMER(1) & 0xff ; + tr += (IN_82c54_TIMER(1) & 0xff)<<8 ; +#else /* PCI */ + tr = (u_short)((inpd(ADDR(B2_TI_VAL))/200) & 0xffff) ; +#endif /* PCI */ + is = GET_ISR() ; + /* Check if timer expired (or wraparound). */ + if ((tr > smc->hw.t_start) || (is & IS_TIMINT)) { + hwt_restart(smc) ; + smc->hw.t_stop = smc->hw.t_start ; + } + else + smc->hw.t_stop = smc->hw.t_start - tr ; + } + return (smc->hw.t_stop) ; +} + +#ifdef PCI +/************************ + * + * hwt_quick_read + * + * Stop hardware timer and read timer value and start the timer again. + * + * u_long hwt_read(smc) ; + * In + * smc - A pointer to the SMT Context structure. + * Out + * current timer value in units of 80ns. + * + ************************/ +u_long hwt_quick_read(smc) +struct s_smc *smc ; +{ + u_long interval ; + u_long time ; + + interval = inpd(ADDR(B2_TI_INI)) ; + outpw(ADDR(B2_TI_CRTL), TIM_STOP) ; + time = inpd(ADDR(B2_TI_VAL)) ; + outpd(ADDR(B2_TI_INI),time) ; + outpw(ADDR(B2_TI_CRTL), TIM_START) ; + outpd(ADDR(B2_TI_INI),interval) ; + + return(time) ; +} + +/************************ + * + * hwt_wait_time(smc,start,duration) + * + * This function returnes after the amount of time is elapsed + * since the start time. + * + * para start start time + * duration time to wait + * + * NOTE: The fuction will return immediatly, if the timer is not + * started + ************************/ +void hwt_wait_time(smc,start,duration) +struct s_smc *smc ; +u_long start ; +long duration ; +{ + long diff ; + long interval ; + int wrapped ; + + /* + * check if timer is running + */ + if (smc->hw.timer_activ == FALSE || + hwt_quick_read(smc) == hwt_quick_read(smc)) { + return ; + } + + interval = inpd(ADDR(B2_TI_INI)) ; + if (interval > duration) { + do { + diff = (long)(start - hwt_quick_read(smc)) ; + if (diff < 0) { + diff += interval ; + } + } while (diff <= duration) ; + } + else { + diff = interval ; + wrapped = 0 ; + do { + if (!wrapped) { + if (hwt_quick_read(smc) >= start) { + diff += interval ; + wrapped = 1 ; + } + } + else { + if (hwt_quick_read(smc) < start) { + wrapped = 0 ; + } + } + } while (diff <= duration) ; + } +} +#endif diff -u --recursive --new-file v2.3.46/linux/drivers/net/skfp/lnkstat.c linux/drivers/net/skfp/lnkstat.c --- v2.3.46/linux/drivers/net/skfp/lnkstat.c Wed Dec 31 16:00:00 1969 +++ linux/drivers/net/skfp/lnkstat.c Fri Feb 18 14:55:53 2000 @@ -0,0 +1,209 @@ +/****************************************************************************** + * + * (C)Copyright 1998,1999 SysKonnect, + * a business unit of Schneider & Koch & Co. Datensysteme GmbH. + * + * See the file "skfddi.c" for further information. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * The information in this file is provided "AS IS" without warranty. + * + ******************************************************************************/ + +/* + IBM FDDI read error log function +*/ + +#include "h/types.h" +#include "h/fddi.h" +#include "h/smc.h" +#include "h/lnkstat.h" + +#ifndef lint +static const char ID_sccs[] = "@(#)lnkstat.c 1.8 97/04/11 (C) SK " ; +#endif + +#ifdef sun +#define _far +#endif + +#define EL_IS_OK(x,l) ((((int)&(((struct s_error_log *)0)->x)) + \ + sizeof(er->x)) <= l) + +/* + BEGIN_MANUAL_ENTRY(if,func;others;11) + + u_long smt_get_error_word(smc) + struct s_smc *smc ; + +Function DOWNCALL (SMT, lnkstat.c) + This functions returns the SMT error work for AIX events. + +Return smt_error_word These bits are supported: + + SMT_ERL_ALC == [PS/PA].fddiPORTLerFlag + SMT_ERL_BLC == [PB].fddiPORTLerFlag + SMT_ERL_NCC == fddiMACNotCopiedFlag + SMT_ERL_FEC == fddiMACFrameErrorFlag + + END_MANUAL_ENTRY() + */ +u_long smt_get_error_word(smc) +struct s_smc *smc ; +{ + u_long st; + + /* + * smt error word low + */ + st = 0 ; + if (smc->s.sas == SMT_SAS) { + if (smc->mib.p[PS].fddiPORTLerFlag) + st |= SMT_ERL_ALC ; + } + else { + if (smc->mib.p[PA].fddiPORTLerFlag) + st |= SMT_ERL_ALC ; + if (smc->mib.p[PB].fddiPORTLerFlag) + st |= SMT_ERL_BLC ; + } + if (smc->mib.m[MAC0].fddiMACNotCopiedFlag) + st |= SMT_ERL_NCC ; /* not copied condition */ + if (smc->mib.m[MAC0].fddiMACFrameErrorFlag) + st |= SMT_ERL_FEC ; /* frame error condition */ + + return st; +} + +/* + BEGIN_MANUAL_ENTRY(if,func;others;11) + + u_long smt_get_event_word(smc) + struct s_smc *smc ; + +Function DOWNCALL (SMT, lnkstat.c) + This functions returns the SMT event work for AIX events. + +Return smt_event_word always 0 + + END_MANUAL_ENTRY() + */ +u_long smt_get_event_word(smc) +struct s_smc *smc ; +{ + return (u_long) 0; +} + +/* + BEGIN_MANUAL_ENTRY(if,func;others;11) + + u_long smt_get_port_event_word(smc) + struct s_smc *smc ; + +Function DOWNCALL (SMT, lnkstat.c) + This functions returns the SMT port event work for AIX events. + +Return smt_port_event_word always 0 + + END_MANUAL_ENTRY() + */ +u_long smt_get_port_event_word(smc) +struct s_smc *smc ; +{ + return (u_long) 0; +} + +/* + BEGIN_MANUAL_ENTRY(if,func;others;11) + + u_long smt_read_errorlog(smc,p,len) + struct s_smc *smc ; + char _far *p ; + int len ; + +Function DOWNCALL (SMT, lnkstat.c) + This functions returns the SMT error log field for AIX events. + +Para p pointer to the error log field + len len of the error log field + +Return len used len of the error log field + + END_MANUAL_ENTRY() + */ +int smt_read_errorlog(smc,p,len) +struct s_smc *smc ; +char _far *p ; +int len ; +{ + int i ; + int st ; + struct s_error_log _far *er ; + + er = (struct s_error_log _far *) p ; + if (len > sizeof(struct s_error_log)) + len = sizeof(struct s_error_log) ; + for (i = 0 ; i < len ; i++) + *p++ = 0 ; + /* + * set count + */ + if (EL_IS_OK(set_count_high,len)) { + er->set_count_low = (u_short)smc->mib.fddiSMTSetCount.count ; + er->set_count_high = + (u_short)(smc->mib.fddiSMTSetCount.count >> 16L) ; + } + /* + * aci + */ + if (EL_IS_OK(aci_id_code,len)) { + er->aci_id_code = 0 ; + } + /* + * purge counter is missed frames; 16 bits only + */ + if (EL_IS_OK(purge_frame_counter,len)) { + if (smc->mib.m[MAC0].fddiMACCopied_Ct > 0xffff) + er->purge_frame_counter = 0xffff ; + else + er->purge_frame_counter = + (u_short)smc->mib.m[MAC0].fddiMACCopied_Ct ; + } + /* + * CMT and RMT state machines + */ + if (EL_IS_OK(ecm_state,len)) + er->ecm_state = smc->mib.fddiSMTECMState ; + + if (EL_IS_OK(pcm_b_state,len)) { + if (smc->s.sas == SMT_SAS) { + er->pcm_a_state = smc->y[PS].mib->fddiPORTPCMState ; + er->pcm_b_state = 0 ; + } + else { + er->pcm_a_state = smc->y[PA].mib->fddiPORTPCMState ; + er->pcm_b_state = smc->y[PB].mib->fddiPORTPCMState ; + } + } + if (EL_IS_OK(cfm_state,len)) + er->cfm_state = smc->mib.fddiSMTCF_State ; + if (EL_IS_OK(rmt_state,len)) + er->rmt_state = smc->mib.m[MAC0].fddiMACRMTState ; + + /* + * smt error word low (we only need the low order 16 bits.) + */ + + st = smt_get_error_word(smc) & 0xffff ; + + if (EL_IS_OK(smt_error_low,len)) + er->smt_error_low = st ; + + if (EL_IS_OK(ucode_version_level,len)) + er->ucode_version_level = 0x0101 ; + return(len) ; +} diff -u --recursive --new-file v2.3.46/linux/drivers/net/skfp/pcmplc.c linux/drivers/net/skfp/pcmplc.c --- v2.3.46/linux/drivers/net/skfp/pcmplc.c Wed Dec 31 16:00:00 1969 +++ linux/drivers/net/skfp/pcmplc.c Fri Feb 18 14:55:53 2000 @@ -0,0 +1,2094 @@ +/****************************************************************************** + * + * (C)Copyright 1998,1999 SysKonnect, + * a business unit of Schneider & Koch & Co. Datensysteme GmbH. + * + * See the file "skfddi.c" for further information. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * The information in this file is provided "AS IS" without warranty. + * + ******************************************************************************/ + +/* + PCM + Physical Connection Management +*/ + +/* + * Hardware independant state machine implemantation + * The following external SMT functions are referenced : + * + * queue_event() + * smt_timer_start() + * smt_timer_stop() + * + * The following external HW dependant functions are referenced : + * sm_pm_control() + * sm_ph_linestate() + * sm_pm_ls_latch() + * + * The following HW dependant events are required : + * PC_QLS + * PC_ILS + * PC_HLS + * PC_MLS + * PC_NSE + * PC_LEM + * + */ + + +#include "h/types.h" +#include "h/fddi.h" +#include "h/smc.h" +#include "h/supern_2.h" +#define KERNEL +#include "h/smtstate.h" + +#ifndef lint +static const char ID_sccs[] = "@(#)pcmplc.c 2.55 99/08/05 (C) SK " ; +#endif + +#ifdef FDDI_MIB +extern int snmp_fddi_trap( +#ifdef ANSIC +struct s_smc * smc, int type, int index +#endif +); +#endif +#ifdef CONCENTRATOR +extern int plc_is_installed( +#ifdef ANSIC +struct s_smc *smc , +int p +#endif +) ; +#endif +/* + * FSM Macros + */ +#define AFLAG (0x20) +#define GO_STATE(x) (mib->fddiPORTPCMState = (x)|AFLAG) +#define ACTIONS_DONE() (mib->fddiPORTPCMState &= ~AFLAG) +#define ACTIONS(x) (x|AFLAG) + +/* + * PCM states + */ +#define PC0_OFF 0 +#define PC1_BREAK 1 +#define PC2_TRACE 2 +#define PC3_CONNECT 3 +#define PC4_NEXT 4 +#define PC5_SIGNAL 5 +#define PC6_JOIN 6 +#define PC7_VERIFY 7 +#define PC8_ACTIVE 8 +#define PC9_MAINT 9 + +#ifdef DEBUG +/* + * symbolic state names + */ +static const char * const pcm_states[] = { + "PC0_OFF","PC1_BREAK","PC2_TRACE","PC3_CONNECT","PC4_NEXT", + "PC5_SIGNAL","PC6_JOIN","PC7_VERIFY","PC8_ACTIVE","PC9_MAINT" +} ; + +/* + * symbolic event names + */ +static const char * const pcm_events[] = { + "NONE","PC_START","PC_STOP","PC_LOOP","PC_JOIN","PC_SIGNAL", + "PC_REJECT","PC_MAINT","PC_TRACE","PC_PDR", + "PC_ENABLE","PC_DISABLE", + "PC_QLS","PC_ILS","PC_MLS","PC_HLS","PC_LS_PDR","PC_LS_NONE", + "PC_TIMEOUT_TB_MAX","PC_TIMEOUT_TB_MIN", + "PC_TIMEOUT_C_MIN","PC_TIMEOUT_T_OUT", + "PC_TIMEOUT_TL_MIN","PC_TIMEOUT_T_NEXT","PC_TIMEOUT_LCT", + "PC_NSE","PC_LEM" +} ; +#endif + +#ifdef MOT_ELM +/* + * PCL-S control register + * this register in the PLC-S controls the scrambling parameters + */ +#define PLCS_CONTROL_C_U 0 +#define PLCS_CONTROL_C_S (PL_C_SDOFF_ENABLE | PL_C_SDON_ENABLE | \ + PL_C_CIPHER_ENABLE) +#define PLCS_FASSERT_U 0 +#define PLCS_FASSERT_S 0xFd76 /* 52.0 us */ +#define PLCS_FDEASSERT_U 0 +#define PLCS_FDEASSERT_S 0 +#else /* nMOT_ELM */ +/* + * PCL-S control register + * this register in the PLC-S controls the scrambling parameters + * can be patched for ANSI compliance if standard changes + */ +static const u_char plcs_control_c_u[17] = "PLC_CNTRL_C_U=\0\0" ; +static const u_char plcs_control_c_s[17] = "PLC_CNTRL_C_S=\01\02" ; + +#define PLCS_CONTROL_C_U (plcs_control_c_u[14] | (plcs_control_c_u[15]<<8)) +#define PLCS_CONTROL_C_S (plcs_control_c_s[14] | (plcs_control_c_s[15]<<8)) +#endif /* nMOT_ELM */ + +/* + * external vars + */ +/* struct definition see 'cmtdef.h' (also used by CFM) */ + +#define PS_OFF 0 +#define PS_BIT3 1 +#define PS_BIT4 2 +#define PS_BIT7 3 +#define PS_LCT 4 +#define PS_BIT8 5 +#define PS_JOIN 6 +#define PS_ACTIVE 7 + +#define LCT_LEM_MAX 255 + +/* + * PLC timing parameter + */ + +#define PLC_MS(m) ((int)((0x10000L-(m*100000L/2048)))) +#define SLOW_TL_MIN PLC_MS(6) +#define SLOW_C_MIN PLC_MS(10) + +static const struct plt { + int timer ; /* relative plc timer address */ + int para ; /* default timing parameters */ +} pltm[] = { + { PL_C_MIN, SLOW_C_MIN }, /* min t. to remain Connect State */ + { PL_TL_MIN, SLOW_TL_MIN }, /* min t. to transmit a Line State */ + { PL_TB_MIN, TP_TB_MIN }, /* min break time */ + { PL_T_OUT, TP_T_OUT }, /* Signaling timeout */ + { PL_LC_LENGTH, TP_LC_LENGTH }, /* Link Confidence Test Time */ + { PL_T_SCRUB, TP_T_SCRUB }, /* Scrub Time == MAC TVX time ! */ + { PL_NS_MAX, TP_NS_MAX }, /* max t. that noise is tolerated */ + { 0,0 } +} ; + +/* + * interrupt mask + */ +#ifdef SUPERNET_3 +/* + * Do we need the EBUF error during signaling, too, to detect SUPERNET_3 + * PLL bug? + */ +static int plc_imsk_na = PL_PCM_CODE | PL_TRACE_PROP | PL_PCM_BREAK | + PL_PCM_ENABLED | PL_SELF_TEST | PL_EBUF_ERR; +#else /* SUPERNET_3 */ +/* + * We do NOT need the elasticity buffer error during signaling. + */ +static int plc_imsk_na = PL_PCM_CODE | PL_TRACE_PROP | PL_PCM_BREAK | + PL_PCM_ENABLED | PL_SELF_TEST ; +#endif /* SUPERNET_3 */ +static int plc_imsk_act = PL_PCM_CODE | PL_TRACE_PROP | PL_PCM_BREAK | + PL_PCM_ENABLED | PL_SELF_TEST | PL_EBUF_ERR; + +/* external functions */ +void all_selection_criteria (); + +/* internal functions */ +static void pcm_fsm() ; +static void pc_rcode_actions() ; +static void pc_tcode_actions() ; +static void reset_lem_struct() ; +static void plc_init() ; +static void sm_ph_lem_start() ; +static void sm_ph_lem_stop() ; +static void sm_ph_linestate() ; +static void real_init_plc() ; + +/* + * SMT timer interface + * start PCM timer 0 + */ +static void start_pcm_timer0(smc,value,event,phy) +struct s_smc *smc ; +u_long value; +int event; +struct s_phy *phy; +{ + phy->timer0_exp = FALSE ; /* clear timer event flag */ + smt_timer_start(smc,&phy->pcm_timer0,value, + EV_TOKEN(EVENT_PCM+phy->np,event)) ; +} +/* + * SMT timer interface + * stop PCM timer 0 + */ +static void stop_pcm_timer0(smc,phy) +struct s_smc *smc ; +struct s_phy *phy; +{ + if (phy->pcm_timer0.tm_active) + smt_timer_stop(smc,&phy->pcm_timer0) ; +} + +/* + init PCM state machine (called by driver) + clear all PCM vars and flags +*/ +void pcm_init(smc) +struct s_smc *smc ; +{ + int i ; + int np ; + struct s_phy *phy ; + struct fddi_mib_p *mib ; + + for (np = 0,phy = smc->y ; np < NUMPHYS ; np++,phy++) { + /* Indicates the type of PHY being used */ + mib = phy->mib ; + mib->fddiPORTPCMState = ACTIONS(PC0_OFF) ; + phy->np = np ; + switch (smc->s.sas) { +#ifdef CONCENTRATOR + case SMT_SAS : + mib->fddiPORTMy_Type = (np == PS) ? TS : TM ; + break ; + case SMT_DAS : + mib->fddiPORTMy_Type = (np == PA) ? TA : + (np == PB) ? TB : TM ; + break ; + case SMT_NAC : + mib->fddiPORTMy_Type = TM ; + break; +#else + case SMT_SAS : + mib->fddiPORTMy_Type = (np == PS) ? TS : TNONE ; + mib->fddiPORTHardwarePresent = (np == PS) ? TRUE : + FALSE ; +#ifndef SUPERNET_3 + smc->y[PA].mib->fddiPORTPCMState = PC0_OFF ; +#else + smc->y[PB].mib->fddiPORTPCMState = PC0_OFF ; +#endif + break ; + case SMT_DAS : + mib->fddiPORTMy_Type = (np == PB) ? TB : TA ; + break ; +#endif + } + /* + * set PMD-type + */ + phy->pmd_scramble = 0 ; + switch (phy->pmd_type[PMD_SK_PMD]) { + case 'P' : + mib->fddiPORTPMDClass = MIB_PMDCLASS_MULTI ; + break ; + case 'L' : + mib->fddiPORTPMDClass = MIB_PMDCLASS_LCF ; + break ; + case 'D' : + mib->fddiPORTPMDClass = MIB_PMDCLASS_TP ; + break ; + case 'S' : + mib->fddiPORTPMDClass = MIB_PMDCLASS_TP ; + phy->pmd_scramble = TRUE ; + break ; + case 'U' : + mib->fddiPORTPMDClass = MIB_PMDCLASS_TP ; + phy->pmd_scramble = TRUE ; + break ; + case '1' : + mib->fddiPORTPMDClass = MIB_PMDCLASS_SINGLE1 ; + break ; + case '2' : + mib->fddiPORTPMDClass = MIB_PMDCLASS_SINGLE2 ; + break ; + case '3' : + mib->fddiPORTPMDClass = MIB_PMDCLASS_SINGLE2 ; + break ; + case '4' : + mib->fddiPORTPMDClass = MIB_PMDCLASS_SINGLE1 ; + break ; + case 'H' : + mib->fddiPORTPMDClass = MIB_PMDCLASS_UNKNOWN ; + break ; + case 'I' : + mib->fddiPORTPMDClass = MIB_PMDCLASS_TP ; + break ; + case 'G' : + mib->fddiPORTPMDClass = MIB_PMDCLASS_TP ; + break ; + default: + mib->fddiPORTPMDClass = MIB_PMDCLASS_UNKNOWN ; + break ; + } + /* + * A and B port can be on primary and secondary path + */ + switch (mib->fddiPORTMy_Type) { + case TA : + mib->fddiPORTAvailablePaths |= MIB_PATH_S ; + mib->fddiPORTRequestedPaths[1] = MIB_P_PATH_LOCAL ; + mib->fddiPORTRequestedPaths[2] = + MIB_P_PATH_LOCAL | + MIB_P_PATH_CON_ALTER | + MIB_P_PATH_SEC_PREFER ; + mib->fddiPORTRequestedPaths[3] = + MIB_P_PATH_LOCAL | + MIB_P_PATH_CON_ALTER | + MIB_P_PATH_SEC_PREFER | + MIB_P_PATH_THRU ; + break ; + case TB : + mib->fddiPORTAvailablePaths |= MIB_PATH_S ; + mib->fddiPORTRequestedPaths[1] = MIB_P_PATH_LOCAL ; + mib->fddiPORTRequestedPaths[2] = + MIB_P_PATH_LOCAL | + MIB_P_PATH_PRIM_PREFER ; + mib->fddiPORTRequestedPaths[3] = + MIB_P_PATH_LOCAL | + MIB_P_PATH_PRIM_PREFER | + MIB_P_PATH_CON_PREFER | + MIB_P_PATH_THRU ; + break ; + case TS : + mib->fddiPORTAvailablePaths |= MIB_PATH_S ; + mib->fddiPORTRequestedPaths[1] = MIB_P_PATH_LOCAL ; + mib->fddiPORTRequestedPaths[2] = + MIB_P_PATH_LOCAL | + MIB_P_PATH_CON_ALTER | + MIB_P_PATH_PRIM_PREFER ; + mib->fddiPORTRequestedPaths[3] = + MIB_P_PATH_LOCAL | + MIB_P_PATH_CON_ALTER | + MIB_P_PATH_PRIM_PREFER ; + break ; + case TM : + mib->fddiPORTRequestedPaths[1] = MIB_P_PATH_LOCAL ; + mib->fddiPORTRequestedPaths[2] = + MIB_P_PATH_LOCAL | + MIB_P_PATH_SEC_ALTER | + MIB_P_PATH_PRIM_ALTER ; + mib->fddiPORTRequestedPaths[3] = 0 ; + break ; + } + + phy->pc_lem_fail = FALSE ; + mib->fddiPORTPCMStateX = mib->fddiPORTPCMState ; + mib->fddiPORTLCTFail_Ct = 0 ; + mib->fddiPORTBS_Flag = 0 ; + mib->fddiPORTCurrentPath = MIB_PATH_ISOLATED ; + mib->fddiPORTNeighborType = TNONE ; + phy->ls_flag = 0 ; + phy->rc_flag = 0 ; + phy->tc_flag = 0 ; + phy->td_flag = 0 ; + if (np >= PM) + phy->phy_name = '0' + np - PM ; + else + phy->phy_name = 'A' + np ; + phy->wc_flag = FALSE ; /* set by SMT */ + memset((char *)&phy->lem,0,sizeof(struct lem_counter)) ; + reset_lem_struct(phy) ; + memset((char *)&phy->plc,0,sizeof(struct s_plc)) ; + phy->plc.p_state = PS_OFF ; + for (i = 0 ; i < NUMBITS ; i++) { + phy->t_next[i] = 0 ; + } + } + real_init_plc(smc) ; +} + +void init_plc(smc) +struct s_smc *smc ; +{ + SK_UNUSED(smc) ; + + /* + * dummy + * this is an obsolete public entry point that has to remain + * for compat. It is used by various drivers. + * the work is now done in real_init_plc() + * which is called from pcm_init() ; + */ +} + +static void real_init_plc(smc) +struct s_smc *smc ; +{ + int p ; + + for (p = 0 ; p < NUMPHYS ; p++) + plc_init(smc,p) ; +} + +static void plc_init(smc,p) +struct s_smc *smc ; +int p; +{ + int i ; +#ifndef MOT_ELM + int rev ; /* Revision of PLC-x */ +#endif /* MOT_ELM */ + + /* transit PCM state machine to MAINT state */ + outpw(PLC(p,PL_CNTRL_B),0) ; + outpw(PLC(p,PL_CNTRL_B),PL_PCM_STOP) ; + outpw(PLC(p,PL_CNTRL_A),0) ; + + /* + * if PLC-S then set control register C + */ +#ifndef MOT_ELM + rev = inpw(PLC(p,PL_STATUS_A)) & PLC_REV_MASK ; + if (rev != PLC_REVISION_A) +#endif /* MOT_ELM */ + { + if (smc->y[p].pmd_scramble) { + outpw(PLC(p,PL_CNTRL_C),PLCS_CONTROL_C_S) ; +#ifdef MOT_ELM + outpw(PLC(p,PL_T_FOT_ASS),PLCS_FASSERT_S) ; + outpw(PLC(p,PL_T_FOT_DEASS),PLCS_FDEASSERT_S) ; +#endif /* MOT_ELM */ + } + else { + outpw(PLC(p,PL_CNTRL_C),PLCS_CONTROL_C_U) ; +#ifdef MOT_ELM + outpw(PLC(p,PL_T_FOT_ASS),PLCS_FASSERT_U) ; + outpw(PLC(p,PL_T_FOT_DEASS),PLCS_FDEASSERT_U) ; +#endif /* MOT_ELM */ + } + } + + /* + * set timer register + */ + for ( i = 0 ; pltm[i].timer; i++) /* set timer parameter reg */ + outpw(PLC(p,pltm[i].timer),pltm[i].para) ; + + (void)inpw(PLC(p,PL_INTR_EVENT)) ; /* clear interrupt event reg */ + plc_clear_irq(smc,p) ; + outpw(PLC(p,PL_INTR_MASK),plc_imsk_na); /* enable non active irq's */ + + /* + * if PCM is configured for class s, it will NOT go to the + * REMOVE state if offline (page 3-36;) + * in the concentrator, all inactive PHYS always must be in + * the remove state + * there's no real need to use this feature at all .. + */ +#ifndef CONCENTRATOR + if ((smc->s.sas == SMT_SAS) && (p == PS)) { + outpw(PLC(p,PL_CNTRL_B),PL_CLASS_S) ; + } +#endif +} + +/* + * control PCM state machine + */ +static void plc_go_state(smc,p,state) +struct s_smc *smc ; +int p; +int state; +{ + HW_PTR port ; + int val ; + + SK_UNUSED(smc) ; + + port = (HW_PTR) (PLC(p,PL_CNTRL_B)) ; + val = inpw(port) & ~(PL_PCM_CNTRL | PL_MAINT) ; + outpw(port,val) ; + outpw(port,val | state) ; +} + +/* + * read current line state (called by ECM & PCM) + */ +int sm_pm_get_ls(smc,phy) +struct s_smc *smc ; +int phy; +{ + int state ; + +#ifdef CONCENTRATOR + if (!plc_is_installed(smc,phy)) + return(PC_QLS) ; +#endif + + state = inpw(PLC(phy,PL_STATUS_A)) & PL_LINE_ST ; + switch(state) { + case PL_L_QLS: + state = PC_QLS ; + break ; + case PL_L_MLS: + state = PC_MLS ; + break ; + case PL_L_HLS: + state = PC_HLS ; + break ; + case PL_L_ILS4: + case PL_L_ILS16: + state = PC_ILS ; + break ; + case PL_L_ALS: + state = PC_LS_PDR ; + break ; + default : + state = PC_LS_NONE ; + } + return(state) ; +} + +static int plc_send_bits(smc,phy,len) +struct s_smc *smc ; +struct s_phy *phy; +int len; +{ + int np = phy->np ; /* PHY index */ + int n ; + int i ; + + SK_UNUSED(smc) ; + + /* create bit vector */ + for (i = len-1,n = 0 ; i >= 0 ; i--) { + n = (n<<1) | phy->t_val[phy->bitn+i] ; + } + if (inpw(PLC(np,PL_STATUS_B)) & PL_PCM_SIGNAL) { +#if 0 + printf("PL_PCM_SIGNAL is set\n") ; +#endif + return(1) ; + } + /* write bit[n] & length = 1 to regs */ + outpw(PLC(np,PL_VECTOR_LEN),len-1) ; /* len=nr-1 */ + outpw(PLC(np,PL_XMIT_VECTOR),n) ; +#ifdef DEBUG +#if 1 +#ifdef DEBUG_BRD + if (smc->debug.d_plc & 0x80) +#else + if (debug.d_plc & 0x80) +#endif + printf("SIGNALING bit %d .. %d\n",phy->bitn,phy->bitn+len-1) ; +#endif +#endif + return(0) ; +} + +/* + * config plc muxes + */ +void plc_config_mux(smc,mux) +struct s_smc *smc ; +int mux ; +{ + if (smc->s.sas != SMT_DAS) + return ; + if (mux == MUX_WRAPB) { + SETMASK(PLC(PA,PL_CNTRL_B),PL_CONFIG_CNTRL,PL_CONFIG_CNTRL) ; + SETMASK(PLC(PA,PL_CNTRL_A),PL_SC_REM_LOOP,PL_SC_REM_LOOP) ; + } + else { + CLEAR(PLC(PA,PL_CNTRL_B),PL_CONFIG_CNTRL) ; + CLEAR(PLC(PA,PL_CNTRL_A),PL_SC_REM_LOOP) ; + } + CLEAR(PLC(PB,PL_CNTRL_B),PL_CONFIG_CNTRL) ; + CLEAR(PLC(PB,PL_CNTRL_A),PL_SC_REM_LOOP) ; +} + +/* + PCM state machine + called by dispatcher & fddi_init() (driver) + do + display state change + process event + until SM is stable +*/ +void pcm(smc,np,event) +struct s_smc *smc ; +const int np; +int event; +{ + int state ; + int oldstate ; + struct s_phy *phy ; + struct fddi_mib_p *mib ; + +#ifndef CONCENTRATOR + /* + * ignore 2nd PHY if SAS + */ + if ((np != PS) && (smc->s.sas == SMT_SAS)) + return ; +#endif + phy = &smc->y[np] ; + mib = phy->mib ; + oldstate = mib->fddiPORTPCMState ; + do { + DB_PCM("PCM %c: state %s", + phy->phy_name, + (mib->fddiPORTPCMState & AFLAG) ? "ACTIONS " : "") ; + DB_PCM("%s, event %s\n", + pcm_states[mib->fddiPORTPCMState & ~AFLAG], + pcm_events[event]) ; + state = mib->fddiPORTPCMState ; + pcm_fsm(smc,phy,event) ; + event = 0 ; + } while (state != mib->fddiPORTPCMState) ; + /* + * because the PLC does the bit signaling for us, + * we're always in SIGNAL state + * the MIB want's to see CONNECT + * we therefore fake an entry in the MIB + */ + if (state == PC5_SIGNAL) + mib->fddiPORTPCMStateX = PC3_CONNECT ; + else + mib->fddiPORTPCMStateX = state ; + +#ifndef SLIM_SMT + /* + * path change + */ + if ( mib->fddiPORTPCMState != oldstate && + ((oldstate == PC8_ACTIVE) || (mib->fddiPORTPCMState == PC8_ACTIVE))) { + smt_srf_event(smc,SMT_EVENT_PORT_PATH_CHANGE, + (int) (INDEX_PORT+ phy->np),0) ; + } +#endif + +#ifdef FDDI_MIB + /* check whether a snmp-trap has to be sent */ + + if ( mib->fddiPORTPCMState != oldstate ) { + /* a real state change took place */ + DB_SNMP ("PCM from %d to %d\n", oldstate, mib->fddiPORTPCMState); + if ( mib->fddiPORTPCMState == PC0_OFF ) { + /* send first trap */ + snmp_fddi_trap (smc, 1, (int) mib->fddiPORTIndex ); + } else if ( oldstate == PC0_OFF ) { + /* send second trap */ + snmp_fddi_trap (smc, 2, (int) mib->fddiPORTIndex ); + } else if ( mib->fddiPORTPCMState != PC2_TRACE && + oldstate == PC8_ACTIVE ) { + /* send third trap */ + snmp_fddi_trap (smc, 3, (int) mib->fddiPORTIndex ); + } else if ( mib->fddiPORTPCMState == PC8_ACTIVE ) { + /* send fourth trap */ + snmp_fddi_trap (smc, 4, (int) mib->fddiPORTIndex ); + } + } +#endif + + pcm_state_change(smc,np,state) ; +} + +/* + * PCM state machine + */ +static void pcm_fsm(smc,phy,cmd) +struct s_smc *smc ; +struct s_phy *phy; +int cmd; +{ + int i ; + int np = phy->np ; /* PHY index */ + struct s_plc *plc ; + struct fddi_mib_p *mib ; +#ifndef MOT_ELM + u_short plc_rev ; /* Revision of the plc */ +#endif /* nMOT_ELM */ + + plc = &phy->plc ; + mib = phy->mib ; + + /* + * general transitions independant of state + */ + switch (cmd) { + case PC_STOP : + /*PC00-PC80*/ + if (mib->fddiPORTPCMState != PC9_MAINT) { + GO_STATE(PC0_OFF) ; + AIX_EVENT(smc, (u_long) FDDI_RING_STATUS, (u_long) + FDDI_PORT_EVENT, (u_long) FDDI_PORT_STOP, + smt_get_port_event_word(smc)); + } + return ; + case PC_START : + /*PC01-PC81*/ + if (mib->fddiPORTPCMState != PC9_MAINT) + GO_STATE(PC1_BREAK) ; + return ; + case PC_DISABLE : + /* PC09-PC99 */ + GO_STATE(PC9_MAINT) ; + AIX_EVENT(smc, (u_long) FDDI_RING_STATUS, (u_long) + FDDI_PORT_EVENT, (u_long) FDDI_PORT_DISABLED, + smt_get_port_event_word(smc)); + return ; + case PC_TIMEOUT_LCT : + /* if long or extended LCT */ + stop_pcm_timer0(smc,phy) ; + CLEAR(PLC(np,PL_CNTRL_B),PL_LONG) ; + /* end of LCT is indicate by PCM_CODE (initiate PCM event) */ + return ; + } + + switch(mib->fddiPORTPCMState) { + case ACTIONS(PC0_OFF) : + stop_pcm_timer0(smc,phy) ; + outpw(PLC(np,PL_CNTRL_A),0) ; + CLEAR(PLC(np,PL_CNTRL_B),PL_PC_JOIN) ; + CLEAR(PLC(np,PL_CNTRL_B),PL_LONG) ; + sm_ph_lem_stop(smc,np) ; /* disable LEM */ + phy->cf_loop = FALSE ; + phy->cf_join = FALSE ; + queue_event(smc,EVENT_CFM,CF_JOIN+np) ; + plc_go_state(smc,np,PL_PCM_STOP) ; + mib->fddiPORTConnectState = PCM_DISABLED ; + ACTIONS_DONE() ; + break ; + case PC0_OFF: + /*PC09*/ + if (cmd == PC_MAINT) { + GO_STATE(PC9_MAINT) ; + break ; + } + break ; + case ACTIONS(PC1_BREAK) : + /* Stop the LCT timer if we came from Signal state */ + stop_pcm_timer0(smc,phy) ; + ACTIONS_DONE() ; + plc_go_state(smc,np,0) ; + CLEAR(PLC(np,PL_CNTRL_B),PL_PC_JOIN) ; + CLEAR(PLC(np,PL_CNTRL_B),PL_LONG) ; + sm_ph_lem_stop(smc,np) ; /* disable LEM */ + /* + * if vector is already loaded, go to OFF to clear PCM_SIGNAL + */ +#if 0 + if (inpw(PLC(np,PL_STATUS_B)) & PL_PCM_SIGNAL) { + plc_go_state(smc,np,PL_PCM_STOP) ; + /* TB_MIN ? */ + } +#endif + /* + * Go to OFF state in any case. + */ + plc_go_state(smc,np,PL_PCM_STOP) ; + + if (mib->fddiPORTPC_Withhold == PC_WH_NONE) + mib->fddiPORTConnectState = PCM_CONNECTING ; + phy->cf_loop = FALSE ; + phy->cf_join = FALSE ; + queue_event(smc,EVENT_CFM,CF_JOIN+np) ; + phy->ls_flag = FALSE ; + phy->pc_mode = PM_NONE ; /* needed by CFM */ + phy->bitn = 0 ; /* bit signaling start bit */ + for (i = 0 ; i < 3 ; i++) + pc_tcode_actions(smc,i,phy) ; + + /* Set the non-active interrupt mask register */ + outpw(PLC(np,PL_INTR_MASK),plc_imsk_na) ; + + /* + * If the LCT was stopped. There might be a + * PCM_CODE interrupt event present. + * This must be cleared. + */ + (void)inpw(PLC(np,PL_INTR_EVENT)) ; +#ifndef MOT_ELM + /* Get the plc revision for revision dependent code */ + plc_rev = inpw(PLC(np,PL_STATUS_A)) & PLC_REV_MASK ; + + if (plc_rev != PLC_REV_SN3) +#endif /* MOT_ELM */ + { + /* + * No supernet III PLC, so set Xmit verctor and + * length BEFORE starting the state machine. + */ + if (plc_send_bits(smc,phy,3)) { + return ; + } + } + + /* + * Now give the Start command. + * - The start command shall be done before setting the bits + * to be signaled. (In PLC-S description and PLCS in SN3. + * - The start command shall be issued AFTER setting the + * XMIT vector and the XMIT length register. + * + * We do it exactly according this specs for the old PLC and + * the new PLCS inside the SN3. + * For the usual PLCS we try it the way it is done for the + * old PLC and set the XMIT registers again, if the PLC is + * not in SIGNAL state. This is done according to an PLCS + * errata workaround. + */ + + plc_go_state(smc,np,PL_PCM_START) ; + + /* + * workaround for PLC-S eng. sample errata + */ +#ifdef MOT_ELM + if (!(inpw(PLC(np,PL_STATUS_B)) & PL_PCM_SIGNAL)) +#else /* nMOT_ELM */ + if (((inpw(PLC(np,PL_STATUS_A)) & PLC_REV_MASK) != + PLC_REVISION_A) && + !(inpw(PLC(np,PL_STATUS_B)) & PL_PCM_SIGNAL)) +#endif /* nMOT_ELM */ + { + /* + * Set register again (PLCS errata) or the first time + * (new SN3 PLCS). + */ + (void) plc_send_bits(smc,phy,3) ; + } + /* + * end of workaround + */ + + GO_STATE(PC5_SIGNAL) ; + plc->p_state = PS_BIT3 ; + plc->p_bits = 3 ; + plc->p_start = 0 ; + + break ; + case PC1_BREAK : + break ; + case ACTIONS(PC2_TRACE) : + plc_go_state(smc,np,PL_PCM_TRACE) ; + ACTIONS_DONE() ; + break ; + case PC2_TRACE : + break ; + + case PC3_CONNECT : /* these states are done by hardware */ + case PC4_NEXT : + break ; + + case ACTIONS(PC5_SIGNAL) : + ACTIONS_DONE() ; + case PC5_SIGNAL : + if ((cmd != PC_SIGNAL) && (cmd != PC_TIMEOUT_LCT)) + break ; + switch (plc->p_state) { + case PS_BIT3 : + for (i = 0 ; i <= 2 ; i++) + pc_rcode_actions(smc,i,phy) ; + pc_tcode_actions(smc,3,phy) ; + plc->p_state = PS_BIT4 ; + plc->p_bits = 1 ; + plc->p_start = 3 ; + phy->bitn = 3 ; + if (plc_send_bits(smc,phy,1)) { + return ; + } + break ; + case PS_BIT4 : + pc_rcode_actions(smc,3,phy) ; + for (i = 4 ; i <= 6 ; i++) + pc_tcode_actions(smc,i,phy) ; + plc->p_state = PS_BIT7 ; + plc->p_bits = 3 ; + plc->p_start = 4 ; + phy->bitn = 4 ; + if (plc_send_bits(smc,phy,3)) { + return ; + } + break ; + case PS_BIT7 : + for (i = 3 ; i <= 6 ; i++) + pc_rcode_actions(smc,i,phy) ; + plc->p_state = PS_LCT ; + plc->p_bits = 0 ; + plc->p_start = 7 ; + phy->bitn = 7 ; + sm_ph_lem_start(smc,np,(int)smc->s.lct_short) ; /* enable LEM */ + /* start LCT */ + i = inpw(PLC(np,PL_CNTRL_B)) & ~PL_PC_LOOP ; + outpw(PLC(np,PL_CNTRL_B),i) ; /* must be cleared */ + outpw(PLC(np,PL_CNTRL_B),i | PL_RLBP) ; + break ; + case PS_LCT : + /* check for local LCT failure */ + pc_tcode_actions(smc,7,phy) ; + /* + * set tval[7] + */ + plc->p_state = PS_BIT8 ; + plc->p_bits = 1 ; + plc->p_start = 7 ; + phy->bitn = 7 ; + if (plc_send_bits(smc,phy,1)) { + return ; + } + break ; + case PS_BIT8 : + /* check for remote LCT failure */ + pc_rcode_actions(smc,7,phy) ; + if (phy->t_val[7] || phy->r_val[7]) { + plc_go_state(smc,np,PL_PCM_STOP) ; + GO_STATE(PC1_BREAK) ; + break ; + } + for (i = 8 ; i <= 9 ; i++) + pc_tcode_actions(smc,i,phy) ; + plc->p_state = PS_JOIN ; + plc->p_bits = 2 ; + plc->p_start = 8 ; + phy->bitn = 8 ; + if (plc_send_bits(smc,phy,2)) { + return ; + } + break ; + case PS_JOIN : + for (i = 8 ; i <= 9 ; i++) + pc_rcode_actions(smc,i,phy) ; + plc->p_state = PS_ACTIVE ; + GO_STATE(PC6_JOIN) ; + break ; + } + break ; + + case ACTIONS(PC6_JOIN) : + /* + * prevent mux error when going from WRAP_A to WRAP_B + */ + if (smc->s.sas == SMT_DAS && np == PB && + (smc->y[PA].pc_mode == PM_TREE || + smc->y[PB].pc_mode == PM_TREE)) { + SETMASK(PLC(np,PL_CNTRL_A), + PL_SC_REM_LOOP,PL_SC_REM_LOOP) ; + SETMASK(PLC(np,PL_CNTRL_B), + PL_CONFIG_CNTRL,PL_CONFIG_CNTRL) ; + } + SETMASK(PLC(np,PL_CNTRL_B),PL_PC_JOIN,PL_PC_JOIN) ; + SETMASK(PLC(np,PL_CNTRL_B),PL_PC_JOIN,PL_PC_JOIN) ; + ACTIONS_DONE() ; + cmd = 0 ; + /* fall thru */ + case PC6_JOIN : + switch (plc->p_state) { + case PS_ACTIVE: + /*PC88b*/ + if (!phy->cf_join) { + phy->cf_join = TRUE ; + queue_event(smc,EVENT_CFM,CF_JOIN+np) ; ; + } + if (cmd == PC_JOIN) + GO_STATE(PC8_ACTIVE) ; + /*PC82*/ + if (cmd == PC_TRACE) { + GO_STATE(PC2_TRACE) ; + break ; + } + break ; + } + break ; + + case PC7_VERIFY : + break ; + + case ACTIONS(PC8_ACTIVE) : + /* + * start LEM for SMT + */ + sm_ph_lem_start(smc,(int)phy->np,LCT_LEM_MAX) ; + + phy->tr_flag = FALSE ; + mib->fddiPORTConnectState = PCM_ACTIVE ; + + /* Set the active interrupt mask register */ + outpw(PLC(np,PL_INTR_MASK),plc_imsk_act) ; + + ACTIONS_DONE() ; + break ; + case PC8_ACTIVE : + /*PC81 is done by PL_TNE_EXPIRED irq */ + /*PC82*/ + if (cmd == PC_TRACE) { + GO_STATE(PC2_TRACE) ; + break ; + } + /*PC88c: is done by TRACE_PROP irq */ + + break ; + case ACTIONS(PC9_MAINT) : + stop_pcm_timer0(smc,phy) ; + CLEAR(PLC(np,PL_CNTRL_B),PL_PC_JOIN) ; + CLEAR(PLC(np,PL_CNTRL_B),PL_LONG) ; + CLEAR(PLC(np,PL_INTR_MASK),PL_LE_CTR) ; /* disable LEM int. */ + sm_ph_lem_stop(smc,np) ; /* disable LEM */ + phy->cf_loop = FALSE ; + phy->cf_join = FALSE ; + queue_event(smc,EVENT_CFM,CF_JOIN+np) ; + plc_go_state(smc,np,PL_PCM_STOP) ; + mib->fddiPORTConnectState = PCM_DISABLED ; + SETMASK(PLC(np,PL_CNTRL_B),PL_MAINT,PL_MAINT) ; + sm_ph_linestate(smc,np,(int) MIB2LS(mib->fddiPORTMaint_LS)) ; + outpw(PLC(np,PL_CNTRL_A),PL_SC_BYPASS) ; + ACTIONS_DONE() ; + break ; + case PC9_MAINT : + DB_PCMN(1,"PCM %c : MAINT\n",phy->phy_name,0) ; + /*PC90*/ + if (cmd == PC_ENABLE) { + GO_STATE(PC0_OFF) ; + break ; + } + break ; + + default: + SMT_PANIC(smc,SMT_E0118, SMT_E0118_MSG) ; + break ; + } +} + +/* + * force line state on a PHY output (only in MAINT state) + */ +static void sm_ph_linestate(smc,phy,ls) +struct s_smc *smc ; +int phy; +int ls; +{ + int cntrl ; + + SK_UNUSED(smc) ; + + cntrl = (inpw(PLC(phy,PL_CNTRL_B)) & ~PL_MAINT_LS) | + PL_PCM_STOP | PL_MAINT ; + switch(ls) { + case PC_QLS: /* Force Quiet */ + cntrl |= PL_M_QUI0 ; + break ; + case PC_MLS: /* Force Master */ + cntrl |= PL_M_MASTR ; + break ; + case PC_HLS: /* Force Halt */ + cntrl |= PL_M_HALT ; + break ; + default : + case PC_ILS: /* Force Idle */ + cntrl |= PL_M_IDLE ; + break ; + case PC_LS_PDR: /* Enable repeat filter */ + cntrl |= PL_M_TPDR ; + break ; + } + outpw(PLC(phy,PL_CNTRL_B),cntrl) ; +} + + +static void reset_lem_struct(phy) +struct s_phy *phy; +{ + struct lem_counter *lem = &phy->lem ; + + phy->mib->fddiPORTLer_Estimate = 15 ; + lem->lem_float_ber = 15 * 100 ; +} + +/* + * link error monitor + */ +static void lem_evaluate(smc,phy) +struct s_smc *smc ; +struct s_phy *phy; +{ + int ber ; + u_long errors ; + struct lem_counter *lem = &phy->lem ; + struct fddi_mib_p *mib ; + int cond ; + + mib = phy->mib ; + + if (!lem->lem_on) + return ; + + errors = inpw(PLC(((int) phy->np),PL_LINK_ERR_CTR)) ; + lem->lem_errors += errors ; + mib->fddiPORTLem_Ct += errors ; + + errors = lem->lem_errors ; + /* + * calculation is called on a intervall of 8 seconds + * -> this means, that one error in 8 sec. is one of 8*125*10E6 + * the same as BER = 10E-9 + * Please note: + * -> 9 errors in 8 seconds mean: + * BER = 9 * 10E-9 and this is + * < 10E-8, so the limit of 10E-8 is not reached! + */ + + if (!errors) ber = 15 ; + else if (errors <= 9) ber = 9 ; + else if (errors <= 99) ber = 8 ; + else if (errors <= 999) ber = 7 ; + else if (errors <= 9999) ber = 6 ; + else if (errors <= 99999) ber = 5 ; + else if (errors <= 999999) ber = 4 ; + else if (errors <= 9999999) ber = 3 ; + else if (errors <= 99999999) ber = 2 ; + else if (errors <= 999999999) ber = 1 ; + else ber = 0 ; + + /* + * weighted average + */ + ber *= 100 ; + lem->lem_float_ber = lem->lem_float_ber * 7 + ber * 3 ; + lem->lem_float_ber /= 10 ; + mib->fddiPORTLer_Estimate = lem->lem_float_ber / 100 ; + if (mib->fddiPORTLer_Estimate < 4) { + mib->fddiPORTLer_Estimate = 4 ; + } + + if (lem->lem_errors) { + DB_PCMN(1,"LEM %c :\n",phy->np == PB? 'B' : 'A',0) ; + DB_PCMN(1,"errors : %ld\n",lem->lem_errors,0) ; + DB_PCMN(1,"sum_errors : %ld\n",mib->fddiPORTLem_Ct,0) ; + DB_PCMN(1,"current BER : 10E-%d\n",ber/100,0) ; + DB_PCMN(1,"float BER : 10E-(%d/100)\n",lem->lem_float_ber,0) ; + DB_PCMN(1,"avg. BER : 10E-%d\n", + mib->fddiPORTLer_Estimate,0) ; + } + + lem->lem_errors = 0L ; + +#ifndef SLIM_SMT + cond = (mib->fddiPORTLer_Estimate <= mib->fddiPORTLer_Alarm) ? + TRUE : FALSE ; +#ifdef SMT_EXT_CUTOFF + smt_ler_alarm_check(smc,phy,cond) ; +#endif /* nSMT_EXT_CUTOFF */ + if (cond != mib->fddiPORTLerFlag) { + smt_srf_event(smc,SMT_COND_PORT_LER, + (int) (INDEX_PORT+ phy->np) ,cond) ; + } +#endif + + if ( mib->fddiPORTLer_Estimate <= mib->fddiPORTLer_Cutoff) { + phy->pc_lem_fail = TRUE ; /* flag */ + mib->fddiPORTLem_Reject_Ct++ ; + /* + * "forgive 10e-2" if we cutoff so we can come + * up again .. + */ + lem->lem_float_ber += 2*100 ; + + /*PC81b*/ +#ifdef CONCENTRATOR + DB_PCMN(1,"PCM: LER cutoff on port %d cutoff %d\n", + phy->np, mib->fddiPORTLer_Cutoff) ; +#endif +#ifdef SMT_EXT_CUTOFF + smt_port_off_event(smc,phy->np); +#else /* nSMT_EXT_CUTOFF */ + queue_event(smc,(int)(EVENT_PCM+phy->np),PC_START) ; +#endif /* nSMT_EXT_CUTOFF */ + } +} + +/* + * called by SMT to calculate LEM bit error rate + */ +void sm_lem_evaluate(smc) +struct s_smc *smc ; +{ + int np ; + + for (np = 0 ; np < NUMPHYS ; np++) + lem_evaluate(smc,&smc->y[np]) ; +} + +static void lem_check_lct(smc,phy) +struct s_smc *smc ; +struct s_phy *phy ; +{ + struct lem_counter *lem = &phy->lem ; + struct fddi_mib_p *mib ; + int errors ; + + mib = phy->mib ; + + phy->pc_lem_fail = FALSE ; /* flag */ + errors = inpw(PLC(((int)phy->np),PL_LINK_ERR_CTR)) ; + lem->lem_errors += errors ; + mib->fddiPORTLem_Ct += errors ; + if (lem->lem_errors) { + switch(phy->lc_test) { + case LC_SHORT: + if (lem->lem_errors >= smc->s.lct_short) + phy->pc_lem_fail = TRUE ; + break ; + case LC_MEDIUM: + if (lem->lem_errors >= smc->s.lct_medium) + phy->pc_lem_fail = TRUE ; + break ; + case LC_LONG: + if (lem->lem_errors >= smc->s.lct_long) + phy->pc_lem_fail = TRUE ; + break ; + case LC_EXTENDED: + if (lem->lem_errors >= smc->s.lct_extended) + phy->pc_lem_fail = TRUE ; + break ; + } + DB_PCMN(1," >>errors : %d\n",lem->lem_errors,0) ; + } + if (phy->pc_lem_fail) { + mib->fddiPORTLCTFail_Ct++ ; + mib->fddiPORTLem_Reject_Ct++ ; + } + else + mib->fddiPORTLCTFail_Ct = 0 ; +} + +/* + * LEM functions + */ +static void sm_ph_lem_start(smc,np,threshold) +struct s_smc *smc ; +int np; +int threshold; +{ + struct lem_counter *lem = &smc->y[np].lem ; + + lem->lem_on = 1 ; + lem->lem_errors = 0L ; + + /* Do NOT reset mib->fddiPORTLer_Estimate here. It is called too + * often. + */ + + outpw(PLC(np,PL_LE_THRESHOLD),threshold) ; + (void)inpw(PLC(np,PL_LINK_ERR_CTR)) ; /* clear error counter */ + + /* enable LE INT */ + SETMASK(PLC(np,PL_INTR_MASK),PL_LE_CTR,PL_LE_CTR) ; +} + +static void sm_ph_lem_stop(smc,np) +struct s_smc *smc ; +int np; +{ + struct lem_counter *lem = &smc->y[np].lem ; + + lem->lem_on = 0 ; + CLEAR(PLC(np,PL_INTR_MASK),PL_LE_CTR) ; +} + +/* ARGSUSED */ +void sm_pm_ls_latch(smc,phy,on_off) +struct s_smc *smc ; +int phy; +int on_off; /* en- or disable ident. ls */ +{ + SK_UNUSED(smc) ; + + phy = phy ; on_off = on_off ; +} + + +/* + * PCM pseudo code + * receive actions are called AFTER the bit n is received, + * i.e. if pc_rcode_actions(5) is called, bit 6 is the next bit to be received + */ + +/* + * PCM pseudo code 5.1 .. 6.1 + */ +static void pc_rcode_actions(smc,bit,phy) +struct s_smc *smc ; +int bit; +struct s_phy *phy; +{ + struct fddi_mib_p *mib ; + + mib = phy->mib ; + + DB_PCMN(1,"SIG rec %x %x: \n", bit,phy->r_val[bit] ) ; + bit++ ; + + switch(bit) { + case 0: + case 1: + case 2: + break ; + case 3 : + if (phy->r_val[1] == 0 && phy->r_val[2] == 0) + mib->fddiPORTNeighborType = TA ; + else if (phy->r_val[1] == 0 && phy->r_val[2] == 1) + mib->fddiPORTNeighborType = TB ; + else if (phy->r_val[1] == 1 && phy->r_val[2] == 0) + mib->fddiPORTNeighborType = TS ; + else if (phy->r_val[1] == 1 && phy->r_val[2] == 1) + mib->fddiPORTNeighborType = TM ; + break ; + case 4: + if (mib->fddiPORTMy_Type == TM && + mib->fddiPORTNeighborType == TM) { + DB_PCMN(1,"PCM %c : E100 withhold M-M\n", + phy->phy_name,0) ; + mib->fddiPORTPC_Withhold = PC_WH_M_M ; + RS_SET(smc,RS_EVENT) ; + } + else if (phy->t_val[3] || phy->r_val[3]) { + mib->fddiPORTPC_Withhold = PC_WH_NONE ; + if (mib->fddiPORTMy_Type == TM || + mib->fddiPORTNeighborType == TM) + phy->pc_mode = PM_TREE ; + else + phy->pc_mode = PM_PEER ; + + /* reevaluate the selection criteria (wc_flag) */ + all_selection_criteria (smc); + + if (phy->wc_flag) { + mib->fddiPORTPC_Withhold = PC_WH_PATH ; + } + } + else { + mib->fddiPORTPC_Withhold = PC_WH_OTHER ; + RS_SET(smc,RS_EVENT) ; + DB_PCMN(1,"PCM %c : E101 withhold other\n", + phy->phy_name,0) ; + } + phy->twisted = ((mib->fddiPORTMy_Type != TS) && + (mib->fddiPORTMy_Type != TM) && + (mib->fddiPORTNeighborType == + mib->fddiPORTMy_Type)) ; + if (phy->twisted) { + DB_PCMN(1,"PCM %c : E102 !!! TWISTED !!!\n", + phy->phy_name,0) ; + } + break ; + case 5 : + break ; + case 6: + if (phy->t_val[4] || phy->r_val[4]) { + if ((phy->t_val[4] && phy->t_val[5]) || + (phy->r_val[4] && phy->r_val[5]) ) + phy->lc_test = LC_EXTENDED ; + else + phy->lc_test = LC_LONG ; + } + else if (phy->t_val[5] || phy->r_val[5]) + phy->lc_test = LC_MEDIUM ; + else + phy->lc_test = LC_SHORT ; + switch (phy->lc_test) { + case LC_SHORT : /* 50ms */ + outpw(PLC((int)phy->np,PL_LC_LENGTH), TP_LC_LENGTH ) ; + phy->t_next[7] = smc->s.pcm_lc_short ; + break ; + case LC_MEDIUM : /* 500ms */ + outpw(PLC((int)phy->np,PL_LC_LENGTH), TP_LC_LONGLN ) ; + phy->t_next[7] = smc->s.pcm_lc_medium ; + break ; + case LC_LONG : + SETMASK(PLC((int)phy->np,PL_CNTRL_B),PL_LONG,PL_LONG) ; + phy->t_next[7] = smc->s.pcm_lc_long ; + break ; + case LC_EXTENDED : + SETMASK(PLC((int)phy->np,PL_CNTRL_B),PL_LONG,PL_LONG) ; + phy->t_next[7] = smc->s.pcm_lc_extended ; + break ; + } + if (phy->t_next[7] > smc->s.pcm_lc_medium) { + start_pcm_timer0(smc,phy->t_next[7],PC_TIMEOUT_LCT,phy); + } + DB_PCMN(1,"LCT timer = %ld us\n", phy->t_next[7], 0) ; + phy->t_next[9] = smc->s.pcm_t_next_9 ; + break ; + case 7: + if (phy->t_val[6]) { + phy->cf_loop = TRUE ; + } + phy->td_flag = TRUE ; + break ; + case 8: + if (phy->t_val[7] || phy->r_val[7]) { + DB_PCMN(1,"PCM %c : E103 LCT fail %s\n", + phy->phy_name,phy->t_val[7]? "local":"remote") ; + queue_event(smc,(int)(EVENT_PCM+phy->np),PC_START) ; + } + break ; + case 9: + if (phy->t_val[8] || phy->r_val[8]) { + if (phy->t_val[8]) + phy->cf_loop = TRUE ; + phy->td_flag = TRUE ; + } + break ; + case 10: + if (phy->r_val[9]) { + /* neighbor intends to have MAC on output */ ; + mib->fddiPORTMacIndicated.R_val = TRUE ; + } + else { + /* neighbor does not intend to have MAC on output */ ; + mib->fddiPORTMacIndicated.R_val = FALSE ; + } + break ; + } +} + +/* + * PCM pseudo code 5.1 .. 6.1 + */ +static void pc_tcode_actions(smc,bit,phy) +struct s_smc *smc ; +const int bit; +struct s_phy *phy; +{ + int np = phy->np ; + struct fddi_mib_p *mib ; + + mib = phy->mib ; + + switch(bit) { + case 0: + phy->t_val[0] = 0 ; /* no escape used */ + break ; + case 1: + if (mib->fddiPORTMy_Type == TS || mib->fddiPORTMy_Type == TM) + phy->t_val[1] = 1 ; + else + phy->t_val[1] = 0 ; + break ; + case 2 : + if (mib->fddiPORTMy_Type == TB || mib->fddiPORTMy_Type == TM) + phy->t_val[2] = 1 ; + else + phy->t_val[2] = 0 ; + break ; + case 3: + { + int type,ne ; + int policy ; + + type = mib->fddiPORTMy_Type ; + ne = mib->fddiPORTNeighborType ; + policy = smc->mib.fddiSMTConnectionPolicy ; + + phy->t_val[3] = 1 ; /* Accept connection */ + switch (type) { + case TA : + if ( + ((policy & POLICY_AA) && ne == TA) || + ((policy & POLICY_AB) && ne == TB) || + ((policy & POLICY_AS) && ne == TS) || + ((policy & POLICY_AM) && ne == TM) ) + phy->t_val[3] = 0 ; /* Reject */ + break ; + case TB : + if ( + ((policy & POLICY_BA) && ne == TA) || + ((policy & POLICY_BB) && ne == TB) || + ((policy & POLICY_BS) && ne == TS) || + ((policy & POLICY_BM) && ne == TM) ) + phy->t_val[3] = 0 ; /* Reject */ + break ; + case TS : + if ( + ((policy & POLICY_SA) && ne == TA) || + ((policy & POLICY_SB) && ne == TB) || + ((policy & POLICY_SS) && ne == TS) || + ((policy & POLICY_SM) && ne == TM) ) + phy->t_val[3] = 0 ; /* Reject */ + break ; + case TM : + if ( ne == TM || + ((policy & POLICY_MA) && ne == TA) || + ((policy & POLICY_MB) && ne == TB) || + ((policy & POLICY_MS) && ne == TS) || + ((policy & POLICY_MM) && ne == TM) ) + phy->t_val[3] = 0 ; /* Reject */ + break ; + } +#ifndef SLIM_SMT + /* + * detect undesirable connection attempt event + */ + if ( (type == TA && ne == TA ) || + (type == TA && ne == TS ) || + (type == TB && ne == TB ) || + (type == TB && ne == TS ) || + (type == TS && ne == TA ) || + (type == TS && ne == TB ) ) { + smt_srf_event(smc,SMT_EVENT_PORT_CONNECTION, + (int) (INDEX_PORT+ phy->np) ,0) ; + } +#endif + } + break ; + case 4: + if (mib->fddiPORTPC_Withhold == PC_WH_NONE) { + if (phy->pc_lem_fail) { + phy->t_val[4] = 1 ; /* long */ + phy->t_val[5] = 0 ; + } + else { + phy->t_val[4] = 0 ; + if (mib->fddiPORTLCTFail_Ct > 0) + phy->t_val[5] = 1 ; /* medium */ + else + phy->t_val[5] = 0 ; /* short */ + + /* + * Implementers choice: use medium + * instead of short when undesired + * connection attempt is made. + */ + if (phy->wc_flag) + phy->t_val[5] = 1 ; /* medium */ + } + mib->fddiPORTConnectState = PCM_CONNECTING ; + } + else { + mib->fddiPORTConnectState = PCM_STANDBY ; + phy->t_val[4] = 1 ; /* extended */ + phy->t_val[5] = 1 ; + } + break ; + case 5: + break ; + case 6: + /* we do NOT have a MAC for LCT */ + phy->t_val[6] = 0 ; + break ; + case 7: + phy->cf_loop = FALSE ; + lem_check_lct(smc,phy) ; + if (phy->pc_lem_fail) { + DB_PCMN(1,"PCM %c : E104 LCT failed\n", + phy->phy_name,0) ; + phy->t_val[7] = 1 ; + } + else + phy->t_val[7] = 0 ; + break ; + case 8: + phy->t_val[8] = 0 ; /* Don't request MAC loopback */ + break ; + case 9: + phy->cf_loop = 0 ; + if ((mib->fddiPORTPC_Withhold != PC_WH_NONE) || + ((smc->s.sas == SMT_DAS) && (phy->wc_flag))) { + queue_event(smc,EVENT_PCM+np,PC_START) ; + break ; + } + phy->t_val[9] = FALSE ; + switch (smc->s.sas) { + case SMT_DAS : + /* + * MAC intended on output + */ + if (phy->pc_mode == PM_TREE) { + if ((np == PB) || ((np == PA) && + (smc->y[PB].mib->fddiPORTConnectState != + PCM_ACTIVE))) + phy->t_val[9] = TRUE ; + } + else { + if (np == PB) + phy->t_val[9] = TRUE ; + } + break ; + case SMT_SAS : + if (np == PS) + phy->t_val[9] = TRUE ; + break ; +#ifdef CONCENTRATOR + case SMT_NAC : + /* + * MAC intended on output + */ + if (np == PB) + phy->t_val[9] = TRUE ; + break ; +#endif + } + mib->fddiPORTMacIndicated.T_val = phy->t_val[9] ; + break ; + } + DB_PCMN(1,"SIG snd %x %x: \n", bit,phy->t_val[bit] ) ; +} + +/* + * return status twisted (called by SMT) + */ +int pcm_status_twisted(smc) +struct s_smc *smc ; +{ + int twist = 0 ; + if (smc->s.sas != SMT_DAS) + return(0) ; + if (smc->y[PA].twisted && (smc->y[PA].mib->fddiPORTPCMState == PC8_ACTIVE)) + twist |= 1 ; + if (smc->y[PB].twisted && (smc->y[PB].mib->fddiPORTPCMState == PC8_ACTIVE)) + twist |= 2 ; + return(twist) ; +} + +/* + * return status (called by SMT) + * type + * state + * remote phy type + * remote mac yes/no + */ +void pcm_status_state(smc,np,type,state,remote,mac) +struct s_smc *smc ; +int np; +int *type; +int *state; +int *remote; +int *mac; +{ + struct s_phy *phy = &smc->y[np] ; + struct fddi_mib_p *mib ; + + mib = phy->mib ; + + /* remote PHY type and MAC - set only if active */ + *mac = 0 ; + *type = mib->fddiPORTMy_Type ; /* our PHY type */ + *state = mib->fddiPORTConnectState ; + *remote = mib->fddiPORTNeighborType ; + + switch(mib->fddiPORTPCMState) { + case PC8_ACTIVE : + *mac = mib->fddiPORTMacIndicated.R_val ; + break ; + } +} + +/* + * return rooted station status (called by SMT) + */ +int pcm_rooted_station(smc) +struct s_smc *smc ; +{ + int n ; + + for (n = 0 ; n < NUMPHYS ; n++) { + if (smc->y[n].mib->fddiPORTPCMState == PC8_ACTIVE && + smc->y[n].mib->fddiPORTNeighborType == TM) + return(0) ; + } + return(1) ; +} + +/* + * Interrupt actions for PLC & PCM events + */ +void plc_irq(smc,np,cmd) +struct s_smc *smc ; +int np; /* PHY index */ +unsigned int cmd; +{ + struct s_phy *phy = &smc->y[np] ; + struct s_plc *plc = &phy->plc ; + int n ; +#ifdef SUPERNET_3 + int corr_mask ; +#endif /* SUPERNET_3 */ + int i ; + + if (np >= smc->s.numphys) { + plc->soft_err++ ; + return ; + } + if (cmd & PL_EBUF_ERR) { /* elastic buff. det. over-|underflow*/ + /* + * Check whether the SRF Condition occured. + */ + if (!plc->ebuf_cont && phy->mib->fddiPORTPCMState == PC8_ACTIVE){ + /* + * This is the real Elasticity Error. + * More than one in a row are treated as a + * single one. + * Only count this in the active state. + */ + phy->mib->fddiPORTEBError_Ct ++ ; + + } + + plc->ebuf_err++ ; + if (plc->ebuf_cont <= 1000) { + /* + * Prevent counter from being wrapped after + * hanging years in that interrupt. + */ + plc->ebuf_cont++ ; /* Ebuf continous error */ + } + +#ifdef SUPERNET_3 + if (plc->ebuf_cont == 1000 && + ((inpw(PLC(np,PL_STATUS_A)) & PLC_REV_MASK) == + PLC_REV_SN3)) { + /* + * This interrupt remeained high for at least + * 1000 consecutive interrupt calls. + * + * This is caused by a hardware error of the + * ORION part of the Supernet III chipset. + * + * Disable this bit from the mask. + */ + corr_mask = (plc_imsk_na & ~PL_EBUF_ERR) ; + outpw(PLC(np,PL_INTR_MASK),corr_mask); + + /* + * Disconnect from the ring. + * Call the driver with the reset indication. + */ + queue_event(smc,EVENT_ECM,EC_DISCONNECT) ; + + /* + * Make an error log entry. + */ + SMT_ERR_LOG(smc,SMT_E0136, SMT_E0136_MSG) ; + + /* + * Indicate the Reset. + */ + drv_reset_indication(smc) ; + } +#endif /* SUPERNET_3 */ + } else { + /* Reset the continous error variable */ + plc->ebuf_cont = 0 ; /* reset Ebuf continous error */ + } + if (cmd & PL_PHYINV) { /* physical layer invalid signal */ + plc->phyinv++ ; + } + if (cmd & PL_VSYM_CTR) { /* violation symbol counter has incr.*/ + plc->vsym_ctr++ ; + } + if (cmd & PL_MINI_CTR) { /* dep. on PLC_CNTRL_A's MINI_CTR_INT*/ + plc->mini_ctr++ ; + } + if (cmd & PL_LE_CTR) { /* link error event counter */ + int j ; + + /* + * note: PL_LINK_ERR_CTR MUST be read to clear it + */ + j = inpw(PLC(np,PL_LE_THRESHOLD)) ; + i = inpw(PLC(np,PL_LINK_ERR_CTR)) ; + + if (i < j) { + /* wrapped around */ + i += 256 ; + } + + if (phy->lem.lem_on) { + /* Note: Lem errors shall only be counted when + * link is ACTIVE or LCT is active. + */ + phy->lem.lem_errors += i ; + phy->mib->fddiPORTLem_Ct += i ; + } + } + if (cmd & PL_TPC_EXPIRED) { /* TPC timer reached zero */ + if (plc->p_state == PS_LCT) { + /* + * end of LCT + */ + ; + } + plc->tpc_exp++ ; + } + if (cmd & PL_LS_MATCH) { /* LS == LS in PLC_CNTRL_B's MATCH_LS*/ + switch (inpw(PLC(np,PL_CNTRL_B)) & PL_MATCH_LS) { + case PL_I_IDLE : phy->curr_ls = PC_ILS ; break ; + case PL_I_HALT : phy->curr_ls = PC_HLS ; break ; + case PL_I_MASTR : phy->curr_ls = PC_MLS ; break ; + case PL_I_QUIET : phy->curr_ls = PC_QLS ; break ; + } + } + if (cmd & PL_PCM_BREAK) { /* PCM has entered the BREAK state */ + int reason; + + reason = inpw(PLC(np,PL_STATUS_B)) & PL_BREAK_REASON ; + + switch (reason) { + case PL_B_PCS : plc->b_pcs++ ; break ; + case PL_B_TPC : plc->b_tpc++ ; break ; + case PL_B_TNE : plc->b_tne++ ; break ; + case PL_B_QLS : plc->b_qls++ ; break ; + case PL_B_ILS : plc->b_ils++ ; break ; + case PL_B_HLS : plc->b_hls++ ; break ; + } + + /*jd 05-Aug-1999 changed: Bug #10419 */ + DB_PCMN(1,"PLC %d: MDcF = %x\n", np, smc->e.DisconnectFlag); + if (smc->e.DisconnectFlag == FALSE) { + DB_PCMN(1,"PLC %d: restart (reason %x)\n", np, reason); + queue_event(smc,EVENT_PCM+np,PC_START) ; + } + else { + DB_PCMN(1,"PLC %d: NO!! restart (reason %x)\n", np, reason); + } + return ; + } + /* + * If both CODE & ENABLE are set ignore enable + */ + if (cmd & PL_PCM_CODE) { /* receive last sign.-bit | LCT complete */ + queue_event(smc,EVENT_PCM+np,PC_SIGNAL) ; + n = inpw(PLC(np,PL_RCV_VECTOR)) ; + for (i = 0 ; i < plc->p_bits ; i++) { + phy->r_val[plc->p_start+i] = n & 1 ; + n >>= 1 ; + } + } + else if (cmd & PL_PCM_ENABLED) { /* asserted SC_JOIN, scrub.completed*/ + queue_event(smc,EVENT_PCM+np,PC_JOIN) ; + } + if (cmd & PL_TRACE_PROP) { /* MLS while PC8_ACTIV || PC2_TRACE */ + /*PC22b*/ + if (!phy->tr_flag) { + DB_PCMN(1,"PCM : irq TRACE_PROP %d %d\n", + np,smc->mib.fddiSMTECMState) ; + phy->tr_flag = TRUE ; + smc->e.trace_prop |= ENTITY_BIT(ENTITY_PHY(np)) ; + queue_event(smc,EVENT_ECM,EC_TRACE_PROP) ; + } + } + /* + * filter PLC glitch ??? + * QLS || HLS only while in PC2_TRACE state + */ + if ((cmd & PL_SELF_TEST) && (phy->mib->fddiPORTPCMState == PC2_TRACE)) { + /*PC22a*/ + if (smc->e.path_test == PT_PASSED) { + DB_PCMN(1,"PCM : state = %s %d\n", get_pcmstate(smc,np), + phy->mib->fddiPORTPCMState) ; + + smc->e.path_test = PT_PENDING ; + queue_event(smc,EVENT_ECM,EC_PATH_TEST) ; + } + } + if (cmd & PL_TNE_EXPIRED) { /* TNE: length of noise events */ + /* break_required (TNE > NS_Max) */ + if (phy->mib->fddiPORTPCMState == PC8_ACTIVE) { + if (!phy->tr_flag) { + DB_PCMN(1,"PCM %c : PC81 %s\n",phy->phy_name,"NSE"); + queue_event(smc,EVENT_PCM+np,PC_START) ; + return ; + } + } + } +#if 0 + if (cmd & PL_NP_ERR) { /* NP has requested to r/w an inv reg*/ + /* + * It's a bug by AMD + */ + plc->np_err++ ; + } + /* pin inactiv (GND) */ + if (cmd & PL_PARITY_ERR) { /* p. error dedected on TX9-0 inp */ + plc->parity_err++ ; + } + if (cmd & PL_LSDO) { /* carrier detected */ + ; + } +#endif +} + +void pcm_set_lct_short(smc,n) +struct s_smc *smc ; +int n ; +{ + if (n <= 0 || n > 1000) + return ; + smc->s.lct_short = n ; +} + +#ifdef DEBUG +/* + * fill state struct + */ +void pcm_get_state(smc,state) +struct s_smc *smc ; +struct smt_state *state ; +{ + struct s_phy *phy ; + struct pcm_state *pcs ; + int i ; + int ii ; + short rbits ; + short tbits ; + struct fddi_mib_p *mib ; + + for (i = 0, phy = smc->y, pcs = state->pcm_state ; i < NUMPHYS ; + i++ , phy++, pcs++ ) { + mib = phy->mib ; + pcs->pcm_type = (u_char) mib->fddiPORTMy_Type ; + pcs->pcm_state = (u_char) mib->fddiPORTPCMState ; + pcs->pcm_mode = phy->pc_mode ; + pcs->pcm_neighbor = (u_char) mib->fddiPORTNeighborType ; + pcs->pcm_bsf = mib->fddiPORTBS_Flag ; + pcs->pcm_lsf = phy->ls_flag ; + pcs->pcm_lct_fail = (u_char) mib->fddiPORTLCTFail_Ct ; + pcs->pcm_ls_rx = LS2MIB(sm_pm_get_ls(smc,i)) ; + for (ii = 0, rbits = tbits = 0 ; ii < NUMBITS ; ii++) { + rbits <<= 1 ; + tbits <<= 1 ; + if (phy->r_val[NUMBITS-1-ii]) + rbits |= 1 ; + if (phy->t_val[NUMBITS-1-ii]) + tbits |= 1 ; + } + pcs->pcm_r_val = rbits ; + pcs->pcm_t_val = tbits ; + } +} + +int get_pcm_state(smc,np) +struct s_smc *smc ; +int np; +{ + int pcs ; + + SK_UNUSED(smc) ; + + switch (inpw(PLC(np,PL_STATUS_B)) & PL_PCM_STATE) { + case PL_PC0 : pcs = PC_STOP ; break ; + case PL_PC1 : pcs = PC_START ; break ; + case PL_PC2 : pcs = PC_TRACE ; break ; + case PL_PC3 : pcs = PC_SIGNAL ; break ; + case PL_PC4 : pcs = PC_SIGNAL ; break ; + case PL_PC5 : pcs = PC_SIGNAL ; break ; + case PL_PC6 : pcs = PC_JOIN ; break ; + case PL_PC7 : pcs = PC_JOIN ; break ; + case PL_PC8 : pcs = PC_ENABLE ; break ; + case PL_PC9 : pcs = PC_MAINT ; break ; + default : pcs = PC_DISABLE ; break ; + } + return(pcs) ; +} + +char *get_linestate(smc,np) +struct s_smc *smc ; +int np; +{ + char *ls = "" ; + + SK_UNUSED(smc) ; + + switch (inpw(PLC(np,PL_STATUS_A)) & PL_LINE_ST) { + case PL_L_NLS : ls = "NOISE" ; break ; + case PL_L_ALS : ls = "ACTIV" ; break ; + case PL_L_UND : ls = "UNDEF" ; break ; + case PL_L_ILS4: ls = "ILS 4" ; break ; + case PL_L_QLS : ls = "QLS" ; break ; + case PL_L_MLS : ls = "MLS" ; break ; + case PL_L_HLS : ls = "HLS" ; break ; + case PL_L_ILS16:ls = "ILS16" ; break ; +#ifdef lint + default: ls = "unknown" ; break ; +#endif + } + return(ls) ; +} + +char *get_pcmstate(smc,np) +struct s_smc *smc ; +int np; +{ + char *pcs ; + + SK_UNUSED(smc) ; + + switch (inpw(PLC(np,PL_STATUS_B)) & PL_PCM_STATE) { + case PL_PC0 : pcs = "OFF" ; break ; + case PL_PC1 : pcs = "BREAK" ; break ; + case PL_PC2 : pcs = "TRACE" ; break ; + case PL_PC3 : pcs = "CONNECT"; break ; + case PL_PC4 : pcs = "NEXT" ; break ; + case PL_PC5 : pcs = "SIGNAL" ; break ; + case PL_PC6 : pcs = "JOIN" ; break ; + case PL_PC7 : pcs = "VERIFY" ; break ; + case PL_PC8 : pcs = "ACTIV" ; break ; + case PL_PC9 : pcs = "MAINT" ; break ; + default : pcs = "UNKNOWN" ; break ; + } + return(pcs) ; +} + +void list_phy(smc) +struct s_smc *smc ; +{ + struct s_plc *plc ; + int np ; + + for (np = 0 ; np < NUMPHYS ; np++) { + plc = &smc->y[np].plc ; + printf("PHY %d:\tERRORS\t\t\tBREAK_REASONS\t\tSTATES:\n",np) ; + printf("\tsoft_error: %ld \t\tPC_Start : %ld\n", + plc->soft_err,plc->b_pcs); + printf("\tparity_err: %ld \t\tTPC exp. : %ld\t\tLine: %s\n", + plc->parity_err,plc->b_tpc,get_linestate(smc,np)) ; + printf("\tebuf_error: %ld \t\tTNE exp. : %ld\n", + plc->ebuf_err,plc->b_tne) ; + printf("\tphyinvalid: %ld \t\tQLS det. : %ld\t\tPCM : %s\n", + plc->phyinv,plc->b_qls,get_pcmstate(smc,np)) ; + printf("\tviosym_ctr: %ld \t\tILS det. : %ld\n", + plc->vsym_ctr,plc->b_ils) ; + printf("\tmingap_ctr: %ld \t\tHLS det. : %ld\n", + plc->mini_ctr,plc->b_hls) ; + printf("\tnodepr_err: %ld\n",plc->np_err) ; + printf("\tTPC_exp : %ld\n",plc->tpc_exp) ; + printf("\tLEM_err : %ld\n",smc->y[np].lem.lem_errors) ; + } +} + + +#ifdef CONCENTRATOR +void pcm_lem_dump(smc) +struct s_smc *smc ; +{ + int i ; + struct s_phy *phy ; + struct fddi_mib_p *mib ; + + char *entostring() ; + + printf("PHY errors BER\n") ; + printf("----------------------\n") ; + for (i = 0,phy = smc->y ; i < NUMPHYS ; i++,phy++) { + if (!plc_is_installed(smc,i)) + continue ; + mib = phy->mib ; + printf("%s\t%ld\t10E-%d\n", + entostring(smc,ENTITY_PHY(i)), + mib->fddiPORTLem_Ct, + mib->fddiPORTLer_Estimate) ; + } +} +#endif +#endif diff -u --recursive --new-file v2.3.46/linux/drivers/net/skfp/pmf.c linux/drivers/net/skfp/pmf.c --- v2.3.46/linux/drivers/net/skfp/pmf.c Wed Dec 31 16:00:00 1969 +++ linux/drivers/net/skfp/pmf.c Fri Feb 18 14:55:53 2000 @@ -0,0 +1,1701 @@ +/****************************************************************************** + * + * (C)Copyright 1998,1999 SysKonnect, + * a business unit of Schneider & Koch & Co. Datensysteme GmbH. + * + * See the file "skfddi.c" for further information. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * The information in this file is provided "AS IS" without warranty. + * + ******************************************************************************/ + +/* + Parameter Management Frame processing for SMT 7.2 +*/ + +#include "h/types.h" +#include "h/fddi.h" +#include "h/smc.h" +#include "h/smt_p.h" + +#define KERNEL +#include "h/smtstate.h" + +#ifndef SLIM_SMT + +#ifndef lint +static const char ID_sccs[] = "@(#)pmf.c 1.37 97/08/04 (C) SK " ; +#endif + +static int smt_authorize() ; +static int smt_check_set_count() ; +static const struct s_p_tab *smt_get_ptab() ; +static int smt_mib_phys() ; +int smt_set_para() ; +void smt_add_para() ; + +#define MOFFSS(e) ((int)&(((struct fddi_mib *)0)->e)) +#define MOFFSA(e) ((int) (((struct fddi_mib *)0)->e)) + +#define MOFFMS(e) ((int)&(((struct fddi_mib_m *)0)->e)) +#define MOFFMA(e) ((int) (((struct fddi_mib_m *)0)->e)) + +#define MOFFAS(e) ((int)&(((struct fddi_mib_a *)0)->e)) +#define MOFFAA(e) ((int) (((struct fddi_mib_a *)0)->e)) + +#define MOFFPS(e) ((int)&(((struct fddi_mib_p *)0)->e)) +#define MOFFPA(e) ((int) (((struct fddi_mib_p *)0)->e)) + + +#define AC_G 0x01 /* Get */ +#define AC_GR 0x02 /* Get/Set */ +#define AC_S 0x04 /* Set */ +#define AC_NA 0x08 +#define AC_GROUP 0x10 /* Group */ +#define MS2BCLK(x) ((x)*12500L) +/* + F LFag (byte) + B byte + S u_short 16 bit + C Counter 32 bit + L Long 32 bit + T Timer_2 32 bit + P TimeStamp ; + A LongAddress (6 byte) + E Enum 16 bit + R ResId 16 Bit +*/ +static const struct s_p_tab { + u_short p_num ; /* parameter code */ + u_char p_access ; /* access rights */ + u_short p_offset ; /* offset in mib */ + char p_swap[3] ; /* format string */ +} p_tab[] = { + /* StationIdGrp */ + { SMT_P100A,AC_GROUP } , + { SMT_P100B,AC_G, MOFFSS(fddiSMTStationId), "8" } , + { SMT_P100D,AC_G, MOFFSS(fddiSMTOpVersionId), "S" } , + { SMT_P100E,AC_G, MOFFSS(fddiSMTHiVersionId), "S" } , + { SMT_P100F,AC_G, MOFFSS(fddiSMTLoVersionId), "S" } , + { SMT_P1010,AC_G, MOFFSA(fddiSMTManufacturerData), "D" } , + { SMT_P1011,AC_GR, MOFFSA(fddiSMTUserData), "D" } , + { SMT_P1012,AC_G, MOFFSS(fddiSMTMIBVersionId), "S" } , + + /* StationConfigGrp */ + { SMT_P1014,AC_GROUP } , + { SMT_P1015,AC_G, MOFFSS(fddiSMTMac_Ct), "B" } , + { SMT_P1016,AC_G, MOFFSS(fddiSMTNonMaster_Ct), "B" } , + { SMT_P1017,AC_G, MOFFSS(fddiSMTMaster_Ct), "B" } , + { SMT_P1018,AC_G, MOFFSS(fddiSMTAvailablePaths), "B" } , + { SMT_P1019,AC_G, MOFFSS(fddiSMTConfigCapabilities),"S" } , + { SMT_P101A,AC_GR, MOFFSS(fddiSMTConfigPolicy), "wS" } , + { SMT_P101B,AC_GR, MOFFSS(fddiSMTConnectionPolicy),"wS" } , + { SMT_P101D,AC_GR, MOFFSS(fddiSMTTT_Notify), "wS" } , + { SMT_P101E,AC_GR, MOFFSS(fddiSMTStatRptPolicy), "bB" } , + { SMT_P101F,AC_GR, MOFFSS(fddiSMTTrace_MaxExpiration),"lL" } , + { SMT_P1020,AC_G, MOFFSA(fddiSMTPORTIndexes), "II" } , + { SMT_P1021,AC_G, MOFFSS(fddiSMTMACIndexes), "I" } , + { SMT_P1022,AC_G, MOFFSS(fddiSMTBypassPresent), "F" } , + + /* StatusGrp */ + { SMT_P1028,AC_GROUP } , + { SMT_P1029,AC_G, MOFFSS(fddiSMTECMState), "E" } , + { SMT_P102A,AC_G, MOFFSS(fddiSMTCF_State), "E" } , + { SMT_P102C,AC_G, MOFFSS(fddiSMTRemoteDisconnectFlag),"F" } , + { SMT_P102D,AC_G, MOFFSS(fddiSMTStationStatus), "E" } , + { SMT_P102E,AC_G, MOFFSS(fddiSMTPeerWrapFlag), "F" } , + + /* MIBOperationGrp */ + { SMT_P1032,AC_GROUP } , + { SMT_P1033,AC_G, MOFFSA(fddiSMTTimeStamp),"P" } , + { SMT_P1034,AC_G, MOFFSA(fddiSMTTransitionTimeStamp),"P" } , + /* NOTE : SMT_P1035 is already swapped ! SMT_P_SETCOUNT */ + { SMT_P1035,AC_G, MOFFSS(fddiSMTSetCount),"4P" } , + { SMT_P1036,AC_G, MOFFSS(fddiSMTLastSetStationId),"8" } , + + { SMT_P103C,AC_S, 0, "wS" } , + + /* + * PRIVATE EXTENSIONS + * only accessable locally to get/set passwd + */ + { SMT_P10F0,AC_GR, MOFFSA(fddiPRPMFPasswd), "8" } , + { SMT_P10F1,AC_GR, MOFFSS(fddiPRPMFStation), "8" } , +#ifdef ESS + { SMT_P10F2,AC_GR, MOFFSS(fddiESSPayload), "lL" } , + { SMT_P10F3,AC_GR, MOFFSS(fddiESSOverhead), "lL" } , + { SMT_P10F4,AC_GR, MOFFSS(fddiESSMaxTNeg), "lL" } , + { SMT_P10F5,AC_GR, MOFFSS(fddiESSMinSegmentSize), "lL" } , + { SMT_P10F6,AC_GR, MOFFSS(fddiESSCategory), "lL" } , + { SMT_P10F7,AC_GR, MOFFSS(fddiESSSynchTxMode), "wS" } , +#endif +#ifdef SBA + { SMT_P10F8,AC_GR, MOFFSS(fddiSBACommand), "bF" } , + { SMT_P10F9,AC_GR, MOFFSS(fddiSBAAvailable), "bF" } , +#endif + /* MAC Attributes */ + { SMT_P200A,AC_GROUP } , + { SMT_P200B,AC_G, MOFFMS(fddiMACFrameStatusFunctions),"S" } , + { SMT_P200D,AC_G, MOFFMS(fddiMACT_MaxCapabilitiy),"T" } , + { SMT_P200E,AC_G, MOFFMS(fddiMACTVXCapabilitiy),"T" } , + + /* ConfigGrp */ + { SMT_P2014,AC_GROUP } , + { SMT_P2016,AC_G, MOFFMS(fddiMACAvailablePaths), "B" } , + { SMT_P2017,AC_G, MOFFMS(fddiMACCurrentPath), "S" } , + { SMT_P2018,AC_G, MOFFMS(fddiMACUpstreamNbr), "A" } , + { SMT_P2019,AC_G, MOFFMS(fddiMACDownstreamNbr), "A" } , + { SMT_P201A,AC_G, MOFFMS(fddiMACOldUpstreamNbr), "A" } , + { SMT_P201B,AC_G, MOFFMS(fddiMACOldDownstreamNbr),"A" } , + { SMT_P201D,AC_G, MOFFMS(fddiMACDupAddressTest), "E" } , + { SMT_P2020,AC_GR, MOFFMS(fddiMACRequestedPaths), "wS" } , + { SMT_P2021,AC_G, MOFFMS(fddiMACDownstreamPORTType),"E" } , + { SMT_P2022,AC_G, MOFFMS(fddiMACIndex), "S" } , + + /* AddressGrp */ + { SMT_P2028,AC_GROUP } , + { SMT_P2029,AC_G, MOFFMS(fddiMACSMTAddress), "A" } , + + /* OperationGrp */ + { SMT_P2032,AC_GROUP } , + { SMT_P2033,AC_G, MOFFMS(fddiMACT_Req), "T" } , + { SMT_P2034,AC_G, MOFFMS(fddiMACT_Neg), "T" } , + { SMT_P2035,AC_G, MOFFMS(fddiMACT_Max), "T" } , + { SMT_P2036,AC_G, MOFFMS(fddiMACTvxValue), "T" } , + { SMT_P2038,AC_G, MOFFMS(fddiMACT_Pri0), "T" } , + { SMT_P2039,AC_G, MOFFMS(fddiMACT_Pri1), "T" } , + { SMT_P203A,AC_G, MOFFMS(fddiMACT_Pri2), "T" } , + { SMT_P203B,AC_G, MOFFMS(fddiMACT_Pri3), "T" } , + { SMT_P203C,AC_G, MOFFMS(fddiMACT_Pri4), "T" } , + { SMT_P203D,AC_G, MOFFMS(fddiMACT_Pri5), "T" } , + { SMT_P203E,AC_G, MOFFMS(fddiMACT_Pri6), "T" } , + + + /* CountersGrp */ + { SMT_P2046,AC_GROUP } , + { SMT_P2047,AC_G, MOFFMS(fddiMACFrame_Ct), "C" } , + { SMT_P2048,AC_G, MOFFMS(fddiMACCopied_Ct), "C" } , + { SMT_P2049,AC_G, MOFFMS(fddiMACTransmit_Ct), "C" } , + { SMT_P204A,AC_G, MOFFMS(fddiMACToken_Ct), "C" } , + { SMT_P2051,AC_G, MOFFMS(fddiMACError_Ct), "C" } , + { SMT_P2052,AC_G, MOFFMS(fddiMACLost_Ct), "C" } , + { SMT_P2053,AC_G, MOFFMS(fddiMACTvxExpired_Ct), "C" } , + { SMT_P2054,AC_G, MOFFMS(fddiMACNotCopied_Ct), "C" } , + { SMT_P2056,AC_G, MOFFMS(fddiMACRingOp_Ct), "C" } , + + /* FrameErrorConditionGrp */ + { SMT_P205A,AC_GROUP } , + { SMT_P205F,AC_GR, MOFFMS(fddiMACFrameErrorThreshold),"wS" } , + { SMT_P2060,AC_G, MOFFMS(fddiMACFrameErrorRatio), "S" } , + + /* NotCopiedConditionGrp */ + { SMT_P2064,AC_GROUP } , + { SMT_P2067,AC_GR, MOFFMS(fddiMACNotCopiedThreshold),"wS" } , + { SMT_P2069,AC_G, MOFFMS(fddiMACNotCopiedRatio), "S" } , + + /* StatusGrp */ + { SMT_P206E,AC_GROUP } , + { SMT_P206F,AC_G, MOFFMS(fddiMACRMTState), "S" } , + { SMT_P2070,AC_G, MOFFMS(fddiMACDA_Flag), "F" } , + { SMT_P2071,AC_G, MOFFMS(fddiMACUNDA_Flag), "F" } , + { SMT_P2072,AC_G, MOFFMS(fddiMACFrameErrorFlag), "F" } , + { SMT_P2073,AC_G, MOFFMS(fddiMACNotCopiedFlag), "F" } , + { SMT_P2074,AC_G, MOFFMS(fddiMACMA_UnitdataAvailable),"F" } , + { SMT_P2075,AC_G, MOFFMS(fddiMACHardwarePresent), "F" } , + { SMT_P2076,AC_GR, MOFFMS(fddiMACMA_UnitdataEnable),"bF" } , + + /* + * PRIVATE EXTENSIONS + * only accessable locally to get/set TMIN + */ + { SMT_P20F0,AC_NA } , + { SMT_P20F1,AC_GR, MOFFMS(fddiMACT_Min), "lT" } , + + /* Path Attributes */ + /* + * DON't swap 320B,320F,3210: they are already swapped in swap_para() + */ + { SMT_P320A,AC_GROUP } , + { SMT_P320B,AC_G, MOFFAS(fddiPATHIndex), "r" } , + { SMT_P320F,AC_GR, MOFFAS(fddiPATHSbaPayload), "l4" } , + { SMT_P3210,AC_GR, MOFFAS(fddiPATHSbaOverhead), "l4" } , + /* fddiPATHConfiguration */ + { SMT_P3212,AC_G, 0, "" } , + { SMT_P3213,AC_GR, MOFFAS(fddiPATHT_Rmode), "lT" } , + { SMT_P3214,AC_GR, MOFFAS(fddiPATHSbaAvailable), "lL" } , + { SMT_P3215,AC_GR, MOFFAS(fddiPATHTVXLowerBound), "lT" } , + { SMT_P3216,AC_GR, MOFFAS(fddiPATHT_MaxLowerBound),"lT" } , + { SMT_P3217,AC_GR, MOFFAS(fddiPATHMaxT_Req), "lT" } , + + /* Port Attributes */ + /* ConfigGrp */ + { SMT_P400A,AC_GROUP } , + { SMT_P400C,AC_G, MOFFPS(fddiPORTMy_Type), "E" } , + { SMT_P400D,AC_G, MOFFPS(fddiPORTNeighborType), "E" } , + { SMT_P400E,AC_GR, MOFFPS(fddiPORTConnectionPolicies),"bB" } , + { SMT_P400F,AC_G, MOFFPS(fddiPORTMacIndicated), "2" } , + { SMT_P4010,AC_G, MOFFPS(fddiPORTCurrentPath), "E" } , + { SMT_P4011,AC_GR, MOFFPA(fddiPORTRequestedPaths), "l4" } , + { SMT_P4012,AC_G, MOFFPS(fddiPORTMACPlacement), "S" } , + { SMT_P4013,AC_G, MOFFPS(fddiPORTAvailablePaths), "B" } , + { SMT_P4016,AC_G, MOFFPS(fddiPORTPMDClass), "E" } , + { SMT_P4017,AC_G, MOFFPS(fddiPORTConnectionCapabilities), "B"} , + { SMT_P401D,AC_G, MOFFPS(fddiPORTIndex), "R" } , + + /* OperationGrp */ + { SMT_P401E,AC_GROUP } , + { SMT_P401F,AC_GR, MOFFPS(fddiPORTMaint_LS), "wE" } , + { SMT_P4021,AC_G, MOFFPS(fddiPORTBS_Flag), "F" } , + { SMT_P4022,AC_G, MOFFPS(fddiPORTPC_LS), "E" } , + + /* ErrorCtrsGrp */ + { SMT_P4028,AC_GROUP } , + { SMT_P4029,AC_G, MOFFPS(fddiPORTEBError_Ct), "C" } , + { SMT_P402A,AC_G, MOFFPS(fddiPORTLCTFail_Ct), "C" } , + + /* LerGrp */ + { SMT_P4032,AC_GROUP } , + { SMT_P4033,AC_G, MOFFPS(fddiPORTLer_Estimate), "F" } , + { SMT_P4034,AC_G, MOFFPS(fddiPORTLem_Reject_Ct), "C" } , + { SMT_P4035,AC_G, MOFFPS(fddiPORTLem_Ct), "C" } , + { SMT_P403A,AC_GR, MOFFPS(fddiPORTLer_Cutoff), "bB" } , + { SMT_P403B,AC_GR, MOFFPS(fddiPORTLer_Alarm), "bB" } , + + /* StatusGrp */ + { SMT_P403C,AC_GROUP } , + { SMT_P403D,AC_G, MOFFPS(fddiPORTConnectState), "E" } , + { SMT_P403E,AC_G, MOFFPS(fddiPORTPCMStateX), "E" } , + { SMT_P403F,AC_G, MOFFPS(fddiPORTPC_Withhold), "E" } , + { SMT_P4040,AC_G, MOFFPS(fddiPORTLerFlag), "F" } , + { SMT_P4041,AC_G, MOFFPS(fddiPORTHardwarePresent),"F" } , + + { SMT_P4046,AC_S, 0, "wS" } , + + { 0, AC_GROUP } , + { 0 } +} ; + + +static SMbuf *smt_build_pmf_response() ; + +void smt_pmf_received_pack(smc,mb,local) +struct s_smc *smc ; +SMbuf *mb ; +int local ; +{ + struct smt_header *sm ; + SMbuf *reply ; + + sm = smtod(mb,struct smt_header *) ; + DB_SMT("SMT: processing PMF frame at %x len %d\n",sm,mb->sm_len) ; +#ifdef DEBUG + dump_smt(smc,sm,"PMF Received") ; +#endif + /* + * Start the watchdog: It may be a long, long packet and + * maybe the watchdog occurs ... + */ + smt_start_watchdog(smc) ; + + if (sm->smt_class == SMT_PMF_GET || + sm->smt_class == SMT_PMF_SET) { + reply = smt_build_pmf_response(smc,sm, + sm->smt_class == SMT_PMF_SET,local) ; + if (reply) { + sm = smtod(reply,struct smt_header *) ; +#ifdef DEBUG + dump_smt(smc,sm,"PMF Reply") ; +#endif + smt_send_frame(smc,reply,FC_SMT_INFO,local) ; + } + } +} + +extern SMbuf *smt_get_mbuf() ; + +static SMbuf *smt_build_pmf_response(smc,req,set,local) +struct s_smc *smc ; +struct smt_header *req ; +int set ; +int local ; +{ + SMbuf *mb ; + struct smt_header *smt ; + struct smt_para *pa ; + struct smt_p_reason *res ; + const struct s_p_tab *pt ; + int len ; + int index ; + int idx_end ; + int error ; + int range ; + SK_LOC_DECL(struct s_pcon,pcon) ; + SK_LOC_DECL(struct s_pcon,set_pcon) ; + + /* + * build SMT header + */ + if (!(mb = smt_get_mbuf(smc))) + return(mb) ; + + smt = smtod(mb, struct smt_header *) ; + smt->smt_dest = req->smt_source ; /* DA == source of request */ + smt->smt_class = req->smt_class ; /* same class (GET/SET) */ + smt->smt_type = SMT_REPLY ; + smt->smt_version = SMT_VID_2 ; + smt->smt_tid = req->smt_tid ; /* same TID */ + smt->smt_pad = 0 ; + smt->smt_len = 0 ; + + /* + * setup parameter status + */ + pcon.pc_len = SMT_MAX_INFO_LEN ; /* max para length */ + pcon.pc_err = 0 ; /* no error */ + pcon.pc_badset = 0 ; /* no bad set count */ + pcon.pc_p = (void *) (smt + 1) ; /* paras start here */ + + /* + * check authoriziation and set count + */ + error = 0 ; + if (set) { + if (!local && smt_authorize(smc,req)) + error = SMT_RDF_AUTHOR ; + else if (smt_check_set_count(smc,req)) + pcon.pc_badset = SMT_RDF_BADSET ; + } + /* + * add reason code and all mandatory parameters + */ + res = (struct smt_p_reason *) pcon.pc_p ; + smt_add_para(smc,&pcon,(u_short) SMT_P_REASON,0,0) ; + smt_add_para(smc,&pcon,(u_short) SMT_P1033,0,0) ; + /* update 1035 and 1036 later if set */ + set_pcon = pcon ; + smt_add_para(smc,&pcon,(u_short) SMT_P1035,0,0) ; + smt_add_para(smc,&pcon,(u_short) SMT_P1036,0,0) ; + + pcon.pc_err = error ; + len = req->smt_len ; + pa = (struct smt_para *) (req + 1) ; + /* + * process list of paras + */ + while (!pcon.pc_err && len > 0 ) { + if (((u_short)len < pa->p_len + PARA_LEN) || (pa->p_len & 3)) { + pcon.pc_err = SMT_RDF_LENGTH ; + break ; + } + + if (((range = (pa->p_type & 0xf000)) == 0x2000) || + range == 0x3000 || range == 0x4000) { + /* + * get index for PART,MAC ad PATH group + */ + index = *((u_char *)pa + PARA_LEN + 3) ;/* index */ + idx_end = index ; + if (!set && (pa->p_len != 4)) { + pcon.pc_err = SMT_RDF_LENGTH ; + break ; + } + if (!index && !set) { + switch (range) { + case 0x2000 : + index = INDEX_MAC ; + idx_end = index - 1 + NUMMACS ; + break ; + case 0x3000 : + index = INDEX_PATH ; + idx_end = index - 1 + NUMPATHS ; + break ; + case 0x4000 : + index = INDEX_PORT ; + idx_end = index - 1 + NUMPHYS ; +#ifndef CONCENTRATOR + if (smc->s.sas == SMT_SAS) + idx_end = INDEX_PORT ; +#endif + break ; + } + } + } + else { + /* + * smt group has no index + */ + if (!set && (pa->p_len != 0)) { + pcon.pc_err = SMT_RDF_LENGTH ; + break ; + } + index = 0 ; + idx_end = 0 ; + } + while (index <= idx_end) { + /* + * if group + * add all paras of group + */ + pt = smt_get_ptab(pa->p_type) ; + if (pt && pt->p_access == AC_GROUP && !set) { + pt++ ; + while (pt->p_access == AC_G || + pt->p_access == AC_GR) { + smt_add_para(smc,&pcon,pt->p_num, + index,local); + pt++ ; + } + } + /* + * ignore + * AUTHORIZATION in get/set + * SET COUNT in set + */ + else if (pa->p_type != SMT_P_AUTHOR && + (!set || (pa->p_type != SMT_P1035))) { + int st ; + if (pcon.pc_badset) { + smt_add_para(smc,&pcon,pa->p_type, + index,local) ; + } + else if (set) { + st = smt_set_para(smc,pa,index,local,1); + /* + * return para even if error + */ + smt_add_para(smc,&pcon,pa->p_type, + index,local) ; + pcon.pc_err = st ; + } + else { + if (pt && pt->p_access == AC_S) { + pcon.pc_err = + SMT_RDF_ILLEGAL ; + } + smt_add_para(smc,&pcon,pa->p_type, + index,local) ; + } + } + if (pcon.pc_err) + break ; + index++ ; + } + len -= pa->p_len + PARA_LEN ; + pa = (struct smt_para *) ((char *)pa + pa->p_len + PARA_LEN) ; + } + smt->smt_len = SMT_MAX_INFO_LEN - pcon.pc_len ; + mb->sm_len = smt->smt_len + sizeof(struct smt_header) ; + + /* update reason code */ + res->rdf_reason = pcon.pc_badset ? pcon.pc_badset : + pcon.pc_err ? pcon.pc_err : SMT_RDF_SUCCESS ; + if (set && (res->rdf_reason == SMT_RDF_SUCCESS)) { + /* + * increment set count + * set time stamp + * store station id of last set + */ + smc->mib.fddiSMTSetCount.count++ ; + smt_set_timestamp(smc,smc->mib.fddiSMTSetCount.timestamp) ; + smc->mib.fddiSMTLastSetStationId = req->smt_sid ; + smt_add_para(smc,&set_pcon,(u_short) SMT_P1035,0,0) ; + smt_add_para(smc,&set_pcon,(u_short) SMT_P1036,0,0) ; + } + return(mb) ; +} + +extern void *sm_to_para() ; + +static int smt_authorize(smc,sm) +struct s_smc *smc ; +struct smt_header *sm ; +{ + struct smt_para *pa ; + int i ; + char *p ; + + /* + * check source station id if not zero + */ + p = (char *) &smc->mib.fddiPRPMFStation ; + for (i = 0 ; i < 8 && !p[i] ; i++) + ; + if (i != 8) { + if (memcmp((char *) &sm->smt_sid, + (char *) &smc->mib.fddiPRPMFStation,8)) + return(1) ; + } + /* + * check authoriziation parameter if passwd not zero + */ + p = (char *) smc->mib.fddiPRPMFPasswd ; + for (i = 0 ; i < 8 && !p[i] ; i++) + ; + if (i != 8) { + pa = (struct smt_para *) sm_to_para(smc,sm,SMT_P_AUTHOR) ; + if (!pa) + return(1) ; + if (pa->p_len != 8) + return(1) ; + if (memcmp((char *)(pa+1),(char *)smc->mib.fddiPRPMFPasswd,8)) + return(1) ; + } + return(0) ; +} + +static int smt_check_set_count(smc,sm) +struct s_smc *smc ; +struct smt_header *sm ; +{ + struct smt_para *pa ; + struct smt_p_setcount *sc ; + + pa = (struct smt_para *) sm_to_para(smc,sm,SMT_P1035) ; + if (pa) { + sc = (struct smt_p_setcount *) pa ; + if ((smc->mib.fddiSMTSetCount.count != sc->count) || + memcmp((char *) smc->mib.fddiSMTSetCount.timestamp, + (char *)sc->timestamp,8)) + return(1) ; + } + return(0) ; +} + +void smt_add_para(smc,pcon,para,index,local) +struct s_smc *smc ; +struct s_pcon *pcon ; +u_short para ; +int index ; +int local ; +{ + struct smt_para *pa ; + const struct s_p_tab *pt ; + struct fddi_mib_m *mib_m = 0 ; + struct fddi_mib_p *mib_p = 0 ; + int len ; + int plen ; + char *from ; + char *to ; + const char *swap ; + char c ; + int range ; + char *mib_addr ; + int mac ; + int path ; + int port ; + int sp_len ; + + /* + * skip if errror + */ + if (pcon->pc_err) + return ; + + /* + * actions don't have a value + */ + pt = smt_get_ptab(para) ; + if (pt && pt->p_access == AC_S) + return ; + + to = (char *) (pcon->pc_p) ; /* destination pointer */ + len = pcon->pc_len ; /* free space */ + plen = len ; /* remember start length */ + pa = (struct smt_para *) to ; /* type/length pointer */ + to += PARA_LEN ; /* skip smt_para */ + len -= PARA_LEN ; + /* + * set index if required + */ + if (((range = (para & 0xf000)) == 0x2000) || + range == 0x3000 || range == 0x4000) { + if (len < 4) + goto wrong_error ; + to[0] = 0 ; + to[1] = 0 ; + to[2] = 0 ; + to[3] = index ; + len -= 4 ; + to += 4 ; + } + mac = index - INDEX_MAC ; + path = index - INDEX_PATH ; + port = index - INDEX_PORT ; + /* + * get pointer to mib + */ + switch (range) { + case 0x1000 : + default : + mib_addr = (char *) (&smc->mib) ; + break ; + case 0x2000 : + if (mac < 0 || mac >= NUMMACS) { + pcon->pc_err = SMT_RDF_NOPARAM ; + return ; + } + mib_addr = (char *) (&smc->mib.m[mac]) ; + mib_m = (struct fddi_mib_m *) mib_addr ; + break ; + case 0x3000 : + if (path < 0 || path >= NUMPATHS) { + pcon->pc_err = SMT_RDF_NOPARAM ; + return ; + } + mib_addr = (char *) (&smc->mib.a[path]) ; + break ; + case 0x4000 : + if (port < 0 || port >= smt_mib_phys(smc)) { + pcon->pc_err = SMT_RDF_NOPARAM ; + return ; + } + mib_addr = (char *) (&smc->mib.p[port_to_mib(smc,port)]) ; + mib_p = (struct fddi_mib_p *) mib_addr ; + break ; + } + /* + * check special paras + */ + swap = 0 ; + switch (para) { + case SMT_P10F0 : + case SMT_P10F1 : +#ifdef ESS + case SMT_P10F2 : + case SMT_P10F3 : + case SMT_P10F4 : + case SMT_P10F5 : + case SMT_P10F6 : + case SMT_P10F7 : +#endif +#ifdef SBA + case SMT_P10F8 : + case SMT_P10F9 : +#endif + case SMT_P20F1 : + if (!local) { + pcon->pc_err = SMT_RDF_NOPARAM ; + return ; + } + break ; + case SMT_P2034 : + case SMT_P2046 : + case SMT_P2047 : + case SMT_P204A : + case SMT_P2051 : + case SMT_P2052 : + mac_update_counter(smc) ; + break ; + case SMT_P4022: + mib_p->fddiPORTPC_LS = LS2MIB( + sm_pm_get_ls(smc,port_to_mib(smc,port))) ; + break ; + case SMT_P_REASON : + * (u_long *) to = 0 ; + sp_len = 4 ; + goto sp_done ; + case SMT_P1033 : /* time stamp */ + smt_set_timestamp(smc,smc->mib.fddiSMTTimeStamp) ; + break ; + + case SMT_P1020: /* port indexes */ +#if NUMPHYS == 12 + swap = "IIIIIIIIIIII" ; +#else +#if NUMPHYS == 2 + if (smc->s.sas == SMT_SAS) + swap = "I" ; + else + swap = "II" ; +#else +#if NUMPHYS == 24 + swap = "IIIIIIIIIIIIIIIIIIIIIIII" ; +#else + ???? +#endif +#endif +#endif + break ; + case SMT_P3212 : + { + sp_len = cem_build_path(smc,to,path) ; + goto sp_done ; + } + case SMT_P1048 : /* peer wrap condition */ + { + struct smt_p_1048 *sp ; + sp = (struct smt_p_1048 *) to ; + sp->p1048_flag = smc->mib.fddiSMTPeerWrapFlag ; + sp->p1048_cf_state = smc->mib.fddiSMTCF_State ; + sp_len = sizeof(struct smt_p_1048) ; + goto sp_done ; + } + case SMT_P208C : + { + struct smt_p_208c *sp ; + sp = (struct smt_p_208c *) to ; + sp->p208c_flag = + smc->mib.m[MAC0].fddiMACDuplicateAddressCond ; + sp->p208c_dupcondition = + (mib_m->fddiMACDA_Flag ? SMT_ST_MY_DUPA : 0) | + (mib_m->fddiMACUNDA_Flag ? SMT_ST_UNA_DUPA : 0); + sp->p208c_fddilong = + mib_m->fddiMACSMTAddress ; + sp->p208c_fddiunalong = + mib_m->fddiMACUpstreamNbr ; + sp->p208c_pad = 0 ; + sp_len = sizeof(struct smt_p_208c) ; + goto sp_done ; + } + case SMT_P208D : /* frame error condition */ + { + struct smt_p_208d *sp ; + sp = (struct smt_p_208d *) to ; + sp->p208d_flag = + mib_m->fddiMACFrameErrorFlag ; + sp->p208d_frame_ct = + mib_m->fddiMACFrame_Ct ; + sp->p208d_error_ct = + mib_m->fddiMACError_Ct ; + sp->p208d_lost_ct = + mib_m->fddiMACLost_Ct ; + sp->p208d_ratio = + mib_m->fddiMACFrameErrorRatio ; + sp_len = sizeof(struct smt_p_208d) ; + goto sp_done ; + } + case SMT_P208E : /* not copied condition */ + { + struct smt_p_208e *sp ; + sp = (struct smt_p_208e *) to ; + sp->p208e_flag = + mib_m->fddiMACNotCopiedFlag ; + sp->p208e_not_copied = + mib_m->fddiMACNotCopied_Ct ; + sp->p208e_copied = + mib_m->fddiMACCopied_Ct ; + sp->p208e_not_copied_ratio = + mib_m->fddiMACNotCopiedRatio ; + sp_len = sizeof(struct smt_p_208e) ; + goto sp_done ; + } + case SMT_P208F : /* neighbor change event */ + { + struct smt_p_208f *sp ; + sp = (struct smt_p_208f *) to ; + sp->p208f_multiple = + mib_m->fddiMACMultiple_N ; + sp->p208f_nacondition = + mib_m->fddiMACDuplicateAddressCond ; + sp->p208f_old_una = + mib_m->fddiMACOldUpstreamNbr ; + sp->p208f_new_una = + mib_m->fddiMACUpstreamNbr ; + sp->p208f_old_dna = + mib_m->fddiMACOldDownstreamNbr ; + sp->p208f_new_dna = + mib_m->fddiMACDownstreamNbr ; + sp->p208f_curren_path = + mib_m->fddiMACCurrentPath ; + sp->p208f_smt_address = + mib_m->fddiMACSMTAddress ; + sp_len = sizeof(struct smt_p_208f) ; + goto sp_done ; + } + case SMT_P2090 : + { + struct smt_p_2090 *sp ; + sp = (struct smt_p_2090 *) to ; + sp->p2090_multiple = + mib_m->fddiMACMultiple_P ; + sp->p2090_availablepaths = + mib_m->fddiMACAvailablePaths ; + sp->p2090_currentpath = + mib_m->fddiMACCurrentPath ; + sp->p2090_requestedpaths = + mib_m->fddiMACRequestedPaths ; + sp_len = sizeof(struct smt_p_2090) ; + goto sp_done ; + } + case SMT_P4050 : + { + struct smt_p_4050 *sp ; + sp = (struct smt_p_4050 *) to ; + sp->p4050_flag = + mib_p->fddiPORTLerFlag ; + sp->p4050_pad = 0 ; + sp->p4050_cutoff = + mib_p->fddiPORTLer_Cutoff ; ; + sp->p4050_alarm = + mib_p->fddiPORTLer_Alarm ; ; + sp->p4050_estimate = + mib_p->fddiPORTLer_Estimate ; + sp->p4050_reject_ct = + mib_p->fddiPORTLem_Reject_Ct ; + sp->p4050_ct = + mib_p->fddiPORTLem_Ct ; + sp_len = sizeof(struct smt_p_4050) ; + goto sp_done ; + } + + case SMT_P4051 : + { + struct smt_p_4051 *sp ; + sp = (struct smt_p_4051 *) to ; + sp->p4051_multiple = + mib_p->fddiPORTMultiple_U ; + sp->p4051_porttype = + mib_p->fddiPORTMy_Type ; + sp->p4051_connectstate = + mib_p->fddiPORTConnectState ; ; + sp->p4051_pc_neighbor = + mib_p->fddiPORTNeighborType ; + sp->p4051_pc_withhold = + mib_p->fddiPORTPC_Withhold ; + sp_len = sizeof(struct smt_p_4051) ; + goto sp_done ; + } + case SMT_P4052 : + { + struct smt_p_4052 *sp ; + sp = (struct smt_p_4052 *) to ; + sp->p4052_flag = + mib_p->fddiPORTEB_Condition ; + sp->p4052_eberrorcount = + mib_p->fddiPORTEBError_Ct ; + sp_len = sizeof(struct smt_p_4052) ; + goto sp_done ; + } + case SMT_P4053 : + { + struct smt_p_4053 *sp ; + sp = (struct smt_p_4053 *) to ; + sp->p4053_multiple = + mib_p->fddiPORTMultiple_P ; ; + sp->p4053_availablepaths = + mib_p->fddiPORTAvailablePaths ; + sp->p4053_currentpath = + mib_p->fddiPORTCurrentPath ; + memcpy( (char *) &sp->p4053_requestedpaths, + (char *) mib_p->fddiPORTRequestedPaths,4) ; + sp->p4053_mytype = + mib_p->fddiPORTMy_Type ; + sp->p4053_neighbortype = + mib_p->fddiPORTNeighborType ; + sp_len = sizeof(struct smt_p_4053) ; + goto sp_done ; + } + default : + break ; + } + /* + * in table ? + */ + if (!pt) { + pcon->pc_err = (para & 0xff00) ? SMT_RDF_NOPARAM : + SMT_RDF_ILLEGAL ; + return ; + } + /* + * check access rights + */ + switch (pt->p_access) { + case AC_G : + case AC_GR : + break ; + default : + pcon->pc_err = SMT_RDF_ILLEGAL ; + return ; + } + from = mib_addr + pt->p_offset ; + if (!swap) + swap = pt->p_swap ; /* pointer to swap string */ + + /* + * copy values + */ + while ((c = *swap++)) { + switch(c) { + case 'b' : + case 'w' : + case 'l' : + break ; + case 'S' : + case 'E' : + case 'R' : + case 'r' : + if (len < 4) + goto len_error ; + to[0] = 0 ; + to[1] = 0 ; +#ifdef LITTLE_ENDIAN + if (c == 'r') { + to[2] = *from++ ; + to[3] = *from++ ; + } + else { + to[3] = *from++ ; + to[2] = *from++ ; + } +#else + to[2] = *from++ ; + to[3] = *from++ ; +#endif + to += 4 ; + len -= 4 ; + break ; + case 'I' : /* for SET of port indexes */ + if (len < 2) + goto len_error ; +#ifdef LITTLE_ENDIAN + to[1] = *from++ ; + to[0] = *from++ ; +#else + to[0] = *from++ ; + to[1] = *from++ ; +#endif + to += 2 ; + len -= 2 ; + break ; + case 'F' : + case 'B' : + if (len < 4) + goto len_error ; + len -= 4 ; + to[0] = 0 ; + to[1] = 0 ; + to[2] = 0 ; + to[3] = *from++ ; + to += 4 ; + break ; + case 'C' : + case 'T' : + case 'L' : + if (len < 4) + goto len_error ; +#ifdef LITTLE_ENDIAN + to[3] = *from++ ; + to[2] = *from++ ; + to[1] = *from++ ; + to[0] = *from++ ; +#else + to[0] = *from++ ; + to[1] = *from++ ; + to[2] = *from++ ; + to[3] = *from++ ; +#endif + len -= 4 ; + to += 4 ; + break ; + case '2' : /* PortMacIndicated */ + if (len < 4) + goto len_error ; + to[0] = 0 ; + to[1] = 0 ; + to[2] = *from++ ; + to[3] = *from++ ; + len -= 4 ; + to += 4 ; + break ; + case '4' : + if (len < 4) + goto len_error ; + to[0] = *from++ ; + to[1] = *from++ ; + to[2] = *from++ ; + to[3] = *from++ ; + len -= 4 ; + to += 4 ; + break ; + case 'A' : + if (len < 8) + goto len_error ; + to[0] = 0 ; + to[1] = 0 ; + memcpy((char *) to+2,(char *) from,6) ; + to += 8 ; + from += 8 ; + len -= 8 ; + break ; + case '8' : + if (len < 8) + goto len_error ; + memcpy((char *) to,(char *) from,8) ; + to += 8 ; + from += 8 ; + len -= 8 ; + break ; + case 'D' : + if (len < 32) + goto len_error ; + memcpy((char *) to,(char *) from,32) ; + to += 32 ; + from += 32 ; + len -= 32 ; + break ; + case 'P' : /* timestamp is NOT swapped */ + if (len < 8) + goto len_error ; + to[0] = *from++ ; + to[1] = *from++ ; + to[2] = *from++ ; + to[3] = *from++ ; + to[4] = *from++ ; + to[5] = *from++ ; + to[6] = *from++ ; + to[7] = *from++ ; + to += 8 ; + len -= 8 ; + break ; + default : + SMT_PANIC(smc,SMT_E0119, SMT_E0119_MSG) ; + break ; + } + } + +done: + /* + * make it even (in case of 'I' encoding) + * note: len is DECREMENTED + */ + if (len & 3) { + to[0] = 0 ; + to[1] = 0 ; + to += 4 - (len & 3 ) ; + len = len & ~ 3 ; + } + + /* set type and length */ + pa->p_type = para ; + pa->p_len = plen - len - PARA_LEN ; + /* return values */ + pcon->pc_p = (void *) to ; + pcon->pc_len = len ; + return ; + +sp_done: + len -= sp_len ; + to += sp_len ; + goto done ; + +len_error: + /* parameter does not fit in frame */ + pcon->pc_err = SMT_RDF_TOOLONG ; + return ; + +wrong_error: + pcon->pc_err = SMT_RDF_LENGTH ; +} + +/* + * set parameter + */ +int smt_set_para(smc,pa,index,local,set) +struct s_smc *smc ; +struct smt_para *pa ; +int index ; +int local ; +int set ; +{ +#define IFSET(x) if (set) (x) + + const struct s_p_tab *pt ; + int len ; + char *from ; + char *to ; + const char *swap ; + char c ; + char *mib_addr ; + struct fddi_mib *mib ; + struct fddi_mib_m *mib_m = 0 ; + struct fddi_mib_a *mib_a = 0 ; + struct fddi_mib_p *mib_p = 0 ; + int mac ; + int path ; + int port ; + SK_LOC_DECL(u_char,byte_val) ; + SK_LOC_DECL(u_short,word_val) ; + SK_LOC_DECL(u_long,long_val) ; + + mac = index - INDEX_MAC ; + path = index - INDEX_PATH ; + port = index - INDEX_PORT ; + len = pa->p_len ; + from = (char *) (pa + 1 ) ; + + mib = &smc->mib ; + switch (pa->p_type & 0xf000) { + case 0x1000 : + default : + mib_addr = (char *) mib ; + break ; + case 0x2000 : + if (mac < 0 || mac >= NUMMACS) { + return(SMT_RDF_NOPARAM) ; + } + mib_m = &smc->mib.m[mac] ; + mib_addr = (char *) mib_m ; + from += 4 ; /* skip index */ + len -= 4 ; + break ; + case 0x3000 : + if (path < 0 || path >= NUMPATHS) { + return(SMT_RDF_NOPARAM) ; + } + mib_a = &smc->mib.a[path] ; + mib_addr = (char *) mib_a ; + from += 4 ; /* skip index */ + len -= 4 ; + break ; + case 0x4000 : + if (port < 0 || port >= smt_mib_phys(smc)) { + return(SMT_RDF_NOPARAM) ; + } + mib_p = &smc->mib.p[port_to_mib(smc,port)] ; + mib_addr = (char *) mib_p ; + from += 4 ; /* skip index */ + len -= 4 ; + break ; + } + switch (pa->p_type) { + case SMT_P10F0 : + case SMT_P10F1 : +#ifdef ESS + case SMT_P10F2 : + case SMT_P10F3 : + case SMT_P10F4 : + case SMT_P10F5 : + case SMT_P10F6 : + case SMT_P10F7 : +#endif +#ifdef SBA + case SMT_P10F8 : + case SMT_P10F9 : +#endif + case SMT_P20F1 : + if (!local) { + return(SMT_RDF_NOPARAM) ; + } + break ; + } + pt = smt_get_ptab(pa->p_type) ; + if (!pt) { + return( (pa->p_type & 0xff00) ? SMT_RDF_NOPARAM : + SMT_RDF_ILLEGAL ) ; + } + switch (pt->p_access) { + case AC_GR : + case AC_S : + break ; + default : + return(SMT_RDF_ILLEGAL) ; + } + to = mib_addr + pt->p_offset ; + swap = pt->p_swap ; /* pointer to swap string */ + + while (swap && (c = *swap++)) { + switch(c) { + case 'b' : + to = (char *) &byte_val ; + break ; + case 'w' : + to = (char *) &word_val ; + break ; + case 'l' : + to = (char *) &long_val ; + break ; + case 'S' : + case 'E' : + case 'R' : + case 'r' : + if (len < 4) { + goto len_error ; + } + if (from[0] | from[1]) + goto val_error ; +#ifdef LITTLE_ENDIAN + if (c == 'r') { + to[0] = from[2] ; + to[1] = from[3] ; + } + else { + to[1] = from[2] ; + to[0] = from[3] ; + } +#else + to[0] = from[2] ; + to[1] = from[3] ; +#endif + from += 4 ; + to += 2 ; + len -= 4 ; + break ; + case 'F' : + case 'B' : + if (len < 4) { + goto len_error ; + } + if (from[0] | from[1] | from[2]) + goto val_error ; + to[0] = from[3] ; + len -= 4 ; + from += 4 ; + to += 4 ; + break ; + case 'C' : + case 'T' : + case 'L' : + if (len < 4) { + goto len_error ; + } +#ifdef LITTLE_ENDIAN + to[3] = *from++ ; + to[2] = *from++ ; + to[1] = *from++ ; + to[0] = *from++ ; +#else + to[0] = *from++ ; + to[1] = *from++ ; + to[2] = *from++ ; + to[3] = *from++ ; +#endif + len -= 4 ; + to += 4 ; + break ; + case 'A' : + if (len < 8) + goto len_error ; + if (set) + memcpy((char *) to,(char *) from+2,6) ; + to += 8 ; + from += 8 ; + len -= 8 ; + break ; + case '4' : + if (len < 4) + goto len_error ; + if (set) + memcpy((char *) to,(char *) from,4) ; + to += 4 ; + from += 4 ; + len -= 4 ; + break ; + case '8' : + if (len < 8) + goto len_error ; + if (set) + memcpy((char *) to,(char *) from,8) ; + to += 8 ; + from += 8 ; + len -= 8 ; + break ; + case 'D' : + if (len < 32) + goto len_error ; + if (set) + memcpy((char *) to,(char *) from,32) ; + to += 32 ; + from += 32 ; + len -= 32 ; + break ; + case 'P' : /* timestamp is NOT swapped */ + if (set) { + to[0] = *from++ ; + to[1] = *from++ ; + to[2] = *from++ ; + to[3] = *from++ ; + to[4] = *from++ ; + to[5] = *from++ ; + to[6] = *from++ ; + to[7] = *from++ ; + } + to += 8 ; + len -= 8 ; + break ; + default : + SMT_PANIC(smc,SMT_E0120, SMT_E0120_MSG) ; + return(SMT_RDF_ILLEGAL) ; + } + } + /* + * actions and internal updates + */ + switch (pa->p_type) { + case SMT_P101A: /* fddiSMTConfigPolicy */ + if (word_val & ~1) + goto val_error ; + IFSET(mib->fddiSMTConfigPolicy = word_val) ; + break ; + case SMT_P101B : /* fddiSMTConnectionPolicy */ + if (!(word_val & POLICY_MM)) + goto val_error ; + IFSET(mib->fddiSMTConnectionPolicy = word_val) ; + break ; + case SMT_P101D : /* fddiSMTTT_Notify */ + if (word_val < 2 || word_val > 30) + goto val_error ; + IFSET(mib->fddiSMTTT_Notify = word_val) ; + break ; + case SMT_P101E : /* fddiSMTStatRptPolicy */ + if (byte_val & ~1) + goto val_error ; + IFSET(mib->fddiSMTStatRptPolicy = byte_val) ; + break ; + case SMT_P101F : /* fddiSMTTrace_MaxExpiration */ + /* + * note: lower limit trace_max = 6.001773... s + * NO upper limit + */ + if (long_val < (long)0x478bf51L) + goto val_error ; + IFSET(mib->fddiSMTTrace_MaxExpiration = long_val) ; + break ; +#ifdef ESS + case SMT_P10F2 : /* fddiESSPayload */ + if (long_val > 1562) + goto val_error ; + if (set && smc->mib.fddiESSPayload != long_val) { + smc->ess.raf_act_timer_poll = TRUE ; + smc->mib.fddiESSPayload = long_val ; + } + break ; + case SMT_P10F3 : /* fddiESSOverhead */ + if (long_val < 50 || long_val > 5000) + goto val_error ; + if (set && smc->mib.fddiESSPayload && + smc->mib.fddiESSOverhead != long_val) { + smc->ess.raf_act_timer_poll = TRUE ; + smc->mib.fddiESSOverhead = long_val ; + } + break ; + case SMT_P10F4 : /* fddiESSMaxTNeg */ + if (long_val > -MS2BCLK(5) || long_val < -MS2BCLK(165)) + goto val_error ; + IFSET(mib->fddiESSMaxTNeg = long_val) ; + break ; + case SMT_P10F5 : /* fddiESSMinSegmentSize */ + if (long_val < 1 || long_val > 4478) + goto val_error ; + IFSET(mib->fddiESSMinSegmentSize = long_val) ; + break ; + case SMT_P10F6 : /* fddiESSCategory */ + if ((long_val & 0xffff) != 1) + goto val_error ; + IFSET(mib->fddiESSCategory = long_val) ; + break ; + case SMT_P10F7 : /* fddiESSSyncTxMode */ + if (word_val > 1) + goto val_error ; + IFSET(mib->fddiESSSynchTxMode = word_val) ; + break ; +#endif +#ifdef SBA + case SMT_P10F8 : /* fddiSBACommand */ + if (byte_val != SB_STOP && byte_val != SB_START) + goto val_error ; + IFSET(mib->fddiSBACommand = byte_val) ; + break ; + case SMT_P10F9 : /* fddiSBAAvailable */ + if (byte_val > 100) + goto val_error ; + IFSET(mib->fddiSBAAvailable = byte_val) ; + break ; +#endif + case SMT_P2020 : /* fddiMACRequestedPaths */ + if ((word_val & (MIB_P_PATH_PRIM_PREFER | + MIB_P_PATH_PRIM_ALTER)) == 0 ) + goto val_error ; + IFSET(mib_m->fddiMACRequestedPaths = word_val) ; + break ; + case SMT_P205F : /* fddiMACFrameErrorThreshold */ + /* 0 .. ffff acceptable */ + IFSET(mib_m->fddiMACFrameErrorThreshold = word_val) ; + break ; + case SMT_P2067 : /* fddiMACNotCopiedThreshold */ + /* 0 .. ffff acceptable */ + IFSET(mib_m->fddiMACNotCopiedThreshold = word_val) ; + break ; + case SMT_P2076: /* fddiMACMA_UnitdataEnable */ + if (byte_val & ~1) + goto val_error ; + if (set) { + mib_m->fddiMACMA_UnitdataEnable = byte_val ; + queue_event(smc,EVENT_RMT,RM_ENABLE_FLAG) ; + } + break ; + case SMT_P20F1 : /* fddiMACT_Min */ + IFSET(mib_m->fddiMACT_Min = long_val) ; + break ; + case SMT_P320F : + if (long_val > 1562) + goto val_error ; + IFSET(mib_a->fddiPATHSbaPayload = long_val) ; +#ifdef ESS + if (set) + ess_para_change(smc) ; +#endif + break ; + case SMT_P3210 : + if (long_val > 5000) + goto val_error ; + + if (long_val != 0 && mib_a->fddiPATHSbaPayload == 0) + goto val_error ; + + IFSET(mib_a->fddiPATHSbaOverhead = long_val) ; +#ifdef ESS + if (set) + ess_para_change(smc) ; +#endif + break ; + case SMT_P3213: /* fddiPATHT_Rmode */ + /* no limit : + * 0 .. 343.597 => 0 .. 2e32 * 80nS + */ + if (set) { + mib_a->fddiPATHT_Rmode = long_val ; + rtm_set_timer(smc) ; + } + break ; + case SMT_P3214 : /* fddiPATHSbaAvailable */ + if (long_val > 0x00BEBC20L) + goto val_error ; +#ifdef SBA + if (set && mib->fddiSBACommand == SB_STOP) + goto val_error ; +#endif + IFSET(mib_a->fddiPATHSbaAvailable = long_val) ; + break ; + case SMT_P3215 : /* fddiPATHTVXLowerBound */ + IFSET(mib_a->fddiPATHTVXLowerBound = long_val) ; + goto change_mac_para ; + case SMT_P3216 : /* fddiPATHT_MaxLowerBound */ + IFSET(mib_a->fddiPATHT_MaxLowerBound = long_val) ; + goto change_mac_para ; + case SMT_P3217 : /* fddiPATHMaxT_Req */ + IFSET(mib_a->fddiPATHMaxT_Req = long_val) ; + +change_mac_para: + if (set && smt_set_mac_opvalues(smc)) { + RS_SET(smc,RS_EVENT) ; + smc->sm.please_reconnect = 1 ; + queue_event(smc,EVENT_ECM,EC_DISCONNECT) ; + } + break ; + case SMT_P400E : /* fddiPORTConnectionPolicies */ + if (byte_val > 1) + goto val_error ; + IFSET(mib_p->fddiPORTConnectionPolicies = byte_val) ; + break ; + case SMT_P4011 : /* fddiPORTRequestedPaths */ + /* all 3*8 bits allowed */ + IFSET(memcpy((char *)mib_p->fddiPORTRequestedPaths, + (char *)&long_val,4)) ; + break ; + case SMT_P401F: /* fddiPORTMaint_LS */ + if (word_val > 4) + goto val_error ; + IFSET(mib_p->fddiPORTMaint_LS = word_val) ; + break ; + case SMT_P403A : /* fddiPORTLer_Cutoff */ + if (byte_val < 4 || byte_val > 15) + goto val_error ; + IFSET(mib_p->fddiPORTLer_Cutoff = byte_val) ; + break ; + case SMT_P403B : /* fddiPORTLer_Alarm */ + if (byte_val < 4 || byte_val > 15) + goto val_error ; + IFSET(mib_p->fddiPORTLer_Alarm = byte_val) ; + break ; + + /* + * Actions + */ + case SMT_P103C : /* fddiSMTStationAction */ + if (smt_action(smc,SMT_STATION_ACTION, (int) word_val, 0)) + goto val_error ; + break ; + case SMT_P4046: /* fddiPORTAction */ + if (smt_action(smc,SMT_PORT_ACTION, (int) word_val, + port_to_mib(smc,port))) + goto val_error ; + break ; + default : + break ; + } + return(0) ; + +val_error: + /* parameter value in frame is out of range */ + return(SMT_RDF_RANGE) ; + +len_error: + /* parameter value in frame is too short */ + return(SMT_RDF_LENGTH) ; + +#if 0 +no_author_error: + /* parameter not setable, because the SBA is not active + * Please note: we give the return code 'not authorizeed + * because SBA denied is not a valid return code in the + * PMF protocol. + */ + return(SMT_RDF_AUTHOR) ; +#endif +} + +static const struct s_p_tab *smt_get_ptab(para) +u_short para ; +{ + const struct s_p_tab *pt ; + for (pt = p_tab ; pt->p_num && pt->p_num != para ; pt++) + ; + return(pt->p_num ? pt : 0) ; +} + +static int smt_mib_phys(smc) +struct s_smc *smc ; +{ +#ifdef CONCENTRATOR + SK_UNUSED(smc) ; + + return(NUMPHYS) ; +#else + if (smc->s.sas == SMT_SAS) + return(1) ; + return(NUMPHYS) ; +#endif +} + +int port_to_mib(smc,p) +struct s_smc *smc ; +int p ; +{ +#ifdef CONCENTRATOR + SK_UNUSED(smc) ; + + return(p) ; +#else + if (smc->s.sas == SMT_SAS) + return(PS) ; + return(p) ; +#endif +} + + +#ifdef DEBUG +#ifndef BOOT +void dump_smt(smc,sm,text) +struct s_smc *smc ; +struct smt_header *sm ; +char *text ; +{ + int len ; + struct smt_para *pa ; + char *c ; + int n ; + int nn ; +#ifdef LITTLE_ENDIAN + int smtlen ; +#endif + + SK_UNUSED(smc) ; + +#ifdef DEBUG_BRD + if (smc->debug.d_smtf < 2) +#else + if (debug.d_smtf < 2) +#endif + return ; +#ifdef LITTLE_ENDIAN + smtlen = sm->smt_len + sizeof(struct smt_header) ; +#endif + printf("SMT Frame [%s]:\nDA ",text) ; + dump_hex((char *) &sm->smt_dest,6) ; + printf("\tSA ") ; + dump_hex((char *) &sm->smt_source,6) ; + printf(" Class %x Type %x Version %x\n", + sm->smt_class,sm->smt_type,sm->smt_version) ; + printf("TID %lx\t\tSID ",sm->smt_tid) ; + dump_hex((char *) &sm->smt_sid,8) ; + printf(" LEN %x\n",sm->smt_len) ; + + len = sm->smt_len ; + pa = (struct smt_para *) (sm + 1) ; + while (len > 0 ) { + int plen ; +#ifdef UNIX + printf("TYPE %x LEN %x VALUE\t",pa->p_type,pa->p_len) ; +#else + printf("TYPE %04x LEN %2x VALUE\t",pa->p_type,pa->p_len) ; +#endif + n = pa->p_len ; + if ( (n < 0 ) || (n > (int)(len - PARA_LEN))) { + n = len - PARA_LEN ; + printf(" BAD LENGTH\n") ; + break ; + } +#ifdef LITTLE_ENDIAN + smt_swap_para(sm,smtlen,0) ; +#endif + if (n < 24) { + dump_hex((char *)(pa+1),(int) n) ; + printf("\n") ; + } + else { + int first = 0 ; + c = (char *)(pa+1) ; + dump_hex(c,16) ; + printf("\n") ; + n -= 16 ; + c += 16 ; + while (n > 0) { + nn = (n > 16) ? 16 : n ; + if (n > 64) { + if (first == 0) + printf("\t\t\t...\n") ; + first = 1 ; + } + else { + printf("\t\t\t") ; + dump_hex(c,nn) ; + printf("\n") ; + } + n -= nn ; + c += 16 ; + } + } +#ifdef LITTLE_ENDIAN + smt_swap_para(sm,smtlen,1) ; +#endif + plen = (pa->p_len + PARA_LEN + 3) & ~3 ; + len -= plen ; + pa = (struct smt_para *)((char *)pa + plen) ; + } + printf("-------------------------------------------------\n\n") ; +} + +void dump_hex(p,len) +char *p ; +int len ; +{ + int n = 0 ; + while (len--) { + n++ ; +#ifdef UNIX + printf("%x%s",*p++ & 0xff,len ? ( (n & 7) ? " " : "-") : "") ; +#else + printf("%02x%s",*p++ & 0xff,len ? ( (n & 7) ? " " : "-") : "") ; +#endif + } +} +#endif /* no BOOT */ +#endif /* DEBUG */ + + +#endif /* no SLIM_SMT */ diff -u --recursive --new-file v2.3.46/linux/drivers/net/skfp/queue.c linux/drivers/net/skfp/queue.c --- v2.3.46/linux/drivers/net/skfp/queue.c Wed Dec 31 16:00:00 1969 +++ linux/drivers/net/skfp/queue.c Fri Feb 18 14:55:53 2000 @@ -0,0 +1,185 @@ +/****************************************************************************** + * + * (C)Copyright 1998,1999 SysKonnect, + * a business unit of Schneider & Koch & Co. Datensysteme GmbH. + * + * See the file "skfddi.c" for further information. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * The information in this file is provided "AS IS" without warranty. + * + ******************************************************************************/ + +/* + SMT Event Queue Management +*/ + +#include "h/types.h" +#include "h/fddi.h" +#include "h/smc.h" + +#ifndef lint +static const char ID_sccs[] = "@(#)queue.c 2.9 97/08/04 (C) SK " ; +#endif + +#define PRINTF(a,b,c) + +/* + * init event queue management + */ +void ev_init(smc) +struct s_smc *smc ; +{ + smc->q.ev_put = smc->q.ev_get = smc->q.ev_queue ; +} + +/* + * add event to queue + */ +void queue_event(smc,class,event) +struct s_smc *smc ; +int class ; +int event ; +{ + PRINTF("queue class %d event %d\n",class,event) ; + smc->q.ev_put->class = class ; + smc->q.ev_put->event = event ; + if (++smc->q.ev_put == &smc->q.ev_queue[MAX_EVENT]) + smc->q.ev_put = smc->q.ev_queue ; + + if (smc->q.ev_put == smc->q.ev_get) { + SMT_ERR_LOG(smc,SMT_E0137, SMT_E0137_MSG) ; + } +} + +/* + * timer_event is called from HW timer package. + */ +void timer_event(smc,token) +struct s_smc *smc ; +u_long token ; +{ + PRINTF("timer event class %d token %d\n", + EV_T_CLASS(token), + EV_T_EVENT(token)) ; + queue_event(smc,EV_T_CLASS(token),EV_T_EVENT(token)); +} + +/* + * event dispatcher + * while event queue is not empty + * get event from queue + * send command to state machine + * end + */ +void ev_dispatcher(smc) +struct s_smc *smc ; +{ + struct event_queue *ev ; /* pointer into queue */ + int class ; + + ev = smc->q.ev_get ; + PRINTF("dispatch get %x put %x\n",ev,smc->q.ev_put) ; + while (ev != smc->q.ev_put) { + PRINTF("dispatch class %d event %d\n",ev->class,ev->event) ; + switch(class = ev->class) { + case EVENT_ECM : /* Entity Corordination Man. */ + ecm(smc,(int)ev->event) ; + break ; + case EVENT_CFM : /* Configuration Man. */ + cfm(smc,(int)ev->event) ; + break ; + case EVENT_RMT : /* Ring Man. */ + rmt(smc,(int)ev->event) ; + break ; + case EVENT_SMT : + smt_event(smc,(int)ev->event) ; + break ; +#ifdef CONCENTRATOR + case 99 : + timer_test_event(smc,(int)ev->event) ; + break ; +#endif + case EVENT_PCMA : /* PHY A */ + case EVENT_PCMB : /* PHY B */ + default : + if (class >= EVENT_PCMA && + class < EVENT_PCMA + NUMPHYS) { + pcm(smc,class - EVENT_PCMA,(int)ev->event) ; + break ; + } + SMT_PANIC(smc,SMT_E0121, SMT_E0121_MSG) ; + return ; + } + + if (++ev == &smc->q.ev_queue[MAX_EVENT]) + ev = smc->q.ev_queue ; + + /* Renew get: it is used in queue_events to detect overruns */ + smc->q.ev_get = ev; + } +} + +/* + * smt_online connects to or disconnects from the ring + * MUST be called to initiate connection establishment + * + * on 0 disconnect + * on 1 connect + */ +u_short smt_online(smc,on) +struct s_smc *smc ; +int on ; +{ + queue_event(smc,EVENT_ECM,on ? EC_CONNECT : EC_DISCONNECT) ; + ev_dispatcher(smc) ; + return(smc->mib.fddiSMTCF_State) ; +} + +/* + * set SMT flag to value + * flag flag name + * value flag value + * dump current flag setting + */ +#ifdef CONCENTRATOR +void do_smt_flag(smc,flag,value) +struct s_smc *smc ; +char *flag ; +int value ; +{ +#ifdef DEBUG + struct smt_debug *deb; + + SK_UNUSED(smc) ; + +#ifdef DEBUG_BRD + deb = &smc->debug; +#else + deb = &debug; +#endif + if (!strcmp(flag,"smt")) + deb->d_smt = value ; + else if (!strcmp(flag,"smtf")) + deb->d_smtf = value ; + else if (!strcmp(flag,"pcm")) + deb->d_pcm = value ; + else if (!strcmp(flag,"rmt")) + deb->d_rmt = value ; + else if (!strcmp(flag,"cfm")) + deb->d_cfm = value ; + else if (!strcmp(flag,"ecm")) + deb->d_ecm = value ; + printf("smt %d\n",deb->d_smt) ; + printf("smtf %d\n",deb->d_smtf) ; + printf("pcm %d\n",deb->d_pcm) ; + printf("rmt %d\n",deb->d_rmt) ; + printf("cfm %d\n",deb->d_cfm) ; + printf("ecm %d\n",deb->d_ecm) ; +#endif /* DEBUG */ +} +#endif diff -u --recursive --new-file v2.3.46/linux/drivers/net/skfp/rmt.c linux/drivers/net/skfp/rmt.c --- v2.3.46/linux/drivers/net/skfp/rmt.c Wed Dec 31 16:00:00 1969 +++ linux/drivers/net/skfp/rmt.c Fri Feb 18 14:55:53 2000 @@ -0,0 +1,674 @@ +/****************************************************************************** + * + * (C)Copyright 1998,1999 SysKonnect, + * a business unit of Schneider & Koch & Co. Datensysteme GmbH. + * + * See the file "skfddi.c" for further information. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * The information in this file is provided "AS IS" without warranty. + * + ******************************************************************************/ + +/* + SMT RMT + Ring Management +*/ + +/* + * Hardware independant state machine implemantation + * The following external SMT functions are referenced : + * + * queue_event() + * smt_timer_start() + * smt_timer_stop() + * + * The following external HW dependant functions are referenced : + * sm_ma_control() + * sm_mac_check_beacon_claim() + * + * The following HW dependant events are required : + * RM_RING_OP + * RM_RING_NON_OP + * RM_MY_BEACON + * RM_OTHER_BEACON + * RM_MY_CLAIM + * RM_TRT_EXP + * RM_VALID_CLAIM + * + */ + +#include "h/types.h" +#include "h/fddi.h" +#include "h/smc.h" + +#define KERNEL +#include "h/smtstate.h" + +#ifndef lint +static const char ID_sccs[] = "@(#)rmt.c 2.13 99/07/02 (C) SK " ; +#endif + +/* + * FSM Macros + */ +#define AFLAG 0x10 +#define GO_STATE(x) (smc->mib.m[MAC0].fddiMACRMTState = (x)|AFLAG) +#define ACTIONS_DONE() (smc->mib.m[MAC0].fddiMACRMTState &= ~AFLAG) +#define ACTIONS(x) (x|AFLAG) + +#define RM0_ISOLATED 0 +#define RM1_NON_OP 1 /* not operational */ +#define RM2_RING_OP 2 /* ring operational */ +#define RM3_DETECT 3 /* detect dupl addresses */ +#define RM4_NON_OP_DUP 4 /* dupl. addr detected */ +#define RM5_RING_OP_DUP 5 /* ring oper. with dupl. addr */ +#define RM6_DIRECTED 6 /* sending directed beacons */ +#define RM7_TRACE 7 /* trace initiated */ + +#ifdef DEBUG +/* + * symbolic state names + */ +static const char * const rmt_states[] = { + "RM0_ISOLATED","RM1_NON_OP","RM2_RING_OP","RM3_DETECT", + "RM4_NON_OP_DUP","RM5_RING_OP_DUP","RM6_DIRECTED", + "RM7_TRACE" +} ; + +/* + * symbolic event names + */ +static const char * const rmt_events[] = { + "NONE","RM_RING_OP","RM_RING_NON_OP","RM_MY_BEACON", + "RM_OTHER_BEACON","RM_MY_CLAIM","RM_TRT_EXP","RM_VALID_CLAIM", + "RM_JOIN","RM_LOOP","RM_DUP_ADDR","RM_ENABLE_FLAG", + "RM_TIMEOUT_NON_OP","RM_TIMEOUT_T_STUCK", + "RM_TIMEOUT_ANNOUNCE","RM_TIMEOUT_T_DIRECT", + "RM_TIMEOUT_D_MAX","RM_TIMEOUT_POLL","RM_TX_STATE_CHANGE" +} ; +#endif + +/* + * Globals + * in struct s_rmt + */ + + +/* + * function declarations + */ +static void rmt_fsm() ; +static void start_rmt_timer0() ; +static void start_rmt_timer1() ; +static void start_rmt_timer2() ; +static void stop_rmt_timer0() ; +static void stop_rmt_timer1() ; +static void stop_rmt_timer2() ; +static void rmt_dup_actions() ; +static void rmt_reinsert_actions() ; +static void rmt_leave_actions() ; +static void rmt_new_dup_actions() ; + +#ifndef SUPERNET_3 +extern void restart_trt_for_dbcn() ; +#endif /*SUPERNET_3*/ + +/* + init RMT state machine + clear all RMT vars and flags +*/ +void rmt_init(smc) +struct s_smc *smc ; +{ + smc->mib.m[MAC0].fddiMACRMTState = ACTIONS(RM0_ISOLATED) ; + smc->r.dup_addr_test = DA_NONE ; + smc->r.da_flag = 0 ; + smc->mib.m[MAC0].fddiMACMA_UnitdataAvailable = FALSE ; + smc->r.sm_ma_avail = FALSE ; + smc->r.loop_avail = 0 ; + smc->r.bn_flag = 0 ; + smc->r.jm_flag = 0 ; + smc->r.no_flag = TRUE ; +} + +/* + RMT state machine + called by dispatcher + + do + display state change + process event + until SM is stable +*/ +void rmt(smc,event) +struct s_smc *smc ; +int event ; +{ + int state ; + + do { + DB_RMT("RMT : state %s%s", + (smc->mib.m[MAC0].fddiMACRMTState & AFLAG) ? "ACTIONS " : "", + rmt_states[smc->mib.m[MAC0].fddiMACRMTState & ~AFLAG]) ; + DB_RMT(" event %s\n",rmt_events[event],0) ; + state = smc->mib.m[MAC0].fddiMACRMTState ; + rmt_fsm(smc,event) ; + event = 0 ; + } while (state != smc->mib.m[MAC0].fddiMACRMTState) ; + rmt_state_change(smc,(int)smc->mib.m[MAC0].fddiMACRMTState) ; +} + +/* + process RMT event +*/ +static void rmt_fsm(smc,cmd) +struct s_smc *smc ; +int cmd ; +{ + /* + * RM00-RM70 : from all states + */ + if (!smc->r.rm_join && !smc->r.rm_loop && + smc->mib.m[MAC0].fddiMACRMTState != ACTIONS(RM0_ISOLATED) && + smc->mib.m[MAC0].fddiMACRMTState != RM0_ISOLATED) { + RS_SET(smc,RS_NORINGOP) ; + rmt_indication(smc,0) ; + GO_STATE(RM0_ISOLATED) ; + return ; + } + + switch(smc->mib.m[MAC0].fddiMACRMTState) { + case ACTIONS(RM0_ISOLATED) : + stop_rmt_timer0(smc) ; + stop_rmt_timer1(smc) ; + stop_rmt_timer2(smc) ; + + /* + * Disable MAC. + */ + sm_ma_control(smc,MA_OFFLINE) ; + smc->mib.m[MAC0].fddiMACMA_UnitdataAvailable = FALSE ; + smc->r.loop_avail = FALSE ; + smc->r.sm_ma_avail = FALSE ; + smc->r.no_flag = TRUE ; + DB_RMTN(1,"RMT : ISOLATED\n",0,0) ; + ACTIONS_DONE() ; + break ; + case RM0_ISOLATED : + /*RM01*/ + if (smc->r.rm_join || smc->r.rm_loop) { + /* + * According to the standard the MAC must be reset + * here. The FORMAC will be initialized and Claim + * and Beacon Frames will be uploaded to the MAC. + * So any change of Treq will take effect NOW. + */ + sm_ma_control(smc,MA_RESET) ; + GO_STATE(RM1_NON_OP) ; + break ; + } + break ; + case ACTIONS(RM1_NON_OP) : + start_rmt_timer0(smc,smc->s.rmt_t_non_op,RM_TIMEOUT_NON_OP) ; + stop_rmt_timer1(smc) ; + stop_rmt_timer2(smc) ; + sm_ma_control(smc,MA_BEACON) ; + DB_RMTN(1,"RMT : RING DOWN\n",0,0) ; + RS_SET(smc,RS_NORINGOP) ; + smc->r.sm_ma_avail = FALSE ; + rmt_indication(smc,0) ; + ACTIONS_DONE() ; + break ; + case RM1_NON_OP : + /*RM12*/ + if (cmd == RM_RING_OP) { + RS_SET(smc,RS_RINGOPCHANGE) ; + GO_STATE(RM2_RING_OP) ; + break ; + } + /*RM13*/ + else if (cmd == RM_TIMEOUT_NON_OP) { + smc->r.bn_flag = FALSE ; + smc->r.no_flag = TRUE ; + GO_STATE(RM3_DETECT) ; + break ; + } + break ; + case ACTIONS(RM2_RING_OP) : + stop_rmt_timer0(smc) ; + stop_rmt_timer1(smc) ; + stop_rmt_timer2(smc) ; + smc->r.no_flag = FALSE ; + if (smc->r.rm_loop) + smc->r.loop_avail = TRUE ; + if (smc->r.rm_join) { + smc->r.sm_ma_avail = TRUE ; + if (smc->mib.m[MAC0].fddiMACMA_UnitdataEnable) + smc->mib.m[MAC0].fddiMACMA_UnitdataAvailable = TRUE ; + else + smc->mib.m[MAC0].fddiMACMA_UnitdataAvailable = FALSE ; + } + DB_RMTN(1,"RMT : RING UP\n",0,0) ; + RS_CLEAR(smc,RS_NORINGOP) ; + RS_SET(smc,RS_RINGOPCHANGE) ; + rmt_indication(smc,1) ; + smt_stat_counter(smc,0) ; + ACTIONS_DONE() ; + break ; + case RM2_RING_OP : + /*RM21*/ + if (cmd == RM_RING_NON_OP) { + smc->mib.m[MAC0].fddiMACMA_UnitdataAvailable = FALSE ; + smc->r.loop_avail = FALSE ; + RS_SET(smc,RS_RINGOPCHANGE) ; + GO_STATE(RM1_NON_OP) ; + break ; + } + /*RM22a*/ + else if (cmd == RM_ENABLE_FLAG) { + if (smc->mib.m[MAC0].fddiMACMA_UnitdataEnable) + smc->mib.m[MAC0].fddiMACMA_UnitdataAvailable = TRUE ; + else + smc->mib.m[MAC0].fddiMACMA_UnitdataAvailable = FALSE ; + } + /*RM25*/ + else if (smc->r.dup_addr_test == DA_FAILED) { + smc->mib.m[MAC0].fddiMACMA_UnitdataAvailable = FALSE ; + smc->r.loop_avail = FALSE ; + smc->r.da_flag = TRUE ; + GO_STATE(RM5_RING_OP_DUP) ; + break ; + } + break ; + case ACTIONS(RM3_DETECT) : + start_rmt_timer0(smc,smc->s.mac_d_max*2,RM_TIMEOUT_D_MAX) ; + start_rmt_timer1(smc,smc->s.rmt_t_stuck,RM_TIMEOUT_T_STUCK) ; + start_rmt_timer2(smc,smc->s.rmt_t_poll,RM_TIMEOUT_POLL) ; + sm_mac_check_beacon_claim(smc) ; + DB_RMTN(1,"RMT : RM3_DETECT\n",0,0) ; + ACTIONS_DONE() ; + break ; + case RM3_DETECT : + if (cmd == RM_TIMEOUT_POLL) { + start_rmt_timer2(smc,smc->s.rmt_t_poll,RM_TIMEOUT_POLL); + sm_mac_check_beacon_claim(smc) ; + break ; + } + if (cmd == RM_TIMEOUT_D_MAX) { + smc->r.timer0_exp = TRUE ; + } + /* + *jd(22-Feb-1999) + * We need a time ">= 2*mac_d_max" since we had finished + * Claim or Beacon state. So we will restart timer0 at + * every state change. + */ + if (cmd == RM_TX_STATE_CHANGE) { + start_rmt_timer0(smc, + smc->s.mac_d_max*2, + RM_TIMEOUT_D_MAX) ; + } + /*RM32*/ + if (cmd == RM_RING_OP) { + GO_STATE(RM2_RING_OP) ; + break ; + } + /*RM33a*/ + else if ((cmd == RM_MY_BEACON || cmd == RM_OTHER_BEACON) + && smc->r.bn_flag) { + smc->r.bn_flag = FALSE ; + } + /*RM33b*/ + else if (cmd == RM_TRT_EXP && !smc->r.bn_flag) { + int tx ; + /* + * set bn_flag only if in state T4 or T5: + * only if we're the beaconer should we start the + * trace ! + */ + if ((tx = sm_mac_get_tx_state(smc)) == 4 || tx == 5) { + DB_RMTN(2,"RMT : DETECT && TRT_EXPIRED && T4/T5\n",0,0); + smc->r.bn_flag = TRUE ; + /* + * If one of the upstream stations beaconed + * and the link to the upstream neighbor is + * lost we need to restart the stuck timer to + * check the "stuck beacon" condition. + */ + start_rmt_timer1(smc,smc->s.rmt_t_stuck, + RM_TIMEOUT_T_STUCK) ; + } + /* + * We do NOT need to clear smc->r.bn_flag in case of + * not being in state T4 or T5, because the flag + * must be cleared in order to get in this condition. + */ + + DB_RMTN(2, + "RMT : sm_mac_get_tx_state() = %d (bn_flag = %d)\n", + tx,smc->r.bn_flag) ; + } + /*RM34a*/ + else if (cmd == RM_MY_CLAIM && smc->r.timer0_exp) { + rmt_new_dup_actions(smc) ; + GO_STATE(RM4_NON_OP_DUP) ; + break ; + } + /*RM34b*/ + else if (cmd == RM_MY_BEACON && smc->r.timer0_exp) { + rmt_new_dup_actions(smc) ; + GO_STATE(RM4_NON_OP_DUP) ; + break ; + } + /*RM34c*/ + else if (cmd == RM_VALID_CLAIM) { + rmt_new_dup_actions(smc) ; + GO_STATE(RM4_NON_OP_DUP) ; + break ; + } + /*RM36*/ + else if (cmd == RM_TIMEOUT_T_STUCK && + smc->r.rm_join && smc->r.bn_flag) { + GO_STATE(RM6_DIRECTED) ; + break ; + } + break ; + case ACTIONS(RM4_NON_OP_DUP) : + start_rmt_timer0(smc,smc->s.rmt_t_announce,RM_TIMEOUT_ANNOUNCE); + start_rmt_timer1(smc,smc->s.rmt_t_stuck,RM_TIMEOUT_T_STUCK) ; + start_rmt_timer2(smc,smc->s.rmt_t_poll,RM_TIMEOUT_POLL) ; + sm_mac_check_beacon_claim(smc) ; + DB_RMTN(1,"RMT : RM4_NON_OP_DUP\n",0,0) ; + ACTIONS_DONE() ; + break ; + case RM4_NON_OP_DUP : + if (cmd == RM_TIMEOUT_POLL) { + start_rmt_timer2(smc,smc->s.rmt_t_poll,RM_TIMEOUT_POLL); + sm_mac_check_beacon_claim(smc) ; + break ; + } + /*RM41*/ + if (!smc->r.da_flag) { + GO_STATE(RM1_NON_OP) ; + break ; + } + /*RM44a*/ + else if ((cmd == RM_MY_BEACON || cmd == RM_OTHER_BEACON) && + smc->r.bn_flag) { + smc->r.bn_flag = FALSE ; + } + /*RM44b*/ + else if (cmd == RM_TRT_EXP && !smc->r.bn_flag) { + int tx ; + /* + * set bn_flag only if in state T4 or T5: + * only if we're the beaconer should we start the + * trace ! + */ + if ((tx = sm_mac_get_tx_state(smc)) == 4 || tx == 5) { + DB_RMTN(2,"RMT : NOPDUP && TRT_EXPIRED && T4/T5\n",0,0); + smc->r.bn_flag = TRUE ; + /* + * If one of the upstream stations beaconed + * and the link to the upstream neighbor is + * lost we need to restart the stuck timer to + * check the "stuck beacon" condition. + */ + start_rmt_timer1(smc,smc->s.rmt_t_stuck, + RM_TIMEOUT_T_STUCK) ; + } + /* + * We do NOT need to clear smc->r.bn_flag in case of + * not being in state T4 or T5, because the flag + * must be cleared in order to get in this condition. + */ + + DB_RMTN(2, + "RMT : sm_mac_get_tx_state() = %d (bn_flag = %d)\n", + tx,smc->r.bn_flag) ; + } + /*RM44c*/ + else if (cmd == RM_TIMEOUT_ANNOUNCE && !smc->r.bn_flag) { + rmt_dup_actions(smc) ; + } + /*RM45*/ + else if (cmd == RM_RING_OP) { + smc->r.no_flag = FALSE ; + GO_STATE(RM5_RING_OP_DUP) ; + break ; + } + /*RM46*/ + else if (cmd == RM_TIMEOUT_T_STUCK && + smc->r.rm_join && smc->r.bn_flag) { + GO_STATE(RM6_DIRECTED) ; + break ; + } + break ; + case ACTIONS(RM5_RING_OP_DUP) : + stop_rmt_timer0(smc) ; + stop_rmt_timer1(smc) ; + stop_rmt_timer2(smc) ; + DB_RMTN(1,"RMT : RM5_RING_OP_DUP\n",0,0) ; + ACTIONS_DONE() ; + break; + case RM5_RING_OP_DUP : + /*RM52*/ + if (smc->r.dup_addr_test == DA_PASSED) { + smc->r.da_flag = FALSE ; + GO_STATE(RM2_RING_OP) ; + break ; + } + /*RM54*/ + else if (cmd == RM_RING_NON_OP) { + smc->r.jm_flag = FALSE ; + smc->r.bn_flag = FALSE ; + GO_STATE(RM4_NON_OP_DUP) ; + break ; + } + break ; + case ACTIONS(RM6_DIRECTED) : + start_rmt_timer0(smc,smc->s.rmt_t_direct,RM_TIMEOUT_T_DIRECT) ; + stop_rmt_timer1(smc) ; + start_rmt_timer2(smc,smc->s.rmt_t_poll,RM_TIMEOUT_POLL) ; + sm_ma_control(smc,MA_DIRECTED) ; + RS_SET(smc,RS_BEACON) ; + DB_RMTN(1,"RMT : RM6_DIRECTED\n",0,0) ; + ACTIONS_DONE() ; + break ; + case RM6_DIRECTED : + /*RM63*/ + if (cmd == RM_TIMEOUT_POLL) { + start_rmt_timer2(smc,smc->s.rmt_t_poll,RM_TIMEOUT_POLL); + sm_mac_check_beacon_claim(smc) ; +#ifndef SUPERNET_3 + /* Because of problems with the Supernet II chip set + * sending of Directed Beacon will stop after 165ms + * therefore restart_trt_for_dbcn(smc) will be called + * to prevent this. + */ + restart_trt_for_dbcn(smc) ; +#endif /*SUPERNET_3*/ + break ; + } + if ((cmd == RM_MY_BEACON || cmd == RM_OTHER_BEACON) && + !smc->r.da_flag) { + smc->r.bn_flag = FALSE ; + GO_STATE(RM3_DETECT) ; + break ; + } + /*RM64*/ + else if ((cmd == RM_MY_BEACON || cmd == RM_OTHER_BEACON) && + smc->r.da_flag) { + smc->r.bn_flag = FALSE ; + GO_STATE(RM4_NON_OP_DUP) ; + break ; + } + /*RM67*/ + else if (cmd == RM_TIMEOUT_T_DIRECT) { + GO_STATE(RM7_TRACE) ; + break ; + } + break ; + case ACTIONS(RM7_TRACE) : + stop_rmt_timer0(smc) ; + stop_rmt_timer1(smc) ; + stop_rmt_timer2(smc) ; + smc->e.trace_prop |= ENTITY_BIT(ENTITY_MAC) ; + queue_event(smc,EVENT_ECM,EC_TRACE_PROP) ; + DB_RMTN(1,"RMT : RM7_TRACE\n",0,0) ; + ACTIONS_DONE() ; + break ; + case RM7_TRACE : + break ; + default: + SMT_PANIC(smc,SMT_E0122, SMT_E0122_MSG) ; + break; + } +} + +/* + * (jd) RMT duplicate address actions + * leave the ring or reinsert just as configured + */ +static void rmt_dup_actions(smc) +struct s_smc *smc ; +{ + if (smc->r.jm_flag) { + } + else { + if (smc->s.rmt_dup_mac_behavior) { + SMT_ERR_LOG(smc,SMT_E0138, SMT_E0138_MSG) ; + rmt_reinsert_actions(smc) ; + } + else { + SMT_ERR_LOG(smc,SMT_E0135, SMT_E0135_MSG) ; + rmt_leave_actions(smc) ; + } + } +} + +/* + * Reconnect to the Ring + */ +static void rmt_reinsert_actions(smc) +struct s_smc *smc ; +{ + queue_event(smc,EVENT_ECM,EC_DISCONNECT) ; + queue_event(smc,EVENT_ECM,EC_CONNECT) ; +} + +/* + * duplicate address detected + */ +static void rmt_new_dup_actions(smc) +struct s_smc *smc ; +{ + smc->r.da_flag = TRUE ; + smc->r.bn_flag = FALSE ; + smc->r.jm_flag = FALSE ; + /* + * we have three options : change address, jam or leave + * we leave the ring as default + * Optionally it's possible to reinsert after leaving the Ring + * but this will not conform with SMT Spec. + */ + if (smc->s.rmt_dup_mac_behavior) { + SMT_ERR_LOG(smc,SMT_E0138, SMT_E0138_MSG) ; + rmt_reinsert_actions(smc) ; + } + else { + SMT_ERR_LOG(smc,SMT_E0135, SMT_E0135_MSG) ; + rmt_leave_actions(smc) ; + } +} + + +/* + * leave the ring + */ +static void rmt_leave_actions(smc) +struct s_smc *smc ; +{ + queue_event(smc,EVENT_ECM,EC_DISCONNECT) ; + /* + * Note: Do NOT try again later. (with please reconnect) + * The station must be left from the ring! + */ +} + +/* + * SMT timer interface + * start RMT timer 0 + */ +static void start_rmt_timer0(smc,value,event) +struct s_smc *smc ; +u_long value ; +int event ; +{ + smc->r.timer0_exp = FALSE ; /* clear timer event flag */ + smt_timer_start(smc,&smc->r.rmt_timer0,value,EV_TOKEN(EVENT_RMT,event)); +} + +/* + * SMT timer interface + * start RMT timer 1 + */ +static void start_rmt_timer1(smc,value,event) +struct s_smc *smc ; +u_long value ; +int event ; +{ + smc->r.timer1_exp = FALSE ; /* clear timer event flag */ + smt_timer_start(smc,&smc->r.rmt_timer1,value,EV_TOKEN(EVENT_RMT,event)); +} + +/* + * SMT timer interface + * start RMT timer 2 + */ +static void start_rmt_timer2(smc,value,event) +struct s_smc *smc ; +u_long value ; +int event ; +{ + smc->r.timer2_exp = FALSE ; /* clear timer event flag */ + smt_timer_start(smc,&smc->r.rmt_timer2,value,EV_TOKEN(EVENT_RMT,event)); +} + +/* + * SMT timer interface + * stop RMT timer 0 + */ +static void stop_rmt_timer0(smc) +struct s_smc *smc ; +{ + if (smc->r.rmt_timer0.tm_active) + smt_timer_stop(smc,&smc->r.rmt_timer0) ; +} + +/* + * SMT timer interface + * stop RMT timer 1 + */ +static void stop_rmt_timer1(smc) +struct s_smc *smc ; +{ + if (smc->r.rmt_timer1.tm_active) + smt_timer_stop(smc,&smc->r.rmt_timer1) ; +} + +/* + * SMT timer interface + * stop RMT timer 2 + */ +static void stop_rmt_timer2(smc) +struct s_smc *smc ; +{ + if (smc->r.rmt_timer2.tm_active) + smt_timer_stop(smc,&smc->r.rmt_timer2) ; +} diff -u --recursive --new-file v2.3.46/linux/drivers/net/skfp/skfddi.c linux/drivers/net/skfp/skfddi.c --- v2.3.46/linux/drivers/net/skfp/skfddi.c Wed Dec 31 16:00:00 1969 +++ linux/drivers/net/skfp/skfddi.c Fri Feb 18 14:55:53 2000 @@ -0,0 +1,2495 @@ +/* + * File Name: + * skfddi.c + * + * Copyright Information: + * Copyright SysKonnect 1998,1999. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * The information in this file is provided "AS IS" without warranty. + * + * Abstract: + * A Linux device driver supporting the SysKonnect FDDI PCI controller + * familie. + * + * Maintainers: + * CG Christoph Goos (cgoos@syskonnect.de) + * + * Address all question to: + * linux@syskonnect.de + * + * The technical manual for the adapters is available from SysKonnect's + * web pages: www.syskonnect.com + * Goto "Support" and search Knowledge Base for "manual". + * + * Driver Architecture: + * The driver architecture is based on the DEC FDDI driver by + * Lawrence V. Stefani and several ethernet drivers. + * I also used an existing Windows NT miniport driver. + * All hardware dependant fuctions are handled by the SysKonnect + * Hardware Module. + * The only headerfiles that are directly related to this source + * are skfddi.c, h/types.h, h/osdef1st.h, h/targetos.h. + * The others belong to the SysKonnect FDDI Hardware Module and + * should better not be changed. + * NOTE: + * Compiling this driver produces some warnings, but I did not fix + * this, because the Hardware Module source is used for different + * drivers, and fixing it for Linux might bring problems on other + * projects. To keep the source common for all those drivers (and + * thus simplify fixes to it), please do not clean it up! + * + * Modification History: + * Date Name Description + * 02-Mar-98 CG Created. + * + * 10-Mar-99 CG Support for 2.2.x added. + * 25-Mar-99 CG Corrected IRQ routing for SMP (APIC) + * 26-Oct-99 CG Fixed compilation error on 2.2.13 + * 12-Nov-99 CG Source code release + * 22-Nov-99 CG Included in kernel source. + * + * Compilation options (-Dxxx): + * DRIVERDEBUG print lots of messages to log file + * DUMPPACKETS print received/transmitted packets to logfile + * + * Limitations: + * I changed the driver to support memory mapped I/O, so it + * might run on non-x86 architectures (not tested). + * But the hardware module does not yet support 64 bit OS'es. + */ + +/* Version information string - should be updated prior to */ +/* each new release!!! */ +#define VERSION "2.05" + +static const char *boot_msg = + "SysKonnect FDDI PCI Adapter driver v" VERSION " for\n" + " SK-55xx/SK-58xx adapters (SK-NET FDDI-FP/UP/LP)"; + +/* Include files */ + +#include + +#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 -u --recursive --new-file v2.3.46/linux/drivers/net/skfp/smt.c linux/drivers/net/skfp/smt.c --- v2.3.46/linux/drivers/net/skfp/smt.c Wed Dec 31 16:00:00 1969 +++ linux/drivers/net/skfp/smt.c Fri Feb 18 14:55:53 2000 @@ -0,0 +1,2225 @@ +/****************************************************************************** + * + * (C)Copyright 1998,1999 SysKonnect, + * a business unit of Schneider & Koch & Co. Datensysteme GmbH. + * + * See the file "skfddi.c" for further information. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * The information in this file is provided "AS IS" without warranty. + * + ******************************************************************************/ + +#include "h/types.h" +#include "h/fddi.h" +#include "h/smc.h" +#include "h/smt_p.h" + +#define KERNEL +#include "h/smtstate.h" + +#ifndef lint +static const char ID_sccs[] = "@(#)smt.c 2.43 98/11/23 (C) SK " ; +#endif + +extern const u_char canonical[256] ; + +/* + * FC in SMbuf + */ +#define m_fc(mb) ((mb)->sm_data[0]) + +#define SMT_TID_MAGIC 0x1f0a7b3c + +#ifdef DEBUG +static const char *const smt_type_name[] = { + "SMT_00??", "SMT_INFO", "SMT_02??", "SMT_03??", + "SMT_04??", "SMT_05??", "SMT_06??", "SMT_07??", + "SMT_08??", "SMT_09??", "SMT_0A??", "SMT_0B??", + "SMT_0C??", "SMT_0D??", "SMT_0E??", "SMT_NSA" +} ; + +static const char *const smt_class_name[] = { + "UNKNOWN","NIF","SIF_CONFIG","SIF_OPER","ECF","RAF","RDF", + "SRF","PMF_GET","PMF_SET","ESF" +} ; +#endif +#define LAST_CLASS (SMT_PMF_SET) + +static const struct fddi_addr SMT_Unknown = { + 0,0,0x1f,0,0,0 +} ; + +/* + * external variables + */ +extern const struct fddi_addr fddi_broadcast ; + +/* + * external functions + */ +int pcm_status_twisted() ; +void pcm_status_state() ; +int pcm_status_type() ; + +extern SMbuf *smt_get_mbuf() ; + +#define EXPORT_PMF +/* + * function prototypes + */ +u_long smt_get_tid() ; +EXPORT_PMF SMbuf *smt_build_frame() ; +EXPORT_PMF void *sm_to_para() ; +#ifdef LITTLE_ENDIAN +static int smt_swap_short() ; +#endif +static int mac_index() ; +static int phy_index() ; +static int mac_con_resource_index() ; +static int phy_con_resource_index() ; +EXPORT_PMF void smt_send_frame() ; +EXPORT_PMF void smt_set_timestamp() ; +static void smt_send_rdf() ; +static void smt_send_nif() ; +static void smt_send_ecf() ; +static void smt_echo_test() ; +static void smt_send_sif_config() ; +static void smt_send_sif_operation() ; +EXPORT_PMF void smt_swap_para() ; +#ifdef LITTLE_ENDIAN +static void smt_string_swap() ; +#endif +static void smt_add_frame_len() ; +static void smt_fill_una() ; +static void smt_fill_sde() ; +static void smt_fill_state() ; +static void smt_fill_timestamp() ; +static void smt_fill_policy() ; +static void smt_fill_latency() ; +static void smt_fill_neighbor() ; +static int smt_fill_path() ; +static void smt_fill_mac_status() ; +static void smt_fill_lem() ; +static void smt_fill_version() ; +static void smt_fill_fsc() ; +static void smt_fill_mac_counter() ; +static void smt_fill_mac_fnc() ; +static void smt_fill_manufacturer() ; +static void smt_fill_user() ; +static void smt_fill_setcount() ; +static void smt_fill_echo() ; +int smt_check_para() ; + +void smt_clear_una_dna() ; +static void smt_clear_old_una_dna() ; +#ifdef CONCENTRATOR +static int entity_to_index() ; +#endif +static void update_dac() ; +static int div_ratio() ; +#ifdef USE_CAN_ADDR +void hwm_conv_can() ; +#else +#define hwm_conv_can(smc,data,len) +#endif + +/* + * list of mandatory paras in frames + */ +static const u_short plist_nif[] = { SMT_P_UNA,SMT_P_SDE,SMT_P_STATE,0 } ; + +/* + * init SMT agent + */ +void smt_agent_init(smc) +struct s_smc *smc ; +{ + int i ; + + /* + * get MAC address + */ + smc->mib.m[MAC0].fddiMACSMTAddress = smc->hw.fddi_home_addr ; + + /* + * get OUI address from driver (bia == built-in-address) + */ + smc->mib.fddiSMTStationId.sid_oem[0] = 0 ; + smc->mib.fddiSMTStationId.sid_oem[1] = 0 ; + driver_get_bia(smc,&smc->mib.fddiSMTStationId.sid_node) ; + for (i = 0 ; i < 6 ; i ++) { + smc->mib.fddiSMTStationId.sid_node.a[i] = + canonical[smc->mib.fddiSMTStationId.sid_node.a[i]] ; + } + smc->mib.fddiSMTManufacturerData[0] = + smc->mib.fddiSMTStationId.sid_node.a[0] ; + smc->mib.fddiSMTManufacturerData[1] = + smc->mib.fddiSMTStationId.sid_node.a[1] ; + smc->mib.fddiSMTManufacturerData[2] = + smc->mib.fddiSMTStationId.sid_node.a[2] ; + smc->sm.smt_tid = 0 ; + smc->mib.m[MAC0].fddiMACDupAddressTest = DA_NONE ; + smc->mib.m[MAC0].fddiMACUNDA_Flag = FALSE ; +#ifndef SLIM_SMT + smt_clear_una_dna(smc) ; + smt_clear_old_una_dna(smc) ; +#endif + for (i = 0 ; i < SMT_MAX_TEST ; i++) + smc->sm.pend[i] = 0 ; + smc->sm.please_reconnect = 0 ; + smc->sm.uniq_ticks = 0 ; +} + +/* + * SMT task + * forever + * delay 30 seconds + * send NIF + * check tvu & tvd + * end + */ +void smt_agent_task(smc) +struct s_smc *smc ; +{ + smt_timer_start(smc,&smc->sm.smt_timer, (u_long)1000000L, + EV_TOKEN(EVENT_SMT,SM_TIMER)) ; + DB_SMT("SMT agent task\n",0,0) ; +} + +void smt_please_reconnect(smc,reconn_time) +struct s_smc *smc ; /* Pointer to SMT context */ +int reconn_time ; /* Wait for reconnect time in seconds */ +{ + /* + * The please reconnect variable is used as a timer. + * It is decremented each time smt_event is called. + * This happens every second or when smt_force_irq is called. + * Note: smt_force_irq () is called on some packet receives and + * when a multicast address is changed. Since nothing + * is received during the disconnect and the multicast + * address changes can be viewed as not very often and + * the timer runs out close to its given value + * (reconn_time). + */ + smc->sm.please_reconnect = reconn_time ; +} + +#ifndef SMT_REAL_TOKEN_CT +void smt_emulate_token_ct(smc, mac_index) +struct s_smc *smc; +int mac_index; +{ + u_long count; + u_long time; + + + time = smt_get_time(); + count = ((time - smc->sm.last_tok_time[mac_index]) * + 100)/TICKS_PER_SECOND; + + /* + * Only when ring is up we will have a token count. The + * flag is unfortunatly a single instance value. This + * doesn't matter now, because we currently have only + * one MAC instance. + */ + if (smc->hw.mac_ring_is_up){ + smc->mib.m[mac_index].fddiMACToken_Ct += count; + } + + /* Remember current time */ + smc->sm.last_tok_time[mac_index] = time; + +} +#endif + +/*ARGSUSED1*/ +void smt_event(smc,event) +struct s_smc *smc ; +int event ; +{ + u_long time ; +#ifndef SMT_REAL_TOKEN_CT + int i ; +#endif + + + if (smc->sm.please_reconnect) { + smc->sm.please_reconnect -- ; + if (smc->sm.please_reconnect == 0) { + /* Counted down */ + queue_event(smc,EVENT_ECM,EC_CONNECT) ; + } + } + + if (event == SM_FAST) + return ; + + /* + * timer for periodic cleanup in driver + * reset and start the watchdog (FM2) + * ESS timer + * SBA timer + */ + smt_timer_poll(smc) ; + smt_start_watchdog(smc) ; +#ifndef SLIM_SMT +#ifndef BOOT +#ifdef ESS + ess_timer_poll(smc) ; +#endif +#endif +#ifdef SBA + sba_timer_poll(smc) ; +#endif + + smt_srf_event(smc,0,0,0) ; + +#endif /* no SLIM_SMT */ + + time = smt_get_time() ; + + if (time - smc->sm.smt_last_lem >= TICKS_PER_SECOND*8) { + /* + * Use 8 sec. for the time intervall, it simplifies the + * LER estimation. + */ + struct fddi_mib_m *mib ; + u_long upper ; + u_long lower ; + int cond ; + int port; + struct s_phy *phy ; + /* + * calculate LEM bit error rate + */ + sm_lem_evaluate(smc) ; + smc->sm.smt_last_lem = time ; + + /* + * check conditions + */ +#ifndef SLIM_SMT + mac_update_counter(smc) ; + mib = smc->mib.m ; + upper = + (mib->fddiMACLost_Ct - mib->fddiMACOld_Lost_Ct) + + (mib->fddiMACError_Ct - mib->fddiMACOld_Error_Ct) ; + lower = + (mib->fddiMACFrame_Ct - mib->fddiMACOld_Frame_Ct) + + (mib->fddiMACLost_Ct - mib->fddiMACOld_Lost_Ct) ; + mib->fddiMACFrameErrorRatio = div_ratio(upper,lower) ; + + cond = + ((!mib->fddiMACFrameErrorThreshold && + mib->fddiMACError_Ct != mib->fddiMACOld_Error_Ct) || + (mib->fddiMACFrameErrorRatio > + mib->fddiMACFrameErrorThreshold)) ; + + if (cond != mib->fddiMACFrameErrorFlag) + smt_srf_event(smc,SMT_COND_MAC_FRAME_ERROR, + INDEX_MAC,cond) ; + + upper = + (mib->fddiMACNotCopied_Ct - mib->fddiMACOld_NotCopied_Ct) ; + lower = + upper + + (mib->fddiMACCopied_Ct - mib->fddiMACOld_Copied_Ct) ; + mib->fddiMACNotCopiedRatio = div_ratio(upper,lower) ; + + cond = + ((!mib->fddiMACNotCopiedThreshold && + mib->fddiMACNotCopied_Ct != + mib->fddiMACOld_NotCopied_Ct)|| + (mib->fddiMACNotCopiedRatio > + mib->fddiMACNotCopiedThreshold)) ; + + if (cond != mib->fddiMACNotCopiedFlag) + smt_srf_event(smc,SMT_COND_MAC_NOT_COPIED, + INDEX_MAC,cond) ; + + /* + * set old values + */ + mib->fddiMACOld_Frame_Ct = mib->fddiMACFrame_Ct ; + mib->fddiMACOld_Copied_Ct = mib->fddiMACCopied_Ct ; + mib->fddiMACOld_Error_Ct = mib->fddiMACError_Ct ; + mib->fddiMACOld_Lost_Ct = mib->fddiMACLost_Ct ; + mib->fddiMACOld_NotCopied_Ct = mib->fddiMACNotCopied_Ct ; + + /* + * Check port EBError Condition + */ + for (port = 0; port < NUMPHYS; port ++) { + phy = &smc->y[port] ; + + if (!phy->mib->fddiPORTHardwarePresent) { + continue; + } + + cond = (phy->mib->fddiPORTEBError_Ct - + phy->mib->fddiPORTOldEBError_Ct > 5) ; + + /* If ratio is more than 5 in 8 seconds + * Set the condition. + */ + smt_srf_event(smc,SMT_COND_PORT_EB_ERROR, + (int) (INDEX_PORT+ phy->np) ,cond) ; + + /* + * set old values + */ + phy->mib->fddiPORTOldEBError_Ct = + phy->mib->fddiPORTEBError_Ct ; + } + +#endif /* no SLIM_SMT */ + } + +#ifndef SLIM_SMT + + if (time - smc->sm.smt_last_notify >= (u_long) + (smc->mib.fddiSMTTT_Notify * TICKS_PER_SECOND) ) { + /* + * we can either send an announcement or a request + * a request will trigger a reply so that we can update + * our dna + * note: same tid must be used until reply is received + */ + if (!smc->sm.pend[SMT_TID_NIF]) + smc->sm.pend[SMT_TID_NIF] = smt_get_tid(smc) ; + smt_send_nif(smc,&fddi_broadcast,FC_SMT_NSA, + smc->sm.pend[SMT_TID_NIF], SMT_REQUEST,0) ; + smc->sm.smt_last_notify = time ; + } + + /* + * check timer + */ + if (smc->sm.smt_tvu && + time - smc->sm.smt_tvu > 228*TICKS_PER_SECOND) { + DB_SMT("SMT : UNA expired\n",0,0) ; + smc->sm.smt_tvu = 0 ; + + if (!is_equal(&smc->mib.m[MAC0].fddiMACUpstreamNbr, + &SMT_Unknown)){ + /* Do not update unknown address */ + smc->mib.m[MAC0].fddiMACOldUpstreamNbr= + smc->mib.m[MAC0].fddiMACUpstreamNbr ; + } + smc->mib.m[MAC0].fddiMACUpstreamNbr = SMT_Unknown ; + smc->mib.m[MAC0].fddiMACUNDA_Flag = FALSE ; + /* + * Make sure the fddiMACUNDA_Flag = FALSE is + * included in the SRF so we don't generate + * a seperate SRF for the deassertion of this + * condition + */ + update_dac(smc,0) ; + smt_srf_event(smc, SMT_EVENT_MAC_NEIGHBOR_CHANGE, + INDEX_MAC,0) ; + } + if (smc->sm.smt_tvd && + time - smc->sm.smt_tvd > 228*TICKS_PER_SECOND) { + DB_SMT("SMT : DNA expired\n",0,0) ; + smc->sm.smt_tvd = 0 ; + if (!is_equal(&smc->mib.m[MAC0].fddiMACDownstreamNbr, + &SMT_Unknown)){ + /* Do not update unknown address */ + smc->mib.m[MAC0].fddiMACOldDownstreamNbr= + smc->mib.m[MAC0].fddiMACDownstreamNbr ; + } + smc->mib.m[MAC0].fddiMACDownstreamNbr = SMT_Unknown ; + smt_srf_event(smc, SMT_EVENT_MAC_NEIGHBOR_CHANGE, + INDEX_MAC,0) ; + } + +#endif /* no SLIM_SMT */ + +#ifndef SMT_REAL_TOKEN_CT + /* + * Token counter emulation section. If hardware supports the token + * count, the token counter will be updated in mac_update_counter. + */ + for (i = MAC0; i < NUMMACS; i++ ){ + if (time - smc->sm.last_tok_time[i] > 2*TICKS_PER_SECOND ){ + smt_emulate_token_ct( smc, i ); + } + } +#endif + + smt_timer_start(smc,&smc->sm.smt_timer, (u_long)1000000L, + EV_TOKEN(EVENT_SMT,SM_TIMER)) ; +} + +static int div_ratio(upper,lower) +u_long upper ; +u_long lower ; +{ + if ((upper<<16L) < upper) + upper = 0xffff0000L ; + else + upper <<= 16L ; + if (!lower) + return(0) ; + return((int)(upper/lower)) ; +} + +#ifndef SLIM_SMT + +/* + * receive packet handler + */ +void smt_received_pack(smc,mb,fs) +struct s_smc *smc ; +SMbuf *mb ; +int fs ; /* frame status */ +{ + struct smt_header *sm ; + int local ; + + int illegal = 0 ; + + switch (m_fc(mb)) { + case FC_SMT_INFO : + case FC_SMT_LAN_LOC : + case FC_SMT_LOC : + case FC_SMT_NSA : + break ; + default : + smt_free_mbuf(smc,mb) ; + return ; + } + + smc->mib.m[MAC0].fddiMACSMTCopied_Ct++ ; + sm = smtod(mb,struct smt_header *) ; + local = ((fs & L_INDICATOR) != 0) ; + hwm_conv_can(smc,(char *)sm,12) ; + + /* check destination address */ + if (is_individual(&sm->smt_dest) && !is_my_addr(smc,&sm->smt_dest)) { + smt_free_mbuf(smc,mb) ; + return ; + } +#if 0 /* for DUP recognition, do NOT filter them */ + /* ignore loop back packets */ + if (is_my_addr(smc,&sm->smt_source) && !local) { + smt_free_mbuf(smc,mb) ; + return ; + } +#endif + + smt_swap_para(sm,(int) mb->sm_len,1) ; + DB_SMT("SMT : received packet [%s] at 0x%x\n", + smt_type_name[m_fc(mb) & 0xf],sm) ; + DB_SMT("SMT : version %d, class %s\n",sm->smt_version, + smt_class_name[(sm->smt_class>LAST_CLASS)?0 : sm->smt_class]) ; + +#ifdef SBA + /* + * check if NSA frame + */ + if (m_fc(mb) == FC_SMT_NSA && sm->smt_class == SMT_NIF && + (sm->smt_type == SMT_ANNOUNCE || sm->smt_type == SMT_REQUEST)) { + smc->sba.sm = sm ; + sba(smc,NIF) ; + } +#endif + + /* + * ignore any packet with NSA and A-indicator set + */ + if ( (fs & A_INDICATOR) && m_fc(mb) == FC_SMT_NSA) { + DB_SMT("SMT : ignoring NSA with A-indicator set from %s\n", + addr_to_string(&sm->smt_source),0) ; + smt_free_mbuf(smc,mb) ; + return ; + } + + /* + * ignore frames with illegal length + */ + if (((sm->smt_class == SMT_ECF) && (sm->smt_len > SMT_MAX_ECHO_LEN)) || + ((sm->smt_class != SMT_ECF) && (sm->smt_len > SMT_MAX_INFO_LEN))) { + smt_free_mbuf(smc,mb) ; + return ; + } + + /* + * check SMT version + */ + switch (sm->smt_class) { + case SMT_NIF : + case SMT_SIF_CONFIG : + case SMT_SIF_OPER : + case SMT_ECF : + if (sm->smt_version != SMT_VID) + illegal = 1; + break ; + default : + if (sm->smt_version != SMT_VID_2) + illegal = 1; + break ; + } + if (illegal) { + DB_SMT("SMT : version = %d, dest = %s\n", + sm->smt_version,addr_to_string(&sm->smt_source)) ; + smt_send_rdf(smc,mb,m_fc(mb),SMT_RDF_VERSION,local) ; + smt_free_mbuf(smc,mb) ; + return ; + } + if ((sm->smt_len > mb->sm_len - sizeof(struct smt_header)) || + ((sm->smt_len & 3) && (sm->smt_class != SMT_ECF))) { + DB_SMT("SMT: info length error, len = %d\n",sm->smt_len,0) ; + smt_send_rdf(smc,mb,m_fc(mb),SMT_RDF_LENGTH,local) ; + smt_free_mbuf(smc,mb) ; + return ; + } + switch (sm->smt_class) { + case SMT_NIF : + if (smt_check_para(smc,sm,plist_nif)) { + DB_SMT("SMT: NIF with para problem, ignoring\n",0,0) ; + break ; + } ; + switch (sm->smt_type) { + case SMT_ANNOUNCE : + case SMT_REQUEST : + if (!(fs & C_INDICATOR) && m_fc(mb) == FC_SMT_NSA + && is_broadcast(&sm->smt_dest)) { + struct smt_p_state *st ; + + /* set my UNA */ + if (!is_equal( + &smc->mib.m[MAC0].fddiMACUpstreamNbr, + &sm->smt_source)) { + DB_SMT("SMT : updated my UNA = %s\n", + addr_to_string(&sm->smt_source),0) ; + if (!is_equal(&smc->mib.m[MAC0]. + fddiMACUpstreamNbr,&SMT_Unknown)){ + /* Do not update unknown address */ + smc->mib.m[MAC0].fddiMACOldUpstreamNbr= + smc->mib.m[MAC0].fddiMACUpstreamNbr ; + } + + smc->mib.m[MAC0].fddiMACUpstreamNbr = + sm->smt_source ; + smt_srf_event(smc, + SMT_EVENT_MAC_NEIGHBOR_CHANGE, + INDEX_MAC,0) ; + smt_echo_test(smc,0) ; + } + smc->sm.smt_tvu = smt_get_time() ; + st = (struct smt_p_state *) + sm_to_para(smc,sm,SMT_P_STATE) ; + if (st) { + smc->mib.m[MAC0].fddiMACUNDA_Flag = + (st->st_dupl_addr & SMT_ST_MY_DUPA) ? + TRUE : FALSE ; + update_dac(smc,1) ; + } + } + if ((sm->smt_type == SMT_REQUEST) && + is_individual(&sm->smt_source) && + ((!(fs & A_INDICATOR) && m_fc(mb) == FC_SMT_NSA) || + (m_fc(mb) != FC_SMT_NSA))) { + DB_SMT("SMT : replying to NIF request %s\n", + addr_to_string(&sm->smt_source),0) ; + smt_send_nif(smc,&sm->smt_source, + FC_SMT_INFO, + sm->smt_tid, + SMT_REPLY,local) ; + } + break ; + case SMT_REPLY : + DB_SMT("SMT : received NIF response from %s\n", + addr_to_string(&sm->smt_source),0) ; + if (fs & A_INDICATOR) { + smc->sm.pend[SMT_TID_NIF] = 0 ; + DB_SMT("SMT : duplicate address\n",0,0) ; + smc->mib.m[MAC0].fddiMACDupAddressTest = + DA_FAILED ; + smc->r.dup_addr_test = DA_FAILED ; + queue_event(smc,EVENT_RMT,RM_DUP_ADDR) ; + smc->mib.m[MAC0].fddiMACDA_Flag = TRUE ; + update_dac(smc,1) ; + break ; + } + if (sm->smt_tid == smc->sm.pend[SMT_TID_NIF]) { + smc->sm.pend[SMT_TID_NIF] = 0 ; + /* set my DNA */ + if (!is_equal( + &smc->mib.m[MAC0].fddiMACDownstreamNbr, + &sm->smt_source)) { + DB_SMT("SMT : updated my DNA\n",0,0) ; + if (!is_equal(&smc->mib.m[MAC0]. + fddiMACDownstreamNbr, &SMT_Unknown)){ + /* Do not update unknown address */ + smc->mib.m[MAC0].fddiMACOldDownstreamNbr = + smc->mib.m[MAC0].fddiMACDownstreamNbr ; + } + + smc->mib.m[MAC0].fddiMACDownstreamNbr = + sm->smt_source ; + smt_srf_event(smc, + SMT_EVENT_MAC_NEIGHBOR_CHANGE, + INDEX_MAC,0) ; + smt_echo_test(smc,1) ; + } + smc->mib.m[MAC0].fddiMACDA_Flag = FALSE ; + update_dac(smc,1) ; + smc->sm.smt_tvd = smt_get_time() ; + smc->mib.m[MAC0].fddiMACDupAddressTest = + DA_PASSED ; + if (smc->r.dup_addr_test != DA_PASSED) { + smc->r.dup_addr_test = DA_PASSED ; + queue_event(smc,EVENT_RMT,RM_DUP_ADDR) ; + } + } + else if (sm->smt_tid == + smc->sm.pend[SMT_TID_NIF_TEST]) { + DB_SMT("SMT : NIF test TID ok\n",0,0) ; + } + else { + DB_SMT("SMT : expected TID %lx, got %lx\n", + smc->sm.pend[SMT_TID_NIF],sm->smt_tid) ; + } + break ; + default : + illegal = 2 ; + break ; + } + break ; + case SMT_SIF_CONFIG : /* station information */ + if (sm->smt_type != SMT_REQUEST) + break ; + DB_SMT("SMT : replying to SIF Config request from %s\n", + addr_to_string(&sm->smt_source),0) ; + smt_send_sif_config(smc,&sm->smt_source,sm->smt_tid,local) ; + break ; + case SMT_SIF_OPER : /* station information */ + if (sm->smt_type != SMT_REQUEST) + break ; + DB_SMT("SMT : replying to SIF Operation request from %s\n", + addr_to_string(&sm->smt_source),0) ; + smt_send_sif_operation(smc,&sm->smt_source,sm->smt_tid,local) ; + break ; + case SMT_ECF : /* echo frame */ + switch (sm->smt_type) { + case SMT_REPLY : + smc->mib.priv.fddiPRIVECF_Reply_Rx++ ; + DB_SMT("SMT: received ECF reply from %s\n", + addr_to_string(&sm->smt_source),0) ; + if (sm_to_para(smc,sm,SMT_P_ECHODATA) == 0) { + DB_SMT("SMT: ECHODATA missing\n",0,0) ; + break ; + } + if (sm->smt_tid == smc->sm.pend[SMT_TID_ECF]) { + DB_SMT("SMT : ECF test TID ok\n",0,0) ; + } + else if (sm->smt_tid == smc->sm.pend[SMT_TID_ECF_UNA]) { + DB_SMT("SMT : ECF test UNA ok\n",0,0) ; + } + else if (sm->smt_tid == smc->sm.pend[SMT_TID_ECF_DNA]) { + DB_SMT("SMT : ECF test DNA ok\n",0,0) ; + } + else { + DB_SMT("SMT : expected TID %lx, got %lx\n", + smc->sm.pend[SMT_TID_ECF], + sm->smt_tid) ; + } + break ; + case SMT_REQUEST : + smc->mib.priv.fddiPRIVECF_Req_Rx++ ; + { + if (sm->smt_len && !sm_to_para(smc,sm,SMT_P_ECHODATA)) { + DB_SMT("SMT: ECF with para problem,sending RDF\n",0,0) ; + smt_send_rdf(smc,mb,m_fc(mb),SMT_RDF_LENGTH, + local) ; + break ; + } + DB_SMT("SMT - sending ECF reply to %s\n", + addr_to_string(&sm->smt_source),0) ; + + /* set destination addr. & reply */ + sm->smt_dest = sm->smt_source ; + sm->smt_type = SMT_REPLY ; + dump_smt(smc,sm,"ECF REPLY") ; + smc->mib.priv.fddiPRIVECF_Reply_Tx++ ; + smt_send_frame(smc,mb,FC_SMT_INFO,local) ; + return ; /* DON'T free mbuf */ + } + default : + illegal = 1 ; + break ; + } + break ; +#ifndef BOOT + case SMT_RAF : /* resource allocation */ +#ifdef ESS + DB_ESSN(2,"ESS: RAF frame received\n",0,0) ; + fs = ess_raf_received_pack(smc,mb,sm,fs) ; +#endif + +#ifdef SBA + DB_SBAN(2,"SBA: RAF frame received\n",0,0) ; + sba_raf_received_pack(smc,sm,fs) ; +#endif + break ; + case SMT_RDF : /* request denied */ + smc->mib.priv.fddiPRIVRDF_Rx++ ; + break ; + case SMT_ESF : /* extended service - not supported */ + if (sm->smt_type == SMT_REQUEST) { + DB_SMT("SMT - received ESF, sending RDF\n",0,0) ; + smt_send_rdf(smc,mb,m_fc(mb),SMT_RDF_CLASS,local) ; + } + break ; + case SMT_PMF_GET : + case SMT_PMF_SET : + if (sm->smt_type != SMT_REQUEST) + break ; + /* update statistics */ + if (sm->smt_class == SMT_PMF_GET) + smc->mib.priv.fddiPRIVPMF_Get_Rx++ ; + else + smc->mib.priv.fddiPRIVPMF_Set_Rx++ ; + /* + * ignore PMF SET with I/G set + */ + if ((sm->smt_class == SMT_PMF_SET) && + !is_individual(&sm->smt_dest)) { + DB_SMT("SMT: ignoring PMF-SET with I/G set\n",0,0) ; + break ; + } + smt_pmf_received_pack(smc,mb, local) ; + break ; + case SMT_SRF : + dump_smt(smc,sm,"SRF received") ; + break ; + default : + if (sm->smt_type != SMT_REQUEST) + break ; + /* + * For frames with unknown class: + * we need to send a RDF frame according to 8.1.3.1.1, + * only if it is a REQUEST. + */ + DB_SMT("SMT : class = %d, send RDF to %s\n", + sm->smt_class, addr_to_string(&sm->smt_source)) ; + + smt_send_rdf(smc,mb,m_fc(mb),SMT_RDF_CLASS,local) ; + break ; +#endif + } + if (illegal) { + DB_SMT("SMT: discarding illegal frame, reason = %d\n", + illegal,0) ; + } + smt_free_mbuf(smc,mb) ; +} + +static void update_dac(smc,report) +struct s_smc *smc ; +int report ; +{ + int cond ; + + cond = ( smc->mib.m[MAC0].fddiMACUNDA_Flag | + smc->mib.m[MAC0].fddiMACDA_Flag) != 0 ; + if (report && (cond != smc->mib.m[MAC0].fddiMACDuplicateAddressCond)) + smt_srf_event(smc, SMT_COND_MAC_DUP_ADDR,INDEX_MAC,cond) ; + else + smc->mib.m[MAC0].fddiMACDuplicateAddressCond = cond ; +} + +/* + * send SMT frame + * set source address + * set station ID + * send frame + */ +EXPORT_PMF void smt_send_frame(smc,mb,fc,local) +struct s_smc *smc ; +SMbuf *mb ; /* buffer to send */ +int fc ; /* FC value */ +int local ; +{ + struct smt_header *sm ; + + if (!smc->r.sm_ma_avail && !local) { + smt_free_mbuf(smc,mb) ; + return ; + } + sm = smtod(mb,struct smt_header *) ; + sm->smt_source = smc->mib.m[MAC0].fddiMACSMTAddress ; + sm->smt_sid = smc->mib.fddiSMTStationId ; + + smt_swap_para(sm,(int) mb->sm_len,0) ; /* swap para & header */ + hwm_conv_can(smc,(char *)sm,12) ; /* convert SA and DA */ + smc->mib.m[MAC0].fddiMACSMTTransmit_Ct++ ; + smt_send_mbuf(smc,mb,local ? FC_SMT_LOC : fc) ; +} + +/* + * generate and send RDF + */ +static void smt_send_rdf(smc,rej,fc,reason,local) +struct s_smc *smc ; +SMbuf *rej ; /* mbuf of offending frame */ +int fc ; /* FC of denied frame */ +int reason ; /* reason code */ +int local ; +{ + SMbuf *mb ; + struct smt_header *sm ; /* header of offending frame */ + struct smt_rdf *rdf ; + int len ; + int frame_len ; + + sm = smtod(rej,struct smt_header *) ; + if (sm->smt_type != SMT_REQUEST) + return ; + + DB_SMT("SMT: sending RDF to %s,reason = 0x%x\n", + addr_to_string(&sm->smt_source),reason) ; + + + /* + * note: get framelength from MAC length, NOT from SMT header + * smt header length is included in sm_len + */ + frame_len = rej->sm_len ; + + if (!(mb=smt_build_frame(smc,SMT_RDF,SMT_REPLY,sizeof(struct smt_rdf)))) + return ; + rdf = smtod(mb,struct smt_rdf *) ; + rdf->smt.smt_tid = sm->smt_tid ; /* use TID from sm */ + rdf->smt.smt_dest = sm->smt_source ; /* set dest = source */ + + /* set P12 */ + rdf->reason.para.p_type = SMT_P_REASON ; + rdf->reason.para.p_len = sizeof(struct smt_p_reason) - PARA_LEN ; + rdf->reason.rdf_reason = reason ; + + /* set P14 */ + rdf->version.para.p_type = SMT_P_VERSION ; + rdf->version.para.p_len = sizeof(struct smt_p_version) - PARA_LEN ; + rdf->version.v_pad = 0 ; + rdf->version.v_n = 1 ; + rdf->version.v_index = 1 ; + rdf->version.v_version[0] = SMT_VID_2 ; + rdf->version.v_pad2 = 0 ; + + /* set P13 */ + if ((unsigned) frame_len <= SMT_MAX_INFO_LEN - sizeof(*rdf) + + 2*sizeof(struct smt_header)) + len = frame_len ; + else + len = SMT_MAX_INFO_LEN - sizeof(*rdf) + + 2*sizeof(struct smt_header) ; + /* make length multiple of 4 */ + len &= ~3 ; + rdf->refused.para.p_type = SMT_P_REFUSED ; + /* length of para is smt_frame + ref_fc */ + rdf->refused.para.p_len = len + 4 ; + rdf->refused.ref_fc = fc ; + + /* swap it back */ + smt_swap_para(sm,frame_len,0) ; + + memcpy((char *) &rdf->refused.ref_header,(char *) sm,len) ; + + len -= sizeof(struct smt_header) ; + mb->sm_len += len ; + rdf->smt.smt_len += len ; + + dump_smt(smc,(struct smt_header *)rdf,"RDF") ; + smc->mib.priv.fddiPRIVRDF_Tx++ ; + smt_send_frame(smc,mb,FC_SMT_INFO,local) ; +} + +/* + * generate and send NIF + */ +static void smt_send_nif(smc,dest,fc,tid,type,local) +struct s_smc *smc ; +struct fddi_addr *dest ; /* dest address */ +int fc ; /* frame control */ +u_long tid ; /* transaction id */ +int type ; /* frame type */ +int local ; +{ + struct smt_nif *nif ; + SMbuf *mb ; + + if (!(mb = smt_build_frame(smc,SMT_NIF,type,sizeof(struct smt_nif)))) + return ; + nif = smtod(mb, struct smt_nif *) ; + smt_fill_una(smc,&nif->una) ; /* set UNA */ + smt_fill_sde(smc,&nif->sde) ; /* set station descriptor */ + smt_fill_state(smc,&nif->state) ; /* set state information */ +#ifdef SMT6_10 + smt_fill_fsc(smc,&nif->fsc) ; /* set frame status cap. */ +#endif + nif->smt.smt_dest = *dest ; /* destination address */ + nif->smt.smt_tid = tid ; /* transaction ID */ + dump_smt(smc,(struct smt_header *)nif,"NIF") ; + smt_send_frame(smc,mb,fc,local) ; +} + +#ifdef DEBUG +/* + * send NIF request (test purpose) + */ +static void smt_send_nif_request(smc,dest) +struct s_smc *smc ; +struct fddi_addr *dest ; +{ + smc->sm.pend[SMT_TID_NIF_TEST] = smt_get_tid(smc) ; + smt_send_nif(smc,dest, FC_SMT_INFO, smc->sm.pend[SMT_TID_NIF_TEST], + SMT_REQUEST,0) ; +} + +/* + * send ECF request (test purpose) + */ +static void smt_send_ecf_request(smc,dest,len) +struct s_smc *smc ; +struct fddi_addr *dest ; +int len ; +{ + smc->sm.pend[SMT_TID_ECF] = smt_get_tid(smc) ; + smt_send_ecf(smc,dest, FC_SMT_INFO, smc->sm.pend[SMT_TID_ECF], + SMT_REQUEST,len) ; +} +#endif + +/* + * echo test + */ +static void smt_echo_test(smc,dna) +struct s_smc *smc ; +int dna ; +{ + u_long tid ; + + smc->sm.pend[dna ? SMT_TID_ECF_DNA : SMT_TID_ECF_UNA] = + tid = smt_get_tid(smc) ; + smt_send_ecf(smc, dna ? + &smc->mib.m[MAC0].fddiMACDownstreamNbr : + &smc->mib.m[MAC0].fddiMACUpstreamNbr, + FC_SMT_INFO,tid, SMT_REQUEST, (SMT_TEST_ECHO_LEN & ~3)-8) ; +} + +/* + * generate and send ECF + */ +static void smt_send_ecf(smc,dest,fc,tid,type,len) +struct s_smc *smc ; +struct fddi_addr *dest ; /* dest address */ +int fc ; /* frame control */ +u_long tid ; /* transaction id */ +int type ; /* frame type */ +int len ; /* frame length */ +{ + struct smt_ecf *ecf ; + SMbuf *mb ; + + if (!(mb = smt_build_frame(smc,SMT_ECF,type,SMT_ECF_LEN + len))) + return ; + ecf = smtod(mb, struct smt_ecf *) ; + + smt_fill_echo(smc,&ecf->ec_echo,tid,len) ; /* set ECHO */ + ecf->smt.smt_dest = *dest ; /* destination address */ + ecf->smt.smt_tid = tid ; /* transaction ID */ + smc->mib.priv.fddiPRIVECF_Req_Tx++ ; + smt_send_frame(smc,mb,fc,0) ; +} + +/* + * generate and send SIF config response + */ + +static void smt_send_sif_config(smc,dest,tid,local) +struct s_smc *smc ; +struct fddi_addr *dest ; /* dest address */ +u_long tid ; /* transaction id */ +int local ; +{ + struct smt_sif_config *sif ; + SMbuf *mb ; + int len ; + if (!(mb = smt_build_frame(smc,SMT_SIF_CONFIG,SMT_REPLY, + SIZEOF_SMT_SIF_CONFIG))) + return ; + + sif = smtod(mb, struct smt_sif_config *) ; + smt_fill_timestamp(smc,&sif->ts) ; /* set time stamp */ + smt_fill_sde(smc,&sif->sde) ; /* set station descriptor */ + smt_fill_version(smc,&sif->version) ; /* set version information */ + smt_fill_state(smc,&sif->state) ; /* set state information */ + smt_fill_policy(smc,&sif->policy) ; /* set station policy */ + smt_fill_latency(smc,&sif->latency); /* set station latency */ + smt_fill_neighbor(smc,&sif->neighbor); /* set station neighbor */ + smt_fill_setcount(smc,&sif->setcount) ; /* set count */ + len = smt_fill_path(smc,&sif->path); /* set station path descriptor*/ + sif->smt.smt_dest = *dest ; /* destination address */ + sif->smt.smt_tid = tid ; /* transaction ID */ + smt_add_frame_len(mb,len) ; /* adjust length fields */ + dump_smt(smc,(struct smt_header *)sif,"SIF Configuration Reply") ; + smt_send_frame(smc,mb,FC_SMT_INFO,local) ; +} + +/* + * generate and send SIF operation response + */ + +static void smt_send_sif_operation(smc,dest,tid,local) +struct s_smc *smc ; +struct fddi_addr *dest ; /* dest address */ +u_long tid ; /* transaction id */ +int local ; +{ + struct smt_sif_operation *sif ; + SMbuf *mb ; + int ports ; + int i ; + + ports = NUMPHYS ; +#ifndef CONCENTRATOR + if (smc->s.sas == SMT_SAS) + ports = 1 ; +#endif + + if (!(mb = smt_build_frame(smc,SMT_SIF_OPER,SMT_REPLY, + SIZEOF_SMT_SIF_OPERATION+ports*sizeof(struct smt_p_lem)))) + return ; + sif = smtod(mb, struct smt_sif_operation *) ; + smt_fill_timestamp(smc,&sif->ts) ; /* set time stamp */ + smt_fill_mac_status(smc,&sif->status) ; /* set mac status */ + smt_fill_mac_counter(smc,&sif->mc) ; /* set mac counter field */ + smt_fill_mac_fnc(smc,&sif->fnc) ; /* set frame not copied counter */ + smt_fill_manufacturer(smc,&sif->man) ; /* set manufacturer field */ + smt_fill_user(smc,&sif->user) ; /* set user field */ + smt_fill_setcount(smc,&sif->setcount) ; /* set count */ + /* + * set link error mon information + */ + if (ports == 1) { + smt_fill_lem(smc,sif->lem,PS) ; + } + else { + for (i = 0 ; i < ports ; i++) { + smt_fill_lem(smc,&sif->lem[i],i) ; + } + } + + sif->smt.smt_dest = *dest ; /* destination address */ + sif->smt.smt_tid = tid ; /* transaction ID */ + dump_smt(smc,(struct smt_header *)sif,"SIF Operation Reply") ; + smt_send_frame(smc,mb,FC_SMT_INFO,local) ; +} + +/* + * get and initialize SMT frame + */ +EXPORT_PMF SMbuf *smt_build_frame(smc,class,type,length) +struct s_smc *smc ; +int class ; +int type ; +int length ; +{ + SMbuf *mb ; + struct smt_header *smt ; + +#if 0 + if (!smc->r.sm_ma_avail) { + return(0) ; + } +#endif + if (!(mb = smt_get_mbuf(smc))) + return(mb) ; + + mb->sm_len = length ; + smt = smtod(mb, struct smt_header *) ; + smt->smt_dest = fddi_broadcast ; /* set dest = broadcast */ + smt->smt_class = class ; + smt->smt_type = type ; + switch (class) { + case SMT_NIF : + case SMT_SIF_CONFIG : + case SMT_SIF_OPER : + case SMT_ECF : + smt->smt_version = SMT_VID ; + break ; + default : + smt->smt_version = SMT_VID_2 ; + break ; + } + smt->smt_tid = smt_get_tid(smc) ; /* set transaction ID */ + smt->smt_pad = 0 ; + smt->smt_len = length - sizeof(struct smt_header) ; + return(mb) ; +} + +static void smt_add_frame_len(mb,len) +SMbuf *mb ; +int len ; +{ + struct smt_header *smt ; + + smt = smtod(mb, struct smt_header *) ; + smt->smt_len += len ; + mb->sm_len += len ; +} + + + +/* + * fill values in UNA parameter + */ +static void smt_fill_una(smc,una) +struct s_smc *smc ; +struct smt_p_una *una ; +{ + SMTSETPARA(una,SMT_P_UNA) ; + una->una_pad = 0 ; + una->una_node = smc->mib.m[MAC0].fddiMACUpstreamNbr ; +} + +/* + * fill values in SDE parameter + */ +static void smt_fill_sde(smc,sde) +struct s_smc *smc ; +struct smt_p_sde *sde ; +{ + SMTSETPARA(sde,SMT_P_SDE) ; + sde->sde_non_master = smc->mib.fddiSMTNonMaster_Ct ; + sde->sde_master = smc->mib.fddiSMTMaster_Ct ; + sde->sde_mac_count = NUMMACS ; /* only 1 MAC */ +#ifdef CONCENTRATOR + sde->sde_type = SMT_SDE_CONCENTRATOR ; +#else + sde->sde_type = SMT_SDE_STATION ; +#endif +} + +/* + * fill in values in station state parameter + */ +static void smt_fill_state(smc,state) +struct s_smc *smc ; +struct smt_p_state *state ; +{ + int top ; + int twist ; + + SMTSETPARA(state,SMT_P_STATE) ; + state->st_pad = 0 ; + + /* determine topology */ + top = 0 ; + if (smc->mib.fddiSMTPeerWrapFlag) { + top |= SMT_ST_WRAPPED ; /* state wrapped */ + } +#ifdef CONCENTRATOR + if (cfm_status_unattached(smc)) { + top |= SMT_ST_UNATTACHED ; /* unattached concentrator */ + } +#endif + if ((twist = pcm_status_twisted(smc)) & 1) { + top |= SMT_ST_TWISTED_A ; /* twisted cable */ + } + if (twist & 2) { + top |= SMT_ST_TWISTED_B ; /* twisted cable */ + } +#ifdef OPT_SRF + top |= SMT_ST_SRF ; +#endif + if (pcm_rooted_station(smc)) + top |= SMT_ST_ROOTED_S ; + if (smc->mib.a[0].fddiPATHSbaPayload != 0) + top |= SMT_ST_SYNC_SERVICE ; + state->st_topology = top ; + state->st_dupl_addr = + ((smc->mib.m[MAC0].fddiMACDA_Flag ? SMT_ST_MY_DUPA : 0 ) | + (smc->mib.m[MAC0].fddiMACUNDA_Flag ? SMT_ST_UNA_DUPA : 0)) ; +} + +/* + * fill values in timestamp parameter + */ +static void smt_fill_timestamp(smc,ts) +struct s_smc *smc ; +struct smt_p_timestamp *ts ; +{ + + SMTSETPARA(ts,SMT_P_TIMESTAMP) ; + smt_set_timestamp(smc,ts->ts_time) ; +} + +EXPORT_PMF void smt_set_timestamp(smc,p) +struct s_smc *smc ; +u_char *p ; +{ + u_long time ; + u_long utime ; + + /* + * timestamp is 64 bits long ; resolution is 80 nS + * our clock resolution is 10mS + * 10mS/80ns = 125000 ~ 2^17 = 131072 + */ + utime = smt_get_time() ; + time = utime * 100 ; + time /= TICKS_PER_SECOND ; + p[0] = 0 ; + p[1] = (u_char)((time>>(8+8+8+8-1)) & 1) ; + p[2] = (u_char)(time>>(8+8+8-1)) ; + p[3] = (u_char)(time>>(8+8-1)) ; + p[4] = (u_char)(time>>(8-1)) ; + p[5] = (u_char)(time<<1) ; + p[6] = (u_char)(smc->sm.uniq_ticks>>8) ; + p[7] = (u_char)smc->sm.uniq_ticks ; + /* + * make sure we don't wrap: restart whenever the upper digits change + */ + if (utime != smc->sm.uniq_time) { + smc->sm.uniq_ticks = 0 ; + } + smc->sm.uniq_ticks++ ; + smc->sm.uniq_time = utime ; +} + +/* + * fill values in station policy parameter + */ +static void smt_fill_policy(smc,policy) +struct s_smc *smc ; +struct smt_p_policy *policy ; +{ + int i ; + u_char *map ; + u_short in ; + u_short out ; + + /* + * MIB para 101b (fddiSMTConnectionPolicy) coding + * is different from 0005 coding + */ + static u_char ansi_weirdness[16] = { + 0,7,5,3,8,1,6,4,9,10,2,11,12,13,14,15 + } ; + SMTSETPARA(policy,SMT_P_POLICY) ; + + out = 0 ; + in = smc->mib.fddiSMTConnectionPolicy ; + for (i = 0, map = ansi_weirdness ; i < 16 ; i++) { + if (in & 1) + out |= (1<<*map) ; + in >>= 1 ; + map++ ; + } + policy->pl_config = smc->mib.fddiSMTConfigPolicy ; + policy->pl_connect = out ; +} + +/* + * fill values in latency equivalent parameter + */ +static void smt_fill_latency(smc,latency) +struct s_smc *smc ; +struct smt_p_latency *latency ; +{ + SMTSETPARA(latency,SMT_P_LATENCY) ; + + latency->lt_phyout_idx1 = phy_index(smc,0) ; + latency->lt_latency1 = 10 ; /* in octets (byte clock) */ + /* + * note: latency has two phy entries by definition + * for a SAS, the 2nd one is null + */ + if (smc->s.sas == SMT_DAS) { + latency->lt_phyout_idx2 = phy_index(smc,1) ; + latency->lt_latency2 = 10 ; /* in octets (byte clock) */ + } + else { + latency->lt_phyout_idx2 = 0 ; + latency->lt_latency2 = 0 ; + } +} + +/* + * fill values in MAC neighbors parameter + */ +static void smt_fill_neighbor(smc,neighbor) +struct s_smc *smc ; +struct smt_p_neighbor *neighbor ; +{ + SMTSETPARA(neighbor,SMT_P_NEIGHBORS) ; + + neighbor->nb_mib_index = INDEX_MAC ; + neighbor->nb_mac_index = mac_index(smc,1) ; + neighbor->nb_una = smc->mib.m[MAC0].fddiMACUpstreamNbr ; + neighbor->nb_dna = smc->mib.m[MAC0].fddiMACDownstreamNbr ; +} + +/* + * fill values in path descriptor + */ +#ifdef CONCENTRATOR +#define ALLPHYS NUMPHYS +#else +#define ALLPHYS ((smc->s.sas == SMT_SAS) ? 1 : 2) +#endif + +static int smt_fill_path(smc,path) +struct s_smc *smc ; +struct smt_p_path *path ; +{ + SK_LOC_DECL(int,type) ; + SK_LOC_DECL(int,state) ; + SK_LOC_DECL(int,remote) ; + SK_LOC_DECL(int,mac) ; + int len ; + int p ; + int physp ; + struct smt_phy_rec *phy ; + struct smt_mac_rec *pd_mac ; + + len = PARA_LEN + + sizeof(struct smt_mac_rec) * NUMMACS + + sizeof(struct smt_phy_rec) * ALLPHYS ; + path->para.p_type = SMT_P_PATH ; + path->para.p_len = len - PARA_LEN ; + + /* PHYs */ + for (p = 0,phy = path->pd_phy ; p < ALLPHYS ; p++, phy++) { + physp = p ; +#ifndef CONCENTRATOR + if (smc->s.sas == SMT_SAS) + physp = PS ; +#endif + pcm_status_state(smc,physp,&type,&state,&remote,&mac) ; +#ifdef LITTLE_ENDIAN + phy->phy_mib_index = smt_swap_short((u_short)p+INDEX_PORT) ; +#else + phy->phy_mib_index = p+INDEX_PORT ; +#endif + phy->phy_type = type ; + phy->phy_connect_state = state ; + phy->phy_remote_type = remote ; + phy->phy_remote_mac = mac ; + phy->phy_resource_idx = phy_con_resource_index(smc,p) ; + } + + /* MAC */ + pd_mac = (struct smt_mac_rec *) phy ; + pd_mac->mac_addr = smc->mib.m[MAC0].fddiMACSMTAddress ; + pd_mac->mac_resource_idx = mac_con_resource_index(smc,1) ; + return(len) ; +} + +/* + * fill values in mac status + */ +static void smt_fill_mac_status(smc,st) +struct s_smc *smc ; +struct smt_p_mac_status *st ; +{ + SMTSETPARA(st,SMT_P_MAC_STATUS) ; + + st->st_mib_index = INDEX_MAC ; + st->st_mac_index = mac_index(smc,1) ; + + mac_update_counter(smc) ; + /* + * timer values are represented in SMT as 2's complement numbers + * units : internal : 2's complement BCLK + */ + st->st_t_req = smc->mib.m[MAC0].fddiMACT_Req ; + st->st_t_neg = smc->mib.m[MAC0].fddiMACT_Neg ; + st->st_t_max = smc->mib.m[MAC0].fddiMACT_Max ; + st->st_tvx_value = smc->mib.m[MAC0].fddiMACTvxValue ; + st->st_t_min = smc->mib.m[MAC0].fddiMACT_Min ; + + st->st_sba = smc->mib.a[PATH0].fddiPATHSbaPayload ; + st->st_frame_ct = smc->mib.m[MAC0].fddiMACFrame_Ct ; + st->st_error_ct = smc->mib.m[MAC0].fddiMACError_Ct ; + st->st_lost_ct = smc->mib.m[MAC0].fddiMACLost_Ct ; +} + +/* + * fill values in LEM status + */ + +static void smt_fill_lem(smc,lem,phy) +struct s_smc *smc ; +struct smt_p_lem *lem ; +int phy ; +{ + struct fddi_mib_p *mib ; + + mib = smc->y[phy].mib ; + + SMTSETPARA(lem,SMT_P_LEM) ; + lem->lem_mib_index = phy+INDEX_PORT ; + lem->lem_phy_index = phy_index(smc,phy) ; + lem->lem_pad2 = 0 ; + lem->lem_cutoff = mib->fddiPORTLer_Cutoff ; + lem->lem_alarm = mib->fddiPORTLer_Alarm ; + /* long term bit error rate */ + lem->lem_estimate = mib->fddiPORTLer_Estimate ; + /* # of rejected connections */ + lem->lem_reject_ct = mib->fddiPORTLem_Reject_Ct ; + lem->lem_ct = mib->fddiPORTLem_Ct ; /* total number of errors */ +} + +/* + * fill version parameter + */ +static void smt_fill_version(smc,vers) +struct s_smc *smc ; +struct smt_p_version *vers ; +{ + SK_UNUSED(smc) ; + SMTSETPARA(vers,SMT_P_VERSION) ; + vers->v_pad = 0 ; + vers->v_n = 1 ; /* one version is enough .. */ + vers->v_index = 1 ; + vers->v_version[0] = SMT_VID_2 ; + vers->v_pad2 = 0 ; +} + +#ifdef SMT6_10 +/* + * fill frame status capabilities + */ +/* + * note: this para 200B is NOT in swap table, because it's also set in + * PMF add_para + */ +static void smt_fill_fsc(smc,fsc) +struct s_smc *smc ; +struct smt_p_fsc *fsc ; +{ + SK_UNUSED(smc) ; + SMTSETPARA(fsc,SMT_P_FSC) ; + fsc->fsc_pad0 = 0 ; + fsc->fsc_mac_index = INDEX_MAC ; /* this is MIB ; MIB is NOT + * mac_index ()i ! + */ + fsc->fsc_pad1 = 0 ; + fsc->fsc_value = FSC_TYPE0 ; /* "normal" node */ +#ifdef LITTLE_ENDIAN + fsc->fsc_mac_index = smt_swap_short(INDEX_MAC) ; + fsc->fsc_value = smt_swap_short(FSC_TYPE0) ; +#endif +} +#endif + +/* + * fill mac counter field + */ +static void smt_fill_mac_counter(smc,mc) +struct s_smc *smc ; +struct smt_p_mac_counter *mc ; +{ + SMTSETPARA(mc,SMT_P_MAC_COUNTER) ; + mc->mc_mib_index = INDEX_MAC ; + mc->mc_index = mac_index(smc,1) ; + mc->mc_receive_ct = smc->mib.m[MAC0].fddiMACCopied_Ct ; + mc->mc_transmit_ct = smc->mib.m[MAC0].fddiMACTransmit_Ct ; +} + +/* + * fill mac frame not copied counter + */ +static void smt_fill_mac_fnc(smc,fnc) +struct s_smc *smc ; +struct smt_p_mac_fnc *fnc ; +{ + SMTSETPARA(fnc,SMT_P_MAC_FNC) ; + fnc->nc_mib_index = INDEX_MAC ; + fnc->nc_index = mac_index(smc,1) ; + fnc->nc_counter = smc->mib.m[MAC0].fddiMACNotCopied_Ct ; +} + + +/* + * fill manufacturer field + */ +static void smt_fill_manufacturer(smc,man) +struct s_smc *smc ; +struct smp_p_manufacturer *man ; +{ + SMTSETPARA(man,SMT_P_MANUFACTURER) ; + memcpy((char *) man->mf_data, + (char *) smc->mib.fddiSMTManufacturerData, + sizeof(man->mf_data)) ; +} + +/* + * fill user field + */ +static void smt_fill_user(smc,user) +struct s_smc *smc ; +struct smp_p_user *user ; +{ + SMTSETPARA(user,SMT_P_USER) ; + memcpy((char *) user->us_data, + (char *) smc->mib.fddiSMTUserData, + sizeof(user->us_data)) ; +} + + + +/* + * fill set count + */ +static void smt_fill_setcount(smc,setcount) +struct s_smc *smc ; +struct smt_p_setcount *setcount ; +{ + SK_UNUSED(smc) ; + SMTSETPARA(setcount,SMT_P_SETCOUNT) ; + setcount->count = smc->mib.fddiSMTSetCount.count ; + memcpy((char *)setcount->timestamp, + (char *)smc->mib.fddiSMTSetCount.timestamp,8) ; +} + +/* + * fill echo data + */ +static void smt_fill_echo(smc,echo,seed,len) +struct s_smc *smc ; +struct smt_p_echo *echo ; +u_long seed ; +int len ; +{ + + u_char *p ; + + SK_UNUSED(smc) ; + SMTSETPARA(echo,SMT_P_ECHODATA) ; + echo->para.p_len = len ; + for (p = echo->ec_data ; len ; len--) { + *p++ = (u_char) seed ; + seed += 13 ; + } +} + +/* + * clear DNA and UNA + * called from CFM if configuration changes + */ +void smt_clear_una_dna(smc) +struct s_smc *smc ; +{ + smc->mib.m[MAC0].fddiMACUpstreamNbr = SMT_Unknown ; + smc->mib.m[MAC0].fddiMACDownstreamNbr = SMT_Unknown ; +} + +static void smt_clear_old_una_dna(smc) +struct s_smc *smc ; +{ + smc->mib.m[MAC0].fddiMACOldUpstreamNbr = SMT_Unknown ; + smc->mib.m[MAC0].fddiMACOldDownstreamNbr = SMT_Unknown ; +} + +u_long smt_get_tid(smc) +struct s_smc *smc ; +{ + u_long tid ; + while ((tid = ++(smc->sm.smt_tid) ^ SMT_TID_MAGIC) == 0) + ; + return(tid & 0x3fffffffL) ; +} + + +/* + * table of parameter lengths + */ +static const struct smt_pdef { + int ptype ; + int plen ; + const char *pswap ; +} smt_pdef[] = { + { SMT_P_UNA, sizeof(struct smt_p_una) , + SWAP_SMT_P_UNA } , + { SMT_P_SDE, sizeof(struct smt_p_sde) , + SWAP_SMT_P_SDE } , + { SMT_P_STATE, sizeof(struct smt_p_state) , + SWAP_SMT_P_STATE } , + { SMT_P_TIMESTAMP,sizeof(struct smt_p_timestamp) , + SWAP_SMT_P_TIMESTAMP } , + { SMT_P_POLICY, sizeof(struct smt_p_policy) , + SWAP_SMT_P_POLICY } , + { SMT_P_LATENCY, sizeof(struct smt_p_latency) , + SWAP_SMT_P_LATENCY } , + { SMT_P_NEIGHBORS,sizeof(struct smt_p_neighbor) , + SWAP_SMT_P_NEIGHBORS } , + { SMT_P_PATH, sizeof(struct smt_p_path) , + SWAP_SMT_P_PATH } , + { SMT_P_MAC_STATUS,sizeof(struct smt_p_mac_status) , + SWAP_SMT_P_MAC_STATUS } , + { SMT_P_LEM, sizeof(struct smt_p_lem) , + SWAP_SMT_P_LEM } , + { SMT_P_MAC_COUNTER,sizeof(struct smt_p_mac_counter) , + SWAP_SMT_P_MAC_COUNTER } , + { SMT_P_MAC_FNC,sizeof(struct smt_p_mac_fnc) , + SWAP_SMT_P_MAC_FNC } , + { SMT_P_PRIORITY,sizeof(struct smt_p_priority) , + SWAP_SMT_P_PRIORITY } , + { SMT_P_EB,sizeof(struct smt_p_eb) , + SWAP_SMT_P_EB } , + { SMT_P_MANUFACTURER,sizeof(struct smp_p_manufacturer) , + SWAP_SMT_P_MANUFACTURER } , + { SMT_P_REASON, sizeof(struct smt_p_reason) , + SWAP_SMT_P_REASON } , + { SMT_P_REFUSED, sizeof(struct smt_p_refused) , + SWAP_SMT_P_REFUSED } , + { SMT_P_VERSION, sizeof(struct smt_p_version) , + SWAP_SMT_P_VERSION } , +#ifdef ESS + { SMT_P0015, sizeof(struct smt_p_0015) , SWAP_SMT_P0015 } , + { SMT_P0016, sizeof(struct smt_p_0016) , SWAP_SMT_P0016 } , + { SMT_P0017, sizeof(struct smt_p_0017) , SWAP_SMT_P0017 } , + { SMT_P0018, sizeof(struct smt_p_0018) , SWAP_SMT_P0018 } , + { SMT_P0019, sizeof(struct smt_p_0019) , SWAP_SMT_P0019 } , + { SMT_P001A, sizeof(struct smt_p_001a) , SWAP_SMT_P001A } , + { SMT_P001B, sizeof(struct smt_p_001b) , SWAP_SMT_P001B } , + { SMT_P001C, sizeof(struct smt_p_001c) , SWAP_SMT_P001C } , + { SMT_P001D, sizeof(struct smt_p_001d) , SWAP_SMT_P001D } , +#endif +#if 0 + { SMT_P_FSC, sizeof(struct smt_p_fsc) , + SWAP_SMT_P_FSC } , +#endif + + { SMT_P_SETCOUNT,0, SWAP_SMT_P_SETCOUNT } , + { SMT_P1048, 0, SWAP_SMT_P1048 } , + { SMT_P208C, 0, SWAP_SMT_P208C } , + { SMT_P208D, 0, SWAP_SMT_P208D } , + { SMT_P208E, 0, SWAP_SMT_P208E } , + { SMT_P208F, 0, SWAP_SMT_P208F } , + { SMT_P2090, 0, SWAP_SMT_P2090 } , +#ifdef ESS + { SMT_P320B, sizeof(struct smt_p_320b) , SWAP_SMT_P320B } , + { SMT_P320F, sizeof(struct smt_p_320f) , SWAP_SMT_P320F } , + { SMT_P3210, sizeof(struct smt_p_3210) , SWAP_SMT_P3210 } , +#endif + { SMT_P4050, 0, SWAP_SMT_P4050 } , + { SMT_P4051, 0, SWAP_SMT_P4051 } , + { SMT_P4052, 0, SWAP_SMT_P4052 } , + { SMT_P4053, 0, SWAP_SMT_P4053 } , +} ; + +#define N_SMT_PLEN (sizeof(smt_pdef)/sizeof(smt_pdef[0])) + +int smt_check_para(smc,sm,list) +struct s_smc *smc ; +struct smt_header *sm ; +const u_short list[] ; +{ + const u_short *p = list ; + while (*p) { + if (!sm_to_para(smc,sm,(int) *p)) { + DB_SMT("SMT: smt_check_para - missing para %x\n",*p,0); + return(-1) ; + } + p++ ; + } + return(0) ; +} + +EXPORT_PMF void *sm_to_para(smc,sm,para) +struct s_smc *smc ; +struct smt_header *sm ; +int para ; +{ + char *p ; + int len ; + int plen ; + void *found = 0 ; + + SK_UNUSED(smc) ; + + len = sm->smt_len ; + p = (char *)(sm+1) ; /* pointer to info */ + while (len > 0 ) { + if (((struct smt_para *)p)->p_type == para) + found = (void *) p ; + plen = ((struct smt_para *)p)->p_len + PARA_LEN ; + p += plen ; + len -= plen ; + if (len < 0) { + DB_SMT("SMT : sm_to_para - length error %d\n",plen,0) ; + return(0) ; + } + if ((plen & 3) && (para != SMT_P_ECHODATA)) { + DB_SMT("SMT : sm_to_para - odd length %d\n",plen,0) ; + return(0) ; + } + if (found) + return(found) ; + } + return(0) ; +} + +int is_my_addr(smc,addr) +struct s_smc *smc ; +struct fddi_addr *addr ; +{ + return(*(short *)(&addr->a[0]) == + *(short *)(&smc->mib.m[MAC0].fddiMACSMTAddress.a[0]) + && *(short *)(&addr->a[2]) == + *(short *)(&smc->mib.m[MAC0].fddiMACSMTAddress.a[2]) + && *(short *)(&addr->a[4]) == + *(short *)(&smc->mib.m[MAC0].fddiMACSMTAddress.a[4])) ; +} + +int is_zero(addr) +struct fddi_addr *addr ; +{ + return(*(short *)(&addr->a[0]) == 0 && + *(short *)(&addr->a[2]) == 0 && + *(short *)(&addr->a[4]) == 0 ) ; +} + +int is_broadcast(addr) +struct fddi_addr *addr ; +{ + return(*(u_short *)(&addr->a[0]) == 0xffff && + *(u_short *)(&addr->a[2]) == 0xffff && + *(u_short *)(&addr->a[4]) == 0xffff ) ; +} + +int is_individual(addr) +struct fddi_addr *addr ; +{ + return(!(addr->a[0] & GROUP_ADDR)) ; +} + +int is_equal(addr1,addr2) +struct fddi_addr *addr1 ; +struct fddi_addr *addr2 ; +{ + return(*(u_short *)(&addr1->a[0]) == *(u_short *)(&addr2->a[0]) && + *(u_short *)(&addr1->a[2]) == *(u_short *)(&addr2->a[2]) && + *(u_short *)(&addr1->a[4]) == *(u_short *)(&addr2->a[4]) ) ; +} + + +#if 0 +/* + * send ANTC data test frame + */ +void fddi_send_antc(smc,dest) +struct s_smc *smc ; +struct fddi_addr *dest ; +{ + SK_UNUSED(smc) ; + SK_UNUSED(dest) ; +#if 0 + SMbuf *mb ; + struct smt_header *smt ; + int i ; + char *p ; + + mb = smt_get_mbuf() ; + mb->sm_len = 3000+12 ; + p = smtod(mb, char *) + 12 ; + for (i = 0 ; i < 3000 ; i++) + *p++ = 1 << (i&7) ; + + smt = smtod(mb, struct smt_header *) ; + smt->smt_dest = *dest ; + smt->smt_source = smc->mib.m[MAC0].fddiMACSMTAddress ; + smt_send_mbuf(smc,mb,FC_ASYNC_LLC) ; +#endif +} +#endif + +#ifdef DEBUG +#define hextoasc(x) "0123456789abcdef"[x] + +char *addr_to_string(addr) +struct fddi_addr *addr ; +{ + int i ; + static char string[6*3] = "****" ; + + for (i = 0 ; i < 6 ; i++) { + string[i*3] = hextoasc((addr->a[i]>>4)&0xf) ; + string[i*3+1] = hextoasc((addr->a[i])&0xf) ; + string[i*3+2] = ':' ; + } + string[5*3+2] = 0 ; + return(string) ; +} +#endif + +#ifdef AM29K +smt_ifconfig(argc,argv) +int argc ; +char *argv[] ; +{ + if (argc >= 2 && !strcmp(argv[0],"opt_bypass") && + !strcmp(argv[1],"yes")) { + smc->mib.fddiSMTBypassPresent = 1 ; + return(0) ; + } + return(amdfddi_config(0,argc,argv)) ; +} +#endif + +/* + * return static mac index + */ +static int mac_index(smc,mac) +struct s_smc *smc ; +int mac ; +{ + SK_UNUSED(mac) ; +#ifdef CONCENTRATOR + SK_UNUSED(smc) ; + return(NUMPHYS+1) ; +#else + return((smc->s.sas == SMT_SAS) ? 2 : 3) ; +#endif +} + +/* + * return static phy index + */ +static int phy_index(smc,phy) +struct s_smc *smc ; +int phy ; +{ + SK_UNUSED(smc) ; + return(phy+1); +} + +/* + * return dynamic mac connection resource index + */ +static int mac_con_resource_index(smc,mac) +struct s_smc *smc ; +int mac ; +{ +#ifdef CONCENTRATOR + SK_UNUSED(smc) ; + SK_UNUSED(mac) ; + return(entity_to_index(smc,cem_get_downstream(smc,ENTITY_MAC))) ; +#else + SK_UNUSED(mac) ; + switch (smc->mib.fddiSMTCF_State) { + case SC9_C_WRAP_A : + case SC5_THRU_B : + case SC11_C_WRAP_S : + return(1) ; + case SC10_C_WRAP_B : + case SC4_THRU_A : + return(2) ; + } + return(smc->s.sas == SMT_SAS ? 2 : 3) ; +#endif +} + +/* + * return dynamic phy connection resource index + */ +static int phy_con_resource_index(smc,phy) +struct s_smc *smc ; +int phy ; +{ +#ifdef CONCENTRATOR + return(entity_to_index(smc,cem_get_downstream(smc,ENTITY_PHY(phy)))) ; +#else + switch (smc->mib.fddiSMTCF_State) { + case SC9_C_WRAP_A : + return(phy == PA ? 3 : 2) ; + case SC10_C_WRAP_B : + return(phy == PA ? 1 : 3) ; + case SC4_THRU_A : + return(phy == PA ? 3 : 1) ; + case SC5_THRU_B : + return(phy == PA ? 2 : 3) ; + case SC11_C_WRAP_S : + return(2) ; + } + return(phy) ; +#endif +} + +#ifdef CONCENTRATOR +static int entity_to_index(smc,e) +struct s_smc *smc ; +int e ; +{ + if (e == ENTITY_MAC) + return(mac_index(smc,1)) ; + else + return(phy_index(smc,e - ENTITY_PHY(0))) ; +} +#endif + +#ifdef LITTLE_ENDIAN +static int smt_swap_short(s) +u_short s ; +{ + return(((s>>8)&0xff)|((s&0xff)<<8)) ; +} + +void smt_swap_para(sm,len,direction) +struct smt_header *sm ; +int len ; +int direction ; /* 0 encode 1 decode */ +{ + struct smt_para *pa ; + const struct smt_pdef *pd ; + char *p ; + int plen ; + int type ; + int i ; + +/* printf("smt_swap_para sm %x len %d dir %d\n", + sm,len,direction) ; + */ + smt_string_swap((char *)sm,SWAP_SMTHEADER,len) ; + + /* swap args */ + len -= sizeof(struct smt_header) ; + + p = (char *) (sm + 1) ; + while (len > 0) { + pa = (struct smt_para *) p ; + plen = pa->p_len ; + type = pa->p_type ; + pa->p_type = smt_swap_short(pa->p_type) ; + pa->p_len = smt_swap_short(pa->p_len) ; + if (direction) { + plen = pa->p_len ; + type = pa->p_type ; + } + /* + * note: paras can have 0 length ! + */ + if (plen < 0) + break ; + plen += PARA_LEN ; + for (i = N_SMT_PLEN, pd = smt_pdef; i ; i--,pd++) { + if (pd->ptype == type) + break ; + } + if (i && pd->pswap) { + smt_string_swap(p+PARA_LEN,pd->pswap,len) ; + } + len -= plen ; + p += plen ; + } +} + +static void smt_string_swap(data,format,len) +char *data ; +const char *format ; +int len ; +{ + const char *open_paren = 0 ; + int x ; + + while (len > 0 && *format) { + switch (*format) { + case '[' : + open_paren = format ; + break ; + case ']' : + format = open_paren ; + break ; + case '1' : + case '2' : + case '3' : + case '4' : + case '5' : + case '6' : + case '7' : + case '8' : + case '9' : + data += *format - '0' ; + len -= *format - '0' ; + break ; + case 'c': + data++ ; + len-- ; + break ; + case 's' : + x = data[0] ; + data[0] = data[1] ; + data[1] = x ; + data += 2 ; + len -= 2 ; + break ; + case 'l' : + x = data[0] ; + data[0] = data[3] ; + data[3] = x ; + x = data[1] ; + data[1] = data[2] ; + data[2] = x ; + data += 4 ; + len -= 4 ; + break ; + } + format++ ; + } +} +#else +void smt_swap_para(sm,len,direction) +struct smt_header *sm ; +int len ; +int direction ; /* 0 encode 1 decode */ +{ + SK_UNUSED(sm) ; + SK_UNUSED(len) ; + SK_UNUSED(direction) ; +} +#endif + +/* + * PMF actions + */ +int smt_action(smc,class,code,index) +struct s_smc *smc ; +int class ; +int code ; +int index ; +{ + int event ; + int port ; + DB_SMT("SMT: action %d code %d\n",class,code) ; + switch(class) { + case SMT_STATION_ACTION : + switch(code) { + case SMT_STATION_ACTION_CONNECT : + smc->mib.fddiSMTRemoteDisconnectFlag = FALSE ; + queue_event(smc,EVENT_ECM,EC_CONNECT) ; + break ; + case SMT_STATION_ACTION_DISCONNECT : + queue_event(smc,EVENT_ECM,EC_DISCONNECT) ; + smc->mib.fddiSMTRemoteDisconnectFlag = TRUE ; + RS_SET(smc,RS_DISCONNECT) ; + AIX_EVENT(smc, (u_long) FDDI_RING_STATUS, (u_long) + FDDI_SMT_EVENT, (u_long) FDDI_REMOTE_DISCONNECT, + smt_get_event_word(smc)); + break ; + case SMT_STATION_ACTION_PATHTEST : + AIX_EVENT(smc, (u_long) FDDI_RING_STATUS, (u_long) + FDDI_SMT_EVENT, (u_long) FDDI_PATH_TEST, + smt_get_event_word(smc)); + break ; + case SMT_STATION_ACTION_SELFTEST : + AIX_EVENT(smc, (u_long) FDDI_RING_STATUS, (u_long) + FDDI_SMT_EVENT, (u_long) FDDI_REMOTE_SELF_TEST, + smt_get_event_word(smc)); + break ; + case SMT_STATION_ACTION_DISABLE_A : + if (smc->y[PA].pc_mode == PM_PEER) { + RS_SET(smc,RS_EVENT) ; + queue_event(smc,EVENT_PCM+PA,PC_DISABLE) ; + } + break ; + case SMT_STATION_ACTION_DISABLE_B : + if (smc->y[PB].pc_mode == PM_PEER) { + RS_SET(smc,RS_EVENT) ; + queue_event(smc,EVENT_PCM+PB,PC_DISABLE) ; + } + break ; + case SMT_STATION_ACTION_DISABLE_M : + for (port = 0 ; port < NUMPHYS ; port++) { + if (smc->mib.p[port].fddiPORTMy_Type != TM) + continue ; + RS_SET(smc,RS_EVENT) ; + queue_event(smc,EVENT_PCM+port,PC_DISABLE) ; + } + break ; + default : + return(1) ; + } + break ; + case SMT_PORT_ACTION : + switch(code) { + case SMT_PORT_ACTION_ENABLE : + event = PC_ENABLE ; + break ; + case SMT_PORT_ACTION_DISABLE : + event = PC_DISABLE ; + break ; + case SMT_PORT_ACTION_MAINT : + event = PC_MAINT ; + break ; + case SMT_PORT_ACTION_START : + event = PC_START ; + break ; + case SMT_PORT_ACTION_STOP : + event = PC_STOP ; + break ; + default : + return(1) ; + } + queue_event(smc,EVENT_PCM+index,event) ; + break ; + default : + return(1) ; + } + return(0) ; +} + +/* + * change tneg + * set T_Req in MIB (Path Attribute) + * calculate new values for MAC + * if change required + * disconnect + * set reconnect + * end + */ +void smt_change_t_neg(smc,tneg) +struct s_smc *smc ; +u_long tneg ; +{ + smc->mib.a[PATH0].fddiPATHMaxT_Req = tneg ; + + if (smt_set_mac_opvalues(smc)) { + RS_SET(smc,RS_EVENT) ; + smc->sm.please_reconnect = 1 ; + queue_event(smc,EVENT_ECM,EC_DISCONNECT) ; + } +} + +/* + * canonical conversion of bytes beginning form *data + */ +#ifdef USE_CAN_ADDR +void hwm_conv_can(smc,data,len) +struct s_smc *smc ; +char *data ; +int len ; +{ + int i ; + + SK_UNUSED(smc) ; + + for (i = len; i ; i--, data++) { + *data = canonical[*(u_char *)data] ; + } +} +#endif + +#endif /* no SLIM_SMT */ diff -u --recursive --new-file v2.3.46/linux/drivers/net/skfp/smtdef.c linux/drivers/net/skfp/smtdef.c --- v2.3.46/linux/drivers/net/skfp/smtdef.c Wed Dec 31 16:00:00 1969 +++ linux/drivers/net/skfp/smtdef.c Fri Feb 18 14:55:53 2000 @@ -0,0 +1,371 @@ +/****************************************************************************** + * + * (C)Copyright 1998,1999 SysKonnect, + * a business unit of Schneider & Koch & Co. Datensysteme GmbH. + * + * See the file "skfddi.c" for further information. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * The information in this file is provided "AS IS" without warranty. + * + ******************************************************************************/ + +/* + SMT/CMT defaults +*/ + +#include "h/types.h" +#include "h/fddi.h" +#include "h/smc.h" + +#ifndef OEM_USER_DATA +#define OEM_USER_DATA "SK-NET FDDI V2.0 Userdata" +#endif + +#ifndef lint +static const char ID_sccs[] = "@(#)smtdef.c 2.53 99/08/11 (C) SK " ; +#endif + +/* + * defaults + */ +#define TTMS(x) ((u_long)(x)*1000L) +#define TTS(x) ((u_long)(x)*1000000L) +#define TTUS(x) ((u_long)(x)) + +#define DEFAULT_TB_MIN TTMS(5) +#define DEFAULT_TB_MAX TTMS(50) +#define DEFAULT_C_MIN TTUS(1600) +#define DEFAULT_T_OUT TTMS(100+5) +#define DEFAULT_TL_MIN TTUS(30) +#define DEFAULT_LC_SHORT TTMS(50+5) +#define DEFAULT_LC_MEDIUM TTMS(500+20) +#define DEFAULT_LC_LONG TTS(5)+TTMS(50) +#define DEFAULT_LC_EXTENDED TTS(50)+TTMS(50) +#define DEFAULT_T_NEXT_9 TTMS(200+10) +#define DEFAULT_NS_MAX TTUS(1310) +#define DEFAULT_I_MAX TTMS(25) +#define DEFAULT_IN_MAX TTMS(40) +#define DEFAULT_TD_MIN TTMS(5) +#define DEFAULT_T_NON_OP TTS(1) +#define DEFAULT_T_STUCK TTS(8) +#define DEFAULT_T_DIRECT TTMS(370) +#define DEFAULT_T_JAM TTMS(370) +#define DEFAULT_T_ANNOUNCE TTMS(2500) +#define DEFAULT_D_MAX TTUS(1617) +#define DEFAULT_LEM_ALARM (8) +#define DEFAULT_LEM_CUTOFF (7) +#define DEFAULT_TEST_DONE TTS(1) +#define DEFAULT_CHECK_POLL TTS(1) +#define DEFAULT_POLL TTMS(50) + +/* + * LCT errors threshold + */ +#define DEFAULT_LCT_SHORT 1 +#define DEFAULT_LCT_MEDIUM 3 +#define DEFAULT_LCT_LONG 5 +#define DEFAULT_LCT_EXTEND 50 + +/* Forward declarations */ +extern void smt_reset_defaults (); +static void smt_init_mib (); + +static int set_min_max() ; + +void smt_set_defaults(smc) +struct s_smc *smc ; +{ + smt_reset_defaults(smc,0) ; +} + +#define MS2BCLK(x) ((x)*12500L) +#define US2BCLK(x) ((x)*1250L) + +void smt_reset_defaults(smc,level) +struct s_smc *smc ; +int level ; +{ + struct smt_config *smt ; + int i ; + u_long smt_boot_time; + + + smt_init_mib(smc,level) ; + + smc->os.smc_version = SMC_VERSION ; + smt_boot_time = smt_get_time(); + for( i = 0; i < NUMMACS; i++ ) + smc->sm.last_tok_time[i] = smt_boot_time ; + smt = &smc->s ; + smt->attach_s = 0 ; + smt->build_ring_map = 1 ; + smt->sas = SMT_DAS ; + smt->numphys = NUMPHYS ; + smt->pcm_tb_min = DEFAULT_TB_MIN ; + smt->pcm_tb_max = DEFAULT_TB_MAX ; + smt->pcm_c_min = DEFAULT_C_MIN ; + smt->pcm_t_out = DEFAULT_T_OUT ; + smt->pcm_tl_min = DEFAULT_TL_MIN ; + smt->pcm_lc_short = DEFAULT_LC_SHORT ; + smt->pcm_lc_medium = DEFAULT_LC_MEDIUM ; + smt->pcm_lc_long = DEFAULT_LC_LONG ; + smt->pcm_lc_extended = DEFAULT_LC_EXTENDED ; + smt->pcm_t_next_9 = DEFAULT_T_NEXT_9 ; + smt->pcm_ns_max = DEFAULT_NS_MAX ; + smt->ecm_i_max = DEFAULT_I_MAX ; + smt->ecm_in_max = DEFAULT_IN_MAX ; + smt->ecm_td_min = DEFAULT_TD_MIN ; + smt->ecm_test_done = DEFAULT_TEST_DONE ; + smt->ecm_check_poll = DEFAULT_CHECK_POLL ; + smt->rmt_t_non_op = DEFAULT_T_NON_OP ; + smt->rmt_t_stuck = DEFAULT_T_STUCK ; + smt->rmt_t_direct = DEFAULT_T_DIRECT ; + smt->rmt_t_jam = DEFAULT_T_JAM ; + smt->rmt_t_announce = DEFAULT_T_ANNOUNCE ; + smt->rmt_t_poll = DEFAULT_POLL ; + smt->rmt_dup_mac_behavior = FALSE ; /* See Struct smt_config */ + smt->mac_d_max = DEFAULT_D_MAX ; + + smt->lct_short = DEFAULT_LCT_SHORT ; + smt->lct_medium = DEFAULT_LCT_MEDIUM ; + smt->lct_long = DEFAULT_LCT_LONG ; + smt->lct_extended = DEFAULT_LCT_EXTEND ; + +#ifndef SLIM_SMT +#ifdef ESS + if (level == 0) { + smc->ess.sync_bw_available = FALSE ; + smc->mib.fddiESSPayload = 0 ; + smc->mib.fddiESSOverhead = 0 ; + smc->mib.fddiESSMaxTNeg = (u_long)(- MS2BCLK(25)) ; + smc->mib.fddiESSMinSegmentSize = 1 ; + smc->mib.fddiESSCategory = SB_STATIC ; + smc->mib.fddiESSSynchTxMode = FALSE ; + smc->ess.raf_act_timer_poll = FALSE ; + smc->ess.timer_count = 7 ; /* first RAF alc req after 3s */ + } + smc->ess.local_sba_active = FALSE ; + smc->ess.sba_reply_pend = NULL ; +#endif +#ifdef SBA + smt_init_sba(smc,level) ; +#endif +#endif /* no SLIM_SMT */ +#ifdef TAG_MODE + if (level == 0) { + smc->hw.pci_fix_value = 0 ; + } +#endif +} + +/* + * manufacturer data + */ +static const char man_data[32] = +/* 01234567890123456789012345678901 */ + "xxxSK-NET FDDI SMT 7.3 - V2.8.8" ; + +static void smt_init_mib(smc,level) +struct s_smc *smc ; +int level ; +{ + struct fddi_mib *mib ; + struct fddi_mib_p *pm ; + int port ; + int path ; + + mib = &smc->mib ; + if (level == 0) { + /* + * set EVERYTHING to ZERO + * EXCEPT hw and os + */ + memset(((char *)smc)+ + sizeof(struct s_smt_os)+sizeof(struct s_smt_hw), 0, + sizeof(struct s_smc) - + sizeof(struct s_smt_os) - sizeof(struct s_smt_hw)) ; + } + else { + mib->fddiSMTRemoteDisconnectFlag = 0 ; + mib->fddiSMTPeerWrapFlag = 0 ; + } + + mib->fddiSMTOpVersionId = 2 ; + mib->fddiSMTHiVersionId = 2 ; + mib->fddiSMTLoVersionId = 2 ; + memcpy((char *) mib->fddiSMTManufacturerData,man_data,32) ; + if (level == 0) { + strcpy(mib->fddiSMTUserData,OEM_USER_DATA) ; + } + mib->fddiSMTMIBVersionId = 1 ; + mib->fddiSMTMac_Ct = NUMMACS ; + mib->fddiSMTConnectionPolicy = POLICY_MM | POLICY_AA | POLICY_BB ; + + /* + * fddiSMTNonMaster_Ct and fddiSMTMaster_Ct are set in smt_fixup_mib + * s.sas is not set yet (is set in init driver) + */ + mib->fddiSMTAvailablePaths = MIB_PATH_P | MIB_PATH_S ; + + mib->fddiSMTConfigCapabilities = 0 ; /* no hold,no wrap_ab*/ + mib->fddiSMTTT_Notify = 10 ; + mib->fddiSMTStatRptPolicy = TRUE ; + mib->fddiSMTTrace_MaxExpiration = SEC2MIB(7) ; + mib->fddiSMTMACIndexes = INDEX_MAC ; + mib->fddiSMTStationStatus = MIB_SMT_STASTA_SEPA ; /* seperated */ + + mib->m[MAC0].fddiMACIndex = INDEX_MAC ; + mib->m[MAC0].fddiMACFrameStatusFunctions = FSC_TYPE0 ; + mib->m[MAC0].fddiMACRequestedPaths = + MIB_P_PATH_LOCAL | + MIB_P_PATH_SEC_ALTER | + MIB_P_PATH_PRIM_ALTER ; + mib->m[MAC0].fddiMACAvailablePaths = MIB_PATH_P ; + mib->m[MAC0].fddiMACCurrentPath = MIB_PATH_PRIMARY ; + mib->m[MAC0].fddiMACT_MaxCapabilitiy = (u_long)(- MS2BCLK(165)) ; + mib->m[MAC0].fddiMACTVXCapabilitiy = (u_long)(- US2BCLK(52)) ; + if (level == 0) { + mib->m[MAC0].fddiMACTvxValue = (u_long)(- US2BCLK(27)) ; + mib->m[MAC0].fddiMACTvxValueMIB = (u_long)(- US2BCLK(27)) ; + mib->m[MAC0].fddiMACT_Req = (u_long)(- MS2BCLK(165)) ; + mib->m[MAC0].fddiMACT_ReqMIB = (u_long)(- MS2BCLK(165)) ; + mib->m[MAC0].fddiMACT_Max = (u_long)(- MS2BCLK(165)) ; + mib->m[MAC0].fddiMACT_MaxMIB = (u_long)(- MS2BCLK(165)) ; + mib->m[MAC0].fddiMACT_Min = (u_long)(- MS2BCLK(4)) ; + } + mib->m[MAC0].fddiMACHardwarePresent = TRUE ; + mib->m[MAC0].fddiMACMA_UnitdataEnable = TRUE ; + mib->m[MAC0].fddiMACFrameErrorThreshold = 1 ; + mib->m[MAC0].fddiMACNotCopiedThreshold = 1 ; + /* + * Path attributes + */ + for (path = 0 ; path < NUMPATHS ; path++) { + mib->a[path].fddiPATHIndex = INDEX_PATH + path ; + if (level == 0) { + mib->a[path].fddiPATHTVXLowerBound = + (u_long)(- US2BCLK(27)) ; + mib->a[path].fddiPATHT_MaxLowerBound = + (u_long)(- MS2BCLK(165)) ; + mib->a[path].fddiPATHMaxT_Req = + (u_long)(- MS2BCLK(165)) ; + } + } + + + /* + * Port attributes + */ + pm = mib->p ; + for (port = 0 ; port < NUMPHYS ; port++) { + /* + * set MIB pointer in phy + */ + /* Attention: don't initialize mib pointer here! */ + /* It must be initialized during phase 2 */ + smc->y[port].mib = 0 ; + mib->fddiSMTPORTIndexes[port] = port+INDEX_PORT ; + + pm->fddiPORTIndex = port+INDEX_PORT ; + pm->fddiPORTHardwarePresent = TRUE ; + if (level == 0) { + pm->fddiPORTLer_Alarm = DEFAULT_LEM_ALARM ; + pm->fddiPORTLer_Cutoff = DEFAULT_LEM_CUTOFF ; + } + /* + * fddiPORTRequestedPaths are set in pcmplc.c + * we don't know the port type yet ! + */ + pm->fddiPORTRequestedPaths[1] = 0 ; + pm->fddiPORTRequestedPaths[2] = 0 ; + pm->fddiPORTRequestedPaths[3] = 0 ; + pm->fddiPORTAvailablePaths = MIB_PATH_P ; + pm->fddiPORTPMDClass = MIB_PMDCLASS_MULTI ; + pm++ ; + } + + (void) smt_set_mac_opvalues(smc) ; +} + +int smt_set_mac_opvalues(smc) +struct s_smc *smc ; +{ + int st ; + int st2 ; + + st = set_min_max(1,smc->mib.m[MAC0].fddiMACTvxValueMIB, + smc->mib.a[PATH0].fddiPATHTVXLowerBound, + &smc->mib.m[MAC0].fddiMACTvxValue) ; + st |= set_min_max(0,smc->mib.m[MAC0].fddiMACT_MaxMIB, + smc->mib.a[PATH0].fddiPATHT_MaxLowerBound, + &smc->mib.m[MAC0].fddiMACT_Max) ; + st |= (st2 = set_min_max(0,smc->mib.m[MAC0].fddiMACT_ReqMIB, + smc->mib.a[PATH0].fddiPATHMaxT_Req, + &smc->mib.m[MAC0].fddiMACT_Req)) ; + if (st2) { + /* Treq attribute changed remotely. So send an AIX_EVENT to the + * user + */ + AIX_EVENT(smc, (u_long) FDDI_RING_STATUS, (u_long) + FDDI_SMT_EVENT, (u_long) FDDI_REMOTE_T_REQ, + smt_get_event_word(smc)); + } + return(st) ; +} + +void smt_fixup_mib(smc) +struct s_smc *smc ; +{ +#ifdef CONCENTRATOR + switch (smc->s.sas) { + case SMT_SAS : + smc->mib.fddiSMTNonMaster_Ct = 1 ; + break ; + case SMT_DAS : + smc->mib.fddiSMTNonMaster_Ct = 2 ; + break ; + case SMT_NAC : + smc->mib.fddiSMTNonMaster_Ct = 0 ; + break ; + } + smc->mib.fddiSMTMaster_Ct = NUMPHYS - smc->mib.fddiSMTNonMaster_Ct ; +#else + switch (smc->s.sas) { + case SMT_SAS : + smc->mib.fddiSMTNonMaster_Ct = 1 ; + break ; + case SMT_DAS : + smc->mib.fddiSMTNonMaster_Ct = 2 ; + break ; + } + smc->mib.fddiSMTMaster_Ct = 0 ; +#endif +} + +/* + * determine new setting for operational value + * if limit is lower than mib + * use limit + * else + * use mib + * NOTE : numbers are negative, negate comparison ! + */ +static int set_min_max(maxflag,mib,limit,oper) +int maxflag ; +u_long mib ; +u_long limit ; +u_long *oper ; +{ + u_long old ; + old = *oper ; + if ((limit > mib) ^ maxflag) + *oper = limit ; + else + *oper = mib ; + return(old != *oper) ; +} diff -u --recursive --new-file v2.3.46/linux/drivers/net/skfp/smtinit.c linux/drivers/net/skfp/smtinit.c --- v2.3.46/linux/drivers/net/skfp/smtinit.c Wed Dec 31 16:00:00 1969 +++ linux/drivers/net/skfp/smtinit.c Fri Feb 18 14:55:53 2000 @@ -0,0 +1,126 @@ +/****************************************************************************** + * + * (C)Copyright 1998,1999 SysKonnect, + * a business unit of Schneider & Koch & Co. Datensysteme GmbH. + * + * See the file "skfddi.c" for further information. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * The information in this file is provided "AS IS" without warranty. + * + ******************************************************************************/ + +/* + Init SMT + call all module level initialization routines +*/ + +#include "h/types.h" +#include "h/fddi.h" +#include "h/smc.h" + +#ifndef lint +static const char ID_sccs[] = "@(#)smtinit.c 1.15 97/05/06 (C) SK " ; +#endif + +extern void init_fddi_driver() ; + +/* define global debug variable */ +#if defined(DEBUG) && !defined(DEBUG_BRD) +struct smt_debug debug; +#endif + +#ifndef MULT_OEM +#define OEMID(smc,i) oem_id[i] + extern u_char oem_id[] ; +#else /* MULT_OEM */ +#define OEMID(smc,i) smc->hw.oem_id->oi_mark[i] + extern struct s_oem_ids oem_ids[] ; +#endif /* MULT_OEM */ + +/* + * Set OEM specific values + * + * Can not be called in smt_reset_defaults, because it is not sure that + * the OEM ID is already defined. + */ +static void set_oem_spec_val(smc) +struct s_smc *smc ; +{ + struct fddi_mib *mib ; + + mib = &smc->mib ; + + /* + * set IBM specific values + */ + if (OEMID(smc,0) == 'I') { + mib->fddiSMTConnectionPolicy = POLICY_MM ; + } +} + +/* + * Init SMT + */ +int init_smt(smc,mac_addr) +struct s_smc *smc ; +u_char *mac_addr ; /* canonical address or NULL */ +{ + int p ; + +#if defined(DEBUG) && !defined(DEBUG_BRD) + debug.d_smt = 0 ; + debug.d_smtf = 0 ; + debug.d_rmt = 0 ; + debug.d_ecm = 0 ; + debug.d_pcm = 0 ; + debug.d_cfm = 0 ; + + debug.d_plc = 0 ; +#ifdef ESS + debug.d_ess = 0 ; +#endif +#ifdef SBA + debug.d_sba = 0 ; +#endif +#endif /* DEBUG && !DEBUG_BRD */ + + /* First initialize the ports mib->pointers */ + for ( p = 0; p < NUMPHYS; p ++ ) { + smc->y[p].mib = & smc->mib.p[p] ; + } + + set_oem_spec_val(smc) ; + (void) smt_set_mac_opvalues(smc) ; + init_fddi_driver(smc,mac_addr) ; /* HW driver */ + smt_fixup_mib(smc) ; /* update values that depend on s.sas */ + + ev_init(smc) ; /* event queue */ +#ifndef SLIM_SMT + smt_init_evc(smc) ; /* evcs in MIB */ +#endif /* no SLIM_SMT */ + smt_timer_init(smc) ; /* timer package */ + smt_agent_init(smc) ; /* SMT frame manager */ + + pcm_init(smc) ; /* PCM state machine */ + ecm_init(smc) ; /* ECM state machine */ + cfm_init(smc) ; /* CFM state machine */ + rmt_init(smc) ; /* RMT state machine */ + + for (p = 0 ; p < NUMPHYS ; p++) { + pcm(smc,p,0) ; /* PCM A state machine */ + } + ecm(smc,0) ; /* ECM state machine */ + cfm(smc,0) ; /* CFM state machine */ + rmt(smc,0) ; /* RMT state machine */ + + smt_agent_task(smc) ; /* NIF FSM etc */ + + PNMI_INIT(smc) ; /* PNMI initialization */ + + return(0) ; +} diff -u --recursive --new-file v2.3.46/linux/drivers/net/skfp/smtparse.c linux/drivers/net/skfp/smtparse.c --- v2.3.46/linux/drivers/net/skfp/smtparse.c Wed Dec 31 16:00:00 1969 +++ linux/drivers/net/skfp/smtparse.c Fri Feb 18 14:55:53 2000 @@ -0,0 +1,475 @@ +/****************************************************************************** + * + * (C)Copyright 1998,1999 SysKonnect, + * a business unit of Schneider & Koch & Co. Datensysteme GmbH. + * + * See the file "skfddi.c" for further information. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * The information in this file is provided "AS IS" without warranty. + * + ******************************************************************************/ + + +/* + parser for SMT parameters +*/ + +#include "h/types.h" +#include "h/fddi.h" +#include "h/smc.h" +#include "h/smt_p.h" + +#define KERNEL +#include "h/smtstate.h" + +#ifndef lint +static const char ID_sccs[] = "@(#)smtparse.c 1.12 98/10/06 (C) SK " ; +#endif + +#ifdef sun +#define _far +#endif + +/* + * convert to BCLK units + */ +#define MS2BCLK(x) ((x)*12500L) +#define US2BCLK(x) ((x/10)*125L) + +/* + * parameter table + */ +static struct s_ptab { + char *pt_name ; + u_short pt_num ; + u_short pt_type ; + u_long pt_min ; + u_long pt_max ; +} ptab[] = { + { "PMFPASSWD",0, 0 } , + { "USERDATA",1, 0 } , + { "LERCUTOFFA",2, 1, 4, 15 } , + { "LERCUTOFFB",3, 1, 4, 15 } , + { "LERALARMA",4, 1, 4, 15 } , + { "LERALARMB",5, 1, 4, 15 } , + { "TMAX",6, 1, 5, 165 } , + { "TMIN",7, 1, 5, 165 } , + { "TREQ",8, 1, 5, 165 } , + { "TVX",9, 1, 2500, 10000 } , +#ifdef ESS + { "SBAPAYLOAD",10, 1, 0, 1562 } , + { "SBAOVERHEAD",11, 1, 50, 5000 } , + { "MAXTNEG",12, 1, 5, 165 } , + { "MINSEGMENTSIZE",13, 1, 0, 4478 } , + { "SBACATEGORY",14, 1, 0, 0xffff } , + { "SYNCHTXMODE",15, 0 } , +#endif +#ifdef SBA + { "SBACOMMAND",16, 0 } , + { "SBAAVAILABLE",17, 1, 0, 100 } , +#endif + { 0 } +} ; + +/* Define maximum string size for values and keybuffer */ +#define MAX_VAL 40 + +/* + * local function declarations + */ +static u_long parse_num() ; +static int parse_word() ; + +#ifdef SIM +#define DB_MAIN(a,b,c) printf(a,b,c) +#else +#define DB_MAIN(a,b,c) +#endif + +/* + * BEGIN_MANUAL_ENTRY() + * + * int smt_parse_arg(struct s_smc *,char _far *keyword,int type, + char _far *value) + * + * parse SMT parameter + * *keyword + * pointer to keyword, must be \0, \n or \r terminated + * *value pointer to value, either char * or u_long * + * if char * + * pointer to value, must be \0, \n or \r terminated + * if u_long * + * contains binary value + * + * type 0: integer + * 1: string + * return + * 0 parameter parsed ok + * != 0 error + * NOTE: + * function can be called with DS != SS + * + * + * END_MANUAL_ENTRY() + */ +int smt_parse_arg(smc,keyword,type,value) +struct s_smc *smc ; +char _far *keyword ; +int type ; +char _far *value ; +{ + char keybuf[MAX_VAL+1]; + char valbuf[MAX_VAL+1]; + char c ; + char *p ; + char *v ; + char *d ; + u_long val = 0 ; + struct s_ptab *pt ; + int st ; + int i ; + + /* + * parse keyword + */ + if ((st = parse_word(keybuf,keyword))) + return(st) ; + /* + * parse value if given as string + */ + if (type == 1) { + if ((st = parse_word(valbuf,value))) + return(st) ; + } + /* + * search in table + */ + st = 0 ; + for (pt = ptab ; (v = pt->pt_name) ; pt++) { + for (p = keybuf ; (c = *p) ; p++,v++) { + if (c != *v) + break ; + } + if (!c && !*v) + break ; + } + if (!v) + return(-1) ; +#if 0 + printf("=>%s<==>%s<=\n",pt->pt_name,valbuf) ; +#endif + /* + * set value in MIB + */ + if (pt->pt_type) + val = parse_num(type,value,valbuf,pt->pt_min,pt->pt_max,1) ; + switch (pt->pt_num) { + case 0 : + v = valbuf ; + d = (char *) smc->mib.fddiPRPMFPasswd ; + for (i = 0 ; i < (signed)sizeof(smc->mib.fddiPRPMFPasswd) ; i++) + *d++ = *v++ ; + DB_MAIN("SET %s = %s\n",pt->pt_name,smc->mib.fddiPRPMFPasswd) ; + break ; + case 1 : + v = valbuf ; + d = (char *) smc->mib.fddiSMTUserData ; + for (i = 0 ; i < (signed)sizeof(smc->mib.fddiSMTUserData) ; i++) + *d++ = *v++ ; + DB_MAIN("SET %s = %s\n",pt->pt_name,smc->mib.fddiSMTUserData) ; + break ; + case 2 : + smc->mib.p[PA].fddiPORTLer_Cutoff = (u_char) val ; + DB_MAIN("SET %s = %d\n", + pt->pt_name,smc->mib.p[PA].fddiPORTLer_Cutoff) ; + break ; + case 3 : + smc->mib.p[PB].fddiPORTLer_Cutoff = (u_char) val ; + DB_MAIN("SET %s = %d\n", + pt->pt_name,smc->mib.p[PB].fddiPORTLer_Cutoff) ; + break ; + case 4 : + smc->mib.p[PA].fddiPORTLer_Alarm = (u_char) val ; + DB_MAIN("SET %s = %d\n", + pt->pt_name,smc->mib.p[PA].fddiPORTLer_Alarm) ; + break ; + case 5 : + smc->mib.p[PB].fddiPORTLer_Alarm = (u_char) val ; + DB_MAIN("SET %s = %d\n", + pt->pt_name,smc->mib.p[PB].fddiPORTLer_Alarm) ; + break ; + case 6 : /* TMAX */ + DB_MAIN("SET %s = %d\n",pt->pt_name,val) ; + smc->mib.a[PATH0].fddiPATHT_MaxLowerBound = + (u_long) -MS2BCLK((long)val) ; + break ; + case 7 : /* TMIN */ + DB_MAIN("SET %s = %d\n",pt->pt_name,val) ; + smc->mib.m[MAC0].fddiMACT_Min = + (u_long) -MS2BCLK((long)val) ; + break ; + case 8 : /* TREQ */ + DB_MAIN("SET %s = %d\n",pt->pt_name,val) ; + smc->mib.a[PATH0].fddiPATHMaxT_Req = + (u_long) -MS2BCLK((long)val) ; + break ; + case 9 : /* TVX */ + DB_MAIN("SET %s = %d \n",pt->pt_name,val) ; + smc->mib.a[PATH0].fddiPATHTVXLowerBound = + (u_long) -US2BCLK((long)val) ; + break ; +#ifdef ESS + case 10 : /* SBAPAYLOAD */ + DB_MAIN("SET %s = %d\n",pt->pt_name,val) ; + if (smc->mib.fddiESSPayload != val) { + smc->ess.raf_act_timer_poll = TRUE ; + smc->mib.fddiESSPayload = val ; + } + break ; + case 11 : /* SBAOVERHEAD */ + DB_MAIN("SET %s = %d\n",pt->pt_name,val) ; + smc->mib.fddiESSOverhead = val ; + break ; + case 12 : /* MAXTNEG */ + DB_MAIN("SET %s = %d\n",pt->pt_name,val) ; + smc->mib.fddiESSMaxTNeg = (u_long) -MS2BCLK((long)val) ; + break ; + case 13 : /* MINSEGMENTSIZE */ + DB_MAIN("SET %s = %d\n",pt->pt_name,val) ; + smc->mib.fddiESSMinSegmentSize = val ; + break ; + case 14 : /* SBACATEGORY */ + DB_MAIN("SET %s = %d\n",pt->pt_name,val) ; + smc->mib.fddiESSCategory = + (smc->mib.fddiESSCategory & 0xffff) | + ((u_long)(val << 16)) ; + break ; + case 15 : /* SYNCHTXMODE */ + /* do not use memcmp(valbuf,"ALL",3) because DS != SS */ + if (valbuf[0] == 'A' && valbuf[1] == 'L' && valbuf[2] == 'L') { + smc->mib.fddiESSSynchTxMode = TRUE ; + DB_MAIN("SET %s = %s\n",pt->pt_name,valbuf) ; + } + /* if (!memcmp(valbuf,"SPLIT",5)) { */ + if (valbuf[0] == 'S' && valbuf[1] == 'P' && valbuf[2] == 'L' && + valbuf[3] == 'I' && valbuf[4] == 'T') { + DB_MAIN("SET %s = %s\n",pt->pt_name,valbuf) ; + smc->mib.fddiESSSynchTxMode = FALSE ; + } + break ; +#endif +#ifdef SBA + case 16 : /* SBACOMMAND */ + /* if (!memcmp(valbuf,"START",5)) { */ + if (valbuf[0] == 'S' && valbuf[1] == 'T' && valbuf[2] == 'A' && + valbuf[3] == 'R' && valbuf[4] == 'T') { + DB_MAIN("SET %s = %s\n",pt->pt_name,valbuf) ; + smc->mib.fddiSBACommand = SB_START ; + } + /* if (!memcmp(valbuf,"STOP",4)) { */ + if (valbuf[0] == 'S' && valbuf[1] == 'T' && valbuf[2] == 'O' && + valbuf[3] == 'P') { + DB_MAIN("SET %s = %s\n",pt->pt_name,valbuf) ; + smc->mib.fddiSBACommand = SB_STOP ; + } + break ; + case 17 : /* SBAAVAILABLE */ + DB_MAIN("SET %s = %d\n",pt->pt_name,val) ; + smc->mib.fddiSBAAvailable = (u_char) val ; + break ; +#endif + } + return(0) ; +} + +static int parse_word(buf,text) +char *buf ; +char _far *text ; +{ + char c ; + char *p ; + int p_len ; + int quote ; + int i ; + int ok ; + + /* + * skip leading white space + */ + p = buf ; + for (i = 0 ; i < MAX_VAL ; i++) + *p++ = 0 ; + p = buf ; + p_len = 0 ; + ok = 0 ; + while ( (c = *text++) && (c != '\n') && (c != '\r')) { + if ((c != ' ') && (c != '\t')) { + ok = 1 ; + break ; + } + } + if (!ok) + return(-1) ; + if (c == '"') { + quote = 1 ; + } + else { + quote = 0 ; + text-- ; + } + /* + * parse valbuf + */ + ok = 0 ; + while (!ok && p_len < MAX_VAL-1 && (c = *text++) && (c != '\n') + && (c != '\r')) { + switch (quote) { + case 0 : + if ((c == ' ') || (c == '\t') || (c == '=')) { + ok = 1 ; + break ; + } + *p++ = c ; + p_len++ ; + break ; + case 2 : + *p++ = c ; + p_len++ ; + quote = 1 ; + break ; + case 1 : + switch (c) { + case '"' : + ok = 1 ; + break ; + case '\\' : + quote = 2 ; + break ; + default : + *p++ = c ; + p_len++ ; + } + } + } + *p++ = 0 ; + for (p = buf ; (c = *p) ; p++) { + if (c >= 'a' && c <= 'z') + *p = c + 'A' - 'a' ; + } + return(0) ; +} + +static u_long parse_num(type,value,v,mn,mx,scale) +int type ; +char _far *value ; +char *v ; +u_long mn ; +u_long mx ; +int scale ; +{ + u_long x = 0 ; + char c ; + + if (type == 0) { /* integer */ + u_long _far *l ; + u_long u1 ; + + l = (u_long _far *) value ; + u1 = *l ; + /* + * if the value is negative take the lower limit + */ + if ((long)u1 < 0) { + if (- ((long)u1) > (long) mx) { + u1 = 0 ; + } + else { + u1 = (u_long) - ((long)u1) ; + } + } + x = u1 ; + } + else { /* string */ + int sign = 0 ; + + if (*v == '-') { + sign = 1 ; + } + while ((c = *v++) && (c >= '0') && (c <= '9')) { + x = x * 10 + c - '0' ; + } + if (scale == 10) { + x *= 10 ; + if (c == '.') { + if ((c = *v++) && (c >= '0') && (c <= '9')) { + x += c - '0' ; + } + } + } + if (sign) + x = (u_long) - ((long)x) ; + } + /* + * if the value is negative + * and the absolute value is outside the limits + * take the lower limit + * else + * take the absoute value + */ + if ((long)x < 0) { + if (- ((long)x) > (long) mx) { + x = 0 ; + } + else { + x = (u_long) - ((long)x) ; + } + } + if (x < mn) + return(mn) ; + else if (x > mx) + return(mx) ; + return(x) ; +} + +#if 0 +struct s_smc SMC ; +main() +{ + char *p ; + char *v ; + char buf[100] ; + int toggle = 0 ; + + while (gets(buf)) { + p = buf ; + while (*p && ((*p == ' ') || (*p == '\t'))) + p++ ; + + while (*p && ((*p != ' ') && (*p != '\t'))) + p++ ; + + v = p ; + while (*v && ((*v == ' ') || (*v == '\t'))) + v++ ; + if ((*v >= '0') && (*v <= '9')) { + toggle = !toggle ; + if (toggle) { + u_long l ; + l = atol(v) ; + smt_parse_arg(&SMC,buf,0,(char _far *)&l) ; + } + else + smt_parse_arg(&SMC,buf,1,(char _far *)p) ; + } + else { + smt_parse_arg(&SMC,buf,1,(char _far *)p) ; + } + } + exit(0) ; +} +#endif diff -u --recursive --new-file v2.3.46/linux/drivers/net/skfp/smttimer.c linux/drivers/net/skfp/smttimer.c --- v2.3.46/linux/drivers/net/skfp/smttimer.c Wed Dec 31 16:00:00 1969 +++ linux/drivers/net/skfp/smttimer.c Fri Feb 18 14:55:53 2000 @@ -0,0 +1,173 @@ +/****************************************************************************** + * + * (C)Copyright 1998,1999 SysKonnect, + * a business unit of Schneider & Koch & Co. Datensysteme GmbH. + * + * See the file "skfddi.c" for further information. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * The information in this file is provided "AS IS" without warranty. + * + ******************************************************************************/ + +/* + SMT timer +*/ + +#include "h/types.h" +#include "h/fddi.h" +#include "h/smc.h" + +#ifndef lint +static const char ID_sccs[] = "@(#)smttimer.c 2.4 97/08/04 (C) SK " ; +#endif + +/* + * external function declarations + */ +extern u_long hwt_read() ; +extern void hwt_stop() ; +extern void hwt_start() ; + +static void timer_done() ; + + +void smt_timer_init(smc) +struct s_smc *smc ; +{ + smc->t.st_queue = 0 ; + smc->t.st_fast.tm_active = FALSE ; + smc->t.st_fast.tm_next = 0 ; + hwt_init(smc) ; +} + +void smt_timer_stop(smc,timer) +struct s_smc *smc ; +struct smt_timer *timer ; +{ + struct smt_timer **prev ; + struct smt_timer *tm ; + + /* + * remove timer from queue + */ + timer->tm_active = FALSE ; + if (smc->t.st_queue == timer && !timer->tm_next) { + hwt_stop(smc) ; + } + for (prev = &smc->t.st_queue ; (tm = *prev) ; prev = &tm->tm_next ) { + if (tm == timer) { + *prev = tm->tm_next ; + if (tm->tm_next) { + tm->tm_next->tm_delta += tm->tm_delta ; + } + return ; + } + } +} + +void smt_timer_start(smc,timer,time,token) +struct s_smc *smc ; +struct smt_timer *timer ; +u_long time ; +u_long token ; +{ + struct smt_timer **prev ; + struct smt_timer *tm ; + u_long delta = 0 ; + + time /= 16 ; /* input is uS, clock ticks are 16uS */ + if (!time) + time = 1 ; + smt_timer_stop(smc,timer) ; + timer->tm_smc = smc ; + timer->tm_token = token ; + timer->tm_active = TRUE ; + if (!smc->t.st_queue) { + smc->t.st_queue = timer ; + timer->tm_next = 0 ; + timer->tm_delta = time ; + hwt_start(smc,time) ; + return ; + } + /* + * timer correction + */ + timer_done(smc,0) ; + + /* + * find position in queue + */ + delta = 0 ; + for (prev = &smc->t.st_queue ; (tm = *prev) ; prev = &tm->tm_next ) { + if (delta + tm->tm_delta > time) { + break ; + } + delta += tm->tm_delta ; + } + /* insert in queue */ + *prev = timer ; + timer->tm_next = tm ; + timer->tm_delta = time - delta ; + if (tm) + tm->tm_delta -= timer->tm_delta ; + /* + * start new with first + */ + hwt_start(smc,smc->t.st_queue->tm_delta) ; +} + +void smt_force_irq(smc) +struct s_smc *smc ; +{ + smt_timer_start(smc,&smc->t.st_fast,32L, EV_TOKEN(EVENT_SMT,SM_FAST)); +} + +void smt_timer_done(smc) +struct s_smc *smc ; +{ + timer_done(smc,1) ; +} + +static void timer_done(smc,restart) +struct s_smc *smc ; +int restart ; +{ + u_long delta ; + struct smt_timer *tm ; + struct smt_timer *next ; + struct smt_timer **last ; + int done = 0 ; + + delta = hwt_read(smc) ; + last = &smc->t.st_queue ; + tm = smc->t.st_queue ; + while (tm && !done) { + if (delta >= tm->tm_delta) { + tm->tm_active = FALSE ; + delta -= tm->tm_delta ; + last = &tm->tm_next ; + tm = tm->tm_next ; + } + else { + tm->tm_delta -= delta ; + delta = 0 ; + done = 1 ; + } + } + *last = 0 ; + next = smc->t.st_queue ; + smc->t.st_queue = tm ; + + for ( tm = next ; tm ; tm = next) { + next = tm->tm_next ; + timer_event(smc,tm->tm_token) ; + } + + if (restart && smc->t.st_queue) + hwt_start(smc,smc->t.st_queue->tm_delta) ; +} diff -u --recursive --new-file v2.3.46/linux/drivers/net/skfp/srf.c linux/drivers/net/skfp/srf.c --- v2.3.46/linux/drivers/net/skfp/srf.c Wed Dec 31 16:00:00 1969 +++ linux/drivers/net/skfp/srf.c Fri Feb 18 14:55:53 2000 @@ -0,0 +1,441 @@ +/****************************************************************************** + * + * (C)Copyright 1998,1999 SysKonnect, + * a business unit of Schneider & Koch & Co. Datensysteme GmbH. + * + * See the file "skfddi.c" for further information. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * The information in this file is provided "AS IS" without warranty. + * + ******************************************************************************/ + +/* + SMT 7.2 Status Response Frame Implementation + SRF state machine and frame generation +*/ + +#include "h/types.h" +#include "h/fddi.h" +#include "h/smc.h" +#include "h/smt_p.h" + +#define KERNEL +#include "h/smtstate.h" + +#ifndef SLIM_SMT +#ifndef BOOT + +#ifndef lint +static const char ID_sccs[] = "@(#)srf.c 1.18 97/08/04 (C) SK " ; +#endif + + +/* + * function declarations + */ +static void clear_all_rep() ; +static void clear_reported() ; +static void smt_send_srf() ; +static struct s_srf_evc *smt_get_evc() ; + +#define MAX_EVCS (sizeof(smc->evcs)/sizeof(smc->evcs[0])) + +struct evc_init { + u_char code ; + u_char index ; + u_char n ; + u_short para ; +} ; + +static const struct evc_init evc_inits[] = { + { SMT_COND_SMT_PEER_WRAP, 0,1,SMT_P1048 } , + + { SMT_COND_MAC_DUP_ADDR, INDEX_MAC, NUMMACS,SMT_P208C } , + { SMT_COND_MAC_FRAME_ERROR, INDEX_MAC, NUMMACS,SMT_P208D } , + { SMT_COND_MAC_NOT_COPIED, INDEX_MAC, NUMMACS,SMT_P208E } , + { SMT_EVENT_MAC_NEIGHBOR_CHANGE, INDEX_MAC, NUMMACS,SMT_P208F } , + { SMT_EVENT_MAC_PATH_CHANGE, INDEX_MAC, NUMMACS,SMT_P2090 } , + + { SMT_COND_PORT_LER, INDEX_PORT,NUMPHYS,SMT_P4050 } , + { SMT_COND_PORT_EB_ERROR, INDEX_PORT,NUMPHYS,SMT_P4052 } , + { SMT_EVENT_PORT_CONNECTION, INDEX_PORT,NUMPHYS,SMT_P4051 } , + { SMT_EVENT_PORT_PATH_CHANGE, INDEX_PORT,NUMPHYS,SMT_P4053 } , +} ; + +#define MAX_INIT_EVC (sizeof(evc_inits)/sizeof(evc_inits[0])) + +void smt_init_evc(smc) +struct s_smc *smc ; +{ + struct s_srf_evc *evc ; + const struct evc_init *init ; + int i ; + int index ; + int offset ; + + static u_char fail_safe = FALSE ; + + memset((char *)smc->evcs,0,sizeof(smc->evcs)) ; + + evc = smc->evcs ; + init = evc_inits ; + + for (i = 0 ; (unsigned) i < MAX_INIT_EVC ; i++) { + for (index = 0 ; index < init->n ; index++) { + evc->evc_code = init->code ; + evc->evc_para = init->para ; + evc->evc_index = init->index + index ; +#ifndef DEBUG + evc->evc_multiple = &fail_safe ; + evc->evc_cond_state = &fail_safe ; +#endif + evc++ ; + } + init++ ; + } + + if ((unsigned) (evc - smc->evcs) > MAX_EVCS) { + SMT_PANIC(smc,SMT_E0127, SMT_E0127_MSG) ; + } + + /* + * conditions + */ + smc->evcs[0].evc_cond_state = &smc->mib.fddiSMTPeerWrapFlag ; + smc->evcs[1].evc_cond_state = + &smc->mib.m[MAC0].fddiMACDuplicateAddressCond ; + smc->evcs[2].evc_cond_state = + &smc->mib.m[MAC0].fddiMACFrameErrorFlag ; + smc->evcs[3].evc_cond_state = + &smc->mib.m[MAC0].fddiMACNotCopiedFlag ; + + /* + * events + */ + smc->evcs[4].evc_multiple = &smc->mib.m[MAC0].fddiMACMultiple_N ; + smc->evcs[5].evc_multiple = &smc->mib.m[MAC0].fddiMACMultiple_P ; + + offset = 6 ; + for (i = 0 ; i < NUMPHYS ; i++) { + /* + * conditions + */ + smc->evcs[offset + 0*NUMPHYS].evc_cond_state = + &smc->mib.p[i].fddiPORTLerFlag ; + smc->evcs[offset + 1*NUMPHYS].evc_cond_state = + &smc->mib.p[i].fddiPORTEB_Condition ; + + /* + * events + */ + smc->evcs[offset + 2*NUMPHYS].evc_multiple = + &smc->mib.p[i].fddiPORTMultiple_U ; + smc->evcs[offset + 3*NUMPHYS].evc_multiple = + &smc->mib.p[i].fddiPORTMultiple_P ; + offset++ ; + } +#ifdef DEBUG + for (i = 0, evc = smc->evcs ; (unsigned) i < MAX_EVCS ; i++, evc++) { + if (SMT_IS_CONDITION(evc->evc_code)) { + if (!evc->evc_cond_state) { + SMT_PANIC(smc,SMT_E0128, SMT_E0128_MSG) ; + } + evc->evc_multiple = &fail_safe ; + } + else { + if (!evc->evc_multiple) { + SMT_PANIC(smc,SMT_E0129, SMT_E0129_MSG) ; + } + evc->evc_cond_state = &fail_safe ; + } + } +#endif + smc->srf.TSR = smt_get_time() ; + smc->srf.sr_state = SR0_WAIT ; +} + +static struct s_srf_evc *smt_get_evc(smc,code,index) +struct s_smc *smc ; +int code ; +int index ; +{ + int i ; + struct s_srf_evc *evc ; + + for (i = 0, evc = smc->evcs ; (unsigned) i < MAX_EVCS ; i++, evc++) { + if (evc->evc_code == code && evc->evc_index == index) + return(evc) ; + } + return(0) ; +} + +#define THRESHOLD_2 (2*TICKS_PER_SECOND) +#define THRESHOLD_32 (32*TICKS_PER_SECOND) + +#ifdef DEBUG +static const char * const srf_names[] = { + "None","MACPathChangeEvent", "MACNeighborChangeEvent", + "PORTPathChangeEvent", "PORTUndesiredConnectionAttemptEvent", + "SMTPeerWrapCondition", "SMTHoldCondition", + "MACFrameErrorCondition", "MACDuplicateAddressCondition", + "MACNotCopiedCondition", "PORTEBErrorCondition", + "PORTLerCondition" +} ; +#endif + +void smt_srf_event(smc,code,index,cond) +struct s_smc *smc ; +int code ; +int index ; +int cond ; +{ + struct s_srf_evc *evc ; + int cond_asserted = 0 ; + int cond_deasserted = 0 ; + int event_occured = 0 ; + int tsr ; + int T_Limit = 2*TICKS_PER_SECOND ; + + if (code == SMT_COND_MAC_DUP_ADDR && cond) { + RS_SET(smc,RS_DUPADDR) ; + } + + if (code) { + DB_SMT("SRF: %s index %d\n",srf_names[code],index) ; + + if (!(evc = smt_get_evc(smc,code,index))) { + DB_SMT("SRF : smt_get_evc() failed\n",0,0) ; + return ; + } + /* + * ignore condition if no change + */ + if (SMT_IS_CONDITION(code)) { + if (*evc->evc_cond_state == cond) + return ; + } + + /* + * set transition time stamp + */ + smt_set_timestamp(smc,smc->mib.fddiSMTTransitionTimeStamp) ; + if (SMT_IS_CONDITION(code)) { + DB_SMT("SRF: condition is %s\n",cond ? "ON":"OFF",0) ; + if (cond) { + *evc->evc_cond_state = TRUE ; + evc->evc_rep_required = TRUE ; + smc->srf.any_report = TRUE ; + cond_asserted = TRUE ; + } + else { + *evc->evc_cond_state = FALSE ; + cond_deasserted = TRUE ; + } + } + else { + if (evc->evc_rep_required) { + *evc->evc_multiple = TRUE ; + } + else { + evc->evc_rep_required = TRUE ; + *evc->evc_multiple = FALSE ; + } + smc->srf.any_report = TRUE ; + event_occured = TRUE ; + } +#ifdef FDDI_MIB + snmp_srf_event(smc,evc) ; +#endif /* FDDI_MIB */ + } + tsr = smt_get_time() - smc->srf.TSR ; + + switch (smc->srf.sr_state) { + case SR0_WAIT : + /* SR01a */ + if (cond_asserted && tsr < T_Limit) { + smc->srf.SRThreshold = THRESHOLD_2 ; + smc->srf.sr_state = SR1_HOLDOFF ; + break ; + } + /* SR01b */ + if (cond_deasserted && tsr < T_Limit) { + smc->srf.sr_state = SR1_HOLDOFF ; + break ; + } + /* SR01c */ + if (event_occured && tsr < T_Limit) { + smc->srf.sr_state = SR1_HOLDOFF ; + break ; + } + /* SR00b */ + if (cond_asserted && tsr >= T_Limit) { + smc->srf.SRThreshold = THRESHOLD_2 ; + smc->srf.TSR = smt_get_time() ; + smt_send_srf(smc) ; + break ; + } + /* SR00c */ + if (cond_deasserted && tsr >= T_Limit) { + smc->srf.TSR = smt_get_time() ; + smt_send_srf(smc) ; + break ; + } + /* SR00d */ + if (event_occured && tsr >= T_Limit) { + smc->srf.TSR = smt_get_time() ; + smt_send_srf(smc) ; + break ; + } + /* SR00e */ + if (smc->srf.any_report && (u_long) tsr >= + smc->srf.SRThreshold) { + smc->srf.SRThreshold *= 2 ; + if (smc->srf.SRThreshold > THRESHOLD_32) + smc->srf.SRThreshold = THRESHOLD_32 ; + smc->srf.TSR = smt_get_time() ; + smt_send_srf(smc) ; + break ; + } + /* SR02 */ + if (!smc->mib.fddiSMTStatRptPolicy) { + smc->srf.sr_state = SR2_DISABLED ; + break ; + } + break ; + case SR1_HOLDOFF : + /* SR10b */ + if (tsr >= T_Limit) { + smc->srf.sr_state = SR0_WAIT ; + smc->srf.TSR = smt_get_time() ; + smt_send_srf(smc) ; + break ; + } + /* SR11a */ + if (cond_asserted) { + smc->srf.SRThreshold = THRESHOLD_2 ; + } + /* SR11b */ + /* SR11c */ + /* handled above */ + /* SR12 */ + if (!smc->mib.fddiSMTStatRptPolicy) { + smc->srf.sr_state = SR2_DISABLED ; + break ; + } + break ; + case SR2_DISABLED : + if (smc->mib.fddiSMTStatRptPolicy) { + smc->srf.sr_state = SR0_WAIT ; + smc->srf.TSR = smt_get_time() ; + smc->srf.SRThreshold = THRESHOLD_2 ; + clear_all_rep(smc) ; + break ; + } + break ; + } +} + +static void clear_all_rep(smc) +struct s_smc *smc ; +{ + struct s_srf_evc *evc ; + int i ; + + for (i = 0, evc = smc->evcs ; (unsigned) i < MAX_EVCS ; i++, evc++) { + evc->evc_rep_required = FALSE ; + if (SMT_IS_CONDITION(evc->evc_code)) + *evc->evc_cond_state = FALSE ; + } + smc->srf.any_report = FALSE ; +} + +static void clear_reported(smc) +struct s_smc *smc ; +{ + struct s_srf_evc *evc ; + int i ; + + smc->srf.any_report = FALSE ; + for (i = 0, evc = smc->evcs ; (unsigned) i < MAX_EVCS ; i++, evc++) { + if (SMT_IS_CONDITION(evc->evc_code)) { + if (*evc->evc_cond_state == FALSE) + evc->evc_rep_required = FALSE ; + else + smc->srf.any_report = TRUE ; + } + else { + evc->evc_rep_required = FALSE ; + *evc->evc_multiple = FALSE ; + } + } +} + +extern SMbuf *smt_build_frame() ; + +/* + * build and send SMT SRF frame + */ +static void smt_send_srf(smc) +struct s_smc *smc ; +{ + + struct smt_header *smt ; + struct s_srf_evc *evc ; + SK_LOC_DECL(struct s_pcon,pcon) ; + SMbuf *mb ; + int i ; + + static const struct fddi_addr SMT_SRF_DA = { + 0x80, 0x01, 0x43, 0x00, 0x80, 0x08 + } ; + + /* + * build SMT header + */ + if (!smc->r.sm_ma_avail) + return ; + if (!(mb = smt_build_frame(smc,SMT_SRF,SMT_ANNOUNCE,0))) + return ; + + RS_SET(smc,RS_SOFTERROR) ; + + smt = smtod(mb, struct smt_header *) ; + smt->smt_dest = SMT_SRF_DA ; /* DA == SRF multicast */ + + /* + * setup parameter status + */ + pcon.pc_len = SMT_MAX_INFO_LEN ; /* max para length */ + pcon.pc_err = 0 ; /* no error */ + pcon.pc_badset = 0 ; /* no bad set count */ + pcon.pc_p = (void *) (smt + 1) ; /* paras start here */ + + smt_add_para(smc,&pcon,(u_short) SMT_P1033,0,0) ; + smt_add_para(smc,&pcon,(u_short) SMT_P1034,0,0) ; + + for (i = 0, evc = smc->evcs ; (unsigned) i < MAX_EVCS ; i++, evc++) { + if (evc->evc_rep_required) { + smt_add_para(smc,&pcon,evc->evc_para, + (int)evc->evc_index,0) ; + } + } + smt->smt_len = SMT_MAX_INFO_LEN - pcon.pc_len ; + mb->sm_len = smt->smt_len + sizeof(struct smt_header) ; + + DB_SMT("SRF: sending SRF at %x, len %d \n",smt,mb->sm_len) ; + DB_SMT("SRF: state SR%d Threshold %d\n", + smc->srf.sr_state,smc->srf.SRThreshold/TICKS_PER_SECOND) ; +#ifdef DEBUG + dump_smt(smc,smt,"SRF Send") ; +#endif + smt_send_frame(smc,mb,FC_SMT_INFO,0) ; + clear_reported(smc) ; +} + +#endif /* no BOOT */ +#endif /* no SLIM_SMT */ diff -u --recursive --new-file v2.3.46/linux/drivers/net/slip.c linux/drivers/net/slip.c --- v2.3.46/linux/drivers/net/slip.c Thu Feb 10 17:11:11 2000 +++ linux/drivers/net/slip.c Thu Feb 17 09:18:47 2000 @@ -449,7 +449,7 @@ struct slip *sl = (struct slip *) tty->disc_data; /* First make sure we're connected. */ - if (!sl || sl->magic != SLIP_MAGIC || !test_bit(LINK_STATE_START, &sl->dev->state)) { + if (!sl || sl->magic != SLIP_MAGIC || !netif_running(sl->dev)) { return; } if (sl->xleft <= 0) { @@ -472,10 +472,10 @@ spin_lock(&sl->lock); - if (test_bit(LINK_STATE_XOFF, &dev->state)) { + if (netif_queue_stopped(dev)) { struct slip *sl = (struct slip*)(dev->priv); - if (!test_bit(LINK_STATE_START, &dev->state)) + if (!netif_running(dev)) goto out; /* May be we must check transmitter timeout here ? @@ -507,7 +507,7 @@ struct slip *sl = (struct slip*)(dev->priv); spin_lock(&sl->lock); - if (!test_bit(LINK_STATE_START, &dev->state)) { + if (!netif_running(dev)) { spin_unlock(&sl->lock); printk("%s: xmit call when iface is down\n", dev->name); dev_kfree_skb(skb); @@ -679,7 +679,7 @@ struct slip *sl = (struct slip *) tty->disc_data; if (!sl || sl->magic != SLIP_MAGIC || - !test_bit(LINK_STATE_START, &sl->dev->state)) + !netif_running(sl->dev)) return; /* Read the characters out of the buffer */ @@ -1468,7 +1468,7 @@ unsigned char s = END; #endif /* put END into tty queue. Is it right ??? */ - if (!test_bit(LINK_STATE_XOFF, &sl->dev->state)) + if (!netif_queue_stopped(sl->dev)) { /* if device busy no outfill */ sl->tty->driver.write(sl->tty, 0, &s, 1); diff -u --recursive --new-file v2.3.46/linux/drivers/net/starfire.c linux/drivers/net/starfire.c --- v2.3.46/linux/drivers/net/starfire.c Thu Feb 10 17:11:11 2000 +++ linux/drivers/net/starfire.c Fri Feb 18 15:07:20 2000 @@ -813,7 +813,7 @@ np->rx_info[i].skb = skb; if (skb == NULL) break; - np->rx_info[i].mapping = pci_map_single(np->pdev, skb->tail, np->rx_buf_sz); + np->rx_info[i].mapping = pci_map_single(np->pdev, skb->tail, np->rx_buf_sz, PCI_DMA_FROMDEVICE); skb->dev = dev; /* Mark as being used by this device. */ /* Grrr, we cannot offset to correctly align the IP header. */ np->rx_ring[i].rxaddr = cpu_to_le32(np->rx_info[i].mapping | RxDescValid); @@ -859,7 +859,7 @@ np->tx_info[entry].skb = skb; np->tx_info[entry].mapping = - pci_map_single(np->pdev, skb->data, skb->len); + pci_map_single(np->pdev, skb->data, skb->len, PCI_DMA_TODEVICE); np->tx_ring[entry].addr = cpu_to_le32(np->tx_info[entry].mapping); /* Add |TxDescIntr to generate Tx-done interrupts. */ @@ -959,10 +959,10 @@ skb = np->tx_info[entry].skb; pci_unmap_single(np->pdev, np->tx_info[entry].mapping, - skb->len); + skb->len, PCI_DMA_TODEVICE); /* Scavenge the descriptor. */ - kfree_skb(skb); + dev_kfree_skb_irq(skb); np->tx_info[entry].skb = NULL; np->tx_info[entry].mapping = 0; np->dirty_tx++; @@ -1044,7 +1044,7 @@ skb_reserve(skb, 2); /* 16 byte align the IP header */ pci_dma_sync_single(np->pdev, np->rx_info[entry].mapping, - pkt_len); + pkt_len, PCI_DMA_FROMDEVICE); #if HAS_IP_COPYSUM /* Call copy + cksum if available. */ eth_copy_and_sum(skb, np->rx_info[entry].skb->tail, pkt_len, 0); skb_put(skb, pkt_len); @@ -1055,7 +1055,7 @@ } else { char *temp; - pci_unmap_single(np->pdev, np->rx_info[entry].mapping, np->rx_buf_sz); + pci_unmap_single(np->pdev, np->rx_info[entry].mapping, np->rx_buf_sz, PCI_DMA_FROMDEVICE); skb = np->rx_info[entry].skb; temp = skb_put(skb, pkt_len); np->rx_info[entry].skb = NULL; @@ -1099,7 +1099,7 @@ if (skb == NULL) break; /* Better luck next round. */ np->rx_info[entry].mapping = - pci_map_single(np->pdev, skb->tail, np->rx_buf_sz); + pci_map_single(np->pdev, skb->tail, np->rx_buf_sz, PCI_DMA_FROMDEVICE); skb->dev = dev; /* Mark as being used by this device. */ np->rx_ring[entry].rxaddr = cpu_to_le32(np->rx_info[entry].mapping | RxDescValid); @@ -1324,8 +1324,8 @@ for (i = 0; i < RX_RING_SIZE; i++) { np->rx_ring[i].rxaddr = cpu_to_le32(0xBADF00D0); /* An invalid address. */ if (np->rx_info[i].skb != NULL) { - pci_unmap_single(np->pdev, np->rx_info[i].mapping, np->rx_buf_sz); - kfree_skb(np->rx_info[i].skb); + pci_unmap_single(np->pdev, np->rx_info[i].mapping, np->rx_buf_sz, PCI_DMA_FROMDEVICE); + dev_kfree_skb(np->rx_info[i].skb); } np->rx_info[i].skb = NULL; np->rx_info[i].mapping = 0; @@ -1335,8 +1335,8 @@ if (skb != NULL) { pci_unmap_single(np->pdev, np->tx_info[i].mapping, - skb->len); - kfree_skb(skb); + skb->len, PCI_DMA_TODEVICE); + dev_kfree_skb(skb); } np->tx_info[i].skb = NULL; np->tx_info[i].mapping = 0; diff -u --recursive --new-file v2.3.46/linux/drivers/net/strip.c linux/drivers/net/strip.c --- v2.3.46/linux/drivers/net/strip.c Sun Feb 13 19:29:04 2000 +++ linux/drivers/net/strip.c Thu Feb 17 09:18:47 2000 @@ -1354,7 +1354,7 @@ /* First make sure we're connected. */ if (!strip_info || strip_info->magic != STRIP_MAGIC || - !test_bit(LINK_STATE_START, &strip_info->dev.state)) + !netif_running(&strip_info->dev)) return; if (strip_info->tx_left > 0) @@ -1644,7 +1644,7 @@ { struct strip *strip_info = (struct strip *)(dev->priv); - if (!test_bit(LINK_STATE_START, &dev->state)) + if (!netif_running(dev)) { printk(KERN_ERR "%s: xmit call when iface is down\n", dev->name); return(1); @@ -2338,7 +2338,7 @@ const unsigned char *end = cp + count; if (!strip_info || strip_info->magic != STRIP_MAGIC - || !test_bit(LINK_STATE_START, &strip_info->dev.state)) + || !netif_running(&strip_info->dev)) return; /* Argh! mtu change time! - costs us the packet part received at the change */ diff -u --recursive --new-file v2.3.46/linux/drivers/net/sunbmac.c linux/drivers/net/sunbmac.c --- v2.3.46/linux/drivers/net/sunbmac.c Sat Feb 12 11:22:10 2000 +++ linux/drivers/net/sunbmac.c Fri Feb 18 15:07:20 2000 @@ -1,4 +1,4 @@ -/* $Id: sunbmac.c,v 1.15 2000/02/10 21:14:22 davem Exp $ +/* $Id: sunbmac.c,v 1.18 2000/02/18 13:49:21 davem Exp $ * sunbmac.c: Driver for Sparc BigMAC 100baseT ethernet adapters. * * Copyright (C) 1997, 1998, 1999 David S. Miller (davem@redhat.com) @@ -190,20 +190,14 @@ for (i = 0; i < RX_RING_SIZE; i++) { if (bp->rx_skbs[i] != NULL) { - if (in_irq()) - dev_kfree_skb_irq(bp->rx_skbs[i]); - else - dev_kfree_skb(bp->rx_skbs[i]); + dev_kfree_skb_any(bp->rx_skbs[i]); bp->rx_skbs[i] = NULL; } } for (i = 0; i < TX_RING_SIZE; i++) { if (bp->tx_skbs[i] != NULL) { - if (in_irq()) - dev_kfree_skb_irq(bp->tx_skbs[i]); - else - dev_kfree_skb(bp->tx_skbs[i]); + dev_kfree_skb_any(bp->tx_skbs[i]); bp->tx_skbs[i] = NULL; } } @@ -240,7 +234,8 @@ bb->be_rxd[i].rx_addr = sbus_map_single(bp->bigmac_sdev, skb->data, - RX_BUF_ALLOC_SIZE - 34); + RX_BUF_ALLOC_SIZE - 34, + SBUS_DMA_FROMDEVICE); bb->be_rxd[i].rx_flags = (RXD_OWN | ((RX_BUF_ALLOC_SIZE - 34) & RXD_LENGTH)); } @@ -776,7 +771,8 @@ bp->enet_stats.tx_packets++; bp->enet_stats.tx_bytes += skb->len; sbus_unmap_single(bp->bigmac_sdev, - this->tx_addr, skb->len); + this->tx_addr, skb->len, + SBUS_DMA_TODEVICE); DTX(("skb(%p) ", skb)); bp->tx_skbs[elem] = NULL; @@ -787,7 +783,7 @@ DTX((" DONE, tx_old=%d\n", elem)); bp->tx_old = elem; - if (test_bit(LINK_STATE_XOFF, &dev->state) && + if (netif_queue_stopped(dev) && TX_BUFFS_AVAIL(bp) > 0) netif_wake_queue(bp->dev); @@ -831,14 +827,16 @@ } sbus_unmap_single(bp->bigmac_sdev, this->rx_addr, - RX_BUF_ALLOC_SIZE - 34); + RX_BUF_ALLOC_SIZE - 34, + SBUS_DMA_FROMDEVICE); bp->rx_skbs[elem] = new_skb; new_skb->dev = bp->dev; skb_put(new_skb, ETH_FRAME_LEN); skb_reserve(new_skb, 34); this->rx_addr = sbus_map_single(bp->bigmac_sdev, new_skb->data, - RX_BUF_ALLOC_SIZE - 34); + RX_BUF_ALLOC_SIZE - 34, + SBUS_DMA_FROMDEVICE); this->rx_flags = (RXD_OWN | ((RX_BUF_ALLOC_SIZE - 34) & RXD_LENGTH)); @@ -855,7 +853,7 @@ skb_reserve(copy_skb, 2); skb_put(copy_skb, len); sbus_dma_sync_single(bp->bigmac_sdev, - this->rx_addr, len); + this->rx_addr, len, SBUS_DMA_FROMDEVICE); eth_copy_and_sum(copy_skb, (unsigned char *)skb->data, len, 0); /* Reuse original ring buffer. */ @@ -951,7 +949,7 @@ u32 mapping; len = skb->len; - mapping = sbus_map_single(bp->bigmac_sdev, skb->data, len); + mapping = sbus_map_single(bp->bigmac_sdev, skb->data, len, SBUS_DMA_TODEVICE); /* Avoid a race... */ spin_lock_irq(&bp->lock); diff -u --recursive --new-file v2.3.46/linux/drivers/net/sunhme.c linux/drivers/net/sunhme.c --- v2.3.46/linux/drivers/net/sunhme.c Sat Feb 12 11:22:10 2000 +++ linux/drivers/net/sunhme.c Fri Feb 18 15:07:20 2000 @@ -1,4 +1,4 @@ -/* $Id: sunhme.c,v 1.87 2000/02/10 21:14:22 davem Exp $ +/* $Id: sunhme.c,v 1.92 2000/02/18 13:49:22 davem Exp $ * sunhme.c: Sparc HME/BigMac 10/100baseT half/full duplex auto switching, * auto carrier detecting ethernet driver. Also known as the * "Happy Meal Ethernet" found on SunSwift SBUS cards. @@ -152,6 +152,13 @@ #define DEFAULT_IPG2 4 /* For all modes */ #define DEFAULT_JAMSIZE 4 /* Toe jam */ +/* NOTE: In the descriptor writes one _must_ write the address + * member _first_. The card must not be allowed to see + * the updated descriptor flags until the address is + * correct. I've added a write memory barrier between + * the two stores so that I can sleep well at night... -DaveM + */ + #if defined(CONFIG_SBUS) && defined(CONFIG_PCI) static void sbus_hme_write32(unsigned long reg, u32 val) { @@ -166,13 +173,15 @@ static void sbus_hme_write_rxd(struct happy_meal_rxd *rxd, u32 flags, u32 addr) { rxd->rx_addr = addr; + wmb(); rxd->rx_flags = flags; } static void sbus_hme_write_txd(struct happy_meal_txd *txd, u32 flags, u32 addr) { - txd->tx_flags = flags; txd->tx_addr = addr; + wmb(); + txd->tx_flags = flags; } static u32 sbus_hme_read_desc32(u32 *p) @@ -193,18 +202,20 @@ static void pci_hme_write_rxd(struct happy_meal_rxd *rxd, u32 flags, u32 addr) { rxd->rx_addr = cpu_to_le32(addr); + wmb(); rxd->rx_flags = cpu_to_le32(flags); } static void pci_hme_write_txd(struct happy_meal_txd *txd, u32 flags, u32 addr) { - txd->tx_flags = cpu_to_le32(flags); txd->tx_addr = cpu_to_le32(addr); + wmb(); + txd->tx_flags = cpu_to_le32(flags); } static u32 pci_hme_read_desc32(u32 *p) { - return cpu_to_le32(*p); + return cpu_to_le32p(p); } #define hme_write32(__hp, __reg, __val) \ @@ -217,12 +228,12 @@ ((__hp)->write_txd((__txd), (__flags), (__addr))) #define hme_read_desc32(__hp, __p) \ ((__hp)->read_desc32(__p)) -#define hme_dma_map(__hp, __ptr, __size) \ - ((__hp)->dma_map((__hp)->happy_dev, (__ptr), (__size))) -#define hme_dma_unmap(__hp, __addr, __size) \ - ((__hp)->dma_unmap((__hp)->happy_dev, (__addr), (__size))) -#define hme_dma_sync(__hp, __addr, __size) \ - ((__hp)->dma_sync((__hp)->happy_dev, (__addr), (__size))) +#define hme_dma_map(__hp, __ptr, __size, __dir) \ + ((__hp)->dma_map((__hp)->happy_dev, (__ptr), (__size), (__dir))) +#define hme_dma_unmap(__hp, __addr, __size, __dir) \ + ((__hp)->dma_unmap((__hp)->happy_dev, (__addr), (__size), (__dir))) +#define hme_dma_sync(__hp, __addr, __size, __dir) \ + ((__hp)->dma_sync((__hp)->happy_dev, (__addr), (__size), (__dir))) #else #ifdef CONFIG_SBUS /* SBUS only compilation */ @@ -232,19 +243,21 @@ sbus_readl(__reg) #define hme_write_rxd(__hp, __rxd, __flags, __addr) \ do { (__rxd)->rx_addr = (__addr); \ + wmb(); \ (__rxd)->rx_flags = (__flags); \ } while(0) #define hme_write_txd(__hp, __txd, __flags, __addr) \ do { (__txd)->tx_addr = (__addr); \ + wmb(); \ (__txd)->tx_flags = (__flags); \ } while(0) #define hme_read_desc32(__hp, __p) (*(__p)) -#define hme_dma_map(__hp, __ptr, __size) \ - sbus_map_single((__hp)->happy_dev, (__ptr), (__size)) +#define hme_dma_map(__hp, __ptr, __size, __dir) \ + sbus_map_single((__hp)->happy_dev, (__ptr), (__size), (__dir)) #define hme_dma_unmap(__hp, __addr, __size) \ - sbus_unmap_single((__hp)->happy_dev, (__addr), (__size)) -#define hme_dma_sync(__hp, __addr, __size) \ - sbus_dma_sync_single((__hp)->happy_dev, (__addr), (__size)) + sbus_unmap_single((__hp)->happy_dev, (__addr), (__size), (__dir)) +#define hme_dma_sync(__hp, __addr, __size, __dir) \ + sbus_dma_sync_single((__hp)->happy_dev, (__addr), (__size), (__dir)) #else /* PCI only compilation */ #define hme_write32(__hp, __reg, __val) \ @@ -253,22 +266,28 @@ readl(__reg) #define hme_write_rxd(__hp, __rxd, __flags, __addr) \ do { (__rxd)->rx_addr = cpu_to_le32(__addr); \ + wmb(); \ (__rxd)->rx_flags = cpu_to_le32(__flags); \ } while(0) #define hme_write_txd(__hp, __txd, __flags, __addr) \ do { (__txd)->tx_addr = cpu_to_le32(__addr); \ + wmb(); \ (__txd)->tx_flags = cpu_to_le32(__flags); \ } while(0) -#define hme_read_desc32(__hp, __p) cpu_to_le32(*(__p)) -#define hme_dma_map(__hp, __ptr, __size) \ - pci_map_single((__hp)->happy_dev, (__ptr), (__size)) -#define hme_dma_unmap(__hp, __addr, __size) \ - pci_unmap_single((__hp)->happy_dev, (__addr), (__size)) -#define hme_dma_sync(__hp, __addr, __size) \ - pci_dma_sync_single((__hp)->happy_dev, (__addr), (__size)) +#define hme_read_desc32(__hp, __p) cpu_to_le32p(__p) +#define hme_dma_map(__hp, __ptr, __size, __dir) \ + pci_map_single((__hp)->happy_dev, (__ptr), (__size), (__dir)) +#define hme_dma_unmap(__hp, __addr, __size, __dir) \ + pci_unmap_single((__hp)->happy_dev, (__addr), (__size), (__dir)) +#define hme_dma_sync(__hp, __addr, __size, __dir) \ + pci_dma_sync_single((__hp)->happy_dev, (__addr), (__size), (__dir)) #endif #endif +#define DMA_BIDIRECTIONAL SBUS_DMA_BIDIRECTIONAL +#define DMA_FROMDEVICE SBUS_DMA_FROMDEVICE +#define DMA_TODEVICE SBUS_DMA_TODEVICE + /* Oh yes, the MIF BitBang is mighty fun to program. BitBucket is more like it. */ static void BB_PUT_BIT(struct happy_meal *hp, unsigned long tregs, int bit) { @@ -1193,11 +1212,8 @@ rxd = &hp->happy_block->happy_meal_rxd[i]; dma_addr = hme_read_desc32(hp, &rxd->rx_addr); - hme_dma_unmap(hp, dma_addr, RX_BUF_ALLOC_SIZE); - if (in_irq()) - dev_kfree_skb_irq(skb); - else - dev_kfree_skb(skb); + hme_dma_unmap(hp, dma_addr, RX_BUF_ALLOC_SIZE, DMA_FROMDEVICE); + dev_kfree_skb_any(skb); hp->rx_skbs[i] = NULL; } } @@ -1210,11 +1226,8 @@ txd = &hp->happy_block->happy_meal_txd[i]; dma_addr = hme_read_desc32(hp, &txd->tx_addr); - hme_dma_unmap(hp, dma_addr, skb->len); - if (in_irq()) - dev_kfree_skb_irq(skb); - else - dev_kfree_skb(skb); + hme_dma_unmap(hp, dma_addr, skb->len, DMA_TODEVICE); + dev_kfree_skb_any(skb); hp->tx_skbs[i] = NULL; } } @@ -1253,7 +1266,7 @@ skb_put(skb, (ETH_FRAME_LEN + RX_OFFSET)); hme_write_rxd(hp, &hb->happy_meal_rxd[i], (RXFLAG_OWN | ((RX_BUF_ALLOC_SIZE - RX_OFFSET) << 16)), - hme_dma_map(hp, skb->data, RX_BUF_ALLOC_SIZE)); + hme_dma_map(hp, skb->data, RX_BUF_ALLOC_SIZE, DMA_FROMDEVICE)); skb_reserve(skb, RX_OFFSET); } @@ -1895,7 +1908,7 @@ break; dma_addr = hme_read_desc32(hp, &this->tx_addr); skb = hp->tx_skbs[elem]; - hme_dma_unmap(hp, dma_addr, skb->len); + hme_dma_unmap(hp, dma_addr, skb->len, DMA_TODEVICE); hp->tx_skbs[elem] = NULL; hp->net_stats.tx_bytes += skb->len; @@ -1907,7 +1920,7 @@ hp->tx_old = elem; TXD((">")); - if (test_bit(LINK_STATE_XOFF, &dev->state) && + if (netif_queue_stopped(dev) && TX_BUFFS_AVAIL(hp) > 0) netif_wake_queue(dev); @@ -1973,13 +1986,13 @@ drops++; goto drop_it; } - hme_dma_unmap(hp, dma_addr, RX_BUF_ALLOC_SIZE); + hme_dma_unmap(hp, dma_addr, RX_BUF_ALLOC_SIZE, DMA_FROMDEVICE); hp->rx_skbs[elem] = new_skb; new_skb->dev = dev; skb_put(new_skb, (ETH_FRAME_LEN + RX_OFFSET)); hme_write_rxd(hp, this, (RXFLAG_OWN|((RX_BUF_ALLOC_SIZE-RX_OFFSET)<<16)), - hme_dma_map(hp, new_skb->data, RX_BUF_ALLOC_SIZE)); + hme_dma_map(hp, new_skb->data, RX_BUF_ALLOC_SIZE, DMA_FROMDEVICE)); skb_reserve(new_skb, RX_OFFSET); /* Trim the original skb for the netif. */ @@ -1995,7 +2008,7 @@ copy_skb->dev = dev; skb_reserve(copy_skb, 2); skb_put(copy_skb, len); - hme_dma_sync(hp, dma_addr, len); + hme_dma_sync(hp, dma_addr, len, DMA_FROMDEVICE); memcpy(copy_skb->data, skb->data, len); /* Reuse original ring buffer. */ @@ -2178,7 +2191,7 @@ u32 mapping; len = skb->len; - mapping = hme_dma_map(hp, skb->data, len); + mapping = hme_dma_map(hp, skb->data, len, DMA_TODEVICE); spin_lock_irq(&hp->happy_lock); @@ -2192,10 +2205,11 @@ if (TX_BUFFS_AVAIL(hp) <= 0) netif_stop_queue(dev); - spin_unlock_irq(&hp->happy_lock); - /* Get it going. */ hme_write32(hp, hp->etxregs + ETX_PENDING, ETX_TP_DMAWAKEUP); + + spin_unlock_irq(&hp->happy_lock); + dev->trans_start = jiffies; tx_add_log(hp, TXLOG_ACTION_TXMIT, 0); @@ -2642,9 +2656,9 @@ hp->read_desc32 = sbus_hme_read_desc32; hp->write_txd = sbus_hme_write_txd; hp->write_rxd = sbus_hme_write_rxd; - hp->dma_map = (u32 (*)(void *, void *, long))sbus_map_single; - hp->dma_unmap = (void (*)(void *, u32, long))sbus_unmap_single; - hp->dma_sync = (void (*)(void *, u32, long))sbus_dma_sync_single; + hp->dma_map = (u32 (*)(void *, void *, long, int))sbus_map_single; + hp->dma_unmap = (void (*)(void *, u32, long, int))sbus_unmap_single; + hp->dma_sync = (void (*)(void *, u32, long, int))sbus_dma_sync_single; hp->read32 = sbus_hme_read32; hp->write32 = sbus_hme_write32; #endif @@ -2817,9 +2831,9 @@ hp->read_desc32 = pci_hme_read_desc32; hp->write_txd = pci_hme_write_txd; hp->write_rxd = pci_hme_write_rxd; - hp->dma_map = (u32 (*)(void *, void *, long))pci_map_single; - hp->dma_unmap = (void (*)(void *, u32, long))pci_unmap_single; - hp->dma_sync = (void (*)(void *, u32, long))pci_dma_sync_single; + hp->dma_map = (u32 (*)(void *, void *, long, int))pci_map_single; + hp->dma_unmap = (void (*)(void *, u32, long, int))pci_unmap_single; + hp->dma_sync = (void (*)(void *, u32, long, int))pci_dma_sync_single; hp->read32 = pci_hme_read32; hp->write32 = pci_hme_write32; #endif diff -u --recursive --new-file v2.3.46/linux/drivers/net/sunhme.h linux/drivers/net/sunhme.h --- v2.3.46/linux/drivers/net/sunhme.h Thu Feb 10 17:11:11 2000 +++ linux/drivers/net/sunhme.h Fri Feb 18 15:07:20 2000 @@ -1,4 +1,4 @@ -/* $Id: sunhme.h,v 1.29 2000/02/09 11:15:40 davem Exp $ +/* $Id: sunhme.h,v 1.30 2000/02/18 13:49:26 davem Exp $ * sunhme.h: Definitions for Sparc HME/BigMac 10/100baseT ethernet driver. * Also known as the "Happy Meal". * @@ -502,9 +502,9 @@ u32 (*read_desc32)(u32 *); void (*write_txd)(struct happy_meal_txd *, u32, u32); void (*write_rxd)(struct happy_meal_rxd *, u32, u32); - u32 (*dma_map)(void *, void *, long); - void (*dma_unmap)(void *, u32, long); - void (*dma_sync)(void *, u32, long); + u32 (*dma_map)(void *, void *, long, int); + void (*dma_unmap)(void *, u32, long, int); + void (*dma_sync)(void *, u32, long, int); #endif /* This is either a sbus_dev or a pci_dev. */ diff -u --recursive --new-file v2.3.46/linux/drivers/net/sunlance.c linux/drivers/net/sunlance.c --- v2.3.46/linux/drivers/net/sunlance.c Wed Feb 16 17:03:52 2000 +++ linux/drivers/net/sunlance.c Thu Feb 17 09:18:47 2000 @@ -1,4 +1,4 @@ -/* $Id: sunlance.c,v 1.97 2000/02/14 09:02:32 davem Exp $ +/* $Id: sunlance.c,v 1.99 2000/02/16 10:36:14 davem Exp $ * lance.c: Linux/Sparc/Lance driver * * Written 1995, 1996 by Miguel de Icaza @@ -640,11 +640,11 @@ j = TX_NEXT(j); } lp->tx_old = j; - - if (test_bit(LINK_STATE_XOFF, &dev->state) && +out: + if (netif_queue_stopped(dev) && TX_BUFFS_AVAIL > 0) netif_wake_queue(dev); -out: + spin_unlock(&lp->lock); } @@ -812,7 +812,7 @@ } lp->tx_old = j; - if (test_bit(LINK_STATE_XOFF, &dev->state) && + if (netif_queue_stopped(dev) && TX_BUFFS_AVAIL > 0) netif_wake_queue(dev); out: @@ -1247,7 +1247,7 @@ volatile struct lance_init_block *ib = lp->init_block; u16 mode; - if (!test_bit(LINK_STATE_START, &dev->state)) + if (!netif_running(dev)) return; if (lp->tx_old != lp->tx_new) { diff -u --recursive --new-file v2.3.46/linux/drivers/net/sunqe.c linux/drivers/net/sunqe.c --- v2.3.46/linux/drivers/net/sunqe.c Sat Feb 12 11:22:10 2000 +++ linux/drivers/net/sunqe.c Thu Feb 17 09:18:47 2000 @@ -1,4 +1,4 @@ -/* $Id: sunqe.c,v 1.44 2000/02/10 21:14:25 davem Exp $ +/* $Id: sunqe.c,v 1.45 2000/02/16 10:36:20 davem Exp $ * sunqe.c: Sparc QuadEthernet 10baseT SBUS card driver. * Once again I am out to prove that every ethernet * controller out there can be most efficiently programmed @@ -481,7 +481,7 @@ } if (qe_status & CREG_STAT_RXIRQ) qe_rx(qep); - if (test_bit(LINK_STATE_XOFF, &qep->dev->state) && + if (netif_queue_stopped(qep->dev) && (qe_status & CREG_STAT_TXIRQ)) { spin_lock(&qep->lock); qe_tx_reclaim(qep); diff -u --recursive --new-file v2.3.46/linux/drivers/net/tlan.c linux/drivers/net/tlan.c --- v2.3.46/linux/drivers/net/tlan.c Sat Feb 12 11:22:10 2000 +++ linux/drivers/net/tlan.c Thu Feb 17 15:32:46 2000 @@ -694,10 +694,7 @@ if ( ! priv->phyOnline ) { TLAN_DBG( TLAN_DEBUG_TX, "TRANSMIT: %s PHY is not ready\n", dev->name ); - if (in_irq()) - dev_kfree_skb_irq(skb); - else - dev_kfree_skb(skb); + dev_kfree_skb_any(skb); return 0; } @@ -754,12 +751,8 @@ CIRC_INC( priv->txTail, TLAN_NUM_TX_LISTS ); - if ( bbuf ) { - if (in_irq()) - dev_kfree_skb_irq(skb); - else - dev_kfree_skb(skb); - } + if ( bbuf ) + dev_kfree_skb_any(skb); dev->trans_start = jiffies; return 0; @@ -1626,10 +1619,7 @@ list = priv->txList + i; skb = (struct sk_buff *) list->buffer[9].address; if ( skb ) { - if (in_irq()) - dev_kfree_skb_irq( skb ); - else - dev_kfree_skb( skb ); + dev_kfree_skb_any( skb ); list->buffer[9].address = 0; } } @@ -1638,10 +1628,7 @@ list = priv->rxList + i; skb = (struct sk_buff *) list->buffer[9].address; if ( skb ) { - if (in_irq()) - dev_kfree_skb_irq( skb ); - else - dev_kfree_skb( skb ); + dev_kfree_skb_any( skb ); list->buffer[9].address = 0; } } diff -u --recursive --new-file v2.3.46/linux/drivers/net/tokenring/ibmtr.c linux/drivers/net/tokenring/ibmtr.c --- v2.3.46/linux/drivers/net/tokenring/ibmtr.c Sat Feb 12 11:22:10 2000 +++ linux/drivers/net/tokenring/ibmtr.c Thu Feb 17 09:18:47 2000 @@ -1177,7 +1177,7 @@ DPRINTK("New ring status: %02X\n", ring_status); if (ring_status & LOG_OVERFLOW) { - if (test_bit(LINK_STATE_XOFF, &dev->state)) + if (netif_queue_stopped(dev)) ti->readlog_pending = 1; else ibmtr_readlog(dev); diff -u --recursive --new-file v2.3.46/linux/drivers/net/tokenring/olympic.c linux/drivers/net/tokenring/olympic.c --- v2.3.46/linux/drivers/net/tokenring/olympic.c Sat Feb 12 11:22:10 2000 +++ linux/drivers/net/tokenring/olympic.c Thu Feb 17 09:18:47 2000 @@ -1152,7 +1152,7 @@ struct sockaddr *saddr = addr ; struct olympic_private *olympic_priv = (struct olympic_private *)dev->priv ; - if (test_bit(LINK_STATE_START, &dev->state)) { + if (netif_running(dev)) { printk(KERN_WARNING "%s: Cannot set mac/laa address while card is open\n", dev->name) ; return -EIO ; } diff -u --recursive --new-file v2.3.46/linux/drivers/net/tulip.c linux/drivers/net/tulip.c --- v2.3.46/linux/drivers/net/tulip.c Wed Feb 16 17:03:52 2000 +++ linux/drivers/net/tulip.c Sun Feb 20 20:13:21 2000 @@ -142,7 +142,7 @@ #include #include #include - +#include /* A few user-configurable values. */ @@ -259,7 +259,7 @@ enum tbl_flag { HAS_MII=1, HAS_MEDIA_TABLE=2, CSR12_IN_SROM=4, ALWAYS_CHECK_MII=8, - HAS_PWRDWN=0x10, MC_HASH_ONLY=0x20, /* Hash-only multicast filter. */ + HAS_ACPI=0x10, MC_HASH_ONLY=0x20, /* Hash-only multicast filter. */ HAS_PNICNWAY=0x80, HAS_NWAY143=0x40, /* Uses internal NWay xcvr. */ HAS_8023X=0x100, }; @@ -275,7 +275,7 @@ { "Digital DS21140 Tulip", 128, 0x0001ebef, HAS_MII | HAS_MEDIA_TABLE | CSR12_IN_SROM, tulip_timer }, { "Digital DS21143 Tulip", 128, 0x0801fbff, - HAS_MII | HAS_MEDIA_TABLE | ALWAYS_CHECK_MII | HAS_PWRDWN | HAS_NWAY143, + HAS_MII | HAS_MEDIA_TABLE | ALWAYS_CHECK_MII | HAS_ACPI | HAS_NWAY143, t21142_timer }, { "Lite-On 82c168 PNIC", 256, 0x0001ebef, HAS_MII | HAS_PNICNWAY, pnic_timer }, @@ -294,10 +294,10 @@ { "Compex 9881 PMAC", 128, 0x0001ebef, HAS_MII | HAS_MEDIA_TABLE | CSR12_IN_SROM, mxic_timer }, { "Intel DS21145 Tulip", 128, 0x0801fbff, - HAS_MII | HAS_MEDIA_TABLE | ALWAYS_CHECK_MII | HAS_PWRDWN | HAS_NWAY143, + HAS_MII | HAS_MEDIA_TABLE | ALWAYS_CHECK_MII | HAS_NWAY143, t21142_timer }, { "Xircom tulip work-alike", 128, 0x0801fbff, - HAS_MII | HAS_MEDIA_TABLE | ALWAYS_CHECK_MII | HAS_PWRDWN | HAS_NWAY143, + HAS_MII | HAS_MEDIA_TABLE | ALWAYS_CHECK_MII | HAS_ACPI | HAS_NWAY143, t21142_timer }, {0}, }; @@ -316,7 +316,7 @@ COMET, COMPEX9881, I21145, - XIRCLONE, + X3201_3, }; @@ -334,7 +334,7 @@ { 0x1317, 0x0981, PCI_ANY_ID, PCI_ANY_ID, 0, 0, COMET }, { 0x11F6, 0x9881, PCI_ANY_ID, PCI_ANY_ID, 0, 0, COMPEX9881 }, { 0x8086, 0x0039, PCI_ANY_ID, PCI_ANY_ID, 0, 0, I21145 }, - { 0x115d, 0x0003, PCI_ANY_ID, PCI_ANY_ID, 0, 0, XIRCLONE }, + { 0x115d, 0x0003, PCI_ANY_ID, PCI_ANY_ID, 0, 0, X3201_3 }, {0}, }; MODULE_DEVICE_TABLE(pci,tulip_pci_tbl); @@ -465,6 +465,7 @@ int ttimer; int susp_rx; unsigned long nir; + unsigned long base_addr; int pad0, pad1; /* Used for 8-byte alignment */ }; @@ -473,7 +474,6 @@ static int mdio_read(struct net_device *dev, int phy_id, int location); static void mdio_write(struct net_device *dev, int phy_id, int location, int value); static void select_media(struct net_device *dev, int startup); -static int tulip_open(struct net_device *dev); /* Chip-specific media selection (timer functions prototyped above). */ static void t21142_lnk_change(struct net_device *dev, int csr5); static void t21142_start_nway(struct net_device *dev); @@ -486,7 +486,10 @@ static int tulip_refill_rx(struct net_device *dev); static int tulip_rx(struct net_device *dev); static void tulip_interrupt(int irq, void *dev_instance, struct pt_regs *regs); +static int tulip_open(struct net_device *dev); static int tulip_close(struct net_device *dev); +static void tulip_up(struct net_device *dev); +static void tulip_down(struct net_device *dev); static struct net_device_stats *tulip_get_stats(struct net_device *dev); static int private_ioctl(struct net_device *dev, struct ifreq *rq, int cmd); static void set_rx_mode(struct net_device *dev); @@ -725,7 +728,7 @@ #define EE_READ_CMD (6) /* Note: this routine returns extra data bits for size detection. */ -static int read_eeprom(long ioaddr, int location, int addr_len) +static int __devinit read_eeprom(long ioaddr, int location, int addr_len) { int i; unsigned retval = 0; @@ -893,9 +896,60 @@ return; } - -static int -tulip_open(struct net_device *dev) + +/* The Xircom cards are picky about when certain bits in CSR6 can be + manipulated. Keith Owens . */ + +static void outl_CSR6 (struct tulip_private *tp, u32 newcsr6) +{ + long ioaddr = tp->base_addr; + const int strict_bits = 0x0060e202; + int csr5, csr5_22_20, csr5_19_17, currcsr6, attempts = 200; + long flags; + + /* really a hw lock */ + spin_lock_irqsave (&tp->tx_lock, flags); + + if (tp->chip_id != X3201_3) + goto out_write; + + newcsr6 &= 0x726cfeca; /* mask out the reserved CSR6 bits that always */ + /* read 0 on the Xircom cards */ + newcsr6 |= 0x320c0000; /* or in the reserved bits that always read 1 */ + currcsr6 = inl (ioaddr + CSR6); + if (((newcsr6 & strict_bits) == (currcsr6 & strict_bits)) || + ((currcsr6 & ~0x2002) == 0)) + goto out_write; + + /* make sure the transmitter and receiver are stopped first */ + currcsr6 &= ~0x2002; + while (1) { + csr5 = inl (ioaddr + CSR5); + if (csr5 == 0xffffffff) + break; /* cannot read csr5, card removed? */ + csr5_22_20 = csr5 & 0x700000; + csr5_19_17 = csr5 & 0x0e0000; + if ((csr5_22_20 == 0 || csr5_22_20 == 0x600000) && + (csr5_19_17 == 0 || csr5_19_17 == 0x80000 || csr5_19_17 == 0xc0000)) + break; /* both are stopped or suspended */ + if (!--attempts) { + printk (KERN_INFO "tulip.c: outl_CSR6 too many attempts," + "csr5=0x%08x\n", csr5); + goto out_write; + } + outl (currcsr6, ioaddr + CSR6); + udelay (1); + } + +out_write: + /* now it is safe to change csr6 */ + outl (newcsr6, ioaddr + CSR6); + + spin_unlock_irqrestore (&tp->lock, flags); +} + + +static void tulip_up(struct net_device *dev) { struct tulip_private *tp = (struct tulip_private *)dev->priv; long ioaddr = dev->base_addr; @@ -903,19 +957,16 @@ int i; /* Wake the chip from sleep/snooze mode. */ - if (tp->flags & HAS_PWRDWN) + if (tp->flags & HAS_ACPI) pci_write_config_dword(tp->pdev, 0x40, 0); /* On some chip revs we must set the MII/SYM port before the reset!? */ if (tp->mii_cnt || (tp->mtable && tp->mtable->has_mii)) - outl(0x00040000, ioaddr + CSR6); + outl_CSR6 (tp, 0x00040000); /* Reset the chip, holding bit 0 set at least 50 PCI cycles. */ outl(0x00000001, ioaddr + CSR0); - if (request_irq(dev->irq, &tulip_interrupt, SA_SHIRQ, dev->name, dev)) - return -EAGAIN; - /* Deassert reset. Wait the specified 50 PCI cycles after a reset by initializing Tx and Rx queues and the address filter list. */ @@ -924,22 +975,6 @@ if (tulip_debug > 1) printk(KERN_DEBUG "%s: tulip_open() irq %d.\n", dev->name, dev->irq); - MOD_INC_USE_COUNT; - - spin_lock_init(&tp->tx_lock); - tulip_init_ring(dev); - -#if 0 - if (tp->chip_id == PNIC2) { - u32 addr_low = cpu_to_le32(get_unaligned((u32 *)dev->dev_addr)); - u32 addr_high = cpu_to_le16(get_unaligned((u16 *)(dev->dev_addr+4))); - addr_high = (dev->dev_addr[4]<<8) + (dev->dev_addr[5]<<0); - outl((dev->dev_addr[0]<<8) + dev->dev_addr[1] + - (dev->dev_addr[2]<<24) + (dev->dev_addr[3]<<16), - ioaddr + 0xB0); - outl(addr_high + (addr_high<<16), ioaddr + 0xB8); - } -#endif if (tp->flags & MC_HASH_ONLY) { u32 addr_low = cpu_to_le32(get_unaligned((u32 *)dev->dev_addr)); u32 addr_high = cpu_to_le32(get_unaligned((u16 *)(dev->dev_addr+4))); @@ -1022,7 +1057,7 @@ printk(KERN_INFO "%s: Using MII transceiver %d, status " "%4.4x.\n", dev->name, tp->phys[0], mdio_read(dev, tp->phys[0], 1)); - outl(0x82020000, ioaddr + CSR6); + outl_CSR6(tp, 0x82020000); tp->csr6 = 0x820E0000; dev->if_port = 11; outl(0x0000, ioaddr + CSR13); @@ -1072,13 +1107,13 @@ select_media(dev, 1); /* Start the chip's Tx to process setup frame. */ - outl(tp->csr6, ioaddr + CSR6); - outl(tp->csr6 | 0x2000, ioaddr + CSR6); + outl_CSR6(tp, tp->csr6); + outl_CSR6(tp, tp->csr6 | 0x2000); /* Enable interrupts by setting the interrupt mask. */ outl(tulip_tbl[tp->chip_id].valid_intrs, ioaddr + CSR5); outl(tulip_tbl[tp->chip_id].valid_intrs, ioaddr + CSR7); - outl(tp->csr6 | 0x2002, ioaddr + CSR6); + outl_CSR6(tp, tp->csr6 | 0x2002); outl(0, ioaddr + CSR2); /* Rx poll demand */ if (tulip_debug > 2) { @@ -1094,11 +1129,28 @@ tp->timer.function = tulip_tbl[tp->chip_id].media_timer; add_timer(&tp->timer); - netif_start_queue(dev); + netif_device_attach(dev); +} + + +static int +tulip_open(struct net_device *dev) +{ + MOD_INC_USE_COUNT; + + if (request_irq(dev->irq, &tulip_interrupt, SA_SHIRQ, dev->name, dev)) { + MOD_DEC_USE_COUNT; + return -EBUSY; + } + tulip_init_ring (dev); + + tulip_up (dev); + return 0; } + /* Set up the transceiver control registers for the selected media type. */ static void select_media(struct net_device *dev, int startup) { @@ -1314,7 +1366,6 @@ */ static int check_duplex(struct net_device *dev) { - long ioaddr = dev->base_addr; struct tulip_private *tp = (struct tulip_private *)dev->priv; int mii_reg1, mii_reg5, negotiated, duplex; @@ -1346,8 +1397,8 @@ tp->csr6 &= ~0x00400000; if (tp->full_duplex) tp->csr6 |= 0x0200; else tp->csr6 &= ~0x0200; - outl(tp->csr6 | 0x0002, ioaddr + CSR6); - outl(tp->csr6 | 0x2002, ioaddr + CSR6); + outl_CSR6(tp, tp->csr6 | 0x0002); + outl_CSR6(tp, tp->csr6 | 0x2002); if (tulip_debug > 0) printk(KERN_INFO "%s: Setting %s-duplex based on MII" "#%d link partner capability of %4.4x.\n", @@ -1492,8 +1543,8 @@ medianame[tp->mtable->mleaf[tp->cur_index].media]); select_media(dev, 0); /* Restart the transmit process. */ - outl(tp->csr6 | 0x0002, ioaddr + CSR6); - outl(tp->csr6 | 0x2002, ioaddr + CSR6); + outl_CSR6(tp, tp->csr6 | 0x0002); + outl_CSR6(tp, tp->csr6 | 0x2002); next_tick = (24*HZ)/10; break; } @@ -1513,6 +1564,7 @@ add_timer(&tp->timer); } + /* Handle the 21143 uniquely: do autoselect with NWay, not the EEPROM list of available transceivers. */ static void t21142_timer(unsigned long data) @@ -1573,8 +1625,8 @@ tp->csr6 &= 0x00D5; tp->csr6 |= new_csr6; outl(0x0301, ioaddr + CSR12); - outl(tp->csr6 | 0x0002, ioaddr + CSR6); - outl(tp->csr6 | 0x2002, ioaddr + CSR6); + outl_CSR6(tp, tp->csr6 | 0x0002); + outl_CSR6(tp, tp->csr6 | 0x2002); } next_tick = 3*HZ; } @@ -1583,6 +1635,7 @@ add_timer(&tp->timer); } + static void t21142_start_nway(struct net_device *dev) { struct tulip_private *tp = (struct tulip_private *)dev->priv; @@ -1599,7 +1652,7 @@ outl(0x0001, ioaddr + CSR13); outl(csr14, ioaddr + CSR14); tp->csr6 = 0x82420000 | (tp->to_advertise & 0x0040 ? 0x0200 : 0); - outl(tp->csr6, ioaddr + CSR6); + outl_CSR6(tp, tp->csr6); if (tp->mtable && tp->mtable->csr15dir) { outl(tp->mtable->csr15dir, ioaddr + CSR15); outl(tp->mtable->csr15val, ioaddr + CSR15); @@ -1608,6 +1661,7 @@ outl(0x1301, ioaddr + CSR12); /* Trigger NWAY. */ } + static void t21142_lnk_change(struct net_device *dev, int csr5) { struct tulip_private *tp = (struct tulip_private *)dev->priv; @@ -1664,12 +1718,12 @@ outl(1, ioaddr + CSR13); } #if 0 /* Restart shouldn't be needed. */ - outl(tp->csr6 | 0x0000, ioaddr + CSR6); + outl_CSR6(tp, tp->csr6 | 0x0000); if (debug > 2) printk(KERN_DEBUG "%s: Restarting Tx and Rx, CSR5 is %8.8x.\n", dev->name, inl(ioaddr + CSR5)); #endif - outl(tp->csr6 | 0x2002, ioaddr + CSR6); + outl_CSR6(tp, tp->csr6 | 0x2002); if (debug > 2) printk(KERN_DEBUG "%s: Setting CSR6 %8.8x/%x CSR12 %8.8x.\n", dev->name, tp->csr6, inl(ioaddr + CSR6), @@ -1715,11 +1769,12 @@ tp->csr6 = 0x83860000; outl(0x0003FF7F, ioaddr + CSR14); outl(0x0301, ioaddr + CSR12); - outl(tp->csr6 | 0x0002, ioaddr + CSR6); - outl(tp->csr6 | 0x2002, ioaddr + CSR6); + outl_CSR6(tp, tp->csr6 | 0x0002); + outl_CSR6(tp, tp->csr6 | 0x2002); } } + static void mxic_timer(unsigned long data) { struct net_device *dev = (struct net_device *)data; @@ -1737,6 +1792,7 @@ } } + static void pnic_do_nway(struct net_device *dev) { struct tulip_private *tp = (struct tulip_private *)dev->priv; @@ -1763,12 +1819,15 @@ dev->name, phy_reg, medianame[dev->if_port]); if (tp->csr6 != new_csr6) { tp->csr6 = new_csr6; - outl(tp->csr6 | 0x0002, ioaddr + CSR6); /* Restart Tx */ - outl(tp->csr6 | 0x2002, ioaddr + CSR6); + /* Restart Tx */ + outl_CSR6(tp, tp->csr6 | 0x0002); + outl_CSR6(tp, tp->csr6 | 0x2002); dev->trans_start = jiffies; } } } + + static void pnic_lnk_change(struct net_device *dev, int csr5) { struct tulip_private *tp = (struct tulip_private *)dev->priv; @@ -1782,7 +1841,7 @@ outl((inl(ioaddr + CSR7) & ~TPLnkFail) | TPLnkPass, ioaddr + CSR7); if (! tp->nwayset || jiffies - dev->trans_start > 1*HZ) { tp->csr6 = 0x00420000 | (tp->csr6 & 0x0000fdff); - outl(tp->csr6, ioaddr + CSR6); + outl_CSR6(tp, tp->csr6); outl(0x30, ioaddr + CSR12); outl(0x0201F078, ioaddr + 0xB8); /* Turn on autonegotiation. */ dev->trans_start = jiffies; @@ -1792,6 +1851,8 @@ outl((inl(ioaddr + CSR7) & ~TPLnkPass) | TPLnkFail, ioaddr + CSR7); } } + + static void pnic_timer(unsigned long data) { struct net_device *dev = (struct net_device *)data; @@ -1842,8 +1903,9 @@ } if (tp->csr6 != new_csr6) { tp->csr6 = new_csr6; - outl(tp->csr6 | 0x0002, ioaddr + CSR6); /* Restart Tx */ - outl(tp->csr6 | 0x2002, ioaddr + CSR6); + /* Restart Tx */ + outl_CSR6(tp, tp->csr6 | 0x0002); + outl_CSR6(tp, tp->csr6 | 0x2002); dev->trans_start = jiffies; if (tulip_debug > 1) printk(KERN_INFO "%s: Changing PNIC configuration to %s " @@ -1965,8 +2027,8 @@ #endif /* Stop and restart the chip's Tx processes . */ - outl(tp->csr6 | 0x0002, ioaddr + CSR6); - outl(tp->csr6 | 0x2002, ioaddr + CSR6); + outl_CSR6(tp, tp->csr6 | 0x0002); + outl_CSR6(tp, tp->csr6 | 0x2002); /* Trigger an immediate transmit demand. */ outl(0, ioaddr + CSR1); @@ -2173,8 +2235,8 @@ printk(KERN_WARNING "%s: The transmitter stopped." " CSR5 is %x, CSR6 %x, new CSR6 %x.\n", dev->name, csr5, inl(ioaddr + CSR6), tp->csr6); - outl(tp->csr6 | 0x0002, ioaddr + CSR6); - outl(tp->csr6 | 0x2002, ioaddr + CSR6); + outl_CSR6(tp, tp->csr6 | 0x0002); + outl_CSR6(tp, tp->csr6 | 0x2002); } spin_unlock(&tp->tx_lock); } @@ -2190,14 +2252,14 @@ else tp->csr6 |= 0x00200000; /* Store-n-forward. */ /* Restart the transmit process. */ - outl(tp->csr6 | 0x0002, ioaddr + CSR6); - outl(tp->csr6 | 0x2002, ioaddr + CSR6); + outl_CSR6(tp, tp->csr6 | 0x0002); + outl_CSR6(tp, tp->csr6 | 0x2002); outl(0, ioaddr + CSR1); } if (csr5 & RxDied) { /* Missed a Rx frame. */ tp->stats.rx_errors++; tp->stats.rx_missed_errors += inl(ioaddr + CSR8) & 0xffff; - outl(tp->csr6 | 0x2002, ioaddr + CSR6); + outl_CSR6(tp, tp->csr6 | 0x2002); } if (csr5 & (TPLnkPass | TPLnkFail | 0x08000000)) { if (tp->link_change) @@ -2378,69 +2440,79 @@ return received; } -static int -tulip_close(struct net_device *dev) + +static void tulip_down (struct net_device *dev) { long ioaddr = dev->base_addr; - struct tulip_private *tp = (struct tulip_private *)dev->priv; - int i; + struct tulip_private *tp = (struct tulip_private *) dev->priv; - netif_stop_queue(dev); + netif_device_detach (dev); - if (tulip_debug > 1) - printk(KERN_DEBUG "%s: Shutting down ethercard, status was %2.2x.\n", - dev->name, inl(ioaddr + CSR5)); + del_timer (&tp->timer); /* Disable interrupts by clearing the interrupt mask. */ - outl(0x00000000, ioaddr + CSR7); + outl (0x00000000, ioaddr + CSR7); + /* Stop the Tx and Rx processes. */ - outl(inl(ioaddr + CSR6) & ~0x2002, ioaddr + CSR6); + outl_CSR6 (tp, inl (ioaddr + CSR6) & ~0x2002); + /* 21040 -- Leave the card in 10baseT state. */ if (tp->chip_id == DC21040) - outl(0x00000004, ioaddr + CSR13); + outl (0x00000004, ioaddr + CSR13); - if (inl(ioaddr + CSR6) != 0xffffffff) - tp->stats.rx_missed_errors += inl(ioaddr + CSR8) & 0xffff; + if (inl (ioaddr + CSR6) != 0xffffffff) + tp->stats.rx_missed_errors += inl (ioaddr + CSR8) & 0xffff; + + dev->if_port = tp->saved_if_port; + + /* Leave the driver in snooze, not sleep, mode. */ + if (tp->flags & HAS_ACPI) + pci_write_config_dword (tp->pdev, 0x40, 0x40000000); +} + + +static int tulip_close (struct net_device *dev) +{ + long ioaddr = dev->base_addr; + struct tulip_private *tp = (struct tulip_private *) dev->priv; + int i; - del_timer(&tp->timer); + tulip_down (dev); - free_irq(dev->irq, dev); + if (tulip_debug > 1) + printk (KERN_DEBUG "%s: Shutting down ethercard, status was %2.2x.\n", + dev->name, inl (ioaddr + CSR5)); - dev->if_port = tp->saved_if_port; + free_irq (dev->irq, dev); /* Free all the skbuffs in the Rx queue. */ for (i = 0; i < RX_RING_SIZE; i++) { struct sk_buff *skb = tp->rx_skbuff[i]; tp->rx_skbuff[i] = 0; - tp->rx_ring[i].status = 0; /* Not owned by Tulip chip. */ + tp->rx_ring[i].status = 0; /* Not owned by Tulip chip. */ tp->rx_ring[i].length = 0; - tp->rx_ring[i].buffer1 = 0xBADF00D0; /* An invalid address. */ + tp->rx_ring[i].buffer1 = 0xBADF00D0; /* An invalid address. */ if (skb) { - dev_kfree_skb(skb); + dev_kfree_skb (skb); } } for (i = 0; i < TX_RING_SIZE; i++) { if (tp->tx_skbuff[i]) - dev_kfree_skb(tp->tx_skbuff[i]); + dev_kfree_skb (tp->tx_skbuff[i]); tp->tx_skbuff[i] = 0; } - /* Leave the driver in snooze, not sleep, mode. */ - if (tp->flags & HAS_PWRDWN) - pci_write_config_dword(tp->pdev, 0x40, 0x40000000); - MOD_DEC_USE_COUNT; return 0; } -static struct enet_statistics * -tulip_get_stats(struct net_device *dev) +static struct enet_statistics *tulip_get_stats(struct net_device *dev) { struct tulip_private *tp = (struct tulip_private *)dev->priv; long ioaddr = dev->base_addr; - if (test_bit(LINK_STATE_START, &dev->state)) + if (netif_running(dev)) tp->stats.rx_missed_errors += inl(ioaddr + CSR8) & 0xffff; return &tp->stats; @@ -2672,7 +2744,7 @@ outl(0, ioaddr + CSR1); } } - outl(csr6 | 0x0000, ioaddr + CSR6); + outl_CSR6(tp, csr6 | 0x0000); } @@ -2697,10 +2769,10 @@ board_idx++; if (tulip_debug > 0 && did_version++ == 0) - printk(KERN_INFO "%s", version); + printk (KERN_INFO "%s", version); if( pdev->subsystem_vendor == 0x1376 ){ - printk(KERN_ERR "tulip: skipping LMC card.\n"); + printk (KERN_ERR PFX "skipping LMC card.\n"); return -ENODEV; } @@ -2709,31 +2781,37 @@ /* Make certain the data structures are quadword aligned. */ dev = init_etherdev (NULL, sizeof (*tp)); - if (!dev) + if (!dev) { + printk (KERN_ERR PFX "unable to allocate ether device, aborting\n"); return -ENOMEM; + } /* We do a request_region() only to register /proc/ioports info. */ /* Note that proper size is tulip_tbl[chip_idx].chip_name, but... */ - if (!request_region (ioaddr, tulip_tbl[chip_idx].io_size, dev->name)) + if (!request_region (ioaddr, tulip_tbl[chip_idx].io_size, dev->name)) { + printk (KERN_ERR PFX "unable to allocate ether device, aborting\n"); + goto err_out_free_netdev; + } + + if (pci_enable_device(pdev)) { + printk (KERN_ERR PFX "cannot enable PCI device (id %04x:%04x, bus %d, devfn %d), aborting\n", + pdev->vendor, pdev->device, + pdev->bus->number, pdev->devfn); goto err_out_free_netdev; + } - pci_enable_device (pdev); + pci_set_master(pdev); tp = dev->priv; memset(tp, 0, sizeof(*tp)); pci_read_config_byte (pdev, PCI_REVISION_ID, &chip_rev); - /* Bring the 21041/21143 out of sleep mode. - Caution: Snooze mode does not work with some boards! */ - if (tulip_tbl[chip_idx].flags & HAS_PWRDWN) - pci_write_config_dword(pdev, 0x40, 0x00000000); - printk(KERN_INFO "%s: %s rev %d at %#3lx,", dev->name, tulip_tbl[chip_idx].chip_name, chip_rev, ioaddr); /* Stop the chip's Tx and Rx processes. */ - outl(inl(ioaddr + CSR6) & ~0x2002, ioaddr + CSR6); + outl_CSR6(tp, inl(ioaddr + CSR6) & ~0x2002); /* Clear the missed-packet counter. */ (volatile int)inl(ioaddr + CSR8); @@ -2835,6 +2913,7 @@ tp->flags = tulip_tbl[chip_idx].flags; tp->csr0 = csr0; tp->pdev = pdev; + tp->base_addr = dev->base_addr; /* BugFixes: The 21143-TD hangs with PCI Write-and-Invalidate cycles. And the ASIX must have a burst limit or horrible things happen. */ @@ -2853,6 +2932,7 @@ #ifdef TULIP_NO_MEDIA_SWITCH tp->medialock = 1; #endif + tp->tx_lock = SPIN_LOCK_UNLOCKED; /* The lower four bits are the media type. */ if (board_idx >= 0 && board_idx < MAX_UNITS) { @@ -2962,7 +3042,7 @@ outl(0x00000000, ioaddr + CSR13); outl(0xFFFFFFFF, ioaddr + CSR14); outl(0x00000008, ioaddr + CSR15); /* Listen on AUI also. */ - outl(inl(ioaddr + CSR6) | 0x0200, ioaddr + CSR6); + outl_CSR6(tp, inl(ioaddr + CSR6) | 0x0200); outl(0x0000EF05, ioaddr + CSR13); break; case DC21040: @@ -2976,10 +3056,10 @@ case DC21142: case PNIC2: if (tp->mii_cnt || media_cap[dev->if_port] & MediaIsMII) { - outl(0x82020000, ioaddr + CSR6); + outl_CSR6(tp, 0x82020000); outl(0x0000, ioaddr + CSR13); outl(0x0000, ioaddr + CSR14); - outl(0x820E0000, ioaddr + CSR6); + outl_CSR6(tp, 0x820E0000); } else t21142_start_nway(dev); break; @@ -2987,19 +3067,19 @@ if ( ! tp->mii_cnt) { tp->nway = 1; tp->nwayset = 0; - outl(0x00420000, ioaddr + CSR6); + outl_CSR6(tp, 0x00420000); outl(0x30, ioaddr + CSR12); - outl(0x0001F078, ioaddr + 0xB8); - outl(0x0201F078, ioaddr + 0xB8); /* Turn on autonegotiation. */ + outl_CSR6(tp, 0x0001F078); + outl_CSR6(tp, 0x0201F078); /* Turn on autonegotiation. */ } break; case MX98713: case COMPEX9881: - outl(0x00000000, ioaddr + CSR6); + outl_CSR6(tp, 0x00000000); outl(0x000711C0, ioaddr + CSR14); /* Turn on NWay. */ outl(0x00000001, ioaddr + CSR13); break; case MX98715: case MX98725: - outl(0x01a80000, ioaddr + CSR6); + outl_CSR6(tp, 0x01a80000); outl(0xFFFFFFFF, ioaddr + CSR14); outl(0x00001000, ioaddr + CSR12); break; @@ -3008,7 +3088,8 @@ break; } - if (tulip_tbl[chip_idx].flags & HAS_PWRDWN) + /* put the chip in snooze mode until opened */ + if (tulip_tbl[chip_idx].flags & HAS_ACPI) pci_write_config_dword(pdev, 0x40, 0x40000000); return 0; @@ -3024,20 +3105,8 @@ { struct net_device *dev = pdev->driver_data; - if (dev) { - long ioaddr = dev->base_addr; - struct tulip_private *tp = (struct tulip_private *)dev->priv; - int csr6 = inl(ioaddr + CSR6); - /* Disable interrupts, stop the chip, gather stats. */ - if (csr6 != 0xffffffff) { - outl(0x00000000, ioaddr + CSR7); - outl(csr6 & ~0x2002, ioaddr + CSR6); - tp->stats.rx_missed_errors += inl(ioaddr + CSR8) & 0xffff; - } - tulip_close(dev); - /* Put the 21143 into sleep mode. */ - pci_write_config_dword(pdev, 0x40,0x80000000); - } + if (dev && netif_device_present (dev)) + tulip_down (dev); } @@ -3045,10 +3114,8 @@ { struct net_device *dev = pdev->driver_data; - if (dev) { - pci_write_config_dword(pdev, 0x40, 0x0000); - tulip_open(dev); - } + if (dev && !netif_device_present (dev)) + tulip_up (dev); } @@ -3078,7 +3145,7 @@ static int __init tulip_init (void) { - return pci_register_driver (&tulip_driver) > 0 ? 0 : -ENODEV; + return pci_module_init (&tulip_driver); } diff -u --recursive --new-file v2.3.46/linux/drivers/net/via-rhine.c linux/drivers/net/via-rhine.c --- v2.3.46/linux/drivers/net/via-rhine.c Wed Feb 16 17:03:52 2000 +++ linux/drivers/net/via-rhine.c Thu Feb 17 09:18:47 2000 @@ -869,7 +869,7 @@ np->tx_skbuff[entry] = 0; } if (np->tx_full && - test_bit(LINK_STATE_XOFF, &dev->flags) && + netif_queue_stopped(dev) && np->cur_tx - np->dirty_tx < TX_RING_SIZE - 4) { /* The ring is no longer full, clear tbusy. */ np->tx_full = 0; diff -u --recursive --new-file v2.3.46/linux/drivers/net/wan/cycx_x25.c linux/drivers/net/wan/cycx_x25.c --- v2.3.46/linux/drivers/net/wan/cycx_x25.c Sun Feb 13 19:29:04 2000 +++ linux/drivers/net/wan/cycx_x25.c Thu Feb 17 09:18:47 2000 @@ -505,7 +505,7 @@ x25_channel_t *chan = dev->priv; cycx_t *card = chan->card; - if (test_bit(LINK_STATE_START, &dev->state)) + if (netif_running(dev)) return -EBUSY; /* only one open is allowed */ netif_start_queue(dev); @@ -1564,7 +1564,7 @@ x25_channel_t *chan = dev->priv; printk(KERN_INFO "%-5.5s %-15.15s %d ETH_P_%s\n", - chan->name, chan->addr, test_bit(LINK_STATE_XOFF, &dev->state), + chan->name, chan->addr, netif_queue_stopped(dev), chan->protocol == ETH_P_IP ? "IP" : "X25"); dev = chan->slave; } diff -u --recursive --new-file v2.3.46/linux/drivers/net/wan/dlci.c linux/drivers/net/wan/dlci.c --- v2.3.46/linux/drivers/net/wan/dlci.c Sat Feb 12 11:22:11 2000 +++ linux/drivers/net/wan/dlci.c Thu Feb 17 09:18:47 2000 @@ -361,7 +361,7 @@ if (!*(short *)(dev->dev_addr)) return(-EINVAL); - if (!test_bit(LINK_STATE_START, &dlp->slave->state)) + if (!netif_running(dlp->slave)) return(-ENOTCONN); flp = dlp->slave->priv; @@ -495,7 +495,7 @@ if (!master) return(-ENODEV); - if (test_bit(LINK_STATE_START, &master->state)) + if (netif_running(master)) return(-EBUSY); dlp = master->priv; diff -u --recursive --new-file v2.3.46/linux/drivers/net/wan/lapbether.c linux/drivers/net/wan/lapbether.c --- v2.3.46/linux/drivers/net/wan/lapbether.c Sun Feb 13 19:29:04 2000 +++ linux/drivers/net/wan/lapbether.c Thu Feb 17 09:18:47 2000 @@ -163,7 +163,7 @@ dev = lapbeth_get_x25_dev(dev); - if (dev == NULL || test_bit(LINK_STATE_START, &dev->state) == 0) { + if (dev == NULL || !netif_running(dev)) { kfree_skb(skb); return 0; } @@ -215,7 +215,7 @@ * Just to be *really* sure not to send anything if the interface * is down, the ethernet device may have gone. */ - if (!test_bit(LINK_STATE_START, &dev->state)) { + if (!netif_running(dev)) { lapbeth_check_devices(dev); kfree_skb(skb); return -ENODEV; diff -u --recursive --new-file v2.3.46/linux/drivers/net/wan/sbni.c linux/drivers/net/wan/sbni.c --- v2.3.46/linux/drivers/net/wan/sbni.c Sun Feb 13 19:29:04 2000 +++ linux/drivers/net/wan/sbni.c Thu Feb 17 09:18:47 2000 @@ -1081,7 +1081,7 @@ } sti(); outb(csr0 | RC_CHK, dev->base_addr + CSR0); - if(test_bit(LINK_STATE_START, &dev->state)) + if(netif_running(dev)) { struct timer_list* watchdog = &lp->watchdog; init_timer(watchdog); @@ -1171,7 +1171,7 @@ /* struct net_local *lp = (struct net_local *)dev->priv; */ struct sockaddr *saddr = addr; - if(test_bit(LINK_STATE_START, &dev->state)) + if(netif_running(dev)) { /* Only possible while card isn't started */ return -EBUSY; diff -u --recursive --new-file v2.3.46/linux/drivers/net/wan/sdla.c linux/drivers/net/wan/sdla.c --- v2.3.46/linux/drivers/net/wan/sdla.c Sat Feb 12 11:22:11 2000 +++ linux/drivers/net/wan/sdla.c Thu Feb 17 09:18:47 2000 @@ -510,7 +510,7 @@ flp->dlci[i] = abs(flp->dlci[i]); - if (test_bit(LINK_STATE_START, &slave->state) && (flp->config.station == FRAD_STATION_NODE)) + if (netif_running(slave) && (flp->config.station == FRAD_STATION_NODE)) sdla_cmd(slave, SDLA_ACTIVATE_DLCI, 0, 0, &flp->dlci[i], sizeof(short), NULL, NULL); return(0); @@ -532,7 +532,7 @@ flp->dlci[i] = -abs(flp->dlci[i]); - if (test_bit(LINK_STATE_START, &slave->state) && (flp->config.station == FRAD_STATION_NODE)) + if (netif_running(slave) && (flp->config.station == FRAD_STATION_NODE)) sdla_cmd(slave, SDLA_DEACTIVATE_DLCI, 0, 0, &flp->dlci[i], sizeof(short), NULL, NULL); return(0); @@ -565,7 +565,7 @@ flp->dlci[i] = -*(short *)(master->dev_addr); master->mtu = slave->mtu; - if (test_bit(LINK_STATE_START, &slave->state)) { + if (netif_running(dev)) { if (flp->config.station == FRAD_STATION_CPE) sdla_reconfig(slave); else @@ -594,7 +594,7 @@ MOD_DEC_USE_COUNT; - if (test_bit(LINK_STATE_START, &slave->state)) { + if (netif_running(slave)) { if (flp->config.station == FRAD_STATION_CPE) sdla_reconfig(slave); else @@ -624,7 +624,7 @@ ret = SDLA_RET_OK; len = sizeof(struct dlci_conf); - if (test_bit(LINK_STATE_START, &slave->state)) { + if (netif_running(slave)) { if (get) ret = sdla_cmd(slave, SDLA_READ_DLCI_CONFIGURATION, abs(flp->dlci[i]), 0, NULL, 0, &dlp->config, &len); @@ -1104,7 +1104,7 @@ if (!get) { - if (test_bit(LINK_STATE_START, &dev->state)) + if (netif_running(dev)) return(-EBUSY); if(copy_from_user(&data.config, conf, sizeof(struct frad_conf))) @@ -1167,7 +1167,7 @@ else { /* no sense reading if the CPU isn't started */ - if (test_bit(LINK_STATE_START, &dev->state)) + if (netif_running(dev)) { size = sizeof(data); if (sdla_cmd(dev, SDLA_READ_DLCI_CONFIGURATION, 0, 0, NULL, 0, &data, &size) != SDLA_RET_OK) @@ -1316,7 +1316,7 @@ flp = dev->priv; - if (test_bit(LINK_STATE_START, &dev->state)) + if (netif_running(dev)) return(-EBUSY); /* for now, you can't change the MTU! */ diff -u --recursive --new-file v2.3.46/linux/drivers/net/wan/x25_asy.c linux/drivers/net/wan/x25_asy.c --- v2.3.46/linux/drivers/net/wan/x25_asy.c Sun Feb 13 19:29:04 2000 +++ linux/drivers/net/wan/x25_asy.c Thu Feb 17 09:18:47 2000 @@ -301,7 +301,7 @@ struct x25_asy *sl = (struct x25_asy *) tty->disc_data; /* First make sure we're connected. */ - if (!sl || sl->magic != X25_ASY_MAGIC || !test_bit(LINK_STATE_START, &sl->dev->state)) + if (!sl || sl->magic != X25_ASY_MAGIC || !netif_running(sl->dev)) return; if (sl->xleft <= 0) @@ -340,7 +340,7 @@ struct x25_asy *sl = (struct x25_asy*)(dev->priv); int err; - if (!test_bit(LINK_STATE_START, &sl->dev->state)) + if (!netif_running(sl->dev)) { printk("%s: xmit call when iface is down\n", dev->name); return 1; @@ -406,7 +406,7 @@ static void x25_asy_data_transmit(void *token, struct sk_buff *skb) { struct x25_asy *sl=token; - if(test_bit(LINK_STATE_XOFF, &sl->dev->state)) + if (netif_queue_stopped(sl->dev)) { printk(KERN_ERR "x25_asy: tbusy drop\n"); kfree_skb(skb); @@ -563,7 +563,7 @@ { struct x25_asy *sl = (struct x25_asy *) tty->disc_data; - if (!sl || sl->magic != X25_ASY_MAGIC || !test_bit(LINK_STATE_START, &sl->dev->state)) + if (!sl || sl->magic != X25_ASY_MAGIC || !netif_running(sl->dev)) return; /* @@ -903,7 +903,7 @@ * VSV = if dev->start==0, then device * unregistered while close proc. */ - if (test_bit(LINK_STATE_START, &x25_asy_ctrls[i]->dev.state)) + if (netif_running(&(x25_asy_ctrls[i]->dev))) unregister_netdev(&(x25_asy_ctrls[i]->dev)); kfree(x25_asy_ctrls[i]); diff -u --recursive --new-file v2.3.46/linux/drivers/net/wavelan.c linux/drivers/net/wavelan.c --- v2.3.46/linux/drivers/net/wavelan.c Sun Feb 13 19:29:04 2000 +++ linux/drivers/net/wavelan.c Thu Feb 17 09:18:47 2000 @@ -871,8 +871,7 @@ net_local *lp = (net_local *) dev->priv; /* Check if we can do it now ! */ - if (!test_bit(LINK_STATE_START, &dev->state) && - test_bit(LINK_STATE_XOFF, &dev->state)) { + if (!netif_running(dev) && netif_queue_stopped(dev)) { lp->reconfig_82586 = 1; #ifdef DEBUG_CONFIG_INFO printk(KERN_DEBUG @@ -3713,7 +3712,7 @@ /* Check the state of the command unit. */ if (((status & SCB_ST_CNA) == SCB_ST_CNA) || - (((status & SCB_ST_CUS) != SCB_ST_CUS_ACTV) && test_bit(LINK_STATE_START, &dev->state))) { + (((status & SCB_ST_CUS) != SCB_ST_CUS_ACTV) && netif_running(dev))) { #ifdef DEBUG_INTERRUPT_ERROR printk(KERN_INFO "%s: wavelan_interrupt(): CU inactive -- restarting\n", @@ -3724,7 +3723,7 @@ /* Check the state of the command unit. */ if (((status & SCB_ST_RNR) == SCB_ST_RNR) || - (((status & SCB_ST_RUS) != SCB_ST_RUS_RDY) && test_bit(LINK_STATE_START, &dev->state))) { + (((status & SCB_ST_RUS) != SCB_ST_RUS_RDY) && netif_running(dev))) { #ifdef DEBUG_INTERRUPT_ERROR printk(KERN_INFO "%s: wavelan_interrupt(): RU not ready -- restarting\n", diff -u --recursive --new-file v2.3.46/linux/drivers/net/yellowfin.c linux/drivers/net/yellowfin.c --- v2.3.46/linux/drivers/net/yellowfin.c Wed Feb 16 17:03:52 2000 +++ linux/drivers/net/yellowfin.c Sun Feb 20 09:06:14 2000 @@ -75,7 +75,6 @@ #error You must compile this driver with "-O". #endif -#include #include #include #include @@ -851,7 +850,7 @@ /* Code that should never be run! Perhaps remove after testing.. */ { static int stopit = 10; - if ((!(test_bit(LINK_STATE_START, &dev->state))) && --stopit < 0) { + if ((!(netif_running(dev))) && --stopit < 0) { printk(KERN_ERR "%s: Emergency stop, looping startup interrupt.\n", dev->name); free_irq(irq, dev); @@ -1378,7 +1377,12 @@ { if (debug) /* Emit version even if no cards detected. */ printk(KERN_INFO "%s", version); - return pci_register_driver (&yellowfin_driver) > 0 ? 0 : -ENODEV; + + if (pci_register_driver (&yellowfin_driver) > 0) + return 0; + + pci_unregister_driver (&yellowfin_driver); + return -ENODEV; } diff -u --recursive --new-file v2.3.46/linux/drivers/parport/parport_pc.c linux/drivers/parport/parport_pc.c --- v2.3.46/linux/drivers/parport/parport_pc.c Thu Feb 10 17:11:12 2000 +++ linux/drivers/parport/parport_pc.c Fri Feb 18 15:07:20 2000 @@ -561,7 +561,8 @@ if ((start ^ end) & ~0xffffUL) maxlen = (0x10000 - start) & 0xffff; - dma_addr = dma_handle = pci_map_single(priv->dev, (void *)buf, length); + dma_addr = dma_handle = pci_map_single(priv->dev, (void *)buf, length, + PCI_DMA_TODEVICE); } else { /* above 16 MB we use a bounce buffer as ISA-DMA is not possible */ maxlen = PAGE_SIZE; /* sizeof(priv->dma_buf) */ @@ -661,7 +662,7 @@ frob_econtrol (port, 1<<3, 0); if (dma_handle) - pci_unmap_single(priv->dev, dma_handle, length); + pci_unmap_single(priv->dev, dma_handle, length, PCI_DMA_TODEVICE); return length - left; } diff -u --recursive --new-file v2.3.46/linux/drivers/pcmcia/cs.c linux/drivers/pcmcia/cs.c --- v2.3.46/linux/drivers/pcmcia/cs.c Wed Feb 16 17:03:52 2000 +++ linux/drivers/pcmcia/cs.c Sun Feb 20 20:37:09 2000 @@ -82,13 +82,14 @@ #else #define CB_OPT "" #endif -#if defined(CONFIG_APM) || defined(CONFIG_ACPI) +#if defined(CONFIG_APM) || defined(CONFIG_APM_MODULE) || defined(CONFIG_ACPI) #define APM_OPT " [apm]" #else #define APM_OPT "" #endif #if !defined(CONFIG_CARDBUS) && !defined(CONFIG_PCI) && \ - !defined(CONFIG_APM) && !defined(CONFIG_ACPI) + !defined(CONFIG_APM) && !defined(CONFIG_APM_MODULE) && \ + !defined(CONFIG_ACPI) #define OPTIONS " none" #else #define OPTIONS PCI_OPT CB_OPT APM_OPT @@ -124,7 +125,7 @@ static int io_speed = 0; /* ns */ /* Optional features */ -#if defined(CONFIG_APM) || defined(CONFIG_ACPI) +#if defined(CONFIG_APM) || defined(CONFIG_APM_MODULE) || defined(CONFIG_ACPI) static int do_apm = 1; MODULE_PARM(do_apm, "i"); #else diff -u --recursive --new-file v2.3.46/linux/drivers/sbus/audio/audio.c linux/drivers/sbus/audio/audio.c --- v2.3.46/linux/drivers/sbus/audio/audio.c Wed Feb 16 17:03:52 2000 +++ linux/drivers/sbus/audio/audio.c Thu Feb 17 09:26:31 2000 @@ -1,4 +1,4 @@ -/* $Id: audio.c,v 1.48 2000/02/09 22:33:19 davem Exp $ +/* $Id: audio.c,v 1.49 2000/02/17 05:52:41 davem Exp $ * drivers/sbus/audio/audio.c * * Copyright 1996 Thomas K. Dyas (tdyas@noc.rutgers.edu) diff -u --recursive --new-file v2.3.46/linux/drivers/sbus/audio/cs4231.c linux/drivers/sbus/audio/cs4231.c --- v2.3.46/linux/drivers/sbus/audio/cs4231.c Tue Feb 1 01:35:44 2000 +++ linux/drivers/sbus/audio/cs4231.c Fri Feb 18 15:07:20 2000 @@ -1,4 +1,4 @@ -/* $Id: cs4231.c,v 1.42 2000/01/28 13:42:48 jj Exp $ +/* $Id: cs4231.c,v 1.43 2000/02/18 13:49:39 davem Exp $ * drivers/sbus/audio/cs4231.c * * Copyright 1996, 1997, 1998, 1999 Derrick J Brashear (shadow@andrew.cmu.edu) @@ -1171,11 +1171,11 @@ static void cs4231_release(struct inode * inode, struct file * file, struct sparcaudio_driver *drv) { struct cs4231_chip *cs4231_chip = (struct cs4231_chip *)drv->private; - void (*dma_unmap_single)(struct sbus_dev *, dma_addr_t, size_t) = sbus_unmap_single; + void (*dma_unmap_single)(struct sbus_dev *, dma_addr_t, size_t, int) = sbus_unmap_single; #ifdef EB4231_SUPPORT if (cs4231_chip->status & CS_STATUS_IS_EBUS) - dma_unmap_single = (void (*)(struct sbus_dev *, dma_addr_t, size_t)) pci_unmap_single; + dma_unmap_single = (void (*)(struct sbus_dev *, dma_addr_t, size_t, int)) pci_unmap_single; #endif /* zero out any info about what data we have as well */ if (file->f_mode & FMODE_READ) { @@ -1184,14 +1184,16 @@ if (cs4231_chip->input_dma_handle) { dma_unmap_single(drv->dev, cs4231_chip->input_dma_handle, - cs4231_chip->input_dma_size); + cs4231_chip->input_dma_size, + SBUS_DMA_FROMDEVICE); cs4231_chip->input_dma_handle = 0; cs4231_chip->input_dma_size = 0; } if (cs4231_chip->input_next_dma_handle) { dma_unmap_single(drv->dev, cs4231_chip->input_next_dma_handle, - cs4231_chip->input_next_dma_size); + cs4231_chip->input_next_dma_size, + SBUS_DMA_FROMDEVICE); cs4231_chip->input_next_dma_handle = 0; cs4231_chip->input_next_dma_size = 0; } @@ -1203,14 +1205,16 @@ if (cs4231_chip->output_dma_handle) { dma_unmap_single(drv->dev, cs4231_chip->output_dma_handle, - cs4231_chip->output_dma_size); + cs4231_chip->output_dma_size, + SBUS_DMA_TODEVICE); cs4231_chip->output_dma_handle = 0; cs4231_chip->output_dma_size = 0; } if (cs4231_chip->output_next_dma_handle) { dma_unmap_single(drv->dev, cs4231_chip->output_next_dma_handle, - cs4231_chip->output_next_dma_size); + cs4231_chip->output_next_dma_size, + SBUS_DMA_TODEVICE); cs4231_chip->output_next_dma_handle = 0; cs4231_chip->output_next_dma_size = 0; } @@ -1248,7 +1252,8 @@ if (cs4231_chip->output_dma_handle) { sbus_unmap_single(drv->dev, cs4231_chip->output_dma_handle, - cs4231_chip->output_dma_size); + cs4231_chip->output_dma_size, + SBUS_DMA_TODEVICE); cs4231_chip->output_dma_handle = 0; cs4231_chip->output_dma_size = 0; cs4231_chip->playing_count--; @@ -1267,7 +1272,8 @@ cs4231_chip->output_next_dma_handle = sbus_map_single(drv->dev, (char *)cs4231_chip->output_ptr, - cs4231_chip->output_size); + cs4231_chip->output_size, + SBUS_DMA_TODEVICE); cs4231_chip->output_next_dma_size = cs4231_chip->output_size; sbus_writel(cs4231_chip->output_next_dma_handle, cs4231_chip->regs + APCPNVA); @@ -1297,7 +1303,8 @@ if (cs4231_chip->output_dma_handle) { pci_unmap_single((struct pci_dev *)drv->dev, cs4231_chip->output_dma_handle, - cs4231_chip->output_dma_size); + cs4231_chip->output_dma_size, + PCI_DMA_TODEVICE); cs4231_chip->output_dma_handle = 0; cs4231_chip->output_dma_size = 0; cs4231_chip->playing_count--; @@ -1316,7 +1323,8 @@ cs4231_chip->output_next_dma_handle = pci_map_single((struct pci_dev *)drv->dev, (char *)cs4231_chip->output_ptr, - cs4231_chip->output_size); + cs4231_chip->output_size, + PCI_DMA_TODEVICE); cs4231_chip->output_next_dma_size = cs4231_chip->output_size; writel(cs4231_chip->output_next_dma_size, @@ -1362,7 +1370,8 @@ if (cs4231_chip->input_dma_handle) { sbus_unmap_single(drv->dev, cs4231_chip->input_dma_handle, - cs4231_chip->input_dma_size); + cs4231_chip->input_dma_size, + SBUS_DMA_FROMDEVICE); cs4231_chip->input_dma_handle = 0; cs4231_chip->input_dma_size = 0; cs4231_chip->recording_count--; @@ -1384,7 +1393,8 @@ cs4231_chip->input_next_dma_handle = sbus_map_single(drv->dev, (char *)cs4231_chip->input_ptr, - cs4231_chip->input_size); + cs4231_chip->input_size, + SBUS_DMA_FROMDEVICE); cs4231_chip->input_next_dma_size = cs4231_chip->input_size; sbus_writel(cs4231_chip->input_next_dma_handle, cs4231_chip->regs + APCCNVA); @@ -1418,7 +1428,8 @@ if (cs4231_chip->input_dma_handle) { pci_unmap_single((struct pci_dev *)drv->dev, cs4231_chip->input_dma_handle, - cs4231_chip->input_dma_size); + cs4231_chip->input_dma_size, + PCI_DMA_FROMDEVICE); cs4231_chip->input_dma_handle = 0; cs4231_chip->input_dma_size = 0; cs4231_chip->recording_count--; @@ -1441,7 +1452,8 @@ cs4231_chip->input_next_dma_handle = pci_map_single((struct pci_dev *)drv->dev, (char *)cs4231_chip->input_ptr, - cs4231_chip->input_size); + cs4231_chip->input_size, + PCI_DMA_FROMDEVICE); cs4231_chip->input_next_dma_size = cs4231_chip->input_size; writel(cs4231_chip->input_next_dma_size, @@ -1556,7 +1568,8 @@ if (cs4231_chip->output_dma_handle) { pci_unmap_single((struct pci_dev *)drv->dev, cs4231_chip->output_dma_handle, - cs4231_chip->output_dma_size); + cs4231_chip->output_dma_size, + PCI_DMA_TODEVICE); cs4231_chip->output_dma_handle = 0; cs4231_chip->output_dma_size = 0; } @@ -1564,7 +1577,8 @@ if (cs4231_chip->output_next_dma_handle) { pci_unmap_single((struct pci_dev *)drv->dev, cs4231_chip->output_next_dma_handle, - cs4231_chip->output_next_dma_size); + cs4231_chip->output_next_dma_size, + PCI_DMA_TODEVICE); cs4231_chip->output_next_dma_handle = 0; cs4231_chip->output_next_dma_size = 0; } @@ -1589,7 +1603,8 @@ if (cs4231_chip->output_dma_handle) { sbus_unmap_single(drv->dev, cs4231_chip->output_dma_handle, - cs4231_chip->output_dma_size); + cs4231_chip->output_dma_size, + SBUS_DMA_TODEVICE); cs4231_chip->output_dma_handle = 0; cs4231_chip->output_dma_size = 0; } @@ -1597,7 +1612,8 @@ if (cs4231_chip->output_next_dma_handle) { sbus_unmap_single(drv->dev, cs4231_chip->output_next_dma_handle, - cs4231_chip->output_next_dma_size); + cs4231_chip->output_next_dma_size, + SBUS_DMA_TODEVICE); cs4231_chip->output_next_dma_handle = 0; cs4231_chip->output_next_dma_size = 0; } @@ -1699,7 +1715,8 @@ if (cs4231_chip->input_dma_handle) { sbus_unmap_single(drv->dev, cs4231_chip->input_dma_handle, - cs4231_chip->input_dma_size); + cs4231_chip->input_dma_size, + SBUS_DMA_FROMDEVICE); cs4231_chip->input_dma_handle = 0; cs4231_chip->input_dma_size = 0; } @@ -1707,7 +1724,8 @@ if (cs4231_chip->input_next_dma_handle) { sbus_unmap_single(drv->dev, cs4231_chip->input_next_dma_handle, - cs4231_chip->input_next_dma_size); + cs4231_chip->input_next_dma_size, + SBUS_DMA_FROMDEVICE); cs4231_chip->input_next_dma_handle = 0; cs4231_chip->input_next_dma_size = 0; } @@ -1765,7 +1783,8 @@ if (cs4231_chip->input_dma_handle) { pci_unmap_single((struct pci_dev *)drv->dev, cs4231_chip->input_dma_handle, - cs4231_chip->input_dma_size); + cs4231_chip->input_dma_size, + PCI_DMA_FROMDEVICE); cs4231_chip->input_dma_handle = 0; cs4231_chip->input_dma_size = 0; } @@ -1773,7 +1792,8 @@ if (cs4231_chip->input_next_dma_handle) { pci_unmap_single((struct pci_dev *)drv->dev, cs4231_chip->input_next_dma_handle, - cs4231_chip->input_next_dma_size); + cs4231_chip->input_next_dma_size, + PCI_DMA_FROMDEVICE); cs4231_chip->input_next_dma_handle = 0; cs4231_chip->input_next_dma_size = 0; } diff -u --recursive --new-file v2.3.46/linux/drivers/sbus/audio/dbri.c linux/drivers/sbus/audio/dbri.c --- v2.3.46/linux/drivers/sbus/audio/dbri.c Tue Feb 1 01:35:44 2000 +++ linux/drivers/sbus/audio/dbri.c Fri Feb 18 15:07:20 2000 @@ -1,4 +1,4 @@ -/* $Id: dbri.c,v 1.18 2000/01/28 13:42:50 jj Exp $ +/* $Id: dbri.c,v 1.19 2000/02/18 13:49:42 davem Exp $ * drivers/sbus/audio/dbri.c * * Copyright (C) 1997 Rudolf Koenig (rfkoenig@immd4.informatik.uni-erlangen.de) @@ -356,7 +356,8 @@ if (buffer) sbus_unmap_single(dbri->sdev, dbri->descs[td].buffer_dvma, - dbri->descs[td].len); + dbri->descs[td].len, + SBUS_DMA_TODEVICE); callback = dbri->descs[td].output_callback; callback_arg = dbri->descs[td].output_callback_arg; @@ -391,7 +392,8 @@ if (buffer) sbus_unmap_single(dbri->sdev, dbri->descs[rd].buffer_dvma, - dbri->descs[rd].len); + dbri->descs[rd].len, + SBUS_DMA_FROMDEVICE); callback = dbri->descs[rd].input_callback; if (callback != NULL) @@ -592,7 +594,9 @@ if (buffer) sbus_unmap_single(dbri->sdev, dbri->descs[desc].buffer_dvma, - dbri->descs[desc].len); + dbri->descs[desc].len, + output_callback != NULL ? SBUS_DMA_TODEVICE + : SBUS_DMA_FROMDEVICE); dbri->descs[desc].inuse = 0; desc = dbri->descs[desc].next; @@ -863,7 +867,8 @@ return; } - dvma_buffer_base = dvma_buffer = sbus_map_single(dbri->sdev, buffer, len); + dvma_buffer_base = dvma_buffer = sbus_map_single(dbri->sdev, buffer, len, + SBUS_DMA_TODEVICE); while (len > 0) { int mylen; @@ -907,6 +912,9 @@ } if (first_td == -1 || last_td == -1) { + sbus_unmap_single(dbri->sdev, dvma_buffer_base, + dvma_buffer - dvma_buffer_base + len, + SBUS_DMA_TODEVICE); return; } @@ -914,7 +922,7 @@ dbri->descs[last_td].buffer = buffer; dbri->descs[last_td].buffer_dvma = dvma_buffer_base; - dbri->descs[last_td].len = len; + dbri->descs[last_td].len = dvma_buffer - dvma_buffer_base + len; dbri->descs[last_td].output_callback = callback; dbri->descs[last_td].output_callback_arg = callback_arg; @@ -999,7 +1007,8 @@ /* Make sure buffer size is multiple of four */ len &= ~3; - bus_buffer_base = bus_buffer = sbus_map_single(dbri->sdev, buffer, len); + bus_buffer_base = bus_buffer = sbus_map_single(dbri->sdev, buffer, len, + SBUS_DMA_FROMDEVICE); while (len > 0) { int rd, mylen; @@ -1043,8 +1052,12 @@ len -= mylen; } - if (last_rd == -1 || first_rd == -1) + if (last_rd == -1 || first_rd == -1) { + sbus_unmap_single(dbri->sdev, bus_buffer_base, + bus_buffer - bus_buffer_base + len, + SBUS_DMA_FROMDEVICE); return; + } for (rd=first_rd; rd != -1; rd = dbri->descs[rd].next) { dprintk(D_DESC, ("DBRI RD %d: %08x %08x %08x %08x\n", @@ -1057,7 +1070,7 @@ dbri->descs[last_rd].buffer = buffer; dbri->descs[last_rd].buffer_dvma = bus_buffer_base; - dbri->descs[last_rd].len = len; + dbri->descs[last_rd].len = bus_buffer - bus_buffer_base + len; dbri->descs[last_rd].input_callback = callback; dbri->descs[last_rd].input_callback_arg = callback_arg; diff -u --recursive --new-file v2.3.46/linux/drivers/sbus/char/bpp.c linux/drivers/sbus/char/bpp.c --- v2.3.46/linux/drivers/sbus/char/bpp.c Wed Feb 16 17:03:52 2000 +++ linux/drivers/sbus/char/bpp.c Sun Feb 20 08:48:46 2000 @@ -1027,7 +1027,6 @@ for (idx = 0; idx < BPP_NO; idx += 1) { instances[idx].opened = 0; probeLptPort(idx); - sprintf(devname, "%s%i", dev_name, idx); } devfs_handle = devfs_mk_dir (NULL, "bpp", 3, NULL); devfs_register_series (devfs_handle, "%u", BPP_NO, DEVFS_FL_DEFAULT, diff -u --recursive --new-file v2.3.46/linux/drivers/sbus/dvma.c linux/drivers/sbus/dvma.c --- v2.3.46/linux/drivers/sbus/dvma.c Wed Dec 29 13:13:18 1999 +++ linux/drivers/sbus/dvma.c Thu Feb 17 09:26:31 2000 @@ -105,7 +105,8 @@ } dma->regs = sbus_ioremap(&dma->sdev->resource[0], 0, - PAGE_SIZE, "dma"); + dma->sdev->resource[0].end - dma->sdev->resource[0].start + 1, + "dma"); dma->node = dma->sdev->prom_node; diff -u --recursive --new-file v2.3.46/linux/drivers/scsi/aic7xxx.c linux/drivers/scsi/aic7xxx.c --- v2.3.46/linux/drivers/scsi/aic7xxx.c Sat Feb 12 11:22:11 2000 +++ linux/drivers/scsi/aic7xxx.c Sun Feb 20 08:48:45 2000 @@ -719,6 +719,11 @@ #define aic7xxx_position(cmd) ((cmd)->SCp.have_data_in) /* + * The stored DMA mapping for single-buffer data transfers. + */ +#define aic7xxx_mapping(cmd) ((cmd)->SCp.phase) + +/* * So we can keep track of our host structs */ static struct aic7xxx_host *first_aic7xxx = NULL; @@ -2894,15 +2899,23 @@ struct aic7xxx_scb *scbp; unsigned char queue_depth; - if (scb->sg_count == 1) - pci_unmap_single(p->pdev, le32_to_cpu(scb->sg_list[0].address), - le32_to_cpu(scb->sg_list[0].length)); - else if (scb->sg_count > 1) + if (cmd->use_sg > 1) { struct scatterlist *sg; sg = (struct scatterlist *)cmd->request_buffer; - pci_unmap_sg(p->pdev, sg, cmd->use_sg); + pci_unmap_sg(p->pdev, sg, cmd->use_sg, scsi_to_pci_dma_dir(cmd->sc_data_direction)); + } + else if (cmd->request_bufflen) + pci_unmap_single(p->pdev, aic7xxx_mapping(cmd), + cmd->request_bufflen, + scsi_to_pci_dma_dir(cmd->sc_data_direction)); + if (scb->flags & SCB_SENSE) + { + pci_unmap_single(p->pdev, + le32_to_cpu(scb->sg_list[0].address), + sizeof(cmd->sense_buffer), + PCI_DMA_FROMDEVICE); } if (scb->flags & SCB_RECOVERY_SCB) { @@ -4887,7 +4900,8 @@ } scb->sg_list[0].address = cpu_to_le32(pci_map_single(p->pdev, sense_buffer, - sizeof(cmd->sense_buffer))); + sizeof(cmd->sense_buffer), + PCI_DMA_FROMDEVICE)); hscb->data_pointer = scb->sg_list[0].address; scb->flags |= SCB_SENSE; @@ -10607,6 +10621,7 @@ cmd->lun = 0; cmd->request_bufflen = 255; cmd->request_buffer = buffer; + cmd->sc_data_direction = SCSI_DATA_READ; cmd->use_sg = cmd->old_use_sg = cmd->sglist_len = 0; cmd->bufflen = 0; cmd->buffer = NULL; @@ -10954,7 +10969,7 @@ sg = (struct scatterlist *)cmd->request_buffer; scb->sg_length = 0; - use_sg = pci_map_sg(p->pdev, sg, cmd->use_sg); + use_sg = pci_map_sg(p->pdev, sg, cmd->use_sg, scsi_to_pci_dma_dir(cmd->sc_data_direction)); /* * Copy the segments into the SG array. NOTE!!! - We used to * have the first entry both in the data_pointer area and the first @@ -10981,7 +10996,9 @@ if (cmd->request_bufflen) { unsigned int address = pci_map_single(p->pdev, cmd->request_buffer, - cmd->request_bufflen); + cmd->request_bufflen, + scsi_to_pci_dma_dir(cmd->sc_data_direction)); + aic7xxx_mapping(cmd) = address; scb->sg_list[0].address = cpu_to_le32(address); scb->sg_list[0].length = cpu_to_le32(cmd->request_bufflen); scb->sg_count = 1; diff -u --recursive --new-file v2.3.46/linux/drivers/scsi/constants.c linux/drivers/scsi/constants.c --- v2.3.46/linux/drivers/scsi/constants.c Mon Jul 5 19:56:46 1999 +++ linux/drivers/scsi/constants.c Wed Feb 16 20:21:45 2000 @@ -410,11 +410,13 @@ #endif /* Print sense information */ -void print_sense(const char * devclass, Scsi_Cmnd * SCpnt) +static +void print_sense_internal(const char * devclass, + const unsigned char * sense_buffer, + kdev_t dev) { int i, s; int sense_class, valid, code; - unsigned char * sense_buffer = SCpnt->sense_buffer; const char * error = NULL; sense_class = (sense_buffer[0] >> 4) & 0x07; @@ -423,8 +425,8 @@ if (sense_class == 7) { /* extended sense data */ s = sense_buffer[7] + 8; - if(s > sizeof(SCpnt->sense_buffer)) - s = sizeof(SCpnt->sense_buffer); + if(s > SCSI_SENSE_BUFFERSIZE) + s = SCSI_SENSE_BUFFERSIZE; if (!valid) printk("[valid=0] "); @@ -455,10 +457,10 @@ #if (CONSTANTS & CONST_SENSE) printk( "%s%s: sense key %s\n", devclass, - kdevname(SCpnt->request.rq_dev), snstext[sense_buffer[2] & 0x0f]); + kdevname(dev), snstext[sense_buffer[2] & 0x0f]); #else printk("%s%s: sns = %2x %2x\n", devclass, - kdevname(SCpnt->request.rq_dev), sense_buffer[0], sense_buffer[2]); + kdevname(dev), sense_buffer[0], sense_buffer[2]); #endif /* Check to see if additional sense information is available */ @@ -495,11 +497,11 @@ #if (CONSTANTS & CONST_SENSE) if (sense_buffer[0] < 15) printk("%s%s: old sense key %s\n", devclass, - kdevname(SCpnt->request.rq_dev), snstext[sense_buffer[0] & 0x0f]); + kdevname(dev), snstext[sense_buffer[0] & 0x0f]); else #endif printk("%s%s: sns = %2x %2x\n", devclass, - kdevname(SCpnt->request.rq_dev), sense_buffer[0], sense_buffer[2]); + kdevname(dev), sense_buffer[0], sense_buffer[2]); printk("Non-extended sense class %d code 0x%0x ", sense_class, code); s = 4; @@ -513,6 +515,18 @@ printk("\n"); #endif return; +} + +void print_sense(const char * devclass, Scsi_Cmnd * SCpnt) +{ + print_sense_internal(devclass, SCpnt->sense_buffer, + SCpnt->request.rq_dev); +} + +void print_req_sense(const char * devclass, Scsi_Request * SRpnt) +{ + print_sense_internal(devclass, SRpnt->sr_sense_buffer, + SRpnt->sr_request.rq_dev); } #if (CONSTANTS & CONST_MSG) diff -u --recursive --new-file v2.3.46/linux/drivers/scsi/eata_dma_proc.c linux/drivers/scsi/eata_dma_proc.c --- v2.3.46/linux/drivers/scsi/eata_dma_proc.c Fri Jan 28 15:09:08 2000 +++ linux/drivers/scsi/eata_dma_proc.c Fri Feb 18 15:07:20 2000 @@ -167,6 +167,7 @@ cmnd[9] = 0; scmd->cmd_len = 10; + scmd->sc_data_direction = DATA_READ; /* * Do the command and wait for it to finish. @@ -291,6 +292,7 @@ cmnd[9] = 0; scmd->cmd_len = 10; + scmd->sc_data_direction = SCSI_DATA_READ; /* * Do the command and wait for it to finish. diff -u --recursive --new-file v2.3.46/linux/drivers/scsi/esp.c linux/drivers/scsi/esp.c --- v2.3.46/linux/drivers/scsi/esp.c Wed Feb 16 17:03:52 2000 +++ linux/drivers/scsi/esp.c Fri Feb 18 15:07:20 2000 @@ -1,4 +1,4 @@ -/* $Id: esp.c,v 1.91 2000/02/14 08:46:24 jj Exp $ +/* $Id: esp.c,v 1.92 2000/02/18 13:49:58 davem Exp $ * esp.c: EnhancedScsiProcessor Sun SCSI driver code. * * Copyright (C) 1995, 1998 David S. Miller (davem@caip.rutgers.edu) @@ -1414,7 +1414,8 @@ sp->SCp.buffers_residual = 0; if (sp->request_bufflen) { sp->SCp.have_data_in = sbus_map_single(esp->sdev, sp->SCp.buffer, - sp->SCp.this_residual); + sp->SCp.this_residual, + scsi_to_sbus_dma_dir(sp->sc_data_direction)); sp->SCp.ptr = (char *) ((unsigned long)sp->SCp.have_data_in); } else { sp->SCp.ptr = NULL; @@ -1423,7 +1424,8 @@ sp->SCp.buffer = (struct scatterlist *) sp->buffer; sp->SCp.buffers_residual = sbus_map_sg(esp->sdev, sp->SCp.buffer, - sp->use_sg); + sp->use_sg, + scsi_to_sbus_dma_dir(sp->sc_data_direction)); sp->SCp.this_residual = sg_dma_len(sp->SCp.buffer); sp->SCp.ptr = (char *) ((unsigned long)sg_dma_address(sp->SCp.buffer)); } @@ -1432,11 +1434,13 @@ static void esp_release_dmabufs(struct esp *esp, Scsi_Cmnd *sp) { if (sp->use_sg) { - sbus_unmap_sg(esp->sdev, sp->buffer, sp->use_sg); + sbus_unmap_sg(esp->sdev, sp->buffer, sp->use_sg, + scsi_to_sbus_dma_dir(sp->sc_data_direction)); } else if (sp->request_bufflen) { sbus_unmap_single(esp->sdev, sp->SCp.have_data_in, - sp->request_bufflen); + sp->request_bufflen, + scsi_to_sbus_dma_dir(sp->sc_data_direction)); } } diff -u --recursive --new-file v2.3.46/linux/drivers/scsi/hosts.c linux/drivers/scsi/hosts.c --- v2.3.46/linux/drivers/scsi/hosts.c Wed Feb 16 17:03:52 2000 +++ linux/drivers/scsi/hosts.c Wed Feb 16 20:21:45 2000 @@ -777,6 +777,14 @@ retval->max_id = 8; retval->max_lun = 8; + /* + * All drivers right now should be able to handle 12 byte commands. + * Every so often there are requests for 16 byte commands, but individual + * low-level drivers need to certify that they actually do something + * sensible with such commands. + */ + retval->max_cmd_len = 12; + retval->unique_id = 0; retval->io_port = 0; retval->hostt = tpnt; @@ -787,6 +795,7 @@ retval->host_blocked = FALSE; + retval->host_self_blocked = FALSE; #ifdef DEBUG printk("Register %x %x: %d\n", (int)retval, (int)retval->hostt, j); diff -u --recursive --new-file v2.3.46/linux/drivers/scsi/hosts.h linux/drivers/scsi/hosts.h --- v2.3.46/linux/drivers/scsi/hosts.h Wed Feb 16 17:03:52 2000 +++ linux/drivers/scsi/hosts.h Sun Feb 20 20:49:29 2000 @@ -362,6 +362,17 @@ * initialized, as required. */ + /* + * The maximum length of SCSI commands that this host can accept. + * Probably 12 for most host adapters, but could be 16 for others. + * For drivers that don't set this field, a value of 12 is + * assumed. I am leaving this as a number rather than a bit + * because you never know what subsequent SCSI standards might do + * (i.e. could there be a 20 byte or a 24-byte command a few years + * down the road?). + */ + unsigned char max_cmd_len; + int this_id; int can_queue; short cmd_per_lun; @@ -379,6 +390,12 @@ * Host has rejected a command because it was busy. */ unsigned host_blocked:1; + + /* + * Host has requested that no further requests come through for the + * time being. + */ + unsigned host_self_blocked:1; /* * Host uses correct SCSI ordering not PC ordering. The bit is @@ -412,6 +429,10 @@ */ extern void scsi_free_host_dev(Scsi_Device * SDpnt); extern Scsi_Device * scsi_get_host_dev(struct Scsi_Host * SHpnt); + +extern void scsi_unblock_requests(struct Scsi_Host * SHpnt); +extern void scsi_block_requests(struct Scsi_Host * SHpnt); +extern void scsi_report_bus_reset(struct Scsi_Host * SHpnt, int channel); typedef struct SHN { diff -u --recursive --new-file v2.3.46/linux/drivers/scsi/pci2000.c linux/drivers/scsi/pci2000.c --- v2.3.46/linux/drivers/scsi/pci2000.c Thu Nov 11 20:11:48 1999 +++ linux/drivers/scsi/pci2000.c Fri Feb 18 14:50:03 2000 @@ -53,7 +53,15 @@ #include "pci2000.h" #include "psi_roy.h" -#include +#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 @@ -120,6 +128,28 @@ return TRUE; } /**************************************************************** + * Name: WaitReadyLong :LOCAL + * + * Description: Wait for controller ready. + * + * Parameters: padapter - Pointer adapter data structure. + * + * Returns: TRUE on not ready. + * + ****************************************************************/ +static int WaitReadyLong (PADAPTER2000 padapter) + { + ULONG z; + + for ( z = 0; z < (5000 * 4); z++ ) + { + if ( !inb_p (padapter->cmd) ) + return FALSE; + udelay (250); + }; + return TRUE; + } +/**************************************************************** * Name: OpDone :LOCAL * * Description: Clean up operation and issue done to caller. @@ -204,7 +234,7 @@ if ( WaitReady (padapter) ) // test for command register ready return DID_TIME_OUT; outb_p (cmd, padapter->cmd); // issue command - if ( WaitReady (padapter) ) // wait for adapter ready + if ( WaitReadyLong (padapter) ) // wait for adapter ready return DID_TIME_OUT; return DID_OK; } @@ -232,13 +262,23 @@ int pun; int bus; int z; +#if LINUX_VERSION_CODE < LINUXVERSION(2,1,95) + int flags; +#else /* version >= v2.1.95 */ unsigned long flags; +#endif /* version >= v2.1.95 */ +#if LINUX_VERSION_CODE < LINUXVERSION(2,1,95) + /* Disable interrupts, if they aren't already disabled. */ + save_flags (flags); + cli (); +#else /* version >= v2.1.95 */ /* * Disable interrupts, if they aren't already disabled and acquire * the I/O spinlock. */ spin_lock_irqsave (&io_request_lock, flags); +#endif /* version >= v2.1.95 */ DEB(printk ("\npci2000 recieved interrupt ")); for ( z = 0; z < NumAdapters; z++ ) // scan for interrupt to process @@ -327,12 +367,20 @@ OpDone (SCpnt, DID_OK << 16); irq_return:; +#if LINUX_VERSION_CODE < LINUXVERSION(2,1,95) + /* + * Restore the original flags which will enable interrupts + * if and only if they were enabled on entry. + */ + restore_flags (flags); +#else /* version >= v2.1.95 */ /* * Release the I/O spinlock and restore the original flags * which will enable interrupts if and only if they were * enabled on entry. */ spin_unlock_irqrestore (&io_request_lock, flags); +#endif /* version >= v2.1.95 */ } /**************************************************************** * Name: Pci2000_QueueCommand @@ -589,21 +637,37 @@ PADAPTER2000 padapter; int z, zz; int setirq; +#if LINUX_VERSION_CODE > LINUXVERSION(2,1,92) struct pci_dev *pdev = NULL; +#else + UCHAR pci_bus, pci_device_fn; +#endif +#if LINUX_VERSION_CODE > LINUXVERSION(2,1,92) if ( !pci_present () ) +#else + if ( !pcibios_present () ) +#endif { printk ("pci2000: PCI BIOS not present\n"); return 0; } +#if LINUX_VERSION_CODE > LINUXVERSION(2,1,92) while ( (pdev = pci_find_device (VENDOR_PSI, DEVICE_ROY_1, pdev)) != NULL ) +#else + while ( !pcibios_find_device (VENDOR_PSI, DEVICE_ROY_1, found, &pci_bus, &pci_device_fn) ) +#endif { pshost = scsi_register (tpnt, sizeof(ADAPTER2000)); padapter = HOSTDATA(pshost); - padapter->basePort = pdev->resource[1].start; - +#if LINUX_VERSION_CODE > LINUXVERSION(2,1,92) + padapter->basePort = pdev->base_address[1] & 0xFFFE; +#else + pcibios_read_config_word (pci_bus, pci_device_fn, PCI_BASE_ADDRESS_1, &padapter->basePort); + padapter->basePort &= 0xFFFE; +#endif DEB (printk ("\nBase Regs = %#04X", padapter->basePort)); // get the base I/O port address padapter->mb0 = padapter->basePort + RTR_MAILBOX; // get the 32 bit mail boxes padapter->mb1 = padapter->basePort + RTR_MAILBOX + 4; @@ -620,7 +684,11 @@ if ( WaitReady (padapter) ) goto unregister; +#if LINUX_VERSION_CODE > LINUXVERSION(2,1,92) pshost->irq = pdev->irq; +#else + pcibios_read_config_byte (pci_bus, pci_device_fn, PCI_INTERRUPT_LINE, &pshost->irq); +#endif setirq = 1; padapter->irqOwned = 0; for ( z = 0; z < installed; z++ ) // scan for shared interrupts @@ -714,7 +782,11 @@ PADAPTER2000 padapter = HOSTDATA (pshost); if ( padapter->irqOwned ) +#if LINUX_VERSION_CODE < LINUXVERSION(1,3,70) + free_irq (pshost->irq); +#else /* version >= v1.3.70 */ free_irq (pshost->irq, padapter); +#endif /* version >= v1.3.70 */ release_region (pshost->io_port, pshost->n_io_port); scsi_unregister(pshost); return 0; @@ -760,4 +832,3 @@ #include "scsi_module.c" #endif - diff -u --recursive --new-file v2.3.46/linux/drivers/scsi/pci2000.h linux/drivers/scsi/pci2000.h --- v2.3.46/linux/drivers/scsi/pci2000.h Thu Nov 11 20:11:48 1999 +++ linux/drivers/scsi/pci2000.h Sun Feb 20 20:49:46 2000 @@ -200,10 +200,13 @@ #define NULL 0 #endif +extern struct proc_dir_entry Proc_Scsi_Pci2000; + +#if LINUX_VERSION_CODE >= LINUXVERSION(2,1,75) #define PCI2000 { \ next: NULL, \ module: NULL, \ - proc_name: "pci2000", \ + proc_dir: &Proc_Scsi_Pci2000, \ proc_info: NULL, /* let's not bloat the kernel */ \ name: "PCI-2000 SCSI Intelligent Disk Controller",\ detect: Pci2000_Detect, \ @@ -229,4 +232,27 @@ use_clustering: DISABLE_CLUSTERING, \ use_new_eh_code: 0 \ } +#else +#define PCI2000 { NULL, NULL, \ + &Proc_Scsi_Pci2000,/* proc_dir_entry */ \ + NULL, \ + "PCI-2000 SCSI Intelligent Disk Controller",\ + Pci2000_Detect, \ + Pci2000_Release, \ + NULL, \ + Pci2000_Command, \ + Pci2000_QueueCommand, \ + Pci2000_Abort, \ + Pci2000_Reset, \ + NULL, \ + Pci2000_BiosParam, \ + 16, \ + -1, \ + 16, \ + 1, \ + 0, \ + 0, \ + DISABLE_CLUSTERING } +#endif + #endif diff -u --recursive --new-file v2.3.46/linux/drivers/scsi/pci2220i.c linux/drivers/scsi/pci2220i.c --- v2.3.46/linux/drivers/scsi/pci2220i.c Thu Nov 11 20:11:48 1999 +++ linux/drivers/scsi/pci2220i.c Fri Feb 18 14:50:03 2000 @@ -24,8 +24,15 @@ * Revisions 1.11 Mar-26-1999 * - Fixed spinlock and PCI configuration. * + * Revision 2.00 December-1-1999 + * - Added code for the PCI-2240I controller + * - Added code for ATAPI devices. + * - Double buffer for scatter/gather support + * ****************************************************************************/ +//#define DEBUG 1 + #include #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 @@ ULONG lastsectorlba[2]; // last addressable sector on the drive USHORT raid; // RAID active flag USHORT mirrorRecon; - UCHAR hotRecon; + UCHAR reconOn; USHORT reconCount; + USHORT reconIsStarting; // indicate hot reconstruct is starting + UCHAR cmdDrqInt; // flag for command interrupt + UCHAR packet; // command packet size in bytes } OUR_DEVICE, *POUR_DEVICE; typedef struct { + USHORT bigD; // identity is a PCI-2240I if true, otherwise a PCI-2220I + USHORT atapi; // this interface is for ATAPI devices only USHORT regDmaDesc; // address of the DMA discriptor register for direction of transfer USHORT regDmaCmdStat; // Byte #1 of DMA command status register USHORT regDmaAddrPci; // 32 bit register for PCI address of DMA @@ -119,16 +135,21 @@ USHORT timingPIO; // TRUE if PIO timing is active ULONG timingAddress; // address to use on adapter for current timing mode ULONG irqOwned; // owned IRQ or zero if shared - OUR_DEVICE device[DALE_MAXDRIVES]; - DISK_MIRROR *raidData[8]; + UCHAR numberOfDrives; // saved number of drives on this controller + UCHAR failRegister; // current inverted data in fail register + OUR_DEVICE device[BIGD_MAXDRIVES]; + DISK_MIRROR *raidData[BIGD_MAXDRIVES]; ULONG startSector; USHORT sectorCount; + ULONG readCount; + UCHAR *currentSgBuffer; + ULONG currentSgCount; + USHORT nextSg; UCHAR cmd; Scsi_Cmnd *SCpnt; - VOID *buffer; POUR_DEVICE pdev; // current device opearating on + USHORT devInReconIndex; USHORT expectingIRQ; - USHORT reconIsStarting; // indicate hot reconstruct is starting USHORT reconOn; // Hot reconstruct is to be done. USHORT reconPhase; // Hot reconstruct operation is in progress. ULONG reconSize; @@ -138,6 +159,9 @@ struct timer_list reconTimer; struct timer_list timer; UCHAR *kBuffer; + UCHAR reqSense; + UCHAR atapiCdb[16]; + UCHAR atapiSpecial; } ADAPTER2220I, *PADAPTER2220I; #define HOSTDATA(host) ((PADAPTER2220I)&host->hostdata) @@ -152,12 +176,41 @@ static struct Scsi_Host *PsiHost[MAXADAPTER] = {NULL,}; // One for each adapter static int NumAdapters = 0; +static int Installed = 0; static SETUP DaleSetup; -static DISK_MIRROR DiskMirror[2]; -static ULONG ModeArray[] = {DALE_DATA_MODE2, DALE_DATA_MODE3, DALE_DATA_MODE4, DALE_DATA_MODE4P}; +static DISK_MIRROR DiskMirror[BIGD_MAXDRIVES]; +static ULONG ModeArray[] = {DALE_DATA_MODE2, DALE_DATA_MODE3, DALE_DATA_MODE4, DALE_DATA_MODE5}; +static ULONG ModeArray2[] = {BIGD_DATA_MODE2, BIGD_DATA_MODE3, BIGD_DATA_MODE4, BIGD_DATA_MODE5}; static void ReconTimerExpiry (unsigned long data); +/******************************************************************************************************* + * Name: Alarm + * + * Description: Sound the for the given device + * + * Parameters: padapter - Pointer adapter data structure. + * device - Device number. + * + * Returns: Nothing. + * + ******************************************************************************************************/ +static void Alarm (PADAPTER2220I padapter, UCHAR device) + { + UCHAR zc; + + if ( padapter->bigD ) + { + zc = device | (FAIL_ANY | FAIL_AUDIBLE); + if ( padapter->failRegister & FAIL_ANY ) + zc |= FAIL_MULTIPLE; + + padapter->failRegister = zc; + outb_p (~zc, padapter->regFail); + } + else + outb_p (0x3C | (1 << device), padapter->regFail); // sound alarm and set fail light + } /**************************************************************** * Name: MuteAlarm :LOCAL * @@ -172,8 +225,16 @@ { UCHAR old; - old = (inb_p (padapter->regStatSel) >> 3) | (inb_p (padapter->regStatSel) & 0x83); - outb_p (old | 0x40, padapter->regFail); + if ( padapter->bigD ) + { + padapter->failRegister &= ~FAIL_AUDIBLE; + outb_p (~padapter->failRegister, padapter->regFail); + } + else + { + old = (inb_p (padapter->regStatSel) >> 3) | (inb_p (padapter->regStatSel) & 0x83); + outb_p (old | 0x40, padapter->regFail); + } } /**************************************************************** * Name: WaitReady :LOCAL @@ -214,17 +275,17 @@ ULONG z; UCHAR status; - for ( z = 0; z < (250 * 4); z++ ) // wait up to 1/4 second + for ( z = 0; z < (125 * 16); z++ ) // wait up to 1/4 second { status = inb_p (padapter->regStatCmd); if ( (status & (IDE_STATUS_DRDY | IDE_STATUS_BUSY)) == IDE_STATUS_DRDY ) { - DEB (printk ("\nPCI2220I: Reset took %ld mSec to be ready", z / 4)); + DEB (printk ("\nPCI2220I: Reset took %ld mSec to be ready", z / 8)); return 0; } - udelay (250); + udelay (125); } - DEB (printk ("\nPCI2220I: Reset took more than 1 Second to come ready, Disk Failure")); + DEB (printk ("\nPCI2220I: Reset took more than 2 Seconds to come ready, Disk Failure")); return status; } /**************************************************************** @@ -252,6 +313,52 @@ return status; } /**************************************************************** + * Name: AtapiWaitReady :LOCAL + * + * Description: Wait for device busy and DRQ to be cleared. + * + * Parameters: padapter - Pointer adapter data structure. + * msec - Number of milliseconds to wait. + * + * Returns: TRUE if drive does not clear busy in time. + * + ****************************************************************/ +static int AtapiWaitReady (PADAPTER2220I padapter, int msec) + { + int z; + + for ( z = 0; z < (msec * 16); z++ ) + { + if ( !(inb_p (padapter->regStatCmd) & (IDE_STATUS_BUSY | IDE_STATUS_DRQ)) ) + return FALSE; + udelay (125); + } + return TRUE; + } +/**************************************************************** + * Name: AtapiWaitDrq :LOCAL + * + * Description: Wait for device ready for data transfer. + * + * Parameters: padapter - Pointer adapter data structure. + * msec - Number of milliseconds to wait. + * + * Returns: TRUE if drive does not assert DRQ in time. + * + ****************************************************************/ +static int AtapiWaitDrq (PADAPTER2220I padapter, int msec) + { + ULONG z; + + for ( z = 0; z < (msec * 16); z++ ) + { + if ( inb_p (padapter->regStatCmd) & IDE_STATUS_DRQ ) + return 0; + udelay (128); + } + return TRUE; + } +/**************************************************************** * Name: HardReset :LOCAL * * Description: Wait for device ready for data transfer. @@ -265,24 +372,113 @@ ****************************************************************/ static int HardReset (PADAPTER2220I padapter, POUR_DEVICE pdev, UCHAR spigot) { - SelectSpigot (padapter, spigot | 0x80); + DEB (printk ("\npci2220i:RESET spigot = %X devices = %d, %d", spigot, pdev->deviceID[0], pdev->deviceID[1])); + udelay (100000); // just wait 100 mSec to let drives flush + SelectSpigot (padapter, spigot | SEL_IRQ_OFF); outb_p (0x0E, padapter->regAltStat); // reset the suvivor udelay (100); // wait a little outb_p (0x08, padapter->regAltStat); // clear the reset udelay (100); - outb_p (0xA0, padapter->regLba24); //Specify drive - outb_p (pdev->byte6, padapter->regLba24); // select the drive + outb_p (0xA0, padapter->regLba24); // select the master drive if ( WaitReadyReset (padapter) ) + { + DEB (printk ("\npci2220i: master not ready after reset")); return TRUE; + } + outb_p (0xB0, padapter->regLba24); // try the slave drive + if ( (inb_p (padapter->regStatCmd) & (IDE_STATUS_DRDY | IDE_STATUS_BUSY)) == IDE_STATUS_DRDY ) + { + DEB (printk ("\nPCI2220I: initializing slave drive on spigot %X", spigot)); + outb_p (SECTORSXFER, padapter->regSectCount); + WriteCommand (padapter, IDE_CMD_SET_MULTIPLE); + if ( WaitReady (padapter) ) + { + DEB (printk ("\npci2220i: slave not ready after set multiple")); + return TRUE; + } + } + + outb_p (0xA0, padapter->regLba24); // select the drive outb_p (SECTORSXFER, padapter->regSectCount); WriteCommand (padapter, IDE_CMD_SET_MULTIPLE); if ( WaitReady (padapter) ) + { + DEB (printk ("\npci2220i: master not ready after set multiple")); + return TRUE; + } + return FALSE; + } +/**************************************************************** + * Name: AtapiReset :LOCAL + * + * Description: Wait for device ready for data transfer. + * + * Parameters: padapter - Pointer adapter data structure. + * pdev - Pointer to device. + * + * Returns: TRUE if drive does not come ready. + * + ****************************************************************/ +static int AtapiReset (PADAPTER2220I padapter, POUR_DEVICE pdev) + { + SelectSpigot (padapter, pdev->spigot); + AtapiDevice (padapter, pdev->byte6); + AtapiCountLo (padapter, 0); + AtapiCountHi (padapter, 0); + WriteCommand (padapter, IDE_COMMAND_ATAPI_RESET); + udelay (125); + if ( AtapiWaitReady (padapter, 1000) ) + return TRUE; + if ( inb_p (padapter->regStatCmd) || (inb_p (padapter->regLba8) != 0x14) || (inb_p (padapter->regLba16) != 0xEB) ) return TRUE; return FALSE; } /**************************************************************** + * Name: WalkScatGath :LOCAL + * + * Description: Transfer data to/from scatter/gather buffers. + * + * Parameters: padapter - Pointer adapter data structure. + * datain - TRUE if data read. + * length - Number of bytes to transfer. + * + * Returns: Nothing. + * + ****************************************************************/ +static void WalkScatGath (PADAPTER2220I padapter, UCHAR datain, ULONG length) + { + ULONG count; + UCHAR *buffer = padapter->kBuffer; + + while ( length ) + { + count = ( length > padapter->currentSgCount ) ? padapter->currentSgCount : length; + + if ( datain ) + memcpy (padapter->currentSgBuffer, buffer, count); + else + memcpy (buffer, padapter->currentSgBuffer, count); + + padapter->currentSgCount -= count; + if ( !padapter->currentSgCount ) + { + if ( padapter->nextSg < padapter->SCpnt->use_sg ) + { + padapter->currentSgBuffer = ((struct scatterlist *)padapter->SCpnt->request_buffer)[padapter->nextSg].address; + padapter->currentSgCount = ((struct scatterlist *)padapter->SCpnt->request_buffer)[padapter->nextSg].length; + padapter->nextSg++; + } + } + else + padapter->currentSgBuffer += count; + + length -= count; + buffer += count; + } + } +/**************************************************************** * Name: BusMaster :LOCAL * * Description: Do a bus master I/O. @@ -291,34 +487,84 @@ * datain - TRUE if data read. * irq - TRUE if bus master interrupt expected. * - * Returns: TRUE if drive does not assert DRQ in time. + * Returns: Nothing. * ****************************************************************/ static void BusMaster (PADAPTER2220I padapter, UCHAR datain, UCHAR irq) { ULONG zl; - outl (padapter->timingAddress, padapter->regDmaAddrLoc); - outl (virt_to_bus (padapter->buffer), padapter->regDmaAddrPci); - zl = (padapter->sectorCount > MAX_BUS_MASTER_BLOCKS) ? MAX_BUS_MASTER_BLOCKS : padapter->sectorCount; + zl = ( padapter->sectorCount > MAX_BUS_MASTER_BLOCKS ) ? MAX_BUS_MASTER_BLOCKS : padapter->sectorCount; padapter->sectorCount -= zl; zl *= (ULONG)BYTES_PER_SECTOR; - padapter->buffer += zl; - outl (zl, padapter->regDmaCount); + if ( datain ) { - outb_p (8, padapter->regDmaDesc); // read operation - if ( irq && !padapter->sectorCount ) - outb_p (5, padapter->regDmaMode); // interrupt on + padapter->readCount = zl; + outb_p (8, padapter->regDmaDesc); // read operation + if ( padapter->bigD ) + { + if ( irq && !padapter->sectorCount ) + outb_p (0x0C, padapter->regDmaMode); // interrupt on + else + outb_p (0x08, padapter->regDmaMode); // no interrupt + } + else + { + if ( irq && !padapter->sectorCount ) + outb_p (0x05, padapter->regDmaMode); // interrupt on + else + outb_p (0x01, padapter->regDmaMode); // no interrupt + } + } + else + { + outb_p (0x00, padapter->regDmaDesc); // write operation + if ( padapter->bigD ) + outb_p (0x08, padapter->regDmaMode); // no interrupt else - outb_p (1, padapter->regDmaMode); // no interrupt + outb_p (0x01, padapter->regDmaMode); // no interrupt + WalkScatGath (padapter, FALSE, zl); + } + + outl (padapter->timingAddress, padapter->regDmaAddrLoc); + outl (virt_to_bus (padapter->kBuffer), padapter->regDmaAddrPci); + outl (zl, padapter->regDmaCount); + outb_p (0x03, padapter->regDmaCmdStat); // kick the DMA engine in gear + } +/**************************************************************** + * Name: AtapiBusMaster :LOCAL + * + * Description: Do a bus master I/O. + * + * Parameters: padapter - Pointer adapter data structure. + * datain - TRUE if data read. + * length - Number of bytes to transfer. + * + * Returns: Nothing. + * + ****************************************************************/ +static void AtapiBusMaster (PADAPTER2220I padapter, UCHAR datain, ULONG length) + { + outl (padapter->timingAddress, padapter->regDmaAddrLoc); + outl (virt_to_bus (padapter->kBuffer), padapter->regDmaAddrPci); + outl (length, padapter->regDmaCount); + if ( datain ) + { + if ( padapter->readCount ) + WalkScatGath (padapter, TRUE, padapter->readCount); + outb_p (0x08, padapter->regDmaDesc); // read operation + outb_p (0x08, padapter->regDmaMode); // no interrupt + padapter->readCount = length; } else { - outb_p (0, padapter->regDmaDesc); // write operation - outb_p (1, padapter->regDmaMode); // no interrupt + outb_p (0x00, padapter->regDmaDesc); // write operation + outb_p (0x08, padapter->regDmaMode); // no interrupt + if ( !padapter->atapiSpecial ) + WalkScatGath (padapter, FALSE, length); } - outb_p (0x03, padapter->regDmaCmdStat); // kick the DMA engine in gear + outb_p (0x03, padapter->regDmaCmdStat); // kick the DMA engine in gear } /**************************************************************** * Name: WriteData :LOCAL @@ -339,9 +585,9 @@ if ( padapter->timingPIO ) { zl = (padapter->sectorCount > MAX_BUS_MASTER_BLOCKS) ? MAX_BUS_MASTER_BLOCKS : padapter->sectorCount; - outsw (padapter->regData, padapter->buffer, zl * (BYTES_PER_SECTOR / 2)); + WalkScatGath (padapter, FALSE, zl * BYTES_PER_SECTOR); + outsw (padapter->regData, padapter->kBuffer, zl * (BYTES_PER_SECTOR / 2)); padapter->sectorCount -= zl; - padapter->buffer += zl * BYTES_PER_SECTOR; } else BusMaster (padapter, 0, 0); @@ -355,31 +601,32 @@ * * Description: Write data to device. * - * Parameters: padapter - Pointer adapter data structure. + * Parameters: padapter - Pointer to adapter structure. + * pdev - Pointer to device structure * - * Returns: TRUE if drive does not assert DRQ in time. + * Returns: Index + 1 of drive not failed or zero for OK. * ****************************************************************/ -static int WriteDataBoth (PADAPTER2220I padapter) +static int WriteDataBoth (PADAPTER2220I padapter, POUR_DEVICE pdev) { ULONG zl; UCHAR status0, status1; - SelectSpigot (padapter, 1); + SelectSpigot (padapter, pdev->spigots[0]); status0 = WaitDrq (padapter); if ( !status0 ) { - SelectSpigot (padapter, 2); + SelectSpigot (padapter, pdev->spigots[1]); status1 = WaitDrq (padapter); if ( !status1 ) { - SelectSpigot (padapter, 3); + SelectSpigot (padapter, pdev->spigots[0] | pdev->spigots[1] | padapter->bigD); if ( padapter->timingPIO ) { zl = (padapter->sectorCount > MAX_BUS_MASTER_BLOCKS) ? MAX_BUS_MASTER_BLOCKS : padapter->sectorCount; - outsw (padapter->regData, padapter->buffer, zl * (BYTES_PER_SECTOR / 2)); + WalkScatGath (padapter, FALSE, zl * BYTES_PER_SECTOR); + outsw (padapter->regData, padapter->kBuffer, zl * (BYTES_PER_SECTOR / 2)); padapter->sectorCount -= zl; - padapter->buffer += zl * BYTES_PER_SECTOR; } else BusMaster (padapter, 0, 0); @@ -388,8 +635,8 @@ } padapter->cmd = 0; // null out the command byte if ( status0 ) - return 1; - return 2; + return 2; + return 1; } /**************************************************************** * Name: IdeCmd :LOCAL @@ -406,7 +653,7 @@ { UCHAR status; - SelectSpigot (padapter, pdev->spigot); // select the spigot + SelectSpigot (padapter, pdev->spigot | padapter->bigD); // select the spigot outb_p (pdev->byte6 | ((UCHAR *)(&padapter->startSector))[3], padapter->regLba24); // select the drive status = WaitReady (padapter); if ( !status ) @@ -429,26 +676,27 @@ * Description: Process an IDE command to both drivers. * * Parameters: padapter - Pointer adapter data structure. + * pdev - Pointer to device structure * - * Returns: Zero if no error or spigot of error. + * Returns: Index + 1 of drive not failed or zero for OK. * ****************************************************************/ -static UCHAR IdeCmdBoth (PADAPTER2220I padapter) +static UCHAR IdeCmdBoth (PADAPTER2220I padapter, POUR_DEVICE pdev) { UCHAR status0; UCHAR status1; - SelectSpigot (padapter, 3); // select the spigots + SelectSpigot (padapter, pdev->spigots[0] | pdev->spigots[1]); // select the spigots outb_p (padapter->pdev->byte6 | ((UCHAR *)(&padapter->startSector))[3], padapter->regLba24);// select the drive - SelectSpigot (padapter, 1); + SelectSpigot (padapter, pdev->spigots[0]); status0 = WaitReady (padapter); if ( !status0 ) { - SelectSpigot (padapter, 2); + SelectSpigot (padapter, pdev->spigots[1]); status1 = WaitReady (padapter); if ( !status1 ) { - SelectSpigot (padapter, 3); + SelectSpigot (padapter, pdev->spigots[0] | pdev->spigots[1] | padapter->bigD); outb_p (padapter->sectorCount, padapter->regSectCount); outb_p (((UCHAR *)(&padapter->startSector))[0], padapter->regLba0); outb_p (((UCHAR *)(&padapter->startSector))[1], padapter->regLba8); @@ -460,8 +708,8 @@ } padapter->cmd = 0; // null out the command byte if ( status0 ) - return 1; - return 2; + return 2; + return 1; } /**************************************************************** * Name: OpDone :LOCAL @@ -498,6 +746,7 @@ { padapter->cmd = 0; padapter->SCpnt = NULL; + padapter->pdev = NULL; SCpnt->result = result; SCpnt->scsi_done (SCpnt); if ( padapter->reconOn && !padapter->reconTimer.data ) @@ -524,8 +773,8 @@ { PIDENTIFY_DATA pid = (PIDENTIFY_DATA)padapter->kBuffer; - SelectSpigot (padapter, spigot | 0x80); // select the spigot - outb_p (device << 4, padapter->regLba24); // select the drive + SelectSpigot (padapter, spigot | SEL_IRQ_OFF); // select the spigot + outb_p ((device << 4) | 0xA0, padapter->regLba24); // select the drive if ( WaitReady (padapter) ) return 0; WriteCommand (padapter, IDE_COMMAND_IDENTIFY); @@ -535,6 +784,192 @@ return (pid->LBATotalSectors - 1); } /**************************************************************** + * Name: AtapiIdentify :LOCAL + * + * Description: Do an intline inquiry on a drive. + * + * Parameters: padapter - Pointer to host data block. + * pdev - Pointer to device table. + * + * Returns: TRUE on error. + * + ****************************************************************/ +static ULONG AtapiIdentify (PADAPTER2220I padapter, POUR_DEVICE pdev) + { + ATAPI_GENERAL_0 ag0; + USHORT zs; + int z; + + AtapiDevice (padapter, pdev->byte6); + WriteCommand (padapter, IDE_COMMAND_ATAPI_IDENTIFY); + if ( AtapiWaitDrq (padapter, 3000) ) + return TRUE; + + *(USHORT *)&ag0 = inw_p (padapter->regData); + for ( z = 0; z < 255; z++ ) + zs = inw_p (padapter->regData); + + if ( ag0.ProtocolType == 2 ) + { + if ( ag0.CmdDrqType == 1 ) + pdev->cmdDrqInt = TRUE; + switch ( ag0.CmdPacketSize ) + { + case 0: + pdev->packet = 6; + break; + case 1: + pdev->packet = 8; + break; + default: + pdev->packet = 6; + break; + } + return FALSE; + } + return TRUE; + } +/**************************************************************** + * Name: Atapi2Scsi + * + * Description: Convert ATAPI data to SCSI data. + * + * Parameters: padapter - Pointer adapter data structure. + * SCpnt - Pointer to SCSI command structure. + * + * Returns: Nothing. + * + ****************************************************************/ +void Atapi2Scsi (PADAPTER2220I padapter, Scsi_Cmnd *SCpnt) + { + UCHAR *buff = padapter->currentSgBuffer; + + switch ( SCpnt->cmnd[0] ) + { + case SCSIOP_MODE_SENSE: + buff[0] = padapter->kBuffer[1]; + buff[1] = padapter->kBuffer[2]; + buff[2] = padapter->kBuffer[3]; + buff[3] = padapter->kBuffer[7]; + memcpy (&buff[4], &padapter->kBuffer[8], padapter->atapiCdb[8] - 8); + break; + case SCSIOP_INQUIRY: + padapter->kBuffer[2] = 2; + memcpy (buff, padapter->kBuffer, padapter->currentSgCount); + break; + default: + if ( padapter->readCount ) + WalkScatGath (padapter, TRUE, padapter->readCount); + break; + } + } +/**************************************************************** + * Name: Scsi2Atapi + * + * Description: Convert SCSI packet command to Atapi packet command. + * + * Parameters: padapter - Pointer adapter data structure. + * SCpnt - Pointer to SCSI command structure. + * + * Returns: Nothing. + * + ****************************************************************/ +static void Scsi2Atapi (PADAPTER2220I padapter, Scsi_Cmnd *SCpnt) + { + UCHAR *cdb = SCpnt->cmnd; + UCHAR *buff = padapter->currentSgBuffer; + + switch (cdb[0]) + { + case SCSIOP_READ6: + padapter->atapiCdb[0] = SCSIOP_READ; + padapter->atapiCdb[1] = cdb[1] & 0xE0; + padapter->atapiCdb[3] = cdb[1] & 0x1F; + padapter->atapiCdb[4] = cdb[2]; + padapter->atapiCdb[5] = cdb[3]; + padapter->atapiCdb[8] = cdb[4]; + padapter->atapiCdb[9] = cdb[5]; + break; + case SCSIOP_WRITE6: + padapter->atapiCdb[0] = SCSIOP_WRITE; + padapter->atapiCdb[1] = cdb[1] & 0xE0; + padapter->atapiCdb[3] = cdb[1] & 0x1F; + padapter->atapiCdb[4] = cdb[2]; + padapter->atapiCdb[5] = cdb[3]; + padapter->atapiCdb[8] = cdb[4]; + padapter->atapiCdb[9] = cdb[5]; + break; + case SCSIOP_MODE_SENSE: + padapter->atapiCdb[0] = SCSIOP_MODE_SENSE10; + padapter->atapiCdb[2] = cdb[2]; + padapter->atapiCdb[8] = cdb[4] + 4; + break; + + case SCSIOP_MODE_SELECT: + padapter->atapiSpecial = TRUE; + padapter->atapiCdb[0] = SCSIOP_MODE_SELECT10; + padapter->atapiCdb[1] = cdb[1] | 0x10; + memcpy (padapter->kBuffer, buff, 4); + padapter->kBuffer[4] = padapter->kBuffer[5] = 0; + padapter->kBuffer[6] = padapter->kBuffer[7] = 0; + memcpy (&padapter->kBuffer[8], &buff[4], cdb[4] - 4); + padapter->atapiCdb[8] = cdb[4] + 4; + break; + } + } +/**************************************************************** + * Name: AtapiSendCdb + * + * Description: Send the CDB packet to the device. + * + * Parameters: padapter - Pointer adapter data structure. + * pdev - Pointer to device. + * cdb - Pointer to 16 byte SCSI cdb. + * + * Returns: Nothing. + * + ****************************************************************/ +static void AtapiSendCdb (PADAPTER2220I padapter, POUR_DEVICE pdev, CHAR *cdb) + { + DEB (printk ("\nPCI2242I: CDB: %X %X %X %X %X %X %X %X %X %X %X %X", cdb[0], cdb[1], cdb[2], cdb[3], cdb[4], cdb[5], cdb[6], cdb[7], cdb[8], cdb[9], cdb[10], cdb[11])); + outsw (padapter->regData, cdb, pdev->packet); + } +/**************************************************************** + * Name: AtapiRequestSense + * + * Description: Send the CDB packet to the device. + * + * Parameters: padapter - Pointer adapter data structure. + * pdev - Pointer to device. + * SCpnt - Pointer to SCSI command structure. + * pass - If true then this is the second pass to send cdb. + * + * Returns: TRUE on error. + * + ****************************************************************/ +static int AtapiRequestSense (PADAPTER2220I padapter, POUR_DEVICE pdev, Scsi_Cmnd *SCpnt, UCHAR pass) + { + UCHAR cdb[16] = {SCSIOP_REQUEST_SENSE,0,0,0,16,0,0,0,0,0,0,0,0,0,0,0}; + + DEB (printk ("\nPCI2242I: AUTO REQUEST SENSE")); + cdb[4] = (UCHAR)(sizeof (SCpnt->sense_buffer)); + if ( !pass ) + { + padapter->reqSense = TRUE; + AtapiCountLo (padapter, cdb[4]); + AtapiCountHi (padapter, 0); + outb_p (0, padapter->regError); + WriteCommand (padapter, IDE_COMMAND_ATAPI_PACKET); + if ( pdev->cmdDrqInt ) + return FALSE; + + if ( AtapiWaitDrq (padapter, 500) ) + return TRUE; + } + AtapiSendCdb (padapter, pdev, cdb); + return FALSE; + } +/**************************************************************** * Name: InlineReadSignature :LOCAL * * Description: Do an inline read RAID sigature. @@ -549,10 +984,9 @@ static UCHAR InlineReadSignature (PADAPTER2220I padapter, POUR_DEVICE pdev, int index) { UCHAR status; - UCHAR spigot = 1 << index; ULONG zl = pdev->lastsectorlba[index]; - SelectSpigot (padapter, spigot | 0x80); // select the spigot without interrupts + SelectSpigot (padapter, pdev->spigots[index] | SEL_IRQ_OFF); // select the spigot without interrupts outb_p (pdev->byte6 | ((UCHAR *)&zl)[3], padapter->regLba24); status = WaitReady (padapter); if ( !status ) @@ -591,6 +1025,10 @@ UCHAR error; padapter->expectingIRQ = 0; +#ifdef DEBUG + printk (" @@@@@@ status: %X @@@@@@@ ", status); + STOP_HERE(); +#endif if ( status & IDE_STATUS_WRITE_FAULT ) { return DID_PARITY << 16; @@ -678,25 +1116,33 @@ ******************************************************************************************************/ static int InitFailover (PADAPTER2220I padapter, POUR_DEVICE pdev) { - UCHAR spigot; + UCHAR spigot; - DEB (printk ("\npci2220i: Initialize failover process - survivor = %d", padapter->survivor)); + DEB (printk ("\npci2220i: Initialize failover process - survivor = %d", pdev->deviceID[padapter->survivor])); pdev->raid = FALSE; //initializes system for non raid mode - pdev->hotRecon = 0; - padapter->reconOn = FALSE; - spigot = (padapter->survivor) ? 2 : 1; + pdev->reconOn = FALSE; + spigot = pdev->spigots[padapter->survivor]; if ( pdev->DiskMirror[padapter->survivor].status & UCBF_REBUILD ) - return (TRUE); + { + DEB (printk ("\n failed, is survivor")); + return (TRUE); + } if ( HardReset (padapter, pdev, spigot) ) + { + DEB (printk ("\n failed, reset")); return TRUE; + } - outb_p (0x3C | spigot, padapter->regFail); // sound alarm and set fail light + Alarm (padapter, pdev->deviceID[padapter->survivor ^ 1]); pdev->DiskMirror[padapter->survivor].status = UCBF_MIRRORED | UCBF_SURVIVOR; //clear present status if ( WriteSignature (padapter, pdev, spigot, padapter->survivor) ) + { + DEB (printk ("\n failed, write signature")); return TRUE; + } padapter->failinprog = TRUE; return FALSE; } @@ -716,13 +1162,23 @@ POUR_DEVICE pdev = padapter->pdev; UCHAR status = IDE_STATUS_BUSY; UCHAR temp, temp1; +#if LINUX_VERSION_CODE < LINUXVERSION(2,1,95) + int flags; +#else /* version >= v2.1.95 */ unsigned long flags; +#endif /* version >= v2.1.95 */ +#if LINUX_VERSION_CODE < LINUXVERSION(2,1,95) + /* Disable interrupts, if they aren't already disabled. */ + save_flags (flags); + cli (); +#else /* version >= v2.1.95 */ /* * Disable interrupts, if they aren't already disabled and acquire * the I/O spinlock. */ spin_lock_irqsave (&io_request_lock, flags); +#endif /* version >= v2.1.95 */ DEB (printk ("\nPCI2220I: Timeout expired ")); if ( padapter->failinprog ) @@ -739,7 +1195,7 @@ { case RECON_PHASE_MARKING: case RECON_PHASE_LAST: - padapter->survivor = (pdev->spigot ^ 3) >> 1; + padapter->survivor = ( pdev->spigot == pdev->spigots[0] ) ? 1 : 0; DEB (printk ("\npci2220i: FAILURE 1")); if ( InitFailover (padapter, pdev) ) OpDone (padapter, DID_ERROR << 16); @@ -750,7 +1206,7 @@ goto timerExpiryDone; case RECON_PHASE_COPY: - padapter->survivor = (pdev->spigot) >> 1; + padapter->survivor = ( pdev->spigot == pdev->spigots[0] ) ? 0 : 1; DEB (printk ("\npci2220i: FAILURE 2")); DEB (printk ("\n spig/stat = %X", inb_p (padapter->regStatSel)); if ( InitFailover (padapter, pdev) ) @@ -758,14 +1214,14 @@ goto timerExpiryDone; case RECON_PHASE_UPDATE: - padapter->survivor = (pdev->spigot) >> 1; + padapter->survivor = ( pdev->spigot == pdev->spigots[0] ) ? 0 : 1; DEB (printk ("\npci2220i: FAILURE 3"))); if ( InitFailover (padapter, pdev) ) OpDone (padapter, DID_ERROR << 16); goto timerExpiryDone; case RECON_PHASE_END: - padapter->survivor = (pdev->spigot) >> 1; + padapter->survivor = ( pdev->spigot == pdev->spigots[0] ) ? 0 : 1; DEB (printk ("\npci2220i: FAILURE 4")); if ( InitFailover (padapter, pdev) ) OpDone (padapter, DID_ERROR << 16); @@ -784,17 +1240,21 @@ if ( padapter->cmd == WRITE_CMD ) { DEB (printk ("in RAID write operation")); - if ( inb_p (padapter->regStatSel) & 1 ) + temp = ( pdev->spigot & (SEL_1 | SEL_2) ) ? SEL_1 : SEL_3; + if ( inb_p (padapter->regStatSel) & temp ) { - SelectSpigot (padapter, 0x81 ); // Masking the interrupt during spigot select + DEB (printk ("\npci2220i: Determined A OK")); + SelectSpigot (padapter, temp | SEL_IRQ_OFF); // Masking the interrupt during spigot select temp = inb_p (padapter->regStatCmd); } else temp = IDE_STATUS_BUSY; - if ( inb (padapter->regStatSel) & 2 ) + temp1 = ( pdev->spigot & (SEL_1 | SEL_2) ) ? SEL_2 : SEL_4; + if ( inb (padapter->regStatSel) & temp1 ) { - SelectSpigot (padapter, 0x82 ); // Masking the interrupt during spigot select + DEB (printk ("\npci2220i: Determined B OK")); + SelectSpigot (padapter, temp1 | SEL_IRQ_OFF); // Masking the interrupt during spigot select temp1 = inb_p (padapter->regStatCmd); } else @@ -802,6 +1262,7 @@ if ( (temp & IDE_STATUS_BUSY) || (temp1 & IDE_STATUS_BUSY) ) { + DEB (printk ("\npci2220i: Status A: %X B: %X", temp & 0xFF, temp1 & 0xFF)); if ( (temp & IDE_STATUS_BUSY) && (temp1 & IDE_STATUS_BUSY) ) { status = temp; @@ -809,11 +1270,10 @@ } else { - if (temp & IDE_STATUS_BUSY) + if ( temp & IDE_STATUS_BUSY ) padapter->survivor = 1; else padapter->survivor = 0; - DEB (printk ("\npci2220i: FAILURE 5")); if ( InitFailover (padapter, pdev) ) { status = inb_p (padapter->regStatCmd); @@ -826,7 +1286,7 @@ else { DEB (printk ("in RAID read operation")); - padapter->survivor = (pdev->spigot ^ 3) >> 1; + padapter->survivor = ( pdev->spigot == pdev->spigots[0] ) ? 0 : 1; DEB (printk ("\npci2220i: FAILURE 6")); if ( InitFailover (padapter, pdev) ) { @@ -847,12 +1307,20 @@ OpDone (padapter, DecodeError (padapter, status)); timerExpiryDone:; +#if LINUX_VERSION_CODE < LINUXVERSION(2,1,95) + /* + * Restore the original flags which will enable interrupts + * if and only if they were enabled on entry. + */ + restore_flags (flags); +#else /* version >= v2.1.95 */ /* * Release the I/O spinlock and restore the original flags * which will enable interrupts if and only if they were * enabled on entry. */ spin_unlock_irqrestore (&io_request_lock, flags); +#endif /* version >= v2.1.95 */ } /**************************************************************** * Name: SetReconstruct :LOCAL @@ -871,7 +1339,6 @@ pdev->DiskMirror[index ^ 1].status = UCBF_MIRRORED | UCBF_REBUILD; pdev->DiskMirror[index ^ 1].reconstructPoint = 0; // start the reconstruct pdev->reconCount = 1990; // mark target drive early - pdev->hotRecon = 1 >> index; return pdev->DiskMirror[index].reconstructPoint; } /**************************************************************** @@ -893,35 +1360,66 @@ USHORT minmode; ULONG zl; UCHAR zc; + USHORT z; +#if LINUX_VERSION_CODE < LINUXVERSION(2,1,95) + int flags; +#else /* version >= v2.1.95 */ unsigned long flags; +#endif /* version >= v2.1.95 */ +#if LINUX_VERSION_CODE < LINUXVERSION(2,1,95) + /* Disable interrupts, if they aren't already disabled. */ + save_flags (flags); + cli (); +#else /* version >= v2.1.95 */ /* * Disable interrupts, if they aren't already disabled and acquire * the I/O spinlock. */ spin_lock_irqsave (&io_request_lock, flags); +#endif /* version >= v2.1.95 */ padapter = (PADAPTER2220I)data; if ( padapter->SCpnt ) goto reconTimerExpiry; - pdev = padapter->device; - pid = (PIDENTIFY_DATA)padapter->kBuffer; padapter->reconTimer.data = 0; + for ( z = padapter->devInReconIndex + 1; z < BIGD_MAXDRIVES; z++ ) + { + if ( padapter->device[z].reconOn ) + break; + } + if ( z < BIGD_MAXDRIVES ) + pdev = &padapter->device[z]; + else + { + for ( z = 0; z < BIGD_MAXDRIVES; z++ ) + { + if ( padapter->device[z].reconOn ) + break; + } + if ( z < BIGD_MAXDRIVES ) + pdev = &padapter->device[z]; + else + { + padapter->reconOn = FALSE; + goto reconTimerExpiry; + } + } + + padapter->devInReconIndex = z; + pid = (PIDENTIFY_DATA)padapter->kBuffer; padapter->pdev = pdev; - if ( padapter->reconIsStarting ) + if ( pdev->reconIsStarting ) { - padapter->reconIsStarting = FALSE; - padapter->reconOn = FALSE; - pdev->hotRecon = FALSE; + pdev->reconIsStarting = FALSE; + pdev->reconOn = FALSE; - if ( (pdev->DiskMirror[0].signature == SIGNATURE) && (pdev->DiskMirror[1].signature == SIGNATURE) && + while ( (pdev->DiskMirror[0].signature == SIGNATURE) && (pdev->DiskMirror[1].signature == SIGNATURE) && (pdev->DiskMirror[0].pairIdentifier == (pdev->DiskMirror[1].pairIdentifier ^ 1)) ) { if ( (pdev->DiskMirror[0].status & UCBF_MATCHED) && (pdev->DiskMirror[1].status & UCBF_MATCHED) ) - { - goto reconTimerExpiry; - } + break;; if ( pdev->DiskMirror[0].status & UCBF_SURVIVOR ) // is first drive survivor? testsize = SetReconstruct (pdev, 0); @@ -932,33 +1430,38 @@ if ( (pdev->DiskMirror[0].status & UCBF_REBUILD) || (pdev->DiskMirror[1].status & UCBF_REBUILD) ) { if ( pdev->DiskMirror[0].status & UCBF_REBUILD ) - { - pdev->hotRecon = 1; pdev->mirrorRecon = 0; - } else - { - pdev->hotRecon = 2; pdev->mirrorRecon = 1; - } + pdev->reconOn = TRUE; } + break; } - if ( !pdev->hotRecon ) + if ( !pdev->reconOn ) goto reconTimerExpiry; - zc = ((inb_p (padapter->regStatSel) >> 3) | inb_p (padapter->regStatSel)) & 0x83; // mute the alarm - outb_p (zc | pdev->hotRecon | 0x40, padapter->regFail); + if ( padapter->bigD ) + { + padapter->failRegister = 0; + outb_p (~padapter->failRegister, padapter->regFail); + } + else + { + zc = ((inb_p (padapter->regStatSel) >> 3) | inb_p (padapter->regStatSel)) & 0x83; // mute the alarm + outb_p (0xFF, padapter->regFail); + } while ( 1 ) { - if ( HardReset (padapter, pdev, pdev->hotRecon) ) + DEB (printk ("\npci2220i: hard reset issue")); + if ( HardReset (padapter, pdev, pdev->spigots[pdev->mirrorRecon]) ) { DEB (printk ("\npci2220i: sub 1")); break; } - pdev->lastsectorlba[pdev->mirrorRecon] = InlineIdentify (padapter, pdev->hotRecon, 0); + pdev->lastsectorlba[pdev->mirrorRecon] = InlineIdentify (padapter, pdev->spigots[pdev->mirrorRecon], pdev->deviceID[pdev->mirrorRecon] & 1); if ( pdev->lastsectorlba[pdev->mirrorRecon] < testsize ) { @@ -1014,12 +1517,11 @@ break; } - if ( !padapter->reconOn ) + if ( !pdev->reconOn ) { - pdev->hotRecon = FALSE; padapter->survivor = pdev->mirrorRecon ^ 1; padapter->reconPhase = RECON_PHASE_FAILOVER; - DEB (printk ("\npci2220i: FAILURE 7")); + DEB (printk ("\npci2220i: FAILURE 7")); InitFailover (padapter, pdev); goto reconTimerExpiry; } @@ -1038,11 +1540,11 @@ if ( pdev->reconCount++ > 2000 ) { pdev->reconCount = 0; - if ( WriteSignature (padapter, pdev, pdev->hotRecon, pdev->mirrorRecon) ) + if ( WriteSignature (padapter, pdev, pdev->spigots[pdev->mirrorRecon], pdev->mirrorRecon) ) { padapter->survivor = pdev->mirrorRecon ^ 1; padapter->reconPhase = RECON_PHASE_FAILOVER; - DEB (printk ("\npci2220i: FAILURE 8")); + DEB (printk ("\npci2220i: FAILURE 8")); InitFailover (padapter, pdev); goto reconTimerExpiry; } @@ -1057,30 +1559,30 @@ if ( padapter->reconSize ) { - SelectSpigot (padapter, 3); // select the spigots - outb_p (pdev->byte6 | ((UCHAR *)(&zl))[3], padapter->regLba24);// select the drive + SelectSpigot (padapter, pdev->spigots[0] | pdev->spigots[1]); // select the spigots + outb_p (pdev->byte6 | ((UCHAR *)(&zl))[3], padapter->regLba24); // select the drive SelectSpigot (padapter, pdev->spigot); if ( WaitReady (padapter) ) goto reconTimerExpiry; - SelectSpigot (padapter, pdev->hotRecon); + SelectSpigot (padapter, pdev->spigots[pdev->mirrorRecon]); if ( WaitReady (padapter) ) { padapter->survivor = pdev->mirrorRecon ^ 1; padapter->reconPhase = RECON_PHASE_FAILOVER; - DEB (printk ("\npci2220i: FAILURE 9")); + DEB (printk ("\npci2220i: FAILURE 9")); InitFailover (padapter, pdev); goto reconTimerExpiry; } - SelectSpigot (padapter, 3); + SelectSpigot (padapter, pdev->spigots[0] | pdev->spigots[1]); outb_p (padapter->reconSize & 0xFF, padapter->regSectCount); outb_p (((UCHAR *)(&zl))[0], padapter->regLba0); outb_p (((UCHAR *)(&zl))[1], padapter->regLba8); outb_p (((UCHAR *)(&zl))[2], padapter->regLba16); padapter->expectingIRQ = TRUE; padapter->reconPhase = RECON_PHASE_READY; - SelectSpigot (padapter, pdev->hotRecon); + SelectSpigot (padapter, pdev->spigots[pdev->mirrorRecon]); WriteCommand (padapter, WRITE_CMD); StartTimer (padapter); SelectSpigot (padapter, pdev->spigot); @@ -1095,12 +1597,20 @@ padapter->reconPhase = RECON_PHASE_LAST; reconTimerExpiry:; +#if LINUX_VERSION_CODE < LINUXVERSION(2,1,95) + /* + * Restore the original flags which will enable interrupts + * if and only if they were enabled on entry. + */ + restore_flags (flags); +#else /* version >= v2.1.95 */ /* * Release the I/O spinlock and restore the original flags * which will enable interrupts if and only if they were * enabled on entry. */ spin_unlock_irqrestore (&io_request_lock, flags); +#endif /* version >= v2.1.95 */ } /**************************************************************** * Name: Irq_Handler :LOCAL @@ -1122,15 +1632,28 @@ Scsi_Cmnd *SCpnt; UCHAR status; UCHAR status1; + ATAPI_STATUS statusa; + ATAPI_REASON reasona; + ATAPI_ERROR errora; int z; ULONG zl; +#if LINUX_VERSION_CODE < LINUXVERSION(2,1,95) + int flags; +#else /* version >= v2.1.95 */ unsigned long flags; +#endif /* version >= v2.1.95 */ +#if LINUX_VERSION_CODE < LINUXVERSION(2,1,95) + /* Disable interrupts, if they aren't already disabled. */ + save_flags (flags); + cli (); +#else /* version >= v2.1.95 */ /* * Disable interrupts, if they aren't already disabled and acquire * the I/O spinlock. */ spin_lock_irqsave (&io_request_lock, flags); +#endif /* version >= v2.1.95 */ // DEB (printk ("\npci2220i recieved interrupt\n")); @@ -1155,7 +1678,70 @@ padapter = HOSTDATA(shost); pdev = padapter->pdev; SCpnt = padapter->SCpnt; + outb_p (0x08, padapter->regDmaCmdStat); // cancel interrupt from DMA engine + if ( padapter->atapi && SCpnt ) + { + *(char *)&statusa = inb_p (padapter->regStatCmd); // read the device status + *(char *)&reasona = inb_p (padapter->regSectCount); // read the device interrupt reason + + if ( !statusa.bsy ) + { + if ( statusa.drq ) // test for transfer phase + { + if ( !reasona.cod ) // test for data phase + { + z = (ULONG)inb_p (padapter->regLba8) | (ULONG)(inb_p (padapter->regLba16) << 8); + if ( padapter->reqSense ) + insw (padapter->regData, SCpnt->sense_buffer, z / 2); + else + AtapiBusMaster (padapter, reasona.io, z); + goto irq_return; + } + if ( reasona.cod && !reasona.io ) // test for command packet phase + { + if ( padapter->reqSense ) + AtapiRequestSense (padapter, pdev, SCpnt, TRUE); + else + AtapiSendCdb (padapter, pdev, padapter->atapiCdb); + goto irq_return; + } + } + else + { + if ( reasona.io && statusa.drdy ) // test for status phase + { + Atapi2Scsi (padapter, SCpnt); + if ( statusa.check ) + { + *(UCHAR *)&errora = inb_p (padapter->regError); // read the device error + if ( errora.senseKey ) + { + if ( padapter->reqSense || AtapiRequestSense (padapter, pdev, SCpnt, FALSE) ) + OpDone (padapter, DID_ERROR << 16); + } + else + { + if ( errora.ili || errora.abort ) + OpDone (padapter, DID_ERROR << 16); + else + OpDone (padapter, DID_OK << 16); + } + } + else + if ( padapter->reqSense ) + { + DEB (printk ("PCI2242I: Sense codes - %X %X %X ", ((UCHAR *)SCpnt->sense_buffer)[0], ((UCHAR *)SCpnt->sense_buffer)[12], ((UCHAR *)SCpnt->sense_buffer)[13])); + OpDone (padapter, (DRIVER_SENSE << 24) | (DID_OK << 16) | 2); + } + else + OpDone (padapter, DID_OK << 16); + } + } + } + goto irq_return; + } + if ( !padapter->expectingIRQ || !(SCpnt || padapter->reconPhase) ) { DEB(printk ("\npci2220i Unsolicited interrupt\n")); @@ -1163,7 +1749,6 @@ goto irq_return; } padapter->expectingIRQ = 0; - outb_p (0x08, padapter->regDmaCmdStat); // cancel interrupt from DMA engine if ( padapter->failinprog ) { @@ -1178,7 +1763,7 @@ else { DEB (printk ("\npci2220i: restarting failed opertation.")); - pdev->spigot = (padapter->survivor) ? 2 : 1; + pdev->spigot = (padapter->survivor) ? pdev->spigots[1] : pdev->spigots[0]; del_timer (&padapter->timer); if ( padapter->reconPhase ) OpDone (padapter, DID_OK << 16); @@ -1200,15 +1785,15 @@ { if ( status & (IDE_STATUS_ERROR | IDE_STATUS_WRITE_FAULT) ) { - padapter->survivor = (pdev->spigot ^ 3) >> 1; + padapter->survivor = ( pdev->spigot == pdev->spigots[0] ) ? 1 : 0; DEB (printk ("\npci2220i: FAILURE 10")); if ( InitFailover (padapter, pdev) ) OpDone (padapter, DecodeError (padapter, status)); goto irq_return; } - if ( WriteSignature (padapter, pdev, pdev->hotRecon, pdev->mirrorRecon) ) + if ( WriteSignature (padapter, pdev, pdev->spigots[pdev->mirrorRecon], pdev->mirrorRecon) ) { - padapter->survivor = (pdev->spigot) >> 1; + padapter->survivor = ( pdev->spigot == pdev->spigots[0] ) ? 0 : 1; DEB (printk ("\npci2220i: FAILURE 11")); if ( InitFailover (padapter, pdev) ) OpDone (padapter, DecodeError (padapter, status)); @@ -1228,17 +1813,17 @@ OpDone (padapter, DecodeError (padapter, status)); goto irq_return; } - SelectSpigot (padapter, pdev->hotRecon); + SelectSpigot (padapter, pdev->spigots[pdev->mirrorRecon]); if ( WaitDrq (padapter) ) { del_timer (&padapter->timer); - padapter->survivor = (pdev->spigot) >> 1; - DEB (printk ("\npci2220i: FAILURE 12")); + padapter->survivor = ( pdev->spigot == pdev->spigots[0] ) ? 0 : 1; + DEB (printk ("\npci2220i: FAILURE 12")); if ( InitFailover (padapter, pdev) ) OpDone (padapter, DecodeError (padapter, status)); goto irq_return; } - SelectSpigot (padapter, pdev->spigot | 0x40); + SelectSpigot (padapter, pdev->spigot | SEL_COPY | padapter->bigD); padapter->reconPhase = RECON_PHASE_COPY; padapter->expectingIRQ = TRUE; if ( padapter->timingPIO ) @@ -1247,11 +1832,22 @@ } else { - outl (padapter->timingAddress, padapter->regDmaAddrLoc); + if ( (padapter->timingMode > 3) ) + { + if ( padapter->bigD ) + outl (BIGD_DATA_MODE3, padapter->regDmaAddrLoc); + else + outl (DALE_DATA_MODE3, padapter->regDmaAddrLoc); + } + else + outl (padapter->timingAddress, padapter->regDmaAddrLoc); outl (virt_to_bus (padapter->kBuffer), padapter->regDmaAddrPci); outl (padapter->reconSize * BYTES_PER_SECTOR, padapter->regDmaCount); outb_p (8, padapter->regDmaDesc); // read operation - outb_p (1, padapter->regDmaMode); // no interrupt + if ( padapter->bigD ) + outb_p (8, padapter->regDmaMode); // no interrupt + else + outb_p (1, padapter->regDmaMode); // no interrupt outb_p (0x03, padapter->regDmaCmdStat); // kick the DMA engine in gear } goto irq_return; @@ -1260,13 +1856,14 @@ pdev->DiskMirror[pdev->mirrorRecon].reconstructPoint += padapter->reconSize; case RECON_PHASE_UPDATE: - SelectSpigot (padapter, pdev->hotRecon | 0x80); + SelectSpigot (padapter, pdev->spigots[pdev->mirrorRecon] | SEL_IRQ_OFF); status = inb_p (padapter->regStatCmd); // read the device status del_timer (&padapter->timer); if ( status & (IDE_STATUS_ERROR | IDE_STATUS_WRITE_FAULT) ) { - padapter->survivor = (pdev->spigot) >> 1; + padapter->survivor = ( pdev->spigot == pdev->spigots[0] ) ? 0 : 1; DEB (printk ("\npci2220i: FAILURE 13")); + DEB (printk ("\n status register = %X error = %X", status, inb_p (padapter->regError))); if ( InitFailover (padapter, pdev) ) OpDone (padapter, DecodeError (padapter, status)); goto irq_return; @@ -1279,14 +1876,29 @@ del_timer (&padapter->timer); if ( status & (IDE_STATUS_ERROR | IDE_STATUS_WRITE_FAULT) ) { - padapter->survivor = (pdev->spigot) >> 1; - DEB (printk ("\npci2220i: FAILURE 14")); + padapter->survivor = ( pdev->spigot == pdev->spigots[0] ) ? 0 : 1; + DEB (printk ("\npci2220i: FAILURE 14")); if ( InitFailover (padapter, pdev) ) OpDone (padapter, DecodeError (padapter, status)); goto irq_return; } - padapter->reconOn = FALSE; - pdev->hotRecon = 0; + pdev->reconOn = 0; + if ( padapter->bigD ) + { + for ( z = 0; z < padapter->numberOfDrives; z++ ) + { + if ( padapter->device[z].DiskMirror[0].status & UCBF_SURVIVOR ) + { + Alarm (padapter, padapter->device[z].deviceID[0] ^ 2); + MuteAlarm (padapter); + } + if ( padapter->device[z].DiskMirror[1].status & UCBF_SURVIVOR ) + { + Alarm (padapter, padapter->device[z].deviceID[1] ^ 2); + MuteAlarm (padapter); + } + } + } OpDone (padapter, DID_OK << 16); goto irq_return; @@ -1305,9 +1917,9 @@ { if ( pdev->raid ) { - padapter->survivor = (pdev->spigot ^ 3) >> 1; + padapter->survivor = ( pdev->spigot == pdev->spigots[0] ) ? 1 : 0; del_timer (&padapter->timer); - DEB (printk ("\npci2220i: FAILURE 15")); + DEB (printk ("\npci2220i: FAILURE 15")); if ( !InitFailover (padapter, pdev) ) goto irq_return; } @@ -1315,10 +1927,9 @@ } if ( padapter->timingPIO ) { - zl = (padapter->sectorCount > MAX_BUS_MASTER_BLOCKS) ? MAX_BUS_MASTER_BLOCKS : padapter->sectorCount; - insw (padapter->regData, padapter->buffer, zl * (BYTES_PER_SECTOR / 2)); - padapter->sectorCount -= zl; - padapter->buffer += zl * BYTES_PER_SECTOR; + insw (padapter->regData, padapter->kBuffer, padapter->readCount / 2); + padapter->sectorCount -= padapter->readCount / BYTES_PER_SECTOR; + WalkScatGath (padapter, TRUE, padapter->readCount); if ( !padapter->sectorCount ) { status = 0; @@ -1326,32 +1937,40 @@ } } else + { + if ( padapter->readCount ) + WalkScatGath (padapter, TRUE, padapter->readCount); BusMaster (padapter, 1, 1); + } padapter->expectingIRQ = TRUE; goto irq_return; } + if ( padapter->readCount && !padapter->timingPIO ) + WalkScatGath (padapter, TRUE, padapter->readCount); status = 0; break; case WRITE_CMD: - SelectSpigot (padapter, pdev->spigot | 0x80); - status = inb_p (padapter->regStatCmd); // read the device status if ( pdev->raid ) { - SelectSpigot (padapter, (pdev->spigot ^ 3) | 0x80); - status1 = inb_p (padapter->regStatCmd); // read the device status + SelectSpigot (padapter, pdev->spigots[0] | SEL_IRQ_OFF); + status = inb_p (padapter->regStatCmd); // read the device status + SelectSpigot (padapter, pdev->spigots[1] | SEL_IRQ_OFF); + status1 = inb_p (padapter->regStatCmd); // read the device status } else + SelectSpigot (padapter, pdev->spigot | SEL_IRQ_OFF); + status = inb_p (padapter->regStatCmd); // read the device status status1 = 0; if ( status & (IDE_STATUS_ERROR | IDE_STATUS_WRITE_FAULT) ) { if ( pdev->raid && !(status1 & (IDE_STATUS_ERROR | IDE_STATUS_WRITE_FAULT)) ) { - padapter->survivor = (pdev->spigot ^ 3) >> 1; + padapter->survivor = 1; del_timer (&padapter->timer); - SelectSpigot (padapter, pdev->spigot | 0x80); - DEB (printk ("\npci2220i: FAILURE 16 status = %X error = %X", status, inb_p (padapter->regError))); + SelectSpigot (padapter, pdev->spigot | SEL_IRQ_OFF); + DEB (printk ("\npci2220i: FAILURE 16 status = %X error = %X", status, inb_p (padapter->regError))); if ( !InitFailover (padapter, pdev) ) goto irq_return; } @@ -1361,9 +1980,9 @@ { if ( status1 & (IDE_STATUS_ERROR | IDE_STATUS_WRITE_FAULT) ) { - padapter->survivor = pdev->spigot >> 1; + padapter->survivor = 0; del_timer (&padapter->timer); - DEB (printk ("\npci2220i: FAILURE 17 status = %X error = %X", status1, inb_p (padapter->regError))); + DEB (printk ("\npci2220i: FAILURE 17 status = %X error = %X", status1, inb_p (padapter->regError))); if ( !InitFailover (padapter, pdev) ) goto irq_return; status = status1; @@ -1371,15 +1990,15 @@ } if ( padapter->sectorCount ) { - status = WriteDataBoth (padapter); + status = WriteDataBoth (padapter, pdev); if ( status ) { - padapter->survivor = (status ^ 3) >> 1; + padapter->survivor = status >> 1; del_timer (&padapter->timer); - DEB (printk ("\npci2220i: FAILURE 18")); + DEB (printk ("\npci2220i: FAILURE 18")); if ( !InitFailover (padapter, pdev) ) goto irq_return; - SelectSpigot (padapter, status | 0x80); + SelectSpigot (padapter, pdev->spigots[status] | SEL_IRQ_OFF); status = inb_p (padapter->regStatCmd); // read the device status break; } @@ -1391,7 +2010,7 @@ } if ( padapter->sectorCount ) { - SelectSpigot (padapter, pdev->spigot); + SelectSpigot (padapter, pdev->spigot | padapter->bigD); status = WriteData (padapter); if ( status ) break; @@ -1458,12 +2077,20 @@ OpDone (padapter, zl); irq_return:; +#if LINUX_VERSION_CODE < LINUXVERSION(2,1,95) + /* + * Restore the original flags which will enable interrupts + * if and only if they were enabled on entry. + */ + restore_flags (flags); +#else /* version >= v2.1.95 */ /* * Release the I/O spinlock and restore the original flags * which will enable interrupts if and only if they were * enabled on entry. */ spin_unlock_irqrestore (&io_request_lock, flags); +#endif /* version >= v2.1.95 */ } /**************************************************************** * Name: Pci2220i_QueueCommand @@ -1486,14 +2113,88 @@ PDEVICE_RAID1 pdr; SCpnt->scsi_done = done; - padapter->buffer = SCpnt->request_buffer; padapter->SCpnt = SCpnt; // Save this command data + padapter->readCount = 0; + + if ( SCpnt->use_sg ) + { + padapter->currentSgBuffer = ((struct scatterlist *)SCpnt->request_buffer)[0].address; + padapter->currentSgCount = ((struct scatterlist *)SCpnt->request_buffer)[0].length; + } + else + { + padapter->currentSgBuffer = SCpnt->request_buffer; + padapter->currentSgCount = SCpnt->request_bufflen; + } + padapter->nextSg = 1; + if ( !done ) { printk("pci2220i_queuecommand: %02X: done can't be NULL\n", *cdb); return 0; } + if ( padapter->atapi ) + { + UCHAR zlo, zhi; + + DEB (printk ("\nPCI2242I: ID %d, LUN %d opcode %X ", SCpnt->target, SCpnt->lun, *cdb)); + padapter->pdev = pdev; + if ( !pdev->byte6 || SCpnt->lun ) + { + OpDone (padapter, DID_BAD_TARGET << 16); + return 0; + } + + padapter->atapiSpecial = FALSE; + padapter->reqSense = FALSE; + memset (padapter->atapiCdb, 0, 16); + SelectSpigot (padapter, pdev->spigot); // select the spigot + AtapiDevice (padapter, pdev->byte6); // select the drive + if ( AtapiWaitReady (padapter, 100) ) + { + OpDone (padapter, DID_NO_CONNECT << 16); + return 0; + } + + switch ( cdb[0] ) + { + case SCSIOP_MODE_SENSE: + case SCSIOP_MODE_SELECT: + Scsi2Atapi (padapter, SCpnt); + z = SCpnt->request_bufflen + 4; + break; + case SCSIOP_READ6: + case SCSIOP_WRITE6: + Scsi2Atapi (padapter, SCpnt); + z = SCpnt->request_bufflen; + break; + default: + memcpy (padapter->atapiCdb, cdb, SCpnt->cmd_len); + z = SCpnt->request_bufflen; + break; + } + if ( z > ATAPI_TRANSFER ) + z = ATAPI_TRANSFER; + zlo = (UCHAR)(z & 0xFF); + zhi = (UCHAR)(z >> 8); + + AtapiCountLo (padapter, zlo); + AtapiCountHi (padapter, zhi); + outb_p (0, padapter->regError); + WriteCommand (padapter, IDE_COMMAND_ATAPI_PACKET); + if ( pdev->cmdDrqInt ) + return 0; + + if ( AtapiWaitDrq (padapter, 500) ) + { + OpDone (padapter, DID_ERROR << 16); + return 0; + } + AtapiSendCdb (padapter, pdev, padapter->atapiCdb); + return 0; + } + if ( padapter->reconPhase ) return 0; if ( padapter->reconTimer.data ) @@ -1502,12 +2203,11 @@ padapter->reconTimer.data = 0; } - if ( !pdev->device || SCpnt->lun ) + if ( (SCpnt->target >= padapter->numberOfDrives) || SCpnt->lun ) { OpDone (padapter, DID_BAD_TARGET << 16); return 0; } - switch ( *cdb ) { @@ -1518,7 +2218,15 @@ switch ( cdb[3] ) { case MY_SCSI_REBUILD: - padapter->reconOn = padapter->reconIsStarting = TRUE; + for ( z = 0; z < padapter->numberOfDrives; z++ ) + { + pdev = &padapter->device[z]; + if ( ((pdev->DiskMirror[0].status & UCBF_SURVIVOR) && (pdev->DiskMirror[1].status & UCBF_MIRRORED)) || + ((pdev->DiskMirror[1].status & UCBF_SURVIVOR) && (pdev->DiskMirror[0].status & UCBF_MIRRORED)) ) + { + padapter->reconOn = pdev->reconOn = pdev->reconIsStarting = TRUE; + } + } OpDone (padapter, DID_OK << 16); break; case MY_SCSI_ALARMMUTE: @@ -1535,7 +2243,10 @@ if ( padapter->raidData[z] ) { memcpy (&pdr->DiskRaid1, padapter->raidData[z], sizeof (DISK_MIRROR)); - pdr->TotalSectors = padapter->device[0].blocks; + if ( padapter->raidData[z]->reconstructPoint > padapter->raidData[z ^ 2]->reconstructPoint ) + pdr->TotalSectors = padapter->raidData[z]->reconstructPoint; + else + pdr->TotalSectors = padapter->raidData[z ^ 2]->reconstructPoint; } else memset (pdr, 0, sizeof (DEVICE_RAID1)); @@ -1598,6 +2309,7 @@ while ( padapter->demoFail ) { + pdev = padapter->pdev = &padapter->device[0]; padapter->demoFail = FALSE; if ( !pdev->raid || (pdev->DiskMirror[0].status & UCBF_SURVIVOR) || @@ -1610,7 +2322,7 @@ else padapter->survivor = 0; DEB (printk ("\npci2220i: FAILURE 19")); - if ( InitFailover (padapter, pdev ) ) + if ( InitFailover (padapter, pdev) ) break; return 0; } @@ -1618,14 +2330,14 @@ StartTimer (padapter); if ( pdev->raid && (padapter->cmd == WRITE_CMD) ) { - rc = IdeCmdBoth (padapter); + rc = IdeCmdBoth (padapter, pdev); if ( !rc ) - rc = WriteDataBoth (padapter); + rc = WriteDataBoth (padapter, pdev); if ( rc ) { del_timer (&padapter->timer); padapter->expectingIRQ = 0; - padapter->survivor = (rc ^ 3) >> 1; + padapter->survivor = rc >> 1; DEB (printk ("\npci2220i: FAILURE 20")); if ( InitFailover (padapter, pdev) ) { @@ -1656,7 +2368,6 @@ } return 0; } - static void internal_done(Scsi_Cmnd *SCpnt) { SCpnt->SCp.Status++; @@ -1692,25 +2403,192 @@ * Returns: Nothing. * ****************************************************************/ -VOID ReadFlash (PADAPTER2220I padapter, VOID *pdata, ULONG base, ULONG length) +static VOID ReadFlash (PADAPTER2220I padapter, VOID *pdata, ULONG base, ULONG length) { ULONG oldremap; UCHAR olddesc; ULONG z; UCHAR *pd = (UCHAR *)pdata; - oldremap = inl (padapter->regRemap); // save values to restore later + oldremap = inl (padapter->regRemap); // save values to restore later olddesc = inb_p (padapter->regDesc); - outl (base | 1, padapter->regRemap); // remap to Flash space as specified - outb_p (0x40, padapter->regDesc); // describe remap region as 8 bit - for ( z = 0; z < length; z++) // get "length" data count - *pd++ = inb_p (padapter->regBase + z); // read in the data + outl (base | 1, padapter->regRemap); // remap to Flash space as specified + outb_p (0x40, padapter->regDesc); // describe remap region as 8 bit + for ( z = 0; z < length; z++) // get "length" data count + *pd++ = inb_p (padapter->regBase + z); // read in the data - outl (oldremap, padapter->regRemap); // restore remap register values + outl (oldremap, padapter->regRemap); // restore remap register values outb_p (olddesc, padapter->regDesc); } /**************************************************************** + * Name: GetRegs + * + * Description: Initialize the regester information. + * + * Parameters: pshost - Pointer to SCSI host data structure. + * bigd - PCI-2240I identifier + * pcidev - Pointer to device data structure. + * pci_bus - PCI bus number. + * pci_device_fn - PCI device and function number. + * + * Returns: TRUE if failure to install. + * + ****************************************************************/ +#if LINUX_VERSION_CODE > LINUXVERSION(2,1,92) +static USHORT GetRegs (struct Scsi_Host *pshost, BOOL bigd, struct pci_dev *pcidev) +#else +static USHORT GetRegs (struct Scsi_Host *pshost, BOOL bigd, UCHAR pci_bus, UCHAR pci_device_fn) +#endif + { + PADAPTER2220I padapter; + int setirq; + int z; + USHORT zr, zl; + + padapter = HOSTDATA(pshost); + memset (padapter, 0, sizeof (ADAPTER2220I)); + memset (&DaleSetup, 0, sizeof (DaleSetup)); + memset (DiskMirror, 0, sizeof (DiskMirror)); + +#if LINUX_VERSION_CODE > LINUXVERSION(2,1,92) + zr = pcidev->base_address[1] & 0xFFFE; + zl = pcidev->base_address[2] & 0xFFFE; +#else + pcibios_read_config_word (pci_bus, pci_device_fn, PCI_BASE_ADDRESS_1, &zr); + zr &= 0xFFFE; + pcibios_read_config_word (pci_bus, pci_device_fn, PCI_BASE_ADDRESS_2, &zl); + zl &= 0xFFFE; +#endif + padapter->basePort = zr; + padapter->regRemap = zr + RTR_LOCAL_REMAP; // 32 bit local space remap + padapter->regDesc = zr + RTR_REGIONS; // 32 bit local region descriptor + padapter->regRange = zr + RTR_LOCAL_RANGE; // 32 bit local range + padapter->regIrqControl = zr + RTR_INT_CONTROL_STATUS; // 16 bit interupt control and status + padapter->regScratchPad = zr + RTR_MAILBOX; // 16 byte scratchpad I/O base address + + padapter->regBase = zl; + padapter->regData = zl + REG_DATA; // data register I/O address + padapter->regError = zl + REG_ERROR; // error register I/O address + padapter->regSectCount = zl + REG_SECTOR_COUNT; // sector count register I/O address + padapter->regLba0 = zl + REG_LBA_0; // least significant byte of LBA + padapter->regLba8 = zl + REG_LBA_8; // next least significant byte of LBA + padapter->regLba16 = zl + REG_LBA_16; // next most significan byte of LBA + padapter->regLba24 = zl + REG_LBA_24; // head and most 4 significant bits of LBA + padapter->regStatCmd = zl + REG_STAT_CMD; // status on read and command on write register + padapter->regStatSel = zl + REG_STAT_SEL; // board status on read and spigot select on write register + padapter->regFail = zl + REG_FAIL; + padapter->regAltStat = zl + REG_ALT_STAT; + + if ( bigd ) + { + padapter->regDmaDesc = zr + RTR_DMA0_DESC_PTR; // address of the DMA discriptor register for direction of transfer + padapter->regDmaCmdStat = zr + RTR_DMA_COMMAND_STATUS; // Byte #0 of DMA command status register + padapter->regDmaAddrPci = zr + RTR_DMA0_PCI_ADDR; // 32 bit register for PCI address of DMA + padapter->regDmaAddrLoc = zr + RTR_DMA0_LOCAL_ADDR; // 32 bit register for local bus address of DMA + padapter->regDmaCount = zr + RTR_DMA0_COUNT; // 32 bit register for DMA transfer count + padapter->regDmaMode = zr + RTR_DMA0_MODE + 1; // 32 bit register for DMA mode control + padapter->bigD = SEL_NEW_SPEED_1; // set spigot speed control bit + } + else + { + padapter->regDmaDesc = zl + RTL_DMA1_DESC_PTR; // address of the DMA discriptor register for direction of transfer + padapter->regDmaCmdStat = zl + RTL_DMA_COMMAND_STATUS + 1; // Byte #1 of DMA command status register + padapter->regDmaAddrPci = zl + RTL_DMA1_PCI_ADDR; // 32 bit register for PCI address of DMA + padapter->regDmaAddrLoc = zl + RTL_DMA1_LOCAL_ADDR; // 32 bit register for local bus address of DMA + padapter->regDmaCount = zl + RTL_DMA1_COUNT; // 32 bit register for DMA transfer count + padapter->regDmaMode = zl + RTL_DMA1_MODE + 1; // 32 bit register for DMA mode control + } + + padapter->numberOfDrives = inb_p (padapter->regScratchPad + BIGD_NUM_DRIVES); + if ( !bigd && !padapter->numberOfDrives ) // if no devices on this board + return TRUE; + +#if LINUX_VERSION_CODE > LINUXVERSION(2,1,92) + pshost->irq = pcidev->irq; +#else + pcibios_read_config_byte (pci_bus, pci_device_fn, PCI_INTERRUPT_LINE, &pshost->irq); +#endif + setirq = 1; + for ( z = 0; z < Installed; z++ ) // scan for shared interrupts + { + if ( PsiHost[z]->irq == pshost->irq ) // if shared then, don't posses + setirq = 0; + } + if ( setirq ) // if not shared, posses + { + if ( request_irq (pshost->irq, Irq_Handler, SA_SHIRQ, "pci2220i", padapter) < 0 ) + { + if ( request_irq (pshost->irq, Irq_Handler, SA_INTERRUPT | SA_SHIRQ, "pci2220i", padapter) < 0 ) + { + printk ("Unable to allocate IRQ for PCI-2220I controller.\n"); + return TRUE; + } + } + padapter->irqOwned = pshost->irq; // set IRQ as owned + } + if ( padapter->numberOfDrives ) + padapter->kBuffer = kmalloc (SECTORSXFER * BYTES_PER_SECTOR, GFP_DMA | GFP_ATOMIC); + else + padapter->kBuffer = kmalloc (ATAPI_TRANSFER, GFP_DMA | GFP_ATOMIC); + if ( !padapter->kBuffer ) + { + printk ("Unable to allocate DMA buffer for PCI-2220I controller.\n"); +#if LINUX_VERSION_CODE < LINUXVERSION(1,3,70) + free_irq (pshost->irq); +#else /* version >= v1.3.70 */ + free_irq (pshost->irq, padapter); +#endif /* version >= v1.3.70 */ + return TRUE; + } + + PsiHost[Installed] = pshost; // save SCSI_HOST pointer + + pshost->io_port = padapter->basePort; + pshost->n_io_port = 0xFF; + pshost->unique_id = padapter->regBase; + + outb_p (0x01, padapter->regRange); // fix our range register because other drivers want to tromp on it + + padapter->timingMode = inb_p (padapter->regScratchPad + DALE_TIMING_MODE); + if ( padapter->timingMode >= 2 ) + { + if ( bigd ) + padapter->timingAddress = ModeArray2[padapter->timingMode - 2]; + else + padapter->timingAddress = ModeArray[padapter->timingMode - 2]; + } + else + padapter->timingPIO = TRUE; + + ReadFlash (padapter, &DaleSetup, DALE_FLASH_SETUP, sizeof (SETUP)); + ReadFlash (padapter, &DiskMirror, DALE_FLASH_RAID, sizeof (DiskMirror)); + + return FALSE; + } +/**************************************************************** + * Name: SetupFinish + * + * Description: Complete the driver initialization process for a card + * + * Parameters: padapter - Pointer to SCSI host data structure. + * str - Pointer to board type string. + * + * Returns: Nothing. + * + ****************************************************************/ +VOID SetupFinish (PADAPTER2220I padapter, char *str, int irq) + { + init_timer (&padapter->timer); + padapter->timer.function = TimerExpiry; + padapter->timer.data = (unsigned long)padapter; + init_timer (&padapter->reconTimer); + padapter->reconTimer.function = ReconTimerExpiry; + padapter->reconTimer.data = (unsigned long)padapter; + printk("\nPCI-%sI EIDE CONTROLLER: at I/O = %X/%X IRQ = %d\n", str, padapter->basePort, padapter->regBase, irq); + printk("Version %s, Compiled %s %s\n\n", PCI2220I_VERSION, __DATE__, __TIME__); + } +/**************************************************************** * Name: Pci2220i_Detect * * Description: Detect and initialize our boards. @@ -1722,204 +2600,284 @@ ****************************************************************/ int Pci2220i_Detect (Scsi_Host_Template *tpnt) { - int found = 0; - int installed = 0; struct Scsi_Host *pshost; PADAPTER2220I padapter; + POUR_DEVICE pdev; int unit; int z; - USHORT zs; - USHORT raidon = FALSE; - int setirq; - UCHAR spigot1 = FALSE; - UCHAR spigot2 = FALSE; - struct pci_dev *pdev = NULL; + USHORT raidon; + UCHAR spigot1, spigot2; + UCHAR device; +#if LINUX_VERSION_CODE > LINUXVERSION(2,1,92) + struct pci_dev *pcidev = NULL; +#else + int found; + UCHAR pci_bus, pci_device_fn; +#endif +#if LINUX_VERSION_CODE > LINUXVERSION(2,1,92) if ( !pci_present () ) +#else + if ( !pcibios_present () ) +#endif { printk ("pci2220i: PCI BIOS not present\n"); return 0; } - while ( (pdev = pci_find_device (VENDOR_PSI, DEVICE_DALE_1, pdev)) != NULL ) +#if LINUX_VERSION_CODE > LINUXVERSION(2,1,92) + while ( (pcidev = pci_find_device (VENDOR_PSI, DEVICE_DALE_1, pcidev)) != NULL ) +#else + found = 0; + while ( !pcibios_find_device (VENDOR_PSI, DEVICE_DALE_1, found++, &pci_bus, &pci_device_fn) ) +#endif { pshost = scsi_register (tpnt, sizeof(ADAPTER2220I)); padapter = HOSTDATA(pshost); - memset (padapter, 0, sizeof (ADAPTER2220I)); - zs = pdev->resource[1].start; - padapter->basePort = zs; - padapter->regRemap = zs + RTR_LOCAL_REMAP; // 32 bit local space remap - padapter->regDesc = zs + RTR_REGIONS; // 32 bit local region descriptor - padapter->regRange = zs + RTR_LOCAL_RANGE; // 32 bit local range - padapter->regIrqControl = zs + RTR_INT_CONTROL_STATUS; // 16 bit interupt control and status - padapter->regScratchPad = zs + RTR_MAILBOX; // 16 byte scratchpad I/O base address - - zs = pdev->resource[2].start; - padapter->regBase = zs; - padapter->regData = zs + REG_DATA; // data register I/O address - padapter->regError = zs + REG_ERROR; // error register I/O address - padapter->regSectCount = zs + REG_SECTOR_COUNT; // sector count register I/O address - padapter->regLba0 = zs + REG_LBA_0; // least significant byte of LBA - padapter->regLba8 = zs + REG_LBA_8; // next least significant byte of LBA - padapter->regLba16 = zs + REG_LBA_16; // next most significan byte of LBA - padapter->regLba24 = zs + REG_LBA_24; // head and most 4 significant bits of LBA - padapter->regStatCmd = zs + REG_STAT_CMD; // status on read and command on write register - padapter->regStatSel = zs + REG_STAT_SEL; // board status on read and spigot select on write register - padapter->regFail = zs + REG_FAIL; - padapter->regAltStat = zs + REG_ALT_STAT; - - padapter->regDmaDesc = zs + RTL_DMA1_DESC_PTR; // address of the DMA discriptor register for direction of transfer - padapter->regDmaCmdStat = zs + RTL_DMA_COMMAND_STATUS + 1; // Byte #1 of DMA command status register - padapter->regDmaAddrPci = zs + RTL_DMA1_PCI_ADDR; // 32 bit register for PCI address of DMA - padapter->regDmaAddrLoc = zs + RTL_DMA1_LOCAL_ADDR; // 32 bit register for local bus address of DMA - padapter->regDmaCount = zs + RTL_DMA1_COUNT; // 32 bit register for DMA transfer count - padapter->regDmaMode = zs + RTL_DMA1_MODE + 1; // 32 bit register for DMA mode control - - if ( !inb_p (padapter->regScratchPad + DALE_NUM_DRIVES) ) // if no devices on this board - goto unregister; - - pshost->irq = pdev->irq; - setirq = 1; - for ( z = 0; z < installed; z++ ) // scan for shared interrupts - { - if ( PsiHost[z]->irq == pshost->irq ) // if shared then, don't posses - setirq = 0; - } - if ( setirq ) // if not shared, posses - { - if ( request_irq (pshost->irq, Irq_Handler, SA_SHIRQ, "pci2220i", padapter) < 0 ) - { - if ( request_irq (pshost->irq, Irq_Handler, SA_INTERRUPT | SA_SHIRQ, "pci2220i", padapter) < 0 ) - { - printk ("Unable to allocate IRQ for PCI-2220I controller.\n"); - goto unregister; - } - } - padapter->irqOwned = pshost->irq; // set IRQ as owned - } - padapter->kBuffer = kmalloc (SECTORSXFER * BYTES_PER_SECTOR, GFP_DMA | GFP_ATOMIC); - if ( !padapter->kBuffer ) - { - printk ("Unable to allocate DMA buffer for PCI-2220I controller.\n"); - free_irq (pshost->irq, padapter); +#if LINUX_VERSION_CODE > LINUXVERSION(2,1,92) + if ( GetRegs (pshost, FALSE, pcidev) ) +#else + if ( GetRegs (pshost, FALSE, pci_bus, pci_device_fn) ) +#endif goto unregister; - } - PsiHost[installed] = pshost; // save SCSI_HOST pointer - - pshost->io_port = padapter->basePort; - pshost->n_io_port = 0xFF; - pshost->unique_id = padapter->regBase; - pshost->max_id = 4; - outb_p (0x01, padapter->regRange); // fix our range register because other drivers want to tromp on it - - padapter->timingMode = inb_p (padapter->regScratchPad + DALE_TIMING_MODE); - if ( padapter->timingMode >= 2 ) - padapter->timingAddress = ModeArray[padapter->timingMode - 2]; - else - padapter->timingPIO = TRUE; - - ReadFlash (padapter, &DaleSetup, DALE_FLASH_SETUP, sizeof (SETUP)); - for ( z = 0; z < inb_p (padapter->regScratchPad + DALE_NUM_DRIVES); ++z ) + pshost->max_id = padapter->numberOfDrives; + for ( z = 0; z < padapter->numberOfDrives; z++ ) { unit = inb_p (padapter->regScratchPad + DALE_CHANNEL_DEVICE_0 + z) & 0x0F; - padapter->device[z].device = inb_p (padapter->regScratchPad + DALE_SCRATH_DEVICE_0 + unit); - padapter->device[z].byte6 = (UCHAR)(((unit & 1) << 4) | 0xE0); - padapter->device[z].spigot = (UCHAR)(1 << (unit >> 1)); - padapter->device[z].sectors = DaleSetup.setupDevice[unit].sectors; - padapter->device[z].heads = DaleSetup.setupDevice[unit].heads; - padapter->device[z].cylinders = DaleSetup.setupDevice[unit].cylinders; - padapter->device[z].blocks = DaleSetup.setupDevice[unit].blocks; + pdev = &padapter->device[z]; + pdev->byte6 = (UCHAR)(((unit & 1) << 4) | 0xE0); + pdev->spigot = (UCHAR)(1 << (unit >> 1)); + pdev->sectors = DaleSetup.setupDevice[unit].sectors; + pdev->heads = DaleSetup.setupDevice[unit].heads; + pdev->cylinders = DaleSetup.setupDevice[unit].cylinders; + pdev->blocks = DaleSetup.setupDevice[unit].blocks; if ( !z ) { - ReadFlash (padapter, &DiskMirror, DALE_FLASH_RAID, sizeof (DiskMirror)); DiskMirror[0].status = inb_p (padapter->regScratchPad + DALE_RAID_0_STATUS); DiskMirror[1].status = inb_p (padapter->regScratchPad + DALE_RAID_1_STATUS); if ( (DiskMirror[0].signature == SIGNATURE) && (DiskMirror[1].signature == SIGNATURE) && (DiskMirror[0].pairIdentifier == (DiskMirror[1].pairIdentifier ^ 1)) ) { raidon = TRUE; + if ( unit > (unit ^ 2) ) + unit = unit ^ 2; } + else + raidon = FALSE; - memcpy (padapter->device[z].DiskMirror, DiskMirror, sizeof (DiskMirror)); - padapter->raidData[0] = &padapter->device[z].DiskMirror[0]; - padapter->raidData[2] = &padapter->device[z].DiskMirror[1]; + memcpy (pdev->DiskMirror, DiskMirror, sizeof (DiskMirror)); + padapter->raidData[0] = &pdev->DiskMirror[0]; + padapter->raidData[2] = &pdev->DiskMirror[1]; - if ( raidon ) - { - padapter->device[z].lastsectorlba[0] = InlineIdentify (padapter, 1, 0); - padapter->device[z].lastsectorlba[1] = InlineIdentify (padapter, 2, 0); + spigot1 = spigot2 = FALSE; + pdev->spigots[0] = 1; + pdev->spigots[1] = 2; + pdev->lastsectorlba[0] = InlineIdentify (padapter, 1, 0); + pdev->lastsectorlba[1] = InlineIdentify (padapter, 2, 0); - if ( !(DiskMirror[1].status & UCBF_SURVIVOR) && padapter->device[z].lastsectorlba[0] ) - spigot1 = TRUE; - if ( !(DiskMirror[0].status & UCBF_SURVIVOR) && padapter->device[z].lastsectorlba[1] ) - spigot2 = TRUE; - if ( DiskMirror[0].status & UCBF_SURVIVOR & DiskMirror[1].status & UCBF_SURVIVOR ) - spigot1 = TRUE; - - if ( spigot1 && (DiskMirror[0].status & UCBF_REBUILD) ) - InlineReadSignature (padapter, &padapter->device[z], 0); - if ( spigot2 && (DiskMirror[1].status & UCBF_REBUILD) ) - InlineReadSignature (padapter, &padapter->device[z], 1); - - if ( spigot1 && spigot2 ) + if ( !(pdev->DiskMirror[1].status & UCBF_SURVIVOR) && pdev->lastsectorlba[0] ) + spigot1 = TRUE; + if ( !(pdev->DiskMirror[0].status & UCBF_SURVIVOR) && pdev->lastsectorlba[1] ) + spigot2 = TRUE; + if ( pdev->DiskMirror[0].status & DiskMirror[1].status & UCBF_SURVIVOR ) + spigot1 = TRUE; + + if ( spigot1 && (pdev->DiskMirror[0].status & UCBF_REBUILD) ) + InlineReadSignature (padapter, pdev, 0); + if ( spigot2 && (pdev->DiskMirror[1].status & UCBF_REBUILD) ) + InlineReadSignature (padapter, pdev, 1); + + if ( spigot1 && spigot2 && raidon ) + { + pdev->raid = 1; + if ( pdev->DiskMirror[0].status & UCBF_REBUILD ) + pdev->spigot = 2; + else + pdev->spigot = 1; + if ( (pdev->DiskMirror[0].status & UCBF_REBUILD) || (pdev->DiskMirror[1].status & UCBF_REBUILD) ) + padapter->reconOn = pdev->reconOn = pdev->reconIsStarting = TRUE; + } + else + { + if ( spigot1 ) { - padapter->device[z].raid = 1; - if ( DiskMirror[0].status & UCBF_REBUILD ) - padapter->device[z].spigot = 2; - else - padapter->device[z].spigot = 1; - if ( (DiskMirror[0].status & UCBF_REBUILD) || (DiskMirror[1].status & UCBF_REBUILD) ) - { - padapter->reconOn = padapter->reconIsStarting = TRUE; - } + if ( pdev->DiskMirror[0].status & UCBF_REBUILD ) + goto unregister; + pdev->DiskMirror[0].status = UCBF_MIRRORED | UCBF_SURVIVOR; + pdev->spigot = 1; } else { - if ( spigot1 ) - { - if ( DiskMirror[0].status & UCBF_REBUILD ) - goto unregister; - DiskMirror[0].status = UCBF_MIRRORED | UCBF_SURVIVOR; - padapter->device[z].spigot = 1; - } - else + if ( pdev->DiskMirror[1].status & UCBF_REBUILD ) + goto unregister; + pdev->DiskMirror[1].status = UCBF_MIRRORED | UCBF_SURVIVOR; + pdev->spigot = 2; + } + if ( DaleSetup.rebootRebuild && raidon ) + padapter->reconOn = pdev->reconOn = pdev->reconIsStarting = TRUE; + } + + if ( raidon ) + break; + } + } + + SetupFinish (padapter, "2220", pshost->irq); + + if ( ++Installed < MAXADAPTER ) + continue; + break;; +unregister:; + scsi_unregister (pshost); + } + +#if LINUX_VERSION_CODE > LINUXVERSION(2,1,92) + while ( (pcidev = pci_find_device (VENDOR_PSI, DEVICE_BIGD_1, pcidev)) != NULL ) +#else + found = 0; + while ( !pcibios_find_device (VENDOR_PSI, DEVICE_BIGD_1, found++, &pci_bus, &pci_device_fn) ) +#endif + { + pshost = scsi_register (tpnt, sizeof(ADAPTER2220I)); + padapter = HOSTDATA(pshost); + +#if LINUX_VERSION_CODE > LINUXVERSION(2,1,92) + if ( GetRegs (pshost, TRUE, pcidev) ) +#else + if ( GetRegs (pshost, TRUE, pci_bus, pci_device_fn) ) +#endif + goto unregister1; + + for ( z = 0; z < BIGD_MAXDRIVES; z++ ) + DiskMirror[z].status = inb_p (padapter->regScratchPad + BIGD_RAID_0_STATUS + z); + + pshost->max_id = padapter->numberOfDrives; + padapter->failRegister = inb_p (padapter->regScratchPad + BIGD_ALARM_IMAGE); + for ( z = 0; z < padapter->numberOfDrives; z++ ) + { + unit = inb_p (padapter->regScratchPad + BIGD_DEVICE_0 + z); + pdev = &padapter->device[z]; + pdev->byte6 = (UCHAR)(((unit & 1) << 4) | 0xE0); + pdev->spigot = (UCHAR)(1 << (unit >> 1)); + pdev->sectors = DaleSetup.setupDevice[unit].sectors; + pdev->heads = DaleSetup.setupDevice[unit].heads; + pdev->cylinders = DaleSetup.setupDevice[unit].cylinders; + pdev->blocks = DaleSetup.setupDevice[unit].blocks; + + if ( (DiskMirror[unit].signature == SIGNATURE) && (DiskMirror[unit ^ 2].signature == SIGNATURE) && + (DiskMirror[unit].pairIdentifier == (DiskMirror[unit ^ 2].pairIdentifier ^ 1)) ) + { + raidon = TRUE; + if ( unit > (unit ^ 2) ) + unit = unit ^ 2; + } + else + raidon = FALSE; + + spigot1 = spigot2 = FALSE; + memcpy (&pdev->DiskMirror[0], &DiskMirror[unit], sizeof (DISK_MIRROR)); + memcpy (&pdev->DiskMirror[1], &DiskMirror[unit ^ 2], sizeof (DISK_MIRROR)); + padapter->raidData[unit] = &pdev->DiskMirror[0]; + padapter->raidData[unit ^ 2] = &pdev->DiskMirror[1]; + pdev->spigots[0] = 1 << (unit >> 1); + pdev->spigots[1] = 1 << ((unit ^ 2) >> 1); + pdev->deviceID[0] = unit; + pdev->deviceID[1] = unit ^ 2; + pdev->lastsectorlba[0] = InlineIdentify (padapter, pdev->spigots[0], unit & 1); + pdev->lastsectorlba[1] = InlineIdentify (padapter, pdev->spigots[1], unit & 1); + + if ( !(pdev->DiskMirror[1].status & UCBF_SURVIVOR) && pdev->lastsectorlba[0] ) + spigot1 = TRUE; + if ( !(pdev->DiskMirror[0].status & UCBF_SURVIVOR) && pdev->lastsectorlba[1] ) + spigot2 = TRUE; + if ( pdev->DiskMirror[0].status & pdev->DiskMirror[1].status & UCBF_SURVIVOR ) + spigot1 = TRUE; + + if ( spigot1 && (pdev->DiskMirror[0].status & UCBF_REBUILD) ) + InlineReadSignature (padapter, pdev, 0); + if ( spigot2 && (pdev->DiskMirror[1].status & UCBF_REBUILD) ) + InlineReadSignature (padapter, pdev, 1); + + if ( spigot1 && spigot2 && raidon ) + { + pdev->raid = 1; + if ( pdev->DiskMirror[0].status & UCBF_REBUILD ) + pdev->spigot = pdev->spigots[1]; + else + pdev->spigot = pdev->spigots[0]; + if ( (pdev->DiskMirror[0].status & UCBF_REBUILD) || (pdev->DiskMirror[1].status & UCBF_REBUILD) ) + padapter->reconOn = pdev->reconOn = pdev->reconIsStarting = TRUE; + } + else + { + if ( spigot1 ) + { + if ( pdev->DiskMirror[0].status & UCBF_REBUILD ) + goto unregister1; + pdev->DiskMirror[0].status = UCBF_MIRRORED | UCBF_SURVIVOR; + pdev->spigot = pdev->spigots[0]; + } + else + { + if ( pdev->DiskMirror[1].status & UCBF_REBUILD ) + goto unregister; + pdev->DiskMirror[1].status = UCBF_MIRRORED | UCBF_SURVIVOR; + pdev->spigot = pdev->spigots[1]; + } + if ( DaleSetup.rebootRebuild && raidon ) + padapter->reconOn = pdev->reconOn = pdev->reconIsStarting = TRUE; + } + } + + if ( !padapter->numberOfDrives ) // If no ATA devices then scan ATAPI + { + unit = 0; + for ( spigot1 = 0; spigot1 < 4; spigot1++ ) + { + for ( device = 0; device < 2; device++ ) + { + DEB (printk ("\nPCI2242I: scanning for ID %d ", (spigot1 * 2) + device)); + pdev = &(padapter->device[(spigot1 * 2) + device]); + pdev->byte6 = 0x0A | (device << 4); + pdev->spigot = 1 << spigot1; + if ( !AtapiReset (padapter, pdev) ) + { + DEB (printk (" Device found ")); + if ( !AtapiIdentify (padapter, pdev) ) { - if ( DiskMirror[1].status & UCBF_REBUILD ) - goto unregister; - DiskMirror[1].status = UCBF_MIRRORED | UCBF_SURVIVOR; - padapter->device[z].spigot = 2; + DEB (printk (" Device verified")); + unit++; + continue; } - if ( DaleSetup.rebootRebuil ) - padapter->reconOn = padapter->reconIsStarting = TRUE; } - - break; + pdev->spigot = pdev->byte6 = 0; } } + + if ( unit ) + { + padapter->atapi = TRUE; + padapter->timingAddress = DALE_DATA_MODE3; + outw_p (0x0900, padapter->regIrqControl); // Turn our interrupts on + outw_p (0x0C41, padapter->regDmaMode - 1); // setup for 16 bits, ready enabled, done IRQ enabled, no incriment + outb_p (0xFF, padapter->regFail); // all fail lights and alarm off + pshost->max_id = 8; + } } - - init_timer (&padapter->timer); - padapter->timer.function = TimerExpiry; - padapter->timer.data = (unsigned long)padapter; - init_timer (&padapter->reconTimer); - padapter->reconTimer.function = ReconTimerExpiry; - padapter->reconTimer.data = (unsigned long)padapter; - printk("\nPCI-2220I EIDE CONTROLLER: at I/O = %X/%X IRQ = %d\n", padapter->basePort, padapter->regBase, pshost->irq); - printk("Version %s, Compiled %s %s\n\n", PCI2220I_VERSION, __DATE__, __TIME__); - found++; - if ( ++installed < MAXADAPTER ) + SetupFinish (padapter, "2240", pshost->irq); + + if ( ++Installed < MAXADAPTER ) continue; break;; -unregister:; +unregister1:; scsi_unregister (pshost); - found++; } - - NumAdapters = installed; - return installed; + + NumAdapters = Installed; + return Installed; } /**************************************************************** * Name: Pci2220i_Abort @@ -1933,6 +2891,19 @@ ****************************************************************/ int Pci2220i_Abort (Scsi_Cmnd *SCpnt) { + PADAPTER2220I padapter = HOSTDATA(SCpnt->host); // Pointer to adapter control structure + POUR_DEVICE pdev = &padapter->device[SCpnt->target];// Pointer to device information + + if ( !padapter->SCpnt ) + return SCSI_ABORT_NOT_RUNNING; + + if ( padapter->atapi ) + { + if ( AtapiReset (padapter, pdev) ) + return SCSI_ABORT_ERROR; + OpDone (padapter, DID_ABORT << 16); + return SCSI_ABORT_SUCCESS; + } return SCSI_ABORT_SNOOZE; } /**************************************************************** @@ -1952,6 +2923,15 @@ ****************************************************************/ int Pci2220i_Reset (Scsi_Cmnd *SCpnt, unsigned int reset_flags) { + PADAPTER2220I padapter = HOSTDATA(SCpnt->host); // Pointer to adapter control structure + POUR_DEVICE pdev = &padapter->device[SCpnt->target];// Pointer to device information + + if ( padapter->atapi ) + { + if ( AtapiReset (padapter, pdev) ) + return SCSI_RESET_ERROR; + return SCSI_RESET_SUCCESS; + } return SCSI_RESET_PUNT; } /**************************************************************** @@ -1967,6 +2947,7 @@ int Pci2220i_Release (struct Scsi_Host *pshost) { PADAPTER2220I padapter = HOSTDATA (pshost); + USHORT z; if ( padapter->reconOn ) { @@ -1981,11 +2962,29 @@ } // save RAID status on the board - outb_p (DiskMirror[0].status, padapter->regScratchPad + DALE_RAID_0_STATUS); - outb_p (DiskMirror[1].status, padapter->regScratchPad + DALE_RAID_1_STATUS); + if ( padapter->bigD ) + { + outb_p (padapter->failRegister, padapter->regScratchPad + BIGD_ALARM_IMAGE); + for ( z = 0; z < BIGD_MAXDRIVES; z++ ) + { + if ( padapter->raidData ) + outb_p (padapter->raidData[z]->status, padapter->regScratchPad + BIGD_RAID_0_STATUS + z); + else + outb_p (0, padapter->regScratchPad + BIGD_RAID_0_STATUS); + } + } + else + { + outb_p (padapter->device[0].DiskMirror[0].status, padapter->regScratchPad + DALE_RAID_0_STATUS); + outb_p (padapter->device[0].DiskMirror[1].status, padapter->regScratchPad + DALE_RAID_1_STATUS); + } if ( padapter->irqOwned ) +#if LINUX_VERSION_CODE < LINUXVERSION(1,3,70) + free_irq (pshost->irq); +#else /* version >= v1.3.70 */ free_irq (pshost->irq, padapter); +#endif /* version >= v1.3.70 */ release_region (pshost->io_port, pshost->n_io_port); kfree (padapter->kBuffer); scsi_unregister(pshost); @@ -2011,11 +3010,14 @@ { POUR_DEVICE pdev; - pdev = &(HOSTDATA(disk->device->host)->device[disk->device->id]); + if ( !(HOSTDATA(disk->device->host))->atapi ) + { + pdev = &(HOSTDATA(disk->device->host)->device[disk->device->id]); - geom[0] = pdev->heads; - geom[1] = pdev->sectors; - geom[2] = pdev->cylinders; + geom[0] = pdev->heads; + geom[1] = pdev->sectors; + geom[2] = pdev->cylinders; + } return 0; } diff -u --recursive --new-file v2.3.46/linux/drivers/scsi/pci2220i.h linux/drivers/scsi/pci2220i.h --- v2.3.46/linux/drivers/scsi/pci2220i.h Fri Jan 28 15:09:08 2000 +++ linux/drivers/scsi/pci2220i.h Sun Feb 20 20:49:46 2000 @@ -21,265 +21,11 @@ #ifndef _PCI2220I_H #define _PCI2220I_H -#ifndef PSI_EIDE_SCSIOP -#define PSI_EIDE_SCSIOP 1 - #ifndef LINUX_VERSION_CODE #include #endif #define LINUXVERSION(v,p,s) (((v)<<16) + ((p)<<8) + (s)) -/************************************************/ -/* Some defines that we like */ -/************************************************/ -#define CHAR char -#define UCHAR unsigned char -#define SHORT short -#define USHORT unsigned short -#define BOOL unsigned short -#define LONG long -#define ULONG unsigned long -#define VOID void - -#include "psi_dale.h" - -/************************************************/ -/* Timeout konstants */ -/************************************************/ -#define TIMEOUT_READY 100 // 100 mSec -#define TIMEOUT_DRQ 300 // 300 mSec -#define TIMEOUT_DATA (3 * HZ) // 3 seconds - -/************************************************/ -/* Misc. macros */ -/************************************************/ -#define ANY2SCSI(up, p) \ -((UCHAR *)up)[0] = (((ULONG)(p)) >> 8); \ -((UCHAR *)up)[1] = ((ULONG)(p)); - -#define SCSI2LONG(up) \ -( (((long)*(((UCHAR *)up))) << 16) \ -+ (((long)(((UCHAR *)up)[1])) << 8) \ -+ ((long)(((UCHAR *)up)[2])) ) - -#define XANY2SCSI(up, p) \ -((UCHAR *)up)[0] = ((long)(p)) >> 24; \ -((UCHAR *)up)[1] = ((long)(p)) >> 16; \ -((UCHAR *)up)[2] = ((long)(p)) >> 8; \ -((UCHAR *)up)[3] = ((long)(p)); - -#define XSCSI2LONG(up) \ -( (((long)(((UCHAR *)up)[0])) << 24) \ -+ (((long)(((UCHAR *)up)[1])) << 16) \ -+ (((long)(((UCHAR *)up)[2])) << 8) \ -+ ((long)(((UCHAR *)up)[3])) ) - -#define SelectSpigot(padapter,spigot) outb_p (spigot, padapter->regStatSel) -#define WriteCommand(padapter,cmd) outb_p (cmd, padapter->regStatCmd) - -/************************************************/ -/* SCSI CDB operation codes */ -/************************************************/ -#define SCSIOP_TEST_UNIT_READY 0x00 -#define SCSIOP_REZERO_UNIT 0x01 -#define SCSIOP_REWIND 0x01 -#define SCSIOP_REQUEST_BLOCK_ADDR 0x02 -#define SCSIOP_REQUEST_SENSE 0x03 -#define SCSIOP_FORMAT_UNIT 0x04 -#define SCSIOP_READ_BLOCK_LIMITS 0x05 -#define SCSIOP_REASSIGN_BLOCKS 0x07 -#define SCSIOP_READ6 0x08 -#define SCSIOP_RECEIVE 0x08 -#define SCSIOP_WRITE6 0x0A -#define SCSIOP_PRINT 0x0A -#define SCSIOP_SEND 0x0A -#define SCSIOP_SEEK6 0x0B -#define SCSIOP_TRACK_SELECT 0x0B -#define SCSIOP_SLEW_PRINT 0x0B -#define SCSIOP_SEEK_BLOCK 0x0C -#define SCSIOP_PARTITION 0x0D -#define SCSIOP_READ_REVERSE 0x0F -#define SCSIOP_WRITE_FILEMARKS 0x10 -#define SCSIOP_FLUSH_BUFFER 0x10 -#define SCSIOP_SPACE 0x11 -#define SCSIOP_INQUIRY 0x12 -#define SCSIOP_VERIFY6 0x13 -#define SCSIOP_RECOVER_BUF_DATA 0x14 -#define SCSIOP_MODE_SELECT 0x15 -#define SCSIOP_RESERVE_UNIT 0x16 -#define SCSIOP_RELEASE_UNIT 0x17 -#define SCSIOP_COPY 0x18 -#define SCSIOP_ERASE 0x19 -#define SCSIOP_MODE_SENSE 0x1A -#define SCSIOP_START_STOP_UNIT 0x1B -#define SCSIOP_STOP_PRINT 0x1B -#define SCSIOP_LOAD_UNLOAD 0x1B -#define SCSIOP_RECEIVE_DIAGNOSTIC 0x1C -#define SCSIOP_SEND_DIAGNOSTIC 0x1D -#define SCSIOP_MEDIUM_REMOVAL 0x1E -#define SCSIOP_READ_CAPACITY 0x25 -#define SCSIOP_READ 0x28 -#define SCSIOP_WRITE 0x2A -#define SCSIOP_SEEK 0x2B -#define SCSIOP_LOCATE 0x2B -#define SCSIOP_WRITE_VERIFY 0x2E -#define SCSIOP_VERIFY 0x2F -#define SCSIOP_SEARCH_DATA_HIGH 0x30 -#define SCSIOP_SEARCH_DATA_EQUAL 0x31 -#define SCSIOP_SEARCH_DATA_LOW 0x32 -#define SCSIOP_SET_LIMITS 0x33 -#define SCSIOP_READ_POSITION 0x34 -#define SCSIOP_SYNCHRONIZE_CACHE 0x35 -#define SCSIOP_COMPARE 0x39 -#define SCSIOP_COPY_COMPARE 0x3A -#define SCSIOP_WRITE_DATA_BUFF 0x3B -#define SCSIOP_READ_DATA_BUFF 0x3C -#define SCSIOP_CHANGE_DEFINITION 0x40 -#define SCSIOP_READ_SUB_CHANNEL 0x42 -#define SCSIOP_READ_TOC 0x43 -#define SCSIOP_READ_HEADER 0x44 -#define SCSIOP_PLAY_AUDIO 0x45 -#define SCSIOP_PLAY_AUDIO_MSF 0x47 -#define SCSIOP_PLAY_TRACK_INDEX 0x48 -#define SCSIOP_PLAY_TRACK_RELATIVE 0x49 -#define SCSIOP_PAUSE_RESUME 0x4B -#define SCSIOP_LOG_SELECT 0x4C -#define SCSIOP_LOG_SENSE 0x4D -#define SCSIOP_MODE_SELECT10 0x55 -#define SCSIOP_MODE_SENSE10 0x5A -#define SCSIOP_LOAD_UNLOAD_SLOT 0xA6 -#define SCSIOP_MECHANISM_STATUS 0xBD -#define SCSIOP_READ_CD 0xBE - -// IDE command definitions -#define IDE_COMMAND_ATAPI_RESET 0x08 -#define IDE_COMMAND_READ 0x20 -#define IDE_COMMAND_WRITE 0x30 -#define IDE_COMMAND_RECALIBRATE 0x10 -#define IDE_COMMAND_SEEK 0x70 -#define IDE_COMMAND_SET_PARAMETERS 0x91 -#define IDE_COMMAND_VERIFY 0x40 -#define IDE_COMMAND_ATAPI_PACKET 0xA0 -#define IDE_COMMAND_ATAPI_IDENTIFY 0xA1 -#define IDE_CMD_READ_MULTIPLE 0xC4 -#define IDE_CMD_WRITE_MULTIPLE 0xC5 -#define IDE_CMD_SET_MULTIPLE 0xC6 -#define IDE_COMMAND_IDENTIFY 0xEC - -// IDE status definitions -#define IDE_STATUS_ERROR 0x01 -#define IDE_STATUS_INDEX 0x02 -#define IDE_STATUS_CORRECTED_ERROR 0x04 -#define IDE_STATUS_DRQ 0x08 -#define IDE_STATUS_DSC 0x10 -#define IDE_STATUS_WRITE_FAULT 0x20 -#define IDE_STATUS_DRDY 0x40 -#define IDE_STATUS_BUSY 0x80 - -// IDE error definitions -#define IDE_ERROR_AMNF 0x01 -#define IDE_ERROR_TKONF 0x02 -#define IDE_ERROR_ABRT 0x04 -#define IDE_ERROR_MCR 0x08 -#define IDE_ERROR_IDFN 0x10 -#define IDE_ERROR_MC 0x20 -#define IDE_ERROR_UNC 0x40 -#define IDE_ERROR_BBK 0x80 - -// SCSI read capacity structure -typedef struct _READ_CAPACITY_DATA - { - ULONG blks; /* total blocks (converted to little endian) */ - ULONG blksiz; /* size of each (converted to little endian) */ - } READ_CAPACITY_DATA, *PREAD_CAPACITY_DATA; - -// SCSI inquiry data -typedef struct _INQUIRYDATA - { - UCHAR DeviceType :5; - UCHAR DeviceTypeQualifier :3; - UCHAR DeviceTypeModifier :7; - UCHAR RemovableMedia :1; - UCHAR Versions; - UCHAR ResponseDataFormat; - UCHAR AdditionalLength; - UCHAR Reserved[2]; - UCHAR SoftReset :1; - UCHAR CommandQueue :1; - UCHAR Reserved2 :1; - UCHAR LinkedCommands :1; - UCHAR Synchronous :1; - UCHAR Wide16Bit :1; - UCHAR Wide32Bit :1; - UCHAR RelativeAddressing :1; - UCHAR VendorId[8]; - UCHAR ProductId[16]; - UCHAR ProductRevisionLevel[4]; - UCHAR VendorSpecific[20]; - UCHAR Reserved3[40]; - } INQUIRYDATA, *PINQUIRYDATA; - -// IDE IDENTIFY data -#pragma pack (1) -#pragma align 1 -typedef struct _IDENTIFY_DATA - { - USHORT GeneralConfiguration; // 0 - USHORT NumberOfCylinders; // 1 - USHORT Reserved1; // 2 - USHORT NumberOfHeads; // 3 - USHORT UnformattedBytesPerTrack; // 4 - USHORT UnformattedBytesPerSector; // 5 - USHORT SectorsPerTrack; // 6 - USHORT NumBytesISG; // 7 Byte Len - inter-sector gap - USHORT NumBytesSync; // 8 - sync field - USHORT NumWordsVUS; // 9 Len - Vendor Unique Info - USHORT SerialNumber[10]; // 10 - USHORT BufferType; // 20 - USHORT BufferSectorSize; // 21 - USHORT NumberOfEccBytes; // 22 - USHORT FirmwareRevision[4]; // 23 - USHORT ModelNumber[20]; // 27 - USHORT NumSectorsPerInt :8; // 47 Multiple Mode - Sec/Blk - USHORT Reserved2 :8; // 47 - USHORT DoubleWordMode; // 48 flag for double word mode capable - USHORT VendorUnique1 :8; // 49 - USHORT SupportDMA :1; // 49 DMA supported - USHORT SupportLBA :1; // 49 LBA supported - USHORT SupportIORDYDisable :1; // 49 IORDY can be disabled - USHORT SupportIORDY :1; // 49 IORDY supported - USHORT ReservedPseudoDMA :1; // 49 reserved for pseudo DMA mode support - USHORT Reserved3 :3; // 49 - USHORT Reserved4; // 50 - USHORT Reserved5 :8; // 51 Transfer Cycle Timing - PIO - USHORT PIOCycleTime :8; // 51 Transfer Cycle Timing - PIO - USHORT Reserved6 :8; // 52 - DMA - USHORT DMACycleTime :8; // 52 - DMA - USHORT Valid_54_58 :1; // 53 words 54 - 58 are vaild - USHORT Valid_64_70 :1; // 53 words 64 - 70 are valid - USHORT Reserved7 :14; // 53 - USHORT LogNumCyl; // 54 Current Translation - Num Cyl - USHORT LogNumHeads; // 55 Num Heads - USHORT LogSectorsPerTrack; // 56 Sec/Trk - ULONG LogTotalSectors; // 57 Total Sec - USHORT CurrentNumSecPerInt :8; // 59 current setting for number of sectors per interrupt - USHORT ValidNumSecPerInt :1; // 59 Current setting is valid for number of sectors per interrupt - USHORT Reserved8 :7; // 59 - ULONG LBATotalSectors; // 60 LBA Mode - Sectors - USHORT DMASWordFlags; // 62 - USHORT DMAMWordFlags; // 63 - USHORT AdvancedPIOSupport :8; // 64 Flow control PIO transfer modes supported - USHORT Reserved9 :8; // 64 - USHORT MinMultiDMACycle; // 65 minimum multiword DMA transfer cycle time per word - USHORT RecomendDMACycle; // 66 Manufacturer's recommende multiword DMA transfer cycle time - USHORT MinPIOCycleWithoutFlow; // 67 Minimum PIO transfer cycle time without flow control - USHORT MinPIOCylceWithFlow; // 68 Minimum PIO transfer cycle time with IORDY flow control - USHORT ReservedSpace[256-69]; // 69 - } IDENTIFY_DATA, *PIDENTIFY_DATA; -#pragma pack () -#pragma align 0 -#endif // PSI_EIDE_SCSIOP - // function prototypes int Pci2220i_Detect (Scsi_Host_Template *tpnt); int Pci2220i_Command (Scsi_Cmnd *SCpnt); @@ -293,12 +39,15 @@ #define NULL 0 #endif +extern struct proc_dir_entry Proc_Scsi_Pci2220i; + +#if LINUX_VERSION_CODE >= LINUXVERSION(2,1,75) #define PCI2220I { \ next: NULL, \ module: NULL, \ - proc_name: "pci2220i", \ + proc_dir: &Proc_Scsi_Pci2220i, \ proc_info: NULL, /* let's not bloat the kernel */\ - name: "PCI-2220I EIDE Disk Controller", \ + name: "PCI-2220I/PCI-2240I", \ detect: Pci2220i_Detect, \ release: Pci2220i_Release, \ info: NULL, /* let's not bloat the kernel */\ @@ -315,11 +64,34 @@ bios_param: Pci2220i_BiosParam, \ can_queue: 1, \ this_id: -1, \ - sg_tablesize: SG_NONE, \ + sg_tablesize: SG_ALL, \ cmd_per_lun: 1, \ present: 0, \ unchecked_isa_dma: 0, \ use_clustering: DISABLE_CLUSTERING, \ use_new_eh_code: 0 \ } +#else +#define PCI2220I { NULL, NULL, \ + &Proc_Scsi_Pci2220i,/* proc_dir_entry */\ + NULL, \ + "PCI-2220I/PCI-2240I", \ + Pci2220i_Detect, \ + Pci2220i_Release, \ + NULL, \ + Pci2220i_Command, \ + Pci2220i_QueueCommand, \ + Pci2220i_Abort, \ + Pci2220i_Reset, \ + NULL, \ + Pci2220i_BiosParam, \ + 1, \ + -1, \ + SG_ALL, \ + 1, \ + 0, \ + 0, \ + DISABLE_CLUSTERING } +#endif + #endif diff -u --recursive --new-file v2.3.46/linux/drivers/scsi/psi_dale.h linux/drivers/scsi/psi_dale.h --- v2.3.46/linux/drivers/scsi/psi_dale.h Tue Apr 13 07:54:02 1999 +++ linux/drivers/scsi/psi_dale.h Fri Feb 18 14:50:03 2000 @@ -20,16 +20,32 @@ ****************************************************************************/ /************************************************/ +/* Some defines that we like */ +/************************************************/ +#define CHAR char +#define UCHAR unsigned char +#define SHORT short +#define USHORT unsigned short +#define BOOL unsigned short +#define LONG long +#define ULONG unsigned long +#define VOID void + +/************************************************/ /* Dale PCI setup */ /************************************************/ #define VENDOR_PSI 0x1256 #define DEVICE_DALE_1 0x4401 /* 'D1' */ +#define DEVICE_BIGD_1 0x4201 /* 'B1' */ +#define DEVICE_BIGD_2 0x4202 /* 'B2' */ /************************************************/ /* Misc konstants */ /************************************************/ #define DALE_MAXDRIVES 4 +#define BIGD_MAXDRIVES 8 #define SECTORSXFER 8 +#define ATAPI_TRANSFER 8192 #define BYTES_PER_SECTOR 512 #define DEFAULT_TIMING_MODE 5 @@ -49,90 +65,136 @@ /************************************************/ /* DALE Register address offsets */ /************************************************/ -#define REG_DATA 0x80 -#define REG_ERROR 0x84 -#define REG_SECTOR_COUNT 0x88 -#define REG_LBA_0 0x8C -#define REG_LBA_8 0x90 -#define REG_LBA_16 0x94 -#define REG_LBA_24 0x98 -#define REG_STAT_CMD 0x9C -#define REG_STAT_SEL 0xA0 -#define REG_FAIL 0xB0 -#define REG_ALT_STAT 0xB8 -#define REG_DRIVE_ADRS 0xBC - -#define DALE_DATA_SLOW 0x00040000L -#define DALE_DATA_MODE2 0x00040000L -#define DALE_DATA_MODE3 0x00050000L -#define DALE_DATA_MODE4 0x00060000L -#define DALE_DATA_MODE4P 0x00070000L - -#define RTR_LOCAL_RANGE 0x000 -#define RTR_LOCAL_REMAP 0x004 -#define RTR_EXP_RANGE 0x010 -#define RTR_EXP_REMAP 0x014 -#define RTR_REGIONS 0x018 -#define RTR_DM_MASK 0x01C -#define RTR_DM_LOCAL_BASE 0x020 -#define RTR_DM_IO_BASE 0x024 -#define RTR_DM_PCI_REMAP 0x028 -#define RTR_DM_IO_CONFIG 0x02C -#define RTR_MAILBOX 0x040 -#define RTR_LOCAL_DOORBELL 0x060 -#define RTR_PCI_DOORBELL 0x064 -#define RTR_INT_CONTROL_STATUS 0x068 -#define RTR_EEPROM_CONTROL_STATUS 0x06C - -#define RTL_DMA0_MODE 0x00 -#define RTL_DMA0_PCI_ADDR 0x04 -#define RTL_DMA0_LOCAL_ADDR 0x08 -#define RTL_DMA0_COUNT 0x0C -#define RTL_DMA0_DESC_PTR 0x10 -#define RTL_DMA1_MODE 0x14 -#define RTL_DMA1_PCI_ADDR 0x18 -#define RTL_DMA1_LOCAL_ADDR 0x1C -#define RTL_DMA1_COUNT 0x20 -#define RTL_DMA1_DESC_PTR 0x24 -#define RTL_DMA_COMMAND_STATUS 0x28 -#define RTL_DMA_ARB0 0x2C -#define RTL_DMA_ARB1 0x30 +#define REG_DATA 0x80 +#define REG_ERROR 0x84 +#define REG_SECTOR_COUNT 0x88 +#define REG_LBA_0 0x8C +#define REG_LBA_8 0x90 +#define REG_LBA_16 0x94 +#define REG_LBA_24 0x98 +#define REG_STAT_CMD 0x9C +#define REG_STAT_SEL 0xA0 +#define REG_FAIL 0xB0 +#define REG_ALT_STAT 0xB8 +#define REG_DRIVE_ADRS 0xBC + +#define DALE_DATA_SLOW 0x00040000L +#define DALE_DATA_MODE2 0x00040000L +#define DALE_DATA_MODE3 0x00050000L +#define DALE_DATA_MODE4 0x00060000L +#define DALE_DATA_MODE5 0x00070000L + +#define BIGD_DATA_SLOW 0x00000000L +#define BIGD_DATA_MODE0 0x00000000L +#define BIGD_DATA_MODE2 0x00000000L +#define BIGD_DATA_MODE3 0x00000008L +#define BIGD_DATA_MODE4 0x00000010L +#define BIGD_DATA_MODE5 0x00000020L + +#define RTR_LOCAL_RANGE 0x000 +#define RTR_LOCAL_REMAP 0x004 +#define RTR_EXP_RANGE 0x010 +#define RTR_EXP_REMAP 0x014 +#define RTR_REGIONS 0x018 +#define RTR_DM_MASK 0x01C +#define RTR_DM_LOCAL_BASE 0x020 +#define RTR_DM_IO_BASE 0x024 +#define RTR_DM_PCI_REMAP 0x028 +#define RTR_DM_IO_CONFIG 0x02C +#define RTR_MAILBOX 0x040 +#define RTR_LOCAL_DOORBELL 0x060 +#define RTR_PCI_DOORBELL 0x064 +#define RTR_INT_CONTROL_STATUS 0x068 +#define RTR_EEPROM_CONTROL_STATUS 0x06C + +#define RTR_DMA0_MODE 0x0080 +#define RTR_DMA0_PCI_ADDR 0x0084 +#define RTR_DMA0_LOCAL_ADDR 0x0088 +#define RTR_DMA0_COUNT 0x008C +#define RTR_DMA0_DESC_PTR 0x0090 +#define RTR_DMA1_MODE 0x0094 +#define RTR_DMA1_PCI_ADDR 0x0098 +#define RTR_DMA1_LOCAL_ADDR 0x009C +#define RTR_DMA1_COUNT 0x00A0 +#define RTR_DMA1_DESC_PTR 0x00A4 +#define RTR_DMA_COMMAND_STATUS 0x00A8 +#define RTR_DMA_ARB0 0x00AC +#define RTR_DMA_ARB1 0x00B0 + +#define RTL_DMA0_MODE 0x00 +#define RTL_DMA0_PCI_ADDR 0x04 +#define RTL_DMA0_LOCAL_ADDR 0x08 +#define RTL_DMA0_COUNT 0x0C +#define RTL_DMA0_DESC_PTR 0x10 +#define RTL_DMA1_MODE 0x14 +#define RTL_DMA1_PCI_ADDR 0x18 +#define RTL_DMA1_LOCAL_ADDR 0x1C +#define RTL_DMA1_COUNT 0x20 +#define RTL_DMA1_DESC_PTR 0x24 +#define RTL_DMA_COMMAND_STATUS 0x28 +#define RTL_DMA_ARB0 0x2C +#define RTL_DMA_ARB1 0x30 /************************************************/ /* Dale Scratchpad locations */ /************************************************/ -#define DALE_CHANNEL_DEVICE_0 0 // device channel locations -#define DALE_CHANNEL_DEVICE_1 1 -#define DALE_CHANNEL_DEVICE_2 2 -#define DALE_CHANNEL_DEVICE_3 3 - -#define DALE_SCRATH_DEVICE_0 4 // device type codes -#define DALE_SCRATH_DEVICE_1 5 -#define DALE_SCRATH_DEVICE_2 6 -#define DALE_SCRATH_DEVICE_3 7 - -#define DALE_RAID_0_STATUS 8 -#define DALE_RAID_1_STATUS 9 - -#define DALE_TIMING_MODE 12 // bus master timing mode (2, 3, 4, 5) -#define DALE_NUM_DRIVES 13 // number of addressable drives on this board -#define DALE_RAID_ON 14 // RAID status On -#define DALE_LAST_ERROR 15 // Last error code from BIOS +#define DALE_CHANNEL_DEVICE_0 0 // device channel locations +#define DALE_CHANNEL_DEVICE_1 1 +#define DALE_CHANNEL_DEVICE_2 2 +#define DALE_CHANNEL_DEVICE_3 3 + +#define DALE_SCRATCH_DEVICE_0 4 // device type codes +#define DALE_SCRATCH_DEVICE_1 5 +#define DALE_SCRATCH_DEVICE_2 6 +#define DALE_SCRATCH_DEVICE_3 7 + +#define DALE_RAID_0_STATUS 8 +#define DALE_RAID_1_STATUS 9 + +#define DALE_TIMING_MODE 12 // bus master timing mode (2, 3, 4, 5) +#define DALE_NUM_DRIVES 13 // number of addressable drives on this board +#define DALE_RAID_ON 14 // RAID status On +#define DALE_LAST_ERROR 15 // Last error code from BIOS + +/************************************************/ +/* BigD Scratchpad locations */ +/************************************************/ +#define BIGD_DEVICE_0 0 // device channel locations +#define BIGD_DEVICE_1 1 +#define BIGD_DEVICE_2 2 +#define BIGD_DEVICE_3 3 + +#define BIGD_DEVICE_4 4 // device type codes +#define BIGD_DEVICE_5 5 +#define BIGD_DEVICE_6 6 +#define BIGD_DEVICE_7 7 + +#define BIGD_ALARM_IMAGE 11 // ~image of alarm fail register +#define BIGD_TIMING_MODE 12 // bus master timing mode (2, 3, 4, 5) +#define BIGD_NUM_DRIVES 13 // number of addressable drives on this board +#define BIGD_RAID_ON 14 // RAID status is on for the whole board +#define BIGD_LAST_ERROR 15 // Last error code from BIOS + +#define BIGD_RAID_0_STATUS 16 +#define BIGD_RAID_1_STATUS 17 +#define BIGD_RAID_2_STATUS 18 +#define BIGD_RAID_3_STATUS 19 +#define BIGD_RAID_4_STATUS 20 +#define BIGD_RAID_5_STATUS 21 +#define BIGD_RAID_6_STATUS 22 +#define BIGD_RAID_7_STATUS 23 /************************************************/ /* Dale cable select bits */ /************************************************/ -#define SEL_NONE 0x00 -#define SEL_1 0x01 -#define SEL_2 0x02 - -/************************************************/ -/* Programmable Interrupt Controller */ -/************************************************/ -#define PIC1 0x20 // first 8259 base port address -#define PIC2 0xA0 // second 8259 base port address -#define INT_OCW1 1 // Operation Control Word 1: IRQ mask -#define EOI 0x20 // non-specific end-of-interrupt +#define SEL_NONE 0x00 +#define SEL_1 0x01 +#define SEL_2 0x02 +#define SEL_3 0x04 +#define SEL_4 0x08 +#define SEL_NEW_SPEED_1 0x20 +#define SEL_COPY 0x40 +#define SEL_IRQ_OFF 0x80 /************************************************/ /* Device/Geometry controls */ @@ -149,6 +211,18 @@ #define DEVICE_DASD_LBA 0x4 // LBA compatible device /************************************************/ +/* BigD fail register bits */ +/************************************************/ +#define FAIL_NONE 0x00 +#define FAIL_0 0x01 +#define FAIL_1 0x02 +#define FAIL_2 0x04 +#define FAIL_MULTIPLE 0x08 +#define FAIL_GOOD 0x20 +#define FAIL_AUDIBLE 0x40 +#define FAIL_ANY 0x80 + +/************************************************/ /* Setup Structure Definitions */ /************************************************/ typedef struct // device setup parameters @@ -168,11 +242,11 @@ BOOL promptBIOS; BOOL fastFormat; BOOL shareInterrupt; - BOOL rebootRebuil; + BOOL rebootRebuild; USHORT timingMode; USHORT spare5; USHORT spare6; - SETUP_DEVICE setupDevice[4]; + SETUP_DEVICE setupDevice[BIGD_MAXDRIVES]; } SETUP, *PSETUP; /************************************************/ @@ -210,3 +284,281 @@ #define MY_SCSI_REBUILD 0x40 // byte 1 subcommand to reconstruct a mirrored pair #define MY_SCSI_DEMOFAIL 0x54 // byte 1 subcommand for RAID failure demonstration #define MY_SCSI_ALARMMUTE 0x60 // byte 1 subcommand to mute any alarm currently on + +/************************************************/ +/* Timeout konstants */ +/************************************************/ +#define TIMEOUT_READY 100 // 100 mSec +#define TIMEOUT_DRQ 300 // 300 mSec +#define TIMEOUT_DATA (3 * HZ) // 3 seconds + +/************************************************/ +/* Misc. macros */ +/************************************************/ +#define ANY2SCSI(up, p) \ +((UCHAR *)up)[0] = (((ULONG)(p)) >> 8); \ +((UCHAR *)up)[1] = ((ULONG)(p)); + +#define SCSI2LONG(up) \ +( (((long)*(((UCHAR *)up))) << 16) \ ++ (((long)(((UCHAR *)up)[1])) << 8) \ ++ ((long)(((UCHAR *)up)[2])) ) + +#define XANY2SCSI(up, p) \ +((UCHAR *)up)[0] = ((long)(p)) >> 24; \ +((UCHAR *)up)[1] = ((long)(p)) >> 16; \ +((UCHAR *)up)[2] = ((long)(p)) >> 8; \ +((UCHAR *)up)[3] = ((long)(p)); + +#define XSCSI2LONG(up) \ +( (((long)(((UCHAR *)up)[0])) << 24) \ ++ (((long)(((UCHAR *)up)[1])) << 16) \ ++ (((long)(((UCHAR *)up)[2])) << 8) \ ++ ((long)(((UCHAR *)up)[3])) ) + +#define SelectSpigot(padapter,spigot) outb_p (spigot, padapter->regStatSel) +#define WriteCommand(padapter,cmd) outb_p (cmd, padapter->regStatCmd) +#define AtapiDevice(padapter,b) outb_p (b, padapter->regLba24); +#define AtapiCountLo(padapter,b) outb_p (b, padapter->regLba8) +#define AtapiCountHi(padapter,b) outb_p (b, padapter->regLba16) + +/************************************************/ +/* SCSI CDB operation codes */ +/************************************************/ +#define SCSIOP_TEST_UNIT_READY 0x00 +#define SCSIOP_REZERO_UNIT 0x01 +#define SCSIOP_REWIND 0x01 +#define SCSIOP_REQUEST_BLOCK_ADDR 0x02 +#define SCSIOP_REQUEST_SENSE 0x03 +#define SCSIOP_FORMAT_UNIT 0x04 +#define SCSIOP_READ_BLOCK_LIMITS 0x05 +#define SCSIOP_REASSIGN_BLOCKS 0x07 +#define SCSIOP_READ6 0x08 +#define SCSIOP_RECEIVE 0x08 +#define SCSIOP_WRITE6 0x0A +#define SCSIOP_PRINT 0x0A +#define SCSIOP_SEND 0x0A +#define SCSIOP_SEEK6 0x0B +#define SCSIOP_TRACK_SELECT 0x0B +#define SCSIOP_SLEW_PRINT 0x0B +#define SCSIOP_SEEK_BLOCK 0x0C +#define SCSIOP_PARTITION 0x0D +#define SCSIOP_READ_REVERSE 0x0F +#define SCSIOP_WRITE_FILEMARKS 0x10 +#define SCSIOP_FLUSH_BUFFER 0x10 +#define SCSIOP_SPACE 0x11 +#define SCSIOP_INQUIRY 0x12 +#define SCSIOP_VERIFY6 0x13 +#define SCSIOP_RECOVER_BUF_DATA 0x14 +#define SCSIOP_MODE_SELECT 0x15 +#define SCSIOP_RESERVE_UNIT 0x16 +#define SCSIOP_RELEASE_UNIT 0x17 +#define SCSIOP_COPY 0x18 +#define SCSIOP_ERASE 0x19 +#define SCSIOP_MODE_SENSE 0x1A +#define SCSIOP_START_STOP_UNIT 0x1B +#define SCSIOP_STOP_PRINT 0x1B +#define SCSIOP_LOAD_UNLOAD 0x1B +#define SCSIOP_RECEIVE_DIAGNOSTIC 0x1C +#define SCSIOP_SEND_DIAGNOSTIC 0x1D +#define SCSIOP_MEDIUM_REMOVAL 0x1E +#define SCSIOP_READ_CAPACITY 0x25 +#define SCSIOP_READ 0x28 +#define SCSIOP_WRITE 0x2A +#define SCSIOP_SEEK 0x2B +#define SCSIOP_LOCATE 0x2B +#define SCSIOP_WRITE_VERIFY 0x2E +#define SCSIOP_VERIFY 0x2F +#define SCSIOP_SEARCH_DATA_HIGH 0x30 +#define SCSIOP_SEARCH_DATA_EQUAL 0x31 +#define SCSIOP_SEARCH_DATA_LOW 0x32 +#define SCSIOP_SET_LIMITS 0x33 +#define SCSIOP_READ_POSITION 0x34 +#define SCSIOP_SYNCHRONIZE_CACHE 0x35 +#define SCSIOP_COMPARE 0x39 +#define SCSIOP_COPY_COMPARE 0x3A +#define SCSIOP_WRITE_DATA_BUFF 0x3B +#define SCSIOP_READ_DATA_BUFF 0x3C +#define SCSIOP_CHANGE_DEFINITION 0x40 +#define SCSIOP_READ_SUB_CHANNEL 0x42 +#define SCSIOP_READ_TOC 0x43 +#define SCSIOP_READ_HEADER 0x44 +#define SCSIOP_PLAY_AUDIO 0x45 +#define SCSIOP_PLAY_AUDIO_MSF 0x47 +#define SCSIOP_PLAY_TRACK_INDEX 0x48 +#define SCSIOP_PLAY_TRACK_RELATIVE 0x49 +#define SCSIOP_PAUSE_RESUME 0x4B +#define SCSIOP_LOG_SELECT 0x4C +#define SCSIOP_LOG_SENSE 0x4D +#define SCSIOP_MODE_SELECT10 0x55 +#define SCSIOP_MODE_SENSE10 0x5A +#define SCSIOP_LOAD_UNLOAD_SLOT 0xA6 +#define SCSIOP_MECHANISM_STATUS 0xBD +#define SCSIOP_READ_CD 0xBE + +// IDE command definitions +#define IDE_COMMAND_ATAPI_RESET 0x08 +#define IDE_COMMAND_READ 0x20 +#define IDE_COMMAND_WRITE 0x30 +#define IDE_COMMAND_RECALIBRATE 0x10 +#define IDE_COMMAND_SEEK 0x70 +#define IDE_COMMAND_SET_PARAMETERS 0x91 +#define IDE_COMMAND_VERIFY 0x40 +#define IDE_COMMAND_ATAPI_PACKET 0xA0 +#define IDE_COMMAND_ATAPI_IDENTIFY 0xA1 +#define IDE_CMD_READ_MULTIPLE 0xC4 +#define IDE_CMD_WRITE_MULTIPLE 0xC5 +#define IDE_CMD_SET_MULTIPLE 0xC6 +#define IDE_COMMAND_IDENTIFY 0xEC + +// IDE status definitions +#define IDE_STATUS_ERROR 0x01 +#define IDE_STATUS_INDEX 0x02 +#define IDE_STATUS_CORRECTED_ERROR 0x04 +#define IDE_STATUS_DRQ 0x08 +#define IDE_STATUS_DSC 0x10 +#define IDE_STATUS_WRITE_FAULT 0x20 +#define IDE_STATUS_DRDY 0x40 +#define IDE_STATUS_BUSY 0x80 + +typedef struct _ATAPI_STATUS + { + CHAR check :1; + CHAR reserved1 :1; + CHAR corr :1; + CHAR drq :1; + CHAR dsc :1; + CHAR reserved2 :1; + CHAR drdy :1; + CHAR bsy :1; + } ATAPI_STATUS; + +typedef struct _ATAPI_REASON + { + CHAR cod :1; + CHAR io :1; + CHAR reserved1 :6; + } ATAPI_REASON; + +typedef struct _ATAPI_ERROR + { + CHAR ili :1; + CHAR eom :1; + CHAR abort :1; + CHAR mcr :1; + CHAR senseKey :4; + } ATAPI_ERROR; + +// IDE error definitions +#define IDE_ERROR_AMNF 0x01 +#define IDE_ERROR_TKONF 0x02 +#define IDE_ERROR_ABRT 0x04 +#define IDE_ERROR_MCR 0x08 +#define IDE_ERROR_IDFN 0x10 +#define IDE_ERROR_MC 0x20 +#define IDE_ERROR_UNC 0x40 +#define IDE_ERROR_BBK 0x80 + +// SCSI read capacity structure +typedef struct _READ_CAPACITY_DATA + { + ULONG blks; /* total blocks (converted to little endian) */ + ULONG blksiz; /* size of each (converted to little endian) */ + } READ_CAPACITY_DATA, *PREAD_CAPACITY_DATA; + +// SCSI inquiry data +typedef struct _INQUIRYDATA + { + UCHAR DeviceType :5; + UCHAR DeviceTypeQualifier :3; + UCHAR DeviceTypeModifier :7; + UCHAR RemovableMedia :1; + UCHAR Versions; + UCHAR ResponseDataFormat; + UCHAR AdditionalLength; + UCHAR Reserved[2]; + UCHAR SoftReset :1; + UCHAR CommandQueue :1; + UCHAR Reserved2 :1; + UCHAR LinkedCommands :1; + UCHAR Synchronous :1; + UCHAR Wide16Bit :1; + UCHAR Wide32Bit :1; + UCHAR RelativeAddressing :1; + UCHAR VendorId[8]; + UCHAR ProductId[16]; + UCHAR ProductRevisionLevel[4]; + UCHAR VendorSpecific[20]; + UCHAR Reserved3[40]; + } INQUIRYDATA, *PINQUIRYDATA; + +// IDE IDENTIFY data +#pragma pack (1) +typedef struct _IDENTIFY_DATA + { + USHORT GeneralConfiguration; // 0 + USHORT NumberOfCylinders; // 1 + USHORT Reserved1; // 2 + USHORT NumberOfHeads; // 3 + USHORT UnformattedBytesPerTrack; // 4 + USHORT UnformattedBytesPerSector; // 5 + USHORT SectorsPerTrack; // 6 + USHORT NumBytesISG; // 7 Byte Len - inter-sector gap + USHORT NumBytesSync; // 8 - sync field + USHORT NumWordsVUS; // 9 Len - Vendor Unique Info + USHORT SerialNumber[10]; // 10 + USHORT BufferType; // 20 + USHORT BufferSectorSize; // 21 + USHORT NumberOfEccBytes; // 22 + USHORT FirmwareRevision[4]; // 23 + USHORT ModelNumber[20]; // 27 + USHORT NumSectorsPerInt :8; // 47 Multiple Mode - Sec/Blk + USHORT Reserved2 :8; // 47 + USHORT DoubleWordMode; // 48 flag for double word mode capable + USHORT VendorUnique1 :8; // 49 + USHORT SupportDMA :1; // 49 DMA supported + USHORT SupportLBA :1; // 49 LBA supported + USHORT SupportIORDYDisable :1; // 49 IORDY can be disabled + USHORT SupportIORDY :1; // 49 IORDY supported + USHORT ReservedPsuedoDMA :1; // 49 reserved for pseudo DMA mode support + USHORT Reserved3 :3; // 49 + USHORT Reserved4; // 50 + USHORT Reserved5 :8; // 51 Transfer Cycle Timing - PIO + USHORT PIOCycleTime :8; // 51 Transfer Cycle Timing - PIO + USHORT Reserved6 :8; // 52 - DMA + USHORT DMACycleTime :8; // 52 - DMA + USHORT Valid_54_58 :1; // 53 words 54 - 58 are vaild + USHORT Valid_64_70 :1; // 53 words 64 - 70 are valid + USHORT Reserved7 :14; // 53 + USHORT LogNumCyl; // 54 Current Translation - Num Cyl + USHORT LogNumHeads; // 55 Num Heads + USHORT LogSectorsPerTrack; // 56 Sec/Trk + ULONG LogTotalSectors; // 57 Total Sec + USHORT CurrentNumSecPerInt :8; // 59 current setting for number of sectors per interrupt + USHORT ValidNumSecPerInt :1; // 59 Current setting is valid for number of sectors per interrupt + USHORT Reserved8 :7; // 59 + ULONG LBATotalSectors; // 60 LBA Mode - Sectors + USHORT DMASWordFlags; // 62 + USHORT DMAMWordFlags; // 63 + USHORT AdvancedPIOSupport :8; // 64 Flow control PIO transfer modes supported + USHORT Reserved9 :8; // 64 + USHORT MinMultiDMACycle; // 65 minimum multiword DMA transfer cycle time per word + USHORT RecomendDMACycle; // 66 Manufacturer's recommende multiword DMA transfer cycle time + USHORT MinPIOCycleWithoutFlow; // 67 Minimum PIO transfer cycle time without flow control + USHORT MinPIOCylceWithFlow; // 68 Minimum PIO transfer cycle time with IORDY flow control + USHORT ReservedSpace[256-69]; // 69 + } IDENTIFY_DATA, *PIDENTIFY_DATA; + +// ATAPI configuration bits +typedef struct _ATAPI_GENERAL_0 + { + USHORT CmdPacketSize :2; // Command packet size + USHORT Reserved1 :3; + USHORT CmdDrqType :2; + USHORT Removable :1; + USHORT DeviceType :5; + USHORT Reserved2 :1; + USHORT ProtocolType :2; + } ATAPI_GENERAL_0; + +#pragma pack () diff -u --recursive --new-file v2.3.46/linux/drivers/scsi/qlogicfc.c linux/drivers/scsi/qlogicfc.c --- v2.3.46/linux/drivers/scsi/qlogicfc.c Fri Jan 28 15:09:08 2000 +++ linux/drivers/scsi/qlogicfc.c Thu Feb 17 15:29:50 2000 @@ -64,7 +64,7 @@ /* Configuration section **************************************************** */ /* Set the following macro to 1 to reload the ISP2x00's firmware. This is - version 1.15.37 of the isp2100's firmware and version 2.00.16 of the + version 1.17.30 of the isp2100's firmware and version 2.00.40 of the isp2200's firmware. */ @@ -91,7 +91,7 @@ /* #define TRACE_ISP 1 */ -#define DEFAULT_LOOP_COUNT 10000000 +#define DEFAULT_LOOP_COUNT 1000000000 /* End Configuration section ************************************************ */ @@ -632,6 +632,17 @@ #define QLOGICFC_MAX_LUN 128 #define QLOGICFC_MAX_LOOP_ID 0x7d +/* the following connection options only apply to the 2200. i have only + * had success with LOOP_ONLY and P2P_ONLY. + */ + +#define LOOP_ONLY 0 +#define P2P_ONLY 1 +#define LOOP_PREFERED 2 +#define P2P_PREFERED 3 + +#define CONNECTION_PREFERENCE LOOP_ONLY + /* adapter_state values */ #define AS_FIRMWARE_DEAD -1 #define AS_LOOP_DOWN 0 @@ -762,7 +773,7 @@ hostdata->queued = 0; /* set up the control block */ hostdata->control_block.version = 0x1; - hostdata->control_block.firm_opts = 0x000e; + hostdata->control_block.firm_opts = 0x800e; hostdata->control_block.max_frame_len = 2048; hostdata->control_block.max_iocb = QLOGICFC_REQ_QUEUE_LEN; hostdata->control_block.exec_throttle = QLOGICFC_CMD_PER_LUN; @@ -780,6 +791,8 @@ hostdata->control_block.req_queue_addr_lo = virt_to_bus_low32(hostdata->req); hostdata->control_block.req_queue_addr_high = virt_to_bus_high32(hostdata->req); + + hostdata->control_block.add_firm_opts |= CONNECTION_PREFERENCE<<4; hostdata->adapter_state = AS_LOOP_DOWN; hostdata->explore_timer.data = 1; hostdata->host_id = hosts; diff -u --recursive --new-file v2.3.46/linux/drivers/scsi/qlogicisp.c linux/drivers/scsi/qlogicisp.c --- v2.3.46/linux/drivers/scsi/qlogicisp.c Sun Feb 13 19:29:04 2000 +++ linux/drivers/scsi/qlogicisp.c Fri Feb 18 15:07:20 2000 @@ -810,8 +810,8 @@ sg = (struct scatterlist *) Cmnd->request_buffer; ds = cmd->dataseg; - sg_count = pci_map_sg(hostdata->pci_dev, sg, Cmnd->use_sg); - Cmnd->use_sg = sg_count; + sg_count = pci_map_sg(hostdata->pci_dev, sg, Cmnd->use_sg, + scsi_to_pci_dma_dir(Cmnd->sc_data_direction)); cmd->segment_cnt = cpu_to_le16(sg_count); @@ -853,17 +853,22 @@ } sg_count -= n; } - } else { + } else if (Cmnd->request_bufflen) { Cmnd->SCp.ptr = (char *)(unsigned long) pci_map_single(hostdata->pci_dev, Cmnd->request_buffer, - Cmnd->request_bufflen); + Cmnd->request_bufflen, + scsi_to_pci_dma_dir(Cmnd->sc_data_direction)); cmd->dataseg[0].d_base = cpu_to_le32((u32)(long)Cmnd->SCp.ptr); cmd->dataseg[0].d_count = cpu_to_le32((u32)Cmnd->request_bufflen); cmd->segment_cnt = cpu_to_le16(1); + } else { + cmd->dataseg[0].d_base = 0; + cmd->dataseg[0].d_count = 0; + cmd->segment_cnt = cpu_to_le16(1); /* Shouldn't this be 0? */ } /* Committed, record Scsi_Cmd so we can find it later. */ @@ -974,11 +979,13 @@ if (Cmnd->use_sg) pci_unmap_sg(hostdata->pci_dev, (struct scatterlist *)Cmnd->buffer, - Cmnd->use_sg); - else + Cmnd->use_sg, + scsi_to_pci_dma_dir(Cmnd->sc_data_direction)); + else if (Cmnd->request_bufflen) pci_unmap_single(hostdata->pci_dev, (u32)((long)Cmnd->SCp.ptr), - Cmnd->request_bufflen); + Cmnd->request_bufflen, + scsi_to_pci_dma_dir(Cmnd->sc_data_direction)); isp_outw(out_ptr, host, MBOX5); (*Cmnd->scsi_done)(Cmnd); diff -u --recursive --new-file v2.3.46/linux/drivers/scsi/qlogicpti.c linux/drivers/scsi/qlogicpti.c --- v2.3.46/linux/drivers/scsi/qlogicpti.c Wed Feb 16 17:03:52 2000 +++ linux/drivers/scsi/qlogicpti.c Fri Feb 18 15:07:20 2000 @@ -1036,7 +1036,7 @@ int sg_count; sg = (struct scatterlist *) Cmnd->buffer; - sg_count = sbus_map_sg(qpti->sdev, sg, Cmnd->use_sg); + sg_count = sbus_map_sg(qpti->sdev, sg, Cmnd->use_sg, scsi_to_sbus_dma_dir(Cmnd->sc_data_direction)); ds = cmd->dataseg; cmd->segment_cnt = sg_count; @@ -1078,7 +1078,8 @@ Cmnd->SCp.ptr = (char *)(unsigned long) sbus_map_single(qpti->sdev, Cmnd->request_buffer, - Cmnd->request_bufflen); + Cmnd->request_bufflen, + scsi_to_sbus_dma_dir(Cmnd->sc_data_direction)); cmd->dataseg[0].d_base = (u32) ((unsigned long)Cmnd->SCp.ptr); cmd->dataseg[0].d_count = Cmnd->request_bufflen; @@ -1413,11 +1414,13 @@ if (Cmnd->use_sg) { sbus_unmap_sg(qpti->sdev, (struct scatterlist *)Cmnd->buffer, - Cmnd->use_sg); + Cmnd->use_sg, + scsi_to_sbus_dma_dir(Cmnd->sc_data_direction)); } else { sbus_unmap_single(qpti->sdev, (__u32)((unsigned long)Cmnd->SCp.ptr), - Cmnd->request_bufflen); + Cmnd->request_bufflen, + scsi_to_sbus_dma_dir(Cmnd->sc_data_direction)); } qpti->cmd_count[Cmnd->target]--; sbus_writew(out_ptr, qpti->qregs + MBOX5); diff -u --recursive --new-file v2.3.46/linux/drivers/scsi/scsi.c linux/drivers/scsi/scsi.c --- v2.3.46/linux/drivers/scsi/scsi.c Wed Feb 16 17:03:52 2000 +++ linux/drivers/scsi/scsi.c Fri Feb 18 15:07:20 2000 @@ -224,6 +224,8 @@ { DECLARE_MUTEX_LOCKED(sem); + if (buffer != NULL && SCpnt->sc_data_direction == SCSI_DATA_NONE) + BUG(); SCpnt->request.sem = &sem; SCpnt->request.rq_status = RQ_SCSI_BUSY; scsi_do_cmd (SCpnt, (void *) cmnd, @@ -248,6 +250,73 @@ static spinlock_t scsi_bhqueue_lock = SPIN_LOCK_UNLOCKED; /* + * Function: scsi_allocate_request + * + * Purpose: Allocate a request descriptor. + * + * Arguments: device - device for which we want a request + * + * Lock status: No locks assumed to be held. This function is SMP-safe. + * + * Returns: Pointer to request block. + * + * Notes: With the new queueing code, it becomes important + * to track the difference between a command and a + * request. A request is a pending item in the queue that + * has not yet reached the top of the queue. + */ + +Scsi_Request *scsi_allocate_request(Scsi_Device * device) +{ + Scsi_Request *SRpnt = NULL; + + if (!device) + panic("No device passed to scsi_allocate_request().\n"); + + SRpnt = (Scsi_Request *) kmalloc(sizeof(Scsi_Request), GFP_ATOMIC); + if( SRpnt == NULL ) + { + return NULL; + } + + memset(SRpnt, 0, sizeof(Scsi_Request)); + SRpnt->sr_device = device; + SRpnt->sr_host = device->host; + SRpnt->sr_magic = SCSI_REQ_MAGIC; + SRpnt->sr_data_direction = SCSI_DATA_UNKNOWN; + + return SRpnt; +} + +/* + * Function: scsi_release_request + * + * Purpose: Release a request descriptor. + * + * Arguments: device - device for which we want a request + * + * Lock status: No locks assumed to be held. This function is SMP-safe. + * + * Returns: Pointer to request block. + * + * Notes: With the new queueing code, it becomes important + * to track the difference between a command and a + * request. A request is a pending item in the queue that + * has not yet reached the top of the queue. We still need + * to free a request when we are done with it, of course. + */ +void scsi_release_request(Scsi_Request * req) +{ + if( req->sr_command != NULL ) + { + scsi_release_command(req->sr_command); + req->sr_command = NULL; + } + + kfree(req); +} + +/* * Function: scsi_allocate_device * * Purpose: Allocate a command descriptor. @@ -269,6 +338,9 @@ * command block, this function will interrupt and return * NULL in the event that a signal arrives that needs to * be handled. + * + * This function is deprecated, and drivers should be + * rewritten to use Scsi_Request instead of Scsi_Cmnd. */ Scsi_Cmnd *scsi_allocate_device(Scsi_Device * device, int wait, @@ -417,6 +489,10 @@ SCpnt->transfersize = 0; /* No default transfer size */ SCpnt->cmd_len = 0; + SCpnt->sc_data_direction = SCSI_DATA_UNKNOWN; + SCpnt->sc_request = NULL; + SCpnt->sc_magic = SCSI_CMND_MAGIC; + SCpnt->result = 0; SCpnt->underflow = 0; /* Do not flag underflow conditions */ SCpnt->resid = 0; @@ -451,6 +527,9 @@ * gets hidden in this function. Upper level drivers don't * have any chickens to wave in the air to get things to * work reliably. + * + * This function is deprecated, and drivers should be + * rewritten to use Scsi_Request instead of Scsi_Cmnd. */ void scsi_release_command(Scsi_Cmnd * SCpnt) { @@ -645,6 +724,215 @@ * drivers go for the same host at the same time. */ +void scsi_wait_req (Scsi_Request * SRpnt, const void *cmnd , + void *buffer, unsigned bufflen, + int timeout, int retries) +{ + DECLARE_MUTEX_LOCKED(sem); + + SRpnt->sr_request.sem = &sem; + SRpnt->sr_request.rq_status = RQ_SCSI_BUSY; + scsi_do_req (SRpnt, (void *) cmnd, + buffer, bufflen, scsi_wait_done, timeout, retries); + down (&sem); + SRpnt->sr_request.sem = NULL; + if( SRpnt->sr_command != NULL ) + { + scsi_release_command(SRpnt->sr_command); + SRpnt->sr_command = NULL; + } + +} + +/* + * Function: scsi_do_req + * + * Purpose: Queue a SCSI request + * + * Arguments: SRpnt - command descriptor. + * cmnd - actual SCSI command to be performed. + * buffer - data buffer. + * bufflen - size of data buffer. + * done - completion function to be run. + * timeout - how long to let it run before timeout. + * retries - number of retries we allow. + * + * Lock status: With the new queueing code, this is SMP-safe, and no locks + * need be held upon entry. The old queueing code the lock was + * assumed to be held upon entry. + * + * Returns: Nothing. + * + * Notes: Prior to the new queue code, this function was not SMP-safe. + * Also, this function is now only used for queueing requests + * for things like ioctls and character device requests - this + * is because we essentially just inject a request into the + * queue for the device. Normal block device handling manipulates + * the queue directly. + */ +void scsi_do_req(Scsi_Request * SRpnt, const void *cmnd, + void *buffer, unsigned bufflen, void (*done) (Scsi_Cmnd *), + int timeout, int retries) +{ + Scsi_Device * SDpnt = SRpnt->sr_device; + struct Scsi_Host *host = SDpnt->host; + + ASSERT_LOCK(&io_request_lock, 0); + + SCSI_LOG_MLQUEUE(4, + { + int i; + int target = SDpnt->id; + printk("scsi_do_req (host = %d, channel = %d target = %d, " + "buffer =%p, bufflen = %d, done = %p, timeout = %d, " + "retries = %d)\n" + "command : ", host->host_no, SDpnt->channel, target, buffer, + bufflen, done, timeout, retries); + for (i = 0; i < 10; ++i) + printk("%02x ", ((unsigned char *) cmnd)[i]); + printk("\n"); + }); + + if (!host) { + panic("Invalid or not present host.\n"); + } + + /* + * If the upper level driver is reusing these things, then + * we should release the low-level block now. Another one will + * be allocated later when this request is getting queued. + */ + if( SRpnt->sr_command != NULL ) + { + scsi_release_command(SRpnt->sr_command); + SRpnt->sr_command = NULL; + } + + /* + * We must prevent reentrancy to the lowlevel host driver. This prevents + * it - we enter a loop until the host we want to talk to is not busy. + * Race conditions are prevented, as interrupts are disabled in between the + * time we check for the host being not busy, and the time we mark it busy + * ourselves. + */ + + + /* + * Our own function scsi_done (which marks the host as not busy, disables + * the timeout counter, etc) will be called by us or by the + * scsi_hosts[host].queuecommand() function needs to also call + * the completion function for the high level driver. + */ + + memcpy((void *) SRpnt->sr_cmnd, (const void *) cmnd, + sizeof(SRpnt->sr_cmnd)); + SRpnt->sr_bufflen = bufflen; + SRpnt->sr_buffer = buffer; + SRpnt->sr_allowed = retries; + SRpnt->sr_done = done; + SRpnt->sr_timeout_per_command = timeout; + + memcpy((void *) SRpnt->sr_cmnd, (const void *) cmnd, + sizeof(SRpnt->sr_cmnd)); + + if (SRpnt->sr_cmd_len == 0) + SRpnt->sr_cmd_len = COMMAND_SIZE(SRpnt->sr_cmnd[0]); + + /* + * At this point, we merely set up the command, stick it in the normal + * request queue, and return. Eventually that request will come to the + * top of the list, and will be dispatched. + */ + scsi_insert_special_req(SRpnt, 0); + + SCSI_LOG_MLQUEUE(3, printk("Leaving scsi_do_cmd()\n")); +} + +/* + * Function: scsi_init_cmd_from_req + * + * Purpose: Queue a SCSI command + * Purpose: Initialize a Scsi_Cmnd from a Scsi_Request + * + * Arguments: SCpnt - command descriptor. + * SRpnt - Request from the queue. + * + * Lock status: None needed. + * + * Returns: Nothing. + * + * Notes: Mainly transfer data from the request structure to the + * command structure. The request structure is allocated + * using the normal memory allocator, and requests can pile + * up to more or less any depth. The command structure represents + * a consumable resource, as these are allocated into a pool + * when the SCSI subsystem initializes. The preallocation is + * required so that in low-memory situations a disk I/O request + * won't cause the memory manager to try and write out a page. + * The request structure is generally used by ioctls and character + * devices. + */ +void scsi_init_cmd_from_req(Scsi_Cmnd * SCpnt, Scsi_Request * SRpnt) +{ + struct Scsi_Host *host = SCpnt->host; + + ASSERT_LOCK(&io_request_lock, 0); + + SCpnt->owner = SCSI_OWNER_MIDLEVEL; + SRpnt->sr_command = SCpnt; + + if (!host) { + panic("Invalid or not present host.\n"); + } + + SCpnt->cmd_len = SRpnt->sr_cmd_len; + SCpnt->use_sg = SRpnt->sr_use_sg; + + memcpy((void *) &SCpnt->request, (const void *) &SRpnt->sr_request, + sizeof(SRpnt->sr_request)); + memcpy((void *) SCpnt->data_cmnd, (const void *) SRpnt->sr_cmnd, + sizeof(SCpnt->data_cmnd)); + SCpnt->reset_chain = NULL; + SCpnt->serial_number = 0; + SCpnt->serial_number_at_timeout = 0; + SCpnt->bufflen = SRpnt->sr_bufflen; + SCpnt->buffer = SRpnt->sr_buffer; + SCpnt->flags = 0; + SCpnt->retries = 0; + SCpnt->allowed = SRpnt->sr_allowed; + SCpnt->done = SRpnt->sr_done; + SCpnt->timeout_per_command = SRpnt->sr_timeout_per_command; + + SCpnt->sc_data_direction = SRpnt->sr_data_direction; + + SCpnt->sglist_len = SRpnt->sr_sglist_len; + SCpnt->underflow = SRpnt->sr_underflow; + + SCpnt->sc_request = SRpnt; + + memcpy((void *) SCpnt->cmnd, (const void *) SRpnt->sr_cmnd, + sizeof(SCpnt->cmnd)); + /* Zero the sense buffer. Some host adapters automatically request + * sense on error. 0 is not a valid sense code. + */ + memset((void *) SCpnt->sense_buffer, 0, sizeof SCpnt->sense_buffer); + SCpnt->request_buffer = SRpnt->sr_buffer; + SCpnt->request_bufflen = SRpnt->sr_bufflen; + SCpnt->old_use_sg = SCpnt->use_sg; + if (SCpnt->cmd_len == 0) + SCpnt->cmd_len = COMMAND_SIZE(SCpnt->cmnd[0]); + SCpnt->old_cmd_len = SCpnt->cmd_len; + SCpnt->sc_old_data_direction = SCpnt->sc_data_direction; + + /* Start the timer ticking. */ + + SCpnt->internal_timeout = NORMAL_TIMEOUT; + SCpnt->abort_reason = 0; + SCpnt->result = 0; + + SCSI_LOG_MLQUEUE(3, printk("Leaving scsi_do_cmd()\n")); +} + /* * Function: scsi_do_cmd * @@ -739,6 +1027,7 @@ if (SCpnt->cmd_len == 0) SCpnt->cmd_len = COMMAND_SIZE(SCpnt->cmnd[0]); SCpnt->old_cmd_len = SCpnt->cmd_len; + SCpnt->sc_old_data_direction = SCpnt->sc_data_direction; /* Start the timer ticking. */ @@ -998,6 +1287,7 @@ SCpnt->request_bufflen = SCpnt->bufflen; SCpnt->use_sg = SCpnt->old_use_sg; SCpnt->cmd_len = SCpnt->old_cmd_len; + SCpnt->sc_data_direction = SCpnt->sc_old_data_direction; /* * Zero the sense information from the last time we tried @@ -1019,6 +1309,7 @@ { struct Scsi_Host *host; Scsi_Device *device; + Scsi_Request * SRpnt; unsigned long flags; ASSERT_LOCK(&io_request_lock, 0); @@ -1063,6 +1354,20 @@ /* We can get here with use_sg=0, causing a panic in the upper level (DB) */ SCpnt->use_sg = SCpnt->old_use_sg; + /* + * If there is an associated request structure, copy the data over before we call the + * completion function. + */ + SRpnt = SCpnt->sc_request; + if( SRpnt != NULL ) { + SRpnt->sr_result = SRpnt->sr_command->result; + if( SRpnt->sr_result != 0 ) { + memcpy(SRpnt->sr_sense_buffer, + SRpnt->sr_command->sense_buffer, + sizeof(SRpnt->sr_sense_buffer)); + } + } + SCpnt->done(SCpnt); } @@ -1098,6 +1403,7 @@ kfree((char *) SCpnt); } SDpnt->has_cmdblocks = 0; + SDpnt->queue_depth = 0; spin_unlock_irqrestore(&device_request_lock, flags); } @@ -2187,11 +2493,12 @@ printk("Dump of scsi host parameters:\n"); i = 0; for (shpnt = scsi_hostlist; shpnt; shpnt = shpnt->next) { - printk(" %d %d %d : %d\n", + printk(" %d %d %d : %d %d\n", shpnt->host_failed, shpnt->host_busy, atomic_read(&shpnt->host_active), - shpnt->host_blocked); + shpnt->host_blocked, + shpnt->host_self_blocked); } diff -u --recursive --new-file v2.3.46/linux/drivers/scsi/scsi.h linux/drivers/scsi/scsi.h --- v2.3.46/linux/drivers/scsi/scsi.h Wed Feb 16 17:03:52 2000 +++ linux/drivers/scsi/scsi.h Sun Feb 20 20:49:29 2000 @@ -32,6 +32,54 @@ #include /* + * These are the values that the SCpnt->sc_data_direction and + * SRpnt->sr_data_direction can take. These need to be set + * The SCSI_DATA_UNKNOWN value is essentially the default. + * In the event that the command creator didn't bother to + * set a value, you will see SCSI_DATA_UNKNOWN. + */ +#define SCSI_DATA_UNKNOWN 0 +#define SCSI_DATA_WRITE 1 +#define SCSI_DATA_READ 2 +#define SCSI_DATA_NONE 3 + +#ifdef CONFIG_PCI +#include +#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. */ #ifndef TRUE @@ -304,6 +352,7 @@ #define SUGGEST_MASK 0xf0 #define MAX_COMMAND_SIZE 12 +#define SCSI_SENSE_BUFFERSIZE 64 /* * SCSI command sets @@ -357,6 +406,10 @@ */ typedef struct scsi_device Scsi_Device; typedef struct scsi_cmnd Scsi_Cmnd; +typedef struct scsi_request Scsi_Request; + +#define SCSI_CMND_MAGIC 0xE25C23A5 +#define SCSI_REQ_MAGIC 0x75F6D354 /* * Here is where we prototype most of the mid-layer. @@ -445,10 +498,25 @@ void (*done) (struct scsi_cmnd *), int timeout, int retries); extern void scsi_wait_cmd(Scsi_Cmnd *, const void *cmnd, + void *buffer, unsigned bufflen, + int timeout, int retries); +extern int scsi_dev_init(void); + +/* + * Newer request-based interfaces. + */ +extern Scsi_Request *scsi_allocate_request(Scsi_Device *); +extern void scsi_release_request(Scsi_Request *); +extern void scsi_wait_req(Scsi_Request *, const void *cmnd, void *buffer, unsigned bufflen, int timeout, int retries); -extern int scsi_dev_init(void); +extern void scsi_do_req(Scsi_Request *, const void *cmnd, + void *buffer, unsigned bufflen, + void (*done) (struct scsi_cmnd *), + int timeout, int retries); +extern int scsi_insert_special_req(Scsi_Request * SRpnt, int); +extern void scsi_init_cmd_from_req(Scsi_Cmnd *, Scsi_Request *); /* @@ -467,6 +535,7 @@ */ extern void print_command(unsigned char *); extern void print_sense(const char *, Scsi_Cmnd *); +extern void print_req_sense(const char *, Scsi_Request *); extern void print_driverbyte(int scsiresult); extern void print_hostbyte(int scsiresult); extern void print_status (int status); @@ -570,6 +639,39 @@ volatile int phase; } Scsi_Pointer; +/* + * This is essentially a slimmed down version of Scsi_Cmnd. The point of + * having this is that requests that are injected into the queue as result + * of things like ioctls and character devices shouldn't be using a + * Scsi_Cmnd until such a time that the command is actually at the head + * of the queue and being sent to the driver. + */ +struct scsi_request { + int sr_magic; + int sr_result; /* Status code from lower level driver */ + unsigned char sr_sense_buffer[SCSI_SENSE_BUFFERSIZE]; /* obtained by REQUEST SENSE + * when CHECK CONDITION is + * received on original command + * (auto-sense) */ + + struct Scsi_Host *sr_host; + Scsi_Device *sr_device; + Scsi_Cmnd *sr_command; + struct request sr_request; /* A copy of the command we are + working on */ + unsigned sr_bufflen; /* Size of data buffer */ + void *sr_buffer; /* Data buffer */ + int sr_allowed; + unsigned char sr_data_direction; + unsigned char sr_cmd_len; + unsigned char sr_cmnd[MAX_COMMAND_SIZE]; + void (*sr_done) (struct scsi_cmnd *); /* Mid-level done function */ + int sr_timeout_per_command; + unsigned short sr_use_sg; /* Number of pieces of scatter-gather */ + unsigned short sr_sglist_len; /* size of malloc'd scatter-gather list */ + unsigned sr_underflow; /* Return error if less than + this amount is transfered */ +}; /* * FIXME(eric) - one of the great regrets that I have is that I failed to define @@ -580,6 +682,7 @@ * go back and retrofit at least some of the elements here with with the prefix. */ struct scsi_cmnd { + int sc_magic; /* private: */ /* * This information is private to the scsi mid-layer. Wrapping it in a @@ -589,6 +692,7 @@ unsigned short state; unsigned short owner; Scsi_Device *device; + Scsi_Request *sc_request; struct scsi_cmnd *next; struct scsi_cmnd *reset_chain; @@ -632,6 +736,8 @@ unsigned char channel; unsigned char cmd_len; unsigned char old_cmd_len; + unsigned char sc_data_direction; + unsigned char sc_old_data_direction; /* These elements define the operation we are about to perform */ unsigned char cmnd[MAX_COMMAND_SIZE]; @@ -667,7 +773,7 @@ struct request request; /* A copy of the command we are working on */ - unsigned char sense_buffer[64]; /* obtained by REQUEST SENSE + unsigned char sense_buffer[SCSI_SENSE_BUFFERSIZE]; /* obtained by REQUEST SENSE * when CHECK CONDITION is * received on original command * (auto-sense) */ diff -u --recursive --new-file v2.3.46/linux/drivers/scsi/scsi_error.c linux/drivers/scsi/scsi_error.c --- v2.3.46/linux/drivers/scsi/scsi_error.c Thu Feb 10 17:11:13 2000 +++ linux/drivers/scsi/scsi_error.c Wed Feb 16 20:21:45 2000 @@ -408,6 +408,7 @@ SCpnt->request_bufflen = SCpnt->bufflen; SCpnt->use_sg = SCpnt->old_use_sg; SCpnt->cmd_len = SCpnt->old_cmd_len; + SCpnt->sc_data_direction = SCpnt->sc_old_data_direction; scsi_send_eh_cmnd(SCpnt, SCpnt->timeout_per_command); @@ -464,6 +465,7 @@ SCpnt->request_bufflen = 256; SCpnt->use_sg = 0; SCpnt->cmd_len = COMMAND_SIZE(SCpnt->cmnd[0]); + SCpnt->sc_data_direction = SCSI_DATA_READ; scsi_send_eh_cmnd(SCpnt, SENSE_TIMEOUT); @@ -486,6 +488,7 @@ SCpnt->request_bufflen = SCpnt->bufflen; SCpnt->use_sg = SCpnt->old_use_sg; SCpnt->cmd_len = SCpnt->old_cmd_len; + SCpnt->sc_data_direction = SCpnt->sc_old_data_direction; /* * Hey, we are done. Let's look to see what happened. @@ -531,6 +534,7 @@ SCpnt->use_sg = 0; SCpnt->cmd_len = COMMAND_SIZE(SCpnt->cmnd[0]); scsi_send_eh_cmnd(SCpnt, SENSE_TIMEOUT); + SCpnt->sc_data_direction = SCSI_DATA_NONE; /* Last chance to have valid sense data */ if (!scsi_sense_valid(SCpnt)) @@ -551,6 +555,7 @@ SCpnt->request_bufflen = SCpnt->bufflen; SCpnt->use_sg = SCpnt->old_use_sg; SCpnt->cmd_len = SCpnt->old_cmd_len; + SCpnt->sc_data_direction = SCpnt->sc_old_data_direction; /* * Hey, we are done. Let's look to see what happened. @@ -730,6 +735,7 @@ * things. */ SCpnt->use_sg = SCpnt->old_use_sg; + SCpnt->sc_data_direction = SCpnt->sc_old_data_direction; *SClist = SCpnt; } @@ -1245,6 +1251,7 @@ request_queue_t *q; if ((host->can_queue > 0 && (host->host_busy >= host->can_queue)) || (host->host_blocked) + || (host->host_self_blocked) || (SDpnt->device_blocked)) { break; } diff -u --recursive --new-file v2.3.46/linux/drivers/scsi/scsi_ioctl.c linux/drivers/scsi/scsi_ioctl.c --- v2.3.46/linux/drivers/scsi/scsi_ioctl.c Thu Feb 10 17:11:13 2000 +++ linux/drivers/scsi/scsi_ioctl.c Wed Feb 16 20:21:45 2000 @@ -105,6 +105,7 @@ return -EINTR; } + SCpnt->sc_data_direction = SCSI_DATA_NONE; scsi_wait_cmd(SCpnt, cmd, NULL, 0, timeout, retries); SCSI_LOG_IOCTL(2, printk("Ioctl returned 0x%x\n", SCpnt->result)); @@ -197,6 +198,7 @@ int inlen, outlen, cmdlen; int needed, buf_needed; int timeout, retries, result; + int data_direction; if (!sic) return -EINVAL; @@ -232,8 +234,21 @@ if (!buf) return -ENOMEM; memset(buf, 0, buf_needed); - } else + if( inlen == 0 ) { + data_direction = SCSI_DATA_WRITE; + } else if (outlen == 0 ) { + data_direction = SCSI_DATA_READ; + } else { + /* + * Can this ever happen? + */ + data_direction = SCSI_DATA_UNKNOWN; + } + + } else { buf = NULL; + data_direction = SCSI_DATA_NONE; + } /* * Obtain the command from the user's address space. @@ -288,6 +303,7 @@ return -EINTR; } + SCpnt->sc_data_direction = data_direction; scsi_wait_cmd(SCpnt, cmd, buf, needed, timeout, retries); /* diff -u --recursive --new-file v2.3.46/linux/drivers/scsi/scsi_lib.c linux/drivers/scsi/scsi_lib.c --- v2.3.46/linux/drivers/scsi/scsi_lib.c Wed Feb 16 17:03:52 2000 +++ linux/drivers/scsi/scsi_lib.c Thu Feb 17 11:39:28 2000 @@ -121,6 +121,74 @@ } /* + * Function: scsi_insert_special_req() + * + * Purpose: Insert pre-formed request into request queue. + * + * Arguments: SRpnt - request that is ready to be queued. + * at_head - boolean. True if we should insert at head + * of queue, false if we should insert at tail. + * + * Lock status: Assumed that lock is not held upon entry. + * + * Returns: Nothing + * + * Notes: This function is called from character device and from + * ioctl types of functions where the caller knows exactly + * what SCSI command needs to be issued. The idea is that + * we merely inject the command into the queue (at the head + * for now), and then call the queue request function to actually + * process it. + */ +int scsi_insert_special_req(Scsi_Request * SRpnt, int at_head) +{ + unsigned long flags; + request_queue_t *q; + + ASSERT_LOCK(&io_request_lock, 0); + + /* + * The SCpnt already contains a request structure - we will doctor the + * thing up with the appropriate values and use that in the actual + * request queue. + */ + q = &SRpnt->sr_device->request_queue; + SRpnt->sr_request.cmd = SPECIAL; + SRpnt->sr_request.special = (void *) SRpnt; + + /* + * We have the option of inserting the head or the tail of the queue. + * Typically we use the tail for new ioctls and so forth. We use the + * head of the queue for things like a QUEUE_FULL message from a + * device, or a host that is unable to accept a particular command. + */ + spin_lock_irqsave(&io_request_lock, flags); + + if (at_head) { + list_add(&SRpnt->sr_request.queue, &q->queue_head); + } else { + /* + * FIXME(eric) - we always insert at the tail of the + * list. Otherwise ioctl commands would always take + * precedence over normal I/O. An ioctl on a busy + * disk might be delayed indefinitely because the + * request might not float high enough in the queue + * to be scheduled. + */ + list_add_tail(&SRpnt->sr_request.queue, &q->queue_head); + } + + /* + * Now hit the requeue function for the queue. If the host is + * already busy, so be it - we have nothing special to do. If + * the host can queue it, then send it off. + */ + q->request_fn(q); + spin_unlock_irqrestore(&io_request_lock, flags); + return 0; +} + +/* * Function: scsi_init_cmd_errh() * * Purpose: Initialize SCpnt fields related to error handling. @@ -160,6 +228,7 @@ */ SCpnt->old_use_sg = SCpnt->use_sg; SCpnt->old_cmd_len = SCpnt->cmd_len; + SCpnt->sc_old_data_direction = SCpnt->sc_data_direction; memcpy((void *) SCpnt->data_cmnd, (const void *) SCpnt->cmnd, sizeof(SCpnt->cmnd)); SCpnt->buffer = SCpnt->request_buffer; @@ -257,6 +326,7 @@ if (((SHpnt->can_queue > 0) && (SHpnt->host_busy >= SHpnt->can_queue)) || (SHpnt->host_blocked) + || (SHpnt->host_self_blocked) || (SDpnt->device_blocked)) { break; } @@ -278,7 +348,8 @@ for (SDpnt = SHpnt->host_queue; SDpnt; SDpnt = SDpnt->next) { request_queue_t *q; if ((SHpnt->can_queue > 0 && (SHpnt->host_busy >= SHpnt->can_queue)) - || (SHpnt->host_blocked)) { + || (SHpnt->host_blocked) + || (SHpnt->host_self_blocked)) { break; } if (SDpnt->device_blocked || !SDpnt->starved) { @@ -759,6 +830,7 @@ { struct request *req; Scsi_Cmnd *SCpnt; + Scsi_Request *SRpnt; Scsi_Device *SDpnt; struct Scsi_Host *SHpnt; struct Scsi_Device_Template *STpnt; @@ -789,13 +861,24 @@ */ while (1 == 1) { /* + * Check this again - each time we loop through we will have + * released the lock and grabbed it again, so each time + * we need to check to see if the queue is plugged or not. + */ + if (SHpnt->in_recovery + || q->plugged) { + return; + } + + /* * If the device cannot accept another request, then quit. */ if (SDpnt->device_blocked) { break; } if ((SHpnt->can_queue > 0 && (SHpnt->host_busy >= SHpnt->can_queue)) - || (SHpnt->host_blocked)) { + || (SHpnt->host_blocked) + || (SHpnt->host_self_blocked)) { /* * If we are unable to process any commands at all for this * device, then we consider it to be starved. What this means @@ -862,6 +945,14 @@ if (req->cmd == SPECIAL) { STpnt = NULL; SCpnt = (Scsi_Cmnd *) req->special; + SRpnt = (Scsi_Request *) req->special; + + if( SRpnt->sr_magic == SCSI_REQ_MAGIC ) { + SCpnt = scsi_allocate_device(SRpnt->sr_device, + FALSE, FALSE); + scsi_init_cmd_from_req(SCpnt, SRpnt); + } + } else { STpnt = scsi_get_request_dev(req); if (!STpnt) { @@ -986,6 +1077,85 @@ * the request queue and try to find another command. */ spin_lock_irq(&io_request_lock); + } +} + +/* + * Function: scsi_block_requests() + * + * Purpose: Utility function used by low-level drivers to prevent further + * commands from being queued to the device. + * + * Arguments: SHpnt - Host in question + * + * Returns: Nothing + * + * Lock status: No locks are assumed held. + * + * Notes: There is no timer nor any other means by which the requests + * get unblocked other than the low-level driver calling + * scsi_unblock_requests(). + */ +void scsi_block_requests(struct Scsi_Host * SHpnt) +{ + SHpnt->host_self_blocked = TRUE; +} + +/* + * Function: scsi_unblock_requests() + * + * Purpose: Utility function used by low-level drivers to allow further + * commands from being queued to the device. + * + * Arguments: SHpnt - Host in question + * + * Returns: Nothing + * + * Lock status: No locks are assumed held. + * + * Notes: There is no timer nor any other means by which the requests + * get unblocked other than the low-level driver calling + * scsi_unblock_requests(). + * + * This is done as an API function so that changes to the + * internals of the scsi mid-layer won't require wholesale + * changes to drivers that use this feature. + */ +void scsi_unblock_requests(struct Scsi_Host * SHpnt) +{ + SHpnt->host_self_blocked = FALSE; +} + + +/* + * Function: scsi_report_bus_reset() + * + * Purpose: Utility function used by low-level drivers to report that + * they have observed a bus reset on the bus being handled. + * + * Arguments: SHpnt - Host in question + * channel - channel on which reset was observed. + * + * Returns: Nothing + * + * Lock status: No locks are assumed held. + * + * Notes: This only needs to be called if the reset is one which + * originates from an unknown location. Resets originated + * by the mid-level itself don't need to call this, but there + * should be no harm. + * + * The main purpose of this is to make sure that a CHECK_CONDITION + * is properly treated. + */ +void scsi_report_bus_reset(struct Scsi_Host * SHpnt, int channel) +{ + Scsi_Device *SDloop; + for (SDloop = SHpnt->host_queue; SDloop; SDloop = SDloop->next) { + if (channel == SDloop->channel) { + SDloop->was_reset = 1; + SDloop->expecting_cc_ua = 1; + } } } diff -u --recursive --new-file v2.3.46/linux/drivers/scsi/scsi_obsolete.c linux/drivers/scsi/scsi_obsolete.c --- v2.3.46/linux/drivers/scsi/scsi_obsolete.c Fri Jan 28 15:09:08 2000 +++ linux/drivers/scsi/scsi_obsolete.c Fri Feb 18 15:07:20 2000 @@ -231,6 +231,8 @@ SCpnt->use_sg = 0; SCpnt->cmd_len = COMMAND_SIZE(SCpnt->cmnd[0]); SCpnt->result = 0; + SCpnt->sc_data_direction = SCSI_DATA_READ; + /* * Ugly, ugly. The newer interfaces all assume that the lock * isn't held. Mustn't disappoint, or we deadlock the system. @@ -374,6 +376,7 @@ if (SCpnt->flags & WAS_SENSE) { SCpnt->use_sg = SCpnt->old_use_sg; SCpnt->cmd_len = SCpnt->old_cmd_len; + SCpnt->sc_data_direction = SCpnt->sc_old_data_direction; } switch (host_byte(result)) { case DID_OK: @@ -633,6 +636,7 @@ SCpnt->request_bufflen = SCpnt->bufflen; SCpnt->use_sg = SCpnt->old_use_sg; SCpnt->cmd_len = SCpnt->old_cmd_len; + SCpnt->sc_data_direction = SCpnt->sc_old_data_direction; SCpnt->result = 0; /* * Ugly, ugly. The newer interfaces all @@ -649,6 +653,7 @@ } if (status == CMD_FINISHED) { + Scsi_Request *SRpnt; #ifdef DEBUG printk("Calling done function - at address %p\n", SCpnt->done); #endif @@ -658,6 +663,7 @@ SCpnt->result = result | ((exit & 0xff) << 24); SCpnt->use_sg = SCpnt->old_use_sg; SCpnt->cmd_len = SCpnt->old_cmd_len; + SCpnt->sc_data_direction = SCpnt->sc_old_data_direction; /* * The upper layers assume the lock isn't held. We mustn't * disappoint them. When the new error handling code is in @@ -665,6 +671,16 @@ * it isn't an issue. */ spin_unlock_irq(&io_request_lock); + SRpnt = SCpnt->sc_request; + if( SRpnt != NULL ) { + SRpnt->sr_result = SRpnt->sr_command->result; + if( SRpnt->sr_result != 0 ) { + memcpy(SRpnt->sr_sense_buffer, + SRpnt->sr_command->sense_buffer, + sizeof(SRpnt->sr_sense_buffer)); + } + } + SCpnt->done(SCpnt); spin_lock_irq(&io_request_lock); } diff -u --recursive --new-file v2.3.46/linux/drivers/scsi/scsi_scan.c linux/drivers/scsi/scsi_scan.c --- v2.3.46/linux/drivers/scsi/scsi_scan.c Wed Feb 16 17:03:52 2000 +++ linux/drivers/scsi/scsi_scan.c Fri Feb 18 15:07:20 2000 @@ -502,6 +502,7 @@ SCpnt->target = SDpnt->id; SCpnt->lun = SDpnt->lun; SCpnt->channel = SDpnt->channel; + SCpnt->sc_data_direction = SCSI_DATA_NONE; scsi_wait_cmd (SCpnt, (void *) scsi_cmd, (void *) NULL, @@ -539,6 +540,7 @@ scsi_cmd[4] = 255; scsi_cmd[5] = 0; SCpnt->cmd_len = 0; + SCpnt->sc_data_direction = SCSI_DATA_READ; scsi_wait_cmd (SCpnt, (void *) scsi_cmd, (void *) scsi_result, @@ -703,6 +705,7 @@ scsi_cmd[4] = 0x2a; scsi_cmd[5] = 0; SCpnt->cmd_len = 0; + SCpnt->sc_data_direction = SCSI_DATA_READ; scsi_wait_cmd (SCpnt, (void *) scsi_cmd, (void *) scsi_result, 0x2a, SCSI_TIMEOUT, 3); diff -u --recursive --new-file v2.3.46/linux/drivers/scsi/scsi_syms.c linux/drivers/scsi/scsi_syms.c --- v2.3.46/linux/drivers/scsi/scsi_syms.c Thu Feb 10 17:11:13 2000 +++ linux/drivers/scsi/scsi_syms.c Wed Feb 16 20:21:45 2000 @@ -28,16 +28,11 @@ #include "sd.h" #include + /* * This source file contains the symbol table used by scsi loadable * modules. */ - -extern void print_command(unsigned char *command); -extern void print_sense(const char *devclass, Scsi_Cmnd * SCpnt); - -extern const char *const scsi_device_types[]; - EXPORT_SYMBOL(scsi_register_module); EXPORT_SYMBOL(scsi_unregister_module); EXPORT_SYMBOL(scsi_free); @@ -53,6 +48,7 @@ EXPORT_SYMBOL(scsi_ioctl); EXPORT_SYMBOL(print_command); EXPORT_SYMBOL(print_sense); +EXPORT_SYMBOL(print_req_sense); EXPORT_SYMBOL(print_msg); EXPORT_SYMBOL(print_status); EXPORT_SYMBOL(scsi_dma_free_sectors); @@ -66,6 +62,15 @@ #if defined(CONFIG_SCSI_LOGGING) /* { */ EXPORT_SYMBOL(scsi_logging_level); #endif + +EXPORT_SYMBOL(scsi_allocate_request); +EXPORT_SYMBOL(scsi_release_request); +EXPORT_SYMBOL(scsi_wait_req); +EXPORT_SYMBOL(scsi_do_req); + +EXPORT_SYMBOL(scsi_report_bus_reset); +EXPORT_SYMBOL(scsi_block_requests); +EXPORT_SYMBOL(scsi_unblock_requests); EXPORT_SYMBOL(scsi_get_host_dev); EXPORT_SYMBOL(scsi_free_host_dev); diff -u --recursive --new-file v2.3.46/linux/drivers/scsi/sd.c linux/drivers/scsi/sd.c --- v2.3.46/linux/drivers/scsi/sd.c Wed Feb 16 17:03:52 2000 +++ linux/drivers/scsi/sd.c Fri Feb 18 15:07:20 2000 @@ -309,9 +309,11 @@ return 0; } SCpnt->cmnd[0] = WRITE_6; + SCpnt->sc_data_direction = SCSI_DATA_WRITE; break; case READ: SCpnt->cmnd[0] = READ_6; + SCpnt->sc_data_direction = SCSI_DATA_READ; break; default: panic("Unknown sd command %d\n", SCpnt->request.cmd); @@ -695,6 +697,7 @@ SCpnt->cmd_len = 0; SCpnt->sense_buffer[0] = 0; SCpnt->sense_buffer[2] = 0; + SCpnt->sc_data_direction = SCSI_DATA_READ; scsi_wait_cmd (SCpnt, (void *) cmd, (void *) buffer, 0/*512*/, SD_TIMEOUT, MAX_RETRIES); @@ -706,6 +709,22 @@ break; } + /* + * If the drive has indicated to us that it doesn't have + * any media in it, don't bother with any of the rest of + * this crap. + */ + if( the_result != 0 + && ((driver_byte(the_result) & DRIVER_SENSE) != 0) + && SCpnt->sense_buffer[2] == UNIT_ATTENTION + && SCpnt->sense_buffer[12] == 0x3A ) { + rscsi_disks[i].capacity = 0x1fffff; + sector_size = 512; + rscsi_disks[i].device->changed = 1; + rscsi_disks[i].ready = 0; + break; + } + /* Look for non-removable devices that return NOT_READY. * Issue command to spin up drive for these cases. */ if (the_result && !rscsi_disks[i].device->removable && @@ -722,6 +741,7 @@ SCpnt->sense_buffer[0] = 0; SCpnt->sense_buffer[2] = 0; + SCpnt->sc_data_direction = SCSI_DATA_READ; scsi_wait_cmd(SCpnt, (void *) cmd, (void *) buffer, 0/*512*/, SD_TIMEOUT, MAX_RETRIES); } @@ -752,6 +772,7 @@ SCpnt->sense_buffer[0] = 0; SCpnt->sense_buffer[2] = 0; + SCpnt->sc_data_direction = SCSI_DATA_READ; scsi_wait_cmd(SCpnt, (void *) cmd, (void *) buffer, 8, SD_TIMEOUT, MAX_RETRIES); @@ -903,6 +924,7 @@ SCpnt->sense_buffer[2] = 0; /* same code as READCAPA !! */ + SCpnt->sc_data_direction = SCSI_DATA_READ; scsi_wait_cmd(SCpnt, (void *) cmd, (void *) buffer, 512, SD_TIMEOUT, MAX_RETRIES); diff -u --recursive --new-file v2.3.46/linux/drivers/scsi/sr.c linux/drivers/scsi/sr.c --- v2.3.46/linux/drivers/scsi/sr.c Wed Feb 16 17:03:52 2000 +++ linux/drivers/scsi/sr.c Wed Feb 16 20:21:45 2000 @@ -89,7 +89,6 @@ void get_sectorsize(int); void get_capabilities(int); -void requeue_sr_request(Scsi_Cmnd * SCpnt); static int sr_media_change(struct cdrom_device_info *, int); static int sr_packet(struct cdrom_device_info *, struct cdrom_generic_command *); @@ -327,9 +326,11 @@ return 0; } SCpnt->cmnd[0] = WRITE_10; + SCpnt->sc_data_direction = SCSI_DATA_WRITE; break; case READ: SCpnt->cmnd[0] = READ_10; + SCpnt->sc_data_direction = SCSI_DATA_READ; break; default: panic("Unknown sr command %d\n", SCpnt->request.cmd); @@ -464,36 +465,37 @@ unsigned char *buffer; int the_result, retries; int sector_size; - Scsi_Cmnd *SCpnt; + Scsi_Request *SRpnt; buffer = (unsigned char *) scsi_malloc(512); - SCpnt = scsi_allocate_device(scsi_CDs[i].device, 1, FALSE); + SRpnt = scsi_allocate_request(scsi_CDs[i].device); retries = 3; do { cmd[0] = READ_CAPACITY; cmd[1] = (scsi_CDs[i].device->lun << 5) & 0xe0; memset((void *) &cmd[2], 0, 8); - SCpnt->request.rq_status = RQ_SCSI_BUSY; /* Mark as really busy */ - SCpnt->cmd_len = 0; + SRpnt->sr_request.rq_status = RQ_SCSI_BUSY; /* Mark as really busy */ + SRpnt->sr_cmd_len = 0; memset(buffer, 0, 8); /* Do the command and wait.. */ - scsi_wait_cmd(SCpnt, (void *) cmd, (void *) buffer, + SRpnt->sr_data_direction = SCSI_DATA_READ; + scsi_wait_req(SRpnt, (void *) cmd, (void *) buffer, 512, SR_TIMEOUT, MAX_RETRIES); - the_result = SCpnt->result; + the_result = SRpnt->sr_result; retries--; } while (the_result && retries); - scsi_release_command(SCpnt); - SCpnt = NULL; + scsi_release_request(SRpnt); + SRpnt = NULL; if (the_result) { scsi_CDs[i].capacity = 0x1fffff; @@ -570,7 +572,7 @@ cmd[2] = 0x2a; cmd[4] = 128; cmd[3] = cmd[5] = 0; - rc = sr_do_ioctl(i, cmd, buffer, 128, 1); + rc = sr_do_ioctl(i, cmd, buffer, 128, 1, SCSI_DATA_READ); if (-EINVAL == rc) { /* failed, drive has'nt this mode page */ @@ -635,19 +637,19 @@ */ static int sr_packet(struct cdrom_device_info *cdi, struct cdrom_generic_command *cgc) { - Scsi_Cmnd *SCpnt; + Scsi_Request *SRpnt; Scsi_Device *device = scsi_CDs[MINOR(cdi->dev)].device; unsigned char *buffer = cgc->buffer; int buflen; /* get the device */ - SCpnt = scsi_allocate_device(device, 1, FALSE); - if (SCpnt == NULL) + SRpnt = scsi_allocate_request(device); + if (SRpnt == NULL) return -ENODEV; /* this just doesn't seem right /axboe */ /* use buffer for ISA DMA */ buflen = (cgc->buflen + 511) & ~511; - if (cgc->buffer && SCpnt->host->unchecked_isa_dma && + if (cgc->buffer && SRpnt->sr_host->unchecked_isa_dma && (virt_to_phys(cgc->buffer) + cgc->buflen - 1 > ISA_DMA_THRESHOLD)) { buffer = scsi_malloc(buflen); if (buffer == NULL) { @@ -660,20 +662,25 @@ cgc->cmd[1] |= device->lun << 5; /* do the locking and issue the command */ - SCpnt->request.rq_dev = cdi->dev; + SRpnt->sr_request.rq_dev = cdi->dev; /* scsi_wait_cmd sets the command length */ - SCpnt->cmd_len = 0; + SRpnt->sr_cmd_len = 0; - scsi_wait_cmd(SCpnt, (void *) cgc->cmd, (void *) buffer, cgc->buflen, + /* + * FIXME(eric) - need to set the data direction here. + */ + SRpnt->sr_data_direction = SCSI_DATA_UNKNOWN; + + scsi_wait_req(SRpnt, (void *) cgc->cmd, (void *) buffer, cgc->buflen, SR_TIMEOUT, MAX_RETRIES); - if ((cgc->stat = SCpnt->result)) - cgc->sense = (struct request_sense *) SCpnt->sense_buffer; + if ((cgc->stat = SRpnt->sr_result)) + cgc->sense = (struct request_sense *) SRpnt->sr_sense_buffer; /* release */ - SCpnt->request.rq_dev = MKDEV(0, 0); - scsi_release_command(SCpnt); - SCpnt = NULL; + SRpnt->sr_request.rq_dev = MKDEV(0, 0); + scsi_release_request(SRpnt); + SRpnt = NULL; /* write DMA buffer back if used */ if (buffer && (buffer != cgc->buffer)) { diff -u --recursive --new-file v2.3.46/linux/drivers/scsi/sr.h linux/drivers/scsi/sr.h --- v2.3.46/linux/drivers/scsi/sr.h Tue Dec 14 01:27:24 1999 +++ linux/drivers/scsi/sr.h Wed Feb 16 20:21:45 2000 @@ -36,7 +36,7 @@ extern Scsi_CD *scsi_CDs; -int sr_do_ioctl(int, unsigned char *, void *, unsigned, int); +int sr_do_ioctl(int, unsigned char *, void *, unsigned, int, int); int sr_lock_door(struct cdrom_device_info *, int); int sr_tray_move(struct cdrom_device_info *, int); diff -u --recursive --new-file v2.3.46/linux/drivers/scsi/sr_ioctl.c linux/drivers/scsi/sr_ioctl.c --- v2.3.46/linux/drivers/scsi/sr_ioctl.c Fri Jan 28 15:09:08 2000 +++ linux/drivers/scsi/sr_ioctl.c Wed Feb 16 20:21:45 2000 @@ -34,20 +34,21 @@ error code is. Normally the UNIT_ATTENTION code will automatically clear after one error */ -int sr_do_ioctl(int target, unsigned char *sr_cmd, void *buffer, unsigned buflength, int quiet) +int sr_do_ioctl(int target, unsigned char *sr_cmd, void *buffer, unsigned buflength, int quiet, int readwrite) { - Scsi_Cmnd *SCpnt; + Scsi_Request *SRpnt; Scsi_Device *SDev; struct request *req; int result, err = 0, retries = 0; char *bounce_buffer; SDev = scsi_CDs[target].device; - SCpnt = scsi_allocate_device(scsi_CDs[target].device, 1, FALSE); + SRpnt = scsi_allocate_request(scsi_CDs[target].device); + SRpnt->sr_data_direction = readwrite; /* use ISA DMA buffer if necessary */ - SCpnt->request.buffer = buffer; - if (buffer && SCpnt->host->unchecked_isa_dma && + SRpnt->sr_request.buffer = buffer; + if (buffer && SRpnt->sr_host->unchecked_isa_dma && (virt_to_phys(buffer) + buflength - 1 > ISA_DMA_THRESHOLD)) { bounce_buffer = (char *) scsi_malloc((buflength + 511) & ~511); if (bounce_buffer == NULL) { @@ -62,21 +63,21 @@ return -ENODEV; - scsi_wait_cmd(SCpnt, (void *) sr_cmd, (void *) buffer, buflength, + scsi_wait_req(SRpnt, (void *) sr_cmd, (void *) buffer, buflength, IOCTL_TIMEOUT, IOCTL_RETRIES); - req = &SCpnt->request; - if (SCpnt->buffer && req->buffer && SCpnt->buffer != req->buffer) { - memcpy(req->buffer, SCpnt->buffer, SCpnt->bufflen); - scsi_free(SCpnt->buffer, (SCpnt->bufflen + 511) & ~511); - SCpnt->buffer = req->buffer; + req = &SRpnt->sr_request; + if (SRpnt->sr_buffer && req->buffer && SRpnt->sr_buffer != req->buffer) { + memcpy(req->buffer, SRpnt->sr_buffer, SRpnt->sr_bufflen); + scsi_free(SRpnt->sr_buffer, (SRpnt->sr_bufflen + 511) & ~511); + SRpnt->sr_buffer = req->buffer; } - result = SCpnt->result; + result = SRpnt->sr_result; /* Minimal error checking. Ignore cases we know about, and report the rest. */ if (driver_byte(result) != 0) { - switch (SCpnt->sense_buffer[2] & 0xf) { + switch (SRpnt->sr_sense_buffer[2] & 0xf) { case UNIT_ATTENTION: scsi_CDs[target].device->changed = 1; if (!quiet) @@ -86,8 +87,8 @@ err = -ENOMEDIUM; break; case NOT_READY: /* This happens if there is no disc in drive */ - if (SCpnt->sense_buffer[12] == 0x04 && - SCpnt->sense_buffer[13] == 0x01) { + if (SRpnt->sr_sense_buffer[12] == 0x04 && + SRpnt->sr_sense_buffer[13] == 0x01) { /* sense: Logical unit is in process of becoming ready */ if (!quiet) printk(KERN_INFO "sr%d: CDROM not ready yet.\n", target); @@ -104,7 +105,7 @@ if (!quiet) printk(KERN_INFO "sr%d: CDROM not ready. Make sure there is a disc in the drive.\n", target); #ifdef DEBUG - print_sense("sr", SCpnt); + print_req_sense("sr", SRpnt); #endif err = -ENOMEDIUM; break; @@ -112,8 +113,8 @@ if (!quiet) printk(KERN_ERR "sr%d: CDROM (ioctl) reports ILLEGAL " "REQUEST.\n", target); - if (SCpnt->sense_buffer[12] == 0x20 && - SCpnt->sense_buffer[13] == 0x00) { + if (SRpnt->sr_sense_buffer[12] == 0x20 && + SRpnt->sr_sense_buffer[13] == 0x00) { /* sense: Invalid command operation code */ err = -EDRIVE_CANT_DO_THIS; } else { @@ -121,20 +122,20 @@ } #ifdef DEBUG print_command(sr_cmd); - print_sense("sr", SCpnt); + print_req_sense("sr", SRpnt); #endif break; default: printk(KERN_ERR "sr%d: CDROM (ioctl) error, command: ", target); print_command(sr_cmd); - print_sense("sr", SCpnt); + print_req_sense("sr", SRpnt); err = -EIO; } } - result = SCpnt->result; + result = SRpnt->sr_result; /* Wake up a process waiting for device */ - scsi_release_command(SCpnt); - SCpnt = NULL; + scsi_release_request(SRpnt); + SRpnt = NULL; return err; } @@ -148,7 +149,7 @@ sr_cmd[0] = GPCMD_TEST_UNIT_READY; sr_cmd[1] = ((scsi_CDs[minor].device->lun) << 5); sr_cmd[2] = sr_cmd[3] = sr_cmd[4] = sr_cmd[5] = 0; - return sr_do_ioctl(minor, sr_cmd, NULL, 255, 1); + return sr_do_ioctl(minor, sr_cmd, NULL, 255, 1, SCSI_DATA_NONE); } int sr_tray_move(struct cdrom_device_info *cdi, int pos) @@ -160,7 +161,7 @@ sr_cmd[2] = sr_cmd[3] = sr_cmd[5] = 0; sr_cmd[4] = (pos == 0) ? 0x03 /* close */ : 0x02 /* eject */ ; - return sr_do_ioctl(MINOR(cdi->dev), sr_cmd, NULL, 255, 0); + return sr_do_ioctl(MINOR(cdi->dev), sr_cmd, NULL, 255, 0, SCSI_DATA_NONE); } int sr_lock_door(struct cdrom_device_info *cdi, int lock) @@ -237,7 +238,7 @@ sr_cmd[8] = 24; sr_cmd[9] = 0; - result = sr_do_ioctl(MINOR(cdi->dev), sr_cmd, buffer, 24, 0); + result = sr_do_ioctl(MINOR(cdi->dev), sr_cmd, buffer, 24, 0, SCSI_DATA_READ); memcpy(mcn->medium_catalog_number, buffer + 9, 13); mcn->medium_catalog_number[13] = 0; @@ -266,7 +267,7 @@ sr_cmd[2] = (speed >> 8) & 0xff; /* MSB for speed (in kbytes/sec) */ sr_cmd[3] = speed & 0xff; /* LSB */ - if (sr_do_ioctl(MINOR(cdi->dev), sr_cmd, NULL, 0, 0)) + if (sr_do_ioctl(MINOR(cdi->dev), sr_cmd, NULL, 0, 0, SCSI_DATA_NONE)) return -EIO; return 0; } @@ -296,7 +297,7 @@ sr_cmd[8] = 12; /* LSB of length */ sr_cmd[9] = 0; - result = sr_do_ioctl(target, sr_cmd, buffer, 12, 1); + result = sr_do_ioctl(target, sr_cmd, buffer, 12, 1, SCSI_DATA_READ); tochdr->cdth_trk0 = buffer[2]; tochdr->cdth_trk1 = buffer[3]; @@ -317,7 +318,7 @@ sr_cmd[8] = 12; /* LSB of length */ sr_cmd[9] = 0; - result = sr_do_ioctl(target, sr_cmd, buffer, 12, 0); + result = sr_do_ioctl(target, sr_cmd, buffer, 12, 0, SCSI_DATA_READ); tocentry->cdte_ctrl = buffer[5] & 0xf; tocentry->cdte_adr = buffer[5] >> 4; @@ -390,7 +391,7 @@ cmd[9] = 0x10; break; } - return sr_do_ioctl(minor, cmd, dest, blksize, 0); + return sr_do_ioctl(minor, cmd, dest, blksize, 0, SCSI_DATA_READ); } /* @@ -428,7 +429,7 @@ cmd[4] = (unsigned char) (lba >> 8) & 0xff; cmd[5] = (unsigned char) lba & 0xff; cmd[8] = 1; - rc = sr_do_ioctl(minor, cmd, dest, blksize, 0); + rc = sr_do_ioctl(minor, cmd, dest, blksize, 0, SCSI_DATA_READ); return rc; } diff -u --recursive --new-file v2.3.46/linux/drivers/scsi/sr_vendor.c linux/drivers/scsi/sr_vendor.c --- v2.3.46/linux/drivers/scsi/sr_vendor.c Fri Jan 28 15:09:08 2000 +++ linux/drivers/scsi/sr_vendor.c Wed Feb 16 20:21:45 2000 @@ -132,7 +132,7 @@ modesel->density = density; modesel->block_length_med = (blocklength >> 8) & 0xff; modesel->block_length_lo = blocklength & 0xff; - if (0 == (rc = sr_do_ioctl(minor, cmd, buffer, sizeof(*modesel), 0))) { + if (0 == (rc = sr_do_ioctl(minor, cmd, buffer, sizeof(*modesel), 0, SCSI_DATA_WRITE))) { scsi_CDs[minor].device->sector_size = blocklength; } #ifdef DEBUG @@ -176,7 +176,7 @@ cmd[1] = (scsi_CDs[minor].device->lun << 5); cmd[8] = 12; cmd[9] = 0x40; - rc = sr_do_ioctl(minor, cmd, buffer, 12, 1); + rc = sr_do_ioctl(minor, cmd, buffer, 12, 1, SCSI_DATA_READ); if (rc != 0) break; if ((buffer[0] << 8) + buffer[1] < 0x0a) { @@ -200,7 +200,7 @@ cmd[0] = 0xde; cmd[1] = (scsi_CDs[minor].device->lun << 5) | 0x03; cmd[2] = 0xb0; - rc = sr_do_ioctl(minor, cmd, buffer, 0x16, 1); + rc = sr_do_ioctl(minor, cmd, buffer, 0x16, 1, SCSI_DATA_READ); if (rc != 0) break; if (buffer[14] != 0 && buffer[14] != 0xb0) { @@ -224,7 +224,7 @@ memset(cmd, 0, MAX_COMMAND_SIZE); cmd[0] = 0xc7; cmd[1] = (scsi_CDs[minor].device->lun << 5) | 3; - rc = sr_do_ioctl(minor, cmd, buffer, 4, 1); + rc = sr_do_ioctl(minor, cmd, buffer, 4, 1, SCSI_DATA_READ); if (rc == -EINVAL) { printk(KERN_INFO "sr%d: Hmm, seems the drive " "doesn't support multisession CD's\n", minor); @@ -249,7 +249,7 @@ cmd[1] = (scsi_CDs[minor].device->lun << 5); cmd[8] = 0x04; cmd[9] = 0x40; - rc = sr_do_ioctl(minor, cmd, buffer, 0x04, 1); + rc = sr_do_ioctl(minor, cmd, buffer, 0x04, 1, SCSI_DATA_READ); if (rc != 0) { break; } @@ -263,7 +263,7 @@ cmd[6] = rc & 0x7f; /* number of last session */ cmd[8] = 0x0c; cmd[9] = 0x40; - rc = sr_do_ioctl(minor, cmd, buffer, 12, 1); + rc = sr_do_ioctl(minor, cmd, buffer, 12, 1, SCSI_DATA_READ); if (rc != 0) { break; } diff -u --recursive --new-file v2.3.46/linux/drivers/scsi/st.c linux/drivers/scsi/st.c --- v2.3.46/linux/drivers/scsi/st.c Wed Feb 16 17:03:52 2000 +++ linux/drivers/scsi/st.c Sun Feb 20 20:20:42 2000 @@ -11,7 +11,7 @@ Copyright 1992 - 2000 Kai Makisara email Kai.Makisara@metla.fi - Last modified: Fri Feb 11 19:43:57 2000 by makisara@kai.makisara.local + Last modified: Sat Feb 19 17:22:34 2000 by makisara@kai.makisara.local Some small formal changes - aeb, 950809 Last modified: 18-JAN-1998 Richard Gooch Devfs support @@ -169,16 +169,15 @@ - /* Convert the result to success code */ -static int st_chk_result(Scsi_Cmnd * SCpnt) +static int st_chk_result(Scsi_Request * SRpnt) { - int dev = TAPE_NR(SCpnt->request.rq_dev); - int result = SCpnt->result; - unsigned char *sense = SCpnt->sense_buffer, scode; + int dev = TAPE_NR(SRpnt->sr_request.rq_dev); + int result = SRpnt->sr_result; + unsigned char *sense = SRpnt->sr_sense_buffer, scode; DEB(const char *stp;) - if (!result /* && SCpnt->sense_buffer[0] == 0 */ ) + if (!result) return 0; if (driver_byte(result) & DRIVER_SENSE) @@ -192,11 +191,11 @@ if (debugging) { printk(ST_DEB_MSG "st%d: Error: %x, cmd: %x %x %x %x %x %x Len: %d\n", dev, result, - SCpnt->data_cmnd[0], SCpnt->data_cmnd[1], SCpnt->data_cmnd[2], - SCpnt->data_cmnd[3], SCpnt->data_cmnd[4], SCpnt->data_cmnd[5], - SCpnt->request_bufflen); + SRpnt->sr_cmnd[0], SRpnt->sr_cmnd[1], SRpnt->sr_cmnd[2], + SRpnt->sr_cmnd[3], SRpnt->sr_cmnd[4], SRpnt->sr_cmnd[5], + SRpnt->sr_bufflen); if (driver_byte(result) & DRIVER_SENSE) - print_sense("st", SCpnt); + print_req_sense("st", SRpnt); } else ) /* end DEB */ if (!(driver_byte(result) & DRIVER_SENSE) || ((sense[0] & 0x70) == 0x70 && @@ -205,11 +204,11 @@ /* scode != UNIT_ATTENTION && */ scode != BLANK_CHECK && scode != VOLUME_OVERFLOW && - SCpnt->data_cmnd[0] != MODE_SENSE && - SCpnt->data_cmnd[0] != TEST_UNIT_READY)) { /* Abnormal conditions for tape */ + SRpnt->sr_cmnd[0] != MODE_SENSE && + SRpnt->sr_cmnd[0] != TEST_UNIT_READY)) { /* Abnormal conditions for tape */ if (driver_byte(result) & DRIVER_SENSE) { printk(KERN_WARNING "st%d: Error with sense data: ", dev); - print_sense("st", SCpnt); + print_req_sense("st", SRpnt); } else printk(KERN_WARNING "st%d: Error %x (sugg. bt 0x%x, driver bt 0x%x, host bt 0x%x).\n", @@ -220,8 +219,8 @@ if ((sense[0] & 0x70) == 0x70 && scode == RECOVERED_ERROR #if ST_RECOVERED_WRITE_FATAL - && SCpnt->data_cmnd[0] != WRITE_6 - && SCpnt->data_cmnd[0] != WRITE_FILEMARKS + && SRpnt->sr_cmnd[0] != WRITE_6 + && SRpnt->sr_cmnd[0] != WRITE_FILEMARKS #endif ) { scsi_tapes[dev].recover_count++; @@ -229,9 +228,9 @@ DEB( if (debugging) { - if (SCpnt->data_cmnd[0] == READ_6) + if (SRpnt->sr_cmnd[0] == READ_6) stp = "read"; - else if (SCpnt->data_cmnd[0] == WRITE_6) + else if (SRpnt->sr_cmnd[0] == WRITE_6) stp = "write"; else stp = "ioctl"; @@ -268,13 +267,13 @@ remainder = 0; if ((SCpnt->sense_buffer[2] & 0x0f) == VOLUME_OVERFLOW || remainder > 0) - (STp->buffer)->last_result = SCpnt->result; /* Error */ + (STp->buffer)->midlevel_result = SCpnt->result; /* Error */ else - (STp->buffer)->last_result = INT_MAX; /* OK */ + (STp->buffer)->midlevel_result = INT_MAX; /* OK */ } else - (STp->buffer)->last_result = SCpnt->result; + (STp->buffer)->midlevel_result = SCpnt->result; SCpnt->request.rq_status = RQ_SCSI_DONE; - (STp->buffer)->last_SCpnt = SCpnt; + (STp->buffer)->last_SRpnt = SCpnt->sc_request; DEB( STp->write_pending = 0; ) up(SCpnt->request.sem); @@ -289,47 +288,49 @@ /* Do the scsi command. Waits until command performed if do_wait is true. Otherwise write_behind_check() is used to check that the command has finished. */ -static Scsi_Cmnd * - st_do_scsi(Scsi_Cmnd * SCpnt, Scsi_Tape * STp, unsigned char *cmd, int bytes, - int timeout, int retries, int do_wait) +static Scsi_Request * + st_do_scsi(Scsi_Request * SRpnt, Scsi_Tape * STp, unsigned char *cmd, int bytes, + int direction, int timeout, int retries, int do_wait) { unsigned char *bp; - if (SCpnt == NULL) - SCpnt = scsi_allocate_device(STp->device, 1, TRUE); - if (SCpnt == NULL) { + if (SRpnt == NULL) + SRpnt = scsi_allocate_request(STp->device); + if (SRpnt == NULL) { DEBC( printk(KERN_ERR "st%d: Can't get SCSI request.\n", TAPE_NR(STp->devt)); ); if (signal_pending(current)) - (STp->buffer)->last_result_fatal = (-EINTR); + (STp->buffer)->syscall_result = (-EINTR); else - (STp->buffer)->last_result_fatal = (-EBUSY); + (STp->buffer)->syscall_result = (-EBUSY); return NULL; } - cmd[1] |= (SCpnt->lun << 5) & 0xe0; + cmd[1] |= (SRpnt->sr_device->lun << 5) & 0xe0; init_MUTEX_LOCKED(&STp->sem); - SCpnt->use_sg = (bytes > (STp->buffer)->sg[0].length) ? + SRpnt->sr_use_sg = (bytes > (STp->buffer)->sg[0].length) ? (STp->buffer)->use_sg : 0; - if (SCpnt->use_sg) { + if (SRpnt->sr_use_sg) { bp = (char *) &((STp->buffer)->sg[0]); - if ((STp->buffer)->sg_segs < SCpnt->use_sg) - SCpnt->use_sg = (STp->buffer)->sg_segs; + if ((STp->buffer)->sg_segs < SRpnt->sr_use_sg) + SRpnt->sr_use_sg = (STp->buffer)->sg_segs; } else bp = (STp->buffer)->b_data; - SCpnt->cmd_len = 0; - SCpnt->request.sem = &(STp->sem); - SCpnt->request.rq_status = RQ_SCSI_BUSY; - SCpnt->request.rq_dev = STp->devt; + SRpnt->sr_data_direction = direction; + SRpnt->sr_cmd_len = 0; + SRpnt->sr_request.sem = &(STp->sem); + SRpnt->sr_request.rq_status = RQ_SCSI_BUSY; + SRpnt->sr_request.rq_dev = STp->devt; - scsi_do_cmd(SCpnt, (void *) cmd, bp, bytes, + scsi_do_req(SRpnt, (void *) cmd, bp, bytes, st_sleep_done, timeout, retries); if (do_wait) { - down(SCpnt->request.sem); - (STp->buffer)->last_result_fatal = st_chk_result(SCpnt); + down(SRpnt->sr_request.sem); + SRpnt->sr_request.sem = NULL; + (STp->buffer)->syscall_result = st_chk_result(SRpnt); } - return SCpnt; + return SRpnt; } @@ -349,9 +350,10 @@ ) /* end DEB */ down(&(STp->sem)); + (STp->buffer)->last_SRpnt->sr_request.sem = NULL; - (STp->buffer)->last_result_fatal = st_chk_result((STp->buffer)->last_SCpnt); - scsi_release_command((STp->buffer)->last_SCpnt); + (STp->buffer)->syscall_result = st_chk_result((STp->buffer)->last_SRpnt); + scsi_release_request((STp->buffer)->last_SRpnt); if (STbuffer->writing < STbuffer->buffer_bytes) #if 0 @@ -380,7 +382,7 @@ it messes up the block number). */ static int cross_eof(Scsi_Tape * STp, int forward) { - Scsi_Cmnd *SCpnt; + Scsi_Request *SRpnt; unsigned char cmd[MAX_COMMAND_SIZE]; cmd[0] = SPACE; @@ -395,18 +397,19 @@ DEBC(printk(ST_DEB_MSG "st%d: Stepping over filemark %s.\n", TAPE_NR(STp->devt), forward ? "forward" : "backward")); - SCpnt = st_do_scsi(NULL, STp, cmd, 0, STp->timeout, MAX_RETRIES, TRUE); - if (!SCpnt) - return (STp->buffer)->last_result_fatal; + SRpnt = st_do_scsi(NULL, STp, cmd, 0, SCSI_DATA_NONE, + STp->timeout, MAX_RETRIES, TRUE); + if (!SRpnt) + return (STp->buffer)->syscall_result; - scsi_release_command(SCpnt); - SCpnt = NULL; + scsi_release_request(SRpnt); + SRpnt = NULL; - if ((STp->buffer)->last_result != 0) + if ((STp->buffer)->midlevel_result != 0) printk(KERN_ERR "st%d: Stepping over filemark %s failed.\n", TAPE_NR(STp->devt), forward ? "forward" : "backward"); - return (STp->buffer)->last_result_fatal; + return (STp->buffer)->syscall_result; } @@ -416,16 +419,16 @@ int offset, transfer, blks; int result; unsigned char cmd[MAX_COMMAND_SIZE]; - Scsi_Cmnd *SCpnt; + Scsi_Request *SRpnt; ST_partstat *STps; if ((STp->buffer)->writing) { write_behind_check(STp); - if ((STp->buffer)->last_result_fatal) { + if ((STp->buffer)->syscall_result) { DEBC(printk(ST_DEB_MSG "st%d: Async write error (flush) %x.\n", - TAPE_NR(STp->devt), (STp->buffer)->last_result)) - if ((STp->buffer)->last_result == INT_MAX) + TAPE_NR(STp->devt), (STp->buffer)->midlevel_result)) + if ((STp->buffer)->midlevel_result == INT_MAX) return (-ENOSPC); return (-EIO); } @@ -452,16 +455,16 @@ cmd[3] = blks >> 8; cmd[4] = blks; - SCpnt = st_do_scsi(NULL, STp, cmd, transfer, STp->timeout, - MAX_WRITE_RETRIES, TRUE); - if (!SCpnt) - return (STp->buffer)->last_result_fatal; + SRpnt = st_do_scsi(NULL, STp, cmd, transfer, SCSI_DATA_WRITE, + STp->timeout, MAX_WRITE_RETRIES, TRUE); + if (!SRpnt) + return (STp->buffer)->syscall_result; STps = &(STp->ps[STp->partition]); - if ((STp->buffer)->last_result_fatal != 0) { - if ((SCpnt->sense_buffer[0] & 0x70) == 0x70 && - (SCpnt->sense_buffer[2] & 0x40) && - (SCpnt->sense_buffer[2] & 0x0f) == NO_SENSE) { + if ((STp->buffer)->syscall_result != 0) { + if ((SRpnt->sr_sense_buffer[0] & 0x70) == 0x70 && + (SRpnt->sr_sense_buffer[2] & 0x40) && + (SRpnt->sr_sense_buffer[2] & 0x0f) == NO_SENSE) { STp->dirty = 0; (STp->buffer)->buffer_bytes = 0; result = (-ENOSPC); @@ -477,8 +480,8 @@ STp->dirty = 0; (STp->buffer)->buffer_bytes = 0; } - scsi_release_command(SCpnt); - SCpnt = NULL; + scsi_release_request(SRpnt); + SRpnt = NULL; } return result; } @@ -585,7 +588,7 @@ int i, need_dma_buffer, new_session = FALSE; int retval; unsigned char cmd[MAX_COMMAND_SIZE]; - Scsi_Cmnd *SCpnt; + Scsi_Request *SRpnt; Scsi_Tape *STp; ST_mode *STm; ST_partstat *STps; @@ -636,7 +639,7 @@ STp->buffer = st_buffers[i]; (STp->buffer)->in_use = 1; (STp->buffer)->writing = 0; - (STp->buffer)->last_result_fatal = 0; + (STp->buffer)->syscall_result = 0; (STp->buffer)->use_sg = STp->device->host->sg_tablesize; /* Compute the usable buffer size for this SCSI adapter */ @@ -663,24 +666,24 @@ memset((void *) &cmd[0], 0, MAX_COMMAND_SIZE); cmd[0] = TEST_UNIT_READY; - SCpnt = st_do_scsi(NULL, STp, cmd, 0, STp->long_timeout, MAX_READY_RETRIES, - TRUE); - if (!SCpnt) { - retval = (STp->buffer)->last_result_fatal; + SRpnt = st_do_scsi(NULL, STp, cmd, 0, SCSI_DATA_NONE, STp->long_timeout, + MAX_READY_RETRIES, TRUE); + if (!SRpnt) { + retval = (STp->buffer)->syscall_result; goto err_out; } - if ((SCpnt->sense_buffer[0] & 0x70) == 0x70 && - (SCpnt->sense_buffer[2] & 0x0f) == UNIT_ATTENTION) { /* New media? */ + if ((SRpnt->sr_sense_buffer[0] & 0x70) == 0x70 && + (SRpnt->sr_sense_buffer[2] & 0x0f) == UNIT_ATTENTION) { /* New media? */ /* Flush the queued UNIT ATTENTION sense data */ for (i=0; i < 10; i++) { memset((void *) &cmd[0], 0, MAX_COMMAND_SIZE); cmd[0] = TEST_UNIT_READY; - SCpnt = st_do_scsi(SCpnt, STp, cmd, 0, STp->long_timeout, - MAX_READY_RETRIES, TRUE); - if ((SCpnt->sense_buffer[0] & 0x70) != 0x70 || - (SCpnt->sense_buffer[2] & 0x0f) != UNIT_ATTENTION) + SRpnt = st_do_scsi(SRpnt, STp, cmd, 0, SCSI_DATA_NONE, + STp->long_timeout, MAX_READY_RETRIES, TRUE); + if ((SRpnt->sr_sense_buffer[0] & 0x70) != 0x70 || + (SRpnt->sr_sense_buffer[2] & 0x0f) != UNIT_ATTENTION) break; } @@ -701,16 +704,16 @@ new_session = TRUE; } - if ((STp->buffer)->last_result_fatal != 0) { + if ((STp->buffer)->syscall_result != 0) { if ((STp->device)->scsi_level >= SCSI_2 && - (SCpnt->sense_buffer[0] & 0x70) == 0x70 && - (SCpnt->sense_buffer[2] & 0x0f) == NOT_READY && - SCpnt->sense_buffer[12] == 0x3a) { /* Check ASC */ + (SRpnt->sr_sense_buffer[0] & 0x70) == 0x70 && + (SRpnt->sr_sense_buffer[2] & 0x0f) == NOT_READY && + SRpnt->sr_sense_buffer[12] == 0x3a) { /* Check ASC */ STp->ready = ST_NO_TAPE; } else STp->ready = ST_NOT_READY; - scsi_release_command(SCpnt); - SCpnt = NULL; + scsi_release_request(SRpnt); + SRpnt = NULL; STp->density = 0; /* Clear the erroneous "residue" */ STp->write_prot = 0; STp->block_size = 0; @@ -726,10 +729,10 @@ memset((void *) &cmd[0], 0, MAX_COMMAND_SIZE); cmd[0] = READ_BLOCK_LIMITS; - SCpnt = st_do_scsi(SCpnt, STp, cmd, 6, STp->timeout, MAX_READY_RETRIES, - TRUE); + SRpnt = st_do_scsi(SRpnt, STp, cmd, 6, SCSI_DATA_READ, STp->timeout, + MAX_READY_RETRIES, TRUE); - if (!SCpnt->result && !SCpnt->sense_buffer[0]) { + if (!SRpnt->sr_result && !SRpnt->sr_sense_buffer[0]) { STp->max_block = ((STp->buffer)->b_data[1] << 16) | ((STp->buffer)->b_data[2] << 8) | (STp->buffer)->b_data[3]; STp->min_block = ((STp->buffer)->b_data[4] << 8) | @@ -749,12 +752,13 @@ cmd[0] = MODE_SENSE; cmd[4] = 12; - SCpnt = st_do_scsi(SCpnt, STp, cmd, 12, STp->timeout, MAX_READY_RETRIES, TRUE); + SRpnt = st_do_scsi(SRpnt, STp, cmd, 12, SCSI_DATA_READ, STp->timeout, + MAX_READY_RETRIES, TRUE); - if ((STp->buffer)->last_result_fatal != 0) { + if ((STp->buffer)->syscall_result != 0) { DEBC(printk(ST_DEB_MSG "st%d: No Mode Sense.\n", dev)); STp->block_size = ST_DEFAULT_BLOCK; /* Educated guess (?) */ - (STp->buffer)->last_result_fatal = 0; /* Prevent error propagation */ + (STp->buffer)->syscall_result = 0; /* Prevent error propagation */ STp->drv_write_prot = 0; } else { DEBC(printk(ST_DEB_MSG @@ -779,14 +783,14 @@ !enlarge_buffer(STp->buffer, STp->block_size, STp->restr_dma)) { printk(KERN_NOTICE "st%d: Blocksize %d too large for buffer.\n", dev, STp->block_size); - scsi_release_command(SCpnt); + scsi_release_request(SRpnt); retval = (-EIO); goto err_out; } STp->drv_write_prot = ((STp->buffer)->b_data[2] & 0x80) != 0; } - scsi_release_command(SCpnt); - SCpnt = NULL; + scsi_release_request(SRpnt); + SRpnt = NULL; STp->inited = TRUE; if (STp->block_size > 0) @@ -863,7 +867,7 @@ { int result = 0, result2; static unsigned char cmd[MAX_COMMAND_SIZE]; - Scsi_Cmnd *SCpnt; + Scsi_Request *SRpnt; Scsi_Tape *STp; ST_mode *STm; ST_partstat *STps; @@ -907,29 +911,29 @@ cmd[0] = WRITE_FILEMARKS; cmd[4] = 1 + STp->two_fm; - SCpnt = st_do_scsi(NULL, STp, cmd, 0, STp->timeout, - MAX_WRITE_RETRIES, TRUE); - if (!SCpnt) { - result = (STp->buffer)->last_result_fatal; + SRpnt = st_do_scsi(NULL, STp, cmd, 0, SCSI_DATA_NONE, + STp->timeout, MAX_WRITE_RETRIES, TRUE); + if (!SRpnt) { + result = (STp->buffer)->syscall_result; goto out; } - if ((STp->buffer)->last_result_fatal != 0 && - ((SCpnt->sense_buffer[0] & 0x70) != 0x70 || - (SCpnt->sense_buffer[2] & 0x4f) != 0x40 || - ((SCpnt->sense_buffer[0] & 0x80) != 0 && - (SCpnt->sense_buffer[3] | SCpnt->sense_buffer[4] | - SCpnt->sense_buffer[5] | - SCpnt->sense_buffer[6]) == 0))) { + if ((STp->buffer)->syscall_result != 0 && + ((SRpnt->sr_sense_buffer[0] & 0x70) != 0x70 || + (SRpnt->sr_sense_buffer[2] & 0x4f) != 0x40 || + ((SRpnt->sr_sense_buffer[0] & 0x80) != 0 && + (SRpnt->sr_sense_buffer[3] | SRpnt->sr_sense_buffer[4] | + SRpnt->sr_sense_buffer[5] | + SRpnt->sr_sense_buffer[6]) == 0))) { /* Filter out successful write at EOM */ - scsi_release_command(SCpnt); - SCpnt = NULL; + scsi_release_request(SRpnt); + SRpnt = NULL; printk(KERN_ERR "st%d: Error on write filemark.\n", dev); if (result == 0) result = (-EIO); } else { - scsi_release_command(SCpnt); - SCpnt = NULL; + scsi_release_request(SRpnt); + SRpnt = NULL; if (STps->drv_file >= 0) STps->drv_file++; STps->drv_block = 0; @@ -1016,7 +1020,7 @@ int doing_write = 0; static unsigned char cmd[MAX_COMMAND_SIZE]; const char *b_point; - Scsi_Cmnd *SCpnt = NULL; + Scsi_Request *SRpnt = NULL; Scsi_Tape *STp; ST_mode *STm; ST_partstat *STps; @@ -1111,10 +1115,10 @@ if ((STp->buffer)->writing) { write_behind_check(STp); - if ((STp->buffer)->last_result_fatal) { + if ((STp->buffer)->syscall_result) { DEBC(printk(ST_DEB_MSG "st%d: Async write error (write) %x.\n", - dev, (STp->buffer)->last_result)); - if ((STp->buffer)->last_result == INT_MAX) + dev, (STp->buffer)->midlevel_result)); + if ((STp->buffer)->midlevel_result == INT_MAX) STps->eof = ST_EOM_OK; else STps->eof = ST_EOM_ERROR; @@ -1168,9 +1172,9 @@ i = append_to_buffer(b_point, STp->buffer, do_count); if (i) { - if (SCpnt != NULL) { - scsi_release_command(SCpnt); - SCpnt = NULL; + if (SRpnt != NULL) { + scsi_release_request(SRpnt); + SRpnt = NULL; } return i; } @@ -1186,23 +1190,23 @@ cmd[3] = blks >> 8; cmd[4] = blks; - SCpnt = st_do_scsi(SCpnt, STp, cmd, transfer, STp->timeout, - MAX_WRITE_RETRIES, TRUE); - if (!SCpnt) - return (STp->buffer)->last_result_fatal; + SRpnt = st_do_scsi(SRpnt, STp, cmd, transfer, SCSI_DATA_WRITE, + STp->timeout, MAX_WRITE_RETRIES, TRUE); + if (!SRpnt) + return (STp->buffer)->syscall_result; - if ((STp->buffer)->last_result_fatal != 0) { + if ((STp->buffer)->syscall_result != 0) { DEBC(printk(ST_DEB_MSG "st%d: Error on write:\n", dev)); - if ((SCpnt->sense_buffer[0] & 0x70) == 0x70 && - (SCpnt->sense_buffer[2] & 0x40)) { + if ((SRpnt->sr_sense_buffer[0] & 0x70) == 0x70 && + (SRpnt->sr_sense_buffer[2] & 0x40)) { if (STp->block_size != 0 && - (SCpnt->sense_buffer[0] & 0x80) != 0) - transfer = (SCpnt->sense_buffer[3] << 24) | - (SCpnt->sense_buffer[4] << 16) | - (SCpnt->sense_buffer[5] << 8) | - SCpnt->sense_buffer[6]; + (SRpnt->sr_sense_buffer[0] & 0x80) != 0) + transfer = (SRpnt->sr_sense_buffer[3] << 24) | + (SRpnt->sr_sense_buffer[4] << 16) | + (SRpnt->sr_sense_buffer[5] << 8) | + SRpnt->sr_sense_buffer[6]; else if (STp->block_size == 0 && - (SCpnt->sense_buffer[2] & 0x0f) == + (SRpnt->sr_sense_buffer[2] & 0x0f) == VOLUME_OVERFLOW) transfer = do_count; else @@ -1239,8 +1243,8 @@ retval = (-EIO); } - scsi_release_command(SCpnt); - SCpnt = NULL; + scsi_release_request(SRpnt); + SRpnt = NULL; (STp->buffer)->buffer_bytes = 0; STp->dirty = 0; if (count < total) @@ -1264,9 +1268,9 @@ STp->dirty = 1; i = append_to_buffer(b_point, STp->buffer, count); if (i) { - if (SCpnt != NULL) { - scsi_release_command(SCpnt); - SCpnt = NULL; + if (SRpnt != NULL) { + scsi_release_request(SRpnt); + SRpnt = NULL; } return i; } @@ -1274,10 +1278,10 @@ count = 0; } - if (doing_write && (STp->buffer)->last_result_fatal != 0) { - scsi_release_command(SCpnt); - SCpnt = NULL; - return (STp->buffer)->last_result_fatal; + if (doing_write && (STp->buffer)->syscall_result != 0) { + scsi_release_request(SRpnt); + SRpnt = NULL; + return (STp->buffer)->syscall_result; } if (STm->do_async_writes && @@ -1302,14 +1306,15 @@ cmd[4] = blks; DEB( STp->write_pending = 1; ) - SCpnt = st_do_scsi(SCpnt, STp, cmd, (STp->buffer)->writing, STp->timeout, + SRpnt = st_do_scsi(SRpnt, STp, cmd, (STp->buffer)->writing, + SCSI_DATA_WRITE, STp->timeout, MAX_WRITE_RETRIES, FALSE); - if (SCpnt == NULL) - return (STp->buffer)->last_result_fatal; + if (SRpnt == NULL) + return (STp->buffer)->syscall_result; - } else if (SCpnt != NULL) { - scsi_release_command(SCpnt); - SCpnt = NULL; + } else if (SRpnt != NULL) { + scsi_release_request(SRpnt); + SRpnt = NULL; } STps->at_sm &= (total == 0); if (total > 0) @@ -1321,11 +1326,11 @@ /* Read data from the tape. Returns zero in the normal case, one if the eof status has changed, and the negative error code in case of a fatal error. Otherwise updates the buffer and the eof state. */ -static long read_tape(struct inode *inode, long count, Scsi_Cmnd ** aSCpnt) +static long read_tape(struct inode *inode, long count, Scsi_Request ** aSRpnt) { int transfer, blks, bytes; static unsigned char cmd[MAX_COMMAND_SIZE]; - Scsi_Cmnd *SCpnt; + Scsi_Request *SRpnt; Scsi_Tape *STp; ST_mode *STm; ST_partstat *STps; @@ -1362,49 +1367,51 @@ cmd[3] = blks >> 8; cmd[4] = blks; - SCpnt = *aSCpnt; - SCpnt = st_do_scsi(SCpnt, STp, cmd, bytes, STp->timeout, MAX_RETRIES, TRUE); - *aSCpnt = SCpnt; - if (!SCpnt) - return (STp->buffer)->last_result_fatal; + SRpnt = *aSRpnt; + SRpnt = st_do_scsi(SRpnt, STp, cmd, bytes, SCSI_DATA_READ, + STp->timeout, MAX_RETRIES, TRUE); + *aSRpnt = SRpnt; + if (!SRpnt) + return (STp->buffer)->syscall_result; (STp->buffer)->read_pointer = 0; STps->at_sm = 0; /* Something to check */ - if ((STp->buffer)->last_result_fatal) { + if ((STp->buffer)->syscall_result) { retval = 1; DEBC(printk(ST_DEB_MSG "st%d: Sense: %2x %2x %2x %2x %2x %2x %2x %2x\n", dev, - SCpnt->sense_buffer[0], SCpnt->sense_buffer[1], - SCpnt->sense_buffer[2], SCpnt->sense_buffer[3], - SCpnt->sense_buffer[4], SCpnt->sense_buffer[5], - SCpnt->sense_buffer[6], SCpnt->sense_buffer[7])); - if ((SCpnt->sense_buffer[0] & 0x70) == 0x70) { /* extended sense */ + SRpnt->sr_sense_buffer[0], SRpnt->sr_sense_buffer[1], + SRpnt->sr_sense_buffer[2], SRpnt->sr_sense_buffer[3], + SRpnt->sr_sense_buffer[4], SRpnt->sr_sense_buffer[5], + SRpnt->sr_sense_buffer[6], SRpnt->sr_sense_buffer[7])); + if ((SRpnt->sr_sense_buffer[0] & 0x70) == 0x70) { /* extended sense */ - if ((SCpnt->sense_buffer[2] & 0x0f) == BLANK_CHECK) - SCpnt->sense_buffer[2] &= 0xcf; /* No need for EOM in this case */ + if ((SRpnt->sr_sense_buffer[2] & 0x0f) == BLANK_CHECK) + SRpnt->sr_sense_buffer[2] &= 0xcf; /* No need for EOM in this case */ - if ((SCpnt->sense_buffer[2] & 0xe0) != 0) { /* EOF, EOM, or ILI */ + if ((SRpnt->sr_sense_buffer[2] & 0xe0) != 0) { /* EOF, EOM, or ILI */ /* Compute the residual count */ - if ((SCpnt->sense_buffer[0] & 0x80) != 0) - transfer = (SCpnt->sense_buffer[3] << 24) | - (SCpnt->sense_buffer[4] << 16) | - (SCpnt->sense_buffer[5] << 8) | SCpnt->sense_buffer[6]; + if ((SRpnt->sr_sense_buffer[0] & 0x80) != 0) + transfer = (SRpnt->sr_sense_buffer[3] << 24) | + (SRpnt->sr_sense_buffer[4] << 16) | + (SRpnt->sr_sense_buffer[5] << 8) | + SRpnt->sr_sense_buffer[6]; else transfer = 0; if (STp->block_size == 0 && - (SCpnt->sense_buffer[2] & 0x0f) == MEDIUM_ERROR) + (SRpnt->sr_sense_buffer[2] & 0x0f) == MEDIUM_ERROR) transfer = bytes; - if (SCpnt->sense_buffer[2] & 0x20) { /* ILI */ + if (SRpnt->sr_sense_buffer[2] & 0x20) { /* ILI */ if (STp->block_size == 0) { if (transfer <= 0) transfer = 0; (STp->buffer)->buffer_bytes = bytes - transfer; } else { - scsi_release_command(SCpnt); - SCpnt = *aSCpnt = NULL; + scsi_release_request(SRpnt); + SRpnt = *aSRpnt = NULL; if (transfer == blks) { /* We did not get anything, error */ printk(KERN_NOTICE "st%d: Incorrect block size.\n", dev); if (STps->drv_block >= 0) @@ -1423,7 +1430,7 @@ if (st_int_ioctl(inode, MTBSR, 1)) return (-EIO); } - } else if (SCpnt->sense_buffer[2] & 0x80) { /* FM overrides EOM */ + } else if (SRpnt->sr_sense_buffer[2] & 0x80) { /* FM overrides EOM */ if (STps->eof != ST_FM_HIT) STps->eof = ST_FM_HIT; else @@ -1436,7 +1443,7 @@ DEBC(printk(ST_DEB_MSG "st%d: EOF detected (%d bytes read).\n", dev, (STp->buffer)->buffer_bytes)); - } else if (SCpnt->sense_buffer[2] & 0x40) { + } else if (SRpnt->sr_sense_buffer[2] & 0x40) { if (STps->eof == ST_FM) STps->eof = ST_EOD_1; else @@ -1457,7 +1464,7 @@ "st%d: Tape error while reading.\n", dev)); STps->drv_block = (-1); if (STps->eof == ST_FM && - (SCpnt->sense_buffer[2] & 0x0f) == BLANK_CHECK) { + (SRpnt->sr_sense_buffer[2] & 0x0f) == BLANK_CHECK) { DEBC(printk(ST_DEB_MSG "st%d: Zero returned for first BLANK CHECK after EOF.\n", dev)); @@ -1468,7 +1475,7 @@ } /* End of extended sense test */ else { /* Non-extended sense */ - retval = (STp->buffer)->last_result_fatal; + retval = (STp->buffer)->syscall_result; } } @@ -1494,7 +1501,7 @@ ssize_t total; ssize_t i, transfer; int special; - Scsi_Cmnd *SCpnt = NULL; + Scsi_Request *SRpnt = NULL; Scsi_Tape *STp; ST_mode *STm; ST_partstat *STps; @@ -1587,10 +1594,10 @@ /* Get new data if the buffer is empty */ if ((STp->buffer)->buffer_bytes == 0) { - special = read_tape(inode, count - total, &SCpnt); + special = read_tape(inode, count - total, &SRpnt); if (special < 0) { /* No need to continue read */ - if (SCpnt != NULL) { - scsi_release_command(SCpnt); + if (SRpnt != NULL) { + scsi_release_request(SRpnt); } return special; } @@ -1609,9 +1616,9 @@ (STp->buffer)->buffer_bytes : count - total; i = from_buffer(STp->buffer, buf, transfer); if (i) { - if (SCpnt != NULL) { - scsi_release_command(SCpnt); - SCpnt = NULL; + if (SRpnt != NULL) { + scsi_release_request(SRpnt); + SRpnt = NULL; } return i; } @@ -1626,9 +1633,9 @@ } /* for (total = 0, special = 0; total < count && !special; ) */ - if (SCpnt != NULL) { - scsi_release_command(SCpnt); - SCpnt = NULL; + if (SRpnt != NULL) { + scsi_release_request(SRpnt); + SRpnt = NULL; } /* Change the eof state if no data from tape or buffer */ @@ -1830,7 +1837,7 @@ { int dev; unsigned char cmd[MAX_COMMAND_SIZE]; - Scsi_Cmnd *SCpnt = NULL; + Scsi_Request *SRpnt = NULL; if (STp->ready != ST_READY) return (-EIO); @@ -1842,17 +1849,18 @@ cmd[2] = COMPRESSION_PAGE; cmd[4] = COMPRESSION_PAGE_LENGTH + MODE_HEADER_LENGTH; - SCpnt = st_do_scsi(SCpnt, STp, cmd, cmd[4], STp->timeout, 0, TRUE); - if (SCpnt == NULL) - return (STp->buffer)->last_result_fatal; + SRpnt = st_do_scsi(SRpnt, STp, cmd, cmd[4], SCSI_DATA_READ, + STp->timeout, 0, TRUE); + if (SRpnt == NULL) + return (STp->buffer)->syscall_result; - dev = TAPE_NR(SCpnt->request.rq_dev); + dev = TAPE_NR(SRpnt->sr_request.rq_dev); - if ((STp->buffer)->last_result_fatal != 0) { + if ((STp->buffer)->syscall_result != 0) { DEBC(printk(ST_DEB_MSG "st%d: Compression mode page not supported.\n", dev)); - scsi_release_command(SCpnt); - SCpnt = NULL; + scsi_release_request(SRpnt); + SRpnt = NULL; return (-EIO); } DEBC(printk(ST_DEB_MSG "st%d: Compression state is %d.\n", dev, @@ -1861,8 +1869,8 @@ /* Check if compression can be changed */ if (((STp->buffer)->b_data[MODE_HEADER_LENGTH + 2] & DCC_MASK) == 0) { DEBC(printk(ST_DEB_MSG "st%d: Compression not supported.\n", dev)); - scsi_release_command(SCpnt); - SCpnt = NULL; + scsi_release_request(SRpnt); + SRpnt = NULL; return (-EIO); } @@ -1880,19 +1888,20 @@ (STp->buffer)->b_data[0] = 0; /* Reserved data length */ (STp->buffer)->b_data[1] = 0; /* Reserved media type byte */ (STp->buffer)->b_data[MODE_HEADER_LENGTH] &= 0x3f; - SCpnt = st_do_scsi(SCpnt, STp, cmd, cmd[4], STp->timeout, 0, TRUE); + SRpnt = st_do_scsi(SRpnt, STp, cmd, cmd[4], SCSI_DATA_WRITE, + STp->timeout, 0, TRUE); - if ((STp->buffer)->last_result_fatal != 0) { + if ((STp->buffer)->syscall_result != 0) { DEBC(printk(ST_DEB_MSG "st%d: Compression change failed.\n", dev)); - scsi_release_command(SCpnt); - SCpnt = NULL; + scsi_release_request(SRpnt); + SRpnt = NULL; return (-EIO); } DEBC(printk(ST_DEB_MSG "st%d: Compression state changed to %d.\n", dev, state)); - scsi_release_command(SCpnt); - SCpnt = NULL; + scsi_release_request(SRpnt); + SRpnt = NULL; STp->compression_changed = TRUE; return 0; } @@ -1907,10 +1916,11 @@ int i, ioctl_result; int chg_eof = TRUE; unsigned char cmd[MAX_COMMAND_SIZE]; - Scsi_Cmnd *SCpnt; + Scsi_Request *SRpnt; Scsi_Tape *STp; ST_partstat *STps; - int fileno, blkno, at_sm, undone, datalen; + int fileno, blkno, at_sm, undone; + int datalen = 0, direction = SCSI_DATA_NONE; int dev = TAPE_NR(inode->i_rdev); STp = &(scsi_tapes[dev]); @@ -1927,7 +1937,6 @@ at_sm = STps->at_sm; memset(cmd, 0, MAX_COMMAND_SIZE); - datalen = 0; switch (cmd_in) { case MTFSFM: chg_eof = FALSE; /* Changed from the FSF after this */ @@ -2169,6 +2178,7 @@ } cmd[0] = MODE_SELECT; cmd[4] = datalen = 12; + direction = SCSI_DATA_WRITE; memset((STp->buffer)->b_data, 0, 12); if (cmd_in == MTSETDRVBUFFER) @@ -2215,15 +2225,16 @@ return (-ENOSYS); } - SCpnt = st_do_scsi(NULL, STp, cmd, datalen, timeout, MAX_RETRIES, TRUE); - if (!SCpnt) - return (STp->buffer)->last_result_fatal; + SRpnt = st_do_scsi(NULL, STp, cmd, datalen, direction, + timeout, MAX_RETRIES, TRUE); + if (!SRpnt) + return (STp->buffer)->syscall_result; - ioctl_result = (STp->buffer)->last_result_fatal; + ioctl_result = (STp->buffer)->syscall_result; if (!ioctl_result) { /* SCSI command successful */ - scsi_release_command(SCpnt); - SCpnt = NULL; + scsi_release_request(SRpnt); + SRpnt = NULL; STps->drv_block = blkno; STps->drv_file = fileno; STps->at_sm = at_sm; @@ -2272,7 +2283,7 @@ } else { /* SCSI command was not completely successful. Don't return from this block without releasing the SCSI command block! */ - if (SCpnt->sense_buffer[2] & 0x40) { + if (SRpnt->sr_sense_buffer[2] & 0x40) { if (cmd_in != MTBSF && cmd_in != MTBSFM && cmd_in != MTBSR && cmd_in != MTBSS) STps->eof = ST_EOM_OK; @@ -2280,14 +2291,14 @@ } undone = ( - (SCpnt->sense_buffer[3] << 24) + - (SCpnt->sense_buffer[4] << 16) + - (SCpnt->sense_buffer[5] << 8) + - SCpnt->sense_buffer[6]); + (SRpnt->sr_sense_buffer[3] << 24) + + (SRpnt->sr_sense_buffer[4] << 16) + + (SRpnt->sr_sense_buffer[5] << 8) + + SRpnt->sr_sense_buffer[6]); if (cmd_in == MTWEOF && - (SCpnt->sense_buffer[0] & 0x70) == 0x70 && - (SCpnt->sense_buffer[2] & 0x4f) == 0x40 && - ((SCpnt->sense_buffer[0] & 0x80) == 0 || undone == 0)) { + (SRpnt->sr_sense_buffer[0] & 0x70) == 0x70 && + (SRpnt->sr_sense_buffer[2] & 0x4f) == 0x40 && + ((SRpnt->sr_sense_buffer[0] & 0x80) == 0 || undone == 0)) { ioctl_result = 0; /* EOF written succesfully at EOM */ if (fileno >= 0) fileno++; @@ -2308,7 +2319,7 @@ STps->drv_block = 0; STps->eof = ST_NOEOF; } else if (cmd_in == MTFSR) { - if (SCpnt->sense_buffer[2] & 0x80) { /* Hit filemark */ + if (SRpnt->sr_sense_buffer[2] & 0x80) { /* Hit filemark */ if (STps->drv_file >= 0) STps->drv_file++; STps->drv_block = 0; @@ -2321,7 +2332,7 @@ STps->eof = ST_NOEOF; } } else if (cmd_in == MTBSR) { - if (SCpnt->sense_buffer[2] & 0x80) { /* Hit filemark */ + if (SRpnt->sr_sense_buffer[2] & 0x80) { /* Hit filemark */ STps->drv_file--; STps->drv_block = (-1); } else { @@ -2338,14 +2349,14 @@ } else if (chg_eof) STps->eof = ST_NOEOF; - if ((SCpnt->sense_buffer[2] & 0x0f) == BLANK_CHECK) + if ((SRpnt->sr_sense_buffer[2] & 0x0f) == BLANK_CHECK) STps->eof = ST_EOD; if (cmd_in == MTLOCK) STp->door_locked = ST_LOCK_FAILS; - scsi_release_command(SCpnt); - SCpnt = NULL; + scsi_release_request(SRpnt); + SRpnt = NULL; } return ioctl_result; @@ -2362,7 +2373,7 @@ int dev = TAPE_NR(inode->i_rdev); int result; unsigned char scmd[MAX_COMMAND_SIZE]; - Scsi_Cmnd *SCpnt; + Scsi_Request *SRpnt; STp = &(scsi_tapes[dev]); if (STp->ready != ST_READY) @@ -2377,11 +2388,12 @@ if (!logical && !STp->scsi2_logical) scmd[1] = 1; } - SCpnt = st_do_scsi(NULL, STp, scmd, 20, STp->timeout, MAX_READY_RETRIES, TRUE); - if (!SCpnt) - return (STp->buffer)->last_result_fatal; + SRpnt = st_do_scsi(NULL, STp, scmd, 20, SCSI_DATA_READ, STp->timeout, + MAX_READY_RETRIES, TRUE); + if (!SRpnt) + return (STp->buffer)->syscall_result; - if ((STp->buffer)->last_result_fatal != 0 || + if ((STp->buffer)->syscall_result != 0 || (STp->device->scsi_level >= SCSI_2 && ((STp->buffer)->b_data[0] & 4) != 0)) { *block = *partition = 0; @@ -2407,8 +2419,8 @@ DEBC(printk(ST_DEB_MSG "st%d: Got tape pos. blk %d part %d.\n", dev, *block, *partition)); } - scsi_release_command(SCpnt); - SCpnt = NULL; + scsi_release_request(SRpnt); + SRpnt = NULL; return result; } @@ -2426,7 +2438,7 @@ unsigned int blk; int timeout; unsigned char scmd[MAX_COMMAND_SIZE]; - Scsi_Cmnd *SCpnt; + Scsi_Request *SRpnt; STp = &(scsi_tapes[dev]); if (STp->ready != ST_READY) @@ -2483,13 +2495,14 @@ timeout = STp->timeout; #endif - SCpnt = st_do_scsi(NULL, STp, scmd, 20, timeout, MAX_READY_RETRIES, TRUE); - if (!SCpnt) - return (STp->buffer)->last_result_fatal; + SRpnt = st_do_scsi(NULL, STp, scmd, 0, SCSI_DATA_NONE, + timeout, MAX_READY_RETRIES, TRUE); + if (!SRpnt) + return (STp->buffer)->syscall_result; STps->drv_block = STps->drv_file = (-1); STps->eof = ST_NOEOF; - if ((STp->buffer)->last_result_fatal != 0) { + if ((STp->buffer)->syscall_result != 0) { result = (-EIO); if (STp->can_partitions && (STp->device)->scsi_level >= SCSI_2 && @@ -2511,8 +2524,8 @@ result = 0; } - scsi_release_command(SCpnt); - SCpnt = NULL; + scsi_release_request(SRpnt); + SRpnt = NULL; return result; } @@ -2561,7 +2574,7 @@ { int dev = TAPE_NR(inode->i_rdev), result; Scsi_Tape *STp; - Scsi_Cmnd *SCpnt = NULL; + Scsi_Request *SRpnt = NULL; unsigned char cmd[MAX_COMMAND_SIZE]; STp = &(scsi_tapes[dev]); @@ -2574,14 +2587,15 @@ cmd[2] = PART_PAGE; cmd[4] = 200; - SCpnt = st_do_scsi(SCpnt, STp, cmd, 200, STp->timeout, MAX_READY_RETRIES, TRUE); - if (SCpnt == NULL) - return (STp->buffer)->last_result_fatal; + SRpnt = st_do_scsi(SRpnt, STp, cmd, 200, SCSI_DATA_READ, STp->timeout, + MAX_READY_RETRIES, TRUE); + if (SRpnt == NULL) + return (STp->buffer)->syscall_result; - scsi_release_command(SCpnt); - SCpnt = NULL; + scsi_release_request(SRpnt); + SRpnt = NULL; - if ((STp->buffer)->last_result_fatal != 0) { + if ((STp->buffer)->syscall_result != 0) { DEBC(printk(ST_DEB_MSG "st%d: Can't read medium partition page.\n", dev)); result = (-EIO); @@ -2601,7 +2615,7 @@ int dev = TAPE_NR(inode->i_rdev), result; int length; Scsi_Tape *STp; - Scsi_Cmnd *SCpnt = NULL; + Scsi_Request *SRpnt = NULL; unsigned char cmd[MAX_COMMAND_SIZE], *bp; if ((result = nbr_partitions(inode)) < 0) @@ -2638,15 +2652,15 @@ cmd[1] = 0x10; cmd[4] = length + MODE_HEADER_LENGTH; - SCpnt = st_do_scsi(SCpnt, STp, cmd, cmd[4], STp->long_timeout, - MAX_READY_RETRIES, TRUE); - if (SCpnt == NULL) - return (STp->buffer)->last_result_fatal; + SRpnt = st_do_scsi(SRpnt, STp, cmd, cmd[4], SCSI_DATA_WRITE, + STp->long_timeout, MAX_READY_RETRIES, TRUE); + if (SRpnt == NULL) + return (STp->buffer)->syscall_result; - scsi_release_command(SCpnt); - SCpnt = NULL; + scsi_release_request(SRpnt); + SRpnt = NULL; - if ((STp->buffer)->last_result_fatal != 0) { + if ((STp->buffer)->syscall_result != 0) { printk(KERN_INFO "st%d: Partitioning of tape failed.\n", dev); result = (-EIO); } else diff -u --recursive --new-file v2.3.46/linux/drivers/scsi/st.h linux/drivers/scsi/st.h --- v2.3.46/linux/drivers/scsi/st.h Wed Feb 16 17:03:52 2000 +++ linux/drivers/scsi/st.h Sun Feb 20 20:20:42 2000 @@ -19,9 +19,9 @@ int buffer_bytes; int read_pointer; int writing; - int last_result; - int last_result_fatal; - Scsi_Cmnd *last_SCpnt; + int midlevel_result; + int syscall_result; + Scsi_Request *last_SRpnt; unsigned char *b_data; unsigned short use_sg; /* zero or number of segments for this adapter */ unsigned short sg_segs; /* total number of allocated segments */ diff -u --recursive --new-file v2.3.46/linux/drivers/sound/ac97_codec.h linux/drivers/sound/ac97_codec.h --- v2.3.46/linux/drivers/sound/ac97_codec.h Sun Feb 13 19:29:04 2000 +++ linux/drivers/sound/ac97_codec.h Thu Feb 17 09:30:35 2000 @@ -107,13 +107,13 @@ /* OSS interface to the ac97s.. */ #define AC97_STEREO_MASK (SOUND_MASK_VOLUME|SOUND_MASK_PCM|\ SOUND_MASK_LINE|SOUND_MASK_CD|\ - SOUND_MIXER_ALTPCM|SOUND_MASK_IGAIN|\ + SOUND_MASK_ALTPCM|SOUND_MASK_IGAIN|\ SOUND_MASK_LINE1|SOUND_MASK_VIDEO) #define AC97_SUPPORTED_MASK (AC97_STEREO_MASK | \ SOUND_MASK_BASS|SOUND_MASK_TREBLE|\ SOUND_MASK_SPEAKER|SOUND_MASK_MIC|\ - SOUND_MIXER_PHONEIN|SOUND_MIXER_PHONEOUT) + SOUND_MASK_PHONEIN|SOUND_MASK_PHONEOUT) #define AC97_RECORD_MASK (SOUND_MASK_MIC|\ SOUND_MASK_CD|SOUND_MASK_VIDEO|\ diff -u --recursive --new-file v2.3.46/linux/drivers/sound/es1370.c linux/drivers/sound/es1370.c --- v2.3.46/linux/drivers/sound/es1370.c Wed Feb 16 17:03:52 2000 +++ linux/drivers/sound/es1370.c Sun Feb 20 20:16:30 2000 @@ -2466,6 +2466,10 @@ return -1; if (pcidev->irq == 0) return -1; + if (!pci_dma_supported(pcidev, 0xffffffff)) { + printk(KERN_WARNING "es1370: architecture does not support 32bit PCI busmaster DMA\n"); + return -1; + } if (!(s = kmalloc(sizeof(struct es1370_state), GFP_KERNEL))) { printk(KERN_WARNING "es1370: out of memory\n"); return -1; @@ -2589,7 +2593,7 @@ dev->driver_data = NULL; } -static const struct pci_device_id id_table[] __devinitdata = { +static struct pci_device_id id_table[] __devinitdata = { { PCI_VENDOR_ID_ENSONIQ, PCI_DEVICE_ID_ENSONIQ_ES1370, PCI_ANY_ID, PCI_ANY_ID, 0, 0 }, { 0, 0, 0, 0, 0, 0 } }; @@ -2608,8 +2612,10 @@ if (!pci_present()) /* No PCI bus in this machine! */ return -ENODEV; printk(KERN_INFO "es1370: version v0.33 time " __TIME__ " " __DATE__ "\n"); - if (!pci_register_driver(&es1370_driver)) + if (!pci_register_driver(&es1370_driver)) { + pci_unregister_driver(&es1370_driver); return -ENODEV; + } return 0; } diff -u --recursive --new-file v2.3.46/linux/drivers/sound/es1371.c linux/drivers/sound/es1371.c --- v2.3.46/linux/drivers/sound/es1371.c Wed Feb 16 17:03:52 2000 +++ linux/drivers/sound/es1371.c Sun Feb 20 20:16:30 2000 @@ -2624,6 +2624,10 @@ return -1; if (pcidev->irq == 0) return -1; + if (!pci_dma_supported(pcidev, 0xffffffff)) { + printk(KERN_WARNING "es1371: architecture does not support 32bit PCI busmaster DMA\n"); + return -1; + } if (!(s = kmalloc(sizeof(struct es1371_state), GFP_KERNEL))) { printk(KERN_WARNING "es1371: out of memory\n"); return -1; @@ -2788,7 +2792,7 @@ dev->driver_data = NULL; } -static const struct pci_device_id id_table[] __devinitdata = { +static struct pci_device_id id_table[] __devinitdata = { { PCI_VENDOR_ID_ENSONIQ, PCI_DEVICE_ID_ENSONIQ_ES1371, PCI_ANY_ID, PCI_ANY_ID, 0, 0 }, { PCI_VENDOR_ID_ENSONIQ, PCI_DEVICE_ID_ENSONIQ_CT5880, PCI_ANY_ID, PCI_ANY_ID, 0, 0 }, { PCI_VENDOR_ID_ECTIVA, PCI_DEVICE_ID_ECTIVA_EV1938, PCI_ANY_ID, PCI_ANY_ID, 0, 0 }, @@ -2809,8 +2813,10 @@ if (!pci_present()) /* No PCI bus in this machine! */ return -ENODEV; printk(KERN_INFO "es1371: version v0.25 time " __TIME__ " " __DATE__ "\n"); - if (!pci_register_driver(&es1371_driver)) + if (!pci_register_driver(&es1371_driver)) { + pci_unregister_driver(&es1371_driver); return -ENODEV; + } return 0; } diff -u --recursive --new-file v2.3.46/linux/drivers/sound/esssolo1.c linux/drivers/sound/esssolo1.c --- v2.3.46/linux/drivers/sound/esssolo1.c Wed Feb 16 17:03:52 2000 +++ linux/drivers/sound/esssolo1.c Sun Feb 20 20:17:31 2000 @@ -67,7 +67,7 @@ * Tim Janik's BSE (Bedevilled Sound Engine) found this * Integrated (aka redid 8-)) APM support patch by Zach Brown * 07.02.2000 0.13 Use pci_alloc_consistent and pci_register_driver - * + * 19.02.2000 0.14 Use pci_dma_supported to determine if recording should be disabled */ /*****************************************************************************/ @@ -412,7 +412,7 @@ db->mapped = db->ready = 0; } -static int prog_dmabuf(struct solo1_state *s, struct dmabuf *db, unsigned long dmamask) +static int prog_dmabuf(struct solo1_state *s, struct dmabuf *db) { int order; unsigned bytespersec; @@ -422,7 +422,6 @@ db->hwptr = db->swptr = db->total_bytes = db->count = db->error = db->endcleared = 0; if (!db->rawbuf) { db->ready = db->mapped = 0; - s->dev->dma_mask = dmamask; for (order = DMABUF_DEFAULTORDER; order >= DMABUF_MINORDER; order--) if ((db->rawbuf = pci_alloc_consistent(s->dev, PAGE_SIZE << order, &db->dmaaddr))) break; @@ -469,7 +468,10 @@ int c; stop_adc(s); - if ((c = prog_dmabuf(s, &s->dma_adc, 0xffffff))) + /* check if PCI implementation supports 24bit busmaster DMA */ + if (s->dev->dma_mask > 0xffffff) + return -EIO; + if ((c = prog_dmabuf(s, &s->dma_adc))) return c; va = s->dma_adc.dmaaddr; if ((va & ~((1<<24)-1))) @@ -494,7 +496,7 @@ int c; stop_dac(s); - if ((c = prog_dmabuf(s, &s->dma_dac, 0xffffffff))) + if ((c = prog_dmabuf(s, &s->dma_dac))) return c; memset(s->dma_dac.rawbuf, (s->fmt & (AFMT_U8 | AFMT_U16_LE)) ? 0 : 0x80, s->dma_dac.dmasize); /* almost correct for U16 */ va = s->dma_dac.dmaaddr; @@ -2193,6 +2195,8 @@ static int __devinit solo1_probe(struct pci_dev *pcidev, const struct pci_device_id *pciid) { struct solo1_state *s; + struct pm_dev *pmdev; + dma_addr_t dma_mask; if (!RSRCISIOREGION(pcidev, 0) || !RSRCISIOREGION(pcidev, 1) || @@ -2201,6 +2205,14 @@ return -1; if (pcidev->irq == 0) return -1; + if (pci_dma_supported(pcidev, 0x00ffffff)) { + dma_mask = 0x00ffffff; /* this enables playback and recording */ + } else if (pci_dma_supported(pcidev, 0xffffffff)) { + dma_mask = 0xffffffff; /* this enables only playback, as the recording BMDMA can handle only 24bits */ + } else { + printk(KERN_WARNING "solo1: architecture does not support 24bit or 32bit PCI busmaster DMA\n"); + return -1; + } if (!(s = kmalloc(sizeof(struct solo1_state), GFP_KERNEL))) { printk(KERN_WARNING "solo1: out of memory\n"); return -1; @@ -2258,7 +2270,7 @@ goto err; /* store it in the driver field */ pcidev->driver_data = s; - pcidev->dma_mask = 0xffffff; /* pessimistic; play can handle 32bit addrs */ + pcidev->dma_mask = dma_mask; /* put it into driver list */ list_add_tail(&s->devs, &devs); @@ -2318,7 +2330,7 @@ dev->driver_data = NULL; } -static const struct pci_device_id id_table[] __devinitdata = { +static struct pci_device_id id_table[] __devinitdata = { { PCI_VENDOR_ID_ESS, PCI_DEVICE_ID_ESS_SOLO1, PCI_ANY_ID, PCI_ANY_ID, 0, 0 }, { 0, 0, 0, 0, 0, 0 } }; @@ -2337,9 +2349,11 @@ { if (!pci_present()) /* No PCI bus in this machine! */ return -ENODEV; - printk(KERN_INFO "solo1: version v0.13 time " __TIME__ " " __DATE__ "\n"); - if (!pci_register_driver(&solo1_driver)) + printk(KERN_INFO "solo1: version v0.14 time " __TIME__ " " __DATE__ "\n"); + if (!pci_register_driver(&solo1_driver)) { + pci_unregister_driver(&solo1_driver); return -ENODEV; + } return 0; } diff -u --recursive --new-file v2.3.46/linux/drivers/sound/sb_card.c linux/drivers/sound/sb_card.c --- v2.3.46/linux/drivers/sound/sb_card.c Thu Feb 10 17:11:14 2000 +++ linux/drivers/sound/sb_card.c Fri Feb 18 16:50:49 2000 @@ -17,10 +17,15 @@ * 06-01-2000 Refined and bugfixed ISA PnP support, added * CMI 8330 support - Alessandro Zummo * - * * 04-02-2000 Added Soundblaster AWE 64 PnP support, isapnpjump * Alessandro Zummo * + * 11-02-2000 Added Soundblaster AWE 32 PnP support, refined PnP code + * Alessandro Zummo + * + * 13-02-2000 Hopefully fixed awe/sb16 related bugs, code cleanup. + * Alessandro Zummo + * */ #include @@ -134,7 +139,8 @@ struct pci_dev *sb_dev = NULL, *wss_dev = NULL, - *jp_dev = NULL, + *jp_dev = NULL, +/* *ide_dev = NULL, */ *mpu_dev = NULL, *wt_dev = NULL; /* @@ -156,9 +162,10 @@ int sm_games = 0; /* Mixer - see sb_mixer.c */ int acer = 0; /* Do acer notebook init */ -#ifdef CONFIG_ISAPNP +#if defined CONFIGISAPNP || defined CONFIG_ISAPNP_MODULE int isapnp = 1; int isapnpjump = 0; +int nosbwave = 0; /* This option will be removed when the new awe_wave driver will be in the kernel tree */ #else int isapnp = 0; #endif @@ -179,11 +186,13 @@ MODULE_PARM(esstype, "i"); MODULE_PARM(acer, "i"); -#ifdef CONFIG_ISAPNP +#if defined CONFIG_ISAPNP || defined CONFIG_ISAPNP_MODULE MODULE_PARM(isapnp, "i"); MODULE_PARM(isapnpjump, "i"); +MODULE_PARM(nosbwave, "i"); MODULE_PARM_DESC(isapnp, "When set to 0, Plug & Play support will be disabled"); MODULE_PARM_DESC(isapnpjump, "Jumps to a specific slot in the driver's PnP table. Use the source, Luke."); +MODULE_PARM_DESC(nosbwave, "Disable SB AWE 32/64 Wavetable initialization. Use this option with the new awe_wave driver."); #endif MODULE_PARM_DESC(io, "Soundblaster i/o base address (0x220,0x240,0x260,0x280)"); @@ -202,79 +211,86 @@ void *smw_free = NULL; -#ifdef CONFIG_ISAPNP +#if defined CONFIGISAPNP || defined CONFIG_ISAPNP_MODULE /* That's useful. */ -static int check_base(char *devname, char *resname, struct resource *res) +#define show_base(devname, resname, resptr) printk(KERN_INFO "sb: %s %s base located at %#lx\n", devname, resname, (resptr)->start) + +static struct pci_dev *activate_dev(char *devname, char *resname, struct pci_dev *dev) { - if (check_region(res->start, res->end - res->start)) + int err; + + if(dev->active) { - printk(KERN_ERR "sb: %s %s error, i/o at %#lx already in use\n", devname, resname, res->start); - return 0; + printk(KERN_INFO "sb: %s %s already in use\n", devname, resname); + return(NULL); } - printk(KERN_INFO "sb: %s %s base located at %#lx\n", devname, resname, res->start); - return 1; -} + if((err = dev->activate(dev)) < 0) + { + printk(KERN_ERR "sb: %s %s config failed (out of resources?)[%d]\n", devname, resname, err); + dev->deactivate(dev); + + return(NULL); + } + return(dev); +} /* Card's specific initialization functions */ -static struct pci_dev *sb_init_generic(struct pci_bus *card, struct address_info *hw_config, struct address_info *mpu_config) +static struct pci_dev *sb_init_generic(struct pci_bus *bus, struct pci_dev *card, struct address_info *hw_config, struct address_info *mpu_config) { - if((sb_dev = isapnp_find_dev(card, - card->vendor, - card->device, - NULL))) + if((sb_dev = isapnp_find_dev(bus, card->vendor, card->device, NULL))) { sb_dev->prepare(sb_dev); - sb_dev->activate(sb_dev); - if (!sb_dev->resource[0].start) - return(NULL); - - hw_config->io_base = sb_dev->resource[0].start; - hw_config->irq = sb_dev->irq_resource[0].start; - hw_config->dma = sb_dev->dma_resource[0].start; - hw_config->dma2 = sb_dev->dma_resource[1].start; - mpu_config->io_base = sb_dev->resource[1].start; + if((sb_dev = activate_dev("Soundblaster", "sb", sb_dev))) + { + hw_config->io_base = sb_dev->resource[0].start; + hw_config->irq = sb_dev->irq_resource[0].start; + hw_config->dma = sb_dev->dma_resource[0].start; + hw_config->dma2 = sb_dev->dma_resource[1].start; + mpu_config->io_base = sb_dev->resource[1].start; + } } return(sb_dev); } -static struct pci_dev *sb_init_ess(struct pci_bus *card, struct address_info *hw_config, struct address_info *mpu_config) +static struct pci_dev *sb_init_ess(struct pci_bus *bus, struct pci_dev *card, struct address_info *hw_config, struct address_info *mpu_config) { - if((sb_dev = isapnp_find_dev(card, - card->vendor, - card->device, - NULL))) + if((sb_dev = isapnp_find_dev(bus, card->vendor, card->device, NULL))) { sb_dev->prepare(sb_dev); - sb_dev->activate(sb_dev); - - if (!sb_dev->resource[0].start) - return(NULL); - hw_config->io_base = sb_dev->resource[0].start; - hw_config->irq = sb_dev->irq_resource[0].start; - hw_config->dma = sb_dev->dma_resource[0].start; - hw_config->dma2 = sb_dev->dma_resource[1].start; - mpu_config->io_base = sb_dev->resource[2].start; + if((sb_dev = activate_dev("ESS", "sb", sb_dev))) + { + hw_config->io_base = sb_dev->resource[0].start; + hw_config->irq = sb_dev->irq_resource[0].start; + hw_config->dma = sb_dev->dma_resource[0].start; + hw_config->dma2 = sb_dev->dma_resource[1].start; + mpu_config->io_base = sb_dev->resource[2].start; + } } return(sb_dev); } -static struct pci_dev *sb_init_cmi(struct pci_bus *card, struct address_info *hw_config, struct address_info *mpu_config) +static struct pci_dev *sb_init_cmi(struct pci_bus *bus, struct pci_dev *card, struct address_info *hw_config, struct address_info *mpu_config) { - /* What a stupid chip... where did they get all those @@@ ?*/ - - printk(KERN_INFO "sb: CMI8330 detected\n"); + /* + * The CMI8330/C3D is a very 'stupid' chip... where did they get al those @@@ ? + * It's ISAPnP section is badly designed and has many flaws, i'll do my best + * to workaround them. I strongly suggest you to buy a real soundcard. + * The CMI8330 on my motherboard has also the bad habit to activate + * the rear channel of my amplifier instead of the front one. + */ - /* Soundblaster compatible logical device. */ + /* @X@0001:Soundblaster. + */ - if((sb_dev = isapnp_find_dev(card, + if((sb_dev = isapnp_find_dev(bus, ISAPNP_VENDOR('@','X','@'), ISAPNP_FUNCTION(0x0001), NULL))) { #ifdef CMI8330_DMA0BAD @@ -283,11 +299,11 @@ sb_dev->prepare(sb_dev); /* This device doesn't work with DMA 0, so we must allocate - it to prevent PnP routines to assign it to the card. - - I know i could have inlined the following lines, but it's cleaner - this way. - */ + * it to prevent PnP routines to assign it to the card. + * + * I know i could have inlined the following lines, but it's cleaner + * this way. + */ #ifdef CMI8330_DMA0BAD if(sb_dev->dma_resource[0].start == 0) @@ -300,69 +316,72 @@ } #endif - if(sb_dev->activate(sb_dev) >= 0) + if((sb_dev = activate_dev("CMI8330", "sb", sb_dev))) { hw_config->io_base = sb_dev->resource[0].start; hw_config->irq = sb_dev->irq_resource[0].start; hw_config->dma = sb_dev->dma_resource[0].start; hw_config->dma2 = sb_dev->dma_resource[1].start; - check_base("CMI8330", "sb", &sb_dev->resource[0]); + show_base("CMI8330", "sb", &sb_dev->resource[0]); } - else - printk(KERN_ERR "sb: CMI8330 sb config failed (out of resources?)\n"); #ifdef CMI8330_DMA0BAD if(dmahack) free_dma(0); #endif + + if(!sb_dev) return(NULL); + } else - printk(KERN_ERR "sb: CMI8330 panic! sb base not found\n"); + printk(KERN_ERR "sb: CMI8330 panic: sb base not found\n"); + + /* @H@0001:mpu + */ - if((mpu_dev = isapnp_find_dev(card, +#ifdef CONFIG_MIDI + if((mpu_dev = isapnp_find_dev(bus, ISAPNP_VENDOR('@','H','@'), ISAPNP_FUNCTION(0x0001), NULL))) { mpu_dev->prepare(mpu_dev); - /* This disables the interrupt on this resource. Do we need it ? */ + /* This disables the interrupt on this resource. Do we need it ? + */ mpu_dev->irq_resource[0].flags = 0; - if(mpu_dev->activate(mpu_dev) >= 0) + if((mpu_dev = activate_dev("CMI8330", "mpu", mpu_dev))) { - if( check_base("CMI8330", "mpu", &mpu_dev->resource[0]) ) - mpu_config->io_base = mpu_dev->resource[0].start; + show_base("CMI8330", "mpu", &mpu_dev->resource[0]); + mpu_config->io_base = mpu_dev->resource[0].start; } - else - printk(KERN_ERR "sb: CMI8330 mpu config failed (out of resources?)\n"); } else - printk(KERN_ERR "sb: CMI8330 panic! mpu not found\n"); + printk(KERN_ERR "sb: CMI8330 panic: mpu not found\n"); +#endif - /* Gameport. */ + /* @P@:Gameport + */ - if((jp_dev = isapnp_find_dev(card, + if((jp_dev = isapnp_find_dev(bus, ISAPNP_VENDOR('@','P','@'), ISAPNP_FUNCTION(0x0001), NULL))) { jp_dev->prepare(jp_dev); - if(jp_dev->activate(jp_dev) >= 0) - { - check_base("CMI8330", "gameport", &jp_dev->resource[0]); - } - else - printk(KERN_ERR "sb: CMI8330 gameport config failed (out of resources?)\n"); + + if((jp_dev = activate_dev("CMI8330", "gameport", jp_dev))) + show_base("CMI8330", "gameport", &jp_dev->resource[0]); } else - printk(KERN_ERR "sb: CMI8330 panic! gameport not found\n"); + printk(KERN_ERR "sb: CMI8330 panic: gameport not found\n"); - - /* OPL3 support */ + /* @@@0001:OPL3 + */ #if defined(CONFIG_SOUND_YM3812) || defined(CONFIG_SOUND_YM3812_MODULE) - if((wss_dev = isapnp_find_dev(card, + if((wss_dev = isapnp_find_dev(bus, ISAPNP_VENDOR('@','@','@'), ISAPNP_FUNCTION(0x0001), NULL))) { wss_dev->prepare(wss_dev); @@ -372,15 +391,11 @@ wss_dev->irq_resource[0].flags = 0; wss_dev->dma_resource[0].flags = 0; - if(wss_dev->activate(wss_dev) >= 0) - { - check_base("CMI8330", "opl3", &wss_dev->resource[1]); - } - else - printk(KERN_ERR "sb: CMI8330 opl3 config failed (out of resources?)\n"); + if((wss_dev = activate_dev("CMI8330", "opl3", wss_dev))) + show_base("CMI8330", "opl3", &wss_dev->resource[1]); } else - printk(KERN_ERR "sb: CMI8330 panic! opl3 not found\n"); + printk(KERN_ERR "sb: CMI8330 panic: opl3 not found\n"); #endif printk(KERN_INFO "sb: CMI8330 mail reports to Alessandro Zummo \n"); @@ -388,18 +403,25 @@ return(sb_dev); } -static struct pci_dev *sb_init_awe64(struct pci_bus *card, struct address_info *hw_config, struct address_info *mpu_config) -{ - printk(KERN_INFO "sb: SoundBlaster AWE 64 detected\n"); - - /* CTL0042:Audio. */ +/* Specific support for awe will be dropped when: + * a) The new awe_wawe driver with PnP support will be introduced in the kernel + * b) The joystick driver will support PnP + */ - if((sb_dev = isapnp_find_dev(card, - ISAPNP_VENDOR('C','T','L'), ISAPNP_FUNCTION(0x0042), NULL))) +static struct pci_dev *sb_init_awe(struct pci_bus *bus, struct pci_dev *card, struct address_info *hw_config, struct address_info *mpu_config) +{ + /* CTL0042:Audio SB64 + * CTL0031:Audio SB32 + * CTL0045:Audio SB64 + */ + + if( (sb_dev = isapnp_find_dev(bus, ISAPNP_VENDOR('C','T','L'), ISAPNP_FUNCTION(0x0042), NULL)) || + (sb_dev = isapnp_find_dev(bus, ISAPNP_VENDOR('C','T','L'), ISAPNP_FUNCTION(0x0031), NULL)) || + (sb_dev = isapnp_find_dev(bus, ISAPNP_VENDOR('C','T','L'), ISAPNP_FUNCTION(0x0045), NULL)) ) { sb_dev->prepare(sb_dev); - if(sb_dev->activate(sb_dev) >= 0) + if((sb_dev = activate_dev("AWE", "sb", sb_dev))) { hw_config->io_base = sb_dev->resource[0].start; hw_config->irq = sb_dev->irq_resource[0].start; @@ -408,87 +430,144 @@ mpu_config->io_base = sb_dev->resource[1].start; - check_base("AWE64", "sb", &sb_dev->resource[0]); - check_base("AWE64", "mpu", &sb_dev->resource[1]); - check_base("AWE64", "opl3", &sb_dev->resource[2]); + show_base("AWE", "sb", &sb_dev->resource[0]); + show_base("AWE", "mpu", &sb_dev->resource[1]); + show_base("AWE", "opl3", &sb_dev->resource[2]); } else - printk(KERN_ERR "sb: AWE64 sb config failed (out of resources?)\n"); + return(NULL); } else - printk(KERN_ERR "sb: AWE64 panic! sb base not found\n"); + printk(KERN_ERR "sb: AWE panic: sb base not found\n"); - /* CTL7002:Game */ + /* CTL7002:Game SB64 + * CTL7001:Game SB32 + */ - if((jp_dev = isapnp_find_dev(card, - ISAPNP_VENDOR('C','T','L'), ISAPNP_FUNCTION(0x7002), NULL))) + if( (jp_dev = isapnp_find_dev(bus, ISAPNP_VENDOR('C','T','L'), ISAPNP_FUNCTION(0x7002), NULL)) || + (jp_dev = isapnp_find_dev(bus, ISAPNP_VENDOR('C','T','L'), ISAPNP_FUNCTION(0x7001), NULL)) ) { jp_dev->prepare(jp_dev); - if(jp_dev->activate(jp_dev) >= 0) + if((jp_dev = activate_dev("AWE", "gameport", jp_dev))) + show_base("AWE", "gameport", &jp_dev->resource[0]); + } + else + printk(KERN_ERR "sb: AWE panic: gameport not found\n"); + + + /* CTL0022:WaveTable SB64 + * CTL0021:WaveTable SB32 + */ + + if( nosbwave == 0 && + ( (wt_dev = isapnp_find_dev(bus, ISAPNP_VENDOR('C','T','L'), ISAPNP_FUNCTION(0x0023), NULL)) || + (wt_dev = isapnp_find_dev(bus, ISAPNP_VENDOR('C','T','L'), ISAPNP_FUNCTION(0x0022), NULL)) || + (wt_dev = isapnp_find_dev(bus, ISAPNP_VENDOR('C','T','L'), ISAPNP_FUNCTION(0x0021), NULL)) )) + { + wt_dev->prepare(wt_dev); + + if((wt_dev = activate_dev("AWE", "wavetable", wt_dev))) { - check_base("AWE64", "gameport", &jp_dev->resource[0]); + show_base("AWE", "wavetable", &wt_dev->resource[0]); + show_base("AWE", "wavetable", &wt_dev->resource[1]); + show_base("AWE", "wavetable", &wt_dev->resource[2]); } - else - printk(KERN_ERR "sb: AWE64 gameport config failed (out of resources?)\n"); } else - printk(KERN_ERR "sb: AWE64 panic! gameport not found\n"); + printk(KERN_ERR "sb: AWE panic: wavetable not found\n"); - /* CTL0022:WaveTable */ + /* CTL2011:IDE SB32/64 + */ - if((wt_dev = isapnp_find_dev(card, - ISAPNP_VENDOR('C','T','L'), ISAPNP_FUNCTION(0x0022), NULL))) +/* No reasons to enable this... or not? */ +/* + if( (ide_dev = isapnp_find_dev(bus, ISAPNP_VENDOR('C','T','L'), ISAPNP_FUNCTION(0x2011), NULL)) ) { - wt_dev->prepare(wt_dev); + ide_dev->prepare(ide_dev); - if(wt_dev->activate(wt_dev) >= 0) + if((ide_dev = activate_dev("AWE", "IDE", ide_dev))) { - check_base("AWE64", "wavetable", &wt_dev->resource[0]); - check_base("AWE64", "wavetable", &wt_dev->resource[1]); - check_base("AWE64", "wavetable", &wt_dev->resource[2]); + show_base("AWE", "IDE 1", &ide_dev->resource[0]); + show_base("AWE", "IDE 2", &ide_dev->resource[1]); } - else - printk(KERN_ERR "sb: AWE64 wavetable config failed (out of resources?)\n"); } else - printk(KERN_ERR "sb: AWE64 panic! wavetable not found\n"); + printk(KERN_ERR "sb: AWE panic: IDE not found\n"); +*/ - printk(KERN_INFO "sb: AWE64 mail reports to Alessandro Zummo \n"); + printk(KERN_INFO "sb: AWE mail reports to Alessandro Zummo \n"); return(sb_dev); } +#define SBF_DEV 0x01 -static struct { unsigned short vendor, function; struct pci_dev * (*initfunc)(struct pci_bus *, struct address_info *, struct address_info *); char *name; } + +static struct { unsigned short vendor, function, flags; struct pci_dev * (*initfunc)(struct pci_bus *, struct pci_dev *, struct address_info *, struct address_info *); char *name; } isapnp_sb_list[] __initdata = { - {ISAPNP_VENDOR('C','T','L'), ISAPNP_FUNCTION(0x0001), &sb_init_generic, "Sound Blaster 16" }, - {ISAPNP_VENDOR('C','T','L'), ISAPNP_FUNCTION(0x0031), &sb_init_generic, "Sound Blaster 16" }, - {ISAPNP_VENDOR('C','T','L'), ISAPNP_FUNCTION(0x0041), &sb_init_generic, "Sound Blaster 16" }, - {ISAPNP_VENDOR('C','T','L'), ISAPNP_FUNCTION(0x0042), &sb_init_generic, "Sound Blaster 16" }, - {ISAPNP_VENDOR('C','T','L'), ISAPNP_FUNCTION(0x0043), &sb_init_generic, "Sound Blaster 16" }, - {ISAPNP_VENDOR('C','T','L'), ISAPNP_FUNCTION(0x0044), &sb_init_generic, "Sound Blaster 16" }, - {ISAPNP_VENDOR('C','T','L'), ISAPNP_FUNCTION(0x0045), &sb_init_generic, "Sound Blaster 16" }, - {ISAPNP_VENDOR('C','T','L'), ISAPNP_FUNCTION(0x009D), &sb_init_awe64, "Sound Blaster AWE 64" }, - {ISAPNP_VENDOR('E','S','S'), ISAPNP_FUNCTION(0x1868), &sb_init_ess, "ESS 1868" }, - {ISAPNP_VENDOR('E','S','S'), ISAPNP_FUNCTION(0x8611), &sb_init_ess, "ESS 1868" }, - {ISAPNP_VENDOR('E','S','S'), ISAPNP_FUNCTION(0x1869), &sb_init_ess, "ESS 1869" }, - {ISAPNP_VENDOR('E','S','S'), ISAPNP_FUNCTION(0x1878), &sb_init_ess, "ESS 1878" }, - {ISAPNP_VENDOR('E','S','S'), ISAPNP_FUNCTION(0x1879), &sb_init_ess, "ESS 1879" }, - {ISAPNP_VENDOR('C','M','I'), ISAPNP_FUNCTION(0x0001), &sb_init_cmi, "CMI 8330 SoundPRO" }, + {ISAPNP_VENDOR('C','T','L'), ISAPNP_FUNCTION(0x0001), SBF_DEV, &sb_init_generic, "Sound Blaster 16" }, + {ISAPNP_VENDOR('C','T','L'), ISAPNP_FUNCTION(0x0031), SBF_DEV, &sb_init_generic, "Sound Blaster 16" }, + {ISAPNP_VENDOR('C','T','L'), ISAPNP_FUNCTION(0x0041), SBF_DEV, &sb_init_generic, "Sound Blaster 16" }, + {ISAPNP_VENDOR('C','T','L'), ISAPNP_FUNCTION(0x0042), SBF_DEV, &sb_init_generic, "Sound Blaster 16" }, + {ISAPNP_VENDOR('C','T','L'), ISAPNP_FUNCTION(0x0043), SBF_DEV, &sb_init_generic, "Sound Blaster 16" }, + {ISAPNP_VENDOR('C','T','L'), ISAPNP_FUNCTION(0x0045), SBF_DEV, &sb_init_generic, "Sound Blaster 16" }, + {ISAPNP_VENDOR('C','T','L'), ISAPNP_FUNCTION(0x0044), 0, &sb_init_awe, "Sound Blaster 32" }, + {ISAPNP_VENDOR('C','T','L'), ISAPNP_FUNCTION(0x0039), 0, &sb_init_awe, "Sound Blaster AWE 32" }, + {ISAPNP_VENDOR('C','T','L'), ISAPNP_FUNCTION(0x009D), 0, &sb_init_awe, "Sound Blaster AWE 64" }, + {ISAPNP_VENDOR('C','T','L'), ISAPNP_FUNCTION(0x00C5), 0, &sb_init_awe, "Sound Blaster AWE 64" }, + {ISAPNP_VENDOR('C','T','L'), ISAPNP_FUNCTION(0x00E4), 0, &sb_init_awe, "Sound Blaster AWE 64" }, + {ISAPNP_VENDOR('E','S','S'), ISAPNP_FUNCTION(0x1868), SBF_DEV, &sb_init_ess, "ESS 1868" }, + {ISAPNP_VENDOR('E','S','S'), ISAPNP_FUNCTION(0x8611), SBF_DEV, &sb_init_ess, "ESS 1868" }, + {ISAPNP_VENDOR('E','S','S'), ISAPNP_FUNCTION(0x1869), SBF_DEV, &sb_init_ess, "ESS 1869" }, + {ISAPNP_VENDOR('E','S','S'), ISAPNP_FUNCTION(0x1878), SBF_DEV, &sb_init_ess, "ESS 1878" }, + {ISAPNP_VENDOR('E','S','S'), ISAPNP_FUNCTION(0x1879), SBF_DEV, &sb_init_ess, "ESS 1879" }, + {ISAPNP_VENDOR('C','M','I'), ISAPNP_FUNCTION(0x0001), 0, &sb_init_cmi, "CMI 8330 SoundPRO" }, {0} }; +static int __init sb_init_isapnp(struct address_info *hw_config, struct address_info *mpu_config, struct pci_bus *bus, struct pci_dev *card, int slot) +{ + struct pci_dev *idev = NULL; + + /* You missed the init func? That's bad. */ + if(isapnp_sb_list[slot].initfunc) + { + char *busname = bus->name[0] ? bus->name : isapnp_sb_list[slot].name; + + printk(KERN_INFO "sb: %s detected\n", busname); + + /* Initialize this baby. */ + + if((idev = isapnp_sb_list[slot].initfunc(bus, card, hw_config, mpu_config))) + { + /* We got it. */ + + printk(KERN_NOTICE "sb: ISAPnP reports '%s' at i/o %#x, irq %d, dma %d, %d\n", + busname, + hw_config->io_base, hw_config->irq, hw_config->dma, + hw_config->dma2); + return 1; + } + else + printk(KERN_INFO "sb: Failed to initialize %s\n", busname); + } + else + printk(KERN_ERR "sb: Bad entry in sb_card.c PnP table\n"); + + return 0; +} + /* Actually this routine will detect and configure only the first card with successful - initalization. isapnpjump could be used to jump to a specific entry. + initialization. isapnpjump could be used to jump to a specific entry. Please always add entries at the end of the array. Should this be fixed? - azummo */ -static int __init sb_probe_isapnp(struct address_info *hw_config, struct address_info *mpu_config) { - +static int __init sb_probe_isapnp(struct address_info *hw_config, struct address_info *mpu_config) +{ int i; /* Count entries in isapnp_sb_list */ @@ -502,34 +581,43 @@ } for (i = isapnpjump; isapnp_sb_list[i].vendor != 0; i++) { - struct pci_bus *card = NULL; - - while ((card = isapnp_find_card( - isapnp_sb_list[i].vendor, - isapnp_sb_list[i].function, - card))) { - /* You missed the init func? That's bad. */ + if(!(isapnp_sb_list[i].flags & SBF_DEV)) + { + struct pci_bus *bus = NULL; + + while ((bus = isapnp_find_card( + isapnp_sb_list[i].vendor, + isapnp_sb_list[i].function, + bus))) { + + if(sb_init_isapnp(hw_config, mpu_config, bus, NULL, i)) + return 0; + } + } + } - if(isapnp_sb_list[i].initfunc) - { - struct pci_dev *idev = NULL; + /* No cards found. I'll try now to search inside every card for a logical device + * that matches any entry marked with SBF_DEV in the table. + */ + + for (i = isapnpjump; isapnp_sb_list[i].vendor != 0; i++) { - /* Initialize this baby. */ + if(isapnp_sb_list[i].flags & SBF_DEV) + { + struct pci_dev *card = NULL; + + while ((card = isapnp_find_dev(NULL, + isapnp_sb_list[i].vendor, + isapnp_sb_list[i].function, + card))) { - if((idev = isapnp_sb_list[i].initfunc(card, hw_config, mpu_config))) - { - /* We got it. */ - - printk(KERN_INFO "sb: ISAPnP reports %s at i/o %#x, irq %d, dma %d, %d\n", - isapnp_sb_list[i].name, - hw_config->io_base, hw_config->irq, hw_config->dma, - hw_config->dma2); + if(sb_init_isapnp(hw_config, mpu_config, card->bus, card, i)) return 0; - } } } } + return -ENODEV; } #endif @@ -544,18 +632,15 @@ able to disable PNP support for this single driver! */ -#ifdef CONFIG_ISAPNP - if (isapnp) +#if defined CONFIGISAPNP || defined CONFIG_ISAPNP_MODULE + if(isapnp && (sb_probe_isapnp(&config, &config_mpu) < 0) ) { - if(sb_probe_isapnp(&config, &config_mpu) < 0 ) - { - printk(KERN_ERR "sb_card: No ISAPnP cards found\n"); - return -EINVAL; - } + printk(KERN_NOTICE "sb_card: No ISAPnP cards found, trying standard ones...\n"); + isapnp = 0; } - else +#endif + if(isapnp == 0) { -#endif if (io == -1 || dma == -1 || irq == -1) { printk(KERN_ERR "sb_card: I/O, IRQ, and DMA are mandatory\n"); @@ -566,11 +651,8 @@ config.irq = irq; config.dma = dma; config.dma2 = dma16; -#ifdef CONFIG_ISAPNP } -#endif - /* If this is not before the #ifdef line, there's a reason... */ config.card_subtype = type; if (!probe_sb(&config)) @@ -604,6 +686,7 @@ if(sb_dev) sb_dev->deactivate(sb_dev); if(jp_dev) jp_dev->deactivate(jp_dev); if(wt_dev) wt_dev->deactivate(wt_dev); +/* if(ide_dev) wt_dev->deactivate(ide_dev); */ if(mpu_dev) mpu_dev->deactivate(mpu_dev); if(wss_dev) wss_dev->deactivate(wss_dev); } diff -u --recursive --new-file v2.3.46/linux/drivers/sound/sonicvibes.c linux/drivers/sound/sonicvibes.c --- v2.3.46/linux/drivers/sound/sonicvibes.c Wed Feb 16 17:03:52 2000 +++ linux/drivers/sound/sonicvibes.c Sun Feb 20 20:16:30 2000 @@ -2447,6 +2447,10 @@ return -1; if (pcidev->irq == 0) return -1; + if (!pci_dma_supported(pcidev, 0x00ffffff)) { + printk(KERN_WARNING "sonicvibes: architecture does not support 24bit PCI busmaster DMA\n"); + return -1; + } /* try to allocate a DDMA resource if not already available */ if (!RSRCISIOREGION(pcidev, RESOURCE_DDMA)) { pcidev->resource[RESOURCE_DDMA].start = 0; @@ -2625,7 +2629,7 @@ dev->driver_data = NULL; } -static const struct pci_device_id id_table[] __devinitdata = { +static struct pci_device_id id_table[] __devinitdata = { { PCI_VENDOR_ID_S3, PCI_DEVICE_ID_S3_SONICVIBES, PCI_ANY_ID, PCI_ANY_ID, 0, 0 }, { 0, 0, 0, 0, 0, 0 } }; @@ -2648,8 +2652,10 @@ if (!(wavetable_mem = __get_free_pages(GFP_KERNEL, 20-PAGE_SHIFT))) printk(KERN_INFO "sv: cannot allocate 1MB of contiguous nonpageable memory for wavetable data\n"); #endif - if (!pci_register_driver(&sv_driver)) + if (!pci_register_driver(&sv_driver)) { + pci_unregister_driver(&sv_driver); return -ENODEV; + } return 0; } diff -u --recursive --new-file v2.3.46/linux/drivers/usb/Makefile linux/drivers/usb/Makefile --- v2.3.46/linux/drivers/usb/Makefile Wed Feb 16 17:03:52 2000 +++ linux/drivers/usb/Makefile Sun Feb 20 16:20:47 2000 @@ -23,16 +23,12 @@ list-multi := usbcore.o usbcore-objs := usb.o usb-debug.o usb-core.o hub.o -usb-storage-objs := usb_storage.o # Optional parts of multipart objects. ifeq ($(CONFIG_USB_DEVICEFS),y) usbcore-objs += devio.o inode.o drivers.o devices.o endif -ifeq ($(CONFIG_USB_STORAGE_DEBUG),y) - usb-storage-objs += usb_storage_debug.o -endif # Object file lists. @@ -106,7 +102,4 @@ usbcore.o: $(usbcore-objs) $(LD) -r -o $@ $(usbcore-objs) - -usb-storage.o: $(usb-storage-objs) - $(LD) -r -o $@ $(usb-storage-objs) diff -u --recursive --new-file v2.3.46/linux/drivers/usb/acm.c linux/drivers/usb/acm.c --- v2.3.46/linux/drivers/usb/acm.c Sat Feb 12 11:22:11 2000 +++ linux/drivers/usb/acm.c Sun Feb 20 13:06:56 2000 @@ -1,5 +1,5 @@ /* - * acm.c Version 0.15 + * acm.c Version 0.16 * * Copyright (c) 1999 Armin Fuerst * Copyright (c) 1999 Pavel Machek @@ -18,6 +18,7 @@ * v0.13 - added termios, added hangup * v0.14 - sized down struct acm * v0.15 - fixed flow control again - characters could be lost + * v0.16 - added code for modems with swapped data and control interfaces */ /* @@ -473,29 +474,34 @@ for (i = 0; i < dev->descriptor.bNumConfigurations; i++) { cfacm = dev->config + i; - dbg("probing config %d", cfacm->bConfigurationValue); - ifcom = cfacm->interface[0].altsetting + 0; - if (ifcom->bInterfaceClass != 2 || ifcom->bInterfaceSubClass != 2 || - ifcom->bInterfaceProtocol != 1 || ifcom->bNumEndpoints != 1) - continue; + dbg("probing config %d", cfacm->bConfigurationValue); - epctrl = ifcom->endpoint + 0; - if ((epctrl->bEndpointAddress & 0x80) != 0x80 || (epctrl->bmAttributes & 3) != 3) + if (cfacm->bNumInterfaces != 2 || + usb_interface_claimed(cfacm->interface + 0) || + usb_interface_claimed(cfacm->interface + 1)) continue; + ifcom = cfacm->interface[0].altsetting + 0; ifdata = cfacm->interface[1].altsetting + 0; - if (ifdata->bInterfaceClass != 10 || ifdata->bNumEndpoints != 2) - continue; - if (usb_interface_claimed(cfacm->interface + 0) || - usb_interface_claimed(cfacm->interface + 1)) + if (ifdata->bInterfaceClass != 10 || ifdata->bNumEndpoints != 2) { + ifcom = cfacm->interface[1].altsetting + 0; + ifdata = cfacm->interface[0].altsetting + 0; + if (ifdata->bInterfaceClass != 10 || ifdata->bNumEndpoints != 2) + continue; + } + + if (ifcom->bInterfaceClass != 2 || ifcom->bInterfaceSubClass != 2 || + ifcom->bInterfaceProtocol != 1 || ifcom->bNumEndpoints != 1) continue; + epctrl = ifcom->endpoint + 0; epread = ifdata->endpoint + 0; epwrite = ifdata->endpoint + 1; - if ((epread->bmAttributes & 3) != 2 || (epwrite->bmAttributes & 3) != 2 || + if ((epctrl->bEndpointAddress & 0x80) != 0x80 || (epctrl->bmAttributes & 3) != 3 || + (epread->bmAttributes & 3) != 2 || (epwrite->bmAttributes & 3) != 2 || ((epread->bEndpointAddress & 0x80) ^ (epwrite->bEndpointAddress & 0x80)) != 0x80) continue; @@ -640,17 +646,13 @@ * Init / cleanup. */ -#ifdef MODULE -void cleanup_module(void) +static void __exit usb_acm_cleanup(void) { usb_deregister(&acm_driver); tty_unregister_driver(&acm_tty_driver); } -int init_module(void) -#else -int usb_acm_init(void) -#endif +static int __init usb_acm_init(void) { acm_tty_driver.init_termios = tty_std_termios; acm_tty_driver.init_termios.c_cflag = B9600 | CS8 | CREAD | HUPCL | CLOCAL; @@ -666,4 +668,5 @@ return 0; } -__initcall(usb_acm_init); +module_init(usb_acm_init); +module_exit(usb_acm_cleanup); diff -u --recursive --new-file v2.3.46/linux/drivers/usb/hid.c linux/drivers/usb/hid.c --- v2.3.46/linux/drivers/usb/hid.c Wed Feb 16 17:03:52 2000 +++ linux/drivers/usb/hid.c Fri Feb 18 10:33:47 2000 @@ -833,23 +833,45 @@ } break; - case HID_UP_HOTKEY: + case HID_UP_CONSUMER: /* USB HUT v1.1, pages 56-62 */ switch (usage->hid & HID_USAGE) { - case 0x0034: usage->code = KEY_PHONE; break; - case 0x0036: usage->code = KEY_NOTEPAD; break; - case 0x008a: usage->code = KEY_MAIL; break; - case 0x0095: usage->code = KEY_CALENDAR; break; - case 0x00b7: usage->code = KEY_PRINT; break; - case 0x00b8: usage->code = KEY_HELP; break; - case 0x00cd: usage->code = KEY_SOUND; break; - case 0x00e2: usage->code = KEY_PROG1; break; - case 0x00e9: usage->code = KEY_PROG2; break; - case 0x00ea: usage->code = KEY_PROG3; break; - case 0x018a: usage->code = KEY_WWW; break; - case 0x0223: usage->code = KEY_FULLSCREEN; break; - default: usage->code = KEY_UNKNOWN; break; + case 0x034: usage->code = KEY_SLEEP; break; + case 0x036: usage->code = BTN_MISC; break; + case 0x08a: usage->code = KEY_WWW; break; + case 0x095: usage->code = KEY_HELP; break; + + case 0x0b4: usage->code = KEY_REWIND; break; + case 0x0b5: usage->code = KEY_NEXTSONG; break; + case 0x0b6: usage->code = KEY_PREVIOUSSONG; break; + case 0x0b7: usage->code = KEY_STOPCD; break; + case 0x0b8: usage->code = KEY_EJECTCD; break; + case 0x0cd: usage->code = KEY_PLAYPAUSE; break; + + case 0x0e2: usage->code = KEY_MUTE; break; + case 0x0e9: usage->code = KEY_VOLUMEUP; break; + case 0x0ea: usage->code = KEY_VOLUMEDOWN; break; + + case 0x183: usage->code = KEY_CONFIG; break; + case 0x18a: usage->code = KEY_MAIL; break; + case 0x192: usage->code = KEY_CALC; break; + case 0x194: usage->code = KEY_FILE; break; + + case 0x21a: usage->code = KEY_UNDO; break; + case 0x21b: usage->code = KEY_COPY; break; + case 0x21c: usage->code = KEY_CUT; break; + case 0x21d: usage->code = KEY_PASTE; break; + + case 0x221: usage->code = KEY_FIND; break; + case 0x223: usage->code = KEY_HOMEPAGE; break; + case 0x224: usage->code = KEY_BACK; break; + case 0x225: usage->code = KEY_FORWARD; break; + case 0x226: usage->code = KEY_STOP; break; + case 0x227: usage->code = KEY_REFRESH; break; + case 0x22a: usage->code = KEY_BOOKMARKS; break; + + default: usage->code = KEY_UNKNOWN; break; } diff -u --recursive --new-file v2.3.46/linux/drivers/usb/hid.h linux/drivers/usb/hid.h --- v2.3.46/linux/drivers/usb/hid.h Sat Feb 12 11:22:11 2000 +++ linux/drivers/usb/hid.h Fri Feb 18 10:33:47 2000 @@ -158,7 +158,7 @@ #define HID_UP_KEYBOARD 0x00070000 #define HID_UP_LED 0x00080000 #define HID_UP_BUTTON 0x00090000 -#define HID_UP_HOTKEY 0x000c0000 +#define HID_UP_CONSUMER 0x000c0000 #define HID_UP_DIGITIZER 0x000d0000 #define HID_UP_PID 0x000f0000 @@ -201,7 +201,7 @@ * This is the local enviroment. It is resistent up the the next main-item. */ -#define MAX_USAGES 256 +#define MAX_USAGES 512 struct hid_local { unsigned usage[MAX_USAGES]; /* usage array */ diff -u --recursive --new-file v2.3.46/linux/drivers/usb/plusb.c linux/drivers/usb/plusb.c --- v2.3.46/linux/drivers/usb/plusb.c Wed Feb 16 17:03:52 2000 +++ linux/drivers/usb/plusb.c Sun Feb 20 13:06:56 2000 @@ -502,7 +502,7 @@ dbg("plusb: probe: vendor id 0x%x, device id 0x%x ifnum:%d", usbdev->descriptor.idVendor, usbdev->descriptor.idProduct, ifnum); - if (usbdev->descriptor.idVendor != 0x067b || usbdev->descriptor.idProduct != 0x1) + if (usbdev->descriptor.idVendor != 0x067b || usbdev->descriptor.idProduct > 0x1) return NULL; /* We don't handle multiple configurations */ diff -u --recursive --new-file v2.3.46/linux/drivers/usb/printer.c linux/drivers/usb/printer.c --- v2.3.46/linux/drivers/usb/printer.c Sat Feb 12 11:22:11 2000 +++ linux/drivers/usb/printer.c Sun Feb 20 13:06:56 2000 @@ -432,15 +432,12 @@ minor: USBLP_MINOR_BASE }; -#ifdef MODULE -void cleanup_module(void) +static void __exit usb_printer_cleanup(void) { usb_deregister(&usblp_driver); } -int init_module(void) -#else -int usb_printer_init(void) -#endif + +static int __init usb_printer_init(void) { if (usb_register(&usblp_driver)) return -1; @@ -448,4 +445,5 @@ return 0; } -__initcall(usb_printer_init); +module_init(usb_printer_init); +module_exit(usb_printer_cleanup); diff -u --recursive --new-file v2.3.46/linux/drivers/usb/uhci-debug.h linux/drivers/usb/uhci-debug.h --- v2.3.46/linux/drivers/usb/uhci-debug.h Tue Feb 1 01:35:44 2000 +++ linux/drivers/usb/uhci-debug.h Sun Feb 20 13:07:04 2000 @@ -193,7 +193,7 @@ void uhci_show_queues(struct uhci *uhci) { - int i, isqh; + int i, isqh = 0; struct uhci_qh *qh; struct uhci_td *td; diff -u --recursive --new-file v2.3.46/linux/drivers/usb/usb-core.c linux/drivers/usb/usb-core.c --- v2.3.46/linux/drivers/usb/usb-core.c Wed Feb 16 17:03:52 2000 +++ linux/drivers/usb/usb-core.c Sun Feb 20 13:06:56 2000 @@ -33,8 +33,6 @@ int usb_cpia_init(void); int usb_ibmcam_init(void); int usb_ov511_init(void); -int usb_dc2xx_init(void); -int usb_scanner_init(void); int usb_stor_init(void); int dabusb_init(void); int plusb_init(void); @@ -76,9 +74,6 @@ usb_hub_init(); #ifndef CONFIG_USB_MODULE -#ifdef CONFIG_USB_SCANNER - usb_scanner_init(); -#endif #ifdef CONFIG_USB_AUDIO usb_audio_init(); #endif @@ -90,9 +85,6 @@ #endif #ifdef CONFIG_USB_OV511 usb_ov511_init(); -#endif -#ifdef CONFIG_USB_DC2XX - usb_dc2xx_init(); #endif #ifdef CONFIG_USB_STORAGE usb_stor_init(); diff -u --recursive --new-file v2.3.46/linux/drivers/usb/usb-storage-debug.h linux/drivers/usb/usb-storage-debug.h --- v2.3.46/linux/drivers/usb/usb-storage-debug.h Wed Dec 31 16:00:00 1969 +++ linux/drivers/usb/usb-storage-debug.h Sun Feb 20 16:20:47 2000 @@ -0,0 +1,88 @@ +#ifdef CONFIG_USB_STORAGE_DEBUG + +/* Debug output for Driver for USB mass storage (scsi-like) devices + * + * (C) Michael Gee (michael@linuxspecific.com) 1999 + * + */ + +void us_show_command(Scsi_Cmnd *srb) +{ + char *what = NULL; + + switch (srb->cmnd[0]) { + case TEST_UNIT_READY: what = "TEST_UNIT_READY"; break; + case REZERO_UNIT: what = "REZERO_UNIT"; break; + case REQUEST_SENSE: what = "REQUEST_SENSE"; break; + case FORMAT_UNIT: what = "FORMAT_UNIT"; break; + case READ_BLOCK_LIMITS: what = "READ_BLOCK_LIMITS"; break; + case REASSIGN_BLOCKS: what = "REASSIGN_BLOCKS"; break; + case READ_6: what = "READ_6"; break; + case WRITE_6: what = "WRITE_6"; break; + case SEEK_6: what = "SEEK_6"; break; + case READ_REVERSE: what = "READ_REVERSE"; break; + case WRITE_FILEMARKS: what = "WRITE_FILEMARKS"; break; + case SPACE: what = "SPACE"; break; + case INQUIRY: what = "INQUIRY"; break; + case RECOVER_BUFFERED_DATA: what = "RECOVER_BUFFERED_DATA"; break; + case MODE_SELECT: what = "MODE_SELECT"; break; + case RESERVE: what = "RESERVE"; break; + case RELEASE: what = "RELEASE"; break; + case COPY: what = "COPY"; break; + case ERASE: what = "ERASE"; break; + case MODE_SENSE: what = "MODE_SENSE"; break; + case START_STOP: what = "START_STOP"; break; + case RECEIVE_DIAGNOSTIC: what = "RECEIVE_DIAGNOSTIC"; break; + case SEND_DIAGNOSTIC: what = "SEND_DIAGNOSTIC"; break; + case ALLOW_MEDIUM_REMOVAL: what = "ALLOW_MEDIUM_REMOVAL"; break; + case SET_WINDOW: what = "SET_WINDOW"; break; + case READ_CAPACITY: what = "READ_CAPACITY"; break; + case READ_10: what = "READ_10"; break; + case WRITE_10: what = "WRITE_10"; break; + case SEEK_10: what = "SEEK_10"; break; + case WRITE_VERIFY: what = "WRITE_VERIFY"; break; + case VERIFY: what = "VERIFY"; break; + case SEARCH_HIGH: what = "SEARCH_HIGH"; break; + case SEARCH_EQUAL: what = "SEARCH_EQUAL"; break; + case SEARCH_LOW: what = "SEARCH_LOW"; break; + case SET_LIMITS: what = "SET_LIMITS"; break; + case READ_POSITION: what = "READ_POSITION"; break; + case SYNCHRONIZE_CACHE: what = "SYNCHRONIZE_CACHE"; break; + case LOCK_UNLOCK_CACHE: what = "LOCK_UNLOCK_CACHE"; break; + case READ_DEFECT_DATA: what = "READ_DEFECT_DATA"; break; + case MEDIUM_SCAN: what = "MEDIUM_SCAN"; break; + case COMPARE: what = "COMPARE"; break; + case COPY_VERIFY: what = "COPY_VERIFY"; break; + case WRITE_BUFFER: what = "WRITE_BUFFER"; break; + case READ_BUFFER: what = "READ_BUFFER"; break; + case UPDATE_BLOCK: what = "UPDATE_BLOCK"; break; + case READ_LONG: what = "READ_LONG"; break; + case WRITE_LONG: what = "WRITE_LONG"; break; + case CHANGE_DEFINITION: what = "CHANGE_DEFINITION"; break; + case WRITE_SAME: what = "WRITE_SAME"; break; + case READ_TOC: what = "READ_TOC"; break; + case LOG_SELECT: what = "LOG_SELECT"; break; + case LOG_SENSE: what = "LOG_SENSE"; break; + case MODE_SELECT_10: what = "MODE_SELECT_10"; break; + case MODE_SENSE_10: what = "MODE_SENSE_10"; break; + case MOVE_MEDIUM: what = "MOVE_MEDIUM"; break; + case READ_12: what = "READ_12"; break; + case WRITE_12: what = "WRITE_12"; break; + case WRITE_VERIFY_12: what = "WRITE_VERIFY_12"; break; + case SEARCH_HIGH_12: what = "SEARCH_HIGH_12"; break; + case SEARCH_EQUAL_12: what = "SEARCH_EQUAL_12"; break; + case SEARCH_LOW_12: what = "SEARCH_LOW_12"; break; + case READ_ELEMENT_STATUS: what = "READ_ELEMENT_STATUS"; break; + case SEND_VOLUME_TAG: what = "SEND_VOLUME_TAG"; break; + case WRITE_LONG_2: what = "WRITE_LONG_2"; break; + default: break; + } + printk(KERN_DEBUG USB_STORAGE + "Command %s (%d bytes)\n", what, srb->cmd_len); + printk(KERN_DEBUG USB_STORAGE + " %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x\n", + srb->cmnd[0], srb->cmnd[1], srb->cmnd[2], srb->cmnd[3], srb->cmnd[4], srb->cmnd[5], + srb->cmnd[6], srb->cmnd[7], srb->cmnd[8], srb->cmnd[9]); +} + +#endif diff -u --recursive --new-file v2.3.46/linux/drivers/usb/usb-storage.c linux/drivers/usb/usb-storage.c --- v2.3.46/linux/drivers/usb/usb-storage.c Wed Dec 31 16:00:00 1969 +++ linux/drivers/usb/usb-storage.c Sun Feb 20 16:20:47 2000 @@ -0,0 +1,1851 @@ +/* Driver for USB Mass Storage compliant devices + * + * (c) 1999 Michael Gee (michael@linuxspecific.com) + * (c) 1999, 2000 Matthew Dharm (mdharm-usb@one-eyed-alien.net) + * + * Further reference: + * This driver is based on the 'USB Mass Storage Class' document. This + * describes in detail the protocol used to communicate with such + * devices. Clearly, the designers had SCSI commands in mind when they + * created this document. The commands are all similar to commands + * in the SCSI-II specification. + * + * It is important to note that in a number of cases this class exhibits + * class-specific exemptions from the USB specification. Notably the + * usage of NAK, STALL and ACK differs from the norm, in that they are + * used to communicate wait, failed and OK on commands. + * Also, for certain devices, the interrupt endpoint is used to convey + * status of a command. + * + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include "../scsi/scsi.h" +#include "../scsi/hosts.h" +#include "../scsi/sd.h" + +#include "usb.h" +#include "usb-storage.h" +#include "usb-storage-debug.h" + + +/* + * This is the size of the structure Scsi_Host_Template. We create + * an instance of this structure in this file and this is a check + * to see if this structure may have changed within the SCSI module. + * This is by no means foolproof, but it does help us some. + */ +#define SCSI_HOST_TEMPLATE_SIZE (104) + +/* direction table -- this indicates the direction of the data + * transfer for each command code -- a 1 indicates input + */ +unsigned char us_direction[256/8] = { + 0x28, 0x81, 0x14, 0x14, 0x20, 0x01, 0x90, 0x77, + 0x0C, 0x20, 0x00, 0x04, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x01, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 +}; + +/* + * Per device data + */ + +static int my_host_number; + +int usb_stor_debug = 1; + +struct us_data; + +typedef int (*trans_cmnd)(Scsi_Cmnd*, struct us_data*); +typedef int (*trans_reset)(struct us_data*); +typedef void (*proto_cmnd)(Scsi_Cmnd*, struct us_data*); + +struct us_data { + struct us_data *next; /* next device */ + struct usb_device *pusb_dev; /* this usb_device */ + unsigned int flags; /* from filter initially */ + __u8 ifnum; /* interface number */ + __u8 ep_in; /* in endpoint */ + __u8 ep_out; /* out ....... */ + __u8 ep_int; /* interrupt . */ + __u8 subclass; /* as in overview */ + __u8 protocol; /* .............. */ + __u8 attention_done; /* force attn on first cmd */ + trans_cmnd transport; /* protocol specific do cmd */ + trans_reset transport_reset; /* .......... device reset */ + proto_cmnd proto_handler; /* protocol handler */ + GUID(guid); /* unique dev id */ + struct Scsi_Host *host; /* our dummy host data */ + Scsi_Host_Template *htmplt; /* own host template */ + int host_number; /* to find us */ + int host_no; /* allocated by scsi */ + Scsi_Cmnd *srb; /* current srb */ + int action; /* what to do */ + wait_queue_head_t waitq; /* thread waits */ + wait_queue_head_t ip_waitq; /* for CBI interrupts */ + __u16 ip_data; /* interrupt data */ + int ip_wanted; /* needed */ + int pid; /* control thread */ + struct semaphore *notify; /* wait for thread to begin */ + void *irq_handle; /* for USB int requests */ + unsigned int irqpipe; /* pipe for release_irq */ +}; + +/* + * kernel thread actions + */ + +#define US_ACT_COMMAND 1 +#define US_ACT_ABORT 2 +#define US_ACT_DEVICE_RESET 3 +#define US_ACT_BUS_RESET 4 +#define US_ACT_HOST_RESET 5 + +static struct us_data *us_list; + +static void * storage_probe(struct usb_device *dev, unsigned int ifnum); +static void storage_disconnect(struct usb_device *dev, void *ptr); +static struct usb_driver storage_driver = { + "usb-storage", + storage_probe, + storage_disconnect, + { NULL, NULL } +}; + +/*********************************************************************** + * Data transfer routines + ***********************************************************************/ + +/* Transfer one buffer (breaking into packets if necessary) + * Note that this function is necessary because if the device NAKs, we + * need to know that information directly + * + * FIXME: is the above true? Or will the URB status show ETIMEDOUT after + * retrying several times allready? Perhaps this is the way we should + * be going anyway? + */ +static int us_one_transfer(struct us_data *us, int pipe, char *buf, int length) +{ + int max_size; + int this_xfer; + int result; + int partial; + int maxtry; + + /* determine the maximum packet size for these transfers */ + max_size = usb_maxpacket(us->pusb_dev, + pipe, usb_pipeout(pipe)) * 16; + + /* while we have data left to transfer */ + while (length) { + + /* calculate how long this will be -- maximum or a remainder */ + this_xfer = length > max_size ? max_size : length; + length -= this_xfer; + + /* FIXME: this number is totally outrageous. We need to pick + * a better (smaller) number). + */ + + /* setup the retry counter */ + maxtry = 100; + + /* set up the transfer loop */ + do { + /* transfer the data */ + US_DEBUGP("Bulk xfer 0x%x(%d) try #%d\n", + (unsigned int)buf, this_xfer, 101 - maxtry); + result = usb_bulk_msg(us->pusb_dev, pipe, buf, + this_xfer, &partial, HZ*5); + US_DEBUGP("bulk_msg returned %d xferred %d/%d\n", + result, partial, this_xfer); + + /* if we stall, we need to clear it before we go on */ + if (result == -EPIPE) { + US_DEBUGP("clearing endpoint halt for pipe 0x%x\n", pipe); + usb_clear_halt(us->pusb_dev, pipe); + } + + /* update to show what data was transferred */ + this_xfer -= partial; + buf += partial; + + /* NAK - we retry a few times */ + if (result == -ETIMEDOUT) { + + US_DEBUGP("us_one_transfer: device NAKed\n"); + + /* if our try counter reaches 0, bail out */ + if (!maxtry--) + return -ETIMEDOUT; + + /* just continue the while loop */ + continue; + } + + /* other errors (besides NAK) -- we just bail out*/ + if (result != 0) { + US_DEBUGP("us_one_transfer: device returned error %d\n", result); + return result; + } + + /* continue until this transfer is done */ + } while ( this_xfer ); + } + + /* if we get here, we're done and successful */ + return 0; +} + +static unsigned int us_transfer_length(Scsi_Cmnd *srb); + +/* transfer one SCSI command, using scatter-gather if requested */ +/* FIXME: what do the return codes here mean? */ +static int us_transfer(Scsi_Cmnd *srb, int dir_in) +{ + struct us_data *us = (struct us_data *)srb->host_scribble; + int i; + int result = -1; + unsigned int pipe = dir_in ? usb_rcvbulkpipe(us->pusb_dev, us->ep_in) : + usb_sndbulkpipe(us->pusb_dev, us->ep_out); + + /* FIXME: stop transferring data at us_transfer_length(), not + * bufflen */ + if (srb->use_sg) { + struct scatterlist *sg = (struct scatterlist *) srb->request_buffer; + + for (i = 0; i < srb->use_sg; i++) { + result = us_one_transfer(us, pipe, sg[i].address, sg[i].length); + if (result) + break; + } + } + else + result = us_one_transfer(us, pipe, srb->request_buffer, + us_transfer_length(srb)); + + if (result < 0) + US_DEBUGP("us_transfer returning error %d\n", result); + return result; +} + +/* calculate the length of the data transfer (not the command) for any + * given SCSI command + */ +static unsigned int us_transfer_length(Scsi_Cmnd *srb) +{ + int i; + unsigned int total = 0; + + /* always zero for some commands */ + switch (srb->cmnd[0]) { + case SEEK_6: + case SEEK_10: + case REZERO_UNIT: + case ALLOW_MEDIUM_REMOVAL: + case START_STOP: + case TEST_UNIT_READY: + return 0; + + case REQUEST_SENSE: + case INQUIRY: + case MODE_SENSE: + return srb->cmnd[4]; + + case LOG_SENSE: + case MODE_SENSE_10: + return (srb->cmnd[7] << 8) + srb->cmnd[8]; + + default: + break; + } + + if (srb->use_sg) { + struct scatterlist *sg = (struct scatterlist *) srb->request_buffer; + + for (i = 0; i < srb->use_sg; i++) { + total += sg[i].length; + } + return total; + } + else + return srb->request_bufflen; +} + +/*********************************************************************** + * Protocol routines + ***********************************************************************/ + +static int CB_transport(Scsi_Cmnd *srb, struct us_data *us); +static int Bulk_transport(Scsi_Cmnd *srb, struct us_data *us); + +static void ufi_command(Scsi_Cmnd *srb, struct us_data *us) +{ + int old_cmnd = 0; + + /* fix some commands -- this is a form of mode translation + * UFI devices only accept 12 byte long commands + * + * NOTE: This only works because a Scsi_Cmnd struct field contains + * a unsigned char cmnd[12], so we know we have storage available + */ + + /* set command length to 12 bytes (this affects the transport layer) */ + srb->cmd_len = 12; + + /* determine the correct (or minimum) data length for these commands */ + switch (us->srb->cmnd[0]) { + + /* for INQUIRY, UFI devices only ever return 36 bytes */ + case INQUIRY: + us->srb->cmnd[4] = 36; + break; + + /* change MODE_SENSE/MODE_SELECT from 6 to 10 byte commands */ + case MODE_SENSE: + case MODE_SELECT: + /* save the command so we can tell what it was */ + old_cmnd = srb->cmnd[0]; + + srb->cmnd[11] = 0; + srb->cmnd[10] = 0; + srb->cmnd[9] = 0; + + /* if we're sending data, we send all. If getting data, + * get the minimum */ + if (srb->cmnd[0] == MODE_SELECT) + srb->cmnd[8] = srb->cmnd[4]; + else + srb->cmnd[8] = 8; + + srb->cmnd[7] = 0; + srb->cmnd[6] = 0; + srb->cmnd[5] = 0; + srb->cmnd[4] = 0; + srb->cmnd[3] = 0; + srb->cmnd[2] = srb->cmnd[2]; + srb->cmnd[1] = srb->cmnd[1]; + srb->cmnd[0] = srb->cmnd[0] | 0x40; + break; + + /* again, for MODE_SENSE_10, we get the minimum (8) */ + case MODE_SENSE_10: + us->srb->cmnd[7] = 0; + us->srb->cmnd[8] = 8; + break; + + /* for REQUEST_SENSE, UFI devices only ever return 18 bytes */ + case REQUEST_SENSE: + us->srb->cmnd[4] = 18; + break; + + /* change READ_6/WRITE_6 to READ_10/WRITE_10, which + * are UFI commands */ + case WRITE_6: + case READ_6: + srb->cmnd[11] = 0; + srb->cmnd[10] = 0; + srb->cmnd[9] = 0; + srb->cmnd[8] = srb->cmnd[4]; + srb->cmnd[7] = 0; + srb->cmnd[6] = 0; + srb->cmnd[5] = srb->cmnd[3]; + srb->cmnd[4] = srb->cmnd[2]; + srb->cmnd[3] = srb->cmnd[1] & 0x1F; + srb->cmnd[2] = 0; + srb->cmnd[1] = srb->cmnd[1] & 0xE0; + srb->cmnd[0] = srb->cmnd[0] | 0x20; + break; + } /* end switch on cmnd[0] */ + + /* send the command to the transport layer */ + us->srb->result = us->transport(srb, us); + + /* if we have an error, we're going to do a + * REQUEST_SENSE automatically */ + + /* FIXME: we should only do this for device + * errors, not system errors */ + if (us->srb->result) { + int temp_result; + int count; + void* old_request_buffer; + + US_DEBUGP("Command FAILED: Issuing auto-REQUEST_SENSE\n"); + + /* set the result so the higher layers expect this data */ + us->srb->result = CHECK_CONDITION; + + us->srb->cmnd[0] = REQUEST_SENSE; + us->srb->cmnd[1] = 0; + us->srb->cmnd[2] = 0; + us->srb->cmnd[3] = 0; + us->srb->cmnd[4] = 18; + us->srb->cmnd[5] = 0; + + /* set the buffer length for transfer */ + old_request_buffer = us->srb->request_buffer; + us->srb->request_bufflen = 18; + us->srb->request_buffer = kmalloc(18, GFP_KERNEL); + + /* FIXME: what if this command fails? */ + temp_result = us->transport(us->srb, us); + US_DEBUGP("-- Result from auto-sense is %d\n", temp_result); + + /* copy the data from the request buffer to the sense buffer */ + for(count = 0; count < 18; count++) + us->srb->sense_buffer[count] = + ((unsigned char *)(us->srb->request_buffer))[count]; + + US_DEBUGP("-- sense key: 0x%x, ASC: 0x%x, ASCQ: 0x%x\n", + us->srb->sense_buffer[2] & 0xf, + us->srb->sense_buffer[12], us->srb->sense_buffer[13]); + + /* we're done here */ + kfree(us->srb->request_buffer); + us->srb->request_buffer = old_request_buffer; + return; + } + + /* FIXME: if we need to send more data, or recieve data, we should + * do it here. Then, we can do status handling here also. + * + * This includes MODE_SENSE from above + */ + if (old_cmnd == MODE_SENSE) { + unsigned char *dta = (unsigned char *)us->srb->request_buffer; + + /* calculate the new length */ + int length = (dta[0] << 8) + dta[1] + 2; + + /* copy the available data length into the structure */ + us->srb->cmnd[7] = length >> 8; + us->srb->cmnd[8] = length & 0xFF; + + /* send the command to the transport layer */ + us->srb->result = us->transport(srb, us); + + /* FIXME: this assumes that the 2nd attempt is always + * successful convert MODE_SENSE_10 return data format + * to MODE_SENSE_6 format */ + dta[0] = dta[1]; /* data len */ + dta[1] = dta[2]; /* med type */ + dta[2] = dta[3]; /* dev-spec prm */ + dta[3] = dta[7]; /* block desc len */ + printk (KERN_DEBUG USB_STORAGE + "new MODE_SENSE_6 data = %.2X %.2X %.2X %.2X\n", + dta[0], dta[1], dta[2], dta[3]); + } + + /* FIXME: if this was a TEST_UNIT_READY, and we get a NOT READY/ + * LOGICAL DRIVE NOT READY then we do a START_STOP, and retry + */ + + /* FIXME: here is where we need to fix-up the return data from + * an INQUIRY command to show ANSI SCSI rev 2 + */ + + /* FIXME: The rest of this is bogus. usb_control_msg() will only + * return an error if we've really honked things up. If it just + * needs a START_STOP, then we'll get some data back via + * REQUEST_SENSE -- either way, this belongs at a higher level + */ + +#if 0 + /* For UFI, if this is the first time we've sent this TEST_UNIT_READY + * command, we can try again + */ + if (!done_start && (us->subclass == US_SC_UFI) + && (cmd[0] == TEST_UNIT_READY) && (result < 0)) { + + /* as per spec try a start command, wait and retry */ + wait_ms(100); + + done_start++; + memset(cmd, 0, sizeof(cmd)); + cmd[0] = START_STOP; + cmd[4] = 1; /* start */ + + result = usb_control_msg(us->pusb_dev, usb_sndctrlpipe(us->pusb_dev,0), + US_CBI_ADSC, + USB_TYPE_CLASS | USB_RECIP_INTERFACE, + 0, us->ifnum, + cmd, 12, HZ*5); + US_DEBUGP("Next usb_control_msg returns %d\n", result); + + /* allow another retry */ + retry++; + continue; + } +#endif +} + +static void transparent_scsi_command(Scsi_Cmnd *srb, struct us_data *us) +{ + unsigned int savelen = us->srb->request_bufflen; + unsigned int saveallocation = 0; + +#if 0 + /* force attention on first command */ + if (!us->attention_done) { + if (us->srb->cmnd[0] == REQUEST_SENSE) { + US_DEBUGP("forcing unit attention\n"); + us->attention_done = 1; + + if (us->srb->result == USB_STOR_TRANSPORT_GOOD) { + unsigned char *p = (unsigned char *)us->srb->request_buffer; + + if ((p[2] & 0x0f) != UNIT_ATTENTION) { + p[2] = UNIT_ATTENTION; + p[12] = 0x29; /* power on, reset or bus-reset */ + p[13] = 0; + } /* if ((p[2] & 0x0f) != UNIT_ATTENTION) */ + } /* if (us->srb->result == USB_STORE_TRANSPORT_GOOD) */ + } + } /* if (!us->attention_done) */ +#endif + + /* If the command has a variable-length payload, then we do them + * in two steps -- first we do the minimum, then we recalculate + * then length, and re-issue the command + * + * we use savelen to remember how much buffer we really have + * we use savealloction to remember how much was really requested + */ + + /* FIXME: remove savelen based on mods to us_transfer_length() */ + switch (us->srb->cmnd[0]) { + case REQUEST_SENSE: + if (us->srb->request_bufflen > 18) + us->srb->request_bufflen = 18; + else + break; + saveallocation = us->srb->cmnd[4]; + us->srb->cmnd[4] = 18; + break; + + case INQUIRY: + if (us->srb->request_bufflen > 36) + us->srb->request_bufflen = 36; + else + break; + saveallocation = us->srb->cmnd[4]; + us->srb->cmnd[4] = 36; + break; + + case MODE_SENSE: + if (us->srb->request_bufflen > 4) + us->srb->request_bufflen = 4; + else + break; + saveallocation = us->srb->cmnd[4]; + us->srb->cmnd[4] = 4; + break; + + case LOG_SENSE: + case MODE_SENSE_10: + if (us->srb->request_bufflen > 8) + us->srb->request_bufflen = 8; + else + break; + saveallocation = (us->srb->cmnd[7] << 8) | us->srb->cmnd[8]; + us->srb->cmnd[7] = 0; + us->srb->cmnd[8] = 8; + break; + + default: + break; + } /* end switch on cmnd[0] */ + + /* This code supports devices which do not support {READ|WRITE}_6 + * Apparently, neither Windows or MacOS will use these commands, + * so some devices do not support them + */ + if (us->flags & US_FL_MODE_XLATE) { + + /* translate READ_6 to READ_10 */ + if (us->srb->cmnd[0] == 0x08) { + + /* get the control */ + us->srb->cmnd[9] = us->srb->cmnd[5]; + + /* get the length */ + us->srb->cmnd[8] = us->srb->cmnd[6]; + us->srb->cmnd[7] = 0; + + /* set the reserved area to 0 */ + us->srb->cmnd[6] = 0; + + /* get LBA */ + us->srb->cmnd[5] = us->srb->cmnd[3]; + us->srb->cmnd[4] = us->srb->cmnd[2]; + us->srb->cmnd[3] = 0; + us->srb->cmnd[2] = 0; + + /* LUN and other info in cmnd[1] can stay */ + + /* fix command code */ + us->srb->cmnd[0] = 0x28; + + US_DEBUGP("Changing READ_6 to READ_10\n"); + US_DEBUG(us_show_command(us->srb)); + } + + /* translate WRITE_6 to WRITE_10 */ + if (us->srb->cmnd[0] == 0x0A) { + + /* get the control */ + us->srb->cmnd[9] = us->srb->cmnd[5]; + + /* get the length */ + us->srb->cmnd[8] = us->srb->cmnd[4]; + us->srb->cmnd[7] = 0; + + /* set the reserved area to 0 */ + us->srb->cmnd[6] = 0; + + /* get LBA */ + us->srb->cmnd[5] = us->srb->cmnd[3]; + us->srb->cmnd[4] = us->srb->cmnd[2]; + us->srb->cmnd[3] = 0; + us->srb->cmnd[2] = 0; + + /* LUN and other info in cmnd[1] can stay */ + + /* fix command code */ + us->srb->cmnd[0] = 0x2A; + + US_DEBUGP("Changing WRITE_6 to WRITE_10\n"); + US_DEBUG(us_show_command(us->srb)); + } + } /* end if (us->flags & US_FL_MODE_XLATE) */ + + /* send the command to the transport layer */ + us->srb->result = us->transport(us->srb, us); + + /* if we have an error, we're going to do a REQUEST_SENSE + * automatically */ + /* FIXME: we should only do this for device errors, not + * system errors */ + if (us->srb->result) { + int temp_result; + int count; + void* old_request_buffer; + + US_DEBUGP("Command FAILED: Issuing auto-REQUEST_SENSE\n"); + + /* set the result so the higher layers expect this data */ + us->srb->result = CHECK_CONDITION; + + us->srb->cmnd[0] = REQUEST_SENSE; + us->srb->cmnd[1] = 0; + us->srb->cmnd[2] = 0; + us->srb->cmnd[3] = 0; + us->srb->cmnd[4] = 18; + us->srb->cmnd[5] = 0; + + /* set the buffer length for transfer */ + old_request_buffer = us->srb->request_buffer; + us->srb->request_bufflen = 18; + us->srb->request_buffer = kmalloc(18, GFP_KERNEL); + + /* FIXME: what if this command fails? */ + temp_result = us->transport(us->srb, us); + US_DEBUGP("-- Result from auto-sense is %d\n", temp_result); + + /* copy the data from the request buffer to the sense buffer */ + for(count = 0; count < 18; count++) + us->srb->sense_buffer[count] = + ((unsigned char *)(us->srb->request_buffer))[count]; + + US_DEBUGP("-- sense key: 0x%x, ASC: 0x%x, ASCQ: 0x%x\n", + us->srb->sense_buffer[2] & 0xf, + us->srb->sense_buffer[12], us->srb->sense_buffer[13]); + + /* we're done here */ + kfree(us->srb->request_buffer); + us->srb->request_buffer = old_request_buffer; + return; + } + + if (savelen != us->srb->request_bufflen) { + unsigned char *p = (unsigned char *)us->srb->request_buffer; + unsigned int length = 0; + + /* set correct length and retry */ + switch (us->srb->cmnd[0]) { + + /* FIXME: we should try to get all the sense data */ + case REQUEST_SENSE: + /* simply return 18 bytes */ + p[7] = 10; + length = us->srb->request_bufflen; + break; + + case INQUIRY: + length = p[4] + 5 > savelen ? savelen : p[4] + 5; + us->srb->cmnd[4] = length; + break; + + case MODE_SENSE: + US_DEBUGP("MODE_SENSE Mode data length is %d\n", p[0]); + length = p[0] + 1 > savelen ? savelen : p[0] + 1; + us->srb->cmnd[4] = length; + break; + + case LOG_SENSE: + length = ((p[2] << 8) + p[3]) + 4 > savelen ? savelen : ((p[2] << 8) + p[3]) + 4; + us->srb->cmnd[7] = length >> 8; + us->srb->cmnd[8] = length; + break; + + case MODE_SENSE_10: + US_DEBUGP("MODE_SENSE_10 Mode data length is %d\n", + (p[0] << 8) + p[1]); + length = ((p[0] << 8) + p[1]) + 6 > savelen ? savelen : ((p[0] << 8) + p[1]) + 6; + us->srb->cmnd[7] = length >> 8; + us->srb->cmnd[8] = length; + break; + } /* end switch on cmnd[0] */ + + US_DEBUGP("Old/New length = %d/%d\n", + savelen, length); + + /* issue the new command */ + /* FIXME: this assumes that the second attempt is + * always successful */ + if (us->srb->request_bufflen != length) { + US_DEBUGP("redoing cmd with len=%d\n", length); + us->srb->request_bufflen = length; + us->srb->result = us->transport(us->srb, us); + } + + /* reset back to original values */ + us->srb->request_bufflen = savelen; + + /* fix data as necessary */ + switch (us->srb->cmnd[0]) { + case INQUIRY: + if ((((unsigned char*)us->srb->request_buffer)[2] & 0x7) == 0) { + US_DEBUGP("Fixing INQUIRY data, setting SCSI rev to 2\n"); + ((unsigned char*)us->srb->request_buffer)[2] |= 2; + } + /* FALL THROUGH */ + case REQUEST_SENSE: + case MODE_SENSE: + if (us->srb->use_sg == 0 && length > 0) { + int i; + printk(KERN_DEBUG "Data is"); + for (i = 0; i < 32 && i < length; ++i) + printk(" %.2x", ((unsigned char *)us->srb->request_buffer)[i]); + if (i < length) + printk(" ..."); + printk("\n"); + } + + /* FIXME: is this really necessary? */ + us->srb->cmnd[4] = saveallocation; + break; + + case LOG_SENSE: + case MODE_SENSE_10: + /* FIXME: is this really necessary? */ + us->srb->cmnd[7] = saveallocation >> 8; + us->srb->cmnd[8] = saveallocation; + break; + } /* end switch on cmnd[0] */ + } /* if good command */ +} + +/*********************************************************************** + * Transport routines + ***********************************************************************/ + +static int CBI_irq(int state, void *buffer, int len, void *dev_id) +{ + struct us_data *us = (struct us_data *)dev_id; + + US_DEBUGP("USB IRQ recieved for device on host %d\n", us->host_no); + + /* save the data for interpretation later */ + if (state != USB_ST_REMOVED) { + us->ip_data = le16_to_cpup((__u16 *)buffer); + US_DEBUGP("Interrupt Status 0x%x\n", us->ip_data); + } + + /* was this a wanted interrupt? */ + if (us->ip_wanted) { + us->ip_wanted = 0; + wake_up(&us->ip_waitq); + } else { + US_DEBUGP("ERROR: Unwanted interrupt received!\n"); + } + + /* This return code is truly meaningless -- and I mean truly. It gets + * ignored by other layers. It used to indicate if we wanted to get + * another interrupt or disable the interrupt callback + */ + return 0; +} + +/* FIXME: this reset function doesn't really reset the port, and it + * should. Actually it should probably do what it's doing here, and + * reset the port physically + */ +static int CB_reset(struct us_data *us) +{ + unsigned char cmd[12]; + int result; + + US_DEBUGP("CB_reset\n"); + + memset(cmd, 0xFF, sizeof(cmd)); + cmd[0] = SEND_DIAGNOSTIC; + cmd[1] = 4; + result = usb_control_msg(us->pusb_dev, usb_sndctrlpipe(us->pusb_dev,0), + US_CBI_ADSC, USB_TYPE_CLASS | USB_RECIP_INTERFACE, + 0, us->ifnum, cmd, sizeof(cmd), HZ*5); + + /* long wait for reset */ + schedule_timeout(HZ*6); + + US_DEBUGP("CB_reset: clearing endpoint halt\n"); + usb_clear_halt(us->pusb_dev, usb_rcvbulkpipe(us->pusb_dev, us->ep_in)); + usb_clear_halt(us->pusb_dev, usb_rcvbulkpipe(us->pusb_dev, us->ep_out)); + + US_DEBUGP("CB_reset done\n"); + return 0; +} + +static int pop_CB_status(Scsi_Cmnd *srb); + +/* FIXME: we also need a CBI_command which sets up the completion + * interrupt, and waits for it + */ +static int CB_transport(Scsi_Cmnd *srb, struct us_data *us) +{ + int result; + + US_DEBUGP("CBI gets a command:\n"); + US_DEBUG(us_show_command(srb)); + + /* FIXME: we aren't setting the ip_wanted indicator early enough, which + * causes some commands to never complete. This hangs the driver. + */ + + /* let's send the command via the control pipe */ + result = usb_control_msg(us->pusb_dev, usb_sndctrlpipe(us->pusb_dev,0), + US_CBI_ADSC, USB_TYPE_CLASS | USB_RECIP_INTERFACE, + 0, us->ifnum, + srb->cmnd, srb->cmd_len, HZ*5); + + /* check the return code for the command */ + if (result < 0) { + US_DEBUGP("Call to usb_control_msg() returned %d\n", result); + + /* a stall is a fatal condition from the device */ + if (result == -EPIPE) { + US_DEBUGP("-- Stall on control pipe detected. Clearing\n"); + + US_DEBUGP("-- Return from usb_clear_halt() is %d\n", + usb_clear_halt(us->pusb_dev, + usb_sndctrlpipe(us->pusb_dev, 0))); + return USB_STOR_TRANSPORT_ERROR; + } + + /* FIXME: we need to handle NAKs here */ + return USB_STOR_TRANSPORT_ERROR; + } + + /* transfer the data payload for this command, if one exists*/ + if (us_transfer_length(srb)) { + result = us_transfer(srb, US_DIRECTION(srb->cmnd[0])); + US_DEBUGP("CBI attempted to transfer data, result is 0x%x\n", result); + + /* FIXME: what do the return codes from us_transfer mean? */ + if ((result < 0) && + (result != USB_ST_DATAUNDERRUN) && + (result != USB_ST_STALL)) { + return DID_ERROR << 16; + } + } /* if (us_transfer_length(srb)) */ + + /* get status and return it */ + return pop_CB_status(srb); +} + +/* + * Control/Bulk status handler + */ + +static int pop_CB_status(Scsi_Cmnd *srb) +{ + struct us_data *us = (struct us_data *)srb->host_scribble; + int result = 0; + __u8 status[2]; + int retry = 5; + + US_DEBUGP("pop_CB_status, proto=0x%x\n", us->protocol); + switch (us->protocol) { + case US_PR_CB: + /* get from control */ + + while (retry--) { + result = usb_control_msg(us->pusb_dev, usb_rcvctrlpipe(us->pusb_dev,0), + USB_REQ_GET_STATUS, USB_DIR_IN | + USB_TYPE_STANDARD | USB_RECIP_DEVICE, + 0, us->ifnum, status, sizeof(status), HZ*5); + if (result != USB_ST_TIMEOUT) + break; + } + if (result) { + US_DEBUGP("Bad AP status request %d\n", result); + return DID_ABORT << 16; + } + US_DEBUGP("Got AP status 0x%x 0x%x\n", status[0], status[1]); + if (srb->cmnd[0] != REQUEST_SENSE && srb->cmnd[0] != INQUIRY && + ( (status[0] & ~3) || status[1])) + return (DID_OK << 16) | 2; + else + return USB_STOR_TRANSPORT_GOOD; + break; + + /* FIXME: this should be in a separate function */ + case US_PR_CBI: + /* get from interrupt pipe */ + + /* add interrupt transfer, marked for removal */ + us->ip_wanted = 1; + + /* go to sleep until we get this interrup */ + /* FIXME: this should be changed to use a timeout */ + sleep_on(&us->ip_waitq); + + if (us->ip_wanted) { + US_DEBUGP("Did not get interrupt on CBI\n"); + us->ip_wanted = 0; + return USB_STOR_TRANSPORT_ERROR; + } + + US_DEBUGP("Got interrupt data 0x%x\n", us->ip_data); + + /* UFI gives us ASC and ASCQ, like a request sense */ + /* FIXME: is this right? do REQUEST_SENSE and INQUIRY need special + * case handling? + */ + if (us->subclass == US_SC_UFI) { + if (srb->cmnd[0] == REQUEST_SENSE || + srb->cmnd[0] == INQUIRY) + return USB_STOR_TRANSPORT_GOOD; + else + if (us->ip_data) + return USB_STOR_TRANSPORT_FAILED; + else + return USB_STOR_TRANSPORT_GOOD; + } + + /* otherwise, we interpret the data normally */ + switch (us->ip_data) { + case 0x0001: + return USB_STOR_TRANSPORT_GOOD; + case 0x0002: + return USB_STOR_TRANSPORT_FAILED; + default: + return USB_STOR_TRANSPORT_ERROR; + } + } + US_DEBUGP("pop_CB_status, reached end of function\n"); + return USB_STOR_TRANSPORT_ERROR; +} + +static int Bulk_reset(struct us_data *us) +{ + int result; + + result = usb_control_msg(us->pusb_dev, usb_sndctrlpipe(us->pusb_dev,0), + US_BULK_RESET, USB_TYPE_CLASS | USB_RECIP_INTERFACE, + US_BULK_RESET_HARD, us->ifnum, + NULL, 0, HZ*5); + if (result) + US_DEBUGP("Bulk hard reset failed %d\n", result); + usb_clear_halt(us->pusb_dev, usb_rcvbulkpipe(us->pusb_dev, us->ep_in)); + usb_clear_halt(us->pusb_dev, usb_sndbulkpipe(us->pusb_dev, us->ep_out)); + + /* long wait for reset */ + schedule_timeout(HZ*6); + + return result; +} + +/* + * The bulk only protocol handler. + * Uses the in and out endpoints to transfer commands and data + */ +static int Bulk_transport(Scsi_Cmnd *srb, struct us_data *us) +{ + struct bulk_cb_wrap bcb; + struct bulk_cs_wrap bcs; + int result; + int pipe; + int partial; + + /* set up the command wrapper */ + bcb.Signature = US_BULK_CB_SIGN; + bcb.DataTransferLength = us_transfer_length(srb); + bcb.Flags = US_DIRECTION(srb->cmnd[0]) << 7; + bcb.Tag = srb->serial_number; + bcb.Lun = 0; + bcb.Length = srb->cmd_len; + + /* construct the pipe handle */ + pipe = usb_sndbulkpipe(us->pusb_dev, us->ep_out); + + /* copy the command payload */ + memset(bcb.CDB, 0, sizeof(bcb.CDB)); + memcpy(bcb.CDB, srb->cmnd, bcb.Length); + + /* send it to out endpoint */ + US_DEBUGP("Bulk command S 0x%x T 0x%x L %d F %d CL %d\n", + bcb.Signature, bcb.Tag, bcb.DataTransferLength, + bcb.Flags, bcb.Length); + result = usb_bulk_msg(us->pusb_dev, pipe, &bcb, + US_BULK_CB_WRAP_LEN, &partial, HZ*5); + US_DEBUGP("Bulk command transfer result=%d\n", result); + + /* if we stall, we need to clear it before we go on */ + if (result == -EPIPE) { + US_DEBUGP("clearing endpoint halt for pipe 0x%x\n", pipe); + usb_clear_halt(us->pusb_dev, pipe); + } + + /* if the command transfered well, then we go to the data stage */ + /* FIXME: Regardless of the status of the data stage, we go on to the + * status stage. Note that this implies that if a command is + * partially successful, we rely on the device reporting an error + * the CSW. The spec says that the device may just decide to short us. + */ + if (result == 0) { + /* send/receive data payload, if there is any */ + if (bcb.DataTransferLength) { + result = us_transfer(srb, bcb.Flags); + US_DEBUGP("Bulk data transfer result 0x%x\n", result); +#if 0 + if ((result < 0) && (result != USB_ST_DATAUNDERRUN) + && (result != USB_ST_STALL)) { + US_DEBUGP("Bulk data transfer result 0x%x\n", result); + return DID_ABORT << 16; + } +#endif + } + } + + /* See flow chart on pg 15 of the Bulk Only Transport spec for + * an explanation of how this code works. + */ + + /* construct the pipe handle */ + pipe = usb_rcvbulkpipe(us->pusb_dev, us->ep_in); + + /* get CSW for device status */ + result = usb_bulk_msg(us->pusb_dev, pipe, &bcs, + US_BULK_CS_WRAP_LEN, &partial, HZ*5); + + /* did the attempt to read the CSW fail? */ + if (result == -EPIPE) { + US_DEBUGP("clearing endpoint halt for pipe 0x%x\n", pipe); + usb_clear_halt(us->pusb_dev, pipe); + + /* get the status again */ + result = usb_bulk_msg(us->pusb_dev, pipe, &bcs, + US_BULK_CS_WRAP_LEN, &partial, HZ*5); + + /* if it fails again, we need a reset and return an error*/ + if (result == -EPIPE) { + Bulk_reset(us); + return (DID_ABORT << 16); + } + } + + /* if we still have a failure at this point, we're in trouble */ + if (result) { + US_DEBUGP("Bulk status result = 0x%x\n", result); + return DID_ABORT << 16; + } + + /* check bulk status */ + US_DEBUGP("Bulk status S 0x%x T 0x%x R %d V 0x%x\n", + bcs.Signature, bcs.Tag, bcs.Residue, bcs.Status); + if (bcs.Signature != US_BULK_CS_SIGN || bcs.Tag != bcb.Tag || + bcs.Status > US_BULK_STAT_PHASE || partial != 13) { + US_DEBUGP("Bulk logical error\n"); + return DID_ABORT << 16; + } + + /* based on the status code, we report good or bad */ + switch (bcs.Status) { + case US_BULK_STAT_OK: + /* if there is residue, we really didn't finish the command */ + if (bcs.Residue) + return DID_ERROR << 16; + else + return DID_OK << 16; + + case US_BULK_STAT_FAIL: + return DID_ERROR << 16; + + case US_BULK_STAT_PHASE: + Bulk_reset(us); + return DID_ERROR << 16; + } + + return DID_OK << 16; /* check sense required */ +} + +/*********************************************************************** + * Host functions + ***********************************************************************/ + +/* detect adapter (always true ) */ +static int us_detect(struct SHT *sht) +{ + /* FIXME - not nice at all, but how else ? */ + struct us_data *us = (struct us_data *)sht->proc_dir; + char name[32]; + + /* set up our name */ + sprintf(name, "usbscsi%d", us->host_number); + sht->name = sht->proc_name = kmalloc(strlen(name)+1, GFP_KERNEL); + if (!sht->proc_name) + return 0; + strcpy(sht->proc_name, name); + + /* we start with no /proc directory entry */ + sht->proc_dir = NULL; + + /* register the host */ + us->host = scsi_register(sht, sizeof(us)); + if (us->host) { + us->host->hostdata[0] = (unsigned long)us; + us->host_no = us->host->host_no; + return 1; + } + + /* odd... didn't register properly. Abort and free pointers */ + kfree(sht->proc_name); + sht->proc_name = NULL; + sht->name = NULL; + return 0; +} + +/* release - must be here to stop scsi + * from trying to release IRQ etc. + * Kill off our data + */ +static int us_release(struct Scsi_Host *psh) +{ + struct us_data *us = (struct us_data *)psh->hostdata[0]; + struct us_data *prev = (struct us_data *)&us_list; + + if (us->irq_handle) { + usb_release_irq(us->pusb_dev, us->irq_handle, us->irqpipe); + us->irq_handle = NULL; + } + if (us->pusb_dev) + usb_deregister(&storage_driver); + + /* FIXME - leaves hanging host template copy */ + /* (because scsi layer uses it after removal !!!) */ + while (prev->next != us) + prev = prev->next; + prev->next = us->next; + return 0; +} + +/* run command */ +static int us_command( Scsi_Cmnd *srb ) +{ + US_DEBUGP("Bad use of us_command\n"); + + return DID_BAD_TARGET << 16; +} + +/* run command */ +static int us_queuecommand( Scsi_Cmnd *srb , void (*done)(Scsi_Cmnd *)) +{ + struct us_data *us = (struct us_data *)srb->host->hostdata[0]; + + US_DEBUGP("Command wakeup\n"); + if (us->srb) { + /* busy */ + } + srb->host_scribble = (unsigned char *)us; + us->srb = srb; + srb->scsi_done = done; + us->action = US_ACT_COMMAND; + + /* wake up the process task */ + + wake_up_interruptible(&us->waitq); + + return 0; +} + +/* FIXME: This doesn't actually abort anything */ +static int us_abort( Scsi_Cmnd *srb ) +{ + return 0; +} + +static int us_bus_reset( Scsi_Cmnd *srb ) +{ + // struct us_data *us = (struct us_data *)srb->host->hostdata[0]; + + US_DEBUGP("Bus reset requested\n"); + // us->transport_reset(us); + return SUCCESS; +} + +/* FIXME: This doesn't actually reset anything */ +static int us_host_reset( Scsi_Cmnd *srb ) +{ + return 0; +} + +/*********************************************************************** + * /proc/scsi/ functions + ***********************************************************************/ + +/* we use this macro to help us write into the buffer */ +#undef SPRINTF +#define SPRINTF(args...) do { if (pos < (buffer + length)) pos += sprintf (pos, ## args); } while (0) + +int usb_stor_proc_info (char *buffer, char **start, off_t offset, + int length, int hostno, int inout) +{ + struct us_data *us = us_list; + char *pos = buffer; + char *tmp_ptr; + + /* find our data from hostno */ + while (us) { + if (us->host_no == hostno) + break; + us = us->next; + } + + /* if we couldn't find it, we return an error */ + if (!us) + return -ESRCH; + + /* if someone is sending us data, just throw it away */ + if (inout) + return length; + + /* print the controler name */ + SPRINTF ("Host scsi%d: usb-storage\n", hostno); + + /* print product and vendor strings */ + tmp_ptr = kmalloc(256, GFP_KERNEL); + if (!us->pusb_dev || !tmp_ptr) { + SPRINTF(" Vendor: Unknown Vendor\n"); + SPRINTF(" Product: Unknown Product\n"); + } else { + SPRINTF(" Vendor: "); + if (usb_string(us->pusb_dev, us->pusb_dev->descriptor.iManufacturer, tmp_ptr, 256) > 0) + SPRINTF("%s\n", tmp_ptr); + else + SPRINTF("Unknown Vendor\n"); + + SPRINTF(" Product: "); + if (usb_string(us->pusb_dev, us->pusb_dev->descriptor.iProduct, tmp_ptr, 256) > 0) + SPRINTF("%s\n", tmp_ptr); + else + SPRINTF("Unknown Product\n"); + kfree(tmp_ptr); + } + + SPRINTF(" Protocol: "); + switch (us->protocol) { + case US_PR_CB: + SPRINTF("Control/Bulk\n"); + break; + + case US_PR_CBI: + SPRINTF("Control/Bulk/Interrupt\n"); + break; + + case US_PR_BULK: + SPRINTF("Bulk only\n"); + break; + + default: + SPRINTF("Unknown Protocol\n"); + break; + } + + /* show the GUID of the device */ + SPRINTF(" GUID: " GUID_FORMAT "\n", GUID_ARGS(us->guid)); + + /* + * Calculate start of next buffer, and return value. + */ + *start = buffer + offset; + + if ((pos - buffer) < offset) + return (0); + else if ((pos - buffer - offset) < length) + return (pos - buffer - offset); + else + return (length); +} + +/* + * this defines our 'host' + */ + +static Scsi_Host_Template my_host_template = { + NULL, /* next */ + NULL, /* module */ + NULL, /* proc_dir */ + usb_stor_proc_info, + NULL, /* name - points to unique */ + us_detect, + us_release, + NULL, /* info */ + NULL, /* ioctl */ + us_command, + us_queuecommand, + NULL, /* eh_strategy */ + us_abort, + us_bus_reset, + us_bus_reset, + us_host_reset, + NULL, /* abort */ + NULL, /* reset */ + NULL, /* slave_attach */ + NULL, /* bios_param */ + NULL, /* select_queue_depths */ + 1, /* can_queue */ + -1, /* this_id */ + SG_ALL, /* sg_tablesize */ + 1, /* cmd_per_lun */ + 0, /* present */ + FALSE, /* unchecked_isa_dma */ + FALSE, /* use_clustering */ + TRUE, /* use_new_eh_code */ + TRUE /* emulated */ +}; + +static unsigned char sense_notready[] = { + 0x70, /* current error */ + 0x00, + 0x02, /* not ready */ + 0x00, + 0x00, + 0x0a, /* additional length */ + 0x00, + 0x00, + 0x00, + 0x00, + 0x04, /* not ready */ + 0x03, /* manual intervention */ + 0x00, + 0x00, + 0x00, + 0x00 +}; + +static int usb_stor_control_thread(void * __us) +{ + struct us_data *us = (struct us_data *)__us; + int action; + + lock_kernel(); + + /* + * This thread doesn't need any user-level access, + * so get rid of all our resources.. + */ + daemonize(); + + sprintf(current->comm, "usbscsi%d", us->host_number); + + unlock_kernel(); + + up(us->notify); + + for(;;) { + siginfo_t info; + int unsigned long signr; + + interruptible_sleep_on(&us->waitq); + + action = us->action; + us->action = 0; + + /* FIXME: we need to examine placment of break; and + * scsi_done() calls */ + + switch (action) { + case US_ACT_COMMAND: + /* bad device */ + if (us->srb->target || us->srb->lun) { + US_DEBUGP( "Bad device number (%d/%d) or dev 0x%x\n", + us->srb->target, us->srb->lun, (unsigned int)us->pusb_dev); + us->srb->result = DID_BAD_TARGET << 16; + + us->srb->scsi_done(us->srb); + us->srb = NULL; + break; + } + + /* our device has gone - pretend not ready */ + /* FIXME: we also need to handle INQUIRY here, + * probably */ + if (!us->pusb_dev) { + if (us->srb->cmnd[0] == REQUEST_SENSE) { + memcpy(us->srb->request_buffer, sense_notready, + sizeof(sense_notready)); + us->srb->result = DID_OK << 16; + } else { + us->srb->result = (DID_OK << 16) | 2; + } + + us->srb->scsi_done(us->srb); + us->srb = NULL; + break; + } + + /* we've got a command, let's do it! */ + US_DEBUG(us_show_command(us->srb)); + + /* FIXME: this is to support Shuttle E-USB bridges, it + * appears */ + if (us->srb->cmnd[0] == START_STOP && + us->pusb_dev->descriptor.idProduct == 0x0001 && + us->pusb_dev->descriptor.idVendor == 0x04e6) + us->srb->result = DID_OK << 16; + else { + us->proto_handler(us->srb, us); + } + + US_DEBUGP("scsi cmd done, result=0x%x\n", us->srb->result); + us->srb->scsi_done(us->srb); + us->srb = NULL; + break; + + case US_ACT_ABORT: + break; + + case US_ACT_DEVICE_RESET: + break; + + case US_ACT_BUS_RESET: + break; + + case US_ACT_HOST_RESET: + break; + + } /* end switch on action */ + + if (signal_pending(current)) { + /* sending SIGUSR1 makes us print out some info */ + spin_lock_irq(¤t->sigmask_lock); + signr = dequeue_signal(¤t->blocked, &info); + spin_unlock_irq(¤t->sigmask_lock); + + if (signr == SIGUSR2) { + usb_stor_debug = !usb_stor_debug; + printk(USB_STORAGE "debug toggle = %d\n", usb_stor_debug); + } else { + break; /* exit the loop on any other signal */ + } + } + } + + // MOD_DEC_USE_COUNT; + + printk("usb_stor_control_thread exiting\n"); + + /* FIXME: this is a hack to allow for debugging */ + // scsi_unregister_module(MODULE_SCSI_HA, us->htmplt); + + return 0; +} + +/* Probe to see if a new device is actually a SCSI device */ +static void * storage_probe(struct usb_device *dev, unsigned int ifnum) +{ + struct usb_interface_descriptor *interface; + int i; + char mf[32]; /* manufacturer */ + char prod[32]; /* product */ + char serial[32]; /* serial number */ + struct us_data *ss = NULL; + unsigned int flags = 0; + GUID(guid); /* Global Unique Identifier */ + struct us_data *prev; + Scsi_Host_Template *htmplt; + int protocol = 0; + int subclass = 0; + struct usb_interface_descriptor *altsetting = + &(dev->actconfig->interface[ifnum].altsetting[0]); + + /* clear the GUID and fetch the strings */ + GUID_CLEAR(guid); + memset(mf, 0, sizeof(mf)); + memset(prod, 0, sizeof(prod)); + memset(serial, 0, sizeof(serial)); + if (dev->descriptor.iManufacturer) + usb_string(dev, dev->descriptor.iManufacturer, mf, sizeof(mf)); + if (dev->descriptor.iProduct) + usb_string(dev, dev->descriptor.iProduct, prod, sizeof(prod)); + if (dev->descriptor.iSerialNumber) + usb_string(dev, dev->descriptor.iSerialNumber, serial, sizeof(serial)); + + /* let's examine the device now */ + + /* We make an exception for the shuttle E-USB */ + if (dev->descriptor.idVendor == 0x04e6 && + dev->descriptor.idProduct == 0x0001) { + protocol = US_PR_CB; + subclass = US_SC_8070; /* an assumption */ + } else if (dev->descriptor.bDeviceClass != 0 || + altsetting->bInterfaceClass != USB_CLASS_MASS_STORAGE || + altsetting->bInterfaceSubClass < US_SC_MIN || + altsetting->bInterfaceSubClass > US_SC_MAX) { + /* if it's not a mass storage, we go no further */ + return NULL; + } + + /* At this point, we know we've got a live one */ + US_DEBUGP("USB Mass Storage device detected\n"); + + /* Create a GUID for this device */ + if (dev->descriptor.iSerialNumber && serial[0]) { + /* If we have a serial number, and it's a non-NULL string */ + make_guid(guid, dev->descriptor.idVendor, + dev->descriptor.idProduct, serial); + } else { + /* We don't have a serial number, so we use 0 */ + make_guid(guid, dev->descriptor.idVendor, + dev->descriptor.idProduct, "0"); + } + + /* Now check if we have seen this GUID before, and restore + * the flags if we find it + */ + for (ss = us_list; ss != NULL; ss = ss->next) { + if (!ss->pusb_dev && GUID_EQUAL(guid, ss->guid)) { + US_DEBUGP("Found existing GUID " GUID_FORMAT "\n", + GUID_ARGS(guid)); + flags = ss->flags; + break; + } + } + + /* If ss == NULL, then this is a new device. Allocate memory for it */ + if (!ss) { + if ((ss = (struct us_data *)kmalloc(sizeof(*ss), + GFP_KERNEL)) == NULL) { + printk(KERN_WARNING USB_STORAGE "Out of memory\n"); + return NULL; + } + memset(ss, 0, sizeof(struct us_data)); + } + + /* Initialize the us_data structure with some useful info */ + interface = altsetting; + ss->flags = flags; + ss->ifnum = ifnum; + ss->pusb_dev = dev; + ss->attention_done = 0; + + /* If the device has subclass and protocol, then use that. Otherwise, + * take data from the specific interface. + */ + if (subclass) { + ss->subclass = subclass; + ss->protocol = protocol; + } else { + ss->subclass = interface->bInterfaceSubClass; + ss->protocol = interface->bInterfaceProtocol; + } + + /* set the handler pointers based on the protocol */ + US_DEBUGP("Transport: "); + switch (ss->protocol) { + case US_PR_CB: + US_DEBUGPX("Control/Bulk\n"); + ss->transport = CB_transport; + ss->transport_reset = CB_reset; + break; + + case US_PR_CBI: + US_DEBUGPX("Control/Bulk/Interrupt\n"); + ss->transport = CB_transport; + ss->transport_reset = CB_reset; + break; + + case US_PR_BULK: + US_DEBUGPX("Bulk\n"); + ss->transport = Bulk_transport; + ss->transport_reset = Bulk_reset; + break; + + default: + US_DEBUGPX("Unknown\n"); + kfree(ss); + return NULL; + break; + } + + /* + * We are expecting a minimum of 2 endpoints - in and out (bulk). + * An optional interrupt is OK (necessary for CBI protocol). + * We will ignore any others. + */ + for (i = 0; i < interface->bNumEndpoints; i++) { + /* is it an BULK endpoint? */ + if ((interface->endpoint[i].bmAttributes & USB_ENDPOINT_XFERTYPE_MASK) + == USB_ENDPOINT_XFER_BULK) { + if (interface->endpoint[i].bEndpointAddress & USB_DIR_IN) + ss->ep_in = interface->endpoint[i].bEndpointAddress & + USB_ENDPOINT_NUMBER_MASK; + else + ss->ep_out = interface->endpoint[i].bEndpointAddress & + USB_ENDPOINT_NUMBER_MASK; + } + + /* is it an interrupt endpoint? */ + if ((interface->endpoint[i].bmAttributes & USB_ENDPOINT_XFERTYPE_MASK) + == USB_ENDPOINT_XFER_INT) { + ss->ep_int = interface->endpoint[i].bEndpointAddress & + USB_ENDPOINT_NUMBER_MASK; + } + } + US_DEBUGP("Endpoints In %d Out %d Int %d\n", + ss->ep_in, ss->ep_out, ss->ep_int); + + /* Do some basic sanity checks, and bail if we find a problem */ + if (usb_set_interface(dev, interface->bInterfaceNumber, 0) || + !ss->ep_in || !ss->ep_out || + (ss->protocol == US_PR_CBI && ss->ep_int == 0)) { + US_DEBUGP("Problems with device\n"); + if (ss->host) { + scsi_unregister_module(MODULE_SCSI_HA, ss->htmplt); + kfree(ss->htmplt->name); + kfree(ss->htmplt); + } + + kfree(ss); + return NULL; + } + + /* If this is a new device (i.e. we haven't seen it before), we need to + * generate a scsi host definition, and register with scsi above us + */ + if (!ss->host) { + /* copy the GUID we created before */ + US_DEBUGP("New GUID " GUID_FORMAT "\n", GUID_ARGS(guid)); + memcpy(ss->guid, guid, sizeof(guid)); + + /* set class specific stuff */ + US_DEBUGP("Protocol: "); + switch (ss->subclass) { + case US_SC_RBC: + US_DEBUGPX("Reduced Block Commands\n"); + break; + + case US_SC_8020: + US_DEBUGPX("8020\n"); + break; + + case US_SC_QIC: + US_DEBUGPX("QIC157\n"); + break; + + case US_SC_8070: + US_DEBUGPX("8070\n"); + break; + + case US_SC_SCSI: + US_DEBUGPX("Transparent SCSI\n"); + ss->proto_handler = transparent_scsi_command; + break; + + case US_SC_UFI: + US_DEBUGPX("UFI\n"); + ss->proto_handler = ufi_command; + break; + + default: + US_DEBUGPX("Unknown\n"); + break; + } + + /* We only handle certain protocols. Currently, these are + *the only ones that devices use. + */ + if ((ss->subclass != US_SC_SCSI) && (ss->subclass != US_SC_UFI)) { + US_DEBUGP("Sorry, we do not support that protocol yet.\n"); + US_DEBUGP("If you have a device which uses one of the unsupported\n"); + US_DEBUGP("protocols, please contact mdharm-usb@one-eyed-alien.net\n"); + + kfree(ss); + return NULL; + } + + /* Allocate memory for the SCSI Host Template */ + if ((htmplt = (Scsi_Host_Template *) + kmalloc(sizeof(*ss->htmplt), GFP_KERNEL)) == NULL ) { + + printk(KERN_WARNING USB_STORAGE "Out of memory\n"); + + kfree(ss); + return NULL; + } + + /* Initialize the host template based on the default one */ + memcpy(htmplt, &my_host_template, sizeof(my_host_template)); + + /* Grab the next host number */ + ss->host_number = my_host_number++; + + /* MDD: FIXME: this is bad. We abuse this pointer so we + * can pass the ss pointer to the host controler thread + * in us_detect + */ + (struct us_data *)htmplt->proc_dir = ss; + + /* shuttle E-USB */ + if (dev->descriptor.idVendor == 0x04e6 && + dev->descriptor.idProduct == 0x0001) { + __u8 qstat[2]; + int result; + + result = usb_control_msg(ss->pusb_dev, usb_rcvctrlpipe(dev,0), + 1, 0xC0, + 0, ss->ifnum, + qstat, 2, HZ*5); + US_DEBUGP("C0 status 0x%x 0x%x\n", qstat[0], qstat[1]); + init_waitqueue_head(&ss->ip_waitq); + ss->irqpipe = usb_rcvintpipe(ss->pusb_dev, ss->ep_int); + result = usb_request_irq(ss->pusb_dev, ss->irqpipe, CBI_irq, + 255, (void *)ss, &ss->irq_handle); + if (result) + return NULL; + + interruptible_sleep_on_timeout(&ss->ip_waitq, HZ*6); + } else if (ss->protocol == US_PR_CBI) + { + int result; + + init_waitqueue_head(&ss->ip_waitq); + + /* set up the IRQ pipe and handler */ + /* FIXME: This needs to get the period from the device */ + ss->irqpipe = usb_rcvintpipe(ss->pusb_dev, ss->ep_int); + result = usb_request_irq(ss->pusb_dev, ss->irqpipe, CBI_irq, + 255, (void *)ss, &ss->irq_handle); + if (result) { + US_DEBUGP("usb_request_irq failed (0x%x), No interrupt for CBI\n", + result); + } + } + + + /* start up our thread */ + { + DECLARE_MUTEX_LOCKED(sem); + + init_waitqueue_head(&ss->waitq); + + ss->notify = &sem; + ss->pid = kernel_thread(usb_stor_control_thread, ss, + CLONE_FS | CLONE_FILES | CLONE_SIGHAND); + if (ss->pid < 0) { + printk(KERN_WARNING USB_STORAGE "Unable to start control thread\n"); + kfree(htmplt); + + kfree(ss); + return NULL; + } + + /* wait for it to start */ + down(&sem); + } + + /* now register - our detect function will be called */ + scsi_register_module(MODULE_SCSI_HA, htmplt); + + /* put us in the list */ + prev = (struct us_data *)&us_list; + while (prev->next) + prev = prev->next; + prev->next = ss; + } + + printk(KERN_INFO "WARNING: USB Mass Storage data integrity not assured\n"); + printk(KERN_INFO "USB Mass Storage device found at %d\n", dev->devnum); + + return ss; +} + +/* Handle a disconnect event from the USB core */ +static void storage_disconnect(struct usb_device *dev, void *ptr) +{ + struct us_data *ss = ptr; + + if (!ss) + return; + + ss->pusb_dev = NULL; + // MOD_DEC_USE_COUNT; +} + + +/*********************************************************************** + * Initialization and registration + ***********************************************************************/ + +int __init usb_stor_init(void) +{ + // MOD_INC_USE_COUNT; + + if (sizeof(my_host_template) != SCSI_HOST_TEMPLATE_SIZE) { + printk(KERN_ERR "usb-storage: SCSI_HOST_TEMPLATE_SIZE does not match\n") ; + printk(KERN_ERR "usb-storage: expected %d bytes, got %d bytes\n", + SCSI_HOST_TEMPLATE_SIZE, sizeof(my_host_template)) ; + + return -1 ; + } + + /* register the driver, return -1 if error */ + if (usb_register(&storage_driver) < 0) + return -1; + + printk(KERN_INFO "USB Mass Storage support registered.\n"); + return 0; +} + +void __exit usb_stor_exit(void) +{ + usb_deregister(&storage_driver) ; +} + +module_init(usb_stor_init) ; +module_exit(usb_stor_exit) ; diff -u --recursive --new-file v2.3.46/linux/drivers/usb/usb-storage.h linux/drivers/usb/usb-storage.h --- v2.3.46/linux/drivers/usb/usb-storage.h Wed Dec 31 16:00:00 1969 +++ linux/drivers/usb/usb-storage.h Sun Feb 20 16:20:47 2000 @@ -0,0 +1,130 @@ +/* Driver for USB mass storage - include file + * + * (c) 1999 Michael Gee (michael@linuxspecific.com) + * (c) 1999, 2000 Matthew Dharm (mdharm-usb@one-eyed-alien.net) + * + */ + +#include + +#define USB_STORAGE "usb-storage: " + +extern int usb_stor_debug; + +#ifdef CONFIG_USB_STORAGE_DEBUG +void us_show_command(Scsi_Cmnd *srb); +#define US_DEBUGP(x...) { if(usb_stor_debug) printk( KERN_DEBUG USB_STORAGE ## x ); } +#define US_DEBUGPX(x...) { if(usb_stor_debug) printk( ## x ); } +#define US_DEBUG(x) { if(usb_stor_debug) x; } +#else +#define US_DEBUGP(x...) +#define US_DEBUGPX(x...) +#define US_DEBUG(x) +#endif + +/* bit set if input */ +extern unsigned char us_direction[256/8]; +#define US_DIRECTION(x) ((us_direction[x>>3] >> (x & 7)) & 1) + +/* Sub Classes */ + +#define US_SC_RBC 1 /* Typically, flash devices */ +#define US_SC_8020 2 /* CD-ROM */ +#define US_SC_QIC 3 /* QIC-157 Tapes */ +#define US_SC_UFI 4 /* Floppy */ +#define US_SC_8070 5 /* Removable media */ +#define US_SC_SCSI 6 /* Transparent */ +#define US_SC_MIN US_SC_RBC +#define US_SC_MAX US_SC_SCSI + +/* Protocols */ + +#define US_PR_CB 1 /* Control/Bulk w/o interrupt */ +#define US_PR_CBI 0 /* Control/Bulk/Interrupt */ +#define US_PR_BULK 0x50 /* bulk only */ + +/* + * Bulk only data structures (Zip 100, for example) + */ + +/* command block wrapper */ +struct bulk_cb_wrap { + __u32 Signature; /* contains 'USBC' */ + __u32 Tag; /* unique per command id */ + __u32 DataTransferLength; /* size of data */ + __u8 Flags; /* direction in bit 0 */ + __u8 Lun; /* LUN normally 0 */ + __u8 Length; /* of of the CDB */ + __u8 CDB[16]; /* max command */ +}; + +#define US_BULK_CB_WRAP_LEN 31 +#define US_BULK_CB_SIGN 0x43425355 +#define US_BULK_FLAG_IN 1 +#define US_BULK_FLAG_OUT 0 + +/* command status wrapper */ +struct bulk_cs_wrap { + __u32 Signature; /* should = 'USBS' */ + __u32 Tag; /* same as original command */ + __u32 Residue; /* amount not transferred */ + __u8 Status; /* see below */ + __u8 Filler[18]; +}; + +#define US_BULK_CS_WRAP_LEN 13 +#define US_BULK_CS_SIGN 0x53425355 +#define US_BULK_STAT_OK 0 +#define US_BULK_STAT_FAIL 1 +#define US_BULK_STAT_PHASE 2 + +#define US_BULK_RESET 0xff +#define US_BULK_RESET_SOFT 1 +#define US_BULK_RESET_HARD 0 + +/* + * Transport return codes + */ + +#define USB_STOR_TRANSPORT_GOOD 0 /* Transport good, command good */ +#define USB_STOR_TRANSPORT_FAILED 1 /* Transport good, command failed */ +#define USB_STOR_TRANSPORT_ERROR 2 /* Transport bad (i.e. device dead */ + +/* + * CBI style + */ + +#define US_CBI_ADSC 0 + +/* + * GUID definitions + */ + +#define GUID(x) __u32 x[3] +#define GUID_EQUAL(x, y) (x[0] == y[0] && x[1] == y[1] && x[2] == y[2]) +#define GUID_CLEAR(x) x[0] = x[1] = x[2] = 0; +#define GUID_NONE(x) (!x[0] && !x[1] && !x[2]) +#define GUID_FORMAT "%08x%08x%08x" +#define GUID_ARGS(x) x[0], x[1], x[2] + +static inline void make_guid( __u32 *pg, __u16 vendor, __u16 product, char *serial) +{ + pg[0] = (vendor << 16) | product; + pg[1] = pg[2] = 0; + while (*serial) { + pg[1] <<= 4; + pg[1] |= pg[2] >> 28; + pg[2] <<= 4; + if (*serial >= 'a') + *serial -= 'a' - 'A'; + pg[2] |= (*serial <= '9' && *serial >= '0') ? *serial - '0' + : *serial - 'A' + 10; + serial++; + } +} + +/* Flag definitions */ +#define US_FL_IP_STATUS 0x00000001 /* status uses interrupt */ +#define US_FL_FIXED_COMMAND 0x00000002 /* expand commands to fixed size */ +#define US_FL_MODE_XLATE 0x00000004 /* translate _6 to _10 comands for + Win/MacOS compatibility */ diff -u --recursive --new-file v2.3.46/linux/drivers/usb/usb_storage.c linux/drivers/usb/usb_storage.c --- v2.3.46/linux/drivers/usb/usb_storage.c Wed Feb 16 17:03:52 2000 +++ linux/drivers/usb/usb_storage.c Wed Dec 31 16:00:00 1969 @@ -1,1849 +0,0 @@ -/* Driver for USB Mass Storage compliant devices - * - * (c) 1999 Michael Gee (michael@linuxspecific.com) - * (c) 1999, 2000 Matthew Dharm (mdharm-usb@one-eyed-alien.net) - * - * Further reference: - * This driver is based on the 'USB Mass Storage Class' document. This - * describes in detail the protocol used to communicate with such - * devices. Clearly, the designers had SCSI commands in mind when they - * created this document. The commands are all similar to commands - * in the SCSI-II specification. - * - * It is important to note that in a number of cases this class exhibits - * class-specific exemptions from the USB specification. Notably the - * usage of NAK, STALL and ACK differs from the norm, in that they are - * used to communicate wait, failed and OK on commands. - * Also, for certain devices, the interrupt endpoint is used to convey - * status of a command. - * - */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include -#include "../scsi/scsi.h" -#include "../scsi/hosts.h" -#include "../scsi/sd.h" - -#include "usb.h" -#include "usb_storage.h" - -/* - * This is the size of the structure Scsi_Host_Template. We create - * an instance of this structure in this file and this is a check - * to see if this structure may have changed within the SCSI module. - * This is by no means foolproof, but it does help us some. - */ -#define SCSI_HOST_TEMPLATE_SIZE (104) - -/* direction table -- this indicates the direction of the data - * transfer for each command code -- a 1 indicates input - */ -unsigned char us_direction[256/8] = { - 0x28, 0x81, 0x14, 0x14, 0x20, 0x01, 0x90, 0x77, - 0x0C, 0x20, 0x00, 0x04, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x01, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 -}; - -/* - * Per device data - */ - -static int my_host_number; - -int usb_stor_debug = 1; - -struct us_data; - -typedef int (*trans_cmnd)(Scsi_Cmnd*, struct us_data*); -typedef int (*trans_reset)(struct us_data*); -typedef void (*proto_cmnd)(Scsi_Cmnd*, struct us_data*); - -struct us_data { - struct us_data *next; /* next device */ - struct usb_device *pusb_dev; /* this usb_device */ - unsigned int flags; /* from filter initially */ - __u8 ifnum; /* interface number */ - __u8 ep_in; /* in endpoint */ - __u8 ep_out; /* out ....... */ - __u8 ep_int; /* interrupt . */ - __u8 subclass; /* as in overview */ - __u8 protocol; /* .............. */ - __u8 attention_done; /* force attn on first cmd */ - trans_cmnd transport; /* protocol specific do cmd */ - trans_reset transport_reset; /* .......... device reset */ - proto_cmnd proto_handler; /* protocol handler */ - GUID(guid); /* unique dev id */ - struct Scsi_Host *host; /* our dummy host data */ - Scsi_Host_Template *htmplt; /* own host template */ - int host_number; /* to find us */ - int host_no; /* allocated by scsi */ - Scsi_Cmnd *srb; /* current srb */ - int action; /* what to do */ - wait_queue_head_t waitq; /* thread waits */ - wait_queue_head_t ip_waitq; /* for CBI interrupts */ - __u16 ip_data; /* interrupt data */ - int ip_wanted; /* needed */ - int pid; /* control thread */ - struct semaphore *notify; /* wait for thread to begin */ - void *irq_handle; /* for USB int requests */ - unsigned int irqpipe; /* pipe for release_irq */ -}; - -/* - * kernel thread actions - */ - -#define US_ACT_COMMAND 1 -#define US_ACT_ABORT 2 -#define US_ACT_DEVICE_RESET 3 -#define US_ACT_BUS_RESET 4 -#define US_ACT_HOST_RESET 5 - -static struct us_data *us_list; - -static void * storage_probe(struct usb_device *dev, unsigned int ifnum); -static void storage_disconnect(struct usb_device *dev, void *ptr); -static struct usb_driver storage_driver = { - "usb-storage", - storage_probe, - storage_disconnect, - { NULL, NULL } -}; - -/*********************************************************************** - * Data transfer routines - ***********************************************************************/ - -/* Transfer one buffer (breaking into packets if necessary) - * Note that this function is necessary because if the device NAKs, we - * need to know that information directly - * - * FIXME: is the above true? Or will the URB status show ETIMEDOUT after - * retrying several times allready? Perhaps this is the way we should - * be going anyway? - */ -static int us_one_transfer(struct us_data *us, int pipe, char *buf, int length) -{ - int max_size; - int this_xfer; - int result; - int partial; - int maxtry; - - /* determine the maximum packet size for these transfers */ - max_size = usb_maxpacket(us->pusb_dev, - pipe, usb_pipeout(pipe)) * 16; - - /* while we have data left to transfer */ - while (length) { - - /* calculate how long this will be -- maximum or a remainder */ - this_xfer = length > max_size ? max_size : length; - length -= this_xfer; - - /* FIXME: this number is totally outrageous. We need to pick - * a better (smaller) number). - */ - - /* setup the retry counter */ - maxtry = 100; - - /* set up the transfer loop */ - do { - /* transfer the data */ - US_DEBUGP("Bulk xfer 0x%x(%d) try #%d\n", - (unsigned int)buf, this_xfer, 101 - maxtry); - result = usb_bulk_msg(us->pusb_dev, pipe, buf, - this_xfer, &partial, HZ*5); - US_DEBUGP("bulk_msg returned %d xferred %d/%d\n", - result, partial, this_xfer); - - /* if we stall, we need to clear it before we go on */ - if (result == -EPIPE) { - US_DEBUGP("clearing endpoint halt for pipe 0x%x\n", pipe); - usb_clear_halt(us->pusb_dev, pipe); - } - - /* update to show what data was transferred */ - this_xfer -= partial; - buf += partial; - - /* NAK - we retry a few times */ - if (result == -ETIMEDOUT) { - - US_DEBUGP("us_one_transfer: device NAKed\n"); - - /* if our try counter reaches 0, bail out */ - if (!maxtry--) - return -ETIMEDOUT; - - /* just continue the while loop */ - continue; - } - - /* other errors (besides NAK) -- we just bail out*/ - if (result != 0) { - US_DEBUGP("us_one_transfer: device returned error %d\n", result); - return result; - } - - /* continue until this transfer is done */ - } while ( this_xfer ); - } - - /* if we get here, we're done and successful */ - return 0; -} - -static unsigned int us_transfer_length(Scsi_Cmnd *srb); - -/* transfer one SCSI command, using scatter-gather if requested */ -/* FIXME: what do the return codes here mean? */ -static int us_transfer(Scsi_Cmnd *srb, int dir_in) -{ - struct us_data *us = (struct us_data *)srb->host_scribble; - int i; - int result = -1; - unsigned int pipe = dir_in ? usb_rcvbulkpipe(us->pusb_dev, us->ep_in) : - usb_sndbulkpipe(us->pusb_dev, us->ep_out); - - /* FIXME: stop transferring data at us_transfer_length(), not - * bufflen */ - if (srb->use_sg) { - struct scatterlist *sg = (struct scatterlist *) srb->request_buffer; - - for (i = 0; i < srb->use_sg; i++) { - result = us_one_transfer(us, pipe, sg[i].address, sg[i].length); - if (result) - break; - } - } - else - result = us_one_transfer(us, pipe, srb->request_buffer, - us_transfer_length(srb)); - - if (result < 0) - US_DEBUGP("us_transfer returning error %d\n", result); - return result; -} - -/* calculate the length of the data transfer (not the command) for any - * given SCSI command - */ -static unsigned int us_transfer_length(Scsi_Cmnd *srb) -{ - int i; - unsigned int total = 0; - - /* always zero for some commands */ - switch (srb->cmnd[0]) { - case SEEK_6: - case SEEK_10: - case REZERO_UNIT: - case ALLOW_MEDIUM_REMOVAL: - case START_STOP: - case TEST_UNIT_READY: - return 0; - - case REQUEST_SENSE: - case INQUIRY: - case MODE_SENSE: - return srb->cmnd[4]; - - case LOG_SENSE: - case MODE_SENSE_10: - return (srb->cmnd[7] << 8) + srb->cmnd[8]; - - default: - break; - } - - if (srb->use_sg) { - struct scatterlist *sg = (struct scatterlist *) srb->request_buffer; - - for (i = 0; i < srb->use_sg; i++) { - total += sg[i].length; - } - return total; - } - else - return srb->request_bufflen; -} - -/*********************************************************************** - * Protocol routines - ***********************************************************************/ - -static int CB_transport(Scsi_Cmnd *srb, struct us_data *us); -static int Bulk_transport(Scsi_Cmnd *srb, struct us_data *us); - -static void ufi_command(Scsi_Cmnd *srb, struct us_data *us) -{ - int old_cmnd = 0; - - /* fix some commands -- this is a form of mode translation - * UFI devices only accept 12 byte long commands - * - * NOTE: This only works because a Scsi_Cmnd struct field contains - * a unsigned char cmnd[12], so we know we have storage available - */ - - /* set command length to 12 bytes (this affects the transport layer) */ - srb->cmd_len = 12; - - /* determine the correct (or minimum) data length for these commands */ - switch (us->srb->cmnd[0]) { - - /* for INQUIRY, UFI devices only ever return 36 bytes */ - case INQUIRY: - us->srb->cmnd[4] = 36; - break; - - /* change MODE_SENSE/MODE_SELECT from 6 to 10 byte commands */ - case MODE_SENSE: - case MODE_SELECT: - /* save the command so we can tell what it was */ - old_cmnd = srb->cmnd[0]; - - srb->cmnd[11] = 0; - srb->cmnd[10] = 0; - srb->cmnd[9] = 0; - - /* if we're sending data, we send all. If getting data, - * get the minimum */ - if (srb->cmnd[0] == MODE_SELECT) - srb->cmnd[8] = srb->cmnd[4]; - else - srb->cmnd[8] = 8; - - srb->cmnd[7] = 0; - srb->cmnd[6] = 0; - srb->cmnd[5] = 0; - srb->cmnd[4] = 0; - srb->cmnd[3] = 0; - srb->cmnd[2] = srb->cmnd[2]; - srb->cmnd[1] = srb->cmnd[1]; - srb->cmnd[0] = srb->cmnd[0] | 0x40; - break; - - /* again, for MODE_SENSE_10, we get the minimum (8) */ - case MODE_SENSE_10: - us->srb->cmnd[7] = 0; - us->srb->cmnd[8] = 8; - break; - - /* for REQUEST_SENSE, UFI devices only ever return 18 bytes */ - case REQUEST_SENSE: - us->srb->cmnd[4] = 18; - break; - - /* change READ_6/WRITE_6 to READ_10/WRITE_10, which - * are UFI commands */ - case WRITE_6: - case READ_6: - srb->cmnd[11] = 0; - srb->cmnd[10] = 0; - srb->cmnd[9] = 0; - srb->cmnd[8] = srb->cmnd[4]; - srb->cmnd[7] = 0; - srb->cmnd[6] = 0; - srb->cmnd[5] = srb->cmnd[3]; - srb->cmnd[4] = srb->cmnd[2]; - srb->cmnd[3] = srb->cmnd[1] & 0x1F; - srb->cmnd[2] = 0; - srb->cmnd[1] = srb->cmnd[1] & 0xE0; - srb->cmnd[0] = srb->cmnd[0] | 0x20; - break; - } /* end switch on cmnd[0] */ - - /* send the command to the transport layer */ - us->srb->result = us->transport(srb, us); - - /* if we have an error, we're going to do a - * REQUEST_SENSE automatically */ - - /* FIXME: we should only do this for device - * errors, not system errors */ - if (us->srb->result) { - int temp_result; - int count; - void* old_request_buffer; - - US_DEBUGP("Command FAILED: Issuing auto-REQUEST_SENSE\n"); - - /* set the result so the higher layers expect this data */ - us->srb->result = CHECK_CONDITION; - - us->srb->cmnd[0] = REQUEST_SENSE; - us->srb->cmnd[1] = 0; - us->srb->cmnd[2] = 0; - us->srb->cmnd[3] = 0; - us->srb->cmnd[4] = 18; - us->srb->cmnd[5] = 0; - - /* set the buffer length for transfer */ - old_request_buffer = us->srb->request_buffer; - us->srb->request_bufflen = 18; - us->srb->request_buffer = kmalloc(18, GFP_KERNEL); - - /* FIXME: what if this command fails? */ - temp_result = us->transport(us->srb, us); - US_DEBUGP("-- Result from auto-sense is %d\n", temp_result); - - /* copy the data from the request buffer to the sense buffer */ - for(count = 0; count < 18; count++) - us->srb->sense_buffer[count] = - ((unsigned char *)(us->srb->request_buffer))[count]; - - US_DEBUGP("-- sense key: 0x%x, ASC: 0x%x, ASCQ: 0x%x\n", - us->srb->sense_buffer[2] & 0xf, - us->srb->sense_buffer[12], us->srb->sense_buffer[13]); - - /* we're done here */ - kfree(us->srb->request_buffer); - us->srb->request_buffer = old_request_buffer; - return; - } - - /* FIXME: if we need to send more data, or recieve data, we should - * do it here. Then, we can do status handling here also. - * - * This includes MODE_SENSE from above - */ - if (old_cmnd == MODE_SENSE) { - unsigned char *dta = (unsigned char *)us->srb->request_buffer; - - /* calculate the new length */ - int length = (dta[0] << 8) + dta[1] + 2; - - /* copy the available data length into the structure */ - us->srb->cmnd[7] = length >> 8; - us->srb->cmnd[8] = length & 0xFF; - - /* send the command to the transport layer */ - us->srb->result = us->transport(srb, us); - - /* FIXME: this assumes that the 2nd attempt is always - * successful convert MODE_SENSE_10 return data format - * to MODE_SENSE_6 format */ - dta[0] = dta[1]; /* data len */ - dta[1] = dta[2]; /* med type */ - dta[2] = dta[3]; /* dev-spec prm */ - dta[3] = dta[7]; /* block desc len */ - printk (KERN_DEBUG USB_STORAGE - "new MODE_SENSE_6 data = %.2X %.2X %.2X %.2X\n", - dta[0], dta[1], dta[2], dta[3]); - } - - /* FIXME: if this was a TEST_UNIT_READY, and we get a NOT READY/ - * LOGICAL DRIVE NOT READY then we do a START_STOP, and retry - */ - - /* FIXME: here is where we need to fix-up the return data from - * an INQUIRY command to show ANSI SCSI rev 2 - */ - - /* FIXME: The rest of this is bogus. usb_control_msg() will only - * return an error if we've really honked things up. If it just - * needs a START_STOP, then we'll get some data back via - * REQUEST_SENSE -- either way, this belongs at a higher level - */ - -#if 0 - /* For UFI, if this is the first time we've sent this TEST_UNIT_READY - * command, we can try again - */ - if (!done_start && (us->subclass == US_SC_UFI) - && (cmd[0] == TEST_UNIT_READY) && (result < 0)) { - - /* as per spec try a start command, wait and retry */ - wait_ms(100); - - done_start++; - memset(cmd, 0, sizeof(cmd)); - cmd[0] = START_STOP; - cmd[4] = 1; /* start */ - - result = usb_control_msg(us->pusb_dev, usb_sndctrlpipe(us->pusb_dev,0), - US_CBI_ADSC, - USB_TYPE_CLASS | USB_RECIP_INTERFACE, - 0, us->ifnum, - cmd, 12, HZ*5); - US_DEBUGP("Next usb_control_msg returns %d\n", result); - - /* allow another retry */ - retry++; - continue; - } -#endif -} - -static void transparent_scsi_command(Scsi_Cmnd *srb, struct us_data *us) -{ - unsigned int savelen = us->srb->request_bufflen; - unsigned int saveallocation = 0; - -#if 0 - /* force attention on first command */ - if (!us->attention_done) { - if (us->srb->cmnd[0] == REQUEST_SENSE) { - US_DEBUGP("forcing unit attention\n"); - us->attention_done = 1; - - if (us->srb->result == USB_STOR_TRANSPORT_GOOD) { - unsigned char *p = (unsigned char *)us->srb->request_buffer; - - if ((p[2] & 0x0f) != UNIT_ATTENTION) { - p[2] = UNIT_ATTENTION; - p[12] = 0x29; /* power on, reset or bus-reset */ - p[13] = 0; - } /* if ((p[2] & 0x0f) != UNIT_ATTENTION) */ - } /* if (us->srb->result == USB_STORE_TRANSPORT_GOOD) */ - } - } /* if (!us->attention_done) */ -#endif - - /* If the command has a variable-length payload, then we do them - * in two steps -- first we do the minimum, then we recalculate - * then length, and re-issue the command - * - * we use savelen to remember how much buffer we really have - * we use savealloction to remember how much was really requested - */ - - /* FIXME: remove savelen based on mods to us_transfer_length() */ - switch (us->srb->cmnd[0]) { - case REQUEST_SENSE: - if (us->srb->request_bufflen > 18) - us->srb->request_bufflen = 18; - else - break; - saveallocation = us->srb->cmnd[4]; - us->srb->cmnd[4] = 18; - break; - - case INQUIRY: - if (us->srb->request_bufflen > 36) - us->srb->request_bufflen = 36; - else - break; - saveallocation = us->srb->cmnd[4]; - us->srb->cmnd[4] = 36; - break; - - case MODE_SENSE: - if (us->srb->request_bufflen > 4) - us->srb->request_bufflen = 4; - else - break; - saveallocation = us->srb->cmnd[4]; - us->srb->cmnd[4] = 4; - break; - - case LOG_SENSE: - case MODE_SENSE_10: - if (us->srb->request_bufflen > 8) - us->srb->request_bufflen = 8; - else - break; - saveallocation = (us->srb->cmnd[7] << 8) | us->srb->cmnd[8]; - us->srb->cmnd[7] = 0; - us->srb->cmnd[8] = 8; - break; - - default: - break; - } /* end switch on cmnd[0] */ - - /* This code supports devices which do not support {READ|WRITE}_6 - * Apparently, neither Windows or MacOS will use these commands, - * so some devices do not support them - */ - if (us->flags & US_FL_MODE_XLATE) { - - /* translate READ_6 to READ_10 */ - if (us->srb->cmnd[0] == 0x08) { - - /* get the control */ - us->srb->cmnd[9] = us->srb->cmnd[5]; - - /* get the length */ - us->srb->cmnd[8] = us->srb->cmnd[6]; - us->srb->cmnd[7] = 0; - - /* set the reserved area to 0 */ - us->srb->cmnd[6] = 0; - - /* get LBA */ - us->srb->cmnd[5] = us->srb->cmnd[3]; - us->srb->cmnd[4] = us->srb->cmnd[2]; - us->srb->cmnd[3] = 0; - us->srb->cmnd[2] = 0; - - /* LUN and other info in cmnd[1] can stay */ - - /* fix command code */ - us->srb->cmnd[0] = 0x28; - - US_DEBUGP("Changing READ_6 to READ_10\n"); - US_DEBUG(us_show_command(us->srb)); - } - - /* translate WRITE_6 to WRITE_10 */ - if (us->srb->cmnd[0] == 0x0A) { - - /* get the control */ - us->srb->cmnd[9] = us->srb->cmnd[5]; - - /* get the length */ - us->srb->cmnd[8] = us->srb->cmnd[4]; - us->srb->cmnd[7] = 0; - - /* set the reserved area to 0 */ - us->srb->cmnd[6] = 0; - - /* get LBA */ - us->srb->cmnd[5] = us->srb->cmnd[3]; - us->srb->cmnd[4] = us->srb->cmnd[2]; - us->srb->cmnd[3] = 0; - us->srb->cmnd[2] = 0; - - /* LUN and other info in cmnd[1] can stay */ - - /* fix command code */ - us->srb->cmnd[0] = 0x2A; - - US_DEBUGP("Changing WRITE_6 to WRITE_10\n"); - US_DEBUG(us_show_command(us->srb)); - } - } /* end if (us->flags & US_FL_MODE_XLATE) */ - - /* send the command to the transport layer */ - us->srb->result = us->transport(us->srb, us); - - /* if we have an error, we're going to do a REQUEST_SENSE - * automatically */ - /* FIXME: we should only do this for device errors, not - * system errors */ - if (us->srb->result) { - int temp_result; - int count; - void* old_request_buffer; - - US_DEBUGP("Command FAILED: Issuing auto-REQUEST_SENSE\n"); - - /* set the result so the higher layers expect this data */ - us->srb->result = CHECK_CONDITION; - - us->srb->cmnd[0] = REQUEST_SENSE; - us->srb->cmnd[1] = 0; - us->srb->cmnd[2] = 0; - us->srb->cmnd[3] = 0; - us->srb->cmnd[4] = 18; - us->srb->cmnd[5] = 0; - - /* set the buffer length for transfer */ - old_request_buffer = us->srb->request_buffer; - us->srb->request_bufflen = 18; - us->srb->request_buffer = kmalloc(18, GFP_KERNEL); - - /* FIXME: what if this command fails? */ - temp_result = us->transport(us->srb, us); - US_DEBUGP("-- Result from auto-sense is %d\n", temp_result); - - /* copy the data from the request buffer to the sense buffer */ - for(count = 0; count < 18; count++) - us->srb->sense_buffer[count] = - ((unsigned char *)(us->srb->request_buffer))[count]; - - US_DEBUGP("-- sense key: 0x%x, ASC: 0x%x, ASCQ: 0x%x\n", - us->srb->sense_buffer[2] & 0xf, - us->srb->sense_buffer[12], us->srb->sense_buffer[13]); - - /* we're done here */ - kfree(us->srb->request_buffer); - us->srb->request_buffer = old_request_buffer; - return; - } - - if (savelen != us->srb->request_bufflen) { - unsigned char *p = (unsigned char *)us->srb->request_buffer; - unsigned int length = 0; - - /* set correct length and retry */ - switch (us->srb->cmnd[0]) { - - /* FIXME: we should try to get all the sense data */ - case REQUEST_SENSE: - /* simply return 18 bytes */ - p[7] = 10; - length = us->srb->request_bufflen; - break; - - case INQUIRY: - length = p[4] + 5 > savelen ? savelen : p[4] + 5; - us->srb->cmnd[4] = length; - break; - - case MODE_SENSE: - US_DEBUGP("MODE_SENSE Mode data length is %d\n", p[0]); - length = p[0] + 1 > savelen ? savelen : p[0] + 1; - us->srb->cmnd[4] = length; - break; - - case LOG_SENSE: - length = ((p[2] << 8) + p[3]) + 4 > savelen ? savelen : ((p[2] << 8) + p[3]) + 4; - us->srb->cmnd[7] = length >> 8; - us->srb->cmnd[8] = length; - break; - - case MODE_SENSE_10: - US_DEBUGP("MODE_SENSE_10 Mode data length is %d\n", - (p[0] << 8) + p[1]); - length = ((p[0] << 8) + p[1]) + 6 > savelen ? savelen : ((p[0] << 8) + p[1]) + 6; - us->srb->cmnd[7] = length >> 8; - us->srb->cmnd[8] = length; - break; - } /* end switch on cmnd[0] */ - - US_DEBUGP("Old/New length = %d/%d\n", - savelen, length); - - /* issue the new command */ - /* FIXME: this assumes that the second attempt is - * always successful */ - if (us->srb->request_bufflen != length) { - US_DEBUGP("redoing cmd with len=%d\n", length); - us->srb->request_bufflen = length; - us->srb->result = us->transport(us->srb, us); - } - - /* reset back to original values */ - us->srb->request_bufflen = savelen; - - /* fix data as necessary */ - switch (us->srb->cmnd[0]) { - case INQUIRY: - if ((((unsigned char*)us->srb->request_buffer)[2] & 0x7) == 0) { - US_DEBUGP("Fixing INQUIRY data, setting SCSI rev to 2\n"); - ((unsigned char*)us->srb->request_buffer)[2] |= 2; - } - /* FALL THROUGH */ - case REQUEST_SENSE: - case MODE_SENSE: - if (us->srb->use_sg == 0 && length > 0) { - int i; - printk(KERN_DEBUG "Data is"); - for (i = 0; i < 32 && i < length; ++i) - printk(" %.2x", ((unsigned char *)us->srb->request_buffer)[i]); - if (i < length) - printk(" ..."); - printk("\n"); - } - - /* FIXME: is this really necessary? */ - us->srb->cmnd[4] = saveallocation; - break; - - case LOG_SENSE: - case MODE_SENSE_10: - /* FIXME: is this really necessary? */ - us->srb->cmnd[7] = saveallocation >> 8; - us->srb->cmnd[8] = saveallocation; - break; - } /* end switch on cmnd[0] */ - } /* if good command */ -} - -/*********************************************************************** - * Transport routines - ***********************************************************************/ - -static int CBI_irq(int state, void *buffer, int len, void *dev_id) -{ - struct us_data *us = (struct us_data *)dev_id; - - US_DEBUGP("USB IRQ recieved for device on host %d\n", us->host_no); - - /* save the data for interpretation later */ - if (state != USB_ST_REMOVED) { - us->ip_data = le16_to_cpup((__u16 *)buffer); - US_DEBUGP("Interrupt Status 0x%x\n", us->ip_data); - } - - /* was this a wanted interrupt? */ - if (us->ip_wanted) { - us->ip_wanted = 0; - wake_up(&us->ip_waitq); - } else { - US_DEBUGP("ERROR: Unwanted interrupt received!\n"); - } - - /* This return code is truly meaningless -- and I mean truly. It gets - * ignored by other layers. It used to indicate if we wanted to get - * another interrupt or disable the interrupt callback - */ - return 0; -} - -/* FIXME: this reset function doesn't really reset the port, and it - * should. Actually it should probably do what it's doing here, and - * reset the port physically - */ -static int CB_reset(struct us_data *us) -{ - unsigned char cmd[12]; - int result; - - US_DEBUGP("CB_reset\n"); - - memset(cmd, 0xFF, sizeof(cmd)); - cmd[0] = SEND_DIAGNOSTIC; - cmd[1] = 4; - result = usb_control_msg(us->pusb_dev, usb_sndctrlpipe(us->pusb_dev,0), - US_CBI_ADSC, USB_TYPE_CLASS | USB_RECIP_INTERFACE, - 0, us->ifnum, cmd, sizeof(cmd), HZ*5); - - /* long wait for reset */ - schedule_timeout(HZ*6); - - US_DEBUGP("CB_reset: clearing endpoint halt\n"); - usb_clear_halt(us->pusb_dev, usb_rcvbulkpipe(us->pusb_dev, us->ep_in)); - usb_clear_halt(us->pusb_dev, usb_rcvbulkpipe(us->pusb_dev, us->ep_out)); - - US_DEBUGP("CB_reset done\n"); - return 0; -} - -static int pop_CB_status(Scsi_Cmnd *srb); - -/* FIXME: we also need a CBI_command which sets up the completion - * interrupt, and waits for it - */ -static int CB_transport(Scsi_Cmnd *srb, struct us_data *us) -{ - int result; - - US_DEBUGP("CBI gets a command:\n"); - US_DEBUG(us_show_command(srb)); - - /* FIXME: we aren't setting the ip_wanted indicator early enough, which - * causes some commands to never complete. This hangs the driver. - */ - - /* let's send the command via the control pipe */ - result = usb_control_msg(us->pusb_dev, usb_sndctrlpipe(us->pusb_dev,0), - US_CBI_ADSC, USB_TYPE_CLASS | USB_RECIP_INTERFACE, - 0, us->ifnum, - srb->cmnd, srb->cmd_len, HZ*5); - - /* check the return code for the command */ - if (result < 0) { - US_DEBUGP("Call to usb_control_msg() returned %d\n", result); - - /* a stall is a fatal condition from the device */ - if (result == -EPIPE) { - US_DEBUGP("-- Stall on control pipe detected. Clearing\n"); - - US_DEBUGP("-- Return from usb_clear_halt() is %d\n", - usb_clear_halt(us->pusb_dev, - usb_sndctrlpipe(us->pusb_dev, 0))); - return USB_STOR_TRANSPORT_ERROR; - } - - /* FIXME: we need to handle NAKs here */ - return USB_STOR_TRANSPORT_ERROR; - } - - /* transfer the data payload for this command, if one exists*/ - if (us_transfer_length(srb)) { - result = us_transfer(srb, US_DIRECTION(srb->cmnd[0])); - US_DEBUGP("CBI attempted to transfer data, result is 0x%x\n", result); - - /* FIXME: what do the return codes from us_transfer mean? */ - if ((result < 0) && - (result != USB_ST_DATAUNDERRUN) && - (result != USB_ST_STALL)) { - return DID_ERROR << 16; - } - } /* if (us_transfer_length(srb)) */ - - /* get status and return it */ - return pop_CB_status(srb); -} - -/* - * Control/Bulk status handler - */ - -static int pop_CB_status(Scsi_Cmnd *srb) -{ - struct us_data *us = (struct us_data *)srb->host_scribble; - int result; - __u8 status[2]; - int retry = 5; - - US_DEBUGP("pop_CB_status, proto=0x%x\n", us->protocol); - switch (us->protocol) { - case US_PR_CB: - /* get from control */ - - while (retry--) { - result = usb_control_msg(us->pusb_dev, usb_rcvctrlpipe(us->pusb_dev,0), - USB_REQ_GET_STATUS, USB_DIR_IN | - USB_TYPE_STANDARD | USB_RECIP_DEVICE, - 0, us->ifnum, status, sizeof(status), HZ*5); - if (result != USB_ST_TIMEOUT) - break; - } - if (result) { - US_DEBUGP("Bad AP status request %d\n", result); - return DID_ABORT << 16; - } - US_DEBUGP("Got AP status 0x%x 0x%x\n", status[0], status[1]); - if (srb->cmnd[0] != REQUEST_SENSE && srb->cmnd[0] != INQUIRY && - ( (status[0] & ~3) || status[1])) - return (DID_OK << 16) | 2; - else - return USB_STOR_TRANSPORT_GOOD; - break; - - /* FIXME: this should be in a separate function */ - case US_PR_CBI: - /* get from interrupt pipe */ - - /* add interrupt transfer, marked for removal */ - us->ip_wanted = 1; - - /* go to sleep until we get this interrup */ - /* FIXME: this should be changed to use a timeout */ - sleep_on(&us->ip_waitq); - - if (us->ip_wanted) { - US_DEBUGP("Did not get interrupt on CBI\n"); - us->ip_wanted = 0; - return USB_STOR_TRANSPORT_ERROR; - } - - US_DEBUGP("Got interrupt data 0x%x\n", us->ip_data); - - /* UFI gives us ASC and ASCQ, like a request sense */ - /* FIXME: is this right? do REQUEST_SENSE and INQUIRY need special - * case handling? - */ - if (us->subclass == US_SC_UFI) { - if (srb->cmnd[0] == REQUEST_SENSE || - srb->cmnd[0] == INQUIRY) - return USB_STOR_TRANSPORT_GOOD; - else - if (us->ip_data) - return USB_STOR_TRANSPORT_FAILED; - else - return USB_STOR_TRANSPORT_GOOD; - } - - /* otherwise, we interpret the data normally */ - switch (us->ip_data) { - case 0x0001: - return USB_STOR_TRANSPORT_GOOD; - case 0x0002: - return USB_STOR_TRANSPORT_FAILED; - default: - return USB_STOR_TRANSPORT_ERROR; - } - } - US_DEBUGP("pop_CB_status, reached end of function\n"); - return USB_STOR_TRANSPORT_ERROR; -} - -static int Bulk_reset(struct us_data *us) -{ - int result; - - result = usb_control_msg(us->pusb_dev, usb_sndctrlpipe(us->pusb_dev,0), - US_BULK_RESET, USB_TYPE_CLASS | USB_RECIP_INTERFACE, - US_BULK_RESET_HARD, us->ifnum, - NULL, 0, HZ*5); - if (result) - US_DEBUGP("Bulk hard reset failed %d\n", result); - usb_clear_halt(us->pusb_dev, usb_rcvbulkpipe(us->pusb_dev, us->ep_in)); - usb_clear_halt(us->pusb_dev, usb_sndbulkpipe(us->pusb_dev, us->ep_out)); - - /* long wait for reset */ - schedule_timeout(HZ*6); - - return result; -} - -/* - * The bulk only protocol handler. - * Uses the in and out endpoints to transfer commands and data - */ -static int Bulk_transport(Scsi_Cmnd *srb, struct us_data *us) -{ - struct bulk_cb_wrap bcb; - struct bulk_cs_wrap bcs; - int result; - int pipe; - int partial; - - /* set up the command wrapper */ - bcb.Signature = US_BULK_CB_SIGN; - bcb.DataTransferLength = us_transfer_length(srb); - bcb.Flags = US_DIRECTION(srb->cmnd[0]) << 7; - bcb.Tag = srb->serial_number; - bcb.Lun = 0; - bcb.Length = srb->cmd_len; - - /* construct the pipe handle */ - pipe = usb_sndbulkpipe(us->pusb_dev, us->ep_out); - - /* copy the command payload */ - memset(bcb.CDB, 0, sizeof(bcb.CDB)); - memcpy(bcb.CDB, srb->cmnd, bcb.Length); - - /* send it to out endpoint */ - US_DEBUGP("Bulk command S 0x%x T 0x%x L %d F %d CL %d\n", - bcb.Signature, bcb.Tag, bcb.DataTransferLength, - bcb.Flags, bcb.Length); - result = usb_bulk_msg(us->pusb_dev, pipe, &bcb, - US_BULK_CB_WRAP_LEN, &partial, HZ*5); - US_DEBUGP("Bulk command transfer result=%d\n", result); - - /* if we stall, we need to clear it before we go on */ - if (result == -EPIPE) { - US_DEBUGP("clearing endpoint halt for pipe 0x%x\n", pipe); - usb_clear_halt(us->pusb_dev, pipe); - } - - /* if the command transfered well, then we go to the data stage */ - /* FIXME: Regardless of the status of the data stage, we go on to the - * status stage. Note that this implies that if a command is - * partially successful, we rely on the device reporting an error - * the CSW. The spec says that the device may just decide to short us. - */ - if (result == 0) { - /* send/receive data payload, if there is any */ - if (bcb.DataTransferLength) { - result = us_transfer(srb, bcb.Flags); - US_DEBUGP("Bulk data transfer result 0x%x\n", result); -#if 0 - if ((result < 0) && (result != USB_ST_DATAUNDERRUN) - && (result != USB_ST_STALL)) { - US_DEBUGP("Bulk data transfer result 0x%x\n", result); - return DID_ABORT << 16; - } -#endif - } - } - - /* See flow chart on pg 15 of the Bulk Only Transport spec for - * an explanation of how this code works. - */ - - /* construct the pipe handle */ - pipe = usb_rcvbulkpipe(us->pusb_dev, us->ep_in); - - /* get CSW for device status */ - result = usb_bulk_msg(us->pusb_dev, pipe, &bcs, - US_BULK_CS_WRAP_LEN, &partial, HZ*5); - - /* did the attempt to read the CSW fail? */ - if (result == -EPIPE) { - US_DEBUGP("clearing endpoint halt for pipe 0x%x\n", pipe); - usb_clear_halt(us->pusb_dev, pipe); - - /* get the status again */ - result = usb_bulk_msg(us->pusb_dev, pipe, &bcs, - US_BULK_CS_WRAP_LEN, &partial, HZ*5); - - /* if it fails again, we need a reset and return an error*/ - if (result == -EPIPE) { - Bulk_reset(us); - return (DID_ABORT << 16); - } - } - - /* if we still have a failure at this point, we're in trouble */ - if (result) { - US_DEBUGP("Bulk status result = 0x%x\n", result); - return DID_ABORT << 16; - } - - /* check bulk status */ - US_DEBUGP("Bulk status S 0x%x T 0x%x R %d V 0x%x\n", - bcs.Signature, bcs.Tag, bcs.Residue, bcs.Status); - if (bcs.Signature != US_BULK_CS_SIGN || bcs.Tag != bcb.Tag || - bcs.Status > US_BULK_STAT_PHASE || partial != 13) { - US_DEBUGP("Bulk logical error\n"); - return DID_ABORT << 16; - } - - /* based on the status code, we report good or bad */ - switch (bcs.Status) { - case US_BULK_STAT_OK: - /* if there is residue, we really didn't finish the command */ - if (bcs.Residue) - return DID_ERROR << 16; - else - return DID_OK << 16; - - case US_BULK_STAT_FAIL: - return DID_ERROR << 16; - - case US_BULK_STAT_PHASE: - Bulk_reset(us); - return DID_ERROR << 16; - } - - return DID_OK << 16; /* check sense required */ -} - -/*********************************************************************** - * Host functions - ***********************************************************************/ - -/* detect adapter (always true ) */ -static int us_detect(struct SHT *sht) -{ - /* FIXME - not nice at all, but how else ? */ - struct us_data *us = (struct us_data *)sht->proc_dir; - char name[32]; - - /* set up our name */ - sprintf(name, "usbscsi%d", us->host_number); - sht->name = sht->proc_name = kmalloc(strlen(name)+1, GFP_KERNEL); - if (!sht->proc_name) - return 0; - strcpy(sht->proc_name, name); - - /* we start with no /proc directory entry */ - sht->proc_dir = NULL; - - /* register the host */ - us->host = scsi_register(sht, sizeof(us)); - if (us->host) { - us->host->hostdata[0] = (unsigned long)us; - us->host_no = us->host->host_no; - return 1; - } - - /* odd... didn't register properly. Abort and free pointers */ - kfree(sht->proc_name); - sht->proc_name = NULL; - sht->name = NULL; - return 0; -} - -/* release - must be here to stop scsi - * from trying to release IRQ etc. - * Kill off our data - */ -static int us_release(struct Scsi_Host *psh) -{ - struct us_data *us = (struct us_data *)psh->hostdata[0]; - struct us_data *prev = (struct us_data *)&us_list; - - if (us->irq_handle) { - usb_release_irq(us->pusb_dev, us->irq_handle, us->irqpipe); - us->irq_handle = NULL; - } - if (us->pusb_dev) - usb_deregister(&storage_driver); - - /* FIXME - leaves hanging host template copy */ - /* (because scsi layer uses it after removal !!!) */ - while (prev->next != us) - prev = prev->next; - prev->next = us->next; - return 0; -} - -/* run command */ -static int us_command( Scsi_Cmnd *srb ) -{ - US_DEBUGP("Bad use of us_command\n"); - - return DID_BAD_TARGET << 16; -} - -/* run command */ -static int us_queuecommand( Scsi_Cmnd *srb , void (*done)(Scsi_Cmnd *)) -{ - struct us_data *us = (struct us_data *)srb->host->hostdata[0]; - - US_DEBUGP("Command wakeup\n"); - if (us->srb) { - /* busy */ - } - srb->host_scribble = (unsigned char *)us; - us->srb = srb; - srb->scsi_done = done; - us->action = US_ACT_COMMAND; - - /* wake up the process task */ - - wake_up_interruptible(&us->waitq); - - return 0; -} - -/* FIXME: This doesn't actually abort anything */ -static int us_abort( Scsi_Cmnd *srb ) -{ - return 0; -} - -static int us_bus_reset( Scsi_Cmnd *srb ) -{ - // struct us_data *us = (struct us_data *)srb->host->hostdata[0]; - - US_DEBUGP("Bus reset requested\n"); - // us->transport_reset(us); - return SUCCESS; -} - -/* FIXME: This doesn't actually reset anything */ -static int us_host_reset( Scsi_Cmnd *srb ) -{ - return 0; -} - -/*********************************************************************** - * /proc/scsi/ functions - ***********************************************************************/ - -/* we use this macro to help us write into the buffer */ -#undef SPRINTF -#define SPRINTF(args...) do { if (pos < (buffer + length)) pos += sprintf (pos, ## args); } while (0) - -int usb_stor_proc_info (char *buffer, char **start, off_t offset, - int length, int hostno, int inout) -{ - struct us_data *us = us_list; - char *pos = buffer; - char *tmp_ptr; - - /* find our data from hostno */ - while (us) { - if (us->host_no == hostno) - break; - us = us->next; - } - - /* if we couldn't find it, we return an error */ - if (!us) - return -ESRCH; - - /* if someone is sending us data, just throw it away */ - if (inout) - return length; - - /* print the controler name */ - SPRINTF ("Host scsi%d: usb-storage\n", hostno); - - /* print product and vendor strings */ - tmp_ptr = kmalloc(256, GFP_KERNEL); - if (!us->pusb_dev || !tmp_ptr) { - SPRINTF(" Vendor: Unknown Vendor\n"); - SPRINTF(" Product: Unknown Product\n"); - } else { - SPRINTF(" Vendor: "); - if (usb_string(us->pusb_dev, us->pusb_dev->descriptor.iManufacturer, tmp_ptr, 256) > 0) - SPRINTF("%s\n", tmp_ptr); - else - SPRINTF("Unknown Vendor\n"); - - SPRINTF(" Product: "); - if (usb_string(us->pusb_dev, us->pusb_dev->descriptor.iProduct, tmp_ptr, 256) > 0) - SPRINTF("%s\n", tmp_ptr); - else - SPRINTF("Unknown Product\n"); - kfree(tmp_ptr); - } - - SPRINTF(" Protocol: "); - switch (us->protocol) { - case US_PR_CB: - SPRINTF("Control/Bulk\n"); - break; - - case US_PR_CBI: - SPRINTF("Control/Bulk/Interrupt\n"); - break; - - case US_PR_BULK: - SPRINTF("Bulk only\n"); - break; - - default: - SPRINTF("Unknown Protocol\n"); - break; - } - - /* show the GUID of the device */ - SPRINTF(" GUID: " GUID_FORMAT "\n", GUID_ARGS(us->guid)); - - /* - * Calculate start of next buffer, and return value. - */ - *start = buffer + offset; - - if ((pos - buffer) < offset) - return (0); - else if ((pos - buffer - offset) < length) - return (pos - buffer - offset); - else - return (length); -} - -/* - * this defines our 'host' - */ - -static Scsi_Host_Template my_host_template = { - NULL, /* next */ - NULL, /* module */ - NULL, /* proc_dir */ - usb_stor_proc_info, - NULL, /* name - points to unique */ - us_detect, - us_release, - NULL, /* info */ - NULL, /* ioctl */ - us_command, - us_queuecommand, - NULL, /* eh_strategy */ - us_abort, - us_bus_reset, - us_bus_reset, - us_host_reset, - NULL, /* abort */ - NULL, /* reset */ - NULL, /* slave_attach */ - NULL, /* bios_param */ - NULL, /* select_queue_depths */ - 1, /* can_queue */ - -1, /* this_id */ - SG_ALL, /* sg_tablesize */ - 1, /* cmd_per_lun */ - 0, /* present */ - FALSE, /* unchecked_isa_dma */ - FALSE, /* use_clustering */ - TRUE, /* use_new_eh_code */ - TRUE /* emulated */ -}; - -static unsigned char sense_notready[] = { - 0x70, /* current error */ - 0x00, - 0x02, /* not ready */ - 0x00, - 0x00, - 0x0a, /* additional length */ - 0x00, - 0x00, - 0x00, - 0x00, - 0x04, /* not ready */ - 0x03, /* manual intervention */ - 0x00, - 0x00, - 0x00, - 0x00 -}; - -static int usb_stor_control_thread(void * __us) -{ - struct us_data *us = (struct us_data *)__us; - int action; - - lock_kernel(); - - /* - * This thread doesn't need any user-level access, - * so get rid of all our resources.. - */ - daemonize(); - - sprintf(current->comm, "usbscsi%d", us->host_number); - - unlock_kernel(); - - up(us->notify); - - for(;;) { - siginfo_t info; - int unsigned long signr; - - interruptible_sleep_on(&us->waitq); - - action = us->action; - us->action = 0; - - /* FIXME: we need to examine placment of break; and - * scsi_done() calls */ - - switch (action) { - case US_ACT_COMMAND: - /* bad device */ - if (us->srb->target || us->srb->lun) { - US_DEBUGP( "Bad device number (%d/%d) or dev 0x%x\n", - us->srb->target, us->srb->lun, (unsigned int)us->pusb_dev); - us->srb->result = DID_BAD_TARGET << 16; - - us->srb->scsi_done(us->srb); - us->srb = NULL; - break; - } - - /* our device has gone - pretend not ready */ - /* FIXME: we also need to handle INQUIRY here, - * probably */ - if (!us->pusb_dev) { - if (us->srb->cmnd[0] == REQUEST_SENSE) { - memcpy(us->srb->request_buffer, sense_notready, - sizeof(sense_notready)); - us->srb->result = DID_OK << 16; - } else { - us->srb->result = (DID_OK << 16) | 2; - } - - us->srb->scsi_done(us->srb); - us->srb = NULL; - break; - } - - /* we've got a command, let's do it! */ - US_DEBUG(us_show_command(us->srb)); - - /* FIXME: this is to support Shuttle E-USB bridges, it - * appears */ - if (us->srb->cmnd[0] == START_STOP && - us->pusb_dev->descriptor.idProduct == 0x0001 && - us->pusb_dev->descriptor.idVendor == 0x04e6) - us->srb->result = DID_OK << 16; - else { - us->proto_handler(us->srb, us); - } - - US_DEBUGP("scsi cmd done, result=0x%x\n", us->srb->result); - us->srb->scsi_done(us->srb); - us->srb = NULL; - break; - - case US_ACT_ABORT: - break; - - case US_ACT_DEVICE_RESET: - break; - - case US_ACT_BUS_RESET: - break; - - case US_ACT_HOST_RESET: - break; - - } /* end switch on action */ - - if (signal_pending(current)) { - /* sending SIGUSR1 makes us print out some info */ - spin_lock_irq(¤t->sigmask_lock); - signr = dequeue_signal(¤t->blocked, &info); - spin_unlock_irq(¤t->sigmask_lock); - - if (signr == SIGUSR2) { - usb_stor_debug = !usb_stor_debug; - printk(USB_STORAGE "debug toggle = %d\n", usb_stor_debug); - } else { - break; /* exit the loop on any other signal */ - } - } - } - - // MOD_DEC_USE_COUNT; - - printk("usb_stor_control_thread exiting\n"); - - /* FIXME: this is a hack to allow for debugging */ - // scsi_unregister_module(MODULE_SCSI_HA, us->htmplt); - - return 0; -} - -/* Probe to see if a new device is actually a SCSI device */ -static void * storage_probe(struct usb_device *dev, unsigned int ifnum) -{ - struct usb_interface_descriptor *interface; - int i; - char mf[32]; /* manufacturer */ - char prod[32]; /* product */ - char serial[32]; /* serial number */ - struct us_data *ss = NULL; - unsigned int flags = 0; - GUID(guid); /* Global Unique Identifier */ - struct us_data *prev; - Scsi_Host_Template *htmplt; - int protocol = 0; - int subclass = 0; - struct usb_interface_descriptor *altsetting = - &(dev->actconfig->interface[ifnum].altsetting[0]); - - /* clear the GUID and fetch the strings */ - GUID_CLEAR(guid); - memset(mf, 0, sizeof(mf)); - memset(prod, 0, sizeof(prod)); - memset(serial, 0, sizeof(serial)); - if (dev->descriptor.iManufacturer) - usb_string(dev, dev->descriptor.iManufacturer, mf, sizeof(mf)); - if (dev->descriptor.iProduct) - usb_string(dev, dev->descriptor.iProduct, prod, sizeof(prod)); - if (dev->descriptor.iSerialNumber) - usb_string(dev, dev->descriptor.iSerialNumber, serial, sizeof(serial)); - - /* let's examine the device now */ - - /* We make an exception for the shuttle E-USB */ - if (dev->descriptor.idVendor == 0x04e6 && - dev->descriptor.idProduct == 0x0001) { - protocol = US_PR_CB; - subclass = US_SC_8070; /* an assumption */ - } else if (dev->descriptor.bDeviceClass != 0 || - altsetting->bInterfaceClass != USB_CLASS_MASS_STORAGE || - altsetting->bInterfaceSubClass < US_SC_MIN || - altsetting->bInterfaceSubClass > US_SC_MAX) { - /* if it's not a mass storage, we go no further */ - return NULL; - } - - /* At this point, we know we've got a live one */ - US_DEBUGP("USB Mass Storage device detected\n"); - - /* Create a GUID for this device */ - if (dev->descriptor.iSerialNumber && serial[0]) { - /* If we have a serial number, and it's a non-NULL string */ - make_guid(guid, dev->descriptor.idVendor, - dev->descriptor.idProduct, serial); - } else { - /* We don't have a serial number, so we use 0 */ - make_guid(guid, dev->descriptor.idVendor, - dev->descriptor.idProduct, "0"); - } - - /* Now check if we have seen this GUID before, and restore - * the flags if we find it - */ - for (ss = us_list; ss != NULL; ss = ss->next) { - if (!ss->pusb_dev && GUID_EQUAL(guid, ss->guid)) { - US_DEBUGP("Found existing GUID " GUID_FORMAT "\n", - GUID_ARGS(guid)); - flags = ss->flags; - break; - } - } - - /* If ss == NULL, then this is a new device. Allocate memory for it */ - if (!ss) { - if ((ss = (struct us_data *)kmalloc(sizeof(*ss), - GFP_KERNEL)) == NULL) { - printk(KERN_WARNING USB_STORAGE "Out of memory\n"); - return NULL; - } - memset(ss, 0, sizeof(struct us_data)); - } - - /* Initialize the us_data structure with some useful info */ - interface = altsetting; - ss->flags = flags; - ss->ifnum = ifnum; - ss->pusb_dev = dev; - ss->attention_done = 0; - - /* If the device has subclass and protocol, then use that. Otherwise, - * take data from the specific interface. - */ - if (subclass) { - ss->subclass = subclass; - ss->protocol = protocol; - } else { - ss->subclass = interface->bInterfaceSubClass; - ss->protocol = interface->bInterfaceProtocol; - } - - /* set the handler pointers based on the protocol */ - US_DEBUGP("Transport: "); - switch (ss->protocol) { - case US_PR_CB: - US_DEBUGPX("Control/Bulk\n"); - ss->transport = CB_transport; - ss->transport_reset = CB_reset; - break; - - case US_PR_CBI: - US_DEBUGPX("Control/Bulk/Interrupt\n"); - ss->transport = CB_transport; - ss->transport_reset = CB_reset; - break; - - case US_PR_BULK: - US_DEBUGPX("Bulk\n"); - ss->transport = Bulk_transport; - ss->transport_reset = Bulk_reset; - break; - - default: - US_DEBUGPX("Unknown\n"); - kfree(ss); - return NULL; - break; - } - - /* - * We are expecting a minimum of 2 endpoints - in and out (bulk). - * An optional interrupt is OK (necessary for CBI protocol). - * We will ignore any others. - */ - for (i = 0; i < interface->bNumEndpoints; i++) { - /* is it an BULK endpoint? */ - if ((interface->endpoint[i].bmAttributes & USB_ENDPOINT_XFERTYPE_MASK) - == USB_ENDPOINT_XFER_BULK) { - if (interface->endpoint[i].bEndpointAddress & USB_DIR_IN) - ss->ep_in = interface->endpoint[i].bEndpointAddress & - USB_ENDPOINT_NUMBER_MASK; - else - ss->ep_out = interface->endpoint[i].bEndpointAddress & - USB_ENDPOINT_NUMBER_MASK; - } - - /* is it an interrupt endpoint? */ - if ((interface->endpoint[i].bmAttributes & USB_ENDPOINT_XFERTYPE_MASK) - == USB_ENDPOINT_XFER_INT) { - ss->ep_int = interface->endpoint[i].bEndpointAddress & - USB_ENDPOINT_NUMBER_MASK; - } - } - US_DEBUGP("Endpoints In %d Out %d Int %d\n", - ss->ep_in, ss->ep_out, ss->ep_int); - - /* Do some basic sanity checks, and bail if we find a problem */ - if (usb_set_interface(dev, interface->bInterfaceNumber, 0) || - !ss->ep_in || !ss->ep_out || - (ss->protocol == US_PR_CBI && ss->ep_int == 0)) { - US_DEBUGP("Problems with device\n"); - if (ss->host) { - scsi_unregister_module(MODULE_SCSI_HA, ss->htmplt); - kfree(ss->htmplt->name); - kfree(ss->htmplt); - } - - kfree(ss); - return NULL; - } - - /* If this is a new device (i.e. we haven't seen it before), we need to - * generate a scsi host definition, and register with scsi above us - */ - if (!ss->host) { - /* copy the GUID we created before */ - US_DEBUGP("New GUID " GUID_FORMAT "\n", GUID_ARGS(guid)); - memcpy(ss->guid, guid, sizeof(guid)); - - /* set class specific stuff */ - US_DEBUGP("Protocol: "); - switch (ss->subclass) { - case US_SC_RBC: - US_DEBUGPX("Reduced Block Commands\n"); - break; - - case US_SC_8020: - US_DEBUGPX("8020\n"); - break; - - case US_SC_QIC: - US_DEBUGPX("QIC157\n"); - break; - - case US_SC_8070: - US_DEBUGPX("8070\n"); - break; - - case US_SC_SCSI: - US_DEBUGPX("Transparent SCSI\n"); - ss->proto_handler = transparent_scsi_command; - break; - - case US_SC_UFI: - US_DEBUGPX("UFI\n"); - ss->proto_handler = ufi_command; - break; - - default: - US_DEBUGPX("Unknown\n"); - break; - } - - /* We only handle certain protocols. Currently, these are - *the only ones that devices use. - */ - if ((ss->subclass != US_SC_SCSI) && (ss->subclass != US_SC_UFI)) { - US_DEBUGP("Sorry, we do not support that protocol yet.\n"); - US_DEBUGP("If you have a device which uses one of the unsupported\n"); - US_DEBUGP("protocols, please contact mdharm-usb@one-eyed-alien.net\n"); - - kfree(ss); - return NULL; - } - - /* Allocate memory for the SCSI Host Template */ - if ((htmplt = (Scsi_Host_Template *) - kmalloc(sizeof(*ss->htmplt), GFP_KERNEL)) == NULL ) { - - printk(KERN_WARNING USB_STORAGE "Out of memory\n"); - - kfree(ss); - return NULL; - } - - /* Initialize the host template based on the default one */ - memcpy(htmplt, &my_host_template, sizeof(my_host_template)); - - /* Grab the next host number */ - ss->host_number = my_host_number++; - - /* MDD: FIXME: this is bad. We abuse this pointer so we - * can pass the ss pointer to the host controler thread - * in us_detect - */ - (struct us_data *)htmplt->proc_dir = ss; - - /* shuttle E-USB */ - if (dev->descriptor.idVendor == 0x04e6 && - dev->descriptor.idProduct == 0x0001) { - __u8 qstat[2]; - int result; - - result = usb_control_msg(ss->pusb_dev, usb_rcvctrlpipe(dev,0), - 1, 0xC0, - 0, ss->ifnum, - qstat, 2, HZ*5); - US_DEBUGP("C0 status 0x%x 0x%x\n", qstat[0], qstat[1]); - init_waitqueue_head(&ss->ip_waitq); - ss->irqpipe = usb_rcvintpipe(ss->pusb_dev, ss->ep_int); - result = usb_request_irq(ss->pusb_dev, ss->irqpipe, CBI_irq, - 255, (void *)ss, &ss->irq_handle); - if (result) - return NULL; - - interruptible_sleep_on_timeout(&ss->ip_waitq, HZ*6); - } else if (ss->protocol == US_PR_CBI) - { - int result; - - init_waitqueue_head(&ss->ip_waitq); - - /* set up the IRQ pipe and handler */ - /* FIXME: This needs to get the period from the device */ - ss->irqpipe = usb_rcvintpipe(ss->pusb_dev, ss->ep_int); - result = usb_request_irq(ss->pusb_dev, ss->irqpipe, CBI_irq, - 255, (void *)ss, &ss->irq_handle); - if (result) { - US_DEBUGP("usb_request_irq failed (0x%x), No interrupt for CBI\n", - result); - } - } - - - /* start up our thread */ - { - DECLARE_MUTEX_LOCKED(sem); - - init_waitqueue_head(&ss->waitq); - - ss->notify = &sem; - ss->pid = kernel_thread(usb_stor_control_thread, ss, - CLONE_FS | CLONE_FILES | CLONE_SIGHAND); - if (ss->pid < 0) { - printk(KERN_WARNING USB_STORAGE "Unable to start control thread\n"); - kfree(htmplt); - - kfree(ss); - return NULL; - } - - /* wait for it to start */ - down(&sem); - } - - /* now register - our detect function will be called */ - scsi_register_module(MODULE_SCSI_HA, htmplt); - - /* put us in the list */ - prev = (struct us_data *)&us_list; - while (prev->next) - prev = prev->next; - prev->next = ss; - } - - printk(KERN_INFO "WARNING: USB Mass Storage data integrity not assured\n"); - printk(KERN_INFO "USB Mass Storage device found at %d\n", dev->devnum); - - return ss; -} - -/* Handle a disconnect event from the USB core */ -static void storage_disconnect(struct usb_device *dev, void *ptr) -{ - struct us_data *ss = ptr; - - if (!ss) - return; - - ss->pusb_dev = NULL; - // MOD_DEC_USE_COUNT; -} - - -/*********************************************************************** - * Initialization and registration - ***********************************************************************/ - -int __init usb_stor_init(void) -{ - // MOD_INC_USE_COUNT; - - if (sizeof(my_host_template) != SCSI_HOST_TEMPLATE_SIZE) { - printk(KERN_ERR "usb-storage: SCSI_HOST_TEMPLATE_SIZE does not match\n") ; - printk(KERN_ERR "usb-storage: expected %d bytes, got %d bytes\n", - SCSI_HOST_TEMPLATE_SIZE, sizeof(my_host_template)) ; - - return -1 ; - } - - /* register the driver, return -1 if error */ - if (usb_register(&storage_driver) < 0) - return -1; - - printk(KERN_INFO "USB Mass Storage support registered.\n"); - return 0; -} - -void __exit usb_stor_exit(void) -{ - usb_deregister(&storage_driver) ; -} - -module_init(usb_stor_init) ; -module_exit(usb_stor_exit) ; diff -u --recursive --new-file v2.3.46/linux/drivers/usb/usb_storage.h linux/drivers/usb/usb_storage.h --- v2.3.46/linux/drivers/usb/usb_storage.h Thu Feb 10 17:11:15 2000 +++ linux/drivers/usb/usb_storage.h Wed Dec 31 16:00:00 1969 @@ -1,130 +0,0 @@ -/* Driver for USB mass storage - include file - * - * (c) 1999 Michael Gee (michael@linuxspecific.com) - * (c) 1999, 2000 Matthew Dharm (mdharm-usb@one-eyed-alien.net) - * - */ - -#include - -#define USB_STORAGE "usb-storage: " - -extern int usb_stor_debug; - -#ifdef CONFIG_USB_STORAGE_DEBUG -void us_show_command(Scsi_Cmnd *srb); -#define US_DEBUGP(x...) { if(usb_stor_debug) printk( KERN_DEBUG USB_STORAGE ## x ); } -#define US_DEBUGPX(x...) { if(usb_stor_debug) printk( ## x ); } -#define US_DEBUG(x) { if(usb_stor_debug) x; } -#else -#define US_DEBUGP(x...) -#define US_DEBUGPX(x...) -#define US_DEBUG(x) -#endif - -/* bit set if input */ -extern unsigned char us_direction[256/8]; -#define US_DIRECTION(x) ((us_direction[x>>3] >> (x & 7)) & 1) - -/* Sub Classes */ - -#define US_SC_RBC 1 /* Typically, flash devices */ -#define US_SC_8020 2 /* CD-ROM */ -#define US_SC_QIC 3 /* QIC-157 Tapes */ -#define US_SC_UFI 4 /* Floppy */ -#define US_SC_8070 5 /* Removable media */ -#define US_SC_SCSI 6 /* Transparent */ -#define US_SC_MIN US_SC_RBC -#define US_SC_MAX US_SC_SCSI - -/* Protocols */ - -#define US_PR_CB 1 /* Control/Bulk w/o interrupt */ -#define US_PR_CBI 0 /* Control/Bulk/Interrupt */ -#define US_PR_BULK 0x50 /* bulk only */ - -/* - * Bulk only data structures (Zip 100, for example) - */ - -/* command block wrapper */ -struct bulk_cb_wrap { - __u32 Signature; /* contains 'USBC' */ - __u32 Tag; /* unique per command id */ - __u32 DataTransferLength; /* size of data */ - __u8 Flags; /* direction in bit 0 */ - __u8 Lun; /* LUN normally 0 */ - __u8 Length; /* of of the CDB */ - __u8 CDB[16]; /* max command */ -}; - -#define US_BULK_CB_WRAP_LEN 31 -#define US_BULK_CB_SIGN 0x43425355 -#define US_BULK_FLAG_IN 1 -#define US_BULK_FLAG_OUT 0 - -/* command status wrapper */ -struct bulk_cs_wrap { - __u32 Signature; /* should = 'USBS' */ - __u32 Tag; /* same as original command */ - __u32 Residue; /* amount not transferred */ - __u8 Status; /* see below */ - __u8 Filler[18]; -}; - -#define US_BULK_CS_WRAP_LEN 13 -#define US_BULK_CS_SIGN 0x53425355 -#define US_BULK_STAT_OK 0 -#define US_BULK_STAT_FAIL 1 -#define US_BULK_STAT_PHASE 2 - -#define US_BULK_RESET 0xff -#define US_BULK_RESET_SOFT 1 -#define US_BULK_RESET_HARD 0 - -/* - * Transport return codes - */ - -#define USB_STOR_TRANSPORT_GOOD 0 /* Transport good, command good */ -#define USB_STOR_TRANSPORT_FAILED 1 /* Transport good, command failed */ -#define USB_STOR_TRANSPORT_ERROR 2 /* Transport bad (i.e. device dead */ - -/* - * CBI style - */ - -#define US_CBI_ADSC 0 - -/* - * GUID definitions - */ - -#define GUID(x) __u32 x[3] -#define GUID_EQUAL(x, y) (x[0] == y[0] && x[1] == y[1] && x[2] == y[2]) -#define GUID_CLEAR(x) x[0] = x[1] = x[2] = 0; -#define GUID_NONE(x) (!x[0] && !x[1] && !x[2]) -#define GUID_FORMAT "%08x%08x%08x" -#define GUID_ARGS(x) x[0], x[1], x[2] - -static inline void make_guid( __u32 *pg, __u16 vendor, __u16 product, char *serial) -{ - pg[0] = (vendor << 16) | product; - pg[1] = pg[2] = 0; - while (*serial) { - pg[1] <<= 4; - pg[1] |= pg[2] >> 28; - pg[2] <<= 4; - if (*serial >= 'a') - *serial -= 'a' - 'A'; - pg[2] |= (*serial <= '9' && *serial >= '0') ? *serial - '0' - : *serial - 'A' + 10; - serial++; - } -} - -/* Flag definitions */ -#define US_FL_IP_STATUS 0x00000001 /* status uses interrupt */ -#define US_FL_FIXED_COMMAND 0x00000002 /* expand commands to fixed size */ -#define US_FL_MODE_XLATE 0x00000004 /* translate _6 to _10 comands for - Win/MacOS compatibility */ diff -u --recursive --new-file v2.3.46/linux/drivers/usb/usb_storage_debug.c linux/drivers/usb/usb_storage_debug.c --- v2.3.46/linux/drivers/usb/usb_storage_debug.c Fri Jan 28 15:09:08 2000 +++ linux/drivers/usb/usb_storage_debug.c Wed Dec 31 16:00:00 1969 @@ -1,104 +0,0 @@ - -/* Driver for USB mass storage (scsi-like) devices - * - * (C) Michael Gee (michael@linuxspecific.com) 1999 - * - */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include -#include "../scsi/scsi.h" -#include "../scsi/hosts.h" -#include "../scsi/sd.h" - -#include "usb.h" -#include "usb_storage.h" - -void us_show_command(Scsi_Cmnd *srb) -{ - char *what = NULL; - - switch (srb->cmnd[0]) { - case TEST_UNIT_READY: what = "TEST_UNIT_READY"; break; - case REZERO_UNIT: what = "REZERO_UNIT"; break; - case REQUEST_SENSE: what = "REQUEST_SENSE"; break; - case FORMAT_UNIT: what = "FORMAT_UNIT"; break; - case READ_BLOCK_LIMITS: what = "READ_BLOCK_LIMITS"; break; - case REASSIGN_BLOCKS: what = "REASSIGN_BLOCKS"; break; - case READ_6: what = "READ_6"; break; - case WRITE_6: what = "WRITE_6"; break; - case SEEK_6: what = "SEEK_6"; break; - case READ_REVERSE: what = "READ_REVERSE"; break; - case WRITE_FILEMARKS: what = "WRITE_FILEMARKS"; break; - case SPACE: what = "SPACE"; break; - case INQUIRY: what = "INQUIRY"; break; - case RECOVER_BUFFERED_DATA: what = "RECOVER_BUFFERED_DATA"; break; - case MODE_SELECT: what = "MODE_SELECT"; break; - case RESERVE: what = "RESERVE"; break; - case RELEASE: what = "RELEASE"; break; - case COPY: what = "COPY"; break; - case ERASE: what = "ERASE"; break; - case MODE_SENSE: what = "MODE_SENSE"; break; - case START_STOP: what = "START_STOP"; break; - case RECEIVE_DIAGNOSTIC: what = "RECEIVE_DIAGNOSTIC"; break; - case SEND_DIAGNOSTIC: what = "SEND_DIAGNOSTIC"; break; - case ALLOW_MEDIUM_REMOVAL: what = "ALLOW_MEDIUM_REMOVAL"; break; - case SET_WINDOW: what = "SET_WINDOW"; break; - case READ_CAPACITY: what = "READ_CAPACITY"; break; - case READ_10: what = "READ_10"; break; - case WRITE_10: what = "WRITE_10"; break; - case SEEK_10: what = "SEEK_10"; break; - case WRITE_VERIFY: what = "WRITE_VERIFY"; break; - case VERIFY: what = "VERIFY"; break; - case SEARCH_HIGH: what = "SEARCH_HIGH"; break; - case SEARCH_EQUAL: what = "SEARCH_EQUAL"; break; - case SEARCH_LOW: what = "SEARCH_LOW"; break; - case SET_LIMITS: what = "SET_LIMITS"; break; - case READ_POSITION: what = "READ_POSITION"; break; - case SYNCHRONIZE_CACHE: what = "SYNCHRONIZE_CACHE"; break; - case LOCK_UNLOCK_CACHE: what = "LOCK_UNLOCK_CACHE"; break; - case READ_DEFECT_DATA: what = "READ_DEFECT_DATA"; break; - case MEDIUM_SCAN: what = "MEDIUM_SCAN"; break; - case COMPARE: what = "COMPARE"; break; - case COPY_VERIFY: what = "COPY_VERIFY"; break; - case WRITE_BUFFER: what = "WRITE_BUFFER"; break; - case READ_BUFFER: what = "READ_BUFFER"; break; - case UPDATE_BLOCK: what = "UPDATE_BLOCK"; break; - case READ_LONG: what = "READ_LONG"; break; - case WRITE_LONG: what = "WRITE_LONG"; break; - case CHANGE_DEFINITION: what = "CHANGE_DEFINITION"; break; - case WRITE_SAME: what = "WRITE_SAME"; break; - case READ_TOC: what = "READ_TOC"; break; - case LOG_SELECT: what = "LOG_SELECT"; break; - case LOG_SENSE: what = "LOG_SENSE"; break; - case MODE_SELECT_10: what = "MODE_SELECT_10"; break; - case MODE_SENSE_10: what = "MODE_SENSE_10"; break; - case MOVE_MEDIUM: what = "MOVE_MEDIUM"; break; - case READ_12: what = "READ_12"; break; - case WRITE_12: what = "WRITE_12"; break; - case WRITE_VERIFY_12: what = "WRITE_VERIFY_12"; break; - case SEARCH_HIGH_12: what = "SEARCH_HIGH_12"; break; - case SEARCH_EQUAL_12: what = "SEARCH_EQUAL_12"; break; - case SEARCH_LOW_12: what = "SEARCH_LOW_12"; break; - case READ_ELEMENT_STATUS: what = "READ_ELEMENT_STATUS"; break; - case SEND_VOLUME_TAG: what = "SEND_VOLUME_TAG"; break; - case WRITE_LONG_2: what = "WRITE_LONG_2"; break; - default: break; - } - printk(KERN_DEBUG USB_STORAGE - "Command %s (%d bytes)\n", what, srb->cmd_len); - printk(KERN_DEBUG USB_STORAGE - " %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x\n", - srb->cmnd[0], srb->cmnd[1], srb->cmnd[2], srb->cmnd[3], srb->cmnd[4], srb->cmnd[5], - srb->cmnd[6], srb->cmnd[7], srb->cmnd[8], srb->cmnd[9]); -} diff -u --recursive --new-file v2.3.46/linux/drivers/video/aty128fb.c linux/drivers/video/aty128fb.c --- v2.3.46/linux/drivers/video/aty128fb.c Sun Feb 13 19:29:04 2000 +++ linux/drivers/video/aty128fb.c Sun Feb 20 08:48:45 2000 @@ -29,7 +29,7 @@ /* * A special note of gratitude to ATI's devrel for providing documentation, - * example code and hardware. Thanks Nitya. -atong + * example code and hardware. Thanks Nitya. -atong and brad */ @@ -129,6 +129,8 @@ {"PCI_DEVICE_ID_ATI_RAGE128_RF", PCI_VENDOR_ID_ATI, 0x5246}, {"PCI_DEVICE_ID_ATI_RAGE128_RK", PCI_VENDOR_ID_ATI, 0x524b}, {"PCI_DEVICE_ID_ATI_RAGE128_RL", PCI_VENDOR_ID_ATI, 0x524c}, + {"PCI_DEVICE_ID_ATI_RAGE128_PF", PCI_VENDOR_ID_ATI, 0x5046}, + {"PCI_DEVICE_ID_ATI_RAGE128_PR", PCI_VENDOR_ID_ATI, 0x5052}, {NULL, 0, 0} }; @@ -1684,8 +1686,8 @@ } else { if (mac_vmode_to_var(default_vmode, default_cmode, &var)) var = default_var; -#endif /* CONFIG_PPC */ } +#endif /* CONFIG_PPC */ #endif /* MODULE */ if (noaccel) @@ -2293,19 +2295,6 @@ /* * Accelerated functions */ - -static void -aty128_rectdraw(s16 x, s16 y, u16 width, u16 height, - struct fb_info_aty128 *info) -{ - /* perform rectangle operation */ - wait_for_fifo(2, info); - aty_st_le32(DST_Y_X, (y << 16) | x); - aty_st_le32(DST_HEIGHT_WIDTH, (height << 16) | width); - - info->blitter_may_be_busy = 1; -} - static void aty128_rectcopy(int srcx, int srcy, int dstx, int dsty, diff -u --recursive --new-file v2.3.46/linux/fs/Config.in linux/fs/Config.in --- v2.3.46/linux/fs/Config.in Wed Feb 16 17:03:52 2000 +++ linux/fs/Config.in Sun Feb 20 16:21:49 2000 @@ -1,32 +1,32 @@ # -# Filesystem configuration +# File system configuration # mainmenu_option next_comment -comment 'Filesystems' +comment 'File systems' bool 'Quota support' CONFIG_QUOTA tristate 'Kernel automounter support' CONFIG_AUTOFS_FS tristate 'Kernel automounter version 4 support (also supports v3)' CONFIG_AUTOFS4_FS -dep_tristate 'ADFS filesystem support (read only) (EXPERIMENTAL)' CONFIG_ADFS_FS $CONFIG_EXPERIMENTAL +dep_tristate 'ADFS file system support (read only) (EXPERIMENTAL)' CONFIG_ADFS_FS $CONFIG_EXPERIMENTAL -tristate 'Amiga FFS filesystem support' CONFIG_AFFS_FS +tristate 'Amiga FFS file system support' CONFIG_AFFS_FS -dep_tristate 'Apple Macintosh filesystem support (EXPERIMENTAL)' CONFIG_HFS_FS $CONFIG_EXPERIMENTAL +dep_tristate 'Apple Macintosh file system support (EXPERIMENTAL)' CONFIG_HFS_FS $CONFIG_EXPERIMENTAL -dep_tristate 'BFS filesystem support (EXPERIMENTAL)' CONFIG_BFS_FS $CONFIG_EXPERIMENTAL +dep_tristate 'BFS file system support (EXPERIMENTAL)' CONFIG_BFS_FS $CONFIG_EXPERIMENTAL -# msdos filesystems +# msdos file systems tristate 'DOS FAT fs support' CONFIG_FAT_FS dep_tristate ' MSDOS fs support' CONFIG_MSDOS_FS $CONFIG_FAT_FS -dep_tristate ' UMSDOS: Unix-like filesystem on top of standard MSDOS fs' CONFIG_UMSDOS_FS $CONFIG_MSDOS_FS +dep_tristate ' UMSDOS: Unix-like file system on top of standard MSDOS fs' CONFIG_UMSDOS_FS $CONFIG_MSDOS_FS dep_tristate ' VFAT (Windows-95) fs support' CONFIG_VFAT_FS $CONFIG_FAT_FS -dep_tristate 'EFS filesystem support (read only) (EXPERIMENTAL)' CONFIG_EFS_FS $CONFIG_EXPERIMENTAL +dep_tristate 'EFS file system support (read only) (EXPERIMENTAL)' CONFIG_EFS_FS $CONFIG_EXPERIMENTAL -tristate 'Compressed ROM filessytem support' CONFIG_CRAMFS +tristate 'Compressed ROM file sytem support' CONFIG_CRAMFS -tristate 'ISO 9660 CDROM filesystem support' CONFIG_ISO9660_FS +tristate 'ISO 9660 CDROM file system support' CONFIG_ISO9660_FS if [ "$CONFIG_ISO9660_FS" != "n" ]; then bool ' Microsoft Joliet CDROM extensions' CONFIG_JOLIET else @@ -36,44 +36,47 @@ tristate 'Minix fs support' CONFIG_MINIX_FS -tristate 'NTFS filesystem support (read only)' CONFIG_NTFS_FS -dep_bool ' NTFS write support (DANGEROUS)' CONFIG_NTFS_RW $CONFIG_NTFS_FS $CONFIG_EXPERIMENTAL +tristate 'NTFS file system support (read only)' CONFIG_NTFS_FS +if [ "$CONFIG_NTFS_FS" != "n" -a "$CONFIG_EXPERIMENTAL" = "y" ]; then + bool ' NTFS write support (DANGEROUS)' CONFIG_NTFS_RW +fi -tristate 'OS/2 HPFS filesystem support' CONFIG_HPFS_FS +tristate 'OS/2 HPFS file system support' CONFIG_HPFS_FS -bool '/proc filesystem support' CONFIG_PROC_FS +bool '/proc file system support' CONFIG_PROC_FS -if [ "$CONFIG_EXPERIMENTAL" = "y" ]; then - bool '/dev filesystem support (EXPERIMENTAL)' CONFIG_DEVFS_FS - if [ "$CONFIG_DEVFS_FS" = "y" ]; then - bool ' Debug devfs' CONFIG_DEVFS_DEBUG - fi -fi +dep_bool '/dev file system support (EXPERIMENTAL)' CONFIG_DEVFS_FS $CONFIG_EXPERIMENTAL +dep_bool ' Debug devfs' CONFIG_DEVFS_DEBUG $CONFIG_DEVFS_FS # It compiles as a module for testing only. It should not be used # as a module in general. If we make this "tristate", a bunch of people # who don't know what they are doing turn it on and complain when it # breaks. -dep_bool '/dev/pts filesystem for Unix98 PTYs' CONFIG_DEVPTS_FS $CONFIG_UNIX98_PTYS +dep_bool '/dev/pts file system for Unix98 PTYs' CONFIG_DEVPTS_FS $CONFIG_UNIX98_PTYS -dep_tristate 'QNX4 filesystem support (read only) (EXPERIMENTAL)' CONFIG_QNX4FS_FS $CONFIG_EXPERIMENTAL -dep_bool ' QNX4FS write support (DANGEROUS)' CONFIG_QNX4FS_RW $CONFIG_QNX4FS_FS +dep_tristate 'QNX4 file system support (read only) (EXPERIMENTAL)' CONFIG_QNX4FS_FS $CONFIG_EXPERIMENTAL +if [ "$CONFIG_QNX4FS_FS" != "n" -a "$CONFIG_EXPERIMENTAL" = "y" ]; then + bool ' QNX4FS write support (DANGEROUS)' CONFIG_QNX4FS_RW +fi -tristate 'ROM filesystem support' CONFIG_ROMFS_FS +tristate 'ROM file system support' CONFIG_ROMFS_FS tristate 'Second extended fs support' CONFIG_EXT2_FS -tristate 'System V and Coherent filesystem support' CONFIG_SYSV_FS -dep_bool ' SYSV filesystem write support (DANGEROUS)' CONFIG_SYSV_FS_WRITE $CONFIG_SYSV_FS $CONFIG_EXPERIMENTAL +tristate 'System V and Coherent file system support (read only)' CONFIG_SYSV_FS +if [ "$CONFIG_SYSV_FS" != "n" -a "$CONFIG_EXPERIMENTAL" = "y" ]; then + bool ' SYSV file system write support (DANGEROUS)' CONFIG_SYSV_FS_WRITE +fi -tristate 'UDF filesystem support (read only)' CONFIG_UDF_FS +tristate 'UDF file system support (read only)' CONFIG_UDF_FS if [ "$CONFIG_UDF_FS" != "n" -a "$CONFIG_EXPERIMENTAL" = "y" ]; then - bool ' UDF write support (DANGEROUS)' CONFIG_UDF_RW + bool ' UDF write support (DANGEROUS)' CONFIG_UDF_RW fi -tristate 'UFS filesystem support (read only)' CONFIG_UFS_FS -dep_bool ' UFS filesystem write support (DANGEROUS)' CONFIG_UFS_FS_WRITE $CONFIG_UFS_FS $CONFIG_EXPERIMENTAL - +tristate 'UFS file system support (read only)' CONFIG_UFS_FS +if [ "$CONFIG_UFS_FS" != "n" -a "$CONFIG_EXPERIMENTAL" = "y" ]; then + bool ' UFS file system write support (DANGEROUS)' CONFIG_UFS_FS_WRITE +fi if [ "$CONFIG_NET" = "y" ]; then @@ -81,13 +84,15 @@ comment 'Network File Systems' if [ "$CONFIG_INET" = "y" ]; then - tristate 'Coda filesystem support (advanced network fs)' CONFIG_CODA_FS + tristate 'Coda file system support (advanced network fs)' CONFIG_CODA_FS - tristate 'NFS filesystem support' CONFIG_NFS_FS + tristate 'NFS file system support' CONFIG_NFS_FS dep_bool ' Root file system on NFS' CONFIG_ROOT_NFS $CONFIG_NFS_FS $CONFIG_IP_PNP tristate 'NFS server support' CONFIG_NFSD - dep_bool ' Provide NFSv3 server support (EXPERIMENTAL)' CONFIG_NFSD_V3 $CONFIG_NFSD $CONFIG_EXPERIMENTAL + if [ "$CONFIG_NFSD" != "n" ]; then + bool ' Provide NFSv3 server support (EXPERIMENTAL)' CONFIG_NFSD_V3 + fi if [ "$CONFIG_NFS_FS" = "y" -o "$CONFIG_NFSD" = "y" ]; then define_tristate CONFIG_SUNRPC y @@ -101,10 +106,13 @@ define_tristate CONFIG_LOCKD n fi fi - tristate 'SMB filesystem support (to mount WfW shares etc.)' CONFIG_SMB_FS + if [ "$CONFIG_NFSD_V3" = "y" ]; then + define_bool CONFIG_LOCKD_V4 y + fi + tristate 'SMB file system support (to mount Windows shares etc.)' CONFIG_SMB_FS fi if [ "$CONFIG_IPX" != "n" -o "$CONFIG_INET" != "n" ]; then - tristate 'NCP filesystem support (to mount NetWare volumes)' CONFIG_NCP_FS + tristate 'NCP file system support (to mount NetWare volumes)' CONFIG_NCP_FS if [ "$CONFIG_NCP_FS" != "n" ]; then source fs/ncpfs/Config.in fi diff -u --recursive --new-file v2.3.46/linux/fs/adfs/inode.c linux/fs/adfs/inode.c --- v2.3.46/linux/fs/adfs/inode.c Sun Feb 13 19:29:04 2000 +++ linux/fs/adfs/inode.c Wed Feb 16 20:23:47 2000 @@ -334,10 +334,8 @@ if (error) goto out; - if (ia_valid & ATTR_SIZE) { - inode->i_size = attr->ia_size; + if (ia_valid & ATTR_SIZE) vmtruncate(inode, attr->ia_size); - } if (ia_valid & ATTR_MTIME) { inode->i_mtime = attr->ia_mtime; adfs_unix2adfs_time(inode, attr->ia_mtime); diff -u --recursive --new-file v2.3.46/linux/fs/attr.c linux/fs/attr.c --- v2.3.46/linux/fs/attr.c Sun Feb 13 19:29:04 2000 +++ linux/fs/attr.c Wed Feb 16 20:23:47 2000 @@ -62,10 +62,8 @@ inode->i_uid = attr->ia_uid; if (ia_valid & ATTR_GID) inode->i_gid = attr->ia_gid; - if (ia_valid & ATTR_SIZE) { - inode->i_size = attr->ia_size; + if (ia_valid & ATTR_SIZE) vmtruncate(inode, attr->ia_size); - } if (ia_valid & ATTR_ATIME) inode->i_atime = attr->ia_atime; if (ia_valid & ATTR_MTIME) diff -u --recursive --new-file v2.3.46/linux/fs/binfmt_script.c linux/fs/binfmt_script.c --- v2.3.46/linux/fs/binfmt_script.c Tue Aug 3 10:18:39 1999 +++ linux/fs/binfmt_script.c Sun Feb 20 20:16:37 2000 @@ -14,7 +14,7 @@ static int do_load_script(struct linux_binprm *bprm,struct pt_regs *regs) { - char *cp, *i_name, *i_name_start, *i_arg; + char *cp, *i_name, *i_arg; struct dentry * dentry; char interp[128]; int retval; @@ -44,17 +44,15 @@ for (cp = bprm->buf+2; (*cp == ' ') || (*cp == '\t'); cp++); if (*cp == '\0') return -ENOEXEC; /* No interpreter name found */ - i_name_start = i_name = cp; + i_name = cp; i_arg = 0; - for ( ; *cp && (*cp != ' ') && (*cp != '\t'); cp++) { - if (*cp == '/') - i_name = cp+1; - } + for ( ; *cp && (*cp != ' ') && (*cp != '\t'); cp++) + /* nothing */ ; while ((*cp == ' ') || (*cp == '\t')) *cp++ = '\0'; if (*cp) i_arg = cp; - strcpy (interp, i_name_start); + strcpy (interp, i_name); /* * OK, we've parsed out the interpreter name and * (optional) argument. diff -u --recursive --new-file v2.3.46/linux/fs/buffer.c linux/fs/buffer.c --- v2.3.46/linux/fs/buffer.c Thu Feb 10 17:11:16 2000 +++ linux/fs/buffer.c Wed Feb 16 20:23:47 2000 @@ -1692,8 +1692,12 @@ int generic_commit_write(struct file *file, struct page *page, unsigned from, unsigned to) { - __block_commit_write((struct inode*)page->mapping->host,page,from,to); + struct inode *inode = (struct inode*)page->mapping->host; + loff_t pos = ((loff_t)page->index << PAGE_CACHE_SHIFT) + to; + __block_commit_write(inode,page,from,to); kunmap(page); + if (pos > inode->i_size) + inode->i_size = pos; return 0; } @@ -2010,7 +2014,6 @@ kaddr = (char*)page_address(page); memcpy(kaddr, symname, len-1); mapping->a_ops->commit_write(NULL, page, 0, len-1); - inode->i_size = len-1; /* * Notice that we are _not_ going to block here - end of page is * unmapped, so this will only try to map the rest of page, see @@ -2026,7 +2029,6 @@ mark_inode_dirty(inode); return 0; fail_map: - inode->i_size = len-1; UnlockPage(page); page_cache_release(page); fail: diff -u --recursive --new-file v2.3.46/linux/fs/ext2/inode.c linux/fs/ext2/inode.c --- v2.3.46/linux/fs/ext2/inode.c Thu Feb 10 17:11:17 2000 +++ linux/fs/ext2/inode.c Sun Feb 20 13:09:46 2000 @@ -35,7 +35,9 @@ */ void ext2_put_inode (struct inode * inode) { + lock_kernel(); ext2_discard_prealloc (inode); + unlock_kernel(); } /* @@ -43,6 +45,8 @@ */ void ext2_delete_inode (struct inode * inode) { + lock_kernel(); + if (is_bad_inode(inode) || inode->i_ino == EXT2_ACL_IDX_INO || inode->i_ino == EXT2_ACL_DATA_INO) @@ -54,6 +58,8 @@ if (inode->i_blocks) ext2_truncate (inode); ext2_free_inode (inode); + + unlock_kernel(); } #define inode_bmap(inode, nr) (le32_to_cpu((inode)->u.ext2_i.i_data[(nr)])) @@ -893,7 +899,9 @@ void ext2_write_inode (struct inode * inode) { + lock_kernel(); ext2_update_inode (inode, 0); + unlock_kernel(); } int ext2_sync_inode (struct inode *inode) diff -u --recursive --new-file v2.3.46/linux/fs/inode.c linux/fs/inode.c --- v2.3.46/linux/fs/inode.c Sun Feb 13 19:29:04 2000 +++ linux/fs/inode.c Sun Feb 20 20:51:56 2000 @@ -156,11 +156,26 @@ inode->i_sb->s_op->write_inode(inode); } +static inline void __iget(struct inode * inode) +{ + if (!inode->i_count++) + { + if (!(inode->i_state & I_DIRTY)) + { + list_del(&inode->i_list); + list_add(&inode->i_list, &inode_in_use); + } + inodes_stat.nr_unused--; + } +} + static inline void sync_one(struct inode *inode) { if (inode->i_state & I_LOCK) { + __iget(inode); spin_unlock(&inode_lock); __wait_on_inode(inode); + iput(inode); spin_lock(&inode_lock); } else { list_del(&inode->i_list); @@ -253,6 +268,8 @@ BUG(); if (!(inode->i_state & I_FREEING)) BUG(); + if (inode->i_state & I_CLEAR) + BUG(); wait_on_inode(inode); if (IS_QUOTAINIT(inode)) DQUOT_DROP(inode); @@ -262,7 +279,7 @@ bdput(inode->i_bdev); inode->i_bdev = NULL; } - inode->i_state = 0; + inode->i_state = I_CLEAR; } /* @@ -377,6 +394,8 @@ entry = entry->prev; inode = INODE(tmp); + if (inode->i_state & (I_FREEING|I_CLEAR)) + BUG(); if (!CAN_UNUSE(inode)) continue; if (inode->i_count) @@ -413,19 +432,6 @@ return 0; } -static inline void __iget(struct inode * inode) -{ - if (!inode->i_count++) - { - if (!(inode->i_state & I_DIRTY)) - { - list_del(&inode->i_list); - list_add(&inode->i_list, &inode_in_use); - } - inodes_stat.nr_unused--; - } -} - /* * Called with the inode lock held. * NOTE: we are not increasing the inode-refcount, you must call __iget() @@ -603,6 +609,11 @@ if (!(inode->i_state & I_FREEING)) __iget(inode); else + /* + * Handle the case where s_op->clear_inode is not been + * called yet, and somebody is calling igrab + * while the inode is getting freed. + */ inode = NULL; spin_unlock(&inode_lock); if (inode) @@ -669,32 +680,39 @@ list_del(&inode->i_list); INIT_LIST_HEAD(&inode->i_list); inode->i_state|=I_FREEING; + spin_unlock(&inode_lock); + + destroy = 1; if (op && op->delete_inode) { void (*delete)(struct inode *) = op->delete_inode; - spin_unlock(&inode_lock); if (inode->i_data.nrpages) truncate_inode_pages(&inode->i_data, 0); + /* s_op->delete_inode internally recalls clear_inode() */ delete(inode); - spin_lock(&inode_lock); - } - } - if (list_empty(&inode->i_hash)) { - list_del(&inode->i_list); - INIT_LIST_HEAD(&inode->i_list); - inode->i_state|=I_FREEING; - spin_unlock(&inode_lock); - clear_inode(inode); - destroy = 1; + } else + clear_inode(inode); + if (inode->i_state != I_CLEAR) + BUG(); + spin_lock(&inode_lock); - } - else - { - if (!(inode->i_state & I_DIRTY)) { + } else { + if (!list_empty(&inode->i_hash)) { + if (!(inode->i_state & I_DIRTY)) { + list_del(&inode->i_list); + list_add(&inode->i_list, + &inode_unused); + } + inodes_stat.nr_unused++; + } else { + /* magic nfs path */ list_del(&inode->i_list); - list_add(&inode->i_list, - &inode_unused); + INIT_LIST_HEAD(&inode->i_list); + inode->i_state|=I_FREEING; + spin_unlock(&inode_lock); + clear_inode(inode); + destroy = 1; + spin_lock(&inode_lock); } - inodes_stat.nr_unused++; } #ifdef INODE_PARANOIA if (inode->i_flock) diff -u --recursive --new-file v2.3.46/linux/fs/lockd/Makefile linux/fs/lockd/Makefile --- v2.3.46/linux/fs/lockd/Makefile Mon Apr 7 11:35:30 1997 +++ linux/fs/lockd/Makefile Thu Feb 17 17:23:30 2000 @@ -10,6 +10,11 @@ O_TARGET := lockd.o O_OBJS := clntlock.o clntproc.o host.o svc.o svclock.o svcshare.o \ svcproc.o svcsubs.o mon.o xdr.o + +ifdef CONFIG_LOCKD_V4 + O_OBJS += xdr4.o svc4proc.o +endif + OX_OBJS := lockd_syms.o M_OBJS := $(O_TARGET) diff -u --recursive --new-file v2.3.46/linux/fs/lockd/clntproc.c linux/fs/lockd/clntproc.c --- v2.3.46/linux/fs/lockd/clntproc.c Wed Oct 27 16:34:12 1999 +++ linux/fs/lockd/clntproc.c Sun Feb 20 20:37:48 2000 @@ -69,7 +69,7 @@ call->a_args.lock = *lock; call->a_args.lock.caller = system_utsname.nodename; - init_waitqueue_head(&lock->fl.fl_wait); + init_waitqueue_head(&call->a_args.lock.fl.fl_wait); /* set default data area */ call->a_args.lock.oh.data = call->a_owner; diff -u --recursive --new-file v2.3.46/linux/fs/lockd/lockd_syms.c linux/fs/lockd/lockd_syms.c --- v2.3.46/linux/fs/lockd/lockd_syms.c Mon Apr 7 11:35:30 1997 +++ linux/fs/lockd/lockd_syms.c Thu Feb 17 17:23:30 2000 @@ -39,4 +39,15 @@ EXPORT_SYMBOL(nlmsvc_grace_period); EXPORT_SYMBOL(nlmsvc_timeout); +#ifdef CONFIG_LOCKD_V4 + +/* NLM4 exported symbols */ +EXPORT_SYMBOL(nlm4_rofs); +EXPORT_SYMBOL(nlm4_stale_fh); +EXPORT_SYMBOL(nlm4_deadlock); +EXPORT_SYMBOL(nlm4_failed); +EXPORT_SYMBOL(nlm4_fbig); + +#endif + #endif /* CONFIG_MODULES */ diff -u --recursive --new-file v2.3.46/linux/fs/lockd/svc.c linux/fs/lockd/svc.c --- v2.3.46/linux/fs/lockd/svc.c Thu Feb 10 17:11:17 2000 +++ linux/fs/lockd/svc.c Thu Feb 17 17:23:30 2000 @@ -343,7 +343,7 @@ static struct svc_version nlmsvc_version3 = { 3, 24, nlmsvc_procedures, NULL }; -#ifdef CONFIG_NFSD_NFS3 +#ifdef CONFIG_LOCKD_V4 static struct svc_version nlmsvc_version4 = { 4, 24, nlmsvc_procedures4, NULL }; @@ -353,7 +353,7 @@ &nlmsvc_version1, NULL, &nlmsvc_version3, -#ifdef CONFIG_NFSD_NFS3 +#ifdef CONFIG_LOCKD_V4 &nlmsvc_version4, #endif }; diff -u --recursive --new-file v2.3.46/linux/fs/lockd/svc4proc.c linux/fs/lockd/svc4proc.c --- v2.3.46/linux/fs/lockd/svc4proc.c Wed Dec 31 16:00:00 1969 +++ linux/fs/lockd/svc4proc.c Thu Feb 17 17:23:30 2000 @@ -0,0 +1,561 @@ +/* + * linux/fs/lockd/svc4proc.c + * + * Lockd server procedures. We don't implement the NLM_*_RES + * procedures because we don't use the async procedures. + * + * Copyright (C) 1996, Olaf Kirch + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + + +#define NLMDBG_FACILITY NLMDBG_CLIENT + +static u32 nlm4svc_callback(struct svc_rqst *, u32, struct nlm_res *); +static void nlm4svc_callback_exit(struct rpc_task *); + +/* + * Obtain client and file from arguments + */ +static u32 +nlm4svc_retrieve_args(struct svc_rqst *rqstp, struct nlm_args *argp, + struct nlm_host **hostp, struct nlm_file **filp) +{ + struct nlm_host *host = NULL; + struct nlm_file *file = NULL; + struct nlm_lock *lock = &argp->lock; + u32 error = 0; + + /* nfsd callbacks must have been installed for this procedure */ + if (!nlmsvc_ops) + return nlm_lck_denied_nolocks; + + /* Obtain handle for client host */ + if (rqstp->rq_client == NULL) { + printk(KERN_NOTICE + "lockd: unauthenticated request from (%08x:%d)\n", + ntohl(rqstp->rq_addr.sin_addr.s_addr), + ntohs(rqstp->rq_addr.sin_port)); + return nlm_lck_denied_nolocks; + } + + /* Obtain host handle */ + if (!(host = nlmsvc_lookup_host(rqstp)) + || (argp->monitor && !host->h_monitored && nsm_monitor(host) < 0)) + goto no_locks; + *hostp = host; + + /* Obtain file pointer. Not used by FREE_ALL call. */ + if (filp != NULL) { + if ((error = nlm_lookup_file(rqstp, &file, &lock->fh)) != 0) + goto no_locks; + *filp = file; + + /* Set up the missing parts of the file_lock structure */ + lock->fl.fl_file = &file->f_file; + lock->fl.fl_owner = (fl_owner_t) host; + } + + return 0; + +no_locks: + if (host) + nlm_release_host(host); + if (error) + return error; + return nlm_lck_denied_nolocks; +} + +/* + * NULL: Test for presence of service + */ +static int +nlm4svc_proc_null(struct svc_rqst *rqstp, void *argp, void *resp) +{ + dprintk("lockd: NULL called\n"); + return rpc_success; +} + +/* + * TEST: Check for conflicting lock + */ +static int +nlm4svc_proc_test(struct svc_rqst *rqstp, struct nlm_args *argp, + struct nlm_res *resp) +{ + struct nlm_host *host; + struct nlm_file *file; + + dprintk("lockd: TEST4 called\n"); + resp->cookie = argp->cookie; + + /* Don't accept test requests during grace period */ + if (nlmsvc_grace_period) { + resp->status = nlm_lck_denied_grace_period; + return rpc_success; + } + + /* Obtain client and file */ + if ((resp->status = nlm4svc_retrieve_args(rqstp, argp, &host, &file))) + return rpc_success; + + /* Now check for conflicting locks */ + resp->status = nlmsvc_testlock(file, &argp->lock, &resp->lock); + + dprintk("lockd: TEST4 status %d\n", ntohl(resp->status)); + nlm_release_host(host); + nlm_release_file(file); + return rpc_success; +} + +static int +nlm4svc_proc_lock(struct svc_rqst *rqstp, struct nlm_args *argp, + struct nlm_res *resp) +{ + struct nlm_host *host; + struct nlm_file *file; + + dprintk("lockd: LOCK called\n"); + + resp->cookie = argp->cookie; + + /* Don't accept new lock requests during grace period */ + if (nlmsvc_grace_period && !argp->reclaim) { + resp->status = nlm_lck_denied_grace_period; + return rpc_success; + } + + /* Obtain client and file */ + if ((resp->status = nlm4svc_retrieve_args(rqstp, argp, &host, &file))) + return rpc_success; + +#if 0 + /* If supplied state doesn't match current state, we assume it's + * an old request that time-warped somehow. Any error return would + * do in this case because it's irrelevant anyway. + * + * NB: We don't retrieve the remote host's state yet. + */ + if (host->h_nsmstate && host->h_nsmstate != argp->state) { + resp->status = nlm_lck_denied_nolocks; + } else +#endif + + /* Now try to lock the file */ + resp->status = nlmsvc_lock(rqstp, file, &argp->lock, + argp->block, &argp->cookie); + + dprintk("lockd: LOCK status %d\n", ntohl(resp->status)); + nlm_release_host(host); + nlm_release_file(file); + return rpc_success; +} + +static int +nlm4svc_proc_cancel(struct svc_rqst *rqstp, struct nlm_args *argp, + struct nlm_res *resp) +{ + struct nlm_host *host; + struct nlm_file *file; + + dprintk("lockd: CANCEL called\n"); + + resp->cookie = argp->cookie; + + /* Don't accept requests during grace period */ + if (nlmsvc_grace_period) { + resp->status = nlm_lck_denied_grace_period; + return rpc_success; + } + + /* Obtain client and file */ + if ((resp->status = nlm4svc_retrieve_args(rqstp, argp, &host, &file))) + return rpc_success; + + /* Try to cancel request. */ + resp->status = nlmsvc_cancel_blocked(file, &argp->lock); + + dprintk("lockd: CANCEL status %d\n", ntohl(resp->status)); + nlm_release_host(host); + nlm_release_file(file); + return rpc_success; +} + +/* + * UNLOCK: release a lock + */ +static int +nlm4svc_proc_unlock(struct svc_rqst *rqstp, struct nlm_args *argp, + struct nlm_res *resp) +{ + struct nlm_host *host; + struct nlm_file *file; + + dprintk("lockd: UNLOCK called\n"); + + resp->cookie = argp->cookie; + + /* Don't accept new lock requests during grace period */ + if (nlmsvc_grace_period) { + resp->status = nlm_lck_denied_grace_period; + return rpc_success; + } + + /* Obtain client and file */ + if ((resp->status = nlm4svc_retrieve_args(rqstp, argp, &host, &file))) + return rpc_success; + + /* Now try to remove the lock */ + resp->status = nlmsvc_unlock(file, &argp->lock); + + dprintk("lockd: UNLOCK status %d\n", ntohl(resp->status)); + nlm_release_host(host); + nlm_release_file(file); + return rpc_success; +} + +/* + * GRANTED: A server calls us to tell that a process' lock request + * was granted + */ +static int +nlm4svc_proc_granted(struct svc_rqst *rqstp, struct nlm_args *argp, + struct nlm_res *resp) +{ + resp->cookie = argp->cookie; + + dprintk("lockd: GRANTED called\n"); + resp->status = nlmclnt_grant(&argp->lock); + dprintk("lockd: GRANTED status %d\n", ntohl(resp->status)); + return rpc_success; +} + +/* + * `Async' versions of the above service routines. They aren't really, + * because we send the callback before the reply proper. I hope this + * doesn't break any clients. + */ +static int +nlm4svc_proc_test_msg(struct svc_rqst *rqstp, struct nlm_args *argp, + void *resp) +{ + struct nlm_res res; + u32 stat; + + dprintk("lockd: TEST_MSG called\n"); + + if ((stat = nlm4svc_proc_test(rqstp, argp, &res)) == 0) + stat = nlm4svc_callback(rqstp, NLMPROC_TEST_RES, &res); + return stat; +} + +static int +nlm4svc_proc_lock_msg(struct svc_rqst *rqstp, struct nlm_args *argp, + void *resp) +{ + struct nlm_res res; + u32 stat; + + dprintk("lockd: LOCK_MSG called\n"); + + if ((stat = nlm4svc_proc_lock(rqstp, argp, &res)) == 0) + stat = nlm4svc_callback(rqstp, NLMPROC_LOCK_RES, &res); + return stat; +} + +static int +nlm4svc_proc_cancel_msg(struct svc_rqst *rqstp, struct nlm_args *argp, + void *resp) +{ + struct nlm_res res; + u32 stat; + + dprintk("lockd: CANCEL_MSG called\n"); + + if ((stat = nlm4svc_proc_cancel(rqstp, argp, &res)) == 0) + stat = nlm4svc_callback(rqstp, NLMPROC_CANCEL_RES, &res); + return stat; +} + +static int +nlm4svc_proc_unlock_msg(struct svc_rqst *rqstp, struct nlm_args *argp, + void *resp) +{ + struct nlm_res res; + u32 stat; + + dprintk("lockd: UNLOCK_MSG called\n"); + + if ((stat = nlm4svc_proc_unlock(rqstp, argp, &res)) == 0) + stat = nlm4svc_callback(rqstp, NLMPROC_UNLOCK_RES, &res); + return stat; +} + +static int +nlm4svc_proc_granted_msg(struct svc_rqst *rqstp, struct nlm_args *argp, + void *resp) +{ + struct nlm_res res; + u32 stat; + + dprintk("lockd: GRANTED_MSG called\n"); + + if ((stat = nlm4svc_proc_granted(rqstp, argp, &res)) == 0) + stat = nlm4svc_callback(rqstp, NLMPROC_GRANTED_RES, &res); + return stat; +} + +/* + * SHARE: create a DOS share or alter existing share. + */ +static int +nlm4svc_proc_share(struct svc_rqst *rqstp, struct nlm_args *argp, + struct nlm_res *resp) +{ + struct nlm_host *host; + struct nlm_file *file; + + dprintk("lockd: SHARE called\n"); + + resp->cookie = argp->cookie; + + /* Don't accept new lock requests during grace period */ + if (nlmsvc_grace_period && !argp->reclaim) { + resp->status = nlm_lck_denied_grace_period; + return rpc_success; + } + + /* Obtain client and file */ + if ((resp->status = nlm4svc_retrieve_args(rqstp, argp, &host, &file))) + return rpc_success; + + /* Now try to create the share */ + resp->status = nlmsvc_share_file(host, file, argp); + + dprintk("lockd: SHARE status %d\n", ntohl(resp->status)); + nlm_release_host(host); + nlm_release_file(file); + return rpc_success; +} + +/* + * UNSHARE: Release a DOS share. + */ +static int +nlm4svc_proc_unshare(struct svc_rqst *rqstp, struct nlm_args *argp, + struct nlm_res *resp) +{ + struct nlm_host *host; + struct nlm_file *file; + + dprintk("lockd: UNSHARE called\n"); + + resp->cookie = argp->cookie; + + /* Don't accept requests during grace period */ + if (nlmsvc_grace_period) { + resp->status = nlm_lck_denied_grace_period; + return rpc_success; + } + + /* Obtain client and file */ + if ((resp->status = nlm4svc_retrieve_args(rqstp, argp, &host, &file))) + return rpc_success; + + /* Now try to lock the file */ + resp->status = nlmsvc_unshare_file(host, file, argp); + + dprintk("lockd: UNSHARE status %d\n", ntohl(resp->status)); + nlm_release_host(host); + nlm_release_file(file); + return rpc_success; +} + +/* + * NM_LOCK: Create an unmonitored lock + */ +static int +nlm4svc_proc_nm_lock(struct svc_rqst *rqstp, struct nlm_args *argp, + struct nlm_res *resp) +{ + dprintk("lockd: NM_LOCK called\n"); + + argp->monitor = 0; /* just clean the monitor flag */ + return nlm4svc_proc_lock(rqstp, argp, resp); +} + +/* + * FREE_ALL: Release all locks and shares held by client + */ +static int +nlm4svc_proc_free_all(struct svc_rqst *rqstp, struct nlm_args *argp, + void *resp) +{ + struct nlm_host *host; + + /* Obtain client */ + if (nlm4svc_retrieve_args(rqstp, argp, &host, NULL)) + return rpc_success; + + nlmsvc_free_host_resources(host); + nlm_release_host(host); + return rpc_success; +} + +/* + * SM_NOTIFY: private callback from statd (not part of official NLM proto) + */ +static int +nlm4svc_proc_sm_notify(struct svc_rqst *rqstp, struct nlm_reboot *argp, + void *resp) +{ + struct sockaddr_in saddr = rqstp->rq_addr; + struct nlm_host *host; + + dprintk("lockd: SM_NOTIFY called\n"); + if (saddr.sin_addr.s_addr != htonl(INADDR_LOOPBACK) + || ntohs(saddr.sin_port) >= 1024) { + printk(KERN_WARNING + "lockd: rejected NSM callback from %08x:%d\n", + ntohl(rqstp->rq_addr.sin_addr.s_addr), + ntohs(rqstp->rq_addr.sin_port)); + return rpc_system_err; + } + + /* Obtain the host pointer for this NFS server and try to + * reclaim all locks we hold on this server. + */ + saddr.sin_addr.s_addr = argp->addr; + if ((host = nlm_lookup_host(NULL, &saddr, IPPROTO_UDP, 1)) != NULL) { + nlmclnt_recovery(host, argp->state); + nlm_release_host(host); + } + + /* If we run on an NFS server, delete all locks held by the client */ + if (nlmsvc_ops != NULL) { + struct svc_client *clnt; + saddr.sin_addr.s_addr = argp->addr; + if ((clnt = nlmsvc_ops->exp_getclient(&saddr)) != NULL + && (host = nlm_lookup_host(clnt, &saddr, 0, 0)) != NULL) { + nlmsvc_free_host_resources(host); + } + nlm_release_host(host); + } + + return rpc_success; +} + +/* + * This is the generic lockd callback for async RPC calls + */ +static u32 +nlm4svc_callback(struct svc_rqst *rqstp, u32 proc, struct nlm_res *resp) +{ + struct nlm_host *host; + struct nlm_rqst *call; + + if (!(call = nlmclnt_alloc_call())) + return rpc_system_err; + + host = nlmclnt_lookup_host(&rqstp->rq_addr, + rqstp->rq_prot, rqstp->rq_vers); + if (!host) { + rpc_free(call); + return rpc_system_err; + } + + call->a_flags = RPC_TASK_ASYNC; + call->a_host = host; + memcpy(&call->a_args, resp, sizeof(*resp)); + +/* FIXME this should become nlmSVC_async_call when that code gets + merged in XXX */ + if (nlmclnt_async_call(call, proc, nlm4svc_callback_exit) < 0) + return rpc_system_err; + + return rpc_success; +} + +static void +nlm4svc_callback_exit(struct rpc_task *task) +{ + struct nlm_rqst *call = (struct nlm_rqst *) task->tk_calldata; + + if (task->tk_status < 0) { + dprintk("lockd: %4d callback failed (errno = %d)\n", + task->tk_pid, -task->tk_status); + } + nlm_release_host(call->a_host); + rpc_free(call); +} + +/* + * NLM Server procedures. + */ + +#define nlm4svc_encode_norep nlm4svc_encode_void +#define nlm4svc_decode_norep nlm4svc_decode_void +#define nlm4svc_decode_testres nlm4svc_decode_void +#define nlm4svc_decode_lockres nlm4svc_decode_void +#define nlm4svc_decode_unlockres nlm4svc_decode_void +#define nlm4svc_decode_cancelres nlm4svc_decode_void +#define nlm4svc_decode_grantedres nlm4svc_decode_void + +#define nlm4svc_proc_none nlm4svc_proc_null +#define nlm4svc_proc_test_res nlm4svc_proc_null +#define nlm4svc_proc_lock_res nlm4svc_proc_null +#define nlm4svc_proc_cancel_res nlm4svc_proc_null +#define nlm4svc_proc_unlock_res nlm4svc_proc_null +#define nlm4svc_proc_granted_res nlm4svc_proc_null + +struct nlm_void { int dummy; }; + +#define PROC(name, xargt, xrest, argt, rest) \ + { (svc_procfunc) nlm4svc_proc_##name, \ + (kxdrproc_t) nlm4svc_decode_##xargt, \ + (kxdrproc_t) nlm4svc_encode_##xrest, \ + NULL, \ + sizeof(struct nlm_##argt), \ + sizeof(struct nlm_##rest), \ + 0, \ + 0 \ + } +struct svc_procedure nlmsvc_procedures4[] = { + PROC(null, void, void, void, void), + PROC(test, testargs, testres, args, res), + PROC(lock, lockargs, res, args, res), + PROC(cancel, cancargs, res, args, res), + PROC(unlock, unlockargs, res, args, res), + PROC(granted, testargs, res, args, res), + PROC(test_msg, testargs, norep, args, void), + PROC(lock_msg, lockargs, norep, args, void), + PROC(cancel_msg, cancargs, norep, args, void), + PROC(unlock_msg, unlockargs, norep, args, void), + PROC(granted_msg, testargs, norep, args, void), + PROC(test_res, testres, norep, res, void), + PROC(lock_res, lockres, norep, res, void), + PROC(cancel_res, cancelres, norep, res, void), + PROC(unlock_res, unlockres, norep, res, void), + PROC(granted_res, grantedres, norep, res, void), + PROC(none, void, void, void, void), + PROC(none, void, void, void, void), + PROC(none, void, void, void, void), + PROC(none, void, void, void, void), + PROC(share, shareargs, shareres, args, res), + PROC(unshare, shareargs, shareres, args, res), + PROC(nm_lock, lockargs, res, args, res), + PROC(free_all, notify, void, args, void), + + /* statd callback */ + PROC(sm_notify, reboot, void, reboot, void), +}; diff -u --recursive --new-file v2.3.46/linux/fs/lockd/svclock.c linux/fs/lockd/svclock.c --- v2.3.46/linux/fs/lockd/svclock.c Thu Aug 26 13:05:40 1999 +++ linux/fs/lockd/svclock.c Sun Feb 20 10:41:18 2000 @@ -20,6 +20,7 @@ * Copyright (C) 1996, Olaf Kirch */ +#include #include #include #include @@ -98,9 +99,10 @@ lock->fl.fl_end, lock->fl.fl_type); for (head = &nlm_blocked; (block = *head); head = &block->b_next) { fl = &block->b_call.a_args.lock.fl; - dprintk(" check f=%p pd=%d %ld-%ld ty=%d\n", + dprintk("lockd: check f=%p pd=%d %ld-%ld ty=%d cookie=%x\n", block->b_file, fl->fl_pid, fl->fl_start, - fl->fl_end, fl->fl_type); + fl->fl_end, fl->fl_type, + *(unsigned int*)(block->b_call.a_args.cookie.data)); if (block->b_file == file && nlm_compare_locks(fl, &lock->fl)) { if (remove) *head = block->b_next; @@ -129,6 +131,8 @@ struct nlm_block *block; for (block = nlm_blocked; block; block = block->b_next) { + dprintk("cookie: head of blocked queue %p, block %p\n", + nlm_blocked, block); if (nlm_cookie_match(&block->b_call.a_args.cookie,cookie)) break; } @@ -310,7 +314,13 @@ switch(-error) { case 0: return nlm_granted; - case EDEADLK: /* no applicable NLM status */ + case EDEADLK: +#ifdef CONFIG_LOCKD_V4 + return nlm4_deadlock; /* will be downgraded to lck_deined if this + * is a NLMv1,3 request */ +#else + /* no applicable NLM status */ +#endif case EAGAIN: return nlm_lck_denied; default: /* includes ENOLCK */ @@ -541,6 +551,8 @@ unsigned long timeout; dprintk("lockd: GRANT_MSG RPC callback\n"); + dprintk("callback: looking for cookie %x \n", + *(unsigned int *)(call->a_args.cookie.data)); if (!(block = nlmsvc_find_block(&call->a_args.cookie))) { dprintk("lockd: no block for cookie %x\n", *(u32 *)(call->a_args.cookie.data)); return; @@ -617,7 +629,7 @@ dprintk("nlmsvc_retry_blocked(%p, when=%ld)\n", nlm_blocked, nlm_blocked? nlm_blocked->b_when : 0); - while ((block = nlm_blocked) && block->b_when < jiffies) { + while ((block = nlm_blocked) && block->b_when <= jiffies) { dprintk("nlmsvc_retry_blocked(%p, when=%ld, done=%d)\n", block, block->b_when, block->b_done); if (block->b_done) diff -u --recursive --new-file v2.3.46/linux/fs/lockd/svcproc.c linux/fs/lockd/svcproc.c --- v2.3.46/linux/fs/lockd/svcproc.c Fri Jan 21 18:19:17 2000 +++ linux/fs/lockd/svcproc.c Sun Feb 20 10:41:18 2000 @@ -7,6 +7,7 @@ * Copyright (C) 1996, Olaf Kirch */ +#include #include #include #include @@ -24,6 +25,31 @@ static u32 nlmsvc_callback(struct svc_rqst *, u32, struct nlm_res *); static void nlmsvc_callback_exit(struct rpc_task *); +#ifdef CONFIG_LOCKD_V4 +static u32 +cast_to_nlm(u32 status, u32 vers) +{ + + if (vers != 4){ + switch(ntohl(status)){ + case NLM_LCK_GRANTED: + case NLM_LCK_DENIED: + case NLM_LCK_DENIED_NOLOCKS: + case NLM_LCK_BLOCKED: + case NLM_LCK_DENIED_GRACE_PERIOD: + break; + default: + status = NLM_LCK_DENIED_NOLOCKS; + } + } + + return (status); +} +#define cast_status(status) (cast_to_nlm(status, rqstp->rq_vers)) +#else +#define cast_status(status) (status) +#endif + /* * Obtain client and file from arguments */ @@ -108,9 +134,10 @@ return rpc_success; /* Now check for conflicting locks */ - resp->status = nlmsvc_testlock(file, &argp->lock, &resp->lock); + resp->status = cast_status(nlmsvc_testlock(file, &argp->lock, &resp->lock)); - dprintk("lockd: TEST status %d\n", ntohl(resp->status)); + dprintk("lockd: TEST status %d vers %d\n", + ntohl(resp->status), rqstp->rq_vers); nlm_release_host(host); nlm_release_file(file); return rpc_success; @@ -150,8 +177,8 @@ #endif /* Now try to lock the file */ - resp->status = nlmsvc_lock(rqstp, file, &argp->lock, - argp->block, &argp->cookie); + resp->status = cast_status(nlmsvc_lock(rqstp, file, &argp->lock, + argp->block, &argp->cookie)); dprintk("lockd: LOCK status %d\n", ntohl(resp->status)); nlm_release_host(host); @@ -181,7 +208,7 @@ return rpc_success; /* Try to cancel request. */ - resp->status = nlmsvc_cancel_blocked(file, &argp->lock); + resp->status = cast_status(nlmsvc_cancel_blocked(file, &argp->lock)); dprintk("lockd: CANCEL status %d\n", ntohl(resp->status)); nlm_release_host(host); @@ -214,7 +241,7 @@ return rpc_success; /* Now try to remove the lock */ - resp->status = nlmsvc_unlock(file, &argp->lock); + resp->status = cast_status(nlmsvc_unlock(file, &argp->lock)); dprintk("lockd: UNLOCK status %d\n", ntohl(resp->status)); nlm_release_host(host); @@ -338,7 +365,7 @@ return rpc_success; /* Now try to create the share */ - resp->status = nlmsvc_share_file(host, file, argp); + resp->status = cast_status(nlmsvc_share_file(host, file, argp)); dprintk("lockd: SHARE status %d\n", ntohl(resp->status)); nlm_release_host(host); @@ -370,8 +397,8 @@ if ((resp->status = nlmsvc_retrieve_args(rqstp, argp, &host, &file))) return rpc_success; - /* Now try to lock the file */ - resp->status = nlmsvc_unshare_file(host, file, argp); + /* Now try to unshare the file */ + resp->status = cast_status(nlmsvc_unshare_file(host, file, argp)); dprintk("lockd: UNSHARE status %d\n", ntohl(resp->status)); nlm_release_host(host); diff -u --recursive --new-file v2.3.46/linux/fs/lockd/svcsubs.c linux/fs/lockd/svcsubs.c --- v2.3.46/linux/fs/lockd/svcsubs.c Fri Jan 21 18:19:17 2000 +++ linux/fs/lockd/svcsubs.c Sun Feb 20 10:41:18 2000 @@ -6,6 +6,7 @@ * Copyright (C) 1996, Olaf Kirch */ +#include #include #include #include @@ -105,6 +106,11 @@ out_free: kfree(file); +#ifdef CONFIG_LOCKD_V4 + if (nfserr == 1) + nfserr = nlm4_stale_fh; + else +#endif nfserr = nlm_lck_denied; goto out_unlock; } diff -u --recursive --new-file v2.3.46/linux/fs/lockd/xdr.c linux/fs/lockd/xdr.c --- v2.3.46/linux/fs/lockd/xdr.c Thu Feb 10 17:11:17 2000 +++ linux/fs/lockd/xdr.c Sun Feb 20 20:37:48 2000 @@ -6,6 +6,7 @@ * Copyright (C) 1995, 1996 Olaf Kirch */ +#include #include #include #include @@ -47,6 +48,14 @@ nlm_lck_blocked = htonl(NLM_LCK_BLOCKED); nlm_lck_denied_grace_period = htonl(NLM_LCK_DENIED_GRACE_PERIOD); +#ifdef CONFIG_LOCKD_V4 + nlm4_deadlock = htonl(NLM_DEADLCK); + nlm4_rofs = htonl(NLM_ROFS); + nlm4_stale_fh = htonl(NLM_STALE_FH); + nlm4_fbig = htonl(NLM_FBIG); + nlm4_failed = htonl(NLM_FAILED); +#endif + inited = 1; } @@ -541,7 +550,8 @@ { "nlm_" #proc, \ (kxdrproc_t) nlmclt_encode_##argtype, \ (kxdrproc_t) nlmclt_decode_##restype, \ - MAX(NLM_##argtype##_sz, NLM_##restype##_sz) << 2 \ + MAX(NLM_##argtype##_sz, NLM_##restype##_sz) << 2, \ + 0 \ } static struct rpc_procinfo nlm_procedures[] = { @@ -586,11 +596,18 @@ 3, 24, nlm_procedures, }; +#ifdef CONFIG_LOCKD_V4 +extern struct rpc_version nlm_version4; +#endif + static struct rpc_version * nlm_versions[] = { NULL, &nlm_version1, NULL, &nlm_version3, +#ifdef CONFIG_LOCKD_V4 + &nlm_version4, +#endif }; static struct rpc_stat nlm_stats; diff -u --recursive --new-file v2.3.46/linux/fs/lockd/xdr4.c linux/fs/lockd/xdr4.c --- v2.3.46/linux/fs/lockd/xdr4.c Wed Dec 31 16:00:00 1969 +++ linux/fs/lockd/xdr4.c Thu Feb 17 17:23:30 2000 @@ -0,0 +1,601 @@ +/* + * linux/fs/lockd/xdr4.c + * + * XDR support for lockd and the lock client. + * + * Copyright (C) 1995, 1996 Olaf Kirch + * Copyright (C) 1999, Trond Myklebust + */ + +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include + +#define NLMDBG_FACILITY NLMDBG_XDR +#define NLM_MAXSTRLEN 1024 +#define OFFSET_MAX ((off_t)LONG_MAX) + +#define QUADLEN(len) (((len) + 3) >> 2) + +u32 nlm4_deadlock, nlm4_rofs, nlm4_stale_fh, nlm4_fbig, + nlm4_failed; + + +typedef struct nlm_args nlm_args; + +static inline off_t +size_to_off_t(__s64 size) +{ + size = (size > (__s64)LONG_MAX) ? (off_t)LONG_MAX : (off_t) size; + return (size < (__s64)-LONG_MAX) ? (off_t)-LONG_MAX : (off_t) size; +} + +/* + * XDR functions for basic NLM types + */ +static u32 * +nlm4_decode_cookie(u32 *p, struct nlm_cookie *c) +{ + unsigned int len; + + len = ntohl(*p++); + + if(len==0) + { + c->len=4; + memset(c->data, 0, 4); /* hockeypux brain damage */ + } + else if(len<=8) + { + c->len=len; + memcpy(c->data, p, len); + p+=(len+3)>>2; + } + else + { + printk(KERN_NOTICE + "lockd: bad cookie size %d (only cookies under 8 bytes are supported.)\n", len); + return NULL; + } + return p; +} + +static u32 * +nlm4_encode_cookie(u32 *p, struct nlm_cookie *c) +{ + *p++ = htonl(c->len); + memcpy(p, c->data, c->len); + p+=(c->len+3)>>2; + return p; +} + +static u32 * +nlm4_decode_fh(u32 *p, struct nfs_fh *f) +{ + memset(f->data, 0, sizeof(f->data)); +#ifdef NFS_MAXFHSIZE + f->size = ntohl(*p++); + if (f->size > NFS_MAXFHSIZE) { + printk(KERN_NOTICE + "lockd: bad fhandle size %x (should be %d)\n", + f->size, NFS_MAXFHSIZE); + return NULL; + } + memcpy(f->data, p, f->size); + return p + XDR_QUADLEN(f->size); +#else + if (ntohl(*p++) != NFS_FHSIZE) + return NULL; /* for now, all filehandles are 32 bytes */ + memcpy(f->data, p, NFS_FHSIZE); + return p + XDR_QUADLEN(NFS_FHSIZE); +#endif +} + +static u32 * +nlm4_encode_fh(u32 *p, struct nfs_fh *f) +{ +#ifdef NFS_MAXFHSIZE + *p++ = htonl(f->size); + memcpy(p, f->data, f->size); + return p + XDR_QUADLEN(f->size); +#else + *p++ = htonl(NFS_FHSIZE); + memcpy(p, f->data, NFS_FHSIZE); + return p + XDR_QUADLEN(NFS_FHSIZE); +#endif +} + +/* + * Encode and decode owner handle + */ +static u32 * +nlm4_decode_oh(u32 *p, struct xdr_netobj *oh) +{ + return xdr_decode_netobj(p, oh); +} + +static u32 * +nlm4_encode_oh(u32 *p, struct xdr_netobj *oh) +{ + return xdr_encode_netobj(p, oh); +} + +static u32 * +nlm4_decode_lock(u32 *p, struct nlm_lock *lock) +{ + struct file_lock *fl = &lock->fl; + __s64 len, start, end; + int tmp; + + if (!(p = xdr_decode_string(p, &lock->caller, &tmp, NLM_MAXSTRLEN)) + || !(p = nlm4_decode_fh(p, &lock->fh)) + || !(p = nlm4_decode_oh(p, &lock->oh))) + return NULL; + + memset(fl, 0, sizeof(*fl)); + fl->fl_owner = current->files; + fl->fl_pid = ntohl(*p++); + fl->fl_flags = FL_POSIX; + fl->fl_type = F_RDLCK; /* as good as anything else */ + p = xdr_decode_hyper(p, &start); + p = xdr_decode_hyper(p, &len); + end = start + len - 1; + + fl->fl_start = size_to_off_t(start); + fl->fl_end = size_to_off_t(end); + + if (len == 0 || fl->fl_end < 0) + fl->fl_end = OFFSET_MAX; + return p; +} + +/* + * Encode a lock as part of an NLM call + */ +static u32 * +nlm4_encode_lock(u32 *p, struct nlm_lock *lock) +{ + struct file_lock *fl = &lock->fl; + + if (!(p = xdr_encode_string(p, lock->caller)) + || !(p = nlm4_encode_fh(p, &lock->fh)) + || !(p = nlm4_encode_oh(p, &lock->oh))) + return NULL; + + *p++ = htonl(fl->fl_pid); + p = xdr_encode_hyper(p, fl->fl_start); + if (fl->fl_end == OFFSET_MAX) + p = xdr_encode_hyper(p, 0); + else + p = xdr_encode_hyper(p, fl->fl_end - fl->fl_start + 1); + + return p; +} + +/* + * Encode result of a TEST/TEST_MSG call + */ +static u32 * +nlm4_encode_testres(u32 *p, struct nlm_res *resp) +{ + dprintk("xdr: before encode_testres (p %p resp %p)\n", p, resp); + if (!(p = nlm4_encode_cookie(p, &resp->cookie))) + return 0; + *p++ = resp->status; + + if (resp->status == nlm_lck_denied) { + struct file_lock *fl = &resp->lock.fl; + + *p++ = (fl->fl_type == F_RDLCK)? xdr_zero : xdr_one; + *p++ = htonl(fl->fl_pid); + + /* Encode owner handle. */ + if (!(p = xdr_encode_netobj(p, &resp->lock.oh))) + return 0; + + p = xdr_encode_hyper(p, fl->fl_start); + if (fl->fl_end == OFFSET_MAX) + p = xdr_encode_hyper(p, 0); + else + p = xdr_encode_hyper(p, fl->fl_end - fl->fl_start + 1); + dprintk("xdr: encode_testres (status %d pid %d type %d start %ld end %ld)\n", resp->status, fl->fl_pid, fl->fl_type, fl->fl_start, fl->fl_end); + } + + dprintk("xdr: after encode_testres (p %p resp %p)\n", p, resp); + return p; +} + + +/* + * Check buffer bounds after decoding arguments + */ +static int +xdr_argsize_check(struct svc_rqst *rqstp, u32 *p) +{ + struct svc_buf *buf = &rqstp->rq_argbuf; + + return p - buf->base <= buf->buflen; +} + +static int +xdr_ressize_check(struct svc_rqst *rqstp, u32 *p) +{ + struct svc_buf *buf = &rqstp->rq_resbuf; + + buf->len = p - buf->base; + return (buf->len <= buf->buflen); +} + +/* + * First, the server side XDR functions + */ +int +nlm4svc_decode_testargs(struct svc_rqst *rqstp, u32 *p, nlm_args *argp) +{ + u32 exclusive; + + if (!(p = nlm4_decode_cookie(p, &argp->cookie))) + return 0; + + exclusive = ntohl(*p++); + if (!(p = nlm4_decode_lock(p, &argp->lock))) + return 0; + if (exclusive) + argp->lock.fl.fl_type = F_WRLCK; + + return xdr_argsize_check(rqstp, p); +} + +int +nlm4svc_encode_testres(struct svc_rqst *rqstp, u32 *p, struct nlm_res *resp) +{ + if (!(p = nlm4_encode_testres(p, resp))) + return 0; + return xdr_ressize_check(rqstp, p); +} + +int +nlm4svc_decode_lockargs(struct svc_rqst *rqstp, u32 *p, nlm_args *argp) +{ + u32 exclusive; + + if (!(p = nlm4_decode_cookie(p, &argp->cookie))) + return 0; + argp->block = ntohl(*p++); + exclusive = ntohl(*p++); + if (!(p = nlm4_decode_lock(p, &argp->lock))) + return 0; + if (exclusive) + argp->lock.fl.fl_type = F_WRLCK; + argp->reclaim = ntohl(*p++); + argp->state = ntohl(*p++); + argp->monitor = 1; /* monitor client by default */ + + return xdr_argsize_check(rqstp, p); +} + +int +nlm4svc_decode_cancargs(struct svc_rqst *rqstp, u32 *p, nlm_args *argp) +{ + u32 exclusive; + + if (!(p = nlm4_decode_cookie(p, &argp->cookie))) + return 0; + argp->block = ntohl(*p++); + exclusive = ntohl(*p++); + if (!(p = nlm4_decode_lock(p, &argp->lock))) + return 0; + if (exclusive) + argp->lock.fl.fl_type = F_WRLCK; + return xdr_argsize_check(rqstp, p); +} + +int +nlm4svc_decode_unlockargs(struct svc_rqst *rqstp, u32 *p, nlm_args *argp) +{ + if (!(p = nlm4_decode_cookie(p, &argp->cookie)) + || !(p = nlm4_decode_lock(p, &argp->lock))) + return 0; + argp->lock.fl.fl_type = F_UNLCK; + return xdr_argsize_check(rqstp, p); +} + +int +nlm4svc_decode_shareargs(struct svc_rqst *rqstp, u32 *p, nlm_args *argp) +{ + struct nlm_lock *lock = &argp->lock; + int len; + + memset(lock, 0, sizeof(*lock)); + lock->fl.fl_pid = ~(u32) 0; + + if (!(p = nlm4_decode_cookie(p, &argp->cookie)) + || !(p = xdr_decode_string(p, &lock->caller, &len, NLM_MAXSTRLEN)) + || !(p = nlm4_decode_fh(p, &lock->fh)) + || !(p = nlm4_decode_oh(p, &lock->oh))) + return 0; + argp->fsm_mode = ntohl(*p++); + argp->fsm_access = ntohl(*p++); + return xdr_argsize_check(rqstp, p); +} + +int +nlm4svc_encode_shareres(struct svc_rqst *rqstp, u32 *p, struct nlm_res *resp) +{ + if (!(p = nlm4_encode_cookie(p, &resp->cookie))) + return 0; + *p++ = resp->status; + *p++ = xdr_zero; /* sequence argument */ + return xdr_ressize_check(rqstp, p); +} + +int +nlm4svc_encode_res(struct svc_rqst *rqstp, u32 *p, struct nlm_res *resp) +{ + if (!(p = nlm4_encode_cookie(p, &resp->cookie))) + return 0; + *p++ = resp->status; + return xdr_ressize_check(rqstp, p); +} + +int +nlm4svc_decode_notify(struct svc_rqst *rqstp, u32 *p, struct nlm_args *argp) +{ + struct nlm_lock *lock = &argp->lock; + int len; + + if (!(p = xdr_decode_string(p, &lock->caller, &len, NLM_MAXSTRLEN))) + return 0; + argp->state = ntohl(*p++); + return xdr_argsize_check(rqstp, p); +} + +int +nlm4svc_decode_reboot(struct svc_rqst *rqstp, u32 *p, struct nlm_reboot *argp) +{ + if (!(p = xdr_decode_string(p, &argp->mon, &argp->len, SM_MAXSTRLEN))) + return 0; + argp->state = ntohl(*p++); + argp->addr = ntohl(*p++); + return xdr_argsize_check(rqstp, p); +} + +int +nlm4svc_decode_res(struct svc_rqst *rqstp, u32 *p, struct nlm_res *resp) +{ + if (!(p = nlm4_decode_cookie(p, &resp->cookie))) + return 0; + resp->status = ntohl(*p++); + return xdr_argsize_check(rqstp, p); +} + +int +nlm4svc_decode_void(struct svc_rqst *rqstp, u32 *p, void *dummy) +{ + return xdr_argsize_check(rqstp, p); +} + +int +nlm4svc_encode_void(struct svc_rqst *rqstp, u32 *p, void *dummy) +{ + return xdr_ressize_check(rqstp, p); +} + +/* + * Now, the client side XDR functions + */ +static int +nlm4clt_encode_void(struct rpc_rqst *req, u32 *p, void *ptr) +{ + req->rq_slen = xdr_adjust_iovec(req->rq_svec, p); + return 0; +} + +static int +nlm4clt_decode_void(struct rpc_rqst *req, u32 *p, void *ptr) +{ + return 0; +} + +static int +nlm4clt_encode_testargs(struct rpc_rqst *req, u32 *p, nlm_args *argp) +{ + struct nlm_lock *lock = &argp->lock; + + if (!(p = nlm4_encode_cookie(p, &argp->cookie))) + return -EIO; + *p++ = (lock->fl.fl_type == F_WRLCK)? xdr_one : xdr_zero; + if (!(p = nlm4_encode_lock(p, lock))) + return -EIO; + req->rq_slen = xdr_adjust_iovec(req->rq_svec, p); + return 0; +} + +static int +nlm4clt_decode_testres(struct rpc_rqst *req, u32 *p, struct nlm_res *resp) +{ + if (!(p = nlm4_decode_cookie(p, &resp->cookie))) + return -EIO; + resp->status = ntohl(*p++); + if (resp->status == NLM_LCK_DENIED) { + struct file_lock *fl = &resp->lock.fl; + u32 excl; + s64 start, end, len; + + memset(&resp->lock, 0, sizeof(resp->lock)); + excl = ntohl(*p++); + fl->fl_pid = ntohl(*p++); + if (!(p = nlm4_decode_oh(p, &resp->lock.oh))) + return -EIO; + + fl->fl_flags = FL_POSIX; + fl->fl_type = excl? F_WRLCK : F_RDLCK; + p = xdr_decode_hyper(p, &start); + p = xdr_decode_hyper(p, &len); + end = start + len - 1; + + fl->fl_start = size_to_off_t(start); + fl->fl_end = size_to_off_t(end); + if (len == 0 || fl->fl_end < 0) + fl->fl_end = OFFSET_MAX; + } + return 0; +} + + +static int +nlm4clt_encode_lockargs(struct rpc_rqst *req, u32 *p, nlm_args *argp) +{ + struct nlm_lock *lock = &argp->lock; + + if (!(p = nlm4_encode_cookie(p, &argp->cookie))) + return -EIO; + *p++ = argp->block? xdr_one : xdr_zero; + *p++ = (lock->fl.fl_type == F_WRLCK)? xdr_one : xdr_zero; + if (!(p = nlm4_encode_lock(p, lock))) + return -EIO; + *p++ = argp->reclaim? xdr_one : xdr_zero; + *p++ = htonl(argp->state); + req->rq_slen = xdr_adjust_iovec(req->rq_svec, p); + return 0; +} + +static int +nlm4clt_encode_cancargs(struct rpc_rqst *req, u32 *p, nlm_args *argp) +{ + struct nlm_lock *lock = &argp->lock; + + if (!(p = nlm4_encode_cookie(p, &argp->cookie))) + return -EIO; + *p++ = argp->block? xdr_one : xdr_zero; + *p++ = (lock->fl.fl_type == F_WRLCK)? xdr_one : xdr_zero; + if (!(p = nlm4_encode_lock(p, lock))) + return -EIO; + req->rq_slen = xdr_adjust_iovec(req->rq_svec, p); + return 0; +} + +static int +nlm4clt_encode_unlockargs(struct rpc_rqst *req, u32 *p, nlm_args *argp) +{ + struct nlm_lock *lock = &argp->lock; + + if (!(p = nlm4_encode_cookie(p, &argp->cookie))) + return -EIO; + if (!(p = nlm4_encode_lock(p, lock))) + return -EIO; + req->rq_slen = xdr_adjust_iovec(req->rq_svec, p); + return 0; +} + +static int +nlm4clt_encode_res(struct rpc_rqst *req, u32 *p, struct nlm_res *resp) +{ + if (!(p = nlm4_encode_cookie(p, &resp->cookie))) + return -EIO; + *p++ = resp->status; + req->rq_slen = xdr_adjust_iovec(req->rq_svec, p); + return 0; +} + +static int +nlm4clt_encode_testres(struct rpc_rqst *req, u32 *p, struct nlm_res *resp) +{ + if (!(p = nlm4_encode_testres(p, resp))) + return -EIO; + req->rq_slen = xdr_adjust_iovec(req->rq_svec, p); + return 0; +} + +static int +nlm4clt_decode_res(struct rpc_rqst *req, u32 *p, struct nlm_res *resp) +{ + if (!(p = nlm4_decode_cookie(p, &resp->cookie))) + return -EIO; + resp->status = ntohl(*p++); + return 0; +} + +/* + * Buffer requirements for NLM + */ +#define NLM4_void_sz 0 +#define NLM4_cookie_sz 3 /* 1 len , 2 data */ +#define NLM4_caller_sz 1+XDR_QUADLEN(NLM_MAXSTRLEN) +#define NLM4_netobj_sz 1+XDR_QUADLEN(XDR_MAX_NETOBJ) +/* #define NLM4_owner_sz 1+XDR_QUADLEN(NLM4_MAXOWNER) */ +#define NLM4_fhandle_sz 1+XDR_QUADLEN(NFS3_FHSIZE) +#define NLM4_lock_sz 5+NLM4_caller_sz+NLM4_netobj_sz+NLM4_fhandle_sz +#define NLM4_holder_sz 6+NLM4_netobj_sz + +#define NLM4_testargs_sz NLM4_cookie_sz+1+NLM4_lock_sz +#define NLM4_lockargs_sz NLM4_cookie_sz+4+NLM4_lock_sz +#define NLM4_cancargs_sz NLM4_cookie_sz+2+NLM4_lock_sz +#define NLM4_unlockargs_sz NLM4_cookie_sz+NLM4_lock_sz + +#define NLM4_testres_sz NLM4_cookie_sz+1+NLM4_holder_sz +#define NLM4_res_sz NLM4_cookie_sz+1 +#define NLM4_norep_sz 0 + +#ifndef MAX +# define MAX(a,b) (((a) > (b))? (a) : (b)) +#endif + +/* + * For NLM, a void procedure really returns nothing + */ +#define nlm4clt_decode_norep NULL + +#define PROC(proc, argtype, restype) \ + { "nlm4_" #proc, \ + (kxdrproc_t) nlm4clt_encode_##argtype, \ + (kxdrproc_t) nlm4clt_decode_##restype, \ + MAX(NLM4_##argtype##_sz, NLM4_##restype##_sz) << 2, \ + 0 \ + } + +static struct rpc_procinfo nlm4_procedures[] = { + PROC(null, void, void), + PROC(test, testargs, testres), + PROC(lock, lockargs, res), + PROC(canc, cancargs, res), + PROC(unlock, unlockargs, res), + PROC(granted, testargs, res), + PROC(test_msg, testargs, norep), + PROC(lock_msg, lockargs, norep), + PROC(canc_msg, cancargs, norep), + PROC(unlock_msg, unlockargs, norep), + PROC(granted_msg, testargs, norep), + PROC(test_res, testres, norep), + PROC(lock_res, res, norep), + PROC(canc_res, res, norep), + PROC(unlock_res, res, norep), + PROC(granted_res, res, norep), + PROC(undef, void, void), + PROC(undef, void, void), + PROC(undef, void, void), + PROC(undef, void, void), +#ifdef NLMCLNT_SUPPORT_SHARES + PROC(share, shareargs, shareres), + PROC(unshare, shareargs, shareres), + PROC(nm_lock, lockargs, res), + PROC(free_all, notify, void), +#else + PROC(undef, void, void), + PROC(undef, void, void), + PROC(undef, void, void), + PROC(undef, void, void), +#endif +}; + +struct rpc_version nlm_version4 = { + 4, 24, nlm4_procedures, +}; diff -u --recursive --new-file v2.3.46/linux/fs/minix/inode.c linux/fs/minix/inode.c --- v2.3.46/linux/fs/minix/inode.c Thu Feb 10 17:11:17 2000 +++ linux/fs/minix/inode.c Sun Feb 20 13:09:46 2000 @@ -35,9 +35,13 @@ static void minix_delete_inode(struct inode *inode) { + lock_kernel(); + inode->i_size = 0; minix_truncate(inode); minix_free_inode(inode); + + unlock_kernel(); } static void minix_commit_super(struct super_block * sb) @@ -1243,7 +1247,9 @@ { struct buffer_head *bh; + lock_kernel(); bh = minix_update_inode(inode); + unlock_kernel(); brelse(bh); } diff -u --recursive --new-file v2.3.46/linux/fs/ncpfs/sock.c linux/fs/ncpfs/sock.c --- v2.3.46/linux/fs/ncpfs/sock.c Mon Nov 1 13:56:27 1999 +++ linux/fs/ncpfs/sock.c Sun Feb 20 20:19:12 2000 @@ -203,7 +203,8 @@ } n = 0; timeout = init_timeout; - init_timeout <<= 1; + if (init_timeout < max_timeout) + init_timeout <<= 1; if (!major_timeout_seen) { printk(KERN_WARNING "NCP server not responding\n"); } diff -u --recursive --new-file v2.3.46/linux/fs/nfs/file.c linux/fs/nfs/file.c --- v2.3.46/linux/fs/nfs/file.c Thu Feb 10 17:11:18 2000 +++ linux/fs/nfs/file.c Wed Feb 16 20:23:47 2000 @@ -165,11 +165,16 @@ static int nfs_commit_write(struct file *file, struct page *page, unsigned offset, unsigned to) { long status; + loff_t pos = ((loff_t)page->index<mapping->host; kunmap(page); lock_kernel(); status = nfs_updatepage(file, page, offset, to-offset); unlock_kernel(); + /* most likely it's already done. CHECKME */ + if (pos > inode->i_size) + inode->i_size = pos; return status; } diff -u --recursive --new-file v2.3.46/linux/fs/nfs/inode.c linux/fs/nfs/inode.c --- v2.3.46/linux/fs/nfs/inode.c Sun Feb 13 19:29:04 2000 +++ linux/fs/nfs/inode.c Sun Feb 20 13:09:46 2000 @@ -28,6 +28,7 @@ #include #include #include +#include #include #include @@ -102,6 +103,7 @@ dprintk("NFS: delete_inode(%x/%ld)\n", inode->i_dev, inode->i_ino); + lock_kernel(); if (S_ISDIR(inode->i_mode)) { nfs_free_dircache(inode); } else { @@ -129,6 +131,8 @@ if (failed) printk("NFS: inode %ld had %d failed requests\n", inode->i_ino, failed); + unlock_kernel(); + clear_inode(inode); } @@ -683,14 +687,12 @@ if (attr->ia_size != fattr.size) printk("nfs_notify_change: attr=%Ld, fattr=%d??\n", (long long) attr->ia_size, fattr.size); - inode->i_size = attr->ia_size; inode->i_mtime = fattr.mtime.seconds; + vmtruncate(inode, attr->ia_size); } if (attr->ia_valid & ATTR_MTIME) inode->i_mtime = fattr.mtime.seconds; error = nfs_refresh_inode(inode, &fattr); - if (!error && (attr->ia_valid & ATTR_SIZE)) - vmtruncate(inode, attr->ia_size); out: return error; } diff -u --recursive --new-file v2.3.46/linux/fs/nfsd/lockd.c linux/fs/nfsd/lockd.c --- v2.3.46/linux/fs/nfsd/lockd.c Tue Feb 1 01:35:44 2000 +++ linux/fs/nfsd/lockd.c Thu Feb 17 17:23:30 2000 @@ -34,7 +34,16 @@ if (!nfserr) dget(filp->f_dentry); fh_put(&fh); - return nfserr; + /* nlm and nfsd don't share error codes. + * we invent: 0 = no error + * 1 = stale file handle + * 2 = other error + */ + if (nfserr == 0) + return 0; + else if (nfserr == nfserr_stale) + return 1; + else return 2; } static void diff -u --recursive --new-file v2.3.46/linux/fs/nfsd/nfs3xdr.c linux/fs/nfsd/nfs3xdr.c --- v2.3.46/linux/fs/nfsd/nfs3xdr.c Wed Feb 16 17:03:52 2000 +++ linux/fs/nfsd/nfs3xdr.c Thu Feb 17 17:23:30 2000 @@ -177,15 +177,15 @@ *p++ = htonl((u32) nfsd_ruid(rqstp, inode->i_uid)); *p++ = htonl((u32) nfsd_rgid(rqstp, inode->i_gid)); if (S_ISLNK(inode->i_mode) && inode->i_size > NFS3_MAXPATHLEN) { - p = enc64(p, (u64) NFS3_MAXPATHLEN); + p = xdr_encode_hyper(p, (u64) NFS3_MAXPATHLEN); } else { - p = enc64(p, (u64) inode->i_size); + p = xdr_encode_hyper(p, (u64) inode->i_size); } - p = enc64(p, ((u64)inode->i_blocks) << 9); + p = xdr_encode_hyper(p, ((u64)inode->i_blocks) << 9); *p++ = htonl((u32) MAJOR(inode->i_rdev)); *p++ = htonl((u32) MINOR(inode->i_rdev)); - p = enc64(p, (u64) inode->i_dev); - p = enc64(p, (u64) inode->i_ino); + p = xdr_encode_hyper(p, (u64) inode->i_dev); + p = xdr_encode_hyper(p, (u64) inode->i_ino); p = encode_time3(p, inode->i_atime); p = encode_time3(p, inode->i_mtime); p = encode_time3(p, inode->i_ctime); @@ -207,15 +207,15 @@ *p++ = htonl((u32) nfsd_ruid(rqstp, fhp->fh_post_uid)); *p++ = htonl((u32) nfsd_rgid(rqstp, fhp->fh_post_gid)); if (S_ISLNK(fhp->fh_post_mode) && fhp->fh_post_size > NFS3_MAXPATHLEN) { - p = enc64(p, (u64) NFS3_MAXPATHLEN); + p = xdr_encode_hyper(p, (u64) NFS3_MAXPATHLEN); } else { - p = enc64(p, (u64) fhp->fh_post_size); + p = xdr_encode_hyper(p, (u64) fhp->fh_post_size); } - p = enc64(p, ((u64)fhp->fh_post_blocks) << 9); + p = xdr_encode_hyper(p, ((u64)fhp->fh_post_blocks) << 9); *p++ = htonl((u32) MAJOR(fhp->fh_post_rdev)); *p++ = htonl((u32) MINOR(fhp->fh_post_rdev)); - p = enc64(p, (u64) inode->i_dev); - p = enc64(p, (u64) inode->i_ino); + p = xdr_encode_hyper(p, (u64) inode->i_dev); + p = xdr_encode_hyper(p, (u64) inode->i_ino); p = encode_time3(p, fhp->fh_post_atime); p = encode_time3(p, fhp->fh_post_mtime); p = encode_time3(p, fhp->fh_post_ctime); @@ -250,7 +250,7 @@ if (dentry && dentry->d_inode && fhp->fh_post_saved) { if (fhp->fh_pre_saved) { *p++ = xdr_one; - p = enc64(p, (u64) fhp->fh_pre_size); + p = xdr_encode_hyper(p, (u64) fhp->fh_pre_size); p = encode_time3(p, fhp->fh_pre_mtime); p = encode_time3(p, fhp->fh_pre_ctime); } else { @@ -669,7 +669,7 @@ int buflen, slen, elen; if (cd->offset) - enc64(cd->offset, (u64) offset); + xdr_encode_hyper(cd->offset, (u64) offset); /* nfsd_readdir calls us with name == 0 when it wants us to * set the last offset entry. */ @@ -693,7 +693,7 @@ return -EINVAL; } *p++ = xdr_one; /* mark entry present */ - p = enc64(p, ino); /* file id */ + p = xdr_encode_hyper(p, ino); /* file id */ #ifdef XDR_ENCODE_STRING_TAKES_LENGTH p = xdr_encode_string(p, name, namlen); /* name length & name */ #else @@ -705,7 +705,7 @@ p[slen - 1] = 0; /* don't leak kernel data */ cd->offset = p; /* remember pointer */ - p = enc64(p, NFS_OFFSET_MAX); /* offset of next entry */ + p = xdr_encode_hyper(p, NFS_OFFSET_MAX); /* offset of next entry */ /* throw in readdirplus baggage */ if (plus) { @@ -756,12 +756,12 @@ *p++ = xdr_zero; /* no post_op_attr */ if (resp->status == 0) { - p = enc64(p, bs * s->f_blocks); /* total bytes */ - p = enc64(p, bs * s->f_bfree); /* free bytes */ - p = enc64(p, bs * s->f_bavail); /* user available bytes */ - p = enc64(p, s->f_files); /* total inodes */ - p = enc64(p, s->f_ffree); /* free inodes */ - p = enc64(p, s->f_ffree); /* user available inodes */ + p = xdr_encode_hyper(p, bs * s->f_blocks); /* total bytes */ + p = xdr_encode_hyper(p, bs * s->f_bfree); /* free bytes */ + p = xdr_encode_hyper(p, bs * s->f_bavail); /* user available bytes */ + p = xdr_encode_hyper(p, s->f_files); /* total inodes */ + p = xdr_encode_hyper(p, s->f_ffree); /* free inodes */ + p = xdr_encode_hyper(p, s->f_ffree); /* user available inodes */ *p++ = htonl(resp->invarsec); /* mean unchanged time */ } return xdr_ressize_check(rqstp, p); @@ -782,7 +782,7 @@ *p++ = htonl(resp->f_wtpref); *p++ = htonl(resp->f_wtmult); *p++ = htonl(resp->f_dtpref); - p = enc64(p, resp->f_maxfilesize); + p = xdr_encode_hyper(p, resp->f_maxfilesize); *p++ = xdr_one; *p++ = xdr_zero; *p++ = htonl(resp->f_properties); diff -u --recursive --new-file v2.3.46/linux/fs/nfsd/nfsfh.c linux/fs/nfsd/nfsfh.c --- v2.3.46/linux/fs/nfsd/nfsfh.c Wed Feb 16 17:03:52 2000 +++ linux/fs/nfsd/nfsfh.c Sun Feb 20 20:41:00 2000 @@ -150,7 +150,7 @@ */ for (lp = inode->i_dentry.next; lp != &inode->i_dentry ; lp=lp->next) { result = list_entry(lp,struct dentry, d_alias); - if (! IS_ROOT(result) || inode->i_sb->s_root == result) { + if (! (result->d_flags & DCACHE_NFSD_DISCONNECTED)) { dget(result); iput(inode); return result; @@ -161,6 +161,7 @@ iput(inode); return ERR_PTR(-ENOMEM); } + result->d_flags |= DCACHE_NFSD_DISCONNECTED; d_rehash(result); /* so a dput won't loose it */ return result; } @@ -175,6 +176,8 @@ #ifdef NFSD_PARANOIA if (!IS_ROOT(target)) printk("nfsd: d_splice with no-root target: %s/%s\n", parent->d_name.name, name->name); + if (!(target->d_flags & DCACHE_NFSD_DISCONNECTED)) + printk("nfsd: d_splice with non-DISCONNECTED target: %s/%s\n", parent->d_name.name, name->name); #endif name->hash = full_name_hash(name->name, name->len); tdentry = d_alloc(parent, name); @@ -189,6 +192,29 @@ tdentry->d_parent = tdentry; d_rehash(target); dput(tdentry); + + /* if parent is properly connected, then we can assert that + * the children are connected, but it must be a singluar (non-forking) + * branch + */ + if (!(parent->d_flags & DCACHE_NFSD_DISCONNECTED)) { + while (target) { + target->d_flags &= ~DCACHE_NFSD_DISCONNECTED; + parent = target; + if (list_empty(&parent->d_subdirs)) + target = NULL; + else { + target = list_entry(parent->d_subdirs.next, struct dentry, d_child); +#ifdef NFSD_PARANOIA + /* must be only child */ + if (target->d_child.next != &parent->d_subdirs + || target->d_child.prev != &parent->d_subdirs) + printk("nfsd: d_splice found non-singular disconnected branch: %s/%s\n", + parent->d_name.name, target->d_name.name); +#endif + } + } + } return 0; } @@ -227,7 +253,10 @@ } if (pdentry == NULL) { pdentry = d_alloc_root(igrab(tdentry->d_inode)); - if (pdentry) d_rehash(pdentry); + if (pdentry) { + pdentry->d_flags |= DCACHE_NFSD_DISCONNECTED; + d_rehash(pdentry); + } } if (pdentry == NULL) pdentry = ERR_PTR(-ENOMEM); @@ -302,13 +331,13 @@ struct dentry *tmp; int found =0; int err; - /* This semaphore is needed to make sure that only one unconnected (free) + /* the sb->s_nfsd_free_path_sem semaphore is needed to make sure that only one unconnected (free) * dcache path ever exists, as otherwise two partial paths might get * joined together, which would be very confusing. * If there is ever an unconnected non-root directory, then this lock - * must be held. This could sensibly be per-filesystem. + * must be held. */ - static DECLARE_MUTEX(free_path_sem); + nfsdstats.fh_lookup++; /* @@ -324,7 +353,7 @@ dprintk("find_fh_dentry: No inode found.\n"); goto err_out; } - if (!IS_ROOT(result) || result->d_inode->i_sb->s_root ==result) + if (! (result->d_flags & DCACHE_NFSD_DISCONNECTED)) return result; /* result is now an anonymous dentry, which may be adequate as it stands, or else @@ -339,7 +368,15 @@ * location in the tree. */ dprintk("nfs_fh: need to look harder for %d/%d\n",sb->s_dev,fh->fh_ino); - down(&free_path_sem); + down(&sb->s_nfsd_free_path_sem); + + /* claiming the semaphore might have allow things to get fixed up */ + if (! (result->d_flags & DCACHE_NFSD_DISCONNECTED)) { + up(&sb->s_nfsd_free_path_sem); + return result; + } + + found = 0; if (!S_ISDIR(result->d_inode->i_mode)) { nfsdstats.fh_nocache_nondir++; @@ -356,7 +393,7 @@ || !S_ISDIR(dentry->d_inode->i_mode)) { goto err_dentry; } - if (!IS_ROOT(dentry) || dentry->d_inode->i_sb->s_root ==dentry) + if ((!dentry->d_flags & DCACHE_NFSD_DISCONNECTED)) found = 1; tmp = splice(result, dentry); err = PTR_ERR(tmp); @@ -393,10 +430,8 @@ dput(pdentry); goto err_dentry; } - /* I'm not sure that this is the best test for - * "is it not a floating dentry?" - */ - if (!IS_ROOT(pdentry) || parent->i_sb->s_root == pdentry) + + if (!(dentry->d_flags & DCACHE_NFSD_DISCONNECTED)) found = 1; tmp = splice(dentry, pdentry); @@ -419,21 +454,21 @@ dput(tmp); dput(dentry); dput(result); /* this will discard the whole free path, so we can up the semaphore */ - up(&free_path_sem); + up(&sb->s_nfsd_free_path_sem); goto retry; } dput(dentry); dentry = pdentry; } dput(dentry); - up(&free_path_sem); + up(&sb->s_nfsd_free_path_sem); return result; err_dentry: dput(dentry); err_result: dput(result); - up(&free_path_sem); + up(&sb->s_nfsd_free_path_sem); err_out: if (err == -ESTALE) nfsdstats.fh_stale++; @@ -515,6 +550,13 @@ error = nfserrno(-PTR_ERR(dentry)); goto out; } +#ifdef NFSD_PARANOIA + if (S_ISDIR(dentry->d_inode->i_mode) && + (dentry->d_flags & DCACHE_NFSD_DISCONNECTED)) { + printk("nfsd: find_fh_dentry returned a DISCONNECTED directory: %s/%s\n", + dentry->d_parent->d_name.name, dentry->d_name.name); + } +#endif fhp->fh_dentry = dentry; fhp->fh_export = exp; diff -u --recursive --new-file v2.3.46/linux/fs/nfsd/vfs.c linux/fs/nfsd/vfs.c --- v2.3.46/linux/fs/nfsd/vfs.c Wed Feb 16 17:03:52 2000 +++ linux/fs/nfsd/vfs.c Thu Feb 17 17:23:30 2000 @@ -1557,7 +1557,7 @@ if (cd.offset) { #ifdef CONFIG_NFSD_V3 if (rqstp->rq_vers == 3) - (void)enc64(cd.offset, file.f_pos); + (void)xdr_encode_hyper(cd.offset, file.f_pos); else #endif /* CONFIG_NFSD_V3 */ *cd.offset = htonl(file.f_pos); diff -u --recursive --new-file v2.3.46/linux/fs/proc/inode.c linux/fs/proc/inode.c --- v2.3.46/linux/fs/proc/inode.c Tue Nov 23 22:42:21 1999 +++ linux/fs/proc/inode.c Sun Feb 20 13:09:46 2000 @@ -15,6 +15,7 @@ #include #define __NO_VERSION__ #include +#include #include #include @@ -34,6 +35,7 @@ void de_put(struct proc_dir_entry *de) { if (de) { + lock_kernel(); /* FIXME: count should be atomic_t */ if (!de->count) { printk("de_put: entry %s already free!\n", de->name); return; @@ -46,6 +48,7 @@ free_proc_entry(de); } } + unlock_kernel(); } } @@ -65,6 +68,8 @@ static void proc_delete_inode(struct inode *inode) { struct proc_dir_entry *de = inode->u.generic_ip; + + inode->i_state = I_CLEAR; if (PROC_INODE_PROPER(inode)) { proc_pid_delete_inode(inode); diff -u --recursive --new-file v2.3.46/linux/fs/smbfs/inode.c linux/fs/smbfs/inode.c --- v2.3.46/linux/fs/smbfs/inode.c Sun Feb 13 19:29:04 2000 +++ linux/fs/smbfs/inode.c Wed Feb 16 20:23:47 2000 @@ -483,16 +483,7 @@ attr->ia_size); if (error) goto out; - /* - * We don't implement an i_op->truncate operation, - * so we have to update the page cache here. - */ - if (attr->ia_size < inode->i_size) - { - /* must die */ - truncate_inode_pages(inode->i_mapping, attr->ia_size); - inode->i_size = attr->ia_size; - } + vmtruncate(inode, attr->ia_size); refresh = 1; } @@ -563,8 +554,6 @@ out: if (refresh) smb_refresh_inode(dentry); - if (!error && (attr->ia_valid & ATTR_SIZE)) - vmtruncate(inode, attr->ia_size); return error; } diff -u --recursive --new-file v2.3.46/linux/fs/super.c linux/fs/super.c --- v2.3.46/linux/fs/super.c Wed Feb 16 17:03:52 2000 +++ linux/fs/super.c Sun Feb 20 20:41:00 2000 @@ -565,6 +565,7 @@ s->s_flags = flags; s->s_dirt = 0; sema_init(&s->s_vfs_rename_sem,1); + sema_init(&s->s_nfsd_free_path_sem,1); /* N.B. Should lock superblock now ... */ if (!type->read_super(s, data, silent)) goto out_fail; @@ -1142,6 +1143,7 @@ sb->s_bdev = NULL; sb->s_flags = root_mountflags; sema_init(&sb->s_vfs_rename_sem,1); + sema_init(&s->s_nfsd_free_path_sem,1); vfsmnt = add_vfsmnt(sb, "/dev/root", "/"); if (vfsmnt) { if (nfs_root_mount(sb) >= 0) { diff -u --recursive --new-file v2.3.46/linux/fs/udf/file.c linux/fs/udf/file.c --- v2.3.46/linux/fs/udf/file.c Thu Feb 10 17:11:19 2000 +++ linux/fs/udf/file.c Wed Feb 16 20:23:47 2000 @@ -145,6 +145,9 @@ brelse(bh); kunmap(page); SetPageUptodate(page); + /* only one page here */ + if (to > inode->i_size) + inode->i_size = to; return 0; } diff -u --recursive --new-file v2.3.46/linux/include/asm-alpha/core_mcpcia.h linux/include/asm-alpha/core_mcpcia.h --- v2.3.46/linux/include/asm-alpha/core_mcpcia.h Thu Feb 10 17:11:19 2000 +++ linux/include/asm-alpha/core_mcpcia.h Sun Feb 20 08:13:56 2000 @@ -74,6 +74,10 @@ #define MCPCIA_MID(m) ((unsigned long)(m) << 33) +/* Dodge has PCI0 and PCI1 at MID 4 and 5 respectively. + Durango adds PCI2 and PCI3 at MID 6 and 7 respectively. */ +#define MCPCIA_HOSE2MID(h) ((h) + 4) + #define MCPCIA_MEM_MASK 0x07ffffff /* SPARSE Mem region mask is 27 bits */ /* diff -u --recursive --new-file v2.3.46/linux/include/asm-alpha/hardirq.h linux/include/asm-alpha/hardirq.h --- v2.3.46/linux/include/asm-alpha/hardirq.h Thu Feb 10 17:11:19 2000 +++ linux/include/asm-alpha/hardirq.h Thu Feb 17 09:44:11 2000 @@ -8,8 +8,11 @@ #ifndef __SMP__ extern int __local_irq_count; #define local_irq_count(cpu) ((void)(cpu), __local_irq_count) +extern unsigned long __irq_attempt[]; +#define irq_attempt(cpu, irq) ((void)(cpu), __irq_attempt[irq]) #else #define local_irq_count(cpu) (cpu_data[cpu].irq_count) +#define irq_attempt(cpu, irq) (cpu_data[cpu].irq_attempt[irq]) #endif /* diff -u --recursive --new-file v2.3.46/linux/include/asm-alpha/hw_irq.h linux/include/asm-alpha/hw_irq.h --- v2.3.46/linux/include/asm-alpha/hw_irq.h Tue Dec 7 09:32:49 1999 +++ linux/include/asm-alpha/hw_irq.h Sun Feb 20 08:13:56 2000 @@ -1,91 +1,5 @@ -#ifndef _ALPHA_HW_IRQ_H -#define _ALPHA_HW_IRQ_H -/* - * linux/arch/alpha/kernel/irq.h - * - * Copyright (C) 1995 Linus Torvalds - * Copyright (C) 1998 Richard Henderson - * - * This file contains declarations and inline functions for interfacing - * with the IRQ handling routines in irq.c. - */ +/* This exists merely to satisfy . There is + nothing that would go here of general interest. -#include - -#define STANDARD_INIT_IRQ_PROLOG \ - outb(0, DMA1_RESET_REG); \ - outb(0, DMA2_RESET_REG); \ - outb(0, DMA1_CLR_MASK_REG); \ - outb(0, DMA2_CLR_MASK_REG) - -extern unsigned long _alpha_irq_masks[2]; -#define alpha_irq_mask _alpha_irq_masks[0] - -extern void common_ack_irq(unsigned long irq); -extern void isa_device_interrupt(unsigned long vector, struct pt_regs * regs); -extern void srm_device_interrupt(unsigned long vector, struct pt_regs * regs); - -extern void handle_irq(int irq, int ack, struct pt_regs * regs); - -#define RTC_IRQ 8 -#ifdef CONFIG_RTC -#define TIMER_IRQ 0 /* timer is the pit */ -#else -#define TIMER_IRQ RTC_IRQ /* timer is the rtc */ -#endif - -/* - * PROBE_MASK is the bitset of irqs that we consider for autoprobing. - */ - -/* NOTE: we only handle the first 64 IRQs in this code. */ - -/* The normal mask includes all the IRQs except timer IRQ 0. */ -#define _PROBE_MASK(nr_irqs) \ - (((nr_irqs > 63) ? ~0UL : ((1UL << (nr_irqs & 63)) - 1)) & ~1UL) - -/* Mask out unused timer irq 0 and RTC irq 8. */ -#define P2K_PROBE_MASK (_PROBE_MASK(16) & ~0x101UL) - -/* Mask out unused timer irq 0, "irqs" 20-30, and the EISA cascade. */ -#define ALCOR_PROBE_MASK (_PROBE_MASK(48) & ~0xfff000000001UL) - -/* Leave timer IRQ 0 in the mask. */ -#define RUFFIAN_PROBE_MASK (_PROBE_MASK(48) | 1UL) - -/* Do not probe/enable beyond the PCI devices. */ -#define TSUNAMI_PROBE_MASK _PROBE_MASK(48) - -#if defined(CONFIG_ALPHA_GENERIC) -# define PROBE_MASK alpha_mv.irq_probe_mask -#elif defined(CONFIG_ALPHA_P2K) -# define PROBE_MASK P2K_PROBE_MASK -#elif defined(CONFIG_ALPHA_ALCOR) || defined(CONFIG_ALPHA_XLT) -# define PROBE_MASK ALCOR_PROBE_MASK -#elif defined(CONFIG_ALPHA_RUFFIAN) -# define PROBE_MASK RUFFIAN_PROBE_MASK -#elif defined(CONFIG_ALPHA_DP264) -# define PROBE_MASK TSUNAMI_PROBE_MASK -#else -# define PROBE_MASK _PROBE_MASK(NR_IRQS) -#endif - - -extern char _stext; -static inline void alpha_do_profile (unsigned long pc) -{ - if (prof_buffer && current->pid) { - pc -= (unsigned long) &_stext; - pc >>= prof_shift; - /* - * Don't ignore out-of-bounds PC values silently, - * put them into the last histogram slot, so if - * present, they will show up as a sharp peak. - */ - if (pc > prof_len - 1) - pc = prof_len - 1; - atomic_inc((atomic_t *)&prof_buffer[pc]); - } -} - -#endif + Everything of consequence is in arch/alpha/kernel/irq_impl.h, + to be used only in arch/alpha/kernel/. */ diff -u --recursive --new-file v2.3.46/linux/include/asm-alpha/hwrpb.h linux/include/asm-alpha/hwrpb.h --- v2.3.46/linux/include/asm-alpha/hwrpb.h Tue Dec 7 09:32:49 1999 +++ linux/include/asm-alpha/hwrpb.h Sun Feb 20 08:13:56 2000 @@ -16,7 +16,7 @@ #define EV56_CPU 7 /* EV5.6 (21164) */ #define EV6_CPU 8 /* EV6 (21164) */ #define PCA56_CPU 9 /* PCA56 (21164PC) */ -#define PCA57_CPU 10 /* PCA57 (21164??) */ +#define PCA57_CPU 10 /* PCA57 (notyet) */ /* * DEC system types for Alpha systems. Found in HWRPB. @@ -62,8 +62,8 @@ #define ST_DTI_RUFFIAN 101 /* RUFFIAN systype */ /* Alpha Processor, Inc. systems */ -#define ST_API_BIAS 200 /* Offset for API systems */ -#define ST_API_NAUTILUS (ST_API_BIAS + 1) /* Nautilus systype */ +#define ST_API_BIAS 200 +#define ST_API_NAUTILUS 201 /* UP1000 systype */ struct pcb_struct { unsigned long ksp; diff -u --recursive --new-file v2.3.46/linux/include/asm-alpha/machvec.h linux/include/asm-alpha/machvec.h --- v2.3.46/linux/include/asm-alpha/machvec.h Thu Feb 10 17:11:19 2000 +++ linux/include/asm-alpha/machvec.h Sun Feb 20 08:13:56 2000 @@ -22,6 +22,7 @@ struct pci_dev; struct pci_ops; struct pci_controler; +struct irqaction; struct alpha_machine_vector { @@ -81,7 +82,7 @@ void (*init_arch)(void); void (*init_irq)(void); - void (*init_pit)(void); + void (*init_rtc)(struct irqaction *); void (*init_pci)(void); void (*kill_arch)(int); diff -u --recursive --new-file v2.3.46/linux/include/asm-alpha/pci.h linux/include/asm-alpha/pci.h --- v2.3.46/linux/include/asm-alpha/pci.h Thu Feb 10 17:11:20 2000 +++ linux/include/asm-alpha/pci.h Fri Feb 18 15:07:20 2000 @@ -74,9 +74,9 @@ /* Map a single buffer of the indicate size for PCI DMA in streaming mode. The 32-bit PCI bus mastering address to use is returned. Once the device is given the dma address, the device owns this memory - until either pci_unmap_single or pci_sync_single is performed. */ + until either pci_unmap_single or pci_dma_sync_single is performed. */ -extern dma_addr_t pci_map_single(struct pci_dev *, void *, long); +extern dma_addr_t pci_map_single(struct pci_dev *, void *, long, int); /* Unmap a single streaming mode DMA translation. The DMA_ADDR and SIZE must match what was provided for in a previous pci_map_single @@ -84,7 +84,7 @@ the cpu to the buffer are guarenteed to see whatever the device wrote there. */ -extern void pci_unmap_single(struct pci_dev *, dma_addr_t, long); +extern void pci_unmap_single(struct pci_dev *, dma_addr_t, long, int); /* Map a set of buffers described by scatterlist in streaming mode for PCI DMA. This is the scather-gather version of the above @@ -100,13 +100,13 @@ Device ownership issues as mentioned above for pci_map_single are the same here. */ -extern int pci_map_sg(struct pci_dev *, struct scatterlist *, int); +extern int pci_map_sg(struct pci_dev *, struct scatterlist *, int, int); /* Unmap a set of streaming mode DMA translations. Again, cpu read rules concerning calls here are the same as for pci_unmap_single() above. */ -extern void pci_unmap_sg(struct pci_dev *, struct scatterlist *, int); +extern void pci_unmap_sg(struct pci_dev *, struct scatterlist *, int, int); /* Make physical memory consistant for a single streaming mode DMA translation after a transfer. @@ -118,7 +118,7 @@ again owns the buffer. */ extern inline void -pci_sync_single(struct pci_dev *dev, dma_addr_t dma_addr, long size) +pci_dma_sync_single(struct pci_dev *dev, dma_addr_t dma_addr, long size, int direction) { /* Nothing to do. */ } @@ -128,9 +128,19 @@ for a scatter-gather list, same rules and usage. */ extern inline void -pci_sync_sg(struct pci_dev *dev, struct scatterlist *sg, int size) +pci_dma_sync_sg(struct pci_dev *dev, struct scatterlist *sg, int nents, int direction) { /* Nothing to do. */ +} + +/* Return whether the given PCI device DMA address mask can + * be supported properly. For example, if your device can + * only drive the low 24-bits during PCI bus mastering, then + * you would pass 0x00ffffff as the mask to this function. + */ +extern inline int pci_dma_supported(struct pci_dev *hwdev, dma_addr_t mask) +{ + return 1; } #endif /* __ALPHA_PCI_H */ diff -u --recursive --new-file v2.3.46/linux/include/asm-alpha/pgalloc.h linux/include/asm-alpha/pgalloc.h --- v2.3.46/linux/include/asm-alpha/pgalloc.h Thu Feb 10 17:11:20 2000 +++ linux/include/asm-alpha/pgalloc.h Fri Feb 18 10:01:32 2000 @@ -9,7 +9,18 @@ #define flush_cache_range(mm, start, end) do { } while (0) #define flush_cache_page(vma, vmaddr) do { } while (0) #define flush_page_to_ram(page) do { } while (0) -#define flush_icache_range(start, end) do { } while (0) +/* + * The icache is not coherent with the dcache on alpha, thus before + * running self modified code like kernel modules we must always run + * an imb(). + */ +#ifndef __SMP__ +#define flush_icache_range(start, end) imb() +#else +#define flush_icache_range(start, end) smp_imb() +extern void smp_imb(void); +#endif +#define flush_icache_page(vma, page) do { } while (0) /* * Use a few helper functions to hide the ugly broken ASN @@ -95,6 +106,18 @@ flush_tlb_current(current->mm); } +/* + * Flush a specified range of user mapping page tables + * from TLB. + * Although Alpha uses VPTE caches, this can be a nop, as Alpha does + * not have finegrained tlb flushing, so it will flush VPTE stuff + * during next flush_tlb_range. + */ +static inline void flush_tlb_pgtables(struct mm_struct *mm, + unsigned long start, unsigned long end) +{ +} + #ifndef __SMP__ /* * Flush everything (kernel mapping may also have @@ -143,18 +166,6 @@ unsigned long start, unsigned long end) { flush_tlb_mm(mm); -} - -/* - * Flush a specified range of user mapping page tables - * from TLB. - * Although Alpha uses VPTE caches, this can be a nop, as Alpha does - * not have finegrained tlb flushing, so it will flush VPTE stuff - * during next flush_tlb_range. - */ -static inline void flush_tlb_pgtables(struct mm_struct *mm, - unsigned long start, unsigned long end) -{ } #else /* __SMP__ */ diff -u --recursive --new-file v2.3.46/linux/include/asm-alpha/smp.h linux/include/asm-alpha/smp.h --- v2.3.46/linux/include/asm-alpha/smp.h Thu Feb 10 17:11:20 2000 +++ linux/include/asm-alpha/smp.h Thu Feb 17 09:44:11 2000 @@ -20,6 +20,7 @@ #ifdef __SMP__ #include +#include struct cpuinfo_alpha { unsigned long loops_per_sec; @@ -28,6 +29,8 @@ unsigned long *pte_cache; unsigned long pgtable_cache_sz; unsigned long ipi_count; + unsigned long irq_attempt[NR_IRQS]; + unsigned long smp_local_irq_count; unsigned long prof_multiplier; unsigned long prof_counter; int irq_count, bh_count; diff -u --recursive --new-file v2.3.46/linux/include/asm-arm/cpu-multi32.h linux/include/asm-arm/cpu-multi32.h --- v2.3.46/linux/include/asm-arm/cpu-multi32.h Fri Oct 22 13:21:53 1999 +++ linux/include/asm-arm/cpu-multi32.h Thu Feb 17 23:34:46 2000 @@ -96,6 +96,10 @@ * Idle the processor */ int (*_do_idle)(void); + /* + * flush I cache for a page + */ + void (*_flush_icache_page)(unsigned long address); } processor; extern const struct processor arm6_processor_functions; @@ -123,6 +127,7 @@ #define cpu_flush_icache_area(start,end) processor._flush_icache_area(start,end) #define cpu_cache_wback_area(start,end) processor._cache_wback_area(start,end) #define cpu_cache_purge_area(start,end) processor._cache_purge_area(start,end) +#define cpu_flush_icache_page(virt) processor._flush_icache_page(virt) #define cpu_switch_mm(pgd,tsk) cpu_set_pgd(__virt_to_phys((unsigned long)(pgd))) diff -u --recursive --new-file v2.3.46/linux/include/asm-arm/cpu-single.h linux/include/asm-arm/cpu-single.h --- v2.3.46/linux/include/asm-arm/cpu-single.h Fri Oct 22 13:21:53 1999 +++ linux/include/asm-arm/cpu-single.h Thu Feb 17 23:34:46 2000 @@ -35,6 +35,7 @@ #define cpu_flush_icache_area cpu_fn(CPU_NAME,_flush_icache_area) #define cpu_cache_wback_area cpu_fn(CPU_NAME,_cache_wback_area) #define cpu_cache_purge_area cpu_fn(CPU_NAME,_cache_purge_area) +#define cpu_flush_icache_page cpu_fn(CPU_NAME,_flush_icache_page) #ifndef __ASSEMBLY__ @@ -65,6 +66,7 @@ extern void cpu_flush_icache_area(unsigned long start, unsigned long size); extern void cpu_cache_wback_area(unsigned long start, unsigned long end); extern void cpu_cache_purge_area(unsigned long start, unsigned long end); +extern void cpu_flush_icache_page(unsigned long virt); #define cpu_switch_mm(pgd,tsk) cpu_set_pgd(__virt_to_phys((unsigned long)(pgd))) diff -u --recursive --new-file v2.3.46/linux/include/asm-arm/pci.h linux/include/asm-arm/pci.h --- v2.3.46/linux/include/asm-arm/pci.h Sun Feb 13 19:29:04 2000 +++ linux/include/asm-arm/pci.h Fri Feb 18 15:07:20 2000 @@ -56,7 +56,7 @@ * until either pci_unmap_single or pci_dma_sync_single is performed. */ extern inline dma_addr_t -pci_map_single(struct pci_dev *hwdev, void *ptr, size_t size) +pci_map_single(struct pci_dev *hwdev, void *ptr, size_t size, int direction) { consistent_sync(ptr, size, 3); return virt_to_bus(ptr); @@ -70,7 +70,7 @@ * whatever the device wrote there. */ extern inline void -pci_unmap_single(struct pci_dev *hwdev, dma_addr_t dma_addr, size_t size) +pci_unmap_single(struct pci_dev *hwdev, dma_addr_t dma_addr, size_t size, int direction) { /* nothing to do */ } @@ -91,7 +91,7 @@ * the same here. */ extern inline int -pci_map_sg(struct pci_dev *hwdev, struct scatterlist *sg, int nents) +pci_map_sg(struct pci_dev *hwdev, struct scatterlist *sg, int nents, int direction) { int i; @@ -106,7 +106,7 @@ * pci_unmap_single() above. */ extern inline void -pci_unmap_sg(struct pci_dev *hwdev, struct scatterlist *sg, int nents) +pci_unmap_sg(struct pci_dev *hwdev, struct scatterlist *sg, int nents, int direction) { /* nothing to do */ } @@ -121,7 +121,7 @@ * device again owns the buffer. */ extern inline void -pci_dma_sync_single(struct pci_dev *hwdev, dma_addr_t dma_handle, size_t size) +pci_dma_sync_single(struct pci_dev *hwdev, dma_addr_t dma_handle, size_t size, int direction) { consistent_sync(bus_to_virt(dma_handle), size, 3); } @@ -133,12 +133,22 @@ * same rules and usage. */ extern inline void -pci_dma_sync_sg(struct pci_dev *hwdev, struct scatterlist *sg, int nelems) +pci_dma_sync_sg(struct pci_dev *hwdev, struct scatterlist *sg, int nelems, int direction) { int i; for (i = 0; i < nelems; i++, sg++) consistent_sync(sg->address, sg->length, 3); +} + +/* Return whether the given PCI device DMA address mask can + * be supported properly. For example, if your device can + * only drive the low 24-bits during PCI bus mastering, then + * you would pass 0x00ffffff as the mask to this function. + */ +extern inline int pci_dma_supported(struct pci_dev *hwdev, dma_addr_t mask) +{ + return 1; } /* These macros should be used after a pci_map_sg call has been done diff -u --recursive --new-file v2.3.46/linux/include/asm-arm/proc-armo/cache.h linux/include/asm-arm/proc-armo/cache.h --- v2.3.46/linux/include/asm-arm/proc-armo/cache.h Mon Nov 1 13:56:27 1999 +++ linux/include/asm-arm/proc-armo/cache.h Thu Feb 17 23:34:46 2000 @@ -6,6 +6,7 @@ #define flush_cache_range(mm,start,end) do { } while (0) #define flush_cache_page(vma,vmaddr) do { } while (0) #define flush_page_to_ram(page) do { } while (0) +#define flush_icache_page(vma,page) do { } while (0) #define flush_icache_range(start,end) do { } while (0) /* diff -u --recursive --new-file v2.3.46/linux/include/asm-arm/proc-armv/cache.h linux/include/asm-arm/proc-armv/cache.h --- v2.3.46/linux/include/asm-arm/proc-armv/cache.h Tue Nov 23 22:42:21 1999 +++ linux/include/asm-arm/proc-armv/cache.h Thu Feb 17 23:34:46 2000 @@ -1,3 +1,5 @@ +#include + /* * Cache flushing... */ @@ -41,6 +43,12 @@ #define flush_icache_range(_start,_end) \ cpu_flush_icache_area((_start), (_end) - (_start)) + +#define flush_icache_page(vma,pg) \ + do { \ + if ((vma)->vm_flags & PROT_EXEC) \ + cpu_flush_icache_page(page_address(pg)); \ + } while (0) /* * We don't have a MEMC chip... diff -u --recursive --new-file v2.3.46/linux/include/asm-arm/unaligned.h linux/include/asm-arm/unaligned.h --- v2.3.46/linux/include/asm-arm/unaligned.h Fri Oct 22 13:21:53 1999 +++ linux/include/asm-arm/unaligned.h Thu Feb 17 23:34:46 2000 @@ -1,6 +1,8 @@ #ifndef __ASM_ARM_UNALIGNED_H #define __ASM_ARM_UNALIGNED_H +#include + #define get_unaligned(ptr) \ ((__typeof__(*(ptr)))__get_unaligned_size((ptr), sizeof(*(ptr)))) diff -u --recursive --new-file v2.3.46/linux/include/asm-i386/pci.h linux/include/asm-i386/pci.h --- v2.3.46/linux/include/asm-i386/pci.h Fri Jan 28 15:09:09 2000 +++ linux/include/asm-i386/pci.h Sun Feb 20 20:48:17 2000 @@ -52,8 +52,10 @@ * until either pci_unmap_single or pci_dma_sync_single is performed. */ extern inline dma_addr_t pci_map_single(struct pci_dev *hwdev, void *ptr, - size_t size) + size_t size, int direction) { + if (direction == PCI_DMA_NONE) + BUG(); return virt_to_bus(ptr); } @@ -65,8 +67,10 @@ * whatever the device wrote there. */ extern inline void pci_unmap_single(struct pci_dev *hwdev, dma_addr_t dma_addr, - size_t size) + size_t size, int direction) { + if (direction == PCI_DMA_NONE) + BUG(); /* Nothing to do */ } @@ -86,8 +90,10 @@ * the same here. */ extern inline int pci_map_sg(struct pci_dev *hwdev, struct scatterlist *sg, - int nents) + int nents, int direction) { + if (direction == PCI_DMA_NONE) + BUG(); return nents; } @@ -96,8 +102,10 @@ * pci_unmap_single() above. */ extern inline void pci_unmap_sg(struct pci_dev *hwdev, struct scatterlist *sg, - int nents) + int nents, int direction) { + if (direction == PCI_DMA_NONE) + BUG(); /* Nothing to do */ } @@ -112,8 +120,10 @@ */ extern inline void pci_dma_sync_single(struct pci_dev *hwdev, dma_addr_t dma_handle, - size_t size) + size_t size, int direction) { + if (direction == PCI_DMA_NONE) + BUG(); /* Nothing to do */ } @@ -125,9 +135,21 @@ */ extern inline void pci_dma_sync_sg(struct pci_dev *hwdev, struct scatterlist *sg, - int nelems) + int nelems, int direction) { + if (direction == PCI_DMA_NONE) + BUG(); /* Nothing to do */ +} + +/* Return whether the given PCI device DMA address mask can + * be supported properly. For example, if your device can + * only drive the low 24-bits during PCI bus mastering, then + * you would pass 0x00ffffff as the mask to this function. + */ +extern inline int pci_dma_supported(struct pci_dev *hwdev, dma_addr_t mask) +{ + return 1; } /* These macros should be used after a pci_map_sg call has been done diff -u --recursive --new-file v2.3.46/linux/include/asm-ia64/pci.h linux/include/asm-ia64/pci.h --- v2.3.46/linux/include/asm-ia64/pci.h Thu Feb 10 17:11:20 2000 +++ linux/include/asm-ia64/pci.h Fri Feb 18 15:07:20 2000 @@ -55,8 +55,10 @@ * until either pci_unmap_single or pci_dma_sync_single is performed. */ extern inline dma_addr_t -pci_map_single (struct pci_dev *hwdev, void *ptr, size_t size) +pci_map_single (struct pci_dev *hwdev, void *ptr, size_t size, int direction) { + if (direction == PCI_DMA_NONE) + BUG(); return virt_to_bus(ptr); } @@ -69,8 +71,10 @@ * whatever the device wrote there. */ extern inline void -pci_unmap_single (struct pci_dev *hwdev, dma_addr_t dma_addr, size_t size) +pci_unmap_single (struct pci_dev *hwdev, dma_addr_t dma_addr, size_t size, int direction) { + if (direction == PCI_DMA_NONE) + BUG(); /* Nothing to do */ } @@ -91,8 +95,10 @@ * the same here. */ extern inline int -pci_map_sg (struct pci_dev *hwdev, struct scatterlist *sg, int nents) +pci_map_sg (struct pci_dev *hwdev, struct scatterlist *sg, int nents, int direction) { + if (direction == PCI_DMA_NONE) + BUG(); return nents; } @@ -102,8 +108,10 @@ * pci_unmap_single() above. */ extern inline void -pci_unmap_sg (struct pci_dev *hwdev, struct scatterlist *sg, int nents) +pci_unmap_sg (struct pci_dev *hwdev, struct scatterlist *sg, int nents, int direction) { + if (direction == PCI_DMA_NONE) + BUG(); /* Nothing to do */ } @@ -118,8 +126,10 @@ * device again owns the buffer. */ extern inline void -pci_dma_sync_single (struct pci_dev *hwdev, dma_addr_t dma_handle, size_t size) +pci_dma_sync_single (struct pci_dev *hwdev, dma_addr_t dma_handle, size_t size, int direction) { + if (direction == PCI_DMA_NONE) + BUG(); /* Nothing to do */ } @@ -131,9 +141,21 @@ * same rules and usage. */ extern inline void -pci_dma_sync_sg (struct pci_dev *hwdev, struct scatterlist *sg, int nelems) +pci_dma_sync_sg (struct pci_dev *hwdev, struct scatterlist *sg, int nelems, int direction) { + if (direction == PCI_DMA_NONE) + BUG(); /* Nothing to do */ +} + +/* Return whether the given PCI device DMA address mask can + * be supported properly. For example, if your device can + * only drive the low 24-bits during PCI bus mastering, then + * you would pass 0x00ffffff as the mask to this function. + */ +extern inline int pci_dma_supported(struct pci_dev *hwdev, dma_addr_t mask) +{ + return 1; } /* These macros should be used after a pci_map_sg call has been done diff -u --recursive --new-file v2.3.46/linux/include/asm-ppc/pci.h linux/include/asm-ppc/pci.h --- v2.3.46/linux/include/asm-ppc/pci.h Thu Feb 10 17:11:21 2000 +++ linux/include/asm-ppc/pci.h Fri Feb 18 15:07:20 2000 @@ -27,36 +27,58 @@ extern void pci_free_consistent(struct pci_dev *hwdev, size_t size, void *vaddr, dma_addr_t dma_handle); extern inline dma_addr_t pci_map_single(struct pci_dev *hwdev, void *ptr, - size_t size) + size_t size, int direction) { + if (direction == PCI_DMA_NONE) + BUG(); return virt_to_bus(ptr); } extern inline void pci_unmap_single(struct pci_dev *hwdev, dma_addr_t dma_addr, - size_t size) + size_t size, int direction) { + if (direction == PCI_DMA_NONE) + BUG(); /* nothing to do */ } extern inline int pci_map_sg(struct pci_dev *hwdev, struct scatterlist *sg, - int nents) + int nents, int direction) { + if (direction == PCI_DMA_NONE) + BUG(); return nents; } extern inline void pci_unmap_sg(struct pci_dev *hwdev, struct scatterlist *sg, - int nents) + int nents, int direction) { + if (direction == PCI_DMA_NONE) + BUG(); /* nothing to do */ } extern inline void pci_dma_sync_single(struct pci_dev *hwdev, dma_addr_t dma_handle, - size_t size) + size_t size, int direction) { + if (direction == PCI_DMA_NONE) + BUG(); /* nothing to do */ } extern inline void pci_dma_syng_sg(struct pci_dev *hwdev, struct scatterlist *sg, - int nelems) + int nelems, int direction) { + if (direction == PCI_DMA_NONE) + BUG(); /* nothing to do */ +} + +/* Return whether the given PCI device DMA address mask can + * be supported properly. For example, if your device can + * only drive the low 24-bits during PCI bus mastering, then + * you would pass 0x00ffffff as the mask to this function. + */ +extern inline int pci_dma_supported(struct pci_dev *hwdev, dma_addr_t mask) +{ + return 1; } #define sg_dma_address(sg) (virt_to_bus((sg)->address)) diff -u --recursive --new-file v2.3.46/linux/include/asm-sparc/asm_offsets.h linux/include/asm-sparc/asm_offsets.h --- v2.3.46/linux/include/asm-sparc/asm_offsets.h Sat Feb 12 11:22:11 2000 +++ linux/include/asm-sparc/asm_offsets.h Sun Feb 20 08:49:40 2000 @@ -79,113 +79,113 @@ #define AOFF_task_pidhash_pprev 0x00000094 #define ASIZ_task_pidhash_pprev 0x00000004 #define AOFF_task_wait_chldexit 0x00000098 -#define ASIZ_task_wait_chldexit 0x00000010 -#define AOFF_task_vfork_sem 0x000000a8 +#define ASIZ_task_wait_chldexit 0x00000014 +#define AOFF_task_vfork_sem 0x000000ac #define ASIZ_task_vfork_sem 0x00000004 -#define AOFF_task_rt_priority 0x000000ac +#define AOFF_task_rt_priority 0x000000b0 #define ASIZ_task_rt_priority 0x00000004 -#define AOFF_task_it_real_value 0x000000b0 +#define AOFF_task_it_real_value 0x000000b4 #define ASIZ_task_it_real_value 0x00000004 -#define AOFF_task_it_prof_value 0x000000b4 +#define AOFF_task_it_prof_value 0x000000b8 #define ASIZ_task_it_prof_value 0x00000004 -#define AOFF_task_it_virt_value 0x000000b8 +#define AOFF_task_it_virt_value 0x000000bc #define ASIZ_task_it_virt_value 0x00000004 -#define AOFF_task_it_real_incr 0x000000bc +#define AOFF_task_it_real_incr 0x000000c0 #define ASIZ_task_it_real_incr 0x00000004 -#define AOFF_task_it_prof_incr 0x000000c0 +#define AOFF_task_it_prof_incr 0x000000c4 #define ASIZ_task_it_prof_incr 0x00000004 -#define AOFF_task_it_virt_incr 0x000000c4 +#define AOFF_task_it_virt_incr 0x000000c8 #define ASIZ_task_it_virt_incr 0x00000004 -#define AOFF_task_real_timer 0x000000c8 +#define AOFF_task_real_timer 0x000000cc #define ASIZ_task_real_timer 0x00000018 -#define AOFF_task_times 0x000000e0 +#define AOFF_task_times 0x000000e4 #define ASIZ_task_times 0x00000010 -#define AOFF_task_start_time 0x000000f0 +#define AOFF_task_start_time 0x000000f4 #define ASIZ_task_start_time 0x00000004 -#define AOFF_task_per_cpu_utime 0x000000f4 +#define AOFF_task_per_cpu_utime 0x000000f8 #define ASIZ_task_per_cpu_utime 0x00000004 -#define AOFF_task_min_flt 0x000000fc +#define AOFF_task_min_flt 0x00000100 #define ASIZ_task_min_flt 0x00000004 -#define AOFF_task_maj_flt 0x00000100 +#define AOFF_task_maj_flt 0x00000104 #define ASIZ_task_maj_flt 0x00000004 -#define AOFF_task_nswap 0x00000104 +#define AOFF_task_nswap 0x00000108 #define ASIZ_task_nswap 0x00000004 -#define AOFF_task_cmin_flt 0x00000108 +#define AOFF_task_cmin_flt 0x0000010c #define ASIZ_task_cmin_flt 0x00000004 -#define AOFF_task_cmaj_flt 0x0000010c +#define AOFF_task_cmaj_flt 0x00000110 #define ASIZ_task_cmaj_flt 0x00000004 -#define AOFF_task_cnswap 0x00000110 +#define AOFF_task_cnswap 0x00000114 #define ASIZ_task_cnswap 0x00000004 -#define AOFF_task_uid 0x00000118 +#define AOFF_task_uid 0x0000011c #define ASIZ_task_uid 0x00000004 -#define AOFF_task_euid 0x0000011c +#define AOFF_task_euid 0x00000120 #define ASIZ_task_euid 0x00000004 -#define AOFF_task_suid 0x00000120 +#define AOFF_task_suid 0x00000124 #define ASIZ_task_suid 0x00000004 -#define AOFF_task_fsuid 0x00000124 +#define AOFF_task_fsuid 0x00000128 #define ASIZ_task_fsuid 0x00000004 -#define AOFF_task_gid 0x00000128 +#define AOFF_task_gid 0x0000012c #define ASIZ_task_gid 0x00000004 -#define AOFF_task_egid 0x0000012c +#define AOFF_task_egid 0x00000130 #define ASIZ_task_egid 0x00000004 -#define AOFF_task_sgid 0x00000130 +#define AOFF_task_sgid 0x00000134 #define ASIZ_task_sgid 0x00000004 -#define AOFF_task_fsgid 0x00000134 +#define AOFF_task_fsgid 0x00000138 #define ASIZ_task_fsgid 0x00000004 -#define AOFF_task_ngroups 0x00000138 +#define AOFF_task_ngroups 0x0000013c #define ASIZ_task_ngroups 0x00000004 -#define AOFF_task_groups 0x0000013c +#define AOFF_task_groups 0x00000140 #define ASIZ_task_groups 0x00000080 -#define AOFF_task_cap_effective 0x000001bc +#define AOFF_task_cap_effective 0x000001c0 #define ASIZ_task_cap_effective 0x00000004 -#define AOFF_task_cap_inheritable 0x000001c0 +#define AOFF_task_cap_inheritable 0x000001c4 #define ASIZ_task_cap_inheritable 0x00000004 -#define AOFF_task_cap_permitted 0x000001c4 +#define AOFF_task_cap_permitted 0x000001c8 #define ASIZ_task_cap_permitted 0x00000004 -#define AOFF_task_user 0x000001c8 +#define AOFF_task_user 0x000001cc #define ASIZ_task_user 0x00000004 -#define AOFF_task_rlim 0x000001cc +#define AOFF_task_rlim 0x000001d0 #define ASIZ_task_rlim 0x00000050 -#define AOFF_task_used_math 0x0000021c +#define AOFF_task_used_math 0x00000220 #define ASIZ_task_used_math 0x00000002 -#define AOFF_task_comm 0x0000021e +#define AOFF_task_comm 0x00000222 #define ASIZ_task_comm 0x00000010 -#define AOFF_task_link_count 0x00000230 +#define AOFF_task_link_count 0x00000234 #define ASIZ_task_link_count 0x00000004 -#define AOFF_task_tty 0x00000234 +#define AOFF_task_tty 0x00000238 #define ASIZ_task_tty 0x00000004 -#define AOFF_task_semundo 0x00000238 +#define AOFF_task_semundo 0x0000023c #define ASIZ_task_semundo 0x00000004 -#define AOFF_task_semsleeping 0x0000023c +#define AOFF_task_semsleeping 0x00000240 #define ASIZ_task_semsleeping 0x00000004 -#define AOFF_task_thread 0x00000240 +#define AOFF_task_thread 0x00000248 #define ASIZ_task_thread 0x00000380 -#define AOFF_task_fs 0x000005c0 +#define AOFF_task_fs 0x000005c8 #define ASIZ_task_fs 0x00000004 -#define AOFF_task_files 0x000005c4 +#define AOFF_task_files 0x000005cc #define ASIZ_task_files 0x00000004 -#define AOFF_task_sigmask_lock 0x000005c8 -#define ASIZ_task_sigmask_lock 0x00000000 -#define AOFF_task_sig 0x000005c8 +#define AOFF_task_sigmask_lock 0x000005d0 +#define ASIZ_task_sigmask_lock 0x00000004 +#define AOFF_task_sig 0x000005d4 #define ASIZ_task_sig 0x00000004 -#define AOFF_task_signal 0x000005cc +#define AOFF_task_signal 0x000005d8 #define ASIZ_task_signal 0x00000008 -#define AOFF_task_blocked 0x000005d4 +#define AOFF_task_blocked 0x000005e0 #define ASIZ_task_blocked 0x00000008 -#define AOFF_task_sigqueue 0x000005dc +#define AOFF_task_sigqueue 0x000005e8 #define ASIZ_task_sigqueue 0x00000004 -#define AOFF_task_sigqueue_tail 0x000005e0 +#define AOFF_task_sigqueue_tail 0x000005ec #define ASIZ_task_sigqueue_tail 0x00000004 -#define AOFF_task_sas_ss_sp 0x000005e4 +#define AOFF_task_sas_ss_sp 0x000005f0 #define ASIZ_task_sas_ss_sp 0x00000004 -#define AOFF_task_sas_ss_size 0x000005e8 +#define AOFF_task_sas_ss_size 0x000005f4 #define ASIZ_task_sas_ss_size 0x00000004 -#define AOFF_task_parent_exec_id 0x000005ec +#define AOFF_task_parent_exec_id 0x000005f8 #define ASIZ_task_parent_exec_id 0x00000004 -#define AOFF_task_self_exec_id 0x000005f0 +#define AOFF_task_self_exec_id 0x000005fc #define ASIZ_task_self_exec_id 0x00000004 -#define AOFF_task_exit_sem 0x000005f4 -#define ASIZ_task_exit_sem 0x0000001c +#define AOFF_task_exit_sem 0x00000600 +#define ASIZ_task_exit_sem 0x00000020 #define AOFF_mm_mmap 0x00000000 #define ASIZ_mm_mmap 0x00000004 #define AOFF_mm_mmap_avl 0x00000004 @@ -201,48 +201,48 @@ #define AOFF_mm_map_count 0x00000018 #define ASIZ_mm_map_count 0x00000004 #define AOFF_mm_mmap_sem 0x0000001c -#define ASIZ_mm_mmap_sem 0x0000001c -#define AOFF_mm_page_table_lock 0x00000038 -#define ASIZ_mm_page_table_lock 0x00000000 -#define AOFF_mm_context 0x00000038 +#define ASIZ_mm_mmap_sem 0x00000020 +#define AOFF_mm_page_table_lock 0x0000003c +#define ASIZ_mm_page_table_lock 0x00000004 +#define AOFF_mm_context 0x00000040 #define ASIZ_mm_context 0x00000004 -#define AOFF_mm_start_code 0x0000003c +#define AOFF_mm_start_code 0x00000044 #define ASIZ_mm_start_code 0x00000004 -#define AOFF_mm_end_code 0x00000040 +#define AOFF_mm_end_code 0x00000048 #define ASIZ_mm_end_code 0x00000004 -#define AOFF_mm_start_data 0x00000044 +#define AOFF_mm_start_data 0x0000004c #define ASIZ_mm_start_data 0x00000004 -#define AOFF_mm_end_data 0x00000048 +#define AOFF_mm_end_data 0x00000050 #define ASIZ_mm_end_data 0x00000004 -#define AOFF_mm_start_brk 0x0000004c +#define AOFF_mm_start_brk 0x00000054 #define ASIZ_mm_start_brk 0x00000004 -#define AOFF_mm_brk 0x00000050 +#define AOFF_mm_brk 0x00000058 #define ASIZ_mm_brk 0x00000004 -#define AOFF_mm_start_stack 0x00000054 +#define AOFF_mm_start_stack 0x0000005c #define ASIZ_mm_start_stack 0x00000004 -#define AOFF_mm_arg_start 0x00000058 +#define AOFF_mm_arg_start 0x00000060 #define ASIZ_mm_arg_start 0x00000004 -#define AOFF_mm_arg_end 0x0000005c +#define AOFF_mm_arg_end 0x00000064 #define ASIZ_mm_arg_end 0x00000004 -#define AOFF_mm_env_start 0x00000060 +#define AOFF_mm_env_start 0x00000068 #define ASIZ_mm_env_start 0x00000004 -#define AOFF_mm_env_end 0x00000064 +#define AOFF_mm_env_end 0x0000006c #define ASIZ_mm_env_end 0x00000004 -#define AOFF_mm_rss 0x00000068 +#define AOFF_mm_rss 0x00000070 #define ASIZ_mm_rss 0x00000004 -#define AOFF_mm_total_vm 0x0000006c +#define AOFF_mm_total_vm 0x00000074 #define ASIZ_mm_total_vm 0x00000004 -#define AOFF_mm_locked_vm 0x00000070 +#define AOFF_mm_locked_vm 0x00000078 #define ASIZ_mm_locked_vm 0x00000004 -#define AOFF_mm_def_flags 0x00000074 +#define AOFF_mm_def_flags 0x0000007c #define ASIZ_mm_def_flags 0x00000004 -#define AOFF_mm_cpu_vm_mask 0x00000078 +#define AOFF_mm_cpu_vm_mask 0x00000080 #define ASIZ_mm_cpu_vm_mask 0x00000004 -#define AOFF_mm_swap_cnt 0x0000007c +#define AOFF_mm_swap_cnt 0x00000084 #define ASIZ_mm_swap_cnt 0x00000004 -#define AOFF_mm_swap_address 0x00000080 +#define AOFF_mm_swap_address 0x00000088 #define ASIZ_mm_swap_address 0x00000004 -#define AOFF_mm_segments 0x00000084 +#define AOFF_mm_segments 0x0000008c #define ASIZ_mm_segments 0x00000004 #define AOFF_thread_uwinmask 0x00000000 #define ASIZ_thread_uwinmask 0x00000004 diff -u --recursive --new-file v2.3.46/linux/include/asm-sparc/page.h linux/include/asm-sparc/page.h --- v2.3.46/linux/include/asm-sparc/page.h Wed Feb 16 17:03:52 2000 +++ linux/include/asm-sparc/page.h Thu Feb 17 09:26:31 2000 @@ -1,4 +1,4 @@ -/* $Id: page.h,v 1.47 2000/01/29 00:41:49 anton Exp $ +/* $Id: page.h,v 1.48 2000/02/16 07:34:51 davem Exp $ * page.h: Various defines and such for MMU operations on the Sparc for * the Linux kernel. * diff -u --recursive --new-file v2.3.46/linux/include/asm-sparc/pci.h linux/include/asm-sparc/pci.h --- v2.3.46/linux/include/asm-sparc/pci.h Thu Feb 10 17:11:21 2000 +++ linux/include/asm-sparc/pci.h Fri Feb 18 15:07:20 2000 @@ -40,7 +40,7 @@ * Once the device is given the dma address, the device owns this memory * until either pci_unmap_single or pci_dma_sync_single is performed. */ -extern dma_addr_t pci_map_single(struct pci_dev *hwdev, void *ptr, size_t size); +extern dma_addr_t pci_map_single(struct pci_dev *hwdev, void *ptr, size_t size, int direction); /* Unmap a single streaming mode DMA translation. The dma_addr and size * must match what was provided for in a previous pci_map_single call. All @@ -49,7 +49,7 @@ * After this call, reads by the cpu to the buffer are guarenteed to see * whatever the device wrote there. */ -extern void pci_unmap_single(struct pci_dev *hwdev, dma_addr_t dma_addr, size_t size); +extern void pci_unmap_single(struct pci_dev *hwdev, dma_addr_t dma_addr, size_t size, int direction); /* Map a set of buffers described by scatterlist in streaming * mode for DMA. This is the scather-gather version of the @@ -66,13 +66,13 @@ * Device ownership issues as mentioned above for pci_map_single are * the same here. */ -extern int pci_map_sg(struct pci_dev *hwdev, struct scatterlist *sg, int nents); +extern int pci_map_sg(struct pci_dev *hwdev, struct scatterlist *sg, int nents, int direction); /* Unmap a set of streaming mode DMA translations. * Again, cpu read rules concerning calls here are the same as for * pci_unmap_single() above. */ -extern void pci_unmap_sg(struct pci_dev *hwdev, struct scatterlist *sg, int nhwents); +extern void pci_unmap_sg(struct pci_dev *hwdev, struct scatterlist *sg, int nhwents, int direction); /* Make physical memory consistent for a single * streaming mode DMA translation after a transfer. @@ -83,7 +83,7 @@ * next point you give the PCI dma address back to the card, the * device again owns the buffer. */ -extern void pci_dma_sync_single(struct pci_dev *hwdev, dma_addr_t dma_handle, size_t size); +extern void pci_dma_sync_single(struct pci_dev *hwdev, dma_addr_t dma_handle, size_t size, int direction); /* Make physical memory consistent for a set of streaming * mode DMA translations after a transfer. @@ -91,7 +91,17 @@ * The same as pci_dma_sync_single but for a scatter-gather list, * same rules and usage. */ -extern void pci_dma_sync_sg(struct pci_dev *hwdev, struct scatterlist *sg, int nelems); +extern void pci_dma_sync_sg(struct pci_dev *hwdev, struct scatterlist *sg, int nelems, int direction); + +/* Return whether the given PCI device DMA address mask can + * be supported properly. For example, if your device can + * only drive the low 24-bits during PCI bus mastering, then + * you would pass 0x00ffffff as the mask to this function. + */ +extern inline int pci_dma_supported(struct pci_dev *hwdev, dma_addr_t mask) +{ + return 1; +} #endif /* __KERNEL__ */ diff -u --recursive --new-file v2.3.46/linux/include/asm-sparc/pgtable.h linux/include/asm-sparc/pgtable.h --- v2.3.46/linux/include/asm-sparc/pgtable.h Wed Feb 16 17:03:52 2000 +++ linux/include/asm-sparc/pgtable.h Thu Feb 17 09:26:31 2000 @@ -1,4 +1,4 @@ -/* $Id: pgtable.h,v 1.88 2000/02/06 22:56:09 zaitcev Exp $ */ +/* $Id: pgtable.h,v 1.91 2000/02/16 08:44:52 anton Exp $ */ #ifndef _SPARC_PGTABLE_H #define _SPARC_PGTABLE_H @@ -327,15 +327,16 @@ pgprot_val(newprot)); } -BTFIXUPDEF_CALL(pgd_t *, pgd_offset, struct mm_struct *, unsigned long) -BTFIXUPDEF_CALL(pmd_t *, pmd_offset, pgd_t *, unsigned long) -BTFIXUPDEF_CALL(pte_t *, pte_offset, pmd_t *, unsigned long) +#define pgd_index(address) ((address) >> PGDIR_SHIFT) + +/* to find an entry in a page-table-directory */ +#define pgd_offset(mm, address) ((mm)->pgd + pgd_index(address)) /* to find an entry in a kernel page-table-directory */ #define pgd_offset_k(address) pgd_offset(&init_mm, address) -/* to find an entry in a page-table-directory */ -#define pgd_offset(mm,addr) BTFIXUP_CALL(pgd_offset)(mm,addr) +BTFIXUPDEF_CALL(pmd_t *, pmd_offset, pgd_t *, unsigned long) +BTFIXUPDEF_CALL(pte_t *, pte_offset, pmd_t *, unsigned long) /* Find an entry in the second-level page table.. */ #define pmd_offset(dir,addr) BTFIXUP_CALL(pmd_offset)(dir,addr) @@ -345,6 +346,8 @@ /* The permissions for pgprot_val to make a page mapped on the obio space */ extern unsigned int pg_iobits; + +#define flush_icache_page(vma, pg) do { } while(0) /* Certain architectures need to do special things when pte's * within a page table are directly modified. Thus, the following diff -u --recursive --new-file v2.3.46/linux/include/asm-sparc/sbus.h linux/include/asm-sparc/sbus.h --- v2.3.46/linux/include/asm-sparc/sbus.h Tue Feb 1 01:35:44 2000 +++ linux/include/asm-sparc/sbus.h Fri Feb 18 15:07:20 2000 @@ -1,4 +1,4 @@ -/* $Id: sbus.h,v 1.21 2000/01/28 13:43:11 jj Exp $ +/* $Id: sbus.h,v 1.22 2000/02/18 13:50:50 davem Exp $ * sbus.h: Defines for the Sun SBus. * * Copyright (C) 1995 David S. Miller (davem@caip.rutgers.edu) @@ -97,22 +97,27 @@ for((bus) = sbus_root, ((device) = (bus) ? (bus)->devices : 0); (bus); (device)=((device)->next ? (device)->next : ((bus) = (bus)->next, (bus) ? (bus)->devices : 0))) /* Driver DVMA interfaces. */ -#define sbus_can_dma_64bit(sdev) (1) -#define sbus_can_burst64(sdev) (1) +#define sbus_can_dma_64bit(sdev) (0) /* actually, sparc_cpu_model==sun4d */ +#define sbus_can_burst64(sdev) (0) /* actually, sparc_cpu_model==sun4d */ extern void sbus_set_sbus64(struct sbus_dev *, int); /* These yield IOMMU mappings in consistent mode. */ extern void *sbus_alloc_consistent(struct sbus_dev *, long, u32 *dma_addrp); extern void sbus_free_consistent(struct sbus_dev *, long, void *, u32); +#define SBUS_DMA_BIDIRECTIONAL 0 +#define SBUS_DMA_TODEVICE 1 +#define SBUS_DMA_FROMDEVICE 2 +#define SBUS_DMA_NONE 3 + /* All the rest use streaming mode mappings. */ -extern u32 sbus_map_single(struct sbus_dev *, void *, long); -extern void sbus_unmap_single(struct sbus_dev *, u32, long); -extern int sbus_map_sg(struct sbus_dev *, struct scatterlist *, int); -extern void sbus_unmap_sg(struct sbus_dev *, struct scatterlist *, int); +extern u32 sbus_map_single(struct sbus_dev *, void *, long, int); +extern void sbus_unmap_single(struct sbus_dev *, u32, long, int); +extern int sbus_map_sg(struct sbus_dev *, struct scatterlist *, int, int); +extern void sbus_unmap_sg(struct sbus_dev *, struct scatterlist *, int, int); /* Finally, allow explicit synchronization of streamable mappings. */ -extern void sbus_dma_sync_single(struct sbus_dev *, u32, long); -extern void sbus_dma_sync_sg(struct sbus_dev *, struct scatterlist *, int); +extern void sbus_dma_sync_single(struct sbus_dev *, u32, long, int); +extern void sbus_dma_sync_sg(struct sbus_dev *, struct scatterlist *, int, int); #endif /* !(_SPARC_SBUS_H) */ diff -u --recursive --new-file v2.3.46/linux/include/asm-sparc64/asm_offsets.h linux/include/asm-sparc64/asm_offsets.h --- v2.3.46/linux/include/asm-sparc64/asm_offsets.h Sat Feb 12 11:22:11 2000 +++ linux/include/asm-sparc64/asm_offsets.h Sun Feb 20 08:49:41 2000 @@ -85,84 +85,84 @@ #define AOFF_task_pidhash_pprev 0x000000f8 #define ASIZ_task_pidhash_pprev 0x00000008 #define AOFF_task_wait_chldexit 0x00000100 -#define ASIZ_task_wait_chldexit 0x00000020 -#define AOFF_task_vfork_sem 0x00000120 +#define ASIZ_task_wait_chldexit 0x00000028 +#define AOFF_task_vfork_sem 0x00000128 #define ASIZ_task_vfork_sem 0x00000008 -#define AOFF_task_rt_priority 0x00000128 +#define AOFF_task_rt_priority 0x00000130 #define ASIZ_task_rt_priority 0x00000008 -#define AOFF_task_it_real_value 0x00000130 +#define AOFF_task_it_real_value 0x00000138 #define ASIZ_task_it_real_value 0x00000008 -#define AOFF_task_it_prof_value 0x00000138 +#define AOFF_task_it_prof_value 0x00000140 #define ASIZ_task_it_prof_value 0x00000008 -#define AOFF_task_it_virt_value 0x00000140 +#define AOFF_task_it_virt_value 0x00000148 #define ASIZ_task_it_virt_value 0x00000008 -#define AOFF_task_it_real_incr 0x00000148 +#define AOFF_task_it_real_incr 0x00000150 #define ASIZ_task_it_real_incr 0x00000008 -#define AOFF_task_it_prof_incr 0x00000150 +#define AOFF_task_it_prof_incr 0x00000158 #define ASIZ_task_it_prof_incr 0x00000008 -#define AOFF_task_it_virt_incr 0x00000158 +#define AOFF_task_it_virt_incr 0x00000160 #define ASIZ_task_it_virt_incr 0x00000008 -#define AOFF_task_real_timer 0x00000160 +#define AOFF_task_real_timer 0x00000168 #define ASIZ_task_real_timer 0x00000030 -#define AOFF_task_times 0x00000190 +#define AOFF_task_times 0x00000198 #define ASIZ_task_times 0x00000020 -#define AOFF_task_start_time 0x000001b0 +#define AOFF_task_start_time 0x000001b8 #define ASIZ_task_start_time 0x00000008 -#define AOFF_task_per_cpu_utime 0x000001b8 +#define AOFF_task_per_cpu_utime 0x000001c0 #define ASIZ_task_per_cpu_utime 0x00000008 -#define AOFF_task_min_flt 0x000001c8 +#define AOFF_task_min_flt 0x000001d0 #define ASIZ_task_min_flt 0x00000008 -#define AOFF_task_maj_flt 0x000001d0 +#define AOFF_task_maj_flt 0x000001d8 #define ASIZ_task_maj_flt 0x00000008 -#define AOFF_task_nswap 0x000001d8 +#define AOFF_task_nswap 0x000001e0 #define ASIZ_task_nswap 0x00000008 -#define AOFF_task_cmin_flt 0x000001e0 +#define AOFF_task_cmin_flt 0x000001e8 #define ASIZ_task_cmin_flt 0x00000008 -#define AOFF_task_cmaj_flt 0x000001e8 +#define AOFF_task_cmaj_flt 0x000001f0 #define ASIZ_task_cmaj_flt 0x00000008 -#define AOFF_task_cnswap 0x000001f0 +#define AOFF_task_cnswap 0x000001f8 #define ASIZ_task_cnswap 0x00000008 -#define AOFF_task_uid 0x000001fc +#define AOFF_task_uid 0x00000204 #define ASIZ_task_uid 0x00000004 -#define AOFF_task_euid 0x00000200 +#define AOFF_task_euid 0x00000208 #define ASIZ_task_euid 0x00000004 -#define AOFF_task_suid 0x00000204 +#define AOFF_task_suid 0x0000020c #define ASIZ_task_suid 0x00000004 -#define AOFF_task_fsuid 0x00000208 +#define AOFF_task_fsuid 0x00000210 #define ASIZ_task_fsuid 0x00000004 -#define AOFF_task_gid 0x0000020c +#define AOFF_task_gid 0x00000214 #define ASIZ_task_gid 0x00000004 -#define AOFF_task_egid 0x00000210 +#define AOFF_task_egid 0x00000218 #define ASIZ_task_egid 0x00000004 -#define AOFF_task_sgid 0x00000214 +#define AOFF_task_sgid 0x0000021c #define ASIZ_task_sgid 0x00000004 -#define AOFF_task_fsgid 0x00000218 +#define AOFF_task_fsgid 0x00000220 #define ASIZ_task_fsgid 0x00000004 -#define AOFF_task_ngroups 0x0000021c +#define AOFF_task_ngroups 0x00000224 #define ASIZ_task_ngroups 0x00000004 -#define AOFF_task_groups 0x00000220 +#define AOFF_task_groups 0x00000228 #define ASIZ_task_groups 0x00000080 -#define AOFF_task_cap_effective 0x000002a0 +#define AOFF_task_cap_effective 0x000002a8 #define ASIZ_task_cap_effective 0x00000004 -#define AOFF_task_cap_inheritable 0x000002a4 +#define AOFF_task_cap_inheritable 0x000002ac #define ASIZ_task_cap_inheritable 0x00000004 -#define AOFF_task_cap_permitted 0x000002a8 +#define AOFF_task_cap_permitted 0x000002b0 #define ASIZ_task_cap_permitted 0x00000004 -#define AOFF_task_user 0x000002b0 +#define AOFF_task_user 0x000002b8 #define ASIZ_task_user 0x00000008 -#define AOFF_task_rlim 0x000002b8 +#define AOFF_task_rlim 0x000002c0 #define ASIZ_task_rlim 0x000000a0 -#define AOFF_task_used_math 0x00000358 +#define AOFF_task_used_math 0x00000360 #define ASIZ_task_used_math 0x00000002 -#define AOFF_task_comm 0x0000035a +#define AOFF_task_comm 0x00000362 #define ASIZ_task_comm 0x00000010 -#define AOFF_task_link_count 0x0000036c +#define AOFF_task_link_count 0x00000374 #define ASIZ_task_link_count 0x00000004 -#define AOFF_task_tty 0x00000370 +#define AOFF_task_tty 0x00000378 #define ASIZ_task_tty 0x00000008 -#define AOFF_task_semundo 0x00000378 +#define AOFF_task_semundo 0x00000380 #define ASIZ_task_semundo 0x00000008 -#define AOFF_task_semsleeping 0x00000380 +#define AOFF_task_semsleeping 0x00000388 #define ASIZ_task_semsleeping 0x00000008 #define AOFF_task_thread 0x00000390 #define ASIZ_task_thread 0x00000450 @@ -171,28 +171,28 @@ #define AOFF_task_files 0x000007e8 #define ASIZ_task_files 0x00000008 #define AOFF_task_sigmask_lock 0x000007f0 -#define ASIZ_task_sigmask_lock 0x00000000 -#define AOFF_task_sig 0x000007f0 +#define ASIZ_task_sigmask_lock 0x00000004 +#define AOFF_task_sig 0x000007f8 #define ASIZ_task_sig 0x00000008 -#define AOFF_task_signal 0x000007f8 +#define AOFF_task_signal 0x00000800 #define ASIZ_task_signal 0x00000008 -#define AOFF_task_blocked 0x00000800 +#define AOFF_task_blocked 0x00000808 #define ASIZ_task_blocked 0x00000008 -#define AOFF_task_sigqueue 0x00000808 +#define AOFF_task_sigqueue 0x00000810 #define ASIZ_task_sigqueue 0x00000008 -#define AOFF_task_sigqueue_tail 0x00000810 +#define AOFF_task_sigqueue_tail 0x00000818 #define ASIZ_task_sigqueue_tail 0x00000008 -#define AOFF_task_sas_ss_sp 0x00000818 +#define AOFF_task_sas_ss_sp 0x00000820 #define ASIZ_task_sas_ss_sp 0x00000008 -#define AOFF_task_sas_ss_size 0x00000820 +#define AOFF_task_sas_ss_size 0x00000828 #define ASIZ_task_sas_ss_size 0x00000008 -#define AOFF_task_parent_exec_id 0x00000828 +#define AOFF_task_parent_exec_id 0x00000830 #define ASIZ_task_parent_exec_id 0x00000004 -#define AOFF_task_self_exec_id 0x0000082c +#define AOFF_task_self_exec_id 0x00000834 #define ASIZ_task_self_exec_id 0x00000004 -#define AOFF_task_exit_sem 0x00000830 -#define ASIZ_task_exit_sem 0x00000030 -#define ASIZ_task 0x00000860 +#define AOFF_task_exit_sem 0x00000838 +#define ASIZ_task_exit_sem 0x00000038 +#define ASIZ_task 0x00000870 #define AOFF_mm_mmap 0x00000000 #define ASIZ_mm_mmap 0x00000008 #define AOFF_mm_mmap_avl 0x00000008 @@ -208,50 +208,50 @@ #define AOFF_mm_map_count 0x00000028 #define ASIZ_mm_map_count 0x00000004 #define AOFF_mm_mmap_sem 0x00000030 -#define ASIZ_mm_mmap_sem 0x00000030 -#define AOFF_mm_page_table_lock 0x00000060 -#define ASIZ_mm_page_table_lock 0x00000000 -#define AOFF_mm_context 0x00000060 +#define ASIZ_mm_mmap_sem 0x00000038 +#define AOFF_mm_page_table_lock 0x00000068 +#define ASIZ_mm_page_table_lock 0x00000004 +#define AOFF_mm_context 0x00000070 #define ASIZ_mm_context 0x00000008 -#define AOFF_mm_start_code 0x00000068 +#define AOFF_mm_start_code 0x00000078 #define ASIZ_mm_start_code 0x00000008 -#define AOFF_mm_end_code 0x00000070 +#define AOFF_mm_end_code 0x00000080 #define ASIZ_mm_end_code 0x00000008 -#define AOFF_mm_start_data 0x00000078 +#define AOFF_mm_start_data 0x00000088 #define ASIZ_mm_start_data 0x00000008 -#define AOFF_mm_end_data 0x00000080 +#define AOFF_mm_end_data 0x00000090 #define ASIZ_mm_end_data 0x00000008 -#define AOFF_mm_start_brk 0x00000088 +#define AOFF_mm_start_brk 0x00000098 #define ASIZ_mm_start_brk 0x00000008 -#define AOFF_mm_brk 0x00000090 +#define AOFF_mm_brk 0x000000a0 #define ASIZ_mm_brk 0x00000008 -#define AOFF_mm_start_stack 0x00000098 +#define AOFF_mm_start_stack 0x000000a8 #define ASIZ_mm_start_stack 0x00000008 -#define AOFF_mm_arg_start 0x000000a0 +#define AOFF_mm_arg_start 0x000000b0 #define ASIZ_mm_arg_start 0x00000008 -#define AOFF_mm_arg_end 0x000000a8 +#define AOFF_mm_arg_end 0x000000b8 #define ASIZ_mm_arg_end 0x00000008 -#define AOFF_mm_env_start 0x000000b0 +#define AOFF_mm_env_start 0x000000c0 #define ASIZ_mm_env_start 0x00000008 -#define AOFF_mm_env_end 0x000000b8 +#define AOFF_mm_env_end 0x000000c8 #define ASIZ_mm_env_end 0x00000008 -#define AOFF_mm_rss 0x000000c0 +#define AOFF_mm_rss 0x000000d0 #define ASIZ_mm_rss 0x00000008 -#define AOFF_mm_total_vm 0x000000c8 +#define AOFF_mm_total_vm 0x000000d8 #define ASIZ_mm_total_vm 0x00000008 -#define AOFF_mm_locked_vm 0x000000d0 +#define AOFF_mm_locked_vm 0x000000e0 #define ASIZ_mm_locked_vm 0x00000008 -#define AOFF_mm_def_flags 0x000000d8 +#define AOFF_mm_def_flags 0x000000e8 #define ASIZ_mm_def_flags 0x00000008 -#define AOFF_mm_cpu_vm_mask 0x000000e0 +#define AOFF_mm_cpu_vm_mask 0x000000f0 #define ASIZ_mm_cpu_vm_mask 0x00000008 -#define AOFF_mm_swap_cnt 0x000000e8 +#define AOFF_mm_swap_cnt 0x000000f8 #define ASIZ_mm_swap_cnt 0x00000008 -#define AOFF_mm_swap_address 0x000000f0 +#define AOFF_mm_swap_address 0x00000100 #define ASIZ_mm_swap_address 0x00000008 -#define AOFF_mm_segments 0x000000f8 +#define AOFF_mm_segments 0x00000108 #define ASIZ_mm_segments 0x00000008 -#define ASIZ_mm 0x00000100 +#define ASIZ_mm 0x00000110 #define AOFF_thread_ksp 0x00000000 #define ASIZ_thread_ksp 0x00000008 #define AOFF_thread_wstate 0x00000008 diff -u --recursive --new-file v2.3.46/linux/include/asm-sparc64/floppy.h linux/include/asm-sparc64/floppy.h --- v2.3.46/linux/include/asm-sparc64/floppy.h Sun Feb 13 19:29:04 2000 +++ linux/include/asm-sparc64/floppy.h Fri Feb 18 15:07:20 2000 @@ -1,4 +1,4 @@ -/* $Id: floppy.h,v 1.26 2000/02/12 23:32:35 davem Exp $ +/* $Id: floppy.h,v 1.28 2000/02/18 13:50:54 davem Exp $ * asm-sparc64/floppy.h: Sparc specific parts of the Floppy driver. * * Copyright (C) 1996 David S. Miller (davem@caip.rutgers.edu) @@ -273,7 +273,7 @@ static struct pci_dev *sun_pci_ebus_dev; static int sun_pci_broken_drive = -1; static unsigned int sun_pci_dma_addr = -1U; -static int sun_pci_dma_len; +static int sun_pci_dma_len, sun_pci_dma_direction; extern void floppy_interrupt(int irq, void *dev_id, struct pt_regs *regs); @@ -369,7 +369,8 @@ if (sun_pci_dma_addr != -1U) pci_unmap_single(sun_pci_ebus_dev, sun_pci_dma_addr, - sun_pci_dma_len); + sun_pci_dma_len, + sun_pci_dma_direction); sun_pci_dma_addr = -1U; } @@ -388,10 +389,13 @@ * For EBus WRITE means to system memory, which is * READ for us. */ - if (mode == DMA_MODE_WRITE) + if (mode == DMA_MODE_WRITE) { dcsr &= ~(EBUS_DCSR_WRITE); - else + sun_pci_dma_direction = PCI_DMA_TODEVICE; + } else { dcsr |= EBUS_DCSR_WRITE; + sun_pci_dma_direction = PCI_DMA_FROMDEVICE; + } writel(dcsr, &sun_pci_fd_ebus_dma->dcsr); } @@ -407,7 +411,8 @@ addr = sun_pci_dma_addr = pci_map_single(sun_pci_ebus_dev, buffer, - sun_pci_dma_len); + sun_pci_dma_len, + sun_pci_dma_direction); writel(addr, &sun_pci_fd_ebus_dma->dacr); } @@ -560,12 +565,9 @@ #endif /* CONFIG_PCI */ -static struct linux_prom_registers fd_regs[2]; - static unsigned long __init sun_floppy_init(void) { char state[128]; - int fd_node, num_regs; struct sbus_bus *bus; struct sbus_dev *sdev = NULL; static int initialized = 0; @@ -714,21 +716,19 @@ return 0; #endif } - fd_node = sdev->prom_node; - prom_getproperty(fd_node, "status", state, sizeof(state)); + prom_getproperty(sdev->prom_node, "status", state, sizeof(state)); if(!strncmp(state, "disabled", 8)) return 0; - num_regs = prom_getproperty(fd_node, "reg", (char *) fd_regs, - sizeof(fd_regs)); - num_regs = (num_regs / sizeof(fd_regs[0])); /* - * We cannot do sparc_alloc_io here: it does request_region, + * We cannot do sbus_ioremap here: it does request_region, * which the generic floppy driver tries to do once again. + * But we must use the sdev resource values as they have + * had parent ranges applied. */ sun_fdc = (struct sun_flpy_controller *) - ((unsigned long)fd_regs[0].phys_addr + - (((unsigned long)fd_regs[0].which_io) << 32UL)); + (sdev->resource[0].start + + ((sdev->resource[0].flags & 0x1ffUL) << 32UL)); /* Last minute sanity check... */ if(sbus_readb(&sun_fdc->status1_82077) == 0xff) { diff -u --recursive --new-file v2.3.46/linux/include/asm-sparc64/io.h linux/include/asm-sparc64/io.h --- v2.3.46/linux/include/asm-sparc64/io.h Thu Feb 10 17:11:21 2000 +++ linux/include/asm-sparc64/io.h Thu Feb 17 09:26:31 2000 @@ -1,4 +1,4 @@ -/* $Id: io.h,v 1.31 2000/02/08 05:11:38 jj Exp $ */ +/* $Id: io.h,v 1.32 2000/02/15 10:04:54 jj Exp $ */ #ifndef __SPARC64_IO_H #define __SPARC64_IO_H @@ -82,6 +82,10 @@ #define inb_p inb #define outb_p outb +#define inw_p inw +#define outw_p outw +#define inl_p inl +#define outl_p outl extern void outsb(unsigned long addr, const void *src, unsigned long count); extern void outsw(unsigned long addr, const void *src, unsigned long count); diff -u --recursive --new-file v2.3.46/linux/include/asm-sparc64/page.h linux/include/asm-sparc64/page.h --- v2.3.46/linux/include/asm-sparc64/page.h Wed Feb 16 17:03:52 2000 +++ linux/include/asm-sparc64/page.h Thu Feb 17 09:26:31 2000 @@ -1,4 +1,4 @@ -/* $Id: page.h,v 1.29 1999/12/09 10:32:43 davem Exp $ */ +/* $Id: page.h,v 1.30 2000/02/16 07:34:54 davem Exp $ */ #ifndef _SPARC64_PAGE_H #define _SPARC64_PAGE_H diff -u --recursive --new-file v2.3.46/linux/include/asm-sparc64/pbm.h linux/include/asm-sparc64/pbm.h --- v2.3.46/linux/include/asm-sparc64/pbm.h Wed Dec 29 13:13:21 1999 +++ linux/include/asm-sparc64/pbm.h Fri Feb 18 15:07:20 2000 @@ -1,4 +1,4 @@ -/* $Id: pbm.h,v 1.19 1999/12/17 12:32:13 jj Exp $ +/* $Id: pbm.h,v 1.20 2000/02/18 13:50:55 davem Exp $ * pbm.h: UltraSparc PCI controller software state. * * Copyright (C) 1997, 1998, 1999 David S. Miller (davem@redhat.com) @@ -69,6 +69,18 @@ * these counters. You have been duly warned. -DaveM */ u16 lowest_free[PBM_NCLUSTERS]; + + /* Here a PCI controller driver describes the areas of + * PCI memory space where DMA to/from physical memory + * are addressed. Drivers interrogate the PCI layer + * if their device has addressing limitations. They + * do so via pci_dma_supported, and pass in a mask of + * DMA address bits their device can actually drive. + * + * The test for being usable is: + * (device_mask & dma_addr_mask) == dma_addr_mask + */ + u32 dma_addr_mask; }; /* This describes a PCI bus module's streaming buffer. */ diff -u --recursive --new-file v2.3.46/linux/include/asm-sparc64/pci.h linux/include/asm-sparc64/pci.h --- v2.3.46/linux/include/asm-sparc64/pci.h Fri Jan 28 15:09:09 2000 +++ linux/include/asm-sparc64/pci.h Fri Feb 18 15:07:20 2000 @@ -40,7 +40,7 @@ * Once the device is given the dma address, the device owns this memory * until either pci_unmap_single or pci_dma_sync_single is performed. */ -extern dma_addr_t pci_map_single(struct pci_dev *hwdev, void *ptr, size_t size); +extern dma_addr_t pci_map_single(struct pci_dev *hwdev, void *ptr, size_t size, int direction); /* Unmap a single streaming mode DMA translation. The dma_addr and size * must match what was provided for in a previous pci_map_single call. All @@ -49,7 +49,7 @@ * After this call, reads by the cpu to the buffer are guarenteed to see * whatever the device wrote there. */ -extern void pci_unmap_single(struct pci_dev *hwdev, dma_addr_t dma_addr, size_t size); +extern void pci_unmap_single(struct pci_dev *hwdev, dma_addr_t dma_addr, size_t size, int direction); /* Map a set of buffers described by scatterlist in streaming * mode for DMA. This is the scather-gather version of the @@ -66,13 +66,13 @@ * Device ownership issues as mentioned above for pci_map_single are * the same here. */ -extern int pci_map_sg(struct pci_dev *hwdev, struct scatterlist *sg, int nents); +extern int pci_map_sg(struct pci_dev *hwdev, struct scatterlist *sg, int nents, int direction); /* Unmap a set of streaming mode DMA translations. * Again, cpu read rules concerning calls here are the same as for * pci_unmap_single() above. */ -extern void pci_unmap_sg(struct pci_dev *hwdev, struct scatterlist *sg, int nhwents); +extern void pci_unmap_sg(struct pci_dev *hwdev, struct scatterlist *sg, int nhwents, int direction); /* Make physical memory consistent for a single * streaming mode DMA translation after a transfer. @@ -83,7 +83,7 @@ * next point you give the PCI dma address back to the card, the * device again owns the buffer. */ -extern void pci_dma_sync_single(struct pci_dev *hwdev, dma_addr_t dma_handle, size_t size); +extern void pci_dma_sync_single(struct pci_dev *hwdev, dma_addr_t dma_handle, size_t size, int direction); /* Make physical memory consistent for a set of streaming * mode DMA translations after a transfer. @@ -91,7 +91,14 @@ * The same as pci_dma_sync_single but for a scatter-gather list, * same rules and usage. */ -extern void pci_dma_sync_sg(struct pci_dev *hwdev, struct scatterlist *sg, int nelems); +extern void pci_dma_sync_sg(struct pci_dev *hwdev, struct scatterlist *sg, int nelems, int direction); + +/* Return whether the given PCI device DMA address mask can + * be supported properly. For example, if your device can + * only drive the low 24-bits during PCI bus mastering, then + * you would pass 0x00ffffff as the mask to this function. + */ +extern int pci_dma_supported(struct pci_dev *hwdev, dma_addr_t mask); #endif /* __KERNEL__ */ diff -u --recursive --new-file v2.3.46/linux/include/asm-sparc64/pgtable.h linux/include/asm-sparc64/pgtable.h --- v2.3.46/linux/include/asm-sparc64/pgtable.h Wed Feb 16 17:03:52 2000 +++ linux/include/asm-sparc64/pgtable.h Thu Feb 17 09:26:31 2000 @@ -1,4 +1,4 @@ -/* $Id: pgtable.h,v 1.119 2000/02/14 02:53:44 davem Exp $ +/* $Id: pgtable.h,v 1.120 2000/02/16 07:34:54 davem Exp $ * pgtable.h: SpitFire page table operations. * * Copyright 1996,1997 David S. Miller (davem@caip.rutgers.edu) diff -u --recursive --new-file v2.3.46/linux/include/asm-sparc64/sbus.h linux/include/asm-sparc64/sbus.h --- v2.3.46/linux/include/asm-sparc64/sbus.h Tue Feb 1 01:35:44 2000 +++ linux/include/asm-sparc64/sbus.h Fri Feb 18 15:07:20 2000 @@ -1,4 +1,4 @@ -/* $Id: sbus.h,v 1.13 2000/01/28 13:43:14 jj Exp $ +/* $Id: sbus.h,v 1.14 2000/02/18 13:50:55 davem Exp $ * sbus.h: Defines for the Sun SBus. * * Copyright (C) 1996, 1999 David S. Miller (davem@redhat.com) @@ -98,14 +98,19 @@ extern void *sbus_alloc_consistent(struct sbus_dev *, size_t, dma_addr_t *dma_addrp); extern void sbus_free_consistent(struct sbus_dev *, size_t, void *, dma_addr_t); +#define SBUS_DMA_BIDIRECTIONAL 0 +#define SBUS_DMA_TODEVICE 1 +#define SBUS_DMA_FROMDEVICE 2 +#define SBUS_DMA_NONE 3 + /* All the rest use streaming mode mappings. */ -extern dma_addr_t sbus_map_single(struct sbus_dev *, void *, size_t); -extern void sbus_unmap_single(struct sbus_dev *, dma_addr_t, size_t); -extern int sbus_map_sg(struct sbus_dev *, struct scatterlist *, int); -extern void sbus_unmap_sg(struct sbus_dev *, struct scatterlist *, int); +extern dma_addr_t sbus_map_single(struct sbus_dev *, void *, size_t, int); +extern void sbus_unmap_single(struct sbus_dev *, dma_addr_t, size_t, int); +extern int sbus_map_sg(struct sbus_dev *, struct scatterlist *, int, int); +extern void sbus_unmap_sg(struct sbus_dev *, struct scatterlist *, int, int); /* Finally, allow explicit synchronization of streamable mappings. */ -extern void sbus_dma_sync_single(struct sbus_dev *, dma_addr_t, size_t); -extern void sbus_dma_sync_sg(struct sbus_dev *, struct scatterlist *, int); +extern void sbus_dma_sync_single(struct sbus_dev *, dma_addr_t, size_t, int); +extern void sbus_dma_sync_sg(struct sbus_dev *, struct scatterlist *, int, int); #endif /* !(_SPARC64_SBUS_H) */ diff -u --recursive --new-file v2.3.46/linux/include/linux/apm_bios.h linux/include/linux/apm_bios.h --- v2.3.46/linux/include/linux/apm_bios.h Mon Dec 20 18:48:22 1999 +++ linux/include/linux/apm_bios.h Sun Feb 20 20:37:09 2000 @@ -3,7 +3,7 @@ /* * Include file for the interface to an APM BIOS - * Copyright 1994-1999 Stephen Rothwell (sfr@linuxcare.com) + * Copyright 1994-2000 Stephen Rothwell (sfr@linuxcare.com) * * This program is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License as published by the @@ -89,32 +89,6 @@ #define APM_FUNC_TIMER_DISABLE 0 #define APM_FUNC_TIMER_ENABLE 1 #define APM_FUNC_TIMER_GET 2 - -/* - * Maximum number of events stored - */ -#define APM_MAX_EVENTS 20 - -/* - * The per-file APM data - */ -struct apm_bios_struct { - int magic; - struct apm_bios_struct * next; - int suser; - int suspends_pending; - int standbys_pending; - int suspends_read; - int standbys_read; - int event_head; - int event_tail; - apm_event_t events[APM_MAX_EVENTS]; -}; - -/* - * The magic number in apm_bios_struct - */ -#define APM_BIOS_MAGIC 0x4101 /* * in init/main.c diff -u --recursive --new-file v2.3.46/linux/include/linux/auto_fs.h linux/include/linux/auto_fs.h --- v2.3.46/linux/include/linux/auto_fs.h Thu Feb 10 17:11:21 2000 +++ linux/include/linux/auto_fs.h Sun Feb 20 20:48:22 2000 @@ -81,11 +81,4 @@ #define AUTOFS_IOC_SETTIMEOUT _IOWR(0x93,0x64,unsigned long) #define AUTOFS_IOC_EXPIRE _IOR(0x93,0x65,struct autofs_packet_expire) -#ifdef __KERNEL__ - -/* Init function */ -int init_autofs_fs(void); - -#endif /* __KERNEL__ */ - #endif /* _LINUX_AUTO_FS_H */ diff -u --recursive --new-file v2.3.46/linux/include/linux/blkdev.h linux/include/linux/blkdev.h --- v2.3.46/linux/include/linux/blkdev.h Wed Feb 16 17:03:52 2000 +++ linux/include/linux/blkdev.h Sun Feb 20 20:48:59 2000 @@ -129,7 +129,6 @@ extern void grok_partitions(struct gendisk *dev, int drive, unsigned minors, long size); extern void register_disk(struct gendisk *dev, kdev_t first, unsigned minors, struct block_device_operations *ops, long size); extern void generic_unplug_device(void * data); -extern void generic_plug_device (request_queue_t *q, kdev_t dev); extern void generic_make_request(int rw, struct buffer_head * bh); extern request_queue_t * blk_get_queue(kdev_t dev); diff -u --recursive --new-file v2.3.46/linux/include/linux/byteorder/big_endian.h linux/include/linux/byteorder/big_endian.h --- v2.3.46/linux/include/linux/byteorder/big_endian.h Fri Dec 5 05:40:24 1997 +++ linux/include/linux/byteorder/big_endian.h Thu Feb 17 09:20:13 2000 @@ -14,6 +14,18 @@ #define __constant_ntohl(x) ((__u32)(x)) #define __constant_htons(x) ((__u16)(x)) #define __constant_ntohs(x) ((__u16)(x)) +#define __constant_cpu_to_le64(x) ___swab64((x)) +#define __constant_le64_to_cpu(x) ___swab64((x)) +#define __constant_cpu_to_le32(x) ___swab32((x)) +#define __constant_le32_to_cpu(x) ___swab32((x)) +#define __constant_cpu_to_le16(x) ___swab16((x)) +#define __constant_le16_to_cpu(x) ___swab16((x)) +#define __constant_cpu_to_be64(x) ((__u64)(x)) +#define __constant_be64_to_cpu(x) ((__u64)(x)) +#define __constant_cpu_to_be32(x) ((__u32)(x)) +#define __constant_be32_to_cpu(x) ((__u32)(x)) +#define __constant_cpu_to_be16(x) ((__u16)(x)) +#define __constant_be16_to_cpu(x) ((__u16)(x)) #define __cpu_to_le64(x) __swab64((x)) #define __le64_to_cpu(x) __swab64((x)) #define __cpu_to_le32(x) __swab32((x)) diff -u --recursive --new-file v2.3.46/linux/include/linux/byteorder/little_endian.h linux/include/linux/byteorder/little_endian.h --- v2.3.46/linux/include/linux/byteorder/little_endian.h Tue Sep 1 11:49:36 1998 +++ linux/include/linux/byteorder/little_endian.h Thu Feb 17 09:20:13 2000 @@ -14,6 +14,18 @@ #define __constant_ntohl(x) ___swab32((x)) #define __constant_htons(x) ___swab16((x)) #define __constant_ntohs(x) ___swab16((x)) +#define __constant_cpu_to_le64(x) ((__u64)(x)) +#define __constant_le64_to_cpu(x) ((__u64)(x)) +#define __constant_cpu_to_le32(x) ((__u32)(x)) +#define __constant_le32_to_cpu(x) ((__u32)(x)) +#define __constant_cpu_to_le16(x) ((__u16)(x)) +#define __constant_le16_to_cpu(x) ((__u16)(x)) +#define __constant_cpu_to_be64(x) ___swab64((x)) +#define __constant_be64_to_cpu(x) ___swab64((x)) +#define __constant_cpu_to_be32(x) ___swab32((x)) +#define __constant_be32_to_cpu(x) ___swab32((x)) +#define __constant_cpu_to_be16(x) ___swab16((x)) +#define __constant_be16_to_cpu(x) ___swab16((x)) #define __cpu_to_le64(x) ((__u64)(x)) #define __le64_to_cpu(x) ((__u64)(x)) #define __cpu_to_le32(x) ((__u32)(x)) diff -u --recursive --new-file v2.3.46/linux/include/linux/byteorder/pdp_endian.h linux/include/linux/byteorder/pdp_endian.h --- v2.3.46/linux/include/linux/byteorder/pdp_endian.h Mon Jan 12 19:47:22 1998 +++ linux/include/linux/byteorder/pdp_endian.h Thu Feb 17 09:20:13 2000 @@ -34,6 +34,18 @@ #define __constant_ntohl(x) ___swahb32((x)) #define __constant_htons(x) ___swab16((x)) #define __constant_ntohs(x) ___swab16((x)) +#define __constant_cpu_to_le64(x) I DON'T KNOW +#define __constant_le64_to_cpu(x) I DON'T KNOW +#define __constant_cpu_to_le32(x) ___swahw32((x)) +#define __constant_le32_to_cpu(x) ___swahw32((x)) +#define __constant_cpu_to_le16(x) ((__u16)(x) +#define __constant_le16_to_cpu(x) ((__u16)(x) +#define __constant_cpu_to_be64(x) I DON'T KNOW +#define __constant_be64_to_cpu(x) I DON'T KNOW +#define __constant_cpu_to_be32(x) ___swahb32((x)) +#define __constant_be32_to_cpu(x) ___swahb32((x)) +#define __constant_cpu_to_be16(x) ___swab16((x)) +#define __constant_be16_to_cpu(x) ___swab16((x)) #define __cpu_to_le64(x) I DON'T KNOW #define __le64_to_cpu(x) I DON'T KNOW #define __cpu_to_le32(x) ___swahw32((x)) diff -u --recursive --new-file v2.3.46/linux/include/linux/dcache.h linux/include/linux/dcache.h --- v2.3.46/linux/include/linux/dcache.h Fri Jan 7 19:13:23 2000 +++ linux/include/linux/dcache.h Sun Feb 20 20:41:00 2000 @@ -98,6 +98,12 @@ * renamed" and has to be * deleted on the last dput() */ +#define DCACHE_NFSD_DISCONNECTED 0x0004 /* This dentry is not currently connected to the + * dcache tree. Its parent will either be itself, + * or will have this flag as well. + * If this dentry points to a directory, then + * s_nfsd_free_path semaphore will be down + */ /* * d_drop() unhashes the entry from the parent diff -u --recursive --new-file v2.3.46/linux/include/linux/fs.h linux/include/linux/fs.h --- v2.3.46/linux/include/linux/fs.h Wed Feb 16 17:03:52 2000 +++ linux/include/linux/fs.h Sun Feb 20 20:47:42 2000 @@ -435,6 +435,7 @@ #define I_DIRTY 1 #define I_LOCK 2 #define I_FREEING 4 +#define I_CLEAR 8 extern void __mark_inode_dirty(struct inode *); static inline void mark_inode_dirty(struct inode *inode) @@ -614,6 +615,15 @@ * even looking at it. You had been warned. */ struct semaphore s_vfs_rename_sem; /* Kludge */ + + /* The next field is used by knfsd when converting a (inode number based) + * file handle into a dentry. As it builds a path in the dcache tree from + * the bottom up, there may for a time be a subpath of dentrys which is not + * connected to the main tree. This semaphore ensure that there is only ever + * one such free path per filesystem. Note that unconnected files (or other + * non-directories) are allowed, but not unconnected diretories. + */ + struct semaphore s_nfsd_free_path_sem; }; /* @@ -676,6 +686,10 @@ int (*revalidate) (struct dentry *); }; +/* + * NOTE: write_inode, delete_inode, clear_inode, put_inode can be called + * without the big kernel lock held in all filesystems. + */ struct super_operations { void (*read_inode) (struct inode *); void (*write_inode) (struct inode *); diff -u --recursive --new-file v2.3.46/linux/include/linux/ide.h linux/include/linux/ide.h --- v2.3.46/linux/include/linux/ide.h Wed Feb 16 17:03:52 2000 +++ linux/include/linux/ide.h Sun Feb 20 20:52:08 2000 @@ -157,11 +157,11 @@ * Timeouts for various operations: */ #define WAIT_DRQ (5*HZ/100) /* 50msec - spec allows up to 20ms */ -#ifdef CONFIG_APM +#if defined(CONFIG_APM) || defined(CONFIG_APM_MODULE) #define WAIT_READY (5*HZ) /* 5sec - some laptops are very slow */ #else #define WAIT_READY (3*HZ/100) /* 30msec - should be instantaneous */ -#endif /* CONFIG_APM */ +#endif /* CONFIG_APM || CONFIG_APM_MODULE */ #define WAIT_PIDENTIFY (10*HZ) /* 10sec - should be less than 3ms (?) if all ATAPI CD is closed at boot */ #define WAIT_WORSTCASE (30*HZ) /* 30sec - worst case when spinning up */ @@ -379,6 +379,7 @@ u32 dmatable_dma; /* dma physical region descriptor table (dma view) */ struct scatterlist *sg_table; /* Scatter-gather list used to build the above */ int sg_nents; /* Current number of entries in it */ + int sg_dma_direction; /* dma transfer direction */ struct hwif_s *mate; /* other hwif from same PCI chip */ unsigned long dma_base; /* base addr for dma ports */ unsigned dma_extra; /* extra addr for dma ports */ diff -u --recursive --new-file v2.3.46/linux/include/linux/if_bridge.h linux/include/linux/if_bridge.h --- v2.3.46/linux/include/linux/if_bridge.h Wed Dec 31 16:00:00 1969 +++ linux/include/linux/if_bridge.h Sun Feb 20 20:49:04 2000 @@ -0,0 +1,109 @@ +/* + * Linux ethernet bridge + * + * Authors: + * Lennert Buytenhek + * + * $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 -u --recursive --new-file v2.3.46/linux/include/linux/input.h linux/include/linux/input.h --- v2.3.46/linux/include/linux/input.h Sat Feb 12 11:22:11 2000 +++ linux/include/linux/input.h Fri Feb 18 10:33:47 2000 @@ -234,12 +234,11 @@ #define KEY_RECORD 167 #define KEY_REWIND 168 #define KEY_PHONE 169 -#define KEY_CALENDAR 170 -#define KEY_NOTEPAD 171 -#define KEY_PROG3 172 -#define KEY_PRINT 173 -#define KEY_SOUND 174 -#define KEY_FULLSCREEN 175 +#define KEY_CONFIG 171 +#define KEY_HOMEPAGE 172 +#define KEY_REFRESH 173 +#define KEY_EXIT 174 +#define KEY_MOVE 175 #define KEY_UNKNOWN 180 diff -u --recursive --new-file v2.3.46/linux/include/linux/irq.h linux/include/linux/irq.h --- v2.3.46/linux/include/linux/irq.h Tue Dec 7 09:32:51 1999 +++ linux/include/linux/irq.h Sun Feb 20 20:50:18 2000 @@ -11,6 +11,7 @@ #define IRQ_REPLAY 8 /* IRQ has been replayed but not acked yet */ #define IRQ_AUTODETECT 16 /* IRQ is being autodetected */ #define IRQ_WAITING 32 /* IRQ not yet seen - for autodetection */ +#define IRQ_LEVEL 64 /* IRQ level triggered */ /* * Interrupt controller descriptor. This is all we need diff -u --recursive --new-file v2.3.46/linux/include/linux/lists.h linux/include/linux/lists.h --- v2.3.46/linux/include/linux/lists.h Mon Mar 30 00:21:41 1998 +++ linux/include/linux/lists.h Sun Feb 20 14:14:16 2000 @@ -48,7 +48,7 @@ #define QUEUE_FIRST(head, listnam) (head)->DLIST_NEXT(listnam) #define QUEUE_LAST(head, listnam) (head)->DLIST_PREV(listnam) -#define QUEUE_EMPTY(head, listnam) \ +#define QUEUE_IS_EMPTY(head, listnam) \ ((QUEUE_FIRST(head, listnam) == QUEUE_LAST(head, listnam)) && \ ((u_long)QUEUE_FIRST(head, listnam) == (u_long)head)) diff -u --recursive --new-file v2.3.46/linux/include/linux/lockd/debug.h linux/include/linux/lockd/debug.h --- v2.3.46/linux/include/linux/lockd/debug.h Wed Aug 18 16:44:09 1999 +++ linux/include/linux/lockd/debug.h Sun Feb 20 20:48:18 2000 @@ -45,6 +45,7 @@ #define NLMDBG_CLNTSUBS 0x0020 #define NLMDBG_SVCSUBS 0x0040 #define NLMDBG_HOSTCACHE 0x0080 +#define NLMDBG_XDR 0x0100 #define NLMDBG_ALL 0x7fff diff -u --recursive --new-file v2.3.46/linux/include/linux/lockd/lockd.h linux/include/linux/lockd/lockd.h --- v2.3.46/linux/include/linux/lockd/lockd.h Wed Aug 18 16:44:13 1999 +++ linux/include/linux/lockd/lockd.h Sun Feb 20 20:52:53 2000 @@ -11,12 +11,16 @@ #ifdef __KERNEL__ +#include #include #include #include #include #include #include +#ifdef CONFIG_LOCKD_V4 +#include +#endif #include /* @@ -112,6 +116,9 @@ */ extern struct rpc_program nlm_program; extern struct svc_procedure nlmsvc_procedures[]; +#ifdef CONFIG_LOCKD_V4 +extern struct svc_procedure nlmsvc_procedures4[]; +#endif extern unsigned long nlmsvc_grace_period; extern unsigned long nlmsvc_timeout; diff -u --recursive --new-file v2.3.46/linux/include/linux/lockd/nlm.h linux/include/linux/lockd/nlm.h --- v2.3.46/linux/include/linux/lockd/nlm.h Mon Apr 7 11:35:31 1997 +++ linux/include/linux/lockd/nlm.h Sun Feb 20 10:41:18 2000 @@ -9,6 +9,8 @@ #ifndef LINUX_LOCKD_NLM_H #define LINUX_LOCKD_NLM_H +#include + /* Maximum file offset in file_lock.fl_end */ #ifdef OFFSET_MAX # define NLM_OFFSET_MAX OFFSET_MAX @@ -18,11 +20,18 @@ /* Return states for NLM */ enum { - NLM_LCK_GRANTED = 0, - NLM_LCK_DENIED, - NLM_LCK_DENIED_NOLOCKS, - NLM_LCK_BLOCKED, - NLM_LCK_DENIED_GRACE_PERIOD, + NLM_LCK_GRANTED = 0, + NLM_LCK_DENIED = 1, + NLM_LCK_DENIED_NOLOCKS = 2, + NLM_LCK_BLOCKED = 3, + NLM_LCK_DENIED_GRACE_PERIOD = 4, +#ifdef CONFIG_LOCKD_V4 + NLM_DEADLCK = 5, + NLM_ROFS = 6, + NLM_STALE_FH = 7, + NLM_FBIG = 8, + NLM_FAILED = 9, +#endif }; #define NLM_PROGRAM 100021 diff -u --recursive --new-file v2.3.46/linux/include/linux/lockd/xdr4.h linux/include/linux/lockd/xdr4.h --- v2.3.46/linux/include/linux/lockd/xdr4.h Wed Dec 31 16:00:00 1969 +++ linux/include/linux/lockd/xdr4.h Sun Feb 20 20:48:19 2000 @@ -0,0 +1,41 @@ +/* + * linux/include/linux/lockd/xdr.h + * + * XDR types for the NLM protocol + * + * Copyright (C) 1996 Olaf Kirch + */ + +#ifndef LOCKD_XDR4_H +#define LOCKD_XDR4_H + +#include +#include +#include +#include + +/* error codes new to NLMv4 */ +extern u32 nlm4_deadlock, nlm4_rofs, nlm4_stale_fh, nlm4_fbig, nlm4_failed; + + +int nlm4svc_decode_testargs(struct svc_rqst *, u32 *, struct nlm_args *); +int nlm4svc_encode_testres(struct svc_rqst *, u32 *, struct nlm_res *); +int nlm4svc_decode_lockargs(struct svc_rqst *, u32 *, struct nlm_args *); +int nlm4svc_decode_cancargs(struct svc_rqst *, u32 *, struct nlm_args *); +int nlm4svc_decode_unlockargs(struct svc_rqst *, u32 *, struct nlm_args *); +int nlm4svc_encode_res(struct svc_rqst *, u32 *, struct nlm_res *); +int nlm4svc_decode_res(struct svc_rqst *, u32 *, struct nlm_res *); +int nlm4svc_encode_void(struct svc_rqst *, u32 *, void *); +int nlm4svc_decode_void(struct svc_rqst *, u32 *, void *); +int nlm4svc_decode_shareargs(struct svc_rqst *, u32 *, struct nlm_args *); +int nlm4svc_encode_shareres(struct svc_rqst *, u32 *, struct nlm_res *); +int nlm4svc_decode_notify(struct svc_rqst *, u32 *, struct nlm_args *); +int nlm4svc_decode_reboot(struct svc_rqst *, u32 *, struct nlm_reboot *); +/* +int nlmclt_encode_testargs(struct rpc_rqst *, u32 *, struct nlm_args *); +int nlmclt_encode_lockargs(struct rpc_rqst *, u32 *, struct nlm_args *); +int nlmclt_encode_cancargs(struct rpc_rqst *, u32 *, struct nlm_args *); +int nlmclt_encode_unlockargs(struct rpc_rqst *, u32 *, struct nlm_args *); + */ + +#endif /* LOCKD_XDR4_H */ diff -u --recursive --new-file v2.3.46/linux/include/linux/lvm.h linux/include/linux/lvm.h --- v2.3.46/linux/include/linux/lvm.h Wed Dec 31 16:00:00 1969 +++ linux/include/linux/lvm.h Thu Feb 17 16:13:05 2000 @@ -0,0 +1,829 @@ +/* + * kernel/lvm.h + * + * Copyright (C) 1997 - 2000 Heinz Mauelshagen, Germany + * + * February-November 1997 + * May-July 1998 + * January-March,July,September,October,Dezember 1999 + * January 2000 + * + * lvm is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2, or (at your option) + * any later version. + * + * lvm is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with GNU CC; see the file COPYING. If not, write to + * the Free Software Foundation, 59 Temple Place - Suite 330, + * Boston, MA 02111-1307, USA. + * + */ + +/* + * Changelog + * + * 10/10/1997 - beginning of new structure creation + * 12/05/1998 - incorporated structures from lvm_v1.h and deleted lvm_v1.h + * 07/06/1998 - avoided LVM_KMALLOC_MAX define by using vmalloc/vfree + * instead of kmalloc/kfree + * 01/07/1998 - fixed wrong LVM_MAX_SIZE + * 07/07/1998 - extended pe_t structure by ios member (for statistic) + * 02/08/1998 - changes for official char/block major numbers + * 07/08/1998 - avoided init_module() and cleanup_module() to be static + * 29/08/1998 - seprated core and disk structure type definitions + * 01/09/1998 - merged kernel integration version (mike) + * 20/01/1999 - added LVM_PE_DISK_OFFSET macro for use in + * vg_read_with_pv_and_lv(), pv_move_pe(), pv_show_pe_text()... + * 18/02/1999 - added definition of time_disk_t structure for; + * keeps time stamps on disk for nonatomic writes (future) + * 15/03/1999 - corrected LV() and VG() macro definition to use argument + * instead of minor + * 03/07/1999 - define for genhd.c name handling + * 23/07/1999 - implemented snapshot part + * 08/12/1999 - changed LVM_LV_SIZE_MAX macro to reflect current 1TB limit + * 01/01/2000 - extended lv_v2 core structure by wait_queue member + * 12/02/2000 - integrated Andrea Arcagnelli's snapshot work + * + */ + + +#ifndef _LVM_H_INCLUDE +#define _LVM_H_INCLUDE + +#define _LVM_H_VERSION "LVM 0.8final (15/2/2000)" + +/* + * preprocessor definitions + */ +/* if you like emergency reset code in the driver */ +#define LVM_TOTAL_RESET + +#define LVM_GET_INODE +#define LVM_HD_NAME + +/* lots of debugging output (see driver source) + #define DEBUG_LVM_GET_INFO + #define DEBUG + #define DEBUG_MAP + #define DEBUG_MAP_SIZE + #define DEBUG_IOCTL + #define DEBUG_READ + #define DEBUG_GENDISK + #define DEBUG_VG_CREATE + #define DEBUG_LVM_BLK_OPEN + #define DEBUG_KFREE + */ + +#include + +#ifndef __KERNEL__ +#define __KERNEL__ +#include +#undef __KERNEL__ +#else +#include +#endif + +#include + +#if LINUX_VERSION_CODE >= KERNEL_VERSION ( 2, 3 ,0) +#include +#else +#include +#endif + +#include +#include + +#if !defined ( LVM_BLK_MAJOR) || !defined ( LVM_CHAR_MAJOR) +#error Bad include/linux/major.h - LVM MAJOR undefined +#endif + + +#define LVM_STRUCT_VERSION 1 /* structure version */ + +#ifndef min +#define min(a,b) (((a)<(b))?(a):(b)) +#endif +#ifndef max +#define max(a,b) (((a)>(b))?(a):(b)) +#endif + +/* set the default structure version */ +#if ( LVM_STRUCT_VERSION == 1) +#define pv_t pv_v1_t +#define lv_t lv_v2_t +#define vg_t vg_v1_t +#define pv_disk_t pv_disk_v1_t +#define lv_disk_t lv_disk_v1_t +#define vg_disk_t vg_disk_v1_t +#define lv_exception_t lv_v2_exception_t +#endif + + +/* + * i/o protocoll version + * + * defined here for the driver and defined seperate in the + * user land LVM parts + * + */ +#define LVM_DRIVER_IOP_VERSION 6 + +#define LVM_NAME "lvm" + +/* + * VG/LV indexing macros + */ +/* character minor maps directly to volume group */ +#define VG_CHR(a) ( a) + +/* block minor indexes into a volume group/logical volume indirection table */ +#define VG_BLK(a) ( vg_lv_map[a].vg_number) +#define LV_BLK(a) ( vg_lv_map[a].lv_number) + +/* + * absolute limits for VGs, PVs per VG and LVs per VG + */ +#define ABS_MAX_VG 99 +#define ABS_MAX_PV 256 +#define ABS_MAX_LV 256 /* caused by 8 bit minor */ + +#define MAX_VG ABS_MAX_VG +#define MAX_LV ABS_MAX_LV +#define MAX_PV ABS_MAX_PV + +#if ( MAX_VG > ABS_MAX_VG) +#undef MAX_VG +#define MAX_VG ABS_MAX_VG +#endif + +#if ( MAX_LV > ABS_MAX_LV) +#undef MAX_LV +#define MAX_LV ABS_MAX_LV +#endif + + +/* + * VGDA: default disk spaces and offsets + * + * there's space after the structures for later extensions. + * + * offset what size + * --------------- ---------------------------------- ------------ + * 0 physical volume structure ~500 byte + * + * 1K volume group structure ~200 byte + * + * 5K time stamp structure ~ + * + * 6K namelist of physical volumes 128 byte each + * + * 6k + n * 128byte n logical volume structures ~300 byte each + * + * + m * 328byte m physical extent alloc. structs 4 byte each + * + * End of disk - first physical extent typical 4 megabyte + * PE total * + * PE size + * + * + */ + +/* DONT TOUCH THESE !!! */ +/* base of PV structure in disk partition */ +#define LVM_PV_DISK_BASE 0L + +/* size reserved for PV structure on disk */ +#define LVM_PV_DISK_SIZE 1024L + +/* base of VG structure in disk partition */ +#define LVM_VG_DISK_BASE LVM_PV_DISK_SIZE + +/* size reserved for VG structure */ +#define LVM_VG_DISK_SIZE ( 9 * 512L) + +/* size reserved for timekeeping */ +#define LVM_TIMESTAMP_DISK_BASE ( LVM_VG_DISK_BASE + LVM_VG_DISK_SIZE) +#define LVM_TIMESTAMP_DISK_SIZE 512L /* reserved for timekeeping */ + +/* name list of physical volumes on disk */ +#define LVM_PV_NAMELIST_DISK_BASE ( LVM_TIMESTAMP_DISK_BASE + \ + LVM_TIMESTAMP_DISK_SIZE) + +/* now for the dynamically calculated parts of the VGDA */ +#define LVM_LV_DISK_OFFSET(a, b) ( (a)->lv_on_disk.base + sizeof ( lv_t) * b) +#define LVM_DISK_SIZE(pv) ( (pv)->pe_on_disk.base + \ + (pv)->pe_on_disk.size) +#define LVM_PE_DISK_OFFSET(pe, pv) ( pe * pv->pe_size + \ + ( LVM_DISK_SIZE ( pv) / SECTOR_SIZE)) +#define LVM_PE_ON_DISK_BASE(pv) \ + { int rest; \ + pv->pe_on_disk.base = pv->lv_on_disk.base + pv->lv_on_disk.size; \ + if ( ( rest = pv->pe_on_disk.base % SECTOR_SIZE) != 0) \ + pv->pe_on_disk.base += ( SECTOR_SIZE - rest); \ + } +/* END default disk spaces and offsets for PVs */ + + +/* + * LVM_PE_T_MAX corresponds to: + * + * 8KB PE size can map a ~512 MB logical volume at the cost of 1MB memory, + * + * 128MB PE size can map a 8TB logical volume at the same cost of memory. + * + * Default PE size of 4 MB gives a maximum logical volume size of 256 GB. + * + * Maximum PE size of 16GB gives a maximum logical volume size of 1024 TB. + * + * AFAIK, the actual kernels limit this to 1 TB. + * + * Should be a sufficient spectrum ;*) + */ + +/* This is the usable size of disk_pe_t.le_num !!! v v */ +#define LVM_PE_T_MAX ( ( 1 << ( sizeof ( uint16_t) * 8)) - 2) + +#define LVM_LV_SIZE_MAX(a) ( ( long long) LVM_PE_T_MAX * (a)->pe_size > ( long long) 2*1024*1024*1024 ? ( long long) 2*1024*1024*1024 : ( long long) LVM_PE_T_MAX * (a)->pe_size) +#define LVM_MIN_PE_SIZE ( 8L * 2) /* 8 KB in sectors */ +#define LVM_MAX_PE_SIZE ( 16L * 1024L * 1024L * 2) /* 16GB in sectors */ +#define LVM_DEFAULT_PE_SIZE ( 4096L * 2) /* 4 MB in sectors */ +#define LVM_DEFAULT_STRIPE_SIZE 16L /* 16 KB */ +#define LVM_MIN_STRIPE_SIZE ( PAGE_SIZE>>9) /* PAGESIZE in sectors */ +#define LVM_MAX_STRIPE_SIZE ( 512L * 2) /* 512 KB in sectors */ +#define LVM_MAX_STRIPES 128 /* max # of stripes */ +#define LVM_MAX_SIZE ( 1024LU * 1024 * 1024 * 2) /* 1TB[sectors] */ +#define LVM_MAX_MIRRORS 2 /* future use */ +#define LVM_MIN_READ_AHEAD 2 /* minimum read ahead sectors */ +#define LVM_MAX_READ_AHEAD 120 /* maximum read ahead sectors */ +#define LVM_MAX_LV_IO_TIMEOUT 60 /* seconds I/O timeout (future use) */ +#define LVM_PARTITION 0xfe /* LVM partition id */ +#define LVM_NEW_PARTITION 0x8e /* new LVM partition id (10/09/1999) */ +#define LVM_PE_SIZE_PV_SIZE_REL 5 /* max relation PV size and PE size */ + +#define LVM_SNAPSHOT_MAX_CHUNK 1024 /* 1024 KB */ +#define LVM_SNAPSHOT_DEF_CHUNK 64 /* 64 KB */ +#define LVM_SNAPSHOT_MIN_CHUNK 1 /* 1 KB */ + +#define UNDEF -1 +#define FALSE 0 +#define TRUE 1 + + +/* + * ioctls + */ +/* volume group */ +#define VG_CREATE _IOW ( 0xfe, 0x00, 1) +#define VG_REMOVE _IOW ( 0xfe, 0x01, 1) + +#define VG_EXTEND _IOW ( 0xfe, 0x03, 1) +#define VG_REDUCE _IOW ( 0xfe, 0x04, 1) + +#define VG_STATUS _IOWR ( 0xfe, 0x05, 1) +#define VG_STATUS_GET_COUNT _IOWR ( 0xfe, 0x06, 1) +#define VG_STATUS_GET_NAMELIST _IOWR ( 0xfe, 0x07, 1) + +#define VG_SET_EXTENDABLE _IOW ( 0xfe, 0x08, 1) + + +/* logical volume */ +#define LV_CREATE _IOW ( 0xfe, 0x20, 1) +#define LV_REMOVE _IOW ( 0xfe, 0x21, 1) + +#define LV_ACTIVATE _IO ( 0xfe, 0x22) +#define LV_DEACTIVATE _IO ( 0xfe, 0x23) + +#define LV_EXTEND _IOW ( 0xfe, 0x24, 1) +#define LV_REDUCE _IOW ( 0xfe, 0x25, 1) + +#define LV_STATUS_BYNAME _IOWR ( 0xfe, 0x26, 1) +#define LV_STATUS_BYINDEX _IOWR ( 0xfe, 0x27, 1) + +#define LV_SET_ACCESS _IOW ( 0xfe, 0x28, 1) +#define LV_SET_ALLOCATION _IOW ( 0xfe, 0x29, 1) +#define LV_SET_STATUS _IOW ( 0xfe, 0x2a, 1) + +#define LE_REMAP _IOW ( 0xfe, 0x2b, 1) + + +/* physical volume */ +#define PV_STATUS _IOWR ( 0xfe, 0x40, 1) +#define PV_CHANGE _IOWR ( 0xfe, 0x41, 1) +#define PV_FLUSH _IOW ( 0xfe, 0x42, 1) + +/* physical extent */ +#define PE_LOCK_UNLOCK _IOW ( 0xfe, 0x50, 1) + +/* i/o protocol version */ +#define LVM_GET_IOP_VERSION _IOR ( 0xfe, 0x98, 1) + +#ifdef LVM_TOTAL_RESET +/* special reset function for testing purposes */ +#define LVM_RESET _IO ( 0xfe, 0x99) +#endif + +/* lock the logical volume manager */ +#define LVM_LOCK_LVM _IO ( 0xfe, 0x100) +/* END ioctls */ + + +/* + * Status flags + */ +/* volume group */ +#define VG_ACTIVE 0x01 /* vg_status */ +#define VG_EXPORTED 0x02 /* " */ +#define VG_EXTENDABLE 0x04 /* " */ + +#define VG_READ 0x01 /* vg_access */ +#define VG_WRITE 0x02 /* " */ + +/* logical volume */ +#define LV_ACTIVE 0x01 /* lv_status */ +#define LV_SPINDOWN 0x02 /* " */ + +#define LV_READ 0x01 /* lv_access */ +#define LV_WRITE 0x02 /* " */ +#define LV_SNAPSHOT 0x04 /* " */ +#define LV_SNAPSHOT_ORG 0x08 /* " */ + +#define LV_BADBLOCK_ON 0x01 /* lv_badblock */ + +#define LV_STRICT 0x01 /* lv_allocation */ +#define LV_CONTIGUOUS 0x02 /* " */ + +/* physical volume */ +#define PV_ACTIVE 0x01 /* pv_status */ +#define PV_ALLOCATABLE 0x02 /* pv_allocatable */ + + +/* + * Structure definitions core/disk follow + * + * conditional conversion takes place on big endian architectures + * in functions * pv_copy_*(), vg_copy_*() and lv_copy_*() + * + */ + +#define NAME_LEN 128 /* don't change!!! */ +#define UUID_LEN 16 /* don't change!!! */ + +/* remap physical sector/rdev pairs */ +typedef struct +{ + struct list_head hash; + ulong rsector_org; + kdev_t rdev_org; + ulong rsector_new; + kdev_t rdev_new; +} lv_block_exception_t; + + +/* disk stored pe information */ +typedef struct + { + uint16_t lv_num; + uint16_t le_num; + } +disk_pe_t; + +/* disk stored PV, VG, LV and PE size and offset information */ +typedef struct + { + uint32_t base; + uint32_t size; + } +lvm_disk_data_t; + + +/* + * Structure Physical Volume (PV) Version 1 + */ + +/* core */ +typedef struct + { + uint8_t id[2]; /* Identifier */ + uint16_t version; /* HM lvm version */ + lvm_disk_data_t pv_on_disk; + lvm_disk_data_t vg_on_disk; + lvm_disk_data_t pv_namelist_on_disk; + lvm_disk_data_t lv_on_disk; + lvm_disk_data_t pe_on_disk; + uint8_t pv_name[NAME_LEN]; + uint8_t vg_name[NAME_LEN]; + uint8_t system_id[NAME_LEN]; /* for vgexport/vgimport */ + kdev_t pv_dev; + uint32_t pv_number; + uint32_t pv_status; + uint32_t pv_allocatable; + uint32_t pv_size; /* HM */ + uint32_t lv_cur; + uint32_t pe_size; + uint32_t pe_total; + uint32_t pe_allocated; + uint32_t pe_stale; /* for future use */ + + disk_pe_t *pe; /* HM */ + struct inode *inode; /* HM */ + } +pv_v1_t; + +/* disk */ +typedef struct + { + uint8_t id[2]; /* Identifier */ + uint16_t version; /* HM lvm version */ + lvm_disk_data_t pv_on_disk; + lvm_disk_data_t vg_on_disk; + lvm_disk_data_t pv_namelist_on_disk; + lvm_disk_data_t lv_on_disk; + lvm_disk_data_t pe_on_disk; + uint8_t pv_name[NAME_LEN]; + uint8_t vg_name[NAME_LEN]; + uint8_t system_id[NAME_LEN]; /* for vgexport/vgimport */ + uint32_t pv_major; + uint32_t pv_number; + uint32_t pv_status; + uint32_t pv_allocatable; + uint32_t pv_size; /* HM */ + uint32_t lv_cur; + uint32_t pe_size; + uint32_t pe_total; + uint32_t pe_allocated; + } +pv_disk_v1_t; + + +/* + * Structure Physical Volume (PV) Version 2 (future!) + */ + +typedef struct + { + uint8_t id[2]; /* Identifier */ + uint16_t version; /* HM lvm version */ + lvm_disk_data_t pv_on_disk; + lvm_disk_data_t vg_on_disk; + lvm_disk_data_t pv_uuid_on_disk; + lvm_disk_data_t lv_on_disk; + lvm_disk_data_t pe_on_disk; + uint8_t pv_name[NAME_LEN]; + uint8_t vg_name[NAME_LEN]; + uint8_t system_id[NAME_LEN]; /* for vgexport/vgimport */ + kdev_t pv_dev; + uint32_t pv_number; + uint32_t pv_status; + uint32_t pv_allocatable; + uint32_t pv_size; /* HM */ + uint32_t lv_cur; + uint32_t pe_size; + uint32_t pe_total; + uint32_t pe_allocated; + uint32_t pe_stale; /* for future use */ + disk_pe_t *pe; /* HM */ + struct inode *inode; /* HM */ + /* delta to version 1 starts here */ + uint8_t pv_uuid[UUID_LEN]; + uint32_t pv_atime; /* PV access time */ + uint32_t pv_ctime; /* PV creation time */ + uint32_t pv_mtime; /* PV modification time */ + } +pv_v2_t; + + +/* + * Structures for Logical Volume (LV) + */ + +/* core PE information */ +typedef struct + { + kdev_t dev; + uint32_t pe; /* to be changed if > 2TB */ + uint32_t reads; + uint32_t writes; + } +pe_t; + +typedef struct + { + uint8_t lv_name[NAME_LEN]; + kdev_t old_dev; + kdev_t new_dev; + ulong old_pe; + ulong new_pe; + } +le_remap_req_t; + + + +/* + * Structure Logical Volume (LV) Version 1 + */ + +/* disk */ +typedef struct + { + uint8_t lv_name[NAME_LEN]; + uint8_t vg_name[NAME_LEN]; + uint32_t lv_access; + uint32_t lv_status; + uint32_t lv_open; /* HM */ + uint32_t lv_dev; /* HM */ + uint32_t lv_number; /* HM */ + uint32_t lv_mirror_copies; /* for future use */ + uint32_t lv_recovery; /* " */ + uint32_t lv_schedule; /* " */ + uint32_t lv_size; + uint32_t dummy; + uint32_t lv_current_le; /* for future use */ + uint32_t lv_allocated_le; + uint32_t lv_stripes; + uint32_t lv_stripesize; + uint32_t lv_badblock; /* for future use */ + uint32_t lv_allocation; + uint32_t lv_io_timeout; /* for future use */ + uint32_t lv_read_ahead; /* HM, for future use */ + } +lv_disk_v1_t; + + +/* + * Structure Logical Volume (LV) Version 2 + */ + +/* core */ +typedef struct lv_v2 + { + uint8_t lv_name[NAME_LEN]; + uint8_t vg_name[NAME_LEN]; + uint32_t lv_access; + uint32_t lv_status; + uint32_t lv_open; /* HM */ + kdev_t lv_dev; /* HM */ + uint32_t lv_number; /* HM */ + uint32_t lv_mirror_copies; /* for future use */ + uint32_t lv_recovery; /* " */ + uint32_t lv_schedule; /* " */ + uint32_t lv_size; + pe_t *lv_current_pe; /* HM */ + uint32_t lv_current_le; /* for future use */ + uint32_t lv_allocated_le; + uint32_t lv_stripes; + uint32_t lv_stripesize; + uint32_t lv_badblock; /* for future use */ + uint32_t lv_allocation; + uint32_t lv_io_timeout; /* for future use */ + uint32_t lv_read_ahead; + + /* delta to version 1 starts here */ + struct lv_v2 *lv_snapshot_org; + struct lv_v2 *lv_snapshot_prev; + struct lv_v2 *lv_snapshot_next; + lv_block_exception_t *lv_block_exception; + uint32_t lv_remap_ptr; + uint32_t lv_remap_end; + uint32_t lv_chunk_size; + uint32_t lv_snapshot_minor; + struct kiobuf * lv_iobuf; + struct semaphore lv_snapshot_sem; + struct list_head * lv_snapshot_hash_table; + unsigned long lv_snapshot_hash_mask; +} lv_v2_t; + +/* disk */ +typedef struct + { + uint8_t lv_name[NAME_LEN]; + uint8_t vg_name[NAME_LEN]; + uint32_t lv_access; + uint32_t lv_status; + uint32_t lv_open; /* HM */ + uint32_t lv_dev; /* HM */ + uint32_t lv_number; /* HM */ + uint32_t lv_mirror_copies; /* for future use */ + uint32_t lv_recovery; /* " */ + uint32_t lv_schedule; /* " */ + uint32_t lv_size; + uint32_t dummy; + uint32_t lv_current_le; /* for future use */ + uint32_t lv_allocated_le; + uint32_t lv_stripes; + uint32_t lv_stripesize; + uint32_t lv_badblock; /* for future use */ + uint32_t lv_allocation; + uint32_t lv_io_timeout; /* for future use */ + uint32_t lv_read_ahead; /* HM, for future use */ + } +lv_disk_v2_t; + + +/* + * Structure Volume Group (VG) Version 1 + */ + +typedef struct + { + uint8_t vg_name[NAME_LEN]; /* volume group name */ + uint32_t vg_number; /* volume group number */ + uint32_t vg_access; /* read/write */ + uint32_t vg_status; /* active or not */ + uint32_t lv_max; /* maximum logical volumes */ + uint32_t lv_cur; /* current logical volumes */ + uint32_t lv_open; /* open logical volumes */ + uint32_t pv_max; /* maximum physical volumes */ + uint32_t pv_cur; /* current physical volumes FU */ + uint32_t pv_act; /* active physical volumes */ + uint32_t dummy; /* was obsolete max_pe_per_pv */ + uint32_t vgda; /* volume group descriptor arrays FU */ + uint32_t pe_size; /* physical extent size in sectors */ + uint32_t pe_total; /* total of physical extents */ + uint32_t pe_allocated; /* allocated physical extents */ + uint32_t pvg_total; /* physical volume groups FU */ + struct proc_dir_entry *proc; + pv_t *pv[ABS_MAX_PV + 1]; /* physical volume struct pointers */ + lv_t *lv[ABS_MAX_LV + 1]; /* logical volume struct pointers */ + } +vg_v1_t; + +typedef struct + { + uint8_t vg_name[NAME_LEN]; /* volume group name */ + uint32_t vg_number; /* volume group number */ + uint32_t vg_access; /* read/write */ + uint32_t vg_status; /* active or not */ + uint32_t lv_max; /* maximum logical volumes */ + uint32_t lv_cur; /* current logical volumes */ + uint32_t lv_open; /* open logical volumes */ + uint32_t pv_max; /* maximum physical volumes */ + uint32_t pv_cur; /* current physical volumes FU */ + uint32_t pv_act; /* active physical volumes */ + uint32_t dummy; + uint32_t vgda; /* volume group descriptor arrays FU */ + uint32_t pe_size; /* physical extent size in sectors */ + uint32_t pe_total; /* total of physical extents */ + uint32_t pe_allocated; /* allocated physical extents */ + uint32_t pvg_total; /* physical volume groups FU */ + } +vg_disk_v1_t; + +/* + * Structure Volume Group (VG) Version 2 + */ + +typedef struct + { + uint8_t vg_name[NAME_LEN]; /* volume group name */ + uint32_t vg_number; /* volume group number */ + uint32_t vg_access; /* read/write */ + uint32_t vg_status; /* active or not */ + uint32_t lv_max; /* maximum logical volumes */ + uint32_t lv_cur; /* current logical volumes */ + uint32_t lv_open; /* open logical volumes */ + uint32_t pv_max; /* maximum physical volumes */ + uint32_t pv_cur; /* current physical volumes FU */ + uint32_t pv_act; /* future: active physical volumes */ + uint32_t max_pe_per_pv; /* OBSOLETE maximum PE/PV */ + uint32_t vgda; /* volume group descriptor arrays FU */ + uint32_t pe_size; /* physical extent size in sectors */ + uint32_t pe_total; /* total of physical extents */ + uint32_t pe_allocated; /* allocated physical extents */ + uint32_t pvg_total; /* physical volume groups FU */ + struct proc_dir_entry *proc; + pv_t *pv[ABS_MAX_PV + 1]; /* physical volume struct pointers */ + lv_t *lv[ABS_MAX_LV + 1]; /* logical volume struct pointers */ + /* delta to version 1 starts here */ + uint8_t vg_uuid[UUID_LEN]; /* volume group UUID */ + time_t vg_atime; /* VG access time */ + time_t vg_ctime; /* VG creation time */ + time_t vg_mtime; /* VG modification time */ + } +vg_v2_t; + + +/* + * Timekeeping structure on disk (0.7 feature) + * + * Holds several timestamps for start/stop time of non + * atomic VGDA disk i/o operations + * + */ + +typedef struct + { + uint32_t seconds; /* seconds since the epoch */ + uint32_t jiffies; /* micro timer */ + } +lvm_time_t; + +#define TIMESTAMP_ID_SIZE 2 +typedef struct + { + uint8_t id[TIMESTAMP_ID_SIZE]; /* Identifier */ + lvm_time_t pv_vg_lv_pe_io_begin; + lvm_time_t pv_vg_lv_pe_io_end; + lvm_time_t pv_io_begin; + lvm_time_t pv_io_end; + lvm_time_t vg_io_begin; + lvm_time_t vg_io_end; + lvm_time_t lv_io_begin; + lvm_time_t lv_io_end; + lvm_time_t pe_io_begin; + lvm_time_t pe_io_end; + lvm_time_t pe_move_io_begin; + lvm_time_t pe_move_io_end; + uint8_t dummy[LVM_TIMESTAMP_DISK_SIZE - + TIMESTAMP_ID_SIZE - + 12 * sizeof (lvm_time_t)]; + /* ATTENTION ^^ */ + } +timestamp_disk_t; + +/* same on disk and in core so far */ +typedef timestamp_disk_t timestamp_t; + +/* function identifiers for timestamp actions */ +typedef enum + { + PV_VG_LV_PE_IO_BEGIN, + PV_VG_LV_PE_IO_END, + PV_IO_BEGIN, + PV_IO_END, + VG_IO_BEGIN, + VG_IO_END, + LV_IO_BEGIN, + LV_IO_END, + PE_IO_BEGIN, + PE_IO_END, + PE_MOVE_IO_BEGIN, + PE_MOVE_IO_END + } +ts_fct_id_t; + + +/* + * Request structures for ioctls + */ + +/* Request structure PV_STATUS */ +typedef struct + { + char pv_name[NAME_LEN]; + pv_t *pv; + } +pv_status_req_t, pv_change_req_t; + +/* Request structure PV_FLUSH */ +typedef struct + { + char pv_name[NAME_LEN]; + kdev_t pv_dev; + } +pv_flush_req_t; + + +/* Request structure PE_MOVE */ +typedef struct + { + enum + { + LOCK_PE, UNLOCK_PE + } + lock; + struct + { + kdev_t lv_dev; + kdev_t pv_dev; + uint32_t pv_offset; + } + data; + } +pe_lock_req_t; + + +/* Request structure LV_STATUS_BYNAME */ +typedef struct + { + char lv_name[NAME_LEN]; + lv_t *lv; + } +lv_status_byname_req_t, lv_req_t; + +/* Request structure LV_STATUS_BYINDEX */ +typedef struct + { + ulong lv_index; + lv_t *lv; + } +lv_status_byindex_req_t; + +#endif /* #ifndef _LVM_H_INCLUDE */ diff -u --recursive --new-file v2.3.46/linux/include/linux/major.h linux/include/linux/major.h --- v2.3.46/linux/include/linux/major.h Fri Jan 21 18:19:17 2000 +++ linux/include/linux/major.h Thu Feb 17 16:13:05 2000 @@ -83,6 +83,8 @@ #define IDE4_MAJOR 56 #define IDE5_MAJOR 57 +#define LVM_BLK_MAJOR 58 /* Logical Volume Manager */ + #define SCSI_DISK1_MAJOR 65 #define SCSI_DISK2_MAJOR 66 #define SCSI_DISK3_MAJOR 67 @@ -92,8 +94,6 @@ #define SCSI_DISK7_MAJOR 71 -#define LVM_BLK_MAJOR 58 /* Logical Volume Manager */ - #define COMPAQ_SMART2_MAJOR 72 #define COMPAQ_SMART2_MAJOR1 73 #define COMPAQ_SMART2_MAJOR2 74 @@ -103,15 +103,11 @@ #define COMPAQ_SMART2_MAJOR6 78 #define COMPAQ_SMART2_MAJOR7 79 -#define LVM_BLK_MAJOR 58 /* Logical Volume Manager */ - #define SPECIALIX_NORMAL_MAJOR 75 #define SPECIALIX_CALLOUT_MAJOR 76 #define DASD_MAJOR 94 /* Official assignations from Peter */ -#define LVM_CHAR_MAJOR 109 /* Logical Volume Manager */ - #define MDISK_MAJOR 95 /* Official assignations from Peter */ #define I2O_MAJOR 80 /* 80->87 */ @@ -124,6 +120,8 @@ #define AURORA_MAJOR 79 #define PHONE_MAJOR 100 + +#define LVM_CHAR_MAJOR 109 /* Logical Volume Manager */ #define RTF_MAJOR 150 #define RAW_MAJOR 162 diff -u --recursive --new-file v2.3.46/linux/include/linux/netdevice.h linux/include/linux/netdevice.h --- v2.3.46/linux/include/linux/netdevice.h Sun Feb 13 19:29:04 2000 +++ linux/include/linux/netdevice.h Sun Feb 20 20:48:57 2000 @@ -174,14 +174,17 @@ unsigned long hh_data[16/sizeof(unsigned long)]; }; +/* These flag bits are private to the generic network queueing + * layer, they may not be explicitly referenced by any other + * code. + */ + enum netdev_state_t { - LINK_STATE_XOFF=0, - LINK_STATE_DOWN, - LINK_STATE_START, - LINK_STATE_RXSEM, - LINK_STATE_TXSEM, - LINK_STATE_SCHED + __LINK_STATE_XOFF=0, + __LINK_STATE_START, + __LINK_STATE_PRESENT, + __LINK_STATE_SCHED }; @@ -313,9 +316,6 @@ /* Called after last user reference disappears. */ void (*destructor)(struct net_device *dev); - /* Bridge stuff */ - int bridge_port_id; - /* Pointers to interface service routines. */ int (*open)(struct net_device *dev); int (*stop)(struct net_device *dev); @@ -356,6 +356,9 @@ int (*neigh_setup)(struct net_device *dev, struct neigh_parms *); int (*accept_fastpath)(struct net_device *, struct dst_entry*); + /* bridge stuff */ + struct net_bridge_port *br_port; + #ifdef CONFIG_NET_FASTROUTE #define NETDEV_FASTROUTE_HMASK 0xF /* Semi-private data. Keep it at the end of device struct. */ @@ -431,7 +434,7 @@ extern __inline__ void __netif_schedule(struct net_device *dev) { - if (!test_and_set_bit(LINK_STATE_SCHED, &dev->state)) { + if (!test_and_set_bit(__LINK_STATE_SCHED, &dev->state)) { unsigned long flags; int cpu = smp_processor_id(); @@ -445,26 +448,59 @@ extern __inline__ void netif_schedule(struct net_device *dev) { - if (!test_bit(LINK_STATE_XOFF, &dev->state)) + if (!test_bit(__LINK_STATE_XOFF, &dev->state)) __netif_schedule(dev); } extern __inline__ void netif_start_queue(struct net_device *dev) { - clear_bit(LINK_STATE_XOFF, &dev->state); + clear_bit(__LINK_STATE_XOFF, &dev->state); } extern __inline__ void netif_wake_queue(struct net_device *dev) { - if (test_and_clear_bit(LINK_STATE_XOFF, &dev->state)) + if (test_and_clear_bit(__LINK_STATE_XOFF, &dev->state)) __netif_schedule(dev); } extern __inline__ void netif_stop_queue(struct net_device *dev) { - set_bit(LINK_STATE_XOFF, &dev->state); + set_bit(__LINK_STATE_XOFF, &dev->state); +} + +extern __inline__ int netif_queue_stopped(struct net_device *dev) +{ + return test_bit(__LINK_STATE_XOFF, &dev->state); +} + +extern __inline__ int netif_running(struct net_device *dev) +{ + return test_bit(__LINK_STATE_START, &dev->state); } +/* Hot-plugging. */ +extern __inline__ int netif_device_present(struct net_device *dev) +{ + return test_bit(__LINK_STATE_PRESENT, &dev->state); +} + +extern __inline__ void netif_device_detach(struct net_device *dev) +{ + if (test_and_clear_bit(__LINK_STATE_PRESENT, &dev->state) && + netif_running(dev)) + netif_stop_queue(dev); +} + +extern __inline__ void netif_device_attach(struct net_device *dev) +{ + if (test_and_set_bit(__LINK_STATE_PRESENT, &dev->state) && + netif_running(dev)) + netif_wake_queue(dev); +} + +/* Use this variant when it is known for sure that it + * is executing from interrupt context. + */ extern __inline__ void dev_kfree_skb_irq(struct sk_buff *skb) { if (atomic_dec_and_test(&skb->users)) { @@ -479,7 +515,18 @@ } } +/* Use this variant in places where it could be invoked + * either from interrupt or non-interrupt context. + */ +extern __inline__ void dev_kfree_skb_any(struct sk_buff *skb) +{ + if (in_irq()) + dev_kfree_skb_irq(skb); + else + dev_kfree_skb(skb); +} +extern void net_call_rx_atomic(void (*fn)(void)); #define HAVE_NETIF_RX 1 extern void netif_rx(struct sk_buff *skb); extern int dev_ioctl(unsigned int cmd, void *); diff -u --recursive --new-file v2.3.46/linux/include/linux/nfsd/xdr3.h linux/include/linux/nfsd/xdr3.h --- v2.3.46/linux/include/linux/nfsd/xdr3.h Tue Dec 14 01:27:24 1999 +++ linux/include/linux/nfsd/xdr3.h Sun Feb 20 20:48:14 2000 @@ -296,19 +296,5 @@ int nfs3svc_encode_entry_plus(struct readdir_cd *, const char *name, int namlen, off_t offset, ino_t ino); -#ifdef __KERNEL__ - -/* - * This is needed in nfs_readdir for encoding NFS3 directory cookies. - */ -static inline u32 * -enc64(u32 *p, u64 val) -{ - *p++ = htonl(val >> 32); - *p++ = htonl(val & 0xffffffff); - return p; -} - -#endif /* __KERNEL__ */ #endif /* _LINUX_NFSD_XDR3_H */ diff -u --recursive --new-file v2.3.46/linux/include/linux/pci.h linux/include/linux/pci.h --- v2.3.46/linux/include/linux/pci.h Thu Feb 10 17:11:22 2000 +++ linux/include/linux/pci.h Sun Feb 20 20:48:23 2000 @@ -286,6 +286,12 @@ #include #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 @@ -568,7 +574,39 @@ { return NULL; } extern inline void pci_set_master(struct pci_dev *dev) { } -extern inline int pci_enable_device(struct pci_dev *dev) { return 0; } +extern inline int pci_enable_device(struct pci_dev *dev) { return -EIO; } +extern inline int pci_module_init(struct pci_driver *drv) { return -ENODEV; } + +#else + +/* + * a helper function which helps ensure correct pci_driver + * setup and cleanup for commonly-encountered hotplug/modular cases + * + * This MUST stay in a header, as it checks for -DMODULE + */ +extern inline int pci_module_init(struct pci_driver *drv) +{ + int rc = pci_register_driver (drv); + + if (rc > 0) + return 0; + + /* iff CONFIG_HOTPLUG and built into kernel, we should + * leave the driver around for future hotplug events. + * For the module case, a hotplug daemon of some sort + * should load a module in response to an insert event. */ +#if defined(CONFIG_HOTPLUG) && !defined(MODULE) + if (rc == 0) + return 0; +#endif + + /* if we get here, we need to clean up pci driver instance + * and return some sort of error */ + pci_unregister_driver (drv); + + return -ENODEV; +} #endif /* !CONFIG_PCI */ diff -u --recursive --new-file v2.3.46/linux/include/linux/pci_ids.h linux/include/linux/pci_ids.h --- v2.3.46/linux/include/linux/pci_ids.h Sat Feb 12 11:22:11 2000 +++ linux/include/linux/pci_ids.h Sun Feb 20 08:48:45 2000 @@ -167,6 +167,8 @@ #define PCI_DEVICE_ID_ATI_RAGE128_RF 0x5246 #define PCI_DEVICE_ID_ATI_RAGE128_RK 0x524b #define PCI_DEVICE_ID_ATI_RAGE128_RL 0x524c +#define PCI_DEVICE_ID_ATI_RAGE128_PF 0x5046 +#define PCI_DEVICE_ID_ATI_RAGE128_PR 0x5052 #define PCI_VENDOR_ID_VLSI 0x1004 #define PCI_DEVICE_ID_VLSI_82C592 0x0005 diff -u --recursive --new-file v2.3.46/linux/include/linux/pm.h linux/include/linux/pm.h --- v2.3.46/linux/include/linux/pm.h Thu Feb 10 17:11:22 2000 +++ linux/include/linux/pm.h Sun Feb 20 20:47:37 2000 @@ -105,7 +105,7 @@ struct list_head entry; }; -#if defined(CONFIG_ACPI) || defined(CONFIG_APM) +#if defined(CONFIG_ACPI) || defined(CONFIG_APM) || defined(CONFIG_APM_MODULE) extern int pm_active; @@ -141,7 +141,7 @@ extern inline void pm_access(struct pm_dev *dev) {} extern inline void pm_dev_idle(struct pm_dev *dev) {} -#else // CONFIG_ACPI || CONFIG_APM +#else /* CONFIG_ACPI || CONFIG_APM || CONFIG_APM_MODULE */ #define PM_IS_ACTIVE() 0 @@ -169,11 +169,11 @@ extern inline void pm_access(struct pm_dev *dev) {} extern inline void pm_dev_idle(struct pm_dev *dev) {} -#endif // CONFIG_ACPI || CONFIG_APM +#endif /* CONFIG_ACPI || CONFIG_APM || CONFIG_APM_MODULE */ extern void (*pm_idle)(void); extern void (*pm_power_off)(void); -#endif // __KERNEL__ +#endif /* __KERNEL__ */ #endif /* _LINUX_PM_H */ diff -u --recursive --new-file v2.3.46/linux/include/linux/sched.h linux/include/linux/sched.h --- v2.3.46/linux/include/linux/sched.h Thu Feb 10 17:11:22 2000 +++ linux/include/linux/sched.h Sun Feb 20 20:47:49 2000 @@ -389,44 +389,45 @@ * INIT_TASK is used to set up the first task table, touch at * your own risk!. Base=0, limit=0x1fffff (=2MB) */ -#define INIT_TASK(name) \ -/* state etc */ { 0,0,0,KERNEL_DS,&default_exec_domain,0, \ -/* avg_slice */ 0, -1, \ -/* counter */ DEF_PRIORITY,DEF_PRIORITY,SCHED_OTHER, \ -/* mm */ NULL, &init_mm, \ -/* has_cpu */ 0,0, \ -/* run_list */ LIST_HEAD_INIT(init_task.run_list), \ -/* next_task */ &init_task,&init_task, \ -/* last_proc */ 0, \ -/* binfmt */ NULL, \ -/* ec,brk... */ 0,0,0,0,0,0, \ -/* pid etc.. */ 0,0,0,0,0, \ -/* proc links*/ &init_task,&init_task,NULL,NULL,NULL, \ -/* pidhash */ NULL, NULL, \ -/* chld wait */ __WAIT_QUEUE_HEAD_INITIALIZER(name.wait_chldexit), NULL, \ -/* timeout */ 0,0,0,0,0,0,0, \ -/* timer */ { NULL, NULL, 0, 0, it_real_fn }, \ -/* utime */ {0,0,0,0},0, \ -/* per CPU times */ {0, }, {0, }, \ -/* flt */ 0,0,0,0,0,0, \ -/* swp */ 0, \ -/* process credentials */ \ -/* uid etc */ 0,0,0,0,0,0,0,0, \ -/* suppl grps*/ 0, {0,}, \ -/* caps */ CAP_INIT_EFF_SET,CAP_INIT_INH_SET,CAP_FULL_SET, \ -/* user */ NULL, \ -/* rlimits */ INIT_RLIMITS, \ -/* math */ 0, \ -/* comm */ "swapper", \ -/* fs info */ 0,NULL, \ -/* ipc */ NULL, NULL, \ -/* thread */ INIT_THREAD, \ -/* fs */ &init_fs, \ -/* files */ &init_files, \ -/* signals */ SPIN_LOCK_UNLOCKED, &init_signals, {{0}}, {{0}}, NULL, &init_task.sigqueue, 0, 0, \ -/* exec cts */ 0,0, \ -/* exit_sem */ __MUTEX_INITIALIZER(name.exit_sem), \ +#define INIT_TASK(tsk) \ +{ \ + state: 0, \ + flags: 0, \ + sigpending: 0, \ + addr_limit: KERNEL_DS, \ + exec_domain: &default_exec_domain, \ + lock_depth: -1, \ + counter: DEF_PRIORITY, \ + priority: DEF_PRIORITY, \ + policy: SCHED_OTHER, \ + mm: NULL, \ + active_mm: &init_mm, \ + run_list: LIST_HEAD_INIT(tsk.run_list), \ + next_task: &tsk, \ + prev_task: &tsk, \ + p_opptr: &tsk, \ + p_pptr: &tsk, \ + wait_chldexit: __WAIT_QUEUE_HEAD_INITIALIZER(tsk.wait_chldexit),\ + real_timer: { \ + function: it_real_fn \ + }, \ + cap_effective: CAP_INIT_EFF_SET, \ + cap_inheritable: CAP_INIT_INH_SET, \ + cap_permitted: CAP_FULL_SET, \ + rlim: INIT_RLIMITS, \ + comm: "swapper", \ + thread: INIT_THREAD, \ + fs: &init_fs, \ + files: &init_files, \ + sigmask_lock: SPIN_LOCK_UNLOCKED, \ + sig: &init_signals, \ + signal: {{0}}, \ + blocked: {{0}}, \ + sigqueue: NULL, \ + sigqueue_tail: &tsk.sigqueue, \ + exit_sem: __MUTEX_INITIALIZER(tsk.exit_sem) \ } + #ifndef INIT_TASK_SIZE # define INIT_TASK_SIZE 2048*sizeof(long) diff -u --recursive --new-file v2.3.46/linux/include/linux/skbuff.h linux/include/linux/skbuff.h --- v2.3.46/linux/include/linux/skbuff.h Fri Jan 28 15:09:09 2000 +++ linux/include/linux/skbuff.h Sun Feb 20 20:48:33 2000 @@ -96,7 +96,6 @@ unsigned char is_clone, /* We are a clone */ cloned, /* head may be cloned (check refcnt to be sure). */ pkt_type, /* Packet class */ - pkt_bridged, /* Tracker for bridging */ ip_summed; /* Driver fed us an IP checksum */ __u32 priority; /* Packet queueing priority */ atomic_t users; /* User count - see datagram.c,tcp.c */ diff -u --recursive --new-file v2.3.46/linux/include/linux/spinlock.h linux/include/linux/spinlock.h --- v2.3.46/linux/include/linux/spinlock.h Thu Feb 10 17:11:22 2000 +++ linux/include/linux/spinlock.h Sun Feb 20 20:47:38 2000 @@ -41,9 +41,9 @@ /* * Your basic spinlocks, allowing only a single CPU anywhere * - * Gcc-2.7.x has a nasty bug with empty initializers. + * Most gcc versions have a nasty bug with empty initializers. */ -#if (__GNUC__ > 2) || (__GNUC__ == 2 && __GNUC_MINOR__ >= 8) +#if (__GNUC__ > 2) typedef struct { } spinlock_t; #define SPIN_LOCK_UNLOCKED (spinlock_t) { } #else @@ -104,9 +104,9 @@ * irq-safe write-lock, but readers can get non-irqsafe * read-locks. * - * Gcc-2.7.x has a nasty bug with empty initializers. + * Most gcc versions have a nasty bug with empty initializers. */ -#if (__GNUC__ > 2) || (__GNUC__ == 2 && __GNUC_MINOR__ >= 8) +#if (__GNUC__ > 2) typedef struct { } rwlock_t; #define RW_LOCK_UNLOCKED (rwlock_t) { } #else diff -u --recursive --new-file v2.3.46/linux/include/linux/sunrpc/xdr.h linux/include/linux/sunrpc/xdr.h --- v2.3.46/linux/include/linux/sunrpc/xdr.h Sun Dec 27 22:18:30 1998 +++ linux/include/linux/sunrpc/xdr.h Sun Feb 20 20:48:08 2000 @@ -1,7 +1,7 @@ /* * include/linux/sunrpc/xdr.h * - * Copyright (C) 1995, 1996 Olaf Kirch + * Copyright (C) 1995-1997 Olaf Kirch */ #ifndef _SUNRPC_XDR_H_ @@ -64,6 +64,25 @@ u32 * xdr_encode_netobj(u32 *p, const struct xdr_netobj *); u32 * xdr_decode_netobj(u32 *p, struct xdr_netobj *); u32 * xdr_decode_netobj_fixed(u32 *p, void *obj, unsigned int len); + +/* + * Decode 64bit quantities (NFSv3 support) + */ +static inline u32 * +xdr_encode_hyper(u32 *p, __u64 val) +{ + *p++ = htonl(val >> 32); + *p++ = htonl(val & 0xFFFFFFFF); + return p; +} + +static inline u32 * +xdr_decode_hyper(u32 *p, __u64 *valp) +{ + *valp = ((__u64) ntohl(*p++)) << 32; + *valp |= ntohl(*p++); + return p; +} /* * Adjust iovec to reflect end of xdr'ed data (RPC client XDR) diff -u --recursive --new-file v2.3.46/linux/include/net/br.h linux/include/net/br.h --- v2.3.46/linux/include/net/br.h Tue Jan 4 13:57:21 2000 +++ linux/include/net/br.h Wed Dec 31 16:00:00 1969 @@ -1,330 +0,0 @@ -#include -/* - * Constants and structure definitions for the bridging code - */ - -#if !defined(One) -#define Zero 0 -#define One 1 -#endif /* !defined(One) */ - -#if !defined(TRUE) -#define FALSE 0 -#define TRUE 1 -#endif /* !defined(TRUE) */ - -/** port states. **/ -#define Disabled 0 /* (4.4 5) */ -#define Listening 1 /* (4.4.2) */ -#define Learning 2 /* (4.4.3) */ -#define Forwarding 3 /* (4 4 4) */ -#define Blocking 4 /* (4.4.1) */ - - -/* MAG Yich! Easiest way of giving a configurable number of ports - * If you want more than 32, change BR_MAX_PORTS and recompile brcfg! - */ -#define BR_MAX_PORTS (32) -#if CONFIG_BRIDGE_NUM_PORTS > BR_MAX_PORTS -#undef CONFIG_BRIDGE_NUM_PORTS -#define CONFIG_BRIDGE_NUM_PORTS BR_MAX_PORTS -#endif -#define No_of_ports CONFIG_BRIDGE_NUM_PORTS -/* arbitrary choice, to allow the code below to compile */ - -#define All_ports (No_of_ports + 1) - -/* - * We time out our entries in the FDB after this many seconds. - */ -#define FDB_TIMEOUT 20 /* JRP: 20s as NSC bridge code, was 300 for Linux */ - -/* - * the following defines are the initial values used when the - * bridge is booted. These may be overridden when this bridge is - * not the root bridge. These are the recommended default values - * from the 802.1d specification. - */ -#define BRIDGE_MAX_AGE 20 -#define BRIDGE_HELLO_TIME 2 -#define BRIDGE_FORWARD_DELAY 15 -#define HOLD_TIME 1 - -/* broacast/multicast storm limitation. This per source. */ -#define MAX_MCAST_PER_PERIOD 4 -#define MCAST_HOLD_TIME (10*HZ/100) - -#define Default_path_cost 10 - -/* - * minimum increment possible to avoid underestimating age, allows for BPDU - * transmission time - */ -#define Message_age_increment 1 - -#define No_port 0 -/* - * reserved value for Bridge's root port parameter indicating no root port, - * used when Bridge is the root - also used to indicate the source when - * a frame is being generated by a higher layer protocol on this host - */ - -/** Configuration BPDU Parameters (4.5.1) **/ - -typedef struct { - union { - struct { - unsigned short priority; - unsigned char ula[6]; - } p_u; - unsigned int id[2]; - } bi; -} bridge_id_t; - -#define BRIDGE_PRIORITY bi.p_u.priority -#define BRIDGE_ID_ULA bi.p_u.ula -#define BRIDGE_ID bi.id - -/* JRP: on the network the flags field is between "type" and "root_id" - * this is unfortunated! To make the code portable to a RISC machine - * the pdus are now massaged a little bit for processing - */ -#define TOPOLOGY_CHANGE 0x01 -#define TOPOLOGY_CHANGE_ACK 0x80 -#define BRIDGE_BPDU_8021_CONFIG_SIZE 35 /* real size */ -#define BRIDGE_BPDU_8021_CONFIG_FLAG_OFFSET 4 -#define BRIDGE_BPDU_8021_PROTOCOL_ID 0 -#define BRIDGE_BPDU_8021_PROTOCOL_VERSION_ID 0 -#define BRIDGE_LLC1_HS 3 -#define BRIDGE_LLC1_DSAP 0x42 -#define BRIDGE_LLC1_SSAP 0x42 -#define BRIDGE_LLC1_CTRL 0x03 - -typedef struct { - unsigned short protocol_id; - unsigned char protocol_version_id; - unsigned char type; - bridge_id_t root_id; /* (4.5.1.1) */ - unsigned int root_path_cost; /* (4.5.1.2) */ - bridge_id_t bridge_id; /* (4.5.1.3) */ - unsigned short port_id; /* (4.5.1.4) */ - unsigned short message_age; /* (4.5.1.5) */ - unsigned short max_age; /* (4.5.1.6) */ - unsigned short hello_time; /* (4.5.1.7) */ - unsigned short forward_delay; /* (4.5.1.8) */ - unsigned char top_change_ack; - unsigned char top_change; -} Config_bpdu; - -#ifdef __LITTLE_ENDIAN -#define config_bpdu_hton(config_bpdu) \ - (config_bpdu)->root_path_cost = htonl((config_bpdu)->root_path_cost); \ - (config_bpdu)->port_id = htons((config_bpdu)->port_id); \ - (config_bpdu)->message_age = htons((config_bpdu)->message_age); \ - (config_bpdu)->max_age = htons((config_bpdu)->max_age); \ - (config_bpdu)->hello_time = htons((config_bpdu)->hello_time); \ - (config_bpdu)->forward_delay = htons((config_bpdu)->forward_delay); -#else -#define config_bpdu_hton(config_bpdu) -#endif -#define config_bpdu_ntoh config_bpdu_hton - - -/** Topology Change Notification BPDU Parameters (4.5.2) **/ - -typedef struct { - unsigned short protocol_id; - unsigned char protocol_version_id; - unsigned char type; -} Tcn_bpdu; - -#define BPDU_TYPE_CONFIG 0 -#define BPDU_TYPE_TOPO_CHANGE 128 - -/** Bridge Parameters (4.5.3) **/ -typedef struct { - bridge_id_t designated_root; /* (4.5.3.1) */ - unsigned int root_path_cost; /* (4.5.3.2) */ - unsigned int root_port; /* (4.5.3.3) */ - unsigned short max_age; /* (4.5.3.4) */ - unsigned short hello_time; /* (4.5.3.5) */ - unsigned short forward_delay; /* (4.5.3.6) */ - bridge_id_t bridge_id; /* (4.5.3.7) */ - unsigned short bridge_max_age; /* (4.5.3.8) */ - unsigned short bridge_hello_time; /* (4.5.3.9) */ - unsigned short bridge_forward_delay; /* (4.5.3.10) */ - unsigned int top_change_detected; /* (4.5.3.11) */ - unsigned int top_change; /* (4.5.3.12) */ - unsigned short topology_change_time; /* (4.5.3.13) */ - unsigned short hold_time; /* (4.5.3.14) */ - unsigned int instance; -} Bridge_data; - -/** Port Parameters (4.5.5) **/ -typedef struct { - unsigned short port_id; /* (4.5.5.1) */ - unsigned int state; /* (4.5.5.2) */ - unsigned int path_cost; /* (4.5.5.3) */ - bridge_id_t designated_root; /* (4.5.5.4) */ - unsigned int designated_cost; /* (4.5.5.5) */ - bridge_id_t designated_bridge; /* (4.5.5.6) */ - unsigned short designated_port; /* (4.5.5.7) */ - unsigned int top_change_ack; /* (4.5.5.8) */ - unsigned int config_pending; /* (4.5.5.9) */ - bridge_id_t ifmac; - char ifname[IFNAMSIZ]; /* Make life easier for brcfg */ - struct net_device *dev; - struct fdb *fdb; /* head of per port fdb chain */ -} Port_data; - - - -/** types to support timers for this pseudo-implementation. **/ -typedef struct { - unsigned int active; /* timer in use. */ - unsigned int value; /* current value of timer, - * counting up. */ -} Timer; - -struct fdb { - unsigned char ula[6]; - unsigned char pad[2]; - unsigned short port; - unsigned int timer; - unsigned short flags; -#define FDB_ENT_VALID 0x01 - unsigned short mcast_count; - unsigned int mcast_timer; /* oldest xxxxxcast */ - -/* AVL tree of all addresses, sorted by address */ - short fdb_avl_height; - struct fdb *fdb_avl_left; - struct fdb *fdb_avl_right; -/* linked list of addresses for each port */ - struct fdb *fdb_next; -}; - -/* data returned on BRCMD_DISPLAY_FDB */ -struct fdb_info { - unsigned char ula[6]; - unsigned char port; - unsigned char flags; - unsigned int timer; -}; -struct fdb_info_hdr { - int copied; /* nb of entries copied to user */ - int not_copied; /* when user buffer is too small */ - int cmd_time; -}; - -#define IS_BRIDGED 0x2e - - -#define BR_MAX_PROTOCOLS 32 -#define BR_MAX_PROT_STATS BR_MAX_PROTOCOLS - -/* policy values for policy field */ -#define BR_ACCEPT 1 -#define BR_REJECT 0 - -/* JRP: extra statistics for debug */ -typedef struct { - /* br_receive_frame counters */ - int port_disable_up_stack; - int rcv_bpdu; - int notForwarding; - int forwarding_up_stack; - int unknown_state; - - /* br_tx_frame counters */ - int port_disable; - int port_not_disable; - - /* br_forward counters */ - int local_multicast; - int forwarded_multicast; /* up stack as well */ - int flood_unicast; - int aged_flood_unicast; - int forwarded_unicast; - int forwarded_unicast_up_stack; - int forwarded_ip_up_stack; - int forwarded_ip_up_stack_lie; /* received on alternate device */ - int arp_for_local_mac; - int drop_same_port; - int drop_same_port_aged; - int drop_multicast; -} br_stats_counter; - -struct br_stat { - unsigned int flags; - Bridge_data bridge_data; - unsigned int policy; - unsigned int exempt_protocols; - unsigned short protocols[BR_MAX_PROTOCOLS]; - unsigned short prot_id[BR_MAX_PROT_STATS]; /* Protocol encountered */ - unsigned int prot_counter[BR_MAX_PROT_STATS]; /* How many packets ? */ - br_stats_counter packet_cnts; - unsigned int num_ports; - Port_data port_data[BR_MAX_PORTS + 1]; -}; - -/* defined flags for br_stat.flags */ -#define BR_UP 0x0001 /* bridging enabled */ -#define BR_DEBUG 0x0002 /* debugging enabled */ -#define BR_PROT_STATS 0x0004 /* protocol statistics enabled */ -#define BR_STP_DISABLED 0x0008 /* Spanning tree protocol disabled */ - -struct br_cf { - unsigned int cmd; - unsigned int arg1; - unsigned int arg2; -}; - -/* defined cmds */ -#define BRCMD_BRIDGE_ENABLE 1 -#define BRCMD_BRIDGE_DISABLE 2 -#define BRCMD_PORT_ENABLE 3 /* arg1 = port */ -#define BRCMD_PORT_DISABLE 4 /* arg1 = port */ -#define BRCMD_SET_BRIDGE_PRIORITY 5 /* arg1 = priority */ -#define BRCMD_SET_PORT_PRIORITY 6 /* arg1 = port, arg2 = priority */ -#define BRCMD_SET_PATH_COST 7 /* arg1 = port, arg2 = cost */ -#define BRCMD_DISPLAY_FDB 8 -#define BRCMD_ENABLE_DEBUG 9 -#define BRCMD_DISABLE_DEBUG 10 -#define BRCMD_SET_POLICY 11 /* arg1 = default policy (1==bridge all) */ -#define BRCMD_EXEMPT_PROTOCOL 12 /* arg1 = protocol (see net/if_ether.h) */ -#define BRCMD_ENABLE_PROT_STATS 13 -#define BRCMD_DISABLE_PROT_STATS 14 -#define BRCMD_ZERO_PROT_STATS 15 -#define BRCMD_TOGGLE_STP 16 -#define BRCMD_IF_ENABLE 17 /* arg1 = if_index */ -#define BRCMD_IF_DISABLE 18 /* arg1 = if_index */ -#define BRCMD_SET_IF_PRIORITY 19 /* arg1 = if_index, arg2 = priority */ -#define BRCMD_SET_IF_PATH_COST 20 /* arg1 = if_index, arg2 = cost */ - -/* prototypes of exported bridging functions... */ - -#ifdef __KERNEL__ -void br_init(void); -int br_receive_frame(struct sk_buff *skb); /* 3.5 */ -int br_tx_frame(struct sk_buff *skb); -int brg_init(void); -int br_ioctl(unsigned int cmd, void *arg); -void requeue_fdb(struct fdb *node, int new_port); - -struct fdb *br_avl_find_addr(unsigned char addr[6]); -struct fdb *br_avl_insert (struct fdb * new_node); -void sprintf_avl (char **pbuffer, struct fdb * tree, off_t *pos,int* len, off_t offset, int length); -void br_avl_delete_by_port(int port); -int br_call_bridge(struct sk_buff *skb, unsigned short type); -void br_spacedevice_register(void); - -/* externs */ - -extern struct br_stat br_stats; -extern Port_data port_info[]; - -#endif - - - diff -u --recursive --new-file v2.3.46/linux/include/net/pkt_sched.h linux/include/net/pkt_sched.h --- v2.3.46/linux/include/net/pkt_sched.h Thu Feb 10 17:11:23 2000 +++ linux/include/net/pkt_sched.h Sun Feb 20 20:49:03 2000 @@ -7,9 +7,14 @@ #define PSCHED_CLOCK_SOURCE PSCHED_JIFFIES +#include #include #include +#ifdef CONFIG_X86_TSC +#include +#endif + struct rtattr; struct Qdisc; @@ -247,11 +252,11 @@ #define PSCHED_US2JIFFIE(delay) (((delay)+psched_clock_per_hz-1)/psched_clock_per_hz) -#if CPU == 586 || CPU == 686 +#ifdef CONFIG_X86_TSC #define PSCHED_GET_TIME(stamp) \ ({ u64 __cur; \ - __asm__ __volatile__ (".byte 0x0f,0x31" :"=A" (__cur)); \ + rdtscll(__cur); \ (stamp) = __cur>>psched_clock_scale; \ }) @@ -430,7 +435,7 @@ extern __inline__ void qdisc_run(struct net_device *dev) { - while (!test_bit(LINK_STATE_XOFF, &dev->state) && + while (!netif_queue_stopped(dev) && qdisc_restart(dev)<0) /* NOTHING */; } diff -u --recursive --new-file v2.3.46/linux/include/net/profile.h linux/include/net/profile.h --- v2.3.46/linux/include/net/profile.h Wed Aug 18 16:43:31 1999 +++ linux/include/net/profile.h Sun Feb 20 20:47:38 2000 @@ -9,6 +9,10 @@ #include #include +#ifdef CONFIG_X86_TSC +#include +#endif + struct net_profile_slot { char id[16]; @@ -25,14 +29,11 @@ extern struct timeval net_profile_adjust; extern void net_profile_irq_adjust(struct timeval *entered, struct timeval* leaved); -#if CPU == 586 || CPU == 686 - +#ifdef CONFIG_X86_TSC extern __inline__ void net_profile_stamp(struct timeval *pstamp) { - __asm__ __volatile__ (".byte 0x0f,0x31" - :"=a" (pstamp->tv_usec), - "=d" (pstamp->tv_sec)); + rdtsc(pstamp->tv_usec, pstamp->tv_sec); } extern __inline__ void net_profile_accumulate(struct timeval *entered, diff -u --recursive --new-file v2.3.46/linux/kernel/ksyms.c linux/kernel/ksyms.c --- v2.3.46/linux/kernel/ksyms.c Wed Feb 16 17:03:52 2000 +++ linux/kernel/ksyms.c Sun Feb 20 20:37:09 2000 @@ -376,6 +376,7 @@ EXPORT_SYMBOL(loops_per_sec); #endif EXPORT_SYMBOL(kstat); +EXPORT_SYMBOL(nr_running); /* misc */ EXPORT_SYMBOL(panic); @@ -461,6 +462,7 @@ /* library functions */ EXPORT_SYMBOL(strnicmp); +EXPORT_SYMBOL(strspn); /* software interrupts */ EXPORT_SYMBOL(tasklet_hi_vec); @@ -468,6 +470,8 @@ EXPORT_SYMBOL(bh_task_vec); EXPORT_SYMBOL(init_bh); EXPORT_SYMBOL(remove_bh); +EXPORT_SYMBOL(tasklet_init); +EXPORT_SYMBOL(tasklet_kill); /* init task, for moving kthread roots - ought to export a function ?? */ diff -u --recursive --new-file v2.3.46/linux/kernel/pm.c linux/kernel/pm.c --- v2.3.46/linux/kernel/pm.c Thu Feb 10 17:11:23 2000 +++ linux/kernel/pm.c Sun Feb 20 20:37:09 2000 @@ -168,3 +168,4 @@ EXPORT_SYMBOL(pm_unregister_all); EXPORT_SYMBOL(pm_send_request); EXPORT_SYMBOL(pm_find); +EXPORT_SYMBOL(pm_active); diff -u --recursive --new-file v2.3.46/linux/kernel/sched.c linux/kernel/sched.c --- v2.3.46/linux/kernel/sched.c Thu Feb 10 17:11:23 2000 +++ linux/kernel/sched.c Sun Feb 20 20:26:10 2000 @@ -141,7 +141,7 @@ #endif /* .. and a slight advantage to the current MM */ - if (p->mm == this_mm) + if (p->mm == this_mm || !p->mm) weight += 1; weight += p->priority; @@ -173,7 +173,7 @@ */ static inline int preemption_goodness(struct task_struct * prev, struct task_struct * p, int cpu) { - return goodness(p, cpu, prev->mm) - goodness(prev, cpu, prev->mm); + return goodness(p, cpu, prev->active_mm) - goodness(prev, cpu, prev->active_mm); } /* diff -u --recursive --new-file v2.3.46/linux/mm/filemap.c linux/mm/filemap.c --- v2.3.46/linux/mm/filemap.c Wed Feb 16 17:03:52 2000 +++ linux/mm/filemap.c Wed Feb 16 20:23:47 2000 @@ -1945,8 +1945,6 @@ count -= status; pos += status; buf += status; - if (pos > inode->i_size) - inode->i_size = pos; } unlock: /* Mark it unlocked again and drop the page.. */ diff -u --recursive --new-file v2.3.46/linux/mm/memory.c linux/mm/memory.c --- v2.3.46/linux/mm/memory.c Sun Feb 13 19:29:04 2000 +++ linux/mm/memory.c Wed Feb 16 20:23:47 2000 @@ -862,6 +862,7 @@ struct vm_area_struct * mpnt; struct address_space *mapping = inode->i_mapping; + inode->i_size = offset; truncate_inode_pages(mapping, offset); spin_lock(&mapping->i_shared_lock); if (!mapping->i_mmap) diff -u --recursive --new-file v2.3.46/linux/mm/mremap.c linux/mm/mremap.c --- v2.3.46/linux/mm/mremap.c Wed Feb 16 17:03:52 2000 +++ linux/mm/mremap.c Sun Feb 20 20:25:19 2000 @@ -275,7 +275,7 @@ ret = -ENOMEM; if (flags & MREMAP_MAYMOVE) { if (!(flags & MREMAP_FIXED)) { - new_addr = get_unmapped_area(addr, new_len); + new_addr = get_unmapped_area(0, new_len); if (!new_addr) goto out; } diff -u --recursive --new-file v2.3.46/linux/mm/page_alloc.c linux/mm/page_alloc.c --- v2.3.46/linux/mm/page_alloc.c Sat Feb 12 11:22:11 2000 +++ linux/mm/page_alloc.c Sun Feb 20 20:25:19 2000 @@ -258,7 +258,9 @@ */ if (!(current->flags & PF_MEMALLOC)) { - if (classfree(z) > z->pages_high) + unsigned long free = classfree(z); + + if (free > z->pages_high) { if (z->low_on_memory) z->low_on_memory = 0; @@ -270,11 +272,11 @@ if (z->low_on_memory) goto balance; - if (classfree(z) <= z->pages_low) + if (free <= z->pages_low) { wake_up_interruptible(&kswapd_wait); - if (classfree(z) <= z->pages_min) + if (free <= z->pages_min) { z->low_on_memory = 1; goto balance; @@ -296,16 +298,6 @@ if (page) return page; } - } - - /* - * If we can schedule, do so, and make sure to yield. - * We may be a real-time process, and if kswapd is - * waiting for us we need to allow it to run a bit. - */ - if (gfp_mask & __GFP_WAIT) { - current->policy |= SCHED_YIELD; - schedule(); } nopage: diff -u --recursive --new-file v2.3.46/linux/net/Changes linux/net/Changes --- v2.3.46/linux/net/Changes Sun Jun 7 10:37:42 1998 +++ linux/net/Changes Fri Feb 18 14:51:22 2000 @@ -6,7 +6,6 @@ o Should unix domain connect never block ? o Screend loadable firewall module -o Fix merging the bridge code o Remove kernel RARP and replace with user mode daemon. o Merge ARM half word trap fixes for ethernet headers o Stop route addition to downed interfaces diff -u --recursive --new-file v2.3.46/linux/net/Config.in linux/net/Config.in --- v2.3.46/linux/net/Config.in Wed Dec 29 13:13:21 1999 +++ linux/net/Config.in Fri Feb 18 14:51:22 2000 @@ -61,11 +61,8 @@ fi tristate 'CCITT X.25 Packet Layer (EXPERIMENTAL)' CONFIG_X25 tristate 'LAPB Data Link Driver (EXPERIMENTAL)' CONFIG_LAPB - bool 'Bridging (EXPERIMENTAL)' CONFIG_BRIDGE - if [ "$CONFIG_BRIDGE" != "n" ]; then - int ' Maximum number of bridged interfaces' CONFIG_BRIDGE_NUM_PORTS 8 - fi -bool '802.2 LLC (EXPERIMENTAL)' CONFIG_LLC + tristate '802.1d Ethernet Bridging' CONFIG_BRIDGE + bool '802.2 LLC (EXPERIMENTAL)' CONFIG_LLC # if [ "$CONFIG_LLC" = "y" ]; then # bool ' Netbeui (EXPERIMENTAL)' CONFIG_NETBEUI # fi diff -u --recursive --new-file v2.3.46/linux/net/Makefile linux/net/Makefile --- v2.3.46/linux/net/Makefile Thu Aug 26 13:05:42 1999 +++ linux/net/Makefile Fri Feb 18 14:51:22 2000 @@ -67,6 +67,10 @@ ifeq ($(CONFIG_BRIDGE),y) SUB_DIRS += bridge +else + ifeq ($(CONFIG_BRIDGE),m) + MOD_SUB_DIRS += bridge + endif endif ifeq ($(CONFIG_IPX),y) diff -u --recursive --new-file v2.3.46/linux/net/README linux/net/README --- v2.3.46/linux/net/README Fri Jan 7 19:13:23 2000 +++ linux/net/README Fri Feb 18 14:51:22 2000 @@ -7,6 +7,7 @@ [token ring ] p.norton@computer.org appletalk jschlst@turbolinux.com ax25 g4klx@g4klx.demon.co.uk +bridge buytenh@openrock.net core alan@lxorguk.ukuu.org.uk decnet SteveW@ACM.org ethernet alan@lxorguk.ukuu.org.uk diff -u --recursive --new-file v2.3.46/linux/net/bridge/Makefile linux/net/bridge/Makefile --- v2.3.46/linux/net/bridge/Makefile Tue Apr 28 11:10:10 1998 +++ linux/net/bridge/Makefile Fri Feb 18 14:51:22 2000 @@ -1,5 +1,5 @@ # -# Makefile for the Linux Bridge layer. +# Makefile for the IEEE 802.1d ethernet bridging layer. # # Note! Dependencies are done automagically by 'make dep', which also # removes any old dependencies. DON'T put your own dependencies here @@ -7,15 +7,10 @@ # # Note 2! The CFLAGS definition is now in the main makefile... -O_TARGET := bridge.o -O_OBJS := br.o br_tree.o -M_OBJS := $(O_TARGET) - -ifeq ($(CONFIG_SYSCTL),y) -O_OBJS += sysctl_net_bridge.o -endif +O_TARGET := bridge.o +O_OBJS := br.o br_device.o br_fdb.o br_forward.o br_if.o br_input.o \ + br_ioctl.o br_notify.o br_stp.o br_stp_bpdu.o \ + br_stp_if.o br_stp_timer.o +M_OBJS := $(O_TARGET) include $(TOPDIR)/Rules.make - -tar: - tar -cvf /dev/f1 . diff -u --recursive --new-file v2.3.46/linux/net/bridge/br.c linux/net/bridge/br.c --- v2.3.46/linux/net/bridge/br.c Tue Jan 4 13:57:21 2000 +++ linux/net/bridge/br.c Fri Feb 18 14:51:22 2000 @@ -1,2740 +1,67 @@ /* - * Linux NET3 Bridge Support + * Generic parts + * Linux ethernet bridge * - * Originally by John Hayes (Network Plumbing). - * Minor hacks to get it to run with 1.3.x by Alan Cox - * 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 - -#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)) */ - } -/* JRP: we want the frame to be xmitted even if no other traffic. - * net_bh() will do a dev_transmit() that kicks all devices - */ - mark_bh(NET_BH); -} - -static int root_bridge(void) -{ - return (br_cmp(bridge_info.designated_root.BRIDGE_ID, - bridge_info.bridge_id.BRIDGE_ID)?FALSE:TRUE); -} - -static int supersedes_port_info(int port_no, Config_bpdu *config) /* (4.6.2.2) */ -{ - return ( - (br_cmp(config->root_id.BRIDGE_ID, - port_info[port_no].designated_root.BRIDGE_ID) < 0) /* (4.6.2.2.1) */ - || - ((br_cmp(config->root_id.BRIDGE_ID, - port_info[port_no].designated_root.BRIDGE_ID) == 0 - ) - && - ((config->root_path_cost - < port_info[port_no].designated_cost /* (4.6.2.2.2) */ - ) - || - ((config->root_path_cost - == port_info[port_no].designated_cost - ) - && - ((br_cmp(config->bridge_id.BRIDGE_ID, - port_info[port_no].designated_bridge.BRIDGE_ID) < 0 /* (4.6.2.2.3) */ - ) - || - ((br_cmp(config->bridge_id.BRIDGE_ID, - port_info[port_no].designated_bridge.BRIDGE_ID) == 0 - ) /* (4.6.2.2.4) */ - && - ((br_cmp(config->bridge_id.BRIDGE_ID, - bridge_info.bridge_id.BRIDGE_ID) != 0 - ) /* (4.6.2.2.4(1)) */ - || - (config->port_id <= - port_info[port_no].designated_port - ) /* (4.6.2.2.4(2)) */ - )))))) - ); -} - -static void record_config_information(int port_no, Config_bpdu *config) /* (4.6.2) */ -{ - port_info[port_no].designated_root = config->root_id; /* (4.6.2.3.1) */ - port_info[port_no].designated_cost = config->root_path_cost; - port_info[port_no].designated_bridge = config->bridge_id; - port_info[port_no].designated_port = config->port_id; - start_message_age_timer(port_no, config->message_age); /* (4.6.2.3.2) */ -} - -static void record_config_timeout_values(Config_bpdu *config) /* (4.6.3) */ -{ - bridge_info.max_age = config->max_age >> 8; /* (4.6.3.3) */ - bridge_info.hello_time = config->hello_time >> 8; - bridge_info.forward_delay = config->forward_delay >> 8; - bridge_info.top_change = config->top_change >> 8; -} - -static void config_bpdu_generation(void) -{ /* (4.6.4) */ - int port_no; - for (port_no = One; port_no <= No_of_ports; port_no++) { /* (4.6.4.3) */ - if (designated_port(port_no) /* (4.6.4.3) */ - && - (port_info[port_no].state != Disabled) - ) { - transmit_config(port_no); /* (4.6.4.3) */ - } /* (4.6.1.2) */ - } -} - -static int designated_port(int port_no) -{ - return ((br_cmp(port_info[port_no].designated_bridge.BRIDGE_ID, - bridge_info.bridge_id.BRIDGE_ID) == 0 - ) - && - (port_info[port_no].designated_port - == port_info[port_no].port_id - ) - ); -} - -static void reply(int port_no) /* (4.6.5) */ -{ - transmit_config(port_no); /* (4.6.5.3) */ -} - -static void transmit_tcn(void) -{ /* (4.6.6) */ - int port_no; - - port_no = bridge_info.root_port; - tcn_bpdu.type = BPDU_TYPE_TOPO_CHANGE; - send_tcn_bpdu(port_no, &tcn_bpdu); /* (4.6.6.3) */ -} - -static void configuration_update(void) /* (4.6.7) */ -{ - root_selection(); /* (4.6.7.3.1) */ - /* (4.6.8.2) */ - designated_port_selection(); /* (4.6.7.3.2) */ - /* (4.6.9.2) */ -} - -static void root_selection(void) -{ /* (4.6.8) */ - int root_port; - int port_no; - root_port = No_port; - for (port_no = One; port_no <= No_of_ports; port_no++) { /* (4.6.8.3.1) */ - if (((!designated_port(port_no)) - && - (port_info[port_no].state != Disabled) - && - (br_cmp(port_info[port_no].designated_root.BRIDGE_ID, - bridge_info.bridge_id.BRIDGE_ID) < 0) - ) - && - ((root_port == No_port) - || - (br_cmp(port_info[port_no].designated_root.BRIDGE_ID, - port_info[root_port].designated_root.BRIDGE_ID) < 0 - ) - || - ((br_cmp(port_info[port_no].designated_root.BRIDGE_ID, - port_info[root_port].designated_root.BRIDGE_ID) == 0 - ) - && - (((port_info[port_no].designated_cost - + port_info[port_no].path_cost - ) - < - (port_info[root_port].designated_cost - + port_info[root_port].path_cost - ) /* (4.6.8.3.1(2)) */ - ) - || - (((port_info[port_no].designated_cost - + port_info[port_no].path_cost - ) - == - (port_info[root_port].designated_cost - + port_info[root_port].path_cost - ) - ) - && - ((br_cmp(port_info[port_no].designated_bridge.BRIDGE_ID, - port_info[root_port].designated_bridge.BRIDGE_ID) < 0 - ) /* (4.6.8.3.1(3)) */ - || - ((br_cmp(port_info[port_no].designated_bridge.BRIDGE_ID, - port_info[root_port].designated_bridge.BRIDGE_ID) == 0 - ) - && - ((port_info[port_no].designated_port - < port_info[root_port].designated_port - ) /* (4.6.8.3.1(4)) */ - || - ((port_info[port_no].designated_port -/* JRP: was missing an "=" ! */ == port_info[root_port].designated_port - ) - && - (port_info[port_no].port_id - < port_info[root_port].port_id - ) /* (4.6.8.3.1(5)) */ - ))))))))) { - root_port = port_no; - } - } - bridge_info.root_port = root_port; /* (4.6.8.3.1) */ - - if (root_port == No_port) { /* (4.6.8.3.2) */ -#ifdef DEBUG_STP - if (br_stats.flags & BR_DEBUG) - printk(KERN_DEBUG "root_selection: becomes root\n"); -#endif - bridge_info.designated_root = bridge_info.bridge_id; - /* (4.6.8.3.2(1)) */ - bridge_info.root_path_cost = Zero;/* (4.6.8.3.2(2)) */ - } else { /* (4.6.8.3.3) */ - bridge_info.designated_root = port_info[root_port].designated_root; - /* (4.6.8.3.3(1)) */ - bridge_info.root_path_cost = (port_info[root_port].designated_cost - + port_info[root_port].path_cost - ); /* (4.6.8.3.3(2)) */ - } -} - -static void designated_port_selection(void) -{ /* (4.6.9) */ - int port_no; - - for (port_no = One; port_no <= No_of_ports; port_no++) { /* (4.6.9.3) */ - if(port_info[port_no].state == Disabled) - continue; - if (designated_port(port_no) /* (4.6.9.3.1) */ - || - ( - br_cmp(port_info[port_no].designated_root.BRIDGE_ID, - bridge_info.designated_root.BRIDGE_ID) != 0 - ) - || - (bridge_info.root_path_cost - < port_info[port_no].designated_cost - ) /* (4.6.9.3.3) */ - || - ((bridge_info.root_path_cost - == port_info[port_no].designated_cost - ) - && - ((br_cmp(bridge_info.bridge_id.BRIDGE_ID, - port_info[port_no].designated_bridge.BRIDGE_ID) < 0 - ) /* (4.6.9.3.4) */ - || - ((br_cmp(bridge_info.bridge_id.BRIDGE_ID, - port_info[port_no].designated_bridge.BRIDGE_ID) == 0 - ) - && - (port_info[port_no].port_id - <= port_info[port_no].designated_port - ) /* (4.6.9.3.5) */ - )))) { - become_designated_port(port_no); /* (4.6.10.3.2.2) */ - } - } -} - -static void become_designated_port(int port_no) -{ /* (4.6.10) */ - - /* (4.6.10.3.1) */ - port_info[port_no].designated_root = bridge_info.designated_root; - /* (4.6.10.3.2) */ - port_info[port_no].designated_cost = bridge_info.root_path_cost; - /* (4.6.10.3.3) */ - port_info[port_no].designated_bridge = bridge_info.bridge_id; - /* (4.6.10.3.4) */ - port_info[port_no].designated_port = port_info[port_no].port_id; -} - -static void port_state_selection(void) -{ /* (4.6.11) */ - int port_no; - char *state_str; - for (port_no = One; port_no <= No_of_ports; port_no++) { - - if(port_info[port_no].state == Disabled) - continue; - if (port_no == bridge_info.root_port) { /* (4.6.11.3.1) */ - state_str = "root"; - port_info[port_no].config_pending = FALSE; /* (4.6.11.3.1(1)) */ - port_info[port_no].top_change_ack = 0; - make_forwarding(port_no); /* (4.6.11.3.1(2)) */ - } else if (designated_port(port_no)) { /* (4.6.11.3.2) */ - state_str = "designated"; - stop_message_age_timer(port_no); /* (4.6.11.3.2(1)) */ - make_forwarding(port_no); /* (4.6.11.3.2(2)) */ - } else { /* (4.6.11.3.3) */ - state_str = "blocking"; - port_info[port_no].config_pending = FALSE; /* (4.6.11.3.3(1)) */ - port_info[port_no].top_change_ack = 0; - make_blocking(port_no); /* (4.6.11.3.3(2)) */ - } -#ifdef DEBUG_STP - if (br_stats.flags & BR_DEBUG) - printk(KERN_DEBUG "port_state_selection: becomes %s port %d\n", - state_str, port_no); -#endif - - } - -} - -static void make_forwarding(int port_no) -{ /* (4.6.12) */ - if (port_info[port_no].state == Blocking) { /* (4.6.12.3) */ - set_port_state(port_no, Listening); /* (4.6.12.3.1) */ - start_forward_delay_timer(port_no); /* (4.6.12.3.2) */ - } -} - -static void topology_change_detection(void) -{ /* (4.6.14) */ -#ifdef DEBUG_STP - if ((br_stats.flags & BR_DEBUG) - && (bridge_info.top_change_detected == 0)) - printk(KERN_DEBUG "topology_change_detected\n"); -#endif - if (root_bridge()) { /* (4.6.14.3.1) */ - bridge_info.top_change = 1; - start_topology_change_timer(); /* (4.6.14.3.1(2)) */ - } else if (!(bridge_info.top_change_detected)) { - transmit_tcn(); /* (4.6.14.3.2(1)) */ - start_tcn_timer(); /* (4.6.14.3.2(2)) */ - } - bridge_info.top_change_detected = 1; /* (4.6.14.3.3) */ -} +#include "br_private.h" -static void topology_change_acknowledged(void) -{ /* (4.6.15) */ -#ifdef DEBUG_STP - if (br_stats.flags & BR_DEBUG) - printk(KERN_DEBUG "topology_change_acked\n"); -#endif - bridge_info.top_change_detected = 0; /* (4.6.15.3.1) */ - stop_tcn_timer(); /* (4.6.15.3.2) */ -} - -static void acknowledge_topology_change(int port_no) -{ /* (4.6.16) */ - port_info[port_no].top_change_ack = 1; - transmit_config(port_no); /* (4.6.16.3.2) */ -} - -static void make_blocking(int port_no) /* (4.6.13) */ -{ - - if ((port_info[port_no].state != Disabled) - && - (port_info[port_no].state != Blocking) - /* (4.6.13.3) */ - ) { - if ((port_info[port_no].state == Forwarding) - || - (port_info[port_no].state == Learning) - ) { - topology_change_detection(); /* (4.6.13.3.1) */ - /* (4.6.14.2.3) */ - } - set_port_state(port_no, Blocking);/* (4.6.13.3.2) */ - stop_forward_delay_timer(port_no);/* (4.6.13.3.3) */ - } -} - -static void set_port_state(int port_no, int state) +void br_dec_use_count() { - port_info[port_no].state = state; + MOD_DEC_USE_COUNT; } -static void received_config_bpdu(int port_no, Config_bpdu *config) /* (4.7.1) */ +void br_inc_use_count() { - int root; - - root = root_bridge(); - if (port_info[port_no].state != Disabled) { - -#ifdef DEBUG_STP - if (br_stats.flags & BR_DEBUG) - printk(KERN_DEBUG "received_config_bpdu: port %d\n", - port_no); -#endif - if (supersedes_port_info(port_no, config)) { /* (4.7.1.1) *//* (4. - * 6.2.2) */ - record_config_information(port_no, config); /* (4.7.1.1.1) */ - /* (4.6.2.2) */ - configuration_update(); /* (4.7.1.1.2) */ - /* (4.6.7.2.1) */ - port_state_selection(); /* (4.7.1.1.3) */ - /* (4.6.11.2.1) */ - if ((!root_bridge()) && root) { /* (4.7.1.1.4) */ - stop_hello_timer(); - if (bridge_info.top_change_detected) { /* (4.7.1.1.5 */ - stop_topology_change_timer(); - transmit_tcn(); /* (4.6.6.1) */ - start_tcn_timer(); - } - } - if (port_no == bridge_info.root_port) { - record_config_timeout_values(config); /* (4.7.1.1.6) */ - /* (4.6.3.2) */ - config_bpdu_generation(); /* (4.6.4.2.1) */ - if (config->top_change_ack) { /* (4.7.1.1.7) */ - topology_change_acknowledged(); /* (4.6.15.2) */ - } - } - } else if (designated_port(port_no)) { /* (4.7.1.2) */ - reply(port_no); /* (4.7.1.2.1) */ - /* (4.6.5.2) */ - } - } + MOD_INC_USE_COUNT; } -static void received_tcn_bpdu(int port_no, Tcn_bpdu *tcn) /* (4.7.2) */ +static int __init br_init(void) { - if (port_info[port_no].state != Disabled) { -#ifdef DEBUG_STP - if (br_stats.flags & BR_DEBUG) - printk(KERN_DEBUG "received_tcn_bpdu: port %d\n", - port_no); -#endif - if (designated_port(port_no)) { - topology_change_detection(); /* (4.7.2.1) */ - /* (4.6.14.2.1) */ - acknowledge_topology_change(port_no); /* (4.7.2.2) */ - } /* (4.6.16.2) */ - } -} + printk(KERN_INFO "NET4: Ethernet Bridge 008 for NET4.0\n"); -static void hello_timer_expiry(void) -{ /* (4.7.3) */ - config_bpdu_generation(); /* (4.6.4.2.2) */ - start_hello_timer(); -} - -static void message_age_timer_expiry(int port_no) /* (4.7.4) */ -{ - int root; - root = root_bridge(); + br_handle_frame_hook = br_handle_frame; + br_ioctl_hook = br_ioctl_deviceless_stub; + register_netdevice_notifier(&br_device_notifier); -#ifdef DEBUG_STP - if (br_stats.flags & BR_DEBUG) - printk(KERN_DEBUG "message_age_timer_expiry: port %d\n", - port_no); -#endif - become_designated_port(port_no); /* (4.7.4.1) */ - /* (4.6.10.2.1) */ - configuration_update(); /* (4.7.4.2) */ - /* (4.6.7.2.2) */ - port_state_selection(); /* (4.7.4.3) */ - /* (4.6.11.2.2) */ - if ((root_bridge()) && (!root)) { /* (4.7.4.4) */ - - bridge_info.max_age = bridge_info.bridge_max_age; /* (4.7.4.4.1) */ - bridge_info.hello_time = bridge_info.bridge_hello_time; - bridge_info.forward_delay = bridge_info.bridge_forward_delay; - topology_change_detection(); /* (4.7.4.4.2) */ - /* (4.6.14.2.4) */ - stop_tcn_timer(); /* (4.7.4.4.3) */ - config_bpdu_generation(); /* (4.7.4.4.4) */ - /* (4.6.4.4.3) */ - start_hello_timer(); - } -} - -static void forward_delay_timer_expiry(int port_no) /* (4.7.5) */ -{ - if (port_info[port_no].state == Listening) - { /* (4.7.5.1) */ - set_port_state(port_no, Learning); /* (4.7.5.1.1) */ - start_forward_delay_timer(port_no); /* (4.7.5.1.2) */ - } - else if (port_info[port_no].state == Learning) - { - /* (4.7.5.2) */ - set_port_state(port_no, Forwarding); /* (4.7.5.2.1) */ - if (designated_for_some_port()) - { /* (4.7.5.2.2) */ - topology_change_detection(); /* (4.6.14.2.2) */ - - } - } -} - -static int designated_for_some_port(void) -{ - int port_no; - - for (port_no = One; port_no <= No_of_ports; port_no++) - { - if(port_info[port_no].state == Disabled) - continue; - if ((br_cmp(port_info[port_no].designated_bridge.BRIDGE_ID, - bridge_info.bridge_id.BRIDGE_ID) == 0)) - { - return (TRUE); - } - } - return (FALSE); -} - -static void tcn_timer_expiry(void) -{ /* (4.7.6) */ - transmit_tcn(); /* (4.7.6.1) */ - start_tcn_timer(); /* (4.7.6.2) */ -} - -static void topology_change_timer_expiry(void) -{ /* (4.7.7) */ - bridge_info.top_change_detected = 0; /* (4.7.7.1) */ - bridge_info.top_change = 0; - /* (4.7.7.2) */ -} - -static void hold_timer_expiry(int port_no) /* (4.7.8) */ -{ - if (port_info[port_no].config_pending) - { - transmit_config(port_no); /* (4.7.8.1) */ - } /* (4.6.1.2.3) */ -} - -/* Vova Oksman: Write the buffer (contents of the Bridge table) */ -/* to a PROCfs file */ -static int br_tree_get_info(char *buffer, char **start, off_t offset, int length) -{ - int size; - int len=0; - off_t pos=0; - char* pbuffer; - - if(0==offset) - { - /* first time write the header */ - size = sprintf(buffer,"%s","MAC address Device Flags Age (sec.)\n"); - len=size; - } - - pbuffer=&buffer[len]; - sprintf_avl(&pbuffer,NULL,&pos,&len,offset,length); - - *start = buffer+len-(pos-offset); /* Start of wanted data */ - len = pos-offset; /* Start slop */ - if (len>length) - len = length; /* Ending slop */ - - return len; -} - -void __init br_init(void) -{ /* (4.8.1) */ - int port_no; - - printk(KERN_INFO "NET4: Ethernet Bridge 006 for NET4.0\n"); - - /* Set up brg device information */ - bridge_info.instance = 0; - brg_init(); - - max_port_used = 0; - - /* - * Form initial topology change time. - * The topology change timer is only used if this is the root bridge. - */ - - bridge_info.topology_change_time = BRIDGE_MAX_AGE + BRIDGE_FORWARD_DELAY; /* (4.5.3.13) */ - - bridge_info.designated_root = bridge_info.bridge_id; /* (4.8.1.1) */ - bridge_info.root_path_cost = Zero; - bridge_info.root_port = No_port; -#ifdef DEBUG_STP - printk(KERN_INFO "br_init: becomes root\n"); -#endif - - bridge_info.bridge_max_age = BRIDGE_MAX_AGE; - bridge_info.bridge_hello_time = BRIDGE_HELLO_TIME; - bridge_info.bridge_forward_delay = BRIDGE_FORWARD_DELAY; - bridge_info.hold_time = HOLD_TIME; - - bridge_info.max_age = bridge_info.bridge_max_age; /* (4.8.1.2) */ - bridge_info.hello_time = bridge_info.bridge_hello_time; - bridge_info.forward_delay = bridge_info.bridge_forward_delay; - - bridge_info.top_change_detected = 0; - bridge_info.top_change = 0; - stop_tcn_timer(); - stop_topology_change_timer(); - memset(newfdb, 0, sizeof(newfdb)); - for (port_no = One; port_no <= No_of_ports; port_no++) { /* (4.8.1.4) */ - /* initial state = Disable */ - user_port_state[port_no] = Disabled; - port_priority[port_no] = 128; - br_init_port(port_no); - disable_port(port_no); - } -#if 0 /* JRP: We are not UP ! Wait for the start command */ - port_state_selection(); /* (4.8.1.5) */ - config_bpdu_generation(); /* (4.8.1.6) */ - /* initialize system timer */ - tl.expires = jiffies+HZ; /* 1 second */ - tl.function = br_tick; - add_timer(&tl); -#endif - - register_netdevice_notifier(&br_dev_notifier); - br_stats.flags = 0; /*BR_UP | BR_DEBUG*/; /* enable bridge */ - br_stats.policy = BR_ACCEPT; /* Enable bridge to accpet all protocols */ - br_stats.exempt_protocols = 0; - /*start_hello_timer();*/ - /* Vova Oksman: register the function for the PROCfs "bridge" file */ - proc_net_create("bridge", 0, br_tree_get_info); -} - -static inline unsigned short make_port_id(int port_no) -{ - return (port_priority[port_no] << 8) | port_no; -} - -static void br_init_port(int port_no) -{ - port_info[port_no].port_id = make_port_id(port_no); - become_designated_port(port_no); /* (4.8.1.4.1) */ - set_port_state(port_no, Blocking); /* (4.8.1.4.2) */ - port_info[port_no].top_change_ack = 0; - port_info[port_no].config_pending = FALSE;/* (4.8.1.4.4) */ - stop_message_age_timer(port_no); /* (4.8.1.4.5) */ - stop_forward_delay_timer(port_no); /* (4.8.1.4.6) */ - stop_hold_timer(port_no); /* (4.8.1.4.7) */ -} - -static void enable_port(int port_no) /* (4.8.2) */ -{ - br_init_port(port_no); - port_state_selection(); /* (4.8.2.7) */ -} /* */ - -static void disable_port(int port_no) /* (4.8.3) */ -{ - int root; - - root = root_bridge(); - become_designated_port(port_no); /* (4.8.3.1) */ - set_port_state(port_no, Disabled); /* (4.8.3.2) */ - port_info[port_no].top_change_ack = 0; - port_info[port_no].config_pending = FALSE;/* (4.8.3.4) */ - stop_message_age_timer(port_no); /* (4.8.3.5) */ - stop_forward_delay_timer(port_no); /* (4.8.3.6) */ - configuration_update(); - port_state_selection(); /* (4.8.3.7) */ - if ((root_bridge()) && (!root)) { /* (4.8.3.8) */ - bridge_info.max_age = bridge_info.bridge_max_age; /* (4.8.3.8.1) */ - bridge_info.hello_time = bridge_info.bridge_hello_time; - bridge_info.forward_delay = bridge_info.bridge_forward_delay; - topology_change_detection(); /* (4.8.3.8.2) */ - stop_tcn_timer(); /* (4.8.3.8.3) */ - config_bpdu_generation(); /* (4.8.3.8.4) */ - start_hello_timer(); - } -} - - -static void set_bridge_priority(bridge_id_t *new_bridge_id) - /* (4.8.4) */ -{ - - int root; - int port_no; - root = root_bridge(); - for (port_no = One; port_no <= No_of_ports; port_no++) { /* (4.8.4.2) */ - if(port_info[port_no].state == Disabled) - continue; - if (designated_port(port_no)) { - port_info[port_no].designated_bridge = *new_bridge_id; - } - } - - bridge_info.bridge_id = *new_bridge_id; /* (4.8.4.3) */ - configuration_update(); /* (4.8.4.4) */ - port_state_selection(); /* (4.8.4.5) */ - if ((root_bridge()) && (!root)) { /* (4.8.4.6) */ - bridge_info.max_age = bridge_info.bridge_max_age; /* (4.8.4.6.1) */ - bridge_info.hello_time = bridge_info.bridge_hello_time; - bridge_info.forward_delay = bridge_info.bridge_forward_delay; - topology_change_detection(); /* (4.8.4.6.2) */ - stop_tcn_timer(); /* (4.8.4.6.3) */ - config_bpdu_generation(), /* (4.8.4.6.4) */ - start_hello_timer(); - } -} - -static void set_port_priority(int port_no) - /* (4.8.5) */ -{int new_port_id = make_port_id(port_no); - - if (designated_port(port_no)) { /* (4.8.5.2) */ - port_info[port_no].designated_port = new_port_id; - } - port_info[port_no].port_id = new_port_id; /* (4.8.5.3) */ - if ((br_cmp(bridge_info.bridge_id.BRIDGE_ID, - port_info[port_no].designated_bridge.BRIDGE_ID) == 0 - ) - && - (port_info[port_no].port_id - < port_info[port_no].designated_port - - ) - ) - { - become_designated_port(port_no); /* (4.8.5.4.1) */ - port_state_selection(); /* (4.8.5.4.2) */ - } -} - -static void set_path_cost(int port_no, unsigned short path_cost) - /* (4.8.6) */ -{ - port_info[port_no].path_cost = path_cost; /* (4.8.6.1) */ - configuration_update(); /* (4.8.6.2) */ - port_state_selection(); /* (4.8.6.3) */ -} - -static void br_tick(unsigned long arg) -{ - int port_no; - - if(!(br_stats.flags & BR_UP)) - return; /* JRP: we have been shot down */ - - if (hello_timer_expired()) - hello_timer_expiry(); - - if (tcn_timer_expired()) - tcn_timer_expiry(); - - if (topology_change_timer_expired()) - topology_change_timer_expiry(); - - for (port_no = One; port_no <= No_of_ports; port_no++) - { - if(port_info[port_no].state == Disabled) - continue; - - if (forward_delay_timer_expired(port_no)) - forward_delay_timer_expiry(port_no); - - if (message_age_timer_expired(port_no)) - message_age_timer_expiry(port_no); - - if (hold_timer_expired(port_no)) - hold_timer_expiry(port_no); - } - /* call me again sometime... */ - tl.expires = jiffies+HZ; /* 1 second */ - tl.function = br_tick; - add_timer(&tl); -} - -static void start_hello_timer(void) -{ - hello_timer.value = 0; - hello_timer.active = TRUE; -} - -static void stop_hello_timer(void) -{ - hello_timer.active = FALSE; -} - -static int hello_timer_expired(void) -{ - if (hello_timer.active && (++hello_timer.value >= bridge_info.hello_time)) - { - hello_timer.active = FALSE; - return (TRUE); - } - return (FALSE); -} - -static void start_tcn_timer(void) -{ - tcn_timer.value = 0; - tcn_timer.active = TRUE; -} - -static void stop_tcn_timer(void) -{ - tcn_timer.active = FALSE; -} - -static int tcn_timer_expired(void) -{ - if (tcn_timer.active && (++tcn_timer.value >= bridge_info.bridge_hello_time)) - { - tcn_timer.active = FALSE; - return (TRUE); - } - return (FALSE); - -} - -static void start_topology_change_timer(void) -{ - topology_change_timer.value = 0; - topology_change_timer.active = TRUE; -} - -static void stop_topology_change_timer(void) -{ - topology_change_timer.active = FALSE; -} - -static int topology_change_timer_expired(void) -{ - if (topology_change_timer.active - && (++topology_change_timer.value >= bridge_info.topology_change_time )) - { - topology_change_timer.active = FALSE; - return (TRUE); - } - return (FALSE); -} - -static void start_message_age_timer(int port_no, unsigned short message_age) -{ - message_age_timer[port_no].value = message_age; - message_age_timer[port_no].active = TRUE; -} - -static void stop_message_age_timer(int port_no) -{ - message_age_timer[port_no].active = FALSE; -} - -static int message_age_timer_expired(int port_no) -{ - if (message_age_timer[port_no].active && (++message_age_timer[port_no].value >= bridge_info.max_age)) - { - message_age_timer[port_no].active = FALSE; - return (TRUE); - } - return (FALSE); -} - -static void start_forward_delay_timer(int port_no) -{ - forward_delay_timer[port_no].value = 0; - forward_delay_timer[port_no].active = TRUE; -} - -static void stop_forward_delay_timer(int port_no) -{ - forward_delay_timer[port_no].active = FALSE; -} - -static int forward_delay_timer_expired(int port_no) -{ - if (forward_delay_timer[port_no].active && (++forward_delay_timer[port_no].value >= bridge_info.forward_delay)) - { - forward_delay_timer[port_no].active = FALSE; - return (TRUE); - } - return (FALSE); -} - -static void start_hold_timer(int port_no) -{ - hold_timer[port_no].value = 0; - hold_timer[port_no].active = TRUE; -} - -static void stop_hold_timer(int port_no) -{ - hold_timer[port_no].active = FALSE; -} - -static int hold_timer_expired(int port_no) -{ - if (hold_timer[port_no].active && - (++hold_timer[port_no].value >= bridge_info.hold_time)) - { - hold_timer[port_no].active = FALSE; - return (TRUE); - } - return (FALSE); - -} - -static struct sk_buff *alloc_bridge_skb(int port_no, int pdu_size, char *pdu_name) -{ - struct sk_buff *skb; - struct net_device *dev = port_info[port_no].dev; - struct ethhdr *eth; - int size = dev->hard_header_len + BRIDGE_LLC1_HS + pdu_size; - unsigned char *llc_buffer; - int pad_size = 60 - size; - - size = 60; /* minimum Ethernet frame - CRC */ - - if (port_info[port_no].state == Disabled) - { - printk(KERN_DEBUG "send_%s_bpdu: port %i not valid\n", pdu_name, port_no); - return NULL; - } - - skb = alloc_skb(size, GFP_ATOMIC); - if (skb == NULL) - { - printk(KERN_DEBUG "send_%s_bpdu: no skb available\n", pdu_name); - return NULL; - } - skb->dev = dev; - skb->mac.raw = skb->nh.raw = skb_put(skb,size); - memset(skb->nh.raw + 60 - pad_size, 0xa5, pad_size); - eth = skb->mac.ethernet; - memcpy(eth->h_dest, bridge_ula, ETH_ALEN); - memcpy(eth->h_source, dev->dev_addr, ETH_ALEN); - - if (br_stats.flags & BR_DEBUG) - printk(KERN_DEBUG "send_%s_bpdu: port %i src %02x:%02x:%02x:%02x:%02x:%02x\n", - pdu_name, - port_no, - eth->h_source[0], - eth->h_source[1], - eth->h_source[2], - eth->h_source[3], - eth->h_source[4], - eth->h_source[5]); -#if 0 - /* 8038 is used in older DEC spanning tree protocol which uses a - * different pdu layout as well - */ - eth->h_proto = htons(0x8038); -#endif - eth->h_proto = htons(pdu_size + BRIDGE_LLC1_HS); - - skb->nh.raw += skb->dev->hard_header_len; - llc_buffer = skb->nh.raw; - *llc_buffer++ = BRIDGE_LLC1_DSAP; - *llc_buffer++ = BRIDGE_LLC1_SSAP; - *llc_buffer++ = BRIDGE_LLC1_CTRL; - /* set nh.raw to where the bpdu starts */ - skb->nh.raw += BRIDGE_LLC1_HS; - - /* mark that we've been here... */ - skb->pkt_bridged = IS_BRIDGED; - return skb; -} - -static int send_config_bpdu(int port_no, Config_bpdu *config_bpdu) -{ - struct sk_buff *skb; - - /* - * Keep silent when disabled or when STP disabled - */ - - if(!(br_stats.flags & BR_UP) || (br_stats.flags & BR_STP_DISABLED)) - return -1; - - /* - * Create and send the message - */ - - skb = alloc_bridge_skb(port_no, BRIDGE_BPDU_8021_CONFIG_SIZE, - "config"); - if (skb == NULL) - return(-1); - - /* copy fields before "flags" */ - memcpy(skb->nh.raw, config_bpdu, BRIDGE_BPDU_8021_CONFIG_FLAG_OFFSET); - - /* build the "flags" field */ - *(skb->nh.raw+BRIDGE_BPDU_8021_CONFIG_FLAG_OFFSET) = 0; - if (config_bpdu->top_change_ack) - *(skb->nh.raw+BRIDGE_BPDU_8021_CONFIG_FLAG_OFFSET) |= 0x80; - if (config_bpdu->top_change) - *(skb->nh.raw+BRIDGE_BPDU_8021_CONFIG_FLAG_OFFSET) |= 0x01; - - config_bpdu_hton(config_bpdu); - /* copy the rest */ - memcpy(skb->nh.raw+BRIDGE_BPDU_8021_CONFIG_FLAG_OFFSET+1, - (char*)&(config_bpdu->root_id), - BRIDGE_BPDU_8021_CONFIG_SIZE-1-BRIDGE_BPDU_8021_CONFIG_FLAG_OFFSET); - - dev_queue_xmit(skb); - return(0); -} - -static int send_tcn_bpdu(int port_no, Tcn_bpdu *bpdu) -{ - struct sk_buff *skb; - - /* - * Keep silent when disabled or when STP disabled - */ - - if(!(br_stats.flags & BR_UP) || (br_stats.flags & BR_STP_DISABLED)) - return -1; - - - skb = alloc_bridge_skb(port_no, sizeof(Tcn_bpdu), "tcn"); - if (skb == NULL) - return(-1); - - memcpy(skb->nh.raw, bpdu, sizeof(Tcn_bpdu)); - - dev_queue_xmit(skb); - return(0); -} - -static int br_device_event(struct notifier_block *unused, unsigned long event, void *ptr) -{ - struct net_device *dev = ptr; - int i; - - /* check for loopback devices */ - if (dev->flags & IFF_LOOPBACK) - return(NOTIFY_DONE); - - if (dev == &brg_if.dev) - return(NOTIFY_DONE); /* Don't attach the brg device to a port! */ - - switch (event) - { - case NETDEV_DOWN: - if (br_stats.flags & BR_DEBUG) - printk(KERN_DEBUG "br_device_event: NETDEV_DOWN...\n"); - /* find our device and mark it down */ - for (i = One; i <= No_of_ports; i++) - { - if (port_info[i].dev == dev) - { - disable_port(i); - return NOTIFY_DONE; - break; - } - } - break; - case NETDEV_UP: - if (br_stats.flags & BR_DEBUG) - printk(KERN_DEBUG "br_device_event: NETDEV_UP...\n"); - /* Only handle ethernet ports */ - if(dev->type!=ARPHRD_ETHER && dev->type!=ARPHRD_LOOPBACK) - return NOTIFY_DONE; - /* look up an unused device and enable it */ - for (i = One; i <= No_of_ports; i++) - { - if (port_info[i].dev == NULL || port_info[i].dev == dev) - { - port_info[i].dev = dev; - port_info[i].port_id = i; - dev->bridge_port_id = i; - if( i > max_port_used ) - max_port_used = i; - /* set bridge addr from 1st device addr */ - if (((htonl(bridge_info.bridge_id.BRIDGE_ID[0])&0xffff) == 0) && - (bridge_info.bridge_id.BRIDGE_ID[1] == 0)) - { - memcpy(bridge_info.bridge_id.BRIDGE_ID_ULA, dev->dev_addr, 6); - if(bridge_info.bridge_id.BRIDGE_PRIORITY == 0) - bridge_info.bridge_id.BRIDGE_PRIORITY = htons(32768); - set_bridge_priority(&bridge_info.bridge_id); - } - /* Add local MAC address */ - br_add_local_mac(dev->dev_addr); - /* Save MAC address for latter change address events */ - memcpy(port_info[i].ifmac.BRIDGE_ID_ULA, dev->dev_addr, 6); - if((br_stats.flags & BR_UP) && - (user_port_state[i] != Disabled)) - { - /* don't start if user said so */ - enable_port(i); - set_path_cost(i, br_port_cost(dev)); - set_port_priority(i); - if (br_stats.flags & BR_STP_DISABLED) - port_info[i].state = Forwarding; - else - make_forwarding(i); - } - return NOTIFY_DONE; - break; - } - } - break; - case NETDEV_REGISTER: - if (br_stats.flags & BR_DEBUG) - printk(KERN_DEBUG "br_device_event: NETDEV_REGISTER...\n"); - /* printk(KERN_ERR "br_device_event: NETDEV_REGISTER...\n"); */ - /* printk(KERN_ERR "br_device_event: dev->type: 0x%X\n", dev->type); */ - /* Only handle ethernet ports */ - if(dev->type!=ARPHRD_ETHER && dev->type!=ARPHRD_LOOPBACK) - return NOTIFY_DONE; - /* printk(KERN_ERR "br_device_event: Looking for port...\n"); */ - for (i = One; i <= No_of_ports; i++) - { - if (port_info[i].dev == NULL || port_info[i].dev == dev) - { - /* printk(KERN_ERR "br_device_event: Found port %d\n", i); */ - port_info[i].dev = dev; - port_info[i].port_id = i; - dev->bridge_port_id = i; - if( i > max_port_used ) - max_port_used = i; - /* handle local MAC address minuplations */ - br_add_local_mac(dev->dev_addr); - memcpy(port_info[i].ifmac.BRIDGE_ID_ULA, dev->dev_addr, 6); - return NOTIFY_DONE; - break; - } - } - break; - case NETDEV_UNREGISTER: - if (br_stats.flags & BR_DEBUG) - printk(KERN_DEBUG "br_device_event: NETDEV_UNREGISTER...\n"); - i = find_port(dev); - if (i > 0) { - br_avl_delete_by_port(i); - memset(port_info[i].ifmac.BRIDGE_ID_ULA, 0, 6); - port_info[i].dev = NULL; - } - break; - case NETDEV_CHANGEADDR: - if (br_stats.flags & BR_DEBUG) - printk(KERN_DEBUG "br_device_event: NETDEV_CHANGEADDR...\n"); - i = find_port(dev); - if (i <= 0) - break; - if (memcmp(port_info[i].ifmac.BRIDGE_ID_ULA, dev->dev_addr, 6) != 0) - break; /* Don't worry about a change of hardware broadcast address! */ - if (dev->start) { - printk(KERN_CRIT "br_device_event: NETDEV_CHANGEADDR on busy device %s - FIX DRIVER!\n", - dev->name); - /* return NOTIFY_BAD; It SHOULD be this, but I want to be friendly... */ - return NOTIFY_DONE; - } - br_avl_delete_by_port(i); - memset(port_info[i].ifmac.BRIDGE_ID_ULA, 0, 6); - break; - } - return NOTIFY_DONE; -} - -/* Routine to loop over device list and register - * interfaces to bridge. Called from last part of net_dev_init just before - * bootp/rarp interface setup - */ -void br_spacedevice_register(void) -{ - struct net_device *dev; - for( dev = dev_base; dev != NULL; dev = dev->next) - { - br_device_event(NULL, NETDEV_REGISTER, dev); - } -} - - -/* This is for SPEED in the kernel in net_bh.c */ - -int br_call_bridge(struct sk_buff *skb, unsigned short type) -{ - int port; - struct net_device *dev; - -#if 0 /* Checked first in handle_bridge to save expense of function call */ - if(!(br_stats.flags & BR_UP)) - return 0; -#endif - - dev = skb->dev; - port = dev->bridge_port_id; - - if(!port) - return 0; - - /* Sanity - make sure we are not leaping off into fairy space! */ - if ( port < 0 || port > max_port_used || port_info[port].dev != dev) { - if (net_ratelimit()) - printk(KERN_CRIT "br_call_bridge: device %s has invalid port ID %d!\n", - dev->name, - dev->bridge_port_id); - return 0; - } - - if(user_port_state[port] == Disabled) - return 0; - - if (!br_protocol_ok(ntohs(type))) - return 0; - - return 1; - -} - - -/* - * following routine is called when a frame is received - * from an interface, it returns 1 when it consumes the - * frame, 0 when it does not - */ - -int br_receive_frame(struct sk_buff *skb) /* 3.5 */ -{ - int port; - Port_data *p; - struct ethhdr *eth; - struct net_device *dev; - - /* sanity */ - if (!skb) { - printk(KERN_CRIT "br_receive_frame: no skb!\n"); - return(1); - } - - dev = skb->dev; - - skb->pkt_bridged = IS_BRIDGED; - - /* check for loopback */ - if (dev->flags & IFF_LOOPBACK) - return 0 ; - -#if 0 - port = find_port(dev); -#else - port = dev->bridge_port_id; -#endif - - if(!port) - return 0; - - /* Hand off to brg_rx BEFORE we screw up the skb */ - if(brg_rx(skb, port)) - return(1); - - skb->nh.raw = skb->mac.raw; - eth = skb->mac.ethernet; - p = &port_info[port]; - - if(p->state == Disabled) - { - /* We are here if BR_UP even if this port is Disabled. - * Send everything up - */ - skb->pkt_type = PACKET_HOST; - ++br_stats_cnt.port_disable_up_stack; - return(0); /* pass frame up our stack (this will */ - /* happen in net_bh() in dev.c) */ - } - - /* Here only if not disable. - * Remark: only frames going up will show up in NIT (tcpdump) - */ - - /* JRP: even if port is Blocking we need to process the Spanning Tree - * frames to keep the port in that state - */ - if (memcmp(eth->h_dest, bridge_ula, ETH_ALEN) == 0) - { - ++br_stats_cnt.rcv_bpdu; - br_bpdu(skb, port); /* br_bpdu consumes skb */ - return(1); - } - switch (p->state) - { - case Learning: - if(br_learn(skb, port)) - { /* 3.8 */ - ++br_stats_cnt.drop_multicast; - return br_drop(skb); - } - /* fall through */ - case Listening: - /* fall through */ - case Blocking: - ++br_stats_cnt.notForwarding; - return(br_drop(skb)); - /* - case Disabled: is now handled before this switch ! - Keep the break to allow GCC to use a jmp table. - */ - break; - case Forwarding: - if(br_learn(skb, port)) { /* 3.8 */ - ++br_stats_cnt.drop_multicast; - return br_drop(skb); - } - /* Now this frame came from one of bridged - ports this means we should attempt to forward it. - JRP: local addresses are now in the AVL tree, - br_forward will pass frames up if it matches - one of our local MACs or if it is a multicast - group address. - br_forward() will not consume the frame if this - is the case */ - return(br_forward(skb, port)); - default: - printk(KERN_DEBUG "br_receive_frame: port [%i] unknown state [%i]\n", - port, p->state); - ++br_stats_cnt.unknown_state; - return(br_drop(skb)); /* discard frame */ - } -} - -/* - * the following routine is called to transmit frames from the host - * stack. it returns 1 when it consumes the frame and - * 0 when it does not. - */ - -int br_tx_frame(struct sk_buff *skb) /* 3.5 */ -{ - int port; - struct ethhdr *eth; - - /* sanity */ - if (!skb) - { - printk(KERN_CRIT "br_tx_frame: no skb!\n"); - return(0); - } - - if (!skb->dev) - { - printk(KERN_CRIT "br_tx_frame: no dev!\n"); - return(0); - } - - /* check for loopback */ - if (skb->dev->flags & IFF_LOOPBACK) - return(0); - - /* if bridging is not enabled on the port we are going to send - to, we have nothing to do with this frame, hands off */ - if (((port=find_port(skb->dev))==0)||(port_info[port].state==Disabled)) { - ++br_stats_cnt.port_disable; - return(0); - } - ++br_stats_cnt.port_not_disable; - skb->mac.raw = skb->nh.raw = skb->data; - eth = skb->mac.ethernet; - port = 0; /* an impossible port (locally generated) */ - if (br_stats.flags & BR_DEBUG) - printk(KERN_DEBUG "br_tx_fr : port %i src %02x:%02x:%02x:%02x:%02x:%02x" - " dest %02x:%02x:%02x:%02x:%02x:%02x\n", - port, - eth->h_source[0], - eth->h_source[1], - eth->h_source[2], - eth->h_source[3], - eth->h_source[4], - eth->h_source[5], - eth->h_dest[0], - eth->h_dest[1], - eth->h_dest[2], - eth->h_dest[3], - eth->h_dest[4], - eth->h_dest[5]); - return(br_forward(skb, port)); -} - -static void br_add_local_mac(unsigned char *mac) -{ - struct fdb *f; - f = (struct fdb *)kmalloc(sizeof(struct fdb), GFP_ATOMIC); - if (!f) - { - printk(KERN_CRIT "br_add_local_mac: unable to malloc fdb\n"); - return; - } - f->port = 0; /* dest port == 0 =>local */ - memcpy(f->ula, mac, 6); - f->timer = 0; /* will not aged anyway */ - f->flags = 0; /* not valid => br_forward special route */ - /* - * add entity to AVL tree. If entity already - * exists in the tree, update the fields with - * what we have here. - */ - if (br_avl_insert(f) != NULL) - { - /* Already in */ - kfree(f); - } -} - -/* Avoid broadcast loop by limiting the number of broacast frames per - * period. The idea is to limit this per source - * returns: 0 if limit is not reached - * 1 if frame should be dropped - */ - -static inline int mcast_quench(struct fdb *f) -{ - if(f->mcast_count++ == 0) /* first time */ - f->mcast_timer = jiffies; - else { - if(f->mcast_count > max_mcast_per_period) { - if(time_after(jiffies, f->mcast_timer + mcast_hold_time)) - f->mcast_count = 0; - else return 1; - } - } - return 0; -} - -/* - * this routine returns 0 when it learns (or updates) from the - * frame, and 1 if we must dropped the frame. - */ - -static int br_learn(struct sk_buff *skb, int port) /* 3.8 */ -{ - struct fdb *f, *oldfdb; - Port_data *p = &port_info[port]; - struct ethhdr *eth = skb->mac.ethernet; - - /* JRP: no reason to check port state again. We are called by - * br_receive_frame() only when in Learning or Forwarding - * Remark: code not realigned yet to keep diffs smaller - */ - - /* don't keep group addresses in the tree */ - if (eth->h_source[0] & 0x01) - return 0; - - if((f= newfdb[port]) == NULL) - { - newfdb[port] = f = (struct fdb *)kmalloc(sizeof(struct fdb), GFP_ATOMIC); - if (!f) - { - printk(KERN_DEBUG "br_learn: unable to malloc fdb\n"); - return(-1); /* this drop the frame */ - } - } - f->port = port; /* source port */ - memcpy(f->ula, eth->h_source, 6); - f->timer = CURRENT_TIME; - f->flags = FDB_ENT_VALID; - /* - * add entity to AVL tree. If entity already - * exists in the tree, update the fields with - * what we have here. - */ - if ((oldfdb = br_avl_insert(f))) - { - /* update if !NULL */ - if((eth->h_dest[0] & 0x01) && /* multicast */ mcast_quench(oldfdb)) - return 1; - return 0; - } - newfdb[port] = NULL; /* force kmalloc next time */ - f->mcast_count = 0; - /* add to head of port chain */ - f->fdb_next = p->fdb; - p->fdb = f; - allocated_fdb_cnt++; - return 0; -} - -/* JRP: always called under br_receive_frame(). No need for Q protection. */ - -void requeue_fdb(struct fdb *node, int new_port) -{ - Port_data *p = &port_info[node->port]; - - /* dequeue */ - if(p->fdb == node) - p->fdb = node->fdb_next; - else - { - struct fdb *prev; - - for(prev = p->fdb; prev; prev = prev->fdb_next) - if (prev->fdb_next == node) - break; - - if(prev != NULL) - prev->fdb_next = node->fdb_next; - else - { - /* Forget about this update. */ - printk(KERN_ERR "br:requeue_fdb\n"); - return; - } - } - /* enqueue */ - node->port = new_port; - node->fdb_next = port_info[new_port].fdb; - port_info[new_port].fdb = node; -} - -/* - * this routine always consumes the frame - */ - -static int br_drop(struct sk_buff *skb) -{ - kfree_skb(skb); - return(1); -} - -/* - * this routine always consumes the frame - */ - -static int br_dev_drop(struct sk_buff *skb) -{ - dev_kfree_skb(skb); - return(1); -} - -/* - * Forward the frame SKB to proper port[s]. PORT is the port that the - * frame has come from; we will not send the frame back there. PORT == 0 - * means we have been called from br_tx_fr(), not from br_receive_frame(). - * - * this routine returns 1 if it consumes the frame, 0 - * if not... - */ - -static int br_forward(struct sk_buff *skb, int port) /* 3.7 */ -{ - struct fdb *f; - - /* - * flood all ports with frames destined for a group - * address. If frame came from above, drop it, - * otherwise it will be handled in br_receive_frame() - * Multicast frames will also need to be seen - * by our upper layers. - */ - if (skb->mac.ethernet->h_dest[0] & 0x01) - { - /* group address */ - br_flood(skb, port); - /* - * External groups are fed out via the normal source - * This probably should be dropped since the flood will - * have sent it anyway. - */ - if (port == 0) - { - /* Locally generated */ - ++br_stats_cnt.local_multicast; - return(br_dev_drop(skb)); - } - ++br_stats_cnt.forwarded_multicast; - return(0); - } - else - { - /* unicast frame, locate port to forward to */ - f = br_avl_find_addr(skb->mac.ethernet->h_dest); - /* - * Send flood and drop. - */ - if (!f || !(f->flags & FDB_ENT_VALID)) - { - if(f && (f->port == 0)) - { - skb->pkt_type = PACKET_HOST; - ++br_stats_cnt.forwarded_unicast_up_stack; - return(0); - } - /* not found or too old; flood all ports */ - ++br_stats_cnt.flood_unicast; - br_flood(skb, port); - return(br_dev_drop(skb)); - } - /* - * Sending - */ - if (f->port!=port && port_info[f->port].state == Forwarding) - { - /* Has entry expired? */ - if (f->timer + fdb_aging_time < CURRENT_TIME) - { - /* timer expired, invalidate entry */ - f->flags &= ~FDB_ENT_VALID; - if (br_stats.flags & BR_DEBUG) - printk(KERN_DEBUG "fdb entry expired...\n"); - /* - * Send flood and drop original - */ - ++br_stats_cnt.aged_flood_unicast; - br_flood(skb, port); - return(br_dev_drop(skb)); - } - ++br_stats_cnt.forwarded_unicast; - /* mark that's we've been here... */ - skb->pkt_bridged = IS_BRIDGED; - - /* reset the skb->ip pointer */ - skb->nh.raw = skb->data + ETH_HLEN; - - /* - * Send the buffer out. - */ - - skb->dev=port_info[f->port].dev; - - /* - * We send this still locked - */ - skb->priority = 1; - dev_queue_xmit(skb); - return(1); /* skb has been consumed */ - } - else - { - /* JRP: Needs to aged entry as well, if topology changes - * the entry would not age. Got this while swapping - * two cables ! - * - * Has entry expired? - */ - - if (f->timer + fdb_aging_time < CURRENT_TIME) - { - /* timer expired, invalidate entry */ - f->flags &= ~FDB_ENT_VALID; - if (br_stats.flags & BR_DEBUG) - printk(KERN_DEBUG "fdb entry expired...\n"); - ++br_stats_cnt.drop_same_port_aged; - } - else ++br_stats_cnt.drop_same_port; - /* - * Arrived on the right port, we discard - */ - return(br_dev_drop(skb)); - } - } -} - -/* - * this routine sends a copy of the frame to all forwarding ports - * with the exception of the port given. This routine never - * consumes the original frame. - */ - -static int br_flood(struct sk_buff *skb, int port) -{ - int i; - struct sk_buff *nskb; - - for (i = One; i <= No_of_ports; i++) - { - if (i == port) /* don't send back where we got it */ - continue; - if (i > max_port_used) - /* Don't go scanning empty port entries */ - break; - if (port_info[i].state == Forwarding) - { - nskb = skb_clone(skb, GFP_ATOMIC); - if(nskb==NULL) - continue; - /* mark that's we've been here... */ - nskb->pkt_bridged = IS_BRIDGED; - /* Send to each port in turn */ - nskb->dev= port_info[i].dev; - /* To get here we must have done ARP already, - or have a received valid MAC header */ - -/* printk(KERN_DEBUG "Flood to port %d\n",i);*/ - nskb->nh.raw = nskb->data + ETH_HLEN; - nskb->priority = 1; - dev_queue_xmit(nskb); - } - } - return(0); -} - -/* - * FIXME: This needs to come from the device structs, eg for - * 10,100,1Gbit ethernet. - */ - -static int br_port_cost(struct net_device *dev) /* 4.10.2 */ -{ - if (strncmp(dev->name, "lec", 3) == 0) /* ATM Lan Emulation (LANE) */ - return(7); /* 155 Mbs */ - if (strncmp(dev->name, "eth", 3) == 0) /* ethernet */ - return(100); - if (strncmp(dev->name, "plip",4) == 0) /* plip */ - return (1600); - return(100); /* default */ -} - -/* - * this routine always consumes the skb - */ - -static void br_bpdu(struct sk_buff *skb, int port) /* consumes skb */ -{ - char *bufp = skb->data + ETH_HLEN; - Tcn_bpdu *bpdu = (Tcn_bpdu *) (bufp + BRIDGE_LLC1_HS); - Config_bpdu rcv_bpdu; - - if(!(br_stats.flags & BR_STP_DISABLED) && - (*bufp++ == BRIDGE_LLC1_DSAP) && (*bufp++ == BRIDGE_LLC1_SSAP) && - (*bufp++ == BRIDGE_LLC1_CTRL) && - (bpdu->protocol_id == BRIDGE_BPDU_8021_PROTOCOL_ID) && - (bpdu->protocol_version_id == BRIDGE_BPDU_8021_PROTOCOL_VERSION_ID)) - { - - switch (bpdu->type) - { - case BPDU_TYPE_CONFIG: - /* realign for portability to RISC */ - memcpy((char*)&rcv_bpdu, bufp, - BRIDGE_BPDU_8021_CONFIG_FLAG_OFFSET); - bufp+= BRIDGE_BPDU_8021_CONFIG_FLAG_OFFSET; - rcv_bpdu.top_change_ack = - (*bufp & TOPOLOGY_CHANGE_ACK) != 0; - rcv_bpdu.top_change = - (*bufp & TOPOLOGY_CHANGE) != 0; - bufp++; - memcpy((char*)&rcv_bpdu.root_id, bufp, - BRIDGE_BPDU_8021_CONFIG_SIZE-1 - -BRIDGE_BPDU_8021_CONFIG_FLAG_OFFSET); - config_bpdu_ntoh(&rcv_bpdu); - received_config_bpdu(port, &rcv_bpdu); - break; - - case BPDU_TYPE_TOPO_CHANGE: - received_tcn_bpdu(port, bpdu); - break; - default: - printk(KERN_DEBUG "br_bpdu: received unknown bpdu, type = %i\n", bpdu->type); - /* break; */ - } - } - br_drop(skb); -} - -struct fdb_info *get_fdb_info(int user_buf_size, int *copied,int *notcopied) -{ - int fdb_size, i, built = 0; - struct fdb_info *fdbi, *fdbis; - - *copied = user_buf_size - sizeof(struct fdb_info_hdr); - *copied /= sizeof(struct fdb_info); - *copied = min(*copied, allocated_fdb_cnt); - *notcopied = allocated_fdb_cnt - *copied; - if(*copied == 0) - return NULL; - fdb_size = *copied * sizeof(struct fdb_info); - fdbis = kmalloc(fdb_size, GFP_KERNEL); - if(fdbis == NULL) - return NULL; - fdbi = fdbis; - - for(i=One; i<=No_of_ports;i++) - { - struct fdb *fdb; - - cli(); - fdb = port_info[i].fdb; - while(fdb) - { - memcpy(fdbi->ula, fdb->ula, ETH_ALEN); - fdbi->port = fdb->port; - fdbi->flags = fdb->flags; - fdbi->timer = fdb->timer; - fdbi++; - if(++built == *copied) - { - sti(); - return fdbis; - } - fdb = fdb->fdb_next; - } - sti(); - } - printk(KERN_DEBUG "get_fdb_info: built=%d\n", built); - return fdbis; -} - - -/* Fill in interface names in port_info structure - */ -static void br_get_ifnames(void) { - int i; - - for(i=One;i<=No_of_ports; i++) { - /* memset IS needed. Kernel strncpy does NOT NULL terminate strings when limit - reached */ - memset(port_info[i].ifname, 0, IFNAMSIZ); - if( port_info[i].dev == 0 ) - continue; - strncpy(port_info[i].ifname, port_info[i].dev->name, IFNAMSIZ-1); - /* Being paranoid */ - port_info[i].ifname[IFNAMSIZ-1] = '\0'; - } -} - -/* Given an interface index, loop over port array to see if configured. If - so, return port number, otherwise error */ -static int br_find_port(int ifindex) -{ - int i; - - for(i=1; i <= No_of_ports; i++) { - if (port_info[i].dev == 0) - continue; - if (port_info[i].dev->ifindex == ifindex) - return(i); - } - - return -EUNATCH; /* Tell me if this is incorrect error code for this case */ -} - - -int br_ioctl(unsigned int cmd, void *arg) -{ - int err, i, ifflags; - struct br_cf bcf; - bridge_id_t new_id; - struct net_device *dev; - - switch(cmd) - { - case SIOCGIFBR: /* get bridging control blocks */ - memcpy(&br_stats.bridge_data, &bridge_info, sizeof(Bridge_data)); - - /* Fill in interface names in port_info*/ - br_get_ifnames(); - - br_stats.num_ports = No_of_ports; - memcpy(&br_stats.port_data, &port_info, sizeof(Port_data)*All_ports); - - err = copy_to_user(arg, &br_stats, sizeof(struct br_stat)); - if (err) - { - err = -EFAULT; - } - return err; - case SIOCSIFBR: - err = copy_from_user(&bcf, arg, sizeof(struct br_cf)); - if (err) - return -EFAULT; - if (bcf.cmd != BRCMD_DISPLAY_FDB && !suser()) - return -EPERM; - switch (bcf.cmd) - { - case BRCMD_BRIDGE_ENABLE: - if (br_stats.flags & BR_UP) - return(-EALREADY); - printk(KERN_DEBUG "br: enabling bridging function\n"); - br_stats.flags |= BR_UP; /* enable bridge */ - for(i=One;i<=No_of_ports; i++) - { - /* don't start if user said so */ - if((user_port_state[i] != Disabled) - && port_info[i].dev) - { - enable_port(i); - } - } - port_state_selection(); /* (4.8.1.5) */ - if (br_stats.flags & BR_STP_DISABLED) - for(i=One;i<=No_of_ports; i++) - if((user_port_state[i] != Disabled) && port_info[i].dev) - port_info[i].state = Forwarding; - config_bpdu_generation(); /* (4.8.1.6) */ - /* initialize system timer */ - tl.expires = jiffies+HZ; /* 1 second */ - tl.function = br_tick; - add_timer(&tl); - start_hello_timer(); - break; - case BRCMD_BRIDGE_DISABLE: - if (!(br_stats.flags & BR_UP)) - return(-EALREADY); - printk(KERN_DEBUG "br: disabling bridging function\n"); - br_stats.flags &= ~BR_UP; /* disable bridge */ - stop_hello_timer(); - for (i = One; i <= No_of_ports; i++) - if (port_info[i].state != Disabled) - disable_port(i); - break; - case BRCMD_TOGGLE_STP: - printk(KERN_DEBUG "br: %s spanning tree protcol\n", - (br_stats.flags & BR_STP_DISABLED) ? "enabling" : "disabling"); - if (br_stats.flags & BR_STP_DISABLED) { /* enable STP */ - for(i=One;i<=No_of_ports; i++) - if((user_port_state[i] != Disabled) && port_info[i].dev) - enable_port(i); - } else { /* STP was enabled, now disable it */ - for (i = One; i <= No_of_ports; i++) - if (port_info[i].state != Disabled && port_info[i].dev) - port_info[i].state = Forwarding; - } - br_stats.flags ^= BR_STP_DISABLED; - break; - case BRCMD_IF_ENABLE: - bcf.arg1 = br_find_port(bcf.arg1); - if (bcf.arg1 < 0) - return(bcf.arg1); - case BRCMD_PORT_ENABLE: - if (port_info[bcf.arg1].dev == 0) - return(-EINVAL); - if (user_port_state[bcf.arg1] != Disabled) - return(-EALREADY); - printk(KERN_DEBUG "br: enabling port %i\n",bcf.arg1); - dev = port_info[bcf.arg1].dev; - ifflags = (dev->flags&~(IFF_PROMISC|IFF_ALLMULTI)) - |(dev->gflags&(IFF_PROMISC|IFF_ALLMULTI)); - dev_change_flags(dev, ifflags|IFF_PROMISC); - user_port_state[bcf.arg1] = ~Disabled; - if(br_stats.flags & BR_UP) - enable_port(bcf.arg1); - break; - case BRCMD_IF_DISABLE: - bcf.arg1 = br_find_port(bcf.arg1); - if (bcf.arg1 < 0) - return(bcf.arg1); - case BRCMD_PORT_DISABLE: - if (port_info[bcf.arg1].dev == 0) - return(-EINVAL); - if (user_port_state[bcf.arg1] == Disabled) - return(-EALREADY); - printk(KERN_DEBUG "br: disabling port %i\n",bcf.arg1); - user_port_state[bcf.arg1] = Disabled; - if(br_stats.flags & BR_UP) - disable_port(bcf.arg1); - dev = port_info[bcf.arg1].dev; - ifflags = (dev->flags&~(IFF_PROMISC|IFF_ALLMULTI)) - |(dev->gflags&(IFF_PROMISC|IFF_ALLMULTI)); - dev_change_flags(port_info[bcf.arg1].dev, ifflags & ~IFF_PROMISC); - break; - case BRCMD_SET_BRIDGE_PRIORITY: - new_id = bridge_info.bridge_id; - new_id.BRIDGE_PRIORITY = htons(bcf.arg1); - set_bridge_priority(&new_id); - break; - case BRCMD_SET_IF_PRIORITY: - bcf.arg1 = br_find_port(bcf.arg1); - if (bcf.arg1 < 0) - return(bcf.arg1); - case BRCMD_SET_PORT_PRIORITY: - if((port_info[bcf.arg1].dev == 0) - || (bcf.arg2 & ~0xff)) - return(-EINVAL); - port_priority[bcf.arg1] = bcf.arg2; - set_port_priority(bcf.arg1); - break; - case BRCMD_SET_IF_PATH_COST: - bcf.arg1 = br_find_port(bcf.arg1); - if (bcf.arg1 < 0) - return(bcf.arg1); - case BRCMD_SET_PATH_COST: - if (port_info[bcf.arg1].dev == 0) - return(-EINVAL); - set_path_cost(bcf.arg1, bcf.arg2); - break; - case BRCMD_ENABLE_DEBUG: - br_stats.flags |= BR_DEBUG; - break; - case BRCMD_DISABLE_DEBUG: - br_stats.flags &= ~BR_DEBUG; - break; - case BRCMD_SET_POLICY: - return br_set_policy(bcf.arg1); - case BRCMD_EXEMPT_PROTOCOL: - return br_add_exempt_protocol(bcf.arg1); - case BRCMD_ENABLE_PROT_STATS: - br_stats.flags |= BR_PROT_STATS; - break; - case BRCMD_DISABLE_PROT_STATS: - br_stats.flags &= ~BR_PROT_STATS; - break; - case BRCMD_ZERO_PROT_STATS: - memset(&br_stats.prot_id,0,sizeof(br_stats.prot_id)); - memset(&br_stats.prot_counter,0,sizeof(br_stats.prot_counter)); - break; - case BRCMD_DISPLAY_FDB: - { - struct fdb_info_hdr *user_buf = (void*) bcf.arg1; - struct fdb_info *u_fdbs, *fdbis; - int copied, notcopied; - u32 j = CURRENT_TIME; - - if(bcf.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) +static void __br_clear_frame_hook(void) { - int i; - for (i=0; i<2; i++) - { - /* JRP: compares prty then MAC address in memory byte order - * OK optimizer does htonl() only once per long ! - */ - if (htonl(a[i]) < htonl(b[i])) - return(-1); - if (htonl(a[i]) > htonl(b[i])) - return(1); - } - return(0); + br_handle_frame_hook = NULL; } - - - -/* -------------------------------------------------------------------------------- - * - * - * Bridge network device here for future modularization - device structures - * must be 'static' inside bridge instance - * Modelled after sch_teql.c - * - */ - - - -/* - * Index to functions. - */ - -int brg_probe(struct net_device *dev); -static int brg_open(struct net_device *dev); -static int brg_start_xmit(struct sk_buff *skb, struct net_device *dev); -static int brg_close(struct net_device *dev); -static struct net_device_stats *brg_get_stats(struct net_device *dev); -static void brg_set_multicast_list(struct net_device *dev); - -/* - * Board-specific info in dev->priv. - */ - -struct net_local +static void __br_clear_ioctl_hook(void) { - __u32 groups; - struct net_device_stats stats; -}; - - - - -/* - * To call this a probe is a bit misleading, however for real - * hardware it would have to check what was present. - */ - -int __init brg_probe(struct net_device *dev) -{ - unsigned int bogomips; - struct timeval utime; - - printk(KERN_INFO "%s: network interface for Ethernet Bridge 006/NET4.0\n", dev->name); - - /* - * Initialize the device structure. - */ - - dev->priv = kmalloc(sizeof(struct net_local), GFP_KERNEL); - if (dev->priv == NULL) - return -ENOMEM; - memset(dev->priv, 0, sizeof(struct net_local)); - - /* Set up MAC address based on BogoMIPs figure for first CPU and time - */ - bogomips = (loops_per_sec+2500)/500000 ; - get_fast_time(&utime); - - /* Ummmm.... YES! */ - dev->dev_addr[0] = '\xFE'; - dev->dev_addr[1] = '\xFD'; - dev->dev_addr[2] = (bridge_info.instance & 0x0F) << 4; - dev->dev_addr[2] |= ((utime.tv_sec & 0x000F0000) >> 16); - dev->dev_addr[3] = bogomips & 0xFF; - dev->dev_addr[4] = (utime.tv_sec & 0x0000FF00) >> 8; - dev->dev_addr[5] = (utime.tv_sec & 0x000000FF); - - printk(KERN_INFO "%s: generated MAC address %2.2X:%2.2X:%2.2X:%2.2X:%2.2X:%2.2X\n", - dev->name, - dev->dev_addr[0], - dev->dev_addr[1], - dev->dev_addr[2], - dev->dev_addr[3], - dev->dev_addr[4], - dev->dev_addr[5]); - - - printk(KERN_INFO "%s: attached to bridge instance %lu\n", dev->name, dev->base_addr); - - /* - * The brg specific entries in the device structure. - */ - - dev->open = brg_open; - dev->hard_start_xmit = brg_start_xmit; - dev->stop = brg_close; - dev->get_stats = brg_get_stats; - dev->set_multicast_list = brg_set_multicast_list; - - /* - * Setup the generic properties - */ - - ether_setup(dev); - - dev->tx_queue_len = 0; - - return 0; + br_ioctl_hook = NULL; } -/* - * Open/initialize the board. - */ - -static int brg_open(struct net_device *dev) +static void __exit br_deinit(void) { - if (br_stats.flags & BR_DEBUG) - printk(KERN_DEBUG "%s: Doing brg_open()...", dev->name); - - if (memcmp(dev->dev_addr, "\x00\x00\x00\x00\x00\x00", ETH_ALEN) == 0) - return -EFAULT; - - dev->start = 1; - dev->tbusy = 0; - return 0; -} - -static unsigned brg_mc_hash(__u8 *dest) -{ - unsigned idx = 0; - idx ^= dest[0]; - idx ^= dest[1]; - idx ^= dest[2]; - idx ^= dest[3]; - idx ^= dest[4]; - idx ^= dest[5]; - return 1U << (idx&0x1F); -} - -static void brg_set_multicast_list(struct net_device *dev) -{ - unsigned groups = ~0; - struct net_local *lp = (struct net_local *)dev->priv; - - if (!(dev->flags&(IFF_PROMISC|IFF_ALLMULTI))) { - struct dev_mc_list *dmi; - - groups = brg_mc_hash(dev->broadcast); - - for (dmi=dev->mc_list; dmi; dmi=dmi->next) { - if (dmi->dmi_addrlen != 6) - continue; - groups |= brg_mc_hash(dmi->dmi_addr); - } - } - lp->groups = groups; -} - -/* - * We transmit by throwing the packet at the bridge. - */ - -static int brg_start_xmit(struct sk_buff *skb, struct net_device *dev) -{ - struct net_local *lp = (struct net_local *)dev->priv; - struct ethhdr *eth = (struct ethhdr*)skb->data; - int port; - - /* Deal with the bridge being disabled */ - if(!(br_stats.flags & BR_UP)) { - /* Either this */ - /* lp->stats.tx_errors++; */ /* this condition is NOT an error */ - /* or this (implied by RFC 2233) */ - lp->stats.tx_dropped++; - dev_kfree_skb(skb); - return 0; - } - - lp->stats.tx_bytes+=skb->len; - lp->stats.tx_packets++; - -#if 0 - ++br_stats_cnt.port_not_disable; -#endif - skb->mac.raw = skb->nh.raw = skb->data; - eth = skb->mac.ethernet; - port = 0; /* an impossible port (locally generated) */ - - if (br_stats.flags & BR_DEBUG) - printk(KERN_DEBUG "%s: brg_start_xmit - src %02x:%02x:%02x:%02x:%02x:%02x" - " dest %02x:%02x:%02x:%02x:%02x:%02x\n", - dev->name, - eth->h_source[0], - eth->h_source[1], - eth->h_source[2], - eth->h_source[3], - eth->h_source[4], - eth->h_source[5], - eth->h_dest[0], - eth->h_dest[1], - eth->h_dest[2], - eth->h_dest[3], - eth->h_dest[4], - eth->h_dest[5]); - - /* Forward the packet ! */ - if(br_forward(skb, port)) - return(0); - - /* Throw packet initially */ - dev_kfree_skb(skb); - return 0; -} - - -/* - * The typical workload of the driver: - * Handle the ether interface interrupts. - * - * (In this case handle the packets posted from the bridge) - */ - -static int brg_rx(struct sk_buff *skb, int port) -{ - struct net_device *dev = &brg_if.dev; - struct net_local *lp = (struct net_local *)dev->priv; - struct ethhdr *eth = (struct ethhdr*)(skb->data); - int len = skb->len; - int clone = 0; - - if (br_stats.flags & BR_DEBUG) - printk(KERN_DEBUG "%s: brg_rx()\n", dev->name); - - /* Get out of here if the bridge interface is not up - */ - if(!(dev->flags & IFF_UP)) - return(0); - - /* Check that the port that this thing came off is in the forwarding state - * We sould only listen to the same address scope we will transmit to. - */ - if(port_info[port].state != Forwarding) - return(0); - - /* Is this for us? - broadcast/mulitcast/promiscuous packets need cloning, - * with uni-cast we eat the packet - */ - clone = 0; - if (dev->flags & IFF_PROMISC) { - clone = 1; - } - else if (eth->h_dest[0]&1) { - if (!(dev->flags&(IFF_ALLMULTI)) - && !(brg_mc_hash(eth->h_dest)&lp->groups)) - return(0); - clone = 1; - } - else if (memcmp(eth->h_dest, dev->dev_addr, ETH_ALEN) != 0) { - return(0); - } - - /* Clone things here - we want to be transparent before we check packet data - * integrity - */ - if(clone) { - struct sk_buff *skb2 = skb; - skb = skb_clone(skb2, GFP_ATOMIC); - if (skb == NULL) { - return(0); - } - - } - - /* Check packet length - */ - if (len < 16) { - printk(KERN_DEBUG "%s : rx len = %d\n", dev->name, len); - kfree_skb(skb); - return(!clone); - } - - if (br_stats.flags & BR_DEBUG) - printk(KERN_DEBUG "%s: brg_rx - src %02x:%02x:%02x:%02x:%02x:%02x" - " dest %02x:%02x:%02x:%02x:%02x:%02x\n", - dev->name, - eth->h_source[0], - eth->h_source[1], - eth->h_source[2], - eth->h_source[3], - eth->h_source[4], - eth->h_source[5], - eth->h_dest[0], - eth->h_dest[1], - eth->h_dest[2], - eth->h_dest[3], - eth->h_dest[4], - eth->h_dest[5]); - - /* Do it */ - skb->pkt_type = PACKET_HOST; - skb->dev = dev; - skb->protocol=eth_type_trans(skb,dev); - memset(skb->cb, 0, sizeof(skb->cb)); - lp->stats.rx_packets++; - lp->stats.rx_bytes+=len; - netif_rx(skb); - return(!clone); -} - -static int brg_close(struct net_device *dev) -{ - if (br_stats.flags & BR_DEBUG) - printk(KERN_DEBUG "%s: Shutting down.\n", dev->name); - - dev->tbusy = 1; - dev->start = 0; - - return 0; -} - -static struct net_device_stats *brg_get_stats(struct net_device *dev) -{ - struct net_local *lp = (struct net_local *)dev->priv; - return &lp->stats; -} - -/* - * - */ - -int __init brg_init(void) -{ - int err; - - memset(&brg_if, 0, sizeof(brg_if)); - - rtnl_lock(); - - brg_if.dev.base_addr = bridge_info.instance; - sprintf (brg_if.name, "brg%d", bridge_info.instance); - brg_if.dev.name = (void*)&brg_if.name; - if(dev_get(brg_if.name)) { - printk(KERN_INFO "%s already loaded.\n", brg_if.name); - return -EBUSY; - } - brg_if.dev.init = brg_probe; - - err = register_netdevice(&brg_if.dev); - rtnl_unlock(); - return err; -} - - -#if 0 /* Its here if we ever need it... */ -#ifdef MODULE - -void cleanup_module(void) -{ - - /* - * Unregister the device - */ - rtnl_lock(); - unregister_netdevice(&the_master.dev); - rtnl_unlock(); - - /* - * Free up the private structure. - */ - - kfree(brg_if.dev.priv); - brg_if.dev.priv = NULL; /* gets re-allocated by brg_probe */ + unregister_netdevice_notifier(&br_device_notifier); + br_call_ioctl_atomic(__br_clear_ioctl_hook); + net_call_rx_atomic(__br_clear_frame_hook); } -#endif /* MODULE */ +EXPORT_NO_SYMBOLS; -#endif +module_init(br_init) +module_exit(br_deinit) diff -u --recursive --new-file v2.3.46/linux/net/bridge/br_device.c linux/net/bridge/br_device.c --- v2.3.46/linux/net/bridge/br_device.c Wed Dec 31 16:00:00 1969 +++ linux/net/bridge/br_device.c Fri Feb 18 14:51:22 2000 @@ -0,0 +1,141 @@ +/* + * Device handling code + * Linux ethernet bridge + * + * Authors: + * Lennert Buytenhek + * + * $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 -u --recursive --new-file v2.3.46/linux/net/bridge/br_fdb.c linux/net/bridge/br_fdb.c --- v2.3.46/linux/net/bridge/br_fdb.c Wed Dec 31 16:00:00 1969 +++ linux/net/bridge/br_fdb.c Sun Feb 20 10:41:18 2000 @@ -0,0 +1,318 @@ +/* + * Forwarding database + * Linux ethernet bridge + * + * Authors: + * Lennert Buytenhek + * + * $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 "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 -u --recursive --new-file v2.3.46/linux/net/bridge/br_forward.c linux/net/bridge/br_forward.c --- v2.3.46/linux/net/bridge/br_forward.c Wed Dec 31 16:00:00 1969 +++ linux/net/bridge/br_forward.c Sun Feb 20 10:41:18 2000 @@ -0,0 +1,95 @@ +/* + * Forwarding decision + * Linux ethernet bridge + * + * Authors: + * Lennert Buytenhek + * + * $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 "br_private.h" + +static inline int should_forward(struct net_bridge_port *p, struct sk_buff *skb) +{ + if (skb->dev == p->dev || + p->state != BR_STATE_FORWARDING) + return 0; + + return 1; +} + +static void __br_forward(struct net_bridge_port *to, struct sk_buff *skb) +{ + skb->dev = to->dev; + dev_queue_xmit(skb); +} + +/* called under bridge lock */ +void br_forward(struct net_bridge_port *to, struct sk_buff *skb) +{ + if (should_forward(to, skb)) { + __br_forward(to, skb); + return; + } + + kfree_skb(skb); +} + +/* called under bridge lock */ +void br_flood(struct net_bridge *br, struct sk_buff *skb, int clone) +{ + struct net_bridge_port *p; + struct net_bridge_port *prev; + + if (clone) { + struct sk_buff *skb2; + + if ((skb2 = skb_clone(skb, GFP_ATOMIC)) == NULL) { + br->statistics.tx_dropped++; + return; + } + + skb = skb2; + } + + prev = NULL; + + p = br->port_list; + while (p != NULL) { + if (should_forward(p, skb)) { + if (prev != NULL) { + struct sk_buff *skb2; + + if ((skb2 = skb_clone(skb, GFP_ATOMIC)) == NULL) { + br->statistics.tx_dropped++; + kfree_skb(skb); + return; + } + + __br_forward(prev, skb2); + } + + prev = p; + } + + p = p->next; + } + + if (prev != NULL) { + __br_forward(prev, skb); + return; + } + + kfree_skb(skb); +} diff -u --recursive --new-file v2.3.46/linux/net/bridge/br_if.c linux/net/bridge/br_if.c --- v2.3.46/linux/net/bridge/br_if.c Wed Dec 31 16:00:00 1969 +++ linux/net/bridge/br_if.c Sun Feb 20 10:41:18 2000 @@ -0,0 +1,293 @@ +/* + * Userspace interface + * Linux ethernet bridge + * + * Authors: + * Lennert Buytenhek + * + * $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 "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 -u --recursive --new-file v2.3.46/linux/net/bridge/br_input.c linux/net/bridge/br_input.c --- v2.3.46/linux/net/bridge/br_input.c Wed Dec 31 16:00:00 1969 +++ linux/net/bridge/br_input.c Sun Feb 20 10:41:18 2000 @@ -0,0 +1,113 @@ +/* + * Handle incoming frames + * Linux ethernet bridge + * + * Authors: + * Lennert Buytenhek + * + * $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 "br_private.h" + +unsigned char bridge_ula[5] = { 0x01, 0x80, 0xc2, 0x00, 0x00 }; + +static void br_pass_frame_up(struct net_bridge *br, struct sk_buff *skb) +{ + if (br->dev.flags & IFF_UP) { + br->statistics.rx_packets++; + br->statistics.rx_bytes += skb->len; + + skb->dev = &br->dev; + skb->pkt_type = PACKET_HOST; + skb->mac.raw = skb->data; + skb_pull(skb, skb->nh.raw - skb->data); + skb->protocol = eth_type_trans(skb, &br->dev); + netif_rx(skb); + + return; + } + + kfree_skb(skb); +} + +static void __br_handle_frame(struct sk_buff *skb) +{ + struct net_bridge *br; + unsigned char *dest; + struct net_bridge_fdb_entry *dst; + struct net_bridge_port *p; + + skb->nh.raw = skb->mac.raw; + dest = skb->mac.ethernet->h_dest; + + p = skb->dev->br_port; + br = p->br; + + if (p->state == BR_STATE_DISABLED || + skb->mac.ethernet->h_source[0] & 1) + goto freeandout; + + if (!memcmp(dest, bridge_ula, 5) && !(dest[5] & 0xF0)) + goto handle_special_frame; + + skb_push(skb, skb->data - skb->mac.raw); + + if (p->state == BR_STATE_LEARNING || + p->state == BR_STATE_FORWARDING) + br_fdb_insert(br, p, skb->mac.ethernet->h_source, 0); + + if (p->state != BR_STATE_FORWARDING) + goto freeandout; + + if (dest[0] & 1) { + br_flood(br, skb, 1); + br_pass_frame_up(br, skb); + return; + } + + dst = br_fdb_get(br, dest); + + if (dst != NULL && dst->is_local) { + br_pass_frame_up(br, skb); + br_fdb_put(dst); + return; + } + + if (dst != NULL) { + br_forward(dst->dst, skb); + br_fdb_put(dst); + return; + } + + br_flood(br, skb, 0); + return; + + handle_special_frame: + if (!dest[5]) { + br_stp_handle_bpdu(skb); + return; + } + + freeandout: + kfree_skb(skb); +} + +void br_handle_frame(struct sk_buff *skb) +{ + struct net_bridge *br; + + br = skb->dev->br_port->br; + read_lock(&br->lock); + __br_handle_frame(skb); + read_unlock(&br->lock); +} diff -u --recursive --new-file v2.3.46/linux/net/bridge/br_ioctl.c linux/net/bridge/br_ioctl.c --- v2.3.46/linux/net/bridge/br_ioctl.c Wed Dec 31 16:00:00 1969 +++ linux/net/bridge/br_ioctl.c Sun Feb 20 10:41:18 2000 @@ -0,0 +1,264 @@ +/* + * Ioctl handler + * Linux ethernet bridge + * + * Authors: + * Lennert Buytenhek + * + * $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 "br_private.h" + +static int br_ioctl_device(struct net_bridge *br, + unsigned int cmd, + unsigned long arg0, + unsigned long arg1, + unsigned long arg2) +{ + if (br == NULL) + return -EINVAL; + + switch (cmd) + { + case BRCTL_ADD_IF: + case BRCTL_DEL_IF: + { + struct net_device *dev; + int ret; + + dev = dev_get_by_index(arg0); + if (dev == NULL) + return -EINVAL; + + if (cmd == BRCTL_ADD_IF) + ret = br_add_if(br, dev); + else + ret = br_del_if(br, dev); + + dev_put(dev); + return ret; + } + + case BRCTL_GET_BRIDGE_INFO: + { + struct __bridge_info b; + + memcpy(&b.designated_root, &br->designated_root, 8); + memcpy(&b.bridge_id, &br->bridge_id, 8); + b.root_path_cost = br->root_path_cost; + b.max_age = br->max_age; + b.hello_time = br->hello_time; + b.forward_delay = br->forward_delay; + b.bridge_max_age = br->bridge_max_age; + b.bridge_hello_time = br->bridge_hello_time; + b.bridge_forward_delay = br->bridge_forward_delay; + b.topology_change = br->topology_change; + b.topology_change_detected = br->topology_change_detected; + b.root_port = br->root_port; + b.stp_enabled = br->stp_enabled; + b.ageing_time = br->ageing_time; + b.gc_interval = br->gc_interval; + b.hello_timer_value = br_timer_get_residue(&br->hello_timer); + b.tcn_timer_value = br_timer_get_residue(&br->tcn_timer); + b.topology_change_timer_value = br_timer_get_residue(&br->topology_change_timer); + b.gc_timer_value = br_timer_get_residue(&br->gc_timer); + + if (copy_to_user((void *)arg0, &b, sizeof(b))) + return -EFAULT; + + return 0; + } + + case BRCTL_GET_PORT_LIST: + { + int indices[256]; + + br_get_port_ifindices(br, indices); + if (copy_to_user((void *)arg0, indices, 256*sizeof(int))) + return -EFAULT; + + return 0; + } + + case BRCTL_SET_BRIDGE_FORWARD_DELAY: + br->bridge_forward_delay = arg0; + if (br_is_root_bridge(br)) + br->forward_delay = arg0; + return 0; + + case BRCTL_SET_BRIDGE_HELLO_TIME: + br->bridge_hello_time = arg0; + if (br_is_root_bridge(br)) + br->hello_time = arg0; + return 0; + + case BRCTL_SET_BRIDGE_MAX_AGE: + br->bridge_max_age = arg0; + if (br_is_root_bridge(br)) + br->max_age = arg0; + return 0; + + case BRCTL_SET_AGEING_TIME: + br->ageing_time = arg0; + return 0; + + case BRCTL_SET_GC_INTERVAL: + br->gc_interval = arg0; + return 0; + + case BRCTL_GET_PORT_INFO: + { + struct __port_info p; + struct net_bridge_port *pt; + + if ((pt = br_get_port(br, arg1)) == NULL) + return -EINVAL; + + memcpy(&p.designated_root, &pt->designated_root, 8); + memcpy(&p.designated_bridge, &pt->designated_bridge, 8); + p.port_id = pt->port_id; + p.designated_port = pt->designated_port; + p.path_cost = pt->path_cost; + p.designated_cost = pt->designated_cost; + p.state = pt->state; + p.top_change_ack = pt->topology_change_ack; + p.config_pending = pt->config_pending; + p.message_age_timer_value = br_timer_get_residue(&pt->message_age_timer); + p.forward_delay_timer_value = br_timer_get_residue(&pt->forward_delay_timer); + p.hold_timer_value = br_timer_get_residue(&pt->hold_timer); + + if (copy_to_user((void *)arg0, &p, sizeof(p))) + return -EINVAL; + + return 0; + } + + case BRCTL_SET_BRIDGE_STP_STATE: + br->stp_enabled = arg0?1:0; + return 0; + + case BRCTL_SET_BRIDGE_PRIORITY: + br_stp_set_bridge_priority(br, arg0); + return 0; + + case BRCTL_SET_PORT_PRIORITY: + { + struct net_bridge_port *p; + + if ((p = br_get_port(br, arg0)) == NULL) + return -EINVAL; + br_stp_set_port_priority(p, arg1); + return 0; + } + + case BRCTL_SET_PATH_COST: + { + struct net_bridge_port *p; + + if ((p = br_get_port(br, arg0)) == NULL) + return -EINVAL; + br_stp_set_path_cost(p, arg1); + return 0; + } + + case BRCTL_GET_FDB_ENTRIES: + return br_fdb_get_entries(br, (void *)arg0, arg1, arg2); + } + + return -EOPNOTSUPP; +} + +static int br_ioctl_deviceless(unsigned int cmd, + unsigned long arg0, + unsigned long arg1) +{ + switch (cmd) + { + case BRCTL_GET_VERSION: + return BRCTL_VERSION; + + case BRCTL_GET_BRIDGES: + { + int indices[64]; + + if (arg1 > 64) + arg1 = 64; + arg1 = br_get_bridge_ifindices(indices, arg1); + if (copy_to_user((void *)arg0, indices, arg1*sizeof(int))) + return -EFAULT; + + return arg1; + } + + case BRCTL_ADD_BRIDGE: + case BRCTL_DEL_BRIDGE: + { + char buf[IFNAMSIZ]; + + if (copy_from_user(buf, (void *)arg0, IFNAMSIZ)) + return -EFAULT; + + buf[IFNAMSIZ-1] = 0; + + if (cmd == BRCTL_ADD_BRIDGE) + return br_add_bridge(buf); + + return br_del_bridge(buf); + } + } + + return -EOPNOTSUPP; +} + +DECLARE_MUTEX(ioctl_mutex); + +int br_ioctl_deviceless_stub(unsigned long arg) +{ + int err; + unsigned long i[3]; + + if (!capable(CAP_NET_ADMIN)) + return -EPERM; + + if (copy_from_user(i, (void *)arg, 3*sizeof(unsigned long))) + return -EFAULT; + + down(&ioctl_mutex); + err = br_ioctl_deviceless(i[0], i[1], i[2]); + up(&ioctl_mutex); + + return err; +} + +int br_ioctl(struct net_bridge *br, unsigned int cmd, unsigned long arg0, unsigned long arg1, unsigned long arg2) +{ + int err; + + if (!capable(CAP_NET_ADMIN)) + return -EPERM; + + down(&ioctl_mutex); + err = br_ioctl_deviceless(cmd, arg0, arg1); + if (err == -EOPNOTSUPP) + err = br_ioctl_device(br, cmd, arg0, arg1, arg2); + up(&ioctl_mutex); + + return err; +} + +void br_call_ioctl_atomic(void (*fn)(void)) +{ + down(&ioctl_mutex); + fn(); + up(&ioctl_mutex); +} diff -u --recursive --new-file v2.3.46/linux/net/bridge/br_notify.c linux/net/bridge/br_notify.c --- v2.3.46/linux/net/bridge/br_notify.c Wed Dec 31 16:00:00 1969 +++ linux/net/bridge/br_notify.c Sun Feb 20 10:41:18 2000 @@ -0,0 +1,75 @@ +/* + * Device event handling + * Linux ethernet bridge + * + * Authors: + * Lennert Buytenhek + * + * $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 "br_private.h" + +static int br_device_event(struct notifier_block *unused, unsigned long event, void *ptr); + +struct notifier_block br_device_notifier = +{ + br_device_event, + NULL, + 0 +}; + +static int br_device_event(struct notifier_block *unused, unsigned long event, void *ptr) +{ + struct net_device *dev; + struct net_bridge_port *p; + + dev = ptr; + p = dev->br_port; + + if (p == NULL) + return NOTIFY_DONE; + + switch (event) + { + case NETDEV_CHANGEADDR: + read_lock(&p->br->lock); + br_fdb_changeaddr(p, dev->dev_addr); + br_stp_recalculate_bridge_id(p->br); + read_unlock(&p->br->lock); + break; + + case NETDEV_GOING_DOWN: + /* extend the protocol to send some kind of notification? */ + break; + + case NETDEV_DOWN: + if (p->br->dev.flags & IFF_UP) { + read_lock(&p->br->lock); + br_stp_disable_port(dev->br_port); + read_unlock(&p->br->lock); + } + break; + + case NETDEV_UP: + if (p->br->dev.flags & IFF_UP) { + read_lock(&p->br->lock); + br_stp_enable_port(dev->br_port); + read_unlock(&p->br->lock); + } + break; + + case NETDEV_UNREGISTER: + br_del_if(dev->br_port->br, dev); + break; + } + + return NOTIFY_DONE; +} diff -u --recursive --new-file v2.3.46/linux/net/bridge/br_private.h linux/net/bridge/br_private.h --- v2.3.46/linux/net/bridge/br_private.h Wed Dec 31 16:00:00 1969 +++ linux/net/bridge/br_private.h Fri Feb 18 14:51:22 2000 @@ -0,0 +1,199 @@ +/* + * Linux ethernet bridge + * + * Authors: + * Lennert Buytenhek + * + * $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 -u --recursive --new-file v2.3.46/linux/net/bridge/br_private_stp.h linux/net/bridge/br_private_stp.h --- v2.3.46/linux/net/bridge/br_private_stp.h Wed Dec 31 16:00:00 1969 +++ linux/net/bridge/br_private_stp.h Fri Feb 18 14:51:22 2000 @@ -0,0 +1,53 @@ +/* + * Linux ethernet bridge + * + * Authors: + * Lennert Buytenhek + * + * $Id: br_private_stp.h,v 1.1 2000/02/18 16:47:13 davem Exp $ + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version + * 2 of the License, or (at your option) any later version. + */ + +#ifndef _BR_PRIVATE_STP_H +#define _BR_PRIVATE_STP_H + +#define BPDU_TYPE_CONFIG 0 +#define BPDU_TYPE_TCN 1 + +struct br_config_bpdu +{ + unsigned topology_change:1; + unsigned topology_change_ack:1; + bridge_id root; + int root_path_cost; + bridge_id bridge_id; + port_id port_id; + int message_age; + int max_age; + int hello_time; + int forward_delay; +}; + +/* br_stp.c */ +void br_become_root_bridge(struct net_bridge *br); +void br_config_bpdu_generation(struct net_bridge *); +void br_configuration_update(struct net_bridge *); +int br_is_designated_port(struct net_bridge_port *p); +int br_is_root_bridge(struct net_bridge *br); +void br_port_state_selection(struct net_bridge *); +void br_received_config_bpdu(struct net_bridge_port *p, struct br_config_bpdu *bpdu); +void br_received_tcn_bpdu(struct net_bridge_port *p); +void br_tick(unsigned long __data); +void br_transmit_config(struct net_bridge_port *p); +void br_transmit_tcn(struct net_bridge *br); +void br_topology_change_detection(struct net_bridge *br); + +/* br_stp_bpdu.c */ +void br_send_config_bpdu(struct net_bridge_port *, struct br_config_bpdu *); +void br_send_tcn_bpdu(struct net_bridge_port *); + +#endif diff -u --recursive --new-file v2.3.46/linux/net/bridge/br_private_timer.h linux/net/bridge/br_private_timer.h --- v2.3.46/linux/net/bridge/br_private_timer.h Wed Dec 31 16:00:00 1969 +++ linux/net/bridge/br_private_timer.h Fri Feb 18 14:51:22 2000 @@ -0,0 +1,54 @@ +/* + * Linux ethernet bridge + * + * Authors: + * Lennert Buytenhek + * + * $Id: br_private_timer.h,v 1.1 2000/02/18 16:47:13 davem Exp $ + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version + * 2 of the License, or (at your option) any later version. + */ + +#ifndef _BR_PRIVATE_TIMER_H +#define _BR_PRIVATE_TIMER_H + +struct br_timer +{ + int running; + unsigned long expires; +}; + +extern __inline__ void br_timer_clear(struct br_timer *t) +{ + t->running = 0; +} + +extern __inline__ unsigned long br_timer_get_residue(struct br_timer *t) +{ + if (t->running) + return jiffies - t->expires; + + return 0; +} + +extern __inline__ void br_timer_set(struct br_timer *t, unsigned long x) +{ + t->expires = x; + t->running = 1; +} + +extern __inline__ int br_timer_is_running(struct br_timer *t) +{ + return t->running; +} + +extern __inline__ int br_timer_has_expired(struct br_timer *t, unsigned long to) +{ + return t->running && time_after_eq(jiffies, t->expires + to); +} + + +#endif diff -u --recursive --new-file v2.3.46/linux/net/bridge/br_stp.c linux/net/bridge/br_stp.c --- v2.3.46/linux/net/bridge/br_stp.c Wed Dec 31 16:00:00 1969 +++ linux/net/bridge/br_stp.c Sun Feb 20 10:41:18 2000 @@ -0,0 +1,465 @@ +/* + * Spanning tree protocol; generic parts + * Linux ethernet bridge + * + * Authors: + * Lennert Buytenhek + * + * $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 "br_private.h" +#include "br_private_stp.h" + + + +/* called under ioctl_lock or bridge lock */ +int br_is_root_bridge(struct net_bridge *br) +{ + return !memcmp(&br->bridge_id, &br->designated_root, 8); +} + +/* called under bridge lock */ +int br_is_designated_port(struct net_bridge_port *p) +{ + return !memcmp(&p->designated_bridge, &p->br->bridge_id, 8) && + (p->designated_port == p->port_id); +} + +/* called under ioctl_lock or bridge lock */ +struct net_bridge_port *br_get_port(struct net_bridge *br, int port_no) +{ + struct net_bridge_port *p; + + p = br->port_list; + while (p != NULL) { + if (p->port_no == port_no) + return p; + + p = p->next; + } + + return NULL; +} + +/* called under bridge lock */ +static int br_should_become_root_port(struct net_bridge_port *p, int root_port) +{ + struct net_bridge *br; + struct net_bridge_port *rp; + int t; + + br = p->br; + if (p->state == BR_STATE_DISABLED || + br_is_designated_port(p)) + return 0; + + if (memcmp(&br->bridge_id, &p->designated_root, 8) <= 0) + return 0; + + if (!root_port) + return 1; + + rp = br_get_port(br, root_port); + + t = memcmp(&p->designated_root, &rp->designated_root, 8); + if (t < 0) + return 1; + else if (t > 0) + return 0; + + if (p->designated_cost + p->path_cost < + rp->designated_cost + rp->path_cost) + return 1; + else if (p->designated_cost + p->path_cost > + rp->designated_cost + rp->path_cost) + return 0; + + t = memcmp(&p->designated_bridge, &rp->designated_bridge, 8); + if (t < 0) + return 1; + else if (t > 0) + return 0; + + if (p->designated_port < rp->designated_port) + return 1; + else if (p->designated_port > rp->designated_port) + return 0; + + if (p->port_id < rp->port_id) + return 1; + + return 0; +} + +/* called under bridge lock */ +static void br_root_selection(struct net_bridge *br) +{ + struct net_bridge_port *p; + int root_port; + + root_port = 0; + + p = br->port_list; + while (p != NULL) { + if (br_should_become_root_port(p, root_port)) + root_port = p->port_no; + + p = p->next; + } + + br->root_port = root_port; + + if (!root_port) { + br->designated_root = br->bridge_id; + br->root_path_cost = 0; + } else { + p = br_get_port(br, root_port); + br->designated_root = p->designated_root; + br->root_path_cost = p->designated_cost + p->path_cost; + } +} + +/* called under bridge lock */ +void br_become_root_bridge(struct net_bridge *br) +{ + br->max_age = br->bridge_max_age; + br->hello_time = br->bridge_hello_time; + br->forward_delay = br->bridge_forward_delay; + br_topology_change_detection(br); + br_timer_clear(&br->tcn_timer); + br_config_bpdu_generation(br); + br_timer_set(&br->hello_timer, jiffies); +} + +/* called under bridge lock */ +void br_transmit_config(struct net_bridge_port *p) +{ + struct br_config_bpdu bpdu; + struct net_bridge *br; + + if (br_timer_is_running(&p->hold_timer)) { + p->config_pending = 1; + return; + } + + br = p->br; + + bpdu.topology_change = br->topology_change; + bpdu.topology_change_ack = p->topology_change_ack; + bpdu.root = br->designated_root; + bpdu.root_path_cost = br->root_path_cost; + bpdu.bridge_id = br->bridge_id; + bpdu.port_id = p->port_id; + bpdu.message_age = 0; + if (!br_is_root_bridge(br)) { + struct net_bridge_port *root; + unsigned long age; + + root = br_get_port(br, br->root_port); + age = br_timer_get_residue(&root->message_age_timer) + 1; + bpdu.message_age = age; + } + bpdu.max_age = br->max_age; + bpdu.hello_time = br->hello_time; + bpdu.forward_delay = br->forward_delay; + + br_send_config_bpdu(p, &bpdu); + + p->topology_change_ack = 0; + p->config_pending = 0; + br_timer_set(&p->hold_timer, jiffies); +} + +/* called under bridge lock */ +static void br_record_config_information(struct net_bridge_port *p, struct br_config_bpdu *bpdu) +{ + p->designated_root = bpdu->root; + p->designated_cost = bpdu->root_path_cost; + p->designated_bridge = bpdu->bridge_id; + p->designated_port = bpdu->port_id; + + br_timer_set(&p->message_age_timer, jiffies - bpdu->message_age); +} + +/* called under bridge lock */ +static void br_record_config_timeout_values(struct net_bridge *br, struct br_config_bpdu *bpdu) +{ + br->max_age = bpdu->max_age; + br->hello_time = bpdu->hello_time; + br->forward_delay = bpdu->forward_delay; + br->topology_change = bpdu->topology_change; +} + +/* called under bridge lock */ +void br_transmit_tcn(struct net_bridge *br) +{ + br_send_tcn_bpdu(br_get_port(br, br->root_port)); +} + +/* called under bridge lock */ +static int br_should_become_designated_port(struct net_bridge_port *p) +{ + struct net_bridge *br; + int t; + + br = p->br; + if (br_is_designated_port(p)) + return 1; + + if (memcmp(&p->designated_root, &br->designated_root, 8)) + return 1; + + if (br->root_path_cost < p->designated_cost) + return 1; + else if (br->root_path_cost > p->designated_cost) + return 0; + + t = memcmp(&br->bridge_id, &p->designated_bridge, 8); + if (t < 0) + return 1; + else if (t > 0) + return 0; + + if (p->port_id < p->designated_port) + return 1; + + return 0; +} + +/* called under bridge lock */ +static void br_designated_port_selection(struct net_bridge *br) +{ + struct net_bridge_port *p; + + p = br->port_list; + while (p != NULL) { + if (p->state != BR_STATE_DISABLED && + br_should_become_designated_port(p)) + br_become_designated_port(p); + + p = p->next; + } +} + +/* called under bridge lock */ +static int br_supersedes_port_info(struct net_bridge_port *p, struct br_config_bpdu *bpdu) +{ + int t; + + t = memcmp(&bpdu->root, &p->designated_root, 8); + if (t < 0) + return 1; + else if (t > 0) + return 0; + + if (bpdu->root_path_cost < p->designated_cost) + return 1; + else if (bpdu->root_path_cost > p->designated_cost) + return 0; + + t = memcmp(&bpdu->bridge_id, &p->designated_bridge, 8); + if (t < 0) + return 1; + else if (t > 0) + return 0; + + if (memcmp(&bpdu->bridge_id, &p->br->bridge_id, 8)) + return 1; + + if (bpdu->port_id <= p->designated_port) + return 1; + + return 0; +} + +/* called under bridge lock */ +static void br_topology_change_acknowledged(struct net_bridge *br) +{ + br->topology_change_detected = 0; + br_timer_clear(&br->tcn_timer); +} + +/* called under bridge lock */ +void br_topology_change_detection(struct net_bridge *br) +{ + printk(KERN_INFO "%s: topology change detected, ", br->name); + + if (br_is_root_bridge(br)) { + printk("propagating\n"); + br->topology_change = 1; + br_timer_set(&br->topology_change_timer, jiffies); + } else if (!br->topology_change_detected) { + printk("sending tcn bpdu\n"); + br_transmit_tcn(br); + br_timer_set(&br->tcn_timer, jiffies); + } + + br->topology_change_detected = 1; +} + +/* called under bridge lock */ +void br_config_bpdu_generation(struct net_bridge *br) +{ + struct net_bridge_port *p; + + p = br->port_list; + while (p != NULL) { + if (p->state != BR_STATE_DISABLED && + br_is_designated_port(p)) + br_transmit_config(p); + + p = p->next; + } +} + +/* called under bridge lock */ +static void br_reply(struct net_bridge_port *p) +{ + br_transmit_config(p); +} + +/* called under bridge lock */ +void br_configuration_update(struct net_bridge *br) +{ + br_root_selection(br); + br_designated_port_selection(br); +} + +/* called under bridge lock */ +void br_become_designated_port(struct net_bridge_port *p) +{ + struct net_bridge *br; + + br = p->br; + p->designated_root = br->designated_root; + p->designated_cost = br->root_path_cost; + p->designated_bridge = br->bridge_id; + p->designated_port = p->port_id; +} + +/* called under bridge lock */ +static void br_make_blocking(struct net_bridge_port *p) +{ + if (p->state != BR_STATE_DISABLED && + p->state != BR_STATE_BLOCKING) { + if (p->state == BR_STATE_FORWARDING || + p->state == BR_STATE_LEARNING) + br_topology_change_detection(p->br); + + printk(KERN_INFO "%s: port %i(%s) entering %s state\n", + p->br->name, p->port_no, p->dev->name, "blocking"); + + p->state = BR_STATE_BLOCKING; + br_timer_clear(&p->forward_delay_timer); + } +} + +/* called under bridge lock */ +static void br_make_forwarding(struct net_bridge_port *p) +{ + if (p->state == BR_STATE_BLOCKING) { + printk(KERN_INFO "%s: port %i(%s) entering %s state\n", + p->br->name, p->port_no, p->dev->name, "listening"); + + p->state = BR_STATE_LISTENING; + br_timer_set(&p->forward_delay_timer, jiffies); + } +} + +/* called under bridge lock */ +void br_port_state_selection(struct net_bridge *br) +{ + struct net_bridge_port *p; + + p = br->port_list; + while (p != NULL) { + if (p->state != BR_STATE_DISABLED) { + if (p->port_no == br->root_port) { + p->config_pending = 0; + p->topology_change_ack = 0; + br_make_forwarding(p); + } else if (br_is_designated_port(p)) { + br_timer_clear(&p->message_age_timer); + br_make_forwarding(p); + } else { + p->config_pending = 0; + p->topology_change_ack = 0; + br_make_blocking(p); + } + } + + p = p->next; + } +} + +/* called under bridge lock */ +static void br_topology_change_acknowledge(struct net_bridge_port *p) +{ + p->topology_change_ack = 1; + br_transmit_config(p); +} + +/* lock-safe */ +void br_received_config_bpdu(struct net_bridge_port *p, struct br_config_bpdu *bpdu) +{ + struct net_bridge *br; + int was_root; + + if (p->state == BR_STATE_DISABLED) + return; + + br = p->br; + read_lock(&br->lock); + + was_root = br_is_root_bridge(br); + if (br_supersedes_port_info(p, bpdu)) { + br_record_config_information(p, bpdu); + br_configuration_update(br); + br_port_state_selection(br); + + if (!br_is_root_bridge(br) && was_root) { + br_timer_clear(&br->hello_timer); + if (br->topology_change_detected) { + br_timer_clear(&br->topology_change_timer); + br_transmit_tcn(br); + br_timer_set(&br->tcn_timer, jiffies); + } + } + + if (p->port_no == br->root_port) { + br_record_config_timeout_values(br, bpdu); + br_config_bpdu_generation(br); + if (bpdu->topology_change_ack) + br_topology_change_acknowledged(br); + } + } else if (br_is_designated_port(p)) { + br_reply(p); + } + + read_unlock(&br->lock); +} + +/* lock-safe */ +void br_received_tcn_bpdu(struct net_bridge_port *p) +{ + read_lock(&p->br->lock); + if (p->state != BR_STATE_DISABLED && + br_is_designated_port(p)) { + printk(KERN_INFO "%s: received tcn bpdu on port %i(%s)\n", + p->br->name, p->port_no, p->dev->name); + + br_topology_change_detection(p->br); + br_topology_change_acknowledge(p); + } + read_unlock(&p->br->lock); +} diff -u --recursive --new-file v2.3.46/linux/net/bridge/br_stp_bpdu.c linux/net/bridge/br_stp_bpdu.c --- v2.3.46/linux/net/bridge/br_stp_bpdu.c Wed Dec 31 16:00:00 1969 +++ linux/net/bridge/br_stp_bpdu.c Sun Feb 20 10:41:18 2000 @@ -0,0 +1,191 @@ +/* + * Spanning tree protocol; BPDU handling + * Linux ethernet bridge + * + * Authors: + * Lennert Buytenhek + * + * $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 "br_private.h" +#include "br_private_stp.h" + +#define JIFFIES_TO_TICKS(j) (((j) << 8) / HZ) +#define TICKS_TO_JIFFIES(j) (((j) * HZ) >> 8) + +static void br_send_bpdu(struct net_bridge_port *p, unsigned char *data, int length) +{ + struct net_device *dev; + struct sk_buff *skb; + int size; + + if (!p->br->stp_enabled) + return; + + size = length + 2*ETH_ALEN + 2; + if (size < 60) + size = 60; + + dev = p->dev; + + if ((skb = dev_alloc_skb(size)) == NULL) { + printk(KERN_INFO "br: memory squeeze!\n"); + return; + } + + skb->dev = dev; + skb->mac.raw = skb_put(skb, size); + memcpy(skb->mac.raw, bridge_ula, ETH_ALEN); + memcpy(skb->mac.raw+ETH_ALEN, dev->dev_addr, ETH_ALEN); + skb->mac.raw[2*ETH_ALEN] = 0; + skb->mac.raw[2*ETH_ALEN+1] = length; + skb->nh.raw = skb->mac.raw + 2*ETH_ALEN + 2; + memcpy(skb->nh.raw, data, length); + memset(skb->nh.raw + length, 0xa5, size - length - 2*ETH_ALEN - 2); + + dev_queue_xmit(skb); +} + +static __inline__ void br_set_ticks(unsigned char *dest, int jiff) +{ + __u16 ticks; + + ticks = JIFFIES_TO_TICKS(jiff); + dest[0] = (ticks >> 8) & 0xFF; + dest[1] = ticks & 0xFF; +} + +static __inline__ int br_get_ticks(unsigned char *dest) +{ + return TICKS_TO_JIFFIES((dest[0] << 8) | dest[1]); +} + +/* called under bridge lock */ +void br_send_config_bpdu(struct net_bridge_port *p, struct br_config_bpdu *bpdu) +{ + unsigned char buf[38]; + + buf[0] = 0x42; + buf[1] = 0x42; + buf[2] = 0x03; + buf[3] = 0; + buf[4] = 0; + buf[5] = 0; + buf[6] = BPDU_TYPE_CONFIG; + buf[7] = (bpdu->topology_change ? 0x01 : 0) | + (bpdu->topology_change_ack ? 0x80 : 0); + buf[8] = bpdu->root.prio[0]; + buf[9] = bpdu->root.prio[1]; + buf[10] = bpdu->root.addr[0]; + buf[11] = bpdu->root.addr[1]; + buf[12] = bpdu->root.addr[2]; + buf[13] = bpdu->root.addr[3]; + buf[14] = bpdu->root.addr[4]; + buf[15] = bpdu->root.addr[5]; + buf[16] = (bpdu->root_path_cost >> 24) & 0xFF; + buf[17] = (bpdu->root_path_cost >> 16) & 0xFF; + buf[18] = (bpdu->root_path_cost >> 8) & 0xFF; + buf[19] = bpdu->root_path_cost & 0xFF; + buf[20] = bpdu->bridge_id.prio[0]; + buf[21] = bpdu->bridge_id.prio[1]; + buf[22] = bpdu->bridge_id.addr[0]; + buf[23] = bpdu->bridge_id.addr[1]; + buf[24] = bpdu->bridge_id.addr[2]; + buf[25] = bpdu->bridge_id.addr[3]; + buf[26] = bpdu->bridge_id.addr[4]; + buf[27] = bpdu->bridge_id.addr[5]; + buf[28] = (bpdu->port_id >> 8) & 0xFF; + buf[29] = bpdu->port_id & 0xFF; + + br_set_ticks(buf+30, bpdu->message_age); + br_set_ticks(buf+32, bpdu->max_age); + br_set_ticks(buf+34, bpdu->hello_time); + br_set_ticks(buf+36, bpdu->forward_delay); + + br_send_bpdu(p, buf, 38); +} + +/* called under bridge lock */ +void br_send_tcn_bpdu(struct net_bridge_port *p) +{ + unsigned char buf[7]; + + buf[0] = 0x42; + buf[1] = 0x42; + buf[2] = 0x03; + buf[3] = 0; + buf[4] = 0; + buf[5] = 0; + buf[6] = BPDU_TYPE_TCN; + br_send_bpdu(p, buf, 7); +} + +static unsigned char header[6] = {0x42, 0x42, 0x03, 0x00, 0x00, 0x00}; + +/* called under bridge lock */ +void br_stp_handle_bpdu(struct sk_buff *skb) +{ + unsigned char *buf; + struct net_bridge_port *p; + + buf = skb->mac.raw + 14; + p = skb->dev->br_port; + if (!p->br->stp_enabled || memcmp(buf, header, 6)) { + kfree_skb(skb); + return; + } + + if (buf[6] == BPDU_TYPE_CONFIG) { + struct br_config_bpdu bpdu; + + bpdu.topology_change = (buf[7] & 0x01) ? 1 : 0; + bpdu.topology_change_ack = (buf[7] & 0x80) ? 1 : 0; + bpdu.root.prio[0] = buf[8]; + bpdu.root.prio[1] = buf[9]; + bpdu.root.addr[0] = buf[10]; + bpdu.root.addr[1] = buf[11]; + bpdu.root.addr[2] = buf[12]; + bpdu.root.addr[3] = buf[13]; + bpdu.root.addr[4] = buf[14]; + bpdu.root.addr[5] = buf[15]; + bpdu.root_path_cost = + (buf[16] << 24) | + (buf[17] << 16) | + (buf[18] << 8) | + buf[19]; + bpdu.bridge_id.prio[0] = buf[20]; + bpdu.bridge_id.prio[1] = buf[21]; + bpdu.bridge_id.addr[0] = buf[22]; + bpdu.bridge_id.addr[1] = buf[23]; + bpdu.bridge_id.addr[2] = buf[24]; + bpdu.bridge_id.addr[3] = buf[25]; + bpdu.bridge_id.addr[4] = buf[26]; + bpdu.bridge_id.addr[5] = buf[27]; + bpdu.port_id = (buf[28] << 8) | buf[29]; + + bpdu.message_age = br_get_ticks(buf+30); + bpdu.max_age = br_get_ticks(buf+32); + bpdu.hello_time = br_get_ticks(buf+34); + bpdu.forward_delay = br_get_ticks(buf+36); + + kfree_skb(skb); + br_received_config_bpdu(p, &bpdu); + return; + } + + if (buf[6] == BPDU_TYPE_TCN) { + br_received_tcn_bpdu(p); + kfree_skb(skb); + return; + } + + kfree_skb(skb); +} diff -u --recursive --new-file v2.3.46/linux/net/bridge/br_stp_if.c linux/net/bridge/br_stp_if.c --- v2.3.46/linux/net/bridge/br_stp_if.c Wed Dec 31 16:00:00 1969 +++ linux/net/bridge/br_stp_if.c Sun Feb 20 10:41:18 2000 @@ -0,0 +1,225 @@ +/* + * Spanning tree protocol; interface code + * Linux ethernet bridge + * + * Authors: + * Lennert Buytenhek + * + * $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 "br_private.h" +#include "br_private_stp.h" + +__u16 br_make_port_id(struct net_bridge_port *p) +{ + return (p->priority << 8) | p->port_no; +} + +/* called under bridge lock */ +void br_init_port(struct net_bridge_port *p) +{ + p->port_id = br_make_port_id(p); + br_become_designated_port(p); + p->state = BR_STATE_BLOCKING; + p->topology_change_ack = 0; + p->config_pending = 0; + br_timer_clear(&p->message_age_timer); + br_timer_clear(&p->forward_delay_timer); + br_timer_clear(&p->hold_timer); +} + +/* called under bridge lock */ +void br_stp_enable_bridge(struct net_bridge *br) +{ + struct net_bridge_port *p; + struct timer_list *timer = &br->tick; + + init_timer(timer); + timer->data = (unsigned long) br; + timer->function = br_tick; + timer->expires = jiffies + 1; + add_timer(timer); + + br_timer_set(&br->hello_timer, jiffies); + br_config_bpdu_generation(br); + + p = br->port_list; + while (p != NULL) { + if (p->dev->flags & IFF_UP) + br_stp_enable_port(p); + + p = p->next; + } + + br_timer_set(&br->gc_timer, jiffies); +} + +/* called under bridge lock */ +void br_stp_disable_bridge(struct net_bridge *br) +{ + struct net_bridge_port *p; + + br->topology_change = 0; + br->topology_change_detected = 0; + br_timer_clear(&br->hello_timer); + br_timer_clear(&br->topology_change_timer); + br_timer_clear(&br->tcn_timer); + br_timer_clear(&br->gc_timer); + br_fdb_cleanup(br); + + p = br->port_list; + while (p != NULL) { + if (p->state != BR_STATE_DISABLED) + br_stp_disable_port(p); + + p = p->next; + } + + del_timer(&br->tick); +} + +/* called under bridge lock */ +void br_stp_enable_port(struct net_bridge_port *p) +{ + br_init_port(p); + br_port_state_selection(p->br); +} + +/* called under bridge lock */ +void br_stp_disable_port(struct net_bridge_port *p) +{ + struct net_bridge *br; + int wasroot; + + br = p->br; + printk(KERN_INFO "%s: port %i(%s) entering %s state\n", + br->name, p->port_no, p->dev->name, "disabled"); + + wasroot = br_is_root_bridge(br); + br_become_designated_port(p); + p->state = BR_STATE_DISABLED; + p->topology_change_ack = 0; + p->config_pending = 0; + br_timer_clear(&p->message_age_timer); + br_timer_clear(&p->forward_delay_timer); + br_timer_clear(&p->hold_timer); + br_configuration_update(br); + br_port_state_selection(br); + + if (br_is_root_bridge(br) && !wasroot) + br_become_root_bridge(br); +} + +/* called under bridge lock */ +static void br_stp_change_bridge_id(struct net_bridge *br, unsigned char *addr) +{ + unsigned char oldaddr[6]; + struct net_bridge_port *p; + int wasroot; + + wasroot = br_is_root_bridge(br); + + memcpy(oldaddr, br->bridge_id.addr, ETH_ALEN); + memcpy(br->bridge_id.addr, addr, ETH_ALEN); + memcpy(br->dev.dev_addr, addr, ETH_ALEN); + + p = br->port_list; + while (p != NULL) { + if (!memcmp(p->designated_bridge.addr, oldaddr, ETH_ALEN)) + memcpy(p->designated_bridge.addr, addr, ETH_ALEN); + + if (!memcmp(p->designated_root.addr, oldaddr, ETH_ALEN)) + memcpy(p->designated_root.addr, addr, ETH_ALEN); + + p = p->next; + } + + br_configuration_update(br); + br_port_state_selection(br); + if (br_is_root_bridge(br) && !wasroot) + br_become_root_bridge(br); +} + +static unsigned char br_mac_zero[6] = {0,0,0,0,0,0}; + +/* called under bridge lock */ +void br_stp_recalculate_bridge_id(struct net_bridge *br) +{ + unsigned char *addr; + struct net_bridge_port *p; + + addr = br_mac_zero; + + p = br->port_list; + while (p != NULL) { + if (addr == br_mac_zero || + memcmp(p->dev->dev_addr, addr, ETH_ALEN) < 0) + addr = p->dev->dev_addr; + + p = p->next; + } + + if (memcmp(br->bridge_id.addr, addr, ETH_ALEN)) + br_stp_change_bridge_id(br, addr); +} + +/* called under bridge lock */ +void br_stp_set_bridge_priority(struct net_bridge *br, int newprio) +{ + struct net_bridge_port *p; + int wasroot; + + wasroot = br_is_root_bridge(br); + + p = br->port_list; + while (p != NULL) { + if (p->state != BR_STATE_DISABLED && + br_is_designated_port(p)) { + p->designated_bridge.prio[0] = (newprio >> 8) & 0xFF; + p->designated_bridge.prio[1] = newprio & 0xFF; + } + + p = p->next; + } + + br->bridge_id.prio[0] = (newprio >> 8) & 0xFF; + br->bridge_id.prio[1] = newprio & 0xFF; + br_configuration_update(br); + br_port_state_selection(br); + if (br_is_root_bridge(br) && !wasroot) + br_become_root_bridge(br); +} + +/* called under bridge lock */ +void br_stp_set_port_priority(struct net_bridge_port *p, int newprio) +{ + int new_port_id = ((newprio & 0xFF) << 8) | p->port_no; + + if (br_is_designated_port(p)) + p->designated_port = new_port_id; + + p->port_id = new_port_id; + if (!memcmp(&p->br->bridge_id, &p->designated_bridge, 8) && + p->port_id < p->designated_port) { + br_become_designated_port(p); + br_port_state_selection(p->br); + } +} + +/* called under bridge lock */ +void br_stp_set_path_cost(struct net_bridge_port *p, int path_cost) +{ + p->path_cost = path_cost; + br_configuration_update(p->br); + br_port_state_selection(p->br); +} diff -u --recursive --new-file v2.3.46/linux/net/bridge/br_stp_timer.c linux/net/bridge/br_stp_timer.c --- v2.3.46/linux/net/bridge/br_stp_timer.c Wed Dec 31 16:00:00 1969 +++ linux/net/bridge/br_stp_timer.c Sun Feb 20 10:41:18 2000 @@ -0,0 +1,184 @@ +/* + * Spanning tree protocol; timer-related code + * Linux ethernet bridge + * + * Authors: + * Lennert Buytenhek + * + * $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 "br_private.h" +#include "br_private_stp.h" + +static void dump_bridge_id(bridge_id *id) +{ + printk("%.2x%.2x.%.2x:%.2x:%.2x:%.2x:%.2x:%.2x", id->prio[0], + id->prio[1], id->addr[0], id->addr[1], id->addr[2], id->addr[3], + id->addr[4], id->addr[5]); +} + +/* called under bridge lock */ +static int br_is_designated_for_some_port(struct net_bridge *br) +{ + struct net_bridge_port *p; + + p = br->port_list; + while (p != NULL) { + if (p->state != BR_STATE_DISABLED && + !memcmp(&p->designated_bridge, &br->bridge_id, 8)) + return 1; + + p = p->next; + } + + return 0; +} + +/* called under bridge lock */ +static void br_hello_timer_expired(struct net_bridge *br) +{ + br_config_bpdu_generation(br); + br_timer_set(&br->hello_timer, jiffies); +} + +/* called under bridge lock */ +static void br_message_age_timer_expired(struct net_bridge_port *p) +{ + struct net_bridge *br; + int was_root; + + br = p->br; + printk(KERN_INFO "%s: ", br->name); + printk("neighbour "); + dump_bridge_id(&p->designated_bridge); + printk(" lost on port %i(%s)\n", p->port_no, p->dev->name); + + /* + * According to the spec, the message age timer cannot be + * running when we are the root bridge. So.. this was_root + * check is redundant. I'm leaving it in for now, though. + */ + was_root = br_is_root_bridge(br); + + br_become_designated_port(p); + br_configuration_update(br); + br_port_state_selection(br); + if (br_is_root_bridge(br) && !was_root) + br_become_root_bridge(br); +} + +/* called under bridge lock */ +static void br_forward_delay_timer_expired(struct net_bridge_port *p) +{ + if (p->state == BR_STATE_LISTENING) { + printk(KERN_INFO "%s: port %i(%s) entering %s state\n", + p->br->name, p->port_no, p->dev->name, "learning"); + + p->state = BR_STATE_LEARNING; + br_timer_set(&p->forward_delay_timer, jiffies); + } else if (p->state == BR_STATE_LEARNING) { + printk(KERN_INFO "%s: port %i(%s) entering %s state\n", + p->br->name, p->port_no, p->dev->name, "forwarding"); + + p->state = BR_STATE_FORWARDING; + if (br_is_designated_for_some_port(p->br)) + br_topology_change_detection(p->br); + } +} + +/* called under bridge lock */ +static void br_tcn_timer_expired(struct net_bridge *br) +{ + printk(KERN_INFO "%s: retransmitting tcn bpdu\n", br->name); + br_transmit_tcn(br); + br_timer_set(&br->tcn_timer, jiffies); +} + +/* called under bridge lock */ +static void br_topology_change_timer_expired(struct net_bridge *br) +{ + br->topology_change_detected = 0; + br->topology_change = 0; +} + +/* called under bridge lock */ +static void br_hold_timer_expired(struct net_bridge_port *p) +{ + if (p->config_pending) + br_transmit_config(p); +} + +/* called under bridge lock */ +static void br_check_port_timers(struct net_bridge_port *p) +{ + if (br_timer_has_expired(&p->message_age_timer, p->br->max_age)) { + br_timer_clear(&p->message_age_timer); + br_message_age_timer_expired(p); + } + + if (br_timer_has_expired(&p->forward_delay_timer, p->br->forward_delay)) { + br_timer_clear(&p->forward_delay_timer); + br_forward_delay_timer_expired(p); + } + + if (br_timer_has_expired(&p->hold_timer, BR_HOLD_TIME)) { + br_timer_clear(&p->hold_timer); + br_hold_timer_expired(p); + } +} + +/* called under bridge lock */ +static void br_check_timers(struct net_bridge *br) +{ + struct net_bridge_port *p; + + if (br_timer_has_expired(&br->gc_timer, br->gc_interval)) { + br_timer_set(&br->gc_timer, jiffies); + br_fdb_cleanup(br); + } + + if (br_timer_has_expired(&br->hello_timer, br->hello_time)) { + br_timer_clear(&br->hello_timer); + br_hello_timer_expired(br); + } + + if (br_timer_has_expired(&br->tcn_timer, br->bridge_hello_time)) { + br_timer_clear(&br->tcn_timer); + br_tcn_timer_expired(br); + } + + if (br_timer_has_expired(&br->topology_change_timer, br->bridge_forward_delay + br->bridge_max_age)) { + br_timer_clear(&br->topology_change_timer); + br_topology_change_timer_expired(br); + } + + p = br->port_list; + while (p != NULL) { + if (p->state != BR_STATE_DISABLED) + br_check_port_timers(p); + + p = p->next; + } +} + +void br_tick(unsigned long __data) +{ + struct net_bridge *br = (struct net_bridge *)__data; + + read_lock(&br->lock); + br_check_timers(br); + read_unlock(&br->lock); + + br->tick.expires = jiffies + 1; + add_timer(&br->tick); +} diff -u --recursive --new-file v2.3.46/linux/net/bridge/br_tree.c linux/net/bridge/br_tree.c --- v2.3.46/linux/net/bridge/br_tree.c Wed Dec 29 13:13:21 1999 +++ linux/net/bridge/br_tree.c Wed Dec 31 16:00:00 1969 @@ -1,501 +0,0 @@ -/* - * This code is derived from the avl functions in mmap.c - */ - -#include -#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 -u --recursive --new-file v2.3.46/linux/net/bridge/sysctl_net_bridge.c linux/net/bridge/sysctl_net_bridge.c --- v2.3.46/linux/net/bridge/sysctl_net_bridge.c Mon Jun 3 02:42:41 1996 +++ linux/net/bridge/sysctl_net_bridge.c Wed Dec 31 16:00:00 1969 @@ -1,13 +0,0 @@ -/* -*- linux-c -*- - * sysctl_net_bridge.c: sysctl interface to net bridge subsystem. - * - * Begun June 1, 1996, Mike Shaver. - * Added /proc/sys/net/bridge directory entry (empty =) ). [MS] - */ - -#include -#include - -ctl_table bridge_table[] = { - {0} -}; diff -u --recursive --new-file v2.3.46/linux/net/core/dev.c linux/net/core/dev.c --- v2.3.46/linux/net/core/dev.c Sun Feb 13 19:29:04 2000 +++ linux/net/core/dev.c Sun Feb 20 20:14:55 2000 @@ -81,7 +81,7 @@ #include #include #include -#include +#include #include #include #include @@ -190,14 +190,11 @@ dev_clear_fastroute(pt->dev); } #endif - if(pt->type==htons(ETH_P_ALL)) - { + if (pt->type == htons(ETH_P_ALL)) { netdev_nit++; pt->next=ptype_all; ptype_all=pt; - } - else - { + } else { hash=ntohs(pt->type)&15; pt->next = ptype_base[hash]; ptype_base[hash] = pt; @@ -216,19 +213,16 @@ write_lock_bh(&ptype_lock); - if(pt->type==htons(ETH_P_ALL)) - { + if (pt->type == htons(ETH_P_ALL)) { netdev_nit--; pt1=&ptype_all; - } - else + } else { pt1=&ptype_base[ntohs(pt->type)&15]; + } - for(; (*pt1)!=NULL; pt1=&((*pt1)->next)) - { - if(pt==(*pt1)) - { - *pt1=pt->next; + for (; (*pt1) != NULL; pt1 = &((*pt1)->next)) { + if (pt == (*pt1)) { + *pt1 = pt->next; #ifdef CONFIG_NET_FASTROUTE if (pt->data) netdev_fastroute_obstacles--; @@ -357,14 +351,13 @@ { int i; char buf[32]; + /* * If you need over 100 please also fix the algorithm... */ - for(i=0;i<100;i++) - { + for (i = 0; i < 100; i++) { sprintf(buf,name,i); - if(__dev_get_by_name(buf)==NULL) - { + if (__dev_get_by_name(buf) == NULL) { strcpy(dev->name, buf); return i; } @@ -375,16 +368,14 @@ struct net_device *dev_alloc(const char *name, int *err) { struct net_device *dev=kmalloc(sizeof(struct net_device)+16, GFP_KERNEL); - if(dev==NULL) - { - *err=-ENOBUFS; + if (dev == NULL) { + *err = -ENOBUFS; return NULL; } memset(dev, 0, sizeof(struct net_device)); - dev->name=(char *)(dev+1); /* Name string space */ - *err=dev_alloc_name(dev,name); - if(*err<0) - { + dev->name = (char *)(dev + 1); /* Name string space */ + *err = dev_alloc_name(dev, name); + if (*err < 0) { kfree(dev); return NULL; } @@ -408,7 +399,7 @@ void dev_load(const char *name) { - if(!__dev_get_by_name(name) && capable(CAP_SYS_MODULE)) + if (!__dev_get_by_name(name) && capable(CAP_SYS_MODULE)) request_module(name); } @@ -441,6 +432,12 @@ return 0; /* + * Is it even present? + */ + if (!netif_device_present(dev)) + return -ENODEV; + + /* * Call device private open method */ @@ -458,7 +455,7 @@ */ dev->flags |= IFF_UP; - set_bit(LINK_STATE_START, &dev->state); + set_bit(__LINK_STATE_START, &dev->state); /* * Initialize multicasting status @@ -528,11 +525,14 @@ dev_deactivate(dev); - clear_bit(LINK_STATE_START, &dev->state); + clear_bit(__LINK_STATE_START, &dev->state); /* * Call the device specific close. This cannot fail. * Only if device is UP + * + * We allow it to be called even after a DETACH hot-plug + * event. */ if (dev->stop) @@ -673,7 +673,7 @@ spin_lock(&dev->xmit_lock); dev->xmit_lock_owner = cpu; - if (!test_bit(LINK_STATE_XOFF, &dev->state)) { + if (!netif_queue_stopped(dev)) { if (netdev_nit) dev_queue_xmit_nit(skb,dev); @@ -781,7 +781,7 @@ struct softnet_data *queue; unsigned long flags; - if(skb->stamp.tv_sec==0) + if (skb->stamp.tv_sec == 0) get_fast_time(&skb->stamp); /* The code is rearranged so that the path is the most @@ -833,37 +833,6 @@ kfree_skb(skb); } -#ifdef CONFIG_BRIDGE -static inline void handle_bridge(struct sk_buff *skb, unsigned short type) -{ - /* - * The br_stats.flags is checked here to save the expense of a - * function call. - */ - if ((br_stats.flags & BR_UP) && br_call_bridge(skb, type)) - { - /* - * We pass the bridge a complete frame. This means - * recovering the MAC header first. - */ - - int offset; - - skb=skb_clone(skb, GFP_ATOMIC); - if(skb==NULL) - return; - - offset=skb->data-skb->mac.raw; - skb_push(skb,offset); /* Put header back on for bridge */ - - if(br_receive_frame(skb)) - return; - kfree_skb(skb); - } - return; -} -#endif - /* Deliver skb to an old protocol, which is not threaded well or which do not understand shared skbs. */ @@ -941,7 +910,7 @@ struct net_device *dev = head; head = head->next_sched; - clear_bit(LINK_STATE_SCHED, &dev->state); + clear_bit(__LINK_STATE_SCHED, &dev->state); if (spin_trylock(&dev->queue_lock)) { qdisc_run(dev); @@ -953,6 +922,32 @@ } } +void net_call_rx_atomic(void (*fn)(void)) +{ + write_lock_bh(&ptype_lock); + fn(); + write_unlock_bh(&ptype_lock); +} + +#if defined(CONFIG_BRIDGE) || defined(CONFIG_BRIDGE_MODULE) +void (*br_handle_frame_hook)(struct sk_buff *skb) = NULL; +#endif + +#define HANDLE_BRIDGE(SKB, PT_PREV) \ +do { \ + if ((SKB)->dev->br_port != NULL && \ + br_handle_frame_hook != NULL) { \ + if (PT_PREV) \ + if (!(PT_PREV->data)) \ + deliver_to_old_ones(PT_PREV, SKB, 1); \ + else \ + pt_prev->func(SKB, SKB->dev, PT_PREV); \ + \ + br_handle_frame_hook(SKB); \ + continue; \ + } \ +} while(0) + static void net_rx_action(struct softirq_action *h) { int this_cpu = smp_processor_id(); @@ -985,9 +980,7 @@ { struct packet_type *ptype, *pt_prev; unsigned short type = skb->protocol; -#ifdef CONFIG_BRIDGE - handle_bridge(skb, type); -#endif + pt_prev = NULL; for (ptype = ptype_all; ptype; ptype = ptype->next) { if (!ptype->dev || ptype->dev == skb->dev) { @@ -1004,6 +997,11 @@ pt_prev = ptype; } } + +#if defined(CONFIG_BRIDGE) || defined(CONFIG_BRIDGE_MODULE) + HANDLE_BRIDGE(skb, pt_prev); +#endif + for (ptype=ptype_base[ntohs(type)&15];ptype;ptype=ptype->next) { if (ptype->type == type && (!ptype->dev || ptype->dev == skb->dev)) { @@ -1020,6 +1018,7 @@ pt_prev = ptype; } } + if (pt_prev) { if (!pt_prev->data) deliver_to_old_ones(pt_prev, skb, 1); @@ -1212,11 +1211,10 @@ static int dev_get_info(char *buffer, char **start, off_t offset, int length) { - int len=0; - off_t begin=0; - off_t pos=0; + int len = 0; + off_t begin = 0; + off_t pos = 0; int size; - struct net_device *dev; @@ -1224,31 +1222,31 @@ "Inter-| Receive | Transmit\n" " face |bytes packets errs drop fifo frame compressed multicast|bytes packets errs drop fifo colls carrier compressed\n"); - pos+=size; - len+=size; + pos += size; + len += size; read_lock(&dev_base_lock); for (dev = dev_base; dev != NULL; dev = dev->next) { size = sprintf_stats(buffer+len, dev); - len+=size; - pos=begin+len; + len += size; + pos = begin + len; - if(posoffset+length) + if (pos > offset + length) break; } read_unlock(&dev_base_lock); - *start=buffer+(offset-begin); /* Start of wanted data */ - len-=(offset-begin); /* Start slop */ - if(len>length) - len=length; /* Ending slop */ - if (len<0) - len=0; + *start = buffer + (offset - begin); /* Start of wanted data */ + len -= (offset - begin); /* Start slop */ + if (len > length) + len = length; /* Ending slop */ + if (len < 0) + len = 0; return len; } @@ -1280,7 +1278,7 @@ if (len > length) len = length; - if(len < 0) + if (len < 0) len = 0; *start = buffer + offset; @@ -1307,8 +1305,7 @@ (struct iw_statistics *) NULL); int size; - if(stats != (struct iw_statistics *) NULL) - { + if (stats != (struct iw_statistics *) NULL) { size = sprintf(buffer, "%6s: %04x %3d%c %3d%c %3d%c %6d %6d %6d\n", dev->name, @@ -1349,30 +1346,30 @@ " face | tus | link level noise | nwid crypt misc\n" ); - pos+=size; - len+=size; + pos += size; + len += size; read_lock(&dev_base_lock); - for(dev = dev_base; dev != NULL; dev = dev->next) { - size = sprintf_wireless_stats(buffer+len, dev); - len+=size; - pos=begin+len; - - if(pos < offset) { - len=0; - begin=pos; + for (dev = dev_base; dev != NULL; dev = dev->next) { + size = sprintf_wireless_stats(buffer + len, dev); + len += size; + pos = begin + len; + + if (pos < offset) { + len = 0; + begin = pos; } - if(pos > offset + length) + if (pos > offset + length) break; } read_unlock(&dev_base_lock); *start = buffer + (offset - begin); /* Start of wanted data */ len -= (offset - begin); /* Start slop */ - if(len > length) - len = length; /* Ending slop */ - if (len<0) - len=0; + if (len > length) + len = length; /* Ending slop */ + if (len < 0) + len = 0; return len; } @@ -1516,7 +1513,7 @@ case SIOCGIFFLAGS: /* Get interface flags */ ifr->ifr_flags = (dev->flags&~(IFF_PROMISC|IFF_ALLMULTI|IFF_RUNNING)) |(dev->gflags&(IFF_PROMISC|IFF_ALLMULTI)); - if (!test_bit(LINK_STATE_DOWN, &dev->state)) + if (netif_running(dev)) ifr->ifr_flags |= IFF_RUNNING; return 0; @@ -1545,6 +1542,9 @@ if (ifr->ifr_mtu<0) return -EINVAL; + if (!netif_device_present(dev)) + return -ENODEV; + if (dev->change_mtu) err = dev->change_mtu(dev, ifr->ifr_mtu); else { @@ -1561,17 +1561,19 @@ return 0; case SIOCSIFHWADDR: - if(dev->set_mac_address==NULL) + if (dev->set_mac_address == NULL) return -EOPNOTSUPP; - if(ifr->ifr_hwaddr.sa_family!=dev->type) + if (ifr->ifr_hwaddr.sa_family!=dev->type) return -EINVAL; - err=dev->set_mac_address(dev,&ifr->ifr_hwaddr); + if (!netif_device_present(dev)) + return -ENODEV; + err = dev->set_mac_address(dev, &ifr->ifr_hwaddr); if (!err) notifier_call_chain(&netdev_chain, NETDEV_CHANGEADDR, dev); return err; case SIOCSIFHWBROADCAST: - if(ifr->ifr_hwaddr.sa_family!=dev->type) + if (ifr->ifr_hwaddr.sa_family!=dev->type) return -EINVAL; memcpy(dev->broadcast, ifr->ifr_hwaddr.sa_data, MAX_ADDR_LEN); notifier_call_chain(&netdev_chain, NETDEV_CHANGEADDR, dev); @@ -1587,21 +1589,28 @@ return 0; case SIOCSIFMAP: - if (dev->set_config) + if (dev->set_config) { + if (!netif_device_present(dev)) + return -ENODEV; return dev->set_config(dev,&ifr->ifr_map); + } return -EOPNOTSUPP; case SIOCADDMULTI: - if(dev->set_multicast_list==NULL || - ifr->ifr_hwaddr.sa_family!=AF_UNSPEC) + if (dev->set_multicast_list == NULL || + ifr->ifr_hwaddr.sa_family != AF_UNSPEC) return -EINVAL; + if (!netif_device_present(dev)) + return -ENODEV; dev_mc_add(dev,ifr->ifr_hwaddr.sa_data, dev->addr_len, 1); return 0; case SIOCDELMULTI: - if(dev->set_multicast_list==NULL || - ifr->ifr_hwaddr.sa_family!=AF_UNSPEC) + if (dev->set_multicast_list == NULL || + ifr->ifr_hwaddr.sa_family!=AF_UNSPEC) return -EINVAL; + if (!netif_device_present(dev)) + return -ENODEV; dev_mc_delete(dev,ifr->ifr_hwaddr.sa_data,dev->addr_len, 1); return 0; @@ -1614,7 +1623,7 @@ return 0; case SIOCSIFTXQLEN: - if(ifr->ifr_qlen<0) + if (ifr->ifr_qlen<0) return -EINVAL; dev->tx_queue_len = ifr->ifr_qlen; return 0; @@ -1634,17 +1643,23 @@ */ default: - if(cmd >= SIOCDEVPRIVATE && - cmd <= SIOCDEVPRIVATE + 15) { - if (dev->do_ioctl) + if (cmd >= SIOCDEVPRIVATE && + cmd <= SIOCDEVPRIVATE + 15) { + if (dev->do_ioctl) { + if (!netif_device_present(dev)) + return -ENODEV; return dev->do_ioctl(dev, ifr, cmd); + } return -EOPNOTSUPP; } #ifdef WIRELESS_EXT - if(cmd >= SIOCIWFIRST && cmd <= SIOCIWLAST) { - if (dev->do_ioctl) + if (cmd >= SIOCIWFIRST && cmd <= SIOCIWLAST) { + if (dev->do_ioctl) { + if (!netif_device_present(dev)) + return -ENODEV; return dev->do_ioctl(dev, ifr, cmd); + } return -EOPNOTSUPP; } #endif /* WIRELESS_EXT */ @@ -1868,6 +1883,13 @@ if (dev->rebuild_header == NULL) dev->rebuild_header = default_rebuild_header; + /* + * Default initial state at registry is that the + * device is present. + */ + + set_bit(__LINK_STATE_PRESENT, &dev->state); + dev->next = NULL; dev_init_scheduler(dev); write_lock_bh(&dev_base_lock); @@ -2048,15 +2070,6 @@ queue->completion_queue = NULL; } - /* - * The bridge has to be up before the devices - */ - -#ifdef CONFIG_BRIDGE - br_init(); -#endif - - #ifdef CONFIG_NET_PROFILE net_profile_init(); NET_PROFILE_REGISTER(dev_queue_xmit); @@ -2124,22 +2137,11 @@ dst_init(); dev_mcast_init(); -#ifdef CONFIG_BRIDGE - /* - * Register any statically linked ethernet devices with the bridge - */ - br_spacedevice_register(); -#endif - /* * Initialise network devices */ net_device_init(); - -#ifdef CONFIG_IP_PNP - ip_auto_config(); -#endif return 0; } diff -u --recursive --new-file v2.3.46/linux/net/core/dev_mcast.c linux/net/core/dev_mcast.c --- v2.3.46/linux/net/core/dev_mcast.c Mon Nov 1 13:56:27 1999 +++ linux/net/core/dev_mcast.c Thu Feb 17 09:18:47 2000 @@ -71,17 +71,20 @@ void dev_mc_upload(struct net_device *dev) { /* Don't do anything till we up the interface - [dev_open will call this function so the list will - stay sane] */ + * [dev_open will call this function so the list will + * stay sane] + */ - if(!(dev->flags&IFF_UP)) + if (!(dev->flags&IFF_UP)) return; /* - * Devices with no set multicast don't get set + * Devices with no set multicast or which have been + * detached don't get set. */ - if(dev->set_multicast_list==NULL) + if (dev->set_multicast_list == NULL || + !netif_device_present(dev)) return; read_lock_bh(&dev_mc_lock); @@ -103,19 +106,20 @@ struct dev_mc_list *dmi, **dmip; write_lock_bh(&dev_mc_lock); - for (dmip=&dev->mc_list; (dmi=*dmip)!=NULL; dmip=&dmi->next) { + for (dmip = &dev->mc_list; (dmi = *dmip) != NULL; dmip = &dmi->next) { /* * Find the entry we want to delete. The device could * have variable length entries so check these too. */ - if (memcmp(dmi->dmi_addr,addr,dmi->dmi_addrlen)==0 && alen==dmi->dmi_addrlen) { + if (memcmp(dmi->dmi_addr, addr, dmi->dmi_addrlen) == 0 && + alen == dmi->dmi_addrlen) { if (glbl) { int old_glbl = dmi->dmi_gusers; dmi->dmi_gusers = 0; if (old_glbl == 0) break; } - if(--dmi->dmi_users) + if (--dmi->dmi_users) goto done; /* @@ -125,7 +129,7 @@ dev->mc_count--; write_unlock_bh(&dev_mc_lock); - kfree_s(dmi,sizeof(*dmi)); + kfree_s(dmi, sizeof(*dmi)); /* * We have altered the list, so the card @@ -153,8 +157,9 @@ dmi1 = (struct dev_mc_list *)kmalloc(sizeof(*dmi), GFP_ATOMIC); write_lock_bh(&dev_mc_lock); - for(dmi=dev->mc_list; dmi!=NULL; dmi=dmi->next) { - if (memcmp(dmi->dmi_addr,addr,dmi->dmi_addrlen)==0 && dmi->dmi_addrlen==alen) { + for (dmi = dev->mc_list; dmi != NULL; dmi = dmi->next) { + if (memcmp(dmi->dmi_addr, addr, dmi->dmi_addrlen) == 0 && + dmi->dmi_addrlen == alen) { if (glbl) { int old_glbl = dmi->dmi_gusers; dmi->dmi_gusers = 1; @@ -166,16 +171,16 @@ } } - if ((dmi=dmi1)==NULL) { + if ((dmi = dmi1) == NULL) { write_unlock_bh(&dev_mc_lock); return -ENOMEM; } memcpy(dmi->dmi_addr, addr, alen); - dmi->dmi_addrlen=alen; - dmi->next=dev->mc_list; - dmi->dmi_users=1; - dmi->dmi_gusers=glbl ? 1 : 0; - dev->mc_list=dmi; + dmi->dmi_addrlen = alen; + dmi->next = dev->mc_list; + dmi->dmi_users = 1; + dmi->dmi_gusers = glbl ? 1 : 0; + dev->mc_list = dmi; dev->mc_count++; write_unlock_bh(&dev_mc_lock); dev_mc_upload(dev); @@ -195,14 +200,14 @@ void dev_mc_discard(struct net_device *dev) { write_lock_bh(&dev_mc_lock); - while (dev->mc_list!=NULL) { - struct dev_mc_list *tmp=dev->mc_list; - dev->mc_list=tmp->next; + while (dev->mc_list != NULL) { + struct dev_mc_list *tmp = dev->mc_list; + dev->mc_list = tmp->next; if (tmp->dmi_users > tmp->dmi_gusers) printk("dev_mc_discard: multicast leakage! dmi_users=%d\n", tmp->dmi_users); - kfree_s(tmp,sizeof(*tmp)); + kfree_s(tmp, sizeof(*tmp)); } - dev->mc_count=0; + dev->mc_count = 0; write_unlock_bh(&dev_mc_lock); } @@ -210,9 +215,9 @@ static int dev_mc_read_proc(char *buffer, char **start, off_t offset, int length, int *eof, void *data) { - off_t pos=0, begin=0; + off_t pos = 0, begin = 0; struct dev_mc_list *m; - int len=0; + int len = 0; struct net_device *dev; read_lock(&dev_base_lock); @@ -221,20 +226,20 @@ for (m = dev->mc_list; m; m = m->next) { int i; - len += sprintf(buffer+len,"%-4d %-15s %-5d %-5d ", dev->ifindex, dev->name, - m->dmi_users, m->dmi_gusers); + len += sprintf(buffer+len,"%-4d %-15s %-5d %-5d ", dev->ifindex, + dev->name, m->dmi_users, m->dmi_gusers); - for (i=0; idmi_addrlen; i++) + for (i = 0; i < m->dmi_addrlen; i++) len += sprintf(buffer+len, "%02x", m->dmi_addr[i]); - len+=sprintf(buffer+len, "\n"); + len += sprintf(buffer+len, "\n"); - pos=begin+len; + pos = begin + len; if (pos < offset) { - len=0; - begin=pos; + len = 0; + begin = pos; } - if (pos > offset+length) { + if (pos > offset + length) { read_unlock_bh(&dev_mc_lock); goto done; } @@ -245,12 +250,12 @@ done: read_unlock(&dev_base_lock); - *start=buffer+(offset-begin); - len-=(offset-begin); - if(len>length) - len=length; - if(len<0) - len=0; + *start = buffer + (offset - begin); + len -= (offset - begin); + if (len > length) + len = length; + if (len < 0) + len = 0; return len; } #endif diff -u --recursive --new-file v2.3.46/linux/net/core/profile.c linux/net/core/profile.c --- v2.3.46/linux/net/core/profile.c Mon Nov 1 13:56:27 1999 +++ linux/net/core/profile.c Sun Feb 20 20:21:25 2000 @@ -271,12 +271,6 @@ register_netdevice(&whitehole_dev); printk("Evaluating net profiler cost ..."); -#if CPU == 586 || CPU == 686 - if (!(boot_cpu_data.x86_capability & X86_FEATURE_TSC)) { - printk(KERN_ERR "Sorry, your CPU does not support TSC. Net profiler disabled.\n"); - return -1; - } -#endif #ifdef __alpha__ alpha_tick(0); #endif diff -u --recursive --new-file v2.3.46/linux/net/core/rtnetlink.c linux/net/core/rtnetlink.c --- v2.3.46/linux/net/core/rtnetlink.c Thu Feb 10 17:11:24 2000 +++ linux/net/core/rtnetlink.c Thu Feb 17 09:18:47 2000 @@ -171,7 +171,7 @@ r->ifi_flags = dev->flags; r->ifi_change = change; - if (test_bit(LINK_STATE_DOWN, &dev->state)) + if (! netif_running(dev)) r->ifi_flags &= ~IFF_RUNNING; else r->ifi_flags |= IFF_RUNNING; diff -u --recursive --new-file v2.3.46/linux/net/core/skbuff.c linux/net/core/skbuff.c --- v2.3.46/linux/net/core/skbuff.c Sat Feb 12 11:22:11 2000 +++ linux/net/core/skbuff.c Fri Feb 18 14:51:22 2000 @@ -4,7 +4,7 @@ * Authors: Alan Cox * 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 @@ skb->destructor = NULL; skb->pkt_type = PACKET_HOST; /* Default type */ - skb->pkt_bridged = 0; /* Not bridged */ skb->prev = skb->next = NULL; skb->list = NULL; skb->sk = NULL; diff -u --recursive --new-file v2.3.46/linux/net/ipv4/af_inet.c linux/net/ipv4/af_inet.c --- v2.3.46/linux/net/ipv4/af_inet.c Thu Feb 10 17:11:24 2000 +++ linux/net/ipv4/af_inet.c Fri Feb 18 14:51:22 2000 @@ -5,7 +5,7 @@ * * PF_INET protocol family socket handler. * - * Version: $Id: af_inet.c,v 1.106 2000/02/04 21:04:06 davem Exp $ + * Version: $Id: af_inet.c,v 1.107 2000/02/18 16:47:20 davem Exp $ * * Authors: Ross Biro, * 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 @@ int (*dlci_ioctl_hook)(unsigned int, void *) = NULL; #endif +int (*br_ioctl_hook)(unsigned long) = NULL; + /* New destruction routine */ void inet_sock_destruct(struct sock *sk) @@ -837,14 +837,14 @@ return(devinet_ioctl(cmd,(void *) arg)); case SIOCGIFBR: case SIOCSIFBR: -#ifdef CONFIG_BRIDGE - lock_kernel(); - err = br_ioctl(cmd,(void *) arg); - unlock_kernel(); - return err; -#else +#ifdef CONFIG_KMOD + if (br_ioctl_hook == NULL) + request_module("bridge"); +#endif + if (br_ioctl_hook != NULL) + return br_ioctl_hook(arg); + return -ENOPKG; -#endif case SIOCADDDLCI: case SIOCDELDLCI: diff -u --recursive --new-file v2.3.46/linux/net/ipv4/ipconfig.c linux/net/ipv4/ipconfig.c --- v2.3.46/linux/net/ipv4/ipconfig.c Tue Feb 1 01:35:44 2000 +++ linux/net/ipv4/ipconfig.c Sun Feb 20 20:14:55 2000 @@ -821,7 +821,7 @@ * IP Autoconfig dispatcher. */ -int __init ip_auto_config(void) +static int __init ip_auto_config(void) { if (!ic_enable) return 0; @@ -878,6 +878,9 @@ system_utsname.domainname, root_server_path)); return 0; } + +module_init(ip_auto_config); + /* * Decode any IP configuration options in the "ip=" or "nfsaddrs=" kernel diff -u --recursive --new-file v2.3.46/linux/net/ipv4/tcp_output.c linux/net/ipv4/tcp_output.c --- v2.3.46/linux/net/ipv4/tcp_output.c Thu Feb 10 17:11:24 2000 +++ linux/net/ipv4/tcp_output.c Sun Feb 20 20:23:20 2000 @@ -857,11 +857,15 @@ } } else { /* Socket is locked, keep trying until memory is available. */ - do { + for (;;) { skb = sock_wmalloc(sk, MAX_TCP_HEADER + 15, 1, GFP_KERNEL); - } while (skb == NULL); + if (skb) + break; + current->policy |= SCHED_YIELD; + schedule(); + } /* Reserve space for headers and prepare control bits. */ skb_reserve(skb, MAX_TCP_HEADER); diff -u --recursive --new-file v2.3.46/linux/net/irda/irlan/irlan_client.c linux/net/irda/irlan/irlan_client.c --- v2.3.46/linux/net/irda/irlan/irlan_client.c Sun Feb 13 19:29:04 2000 +++ linux/net/irda/irlan/irlan_client.c Thu Feb 17 09:18:47 2000 @@ -126,7 +126,7 @@ * is up, that means that the "user" really wants to connect. If not * we notify the user about the possibility of an IrLAN connection */ - if (test_bit(LINK_STATE_START, &self->dev.state)) { + if (netif_running(&self->dev)) { /* Open TSAPs */ irlan_client_open_ctrl_tsap(self); irlan_open_data_tsap(self); diff -u --recursive --new-file v2.3.46/linux/net/irda/irlan/irlan_common.c linux/net/irda/irlan/irlan_common.c --- v2.3.46/linux/net/irda/irlan/irlan_common.c Sun Feb 13 19:29:04 2000 +++ linux/net/irda/irlan/irlan_common.c Thu Feb 17 09:18:47 2000 @@ -120,7 +120,7 @@ ASSERT(self->magic == IRLAN_MAGIC, return;); /* Check if device still configured */ - if (test_bit(LINK_STATE_START, &self->dev.state)) { + if (netif_running(&self->dev)) { IRDA_DEBUG(0, __FUNCTION__ "(), notifying irmanager to stop irlan!\n"); mgr_event.event = EVENT_IRLAN_STOP; @@ -363,7 +363,7 @@ ASSERT(self->magic == IRLAN_MAGIC, return;); /* Check if device is still configured */ - if (test_bit(LINK_STATE_START, &self->dev.state)) { + if (netif_running(&self->dev)) { IRDA_DEBUG(0, __FUNCTION__ "(), Device still configured, closing later!\n"); @@ -1195,7 +1195,7 @@ buf+len); len += sprintf(buf+len, "tx busy: %s\n", - test_bit(LINK_STATE_XOFF, &self->dev.state) ? "TRUE" : "FALSE"); + netif_queue_stopped(&self->dev) ? "TRUE" : "FALSE"); len += sprintf(buf+len, "\n"); } diff -u --recursive --new-file v2.3.46/linux/net/netrom/nr_dev.c linux/net/netrom/nr_dev.c --- v2.3.46/linux/net/netrom/nr_dev.c Sun Feb 13 19:29:04 2000 +++ linux/net/netrom/nr_dev.c Thu Feb 17 09:18:47 2000 @@ -62,7 +62,7 @@ { struct net_device_stats *stats = (struct net_device_stats *)dev->priv; - if (!test_bit(LINK_STATE_START, &dev->state)) { + if (!netif_running(dev)) { stats->rx_errors++; return 0; } diff -u --recursive --new-file v2.3.46/linux/net/netsyms.c linux/net/netsyms.c --- v2.3.46/linux/net/netsyms.c Sun Feb 13 19:29:04 2000 +++ linux/net/netsyms.c Fri Feb 18 14:51:22 2000 @@ -28,12 +28,9 @@ #endif #include #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(scm_detach_fds); -#ifdef CONFIG_BRIDGE -EXPORT_SYMBOL(br_ioctl); -EXPORT_SYMBOL(port_info); -EXPORT_SYMBOL(br_avl_find_addr); +#if defined(CONFIG_BRIDGE) || defined(CONFIG_BRIDGE_MODULE) +EXPORT_SYMBOL(br_handle_frame_hook); +EXPORT_SYMBOL(br_ioctl_hook); #endif #ifdef CONFIG_INET @@ -597,6 +593,7 @@ EXPORT_SYMBOL(register_gifconf); +EXPORT_SYMBOL(net_call_rx_atomic); EXPORT_SYMBOL(softirq_state); EXPORT_SYMBOL(softnet_data); diff -u --recursive --new-file v2.3.46/linux/net/packet/af_packet.c linux/net/packet/af_packet.c --- v2.3.46/linux/net/packet/af_packet.c Thu Feb 10 17:11:25 2000 +++ linux/net/packet/af_packet.c Fri Feb 18 14:51:22 2000 @@ -5,7 +5,7 @@ * * PACKET - implements raw packet sockets. * - * Version: $Id: af_packet.c,v 1.30 2000/02/01 12:38:30 freitag Exp $ + * Version: $Id: af_packet.c,v 1.31 2000/02/18 16:47:23 davem Exp $ * * Authors: Ross Biro, * 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 @@ case SIOCGIFBR: case SIOCSIFBR: -#ifdef CONFIG_BRIDGE - lock_kernel(); - err = br_ioctl(cmd,(void *) arg); - unlock_kernel(); - return err; -#else +#ifdef CONFIG_KMOD + if (br_ioctl_hook == NULL) + request_module("bridge"); +#endif + if (br_ioctl_hook != NULL) + return br_ioctl_hook(arg); + return -ENOPKG; -#endif #ifdef CONFIG_INET case SIOCADDRT: diff -u --recursive --new-file v2.3.46/linux/net/rose/rose_dev.c linux/net/rose/rose_dev.c --- v2.3.46/linux/net/rose/rose_dev.c Sun Feb 13 19:29:04 2000 +++ linux/net/rose/rose_dev.c Thu Feb 17 09:18:47 2000 @@ -57,7 +57,7 @@ struct net_device_stats *stats = (struct net_device_stats *)dev->priv; #ifdef CONFIG_INET - if (!test_bit(LINK_STATE_START, &dev->state)) { + if (!netif_running(dev)) { stats->rx_errors++; return 0; } @@ -163,7 +163,7 @@ { struct net_device_stats *stats = (struct net_device_stats *)dev->priv; - if (!test_bit(LINK_STATE_START, &dev->state)) { + if (!netif_running(dev)) { printk(KERN_ERR "ROSE: rose_xmit - called when iface is down\n"); return 1; } diff -u --recursive --new-file v2.3.46/linux/net/sched/sch_api.c linux/net/sched/sch_api.c --- v2.3.46/linux/net/sched/sch_api.c Fri Jan 7 19:13:23 2000 +++ linux/net/sched/sch_api.c Sun Feb 20 20:21:25 2000 @@ -1139,11 +1139,6 @@ long rdelay; unsigned long stop; -#if CPU == 586 || CPU == 686 - if (!(boot_cpu_data.x86_capability & X86_FEATURE_TSC)) - return -1; -#endif - #ifdef PSCHED_WATCHER psched_tick(0); #endif diff -u --recursive --new-file v2.3.46/linux/net/sched/sch_cbq.c linux/net/sched/sch_cbq.c --- v2.3.46/linux/net/sched/sch_cbq.c Thu Feb 10 17:11:25 2000 +++ linux/net/sched/sch_cbq.c Thu Feb 17 09:18:47 2000 @@ -1053,7 +1053,7 @@ if (sch->q.qlen) { sch->stats.overlimits++; - if (q->wd_expires && !test_bit(LINK_STATE_XOFF, &sch->dev->state)) { + if (q->wd_expires && !netif_queue_stopped(sch->dev)) { long delay = PSCHED_US2JIFFIE(q->wd_expires); del_timer(&q->wd_timer); if (delay <= 0) diff -u --recursive --new-file v2.3.46/linux/net/sched/sch_generic.c linux/net/sched/sch_generic.c --- v2.3.46/linux/net/sched/sch_generic.c Thu Feb 10 17:11:25 2000 +++ linux/net/sched/sch_generic.c Fri Feb 18 14:51:22 2000 @@ -88,7 +88,7 @@ /* And release queue */ spin_unlock(&dev->queue_lock); - if (!test_bit(LINK_STATE_XOFF, &dev->state)) { + if (!netif_queue_stopped(dev)) { if (netdev_nit) dev_queue_xmit_nit(skb, dev); @@ -146,7 +146,7 @@ spin_lock(&dev->xmit_lock); if (dev->qdisc != &noop_qdisc) { - if (test_bit(LINK_STATE_XOFF, &dev->state) && + if (netif_queue_stopped(dev) && (jiffies - dev->trans_start) > dev->watchdog_timeo) { printk(KERN_INFO "NETDEV WATCHDOG: %s: transmit timed out\n", dev->name); dev->tx_timeout(dev); @@ -476,7 +476,7 @@ dev_watchdog_down(dev); - if (test_bit(LINK_STATE_SCHED, &dev->state)) { + while (test_bit(__LINK_STATE_SCHED, &dev->state)) { current->policy |= SCHED_YIELD; schedule(); } diff -u --recursive --new-file v2.3.46/linux/net/sched/sch_tbf.c linux/net/sched/sch_tbf.c --- v2.3.46/linux/net/sched/sch_tbf.c Thu Feb 10 17:11:25 2000 +++ linux/net/sched/sch_tbf.c Thu Feb 17 09:18:47 2000 @@ -226,7 +226,7 @@ return skb; } - if (!test_bit(LINK_STATE_XOFF, &sch->dev->state)) { + if (!netif_queue_stopped(sch->dev)) { long delay = PSCHED_US2JIFFIE(max(-toks, -ptoks)); if (delay == 0) diff -u --recursive --new-file v2.3.46/linux/net/sched/sch_teql.c linux/net/sched/sch_teql.c --- v2.3.46/linux/net/sched/sch_teql.c Thu Feb 10 17:11:25 2000 +++ linux/net/sched/sch_teql.c Thu Feb 17 09:18:47 2000 @@ -296,8 +296,7 @@ if (slave->qdisc_sleeping != q) continue; - if (test_bit(LINK_STATE_XOFF, &slave->state) || - test_bit(LINK_STATE_DOWN, &slave->state)) { + if (netif_queue_stopped(slave) || ! netif_running(slave)) { busy = 1; continue; } @@ -306,7 +305,7 @@ case 0: if (spin_trylock(&slave->xmit_lock)) { slave->xmit_lock_owner = smp_processor_id(); - if (!test_bit(LINK_STATE_XOFF, &slave->state) && + if (!netif_queue_stopped(slave) && slave->hard_start_xmit(skb, slave) == 0) { slave->xmit_lock_owner = -1; spin_unlock(&slave->xmit_lock); @@ -319,7 +318,7 @@ slave->xmit_lock_owner = -1; spin_unlock(&slave->xmit_lock); } - if (test_bit(LINK_STATE_XOFF, &dev->state)) + if (netif_queue_stopped(dev)) busy = 1; break; case 1: diff -u --recursive --new-file v2.3.46/linux/net/sysctl_net.c linux/net/sysctl_net.c --- v2.3.46/linux/net/sysctl_net.c Sun Nov 30 14:00:40 1997 +++ linux/net/sysctl_net.c Fri Feb 18 14:51:22 2000 @@ -34,10 +34,6 @@ extern ctl_table ether_table[], e802_table[]; #endif -#ifdef CONFIG_BRIDGE -extern ctl_table bridge_table[]; -#endif - #ifdef CONFIG_IPV6 extern ctl_table ipv6_table[]; #endif @@ -60,9 +56,6 @@ #endif #ifdef CONFIG_IPX {NET_IPX, "ipx", NULL, 0, 0555, ipx_table}, -#endif -#ifdef CONFIG_BRIDGE - {NET_BRIDGE, "bridge", NULL, 0, 0555, bridge_table}, #endif #ifdef CONFIG_IPV6 {NET_IPV6, "ipv6", NULL, 0, 0555, ipv6_table}, diff -u --recursive --new-file v2.3.46/linux/net/wanrouter/wanmain.c linux/net/wanrouter/wanmain.c --- v2.3.46/linux/net/wanrouter/wanmain.c Sun Feb 13 19:29:04 2000 +++ linux/net/wanrouter/wanmain.c Thu Feb 17 09:18:47 2000 @@ -701,7 +701,7 @@ if (dev == NULL) return -ENODEV; /* interface not found */ - if (test_bit(LINK_STATE_START, &dev->state)) { + if (netif_running(dev)) { if (force) { printk(KERN_WARNING "%s: deleting opened interface %s!\n", diff -u --recursive --new-file v2.3.46/linux/scripts/Configure linux/scripts/Configure --- v2.3.46/linux/scripts/Configure Mon Nov 1 13:56:27 1999 +++ linux/scripts/Configure Sun Feb 20 20:13:10 2000 @@ -311,6 +311,26 @@ bool "$ques" "$var" } +function dep_mbool () { + ques=$1 + var=$2 + shift 2 + while [ $# -gt 0 ]; do + case "$1" in + n) + define_bool "$var" "n" + return + ;; + m) + eval "$var=y" + ;; + esac + shift + done + + bool "$ques" "$var" +} + # # define_int sets the value of a integer argument # diff -u --recursive --new-file v2.3.46/linux/scripts/Menuconfig linux/scripts/Menuconfig --- v2.3.46/linux/scripts/Menuconfig Tue Dec 7 09:32:52 1999 +++ linux/scripts/Menuconfig Sun Feb 20 20:13:10 2000 @@ -258,6 +258,26 @@ fi } +function dep_mbool () { + ques="$1" + var="$2" + dep=y + shift 2 + while [ $# -gt 0 ]; do + if [ "$1" = y -o "$1" = m ]; then + shift + else + dep=n + shift $# + fi + done + if [ "$dep" = y ]; then + bool "$ques" "$var" + else + define_bool "$var" n + fi +} + # # Add a menu item which will call our local int function. # @@ -1075,6 +1095,20 @@ shift 2 while [ $# -gt 0 ]; do if [ "$1" = y ]; then + shift + else + x=n; shift $# + fi + done + define_bool "$var" "$x" + } + + function dep_mbool () { + set_x_info "$2" "n" + var="$2" + shift 2 + while [ $# -gt 0 ]; do + if [ "$1" = y -o "$1" = m ]; then shift else x=n; shift $# diff -u --recursive --new-file v2.3.46/linux/scripts/header.tk linux/scripts/header.tk --- v2.3.46/linux/scripts/header.tk Mon Oct 4 15:49:30 1999 +++ linux/scripts/header.tk Sun Feb 20 20:13:10 2000 @@ -249,17 +249,19 @@ return $var } -proc sync_bool { var dep } { +proc sync_bool { var dep modset } { set var [sync_tristate $var $dep] - if {$dep == 2} then { - set var 0 + if {$dep == 2 && $var == 2} then { + set var $modset } return $var } -proc write_tristate { file1 file2 varname variable deplist } { +proc write_tristate { file1 file2 varname variable deplist modset } { set variable [sync_tristate $variable [effective_dep $deplist]] - if { $variable == 1 }\ + if { $variable == 2 } \ + then { set variable $modset } + if { $variable == 1 } \ then { puts $file1 "$varname=y"; \ puts $file2 "#define $varname 1" } \ elseif { $variable == 2 } \ diff -u --recursive --new-file v2.3.46/linux/scripts/tkcond.c linux/scripts/tkcond.c --- v2.3.46/linux/scripts/tkcond.c Sun Feb 13 19:29:04 2000 +++ linux/scripts/tkcond.c Sun Feb 20 20:13:10 2000 @@ -53,6 +53,7 @@ || cfg->token == token_define_string || cfg->token == token_define_tristate || cfg->token == token_dep_bool + || cfg->token == token_dep_mbool || cfg->token == token_dep_tristate || cfg->token == token_hex || cfg->token == token_int @@ -517,6 +518,7 @@ break; case token_dep_bool: + case token_dep_mbool: case token_dep_tristate: /* * Same as the other simple statements, plus an additional diff -u --recursive --new-file v2.3.46/linux/scripts/tkgen.c linux/scripts/tkgen.c --- v2.3.46/linux/scripts/tkgen.c Mon Oct 4 15:49:30 1999 +++ linux/scripts/tkgen.c Sun Feb 20 20:13:10 2000 @@ -343,12 +343,16 @@ */ if ( line_num >= -1 ) { + int modtoyes = 0; + switch ( cfg->token ) { default: printf( " }\n" ); break; + case token_dep_mbool: + modtoyes = 1; case token_dep_bool: printf( "\n" ); for ( tmp = cfg->depend; tmp; tmp = tmp->next ) @@ -359,10 +363,13 @@ printf( "\tset tmpvar_dep [effective_dep [list" ); for ( tmp = cfg->depend; tmp; tmp = tmp->next ) printf( " $%s", tmp->name ); - printf( "]];set %s [sync_bool $%s $tmpvar_dep];", - vartable[cfg->nameindex].name, vartable[cfg->nameindex].name ); - printf( "if {$tmpvar_dep != 1} then {" ); - printf( "configure_entry .menu%d.config.f.x%d disabled {y};", + printf( "]];set %s [sync_bool $%s $tmpvar_dep %d];", + vartable[cfg->nameindex].name, vartable[cfg->nameindex].name, + modtoyes ); + printf( "if {$tmpvar_dep != 1" ); + if (modtoyes) + printf( " && $tmpvar_dep != 2" ); + printf( "} then {configure_entry .menu%d.config.f.x%d disabled {y};", menu_num, line_num ); printf( "} else {" ); printf( "configure_entry .menu%d.config.f.x%d normal {y};", @@ -474,12 +481,16 @@ } else { + int modtoyes = 0; + switch ( cfg->token ) { default: printf( " }\n" ); break; + case token_dep_mbool: + modtoyes = 1; case token_dep_bool: printf( "\n" ); for ( tmp = cfg->depend; tmp; tmp = tmp->next ) @@ -490,8 +501,9 @@ printf( "\tset tmpvar_dep [effective_dep [list" ); for ( tmp = cfg->depend; tmp; tmp = tmp->next ) printf( " $%s", tmp->name ); - printf( "]];set %s [sync_bool $%s $tmpvar_dep];", - vartable[cfg->nameindex].name, vartable[cfg->nameindex].name ); + printf( "]];set %s [sync_bool $%s $tmpvar_dep %d];", + vartable[cfg->nameindex].name, vartable[cfg->nameindex].name, + modtoyes ); case token_bool: if ( cfg->token == token_bool ) printf( "\n\t" ); @@ -604,6 +616,7 @@ { struct condition * cond; struct dependency * tmp; + int depmod = 2; /* * Generate global declaration for this symbol. @@ -705,7 +718,7 @@ case token_bool: case token_tristate: - printf( "write_tristate $cfg $autocfg %s $%s [list $notmod]", + printf( "write_tristate $cfg $autocfg %s $%s [list $notmod] 2", vartable[cfg->nameindex].name, vartable[cfg->nameindex].name ); if ( cfg->cond != NULL ) printf( " }" ); @@ -724,7 +737,7 @@ cfg1 != NULL && cfg1->token == token_choice_item; cfg1 = cfg1->next ) { - printf("\n\tif { $tmpvar_%d == \"%s\" } then { write_tristate $cfg $autocfg %s 1 [list $notmod] } else { write_tristate $cfg $autocfg %s 0 [list $notmod] }", + printf("\n\tif { $tmpvar_%d == \"%s\" } then { write_tristate $cfg $autocfg %s 1 [list $notmod] 2 } else { write_tristate $cfg $autocfg %s 0 [list $notmod] 2 }", -(cfg->nameindex), cfg1->label, vartable[cfg1->nameindex].name, vartable[cfg1->nameindex].name ); @@ -751,23 +764,25 @@ case token_define_tristate: if ( cfg->cond == NULL ) { - printf( "write_tristate $cfg $autocfg %s $%s [list $notmod]\n", + printf( "write_tristate $cfg $autocfg %s $%s [list $notmod] 2\n", vartable[cfg->nameindex].name, vartable[cfg->nameindex].name ); } else { - printf( "write_tristate $cfg $autocfg %s $%s [list $notmod] }\n", + printf( "write_tristate $cfg $autocfg %s $%s [list $notmod] 2 }\n", vartable[cfg->nameindex].name, cfg->value ); } break; + case token_dep_mbool: + depmod = 1; case token_dep_bool: case token_dep_tristate: printf( "write_tristate $cfg $autocfg %s $%s [list", vartable[cfg->nameindex].name, vartable[cfg->nameindex].name ); for ( tmp = cfg->depend; tmp; tmp = tmp->next ) printf( " $%s", tmp->name ); - printf( "]" ); + printf( "] %d", depmod ); if ( cfg->cond != NULL ) printf( " }" ); printf( "\n" ); @@ -887,6 +902,7 @@ case token_define_string: case token_dep_bool: case token_dep_tristate: + case token_dep_mbool: case token_int: case token_hex: case token_mainmenu_option: @@ -1121,6 +1137,7 @@ case token_choice_item: case token_dep_bool: case token_dep_tristate: + case token_dep_mbool: case token_hex: case token_int: case token_string: @@ -1222,6 +1239,7 @@ break; case token_dep_bool: + case token_dep_mbool: cfg->menu_line = menu_line++; printf( "\tdep_bool $w.config.f %d %d \"%s\" %s\n", cfg->menu_number, cfg->menu_line, cfg->label, @@ -1300,6 +1318,7 @@ case token_choice_item: case token_dep_bool: case token_dep_tristate: + case token_dep_mbool: case token_tristate: if ( ! vartable[cfg->nameindex].global_written ) { @@ -1376,6 +1395,7 @@ case token_define_tristate: case token_dep_bool: case token_dep_tristate: + case token_dep_mbool: case token_hex: case token_int: case token_string: diff -u --recursive --new-file v2.3.46/linux/scripts/tkparse.c linux/scripts/tkparse.c --- v2.3.46/linux/scripts/tkparse.c Mon Oct 4 15:49:30 1999 +++ linux/scripts/tkparse.c Sun Feb 20 20:13:10 2000 @@ -386,6 +386,7 @@ match_token( token_define_string, "define_string" ); match_token( token_define_tristate, "define_tristate" ); match_token( token_dep_bool, "dep_bool" ); + match_token( token_dep_mbool, "dep_mbool" ); match_token( token_dep_tristate, "dep_tristate" ); break; @@ -549,6 +550,7 @@ break; case token_dep_bool: + case token_dep_mbool: case token_dep_tristate: pnt = get_qstring ( pnt, &cfg->label ); pnt = get_string ( pnt, &buffer ); @@ -585,7 +587,7 @@ } else { - syntax_error( "can't handle dep_bool/dep_tristate condition" ); + syntax_error( "can't handle dep_bool/dep_mbool/dep_tristate condition" ); } dep_ptr = &(*dep_ptr)->next; while ( *pnt == ' ' || *pnt == '\t' ) @@ -623,12 +625,12 @@ *cond_ptr = malloc( sizeof(struct condition) ); memset( *cond_ptr, 0, sizeof(struct condition) ); (*cond_ptr)->op = op_lparen; - if ( token == token_dep_tristate ) - sprintf( fake_if, "[ \"$%s\" = \"y\" -o \"$%s\" = \"m\" -o \"$%s\" = \"\" ]; then", - dep->name, dep->name, dep->name ); - else + if ( token == token_dep_bool ) sprintf( fake_if, "[ \"$%s\" = \"y\" -o \"$%s\" = \"\" ]; then", dep->name, dep->name ); + else + sprintf( fake_if, "[ \"$%s\" = \"y\" -o \"$%s\" = \"m\" -o \"$%s\" = \"\" ]; then", + dep->name, dep->name, dep->name ); (*cond_ptr)->next = tokenize_if( fake_if ); while ( *cond_ptr ) cond_ptr = &(*cond_ptr)->next; diff -u --recursive --new-file v2.3.46/linux/scripts/tkparse.h linux/scripts/tkparse.h --- v2.3.46/linux/scripts/tkparse.h Mon Oct 4 15:49:30 1999 +++ linux/scripts/tkparse.h Sun Feb 20 20:13:10 2000 @@ -19,6 +19,7 @@ token_define_string, token_define_tristate, token_dep_bool, + token_dep_mbool, token_dep_tristate, token_else, token_endmenu, @@ -77,7 +78,7 @@ }; /* - * Dependency list for dep_bool, dep_tristate + * Dependency list for dep_bool, dep_mbool, dep_tristate */ struct dependency