diff -u --recursive --new-file v2.1.101/linux/CREDITS linux/CREDITS --- v2.1.101/linux/CREDITS Sat May 2 14:19:50 1998 +++ linux/CREDITS Tue May 12 18:14:32 1998 @@ -1279,6 +1279,16 @@ S: Derbyshire DE4 3RL S: United Kingdom +N: Russell Nelson +E: nelson@crynwr.com +W: http://www.crynwr.com/~nelson +P: 1024/83942741 FF 68 EE 27 A0 5A AA C3 F5 DC 05 62 BD 5B 20 2F +D: Author of cs89x0, maintainer of kernel changelog through 1.3.3 +D: Wrote many packet drivers, from which some Ethernet drivers are derived. +S: 521 Pleasant Valley Rd. +S: Potsdam, NY 13676 +S: USA + N: Michael Neuffer E: mike@i-Connect.Net E: neuffer@goofy.zdv.uni-mainz.de @@ -1801,9 +1811,9 @@ N: Tim Waugh E: tim@cyberelk.demon.co.uk D: Co-architect of the parallel-port sharing system -S: 12 Station Road -S: Park Gate -S: Southampton SO31 7GJ +S: 110 Twyford Road +S: EASTLEIGH +S: SO50 4HN S: United Kingdom N: Juergen Weigert diff -u --recursive --new-file v2.1.101/linux/Documentation/Changes linux/Documentation/Changes --- v2.1.101/linux/Documentation/Changes Thu May 7 22:51:45 1998 +++ linux/Documentation/Changes Tue May 12 21:19:02 1998 @@ -33,7 +33,7 @@ Also, don't forget http://www.linuxhq.com/ for all your Linux kernel needs. -Last updated: May 5, 1998 +Last updated: May 12, 1998 Current Author: Chris Ricker (kaboom@gatech.edu). Current Minimal Requirements @@ -45,21 +45,21 @@ - Kernel modules modutils-2.1.85 ; insmod -V - Gnu C 2.7.2.3 ; gcc --version -- Binutils 2.8.1.0.1 ; ld -v +- Binutils 2.8.1.0.23 ; ld -v - Linux C Library 5.4.44 ; ls -l /lib/libc.so.* - Dynamic Linker (ld.so) 1.9.5 ; ldd --version - Linux C++ Library 2.7.2.8 ; ls -l /usr/lib/libg++.so.* -- Procps 1.2.5 ; ps --version +- Procps 1.2.7 ; ps --version - Procinfo 13 ; procinfo -v - Mount 2.7l ; mount --version -- Net-tools 1.41 ; hostname -V +- Net-tools 1.45 ; hostname -V - Loadlin 1.6a - Sh-utils 1.16 ; basename --v - Autofs 0.3.11 ; automount --version - NFS 0.4.21 ; showmount --version - Bash 1.14.7 ; bash -version -- Ncpfs 2.1.1 ; ncpmount -v -- Pcmcia-cs 3.0.0 +- Ncpfs 2.2.0 ; ncpmount -v +- Pcmcia-cs 3.0.1 - PPP 2.3.5 ; pppd -v Upgrade notes @@ -78,6 +78,11 @@ the corresponding ttyS* device instead (e.g., cua0 -> ttyS0, cua1 -> ttyS1, etc.). + In addition, some software still works, but needs to be compiled +against 2.1 headers for complete functionality. Fdutils binaries +compiled under 2.0 or earlier kernels should be replaced with ones +compiled under 2.1, for example. + Libc ==== @@ -127,11 +132,13 @@ to find out the proper way to upgrade it. No, the instruction to "rm `which encaps`" is not a joke. -The last public release of the binutils 2.8.x series is 2.8.1.0.23. -Binutils 2.8.1.0.25 to 2.9.1.0.2 are all very buggy; do not use them. -Binutils 2.9.1 (note the absence of a suffix) is all right, and binutils -2.9.1.0.3 (and presumably later revisions) will probably work, too. -Stick with 2.8.1.0.23 to be safe. + The last public release of the binutils 2.8.x series was 2.8.1.0.23. +Binutils 2.8.1.0.25 to 2.9.1.0.2 are beta releases, and are known to be +very buggy. Binutils 2.9.1 (note the absence of a suffix) from the FSF +should work, and binutils 2.9.1.0.3 and later releases are also good. +Either use binutils-2.8.1.0.23 or binutils-2.9.1.0.4 or later. Glibc2 +users should especially try to use the 2.9.1.0.x releases, as they +resolve known issues with glibc2 and binutils-2.8.x releases. Gnu C ===== @@ -273,13 +280,24 @@ Binutils ======== -The 2.8.1.0.1 release: +The 2.8.1.0.23 release: ftp://tsx-11.mit.edu/pub/linux/packages/GCC/binutils-2.8.1.0.23.bin.tar.gz ftp://sunsite.unc.edu/pub/Linux/GCC/binutils-2.8.1.0.23.bin.tar.gz Installation notes: ftp://tsx-11.mit.edu/pub/linux/packages/GCC/release.binutils-2.8.1.0.23 ftp://sunsite.unc.edu/pub/Linux/GCC/release.binutils-2.8.1.0.23 +The 2.9.1.0.4 release: +ftp://tsx-11.mit.edu/pub/linux/packages/GCC/binutils-2.9.1.0.4-glibc.x86.tar.gz +ftp://tsx-11.mit.edu/pub/linux/packages/GCC/binutils-2.9.1.0.4-libc5.x86.tar.gz +ftp://tsx-11.mit.edu/pub/linux/packages/GCC/binutils-2.9.1.0.4.tar.gz +ftp://sunsite.unc.edu/pub/Linux/GCC/binutils-2.9.1.0.4-glibc.x86.tar.gz +ftp://sunsite.unc.edu/pub/Linux/GCC/binutils-2.9.1.0.4-libc5.x86.tar.gz +ftp://sunsite.unc.edu/pub/Linux/GCC/binutils-2.9.1.0.4.tar.gz +Installation notes: +ftp://tsx-11.mit.edu/pub/linux/packages/GCC/release.binutils-2.9.1.0.4 +ftp://sunsite.unc.edu/pub/Linux/GCC/release.binutils-2.9.1.0.4 + Gnu C ===== @@ -399,7 +417,7 @@ The 0.4.21 release: ftp://ftp.mathematik.th-darmstadt.de/pub/linux/okir/linux-nfs-0.4.21.tar.gz -ftp://linux.nrao.edu/pub/people/okir/linux-nfs-0.4.21.tar.gz +ftp://linux.nrao.edu/mirrors/fb0429.mathematik.th-darmstadt.de/pub/linux/okir/linux-nfs-0.4.21.tar.gz Net-tools ========= @@ -423,14 +441,14 @@ Ncpfs ===== -The 2.1.1 release: -ftp://ftp.gwdg.de/pub/linux/misc/ncpfs/ncpfs-2.1.1.tgz +The 2.2.0 release: +ftp://ftp.gwdg.de/pub/linux/misc/ncpfs/ncpfs-2.2.0.tgz Pcmcia-cs ========= -The May 4, 1998 release: -ftp://hyper.stanford.edu/pub/pcmcia/NEW/pcmcia-cs.04-May-98.tar.gz +The 3.0.1 release: +ftp://hyper.stanford.edu/pub/pcmcia/pcmcia-cs.3.0.1.tar.gz PPP === diff -u --recursive --new-file v2.1.101/linux/Documentation/Configure.help linux/Documentation/Configure.help --- v2.1.101/linux/Documentation/Configure.help Fri May 8 23:14:41 1998 +++ linux/Documentation/Configure.help Thu May 14 16:13:02 1998 @@ -1611,44 +1611,17 @@ IP: firewalling CONFIG_IP_FIREWALL - If you want to configure your Linux box as a packet filter firewall - for a local TCP/IP based network, say Y here. This will enlarge your - kernel by about 2kB. You may need to read the FIREWALL-HOWTO, - available via ftp (user: anonymous) in - ftp://sunsite.unc.edu/pub/Linux/docs/HOWTO. - - Also, you will need the ipfwadm tool (available via ftp (user: - anonymous) from ftp://ftp.xos.nl/pub/linux/ipfwadm/) to allow selective - blocking of Internet traffic based on type, origin and destination; - this type of firewall is called a "packet filter". The other type of - firewall, "proxy-based" ones, is more secure but more intrusive and - more bothersome to set up; it inspects the network traffic much more - closely, modifies it and has knowledge about the higher level - protocols, which a packet filter lacks. Moreover, proxy-based - firewalls often require changes to the programs running on the local - clients. Proxy-based firewalls don't need support by the kernel, but - they are often combined with a packet filter, which only works if - you say Y here. - - The firewalling code will only work if IP forwarding is enabled in - your kernel. You can do that by saying Y to "/proc filesystem - 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 need to say Y to "IP firewalling" in order to be able to use IP - masquerading (masquerading means that local computers can chat with - an outside host, but that outside host is made to think that it is - talking to the firewall box -- makes the local network completely - invisible to the outside world and avoids the need to allocate - globally valid IP host addresses for the machines on the local net) - and IP packet accounting (keeping track of what is using all your - network bandwidth) and IP transparent proxying (makes the computers - on the local network think they're talking to a remote computer, - while in reality the traffic is redirected by your Linux firewall to - a local proxy server). + Complete rewrite of IP firewalling support. Requires new ipfwadm. + This was previously called CONFIG_IP_FIREWALL_CHAINS in patch sets + released by the author, but now it is and will be the standard + firewalling implementation for 2.1.x and onward. + + More powerful than the old IP firewalling but also provides similar + structure to original firewalling for experienced users. IP + accounting and packet logging are automatically included with firewall + chains, so you don't need them them if you say Y here. See + http://www.adelaide.net.au/~rustcorp for new ipfwadm (called ipchains). + If in doubt, say N here. IP: firewall packet netlink device CONFIG_IP_FIREWALL_NETLINK @@ -1660,17 +1633,8 @@ /dev with major number 36 and minor number 3 using mknod ("man mknod"), and you need (to write) a program that reads from that device and takes appropriate action. - -IP: accounting -CONFIG_IP_ACCT - This keeps track of your IP network traffic and produces some - statistics. Usually, you only want to say Y here if your box will be - a router or a firewall for some local network. For the latter, you - need to say Y to "IP firewalling". The data is accessible with "cat - /proc/net/ip_acct", so you want to say Y to the /proc filesystem - below, if you say Y here. To specify what exactly should be - recorded, you need the tool ipfwadm (available via ftp (user: - anonymous) from ftp://ftp.xos.nl/pub/linux/ipfwadm/). + With the current generic firewalling chains you can specify which + packets go to this device, as well as how many bytes. IP: kernel level autoconfiguration CONFIG_IP_PNP @@ -1832,6 +1796,37 @@ to allow some forwarding of packets from outside to inside a firewall on given ports. Information and source for ipportfw is available from + http://www.monmouth.demon.co.uk/ipsubs/portforwarding.html + The portfw code is still under development and so is currently + marked EXPERIMENTAL. + If you want this, say Y. + +IP: ICMP masquerading +CONFIG_IP_MASQUERADE_ICMP + The basic masquerade code described for CONFIG_IP_MASQUERADE only + handles TCP or UDP packets (and ICMP errors for existing + connections). This option adds additional support for masquerading + ICMP packets, such as ping or the probes used by the Windows 95 + tracert program. + If you want this, say Y. + +IP: ipautofw masquerade support +CONFIG_IP_MASQUERADE_IPAUTOFW (Experimental) + ipautofw is a program by Richard Lynch allowing additional + support for masquerading protocols which do not (as yet) + have additional protocol helpers. + Information and source for ipautofw is available from + ftp://ftp.netis.com/pub/members/rlynch/ + The ipautofw code is still under development and so is currently + marked EXPERIMENTAL. + If you want this, say Y. + +IP: ipportfw masquerade support +CONFIG_IP_MASQUERADE_IPPORTFW + ipportfw is an addition to IP Masquerading written by Steven Clarke + to allow some forwarding of packets from outside to inside a + firewall on given ports. Information and source for ipportfw is + available from http://www.monmouth.demon.co.uk/ipsubs/portforwarding.html (to browse the WWW, you need to have access to a machine on the Internet that has a program like lynx or netscape). @@ -2029,7 +2024,8 @@ as a module, say M here and read Documentation/modules.txt. If you try building this as a module and you are running kerneld, be sure to add 'alias net-pf-1 unix' to your /etc/conf.module file. If - unsure, say Y. + unsure, say Y. (NOTE: X Windows and syslog probably won't work + if you say N to this or fail to configure it correctly) The IPv6 protocol CONFIG_IPV6 @@ -2069,44 +2065,26 @@ some problems caused by the presence of two link-local addresses on an interface. -IPv6: routing messages via old netlink -CONFIG_IPV6_NETLINK - You can say Y here to receive routing messages from the IPv6 code - through the old netlink interface. However, a better option is to - say Y to "Kernel/User network link driver" and to "Routing - messages" instead. - -The IPX protocol +IPX networking CONFIG_IPX This is support for the Novell networking protocol, IPX, commonly used for local networks of Windows machines. You need it if you want to access Novell NetWare file or print servers using the Linux Novell client ncpfs (available via ftp (user: anonymous) from - ftp://sunsite.unc.edu/pub/Linux/system/filesystems/) or from within - the Linux DOS emulator dosemu (read the DOSEMU-HOWTO, available in - ftp://sunsite.unc.edu/pub/Linux/docs/HOWTO). In order to do the - former, you'll also have to say Y to "NCP filesystem support", - below. - - IPX is similar in scope to IP, while SPX, which runs on top of IPX, - is similar to TCP. There is also experimental support for SPX in - Linux (see "SPX networking", below). - - To turn your Linux box into a fully featured NetWare file server and + sunsite.unc.edu:/pub/Linux/system/filesystems/) or from within the + Linux DOS emulator dosemu (read the DOSEMU-HOWTO, available in + sunsite.unc.edu:/pub/Linux/docs/HOWTO). In order to do the former, + you'll also have to say Y to "NCP filesystem support", below. To + turn your Linux box into a fully featured NetWare file server and IPX router, say Y here and fetch either lwared from - ftp://sunsite.unc.edu/pub/Linux/system/network/daemons/ or mars_nwe from - ftp://ftp.gwdg.de/pub/linux/misc/ncpfs. For more information, read the - IPX-HOWTO in ftp://sunsite.unc.edu/pub/Linux/docs/HOWTO. - General information about how to connect Linux, Windows machines and - Macs is on the WWW at http://www.eats.com/linux_mac_win.html (to - browse the WWW, you need to have access to a machine on the Internet - that has a program like lynx or netscape). - - The IPX driver would enlarge your kernel by about 5 kB. This driver - is also available as a module ( = code which can be inserted in and - removed from the running kernel whenever you want). The module will - be called ipx.o. If you want to compile it as a module, say M here - and read Documentation/modules.txt. Unless you want to integrate + sunsite.unc.edu:/pub/Linux/system/network/daemons/ or mars_nwe from + ftp.gwdg.de:/pub/linux/misc/ncpfs. For more information, read the + IPX-HOWTO in sunsite.unc.edu:/pub/Linux/docs/howto. The IPX driver + would enlarge your kernel by about 5 kB. This driver is also + available as a module ( = code which can be inserted in and removed + from the running kernel whenever you want). The module will be + called ipx.o. If you want to compile it as a module, say M here + and read Documentation/modules.txt. Unless you want to integrate your Linux box with a local Novell network, say N. IPX: Full internal IPX network @@ -2114,12 +2092,11 @@ Every IPX network has an address that identifies it. Sometimes it is useful to give an IPX "network" address to your Linux box as well (for example if your box is acting as a fileserver for different IPX - networks: it will then be accessible from everywhere using the same + networks: it will then be accessible form everywhere using the same address). The way this is done is to create a virtual internal "network" inside your box and to assign an IPX address to this network. Say Y here if you want to do this; read the IPX-HOWTO at sunsite.unc.edu:/pub/Linux/docs/howto for details. - The full internal IPX network enables you to allocate sockets on different virtual nodes of the internal network. This is done by evaluating the field sipx_node of the socket address given to the @@ -2131,72 +2108,54 @@ 'special' sockets to sockets listening on the primary network is disabled. This might break existing applications, especially RIP/SAP daemons. A RIP/SAP daemon that works well with the full internal net - can be found on ftp://ftp.gwdg.de/pub/linux/misc/ncpfs. If you don't + can be found on ftp.gwdg.de:/pub/linux/misc/ncpfs. If you don't know what you are doing, say N. IPX: SPX networking (EXPERIMENTAL) CONFIG_SPX - The Sequenced Packet eXchange protocol is a transport layer protocol - built on top of IPX. It is used in Novell NetWare systems for - client-server applications and is similar to TCP (which runs on top - of IP). - - 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 - space programs lwared or mars_nwe for the server side). - - Say Y here if you have use for SPX; read the IPX-HOWTO at - sunsite.unc.edu:/pub/Linux/docs/howto for details. - - This driver is also available as a module ( = code which can be - inserted in and removed from the running kernel whenever you want). - The module will be called af_spx.o. If you want to compile it as a - module, say M here and read Documentation/modules.txt. + The (SPP-derived) Sequenced Packet eXchange (SPX) protocol. Novell's + networking protocol which monitors transmissions to guarantee + successful delivery. An example server/client program (SPX-0.0x.tar.gz) + is available at ftp://ftp.spacs.k12.wi.us/users/jschlst/SPX-0.0x.tar.gz. + It is safe to say Y/M here. Appletalk DDP CONFIG_ATALK Appletalk is the way Apple computers speak to each other on a - network. If your Linux box is connected to such a network and you + network. If your linux box is connected to such a network and you want to join the conversation, say Y. You will need to use the netatalk package so that your Linux box can act as a print and file server for macs as well as access appletalk printers. Check out - http://threepio.hitchcock.org/cgi-bin/faq/netatalk/faq.pl on the WWW - for details (to browse the WWW, you need to have access to a machine - on the Internet that has a program like lynx or netscape). EtherTalk - is the name used for appletalk over Ethernet and the cheaper and - slower LocalTalk is appletalk over a proprietary apple network using - serial links. Ethertalk and Localtalk are fully supported by Linux. - The NET-2-HOWTO, available via ftp (user: anonymous) in - ftp://sunsite.unc.edu/pub/Linux/docs/HOWTO contains valuable - information as well. - - General information about how to connect Linux, Windows machines and - Macs is on the WWW at http://www.eats.com/linux_mac_win.html - - This driver 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 appletalk.o. If you want to compile it as a - module, say M here and read Documentation/modules.txt. I hear that - the GNU boycott of Apple is over, so even politically correct people - are allowed to say Y here. + http://artoo.hitchcock.org/~flowerpt/projects/linux-netatalk/ on the + WWW for details (to browse the WWW, you need to have access to a + machine on the Internet that has a program like lynx or + netscape). EtherTalk is the name used for appletalk over Ethernet + and the cheaper and slower LocalTalk is appletalk over a proprietary + apple network using serial links. Ethertalk and Localtalk are fully + supported by Linux. The NET-2-HOWTO, available via ftp (user: anonymous) + in sunsite.unc.edu:/pub/Linux/docs/HOWTO contains valuable information + as well. This driver is also available as a module ( = code which + can be inserted in and removed from the running kernel whenever you + want). The module is called appletalk.o. If you want to compile + it as a module, say M here and read Documentation/modules.txt. I + hear that the GNU boycott of Apple is over, so even politically + correct people are allowed to say Y here. Appletalk-IP driver support CONFIG_IPDDP This allows IP networking for users who only have Appletalk - networking available. This feature is experimental. With this + networking available. This feature is experimental. With this driver, you can either encapsulate IP inside Appletalk (e.g. if your - Linux box is stuck on an Appletalk only network) or decapsulate - (e.g. if you want your Linux box to act as an Internet gateway for a + Linux box is stuck on an appletalk only network) or decapsulate + (e.g. if you want your Linux box to act as a Internet gateway for a zoo of appletalk connected Macs). You decide which one of the two you want in the following two questions; you can say Y to only one of them. Please see Documentation/networking/ipddp.txt for more - information. - - This driver 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 ipddp.o. If you want to compile it as a module, - say M here and read Documentation/modules.txt. + information. This driver 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 ipddp.o. If you want to + compile it as a module, say M here and read + Documentation/modules.txt. IP to Appletalk-IP Encapsulation support CONFIG_IPDDP_ENCAP @@ -4896,6 +4855,18 @@ module, say M here and read Documentation/modules.txt as well as Documentation/networking/net-modules.txt. +Mylex EISA LNE390A/LNE390B support +CONFIG_LNE390 + If you have a network (Ethernet) card of this type, say Y and read + the Ethernet-HOWTO, available via ftp (user: anonymous) in + ftp://sunsite.unc.edu/pub/Linux/docs/HOWTO. + + This driver is also available as a module ( = code which can be + inserted in and removed from the running kernel whenever you want). + The module will be called lne390.o. If you want to compile it as a + module, say M here and read Documentation/modules.txt as well as + Documentation/networking/net-modules.txt. + Apricot Xen-II on board Ethernet CONFIG_APRICOT If you have a network (Ethernet) controller of this type, say Y and @@ -6045,16 +6016,20 @@ ADFS filesystem support (read only) (EXPERIMENTAL) CONFIG_ADFS_FS - Acorn Disc Filing System is the standard filesystem of the Risc OS - operating system which runs on Acorn's ARM based Risc PC computers. - If you say Y here, Linux will be able to read from ADFS partitions - on hard drives and from ADFS-formatted floppy disks. + The Acorn Disc Filing System is the standard filesystem of the RiscOS + operating system which runs on Acorn's ARM based Risc PC systems and + the Acorn Archimedes range of machines. These should be the first + partition (ie, /dev/[hs]d?1) on each of your drives. If you say Y + here, Linux will be able to read from ADFS partitions on hard drives + and from ADFS-formatted floppy discs. This code is also available as a module called adfs.o ( = code which can be inserted in and removed from the running kernel whenever you want). If you want to compile it as a module, say M here and read Documentation/modules.txt. + If unsure, say N. + /dev/pts filesystem (experimental) CONFIG_DEVPTS_FS If you say Y here, you'll get a virtual filesystem which can be @@ -6534,13 +6509,6 @@ non-blinking block cursors which are more visible on laptop screens, or change their color depending on the virtual console you're on. See Documentation/VGA-softcursor.txt for more information. - -Acorn's ADFS filesystem support (read only) (EXPERIMENTAL) -CONFIG_ADFS_FS - The Advanced Disk File System is the filesystem used on floppy and - hard disks by Acorn Systems. Currently in development, as a read- - only driver for hard disks. These should be the first partition - (eg. /dev/[sh]d?1) on each of your drives. If unsure, say N. Standard/generic serial support CONFIG_SERIAL diff -u --recursive --new-file v2.1.101/linux/Documentation/joystick.txt linux/Documentation/joystick.txt --- v2.1.101/linux/Documentation/joystick.txt Sat May 2 14:19:51 1998 +++ linux/Documentation/joystick.txt Fri May 8 23:07:44 1998 @@ -1,5 +1,5 @@ - PC Joystick driver v1.0.6 beta - (c) 1997 Vojtech Pavlik + PC Joystick driver v1.0.9 + (c) 1997 Vojtech Pavlik ---------------------------------------------------------------------------- 1. Intro @@ -8,20 +8,22 @@ resistor based) and digital (switch based) joysticks connected via the PC game port. It can support up to 2 joysticks. - Because the joystick driver is still in its beta stage I'm very interested -in any problems you encounter while using it. Bug reports and success -stories are also welcome. + Should you encounter any problems while using the driver, or joysticks +this driver can't make complete use of, I'm very interested in hearing about +them. Bug reports and success stories are also welcome. 2. Usage ~~~~~~~~ If you enable the joystick driver in the kernel configuration, all -connected joysticks should be found automatically. If that doesn't work, you -can pass the joystick driver the following kernel command line arguments: +connected joysticks should be found automatically. The driver can detect +standard two-axis two-button, and three-axis four-button joysticks only. If +that isn't your case, you can pass the joystick driver the following kernel +command line arguments: js=0xXX,0xYY Where XX and YY are bit masks for the two joysticks, with the bits -representing: +representing which buttons and axes of the joystick are present: Bit | Explanation ----------------- @@ -34,9 +36,6 @@ 6 | Button 2 7 | Button 3 - These bitmasks are ANDed with what's found by the driver and the result is -used. - Another method of using the driver is loading it as a module. For that, select `M' for this driver in the kernel configuration and insert the module: @@ -53,23 +52,19 @@ create the device files using mknod (man mknod for more info): mknod /dev/js0 c 15 0 -mknod /dev/js1 c 15 1 +mknod /dev/js1 c 15 1 3. Calibration ~~~~~~~~~~~~~~ As of version 1.0 the calibration routines used in the joystick driver are worth using. The idea of calibration is that you have to calibrate the joystick only once, and then set the calibration at boot-time, thus removing -the need of re-calibrating it in each program that uses it. +the need of re-calibrating it in each program that uses it. For calibration, use the jscal program, contained in the joystick package which is available at: -ftp://atrey.karlin.mff.cuni.cz/pub/local/vojtech/joystick/joystick-1.0.6.tar.gz - -And soon also at: - -ftp://sunsite.unc.edu/pub/Linux/kernel/patches/console/joystick-1.0.6.tar.gz +ftp://atrey.karlin.mff.cuni.cz/pub/linux/joystick/joystick-1.0.9.tar.gz 4. Programming Interface ~~~~~~~~~~~~~~~~~~~~~~~~ @@ -88,65 +83,65 @@ Thanks to the following authors that contributed to the joystick driver development: - 0.1-0.5 Arthur C. Smith - 0.5 Eyal Lebedinsky - 0.6 Jeff Tranter - 0.7 Carlos Puchol - 0.7.1-0.8 Matt Rhoten - 0.7.3 Dan Fandrich - 0.7.3 Sverker Wilberg - 0.8 Hal Maney - 0.8 Bernd Schmidt - 0.9 Alan Cox - 0.9.0-1.0.6 Vojtech Pavlik + 0.1-0.5 Arthur C. Smith + 0.5 Eyal Lebedinsky + 0.6 Jeff Tranter + 0.7 Carlos Puchol + 0.7.1-0.8 Matt Rhoten + 0.7.3 Dan Fandrich + 0.7.3 Sverker Wilberg + 0.8 Hal Maney + 0.8 Bernd Schmidt + 0.9 Alan Cox + 0.9.0-1.0.9 Vojtech Pavlik 6. Change Log ~~~~~~~~~~~~~ The current (1.0.x) version was originally based on the 0.7.3 version of the joystick driver, which caused some inconsistencies in version numbering. -The following log documents all changes done to the driver by various +The following log documents all changes done to the driver by the above contributors: -Version 0.1 Original version +Version 0.1 Original version Works but lacks multi-joystick support Version 0.2 Added multi-joystick support (minor 0 and 1) - Added delay between measuring joystick axis - Added scaling ioctl + Added delay between measuring joystick axis + Added scaling ioctl Version 0.3 Modified scaling to use ints to prevent kernel - panics 8-) + panics 8-) Version 0.4 Linux 0.99.6 and fixed race condition in js_read. - After looking at a schematic of a joystick card - it became apparent that any write to the joystick - port started ALL the joystick one shots. If the - one that we are reading is short enough and the - first one to be read, the second one will return - bad data if its one shot has not expired when - the joystick port is written for the second time. - Thus solves the mystery delay problem in 0.2! + After looking at a schematic of a joystick card + it became apparent that any write to the joystick + port started ALL the joystick one shots. If the + one that we are reading is short enough and the + first one to be read, the second one will return + bad data if its one shot has not expired when + the joystick port is written for the second time. + Thus solves the mystery delay problem in 0.2! Version 0.5 Upgraded the driver to the 0.99.9 kernel, added - joystick support to the make config options, - updated the driver to return the buttons as - positive logic, and read both axis at once - and added some new ioctls. + joystick support to the make config options, + updated the driver to return the buttons as + positive logic, and read both axis at once + and added some new ioctls. Version 0.6 Made necessary changes to work with 0.99.15 - kernel (and hopefully 1.0). Also did some - cleanup: indented code, fixed some typos, wrote - man page, etc ... -Version 0.7 Support for modules + kernel (and hopefully 1.0). Also did some + cleanup: indented code, fixed some typos, wrote + man page, etc ... +Version 0.7 Support for modules Version 0.7.1 Fix bug in reading button state of js1 - Add include so module compiles under recent kernels + Add include so module compiles under recent kernels Version 0.7.3 Include directives changed for joystick.h - Separated out joystick detection/counting, cleanup - Fix for detection of 3-axis joysticks - Better detection announcement - Added I/O port registration, cleaned up code + Separated out joystick detection/counting, cleanup + Fix for detection of 3-axis joysticks + Better detection announcement + Added I/O port registration, cleaned up code Version 0.8 New read loop - Cleaned up #includes to allow #include of joystick.h with - gcc -Wall and from g++ - Made js_init fail if it finds zero joysticks - General source/comment cleanup - Use of MOD_(INC|DEC)_USE_COUNT - Changes to compile correctly under 1.3 in kernel or as module + Cleaned up #includes to allow #include of joystick.h with + gcc -Wall and from g++ + Made js_init fail if it finds zero joysticks + General source/comment cleanup + Use of MOD_(INC|DEC)_USE_COUNT + Changes to compile correctly under 1.3 in kernel or as module Version 0.9 Ported to 2.1.x Reformatted to resemble Linux coding standard Removed semaphore bug (we can dump the lot I think) @@ -156,51 +151,63 @@ Removed 'save_busy'. Just set busy to 1. Version 0.9.0 Based on 0.7.3 New read function that allows two axes to have the same value - New joystick calibration code - Real support for 3-axis joysticks - CPU speed independent timeouts - Reads may happen even for unwhole record size => cat /dev/js0 works - Correct error for lseek - /dev/js? can be read simultaneously by several processes + New joystick calibration code + Real support for 3-axis joysticks + CPU speed independent timeouts + Reads may happen even for unwhole record size => cat /dev/js0 works + Correct error for lseek + /dev/js? can be read simultaneously by several processes Version 0.9.1 IOCTLs now obey general Linux IOCTL rules ('j' letter assigned) - Use of verify_area result codes + Use of verify_area result codes Fuzz correction added - Semaphore and many cli()'s removed - Fix for TurboFire joysticks - read buttons always - Fix for broken joysticks - return with -ENODEV only if joystick - completely disconnected - Fix in read function to allow zero results - Broken line correction added for broken joysticks (eg. JB-500) - Timeouts back separated for easier setting - Some fixes and cleanups in read function + Semaphore and many cli()'s removed + Fix for TurboFire joysticks - read buttons always + Fix for broken joysticks - return with -ENODEV only if joystick + completely disconnected + Fix in read function to allow zero results + Broken line correction added for broken joysticks (eg. JB-500) + Timeouts back separated for easier setting + Some fixes and cleanups in read function Version 0.9.2 Fixed a typo causing nothing to be working Version 1.0.0 Event approach started Version 1.0.1 Complete rewrite Compiles but doesn't work Version 1.0.2 Works, many bugs fixed, more yet to come Version 1.0.3 Tail cutting logic changes & fixes - Fix in js_do_bh - no more zero values for axes - Lost event changes & fixes + Fix in js_do_bh - no more zero values for axes + Lost event changes & fixes Version 1.0.4 Kernel command line & module configuration support - Better cli()/sti() handling - Linux 2.1.25 select => poll changes + Better cli()/sti() handling + Linux 2.1.25 select => poll changes Version 1.0.5 Fixes in calibration routines Better jscal Version 1.0.6 Backward compatibility with old js driver added - Init value after recalibration bug fixed + Init value after recalibration bug fixed Using KERN_* printk() codes - Finally leaving ALPHA and going beta - Cosmetic changes + Finally leaving ALPHA and going beta + Cosmetic changes +Version 1.0.7 Readme update + Linux 2.1.89 poll update + Compatibility mode fix - refresh data after open + Cosmetic changes & cleanup +Version 1.0.8 Changing the __u16 data to __s16 in event packet + The range is now -32727..0..32767 + Broken line correction needs 2 coefs less + Fix to report number of buttons correctly + Removed various trailing spaces +Version 1.0.9 Fix for compatibility mode - don't do correction + Fix max number of module parameters 7. To do ~~~~~~~~ Sooner or later I'll get to these: - Backport & create patches for 2.0 - Try using Pentium timers for better precision - Create patches for most common programs using joystick - Support for cards with hw calibration (Gravis Ultrasound, QuickShot) - Support for multiport cards (QuickShot 4-joy board) - Support for multiaxis, multibutton joysticks (Gravis Firebird) - Support for MS digital joystick + Make an optional read routine using Pentium timers for better precision (*) + Support for hats and more buttons ala CH Flightstick (*) + Support for hats ala TM FCS (*) + Include support for MS SideWinder digital mode (*) + Create patches for most common programs using joystick + Support for cards with HW speed compensation + Support for more than one joystick port + (*) - Already in the development 1.1 version. diff -u --recursive --new-file v2.1.101/linux/Documentation/networking/ip-sysctl.txt linux/Documentation/networking/ip-sysctl.txt --- v2.1.101/linux/Documentation/networking/ip-sysctl.txt Sat May 2 14:19:51 1998 +++ linux/Documentation/networking/ip-sysctl.txt Thu May 14 10:26:22 1998 @@ -1,8 +1,10 @@ -/proc/sys/net/ipv4/* variables: +/proc/sys/net/ipv4/* Variables: -ip_forwarding - "SNMP" BOOLEAN - 2 - disabled (default) - 1 - enabled +ip_forward - BOOLEAN + 0 - disabled (default) + not 0 - enabled + + Forward Packets between interfaces. This variable is special, its change resets all configuration parameters to their default state (RFC1122 for hosts, RFC1812 @@ -11,32 +13,11 @@ ip_default_ttl - INTEGER default 64 -ip_log_martians - BOOLEAN - log packets with strange or impossible addresses. - default TRUE (router) - FALSE (host) - -ip_accept_redirects - BOOLEAN - Accept ICMP redirect messages. - default TRUE (host) - FALSE (router) - -ip_secure_redirects - BOOLEAN - Accept ICMP redirect messages only for gateways, - listed in default gateway list. - default TRUE - ip_addrmask_agent - BOOLEAN Reply to ICMP ADDRESS MASK requests. default TRUE (router) FALSE (host) -ip_rfc1620_redirects - BOOLEAN - Send(router) or accept(host) RFC1620 shared media redirects. - Overrides ip_secure_redirects. - default TRUE (should be FALSE for distributed version, - but I use it...) - ip_bootp_agent - BOOLEAN Accept packets with source address of sort 0.b.c.d and destined to this host, broadcast or multicast. @@ -44,46 +25,10 @@ default FALSE -ip_bootp_relay - BOOLEAN - Accept packets with source address 0.b.c.d destined - not to this host as local ones. It is supposed, that - BOOTP relay deamon will catch and forward such packets. - - default FALSE - Not Implemented Yet. - - -ip_source_route - BOOLEAN - Accept packets with SRR option. - default TRUE (router) - FALSE (host) - - ip_no_pmtu_disc - BOOLEAN Disable Path MTU Discovery. default FALSE -ip_rfc1812_filter - INTEGER - 2 - do source validation by reversed path, as specified in RFC1812 - Recommended option for single homed hosts and stub network - routers. Could cause troubles for complicated (not loop free) - networks running a slow unreliable protocol (sort of RIP), - or using static routes. - - 1 - (DEFAULT) Weaker form of RP filtering: drop all the packets - that look as sourced at a directly connected interface, but - were input from another interface. - - 0 - No source validation. - - NOTE: do not disable this option! All BSD derived routing software - (sort of gated, routed etc. etc.) is confused by such packets, - even if they are valid. - - NOTE: this option is turned on per default only when ip_forwarding - is on. For non-forwarding hosts it doesn't make much sense and - makes some legal multihoming configurations impossible. - ip_fib_model - INTEGER 0 - (DEFAULT) Standard model. All routes are in class MAIN. 1 - default routes go to class DEFAULT. This mode should @@ -125,6 +70,7 @@ tcp_max_delay_acks - INTEGER tcp_fin_timeout - INTEGER tcp_max_ka_probes - INTEGER +tcp_hoe_retransmits - INTEGER Undocumented for now. tcp_syncookies - BOOLEAN @@ -143,6 +89,20 @@ tcp_max_syn_backlog - INTEGER Undocumented (work in progress) +tcp_window_scaling - BOOLEAN + Enable window scaling as defined in RFC1323. + +tcp_timestamps - BOOLEAN + Enable timestamps as defined in RFC1323. + +tcp_sack - BOOLEAN + Enable select acknowledgements. + +tcp_retrans_collapse - BOOLEAN + Bug-to-bug compatibility with some broken printers. + On retransmit try to send bigger packets to work around bugs in + certain TCP stacks. + ip_local_port_range - 2 INTEGERS Defines the local port range that is used by TCP and UDP to choose the local port. The first number is the first, the @@ -155,10 +115,94 @@ ICMP ECHO requests sent to it or just those to broadcast/multicast addresses, respectively. +icmp_destunreach_rate - INTEGER +icmp_paramprob_rate - INTEGER +icmp_timeexceed_rate - INTEGER +icmp_echoreply_rate - INTEGER (not enabled per default) + Limit the maximal rates for sending ICMP packets to specifc targets. + 0 to disable any limiting, otherwise the maximal rate in jiffies(1) + See the source for more information. + + +(1) Jiffie: internal timeunit for the kernel. On the i386 1/100s, on the +Alpha 1/1024s. See the HZ define in /usr/include/asm/param.h for the exact +value on your system. + +conf/interface/*: +conf/all/* is special and changes the settings for all interfaces. + Change special settings per interface. + +log_martians - BOOLEAN + Log packets with impossible addresses to kernel log. + +accept_redirects - BOOLEAN + Accept ICMP redirect messages. + default TRUE (host) + FALSE (router) + +forwarding - BOOLEAN + Enable IP forwarding on this interface. + +mc_forwarding - BOOLEAN + Do multicast routing. The kernel needs to be compiled with CONFIG_MROUTE + and a multicast routing daemon is required. + +proxy_arp - BOOLEAN + Do proxy arp. + +shared_media - BOOLEAN + undocumented. + +secure_redirects - BOOLEAN + Accept ICMP redirect messages only for gateways, + listed in default gateway list. + default TRUE + +redirects - BOOLEAN + Send(router) or accept(host) RFC1620 shared media redirects. + Overrides ip_secure_redirects. + default TRUE (should be FALSE for distributed version, + but I use it...) + +bootp_relay - BOOLEAN + Accept packets with source address 0.b.c.d destined + not to this host as local ones. It is supposed, that + BOOTP relay deamon will catch and forward such packets. + + default FALSE + Not Implemented Yet. + +accept_source_route - BOOLEAN + Accept packets with SRR option. + default TRUE (router) + FALSE (host) + +rp_filter - INTEGER + 2 - do source validation by reversed path, as specified in RFC1812 + Recommended option for single homed hosts and stub network + routers. Could cause troubles for complicated (not loop free) + networks running a slow unreliable protocol (sort of RIP), + or using static routes. + + 1 - (DEFAULT) Weaker form of RP filtering: drop all the packets + that look as sourced at a directly connected interface, but + were input from another interface. + + 0 - No source validation. + + NOTE: do not disable this option! All BSD derived routing software + (sort of gated, routed etc. etc.) is confused by such packets, + even if they are valid. When enabled it also prevents ip spoofing + in some limited fashion. + + NOTE: this option is turned on per default only when ip_forwarding + is on. For non-forwarding hosts it doesn't make much sense and + makes some legal multihoming configurations impossible. + Alexey Kuznetsov. kuznet@ms2.inr.ac.ru Updated by: Andi Kleen ak@muc.de -$Id: ip-sysctl.txt,v 1.5 1997/10/17 03:58:23 tdyas Exp $ +$Id: ip-sysctl.txt,v 1.7 1998/05/02 12:05:00 davem Exp $ diff -u --recursive --new-file v2.1.101/linux/Documentation/networking/policy-routing.txt linux/Documentation/networking/policy-routing.txt --- v2.1.101/linux/Documentation/networking/policy-routing.txt Sat May 2 14:19:51 1998 +++ linux/Documentation/networking/policy-routing.txt Thu May 14 10:26:22 1998 @@ -1,7 +1,7 @@ Classes ------- - "Class" is complete routing table in common sence. + "Class" is a complete routing table in common sense. I.e. it is tree of nodes (destination prefix, tos, metric) with attached information: gateway, device etc. This tree is looked up as specified in RFC1812 5.2.4.3 @@ -16,7 +16,7 @@ THROW - abort route lookup in this class. - Currently number of classes is limited by 255 + Currently the number of classes is limited to 255 (0 is reserved for "not specified class") Three classes are builtin: @@ -34,7 +34,7 @@ Rules ----- - Rule is record of (src prefix, src interface, tos, dst prefix) + Rule is a record of (src prefix, src interface, tos, dst prefix) with attached information. Rule types: @@ -65,15 +65,15 @@ ---------------- We scan rules list, and if a rule is matched, apply it. - If route is found, return it. - If it is not found or THROW node was matched, continue + If a route is found, return it. + If it is not found or a THROW node was matched, continue to scan rules. Applications ------------ -1. Just ignore classes. All the routes are put to MAIN class - (and/or to DEFAULT class). +1. Just ignore classes. All the routes are put into MAIN class + (and/or into DEFAULT class). HOWTO: iproute add PREFIX [ tos TOS ] [ gw GW ] [ dev DEV ] [ metric METRIC ] [ reject ] ... (look at iproute utility) @@ -89,13 +89,13 @@ [ dev INPUTDEV] [ pref PREFERENCE ] route [ gw GATEWAY ] [ dev OUTDEV ] ..... - Warning: just now size of routing table in this approach is - limited by 256. If someone will like this model, I'll + Warning: As of now the size of the routing table in this + approach is limited to 256. If someone likes this model, I'll relax this limitation. 3. OSPF classes (see RFC1583, RFC1812 E.3.3) Very clean, stable and robust algorithm for OSPF routing - domains. Unfortunately, it is not used widely in the Internet. + domains. Unfortunately, it is not widely used in the Internet. Proposed setup: 255 local addresses @@ -124,8 +124,8 @@ 4. The Variant Router Requirements Algorithm (RFC1812 E.3.2) Create 16 classes for different TOS values. - It is funny, but pretty useless algorithm. - I listed it just to show power of new routing code. + It is a funny, but pretty useless algorithm. + I listed it just to show the power of new routing code. 5. All the variety of combinations...... @@ -139,10 +139,10 @@ IMPORTANT NOTE -------------- - route.c has compilation time switch CONFIG_IP_LOCAL_RT_POLICY. + route.c has a compilation time switch CONFIG_IP_LOCAL_RT_POLICY. If it is set, locally originated packets are routed - using all the policy list. It is not very convenient and - pretty ambiguous, when used with NAT and masquerading. + using all the policy list. This is not very convenient and + pretty ambiguous when used with NAT and masquerading. I set it to FALSE by default. diff -u --recursive --new-file v2.1.101/linux/Documentation/networking/routing.txt linux/Documentation/networking/routing.txt --- v2.1.101/linux/Documentation/networking/routing.txt Sat May 2 14:19:51 1998 +++ linux/Documentation/networking/routing.txt Thu May 14 10:26:22 1998 @@ -27,17 +27,17 @@ - New interface addressing paradigm. Assignment of address ranges to interface, multiple prefixes etc. etc. - Do not bother, it is compatible with old one. Moreover: -- You more need not do "route add aaa.bbb.ccc... eth0", + Do not bother, it is compatible with the old one. Moreover: +- You don't need to do "route add aaa.bbb.ccc... eth0" anymore, it is done automatically. - "Abstract" UNIX sockets and security enhancements. - It is necessary to use TIRPC and TLI emulation library. + This is necessary to use TIRPC and TLI emulation library. NEWS for hacker. - New destination cache. Flexible, robust and just beautiful. - Network stack is reordered, simplified, optimized, a lot of bugs fixed. - (well, and new bugs are introduced, but I haven't seen them yet 8)) + (well, and new bugs were introduced, but I haven't seen them yet 8)) It is difficult to describe all the changes, look into source. If you see this file, then this patch works 8) diff -u --recursive --new-file v2.1.101/linux/MAINTAINERS linux/MAINTAINERS --- v2.1.101/linux/MAINTAINERS Wed Apr 8 19:36:24 1998 +++ linux/MAINTAINERS Mon May 11 14:38:28 1998 @@ -84,7 +84,7 @@ 8390 NETWORK DRIVERS [WD80x3/SMC-ELITE, SMC-ULTRA, NE2000, 3C503, etc.] P: Paul Gortmaker -M gpg109@rsphy1.anu.edu.au +M: gpg109@rsphy1.anu.edu.au L: linux-net@vger.rutgers.edu S: Maintained W: http://rsphy1.anu.edu.au/~gpg109/ne2000.html diff -u --recursive --new-file v2.1.101/linux/Makefile linux/Makefile --- v2.1.101/linux/Makefile Fri May 8 23:14:41 1998 +++ linux/Makefile Mon May 11 14:38:28 1998 @@ -1,6 +1,6 @@ VERSION = 2 PATCHLEVEL = 1 -SUBLEVEL = 101 +SUBLEVEL = 102 ARCH := $(shell uname -m | sed -e s/i.86/i386/ -e s/sun4u/sparc64/) @@ -86,10 +86,6 @@ # CFLAGS = -Wall -Wstrict-prototypes -O2 -fomit-frame-pointer - -ifdef CONFIG_CPP -CFLAGS := $(CFLAGS) -x c++ -endif ifdef SMP CFLAGS += -D__SMP__ diff -u --recursive --new-file v2.1.101/linux/README linux/README --- v2.1.101/linux/README Sun Jan 19 05:47:24 1997 +++ linux/README Sat May 9 12:49:12 1998 @@ -40,7 +40,7 @@ Linux was first developed for 386/486-based PCs. These days it also runs on DEC Alphas, SUN Sparcs, M68000 machines (like Atari and Amiga), - MIPS and PowerPC. + MIPS, PowerPC, and others. DOCUMENTATION: @@ -68,12 +68,17 @@ to get it all put in place. Replace "XX" with the version number of the latest kernel. - - You can also upgrade between 2.1.xx releases by patching. To install - by patching, get all the newer patch files and do + - You can also upgrade between 2.1.xx releases by patching. Patches are + distributed in the traditional gzip and the new bzip2 format. To + install by patching, get all the newer patch files and do cd /usr/src gzip -cd patchXX.gz | patch -p0 + or + cd /usr/src + bzip2 -dc patchXX.bz2 | patch -p0 + (repeat xx for all versions bigger than the version of your current source tree, _in_order_) and you should be ok. You may want to remove the backup files (xxx~ or xxx.orig), and make sure that there are no @@ -190,7 +195,11 @@ - Keep a backup kernel handy in case something goes wrong. This is especially true for the development releases, since each new release - contains new code which has not been debugged. + contains new code which has not been debugged. Make sure you keep a + backup of the modules corresponding to that kernel, as well. If you + are installing a new kernel with the same version number as your + working kernel, make a backup of your modules directory before you + do a "make modules_install". - In order to boot your new kernel, you'll need to copy the kernel image (found in /usr/src/linux/arch/i386/boot/zImage after compilation) @@ -206,8 +215,8 @@ If you boot Linux from the hard drive, chances are you use LILO which uses the kernel image as specified in the file /etc/lilo.conf. The kernel image file is usually /vmlinuz, or /zImage, or /etc/zImage. - To use the new kernel, copy the new image over the old one (save a - backup of the original!). Then, you MUST RERUN LILO to update the + To use the new kernel, save a copy of the old image and copy the new + image over the old one. Then, you MUST RERUN LILO to update the loading map!! If you don't, you won't be able to boot the new kernel image. diff -u --recursive --new-file v2.1.101/linux/arch/arm/boot/tools/build.c linux/arch/arm/boot/tools/build.c --- v2.1.101/linux/arch/arm/boot/tools/build.c Fri May 8 23:14:41 1998 +++ linux/arch/arm/boot/tools/build.c Wed Dec 31 16:00:00 1969 @@ -1,70 +0,0 @@ -#include -#include -#include -#include -#include - -typedef unsigned char byte; -typedef unsigned short word; -typedef unsigned long u32; - -void die(const char * str, ...) -{ - va_list args; - va_start(args, str); - vfprintf(stderr, str, args); - fputc('\n', stderr); - exit (1); -} - -int main(int argc, char **argv) -{ - void *data; - struct exec ex; - FILE *f; - int totlen; - - if (argc < 2) { - fprintf(stderr, "Usage: build kernel-name\n"); - exit(1); - } - - f = fopen(argv[1], "rb"); - if (!f) - die("Unable to open `%s': %m", argv[1]); - - fread(&ex, 1, sizeof(ex), f); - - if(N_MAGIC(ex) == ZMAGIC) { - fseek(f, 4096, SEEK_SET); - totlen = ex.a_text + ex.a_data; - } else - if(N_MAGIC(ex) == QMAGIC) { - unsigned long my_header; - - fseek(f, 4, SEEK_SET); - - my_header = 0xea000006; - - fwrite(&my_header, 4, 1, stdout); - - totlen = ex.a_text + ex.a_data - 4; - } else { - fprintf(stderr, "Unacceptable a.out header on kernel\n"); - fclose(f); - exit(1); - } - - fprintf(stderr, "Kernel is %dk (%dk text, %dk data, %dk bss)\n", - (ex.a_text + ex.a_data + ex.a_bss)/1024, - ex.a_text/1024, ex.a_data/1024, ex.a_bss/1024); - - data = malloc(totlen); - fread(data, 1, totlen, f); - fwrite(data, 1, totlen, stdout); - - free(data); - fclose(f); - fflush(stdout); - return 0; -} diff -u --recursive --new-file v2.1.101/linux/arch/arm/kernel/dec21285.c linux/arch/arm/kernel/dec21285.c --- v2.1.101/linux/arch/arm/kernel/dec21285.c Fri May 8 23:14:42 1998 +++ linux/arch/arm/kernel/dec21285.c Fri May 8 23:03:57 1998 @@ -3,7 +3,6 @@ * * Copyright (C) 1998 Russell King */ -#include #include #include #include diff -u --recursive --new-file v2.1.101/linux/arch/arm/kernel/entry-common.S linux/arch/arm/kernel/entry-common.S --- v2.1.101/linux/arch/arm/kernel/entry-common.S Fri May 8 23:14:42 1998 +++ linux/arch/arm/kernel/entry-common.S Fri May 8 23:03:57 1998 @@ -2,6 +2,8 @@ * All exits to user mode from the kernel go through this code. */ +#include + .globl ret_from_sys_call .globl SYMBOL_NAME(fpreturn) diff -u --recursive --new-file v2.1.101/linux/arch/arm/lib/extractinfo.perl linux/arch/arm/lib/extractinfo.perl --- v2.1.101/linux/arch/arm/lib/extractinfo.perl Fri May 8 23:14:42 1998 +++ linux/arch/arm/lib/extractinfo.perl Wed Dec 31 16:00:00 1969 @@ -1,45 +0,0 @@ -#!/usr/bin/perl - -$OBJDUMP=$ARGV[0]; - -sub swapdata { - local ($num) = @_; - - return substr($num, 6, 2).substr($num, 4, 2).substr ($num, 2, 2).substr ($num, 0, 2); -} - -open (DATA, $OBJDUMP.' --full-contents --section=.data getconsdata.o | grep \'^ 00\' |') || - die ('Cant objdump!'); -while () { - ($addr, $data0, $data1, $data2, $data3) = split (' '); - $dat[hex($addr)] = hex(&swapdata($data0)); - $dat[hex($addr)+4] = hex(&swapdata($data1)); - $dat[hex($addr)+8] = hex(&swapdata($data2)); - $dat[hex($addr)+12] = hex(&swapdata($data3)); -} -close (DATA); - -open (DATA, $OBJDUMP.' --syms getconsdata.o |') || die ('Cant objdump!'); -while () { - /elf32/ && ( $elf = 1 ); - /a.out/ && ( $aout = 1 ); - next if ($aout && ! / 07 /); - next if ($elf && ! (/^00...... g/ && /.data/)); - next if (!$aout && !$elf); - - ($addr, $flags, $sect, $a1, $a2, $a3, $name) = split (' ') if $aout; - $nam[hex($addr)] = substr($name, 1) if $aout; - if ($elf) { - chomp; - $addr = substr ($_, 0, 8); - $name = substr ($_, 32); - $nam[hex($addr)] = $name; - } -} -close (DATA); - -print "/*\n * *** THIS FILE IS AUTOMATICALLY GENERATED. DO NOT EDIT! ***\n */\n"; -for ($i = 0; $i < hex($addr)+12; $i ++) { - print "unsigned long $nam[$i] = $dat[$i];\n" if $dat[$i]; - print "#define __HAS_$nam[$i]\n" if $dat[$i]; -} diff -u --recursive --new-file v2.1.101/linux/arch/arm/mm/fault-armo.c linux/arch/arm/mm/fault-armo.c --- v2.1.101/linux/arch/arm/mm/fault-armo.c Fri May 8 23:14:42 1998 +++ linux/arch/arm/mm/fault-armo.c Fri May 8 23:03:57 1998 @@ -5,6 +5,7 @@ * Modifications for ARM processor (c) 1995, 1996 Russell King */ +#include #include #include #include diff -u --recursive --new-file v2.1.101/linux/arch/i386/defconfig linux/arch/i386/defconfig --- v2.1.101/linux/arch/i386/defconfig Fri May 8 23:14:42 1998 +++ linux/arch/i386/defconfig Thu May 14 10:43:36 1998 @@ -48,7 +48,7 @@ # CONFIG_PNP is not set # -# Floppy, IDE, and other block devices +# Block devices # CONFIG_BLK_DEV_FD=y CONFIG_BLK_DEV_IDE=y @@ -94,7 +94,6 @@ # CONFIG_IP_MULTICAST is not set # CONFIG_IP_ADVANCED_ROUTER is not set # CONFIG_IP_PNP is not set -# CONFIG_IP_ACCT is not set # CONFIG_IP_ROUTER is not set # CONFIG_NET_IPIP is not set # CONFIG_NET_IPGRE is not set diff -u --recursive --new-file v2.1.101/linux/arch/i386/kernel/entry.S linux/arch/i386/kernel/entry.S --- v2.1.101/linux/arch/i386/kernel/entry.S Thu May 7 22:51:46 1998 +++ linux/arch/i386/kernel/entry.S Tue May 12 13:13:15 1998 @@ -547,6 +547,6 @@ .long SYMBOL_NAME(sys_capget) .long SYMBOL_NAME(sys_capset) /* 185 */ - .rept NR_syscalls-184 + .rept NR_syscalls-185 .long SYMBOL_NAME(sys_ni_syscall) .endr diff -u --recursive --new-file v2.1.101/linux/arch/i386/kernel/io_apic.c linux/arch/i386/kernel/io_apic.c --- v2.1.101/linux/arch/i386/kernel/io_apic.c Thu May 7 22:51:46 1998 +++ linux/arch/i386/kernel/io_apic.c Thu May 14 09:43:35 1998 @@ -110,6 +110,12 @@ int mpc_default_type = 0; /* non-0 if default (table-less) MP configuration */ + +/* + * This is performance-critical, we want to do it O(1) + */ +static int irq_2_pin[NR_IRQS]; + unsigned int io_apic_read (unsigned int reg) { *IO_APIC_BASE = reg; @@ -122,32 +128,32 @@ *(IO_APIC_BASE+4) = value; } -void enable_IO_APIC_irq (unsigned int irq) +/* + * We disable IO-APIC IRQs by setting their 'destination CPU mask' to + * zero. Trick, trick. + */ +void disable_IO_APIC_irq(unsigned int irq) { + int pin = irq_2_pin[irq]; struct IO_APIC_route_entry entry; - /* - * Enable it in the IO-APIC irq-routing table: - */ - *(((int *)&entry)+0) = io_apic_read(0x10+irq*2); - entry.mask = 0; - io_apic_write(0x10+2*irq, *(((int *)&entry)+0)); + if (pin != -1) { + *(((int *)&entry)+1) = io_apic_read(0x11+pin*2); + entry.dest.logical.logical_dest = 0x0; + io_apic_write(0x11+2*pin, *(((int *)&entry)+1)); + } } -/* - * this function is just here to make things complete, otherwise it's - * unused - */ -void disable_IO_APIC_irq (unsigned int irq) +void enable_IO_APIC_irq(unsigned int irq) { + int pin = irq_2_pin[irq]; struct IO_APIC_route_entry entry; - /* - * Disable it in the IO-APIC irq-routing table: - */ - *(((int *)&entry)+0) = io_apic_read(0x10+irq*2); - entry.mask = 1; - io_apic_write(0x10+2*irq, *(((int *)&entry)+0)); + if (pin != -1) { + *(((int *)&entry)+1) = io_apic_read(0x11+pin*2); + entry.dest.logical.logical_dest = 0xff; + io_apic_write(0x11+2*pin, *(((int *)&entry)+1)); + } } void clear_IO_APIC_pin (unsigned int pin) @@ -163,6 +169,7 @@ io_apic_write(0x11+2*pin, *(((int *)&entry)+1)); } + /* * support for broken MP BIOSes, enables hand-redirection of PIRQ0-7 to * specific CPU-side IRQs. @@ -258,129 +265,176 @@ return -1; } -static int irq_trigger(int idx) +/* + * There are broken mptables which register ISA+high-active+level IRQs, + * these are illegal and are converted here to ISA+high-active+edge + * IRQ sources. Careful, ISA+low-active+level is another broken entry + * type, it represents PCI IRQs 'embedded into an ISA bus', they have + * to be accepted. Yes, ugh. + */ + +static int MPBIOS_polarity(int idx) { int bus = mp_irqs[idx].mpc_srcbus; - int trigger; + int polarity; /* - * Determine IRQ trigger mode (edge or level sensitive): + * Determine IRQ line polarity (high active or low active): */ - switch ((mp_irqs[idx].mpc_irqflag>>2) & 3) + switch (mp_irqs[idx].mpc_irqflag & 3) { - case 0: /* conforms, ie. bus-type dependent */ + case 0: /* conforms, ie. bus-type dependent polarity */ { switch (mp_bus_id_to_type[bus]) { - case MP_BUS_ISA: /* ISA pin, edge */ + case MP_BUS_ISA: /* ISA pin */ { - trigger = 0; + polarity = 0; break; } - case MP_BUS_PCI: /* PCI pin, level */ + case MP_BUS_PCI: /* PCI pin */ { - trigger = 1; + polarity = 1; break; } default: { printk("broken BIOS!!\n"); - trigger = 1; + polarity = 1; break; } } break; } - case 1: /* edge */ + case 1: /* high active */ { - trigger = 0; + polarity = 0; break; } case 2: /* reserved */ { printk("broken BIOS!!\n"); - trigger = 1; + polarity = 1; break; } - case 3: /* level */ + case 3: /* low active */ { - trigger = 1; + polarity = 1; break; } default: /* invalid */ { printk("broken BIOS!!\n"); - trigger = 0; + polarity = 1; break; } } - return trigger; + return polarity; } -__initfunc(static int irq_polarity(int idx)) + +static int MPBIOS_trigger(int idx) { int bus = mp_irqs[idx].mpc_srcbus; - int polarity; + int trigger; /* - * Determine IRQ line polarity (high active or low active): + * Determine IRQ trigger mode (edge or level sensitive): */ - switch (mp_irqs[idx].mpc_irqflag & 3) + switch ((mp_irqs[idx].mpc_irqflag>>2) & 3) { - case 0: /* conforms, ie. bus-type dependent polarity */ + case 0: /* conforms, ie. bus-type dependent */ { switch (mp_bus_id_to_type[bus]) { - case MP_BUS_ISA: /* ISA pin */ + case MP_BUS_ISA: /* ISA pin, edge */ { - polarity = 0; + trigger = 0; break; } - case MP_BUS_PCI: /* PCI pin */ + case MP_BUS_PCI: /* PCI pin, level */ { - polarity = 1; + trigger = 1; break; } default: { printk("broken BIOS!!\n"); - polarity = 1; + trigger = 1; break; } } break; } - case 1: /* high active */ + case 1: /* edge */ { - polarity = 0; + trigger = 0; break; } case 2: /* reserved */ { printk("broken BIOS!!\n"); - polarity = 1; + trigger = 1; break; } - case 3: /* low active */ + case 3: /* level */ { - polarity = 1; + trigger = 1; break; } default: /* invalid */ { printk("broken BIOS!!\n"); - polarity = 1; + trigger = 0; break; } } - return polarity; + return trigger; +} + +static int trigger_flag_broken (int idx) +{ + int bus = mp_irqs[idx].mpc_srcbus; + int polarity = MPBIOS_polarity(idx); + int trigger = MPBIOS_trigger(idx); + + if ( (mp_bus_id_to_type[bus] == MP_BUS_ISA) && + (polarity == 0) /* active-high */ && + (trigger == 1) /* level */ ) + + return 1; /* broken */ + + return 0; +} + +static int irq_polarity (int idx) +{ + /* + * There are no known BIOS bugs wrt polarity. yet. + */ + return MPBIOS_polarity(idx); } -__initfunc(static int pin_2_irq (int idx, int pin)) +static int irq_trigger (int idx) +{ + int trigger = MPBIOS_trigger(idx); + + if (trigger_flag_broken (idx)) + trigger = 0; + return trigger; +} + +static int pin_2_irq (int idx, int pin) { int irq; int bus = mp_irqs[idx].mpc_srcbus; + /* + * Debugging check, we are in big trouble if this message pops up! + */ + if (mp_irqs[idx].mpc_dstirq != pin) + printk("broken BIOS or MPTABLE parser, ayiee!!\n"); + switch (mp_bus_id_to_type[bus]) { case MP_BUS_ISA: /* ISA pin */ @@ -423,12 +477,12 @@ int IO_APIC_irq_trigger (int irq) { - int idx, i; + int idx, pin; - for (i=0; i%d ", i, irq_2_pin[i]); + printk("\n"); + printk(".................................... done.\n"); return; @@ -632,8 +680,10 @@ __initfunc(static void init_sym_mode (void)) { - int i; + int i, pin; + for (i=0; itypename); p += sprintf(p, " %s", action->name); for (action=action->next; action; action = action->next) { @@ -695,6 +684,16 @@ set_8259A_irq_mask(irq); } +int i8259A_irq_pending (unsigned int irq) +{ + unsigned int mask = 1<> 8)); +} + + void make_8259A_irq (unsigned int irq) { io_apic_irqs &= ~(1<events; desc->events = 0; if (!pending) @@ -822,7 +817,6 @@ spin_unlock(&irq_controller_lock); } desc->status &= IRQ_DISABLED; - spin_unlock(&irq_controller_lock); no_handler: } @@ -850,6 +844,7 @@ } handle_ioapic_event(irq,cpu,regs); + spin_unlock(&irq_controller_lock); hardirq_exit(cpu); release_irqlock(cpu); @@ -862,13 +857,14 @@ spin_lock(&irq_controller_lock); /* - * in the level triggered case we first disable the IRQ + * In the level triggered case we first disable the IRQ * in the IO-APIC, then we 'early ACK' the IRQ, then we * handle it and enable the IRQ when finished. + * + * disable has to happen before the ACK, to avoid IRQ storms. + * So this all has to be within the spinlock. */ -#if NOT_BROKEN disable_IO_APIC_irq(irq); -#endif ack_APIC_irq(); desc->ipi = 0; @@ -883,6 +879,10 @@ } handle_ioapic_event(irq,cpu,regs); + /* we still have the spinlock held here */ + + enable_IO_APIC_irq(irq); + spin_unlock(&irq_controller_lock); hardirq_exit(cpu); release_irqlock(cpu); @@ -981,11 +981,34 @@ 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)) + 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 { @@ -995,15 +1018,9 @@ shared = 1; } - if (new->flags & SA_SAMPLE_RANDOM) - rand_initialize_irq(irq); - - save_flags(flags); - cli(); *p = new; if (!shared) { - spin_lock(&irq_controller_lock); #ifdef __SMP__ if (IO_APIC_IRQ(irq)) { if (IO_APIC_VECTOR(irq) > 0xfe) @@ -1016,14 +1033,21 @@ * First disable it in the 8259A: */ cached_irq_mask |= 1 << irq; - if (irq < 16) + if (irq < 16) { set_8259A_irq_mask(irq); + /* + * transport pending ISA IRQs to + * the new descriptor + */ + if (i8259A_irq_pending(irq)) + irq_desc[irq].events = 1; + } } #endif - unmask_generic_irq(irq); - spin_unlock(&irq_controller_lock); + irq_desc[irq].status = 0; + irq_desc[irq].handler->enable(irq); } - restore_flags(flags); + spin_unlock_irqrestore(&irq_controller_lock,flags); return 0; } @@ -1065,23 +1089,23 @@ struct irqaction * action, **p; unsigned long flags; - if (irq >= NR_IRQS) { - printk("Trying to free IRQ%d\n",irq); + if (irq >= NR_IRQS) return; - } + + spin_lock_irqsave(&irq_controller_lock,flags); 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_flags(flags); - cli(); *p = action->next; - restore_flags(flags); kfree(action); - return; + irq_desc[irq].handler->disable(irq); + goto out; } printk("Trying to free free IRQ%d\n",irq); +out: + spin_unlock_irqrestore(&irq_controller_lock,flags); } /* @@ -1103,7 +1127,7 @@ spin_lock_irq(&irq_controller_lock); for (i = NR_IRQS-1; i > 0; i--) { if (!irq_desc[i].action) { - unmask_generic_irq(i); + irq_desc[i].handler->enable(i); irqs |= (1 << i); } } @@ -1170,8 +1194,8 @@ (IO_APIC_IRQ(i))) { if (IO_APIC_irq_trigger(i)) irq_desc[i].handler = &ioapic_level_irq_type; - else - irq_desc[i].handler = &ioapic_edge_irq_type; + else /* edge */ + irq_desc[i].handler = &ioapic_level_irq_type; /* * disable it in the 8259A: */ @@ -1233,6 +1257,8 @@ /* IPI for MTRR control */ set_intr_gate(0x50, mtrr_interrupt); + /* IPI vector for APIC spurious interrupts */ + set_intr_gate(0xff, spurious_interrupt); #endif request_region(0x20,0x20,"pic1"); request_region(0xa0,0x20,"pic2"); diff -u --recursive --new-file v2.1.101/linux/arch/i386/kernel/irq.h linux/arch/i386/kernel/irq.h --- v2.1.101/linux/arch/i386/kernel/irq.h Thu May 7 22:51:46 1998 +++ linux/arch/i386/kernel/irq.h Thu May 14 09:43:35 1998 @@ -12,7 +12,8 @@ void unmask_irq(unsigned int irq); void enable_IO_APIC_irq (unsigned int irq); void disable_IO_APIC_irq (unsigned int irq); -void set_8259A_irq_mask(unsigned int irq); +void set_8259A_irq_mask (unsigned int irq); +int i8259A_irq_pending (unsigned int irq); void ack_APIC_irq (void); void setup_IO_APIC (void); void init_IO_APIC_traps(void); @@ -21,6 +22,7 @@ void make_8259A_irq (unsigned int irq); void send_IPI (int dest, int vector); void init_pic_mode (void); +void print_IO_APIC (void); extern unsigned int io_apic_irqs; diff -u --recursive --new-file v2.1.101/linux/arch/i386/kernel/process.c linux/arch/i386/kernel/process.c --- v2.1.101/linux/arch/i386/kernel/process.c Thu May 7 22:51:46 1998 +++ linux/arch/i386/kernel/process.c Thu May 14 10:56:50 1998 @@ -528,8 +528,18 @@ */ p->tss.bitmap = sizeof(struct thread_struct); +/* + * This tried to copy the FPU state, but I wonder whether we really + * want this at all. It is probably nicer to just have a newly started + * process start with a clean slate wrt the fpu. - Linus + */ +#if 1 + current->used_math = 0; + current->flags &= ~PF_USEDFPU; +#else if (last_task_used_math == current) __asm__("clts ; fnsave %0 ; frstor %0":"=m" (p->tss.i387)); +#endif return 0; } diff -u --recursive --new-file v2.1.101/linux/arch/i386/kernel/setup.c linux/arch/i386/kernel/setup.c --- v2.1.101/linux/arch/i386/kernel/setup.c Tue Mar 10 10:03:30 1998 +++ linux/arch/i386/kernel/setup.c Wed May 13 11:47:26 1998 @@ -238,6 +238,9 @@ int nr = c->x86_model; char *buf = c->x86_model_id; + /* Cyrix claims they have a TSC, but it is broken */ + c->x86_capability &= ~16; + /* Note that some of the possibilities this decoding allows * have never actually been manufactured - but those that * do actually exist are correctly decoded. diff -u --recursive --new-file v2.1.101/linux/arch/i386/kernel/smp.c linux/arch/i386/kernel/smp.c --- v2.1.101/linux/arch/i386/kernel/smp.c Thu May 7 22:51:46 1998 +++ linux/arch/i386/kernel/smp.c Thu May 14 09:43:35 1998 @@ -636,9 +636,16 @@ value = apic_read(APIC_SPIV); value |= (1<<8); /* Enable APIC (bit==1) */ value &= ~(1<<9); /* Enable focus processor (bit==0) */ + value |= 0xff; /* Set spurious IRQ vector to 0xff */ apic_write(APIC_SPIV,value); + value = apic_read(APIC_TASKPRI); + value &= ~APIC_TPRI_MASK; /* Set Task Priority to 'accept all' */ + apic_write(APIC_TASKPRI,value); + udelay(100); /* B safe */ + ack_APIC_irq(); + udelay(100); } __initfunc(void smp_callin(void)) @@ -1152,12 +1159,6 @@ __restore_flags(flags); } -void funny (void) -{ - send_IPI(APIC_DEST_ALLBUT,0x30 /*IO_APIC_VECTOR(11)*/); - for(;;)__cli(); -} - /* * A non wait message cannot pass data or cpu source info. This current setup * is only safe because the kernel lock owner is the only person who can send @@ -1474,19 +1475,18 @@ } /* - * Reschedule call back + * Reschedule call back (not used currently) */ + asmlinkage void smp_reschedule_interrupt(void) { int cpu = smp_processor_id(); ack_APIC_irq(); - for (;;) __cli(); /* * This looks silly, but we actually do need to wait * for the global interrupt lock. */ - printk("huh, this is used, where???\n"); irq_enter(cpu, 0); need_resched = 1; irq_exit(cpu, 0); @@ -1522,6 +1522,15 @@ } /* + * This interrupt should _never_ happen with our APIC/SMP architecture + */ +asmlinkage void smp_spurious_interrupt(void) +{ + ack_APIC_irq (); + printk("spurious APIC interrupt, ayiee, should never happen.\n"); +} + +/* * This part sets up the APIC 32 bit clock in LVTT1, with HZ interrupts * per second. We assume that the caller has already set up the local * APIC. @@ -1564,7 +1573,7 @@ * APIC double write bug. */ -#define APIC_DIVISOR 1 +#define APIC_DIVISOR 16 void setup_APIC_timer (unsigned int clocks) { @@ -1588,7 +1597,7 @@ */ tmp_value = apic_read(APIC_TDCR); apic_write(APIC_TDCR , (tmp_value & ~APIC_TDR_DIV_1 ) - | APIC_TDR_DIV_1); + | APIC_TDR_DIV_16); tmp_value = apic_read(APIC_TMICT); apic_write(APIC_TMICT, clocks/APIC_DIVISOR); diff -u --recursive --new-file v2.1.101/linux/arch/i386/kernel/time.c linux/arch/i386/kernel/time.c --- v2.1.101/linux/arch/i386/kernel/time.c Fri Jan 30 11:28:06 1998 +++ linux/arch/i386/kernel/time.c Wed May 13 13:23:13 1998 @@ -525,10 +525,6 @@ xtime.tv_usec = 0; /* If we have the CPU hardware time counters, use them */ -#ifndef CONFIG_APM - /* Don't use them if a suspend/resume could - corrupt the timer value. This problem - needs more debugging. */ if (boot_cpu_data.x86_capability & 16) { do_gettimeoffset = do_fast_gettimeoffset; do_get_fast_time = do_x86_get_fast_time; @@ -551,6 +547,5 @@ "=d" (init_timer_cc.high)); irq0.handler = pentium_timer_interrupt; } -#endif setup_x86_irq(0, &irq0); } diff -u --recursive --new-file v2.1.101/linux/arch/m68k/kernel/m68k_ksyms.c linux/arch/m68k/kernel/m68k_ksyms.c --- v2.1.101/linux/arch/m68k/kernel/m68k_ksyms.c Fri May 8 23:14:42 1998 +++ linux/arch/m68k/kernel/m68k_ksyms.c Fri May 8 23:03:57 1998 @@ -1,3 +1,4 @@ +#include #include #include #include diff -u --recursive --new-file v2.1.101/linux/arch/mips/kernel/process.c linux/arch/mips/kernel/process.c --- v2.1.101/linux/arch/mips/kernel/process.c Fri May 8 23:14:43 1998 +++ linux/arch/mips/kernel/process.c Fri May 8 23:03:57 1998 @@ -9,7 +9,6 @@ * * $Id: process.c,v 1.10 1998/05/04 09:17:53 ralf Exp $ */ -#include #include #include #include diff -u --recursive --new-file v2.1.101/linux/arch/mips/mm/r4xx0.c linux/arch/mips/mm/r4xx0.c --- v2.1.101/linux/arch/mips/mm/r4xx0.c Fri May 8 23:14:43 1998 +++ linux/arch/mips/mm/r4xx0.c Fri May 8 23:03:57 1998 @@ -11,6 +11,7 @@ * - many of the bug workarounds are not efficient at all, but at * least they are functional ... */ +#include #include #include #include diff -u --recursive --new-file v2.1.101/linux/arch/mips/sgi/kernel/indy_sc.c linux/arch/mips/sgi/kernel/indy_sc.c --- v2.1.101/linux/arch/mips/sgi/kernel/indy_sc.c Fri May 8 23:14:43 1998 +++ linux/arch/mips/sgi/kernel/indy_sc.c Fri May 8 23:03:57 1998 @@ -6,7 +6,6 @@ * * $Id: indy_sc.c,v 1.4 1998/05/04 09:12:57 ralf Exp $ */ -#include #include #include #include diff -u --recursive --new-file v2.1.101/linux/arch/ppc/kernel/prep_time.c linux/arch/ppc/kernel/prep_time.c --- v2.1.101/linux/arch/ppc/kernel/prep_time.c Fri May 8 23:14:45 1998 +++ linux/arch/ppc/kernel/prep_time.c Fri May 8 23:03:57 1998 @@ -8,7 +8,6 @@ * copied and modified from intel version * */ -#include #include #include #include diff -u --recursive --new-file v2.1.101/linux/arch/ppc/lib/string.S linux/arch/ppc/lib/string.S --- v2.1.101/linux/arch/ppc/lib/string.S Fri May 8 23:14:45 1998 +++ linux/arch/ppc/lib/string.S Fri May 8 23:03:57 1998 @@ -8,6 +8,7 @@ * as published by the Free Software Foundation; either version * 2 of the License, or (at your option) any later version. */ +#include #include "../kernel/ppc_asm.tmpl" #include #include diff -u --recursive --new-file v2.1.101/linux/arch/sparc64/solaris/fs.c linux/arch/sparc64/solaris/fs.c --- v2.1.101/linux/arch/sparc64/solaris/fs.c Thu May 7 22:51:47 1998 +++ linux/arch/sparc64/solaris/fs.c Fri May 8 22:55:06 1998 @@ -523,7 +523,7 @@ newattrs.ia_mode &= ~S_ISGID; newattrs.ia_valid |= ATTR_MODE; } - DQUOT_TRANSFER(dentry, newattrs); + error = DQUOT_TRANSFER(dentry, &newattrs); out: return error; } diff -u --recursive --new-file v2.1.101/linux/drivers/block/Config.in linux/drivers/block/Config.in --- v2.1.101/linux/drivers/block/Config.in Fri May 8 23:14:47 1998 +++ linux/drivers/block/Config.in Mon May 11 14:38:28 1998 @@ -2,7 +2,7 @@ # Block device driver configuration # mainmenu_option next_comment -comment 'Floppy, IDE, and other block devices' +comment 'Block devices' tristate 'Normal floppy disk support' CONFIG_BLK_DEV_FD tristate 'Enhanced IDE/MFM/RLL disk/cdrom/tape/floppy support' CONFIG_BLK_DEV_IDE diff -u --recursive --new-file v2.1.101/linux/drivers/block/ide.c linux/drivers/block/ide.c --- v2.1.101/linux/drivers/block/ide.c Fri May 8 23:14:47 1998 +++ linux/drivers/block/ide.c Sat May 9 11:54:19 1998 @@ -1333,6 +1333,7 @@ } hwgroup->busy = 1; /* should already be "1" */ hwgroup->handler = NULL; + del_timer(&hwgroup->timer); if (hwgroup->poll_timeout != 0) { /* polling in progress? */ IDE_SPIN_UNLOCK_IRQRESTORE("ide_timer_expiry3", &hwgroup->spinlock, flags); handler(drive); @@ -1348,7 +1349,6 @@ IDE_SPIN_UNLOCK_IRQRESTORE("ide_timer_expiry5", &hwgroup->spinlock, flags); ide_error(drive, "irq timeout", GET_STAT()); } - del_timer(&hwgroup->timer); start_next_request(hwgroup, 0); } diff -u --recursive --new-file v2.1.101/linux/drivers/block/nbd.c linux/drivers/block/nbd.c --- v2.1.101/linux/drivers/block/nbd.c Thu May 7 22:51:48 1998 +++ linux/drivers/block/nbd.c Mon May 11 14:38:28 1998 @@ -316,6 +316,8 @@ struct nbd_device *lo; int dev, error; + /* Anyone capable of this syscall can do *real bad* things */ + if (!capable(CAP_SYS_ADMIN)) return -EPERM; if (!inode) @@ -422,6 +424,11 @@ int nbd_init(void) { int i; + + if (sizeof(struct nbd_request) != 24) { + printk(KERN_CRIT "Sizeof nbd_request needs to be 24 in order to work!\n" ); + return -EIO; + } if (register_blkdev(MAJOR_NR, "nbd", &nbd_fops)) { printk("Unable to get major number %d for NBD\n", diff -u --recursive --new-file v2.1.101/linux/drivers/char/cyclades.c linux/drivers/char/cyclades.c --- v2.1.101/linux/drivers/char/cyclades.c Tue Apr 14 14:29:20 1998 +++ linux/drivers/char/cyclades.c Sat May 9 13:06:26 1998 @@ -3382,7 +3382,7 @@ copy_from_user(&new_serial,new_info,sizeof(new_serial)); old_info = *info; - if (!suser()) { + if (!capable(CAP_SYS_ADMIN)) { if ((new_serial.close_delay != info->close_delay) || (new_serial.baud_base != info->baud) || ((new_serial.flags & ASYNC_FLAGS & ~ASYNC_USR_MASK) != diff -u --recursive --new-file v2.1.101/linux/drivers/char/joystick.c linux/drivers/char/joystick.c --- v2.1.101/linux/drivers/char/joystick.c Wed Apr 8 19:36:26 1998 +++ linux/drivers/char/joystick.c Fri May 8 23:07:44 1998 @@ -1,13 +1,12 @@ /* - * $Id: joystick.c,v 1.6 1998/03/30 11:10:43 mj Exp $ - * - * Copyright (C) 1997, 1998 Vojtech Pavlik + * linux/drivers/char/joystick.c Version 1.0.9 + * Copyright (C) 1996-1998 Vojtech Pavlik */ /* - * This is joystick driver for Linux. It supports up to two analog joysticks - * on a PC compatible machine. See Documentation/joystick.txt for changelog - * and credits. + * This is joystick driver for Linux. It supports up to two analog joysticks + * on a PC compatible machine. See Documentation/joystick.txt for changelog + * and credits. */ #include @@ -30,10 +29,10 @@ #define JS_BH_MIN_PERIOD HZ/25 /* axis min valid time (40 ms) */ #define JS_BH_MAX_PERIOD HZ/25*2 /* axis max valid time (80 ms) */ -#define JS_FIFO_SIZE 16 /* number of FIFO entries */ +#define JS_FIFO_SIZE 16 /* number of FIFO entries */ #define JS_BUFF_SIZE 32 /* output buffer size */ -#define JS_RETRIES 4 /* number of retries */ -#define JS_DEF_PREC 8 /* initial precision for all axes */ +#define JS_RETRIES 4 /* number of retries */ +#define JS_DEF_PREC 16 /* initial precision for all axes */ #define JS_NUM 2 /* number of joysticks */ @@ -44,7 +43,7 @@ #define PIT_DATA 0x40 /* timer 0 data port */ #define JS_PORT 0x201 /* joystick port */ -#define JS_TRIGGER 0xff /* triggers one-shots */ +#define JS_TRIGGER 0xff /* triggers one-shots */ #define PIT_READ_TIMER 0x00 /* to read timer 0 */ #define DELTA(X,Y,Z) ((X)-(Y)+(((X)>=(Y))?0:Z)) /* cyclic delta */ @@ -101,7 +100,7 @@ MODULE_AUTHOR("Vojtech Pavlik "); MODULE_SUPPORTED_DEVICE("js"); -MODULE_PARM(js, "0-1b"); +MODULE_PARM(js, "1-2b"); static char js[] = {0, 0}; @@ -113,7 +112,7 @@ static inline int get_pit(void) { int t, flags; - + save_flags(flags); cli(); outb(PIT_READ_TIMER, PIT_MODE); @@ -146,36 +145,34 @@ int t; if (corr->type == JS_CORR_NONE) return value; - t = value > corr->coef[0] ? (value < corr->coef[1] ? corr->coef[0] : value - corr->coef[1] + corr->coef[0]) : value; - if (t == corr->coef[0]) return 32768; + t = value > corr->coef[0] ? (value < corr->coef[1] ? 0 : value - corr->coef[1]) : value - corr->coef[0]; switch (corr->type) { case JS_CORR_BROKEN: - t = t < corr->coef[0] ? ((corr->coef[2] * t) >> 14) + corr->coef[3] : - ((corr->coef[4] * t) >> 14) + corr->coef[5]; + t = t < 0 ? ((corr->coef[2] * t) >> 14) : ((corr->coef[3] * t) >> 14); break; - default: + default: return 0; } - if (t < 0) return 0; - if (t > 65535) return 65535; + if (t < -32767) return -32767; + if (t > 32767) return 32767; - return t; + return t; } /* - * js_compare() compares two close axis values and decides + * js_compare() compares two close axis values and decides * whether they are "same". */ static int js_compare(int x, int y, int prec) { - return (x < y + prec) && (y < x + prec); + return (x < y + prec) && (y < x + prec); } /* - * js_probe() probes for joysticks + * js_probe() probes for joysticks */ inline int js_probe(void) @@ -193,10 +190,10 @@ } else switch (t & JS_AXES) { case 0x0c: jsd[0].exist = 0x33; jsd[1].exist = 0x00; break; /* joystick 0 connected */ - case 0x03: jsd[0].exist = 0x00; jsd[1].exist = 0xcc; break; /* joystick 1 connected */ + case 0x03: jsd[0].exist = 0xcc; jsd[1].exist = 0x00; break; /* joystick 1 connected */ case 0x04: jsd[0].exist = 0xfb; jsd[1].exist = 0x00; break; /* 3-axis joystick connected */ case 0x00: jsd[0].exist = 0x33; jsd[1].exist = 0xcc; break; /* joysticks 0 and 1 connected */ - default: jsd[0].exist = 0x00; jsd[1].exist = 0x00; return -1; /* no joysticks */ + default: jsd[0].exist = 0x00; jsd[1].exist = 0x00; return -1; /* no joysticks */ } js_axes_exist = (jsd[0].exist | jsd[1].exist) & JS_AXES; @@ -205,7 +202,7 @@ return 0; } -/* +/* * js_do_timer() controls the action by adding entries to the event * fifo each time a button changes its state or axis valid time * expires. @@ -223,7 +220,7 @@ js_mark_time = jiffies; mark_bh(JS_BH); } - } + } else if ((jiffies > js_bh_time + JS_BH_MAX_PERIOD) && !js_mark_time) { js_mark_time = jiffies; @@ -257,7 +254,7 @@ static void js_sync_buff(void) { int i; - + for (i = 0; i < JS_NUM; i++) if (jsd[i].list) if (jsd[i].bhead != jsd[i].ahead) { @@ -266,12 +263,12 @@ curl = jsd[i].list; while (curl) { if (ROT(jsd[i].bhead, curl->tail, jsd[i].ahead) || (curl->tail == jsd[i].bhead)) { - curl->tail = jsd[i].ahead; + curl->tail = jsd[i].ahead; curl->startup = jsd[i].exist; } curl = curl->next; } - jsd[i].tail = jsd[i].ahead; + jsd[i].tail = jsd[i].ahead; } jsd[i].bhead = jsd[i].ahead; wake_up_interruptible(&jsd[i].wait); @@ -316,8 +313,8 @@ cli(); /* no interrupts */ outb(JS_TRIGGER, JS_PORT); /* trigger one-shots */ outb(PIT_READ_TIMER, PIT_MODE); /* read timer */ - t = (t1l = inb(PIT_DATA)) | - (t1h = inb(PIT_DATA)) << 8; + t = (t1l = inb(PIT_DATA)) | + (t1h = inb(PIT_DATA)) << 8; restore_flags(flags); do { @@ -328,7 +325,7 @@ joy_state = (joy_state << 8) | jss; i++; } - + cli(); outb(PIT_READ_TIMER, PIT_MODE); t1l = inb(PIT_DATA); @@ -341,15 +338,15 @@ * Process the gathered axis data in joy_state. */ - joy_state ^= ((joy_state >> 8) | 0xff000000L); /* More magic */ + joy_state ^= ((joy_state >> 8) | 0xff000000L); /* More magic */ for (; i > 0; i--) { for (j = 0; j < 4; j++) if (joy_state & js_axes_exist & (1 << j)) { - jsm = js_correct(DELTA_TX(t, t_low, t_high), &js_axis[j].corr); + jsm = DELTA_TX(t, t_low, t_high); if (!js_compare(jsm, js_axis[j].value, js_axis[j].corr.prec)) { if (jsm < js_axis[j].value || !retries) - js_axis[j].value = jsm; + js_axis[j].value = jsm; again = 1; } } @@ -358,7 +355,7 @@ t_high = t_high >> 8; } - } while (retries++ < JS_RETRIES && again); + } while (retries++ < JS_RETRIES && again); /* * Check if joystick lost. @@ -390,8 +387,9 @@ k = 0; for (j = 0; j < 4; j++) if ((1 << j) & jsd[i].exist) { - if (!js_compare(js_axis[j].value, old_axis[j], js_axis[j].corr.prec)) - js_add_event(i, js_mark_time, JS_EVENT_AXIS, k, js_axis[j].value); + if ((t = js_correct(js_axis[j].value, &js_axis[j].corr)) != + js_correct(old_axis[j], &js_axis[j].corr)) + js_add_event(i, js_mark_time, JS_EVENT_AXIS, k, t); k++; } } @@ -448,7 +446,7 @@ unsigned long blocks = count / sizeof(struct js_event); unsigned long i = 0, j; int t, u = curl->tail; - int retval = 0; + int retval = 0; /* * Check user data. @@ -474,13 +472,13 @@ if ((GOF(curl->tail) == jsd[minor].ahead && !curl->startup && count != sizeof(struct JS_DATA_TYPE)) - || (curl->startup && !js_bh_time)) { + || (curl->startup && !js_bh_time)) { add_wait_queue(&jsd[minor].wait, &wait); current->state = TASK_INTERRUPTIBLE; while ((GOF(curl->tail) == jsd[minor].ahead && !curl->startup && count != sizeof(struct JS_DATA_TYPE)) - || (curl->startup && !js_bh_time)) { + || (curl->startup && !js_bh_time)) { if (file->f_flags & O_NONBLOCK) { retval = -EAGAIN; @@ -501,7 +499,7 @@ } if (retval) return retval; - + /* * Do the i/o. */ @@ -519,15 +517,15 @@ if (curl->startup & (1 << j)) { tmpevent.type = JS_EVENT_AXIS | JS_EVENT_INIT; tmpevent.number = t; - tmpevent.value = js_axis[j].value; - if (copy_to_user(&buff[i], &tmpevent, sizeof(struct js_event))) + tmpevent.value = js_correct(js_axis[j].value, &js_axis[j].corr); + if (copy_to_user(&buff[i], &tmpevent, sizeof(struct js_event))) retval = -EFAULT; if (put_user((__u32)((jiffies - curl->time) * (1000/HZ)), &buff[i].time)) retval = -EFAULT; curl->startup &= ~(1 << j); i++; } - t++; + t++; } /* @@ -541,14 +539,14 @@ tmpevent.type = JS_EVENT_BUTTON | JS_EVENT_INIT; tmpevent.number = t; tmpevent.value = (js_buttons >> j) & 1; - if (copy_to_user(&buff[i], &tmpevent, sizeof(struct js_event))) + if (copy_to_user(&buff[i], &tmpevent, sizeof(struct js_event))) retval = -EFAULT; if (put_user((__u32)((jiffies - curl->time) * (1000/HZ)), &buff[i].time)) retval = -EFAULT; curl->startup &= ~(1 << j); i++; } - t++; + t++; } } @@ -564,7 +562,7 @@ curl->tail = t; i++; } - + } else @@ -609,7 +607,7 @@ } if (!curl) jsd[minor].tail = t; } - + return retval ? retval : i*sizeof(struct js_event); } @@ -624,19 +622,16 @@ curl = file->private_data; poll_wait(file, &jsd[minor].wait, wait); - if (GOF(curl->tail) != jsd[minor].ahead) + if (GOF(curl->tail) != jsd[minor].ahead) return POLLIN | POLLRDNORM; - return 0; + return 0; } /* * js_ioctl handles misc ioctl calls. */ -static int js_ioctl(struct inode *inode, - struct file *file, - unsigned int cmd, - unsigned long arg) +static int js_ioctl(struct inode *inode, struct file *file, unsigned int cmd, unsigned long arg) { unsigned int minor = MINOR(inode->i_rdev); int i, j; @@ -672,7 +667,7 @@ j = 0; for (i = 0; i < 4; i++) if ((1 << i) & jsd[minor].exist) { - if (copy_to_user((void *) arg + j * sizeof(struct js_corr), &js_axis[i].corr, + if (copy_to_user((void *) arg + j * sizeof(struct js_corr), &js_axis[i].corr, sizeof(struct js_corr))) return -EFAULT; j++; } @@ -680,7 +675,7 @@ default: return -EINVAL; } - + return 0; } @@ -701,14 +696,14 @@ return -ENODEV; if (!jsd[minor].exist) { js_probe(); - if (jsd[minor].exist) printk(KERN_INFO "js%d: %d-axis joystick at %#x\n", - minor, count_bits(jsd[minor].exist & JS_AXES), JS_PORT); + if (jsd[minor].exist) printk(KERN_INFO "js%d: %d-axis %d-button joystick at %#x\n", + minor, count_bits(jsd[minor].exist & JS_AXES), count_bits(jsd[minor].exist & JS_BUTTONS), JS_PORT); else return -ENODEV; } MOD_INC_USE_COUNT; - if (!jsd[0].list && !jsd[1].list) { + if (!jsd[0].list && !jsd[1].list) { js_timer.expires = jiffies + JS_TIMER_PERIOD; add_timer(&js_timer); } @@ -789,7 +784,7 @@ { js[0] = ((ints[0] > 0) ? ints[1] : 0 ); - js[1] = ((ints[0] > 1) ? ints[2] : 0 ); + js[1] = ((ints[0] > 1) ? ints[2] : 0 ); } #endif @@ -799,7 +794,7 @@ */ #ifdef MODULE -int init_module(void) +int init_module(void) #else __initfunc(int js_init(void)) #endif @@ -823,7 +818,7 @@ for (i = 0; i < JS_NUM; i++) { if (jsd[i].exist) printk(KERN_INFO "js%d: %d-axis %d-button joystick at %#x\n", - i, count_bits(jsd[i].exist & JS_AXES), count_bits(jsd[i].exist & JS_AXES), JS_PORT); + i, count_bits(jsd[i].exist & JS_AXES), count_bits(jsd[i].exist & JS_BUTTONS), JS_PORT); jsd[i].ahead = jsd[i].bhead = 0; jsd[i].tail = JS_BUFF_SIZE - 1; jsd[i].list = NULL; @@ -832,7 +827,7 @@ } for (i = 0; i < 4; i++) { - js_axis[i].corr.type = JS_CORR_NONE; + js_axis[i].corr.type = JS_CORR_NONE; js_axis[i].corr.prec = JS_DEF_PREC; } @@ -841,7 +836,7 @@ enable_bh(JS_BH); init_timer(&js_timer); js_timer.function = js_do_timer; - + return 0; } diff -u --recursive --new-file v2.1.101/linux/drivers/char/mem.c linux/drivers/char/mem.c --- v2.1.101/linux/drivers/char/mem.c Thu Apr 23 20:21:32 1998 +++ linux/drivers/char/mem.c Mon May 11 14:38:28 1998 @@ -32,9 +32,6 @@ #ifdef CONFIG_ISDN int isdn_init(void); #endif -#ifdef CONFIG_PCWATCHDOG -int pcwatchdog_init(void); -#endif #ifdef CONFIG_VIDEO_DEV extern int videodev_init(void); #endif diff -u --recursive --new-file v2.1.101/linux/drivers/char/misc.c linux/drivers/char/misc.c --- v2.1.101/linux/drivers/char/misc.c Tue Mar 17 22:18:14 1998 +++ linux/drivers/char/misc.c Mon May 11 14:38:28 1998 @@ -81,9 +81,7 @@ extern int nvram_init(void); extern int radio_init(void); extern void hfmodem_init(void); -#ifdef CONFIG_PC110_PAD extern int pc110pad_init(void); -#endif #ifdef CONFIG_PROC_FS static int misc_read_proc(char *buf, char **start, off_t offset, diff -u --recursive --new-file v2.1.101/linux/drivers/fc4/Config.in linux/drivers/fc4/Config.in --- v2.1.101/linux/drivers/fc4/Config.in Mon Jan 12 15:19:36 1998 +++ linux/drivers/fc4/Config.in Fri May 8 23:07:43 1998 @@ -9,9 +9,10 @@ comment 'FC4 drivers' tristate 'Sun SOC/Sbus' CONFIG_FC4_SOC m comment 'FC4 targets' - dep_tristate 'SparcSTORAGE Array 100 and 200 series' CONFIG_SCSI_PLUTO "$CONFIG_SCSI" + dep_tristate 'SparcSTORAGE Array 100 and 200 series' CONFIG_SCSI_PLUTO $CONFIG_SCSI else define_bool CONFIG_FC4_SOC n define_bool CONFIG_SCSI_PLUTO n fi endmenu + diff -u --recursive --new-file v2.1.101/linux/drivers/fc4/soc.c linux/drivers/fc4/soc.c --- v2.1.101/linux/drivers/fc4/soc.c Thu Apr 23 20:21:33 1998 +++ linux/drivers/fc4/soc.c Fri May 8 23:07:43 1998 @@ -304,14 +304,17 @@ static void soc_intr(int irq, void *dev_id, struct pt_regs *regs) { u32 cmd; + unsigned long flags; register struct soc *s = (struct soc *)dev_id; + spin_lock_irqsave(&io_request_lock, flags); cmd = s->regs->cmd; for (; (cmd = SOC_INTR (s, cmd)); cmd = s->regs->cmd) { if (cmd & SOC_CMD_RSP_Q1) soc_unsolicited (s); if (cmd & SOC_CMD_RSP_Q0) soc_solicited (s); if (cmd & SOC_CMD_REQ_QALL) soc_request (s, cmd); } + spin_unlock_irqrestore(&io_request_lock, flags); } #define TOKEN(proto, port, token) (((proto)<<12)|(token)|(port)) diff -u --recursive --new-file v2.1.101/linux/drivers/isdn/isdn_net.c linux/drivers/isdn/isdn_net.c --- v2.1.101/linux/drivers/isdn/isdn_net.c Wed Apr 1 20:11:51 1998 +++ linux/drivers/isdn/isdn_net.c Fri May 8 23:07:44 1998 @@ -1764,6 +1764,8 @@ ndev->type = ARPHRD_ETHER; ndev->addr_len = ETH_ALEN; + ndev->tx_queue_len = 10; /* for clients without MPPP 5 is better. */ + for (i = 0; i < ETH_ALEN; i++) ndev->broadcast[i] = 0xff; diff -u --recursive --new-file v2.1.101/linux/drivers/net/8390.c linux/drivers/net/8390.c --- v2.1.101/linux/drivers/net/8390.c Fri May 8 23:14:48 1998 +++ linux/drivers/net/8390.c Fri May 8 23:03:57 1998 @@ -45,7 +45,6 @@ static const char *version = "8390.c:v1.10cvs 9/23/94 Donald Becker (becker@cesdis.gsfc.nasa.gov)\n"; -#include #include #include #include diff -u --recursive --new-file v2.1.101/linux/drivers/net/8390.h linux/drivers/net/8390.h --- v2.1.101/linux/drivers/net/8390.h Fri May 8 23:14:48 1998 +++ linux/drivers/net/8390.h Fri May 8 23:03:57 1998 @@ -7,6 +7,7 @@ #ifndef _8390_h #define _8390_h +#include #include #include #include diff -u --recursive --new-file v2.1.101/linux/drivers/net/Config.in linux/drivers/net/Config.in --- v2.1.101/linux/drivers/net/Config.in Fri May 8 23:14:48 1998 +++ linux/drivers/net/Config.in Thu May 14 10:35:55 1998 @@ -106,6 +106,7 @@ tristate 'Digi Intl. RightSwitch SE-X support' CONFIG_DGRS tristate 'EtherExpressPro/100 support' CONFIG_EEXPRESS_PRO100 if [ "$CONFIG_EXPERIMENTAL" = "y" ]; then + tristate 'Mylex EISA LNE390A/B support (EXPERIMENTAL)' CONFIG_LNE390 tristate 'Racal-Interlan EISA ES3210 support (EXPERIMENTAL)' CONFIG_ES3210 tristate 'SMC EtherPower II (EXPERIMENTAL)' CONFIG_EPIC100 tristate 'TI ThunderLAN support (EXPERIMENTAL)' CONFIG_TLAN diff -u --recursive --new-file v2.1.101/linux/drivers/net/Makefile linux/drivers/net/Makefile --- v2.1.101/linux/drivers/net/Makefile Fri May 8 23:14:48 1998 +++ linux/drivers/net/Makefile Thu May 14 10:35:55 1998 @@ -204,6 +204,15 @@ endif endif +ifeq ($(CONFIG_LNE390),y) +L_OBJS += lne390.o +CONFIG_8390_BUILTIN = y +else + ifeq ($(CONFIG_LNE390),m) + CONFIG_8390_MODULE = y + M_OBJS += lne390.o + endif +endif ifeq ($(CONFIG_PLIP),y) L_OBJS += plip.o diff -u --recursive --new-file v2.1.101/linux/drivers/net/Space.c linux/drivers/net/Space.c --- v2.1.101/linux/drivers/net/Space.c Fri May 8 23:14:48 1998 +++ linux/drivers/net/Space.c Thu May 14 10:35:55 1998 @@ -71,6 +71,7 @@ extern int elplus_probe(struct device *); extern int ac3200_probe(struct device *); extern int es_probe(struct device *); +extern int lne390_probe(struct device *); extern int e2100_probe(struct device *); extern int ni5010_probe(struct device *); extern int ni52_probe(struct device *); @@ -171,6 +172,9 @@ #endif #ifdef CONFIG_ES3210 && es_probe(dev) +#endif +#ifdef CONFIG_LNE390 + && lne390_probe(dev) #endif #ifdef CONFIG_E2100 /* Cabletron E21xx series. */ && e2100_probe(dev) diff -u --recursive --new-file v2.1.101/linux/drivers/net/lne390.c linux/drivers/net/lne390.c --- v2.1.101/linux/drivers/net/lne390.c Wed Dec 31 16:00:00 1969 +++ linux/drivers/net/lne390.c Thu May 14 10:35:55 1998 @@ -0,0 +1,425 @@ +/* + lne390.c + + Linux driver for Mylex LNE390 EISA Network Adapter + + Copyright (C) 1996-1998, Paul Gortmaker. + + This software may be used and distributed according to the terms + of the GNU Public License, incorporated herein by reference. + + Information and Code Sources: + + 1) Based upon framework of es3210 driver. + 2) The existing myriad of other Linux 8390 drivers by Donald Becker. + 3) Russ Nelson's asm packet driver provided additional info. + 4) Info for getting IRQ and sh-mem gleaned from the EISA cfg files. + + The LNE390 is an EISA shared memory NS8390 implementation. Note + that all memory copies to/from the board must be 32bit transfers. + There are two versions of the card: the lne390a and the lne390b. + Going by the EISA cfg files, the "a" has jumpers to select between + BNC/AUI, but the "b" also has RJ-45 and selection is via the SCU. + The shared memory address selection is also slightly different. + Note that shared memory address > 1MB are supported with this driver. + + You can try if you want more info, as I've + never even seen one of these cards. :) + +*/ + +static const char *version = + "lne390.c: Driver revision v0.99, 12/05/98\n"; + +#include +#include +#include +#include +#include +#include +#include + +#include +#include + +#include +#include +#include "8390.h" + +int lne390_probe(struct device *dev); +int lne390_probe1(struct device *dev, int ioaddr); + +static int lne390_open(struct device *dev); +static int lne390_close(struct device *dev); + +static void lne390_reset_8390(struct device *dev); + +static void lne390_get_8390_hdr(struct device *dev, struct e8390_pkt_hdr *hdr, int ring_page); +static void lne390_block_input(struct device *dev, int count, struct sk_buff *skb, int ring_offset); +static void lne390_block_output(struct device *dev, int count, const unsigned char *buf, const start_page); + +#define LNE390_START_PG 0x00 /* First page of TX buffer */ +#define LNE390_STOP_PG 0x80 /* Last page +1 of RX ring */ + +#define LNE390_ID_PORT 0xc80 /* Same for all EISA cards */ +#define LNE390_IO_EXTENT 0x20 +#define LNE390_SA_PROM 0x16 /* Start of e'net addr. */ +#define LNE390_RESET_PORT 0xc84 /* From the pkt driver source */ +#define LNE390_NIC_OFFSET 0x00 /* Hello, the 8390 is *here* */ + +#define LNE390_ADDR0 0x00 /* 3 byte vendor prefix */ +#define LNE390_ADDR1 0x80 +#define LNE390_ADDR2 0xe5 + +#define LNE390_ID0 0x10009835 /* 0x3598 = 01101 01100 11000 = mlx */ +#define LNE390_ID1 0x11009835 /* above is the 390A, this is 390B */ + +#define LNE390_CFG1 0xc84 /* NB: 0xc84 is also "reset" port. */ +#define LNE390_CFG2 0xc90 + +/* + * You can OR any of the following bits together and assign it + * to LNE390_DEBUG to get verbose driver info during operation. + * Currently only the probe one is implemented. + */ + +#define LNE390_D_PROBE 0x01 +#define LNE390_D_RX_PKT 0x02 +#define LNE390_D_TX_PKT 0x04 +#define LNE390_D_IRQ 0x08 + +#define LNE390_DEBUG 0 + +static unsigned char irq_map[] __initdata = {15, 12, 11, 10, 9, 7, 5, 3}; +static unsigned int shmem_mapA[] __initdata = {0xff, 0xfe, 0xfd, 0xfff, 0xffe, 0xffc, 0x0d, 0x0}; +static unsigned int shmem_mapB[] __initdata = {0xff, 0xfe, 0x0e, 0xfff, 0xffe, 0xffc, 0x0d, 0x0}; + +/* + * Probe for the card. The best way is to read the EISA ID if it + * is known. Then we can check the prefix of the station address + * PROM for a match against the value assigned to Mylex. + */ + +__initfunc(int lne390_probe(struct device *dev)) +{ + unsigned short ioaddr = dev->base_addr; + + if (ioaddr > 0x1ff) /* Check a single specified location. */ + return lne390_probe1(dev, ioaddr); + else if (ioaddr > 0) /* Don't probe at all. */ + return ENXIO; + + if (!EISA_bus) { +#if LNE390_DEBUG & LNE390_D_PROBE + printk("lne390-debug: Not an EISA bus. Not probing high ports.\n"); +#endif + return ENXIO; + } + + /* EISA spec allows for up to 16 slots, but 8 is typical. */ + for (ioaddr = 0x1000; ioaddr < 0x9000; ioaddr += 0x1000) { + if (check_region(ioaddr , LNE390_IO_EXTENT)) + continue; + if (lne390_probe1(dev, ioaddr) == 0) + return 0; + } + + return ENODEV; +} + +__initfunc(int lne390_probe1(struct device *dev, int ioaddr)) +{ + int i, revision; + unsigned long eisa_id; + + if (inb_p(ioaddr + LNE390_ID_PORT) == 0xff) return -ENODEV; + +#if LNE390_DEBUG & LNE390_D_PROBE + printk("lne390-debug: probe at %#x, ID %#8x\n", ioaddr, inl(ioaddr + LNE390_ID_PORT)); + printk("lne390-debug: config regs: %#x %#x\n", + inb(ioaddr + LNE390_CFG1), inb(ioaddr + LNE390_CFG2)); +#endif + + +/* Check the EISA ID of the card. */ + eisa_id = inl(ioaddr + LNE390_ID_PORT); + if ((eisa_id != LNE390_ID0) && (eisa_id != LNE390_ID1)) { + return ENODEV; + } + + revision = (eisa_id >> 24) & 0x01; /* 0 = rev A, 1 rev B */ + +#if 0 +/* Check the Mylex vendor ID as well. Not really required. */ + if (inb(ioaddr + LNE390_SA_PROM + 0) != LNE390_ADDR0 + || inb(ioaddr + LNE390_SA_PROM + 1) != LNE390_ADDR1 + || inb(ioaddr + LNE390_SA_PROM + 2) != LNE390_ADDR2 ) { + printk("lne390.c: card not found"); + for(i = 0; i < ETHER_ADDR_LEN; i++) + printk(" %02x", inb(ioaddr + LNE390_SA_PROM + i)); + printk(" (invalid prefix).\n"); + return ENODEV; + } +#endif + + /* We should have a "dev" from Space.c or the static module table. */ + if (dev == NULL) { + printk("lne390.c: Passed a NULL device.\n"); + dev = init_etherdev(0, 0); + } + + printk("lne390.c: LNE390%X in EISA slot %d, address", 0xa+revision, ioaddr/0x1000); + for(i = 0; i < ETHER_ADDR_LEN; i++) + printk(" %02x", (dev->dev_addr[i] = inb(ioaddr + LNE390_SA_PROM + i))); + printk(".\nlne390.c: "); + + /* Snarf the interrupt now. CFG file has them all listed as `edge' with share=NO */ + if (dev->irq == 0) { + unsigned char irq_reg = inb(ioaddr + LNE390_CFG2) >> 3; + dev->irq = irq_map[irq_reg & 0x07]; + printk("using"); + } else { + /* This is useless unless we reprogram the card here too */ + if (dev->irq == 2) dev->irq = 9; /* Doh! */ + printk("assigning"); + } + printk(" IRQ %d,", dev->irq); + + if (request_irq(dev->irq, ei_interrupt, 0, "lne390", NULL)) { + printk (" unable to get IRQ %d.\n", dev->irq); + return EAGAIN; + } + + if (dev->mem_start == 0) { + unsigned char mem_reg = inb(ioaddr + LNE390_CFG2) & 0x07; + + if (revision) /* LNE390B */ + dev->mem_start = shmem_mapB[mem_reg] * 0x10000; + else /* LNE390A */ + dev->mem_start = shmem_mapA[mem_reg] * 0x10000; + printk(" using "); + } else { + /* Should check for value in shmem_map and reprogram the card to use it */ + dev->mem_start &= 0xfff0000; + printk(" assigning "); + } + + printk("%dkB memory at physical address %#lx\n", + LNE390_STOP_PG/4, dev->mem_start); + + /* + BEWARE!! Some dain-bramaged EISA SCUs will allow you to put + the card mem within the region covered by `normal' RAM !!! + */ + if (dev->mem_start > 1024*1024) { /* phys addr > 1MB */ + if (dev->mem_start < (unsigned long)high_memory) { + printk(KERN_CRIT "lne390.c: Card RAM overlaps with normal memory!!!\n"); + printk(KERN_CRIT "lne390.c: Use EISA SCU to set card memory below 1MB,\n"); + printk(KERN_CRIT "lne390.c: or to an address above %p.\n", high_memory); + printk(KERN_CRIT "lne390.c: Driver NOT installed.\n"); + free_irq(dev->irq, dev); + return EINVAL; + } + dev->mem_start = (unsigned long)ioremap(dev->mem_start, LNE390_STOP_PG*0x100); + if (dev->mem_start == 0) { + printk(KERN_ERR "lne390.c: Unable to remap card memory above 1MB !!\n"); + printk(KERN_ERR "lne390.c: Try using EISA SCU to set memory below 1MB.\n"); + printk(KERN_ERR "lne390.c: Driver NOT installed.\n"); + free_irq(dev->irq, dev); + return EAGAIN; + } + printk("lne390.c: remapped %dkB card memory to virtual address %#lx\n", + LNE390_STOP_PG/4, dev->mem_start); + } + + dev->mem_end = dev->rmem_end = dev->mem_start + + (LNE390_STOP_PG - LNE390_START_PG)*256; + dev->rmem_start = dev->mem_start + TX_PAGES*256; + + /* Allocate dev->priv and fill in 8390 specific dev fields. */ + if (ethdev_init(dev)) { + printk ("lne390.c: unable to allocate memory for dev->priv!\n"); + free_irq(dev->irq, dev); + return -ENOMEM; + } + + /* The 8390 offset is zero for the LNE390 */ + dev->base_addr = ioaddr; + request_region(dev->base_addr, LNE390_IO_EXTENT, "lne390"); + + ei_status.name = "LNE390"; + ei_status.tx_start_page = LNE390_START_PG; + ei_status.rx_start_page = LNE390_START_PG + TX_PAGES; + ei_status.stop_page = LNE390_STOP_PG; + ei_status.word16 = 1; + + if (ei_debug > 0) + printk(version); + + ei_status.reset_8390 = &lne390_reset_8390; + ei_status.block_input = &lne390_block_input; + ei_status.block_output = &lne390_block_output; + ei_status.get_8390_hdr = &lne390_get_8390_hdr; + + dev->open = &lne390_open; + dev->stop = &lne390_close; + NS8390_init(dev, 0); + return 0; +} + +/* + * Reset as per the packet driver method. Judging by the EISA cfg + * file, this just toggles the "Board Enable" bits (bit 2 and 0). + */ + +static void lne390_reset_8390(struct device *dev) +{ + unsigned short ioaddr = dev->base_addr; + + outb(0x04, ioaddr + LNE390_RESET_PORT); + if (ei_debug > 1) printk("%s: resetting the LNE390...", dev->name); + + udelay(2*1000); + + ei_status.txing = 0; + outb(0x01, ioaddr + LNE390_RESET_PORT); + if (ei_debug > 1) printk("reset done\n"); + + return; +} + +/* + * Note: In the following three functions is the implicit assumption + * that the associated memcpy will only use "rep; movsl" as long as + * we keep the counts as some multiple of doublewords. This is a + * requirement of the hardware, and also prevents us from using + * eth_io_copy_and_sum() since we can't guarantee it will limit + * itself to doubleword access. + */ + +/* + * Grab the 8390 specific header. Similar to the block_input routine, but + * we don't need to be concerned with ring wrap as the header will be at + * the start of a page, so we optimize accordingly. (A single doubleword.) + */ + +static void +lne390_get_8390_hdr(struct device *dev, struct e8390_pkt_hdr *hdr, int ring_page) +{ + unsigned long hdr_start = dev->mem_start + ((ring_page - LNE390_START_PG)<<8); + memcpy_fromio(hdr, hdr_start, sizeof(struct e8390_pkt_hdr)); + hdr->count = (hdr->count + 3) & ~3; /* Round up allocation. */ +} + +/* + * Block input and output are easy on shared memory ethercards, the only + * complication is when the ring buffer wraps. The count will already + * be rounded up to a doubleword value via lne390_get_8390_hdr() above. + */ + +static void lne390_block_input(struct device *dev, int count, struct sk_buff *skb, + int ring_offset) +{ + unsigned long xfer_start = dev->mem_start + ring_offset - (LNE390_START_PG<<8); + + if (xfer_start + count > dev->rmem_end) { + /* Packet wraps over end of ring buffer. */ + int semi_count = dev->rmem_end - xfer_start; + memcpy_fromio(skb->data, xfer_start, semi_count); + count -= semi_count; + memcpy_fromio(skb->data + semi_count, dev->rmem_start, count); + } else { + /* Packet is in one chunk. */ + memcpy_fromio(skb->data, xfer_start, count); + } +} + +static void lne390_block_output(struct device *dev, int count, + const unsigned char *buf, int start_page) +{ + unsigned long shmem = dev->mem_start + ((start_page - LNE390_START_PG)<<8); + + count = (count + 3) & ~3; /* Round up to doubleword */ + memcpy_toio(shmem, buf, count); +} + +static int lne390_open(struct device *dev) +{ + ei_open(dev); + MOD_INC_USE_COUNT; + return 0; +} + +static int lne390_close(struct device *dev) +{ + + if (ei_debug > 1) + printk("%s: Shutting down ethercard.\n", dev->name); + + ei_close(dev); + MOD_DEC_USE_COUNT; + return 0; +} + +#ifdef MODULE +#define MAX_LNE_CARDS 4 /* Max number of LNE390 cards per module */ +#define NAMELEN 8 /* # of chars for storing dev->name */ +static char namelist[NAMELEN * MAX_LNE_CARDS] = { 0, }; +static struct device dev_lne[MAX_LNE_CARDS] = { + { + NULL, /* assign a chunk of namelist[] below */ + 0, 0, 0, 0, + 0, 0, + 0, 0, 0, NULL, NULL + }, +}; + +static int io[MAX_LNE_CARDS] = { 0, }; +static int irq[MAX_LNE_CARDS] = { 0, }; +static int mem[MAX_LNE_CARDS] = { 0, }; + +MODULE_PARM(io, "1-" __MODULE_STRING(MAX_LNE_CARDS) "i"); +MODULE_PARM(irq, "1-" __MODULE_STRING(MAX_LNE_CARDS) "i"); +MODULE_PARM(mem, "1-" __MODULE_STRING(MAX_LNE_CARDS) "i"); + +int init_module(void) +{ + int this_dev, found = 0; + + for (this_dev = 0; this_dev < MAX_LNE_CARDS; this_dev++) { + struct device *dev = &dev_lne[this_dev]; + dev->name = namelist+(NAMELEN*this_dev); + dev->irq = irq[this_dev]; + dev->base_addr = io[this_dev]; + dev->mem_start = mem[this_dev]; + dev->init = lne390_probe; + /* Default is to only install one card. */ + if (io[this_dev] == 0 && this_dev != 0) break; + if (register_netdev(dev) != 0) { + printk(KERN_WARNING "lne390.c: No LNE390 card found (i/o = 0x%x).\n", io[this_dev]); + if (found != 0) return 0; /* Got at least one. */ + return -ENXIO; + } + found++; + } + + return 0; +} + +void cleanup_module(void) +{ + int this_dev; + + for (this_dev = 0; this_dev < MAX_LNE_CARDS; this_dev++) { + struct device *dev = &dev_lne[this_dev]; + if (dev->priv != NULL) { + kfree(dev->priv); + dev->priv = NULL; + free_irq(dev->irq, dev); + release_region(dev->base_addr, LNE390_IO_EXTENT); + unregister_netdev(dev); + } + } +} +#endif /* MODULE */ + diff -u --recursive --new-file v2.1.101/linux/drivers/sbus/audio/cs4231.c linux/drivers/sbus/audio/cs4231.c --- v2.1.101/linux/drivers/sbus/audio/cs4231.c Fri May 8 23:14:48 1998 +++ linux/drivers/sbus/audio/cs4231.c Fri May 8 23:03:57 1998 @@ -14,7 +14,6 @@ * The APC DMA controller support unfortunately is not documented. Thanks, Sun */ -#include #include #include #include diff -u --recursive --new-file v2.1.101/linux/drivers/scsi/53c7,8xx.c linux/drivers/scsi/53c7,8xx.c --- v2.1.101/linux/drivers/scsi/53c7,8xx.c Sat May 2 14:19:53 1998 +++ linux/drivers/scsi/53c7,8xx.c Mon May 11 10:50:35 1998 @@ -1891,7 +1891,7 @@ printk ("scsi%d : test 1", host->host_no); NCR53c7x0_write32 (DSP_REG, start); printk (" started\n"); - sti(); + restore_flags(flags); /* * This is currently a .5 second timeout, since (in theory) no slow @@ -1983,7 +1983,7 @@ hostdata->state = STATE_RUNNING; NCR53c7x0_write32 (DSA_REG, virt_to_bus(dsa)); NCR53c7x0_write32 (DSP_REG, start); - sti(); + restore_flags(flags); timeout = jiffies + 5 * HZ; /* arbitrary */ while ((hostdata->test_completed == -1) && jiffies < timeout) @@ -5737,7 +5737,7 @@ disable(host); else if (hostdata->resets != -1) --hostdata->resets; - sti(); + restore_flags(flags); for (; nuke_list; nuke_list = tmp) { tmp = (Scsi_Cmnd *) nuke_list->SCp.buffer; nuke_list->result = DID_RESET << 16; @@ -6193,7 +6193,7 @@ printk ("scsi%d : loop detected in running list!\n", host->host_no); break; } else { - printk ("The sti() implicit in a printk() prevents hangs\n"); + printk ("Duh? Bad things happening in the NCR driver\n"); break; } diff -u --recursive --new-file v2.1.101/linux/drivers/scsi/53c7xx.c linux/drivers/scsi/53c7xx.c --- v2.1.101/linux/drivers/scsi/53c7xx.c Tue Apr 14 14:29:21 1998 +++ linux/drivers/scsi/53c7xx.c Mon May 11 10:50:35 1998 @@ -1620,7 +1620,7 @@ NCR53c7x0_write8 (DCNTL_REG, hostdata->saved_dcntl | DCNTL_SSM | DCNTL_STD); printk (" started\n"); - sti(); + restore_flags(flags); /* * This is currently a .5 second timeout, since (in theory) no slow @@ -1715,7 +1715,7 @@ if (hostdata->options & OPTION_DEBUG_TRACE) NCR53c7x0_write8 (DCNTL_REG, hostdata->saved_dcntl | DCNTL_SSM | DCNTL_STD); - sti(); + restore_flags(flags); timeout = jiffies + 5 * HZ; /* arbitrary */ while ((hostdata->test_completed == -1) && jiffies < timeout) @@ -5372,7 +5372,7 @@ disable(host); else if (hostdata->resets != -1) --hostdata->resets; - sti(); + restore_flags(flags); for (; nuke_list; nuke_list = tmp) { tmp = (Scsi_Cmnd *) nuke_list->SCp.buffer; nuke_list->result = DID_RESET << 16; @@ -5828,7 +5828,7 @@ printk ("scsi%d : loop detected in running list!\n", host->host_no); break; } else { - printk ("The sti() implicit in a printk() prevents hangs\n"); + printk ("Duh? Bad things happening in the NCR driver\n"); break; } diff -u --recursive --new-file v2.1.101/linux/drivers/scsi/AM53C974.c linux/drivers/scsi/AM53C974.c --- v2.1.101/linux/drivers/scsi/AM53C974.c Tue Apr 14 14:29:21 1998 +++ linux/drivers/scsi/AM53C974.c Mon May 11 13:00:36 1998 @@ -19,17 +19,17 @@ #include "sd.h" /* AM53/79C974 (PCscsi) driver release 0.5 - * + * The architecture and much of the code of this device * driver was originally developed by Drew Eckhardt for * the NCR5380. The following copyrights apply: * For the architecture and all pieces of code which can also be found * in the NCR5380 device driver: * Copyright 1993, Drew Eckhardt - * Visionary Computing - * (Unix and Linux consulting and custom programming) - * drew@colorado.edu - * +1 (303) 666-5836 + * Visionary Computing + * (Unix and Linux consulting and custom programming) + * drew@colorado.edu + * +1 (303) 666-5836 * * The AM53C974_nobios_detect code was originally developed by * Robin Cutshaw (robin@xfree86.org) and is used here in a @@ -48,69 +48,69 @@ */ #ifdef AM53C974_DEBUG - #define DEB(x) x - #ifdef AM53C974_DEBUG_KEYWAIT - #define KEYWAIT() AM53C974_keywait() - #else - #define KEYWAIT() - #endif - #ifdef AM53C974_DEBUG_INIT - #define DEB_INIT(x) x - #else - #define DEB_INIT(x) - #endif - #ifdef AM53C974_DEBUG_MSG - #define DEB_MSG(x) x - #else - #define DEB_MSG(x) - #endif - #ifdef AM53C974_DEB_RESEL - #define DEB_RESEL(x) x - #else - #define DEB_RESEL(x) - #endif - #ifdef AM53C974_DEBUG_QUEUE - #define DEB_QUEUE(x) x - #define LIST(x,y) {printk("LINE:%d Adding %p to %p\n", __LINE__, (void*)(x), (void*)(y)); if ((x)==(y)) udelay(5); } - #define REMOVE(w,x,y,z) {printk("LINE:%d Removing: %p->%p %p->%p \n", __LINE__, (void*)(w), (void*)(x), (void*)(y), (void*)(z)); if ((x)==(y)) udelay(5); } - #else - #define DEB_QUEUE(x) - #define LIST(x,y) - #define REMOVE(w,x,y,z) - #endif - #ifdef AM53C974_DEBUG_INFO - #define DEB_INFO(x) x - #else - #define DEB_INFO(x) - #endif - #ifdef AM53C974_DEBUG_LINKED - #define DEB_LINKED(x) x - #else - #define DEB_LINKED(x) - #endif - #ifdef AM53C974_DEBUG_INTR - #define DEB_INTR(x) x - #else - #define DEB_INTR(x) - #endif +#define DEB(x) x +#ifdef AM53C974_DEBUG_KEYWAIT +#define KEYWAIT() AM53C974_keywait() +#else +#define KEYWAIT() +#endif +#ifdef AM53C974_DEBUG_INIT +#define DEB_INIT(x) x +#else +#define DEB_INIT(x) +#endif +#ifdef AM53C974_DEBUG_MSG +#define DEB_MSG(x) x #else - #define DEB_INIT(x) - #define DEB(x) - #define DEB_QUEUE(x) - #define LIST(x,y) - #define REMOVE(w,x,y,z) - #define DEB_INFO(x) - #define DEB_LINKED(x) - #define DEB_INTR(x) - #define DEB_MSG(x) - #define DEB_RESEL(x) - #define KEYWAIT() -#endif - #ifdef AM53C974_DEBUG_ABORT - #define DEB_ABORT(x) x - #else - #define DEB_ABORT(x) - #endif +#define DEB_MSG(x) +#endif +#ifdef AM53C974_DEB_RESEL +#define DEB_RESEL(x) x +#else +#define DEB_RESEL(x) +#endif +#ifdef AM53C974_DEBUG_QUEUE +#define DEB_QUEUE(x) x +#define LIST(x,y) {printk("LINE:%d Adding %p to %p\n", __LINE__, (void*)(x), (void*)(y)); if ((x)==(y)) udelay(5); } +#define REMOVE(w,x,y,z) {printk("LINE:%d Removing: %p->%p %p->%p \n", __LINE__, (void*)(w), (void*)(x), (void*)(y), (void*)(z)); if ((x)==(y)) udelay(5); } +#else +#define DEB_QUEUE(x) +#define LIST(x,y) +#define REMOVE(w,x,y,z) +#endif +#ifdef AM53C974_DEBUG_INFO +#define DEB_INFO(x) x +#else +#define DEB_INFO(x) +#endif +#ifdef AM53C974_DEBUG_LINKED +#define DEB_LINKED(x) x +#else +#define DEB_LINKED(x) +#endif +#ifdef AM53C974_DEBUG_INTR +#define DEB_INTR(x) x +#else +#define DEB_INTR(x) +#endif +#else +#define DEB_INIT(x) +#define DEB(x) +#define DEB_QUEUE(x) +#define LIST(x,y) +#define REMOVE(w,x,y,z) +#define DEB_INFO(x) +#define DEB_LINKED(x) +#define DEB_INTR(x) +#define DEB_MSG(x) +#define DEB_RESEL(x) +#define KEYWAIT() +#endif +#ifdef AM53C974_DEBUG_ABORT +#define DEB_ABORT(x) x +#else +#define DEB_ABORT(x) +#endif #ifdef VERBOSE_AM53C974_DEBUG #define VDEB(x) x @@ -137,9 +137,9 @@ * Sync. negotiation is disabled by default and will be enabled for those targets which * * are specified in the LILO override * ****************************************************************************************/ -#define DEFAULT_SYNC_NEGOTIATION_ENABLED 0 /* 0 or 1 */ -#define DEFAULT_RATE 5 /* MHz, min: 3; max: 10 */ -#define DEFAULT_SYNC_OFFSET 0 /* bytes, min: 0; max: 15; use 0 for async. mode */ +#define DEFAULT_SYNC_NEGOTIATION_ENABLED 0 /* 0 or 1 */ +#define DEFAULT_RATE 5 /* MHz, min: 3; max: 10 */ +#define DEFAULT_SYNC_OFFSET 0 /* bytes, min: 0; max: 15; use 0 for async. mode */ /*************************************************************************************** * If defined, don't allow targets to disconnect during commands. This will reduce * @@ -170,145 +170,145 @@ /* #define AM53C974_OPTION_DEBUG_PROBE_ONLY */ /* special options/constants */ -#define DEF_CLK 40 /* chip clock freq. in MHz */ -#define MIN_PERIOD 4 /* for negotiation: min. number of clocks per cycle */ -#define MAX_PERIOD 13 /* for negotiation: max. number of clocks per cycle */ -#define MAX_OFFSET 15 /* for negotiation: max. offset (0=async) */ - -#define DEF_SCSI_TIMEOUT 245 /* STIMREG value, 40 Mhz */ -#define DEF_STP 8 /* STPREG value assuming 5.0 MB/sec, FASTCLK, FASTSCSI */ -#define DEF_SOF_RAD 0 /* REQ/ACK deassertion delay */ -#define DEF_SOF_RAA 0 /* REQ/ACK assertion delay */ -#define DEF_ETM 0 /* CNTLREG1, ext. timing mode */ -#define DEF_PERE 1 /* CNTLREG1, parity error reporting */ -#define DEF_CLKF 0 /* CLKFREG, 0=40 Mhz */ -#define DEF_ENF 1 /* CNTLREG2, enable features */ -#define DEF_ADIDCHK 0 /* CNTLREG3, additional ID check */ -#define DEF_FASTSCSI 1 /* CNTLREG3, fast SCSI */ -#define DEF_FASTCLK 1 /* CNTLREG3, fast clocking, 5 MB/sec at 40MHz chip clk */ -#define DEF_GLITCH 1 /* CNTLREG4, glitch eater, 0=12ns, 1=35ns, 2=25ns, 3=off */ -#define DEF_PWD 0 /* CNTLREG4, reduced power feature */ -#define DEF_RAE 0 /* CNTLREG4, RAE active negation on REQ, ACK only */ -#define DEF_RADE 1 /* 1CNTLREG4, active negation on REQ, ACK and data */ +#define DEF_CLK 40 /* chip clock freq. in MHz */ +#define MIN_PERIOD 4 /* for negotiation: min. number of clocks per cycle */ +#define MAX_PERIOD 13 /* for negotiation: max. number of clocks per cycle */ +#define MAX_OFFSET 15 /* for negotiation: max. offset (0=async) */ + +#define DEF_SCSI_TIMEOUT 245 /* STIMREG value, 40 Mhz */ +#define DEF_STP 8 /* STPREG value assuming 5.0 MB/sec, FASTCLK, FASTSCSI */ +#define DEF_SOF_RAD 0 /* REQ/ACK deassertion delay */ +#define DEF_SOF_RAA 0 /* REQ/ACK assertion delay */ +#define DEF_ETM 0 /* CNTLREG1, ext. timing mode */ +#define DEF_PERE 1 /* CNTLREG1, parity error reporting */ +#define DEF_CLKF 0 /* CLKFREG, 0=40 Mhz */ +#define DEF_ENF 1 /* CNTLREG2, enable features */ +#define DEF_ADIDCHK 0 /* CNTLREG3, additional ID check */ +#define DEF_FASTSCSI 1 /* CNTLREG3, fast SCSI */ +#define DEF_FASTCLK 1 /* CNTLREG3, fast clocking, 5 MB/sec at 40MHz chip clk */ +#define DEF_GLITCH 1 /* CNTLREG4, glitch eater, 0=12ns, 1=35ns, 2=25ns, 3=off */ +#define DEF_PWD 0 /* CNTLREG4, reduced power feature */ +#define DEF_RAE 0 /* CNTLREG4, RAE active negation on REQ, ACK only */ +#define DEF_RADE 1 /* 1CNTLREG4, active negation on REQ, ACK and data */ /*** SCSI block ***/ -#define CTCLREG 0x00 /* r current transf. count, low byte */ -#define CTCMREG 0x04 /* r current transf. count, middle byte */ -#define CTCHREG 0x38 /* r current transf. count, high byte */ -#define STCLREG 0x00 /* w start transf. count, low byte */ -#define STCMREG 0x04 /* w start transf. count, middle byte */ -#define STCHREG 0x38 /* w start transf. count, high byte */ -#define FFREG 0x08 /* rw SCSI FIFO reg. */ -#define STIMREG 0x14 /* w SCSI timeout reg. */ - -#define SDIDREG 0x10 /* w SCSI destination ID reg. */ -#define SDIREG_MASK 0x07 /* mask */ - -#define STPREG 0x18 /* w synchronous transf. period reg. */ -#define STPREG_STP 0x1F /* synchr. transfer period */ - -#define CLKFREG 0x24 /* w clock factor reg. */ -#define CLKFREG_MASK 0x07 /* mask */ - -#define CMDREG 0x0C /* rw SCSI command reg. */ -#define CMDREG_DMA 0x80 /* set DMA mode (set together with opcodes below) */ -#define CMDREG_IT 0x10 /* information transfer */ -#define CMDREG_ICCS 0x11 /* initiator command complete steps */ -#define CMDREG_MA 0x12 /* message accepted */ -#define CMDREG_TPB 0x98 /* transfer pad bytes, DMA mode only */ -#define CMDREG_SATN 0x1A /* set ATN */ -#define CMDREG_RATN 0x1B /* reset ATN */ -#define CMDREG_SOAS 0x41 /* select without ATN steps */ -#define CMDREG_SAS 0x42 /* select with ATN steps (1 msg byte) */ -#define CMDREG_SASS 0x43 /* select with ATN and stop steps */ -#define CMDREG_ESR 0x44 /* enable selection/reselection */ -#define CMDREG_DSR 0x45 /* disable selection/reselection */ +#define CTCLREG 0x00 /* r current transf. count, low byte */ +#define CTCMREG 0x04 /* r current transf. count, middle byte */ +#define CTCHREG 0x38 /* r current transf. count, high byte */ +#define STCLREG 0x00 /* w start transf. count, low byte */ +#define STCMREG 0x04 /* w start transf. count, middle byte */ +#define STCHREG 0x38 /* w start transf. count, high byte */ +#define FFREG 0x08 /* rw SCSI FIFO reg. */ +#define STIMREG 0x14 /* w SCSI timeout reg. */ + +#define SDIDREG 0x10 /* w SCSI destination ID reg. */ +#define SDIREG_MASK 0x07 /* mask */ + +#define STPREG 0x18 /* w synchronous transf. period reg. */ +#define STPREG_STP 0x1F /* synchr. transfer period */ + +#define CLKFREG 0x24 /* w clock factor reg. */ +#define CLKFREG_MASK 0x07 /* mask */ + +#define CMDREG 0x0C /* rw SCSI command reg. */ +#define CMDREG_DMA 0x80 /* set DMA mode (set together with opcodes below) */ +#define CMDREG_IT 0x10 /* information transfer */ +#define CMDREG_ICCS 0x11 /* initiator command complete steps */ +#define CMDREG_MA 0x12 /* message accepted */ +#define CMDREG_TPB 0x98 /* transfer pad bytes, DMA mode only */ +#define CMDREG_SATN 0x1A /* set ATN */ +#define CMDREG_RATN 0x1B /* reset ATN */ +#define CMDREG_SOAS 0x41 /* select without ATN steps */ +#define CMDREG_SAS 0x42 /* select with ATN steps (1 msg byte) */ +#define CMDREG_SASS 0x43 /* select with ATN and stop steps */ +#define CMDREG_ESR 0x44 /* enable selection/reselection */ +#define CMDREG_DSR 0x45 /* disable selection/reselection */ #define CMDREG_SA3S 0x46 /* select with ATN 3 steps (3 msg bytes) */ -#define CMDREG_NOP 0x00 /* no operation */ -#define CMDREG_CFIFO 0x01 /* clear FIFO */ -#define CMDREG_RDEV 0x02 /* reset device */ -#define CMDREG_RBUS 0x03 /* reset SCSI bus */ +#define CMDREG_NOP 0x00 /* no operation */ +#define CMDREG_CFIFO 0x01 /* clear FIFO */ +#define CMDREG_RDEV 0x02 /* reset device */ +#define CMDREG_RBUS 0x03 /* reset SCSI bus */ -#define STATREG 0x10 /* r SCSI status reg. */ -#define STATREG_INT 0x80 /* SCSI interrupt condition detected */ +#define STATREG 0x10 /* r SCSI status reg. */ +#define STATREG_INT 0x80 /* SCSI interrupt condition detected */ #define STATREG_IOE 0x40 /* SCSI illegal operation error detected */ -#define STATREG_PE 0x20 /* SCSI parity error detected */ -#define STATREG_CTZ 0x10 /* CTC reg decremented to zero */ -#define STATREG_MSG 0x04 /* SCSI MSG phase (latched?) */ -#define STATREG_CD 0x02 /* SCSI C/D phase (latched?) */ -#define STATREG_IO 0x01 /* SCSI I/O phase (latched?) */ -#define STATREG_PHASE 0x07 /* SCSI phase mask */ - -#define INSTREG 0x14 /* r interrupt status reg. */ -#define INSTREG_SRST 0x80 /* SCSI reset detected */ -#define INSTREG_ICMD 0x40 /* SCSI invalid command detected */ -#define INSTREG_DIS 0x20 /* target disconnected or sel/resel timeout*/ +#define STATREG_PE 0x20 /* SCSI parity error detected */ +#define STATREG_CTZ 0x10 /* CTC reg decremented to zero */ +#define STATREG_MSG 0x04 /* SCSI MSG phase (latched?) */ +#define STATREG_CD 0x02 /* SCSI C/D phase (latched?) */ +#define STATREG_IO 0x01 /* SCSI I/O phase (latched?) */ +#define STATREG_PHASE 0x07 /* SCSI phase mask */ + +#define INSTREG 0x14 /* r interrupt status reg. */ +#define INSTREG_SRST 0x80 /* SCSI reset detected */ +#define INSTREG_ICMD 0x40 /* SCSI invalid command detected */ +#define INSTREG_DIS 0x20 /* target disconnected or sel/resel timeout */ #define INSTREG_SR 0x10 /* device on bus has service request */ -#define INSTREG_SO 0x08 /* successful operation */ -#define INSTREG_RESEL 0x04 /* device reselected as initiator */ +#define INSTREG_SO 0x08 /* successful operation */ +#define INSTREG_RESEL 0x04 /* device reselected as initiator */ -#define ISREG 0x18 /* r internal state reg. */ -#define ISREG_SOF 0x08 /* synchronous offset flag (act. low) */ -#define ISREG_IS 0x07 /* status of intermediate op. */ -#define ISREG_OK_NO_STOP 0x04 /* selection successful */ -#define ISREG_OK_STOP 0x01 /* selection successful */ - -#define CFIREG 0x1C /* r current FIFO/internal state reg. */ -#define CFIREG_IS 0xE0 /* status of intermediate op. */ -#define CFIREG_CF 0x1F /* number of bytes in SCSI FIFO */ - -#define SOFREG 0x1C /* w synchr. offset reg. */ -#define SOFREG_RAD 0xC0 /* REQ/ACK deassertion delay (sync.) */ -#define SOFREG_RAA 0x30 /* REQ/ACK assertion delay (sync.) */ -#define SOFREG_SO 0x0F /* synch. offset (sync.) */ - -#define CNTLREG1 0x20 /* rw control register one */ -#define CNTLREG1_ETM 0x80 /* set extended timing mode */ -#define CNTLREG1_DISR 0x40 /* disable interrupt on SCSI reset */ -#define CNTLREG1_PERE 0x10 /* enable parity error reporting */ -#define CNTLREG1_SID 0x07 /* host adapter SCSI ID */ - -#define CNTLREG2 0x2C /* rw control register two */ -#define CNTLREG2_ENF 0x40 /* enable features */ - -#define CNTLREG3 0x30 /* rw control register three */ -#define CNTLREG3_ADIDCHK 0x80 /* additional ID check */ -#define CNTLREG3_FASTSCSI 0x10 /* fast SCSI */ -#define CNTLREG3_FASTCLK 0x08 /* fast SCSI clocking */ - -#define CNTLREG4 0x34 /* rw control register four */ -#define CNTLREG4_GLITCH 0xC0 /* glitch eater */ -#define CNTLREG4_PWD 0x20 /* reduced power feature */ -#define CNTLREG4_RAE 0x08 /* write only, active negot. ctrl. */ -#define CNTLREG4_RADE 0x04 /* active negot. ctrl. */ -#define CNTLREG4_RES 0x10 /* reserved bit, must be 1 */ +#define ISREG 0x18 /* r internal state reg. */ +#define ISREG_SOF 0x08 /* synchronous offset flag (act. low) */ +#define ISREG_IS 0x07 /* status of intermediate op. */ +#define ISREG_OK_NO_STOP 0x04 /* selection successful */ +#define ISREG_OK_STOP 0x01 /* selection successful */ + +#define CFIREG 0x1C /* r current FIFO/internal state reg. */ +#define CFIREG_IS 0xE0 /* status of intermediate op. */ +#define CFIREG_CF 0x1F /* number of bytes in SCSI FIFO */ + +#define SOFREG 0x1C /* w synchr. offset reg. */ +#define SOFREG_RAD 0xC0 /* REQ/ACK deassertion delay (sync.) */ +#define SOFREG_RAA 0x30 /* REQ/ACK assertion delay (sync.) */ +#define SOFREG_SO 0x0F /* synch. offset (sync.) */ + +#define CNTLREG1 0x20 /* rw control register one */ +#define CNTLREG1_ETM 0x80 /* set extended timing mode */ +#define CNTLREG1_DISR 0x40 /* disable interrupt on SCSI reset */ +#define CNTLREG1_PERE 0x10 /* enable parity error reporting */ +#define CNTLREG1_SID 0x07 /* host adapter SCSI ID */ + +#define CNTLREG2 0x2C /* rw control register two */ +#define CNTLREG2_ENF 0x40 /* enable features */ + +#define CNTLREG3 0x30 /* rw control register three */ +#define CNTLREG3_ADIDCHK 0x80 /* additional ID check */ +#define CNTLREG3_FASTSCSI 0x10 /* fast SCSI */ +#define CNTLREG3_FASTCLK 0x08 /* fast SCSI clocking */ + +#define CNTLREG4 0x34 /* rw control register four */ +#define CNTLREG4_GLITCH 0xC0 /* glitch eater */ +#define CNTLREG4_PWD 0x20 /* reduced power feature */ +#define CNTLREG4_RAE 0x08 /* write only, active negot. ctrl. */ +#define CNTLREG4_RADE 0x04 /* active negot. ctrl. */ +#define CNTLREG4_RES 0x10 /* reserved bit, must be 1 */ /*** DMA block ***/ -#define DMACMD 0x40 /* rw command */ +#define DMACMD 0x40 /* rw command */ #define DMACMD_DIR 0x80 /* transfer direction (1=read from device) */ -#define DMACMD_INTE_D 0x40 /* DMA transfer interrupt enable */ -#define DMACMD_INTE_P 0x20 /* page transfer interrupt enable */ -#define DMACMD_MDL 0x10 /* map to memory descriptor list */ -#define DMACMD_DIAG 0x04 /* diagnostics, set to 0 */ -#define DMACMD_IDLE 0x00 /* idle cmd */ -#define DMACMD_BLAST 0x01 /* flush FIFO to memory */ -#define DMACMD_ABORT 0x02 /* terminate DMA */ -#define DMACMD_START 0x03 /* start DMA */ - -#define DMASTATUS 0x54 /* r status register */ -#define DMASTATUS_BCMPLT 0x20 /* BLAST complete */ -#define DMASTATUS_SCSIINT 0x10 /* SCSI interrupt pending */ -#define DMASTATUS_DONE 0x08 /* DMA transfer terminated */ -#define DMASTATUS_ABORT 0x04 /* DMA transfer aborted */ -#define DMASTATUS_ERROR 0x02 /* DMA transfer error */ -#define DMASTATUS_PWDN 0x02 /* power down indicator */ - -#define DMASTC 0x44 /* rw starting transfer count */ -#define DMASPA 0x48 /* rw starting physical address */ -#define DMAWBC 0x4C /* r working byte counter */ -#define DMAWAC 0x50 /* r working address counter */ -#define DMASMDLA 0x58 /* rw starting MDL address */ -#define DMAWMAC 0x5C /* r working MDL counter */ +#define DMACMD_INTE_D 0x40 /* DMA transfer interrupt enable */ +#define DMACMD_INTE_P 0x20 /* page transfer interrupt enable */ +#define DMACMD_MDL 0x10 /* map to memory descriptor list */ +#define DMACMD_DIAG 0x04 /* diagnostics, set to 0 */ +#define DMACMD_IDLE 0x00 /* idle cmd */ +#define DMACMD_BLAST 0x01 /* flush FIFO to memory */ +#define DMACMD_ABORT 0x02 /* terminate DMA */ +#define DMACMD_START 0x03 /* start DMA */ + +#define DMASTATUS 0x54 /* r status register */ +#define DMASTATUS_BCMPLT 0x20 /* BLAST complete */ +#define DMASTATUS_SCSIINT 0x10 /* SCSI interrupt pending */ +#define DMASTATUS_DONE 0x08 /* DMA transfer terminated */ +#define DMASTATUS_ABORT 0x04 /* DMA transfer aborted */ +#define DMASTATUS_ERROR 0x02 /* DMA transfer error */ +#define DMASTATUS_PWDN 0x02 /* power down indicator */ + +#define DMASTC 0x44 /* rw starting transfer count */ +#define DMASPA 0x48 /* rw starting physical address */ +#define DMAWBC 0x4C /* r working byte counter */ +#define DMAWAC 0x50 /* r working address counter */ +#define DMASMDLA 0x58 /* rw starting MDL address */ +#define DMAWMAC 0x5C /* r working MDL counter */ /*** SCSI phases ***/ #define PHASE_MSGIN 0x07 @@ -332,52 +332,52 @@ #define AM53C974_poll_int() { do { statreg = AM53C974_read_8(STATREG); } \ while (!(statreg & STATREG_INT)) ; \ - AM53C974_read_8(INSTREG) ; } /* clear int */ + AM53C974_read_8(INSTREG) ; } /* clear int */ #define AM53C974_cfifo() (AM53C974_read_8(CFIREG) & CFIREG_CF) /* These are "special" values for the tag parameter passed to AM53C974_select. */ -#define TAG_NEXT -1 /* Use next free tag */ +#define TAG_NEXT -1 /* Use next free tag */ #define TAG_NONE -2 /* Establish I_T_L nexus instead of I_T_L_Q - * even on SCSI-II devices */ + * even on SCSI-II devices */ /************ LILO overrides *************/ typedef struct _override_t { - int host_scsi_id; /* SCSI id of the bus controller */ - int target_scsi_id; /* SCSI id of target */ - int max_rate; /* max. transfer rate */ - int max_offset; /* max. sync. offset, 0 = asynchronous */ - } override_t; + int host_scsi_id; /* SCSI id of the bus controller */ + int target_scsi_id; /* SCSI id of target */ + int max_rate; /* max. transfer rate */ + int max_offset; /* max. sync. offset, 0 = asynchronous */ +} override_t; #ifdef AM53C974_DEBUG static void AM53C974_print_phase(struct Scsi_Host *instance); static void AM53C974_print_queues(struct Scsi_Host *instance); -#endif /* AM53C974_DEBUG */ +#endif /* AM53C974_DEBUG */ static void AM53C974_print(struct Scsi_Host *instance); static void AM53C974_keywait(void); -static __inline__ int AM53C974_pci_detect(Scsi_Host_Template *tpnt); -static int AM53C974_init(Scsi_Host_Template *tpnt, struct pci_dev *pdev); +static __inline__ int AM53C974_pci_detect(Scsi_Host_Template * tpnt); +static int AM53C974_init(Scsi_Host_Template * tpnt, struct pci_dev *pdev); static void AM53C974_config_after_reset(struct Scsi_Host *instance); -static __inline__ void initialize_SCp(Scsi_Cmnd *cmd); +static __inline__ void initialize_SCp(Scsi_Cmnd * cmd); static __inline__ void run_main(void); -static void AM53C974_main (void); +static void AM53C974_main(void); static void AM53C974_intr(int irq, void *dev_id, struct pt_regs *regs); static void do_AM53C974_intr(int irq, void *dev_id, struct pt_regs *regs); -static void AM53C974_intr_disconnect(struct Scsi_Host *instance); +static void AM53C974_intr_disconnect(struct Scsi_Host *instance); static int AM53C974_sync_neg(struct Scsi_Host *instance, int target, unsigned char *msg); static __inline__ void AM53C974_set_async(struct Scsi_Host *instance, int target); static __inline__ void AM53C974_set_sync(struct Scsi_Host *instance, int target); -static void AM53C974_information_transfer(struct Scsi_Host *instance, - unsigned char statreg, unsigned char isreg, - unsigned char instreg, unsigned char cfifo, - unsigned char dmastatus); -static int AM53C974_message(struct Scsi_Host *instance, Scsi_Cmnd *cmd, unsigned char msg); -static void AM53C974_select(struct Scsi_Host *instance, Scsi_Cmnd *cmd, int tag); +static void AM53C974_information_transfer(struct Scsi_Host *instance, + unsigned char statreg, unsigned char isreg, + unsigned char instreg, unsigned char cfifo, + unsigned char dmastatus); +static int AM53C974_message(struct Scsi_Host *instance, Scsi_Cmnd * cmd, unsigned char msg); +static void AM53C974_select(struct Scsi_Host *instance, Scsi_Cmnd * cmd, int tag); static void AM53C974_intr_reselect(struct Scsi_Host *instance, unsigned char statreg); -static __inline__ void AM53C974_transfer_dma(struct Scsi_Host *instance, short dir, - unsigned long length, char *data); -static void AM53C974_dma_blast(struct Scsi_Host *instance, unsigned char dmastatus, - unsigned char statreg); +static __inline__ void AM53C974_transfer_dma(struct Scsi_Host *instance, short dir, + unsigned long length, char *data); +static void AM53C974_dma_blast(struct Scsi_Host *instance, unsigned char dmastatus, + unsigned char statreg); static void AM53C974_intr_bus_reset(struct Scsi_Host *instance); static struct Scsi_Host *first_instance = NULL; @@ -385,9 +385,12 @@ static struct Scsi_Host *first_host = NULL; /* Head of list of AMD boards */ static volatile int main_running = 0; static int commandline_current = 0; -override_t overrides[7] = { {-1, 0, 0, 0}, }; /* LILO overrides */ +override_t overrides[7] = +{ + {-1, 0, 0, 0},}; /* LILO overrides */ -struct proc_dir_entry proc_scsi_am53c974 = { +struct proc_dir_entry proc_scsi_am53c974 = +{ PROC_SCSI_AM53C974, 8, "am53c974", S_IFDIR | S_IRUGO | S_IXUGO, 2 }; @@ -396,12 +399,30 @@ static int deb_stop = 1; static struct { - unsigned char value; - char *name; + unsigned char value; + char *name; } phases[] = { -{PHASE_DATAOUT, "DATAOUT"}, {PHASE_DATAIN, "DATAIN"}, {PHASE_CMDOUT, "CMDOUT"}, -{PHASE_STATIN, "STATIN"}, {PHASE_MSGOUT, "MSGOUT"}, {PHASE_MSGIN, "MSGIN"}, -{PHASE_RES_0, "RESERVED 0"}, {PHASE_RES_1, "RESERVED 1"}}; + + { + PHASE_DATAOUT, "DATAOUT" + }, { + PHASE_DATAIN, "DATAIN" + }, { + PHASE_CMDOUT, "CMDOUT" + }, + { + PHASE_STATIN, "STATIN" + }, { + PHASE_MSGOUT, "MSGOUT" + }, { + PHASE_MSGIN, "MSGIN" + }, + { + PHASE_RES_0, "RESERVED 0" + }, { + PHASE_RES_1, "RESERVED 1" + } +}; /************************************************************************** * Function : void AM53C974_print_phase(struct Scsi_Host *instance) @@ -412,19 +433,19 @@ **************************************************************************/ static void AM53C974_print_phase(struct Scsi_Host *instance) { -AM53C974_local_declare(); -unsigned char statreg, latched; -int i; -AM53C974_setio(instance); - -latched = (AM53C974_read_8(CNTLREG2)) & CNTLREG2_ENF; -statreg = AM53C974_read_8(STATREG); -for (i = 0; (phases[i].value != PHASE_RES_1) && - (phases[i].value != (statreg & STATREG_PHASE)); ++i); -if (latched) - printk("scsi%d : phase %s, latched at end of last command\n", instance->host_no, phases[i].name); - else - printk("scsi%d : phase %s, real time\n", instance->host_no, phases[i].name); + AM53C974_local_declare(); + unsigned char statreg, latched; + int i; + AM53C974_setio(instance); + + latched = (AM53C974_read_8(CNTLREG2)) & CNTLREG2_ENF; + statreg = AM53C974_read_8(STATREG); + for (i = 0; (phases[i].value != PHASE_RES_1) && + (phases[i].value != (statreg & STATREG_PHASE)); ++i); + if (latched) + printk("scsi%d : phase %s, latched at end of last command\n", instance->host_no, phases[i].name); + else + printk("scsi%d : phase %s, real time\n", instance->host_no, phases[i].name); } /************************************************************************** @@ -436,42 +457,48 @@ **************************************************************************/ static void AM53C974_print_queues(struct Scsi_Host *instance) { -struct AM53C974_hostdata *hostdata = (struct AM53C974_hostdata *)instance->hostdata; -Scsi_Cmnd *ptr; + unsigned long flags; + struct AM53C974_hostdata *hostdata = (struct AM53C974_hostdata *) instance->hostdata; + Scsi_Cmnd *ptr; + + printk("AM53C974: coroutine is%s running.\n", main_running ? "" : "n't"); + + save_flags(flags); + cli(); + + if (!hostdata->connected) { + printk("scsi%d: no currently connected command\n", instance->host_no); + } else { + print_Scsi_Cmnd((Scsi_Cmnd *) hostdata->connected); + } + if (!hostdata->sel_cmd) { + printk("scsi%d: no currently arbitrating command\n", instance->host_no); + } else { + print_Scsi_Cmnd((Scsi_Cmnd *) hostdata->sel_cmd); + } + + printk("scsi%d: issue_queue ", instance->host_no); + if (!hostdata->issue_queue) + printk("empty\n"); + else { + printk(":\n"); + for (ptr = (Scsi_Cmnd *) hostdata->issue_queue; ptr; ptr = (Scsi_Cmnd *) ptr->host_scribble) + print_Scsi_Cmnd(ptr); + } + + printk("scsi%d: disconnected_queue ", instance->host_no); + if (!hostdata->disconnected_queue) + printk("empty\n"); + else { + printk(":\n"); + for (ptr = (Scsi_Cmnd *) hostdata->disconnected_queue; ptr; ptr = (Scsi_Cmnd *) ptr->host_scribble) + print_Scsi_Cmnd(ptr); + } -printk("AM53C974: coroutine is%s running.\n", main_running ? "" : "n't"); - -cli(); - -if (!hostdata->connected) { - printk ("scsi%d: no currently connected command\n", instance->host_no); } - else { - print_Scsi_Cmnd ((Scsi_Cmnd *)hostdata->connected); } -if (!hostdata->sel_cmd) { - printk ("scsi%d: no currently arbitrating command\n", instance->host_no); } - else { - print_Scsi_Cmnd ((Scsi_Cmnd *)hostdata->sel_cmd); } - -printk ("scsi%d: issue_queue ", instance->host_no); -if (!hostdata->issue_queue) - printk("empty\n"); - else { - printk(":\n"); - for (ptr = (Scsi_Cmnd *)hostdata->issue_queue; ptr; ptr = (Scsi_Cmnd *)ptr->host_scribble) - print_Scsi_Cmnd (ptr); } - -printk ("scsi%d: disconnected_queue ", instance->host_no); -if (!hostdata->disconnected_queue) - printk("empty\n"); - else { - printk(":\n"); - for (ptr = (Scsi_Cmnd *) hostdata->disconnected_queue; ptr; ptr = (Scsi_Cmnd *)ptr->host_scribble) - print_Scsi_Cmnd (ptr); } - -sti(); + restore_flags(flags); } -#endif /* AM53C974_DEBUG */ +#endif /* AM53C974_DEBUG */ /************************************************************************** * Function : void AM53C974_print(struct Scsi_Host *instance) @@ -482,39 +509,42 @@ **************************************************************************/ static void AM53C974_print(struct Scsi_Host *instance) { -AM53C974_local_declare(); -unsigned long ctcreg, dmastc, dmaspa, dmawbc, dmawac; -unsigned char cmdreg, statreg, isreg, cfireg, cntlreg[4], dmacmd, dmastatus; -AM53C974_setio(instance); - -cli(); -ctcreg = AM53C974_read_8(CTCHREG) << 16; -ctcreg |= AM53C974_read_8(CTCMREG) << 8; -ctcreg |= AM53C974_read_8(CTCLREG); -cmdreg = AM53C974_read_8(CMDREG); -statreg = AM53C974_read_8(STATREG); -isreg = AM53C974_read_8(ISREG); -cfireg = AM53C974_read_8(CFIREG); -cntlreg[0] = AM53C974_read_8(CNTLREG1); -cntlreg[1] = AM53C974_read_8(CNTLREG2); -cntlreg[2] = AM53C974_read_8(CNTLREG3); -cntlreg[3] = AM53C974_read_8(CNTLREG4); -dmacmd = AM53C974_read_8(DMACMD); -dmastc = AM53C974_read_32(DMASTC); -dmaspa = AM53C974_read_32(DMASPA); -dmawbc = AM53C974_read_32(DMAWBC); -dmawac = AM53C974_read_32(DMAWAC); -dmastatus = AM53C974_read_8(DMASTATUS); -sti(); - -printk("AM53C974 register dump:\n"); -printk("IO base: 0x%04lx; CTCREG: 0x%04lx; CMDREG: 0x%02x; STATREG: 0x%02x; ISREG: 0x%02x\n", - io_port, ctcreg, cmdreg, statreg, isreg); -printk("CFIREG: 0x%02x; CNTLREG1-4: 0x%02x; 0x%02x; 0x%02x; 0x%02x\n", - cfireg, cntlreg[0], cntlreg[1], cntlreg[2], cntlreg[3]); -printk("DMACMD: 0x%02x; DMASTC: 0x%04lx; DMASPA: 0x%04lx\n", dmacmd, dmastc, dmaspa); -printk("DMAWBC: 0x%04lx; DMAWAC: 0x%04lx; DMASTATUS: 0x%02x\n", dmawbc, dmawac, dmastatus); -printk("---------------------------------------------------------\n"); + AM53C974_local_declare(); + unsigned long flags; + unsigned long ctcreg, dmastc, dmaspa, dmawbc, dmawac; + unsigned char cmdreg, statreg, isreg, cfireg, cntlreg[4], dmacmd, + dmastatus; + AM53C974_setio(instance); + + save_flags(flags); + cli(); + ctcreg = AM53C974_read_8(CTCHREG) << 16; + ctcreg |= AM53C974_read_8(CTCMREG) << 8; + ctcreg |= AM53C974_read_8(CTCLREG); + cmdreg = AM53C974_read_8(CMDREG); + statreg = AM53C974_read_8(STATREG); + isreg = AM53C974_read_8(ISREG); + cfireg = AM53C974_read_8(CFIREG); + cntlreg[0] = AM53C974_read_8(CNTLREG1); + cntlreg[1] = AM53C974_read_8(CNTLREG2); + cntlreg[2] = AM53C974_read_8(CNTLREG3); + cntlreg[3] = AM53C974_read_8(CNTLREG4); + dmacmd = AM53C974_read_8(DMACMD); + dmastc = AM53C974_read_32(DMASTC); + dmaspa = AM53C974_read_32(DMASPA); + dmawbc = AM53C974_read_32(DMAWBC); + dmawac = AM53C974_read_32(DMAWAC); + dmastatus = AM53C974_read_8(DMASTATUS); + restore_flags(flags); + + printk("AM53C974 register dump:\n"); + printk("IO base: 0x%04lx; CTCREG: 0x%04lx; CMDREG: 0x%02x; STATREG: 0x%02x; ISREG: 0x%02x\n", + io_port, ctcreg, cmdreg, statreg, isreg); + printk("CFIREG: 0x%02x; CNTLREG1-4: 0x%02x; 0x%02x; 0x%02x; 0x%02x\n", + cfireg, cntlreg[0], cntlreg[1], cntlreg[2], cntlreg[3]); + printk("DMACMD: 0x%02x; DMASTC: 0x%04lx; DMASPA: 0x%04lx\n", dmacmd, dmastc, dmaspa); + printk("DMAWBC: 0x%04lx; DMAWAC: 0x%04lx; DMASTATUS: 0x%02x\n", dmawbc, dmawac, dmastatus); + printk("---------------------------------------------------------\n"); } /************************************************************************** @@ -527,19 +557,23 @@ **************************************************************************/ static void AM53C974_keywait(void) { + unsigned long flags; #ifdef AM53C974_DEBUG -int key; + int key; -if (!deb_stop) return; + if (!deb_stop) + return; #endif -cli(); -while ((inb_p(0x64) & 0x01) != 0x01) ; + save_flags(flags); + cli(); + while ((inb_p(0x64) & 0x01) != 0x01); #ifdef AM53C974_DEBUG -key = inb(0x60); -if (key == 0x93) deb_stop = 0; /* don't stop if 'r' was pressed */ + key = inb(0x60); + if (key == 0x93) + deb_stop = 0; /* don't stop if 'r' was pressed */ #endif -sti(); + restore_flags(flags); } /************************************************************************** @@ -555,26 +589,26 @@ ***************************************************************************/ void AM53C974_setup(char *str, int *ints) { -if (ints[0] < 4) - printk("AM53C974_setup: wrong number of parameters;\n correct syntax is: AM53C974=host-scsi-id, target-scsi-id, max-rate, max-offset\n"); - else { - if (commandline_current < (sizeof(overrides) / sizeof(override_t))) { - if ((ints[1] < 0) || (ints[1] > 7) || - (ints[2] < 0) || (ints[2] > 7) || - (ints[1] == ints[2]) || - (ints[3] < (DEF_CLK / MAX_PERIOD)) || (ints[3] > (DEF_CLK / MIN_PERIOD)) || - (ints[4] < 0) || (ints[4] > MAX_OFFSET)) - printk("AM53C974_setup: illegal parameter\n"); - else { - overrides[commandline_current].host_scsi_id = ints[1]; - overrides[commandline_current].target_scsi_id = ints[2]; - overrides[commandline_current].max_rate = ints[3]; - overrides[commandline_current].max_offset = ints[4]; - commandline_current++; } - } - else - printk("AM53C974_setup: too many overrides\n"); - } + if (ints[0] < 4) + printk("AM53C974_setup: wrong number of parameters;\n correct syntax is: AM53C974=host-scsi-id, target-scsi-id, max-rate, max-offset\n"); + else { + if (commandline_current < (sizeof(overrides) / sizeof(override_t))) { + if ((ints[1] < 0) || (ints[1] > 7) || + (ints[2] < 0) || (ints[2] > 7) || + (ints[1] == ints[2]) || + (ints[3] < (DEF_CLK / MAX_PERIOD)) || (ints[3] > (DEF_CLK / MIN_PERIOD)) || + (ints[4] < 0) || (ints[4] > MAX_OFFSET)) + printk("AM53C974_setup: illegal parameter\n"); + else { + overrides[commandline_current].host_scsi_id = ints[1]; + overrides[commandline_current].target_scsi_id = ints[2]; + overrides[commandline_current].max_rate = ints[3]; + overrides[commandline_current].max_offset = ints[4]; + commandline_current++; + } + } else + printk("AM53C974_setup: too many overrides\n"); + } } #if defined (CONFIG_PCI) @@ -587,30 +621,32 @@ * * Returns : number of host adapters detected **************************************************************************/ -static __inline__ int AM53C974_pci_detect(Scsi_Host_Template *tpnt) +static __inline__ int AM53C974_pci_detect(Scsi_Host_Template * tpnt) { -int count = 0; /* number of boards detected */ -struct pci_dev *pdev = NULL; -unsigned short command; - -while ((pdev = pci_find_device(PCI_VENDOR_ID_AMD, PCI_DEVICE_ID_AMD_SCSI, pdev))) { - pci_read_config_word(pdev, PCI_COMMAND, &command); - - /* check whether device is I/O mapped -- should be */ - if (!(command & PCI_COMMAND_IO)) continue; - - /* PCI Spec 2.1 states that it is either the driver's or the PCI card's responsibility - to set the PCI Master Enable Bit if needed. - (from Mark Stockton ) */ - if (!(command & PCI_COMMAND_MASTER)) { - command |= PCI_COMMAND_MASTER; - printk("PCI Master Bit has not been set. Setting...\n"); - pci_write_config_word(pdev, PCI_COMMAND, command); } - - /* everything seems OK now, so initialize */ - if (AM53C974_init(tpnt, pdev)) count++ ; - } -return (count); + int count = 0; /* number of boards detected */ + struct pci_dev *pdev = NULL; + unsigned short command; + + while ((pdev = pci_find_device(PCI_VENDOR_ID_AMD, PCI_DEVICE_ID_AMD_SCSI, pdev))) { + pci_read_config_word(pdev, PCI_COMMAND, &command); + + /* check whether device is I/O mapped -- should be */ + if (!(command & PCI_COMMAND_IO)) + continue; + + /* PCI Spec 2.1 states that it is either the driver's or the PCI card's responsibility + to set the PCI Master Enable Bit if needed. + (from Mark Stockton ) */ + if (!(command & PCI_COMMAND_MASTER)) { + command |= PCI_COMMAND_MASTER; + printk("PCI Master Bit has not been set. Setting...\n"); + pci_write_config_word(pdev, PCI_COMMAND, command); + } + /* everything seems OK now, so initialize */ + if (AM53C974_init(tpnt, pdev)) + count++; + } + return (count); } #endif @@ -623,17 +659,17 @@ * * Returns : number of host adapters detected **************************************************************************/ -__initfunc(int AM53C974_detect(Scsi_Host_Template *tpnt)) +__initfunc(int AM53C974_detect(Scsi_Host_Template * tpnt)) { -int count = 0; /* number of boards detected */ + int count = 0; /* number of boards detected */ -tpnt->proc_dir = &proc_scsi_am53c974; + tpnt->proc_dir = &proc_scsi_am53c974; #if defined (CONFIG_PCI) -if (pci_present()) - count = AM53C974_pci_detect(tpnt); + if (pci_present()) + count = AM53C974_pci_detect(tpnt); #endif -return (count); + return (count); } /************************************************************************** @@ -650,97 +686,100 @@ * set up by the BIOS (as reflected by contents of register CNTLREG1). * This is the only BIOS assistance we need. **************************************************************************/ -__initfunc(static int AM53C974_init(Scsi_Host_Template *tpnt, struct pci_dev *pdev)) +__initfunc(static int AM53C974_init(Scsi_Host_Template * tpnt, struct pci_dev *pdev)) { -AM53C974_local_declare(); -int i, j; -struct Scsi_Host *instance, *search; -struct AM53C974_hostdata *hostdata; + AM53C974_local_declare(); + int i, j; + struct Scsi_Host *instance, *search; + struct AM53C974_hostdata *hostdata; #ifdef AM53C974_OPTION_DEBUG_PROBE_ONLY - printk ("AM53C974: probe only enabled, aborting initialization\n"); - return 0; + printk("AM53C974: probe only enabled, aborting initialization\n"); + return 0; #endif -instance = scsi_register(tpnt, sizeof(struct AM53C974_hostdata)); -hostdata = (struct AM53C974_hostdata *)instance->hostdata; -instance->base = NULL; -instance->io_port = pdev->base_address[0] & PCI_BASE_ADDRESS_IO_MASK; -instance->irq = pdev->irq; -instance->dma_channel = -1; -AM53C974_setio(instance); + instance = scsi_register(tpnt, sizeof(struct AM53C974_hostdata)); + hostdata = (struct AM53C974_hostdata *) instance->hostdata; + instance->base = NULL; + instance->io_port = pdev->base_address[0] & PCI_BASE_ADDRESS_IO_MASK; + instance->irq = pdev->irq; + instance->dma_channel = -1; + AM53C974_setio(instance); #ifdef AM53C974_SCSI_ID -instance->this_id = AM53C974_SCSI_ID; -AM53C974_write_8(CNTLREG1, instance->this_id & CNTLREG1_SID); + instance->this_id = AM53C974_SCSI_ID; + AM53C974_write_8(CNTLREG1, instance->this_id & CNTLREG1_SID); #else -instance->this_id = AM53C974_read_8(CNTLREG1) & CNTLREG1_SID; -if (instance->this_id != 7) - printk("scsi%d: WARNING: unusual hostadapter SCSI id %d; please verify!\n", - instance->host_no, instance->this_id); -#endif - -for (i = 0; i < sizeof(hostdata->msgout); i++) { - hostdata->msgout[i] = NOP; - hostdata->last_message[i] = NOP; } -for (i = 0; i < 8; i++) { - hostdata->busy[i] = 0; - hostdata->sync_per[i] = DEF_STP; - hostdata->sync_off[i] = 0; - hostdata->sync_neg[i] = 0; - hostdata->sync_en[i] = DEFAULT_SYNC_NEGOTIATION_ENABLED; - hostdata->max_rate[i] = DEFAULT_RATE; - hostdata->max_offset[i] = DEFAULT_SYNC_OFFSET; } + instance->this_id = AM53C974_read_8(CNTLREG1) & CNTLREG1_SID; + if (instance->this_id != 7) + printk("scsi%d: WARNING: unusual hostadapter SCSI id %d; please verify!\n", + instance->host_no, instance->this_id); +#endif + + for (i = 0; i < sizeof(hostdata->msgout); i++) { + hostdata->msgout[i] = NOP; + hostdata->last_message[i] = NOP; + } + for (i = 0; i < 8; i++) { + hostdata->busy[i] = 0; + hostdata->sync_per[i] = DEF_STP; + hostdata->sync_off[i] = 0; + hostdata->sync_neg[i] = 0; + hostdata->sync_en[i] = DEFAULT_SYNC_NEGOTIATION_ENABLED; + hostdata->max_rate[i] = DEFAULT_RATE; + hostdata->max_offset[i] = DEFAULT_SYNC_OFFSET; + } /* overwrite defaults by LILO overrides */ -for (i = 0; i < commandline_current; i++) { - if (overrides[i].host_scsi_id == instance->this_id) { - j = overrides[i].target_scsi_id; - hostdata->sync_en[j] = 1; - hostdata->max_rate[j] = overrides[i].max_rate; - hostdata->max_offset[j] = overrides[i].max_offset; - } - } - -hostdata->sel_cmd = NULL; -hostdata->connected = NULL; -hostdata->issue_queue = NULL; -hostdata->disconnected_queue = NULL; -hostdata->in_reset = 0; -hostdata->aborted = 0; -hostdata->selecting = 0; -hostdata->disconnecting = 0; -hostdata->dma_busy = 0; + for (i = 0; i < commandline_current; i++) { + if (overrides[i].host_scsi_id == instance->this_id) { + j = overrides[i].target_scsi_id; + hostdata->sync_en[j] = 1; + hostdata->max_rate[j] = overrides[i].max_rate; + hostdata->max_offset[j] = overrides[i].max_offset; + } + } + + hostdata->sel_cmd = NULL; + hostdata->connected = NULL; + hostdata->issue_queue = NULL; + hostdata->disconnected_queue = NULL; + hostdata->in_reset = 0; + hostdata->aborted = 0; + hostdata->selecting = 0; + hostdata->disconnecting = 0; + hostdata->dma_busy = 0; /* Set up an interrupt handler if we aren't already sharing an IRQ with another board */ -for (search = first_host; - search && ( ((the_template != NULL) && (search->hostt != the_template)) || - (search->irq != instance->irq) || (search == instance) ); - search = search->next); -if (!search) { - if (request_irq(instance->irq, do_AM53C974_intr, SA_INTERRUPT, "AM53C974", NULL)) { - printk("scsi%d: IRQ%d not free, detaching\n", instance->host_no, instance->irq); - scsi_unregister(instance); - return 0; } - } - else { - printk("scsi%d: using interrupt handler previously installed for scsi%d\n", - instance->host_no, search->host_no); } - -if (!the_template) { - the_template = instance->hostt; - first_instance = instance; } - + for (search = first_host; + search && (((the_template != NULL) && (search->hostt != the_template)) || + (search->irq != instance->irq) || (search == instance)); + search = search->next); + if (!search) { + if (request_irq(instance->irq, do_AM53C974_intr, SA_INTERRUPT, "AM53C974", NULL)) { + printk("scsi%d: IRQ%d not free, detaching\n", instance->host_no, instance->irq); + scsi_unregister(instance); + return 0; + } + } else { + printk("scsi%d: using interrupt handler previously installed for scsi%d\n", + instance->host_no, search->host_no); + } + + if (!the_template) { + the_template = instance->hostt; + first_instance = instance; + } /* do hard reset */ -AM53C974_write_8(CMDREG, CMDREG_RDEV); /* reset device */ -udelay(5); -AM53C974_write_8(CMDREG, CMDREG_NOP); -AM53C974_write_8(CNTLREG1, CNTLREG1_DISR | instance->this_id); -AM53C974_write_8(CMDREG, CMDREG_RBUS); /* reset SCSI bus */ -udelay(10); -AM53C974_config_after_reset(instance); -udelay(500000); -return(1); + AM53C974_write_8(CMDREG, CMDREG_RDEV); /* reset device */ + udelay(5); + AM53C974_write_8(CMDREG, CMDREG_NOP); + AM53C974_write_8(CNTLREG1, CNTLREG1_DISR | instance->this_id); + AM53C974_write_8(CMDREG, CMDREG_RBUS); /* reset SCSI bus */ + udelay(10); + AM53C974_config_after_reset(instance); + udelay(500000); + return (1); } /********************************************************************* @@ -754,21 +793,21 @@ **********************************************************************/ static void AM53C974_config_after_reset(struct Scsi_Host *instance) { -AM53C974_local_declare(); -AM53C974_setio(instance); + AM53C974_local_declare(); + AM53C974_setio(instance); /* clear SCSI FIFO */ -AM53C974_write_8(CMDREG, CMDREG_CFIFO); + AM53C974_write_8(CMDREG, CMDREG_CFIFO); /* configure device */ -AM53C974_write_8(STIMREG, DEF_SCSI_TIMEOUT); -AM53C974_write_8(STPREG, DEF_STP & STPREG_STP); -AM53C974_write_8(SOFREG, (DEF_SOF_RAD<<6) | (DEF_SOF_RAA<<4)); -AM53C974_write_8(CLKFREG, DEF_CLKF & CLKFREG_MASK); -AM53C974_write_8(CNTLREG1, (DEF_ETM<<7) | CNTLREG1_DISR | (DEF_PERE<<4) | instance->this_id); -AM53C974_write_8(CNTLREG2, (DEF_ENF<<6)); -AM53C974_write_8(CNTLREG3, (DEF_ADIDCHK<<7) | (DEF_FASTSCSI<<4) | (DEF_FASTCLK<<3)); -AM53C974_write_8(CNTLREG4, (DEF_GLITCH<<6) | (DEF_PWD<<5) | (DEF_RAE<<3) | (DEF_RADE<<2) | CNTLREG4_RES); + AM53C974_write_8(STIMREG, DEF_SCSI_TIMEOUT); + AM53C974_write_8(STPREG, DEF_STP & STPREG_STP); + AM53C974_write_8(SOFREG, (DEF_SOF_RAD << 6) | (DEF_SOF_RAA << 4)); + AM53C974_write_8(CLKFREG, DEF_CLKF & CLKFREG_MASK); + AM53C974_write_8(CNTLREG1, (DEF_ETM << 7) | CNTLREG1_DISR | (DEF_PERE << 4) | instance->this_id); + AM53C974_write_8(CNTLREG2, (DEF_ENF << 6)); + AM53C974_write_8(CNTLREG3, (DEF_ADIDCHK << 7) | (DEF_FASTSCSI << 4) | (DEF_FASTCLK << 3)); + AM53C974_write_8(CNTLREG4, (DEF_GLITCH << 6) | (DEF_PWD << 5) | (DEF_RAE << 3) | (DEF_RADE << 2) | CNTLREG4_RES); } /*********************************************************************** @@ -782,12 +821,12 @@ ************************************************************************/ const char *AM53C974_info(struct Scsi_Host *instance) { -static char info[100]; + static char info[100]; -sprintf(info, "AM53/79C974 PCscsi driver rev. %d.%d; host I/O address: 0x%x; irq: %d\n", - AM53C974_DRIVER_REVISION_MAJOR, AM53C974_DRIVER_REVISION_MINOR, - instance->io_port, instance->irq); -return (info); + sprintf(info, "AM53/79C974 PCscsi driver rev. %d.%d; host I/O address: 0x%x; irq: %d\n", + AM53C974_DRIVER_REVISION_MAJOR, AM53C974_DRIVER_REVISION_MINOR, + instance->io_port, instance->irq); + return (info); } /************************************************************************** @@ -800,10 +839,10 @@ * * * Returns :status, see hosts.h for details * ***************************************************************************/ -int AM53C974_command(Scsi_Cmnd *SCpnt) +int AM53C974_command(Scsi_Cmnd * SCpnt) { -DEB(printk("AM53C974_command called\n")); -return 0; + DEB(printk("AM53C974_command called\n")); + return 0; } /************************************************************************** @@ -816,18 +855,19 @@ * * * Returns : nothing * **************************************************************************/ -static __inline__ void initialize_SCp(Scsi_Cmnd *cmd) +static __inline__ void initialize_SCp(Scsi_Cmnd * cmd) { -if (cmd->use_sg) { - cmd->SCp.buffer = (struct scatterlist *)cmd->buffer; - cmd->SCp.buffers_residual = cmd->use_sg - 1; - cmd->SCp.ptr = (char *)cmd->SCp.buffer->address; - cmd->SCp.this_residual = cmd->SCp.buffer->length; } - else { - cmd->SCp.buffer = NULL; - cmd->SCp.buffers_residual = 0; - cmd->SCp.ptr = (char *)cmd->request_buffer; - cmd->SCp.this_residual = cmd->request_bufflen; } + if (cmd->use_sg) { + cmd->SCp.buffer = (struct scatterlist *) cmd->buffer; + cmd->SCp.buffers_residual = cmd->use_sg - 1; + cmd->SCp.ptr = (char *) cmd->SCp.buffer->address; + cmd->SCp.this_residual = cmd->SCp.buffer->length; + } else { + cmd->SCp.buffer = NULL; + cmd->SCp.buffers_residual = 0; + cmd->SCp.ptr = (char *) cmd->request_buffer; + cmd->SCp.this_residual = cmd->request_bufflen; + } } /************************************************************************** @@ -845,15 +885,16 @@ **************************************************************************/ static __inline__ void run_main(void) { -cli(); -if (!main_running) { - /* main_running is cleared in AM53C974_main once it can't do - more work, and AM53C974_main exits with interrupts disabled. */ - main_running = 1; - AM53C974_main(); - sti(); } - else - sti(); + unsigned long flags; + save_flags(flags); + cli(); + if (!main_running) { + /* main_running is cleared in AM53C974_main once it can't do + more work, and AM53C974_main exits with interrupts disabled. */ + main_running = 1; + AM53C974_main(); + } + restore_flags(flags); } /************************************************************************** @@ -871,44 +912,48 @@ * twiddling done to the host specific fields of cmd. If the * main coroutine is not running, it is restarted. **************************************************************************/ -int AM53C974_queue_command(Scsi_Cmnd *cmd, void (*done)(Scsi_Cmnd *)) +int AM53C974_queue_command(Scsi_Cmnd * cmd, void (*done) (Scsi_Cmnd *)) { -struct Scsi_Host *instance = cmd->host; -struct AM53C974_hostdata *hostdata = (struct AM53C974_hostdata *)instance->hostdata; -Scsi_Cmnd *tmp; - -cli(); -DEB_QUEUE(printk(SEPARATOR_LINE)); -DEB_QUEUE(printk("scsi%d: AM53C974_queue_command called\n", instance->host_no)); -DEB_QUEUE(printk("cmd=%02x target=%02x lun=%02x bufflen=%d use_sg = %02x\n", - cmd->cmnd[0], cmd->target, cmd->lun, cmd->request_bufflen, cmd->use_sg)); + unsigned long flags; + struct Scsi_Host *instance = cmd->host; + struct AM53C974_hostdata *hostdata = (struct AM53C974_hostdata *) instance->hostdata; + Scsi_Cmnd *tmp; + + save_flags(flags); + cli(); + DEB_QUEUE(printk(SEPARATOR_LINE)); + DEB_QUEUE(printk("scsi%d: AM53C974_queue_command called\n", instance->host_no)); + DEB_QUEUE(printk("cmd=%02x target=%02x lun=%02x bufflen=%d use_sg = %02x\n", + cmd->cmnd[0], cmd->target, cmd->lun, cmd->request_bufflen, cmd->use_sg)); /* We use the host_scribble field as a pointer to the next command in a queue */ -cmd->host_scribble = NULL; -cmd->scsi_done = done; -cmd->result = 0; -cmd->device->disconnect = 0; + cmd->host_scribble = NULL; + cmd->scsi_done = done; + cmd->result = 0; + cmd->device->disconnect = 0; /* Insert the cmd into the issue queue. Note that REQUEST SENSE * commands are added to the head of the queue since any command will * clear the contingent allegiance condition that exists and the * sense data is only guaranteed to be valid while the condition exists. */ -if (!(hostdata->issue_queue) || (cmd->cmnd[0] == REQUEST_SENSE)) { - LIST(cmd, hostdata->issue_queue); - cmd->host_scribble = (unsigned char *)hostdata->issue_queue; - hostdata->issue_queue = cmd; } - else { - for (tmp = (Scsi_Cmnd *)hostdata->issue_queue; tmp->host_scribble; - tmp = (Scsi_Cmnd *)tmp->host_scribble); - LIST(cmd, tmp); - tmp->host_scribble = (unsigned char *)cmd; } + if (!(hostdata->issue_queue) || (cmd->cmnd[0] == REQUEST_SENSE)) { + LIST(cmd, hostdata->issue_queue); + cmd->host_scribble = (unsigned char *) hostdata->issue_queue; + hostdata->issue_queue = cmd; + } else { + for (tmp = (Scsi_Cmnd *) hostdata->issue_queue; tmp->host_scribble; + tmp = (Scsi_Cmnd *) tmp->host_scribble); + LIST(cmd, tmp); + tmp->host_scribble = (unsigned char *) cmd; + } -DEB_QUEUE(printk("scsi%d : command added to %s of queue\n", instance->host_no, - (cmd->cmnd[0] == REQUEST_SENSE) ? "head" : "tail")); + DEB_QUEUE(printk("scsi%d : command added to %s of queue\n", instance->host_no, + (cmd->cmnd[0] == REQUEST_SENSE) ? "head" : "tail")); /* Run the coroutine if it isn't already running. */ -run_main(); -return 0; + run_main(); + restore_flags(flags); + return 0; } /************************************************************************** @@ -921,61 +966,65 @@ * * NOTE : AM53C974_main exits with interrupts *disabled*, the caller should * reenable them. This prevents reentrancy and kernel stack overflow. - **************************************************************************/ + **************************************************************************/ static void AM53C974_main(void) { -AM53C974_local_declare(); -Scsi_Cmnd *tmp, *prev; -struct Scsi_Host *instance; -struct AM53C974_hostdata *hostdata; -int done; + AM53C974_local_declare(); + unsigned long flags; + Scsi_Cmnd *tmp, *prev; + struct Scsi_Host *instance; + struct AM53C974_hostdata *hostdata; + int done; /* We run (with interrupts disabled) until we're sure that none of * the host adapters have anything that can be done, at which point * we set main_running to 0 and exit. */ -do { - cli(); /* Freeze request queues */ - done = 1; - for (instance = first_instance; instance && instance->hostt == the_template; - instance = instance->next) { - hostdata = (struct AM53C974_hostdata *)instance->hostdata; - AM53C974_setio(instance); - /* start to select target if we are not connected and not in the - selection process */ - if (!hostdata->connected && !hostdata->sel_cmd) { - /* Search through the issue_queue for a command destined for a target - that is not busy. */ - for (tmp = (Scsi_Cmnd *)hostdata->issue_queue, prev = NULL; tmp; - prev = tmp, tmp = (Scsi_Cmnd *)tmp->host_scribble) { - /* When we find one, remove it from the issue queue. */ - if (!(hostdata->busy[tmp->target] & (1 << tmp->lun))) { - if (prev) { - REMOVE(prev, (Scsi_Cmnd *)(prev->host_scribble), tmp, - (Scsi_Cmnd *)(tmp->host_scribble)); - prev->host_scribble = tmp->host_scribble; } - else { - REMOVE(-1, hostdata->issue_queue, tmp, tmp->host_scribble); - hostdata->issue_queue = (Scsi_Cmnd *)tmp->host_scribble; } - tmp->host_scribble = NULL; - - /* go into selection mode, disable reselection and wait for - SO interrupt which will continue with the selection process */ - hostdata->selecting = 1; - hostdata->sel_cmd = tmp; - AM53C974_write_8(CMDREG, CMDREG_DSR); - break; - } /* if target/lun is not busy */ - - } /* for */ - } /* if (!hostdata->connected) */ - else { - DEB(printk("main: connected; cmd = 0x%lx, sel_cmd = 0x%lx\n", - (long)hostdata->connected, (long)hostdata->sel_cmd)); - } - } /* for instance */ - } while (!done); -main_running = 0; + save_flags(flags); + cli(); /* Freeze request queues */ + do { + done = 1; + for (instance = first_instance; instance && instance->hostt == the_template; + instance = instance->next) { + hostdata = (struct AM53C974_hostdata *) instance->hostdata; + AM53C974_setio(instance); + /* start to select target if we are not connected and not in the + selection process */ + if (!hostdata->connected && !hostdata->sel_cmd) { + /* Search through the issue_queue for a command destined for a target + that is not busy. */ + for (tmp = (Scsi_Cmnd *) hostdata->issue_queue, prev = NULL; tmp; + prev = tmp, tmp = (Scsi_Cmnd *) tmp->host_scribble) { + /* When we find one, remove it from the issue queue. */ + if (!(hostdata->busy[tmp->target] & (1 << tmp->lun))) { + if (prev) { + REMOVE(prev, (Scsi_Cmnd *) (prev->host_scribble), tmp, + (Scsi_Cmnd *) (tmp->host_scribble)); + prev->host_scribble = tmp->host_scribble; + } else { + REMOVE(-1, hostdata->issue_queue, tmp, tmp->host_scribble); + hostdata->issue_queue = (Scsi_Cmnd *) tmp->host_scribble; + } + tmp->host_scribble = NULL; + + /* go into selection mode, disable reselection and wait for + SO interrupt which will continue with the selection process */ + hostdata->selecting = 1; + hostdata->sel_cmd = tmp; + AM53C974_write_8(CMDREG, CMDREG_DSR); + break; + } /* if target/lun is not busy */ + } /* for */ + } + /* if (!hostdata->connected) */ + else { + DEB(printk("main: connected; cmd = 0x%lx, sel_cmd = 0x%lx\n", + (long) hostdata->connected, (long) hostdata->sel_cmd)); + } + } /* for instance */ + } while (!done); + main_running = 0; + restore_flags(flags); } /************************************************************************ @@ -989,11 +1038,11 @@ ************************************************************************/ static void do_AM53C974_intr(int irq, void *dev_id, struct pt_regs *regs) { -unsigned long flags; + unsigned long flags; -spin_lock_irqsave(&io_request_lock, flags); -AM53C974_intr(irq, dev_id, regs); -spin_unlock_irqrestore(&io_request_lock, flags); + spin_lock_irqsave(&io_request_lock, flags); + AM53C974_intr(irq, dev_id, regs); + spin_unlock_irqrestore(&io_request_lock, flags); } /************************************************************************ @@ -1007,230 +1056,251 @@ ************************************************************************/ static void AM53C974_intr(int irq, void *dev_id, struct pt_regs *regs) { -AM53C974_local_declare(); -struct Scsi_Host *instance; -struct AM53C974_hostdata *hostdata; -unsigned char cmdreg, dmastatus, statreg, isreg, instreg, cfifo; + AM53C974_local_declare(); + struct Scsi_Host *instance; + struct AM53C974_hostdata *hostdata; + unsigned char cmdreg, dmastatus, statreg, isreg, instreg, cfifo; /* find AM53C974 hostadapter responsible for this interrupt */ -for (instance = first_instance; instance; instance = instance->next) - if ((instance->irq == irq) && (instance->hostt == the_template)) goto FOUND; -sti(); -return; + for (instance = first_instance; instance; instance = instance->next) + if ((instance->irq == irq) && (instance->hostt == the_template)) + goto FOUND; + return; /* found; now decode and process */ -FOUND: -hostdata = (struct AM53C974_hostdata *)instance->hostdata; -AM53C974_setio(instance); -dmastatus = AM53C974_read_8(DMASTATUS); - -DEB_INTR(printk(SEPARATOR_LINE)); -DEB_INTR(printk("AM53C974 interrupt; dmastatus=0x%02x\n", dmastatus)); -KEYWAIT(); + FOUND: + hostdata = (struct AM53C974_hostdata *) instance->hostdata; + AM53C974_setio(instance); + dmastatus = AM53C974_read_8(DMASTATUS); + + DEB_INTR(printk(SEPARATOR_LINE)); + DEB_INTR(printk("AM53C974 interrupt; dmastatus=0x%02x\n", dmastatus)); + KEYWAIT(); /*** DMA related interrupts ***/ -if (hostdata->connected && (dmastatus & (DMASTATUS_ERROR | DMASTATUS_PWDN | - DMASTATUS_ABORT))) { - /* DMA error or POWERDOWN */ - printk("scsi%d: DMA error or powerdown; dmastatus: 0x%02x\n", - instance->host_no, dmastatus); + if (hostdata->connected && (dmastatus & (DMASTATUS_ERROR | DMASTATUS_PWDN | + DMASTATUS_ABORT))) { + /* DMA error or POWERDOWN */ + printk("scsi%d: DMA error or powerdown; dmastatus: 0x%02x\n", + instance->host_no, dmastatus); #ifdef AM53C974_DEBUG - deb_stop = 1; + deb_stop = 1; #endif - panic("scsi%d: cannot recover\n", instance->host_no); } - -if (hostdata->connected && (dmastatus & DMASTATUS_DONE)) { - /* DMA transfer done */ - unsigned long residual; - cli(); - if (!(AM53C974_read_8(DMACMD) & DMACMD_DIR)) { - do { - dmastatus = AM53C974_read_8(DMASTATUS); - residual = AM53C974_read_8(CTCLREG) | (AM53C974_read_8(CTCMREG) << 8) | - (AM53C974_read_8(CTCHREG) << 16); - residual += AM53C974_read_8(CFIREG) & CFIREG_CF; - } while (!(dmastatus & DMASTATUS_SCSIINT) && residual); - residual = AM53C974_read_8(CTCLREG) | (AM53C974_read_8(CTCMREG) << 8) | - (AM53C974_read_8(CTCHREG) << 16); - residual += AM53C974_read_8(CFIREG) & CFIREG_CF; - } - else - residual = 0; - hostdata->connected->SCp.ptr += hostdata->connected->SCp.this_residual - residual; - hostdata->connected->SCp.this_residual = residual; - - AM53C974_write_8(DMACMD, DMACMD_IDLE); - - /* if service request missed before, process it now (ugly) */ - if (hostdata->dma_busy) { - hostdata->dma_busy = 0; - cmdreg = AM53C974_read_8(CMDREG); - statreg = AM53C974_read_8(STATREG); - isreg = AM53C974_read_8(ISREG); - instreg = AM53C974_read_8(INSTREG); - cfifo = AM53C974_cfifo(); - AM53C974_information_transfer(instance, statreg, isreg, instreg, cfifo, - dmastatus); } - sti(); - } - -if (!(dmastatus & DMASTATUS_SCSIINT)) { - sti(); - return; } - + panic("scsi%d: cannot recover\n", instance->host_no); + } + if (hostdata->connected && (dmastatus & DMASTATUS_DONE)) { + /* DMA transfer done */ + unsigned long residual; + unsigned long flags; + save_flags(flags); + cli(); + if (!(AM53C974_read_8(DMACMD) & DMACMD_DIR)) { + do { + dmastatus = AM53C974_read_8(DMASTATUS); + residual = AM53C974_read_8(CTCLREG) | (AM53C974_read_8(CTCMREG) << 8) | + (AM53C974_read_8(CTCHREG) << 16); + residual += AM53C974_read_8(CFIREG) & CFIREG_CF; + } while (!(dmastatus & DMASTATUS_SCSIINT) && residual); + residual = AM53C974_read_8(CTCLREG) | (AM53C974_read_8(CTCMREG) << 8) | + (AM53C974_read_8(CTCHREG) << 16); + residual += AM53C974_read_8(CFIREG) & CFIREG_CF; + } else + residual = 0; + hostdata->connected->SCp.ptr += hostdata->connected->SCp.this_residual - residual; + hostdata->connected->SCp.this_residual = residual; + + AM53C974_write_8(DMACMD, DMACMD_IDLE); + + /* if service request missed before, process it now (ugly) */ + if (hostdata->dma_busy) { + hostdata->dma_busy = 0; + cmdreg = AM53C974_read_8(CMDREG); + statreg = AM53C974_read_8(STATREG); + isreg = AM53C974_read_8(ISREG); + instreg = AM53C974_read_8(INSTREG); + cfifo = AM53C974_cfifo(); + AM53C974_information_transfer(instance, statreg, isreg, instreg, cfifo, + dmastatus); + } + restore_flags(flags); + } + if (!(dmastatus & DMASTATUS_SCSIINT)) { + return; + } /*** SCSI related interrupts ***/ -cmdreg = AM53C974_read_8(CMDREG); -statreg = AM53C974_read_8(STATREG); -isreg = AM53C974_read_8(ISREG); -instreg = AM53C974_read_8(INSTREG); -cfifo = AM53C974_cfifo(); + cmdreg = AM53C974_read_8(CMDREG); + statreg = AM53C974_read_8(STATREG); + isreg = AM53C974_read_8(ISREG); + instreg = AM53C974_read_8(INSTREG); + cfifo = AM53C974_cfifo(); -DEB_INTR(printk("scsi%d: statreg: 0x%02x; isreg: 0x%02x; instreg: 0x%02x; cfifo: 0x%02x\n", - instance->host_no, statreg, isreg, instreg, cfifo)); + DEB_INTR(printk("scsi%d: statreg: 0x%02x; isreg: 0x%02x; instreg: 0x%02x; cfifo: 0x%02x\n", + instance->host_no, statreg, isreg, instreg, cfifo)); -if (statreg & STATREG_PE) { - /* parity error */ + if (statreg & STATREG_PE) { + /* parity error */ #ifdef AM53C974_DEBUG - deb_stop = 1; + deb_stop = 1; #endif - printk("scsi%d : PARITY error\n", instance->host_no); - if (hostdata->connected) hostdata->sync_off[hostdata->connected->target] = 0; /* setup asynchronous transfer */ - hostdata->aborted = 1; } - -if (statreg & STATREG_IOE) { - /* illegal operation error */ + printk("scsi%d : PARITY error\n", instance->host_no); + if (hostdata->connected) + hostdata->sync_off[hostdata->connected->target] = 0; /* setup asynchronous transfer */ + hostdata->aborted = 1; + } + if (statreg & STATREG_IOE) { + /* illegal operation error */ #ifdef AM53C974_DEBUG - deb_stop = 1; + deb_stop = 1; #endif - printk("scsi%d : ILLEGAL OPERATION error\n", instance->host_no); - printk("cmdreg: 0x%02x; dmacmd: 0x%02x; statreg: 0x%02x; \n" - "isreg: 0x%02x; instreg: 0x%02x; cfifo: 0x%02x\n", - cmdreg, AM53C974_read_8(DMACMD), statreg, isreg, instreg, cfifo); } -if (hostdata->in_reset && (instreg & INSTREG_SRST)) { - /* RESET INTERRUPT */ + printk("scsi%d : ILLEGAL OPERATION error\n", instance->host_no); + printk("cmdreg: 0x%02x; dmacmd: 0x%02x; statreg: 0x%02x; \n" + "isreg: 0x%02x; instreg: 0x%02x; cfifo: 0x%02x\n", + cmdreg, AM53C974_read_8(DMACMD), statreg, isreg, instreg, cfifo); + } + if (hostdata->in_reset && (instreg & INSTREG_SRST)) { + unsigned long flags; + /* RESET INTERRUPT */ #ifdef AM53C974_DEBUG - deb_stop = 1; + deb_stop = 1; #endif - DEB(printk("Bus reset interrupt received\n")); - AM53C974_intr_bus_reset(instance); - cli(); - if (hostdata->connected) { - hostdata->connected->result = DID_RESET << 16; - hostdata->connected->scsi_done((Scsi_Cmnd *)hostdata->connected); - hostdata->connected = NULL; } - else { - if (hostdata->sel_cmd) { - hostdata->sel_cmd->result = DID_RESET << 16; - hostdata->sel_cmd->scsi_done((Scsi_Cmnd *)hostdata->sel_cmd); - hostdata->sel_cmd = NULL; } - } - sti(); - if (hostdata->in_reset == 1) goto EXIT; - else return; - } - -if (instreg & INSTREG_ICMD) { - /* INVALID COMMAND INTERRUPT */ + DEB(printk("Bus reset interrupt received\n")); + AM53C974_intr_bus_reset(instance); + save_flags(flags); + cli(); + if (hostdata->connected) { + hostdata->connected->result = DID_RESET << 16; + hostdata->connected->scsi_done((Scsi_Cmnd *) hostdata->connected); + hostdata->connected = NULL; + } else { + if (hostdata->sel_cmd) { + hostdata->sel_cmd->result = DID_RESET << 16; + hostdata->sel_cmd->scsi_done((Scsi_Cmnd *) hostdata->sel_cmd); + hostdata->sel_cmd = NULL; + } + } + restore_flags(flags); + if (hostdata->in_reset == 1) + goto EXIT; + else + return; + } + if (instreg & INSTREG_ICMD) { + /* INVALID COMMAND INTERRUPT */ #ifdef AM53C974_DEBUG - deb_stop = 1; + deb_stop = 1; #endif - printk("scsi%d: Invalid command interrupt\n", instance->host_no); - printk("cmdreg: 0x%02x; dmacmd: 0x%02x; statreg: 0x%02x; dmastatus: 0x%02x; \n" - "isreg: 0x%02x; instreg: 0x%02x; cfifo: 0x%02x\n", - cmdreg, AM53C974_read_8(DMACMD), statreg, dmastatus, isreg, instreg, cfifo); - panic("scsi%d: cannot recover\n", instance->host_no); } - -if (instreg & INSTREG_DIS) { - /* DISCONNECT INTERRUPT */ - DEB_INTR(printk("Disconnect interrupt received; ")); - cli(); - AM53C974_intr_disconnect(instance); - sti(); - goto EXIT; } - -if (instreg & INSTREG_RESEL) { - /* RESELECTION INTERRUPT */ - DEB_INTR(printk("Reselection interrupt received\n")); - cli(); - AM53C974_intr_reselect(instance, statreg); - sti(); - goto EXIT; } - -if (instreg & INSTREG_SO) { - DEB_INTR(printk("Successful operation interrupt received\n")); - if (hostdata->selecting) { - DEB_INTR(printk("DSR completed, starting select\n")); - cli(); - AM53C974_select(instance, (Scsi_Cmnd *)hostdata->sel_cmd, - (hostdata->sel_cmd->cmnd[0] == REQUEST_SENSE) ? - TAG_NONE : TAG_NEXT); - hostdata->selecting = 0; - AM53C974_set_sync(instance, hostdata->sel_cmd->target); - sti(); - return; } - - if (hostdata->sel_cmd != NULL) { - if ( ((isreg & ISREG_IS) != ISREG_OK_NO_STOP) && - ((isreg & ISREG_IS) != ISREG_OK_STOP) ) { - /* UNSUCCESSFUL SELECTION */ - DEB_INTR(printk("unsuccessful selection\n")); - cli(); - hostdata->dma_busy = 0; - LIST(hostdata->sel_cmd, hostdata->issue_queue); - hostdata->sel_cmd->host_scribble = (unsigned char *)hostdata->issue_queue; - hostdata->issue_queue = hostdata->sel_cmd; - hostdata->sel_cmd = NULL; - hostdata->selecting = 0; - sti(); - goto EXIT; } - else { - /* SUCCESSFUL SELECTION */ - DEB(printk("successful selection; cmd=0x%02lx\n", (long)hostdata->sel_cmd)); - cli(); - hostdata->dma_busy = 0; - hostdata->disconnecting = 0; - hostdata->connected = hostdata->sel_cmd; - hostdata->sel_cmd = NULL; - hostdata->selecting = 0; + printk("scsi%d: Invalid command interrupt\n", instance->host_no); + printk("cmdreg: 0x%02x; dmacmd: 0x%02x; statreg: 0x%02x; dmastatus: 0x%02x; \n" + "isreg: 0x%02x; instreg: 0x%02x; cfifo: 0x%02x\n", + cmdreg, AM53C974_read_8(DMACMD), statreg, dmastatus, isreg, instreg, cfifo); + panic("scsi%d: cannot recover\n", instance->host_no); + } + if (instreg & INSTREG_DIS) { + unsigned long flags; + /* DISCONNECT INTERRUPT */ + DEB_INTR(printk("Disconnect interrupt received; ")); + save_flags(flags); + cli(); + AM53C974_intr_disconnect(instance); + restore_flags(flags); + goto EXIT; + } + if (instreg & INSTREG_RESEL) { + unsigned long flags; + /* RESELECTION INTERRUPT */ + DEB_INTR(printk("Reselection interrupt received\n")); + save_flags(flags); + cli(); + AM53C974_intr_reselect(instance, statreg); + restore_flags(flags); + goto EXIT; + } + if (instreg & INSTREG_SO) { + DEB_INTR(printk("Successful operation interrupt received\n")); + if (hostdata->selecting) { + unsigned long flags; + DEB_INTR(printk("DSR completed, starting select\n")); + save_flags(flags); + cli(); + AM53C974_select(instance, (Scsi_Cmnd *) hostdata->sel_cmd, + (hostdata->sel_cmd->cmnd[0] == REQUEST_SENSE) ? + TAG_NONE : TAG_NEXT); + hostdata->selecting = 0; + AM53C974_set_sync(instance, hostdata->sel_cmd->target); + restore_flags(flags); + return; + } + if (hostdata->sel_cmd != NULL) { + if (((isreg & ISREG_IS) != ISREG_OK_NO_STOP) && + ((isreg & ISREG_IS) != ISREG_OK_STOP)) { + unsigned long flags; + /* UNSUCCESSFUL SELECTION */ + DEB_INTR(printk("unsuccessful selection\n")); + save_flags(flags); + cli(); + hostdata->dma_busy = 0; + LIST(hostdata->sel_cmd, hostdata->issue_queue); + hostdata->sel_cmd->host_scribble = (unsigned char *) hostdata->issue_queue; + hostdata->issue_queue = hostdata->sel_cmd; + hostdata->sel_cmd = NULL; + hostdata->selecting = 0; + restore_flags(flags); + goto EXIT; + } else { + unsigned long flags; + /* SUCCESSFUL SELECTION */ + DEB(printk("successful selection; cmd=0x%02lx\n", (long) hostdata->sel_cmd)); + save_flags(flags); + cli(); + hostdata->dma_busy = 0; + hostdata->disconnecting = 0; + hostdata->connected = hostdata->sel_cmd; + hostdata->sel_cmd = NULL; + hostdata->selecting = 0; #ifdef SCSI2 - if (!hostdata->connected->device->tagged_queue) -#endif - hostdata->busy[hostdata->connected->target] |= (1 << hostdata->connected->lun); - /* very strange -- use_sg is sometimes nonzero for request sense commands !! */ - if ((hostdata->connected->cmnd[0] == REQUEST_SENSE) && hostdata->connected->use_sg) { - DEB(printk("scsi%d: REQUEST_SENSE command with nonzero use_sg\n", instance->host_no)); - KEYWAIT(); - hostdata->connected->use_sg = 0; } - initialize_SCp((Scsi_Cmnd *)hostdata->connected); - hostdata->connected->SCp.phase = PHASE_CMDOUT; - AM53C974_information_transfer(instance, statreg, isreg, instreg, cfifo, dmastatus); - sti(); - return; } - } - else { - cli(); - AM53C974_information_transfer(instance, statreg, isreg, instreg, cfifo, dmastatus); - sti(); - return; } - } - -if (instreg & INSTREG_SR) { - DEB_INTR(printk("Service request interrupt received, ")); - if (hostdata->connected) { - DEB_INTR(printk("calling information_transfer\n")); - cli(); - AM53C974_information_transfer(instance, statreg, isreg, instreg, cfifo, dmastatus); - sti(); } - else { - printk("scsi%d: weird: service request when no command connected\n", instance->host_no); - AM53C974_write_8(CMDREG, CMDREG_CFIFO); } /* clear FIFO */ - return; - } - -EXIT: - DEB_INTR(printk("intr: starting main\n")); - run_main(); - DEB_INTR(printk("end of intr\n")); + if (!hostdata->connected->device->tagged_queue) +#endif + hostdata->busy[hostdata->connected->target] |= (1 << hostdata->connected->lun); + /* very strange -- use_sg is sometimes nonzero for request sense commands !! */ + if ((hostdata->connected->cmnd[0] == REQUEST_SENSE) && hostdata->connected->use_sg) { + DEB(printk("scsi%d: REQUEST_SENSE command with nonzero use_sg\n", instance->host_no)); + KEYWAIT(); + hostdata->connected->use_sg = 0; + } + initialize_SCp((Scsi_Cmnd *) hostdata->connected); + hostdata->connected->SCp.phase = PHASE_CMDOUT; + AM53C974_information_transfer(instance, statreg, isreg, instreg, cfifo, dmastatus); + restore_flags(flags); + return; + } + } else { + unsigned long flags; + save_flags(flags); + cli(); + AM53C974_information_transfer(instance, statreg, isreg, instreg, cfifo, dmastatus); + restore_flags(flags); + return; + } + } + if (instreg & INSTREG_SR) { + DEB_INTR(printk("Service request interrupt received, ")); + if (hostdata->connected) { + unsigned long flags; + DEB_INTR(printk("calling information_transfer\n")); + save_flags(flags); + cli(); + AM53C974_information_transfer(instance, statreg, isreg, instreg, cfifo, dmastatus); + restore_flags(flags); + } else { + printk("scsi%d: weird: service request when no command connected\n", instance->host_no); + AM53C974_write_8(CMDREG, CMDREG_CFIFO); + } /* clear FIFO */ + return; + } + EXIT: + DEB_INTR(printk("intr: starting main\n")); + run_main(); + DEB_INTR(printk("end of intr\n")); } /************************************************************************** @@ -1242,114 +1312,120 @@ * * Returns : nothing **************************************************************************/ -static void AM53C974_intr_disconnect(struct Scsi_Host *instance) +static void AM53C974_intr_disconnect(struct Scsi_Host *instance) { -AM53C974_local_declare(); -struct AM53C974_hostdata *hostdata = (struct AM53C974_hostdata *)instance->hostdata; -Scsi_Cmnd *cmd; -AM53C974_setio(instance); - -if (hostdata->sel_cmd != NULL) { - /* normal selection timeout, typical for nonexisting targets */ - cmd = (Scsi_Cmnd *)hostdata->sel_cmd; - DEB_INTR(printk("bad target\n")); - cmd->result = DID_BAD_TARGET << 16; - goto EXIT_FINISHED; } - -if (!hostdata->connected) { - /* can happen if controller was reset, a device tried to reconnect, - failed and disconnects now */ - AM53C974_write_8(CMDREG, CMDREG_CFIFO); - return; } - -if (hostdata->disconnecting) { - /* target sent disconnect message, so we are prepared */ - cmd = (Scsi_Cmnd *)hostdata->connected; - AM53C974_set_async(instance, cmd->target); - DEB_INTR(printk("scsi%d : disc. from cmnd %d for ta %d, lun %d\n", - instance->host_no, cmd->cmnd[0], cmd->target, cmd->lun)); - if (cmd->device->disconnect) { - /* target wants to reselect later */ - DEB_INTR(printk("ok, re-enabling selection\n")); - LIST(cmd,hostdata->disconnected_queue); - cmd->host_scribble = (unsigned char *)hostdata->disconnected_queue; - hostdata->disconnected_queue = cmd; - DEB_QUEUE(printk("scsi%d : command for target %d lun %d this %d was moved from connected to" - " the disconnected_queue\n", instance->host_no, cmd->target, - cmd->lun, hostdata->disconnected_queue->SCp.this_residual)); - DEB_QUEUE(AM53C974_print_queues(instance)); - goto EXIT_UNFINISHED; } - else { - /* target does not want to reselect later, we are really finished */ + AM53C974_local_declare(); + struct AM53C974_hostdata *hostdata = (struct AM53C974_hostdata *) instance->hostdata; + Scsi_Cmnd *cmd; + AM53C974_setio(instance); + + if (hostdata->sel_cmd != NULL) { + /* normal selection timeout, typical for nonexisting targets */ + cmd = (Scsi_Cmnd *) hostdata->sel_cmd; + DEB_INTR(printk("bad target\n")); + cmd->result = DID_BAD_TARGET << 16; + goto EXIT_FINISHED; + } + if (!hostdata->connected) { + /* can happen if controller was reset, a device tried to reconnect, + failed and disconnects now */ + AM53C974_write_8(CMDREG, CMDREG_CFIFO); + return; + } + if (hostdata->disconnecting) { + /* target sent disconnect message, so we are prepared */ + cmd = (Scsi_Cmnd *) hostdata->connected; + AM53C974_set_async(instance, cmd->target); + DEB_INTR(printk("scsi%d : disc. from cmnd %d for ta %d, lun %d\n", + instance->host_no, cmd->cmnd[0], cmd->target, cmd->lun)); + if (cmd->device->disconnect) { + /* target wants to reselect later */ + DEB_INTR(printk("ok, re-enabling selection\n")); + LIST(cmd, hostdata->disconnected_queue); + cmd->host_scribble = (unsigned char *) hostdata->disconnected_queue; + hostdata->disconnected_queue = cmd; + DEB_QUEUE(printk("scsi%d : command for target %d lun %d this %d was moved from connected to" + " the disconnected_queue\n", instance->host_no, cmd->target, + cmd->lun, hostdata->disconnected_queue->SCp.this_residual)); + DEB_QUEUE(AM53C974_print_queues(instance)); + goto EXIT_UNFINISHED; + } else { + /* target does not want to reselect later, we are really finished */ #ifdef AM53C974_DEBUG - if (cmd->cmnd[0] == REQUEST_SENSE) { - int i; - printk("Request sense data dump:\n"); - for (i = 0; i < cmd->request_bufflen; i++) { - printk("%02x ", *((char *)(cmd->request_buffer) + i)); - if (i && !(i % 16)) printk("\n"); } - printk("\n"); } -#endif - goto EXIT_FINISHED; } /* !cmd->device->disconnect */ - } /* if (hostdata->disconnecting) */ - -/* no disconnect message received; unexpected disconnection */ -cmd = (Scsi_Cmnd *)hostdata->connected; -if (cmd) { + if (cmd->cmnd[0] == REQUEST_SENSE) { + int i; + printk("Request sense data dump:\n"); + for (i = 0; i < cmd->request_bufflen; i++) { + printk("%02x ", *((char *) (cmd->request_buffer) + i)); + if (i && !(i % 16)) + printk("\n"); + } + printk("\n"); + } +#endif + goto EXIT_FINISHED; + } /* !cmd->device->disconnect */ + } /* if (hostdata->disconnecting) */ + /* no disconnect message received; unexpected disconnection */ + cmd = (Scsi_Cmnd *) hostdata->connected; + if (cmd) { #ifdef AM53C974_DEBUG - deb_stop = 1; + deb_stop = 1; #endif - AM53C974_set_async(instance, cmd->target); - printk("scsi%d: Unexpected disconnect; phase: %d; target: %d; this_residual: %d; buffers_residual: %d; message: %d\n", - instance->host_no, cmd->SCp.phase, cmd->target, cmd->SCp.this_residual, cmd->SCp.buffers_residual, - cmd->SCp.Message); - printk("cmdreg: 0x%02x; statreg: 0x%02x; isreg: 0x%02x; cfifo: 0x%02x\n", - AM53C974_read_8(CMDREG), AM53C974_read_8(STATREG), AM53C974_read_8(ISREG), - AM53C974_read_8(CFIREG) & CFIREG_CF); - - if ((hostdata->last_message[0] == EXTENDED_MESSAGE) && - (hostdata->last_message[2] == EXTENDED_SDTR)) { - /* sync. negotiation was aborted, setup asynchronous transfer with target */ - hostdata->sync_off[cmd->target] = 0; } - if (hostdata->aborted || hostdata->msgout[0] == ABORT) - cmd->result = DID_ABORT << 16; - else - cmd->result = DID_ERROR << 16; - goto EXIT_FINISHED; } - -EXIT_FINISHED: -hostdata->aborted = 0; -hostdata->msgout[0] = NOP; -hostdata->sel_cmd = NULL; -hostdata->connected = NULL; -hostdata->selecting = 0; -hostdata->disconnecting = 0; -hostdata->dma_busy = 0; -hostdata->busy[cmd->target] &= ~(1 << cmd->lun); -AM53C974_write_8(CMDREG, CMDREG_CFIFO); -DEB(printk("disconnect; issue_queue: 0x%lx, disconnected_queue: 0x%lx\n", - (long)hostdata->issue_queue, (long)hostdata->disconnected_queue)); -cmd->scsi_done(cmd); - -if (!hostdata->selecting) { - AM53C974_set_async(instance, cmd->target); - AM53C974_write_8(CMDREG, CMDREG_ESR); } /* allow reselect */ -return; - -EXIT_UNFINISHED: -hostdata->msgout[0] = NOP; -hostdata->sel_cmd = NULL; -hostdata->connected = NULL; -hostdata->aborted = 0; -hostdata->selecting = 0; -hostdata->disconnecting = 0; -hostdata->dma_busy = 0; -DEB(printk("disconnect; issue_queue: 0x%lx, disconnected_queue: 0x%lx\n", - (long)hostdata->issue_queue, (long)hostdata->disconnected_queue)); -if (!hostdata->selecting) { - AM53C974_set_async(instance, cmd->target); - AM53C974_write_8(CMDREG, CMDREG_ESR); } /* allow reselect */ -return; + AM53C974_set_async(instance, cmd->target); + printk("scsi%d: Unexpected disconnect; phase: %d; target: %d; this_residual: %d; buffers_residual: %d; message: %d\n", + instance->host_no, cmd->SCp.phase, cmd->target, cmd->SCp.this_residual, cmd->SCp.buffers_residual, + cmd->SCp.Message); + printk("cmdreg: 0x%02x; statreg: 0x%02x; isreg: 0x%02x; cfifo: 0x%02x\n", + AM53C974_read_8(CMDREG), AM53C974_read_8(STATREG), AM53C974_read_8(ISREG), + AM53C974_read_8(CFIREG) & CFIREG_CF); + + if ((hostdata->last_message[0] == EXTENDED_MESSAGE) && + (hostdata->last_message[2] == EXTENDED_SDTR)) { + /* sync. negotiation was aborted, setup asynchronous transfer with target */ + hostdata->sync_off[cmd->target] = 0; + } + if (hostdata->aborted || hostdata->msgout[0] == ABORT) + cmd->result = DID_ABORT << 16; + else + cmd->result = DID_ERROR << 16; + goto EXIT_FINISHED; + } + EXIT_FINISHED: + hostdata->aborted = 0; + hostdata->msgout[0] = NOP; + hostdata->sel_cmd = NULL; + hostdata->connected = NULL; + hostdata->selecting = 0; + hostdata->disconnecting = 0; + hostdata->dma_busy = 0; + hostdata->busy[cmd->target] &= ~(1 << cmd->lun); + AM53C974_write_8(CMDREG, CMDREG_CFIFO); + DEB(printk("disconnect; issue_queue: 0x%lx, disconnected_queue: 0x%lx\n", + (long) hostdata->issue_queue, (long) hostdata->disconnected_queue)); + cmd->scsi_done(cmd); + + if (!hostdata->selecting) { + AM53C974_set_async(instance, cmd->target); + AM53C974_write_8(CMDREG, CMDREG_ESR); + } /* allow reselect */ + return; + + EXIT_UNFINISHED: + hostdata->msgout[0] = NOP; + hostdata->sel_cmd = NULL; + hostdata->connected = NULL; + hostdata->aborted = 0; + hostdata->selecting = 0; + hostdata->disconnecting = 0; + hostdata->dma_busy = 0; + DEB(printk("disconnect; issue_queue: 0x%lx, disconnected_queue: 0x%lx\n", + (long) hostdata->issue_queue, (long) hostdata->disconnected_queue)); + if (!hostdata->selecting) { + AM53C974_set_async(instance, cmd->target); + AM53C974_write_8(CMDREG, CMDREG_ESR); + } /* allow reselect */ + return; } /************************************************************************** @@ -1367,41 +1443,43 @@ * * Note: we assume here that fastclk is enabled **************************************************************************/ -static int AM53C974_sync_neg(struct Scsi_Host *instance, int target, unsigned char *msg) +static int AM53C974_sync_neg(struct Scsi_Host *instance, int target, unsigned char *msg) { -AM53C974_local_declare(); -struct AM53C974_hostdata *hostdata = (struct AM53C974_hostdata *)instance->hostdata; -int period, offset, i, rate, rate_rem; -AM53C974_setio(instance); - -period = (DEF_CLK * msg[3] * 8 + 1000) / 2000; -if (period < MIN_PERIOD) { - period = MIN_PERIOD; - hostdata->msgout[3] = period / 4; } - else - if (period > MAX_PERIOD) { - period = MAX_PERIOD; - hostdata->msgout[3] = period / 4; } - else - hostdata->msgout[3] = msg[3]; -offset = msg[4]; -if (offset > MAX_OFFSET) offset = MAX_OFFSET; -hostdata->msgout[4] = offset; -hostdata->sync_per[target] = period; -hostdata->sync_off[target] = offset; -for (i = 0; i < 3; i++) hostdata->msgout[i] = msg[i]; -if ((hostdata->msgout[3] != msg[3]) || (msg[4] != offset)) return(1); - -rate = DEF_CLK / period; -rate_rem = 10 * (DEF_CLK - period * rate) / period; - -if (offset) - printk("\ntarget %d: rate=%d.%d Mhz, synchronous, sync offset=%d bytes\n", - target, rate, rate_rem, offset); - else - printk("\ntarget %d: rate=%d.%d Mhz, asynchronous\n", target, rate, rate_rem); + AM53C974_local_declare(); + struct AM53C974_hostdata *hostdata = (struct AM53C974_hostdata *) instance->hostdata; + int period, offset, i, rate, rate_rem; + AM53C974_setio(instance); + + period = (DEF_CLK * msg[3] * 8 + 1000) / 2000; + if (period < MIN_PERIOD) { + period = MIN_PERIOD; + hostdata->msgout[3] = period / 4; + } else if (period > MAX_PERIOD) { + period = MAX_PERIOD; + hostdata->msgout[3] = period / 4; + } else + hostdata->msgout[3] = msg[3]; + offset = msg[4]; + if (offset > MAX_OFFSET) + offset = MAX_OFFSET; + hostdata->msgout[4] = offset; + hostdata->sync_per[target] = period; + hostdata->sync_off[target] = offset; + for (i = 0; i < 3; i++) + hostdata->msgout[i] = msg[i]; + if ((hostdata->msgout[3] != msg[3]) || (msg[4] != offset)) + return (1); + + rate = DEF_CLK / period; + rate_rem = 10 * (DEF_CLK - period * rate) / period; + + if (offset) + printk("\ntarget %d: rate=%d.%d Mhz, synchronous, sync offset=%d bytes\n", + target, rate, rate_rem, offset); + else + printk("\ntarget %d: rate=%d.%d Mhz, asynchronous\n", target, rate, rate_rem); -return(0); + return (0); } /************************************************************************** @@ -1416,12 +1494,12 @@ **************************************************************************/ static __inline__ void AM53C974_set_async(struct Scsi_Host *instance, int target) { -AM53C974_local_declare(); -struct AM53C974_hostdata *hostdata = (struct AM53C974_hostdata *)instance->hostdata; -AM53C974_setio(instance); + AM53C974_local_declare(); + struct AM53C974_hostdata *hostdata = (struct AM53C974_hostdata *) instance->hostdata; + AM53C974_setio(instance); -AM53C974_write_8(STPREG, hostdata->sync_per[target]); -AM53C974_write_8(SOFREG, (DEF_SOF_RAD<<6) | (DEF_SOF_RAA<<4)); + AM53C974_write_8(STPREG, hostdata->sync_per[target]); + AM53C974_write_8(SOFREG, (DEF_SOF_RAD << 6) | (DEF_SOF_RAA << 4)); } /************************************************************************** @@ -1436,13 +1514,13 @@ **************************************************************************/ static __inline__ void AM53C974_set_sync(struct Scsi_Host *instance, int target) { -AM53C974_local_declare(); -struct AM53C974_hostdata *hostdata = (struct AM53C974_hostdata *)instance->hostdata; -AM53C974_setio(instance); - -AM53C974_write_8(STPREG, hostdata->sync_per[target]); -AM53C974_write_8(SOFREG, (SOFREG_SO & hostdata->sync_off[target]) | - (DEF_SOF_RAD<<6) | (DEF_SOF_RAA<<4)); + AM53C974_local_declare(); + struct AM53C974_hostdata *hostdata = (struct AM53C974_hostdata *) instance->hostdata; + AM53C974_setio(instance); + + AM53C974_write_8(STPREG, hostdata->sync_per[target]); + AM53C974_write_8(SOFREG, (SOFREG_SO & hostdata->sync_off[target]) | + (DEF_SOF_RAD << 6) | (DEF_SOF_RAA << 4)); } /*********************************************************************** @@ -1462,151 +1540,164 @@ * * * Returns : nothing * ************************************************************************/ -static void AM53C974_information_transfer(struct Scsi_Host *instance, - unsigned char statreg, unsigned char isreg, - unsigned char instreg, unsigned char cfifo, - unsigned char dmastatus) -{ -AM53C974_local_declare(); -struct AM53C974_hostdata *hostdata = (struct AM53C974_hostdata *)instance->hostdata; -Scsi_Cmnd *cmd = (Scsi_Cmnd *)hostdata->connected; -int ret, i, len, residual=-1; -AM53C974_setio(instance); - -DEB_INFO(printk(SEPARATOR_LINE)); -switch (statreg & STATREG_PHASE) { /* scsi phase */ - case PHASE_DATAOUT: - DEB_INFO(printk("Dataout phase; cmd=0x%lx, sel_cmd=0x%lx, this_residual=%d, buffers_residual=%d\n", - (long)hostdata->connected, (long)hostdata->sel_cmd, cmd->SCp.this_residual, cmd->SCp.buffers_residual)); - cmd->SCp.phase = PHASE_DATAOUT; - goto PHASE_DATA_IO; - - case PHASE_DATAIN: - DEB_INFO(printk("Datain phase; cmd=0x%lx, sel_cmd=0x%lx, this_residual=%d, buffers_residual=%d\n", - (long)hostdata->connected, (long)hostdata->sel_cmd, cmd->SCp.this_residual, cmd->SCp.buffers_residual)); - cmd->SCp.phase = PHASE_DATAIN; - PHASE_DATA_IO: - if (hostdata->aborted) { - AM53C974_write_8(DMACMD, DMACMD_IDLE); - AM53C974_write_8(CMDREG, CMDREG_CFIFO); - AM53C974_write_8(CMDREG, CMDREG_SATN); - return; } - if ((!cmd->SCp.this_residual) && cmd->SCp.buffers_residual) { - cmd->SCp.buffer++; - cmd->SCp.buffers_residual--; - cmd->SCp.ptr = (unsigned char *)cmd->SCp.buffer->address; - cmd->SCp.this_residual = cmd->SCp.buffer->length; } - if (cmd->SCp.this_residual) { - if (!(AM53C974_read_8(DMACMD) & DMACMD_START)) { - hostdata->dma_busy = 0; - AM53C974_transfer_dma(instance, statreg & STATREG_IO, - (unsigned long)cmd->SCp.this_residual, - cmd->SCp.ptr); } - else - hostdata->dma_busy = 1; - } - return; - - case PHASE_MSGIN: - DEB_INFO(printk("Message-In phase; cmd=0x%lx, sel_cmd=0x%lx\n", - (long)hostdata->connected, (long)hostdata->sel_cmd)); - AM53C974_set_async(instance, cmd->target); - if (cmd->SCp.phase == PHASE_DATAIN) - AM53C974_dma_blast(instance, dmastatus, statreg); - if ((cmd->SCp.phase == PHASE_DATAOUT) && (AM53C974_read_8(DMACMD) & DMACMD_START)) { - AM53C974_write_8(DMACMD, DMACMD_IDLE); - residual = cfifo + (AM53C974_read_8(CTCLREG) | (AM53C974_read_8(CTCMREG) << 8) | - (AM53C974_read_8(CTCHREG) << 16)); - cmd->SCp.ptr += cmd->SCp.this_residual - residual; - cmd->SCp.this_residual = residual; - if (cfifo) { AM53C974_write_8(CMDREG, CMDREG_CFIFO); cfifo = 0; } - } - if (cmd->SCp.phase == PHASE_STATIN) { - while ((AM53C974_read_8(CFIREG) & CFIREG_CF) < 2) ; - cmd->SCp.Status = AM53C974_read_8(FFREG); - cmd->SCp.Message = AM53C974_read_8(FFREG); - DEB_INFO(printk("Message-In phase; status=0x%02x, message=0x%02x\n", - cmd->SCp.Status, cmd->SCp.Message)); - ret = AM53C974_message(instance, cmd, cmd->SCp.Message); } - else { - if (!cfifo) { - AM53C974_write_8(CMDREG, CMDREG_IT); - AM53C974_poll_int(); - cmd->SCp.Message = AM53C974_read_8(FFREG); - } - ret = AM53C974_message(instance, cmd, cmd->SCp.Message); - } - cmd->SCp.phase = PHASE_MSGIN; - AM53C974_set_sync(instance, cmd->target); - break; - case PHASE_MSGOUT: - DEB_INFO(printk("Message-Out phase; cfifo=%d; msgout[0]=0x%02x\n", - AM53C974_read_8(CFIREG) & CFIREG_CF, hostdata->msgout[0])); - AM53C974_write_8(DMACMD, DMACMD_IDLE); - AM53C974_set_async(instance, cmd->target); - for (i = 0; i < sizeof(hostdata->last_message); i++) - hostdata->last_message[i] = hostdata->msgout[i]; - if ((hostdata->msgout[0] == 0) || INSIDE(hostdata->msgout[0], 0x02, 0x1F) || - INSIDE(hostdata->msgout[0], 0x80, 0xFF)) - len = 1; - else { - if (hostdata->msgout[0] == EXTENDED_MESSAGE) { +static void AM53C974_information_transfer(struct Scsi_Host *instance, + unsigned char statreg, unsigned char isreg, + unsigned char instreg, unsigned char cfifo, + unsigned char dmastatus) +{ + AM53C974_local_declare(); + struct AM53C974_hostdata *hostdata = (struct AM53C974_hostdata *) instance->hostdata; + Scsi_Cmnd *cmd = (Scsi_Cmnd *) hostdata->connected; + int ret, i, len, residual = -1; + AM53C974_setio(instance); + + DEB_INFO(printk(SEPARATOR_LINE)); + switch (statreg & STATREG_PHASE) { /* scsi phase */ + case PHASE_DATAOUT: + DEB_INFO(printk("Dataout phase; cmd=0x%lx, sel_cmd=0x%lx, this_residual=%d, buffers_residual=%d\n", + (long) hostdata->connected, (long) hostdata->sel_cmd, cmd->SCp.this_residual, cmd->SCp.buffers_residual)); + cmd->SCp.phase = PHASE_DATAOUT; + goto PHASE_DATA_IO; + + case PHASE_DATAIN: + DEB_INFO(printk("Datain phase; cmd=0x%lx, sel_cmd=0x%lx, this_residual=%d, buffers_residual=%d\n", + (long) hostdata->connected, (long) hostdata->sel_cmd, cmd->SCp.this_residual, cmd->SCp.buffers_residual)); + cmd->SCp.phase = PHASE_DATAIN; + PHASE_DATA_IO: + if (hostdata->aborted) { + AM53C974_write_8(DMACMD, DMACMD_IDLE); + AM53C974_write_8(CMDREG, CMDREG_CFIFO); + AM53C974_write_8(CMDREG, CMDREG_SATN); + return; + } + if ((!cmd->SCp.this_residual) && cmd->SCp.buffers_residual) { + cmd->SCp.buffer++; + cmd->SCp.buffers_residual--; + cmd->SCp.ptr = (unsigned char *) cmd->SCp.buffer->address; + cmd->SCp.this_residual = cmd->SCp.buffer->length; + } + if (cmd->SCp.this_residual) { + if (!(AM53C974_read_8(DMACMD) & DMACMD_START)) { + hostdata->dma_busy = 0; + AM53C974_transfer_dma(instance, statreg & STATREG_IO, + (unsigned long) cmd->SCp.this_residual, + cmd->SCp.ptr); + } else + hostdata->dma_busy = 1; + } + return; + + case PHASE_MSGIN: + DEB_INFO(printk("Message-In phase; cmd=0x%lx, sel_cmd=0x%lx\n", + (long) hostdata->connected, (long) hostdata->sel_cmd)); + AM53C974_set_async(instance, cmd->target); + if (cmd->SCp.phase == PHASE_DATAIN) + AM53C974_dma_blast(instance, dmastatus, statreg); + if ((cmd->SCp.phase == PHASE_DATAOUT) && (AM53C974_read_8(DMACMD) & DMACMD_START)) { + AM53C974_write_8(DMACMD, DMACMD_IDLE); + residual = cfifo + (AM53C974_read_8(CTCLREG) | (AM53C974_read_8(CTCMREG) << 8) | + (AM53C974_read_8(CTCHREG) << 16)); + cmd->SCp.ptr += cmd->SCp.this_residual - residual; + cmd->SCp.this_residual = residual; + if (cfifo) { + AM53C974_write_8(CMDREG, CMDREG_CFIFO); + cfifo = 0; + } + } + if (cmd->SCp.phase == PHASE_STATIN) { + while ((AM53C974_read_8(CFIREG) & CFIREG_CF) < 2); + cmd->SCp.Status = AM53C974_read_8(FFREG); + cmd->SCp.Message = AM53C974_read_8(FFREG); + DEB_INFO(printk("Message-In phase; status=0x%02x, message=0x%02x\n", + cmd->SCp.Status, cmd->SCp.Message)); + ret = AM53C974_message(instance, cmd, cmd->SCp.Message); + } else { + if (!cfifo) { + AM53C974_write_8(CMDREG, CMDREG_IT); + AM53C974_poll_int(); + cmd->SCp.Message = AM53C974_read_8(FFREG); + } + ret = AM53C974_message(instance, cmd, cmd->SCp.Message); + } + cmd->SCp.phase = PHASE_MSGIN; + AM53C974_set_sync(instance, cmd->target); + break; + case PHASE_MSGOUT: + DEB_INFO(printk("Message-Out phase; cfifo=%d; msgout[0]=0x%02x\n", + AM53C974_read_8(CFIREG) & CFIREG_CF, hostdata->msgout[0])); + AM53C974_write_8(DMACMD, DMACMD_IDLE); + AM53C974_set_async(instance, cmd->target); + for (i = 0; i < sizeof(hostdata->last_message); i++) + hostdata->last_message[i] = hostdata->msgout[i]; + if ((hostdata->msgout[0] == 0) || INSIDE(hostdata->msgout[0], 0x02, 0x1F) || + INSIDE(hostdata->msgout[0], 0x80, 0xFF)) + len = 1; + else { + if (hostdata->msgout[0] == EXTENDED_MESSAGE) { #ifdef AM53C974_DEBUG_INFO - printk("Extended message dump:\n"); - for (i = 0; i < hostdata->msgout[1] + 2; i++) { - printk("%02x ", hostdata->msgout[i]); - if (i && !(i % 16)) printk("\n"); } - printk("\n"); -#endif - len = hostdata->msgout[1] + 2; } - else - len = 2; - } - for (i = 0; i < len; i++) AM53C974_write_8(FFREG, hostdata->msgout[i]); - AM53C974_write_8(CMDREG, CMDREG_IT); - cmd->SCp.phase = PHASE_MSGOUT; - hostdata->msgout[0] = NOP; - AM53C974_set_sync(instance, cmd->target); - break; - - case PHASE_CMDOUT: - DEB_INFO(printk("Command-Out phase\n")); - AM53C974_set_async(instance, cmd->target); - for (i = 0; i < cmd->cmd_len; i++) AM53C974_write_8(FFREG, cmd->cmnd[i]); - AM53C974_write_8(CMDREG, CMDREG_IT); - cmd->SCp.phase = PHASE_CMDOUT; - AM53C974_set_sync(instance, cmd->target); - break; - - case PHASE_STATIN: - DEB_INFO(printk("Status phase\n")); - if (cmd->SCp.phase == PHASE_DATAIN) - AM53C974_dma_blast(instance, dmastatus, statreg); - AM53C974_set_async(instance, cmd->target); - if (cmd->SCp.phase == PHASE_DATAOUT) { - unsigned long residual; - - if (AM53C974_read_8(DMACMD) & DMACMD_START) { - AM53C974_write_8(DMACMD, DMACMD_IDLE); - residual = cfifo + (AM53C974_read_8(CTCLREG) | (AM53C974_read_8(CTCMREG) << 8) | - (AM53C974_read_8(CTCHREG) << 16)); - cmd->SCp.ptr += cmd->SCp.this_residual - residual; - cmd->SCp.this_residual = residual; } - if (cfifo) { AM53C974_write_8(CMDREG, CMDREG_CFIFO); cfifo = 0; } - } - cmd->SCp.phase = PHASE_STATIN; - AM53C974_write_8(CMDREG, CMDREG_ICCS); /* command complete */ - break; + printk("Extended message dump:\n"); + for (i = 0; i < hostdata->msgout[1] + 2; i++) { + printk("%02x ", hostdata->msgout[i]); + if (i && !(i % 16)) + printk("\n"); + } + printk("\n"); +#endif + len = hostdata->msgout[1] + 2; + } else + len = 2; + } + for (i = 0; i < len; i++) + AM53C974_write_8(FFREG, hostdata->msgout[i]); + AM53C974_write_8(CMDREG, CMDREG_IT); + cmd->SCp.phase = PHASE_MSGOUT; + hostdata->msgout[0] = NOP; + AM53C974_set_sync(instance, cmd->target); + break; + + case PHASE_CMDOUT: + DEB_INFO(printk("Command-Out phase\n")); + AM53C974_set_async(instance, cmd->target); + for (i = 0; i < cmd->cmd_len; i++) + AM53C974_write_8(FFREG, cmd->cmnd[i]); + AM53C974_write_8(CMDREG, CMDREG_IT); + cmd->SCp.phase = PHASE_CMDOUT; + AM53C974_set_sync(instance, cmd->target); + break; + + case PHASE_STATIN: + DEB_INFO(printk("Status phase\n")); + if (cmd->SCp.phase == PHASE_DATAIN) + AM53C974_dma_blast(instance, dmastatus, statreg); + AM53C974_set_async(instance, cmd->target); + if (cmd->SCp.phase == PHASE_DATAOUT) { + unsigned long residual; + + if (AM53C974_read_8(DMACMD) & DMACMD_START) { + AM53C974_write_8(DMACMD, DMACMD_IDLE); + residual = cfifo + (AM53C974_read_8(CTCLREG) | (AM53C974_read_8(CTCMREG) << 8) | + (AM53C974_read_8(CTCHREG) << 16)); + cmd->SCp.ptr += cmd->SCp.this_residual - residual; + cmd->SCp.this_residual = residual; + } + if (cfifo) { + AM53C974_write_8(CMDREG, CMDREG_CFIFO); + cfifo = 0; + } + } + cmd->SCp.phase = PHASE_STATIN; + AM53C974_write_8(CMDREG, CMDREG_ICCS); /* command complete */ + break; - case PHASE_RES_0: - case PHASE_RES_1: + case PHASE_RES_0: + case PHASE_RES_1: #ifdef AM53C974_DEBUG - deb_stop = 1; + deb_stop = 1; #endif - DEB_INFO(printk("Reserved phase\n")); - break; - } -KEYWAIT(); + DEB_INFO(printk("Reserved phase\n")); + break; + } + KEYWAIT(); } /****************************************************************************** @@ -1621,21 +1712,21 @@ * * Returns : 1 on success, 0 on failure. **************************************************************************/ -static int AM53C974_message(struct Scsi_Host *instance, Scsi_Cmnd *cmd, - unsigned char msg) +static int AM53C974_message(struct Scsi_Host *instance, Scsi_Cmnd * cmd, + unsigned char msg) { -AM53C974_local_declare(); -static unsigned char extended_msg[10]; -unsigned char statreg; -int len, ret = 0; -unsigned char *p; + AM53C974_local_declare(); + static unsigned char extended_msg[10]; + unsigned char statreg; + int len, ret = 0; + unsigned char *p; #ifdef AM53C974_DEBUG_MSG -int j; + int j; #endif -struct AM53C974_hostdata *hostdata = (struct AM53C974_hostdata *)instance->hostdata; -AM53C974_setio(instance); + struct AM53C974_hostdata *hostdata = (struct AM53C974_hostdata *) instance->hostdata; + AM53C974_setio(instance); -DEB_MSG(printk(SEPARATOR_LINE)); + DEB_MSG(printk(SEPARATOR_LINE)); /* Linking lets us reduce the time required to get the * next command out to the device, hopefully this will @@ -1644,206 +1735,217 @@ * In the current implementation proposal, low level drivers * merely have to start the next command, pointed to by * next_link, done() is called as with unlinked commands. */ -switch (msg) { + switch (msg) { #ifdef LINKED - case LINKED_CMD_COMPLETE: - case LINKED_FLG_CMD_COMPLETE: - /* Accept message by releasing ACK */ - DEB_LINKED(printk("scsi%d : target %d lun %d linked command complete.\n", - instance->host_no, cmd->target, cmd->lun)); - /* Sanity check : A linked command should only terminate with - * one of these messages if there are more linked commands available. */ - if (!cmd->next_link) { - printk("scsi%d : target %d lun %d linked command complete, no next_link\n" - instance->host_no, cmd->target, cmd->lun); - hostdata->aborted = 1; - AM53C974_write_8(CMDREG, CMDREG_SATN); - AM53C974_write_8(CMDREG, CMDREG_MA); - break; } - if (hostdata->aborted) { - DEB_ABORT(printk("ATN set for cmnd %d upon reception of LINKED_CMD_COMPLETE or" - "LINKED_FLG_CMD_COMPLETE message\n", cmd->cmnd[0])); - AM53C974_write_8(CMDREG, CMDREG_SATN); } - AM53C974_write_8(CMDREG, CMDREG_MA); - - initialize_SCp(cmd->next_link); - /* The next command is still part of this process */ - cmd->next_link->tag = cmd->tag; - cmd->result = cmd->SCp.Status | (cmd->SCp.Message << 8); - DEB_LINKED(printk("scsi%d : target %d lun %d linked request done, calling scsi_done().\n", - instance->host_no, cmd->target, cmd->lun)); - cmd->scsi_done(cmd); - cmd = hostdata->connected; - break; - -#endif /* def LINKED */ - - case ABORT: - case COMMAND_COMPLETE: - DEB_MSG(printk("scsi%d: command complete message received; cmd %d for target %d, lun %d\n", - instance->host_no, cmd->cmnd[0], cmd->target, cmd->lun)); - hostdata->disconnecting = 1; - cmd->device->disconnect = 0; - - /* I'm not sure what the correct thing to do here is : - * - * If the command that just executed is NOT a request - * sense, the obvious thing to do is to set the result - * code to the values of the stored parameters. - * If it was a REQUEST SENSE command, we need some way - * to differentiate between the failure code of the original - * and the failure code of the REQUEST sense - the obvious - * case is success, where we fall through and leave the result - * code unchanged. - * - * The non-obvious place is where the REQUEST SENSE failed */ - if (cmd->cmnd[0] != REQUEST_SENSE) - cmd->result = cmd->SCp.Status | (cmd->SCp.Message << 8); - else if (cmd->SCp.Status != GOOD) - cmd->result = (cmd->result & 0x00ffff) | (DID_ERROR << 16); - if (hostdata->aborted) { - AM53C974_write_8(CMDREG, CMDREG_SATN); - AM53C974_write_8(CMDREG, CMDREG_MA); - DEB_ABORT(printk("ATN set for cmnd %d upon reception of ABORT or" - "COMMAND_COMPLETE message\n", cmd->cmnd[0])); - break; } - if ((cmd->cmnd[0] != REQUEST_SENSE) && (cmd->SCp.Status == CHECK_CONDITION)) { - DEB_MSG(printk("scsi%d : performing request sense\n", instance->host_no)); - cmd->cmnd[0] = REQUEST_SENSE; - cmd->cmnd[1] &= 0xe0; - cmd->cmnd[2] = 0; - cmd->cmnd[3] = 0; - cmd->cmnd[4] = sizeof(cmd->sense_buffer); - cmd->cmnd[5] = 0; - cmd->SCp.buffer = NULL; - cmd->SCp.buffers_residual = 0; - cmd->SCp.ptr = (char *)cmd->sense_buffer; - cmd->SCp.this_residual = sizeof(cmd->sense_buffer); - LIST(cmd,hostdata->issue_queue); - cmd->host_scribble = (unsigned char *)hostdata->issue_queue; - hostdata->issue_queue = (Scsi_Cmnd *)cmd; - DEB_MSG(printk("scsi%d : REQUEST SENSE added to head of issue queue\n",instance->host_no)); - } - - /* Accept message by clearing ACK */ - AM53C974_write_8(CMDREG, CMDREG_MA); - break; - - case MESSAGE_REJECT: - DEB_MSG(printk("scsi%d: reject message received; cmd %d for target %d, lun %d\n", - instance->host_no, cmd->cmnd[0], cmd->target, cmd->lun)); - switch (hostdata->last_message[0]) { - case EXTENDED_MESSAGE: - if (hostdata->last_message[2] == EXTENDED_SDTR) { - /* sync. negotiation was rejected, setup asynchronous transfer with target */ - printk("\ntarget %d: rate=%d Mhz, asynchronous (sync. negotiation rejected)\n", - cmd->target, DEF_CLK / DEF_STP); - hostdata->sync_off[cmd->target] = 0; - hostdata->sync_per[cmd->target] = DEF_STP; } - break; - case HEAD_OF_QUEUE_TAG: - case ORDERED_QUEUE_TAG: - case SIMPLE_QUEUE_TAG: - cmd->device->tagged_queue = 0; - hostdata->busy[cmd->target] |= (1 << cmd->lun); - break; - default: - break; - } - if (hostdata->aborted) AM53C974_write_8(CMDREG, CMDREG_SATN); - AM53C974_write_8(CMDREG, CMDREG_MA); - break; - - case DISCONNECT: - DEB_MSG(printk("scsi%d: disconnect message received; cmd %d for target %d, lun %d\n", - instance->host_no, cmd->cmnd[0], cmd->target, cmd->lun)); - cmd->device->disconnect = 1; - hostdata->disconnecting = 1; - AM53C974_write_8(CMDREG, CMDREG_MA); /* Accept message by clearing ACK */ - break; - - case SAVE_POINTERS: - case RESTORE_POINTERS: - DEB_MSG(printk("scsi%d: save/restore pointers message received; cmd %d for target %d, lun %d\n", - instance->host_no, cmd->cmnd[0], cmd->target, cmd->lun)); - /* The SCSI data pointer is *IMPLICITLY* saved on a disconnect - * operation, in violation of the SCSI spec so we can safely - * ignore SAVE/RESTORE pointers calls. - * - * Unfortunately, some disks violate the SCSI spec and - * don't issue the required SAVE_POINTERS message before - * disconnecting, and we have to break spec to remain - * compatible. */ - if (hostdata->aborted) { - DEB_ABORT(printk("ATN set for cmnd %d upon reception of SAVE/REST. POINTERS message\n", - cmd->cmnd[0])); - AM53C974_write_8(CMDREG, CMDREG_SATN); } - AM53C974_write_8(CMDREG, CMDREG_MA); - break; - - case EXTENDED_MESSAGE: - DEB_MSG(printk("scsi%d: extended message received; cmd %d for target %d, lun %d\n", - instance->host_no, cmd->cmnd[0], cmd->target, cmd->lun)); - /* Extended messages are sent in the following format : - * Byte - * 0 EXTENDED_MESSAGE == 1 - * 1 length (includes one byte for code, doesn't include first two bytes) - * 2 code - * 3..length+1 arguments - */ - /* BEWARE!! THIS CODE IS EXTREMELY UGLY */ - extended_msg[0] = EXTENDED_MESSAGE; - AM53C974_read_8(INSTREG) ; /* clear int */ - AM53C974_write_8(CMDREG, CMDREG_MA); /* ack. msg byte, then wait for SO */ - AM53C974_poll_int(); - /* get length */ - AM53C974_write_8(CMDREG, CMDREG_IT); - AM53C974_poll_int(); - AM53C974_write_8(CMDREG, CMDREG_MA); /* ack. msg byte, then wait for SO */ - AM53C974_poll_int(); - extended_msg[1] = len = AM53C974_read_8(FFREG); /* get length */ - p = extended_msg+2; - /* read the remaining (len) bytes */ - while (len) { - AM53C974_write_8(CMDREG, CMDREG_IT); - AM53C974_poll_int(); - if (len > 1) { - AM53C974_write_8(CMDREG, CMDREG_MA); /* ack. msg byte, then wait for SO */ - AM53C974_poll_int(); } - *p = AM53C974_read_8(FFREG); - p++; len--; } + case LINKED_CMD_COMPLETE: + case LINKED_FLG_CMD_COMPLETE: + /* Accept message by releasing ACK */ + DEB_LINKED(printk("scsi%d : target %d lun %d linked command complete.\n", + instance->host_no, cmd->target, cmd->lun)); + /* Sanity check : A linked command should only terminate with + * one of these messages if there are more linked commands available. */ + if (!cmd->next_link) { + printk("scsi%d : target %d lun %d linked command complete, no next_link\n" + instance->host_no, cmd->target, cmd->lun); + hostdata->aborted = 1; + AM53C974_write_8(CMDREG, CMDREG_SATN); + AM53C974_write_8(CMDREG, CMDREG_MA); + break; + } + if (hostdata->aborted) { + DEB_ABORT(printk("ATN set for cmnd %d upon reception of LINKED_CMD_COMPLETE or" + "LINKED_FLG_CMD_COMPLETE message\n", cmd->cmnd[0])); + AM53C974_write_8(CMDREG, CMDREG_SATN); + } + AM53C974_write_8(CMDREG, CMDREG_MA); + + initialize_SCp(cmd->next_link); + /* The next command is still part of this process */ + cmd->next_link->tag = cmd->tag; + cmd->result = cmd->SCp.Status | (cmd->SCp.Message << 8); + DEB_LINKED(printk("scsi%d : target %d lun %d linked request done, calling scsi_done().\n", + instance->host_no, cmd->target, cmd->lun)); + cmd->scsi_done(cmd); + cmd = hostdata->connected; + break; + +#endif /* def LINKED */ + + case ABORT: + case COMMAND_COMPLETE: + DEB_MSG(printk("scsi%d: command complete message received; cmd %d for target %d, lun %d\n", + instance->host_no, cmd->cmnd[0], cmd->target, cmd->lun)); + hostdata->disconnecting = 1; + cmd->device->disconnect = 0; + + /* I'm not sure what the correct thing to do here is : + + * If the command that just executed is NOT a request + * sense, the obvious thing to do is to set the result + * code to the values of the stored parameters. + * If it was a REQUEST SENSE command, we need some way + * to differentiate between the failure code of the original + * and the failure code of the REQUEST sense - the obvious + * case is success, where we fall through and leave the result + * code unchanged. + * + * The non-obvious place is where the REQUEST SENSE failed */ + if (cmd->cmnd[0] != REQUEST_SENSE) + cmd->result = cmd->SCp.Status | (cmd->SCp.Message << 8); + else if (cmd->SCp.Status != GOOD) + cmd->result = (cmd->result & 0x00ffff) | (DID_ERROR << 16); + if (hostdata->aborted) { + AM53C974_write_8(CMDREG, CMDREG_SATN); + AM53C974_write_8(CMDREG, CMDREG_MA); + DEB_ABORT(printk("ATN set for cmnd %d upon reception of ABORT or" + "COMMAND_COMPLETE message\n", cmd->cmnd[0])); + break; + } + if ((cmd->cmnd[0] != REQUEST_SENSE) && (cmd->SCp.Status == CHECK_CONDITION)) { + DEB_MSG(printk("scsi%d : performing request sense\n", instance->host_no)); + cmd->cmnd[0] = REQUEST_SENSE; + cmd->cmnd[1] &= 0xe0; + cmd->cmnd[2] = 0; + cmd->cmnd[3] = 0; + cmd->cmnd[4] = sizeof(cmd->sense_buffer); + cmd->cmnd[5] = 0; + cmd->SCp.buffer = NULL; + cmd->SCp.buffers_residual = 0; + cmd->SCp.ptr = (char *) cmd->sense_buffer; + cmd->SCp.this_residual = sizeof(cmd->sense_buffer); + LIST(cmd, hostdata->issue_queue); + cmd->host_scribble = (unsigned char *) hostdata->issue_queue; + hostdata->issue_queue = (Scsi_Cmnd *) cmd; + DEB_MSG(printk("scsi%d : REQUEST SENSE added to head of issue queue\n", instance->host_no)); + } + /* Accept message by clearing ACK */ + AM53C974_write_8(CMDREG, CMDREG_MA); + break; + + case MESSAGE_REJECT: + DEB_MSG(printk("scsi%d: reject message received; cmd %d for target %d, lun %d\n", + instance->host_no, cmd->cmnd[0], cmd->target, cmd->lun)); + switch (hostdata->last_message[0]) { + case EXTENDED_MESSAGE: + if (hostdata->last_message[2] == EXTENDED_SDTR) { + /* sync. negotiation was rejected, setup asynchronous transfer with target */ + printk("\ntarget %d: rate=%d Mhz, asynchronous (sync. negotiation rejected)\n", + cmd->target, DEF_CLK / DEF_STP); + hostdata->sync_off[cmd->target] = 0; + hostdata->sync_per[cmd->target] = DEF_STP; + } + break; + case HEAD_OF_QUEUE_TAG: + case ORDERED_QUEUE_TAG: + case SIMPLE_QUEUE_TAG: + cmd->device->tagged_queue = 0; + hostdata->busy[cmd->target] |= (1 << cmd->lun); + break; + default: + break; + } + if (hostdata->aborted) + AM53C974_write_8(CMDREG, CMDREG_SATN); + AM53C974_write_8(CMDREG, CMDREG_MA); + break; + + case DISCONNECT: + DEB_MSG(printk("scsi%d: disconnect message received; cmd %d for target %d, lun %d\n", + instance->host_no, cmd->cmnd[0], cmd->target, cmd->lun)); + cmd->device->disconnect = 1; + hostdata->disconnecting = 1; + AM53C974_write_8(CMDREG, CMDREG_MA); /* Accept message by clearing ACK */ + break; + + case SAVE_POINTERS: + case RESTORE_POINTERS: + DEB_MSG(printk("scsi%d: save/restore pointers message received; cmd %d for target %d, lun %d\n", + instance->host_no, cmd->cmnd[0], cmd->target, cmd->lun)); + /* The SCSI data pointer is *IMPLICITLY* saved on a disconnect + * operation, in violation of the SCSI spec so we can safely + * ignore SAVE/RESTORE pointers calls. + * + * Unfortunately, some disks violate the SCSI spec and + * don't issue the required SAVE_POINTERS message before + * disconnecting, and we have to break spec to remain + * compatible. */ + if (hostdata->aborted) { + DEB_ABORT(printk("ATN set for cmnd %d upon reception of SAVE/REST. POINTERS message\n", + cmd->cmnd[0])); + AM53C974_write_8(CMDREG, CMDREG_SATN); + } + AM53C974_write_8(CMDREG, CMDREG_MA); + break; + + case EXTENDED_MESSAGE: + DEB_MSG(printk("scsi%d: extended message received; cmd %d for target %d, lun %d\n", + instance->host_no, cmd->cmnd[0], cmd->target, cmd->lun)); + /* Extended messages are sent in the following format : + * Byte + * 0 EXTENDED_MESSAGE == 1 + * 1 length (includes one byte for code, doesn't include first two bytes) + * 2 code + * 3..length+1 arguments + */ + /* BEWARE!! THIS CODE IS EXTREMELY UGLY */ + extended_msg[0] = EXTENDED_MESSAGE; + AM53C974_read_8(INSTREG); /* clear int */ + AM53C974_write_8(CMDREG, CMDREG_MA); /* ack. msg byte, then wait for SO */ + AM53C974_poll_int(); + /* get length */ + AM53C974_write_8(CMDREG, CMDREG_IT); + AM53C974_poll_int(); + AM53C974_write_8(CMDREG, CMDREG_MA); /* ack. msg byte, then wait for SO */ + AM53C974_poll_int(); + extended_msg[1] = len = AM53C974_read_8(FFREG); /* get length */ + p = extended_msg + 2; + /* read the remaining (len) bytes */ + while (len) { + AM53C974_write_8(CMDREG, CMDREG_IT); + AM53C974_poll_int(); + if (len > 1) { + AM53C974_write_8(CMDREG, CMDREG_MA); /* ack. msg byte, then wait for SO */ + AM53C974_poll_int(); + } + *p = AM53C974_read_8(FFREG); + p++; + len--; + } #ifdef AM53C974_DEBUG_MSG - printk("scsi%d: received extended message: ", instance->host_no); - for (j = 0; j < extended_msg[1] + 2; j++) { - printk("0x%02x ", extended_msg[j]); - if (j && !(j % 16)) printk("\n"); } - printk("\n"); -#endif - - /* check message */ - if (extended_msg[2] == EXTENDED_SDTR) - ret = AM53C974_sync_neg(instance, cmd->target, extended_msg); - if (ret || hostdata->aborted) AM53C974_write_8(CMDREG, CMDREG_SATN); + printk("scsi%d: received extended message: ", instance->host_no); + for (j = 0; j < extended_msg[1] + 2; j++) { + printk("0x%02x ", extended_msg[j]); + if (j && !(j % 16)) + printk("\n"); + } + printk("\n"); +#endif + + /* check message */ + if (extended_msg[2] == EXTENDED_SDTR) + ret = AM53C974_sync_neg(instance, cmd->target, extended_msg); + if (ret || hostdata->aborted) + AM53C974_write_8(CMDREG, CMDREG_SATN); - AM53C974_write_8(CMDREG, CMDREG_MA); - break; + AM53C974_write_8(CMDREG, CMDREG_MA); + break; - default: - printk("scsi%d: unknown message 0x%02x received\n",instance->host_no, msg); + default: + printk("scsi%d: unknown message 0x%02x received\n", instance->host_no, msg); #ifdef AM53C974_DEBUG - deb_stop = 1; + deb_stop = 1; #endif - /* reject message */ - hostdata->msgout[0] = MESSAGE_REJECT; - AM53C974_write_8(CMDREG, CMDREG_SATN); - AM53C974_write_8(CMDREG, CMDREG_MA); - return(0); - break; - - } /* switch (msg) */ -KEYWAIT(); -return(1); + /* reject message */ + hostdata->msgout[0] = MESSAGE_REJECT; + AM53C974_write_8(CMDREG, CMDREG_SATN); + AM53C974_write_8(CMDREG, CMDREG_MA); + return (0); + break; + + } /* switch (msg) */ + KEYWAIT(); + return (1); } /************************************************************************** @@ -1863,79 +1965,81 @@ * Note: this function initializes the selection process, which is continued * in the interrupt handler **************************************************************************/ -static void AM53C974_select(struct Scsi_Host *instance, Scsi_Cmnd *cmd, int tag) +static void AM53C974_select(struct Scsi_Host *instance, Scsi_Cmnd * cmd, int tag) { -AM53C974_local_declare(); -struct AM53C974_hostdata *hostdata = (struct AM53C974_hostdata *)instance->hostdata; -unsigned char cfifo, tmp[3]; -unsigned int i, len, cmd_size = COMMAND_SIZE(cmd->cmnd[0]); -AM53C974_setio(instance); - -cfifo = AM53C974_cfifo(); -if (cfifo) { - printk("scsi%d: select error; %d residual bytes in FIFO\n", instance->host_no, cfifo); - AM53C974_write_8(CMDREG, CMDREG_CFIFO); /* clear FIFO */ - } - + AM53C974_local_declare(); + struct AM53C974_hostdata *hostdata = (struct AM53C974_hostdata *) instance->hostdata; + unsigned char cfifo, tmp[3]; + unsigned int i, len, cmd_size = COMMAND_SIZE(cmd->cmnd[0]); + AM53C974_setio(instance); + + cfifo = AM53C974_cfifo(); + if (cfifo) { + printk("scsi%d: select error; %d residual bytes in FIFO\n", instance->host_no, cfifo); + AM53C974_write_8(CMDREG, CMDREG_CFIFO); /* clear FIFO */ + } #ifdef AM53C974_PROHIBIT_DISCONNECT -tmp[0] = IDENTIFY(0, cmd->lun); + tmp[0] = IDENTIFY(0, cmd->lun); #else -tmp[0] = IDENTIFY(1, cmd->lun); + tmp[0] = IDENTIFY(1, cmd->lun); #endif #ifdef SCSI2 -if (cmd->device->tagged_queue && (tag != TAG_NONE)) { - tmp[1] = SIMPLE_QUEUE_TAG; - if (tag == TAG_NEXT) { - /* 0 is TAG_NONE, used to imply no tag for this command */ - if (cmd->device->current_tag == 0) cmd->device->current_tag = 1; - cmd->tag = cmd->device->current_tag; - cmd->device->current_tag++; } - else - cmd->tag = (unsigned char)tag; - tmp[2] = cmd->tag; - hostdata->last_message[0] = SIMPLE_QUEUE_TAG; - len = 3; - AM53C974_write_8(FFREG, tmp[0]); - AM53C974_write_8(FFREG, tmp[1]); - AM53C974_write_8(FFREG, tmp[2]); - } - else -#endif /* def SCSI2 */ - { - len = 1; - AM53C974_write_8(FFREG, tmp[0]); - cmd->tag = 0; } + if (cmd->device->tagged_queue && (tag != TAG_NONE)) { + tmp[1] = SIMPLE_QUEUE_TAG; + if (tag == TAG_NEXT) { + /* 0 is TAG_NONE, used to imply no tag for this command */ + if (cmd->device->current_tag == 0) + cmd->device->current_tag = 1; + cmd->tag = cmd->device->current_tag; + cmd->device->current_tag++; + } else + cmd->tag = (unsigned char) tag; + tmp[2] = cmd->tag; + hostdata->last_message[0] = SIMPLE_QUEUE_TAG; + len = 3; + AM53C974_write_8(FFREG, tmp[0]); + AM53C974_write_8(FFREG, tmp[1]); + AM53C974_write_8(FFREG, tmp[2]); + } else +#endif /* def SCSI2 */ + { + len = 1; + AM53C974_write_8(FFREG, tmp[0]); + cmd->tag = 0; + } /* in case of an inquiry or req. sense command with no sync. neg performed yet, we start sync negotiation via start stops and transfer the command in cmdout phase */ -if (((cmd->cmnd[0] == INQUIRY) || (cmd->cmnd[0] == REQUEST_SENSE)) && - !(hostdata->sync_neg[cmd->target]) && hostdata->sync_en[cmd->target]) { - hostdata->sync_neg[cmd->target] = 1; - hostdata->msgout[0] = EXTENDED_MESSAGE; - hostdata->msgout[1] = 3; - hostdata->msgout[2] = EXTENDED_SDTR; - hostdata->msgout[3] = 250 / (int)hostdata->max_rate[cmd->target]; - hostdata->msgout[4] = hostdata->max_offset[cmd->target]; - len += 5; } - -AM53C974_write_8(SDIDREG, SDIREG_MASK & cmd->target); /* setup dest. id */ -AM53C974_write_8(STIMREG, DEF_SCSI_TIMEOUT); /* setup timeout reg */ -switch (len) { - case 1: - for (i = 0; i < cmd_size; i++) AM53C974_write_8(FFREG, cmd->cmnd[i]); - AM53C974_write_8(CMDREG, CMDREG_SAS); /* select with ATN, 1 msg byte */ - hostdata->msgout[0] = NOP; - break; - case 3: - for (i = 0; i < cmd_size; i++) AM53C974_write_8(FFREG, cmd->cmnd[i]); - AM53C974_write_8(CMDREG, CMDREG_SA3S); /* select with ATN, 3 msg bytes */ - hostdata->msgout[0] = NOP; - break; - default: - AM53C974_write_8(CMDREG, CMDREG_SASS); /* select with ATN, stop steps; continue in message out phase */ - break; - } + if (((cmd->cmnd[0] == INQUIRY) || (cmd->cmnd[0] == REQUEST_SENSE)) && + !(hostdata->sync_neg[cmd->target]) && hostdata->sync_en[cmd->target]) { + hostdata->sync_neg[cmd->target] = 1; + hostdata->msgout[0] = EXTENDED_MESSAGE; + hostdata->msgout[1] = 3; + hostdata->msgout[2] = EXTENDED_SDTR; + hostdata->msgout[3] = 250 / (int) hostdata->max_rate[cmd->target]; + hostdata->msgout[4] = hostdata->max_offset[cmd->target]; + len += 5; + } + AM53C974_write_8(SDIDREG, SDIREG_MASK & cmd->target); /* setup dest. id */ + AM53C974_write_8(STIMREG, DEF_SCSI_TIMEOUT); /* setup timeout reg */ + switch (len) { + case 1: + for (i = 0; i < cmd_size; i++) + AM53C974_write_8(FFREG, cmd->cmnd[i]); + AM53C974_write_8(CMDREG, CMDREG_SAS); /* select with ATN, 1 msg byte */ + hostdata->msgout[0] = NOP; + break; + case 3: + for (i = 0; i < cmd_size; i++) + AM53C974_write_8(FFREG, cmd->cmnd[i]); + AM53C974_write_8(CMDREG, CMDREG_SA3S); /* select with ATN, 3 msg bytes */ + hostdata->msgout[0] = NOP; + break; + default: + AM53C974_write_8(CMDREG, CMDREG_SASS); /* select with ATN, stop steps; continue in message out phase */ + break; + } } /************************************************************************** @@ -1952,59 +2056,65 @@ **************************************************************************/ static void AM53C974_intr_reselect(struct Scsi_Host *instance, unsigned char statreg) { -AM53C974_local_declare(); -struct AM53C974_hostdata *hostdata = (struct AM53C974_hostdata *)instance->hostdata; -unsigned char cfifo, msg[3], lun, t, target = 0; + AM53C974_local_declare(); + struct AM53C974_hostdata *hostdata = (struct AM53C974_hostdata *) instance->hostdata; + unsigned char cfifo, msg[3], lun, t, target = 0; #ifdef SCSI2 - unsigned char tag; + unsigned char tag; #endif -Scsi_Cmnd *tmp = NULL, *prev; -AM53C974_setio(instance); - -cfifo = AM53C974_cfifo(); + Scsi_Cmnd *tmp = NULL, *prev; + AM53C974_setio(instance); -if (hostdata->selecting) { - /* caught reselect interrupt in selection process; - put selecting command back into the issue queue and continue with the - reselecting command */ - DEB_RESEL(printk("AM53C974_intr_reselect: in selection process\n")); - LIST(hostdata->sel_cmd, hostdata->issue_queue); - hostdata->sel_cmd->host_scribble = (unsigned char *)hostdata->issue_queue; - hostdata->issue_queue = hostdata->sel_cmd; - hostdata->sel_cmd = NULL; - hostdata->selecting = 0; } + cfifo = AM53C974_cfifo(); + if (hostdata->selecting) { + /* caught reselect interrupt in selection process; + put selecting command back into the issue queue and continue with the + reselecting command */ + DEB_RESEL(printk("AM53C974_intr_reselect: in selection process\n")); + LIST(hostdata->sel_cmd, hostdata->issue_queue); + hostdata->sel_cmd->host_scribble = (unsigned char *) hostdata->issue_queue; + hostdata->issue_queue = hostdata->sel_cmd; + hostdata->sel_cmd = NULL; + hostdata->selecting = 0; + } /* 2 bytes must be in the FIFO now */ -if (cfifo != 2) { - printk("scsi %d: error: %d bytes in fifo, 2 expected\n", instance->host_no, cfifo); - hostdata->aborted = 1; - goto EXIT_ABORT; } - + if (cfifo != 2) { + printk("scsi %d: error: %d bytes in fifo, 2 expected\n", instance->host_no, cfifo); + hostdata->aborted = 1; + goto EXIT_ABORT; + } /* determine target which reselected */ -t = AM53C974_read_8(FFREG); -if (!(t & (1 << instance->this_id))) { - printk("scsi %d: error: invalid host id\n", instance->host_no); - hostdata->aborted = 1; - goto EXIT_ABORT; } -t ^= (1 << instance->this_id); -target = 0; while (t != 1) { t >>= 1; target++; } -DEB_RESEL(printk("scsi %d: reselect; target: %d\n", instance->host_no, target)); - -if (hostdata->aborted) goto EXIT_ABORT; - -if ((statreg & STATREG_PHASE) != PHASE_MSGIN) { - printk("scsi %d: error: upon reselection interrupt not in MSGIN\n", instance->host_no); - hostdata->aborted = 1; - goto EXIT_ABORT; } - -msg[0] = AM53C974_read_8(FFREG); -if (!msg[0] & 0x80) { - printk("scsi%d: error: expecting IDENTIFY message, got ", instance->host_no); - print_msg(msg); - hostdata->aborted = 1; - goto EXIT_ABORT; } - -lun = (msg[0] & 0x07); + t = AM53C974_read_8(FFREG); + if (!(t & (1 << instance->this_id))) { + printk("scsi %d: error: invalid host id\n", instance->host_no); + hostdata->aborted = 1; + goto EXIT_ABORT; + } + t ^= (1 << instance->this_id); + target = 0; + while (t != 1) { + t >>= 1; + target++; + } + DEB_RESEL(printk("scsi %d: reselect; target: %d\n", instance->host_no, target)); + + if (hostdata->aborted) + goto EXIT_ABORT; + + if ((statreg & STATREG_PHASE) != PHASE_MSGIN) { + printk("scsi %d: error: upon reselection interrupt not in MSGIN\n", instance->host_no); + hostdata->aborted = 1; + goto EXIT_ABORT; + } + msg[0] = AM53C974_read_8(FFREG); + if (!msg[0] & 0x80) { + printk("scsi%d: error: expecting IDENTIFY message, got ", instance->host_no); + print_msg(msg); + hostdata->aborted = 1; + goto EXIT_ABORT; + } + lun = (msg[0] & 0x07); /* We need to add code for SCSI-II to track which devices have * I_T_L_Q nexuses established, and which have simple I_T_L @@ -2015,52 +2125,53 @@ /* Find the command corresponding to the I_T_L or I_T_L_Q nexus we * just reestablished, and remove it from the disconnected queue. */ -for (tmp = (Scsi_Cmnd *)hostdata->disconnected_queue, prev = NULL; - tmp; prev = tmp, tmp = (Scsi_Cmnd *)tmp->host_scribble) - if ((target == tmp->target) && (lun == tmp->lun) + for (tmp = (Scsi_Cmnd *) hostdata->disconnected_queue, prev = NULL; + tmp; prev = tmp, tmp = (Scsi_Cmnd *) tmp->host_scribble) + if ((target == tmp->target) && (lun == tmp->lun) #ifdef SCSI2 - && (tag == tmp->tag) + && (tag == tmp->tag) #endif - ) { - if (prev) { - REMOVE(prev, (Scsi_Cmnd *)(prev->host_scribble), tmp, - (Scsi_Cmnd *)(tmp->host_scribble)); - prev->host_scribble = tmp->host_scribble; } - else { - REMOVE(-1, hostdata->disconnected_queue, tmp, tmp->host_scribble); - hostdata->disconnected_queue = (Scsi_Cmnd *)tmp->host_scribble; } - tmp->host_scribble = NULL; - hostdata->connected = tmp; - break; } - -if (!tmp) { + ) { + if (prev) { + REMOVE(prev, (Scsi_Cmnd *) (prev->host_scribble), tmp, + (Scsi_Cmnd *) (tmp->host_scribble)); + prev->host_scribble = tmp->host_scribble; + } else { + REMOVE(-1, hostdata->disconnected_queue, tmp, tmp->host_scribble); + hostdata->disconnected_queue = (Scsi_Cmnd *) tmp->host_scribble; + } + tmp->host_scribble = NULL; + hostdata->connected = tmp; + break; + } + if (!tmp) { #ifdef SCSI2 - printk("scsi%d: warning : target %d lun %d tag %d not in disconnect_queue.\n", - instance->host_no, target, lun, tag); + printk("scsi%d: warning : target %d lun %d tag %d not in disconnect_queue.\n", + instance->host_no, target, lun, tag); #else - printk("scsi%d: warning : target %d lun %d not in disconnect_queue.\n", - instance->host_no, target, lun); + printk("scsi%d: warning : target %d lun %d not in disconnect_queue.\n", + instance->host_no, target, lun); #endif - /* Since we have an established nexus that we can't do anything with, we must abort it. */ - hostdata->aborted = 1; - DEB(AM53C974_keywait()); - goto EXIT_ABORT; } - else - goto EXIT_OK; - -EXIT_ABORT: -AM53C974_write_8(CMDREG, CMDREG_SATN); -AM53C974_write_8(CMDREG, CMDREG_MA); -return; - -EXIT_OK: -DEB_RESEL(printk("scsi%d: nexus established, target = %d, lun = %d, tag = %d\n", - instance->host_no, target, tmp->lun, tmp->tag)); -AM53C974_set_sync(instance, target); -AM53C974_write_8(SDIDREG, SDIREG_MASK & target); /* setup dest. id */ -AM53C974_write_8(CMDREG, CMDREG_MA); -hostdata->dma_busy = 0; -hostdata->connected->SCp.phase = PHASE_CMDOUT; + /* Since we have an established nexus that we can't do anything with, we must abort it. */ + hostdata->aborted = 1; + DEB(AM53C974_keywait()); + goto EXIT_ABORT; + } else + goto EXIT_OK; + + EXIT_ABORT: + AM53C974_write_8(CMDREG, CMDREG_SATN); + AM53C974_write_8(CMDREG, CMDREG_MA); + return; + + EXIT_OK: + DEB_RESEL(printk("scsi%d: nexus established, target = %d, lun = %d, tag = %d\n", + instance->host_no, target, tmp->lun, tmp->tag)); + AM53C974_set_sync(instance, target); + AM53C974_write_8(SDIDREG, SDIREG_MASK & target); /* setup dest. id */ + AM53C974_write_8(CMDREG, CMDREG_MA); + hostdata->dma_busy = 0; + hostdata->connected->SCp.phase = PHASE_CMDOUT; } /************************************************************************** @@ -2078,20 +2189,20 @@ * Returns : nothing **************************************************************************/ static __inline__ void AM53C974_transfer_dma(struct Scsi_Host *instance, short dir, - unsigned long length, char *data) + unsigned long length, char *data) { -AM53C974_local_declare(); -AM53C974_setio(instance); + AM53C974_local_declare(); + AM53C974_setio(instance); -AM53C974_write_8(CMDREG, CMDREG_NOP); -AM53C974_write_8(DMACMD, (dir << 7) | DMACMD_INTE_D); /* idle command */ -AM53C974_write_8(STCLREG, (unsigned char)(length & 0xff)); -AM53C974_write_8(STCMREG, (unsigned char)((length & 0xff00) >> 8)); -AM53C974_write_8(STCHREG, (unsigned char)((length & 0xff0000) >> 16)); -AM53C974_write_32(DMASTC, length & 0xffffff); -AM53C974_write_32(DMASPA, virt_to_bus(data)); -AM53C974_write_8(CMDREG, CMDREG_IT | CMDREG_DMA); -AM53C974_write_8(DMACMD, (dir << 7) | DMACMD_INTE_D | DMACMD_START); + AM53C974_write_8(CMDREG, CMDREG_NOP); + AM53C974_write_8(DMACMD, (dir << 7) | DMACMD_INTE_D); /* idle command */ + AM53C974_write_8(STCLREG, (unsigned char) (length & 0xff)); + AM53C974_write_8(STCMREG, (unsigned char) ((length & 0xff00) >> 8)); + AM53C974_write_8(STCHREG, (unsigned char) ((length & 0xff0000) >> 16)); + AM53C974_write_32(DMASTC, length & 0xffffff); + AM53C974_write_32(DMASPA, virt_to_bus(data)); + AM53C974_write_8(CMDREG, CMDREG_IT | CMDREG_DMA); + AM53C974_write_8(DMACMD, (dir << 7) | DMACMD_INTE_D | DMACMD_START); } /************************************************************************** @@ -2107,41 +2218,45 @@ * Returns : nothing **************************************************************************/ static void AM53C974_dma_blast(struct Scsi_Host *instance, unsigned char dmastatus, - unsigned char statreg) + unsigned char statreg) { -AM53C974_local_declare(); -struct AM53C974_hostdata *hostdata = (struct AM53C974_hostdata *)instance->hostdata; -unsigned long ctcreg; -int dir = statreg & STATREG_IO; -int cfifo, pio, i = 0; -AM53C974_setio(instance); - -do { - cfifo = AM53C974_cfifo(); - i++; - } while (cfifo && (i < 50000)); -pio = (i == 50000) ? 1: 0; - -if (statreg & STATREG_CTZ) { AM53C974_write_8(DMACMD, DMACMD_IDLE); return; } - -if (dmastatus & DMASTATUS_DONE) { AM53C974_write_8(DMACMD, DMACMD_IDLE); return; } - -AM53C974_write_8(DMACMD, ((dir << 7) & DMACMD_DIR) | DMACMD_BLAST); -while(!(AM53C974_read_8(DMASTATUS) & DMASTATUS_BCMPLT)) ; -AM53C974_write_8(DMACMD, DMACMD_IDLE); - -if (pio) { - /* transfer residual bytes via PIO */ - unsigned char *wac = (unsigned char *)AM53C974_read_32(DMAWAC); - printk("pio mode, residual=%d\n", AM53C974_read_8(CFIREG) & CFIREG_CF); - while (AM53C974_read_8(CFIREG) & CFIREG_CF) *(wac++) = AM53C974_read_8(FFREG); - } - -ctcreg = AM53C974_read_8(CTCLREG) | (AM53C974_read_8(CTCMREG) << 8) | - (AM53C974_read_8(CTCHREG) << 16); + AM53C974_local_declare(); + struct AM53C974_hostdata *hostdata = (struct AM53C974_hostdata *) instance->hostdata; + unsigned long ctcreg; + int dir = statreg & STATREG_IO; + int cfifo, pio, i = 0; + AM53C974_setio(instance); + + do { + cfifo = AM53C974_cfifo(); + i++; + } while (cfifo && (i < 50000)); + pio = (i == 50000) ? 1 : 0; + + if (statreg & STATREG_CTZ) { + AM53C974_write_8(DMACMD, DMACMD_IDLE); + return; + } + if (dmastatus & DMASTATUS_DONE) { + AM53C974_write_8(DMACMD, DMACMD_IDLE); + return; + } + AM53C974_write_8(DMACMD, ((dir << 7) & DMACMD_DIR) | DMACMD_BLAST); + while (!(AM53C974_read_8(DMASTATUS) & DMASTATUS_BCMPLT)); + AM53C974_write_8(DMACMD, DMACMD_IDLE); + + if (pio) { + /* transfer residual bytes via PIO */ + unsigned char *wac = (unsigned char *) AM53C974_read_32(DMAWAC); + printk("pio mode, residual=%d\n", AM53C974_read_8(CFIREG) & CFIREG_CF); + while (AM53C974_read_8(CFIREG) & CFIREG_CF) + *(wac++) = AM53C974_read_8(FFREG); + } + ctcreg = AM53C974_read_8(CTCLREG) | (AM53C974_read_8(CTCMREG) << 8) | + (AM53C974_read_8(CTCHREG) << 16); -hostdata->connected->SCp.ptr += hostdata->connected->SCp.this_residual - ctcreg; -hostdata->connected->SCp.this_residual = ctcreg; + hostdata->connected->SCp.ptr += hostdata->connected->SCp.this_residual - ctcreg; + hostdata->connected->SCp.this_residual = ctcreg; } /************************************************************************** @@ -2155,15 +2270,15 @@ **************************************************************************/ static void AM53C974_intr_bus_reset(struct Scsi_Host *instance) { -AM53C974_local_declare(); -unsigned char cntlreg1; -AM53C974_setio(instance); + AM53C974_local_declare(); + unsigned char cntlreg1; + AM53C974_setio(instance); -AM53C974_write_8(CMDREG, CMDREG_CFIFO); -AM53C974_write_8(CMDREG, CMDREG_NOP); + AM53C974_write_8(CMDREG, CMDREG_CFIFO); + AM53C974_write_8(CMDREG, CMDREG_NOP); -cntlreg1 = AM53C974_read_8(CNTLREG1); -AM53C974_write_8(CNTLREG1, cntlreg1 | CNTLREG1_DISR); + cntlreg1 = AM53C974_read_8(CNTLREG1); + AM53C974_write_8(CNTLREG1, cntlreg1 | CNTLREG1_DISR); } /************************************************************************** @@ -2177,97 +2292,101 @@ * * Returns : 0 - success, -1 on failure. **************************************************************************/ -int AM53C974_abort(Scsi_Cmnd *cmd) +int AM53C974_abort(Scsi_Cmnd * cmd) { -AM53C974_local_declare(); -struct Scsi_Host *instance = cmd->host; -struct AM53C974_hostdata *hostdata = (struct AM53C974_hostdata *)instance->hostdata; -Scsi_Cmnd *tmp, **prev; + AM53C974_local_declare(); + unsigned long flags; + struct Scsi_Host *instance = cmd->host; + struct AM53C974_hostdata *hostdata = (struct AM53C974_hostdata *) instance->hostdata; + Scsi_Cmnd *tmp, **prev; #ifdef AM53C974_DEBUG - deb_stop = 1; + deb_stop = 1; #endif -cli(); -AM53C974_setio(instance); - -DEB_ABORT(printk(SEPARATOR_LINE)); -DEB_ABORT(printk("scsi%d : AM53C974_abort called -- trouble starts!!\n", instance->host_no)); -DEB_ABORT(AM53C974_print(instance)); -DEB_ABORT(AM53C974_keywait()); + save_flags(flags); + cli(); + AM53C974_setio(instance); + + DEB_ABORT(printk(SEPARATOR_LINE)); + DEB_ABORT(printk("scsi%d : AM53C974_abort called -- trouble starts!!\n", instance->host_no)); + DEB_ABORT(AM53C974_print(instance)); + DEB_ABORT(AM53C974_keywait()); /* Case 1 : If the command is the currently executing command, - we'll set the aborted flag and return control so that the - information transfer routine can exit cleanly. */ -if ((hostdata->connected == cmd) || (hostdata->sel_cmd == cmd)) { - DEB_ABORT(printk("scsi%d: aborting connected command\n", instance->host_no)); - hostdata->aborted = 1; - hostdata->msgout[0] = ABORT; - sti(); - return(SCSI_ABORT_PENDING); } - + we'll set the aborted flag and return control so that the + information transfer routine can exit cleanly. */ + if ((hostdata->connected == cmd) || (hostdata->sel_cmd == cmd)) { + DEB_ABORT(printk("scsi%d: aborting connected command\n", instance->host_no)); + hostdata->aborted = 1; + hostdata->msgout[0] = ABORT; + restore_flags(flags); + return (SCSI_ABORT_PENDING); + } /* Case 2 : If the command hasn't been issued yet, - we simply remove it from the issue queue. */ -for (prev = (Scsi_Cmnd **)&(hostdata->issue_queue), - tmp = (Scsi_Cmnd *)hostdata->issue_queue; tmp; - prev = (Scsi_Cmnd **)&(tmp->host_scribble), - tmp = (Scsi_Cmnd *)tmp->host_scribble) { - if (cmd == tmp) { - DEB_ABORT(printk("scsi%d : abort removed command from issue queue.\n", instance->host_no)); - REMOVE(5, *prev, tmp, tmp->host_scribble); - (*prev) = (Scsi_Cmnd *)tmp->host_scribble; - tmp->host_scribble = NULL; - tmp->result = DID_ABORT << 16; - sti(); - tmp->done(tmp); - return(SCSI_ABORT_SUCCESS); } + we simply remove it from the issue queue. */ + for (prev = (Scsi_Cmnd **) & (hostdata->issue_queue), + tmp = (Scsi_Cmnd *) hostdata->issue_queue; tmp; + prev = (Scsi_Cmnd **) & (tmp->host_scribble), + tmp = (Scsi_Cmnd *) tmp->host_scribble) { + if (cmd == tmp) { + DEB_ABORT(printk("scsi%d : abort removed command from issue queue.\n", instance->host_no)); + REMOVE(5, *prev, tmp, tmp->host_scribble); + (*prev) = (Scsi_Cmnd *) tmp->host_scribble; + tmp->host_scribble = NULL; + tmp->result = DID_ABORT << 16; + restore_flags(flags); + tmp->done(tmp); + return (SCSI_ABORT_SUCCESS); + } #ifdef AM53C974_DEBUG_ABORT - else { - if (prev == (Scsi_Cmnd **)tmp) - printk("scsi%d : LOOP\n", instance->host_no); - } + else { + if (prev == (Scsi_Cmnd **) tmp) + printk("scsi%d : LOOP\n", instance->host_no); + } #endif - } - + } + /* Case 3 : If any commands are connected, we're going to fail the abort - * and let the high level SCSI driver retry at a later time or - * issue a reset. + * and let the high level SCSI driver retry at a later time or + * issue a reset. * - * Timeouts, and therefore aborted commands, will be highly unlikely + * Timeouts, and therefore aborted commands, will be highly unlikely * and handling them cleanly in this situation would make the common - * case of noresets less efficient, and would pollute our code. So, - * we fail. */ -if (hostdata->connected || hostdata->sel_cmd) { - DEB_ABORT(printk("scsi%d : abort failed, other command connected.\n", instance->host_no)); - sti(); - return(SCSI_ABORT_NOT_RUNNING); } - + * case of noresets less efficient, and would pollute our code. So, + * we fail. */ + if (hostdata->connected || hostdata->sel_cmd) { + DEB_ABORT(printk("scsi%d : abort failed, other command connected.\n", instance->host_no)); + restore_flags(flags); + return (SCSI_ABORT_NOT_RUNNING); + } /* Case 4: If the command is currently disconnected from the bus, and - * there are no connected commands, we reconnect the I_T_L or - * I_T_L_Q nexus associated with it, go into message out, and send + * there are no connected commands, we reconnect the I_T_L or + * I_T_L_Q nexus associated with it, go into message out, and send * an abort message. */ -for (tmp = (Scsi_Cmnd *)hostdata->disconnected_queue; tmp; - tmp = (Scsi_Cmnd *)tmp->host_scribble) { - if (cmd == tmp) { - DEB_ABORT(printk("scsi%d: aborting disconnected command\n", instance->host_no)); - hostdata->aborted = 1; - hostdata->msgout[0] = ABORT; - hostdata->selecting = 1; - hostdata->sel_cmd = tmp; - AM53C974_write_8(CMDREG, CMDREG_DSR); - sti(); - return(SCSI_ABORT_PENDING); } - } + for (tmp = (Scsi_Cmnd *) hostdata->disconnected_queue; tmp; + tmp = (Scsi_Cmnd *) tmp->host_scribble) { + if (cmd == tmp) { + DEB_ABORT(printk("scsi%d: aborting disconnected command\n", instance->host_no)); + hostdata->aborted = 1; + hostdata->msgout[0] = ABORT; + hostdata->selecting = 1; + hostdata->sel_cmd = tmp; + AM53C974_write_8(CMDREG, CMDREG_DSR); + restore_flags(flags); + return (SCSI_ABORT_PENDING); + } + } /* Case 5 : If we reached this point, the command was not found in any of - * the queues. + * the queues. * * We probably reached this point because of an unlikely race condition * between the command completing successfully and the abortion code, * so we won't panic, but we will notify the user in case something really * broke. */ -DEB_ABORT(printk("scsi%d : abort failed, command not found.\n", instance->host_no)); -sti(); -return(SCSI_ABORT_NOT_RUNNING); + DEB_ABORT(printk("scsi%d : abort failed, command not found.\n", instance->host_no)); + restore_flags(flags); + return (SCSI_ABORT_NOT_RUNNING); } /************************************************************************** @@ -2281,51 +2400,54 @@ * * FIXME(eric) the reset_flags are ignored. **************************************************************************/ -int AM53C974_reset(Scsi_Cmnd *cmd, unsigned int reset_flags) +int AM53C974_reset(Scsi_Cmnd * cmd, unsigned int reset_flags) { - AM53C974_local_declare(); - int i; - struct Scsi_Host *instance = cmd->host; - struct AM53C974_hostdata *hostdata = (struct AM53C974_hostdata *)instance->hostdata; - AM53C974_setio(instance); - - cli(); - DEB(printk("AM53C974_reset called; ")); - - printk("AM53C974_reset called\n"); - AM53C974_print(instance); - AM53C974_keywait(); - + AM53C974_local_declare(); + unsigned long flags; + int i; + struct Scsi_Host *instance = cmd->host; + struct AM53C974_hostdata *hostdata = (struct AM53C974_hostdata *) instance->hostdata; + AM53C974_setio(instance); + + save_flags(flags); + cli(); + DEB(printk("AM53C974_reset called; ")); + + printk("AM53C974_reset called\n"); + AM53C974_print(instance); + AM53C974_keywait(); + /* do hard reset */ - AM53C974_write_8(CMDREG, CMDREG_RDEV); - AM53C974_write_8(CMDREG, CMDREG_NOP); - hostdata->msgout[0] = NOP; - for (i = 0; i < 8; i++) { - hostdata->busy[i] = 0; - hostdata->sync_per[i] = DEF_STP; - hostdata->sync_off[i] = 0; - hostdata->sync_neg[i] = 0; } - hostdata->last_message[0] = NOP; - hostdata->sel_cmd = NULL; - hostdata->connected = NULL; - hostdata->issue_queue = NULL; - hostdata->disconnected_queue = NULL; - hostdata->in_reset = 0; - hostdata->aborted = 0; - hostdata->selecting = 0; - hostdata->disconnecting = 0; - hostdata->dma_busy = 0; - + AM53C974_write_8(CMDREG, CMDREG_RDEV); + AM53C974_write_8(CMDREG, CMDREG_NOP); + hostdata->msgout[0] = NOP; + for (i = 0; i < 8; i++) { + hostdata->busy[i] = 0; + hostdata->sync_per[i] = DEF_STP; + hostdata->sync_off[i] = 0; + hostdata->sync_neg[i] = 0; + } + hostdata->last_message[0] = NOP; + hostdata->sel_cmd = NULL; + hostdata->connected = NULL; + hostdata->issue_queue = NULL; + hostdata->disconnected_queue = NULL; + hostdata->in_reset = 0; + hostdata->aborted = 0; + hostdata->selecting = 0; + hostdata->disconnecting = 0; + hostdata->dma_busy = 0; + /* reset bus */ - AM53C974_write_8(CNTLREG1, CNTLREG1_DISR | instance->this_id); /* disable interrupt upon SCSI RESET */ - AM53C974_write_8(CMDREG, CMDREG_RBUS); /* reset SCSI bus */ - udelay(40); - AM53C974_config_after_reset(instance); - - sti(); - cmd->result = DID_RESET << 16; - cmd->scsi_done(cmd); - return SCSI_ABORT_SUCCESS; + AM53C974_write_8(CNTLREG1, CNTLREG1_DISR | instance->this_id); /* disable interrupt upon SCSI RESET */ + AM53C974_write_8(CMDREG, CMDREG_RBUS); /* reset SCSI bus */ + udelay(40); + AM53C974_config_after_reset(instance); + + restore_flags(flags); + cmd->result = DID_RESET << 16; + cmd->scsi_done(cmd); + return SCSI_ABORT_SUCCESS; } @@ -2334,8 +2456,7 @@ * * Release resources allocated for a single AM53C974 adapter. */ -int -AM53C974_release(struct Scsi_Host *shp) +int AM53C974_release(struct Scsi_Host *shp) { free_irq(shp->irq, NULL); scsi_unregister(shp); diff -u --recursive --new-file v2.1.101/linux/drivers/scsi/AM53C974.h linux/drivers/scsi/AM53C974.h --- v2.1.101/linux/drivers/scsi/AM53C974.h Sun Dec 21 17:04:48 1997 +++ linux/drivers/scsi/AM53C974.h Mon May 11 10:51:34 1998 @@ -1,14 +1,14 @@ /* AM53/79C974 (PCscsi) driver release 0.5 - * + * The architecture and much of the code of this device * driver was originally developed by Drew Eckhardt for * the NCR5380. The following copyrights apply: * For the architecture and all parts similar to the NCR5380: * Copyright 1993, Drew Eckhardt - * Visionary Computing - * (Unix and Linux consulting and custom programming) - * drew@colorado.edu - * +1 (303) 666-5836 + * Visionary Computing + * (Unix and Linux consulting and custom programming) + * drew@colorado.edu + * +1 (303) 666-5836 * * The AM53C974_nobios_detect code was originally developed by * Robin Cutshaw (robin@xfree86.org) and is used here in a @@ -30,25 +30,25 @@ #include struct AM53C974_hostdata { - volatile unsigned in_reset:1; /* flag, says bus reset pending */ - volatile unsigned aborted:1; /* flag, says aborted */ - volatile unsigned selecting:1; /* selection started, but not yet finished */ - volatile unsigned disconnecting: 1; /* disconnection started, but not yet finished */ - volatile unsigned dma_busy:1; /* dma busy when service request for info transfer received */ - volatile unsigned char msgout[10]; /* message to output in MSGOUT_PHASE */ - volatile unsigned char last_message[10]; /* last message OUT */ - volatile Scsi_Cmnd *issue_queue; /* waiting to be issued */ - volatile Scsi_Cmnd *disconnected_queue; /* waiting for reconnect */ - volatile Scsi_Cmnd *sel_cmd; /* command for selection */ - volatile Scsi_Cmnd *connected; /* currently connected command */ - volatile unsigned char busy[8]; /* index = target, bit = lun */ - unsigned char sync_per[8]; /* synchronous transfer period (in effect) */ - unsigned char sync_off[8]; /* synchronous offset (in effect) */ - unsigned char sync_neg[8]; /* sync. negotiation performed (in effect) */ - unsigned char sync_en[8]; /* sync. negotiation performed (in effect) */ - unsigned char max_rate[8]; /* max. transfer rate (setup) */ - unsigned char max_offset[8]; /* max. sync. offset (setup), only valid if corresponding sync_en is nonzero */ - }; + volatile unsigned in_reset:1; /* flag, says bus reset pending */ + volatile unsigned aborted:1; /* flag, says aborted */ + volatile unsigned selecting:1; /* selection started, but not yet finished */ + volatile unsigned disconnecting: 1; /* disconnection started, but not yet finished */ + volatile unsigned dma_busy:1; /* dma busy when service request for info transfer received */ + volatile unsigned char msgout[10]; /* message to output in MSGOUT_PHASE */ + volatile unsigned char last_message[10]; /* last message OUT */ + volatile Scsi_Cmnd *issue_queue; /* waiting to be issued */ + volatile Scsi_Cmnd *disconnected_queue; /* waiting for reconnect */ + volatile Scsi_Cmnd *sel_cmd; /* command for selection */ + volatile Scsi_Cmnd *connected; /* currently connected command */ + volatile unsigned char busy[8]; /* index = target, bit = lun */ + unsigned char sync_per[8]; /* synchronous transfer period (in effect) */ + unsigned char sync_off[8]; /* synchronous offset (in effect) */ + unsigned char sync_neg[8]; /* sync. negotiation performed (in effect) */ + unsigned char sync_en[8]; /* sync. negotiation performed (in effect) */ + unsigned char max_rate[8]; /* max. transfer rate (setup) */ + unsigned char max_offset[8]; /* max. sync. offset (setup), only valid if corresponding sync_en is nonzero */ +}; extern struct proc_dir_entry proc_scsi_am53c974; @@ -71,14 +71,13 @@ } void AM53C974_setup(char *str, int *ints); -int AM53C974_detect(Scsi_Host_Template *tpnt); +int AM53C974_detect(Scsi_Host_Template * tpnt); int AM53C974_release(struct Scsi_Host *shp); -int AM53C974_biosparm(Disk *disk, int dev, int *info_array); +int AM53C974_biosparm(Disk * disk, int dev, int *info_array); const char *AM53C974_info(struct Scsi_Host *); -int AM53C974_command(Scsi_Cmnd *SCpnt); -int AM53C974_queue_command(Scsi_Cmnd *cmd, void (*done)(Scsi_Cmnd *)); -int AM53C974_abort(Scsi_Cmnd *cmd); -int AM53C974_reset (Scsi_Cmnd *cmd, unsigned int); - -#endif /* AM53C974_H */ +int AM53C974_command(Scsi_Cmnd * SCpnt); +int AM53C974_queue_command(Scsi_Cmnd * cmd, void (*done) (Scsi_Cmnd *)); +int AM53C974_abort(Scsi_Cmnd * cmd); +int AM53C974_reset(Scsi_Cmnd * cmd, unsigned int); +#endif /* AM53C974_H */ diff -u --recursive --new-file v2.1.101/linux/drivers/scsi/NCR5380.c linux/drivers/scsi/NCR5380.c --- v2.1.101/linux/drivers/scsi/NCR5380.c Tue Apr 14 14:29:21 1998 +++ linux/drivers/scsi/NCR5380.c Mon May 11 13:19:45 1998 @@ -3,16 +3,16 @@ #endif /* * NCR 5380 generic driver routines. These should make it *trivial* - * to implement 5380 SCSI drivers under Linux with a non-trantor - * architecture. + * to implement 5380 SCSI drivers under Linux with a non-trantor + * architecture. * - * Note that these routines also work with NR53c400 family chips. + * Note that these routines also work with NR53c400 family chips. * * Copyright 1993, Drew Eckhardt - * Visionary Computing - * (Unix and Linux consulting and custom programming) - * drew@colorado.edu - * +1 (303) 666-5836 + * Visionary Computing + * (Unix and Linux consulting and custom programming) + * drew@colorado.edu + * +1 (303) 666-5836 * * DISTRIBUTION RELEASE 6. * @@ -31,7 +31,7 @@ /* * $Log: NCR5380.c,v $ - * Revision 1.7 1996/3/2 Ray Van Tassle (rayvt@comm.mot.com) + * Revision 1.7 1996/3/2 Ray Van Tassle (rayvt@comm.mot.com) * added proc_info * added support needed for DTC 3180/3280 * fixed a couple of bugs @@ -68,7 +68,7 @@ * 3. Test USLEEP code * * 4. Test SCSI-II tagged queueing (I have no devices which support - * tagged queueing) + * tagged queueing) * * 5. Test linked command handling code after Eric is ready with * the high level code. @@ -201,21 +201,21 @@ * * These macros control options : * AUTOPROBE_IRQ - if defined, the NCR5380_probe_irq() function will be - * defined. + * defined. * * AUTOSENSE - if defined, REQUEST SENSE will be performed automatically - * for commands that return with a CHECK CONDITION status. + * for commands that return with a CHECK CONDITION status. * * DIFFERENTIAL - if defined, NCR53c81 chips will use external differential - * transceivers. + * transceivers. * * DONT_USE_INTR - if defined, never use interrupts, even if we probe or - * override-configure an IRQ. + * override-configure an IRQ. * * LIMIT_TRANSFERSIZE - if defined, limit the pseudo-dma transfers to 512 - * bytes at a time. Since interrupts are disabled by default during - * these transfers, we might need this to give reasonable interrupt - * service time if the transfer size gets too large. + * bytes at a time. Since interrupts are disabled by default during + * these transfers, we might need this to give reasonable interrupt + * service time if the transfer size gets too large. * * LINKED - if defined, linked commands are supported. * @@ -224,20 +224,20 @@ * REAL_DMA - if defined, REAL DMA is used during the data transfer phases. * * REAL_DMA_POLL - if defined, REAL DMA is used but the driver doesn't - * rely on phase mismatch and EOP interrupts to determine end - * of phase. + * rely on phase mismatch and EOP interrupts to determine end + * of phase. * * SCSI2 - if defined, SCSI-2 tagged queuing is used where possible * * UNSAFE - leave interrupts enabled during pseudo-DMA transfers. You - * only really want to use this if you're having a problem with - * dropped characters during high speed communications, and even - * then, you're going to be better off twiddling with transfersize - * in the high level code. + * only really want to use this if you're having a problem with + * dropped characters during high speed communications, and even + * then, you're going to be better off twiddling with transfersize + * in the high level code. * * USLEEP - if defined, on devices that aren't disconnecting from the - * bus, we will go to sleep so that the CPU can get real work done - * when we run a command that won't complete immediately. + * bus, we will go to sleep so that the CPU can get real work done + * when we run a command that won't complete immediately. * * Note that if USLEEP is defined, NCR5380_TIMER *must* also be * defined. @@ -252,27 +252,27 @@ * * These macros MUST be defined : * NCR5380_local_declare() - declare any local variables needed for your - * transfer routines. + * transfer routines. * * NCR5380_setup(instance) - initialize any local variables needed from a given - * instance of the host adapter for NCR5380_{read,write,pread,pwrite} + * instance of the host adapter for NCR5380_{read,write,pread,pwrite} * * NCR5380_read(register) - read from the specified register * * NCR5380_write(register, value) - write to the specific register * * NCR5380_implementation_fields - additional fields needed for this - * specific implementation of the NCR5380 + * specific implementation of the NCR5380 * * Either real DMA *or* pseudo DMA may be implemented * REAL functions : * NCR5380_REAL_DMA should be defined if real DMA is to be used. * Note that the DMA setup functions should return the number of bytes - * that they were able to program the controller for. + * that they were able to program the controller for. * * Also note that generic i386/PC versions of these macros are - * available as NCR5380_i386_dma_write_setup, - * NCR5380_i386_dma_read_setup, and NCR5380_i386_dma_residual. + * available as NCR5380_i386_dma_write_setup, + * NCR5380_i386_dma_read_setup, and NCR5380_i386_dma_residual. * * NCR5380_dma_write_setup(instance, src, count) - initialize * NCR5380_dma_read_setup(instance, dst, count) - initialize @@ -304,8 +304,8 @@ * code finishes, NCR5380_print_options should be called. */ -static int do_abort (struct Scsi_Host *host); -static void do_reset (struct Scsi_Host *host); +static int do_abort(struct Scsi_Host *host); +static void do_reset(struct Scsi_Host *host); static struct Scsi_Host *first_instance = NULL; static Scsi_Host_Template *the_template = NULL; @@ -313,49 +313,112 @@ * Function : void initialize_SCp(Scsi_Cmnd *cmd) * * Purpose : initialize the saved data pointers for cmd to point to the - * start of the buffer. + * start of the buffer. * * Inputs : cmd - Scsi_Cmnd structure to have pointers reset. */ -static __inline__ void initialize_SCp(Scsi_Cmnd *cmd) { - /* - * Initialize the Scsi Pointer field so that all of the commands in the - * various queues are valid. - */ - - if (cmd->use_sg) { - cmd->SCp.buffer = (struct scatterlist *) cmd->buffer; - cmd->SCp.buffers_residual = cmd->use_sg - 1; - cmd->SCp.ptr = (char *) cmd->SCp.buffer->address; - cmd->SCp.this_residual = cmd->SCp.buffer->length; - } else { - cmd->SCp.buffer = NULL; - cmd->SCp.buffers_residual = 0; - cmd->SCp.ptr = (char *) cmd->request_buffer; - cmd->SCp.this_residual = cmd->request_bufflen; - } +static __inline__ void initialize_SCp(Scsi_Cmnd * cmd) +{ + /* + * Initialize the Scsi Pointer field so that all of the commands in the + * various queues are valid. + */ + + if (cmd->use_sg) { + cmd->SCp.buffer = (struct scatterlist *) cmd->buffer; + cmd->SCp.buffers_residual = cmd->use_sg - 1; + cmd->SCp.ptr = (char *) cmd->SCp.buffer->address; + cmd->SCp.this_residual = cmd->SCp.buffer->length; + } else { + cmd->SCp.buffer = NULL; + cmd->SCp.buffers_residual = 0; + cmd->SCp.ptr = (char *) cmd->request_buffer; + cmd->SCp.this_residual = cmd->request_bufflen; + } } #include #ifdef NDEBUG static struct { - unsigned char mask; - const char * name;} -signals[] = {{ SR_DBP, "PARITY"}, { SR_RST, "RST" }, { SR_BSY, "BSY" }, - { SR_REQ, "REQ" }, { SR_MSG, "MSG" }, { SR_CD, "CD" }, { SR_IO, "IO" }, - { SR_SEL, "SEL" }, {0, NULL}}, -basrs[] = {{BASR_ATN, "ATN"}, {BASR_ACK, "ACK"}, {0, NULL}}, -icrs[] = {{ICR_ASSERT_RST, "ASSERT RST"},{ICR_ASSERT_ACK, "ASSERT ACK"}, - {ICR_ASSERT_BSY, "ASSERT BSY"}, {ICR_ASSERT_SEL, "ASSERT SEL"}, - {ICR_ASSERT_ATN, "ASSERT ATN"}, {ICR_ASSERT_DATA, "ASSERT DATA"}, - {0, NULL}}, -mrs[] = {{MR_BLOCK_DMA_MODE, "MODE BLOCK DMA"}, {MR_TARGET, "MODE TARGET"}, - {MR_ENABLE_PAR_CHECK, "MODE PARITY CHECK"}, {MR_ENABLE_PAR_INTR, - "MODE PARITY INTR"}, {MR_MONITOR_BSY, "MODE MONITOR BSY"}, - {MR_DMA_MODE, "MODE DMA"}, {MR_ARBITRATE, "MODE ARBITRATION"}, - {0, NULL}}; + unsigned char mask; + const char *name; +} signals[] = { { + + SR_DBP, "PARITY" +}, { + SR_RST, "RST" +}, { + SR_BSY, "BSY" +}, +{ + SR_REQ, "REQ" +}, { + SR_MSG, "MSG" +}, { + SR_CD, "CD" +}, { + SR_IO, "IO" +}, +{ + SR_SEL, "SEL" +}, { + 0, NULL +} +}, + +basrs[] = { { + BASR_ATN, "ATN" +}, { + BASR_ACK, "ACK" +}, { + 0, NULL +} +}, + +icrs[] = { { + ICR_ASSERT_RST, "ASSERT RST" +}, { + ICR_ASSERT_ACK, "ASSERT ACK" +}, +{ + ICR_ASSERT_BSY, "ASSERT BSY" +}, { + ICR_ASSERT_SEL, "ASSERT SEL" +}, +{ + ICR_ASSERT_ATN, "ASSERT ATN" +}, { + ICR_ASSERT_DATA, "ASSERT DATA" +}, +{ + 0, NULL +} +}, + +mrs[] = { { + MR_BLOCK_DMA_MODE, "MODE BLOCK DMA" +}, { + MR_TARGET, "MODE TARGET" +}, +{ + MR_ENABLE_PAR_CHECK, "MODE PARITY CHECK" +}, { + MR_ENABLE_PAR_INTR, + "MODE PARITY INTR" +}, { + MR_MONITOR_BSY, "MODE MONITOR BSY" +}, +{ + MR_DMA_MODE, "MODE DMA" +}, { + MR_ARBITRATE, "MODE ARBITRATION" +}, +{ + 0, NULL +} +}; /* * Function : void NCR5380_print(struct Scsi_Host *instance) @@ -365,43 +428,62 @@ * Input : instance - which NCR5380 */ -static void NCR5380_print(struct Scsi_Host *instance) { - NCR5380_local_declare(); - unsigned char status, data, basr, mr, icr, i; - NCR5380_setup(instance); - cli(); - data = NCR5380_read(CURRENT_SCSI_DATA_REG); - status = NCR5380_read(STATUS_REG); - mr = NCR5380_read(MODE_REG); - icr = NCR5380_read(INITIATOR_COMMAND_REG); - basr = NCR5380_read(BUS_AND_STATUS_REG); - sti(); - printk("STATUS_REG: %02x ", status); - for (i = 0; signals[i].mask ; ++i) - if (status & signals[i].mask) - printk(",%s", signals[i].name); - printk("\nBASR: %02x ", basr); - for (i = 0; basrs[i].mask ; ++i) - if (basr & basrs[i].mask) - printk(",%s", basrs[i].name); - printk("\nICR: %02x ", icr); - for (i = 0; icrs[i].mask; ++i) - if (icr & icrs[i].mask) - printk(",%s", icrs[i].name); - printk("\nMODE: %02x ", mr); - for (i = 0; mrs[i].mask; ++i) - if (mr & mrs[i].mask) - printk(",%s", mrs[i].name); - printk("\n"); +static void NCR5380_print(struct Scsi_Host *instance) +{ + NCR5380_local_declare(); + unsigned long flags; + unsigned char status, data, basr, mr, icr, i; + NCR5380_setup(instance); + save_flags(flags); + cli(); + data = NCR5380_read(CURRENT_SCSI_DATA_REG); + status = NCR5380_read(STATUS_REG); + mr = NCR5380_read(MODE_REG); + icr = NCR5380_read(INITIATOR_COMMAND_REG); + basr = NCR5380_read(BUS_AND_STATUS_REG); + restore_flags(flags); + printk("STATUS_REG: %02x ", status); + for (i = 0; signals[i].mask; ++i) + if (status & signals[i].mask) + printk(",%s", signals[i].name); + printk("\nBASR: %02x ", basr); + for (i = 0; basrs[i].mask; ++i) + if (basr & basrs[i].mask) + printk(",%s", basrs[i].name); + printk("\nICR: %02x ", icr); + for (i = 0; icrs[i].mask; ++i) + if (icr & icrs[i].mask) + printk(",%s", icrs[i].name); + printk("\nMODE: %02x ", mr); + for (i = 0; mrs[i].mask; ++i) + if (mr & mrs[i].mask) + printk(",%s", mrs[i].name); + printk("\n"); } static struct { - unsigned char value; - const char *name; + unsigned char value; + const char *name; } phases[] = { -{PHASE_DATAOUT, "DATAOUT"}, {PHASE_DATAIN, "DATAIN"}, {PHASE_CMDOUT, "CMDOUT"}, -{PHASE_STATIN, "STATIN"}, {PHASE_MSGOUT, "MSGOUT"}, {PHASE_MSGIN, "MSGIN"}, -{PHASE_UNKNOWN, "UNKNOWN"}}; + + { + PHASE_DATAOUT, "DATAOUT" + }, { + PHASE_DATAIN, "DATAIN" + }, { + PHASE_CMDOUT, "CMDOUT" + }, + { + PHASE_STATIN, "STATIN" + }, { + PHASE_MSGOUT, "MSGOUT" + }, { + PHASE_MSGIN, "MSGIN" + }, + { + PHASE_UNKNOWN, "UNKNOWN" + } +}; /* * Function : void NCR5380_print_phase(struct Scsi_Host *instance) @@ -411,21 +493,22 @@ * Input : instance - which NCR5380 */ -static void NCR5380_print_phase(struct Scsi_Host *instance) { - NCR5380_local_declare(); - unsigned char status; - int i; - NCR5380_setup(instance); - - status = NCR5380_read(STATUS_REG); - if (!(status & SR_REQ)) - printk("scsi%d : REQ not asserted, phase unknown.\n", - instance->host_no); - else { - for (i = 0; (phases[i].value != PHASE_UNKNOWN) && - (phases[i].value != (status & PHASE_MASK)); ++i); - printk("scsi%d : phase %s\n", instance->host_no, phases[i].name); - } +static void NCR5380_print_phase(struct Scsi_Host *instance) +{ + NCR5380_local_declare(); + unsigned char status; + int i; + NCR5380_setup(instance); + + status = NCR5380_read(STATUS_REG); + if (!(status & SR_REQ)) + printk("scsi%d : REQ not asserted, phase unknown.\n", + instance->host_no); + else { + for (i = 0; (phases[i].value != PHASE_UNKNOWN) && + (phases[i].value != (status & PHASE_MASK)); ++i); + printk("scsi%d : phase %s\n", instance->host_no, phases[i].name); + } } #endif @@ -454,24 +537,26 @@ * Function : run_main(void) * * Purpose : insure that the coroutine is running and will process our - * request. main_running is checked/set here (in an inline function) - * rather than in NCR5380_main itself to reduce the chances of stack - * overflow. + * request. main_running is checked/set here (in an inline function) + * rather than in NCR5380_main itself to reduce the chances of stack + * overflow. * */ -static __inline__ void run_main(void) { - cli(); - if (!main_running) { - main_running = 1; - NCR5380_main(); - /* - * main_running is cleared in NCR5380_main once it can't do - * more work, and NCR5380_main exits with interrupts disabled. - */ - sti(); - } else - sti(); +static __inline__ void run_main(void) +{ + unsigned long flags; + save_flags(flags); + cli(); + if (!main_running) { + main_running = 1; + NCR5380_main(); + /* + * main_running is cleared in NCR5380_main once it can't do + * more work, and NCR5380_main exits with interrupts disabled. + */ + } + restore_flags(flags); } #ifdef USLEEP @@ -498,116 +583,123 @@ #define USLEEP_POLL (200*HZ/1000) #endif -static struct Scsi_Host * expires_first = NULL; +static struct Scsi_Host *expires_first = NULL; /* * Function : int should_disconnect (unsigned char cmd) * * Purpose : decide weather a command would normally disconnect or - * not, since if it won't disconnect we should go to sleep. + * not, since if it won't disconnect we should go to sleep. * * Input : cmd - opcode of SCSI command * * Returns : DISCONNECT_LONG if we should disconnect for a really long - * time (ie always, sleep, look for REQ active, sleep), - * DISCONNECT_TIME_TO_DATA if we would only disconnect for a normal - * time-to-data delay, DISCONNECT_NONE if this command would return - * immediately. + * time (ie always, sleep, look for REQ active, sleep), + * DISCONNECT_TIME_TO_DATA if we would only disconnect for a normal + * time-to-data delay, DISCONNECT_NONE if this command would return + * immediately. * * Future sleep algorithms based on time to data can exploit * something like this so they can differentiate between "normal" - * (ie, read, write, seek) and unusual commands (ie, * format). + * (ie, read, write, seek) and unusual commands (ie, * format). * * Note : We don't deal with commands that handle an immediate disconnect, * */ -static int should_disconnect (unsigned char cmd) { - switch (cmd) { - case READ_6: - case WRITE_6: - case SEEK_6: - case READ_10: - case WRITE_10: - case SEEK_10: - return DISCONNECT_TIME_TO_DATA; - case FORMAT_UNIT: - case SEARCH_HIGH: - case SEARCH_LOW: - case SEARCH_EQUAL: - return DISCONNECT_LONG; - default: - return DISCONNECT_NONE; - } +static int should_disconnect(unsigned char cmd) +{ + switch (cmd) { + case READ_6: + case WRITE_6: + case SEEK_6: + case READ_10: + case WRITE_10: + case SEEK_10: + return DISCONNECT_TIME_TO_DATA; + case FORMAT_UNIT: + case SEARCH_HIGH: + case SEARCH_LOW: + case SEARCH_EQUAL: + return DISCONNECT_LONG; + default: + return DISCONNECT_NONE; + } } /* * Assumes instance->time_expires has been set in higher level code. */ -static int NCR5380_set_timer (struct Scsi_Host *instance) { - struct Scsi_Host *tmp, **prev; - - cli(); - if (((struct NCR5380_hostdata *) (instance->host_data))->next_timer) { - sti(); - return -1; - } - - for (prev = &expires_first, tmp = expires_first; tmp; - prev = &(((struct NCR5380_hostdata *) tmp->host_data)->next_timer), - tmp = ((struct NCR5380_hostdata *) tmp->host_data)->next_timer) - if (instance->time_expires < tmp->time_expires) - break; - - instance->next_timer = tmp; - *prev = instance; - timer_table[NCR5380_TIMER].expires = expires_first->time_expires; - timer_active |= 1 << NCR5380_TIMER; - sti(); - return 0; -} +static int NCR5380_set_timer(struct Scsi_Host *instance) +{ + unsigned long flags; + struct Scsi_Host *tmp, **prev; + + save_flags(flags); + cli(); + if (((struct NCR5380_hostdata *) (instance->host_data))->next_timer) { + restore_flags(flags); + return -1; + } + for (prev = &expires_first, tmp = expires_first; tmp; + prev = &(((struct NCR5380_hostdata *) tmp->host_data)->next_timer), + tmp = ((struct NCR5380_hostdata *) tmp->host_data)->next_timer) + if (instance->time_expires < tmp->time_expires) + break; + + instance->next_timer = tmp; + *prev = instance; + timer_table[NCR5380_TIMER].expires = expires_first->time_expires; + timer_active |= 1 << NCR5380_TIMER; + restore_flags(flags); + return 0; +} /* Doing something about unwanted reentrancy here might be useful */ -void NCR5380_timer_fn(void) { - struct Scsi_Host *instance; - cli(); - for (; expires_first && expires_first->time_expires >= jiffies; ) { - instance = ((NCR5380_hostdata *) expires_first->host_data)-> - expires_next; - ((NCR5380_hostdata *) expires_first->host_data)->expires_next = - NULL; - ((NCR5380_hostdata *) expires_first->host_data)->time_expires = - 0; - expires_first = instance; - } - - if (expires_first) { - timer_table[NCR5380_TIMER].expires = ((NCR5380_hostdata *) - expires_first->host_data)->time_expires; - timer_active |= (1 << NCR5380_TIMER); - } else { - timer_table[NCR5380_TIMER].expires = 0; - timer_active &= ~(1 << MCR5380_TIMER); - } - sti(); - - run_main(); -} -#endif /* def USLEEP */ - -static inline void NCR5380_all_init (void) { - static int done = 0; - if (!done) { +void NCR5380_timer_fn(void) +{ + unsigned long flags; + struct Scsi_Host *instance; + save_flags(flags); + cli(); + for (; expires_first && expires_first->time_expires >= jiffies;) { + instance = ((NCR5380_hostdata *) expires_first->host_data)-> + expires_next; + ((NCR5380_hostdata *) expires_first->host_data)->expires_next = + NULL; + ((NCR5380_hostdata *) expires_first->host_data)->time_expires = + 0; + expires_first = instance; + } + + if (expires_first) { + timer_table[NCR5380_TIMER].expires = ((NCR5380_hostdata *) + expires_first->host_data)->time_expires; + timer_active |= (1 << NCR5380_TIMER); + } else { + timer_table[NCR5380_TIMER].expires = 0; + timer_active &= ~(1 << MCR5380_TIMER); + } + restore_flags(flags); + + run_main(); +} +#endif /* def USLEEP */ + +static inline void NCR5380_all_init(void) +{ + static int done = 0; + if (!done) { #if (NDEBUG & NDEBUG_INIT) - printk("scsi : NCR5380_all_init()\n"); + printk("scsi : NCR5380_all_init()\n"); #endif - done = 1; + done = 1; #ifdef USLEEP - timer_table[NCR5380_TIMER].expires = 0; - timer_table[NCR5380_TIMER].fn = NCR5380_timer_fn; + timer_table[NCR5380_TIMER].expires = 0; + timer_table[NCR5380_TIMER].fn = NCR5380_timer_fn; #endif - } + } } #ifdef AUTOPROBE_IRQ @@ -627,25 +719,27 @@ static int probe_irq __initdata = 0; -__initfunc(static void probe_intr (int irq, void *dev_id, struct pt_regs * regs)) { - probe_irq = irq; -}; +__initfunc(static void probe_intr(int irq, void *dev_id, struct pt_regs *regs)) +{ + probe_irq = irq; +} -__initfunc(static int NCR5380_probe_irq (struct Scsi_Host *instance, int possible)) { - NCR5380_local_declare(); - struct NCR5380_hostdata *hostdata = (struct NCR5380_hostdata *) - instance->hostdata; - unsigned long timeout; - int trying_irqs, i, mask; - NCR5380_setup(instance); - - for (trying_irqs = i = 0, mask = 1; i < 16; ++i, mask <<= 1) - if ((mask & possible) && (request_irq(i, &probe_intr, SA_INTERRUPT, "NCR-probe", NULL) - == 0)) - trying_irqs |= mask; +__initfunc(static int NCR5380_probe_irq(struct Scsi_Host *instance, int possible)) +{ + NCR5380_local_declare(); + struct NCR5380_hostdata *hostdata = (struct NCR5380_hostdata *) + instance->hostdata; + unsigned long timeout; + int trying_irqs, i, mask; + NCR5380_setup(instance); + + for (trying_irqs = i = 0, mask = 1; i < 16; ++i, mask <<= 1) + if ((mask & possible) && (request_irq(i, &probe_intr, SA_INTERRUPT, "NCR-probe", NULL) + == 0)) + trying_irqs |= mask; - timeout = jiffies + (250*HZ/1000); - probe_irq = IRQ_NONE; + timeout = jiffies + (250 * HZ / 1000); + probe_irq = IRQ_NONE; /* * A interrupt is triggered whenever BSY = false, SEL = true @@ -657,101 +751,103 @@ * to zero. */ - NCR5380_write(TARGET_COMMAND_REG, 0); - NCR5380_write(SELECT_ENABLE_REG, hostdata->id_mask); - NCR5380_write(OUTPUT_DATA_REG, hostdata->id_mask); - NCR5380_write(INITIATOR_COMMAND_REG, ICR_BASE | ICR_ASSERT_DATA | - ICR_ASSERT_SEL); - - while (probe_irq == IRQ_NONE && jiffies < timeout) - barrier(); - - NCR5380_write(SELECT_ENABLE_REG, 0); - NCR5380_write(INITIATOR_COMMAND_REG, ICR_BASE); - - for (i = 0, mask = 1; i < 16; ++i, mask <<= 1) - if (trying_irqs & mask) - free_irq(i, NULL); + NCR5380_write(TARGET_COMMAND_REG, 0); + NCR5380_write(SELECT_ENABLE_REG, hostdata->id_mask); + NCR5380_write(OUTPUT_DATA_REG, hostdata->id_mask); + NCR5380_write(INITIATOR_COMMAND_REG, ICR_BASE | ICR_ASSERT_DATA | + ICR_ASSERT_SEL); + + while (probe_irq == IRQ_NONE && jiffies < timeout) + barrier(); - return probe_irq; + NCR5380_write(SELECT_ENABLE_REG, 0); + NCR5380_write(INITIATOR_COMMAND_REG, ICR_BASE); + + for (i = 0, mask = 1; i < 16; ++i, mask <<= 1) + if (trying_irqs & mask) + free_irq(i, NULL); + + return probe_irq; } -#endif /* AUTOPROBE_IRQ */ - +#endif /* AUTOPROBE_IRQ */ + /* * Function : void NCR58380_print_options (struct Scsi_Host *instance) * * Purpose : called by probe code indicating the NCR5380 driver - * options that were selected. + * options that were selected. * * Inputs : instance, pointer to this instance. Unused. */ -__initfunc(static void NCR5380_print_options (struct Scsi_Host *instance)) { - printk(" generic options" +__initfunc(static void NCR5380_print_options(struct Scsi_Host *instance)) +{ + printk(" generic options" #ifdef AUTOPROBE_IRQ - " AUTOPROBE_IRQ" + " AUTOPROBE_IRQ" #endif -#ifdef AUTOSENSE - " AUTOSENSE" +#ifdef AUTOSENSE + " AUTOSENSE" #endif #ifdef DIFFERENTIAL - " DIFFERENTIAL" + " DIFFERENTIAL" #endif #ifdef REAL_DMA - " REAL DMA" + " REAL DMA" #endif #ifdef REAL_DMA_POLL - " REAL DMA POLL" + " REAL DMA POLL" #endif #ifdef PARITY - " PARITY" + " PARITY" #endif #ifdef PSEUDO_DMA - " PSEUDO DMA" + " PSEUDO DMA" #endif #ifdef SCSI2 - " SCSI-2" + " SCSI-2" #endif #ifdef UNSAFE - " UNSAFE " + " UNSAFE " #endif - ); + ); #ifdef USLEEP - printk(" USLEEP, USLEEP_POLL=%d USLEEP_SLEEP=%d", USLEEP_POLL, USLEEP_SLEEP); + printk(" USLEEP, USLEEP_POLL=%d USLEEP_SLEEP=%d", USLEEP_POLL, USLEEP_SLEEP); #endif - printk(" generic release=%d", NCR5380_PUBLIC_RELEASE); - if (((struct NCR5380_hostdata *)instance->hostdata)->flags & FLAG_NCR53C400) { - printk(" ncr53c400 release=%d", NCR53C400_PUBLIC_RELEASE); - } + printk(" generic release=%d", NCR5380_PUBLIC_RELEASE); + if (((struct NCR5380_hostdata *) instance->hostdata)->flags & FLAG_NCR53C400) { + printk(" ncr53c400 release=%d", NCR53C400_PUBLIC_RELEASE); + } } /* * Function : void NCR5380_print_status (struct Scsi_Host *instance) * * Purpose : print commands in the various queues, called from - * NCR5380_abort and NCR5380_debug to aid debugging. + * NCR5380_abort and NCR5380_debug to aid debugging. * * Inputs : instance, pointer to this instance. */ -static void NCR5380_print_status (struct Scsi_Host *instance) { - static char pr_bfr[512]; - char *start; - int len; - - printk("NCR5380 : coroutine is%s running.\n", - main_running ? "" : "n't"); - +static void NCR5380_print_status(struct Scsi_Host *instance) +{ + static char pr_bfr[512]; + char *start; + int len; + + printk("NCR5380 : coroutine is%s running.\n", + main_running ? "" : "n't"); + #ifdef NDEBUG - NCR5380_print (instance); - NCR5380_print_phase (instance); + NCR5380_print(instance); + NCR5380_print_phase(instance); #endif - len = NCR5380_proc_info(pr_bfr, &start, 0, sizeof(pr_bfr), - instance->host_no, 0); - pr_bfr[len] = 0; - printk("\n%s\n", pr_bfr); - } + len = NCR5380_proc_info(pr_bfr, &start, 0, sizeof(pr_bfr), + instance->host_no, 0); + pr_bfr[len] = 0; + printk("\n%s\n", pr_bfr); +} /******************************************/ /* @@ -765,126 +861,130 @@ * inout: TRUE - user is writing; FALSE - user is reading * * Return the number of bytes read from or written -*/ + */ #undef SPRINTF #define SPRINTF(args...) do { if(pos < buffer + length-80) pos += sprintf(pos, ## args); } while(0) static -char *lprint_Scsi_Cmnd (Scsi_Cmnd *cmd, char *pos, char *buffer, int length); +char *lprint_Scsi_Cmnd(Scsi_Cmnd * cmd, char *pos, char *buffer, int length); static -char *lprint_command (unsigned char *cmd, char *pos, char *buffer, int len); +char *lprint_command(unsigned char *cmd, char *pos, char *buffer, int len); static char *lprint_opcode(int opcode, char *pos, char *buffer, int length); #ifndef NCR5380_proc_info static #endif -int NCR5380_proc_info ( - char *buffer, char **start,off_t offset, - int length,int hostno,int inout) -{ - char *pos = buffer; - struct Scsi_Host *instance; - struct NCR5380_hostdata *hostdata; - Scsi_Cmnd *ptr; - - for (instance = first_instance; instance && - instance->host_no != hostno; instance=instance->next) - ; - if (!instance) - return(-ESRCH); - hostdata = (struct NCR5380_hostdata *)instance->hostdata; +int NCR5380_proc_info( + char *buffer, char **start, off_t offset, + int length, int hostno, int inout) +{ + unsigned long flags; + char *pos = buffer; + struct Scsi_Host *instance; + struct NCR5380_hostdata *hostdata; + Scsi_Cmnd *ptr; + + for (instance = first_instance; instance && + instance->host_no != hostno; instance = instance->next); + if (!instance) + return (-ESRCH); + hostdata = (struct NCR5380_hostdata *) instance->hostdata; - if (inout) { /* Has data been written to the file ? */ + if (inout) { /* Has data been written to the file ? */ #ifdef DTC_PUBLIC_RELEASE - dtc_wmaxi = dtc_maxi = 0; + dtc_wmaxi = dtc_maxi = 0; #endif #ifdef PAS16_PUBLIC_RELEASE - pas_wmaxi = pas_maxi = 0; + pas_wmaxi = pas_maxi = 0; #endif - return(-ENOSYS); /* Currently this is a no-op */ - } - SPRINTF("NCR5380 core release=%d. ", NCR5380_PUBLIC_RELEASE); - if (((struct NCR5380_hostdata *)instance->hostdata)->flags & FLAG_NCR53C400) - SPRINTF("ncr53c400 release=%d. ", NCR53C400_PUBLIC_RELEASE); + return (-ENOSYS); /* Currently this is a no-op */ + } + SPRINTF("NCR5380 core release=%d. ", NCR5380_PUBLIC_RELEASE); + if (((struct NCR5380_hostdata *) instance->hostdata)->flags & FLAG_NCR53C400) + SPRINTF("ncr53c400 release=%d. ", NCR53C400_PUBLIC_RELEASE); #ifdef DTC_PUBLIC_RELEASE - SPRINTF("DTC 3180/3280 release %d", DTC_PUBLIC_RELEASE); + SPRINTF("DTC 3180/3280 release %d", DTC_PUBLIC_RELEASE); #endif #ifdef T128_PUBLIC_RELEASE - SPRINTF("T128 release %d", T128_PUBLIC_RELEASE); + SPRINTF("T128 release %d", T128_PUBLIC_RELEASE); #endif #ifdef GENERIC_NCR5380_PUBLIC_RELEASE - SPRINTF("Generic5380 release %d", GENERIC_NCR5380_PUBLIC_RELEASE); + SPRINTF("Generic5380 release %d", GENERIC_NCR5380_PUBLIC_RELEASE); #endif #ifdef PAS16_PUBLIC_RELEASE -SPRINTF("PAS16 release=%d", PAS16_PUBLIC_RELEASE); + SPRINTF("PAS16 release=%d", PAS16_PUBLIC_RELEASE); #endif - SPRINTF("\nBase Addr: 0x%05lX ", (long)instance->base); - SPRINTF("io_port: %04x ", (int)instance->io_port); - if (instance->irq == IRQ_NONE) - SPRINTF("IRQ: None.\n"); - else - SPRINTF("IRQ: %d.\n", instance->irq); + SPRINTF("\nBase Addr: 0x%05lX ", (long) instance->base); + SPRINTF("io_port: %04x ", (int) instance->io_port); + if (instance->irq == IRQ_NONE) + SPRINTF("IRQ: None.\n"); + else + SPRINTF("IRQ: %d.\n", instance->irq); #ifdef DTC_PUBLIC_RELEASE - SPRINTF("Highwater I/O busy_spin_counts -- write: %d read: %d\n", - dtc_wmaxi, dtc_maxi); + SPRINTF("Highwater I/O busy_spin_counts -- write: %d read: %d\n", + dtc_wmaxi, dtc_maxi); #endif #ifdef PAS16_PUBLIC_RELEASE - SPRINTF("Highwater I/O busy_spin_counts -- write: %d read: %d\n", - pas_wmaxi, pas_maxi); + SPRINTF("Highwater I/O busy_spin_counts -- write: %d read: %d\n", + pas_wmaxi, pas_maxi); #endif - cli(); - SPRINTF("NCR5380 : coroutine is%s running.\n", main_running ? "" : "n't"); - if (!hostdata->connected) - SPRINTF("scsi%d: no currently connected command\n", instance->host_no); - else - pos = lprint_Scsi_Cmnd ((Scsi_Cmnd *) hostdata->connected, - pos, buffer, length); - SPRINTF("scsi%d: issue_queue\n", instance->host_no); - for (ptr = (Scsi_Cmnd *) hostdata->issue_queue; ptr; - ptr = (Scsi_Cmnd *) ptr->host_scribble) - pos = lprint_Scsi_Cmnd (ptr, pos, buffer, length); - - SPRINTF("scsi%d: disconnected_queue\n", instance->host_no); - for (ptr = (Scsi_Cmnd *) hostdata->disconnected_queue; ptr; - ptr = (Scsi_Cmnd *) ptr->host_scribble) - pos = lprint_Scsi_Cmnd (ptr, pos, buffer, length); - - sti(); - *start=buffer; - if (pos - buffer < offset) - return 0; - else if (pos - buffer - offset < length) - return pos - buffer - offset; - return length; -} - -static -char *lprint_Scsi_Cmnd (Scsi_Cmnd *cmd, char *pos, char *buffer, int length) { - SPRINTF("scsi%d : destination target %d, lun %d\n", - cmd->host->host_no, cmd->target, cmd->lun); - SPRINTF(" command = "); - pos = lprint_command (cmd->cmnd, pos, buffer, length); - return (pos); -} - -static -char *lprint_command (unsigned char *command, - char *pos, char *buffer, int length) { - int i, s; - pos = lprint_opcode(command[0], pos, buffer, length); - for ( i = 1, s = COMMAND_SIZE(command[0]); i < s; ++i) - SPRINTF("%02x ", command[i]); - SPRINTF("\n"); - return(pos); -} - -static -char *lprint_opcode(int opcode, char *pos, char *buffer, int length) { - SPRINTF("%2d (0x%02x)", opcode, opcode); - return(pos); + save_flags(flags); + cli(); + SPRINTF("NCR5380 : coroutine is%s running.\n", main_running ? "" : "n't"); + if (!hostdata->connected) + SPRINTF("scsi%d: no currently connected command\n", instance->host_no); + else + pos = lprint_Scsi_Cmnd((Scsi_Cmnd *) hostdata->connected, + pos, buffer, length); + SPRINTF("scsi%d: issue_queue\n", instance->host_no); + for (ptr = (Scsi_Cmnd *) hostdata->issue_queue; ptr; + ptr = (Scsi_Cmnd *) ptr->host_scribble) + pos = lprint_Scsi_Cmnd(ptr, pos, buffer, length); + + SPRINTF("scsi%d: disconnected_queue\n", instance->host_no); + for (ptr = (Scsi_Cmnd *) hostdata->disconnected_queue; ptr; + ptr = (Scsi_Cmnd *) ptr->host_scribble) + pos = lprint_Scsi_Cmnd(ptr, pos, buffer, length); + + restore_flags(flags); + *start = buffer; + if (pos - buffer < offset) + return 0; + else if (pos - buffer - offset < length) + return pos - buffer - offset; + return length; +} + +static +char *lprint_Scsi_Cmnd(Scsi_Cmnd * cmd, char *pos, char *buffer, int length) +{ + SPRINTF("scsi%d : destination target %d, lun %d\n", + cmd->host->host_no, cmd->target, cmd->lun); + SPRINTF(" command = "); + pos = lprint_command(cmd->cmnd, pos, buffer, length); + return (pos); +} + +static +char *lprint_command(unsigned char *command, + char *pos, char *buffer, int length) +{ + int i, s; + pos = lprint_opcode(command[0], pos, buffer, length); + for (i = 1, s = COMMAND_SIZE(command[0]); i < s; ++i) + SPRINTF("%02x ", command[i]); + SPRINTF("\n"); + return (pos); +} + +static +char *lprint_opcode(int opcode, char *pos, char *buffer, int length) +{ + SPRINTF("%2d (0x%02x)", opcode, opcode); + return (pos); } @@ -892,152 +992,152 @@ * Function : void NCR5380_init (struct Scsi_Host *instance, flags) * * Purpose : initializes *instance and corresponding 5380 chip, - * with flags OR'd into the initial flags value. + * with flags OR'd into the initial flags value. * * Inputs : instance - instantiation of the 5380 driver. * * Notes : I assume that the host, hostno, and id bits have been - * set correctly. I don't care about the irq and other fields. + * set correctly. I don't care about the irq and other fields. * */ -__initfunc(static void NCR5380_init (struct Scsi_Host *instance, int flags)) { - NCR5380_local_declare(); - int i, pass; - unsigned long timeout; - struct NCR5380_hostdata *hostdata = (struct NCR5380_hostdata *) +__initfunc(static void NCR5380_init(struct Scsi_Host *instance, int flags)) +{ + NCR5380_local_declare(); + int i, pass; + unsigned long timeout; + struct NCR5380_hostdata *hostdata = (struct NCR5380_hostdata *) instance->hostdata; - /* - * On NCR53C400 boards, NCR5380 registers are mapped 8 past - * the base address. - */ + /* + * On NCR53C400 boards, NCR5380 registers are mapped 8 past + * the base address. + */ #ifdef NCR53C400 - if (flags & FLAG_NCR53C400) - instance->NCR5380_instance_name += NCR53C400_address_adjust; + if (flags & FLAG_NCR53C400) + instance->NCR5380_instance_name += NCR53C400_address_adjust; #endif - NCR5380_setup(instance); + NCR5380_setup(instance); - NCR5380_all_init(); + NCR5380_all_init(); - hostdata->aborted = 0; - hostdata->id_mask = 1 << instance->this_id; - for (i = hostdata->id_mask; i <= 0x80; i <<= 1) - if (i > hostdata->id_mask) - hostdata->id_higher_mask |= i; - for (i = 0; i < 8; ++i) - hostdata->busy[i] = 0; + hostdata->aborted = 0; + hostdata->id_mask = 1 << instance->this_id; + for (i = hostdata->id_mask; i <= 0x80; i <<= 1) + if (i > hostdata->id_mask) + hostdata->id_higher_mask |= i; + for (i = 0; i < 8; ++i) + hostdata->busy[i] = 0; #ifdef REAL_DMA - hostdata->dmalen = 0; + hostdata->dmalen = 0; #endif - hostdata->targets_present = 0; - hostdata->connected = NULL; - hostdata->issue_queue = NULL; - hostdata->disconnected_queue = NULL; + hostdata->targets_present = 0; + hostdata->connected = NULL; + hostdata->issue_queue = NULL; + hostdata->disconnected_queue = NULL; #ifdef NCR5380_STATS - for (i = 0; i < 8; ++i) { - hostdata->time_read[i] = 0; - hostdata->time_write[i] = 0; - hostdata->bytes_read[i] = 0; - hostdata->bytes_write[i] = 0; - } - hostdata->timebase = 0; - hostdata->pendingw = 0; - hostdata->pendingr = 0; -#endif - - /* The CHECK code seems to break the 53C400. Will check it later maybe */ - if (flags & FLAG_NCR53C400) - hostdata->flags = FLAG_HAS_LAST_BYTE_SENT | flags; - else - hostdata->flags = FLAG_CHECK_LAST_BYTE_SENT | flags; - - if (!the_template) { - the_template = instance->hostt; - first_instance = instance; - } - + for (i = 0; i < 8; ++i) { + hostdata->time_read[i] = 0; + hostdata->time_write[i] = 0; + hostdata->bytes_read[i] = 0; + hostdata->bytes_write[i] = 0; + } + hostdata->timebase = 0; + hostdata->pendingw = 0; + hostdata->pendingr = 0; +#endif + /* The CHECK code seems to break the 53C400. Will check it later maybe */ + if (flags & FLAG_NCR53C400) + hostdata->flags = FLAG_HAS_LAST_BYTE_SENT | flags; + else + hostdata->flags = FLAG_CHECK_LAST_BYTE_SENT | flags; + + if (!the_template) { + the_template = instance->hostt; + first_instance = instance; + } #ifdef USLEEP - hostdata->time_expires = 0; - hostdata->next_timer = NULL; + hostdata->time_expires = 0; + hostdata->next_timer = NULL; #endif #ifndef AUTOSENSE - if ((instance->cmd_per_lun > 1) || instance->can_queue > 1)) - printk("scsi%d : WARNING : support for multiple outstanding commands enabled\n" - " without AUTOSENSE option, contingent allegiance conditions may\n" + if ((instance->cmd_per_lun > 1) || instance->can_queue > 1) + ) + printk("scsi%d : WARNING : support for multiple outstanding commands enabled\n" + " without AUTOSENSE option, contingent allegiance conditions may\n" " be incorrectly cleared.\n", instance->host_no); -#endif /* def AUTOSENSE */ +#endif /* def AUTOSENSE */ - NCR5380_write(INITIATOR_COMMAND_REG, ICR_BASE); - NCR5380_write(MODE_REG, MR_BASE); - NCR5380_write(TARGET_COMMAND_REG, 0); - NCR5380_write(SELECT_ENABLE_REG, 0); + NCR5380_write(INITIATOR_COMMAND_REG, ICR_BASE); + NCR5380_write(MODE_REG, MR_BASE); + NCR5380_write(TARGET_COMMAND_REG, 0); + NCR5380_write(SELECT_ENABLE_REG, 0); #ifdef NCR53C400 - if (hostdata->flags & FLAG_NCR53C400) { - NCR5380_write(C400_CONTROL_STATUS_REG, CSR_BASE); - } -#endif - - /* - * Detect and correct bus wedge problems. - * - * If the system crashed, it may have crashed in a state - * where a SCSI command was still executing, and the - * SCSI bus is not in a BUS FREE STATE. - * - * If this is the case, we'll try to abort the currently - * established nexus which we know nothing about, and that - * failing, do a hard reset of the SCSI bus - */ - - for (pass = 1; (NCR5380_read(STATUS_REG) & SR_BSY) && - pass <= 6 ; ++pass) { - switch (pass) { - case 1: - case 3: - case 5: - printk("scsi%d: SCSI bus busy, waiting up to five seconds\n", - instance->host_no); - timeout = jiffies + 5*HZ; - while (jiffies < timeout && (NCR5380_read(STATUS_REG) & SR_BSY)); - break; - case 2: - printk("scsi%d: bus busy, attempting abort\n", - instance->host_no); - do_abort (instance); - break; - case 4: - printk("scsi%d: bus busy, attempting reset\n", - instance->host_no); - do_reset (instance); - break; - case 6: - printk("scsi%d: bus locked solid or invalid override\n", - instance->host_no); + if (hostdata->flags & FLAG_NCR53C400) { + NCR5380_write(C400_CONTROL_STATUS_REG, CSR_BASE); + } +#endif + + /* + * Detect and correct bus wedge problems. + * + * If the system crashed, it may have crashed in a state + * where a SCSI command was still executing, and the + * SCSI bus is not in a BUS FREE STATE. + * + * If this is the case, we'll try to abort the currently + * established nexus which we know nothing about, and that + * failing, do a hard reset of the SCSI bus + */ + + for (pass = 1; (NCR5380_read(STATUS_REG) & SR_BSY) && + pass <= 6; ++pass) { + switch (pass) { + case 1: + case 3: + case 5: + printk("scsi%d: SCSI bus busy, waiting up to five seconds\n", + instance->host_no); + timeout = jiffies + 5 * HZ; + while (jiffies < timeout && (NCR5380_read(STATUS_REG) & SR_BSY)); + break; + case 2: + printk("scsi%d: bus busy, attempting abort\n", + instance->host_no); + do_abort(instance); + break; + case 4: + printk("scsi%d: bus busy, attempting reset\n", + instance->host_no); + do_reset(instance); + break; + case 6: + printk("scsi%d: bus locked solid or invalid override\n", + instance->host_no); + } } - } } /* * Function : int NCR5380_queue_command (Scsi_Cmnd *cmd, - * void (*done)(Scsi_Cmnd *)) + * void (*done)(Scsi_Cmnd *)) * * Purpose : enqueues a SCSI command * * Inputs : cmd - SCSI command, done - function called on completion, with - * a pointer to the command descriptor. + * a pointer to the command descriptor. * * Returns : 0 * * Side effects : * cmd is added to the per instance issue_queue, with minor - * twiddling done to the host specific fields of cmd. If the - * main coroutine is not running, it is restarted. + * twiddling done to the host specific fields of cmd. If the + * main coroutine is not running, it is restarted. * */ @@ -1045,237 +1145,239 @@ #ifndef NCR5380_queue_command static #endif -int NCR5380_queue_command (Scsi_Cmnd *cmd, void (*done)(Scsi_Cmnd *)) { - struct Scsi_Host *instance = cmd->host; - struct NCR5380_hostdata *hostdata = (struct NCR5380_hostdata *) - instance->hostdata; - Scsi_Cmnd *tmp; +int NCR5380_queue_command(Scsi_Cmnd * cmd, void (*done) (Scsi_Cmnd *)) { + struct Scsi_Host *instance = cmd->host; + struct NCR5380_hostdata *hostdata = (struct NCR5380_hostdata *) + instance->hostdata; + Scsi_Cmnd *tmp; #if (NDEBUG & NDEBUG_NO_WRITE) - switch (cmd->cmnd[0]) { - case WRITE_6: - case WRITE_10: - printk("scsi%d : WRITE attempted with NO_WRITE debugging flag set\n", - instance->host_no); - cmd->result = (DID_ERROR << 16); - done(cmd); - return 0; - } -#endif /* (NDEBUG & NDEBUG_NO_WRITE) */ + switch (cmd->cmnd[0]) { + case WRITE_6: + case WRITE_10: + printk("scsi%d : WRITE attempted with NO_WRITE debugging flag set\n", + instance->host_no); + cmd->result = (DID_ERROR << 16); + done(cmd); + return 0; + } +#endif /* (NDEBUG & NDEBUG_NO_WRITE) */ #ifdef NCR5380_STATS -# if 0 - if (!hostdata->connected && !hostdata->issue_queue && - !hostdata->disconnected_queue) { - hostdata->timebase = jiffies; - } -# endif -# ifdef NCR5380_STAT_LIMIT - if (cmd->request_bufflen > NCR5380_STAT_LIMIT) -# endif - switch (cmd->cmnd[0]) - { - case WRITE: - case WRITE_6: - case WRITE_10: - hostdata->time_write[cmd->target] -= (jiffies - hostdata->timebase); - hostdata->bytes_write[cmd->target] += cmd->request_bufflen; - hostdata->pendingw++; - break; - case READ: - case READ_6: - case READ_10: - hostdata->time_read[cmd->target] -= (jiffies - hostdata->timebase); - hostdata->bytes_read[cmd->target] += cmd->request_bufflen; - hostdata->pendingr++; - break; +#if 0 + if (!hostdata->connected && !hostdata->issue_queue && + !hostdata->disconnected_queue) { + hostdata->timebase = jiffies; } #endif +#ifdef NCR5380_STAT_LIMIT + if (cmd->request_bufflen > NCR5380_STAT_LIMIT) +#endif + switch (cmd->cmnd[0]) { + case WRITE: + case WRITE_6: + case WRITE_10: + hostdata->time_write[cmd->target] -= (jiffies - hostdata->timebase); + hostdata->bytes_write[cmd->target] += cmd->request_bufflen; + hostdata->pendingw++; + break; + case READ: + case READ_6: + case READ_10: + hostdata->time_read[cmd->target] -= (jiffies - hostdata->timebase); + hostdata->bytes_read[cmd->target] += cmd->request_bufflen; + hostdata->pendingr++; + break; + } +#endif + + /* + * We use the host_scribble field as a pointer to the next command + * in a queue + */ + + cmd->host_scribble = NULL; + cmd->scsi_done = done; - /* - * We use the host_scribble field as a pointer to the next command - * in a queue - */ - - cmd->host_scribble = NULL; - cmd->scsi_done = done; - - cmd->result = 0; - - - /* - * Insert the cmd into the issue queue. Note that REQUEST SENSE - * commands are added to the head of the queue since any command will - * clear the contingent allegiance condition that exists and the - * sense data is only guaranteed to be valid while the condition exists. - */ - - cli(); - if (!(hostdata->issue_queue) || (cmd->cmnd[0] == REQUEST_SENSE)) { - LIST(cmd, hostdata->issue_queue); - cmd->host_scribble = (unsigned char *) hostdata->issue_queue; - hostdata->issue_queue = cmd; - } else { - for (tmp = (Scsi_Cmnd *) hostdata->issue_queue; tmp->host_scribble; - tmp = (Scsi_Cmnd *) tmp->host_scribble); - LIST(cmd, tmp); - tmp->host_scribble = (unsigned char *) cmd; - } + cmd->result = 0; + + + /* + * Insert the cmd into the issue queue. Note that REQUEST SENSE + * commands are added to the head of the queue since any command will + * clear the contingent allegiance condition that exists and the + * sense data is only guaranteed to be valid while the condition exists. + */ + + cli(); + if (!(hostdata->issue_queue) || (cmd->cmnd[0] == REQUEST_SENSE)) { + LIST(cmd, hostdata->issue_queue); + cmd->host_scribble = (unsigned char *) hostdata->issue_queue; + hostdata->issue_queue = cmd; + } else { + for (tmp = (Scsi_Cmnd *) hostdata->issue_queue; tmp->host_scribble; + tmp = (Scsi_Cmnd *) tmp->host_scribble); + LIST(cmd, tmp); + tmp->host_scribble = (unsigned char *) cmd; + } #if (NDEBUG & NDEBUG_QUEUES) - printk("scsi%d : command added to %s of queue\n", instance->host_no, - (cmd->cmnd[0] == REQUEST_SENSE) ? "head" : "tail"); + printk("scsi%d : command added to %s of queue\n", instance->host_no, + (cmd->cmnd[0] == REQUEST_SENSE) ? "head" : "tail"); #endif /* Run the coroutine if it isn't already running. */ - run_main(); - return 0; + run_main(); + return 0; } /* * Function : NCR5380_main (void) * * Purpose : NCR5380_main is a coroutine that runs as long as more work can - * be done on the NCR5380 host adapters in a system. Both - * NCR5380_queue_command() and NCR5380_intr() will try to start it - * in case it is not running. + * be done on the NCR5380 host adapters in a system. Both + * NCR5380_queue_command() and NCR5380_intr() will try to start it + * in case it is not running. * * NOTE : NCR5380_main exits with interrupts *disabled*, the caller should * reenable them. This prevents reentrancy and kernel stack overflow. - */ - -static void NCR5380_main (void) { - Scsi_Cmnd *tmp, *prev; - struct Scsi_Host *instance; - struct NCR5380_hostdata *hostdata; - int done; - - /* - * We run (with interrupts disabled) until we're sure that none of - * the host adapters have anything that can be done, at which point - * we set main_running to 0 and exit. - * - * Interrupts are enabled before doing various other internal - * instructions, after we've decided that we need to run through - * the loop again. - * - * this should prevent any race conditions. - */ - - do { - cli(); /* Freeze request queues */ - done = 1; - for (instance = first_instance; instance && - instance->hostt == the_template; instance=instance->next) { - hostdata = (struct NCR5380_hostdata *) instance->hostdata; - cli(); - if (!hostdata->connected) { + */ + +static void NCR5380_main(void) { + Scsi_Cmnd *tmp, *prev; + struct Scsi_Host *instance; + struct NCR5380_hostdata *hostdata; + int done; + + /* + * We run (with interrupts disabled) until we're sure that none of + * the host adapters have anything that can be done, at which point + * we set main_running to 0 and exit. + * + * Interrupts are enabled before doing various other internal + * instructions, after we've decided that we need to run through + * the loop again. + * + * this should prevent any race conditions. + */ + + do { + cli(); /* Freeze request queues */ + done = 1; + for (instance = first_instance; instance && + instance->hostt == the_template; instance = instance->next) { + unsigned long flags; + hostdata = (struct NCR5380_hostdata *) instance->hostdata; + save_flags(flags); + cli(); + if (!hostdata->connected) { #if (NDEBUG & NDEBUG_MAIN) - printk("scsi%d : not connected\n", instance->host_no); + printk("scsi%d : not connected\n", instance->host_no); #endif - /* - * Search through the issue_queue for a command destined - * for a target that's not busy. - */ + /* + * Search through the issue_queue for a command destined + * for a target that's not busy. + */ #if (NDEBUG & NDEBUG_LISTS) - for (tmp= (Scsi_Cmnd *) hostdata->issue_queue, prev=NULL; tmp && (tmp != prev); prev=tmp, tmp=(Scsi_Cmnd*)tmp->host_scribble) - ; - /*printk("%p ", tmp);*/ - if ((tmp == prev) && tmp) printk(" LOOP\n");/* else printk("\n");*/ -#endif - for (tmp = (Scsi_Cmnd *) hostdata->issue_queue, - prev = NULL; tmp; prev = tmp, tmp = (Scsi_Cmnd *) - tmp->host_scribble) { + for (tmp = (Scsi_Cmnd *) hostdata->issue_queue, prev = NULL; tmp && (tmp != prev); prev = tmp, tmp = (Scsi_Cmnd *) tmp->host_scribble); + /*printk("%p ", tmp); */ + if ((tmp == prev) && tmp) + printk(" LOOP\n"); /* else printk("\n"); */ +#endif + for (tmp = (Scsi_Cmnd *) hostdata->issue_queue, + prev = NULL; tmp; prev = tmp, tmp = (Scsi_Cmnd *) + tmp->host_scribble) { #if (NDEBUG & NDEBUG_LISTS) - if (prev != tmp) - printk("MAIN tmp=%p target=%d busy=%d lun=%d\n", tmp, tmp->target, hostdata->busy[tmp->target], tmp->lun); + if (prev != tmp) + printk("MAIN tmp=%p target=%d busy=%d lun=%d\n", tmp, tmp->target, hostdata->busy[tmp->target], tmp->lun); #endif - /* When we find one, remove it from the issue queue. */ - if (!(hostdata->busy[tmp->target] & (1 << tmp->lun))) { - if (prev) { - REMOVE(prev,prev->host_scribble,tmp,tmp->host_scribble); - prev->host_scribble = tmp->host_scribble; - } else { - REMOVE(-1,hostdata->issue_queue,tmp,tmp->host_scribble); - hostdata->issue_queue = (Scsi_Cmnd *) tmp->host_scribble; - } - tmp->host_scribble = NULL; - - /* reenable interrupts after finding one */ - sti(); - - /* - * Attempt to establish an I_T_L nexus here. - * On success, instance->hostdata->connected is set. - * On failure, we must add the command back to the - * issue queue so we can keep trying. - */ + /* When we find one, remove it from the issue queue. */ + if (!(hostdata->busy[tmp->target] & (1 << tmp->lun))) { + if (prev) { + REMOVE(prev, prev->host_scribble, tmp, tmp->host_scribble); + prev->host_scribble = tmp->host_scribble; + } else { + REMOVE(-1, hostdata->issue_queue, tmp, tmp->host_scribble); + hostdata->issue_queue = (Scsi_Cmnd *) tmp->host_scribble; + } + tmp->host_scribble = NULL; + + /* reenable interrupts after finding one */ + restore_flags(flags); + + /* + * Attempt to establish an I_T_L nexus here. + * On success, instance->hostdata->connected is set. + * On failure, we must add the command back to the + * issue queue so we can keep trying. + */ #if (NDEBUG & (NDEBUG_MAIN | NDEBUG_QUEUES)) - printk("scsi%d : main() : command for target %d lun %d removed from issue_queue\n", - instance->host_no, tmp->target, tmp->lun); + printk("scsi%d : main() : command for target %d lun %d removed from issue_queue\n", + instance->host_no, tmp->target, tmp->lun); #endif - - /* - * A successful selection is defined as one that - * leaves us with the command connected and - * in hostdata->connected, OR has terminated the - * command. - * - * With successful commands, we fall through - * and see if we can do an information transfer, - * with failures we will restart. - */ - if (!NCR5380_select(instance, tmp, - /* - * REQUEST SENSE commands are issued without tagged - * queueing, even on SCSI-II devices because the - * contingent allegiance condition exists for the - * entire unit. - */ - (tmp->cmnd[0] == REQUEST_SENSE) ? TAG_NONE : - TAG_NEXT)) { - break; - } else { - cli(); - LIST(tmp, hostdata->issue_queue); - tmp->host_scribble = (unsigned char *) - hostdata->issue_queue; - hostdata->issue_queue = tmp; - done = 0; - sti(); + /* + * A successful selection is defined as one that + * leaves us with the command connected and + * in hostdata->connected, OR has terminated the + * command. + * + * With successful commands, we fall through + * and see if we can do an information transfer, + * with failures we will restart. + */ + + if (!NCR5380_select(instance, tmp, + /* + * REQUEST SENSE commands are issued without tagged + * queueing, even on SCSI-II devices because the + * contingent allegiance condition exists for the + * entire unit. + */ + (tmp->cmnd[0] == REQUEST_SENSE) ? TAG_NONE : + TAG_NEXT)) { + break; + } else { + unsigned long flags; + save_flags(flags); + cli(); + LIST(tmp, hostdata->issue_queue); + tmp->host_scribble = (unsigned char *) + hostdata->issue_queue; + hostdata->issue_queue = tmp; + done = 0; + restore_flags(flags); #if (NDEBUG & (NDEBUG_MAIN | NDEBUG_QUEUES)) - printk("scsi%d : main(): select() failed, returned to issue_queue\n", - instance->host_no); + printk("scsi%d : main(): select() failed, returned to issue_queue\n", + instance->host_no); #endif - } - } /* if target/lun is not busy */ - } /* for */ - } /* if (!hostdata->connected) */ - - if (hostdata->connected + } + } /* if target/lun is not busy */ + } /* for */ + } /* if (!hostdata->connected) */ + if (hostdata->connected #ifdef REAL_DMA - && !hostdata->dmalen + && !hostdata->dmalen #endif #ifdef USLEEP - && (!hostdata->time_expires || hostdata->time_expires >= jiffies) + && (!hostdata->time_expires || hostdata->time_expires >= jiffies) #endif - ) { - sti(); + ) { + restore_flags(flags); #if (NDEBUG & NDEBUG_MAIN) - printk("scsi%d : main() : performing information transfer\n", - instance->host_no); + printk("scsi%d : main() : performing information transfer\n", + instance->host_no); #endif - NCR5380_information_transfer(instance); + NCR5380_information_transfer(instance); #if (NDEBUG & NDEBUG_MAIN) - printk("scsi%d : main() : done set false\n", instance->host_no); + printk("scsi%d : main() : done set false\n", instance->host_no); #endif - done = 0; - } else - break; - } /* for instance */ - } while (!done); - main_running = 0; + done = 0; + } else + break; + } /* for instance */ + } while (!done); + main_running = 0; } #ifndef DONT_USE_INTR @@ -1286,489 +1388,481 @@ * Function : void NCR5380_intr (int irq) * * Purpose : handle interrupts, reestablishing I_T_L or I_T_L_Q nexuses - * from the disconnected queue, and restarting NCR5380_main() - * as required. + * from the disconnected queue, and restarting NCR5380_main() + * as required. * * Inputs : int irq, irq that caused this interrupt. * */ -static void NCR5380_intr (int irq, void *dev_id, struct pt_regs * regs) { - NCR5380_local_declare(); - struct Scsi_Host *instance; - int done; - unsigned char basr; +static void NCR5380_intr(int irq, void *dev_id, struct pt_regs *regs) { + NCR5380_local_declare(); + struct Scsi_Host *instance; + int done; + unsigned char basr; + unsigned long flags; + + save_flags(flags); + cli(); #if (NDEBUG & NDEBUG_INTR) - printk("scsi : NCR5380 irq %d triggered\n", irq); + printk("scsi : NCR5380 irq %d triggered\n", irq); #endif - do { - done = 1; - for (instance = first_instance; instance && (instance->hostt == - the_template); instance = instance->next) - if (instance->irq == irq) { - - /* Look for pending interrupts */ - NCR5380_setup(instance); - basr = NCR5380_read(BUS_AND_STATUS_REG); - /* XXX dispatch to appropriate routine if found and done=0 */ - if (basr & BASR_IRQ) { + do { + done = 1; + for (instance = first_instance; instance && (instance->hostt == + the_template); instance = instance->next) + if (instance->irq == irq) { + + /* Look for pending interrupts */ + NCR5380_setup(instance); + basr = NCR5380_read(BUS_AND_STATUS_REG); + /* XXX dispatch to appropriate routine if found and done=0 */ + if (basr & BASR_IRQ) { #if (NDEBUG & NDEBUG_INTR) - NCR5380_print(instance); + NCR5380_print(instance); #endif - if ((NCR5380_read(STATUS_REG) & (SR_SEL | SR_IO)) == - (SR_SEL | SR_IO)) { - done = 0; - sti(); + if ((NCR5380_read(STATUS_REG) & (SR_SEL | SR_IO)) == + (SR_SEL | SR_IO)) { + done = 0; + restore_flags(flags); #if (NDEBUG & NDEBUG_INTR) - printk("scsi%d : SEL interrupt\n", instance->host_no); + printk("scsi%d : SEL interrupt\n", instance->host_no); #endif - NCR5380_reselect(instance); - (void) NCR5380_read(RESET_PARITY_INTERRUPT_REG); - } else if (basr & BASR_PARITY_ERROR) { + NCR5380_reselect(instance); + (void) NCR5380_read(RESET_PARITY_INTERRUPT_REG); + } else if (basr & BASR_PARITY_ERROR) { #if (NDEBUG & NDEBUG_INTR) - printk("scsi%d : PARITY interrupt\n", instance->host_no); + printk("scsi%d : PARITY interrupt\n", instance->host_no); #endif - (void) NCR5380_read(RESET_PARITY_INTERRUPT_REG); - } else if ((NCR5380_read(STATUS_REG) & SR_RST) == SR_RST) { + (void) NCR5380_read(RESET_PARITY_INTERRUPT_REG); + } else if ((NCR5380_read(STATUS_REG) & SR_RST) == SR_RST) { #if (NDEBUG & NDEBUG_INTR) - printk("scsi%d : RESET interrupt\n", instance->host_no); + printk("scsi%d : RESET interrupt\n", instance->host_no); #endif - (void)NCR5380_read(RESET_PARITY_INTERRUPT_REG); - } else { + (void) NCR5380_read(RESET_PARITY_INTERRUPT_REG); + } else { /* * XXX the rest of the interrupt conditions should *only* occur during a * DMA transfer, which I haven't gotten around to fixing yet. */ #if defined(REAL_DMA) - /* - * We should only get PHASE MISMATCH and EOP interrupts - * if we have DMA enabled, so do a sanity check based on - * the current setting of the MODE register. - */ - - if ((NCR5380_read(MODE_REG) & MR_DMA) && ((basr & - BASR_END_DMA_TRANSFER) || - !(basr & BASR_PHASE_MATCH))) { - int transfered; - - if (!hostdata->connected) - panic("scsi%d : received end of DMA interrupt with no connected cmd\n", - instance->hostno); - - transfered = (hostdata->dmalen - NCR5380_dma_residual(instance)); - hostdata->connected->SCp.this_residual -= transferred; - hostdata->connected->SCp.ptr += transferred; - hostdata->dmalen = 0; + /* + * We should only get PHASE MISMATCH and EOP interrupts + * if we have DMA enabled, so do a sanity check based on + * the current setting of the MODE register. + */ + + if ((NCR5380_read(MODE_REG) & MR_DMA) && ((basr & + BASR_END_DMA_TRANSFER) || + !(basr & BASR_PHASE_MATCH))) { + int transfered; + + if (!hostdata->connected) + panic("scsi%d : received end of DMA interrupt with no connected cmd\n", + instance->hostno); + + transfered = (hostdata->dmalen - NCR5380_dma_residual(instance)); + hostdata->connected->SCp.this_residual -= transferred; + hostdata->connected->SCp.ptr += transferred; + hostdata->dmalen = 0; - (void) NCR5380_read(RESET_PARITY_INTERRUPT_REG); + (void) NCR5380_read(RESET_PARITY_INTERRUPT_REG); #if NCR_TIMEOUT - { - unsigned long timeout = jiffies + NCR_TIMEOUT; + { + unsigned long timeout = jiffies + NCR_TIMEOUT; - while (NCR5380_read(BUS_AND_STATUS_REG) & BASR_ACK - && jiffies < timeout) - ; - if (jiffies >= timeout) - printk("scsi%d: timeout at NCR5380.c:%d\n", - host->host_no, __LINE__); - } -#else /* NCR_TIMEOUT */ - while (NCR5380_read(BUS_AND_STATUS_REG) & BASR_ACK); -#endif - - NCR5380_write(MODE_REG, MR_BASE); - NCR5380_write(INITIATOR_COMMAND_REG, ICR_BASE); - } + while (NCR5380_read(BUS_AND_STATUS_REG) & BASR_ACK + && jiffies < timeout); + if (jiffies >= timeout) + printk("scsi%d: timeout at NCR5380.c:%d\n", + host->host_no, __LINE__); + } +#else /* NCR_TIMEOUT */ + while (NCR5380_read(BUS_AND_STATUS_REG) & BASR_ACK); +#endif + + NCR5380_write(MODE_REG, MR_BASE); + NCR5380_write(INITIATOR_COMMAND_REG, ICR_BASE); + } #else #if (NDEBUG & NDEBUG_INTR) - printk("scsi : unknown interrupt, BASR 0x%X, MR 0x%X, SR 0x%x\n", basr, NCR5380_read(MODE_REG), NCR5380_read(STATUS_REG)); + printk("scsi : unknown interrupt, BASR 0x%X, MR 0x%X, SR 0x%x\n", basr, NCR5380_read(MODE_REG), NCR5380_read(STATUS_REG)); #endif - (void) NCR5380_read(RESET_PARITY_INTERRUPT_REG); + (void) NCR5380_read(RESET_PARITY_INTERRUPT_REG); #endif - } - } /* if BASR_IRQ */ - if (!done) - run_main(); - } /* if (instance->irq == irq) */ - } while (!done); + } + } /* if BASR_IRQ */ + if (!done) + run_main(); + } /* if (instance->irq == irq) */ + } while (!done); } -static void do_NCR5380_intr (int irq, void *dev_id, struct pt_regs * regs) { - unsigned long flags; +static void do_NCR5380_intr(int irq, void *dev_id, struct pt_regs *regs) { + unsigned long flags; - spin_lock_irqsave(&io_request_lock, flags); - NCR5380_intr(irq, dev_id, regs); - spin_unlock_irqrestore(&io_request_lock, flags); + spin_lock_irqsave(&io_request_lock, flags); + NCR5380_intr(irq, dev_id, regs); + spin_unlock_irqrestore(&io_request_lock, flags); } #endif #ifdef NCR5380_STATS -static void collect_stats(struct NCR5380_hostdata* hostdata, Scsi_Cmnd* cmd) -{ -# ifdef NCR5380_STAT_LIMIT - if (cmd->request_bufflen > NCR5380_STAT_LIMIT) -# endif - switch (cmd->cmnd[0]) - { - case WRITE: - case WRITE_6: - case WRITE_10: - hostdata->time_write[cmd->target] += (jiffies - hostdata->timebase); - /*hostdata->bytes_write[cmd->target] += cmd->request_bufflen;*/ - hostdata->pendingw--; - break; - case READ: - case READ_6: - case READ_10: - hostdata->time_read[cmd->target] += (jiffies - hostdata->timebase); - /*hostdata->bytes_read[cmd->target] += cmd->request_bufflen;*/ - hostdata->pendingr--; - break; - } +static void collect_stats(struct NCR5380_hostdata *hostdata, Scsi_Cmnd * cmd) { +#ifdef NCR5380_STAT_LIMIT + if (cmd->request_bufflen > NCR5380_STAT_LIMIT) +#endif + switch (cmd->cmnd[0]) { + case WRITE: + case WRITE_6: + case WRITE_10: + hostdata->time_write[cmd->target] += (jiffies - hostdata->timebase); + /*hostdata->bytes_write[cmd->target] += cmd->request_bufflen; */ + hostdata->pendingw--; + break; + case READ: + case READ_6: + case READ_10: + hostdata->time_read[cmd->target] += (jiffies - hostdata->timebase); + /*hostdata->bytes_read[cmd->target] += cmd->request_bufflen; */ + hostdata->pendingr--; + break; + } } #endif - /* * Function : int NCR5380_select (struct Scsi_Host *instance, Scsi_Cmnd *cmd, - * int tag); + * int tag); * * Purpose : establishes I_T_L or I_T_L_Q nexus for new or existing command, - * including ARBITRATION, SELECTION, and initial message out for - * IDENTIFY and queue messages. + * including ARBITRATION, SELECTION, and initial message out for + * IDENTIFY and queue messages. * * Inputs : instance - instantiation of the 5380 driver on which this - * target lives, cmd - SCSI command to execute, tag - set to TAG_NEXT for - * new tag, TAG_NONE for untagged queueing, otherwise set to the tag for - * the command that is presently connected. + * target lives, cmd - SCSI command to execute, tag - set to TAG_NEXT for + * new tag, TAG_NONE for untagged queueing, otherwise set to the tag for + * the command that is presently connected. * * Returns : -1 if selection could not execute for some reason, - * 0 if selection succeeded or failed because the target - * did not respond. + * 0 if selection succeeded or failed because the target + * did not respond. * * Side effects : - * If bus busy, arbitration failed, etc, NCR5380_select() will exit - * with registers as they should have been on entry - ie - * SELECT_ENABLE will be set appropriately, the NCR5380 - * will cease to drive any SCSI bus signals. - * - * If successful : I_T_L or I_T_L_Q nexus will be established, - * instance->connected will be set to cmd. - * SELECT interrupt will be disabled. - * - * If failed (no target) : cmd->scsi_done() will be called, and the - * cmd->result host byte set to DID_BAD_TARGET. - */ - -static int NCR5380_select (struct Scsi_Host *instance, Scsi_Cmnd *cmd, - int tag) { - NCR5380_local_declare(); - struct NCR5380_hostdata *hostdata = (struct NCR5380_hostdata*) - instance->hostdata; - unsigned char tmp[3], phase; - unsigned char *data; - int len; - unsigned long timeout; - NCR5380_setup(instance); - - hostdata->restart_select = 0; -#if defined (NDEBUG) && (NDEBUG & NDEBUG_ARBITRATION) - NCR5380_print(instance); - printk("scsi%d : starting arbitration, id = %d\n", instance->host_no, - instance->this_id); -#endif - cli(); - - /* - * Set the phase bits to 0, otherwise the NCR5380 won't drive the - * data bus during SELECTION. - */ - - NCR5380_write(TARGET_COMMAND_REG, 0); - - - /* - * Start arbitration. - */ - - NCR5380_write(OUTPUT_DATA_REG, hostdata->id_mask); - NCR5380_write(MODE_REG, MR_ARBITRATE); + * If bus busy, arbitration failed, etc, NCR5380_select() will exit + * with registers as they should have been on entry - ie + * SELECT_ENABLE will be set appropriately, the NCR5380 + * will cease to drive any SCSI bus signals. + * + * If successful : I_T_L or I_T_L_Q nexus will be established, + * instance->connected will be set to cmd. + * SELECT interrupt will be disabled. + * + * If failed (no target) : cmd->scsi_done() will be called, and the + * cmd->result host byte set to DID_BAD_TARGET. + */ +static int NCR5380_select(struct Scsi_Host *instance, Scsi_Cmnd * cmd, int tag) { + NCR5380_local_declare(); + struct NCR5380_hostdata *hostdata = (struct NCR5380_hostdata *) instance->hostdata; + unsigned char tmp[3], phase; + unsigned char *data; + int len; + unsigned long timeout; + unsigned long flags; + + NCR5380_setup(instance); + + hostdata->restart_select = 0; +#if defined (NDEBUG) && (NDEBUG & NDEBUG_ARBITRATION) + NCR5380_print(instance); + printk("scsi%d : starting arbitration, id = %d\n", instance->host_no, + instance->this_id); +#endif + save_flags(flags); + cli(); + + /* + * Set the phase bits to 0, otherwise the NCR5380 won't drive the + * data bus during SELECTION. + */ + + NCR5380_write(TARGET_COMMAND_REG, 0); - sti(); - /* Wait for arbitration logic to complete */ + /* + * Start arbitration. + */ + + NCR5380_write(OUTPUT_DATA_REG, hostdata->id_mask); + NCR5380_write(MODE_REG, MR_ARBITRATE); + + restore_flags(flags); + + /* Wait for arbitration logic to complete */ #if NCR_TIMEOUT - { - unsigned long timeout = jiffies + 2*NCR_TIMEOUT; + { + unsigned long timeout = jiffies + 2 * NCR_TIMEOUT; - while (!(NCR5380_read(INITIATOR_COMMAND_REG) & ICR_ARBITRATION_PROGRESS) - && jiffies < timeout) - ; - if (jiffies >= timeout) - { - printk("scsi: arbitration timeout at %d\n", __LINE__); - NCR5380_write(MODE_REG, MR_BASE); - NCR5380_write(SELECT_ENABLE_REG, hostdata->id_mask); - return -1; - } - } -#else /* NCR_TIMEOUT */ - while (!(NCR5380_read(INITIATOR_COMMAND_REG) & ICR_ARBITRATION_PROGRESS)); + while (!(NCR5380_read(INITIATOR_COMMAND_REG) & ICR_ARBITRATION_PROGRESS) + && jiffies < timeout); + if (jiffies >= timeout) { + printk("scsi: arbitration timeout at %d\n", __LINE__); + NCR5380_write(MODE_REG, MR_BASE); + NCR5380_write(SELECT_ENABLE_REG, hostdata->id_mask); + return -1; + } + } +#else /* NCR_TIMEOUT */ + while (!(NCR5380_read(INITIATOR_COMMAND_REG) & ICR_ARBITRATION_PROGRESS)); #endif -#if (NDEBUG & NDEBUG_ARBITRATION) - printk("scsi%d : arbitration complete\n", instance->host_no); +#if (NDEBUG & NDEBUG_ARBITRATION) + printk("scsi%d : arbitration complete\n", instance->host_no); /* Avoid GCC 2.4.5 asm needs to many reloads error */ - __asm__("nop"); + __asm__("nop"); #endif - /* - * The arbitration delay is 2.2us, but this is a minimum and there is - * no maximum so we can safely sleep for ceil(2.2) usecs to accommodate - * the integral nature of udelay(). - * - */ - - udelay(3); - - /* Check for lost arbitration */ - if ((NCR5380_read(INITIATOR_COMMAND_REG) & ICR_ARBITRATION_LOST) || - (NCR5380_read(CURRENT_SCSI_DATA_REG) & hostdata->id_higher_mask) || - (NCR5380_read(INITIATOR_COMMAND_REG) & ICR_ARBITRATION_LOST)) { - NCR5380_write(MODE_REG, MR_BASE); + /* + * The arbitration delay is 2.2us, but this is a minimum and there is + * no maximum so we can safely sleep for ceil(2.2) usecs to accommodate + * the integral nature of udelay(). + * + */ + + udelay(3); + + /* Check for lost arbitration */ + if ((NCR5380_read(INITIATOR_COMMAND_REG) & ICR_ARBITRATION_LOST) || + (NCR5380_read(CURRENT_SCSI_DATA_REG) & hostdata->id_higher_mask) || + (NCR5380_read(INITIATOR_COMMAND_REG) & ICR_ARBITRATION_LOST)) { + NCR5380_write(MODE_REG, MR_BASE); #if (NDEBUG & NDEBUG_ARBITRATION) - printk("scsi%d : lost arbitration, deasserting MR_ARBITRATE\n", - instance->host_no); + printk("scsi%d : lost arbitration, deasserting MR_ARBITRATE\n", + instance->host_no); #endif - return -1; - } + return -1; + } + NCR5380_write(INITIATOR_COMMAND_REG, ICR_BASE | ICR_ASSERT_SEL); + if (NCR5380_read(INITIATOR_COMMAND_REG) & ICR_ARBITRATION_LOST) { + NCR5380_write(MODE_REG, MR_BASE); + NCR5380_write(INITIATOR_COMMAND_REG, ICR_BASE); +#if (NDEBUG & NDEBUG_ARBITRATION) + printk("scsi%d : lost arbitration, deasserting ICR_ASSERT_SEL\n", + instance->host_no); +#endif + return -1; + } + /* + * Again, bus clear + bus settle time is 1.2us, however, this is + * a minimum so we'll udelay ceil(1.2) + */ + udelay(2); - NCR5380_write(INITIATOR_COMMAND_REG, ICR_BASE | ICR_ASSERT_SEL); - - if (NCR5380_read(INITIATOR_COMMAND_REG) & ICR_ARBITRATION_LOST) { - NCR5380_write(MODE_REG, MR_BASE); - NCR5380_write(INITIATOR_COMMAND_REG, ICR_BASE); #if (NDEBUG & NDEBUG_ARBITRATION) - printk("scsi%d : lost arbitration, deasserting ICR_ASSERT_SEL\n", - instance->host_no); + printk("scsi%d : won arbitration\n", instance->host_no); #endif - return -1; - } - /* - * Again, bus clear + bus settle time is 1.2us, however, this is - * a minimum so we'll udelay ceil(1.2) - */ - udelay(2); + /* + * Now that we have won arbitration, start Selection process, asserting + * the host and target ID's on the SCSI bus. + */ -#if (NDEBUG & NDEBUG_ARBITRATION) - printk("scsi%d : won arbitration\n", instance->host_no); -#endif + NCR5380_write(OUTPUT_DATA_REG, (hostdata->id_mask | (1 << cmd->target))); + + /* + * Raise ATN while SEL is true before BSY goes false from arbitration, + * since this is the only way to guarantee that we'll get a MESSAGE OUT + * phase immediately after selection. + */ + + NCR5380_write(INITIATOR_COMMAND_REG, (ICR_BASE | ICR_ASSERT_BSY | + ICR_ASSERT_DATA | ICR_ASSERT_ATN | ICR_ASSERT_SEL)); + NCR5380_write(MODE_REG, MR_BASE); + + /* + * Reselect interrupts must be turned off prior to the dropping of BSY, + * otherwise we will trigger an interrupt. + */ + NCR5380_write(SELECT_ENABLE_REG, 0); + /* + * The initiator shall then wait at least two deskew delays and release + * the BSY signal. + */ + udelay(1); /* wingel -- wait two bus deskew delay >2*45ns */ - /* - * Now that we have won arbitration, start Selection process, asserting - * the host and target ID's on the SCSI bus. - */ - - NCR5380_write(OUTPUT_DATA_REG, (hostdata->id_mask | (1 << cmd->target))); - - /* - * Raise ATN while SEL is true before BSY goes false from arbitration, - * since this is the only way to guarantee that we'll get a MESSAGE OUT - * phase immediately after selection. - */ - - NCR5380_write(INITIATOR_COMMAND_REG, (ICR_BASE | ICR_ASSERT_BSY | - ICR_ASSERT_DATA | ICR_ASSERT_ATN | ICR_ASSERT_SEL )); - NCR5380_write(MODE_REG, MR_BASE); - - /* - * Reselect interrupts must be turned off prior to the dropping of BSY, - * otherwise we will trigger an interrupt. - */ - NCR5380_write(SELECT_ENABLE_REG, 0); - - /* - * The initiator shall then wait at least two deskew delays and release - * the BSY signal. - */ - udelay(1); /* wingel -- wait two bus deskew delay >2*45ns */ - - /* Reset BSY */ - NCR5380_write(INITIATOR_COMMAND_REG, (ICR_BASE | ICR_ASSERT_DATA | - ICR_ASSERT_ATN | ICR_ASSERT_SEL)); - - /* - * Something weird happens when we cease to drive BSY - looks - * like the board/chip is letting us do another read before the - * appropriate propagation delay has expired, and we're confusing - * a BSY signal from ourselves as the target's response to SELECTION. - * - * A small delay (the 'C++' frontend breaks the pipeline with an - * unnecessary jump, making it work on my 386-33/Trantor T128, the - * tighter 'C' code breaks and requires this) solves the problem - - * the 1 us delay is arbitrary, and only used because this delay will - * be the same on other platforms and since it works here, it should - * work there. - * - * wingel suggests that this could be due to failing to wait - * one deskew delay. - */ + /* Reset BSY */ + NCR5380_write(INITIATOR_COMMAND_REG, (ICR_BASE | ICR_ASSERT_DATA | + ICR_ASSERT_ATN | ICR_ASSERT_SEL)); - udelay(1); + /* + * Something weird happens when we cease to drive BSY - looks + * like the board/chip is letting us do another read before the + * appropriate propagation delay has expired, and we're confusing + * a BSY signal from ourselves as the target's response to SELECTION. + * + * A small delay (the 'C++' frontend breaks the pipeline with an + * unnecessary jump, making it work on my 386-33/Trantor T128, the + * tighter 'C' code breaks and requires this) solves the problem - + * the 1 us delay is arbitrary, and only used because this delay will + * be the same on other platforms and since it works here, it should + * work there. + * + * wingel suggests that this could be due to failing to wait + * one deskew delay. + */ + + udelay(1); #if (NDEBUG & NDEBUG_SELECTION) - printk("scsi%d : selecting target %d\n", instance->host_no, cmd->target); + printk("scsi%d : selecting target %d\n", instance->host_no, cmd->target); #endif - /* - * The SCSI specification calls for a 250 ms timeout for the actual - * selection. - */ + /* + * The SCSI specification calls for a 250 ms timeout for the actual + * selection. + */ - timeout = jiffies + (250*HZ/1000); + timeout = jiffies + (250 * HZ / 1000); - /* - * XXX very interesting - we're seeing a bounce where the BSY we - * asserted is being reflected / still asserted (propagation delay?) - * and it's detecting as true. Sigh. - */ + /* + * XXX very interesting - we're seeing a bounce where the BSY we + * asserted is being reflected / still asserted (propagation delay?) + * and it's detecting as true. Sigh. + */ - while ((jiffies < timeout) && !(NCR5380_read(STATUS_REG) & - (SR_BSY | SR_IO))); + while ((jiffies < timeout) && !(NCR5380_read(STATUS_REG) & + (SR_BSY | SR_IO))); - if ((NCR5380_read(STATUS_REG) & (SR_SEL | SR_IO)) == + if ((NCR5380_read(STATUS_REG) & (SR_SEL | SR_IO)) == (SR_SEL | SR_IO)) { - NCR5380_write(INITIATOR_COMMAND_REG, ICR_BASE); - NCR5380_reselect(instance); - printk ("scsi%d : reselection after won arbitration?\n", - instance->host_no); - NCR5380_write(SELECT_ENABLE_REG, hostdata->id_mask); - return -1; - } - - /* - * No less than two deskew delays after the initiator detects the - * BSY signal is true, it shall release the SEL signal and may - * change the DATA BUS. -wingel - */ + NCR5380_write(INITIATOR_COMMAND_REG, ICR_BASE); + NCR5380_reselect(instance); + printk("scsi%d : reselection after won arbitration?\n", + instance->host_no); + NCR5380_write(SELECT_ENABLE_REG, hostdata->id_mask); + return -1; + } + /* + * No less than two deskew delays after the initiator detects the + * BSY signal is true, it shall release the SEL signal and may + * change the DATA BUS. -wingel + */ - udelay(1); + udelay(1); - NCR5380_write(INITIATOR_COMMAND_REG, ICR_BASE | ICR_ASSERT_ATN); + NCR5380_write(INITIATOR_COMMAND_REG, ICR_BASE | ICR_ASSERT_ATN); - if (!(NCR5380_read(STATUS_REG) & SR_BSY)) { - NCR5380_write(INITIATOR_COMMAND_REG, ICR_BASE); - if (hostdata->targets_present & (1 << cmd->target)) { - printk("scsi%d : weirdness\n", instance->host_no); - if (hostdata->restart_select) - printk("\trestart select\n"); + if (!(NCR5380_read(STATUS_REG) & SR_BSY)) { + NCR5380_write(INITIATOR_COMMAND_REG, ICR_BASE); + if (hostdata->targets_present & (1 << cmd->target)) { + printk("scsi%d : weirdness\n", instance->host_no); + if (hostdata->restart_select) + printk("\trestart select\n"); #ifdef NDEBUG - NCR5380_print (instance); + NCR5380_print(instance); #endif - NCR5380_write(SELECT_ENABLE_REG, hostdata->id_mask); - return -1; - } - cmd->result = DID_BAD_TARGET << 16; + NCR5380_write(SELECT_ENABLE_REG, hostdata->id_mask); + return -1; + } + cmd->result = DID_BAD_TARGET << 16; #ifdef NCR5380_STATS - collect_stats(hostdata, cmd); + collect_stats(hostdata, cmd); #endif - cmd->scsi_done(cmd); - NCR5380_write(SELECT_ENABLE_REG, hostdata->id_mask); + cmd->scsi_done(cmd); + NCR5380_write(SELECT_ENABLE_REG, hostdata->id_mask); #if (NDEBUG & NDEBUG_SELECTION) - printk("scsi%d : target did not respond within 250ms\n", - instance->host_no); + printk("scsi%d : target did not respond within 250ms\n", + instance->host_no); #endif - NCR5380_write(SELECT_ENABLE_REG, hostdata->id_mask); - return 0; - } - - hostdata->targets_present |= (1 << cmd->target); + NCR5380_write(SELECT_ENABLE_REG, hostdata->id_mask); + return 0; + } + hostdata->targets_present |= (1 << cmd->target); - /* - * Since we followed the SCSI spec, and raised ATN while SEL - * was true but before BSY was false during selection, the information - * transfer phase should be a MESSAGE OUT phase so that we can send the - * IDENTIFY message. - * - * If SCSI-II tagged queuing is enabled, we also send a SIMPLE_QUEUE_TAG - * message (2 bytes) with a tag ID that we increment with every command - * until it wraps back to 0. - * - * XXX - it turns out that there are some broken SCSI-II devices, - * which claim to support tagged queuing but fail when more than - * some number of commands are issued at once. - */ + /* + * Since we followed the SCSI spec, and raised ATN while SEL + * was true but before BSY was false during selection, the information + * transfer phase should be a MESSAGE OUT phase so that we can send the + * IDENTIFY message. + * + * If SCSI-II tagged queuing is enabled, we also send a SIMPLE_QUEUE_TAG + * message (2 bytes) with a tag ID that we increment with every command + * until it wraps back to 0. + * + * XXX - it turns out that there are some broken SCSI-II devices, + * which claim to support tagged queuing but fail when more than + * some number of commands are issued at once. + */ - /* Wait for start of REQ/ACK handshake */ + /* Wait for start of REQ/ACK handshake */ #ifdef NCR_TIMEOUT - { - unsigned long timeout = jiffies + NCR_TIMEOUT; - - while (!(NCR5380_read(STATUS_REG) & SR_REQ) && jiffies < timeout); - - if (jiffies >= timeout) { - printk("scsi%d: timeout at NCR5380.c:%d\n", __LINE__); - NCR5380_write(SELECT_ENABLE_REG, hostdata->id_mask); - return -1; - } - } -#else /* NCR_TIMEOUT */ - while (!(NCR5380_read(STATUS_REG) & SR_REQ)); -#endif /* def NCR_TIMEOUT */ + { + unsigned long timeout = jiffies + NCR_TIMEOUT; + + while (!(NCR5380_read(STATUS_REG) & SR_REQ) && jiffies < timeout); + + if (jiffies >= timeout) { + printk("scsi%d: timeout at NCR5380.c:%d\n", __LINE__); + NCR5380_write(SELECT_ENABLE_REG, hostdata->id_mask); + return -1; + } + } +#else /* NCR_TIMEOUT */ + while (!(NCR5380_read(STATUS_REG) & SR_REQ)); +#endif /* def NCR_TIMEOUT */ #if (NDEBUG & NDEBUG_SELECTION) - printk("scsi%d : target %d selected, going into MESSAGE OUT phase.\n", - instance->host_no, cmd->target); + printk("scsi%d : target %d selected, going into MESSAGE OUT phase.\n", + instance->host_no, cmd->target); #endif - tmp[0] = IDENTIFY(((instance->irq == IRQ_NONE) ? 0 : 1), cmd->lun); + tmp[0] = IDENTIFY(((instance->irq == IRQ_NONE) ? 0 : 1), cmd->lun); #ifdef SCSI2 - if (cmd->device->tagged_queue && (tag != TAG_NONE)) { - tmp[1] = SIMPLE_QUEUE_TAG; - if (tag == TAG_NEXT) { - /* 0 is TAG_NONE, used to imply no tag for this command */ - if (cmd->device->current_tag == 0) - cmd->device->current_tag = 1; - - cmd->tag = cmd->device->current_tag; - cmd->device->current_tag++; - } else - cmd->tag = (unsigned char) tag; - - tmp[2] = cmd->tag; - hostdata->last_message = SIMPLE_QUEUE_TAG; - len = 3; - } else -#endif /* def SCSI2 */ - { - len = 1; - cmd->tag=0; - } + if (cmd->device->tagged_queue && (tag != TAG_NONE)) { + tmp[1] = SIMPLE_QUEUE_TAG; + if (tag == TAG_NEXT) { + /* 0 is TAG_NONE, used to imply no tag for this command */ + if (cmd->device->current_tag == 0) + cmd->device->current_tag = 1; + + cmd->tag = cmd->device->current_tag; + cmd->device->current_tag++; + } else + cmd->tag = (unsigned char) tag; - /* Send message(s) */ - data = tmp; - phase = PHASE_MSGOUT; - NCR5380_transfer_pio(instance, &phase, &len, &data); + tmp[2] = cmd->tag; + hostdata->last_message = SIMPLE_QUEUE_TAG; + len = 3; + } else +#endif /* def SCSI2 */ + { + len = 1; + cmd->tag = 0; + } + + /* Send message(s) */ + data = tmp; + phase = PHASE_MSGOUT; + NCR5380_transfer_pio(instance, &phase, &len, &data); #if (NDEBUG & NDEBUG_SELECTION) - printk("scsi%d : nexus established.\n", instance->host_no); + printk("scsi%d : nexus established.\n", instance->host_no); #endif - /* XXX need to handle errors here */ - hostdata->connected = cmd; + /* XXX need to handle errors here */ + hostdata->connected = cmd; #ifdef SCSI2 - if (!cmd->device->tagged_queue) -#endif - hostdata->busy[cmd->target] |= (1 << cmd->lun); + if (!cmd->device->tagged_queue) +#endif + hostdata->busy[cmd->target] |= (1 << cmd->lun); - initialize_SCp(cmd); + initialize_SCp(cmd); - return 0; + return 0; } /* @@ -1778,14 +1872,14 @@ * Purpose : transfers data in given phase using polled I/O * * Inputs : instance - instance of driver, *phase - pointer to - * what phase is expected, *count - pointer to number of - * bytes to transfer, **data - pointer to data pointer. + * what phase is expected, *count - pointer to number of + * bytes to transfer, **data - pointer to data pointer. * * Returns : -1 when different phase is entered without transferring - * maximum number of bytes, 0 if all bytes or transfered or exit - * is in same phase. + * maximum number of bytes, 0 if all bytes or transfered or exit + * is in same phase. * - * Also, *phase, *count, *data are modified in place. + * Also, *phase, *count, *data are modified in place. * * XXX Note : handling for bus free may be useful. */ @@ -1796,197 +1890,193 @@ * counts, we will always do a pseudo DMA or DMA transfer. */ -static int NCR5380_transfer_pio (struct Scsi_Host *instance, - unsigned char *phase, int *count, unsigned char **data) { - NCR5380_local_declare(); - register unsigned char p = *phase, tmp; - register int c = *count; - register unsigned char *d = *data; - NCR5380_setup(instance); +static int NCR5380_transfer_pio(struct Scsi_Host *instance, + unsigned char *phase, int *count, unsigned char **data) { + NCR5380_local_declare(); + register unsigned char p = *phase, tmp; + register int c = *count; + register unsigned char *d = *data; + NCR5380_setup(instance); #if (NDEBUG & NDEBUG_PIO) - if (!(p & SR_IO)) - printk("scsi%d : pio write %d bytes\n", instance->host_no, c); - else - printk("scsi%d : pio read %d bytes\n", instance->host_no, c); + if (!(p & SR_IO)) + printk("scsi%d : pio write %d bytes\n", instance->host_no, c); + else + printk("scsi%d : pio read %d bytes\n", instance->host_no, c); #endif - /* - * The NCR5380 chip will only drive the SCSI bus when the - * phase specified in the appropriate bits of the TARGET COMMAND - * REGISTER match the STATUS REGISTER - */ - - NCR5380_write(TARGET_COMMAND_REG, PHASE_SR_TO_TCR(p)); - - do { /* - * Wait for assertion of REQ, after which the phase bits will be - * valid + * The NCR5380 chip will only drive the SCSI bus when the + * phase specified in the appropriate bits of the TARGET COMMAND + * REGISTER match the STATUS REGISTER */ - while (!((tmp = NCR5380_read(STATUS_REG)) & SR_REQ)); + + NCR5380_write(TARGET_COMMAND_REG, PHASE_SR_TO_TCR(p)); + + do { + /* + * Wait for assertion of REQ, after which the phase bits will be + * valid + */ + while (!((tmp = NCR5380_read(STATUS_REG)) & SR_REQ)); #if (NDEBUG & NDEBUG_HANDSHAKE) - printk("scsi%d : REQ detected\n", instance->host_no); + printk("scsi%d : REQ detected\n", instance->host_no); #endif - /* Check for phase mismatch */ - if ((tmp & PHASE_MASK) != p) { + /* Check for phase mismatch */ + if ((tmp & PHASE_MASK) != p) { #if (NDEBUG & NDEBUG_PIO) - printk("scsi%d : phase mismatch\n", instance->host_no); - NCR5380_print_phase(instance); + printk("scsi%d : phase mismatch\n", instance->host_no); + NCR5380_print_phase(instance); #endif - break; - } - - /* Do actual transfer from SCSI bus to / from memory */ - if (!(p & SR_IO)) - NCR5380_write(OUTPUT_DATA_REG, *d); - else - *d = NCR5380_read(CURRENT_SCSI_DATA_REG); + break; + } + /* Do actual transfer from SCSI bus to / from memory */ if (!(p & SR_IO)) + NCR5380_write(OUTPUT_DATA_REG, *d); + else + *d = NCR5380_read(CURRENT_SCSI_DATA_REG); - ++d; + ++d; - /* - * The SCSI standard suggests that in MSGOUT phase, the initiator - * should drop ATN on the last byte of the message phase - * after REQ has been asserted for the handshake but before - * the initiator raises ACK. - */ + /* + * The SCSI standard suggests that in MSGOUT phase, the initiator + * should drop ATN on the last byte of the message phase + * after REQ has been asserted for the handshake but before + * the initiator raises ACK. + */ - if (!(p & SR_IO)) { - if (!((p & SR_MSG) && c > 1)) { - NCR5380_write(INITIATOR_COMMAND_REG, ICR_BASE | - ICR_ASSERT_DATA); + if (!(p & SR_IO)) { + if (!((p & SR_MSG) && c > 1)) { + NCR5380_write(INITIATOR_COMMAND_REG, ICR_BASE | + ICR_ASSERT_DATA); #if (NDEBUG & NDEBUG_PIO) - NCR5380_print(instance); + NCR5380_print(instance); #endif - NCR5380_write(INITIATOR_COMMAND_REG, ICR_BASE | - ICR_ASSERT_DATA | ICR_ASSERT_ACK); - } else { - NCR5380_write(INITIATOR_COMMAND_REG, ICR_BASE | - ICR_ASSERT_DATA | ICR_ASSERT_ATN); + NCR5380_write(INITIATOR_COMMAND_REG, ICR_BASE | + ICR_ASSERT_DATA | ICR_ASSERT_ACK); + } else { + NCR5380_write(INITIATOR_COMMAND_REG, ICR_BASE | + ICR_ASSERT_DATA | ICR_ASSERT_ATN); #if (NDEBUG & NDEBUG_PIO) - NCR5380_print(instance); + NCR5380_print(instance); #endif - NCR5380_write(INITIATOR_COMMAND_REG, ICR_BASE | - ICR_ASSERT_DATA | ICR_ASSERT_ATN | ICR_ASSERT_ACK); - } - } else { + NCR5380_write(INITIATOR_COMMAND_REG, ICR_BASE | + ICR_ASSERT_DATA | ICR_ASSERT_ATN | ICR_ASSERT_ACK); + } + } else { #if (NDEBUG & NDEBUG_PIO) - NCR5380_print(instance); + NCR5380_print(instance); #endif - NCR5380_write(INITIATOR_COMMAND_REG, ICR_BASE | ICR_ASSERT_ACK); - } + NCR5380_write(INITIATOR_COMMAND_REG, ICR_BASE | ICR_ASSERT_ACK); + } - while (NCR5380_read(STATUS_REG) & SR_REQ); + while (NCR5380_read(STATUS_REG) & SR_REQ); #if (NDEBUG & NDEBUG_HANDSHAKE) - printk("scsi%d : req false, handshake complete\n", instance->host_no); + printk("scsi%d : req false, handshake complete\n", instance->host_no); #endif /* * We have several special cases to consider during REQ/ACK handshaking : * 1. We were in MSGOUT phase, and we are on the last byte of the - * message. ATN must be dropped as ACK is dropped. + * message. ATN must be dropped as ACK is dropped. * * 2. We are in a MSGIN phase, and we are on the last byte of the - * message. We must exit with ACK asserted, so that the calling - * code may raise ATN before dropping ACK to reject the message. + * message. We must exit with ACK asserted, so that the calling + * code may raise ATN before dropping ACK to reject the message. * * 3. ACK and ATN are clear and the target may proceed as normal. */ - if (!(p == PHASE_MSGIN && c == 1)) { - if (p == PHASE_MSGOUT && c > 1) - NCR5380_write(INITIATOR_COMMAND_REG, ICR_BASE | ICR_ASSERT_ATN); - else - NCR5380_write(INITIATOR_COMMAND_REG, ICR_BASE); - } - } while (--c); + if (!(p == PHASE_MSGIN && c == 1)) { + if (p == PHASE_MSGOUT && c > 1) + NCR5380_write(INITIATOR_COMMAND_REG, ICR_BASE | ICR_ASSERT_ATN); + else + NCR5380_write(INITIATOR_COMMAND_REG, ICR_BASE); + } + } while (--c); -#if (NDEBUG & NDEBUG_PIO) - printk("scsi%d : residual %d\n", instance->host_no, c); +#if (NDEBUG & NDEBUG_PIO) + printk("scsi%d : residual %d\n", instance->host_no, c); #endif - *count = c; - *data = d; - tmp = NCR5380_read(STATUS_REG); - if (tmp & SR_REQ) - *phase = tmp & PHASE_MASK; - else - *phase = PHASE_UNKNOWN; + *count = c; + *data = d; + tmp = NCR5380_read(STATUS_REG); + if (tmp & SR_REQ) + *phase = tmp & PHASE_MASK; + else + *phase = PHASE_UNKNOWN; + + if (!c || (*phase == p)) + return 0; + else + return -1; +} + +static void do_reset(struct Scsi_Host *host) { + unsigned long flags; + NCR5380_local_declare(); + NCR5380_setup(host); + + save_flags(flags); + cli(); + NCR5380_write(TARGET_COMMAND_REG, + PHASE_SR_TO_TCR(NCR5380_read(STATUS_REG) & PHASE_MASK)); + NCR5380_write(INITIATOR_COMMAND_REG, ICR_BASE | ICR_ASSERT_RST); + udelay(25); + NCR5380_write(INITIATOR_COMMAND_REG, ICR_BASE); + restore_flags(flags); +} /* + + * Function : do_abort (Scsi_Host *host) + * + * Purpose : abort the currently established nexus. Should only be + * called from a routine which can drop into a + * + * Returns : 0 on success, -1 on failure. + */ static int do_abort(struct Scsi_Host *host) { + NCR5380_local_declare(); + unsigned char tmp, *msgptr, phase; + int len; + NCR5380_setup(host); - if (!c || (*phase == p)) - return 0; - else - return -1; -} -static void do_reset (struct Scsi_Host *host) { - NCR5380_local_declare(); - NCR5380_setup(host); + /* Request message out phase */ + NCR5380_write(INITIATOR_COMMAND_REG, ICR_BASE | ICR_ASSERT_ATN); - cli(); - NCR5380_write(TARGET_COMMAND_REG, - PHASE_SR_TO_TCR(NCR5380_read(STATUS_REG) & PHASE_MASK)); - NCR5380_write(INITIATOR_COMMAND_REG, ICR_BASE | ICR_ASSERT_RST); - udelay(25); - NCR5380_write(INITIATOR_COMMAND_REG, ICR_BASE); - sti(); -} + /* + * Wait for the target to indicate a valid phase by asserting + * REQ. Once this happens, we'll have either a MSGOUT phase + * and can immediately send the ABORT message, or we'll have some + * other phase and will have to source/sink data. + * + * We really don't care what value was on the bus or what value + * the target sees, so we just handshake. + */ -/* - * Function : do_abort (Scsi_Host *host) - * - * Purpose : abort the currently established nexus. Should only be - * called from a routine which can drop into a - * - * Returns : 0 on success, -1 on failure. - */ + while (!(tmp = NCR5380_read(STATUS_REG)) & SR_REQ); -static int do_abort (struct Scsi_Host *host) { - NCR5380_local_declare(); - unsigned char tmp, *msgptr, phase; - int len; - NCR5380_setup(host); - - - /* Request message out phase */ - NCR5380_write(INITIATOR_COMMAND_REG, ICR_BASE | ICR_ASSERT_ATN); - - /* - * Wait for the target to indicate a valid phase by asserting - * REQ. Once this happens, we'll have either a MSGOUT phase - * and can immediately send the ABORT message, or we'll have some - * other phase and will have to source/sink data. - * - * We really don't care what value was on the bus or what value - * the target sees, so we just handshake. - */ - - while (!(tmp = NCR5380_read(STATUS_REG)) & SR_REQ); - - NCR5380_write(TARGET_COMMAND_REG, PHASE_SR_TO_TCR(tmp)); - - if ((tmp & PHASE_MASK) != PHASE_MSGOUT) { - NCR5380_write(INITIATOR_COMMAND_REG, ICR_BASE | ICR_ASSERT_ATN | - ICR_ASSERT_ACK); - while (NCR5380_read(STATUS_REG) & SR_REQ); - NCR5380_write(INITIATOR_COMMAND_REG, ICR_BASE | ICR_ASSERT_ATN); - } - - tmp = ABORT; - msgptr = &tmp; - len = 1; - phase = PHASE_MSGOUT; - NCR5380_transfer_pio (host, &phase, &len, &msgptr); - - /* - * If we got here, and the command completed successfully, - * we're about to go into bus free state. - */ + NCR5380_write(TARGET_COMMAND_REG, PHASE_SR_TO_TCR(tmp)); + + if ((tmp & PHASE_MASK) != PHASE_MSGOUT) { + NCR5380_write(INITIATOR_COMMAND_REG, ICR_BASE | ICR_ASSERT_ATN | + ICR_ASSERT_ACK); + while (NCR5380_read(STATUS_REG) & SR_REQ); + NCR5380_write(INITIATOR_COMMAND_REG, ICR_BASE | ICR_ASSERT_ATN); + } + tmp = ABORT; + msgptr = &tmp; + len = 1; + phase = PHASE_MSGOUT; + NCR5380_transfer_pio(host, &phase, &len, &msgptr); + + /* + * If we got here, and the command completed successfully, + * we're about to go into bus free state. + */ - return len ? -1 : 0; + return len ? -1 : 0; } #if defined(REAL_DMA) || defined(PSEUDO_DMA) || defined (REAL_DMA_POLL) @@ -1995,86 +2085,86 @@ * unsigned char *phase, int *count, unsigned char **data) * * Purpose : transfers data in given phase using either real - * or pseudo DMA. + * or pseudo DMA. * * Inputs : instance - instance of driver, *phase - pointer to - * what phase is expected, *count - pointer to number of - * bytes to transfer, **data - pointer to data pointer. + * what phase is expected, *count - pointer to number of + * bytes to transfer, **data - pointer to data pointer. * * Returns : -1 when different phase is entered without transferring - * maximum number of bytes, 0 if all bytes or transfered or exit - * is in same phase. + * maximum number of bytes, 0 if all bytes or transfered or exit + * is in same phase. * - * Also, *phase, *count, *data are modified in place. + * Also, *phase, *count, *data are modified in place. * */ -static int NCR5380_transfer_dma (struct Scsi_Host *instance, - unsigned char *phase, int *count, unsigned char **data) { - NCR5380_local_declare(); - register int c = *count; - register unsigned char p = *phase; - register unsigned char *d = *data; - unsigned char tmp; - int foo; +static int NCR5380_transfer_dma(struct Scsi_Host *instance, + unsigned char *phase, int *count, unsigned char **data) { + NCR5380_local_declare(); + register int c = *count; + register unsigned char p = *phase; + register unsigned char *d = *data; + unsigned char tmp; + int foo; + unsigned long flags; #if defined(REAL_DMA_POLL) - int cnt, toPIO; - unsigned char saved_data = 0, overrun = 0, residue; + int cnt, toPIO; + unsigned char saved_data = 0, overrun = 0, residue; #endif - struct NCR5380_hostdata *hostdata = (struct NCR5380_hostdata *) - instance->hostdata; + struct NCR5380_hostdata *hostdata = (struct NCR5380_hostdata *) + instance->hostdata; - NCR5380_setup(instance); + NCR5380_setup(instance); - if ((tmp = (NCR5380_read(STATUS_REG) & PHASE_MASK)) != p) { - *phase = tmp; - return -1; - } -#if defined(REAL_DMA) || defined(REAL_DMA_POLL) -#ifdef READ_OVERRUNS - if (p & SR_IO) { - c -= 2; - } + if ((tmp = (NCR5380_read(STATUS_REG) & PHASE_MASK)) != p) { + *phase = tmp; + return -1; + } +#if defined(REAL_DMA) || defined(REAL_DMA_POLL) +#ifdef READ_OVERRUNS if (p & SR_IO) { c -= 2; +} #endif #if (NDEBUG & NDEBUG_DMA) - printk("scsi%d : initializing DMA channel %d for %s, %d bytes %s %0x\n", - instance->host_no, instance->dma_channel, (p & SR_IO) ? "reading" : - "writing", c, (p & SR_IO) ? "to" : "from", (unsigned) d); +printk("scsi%d : initializing DMA channel %d for %s, %d bytes %s %0x\n", + instance->host_no, instance->dma_channel, (p & SR_IO) ? "reading" : + "writing", c, (p & SR_IO) ? "to" : "from", (unsigned) d); #endif - hostdata->dma_len = (p & SR_IO) ? - NCR5380_dma_read_setup(instance, d, c) : - NCR5380_dma_write_setup(instance, d, c); +hostdata->dma_len = (p & SR_IO) ? +NCR5380_dma_read_setup(instance, d, c) : +NCR5380_dma_write_setup(instance, d, c); #endif - NCR5380_write(TARGET_COMMAND_REG, PHASE_SR_TO_TCR(p)); +NCR5380_write(TARGET_COMMAND_REG, PHASE_SR_TO_TCR(p)); #ifdef REAL_DMA - NCR5380_write(MODE_REG, MR_BASE | MR_DMA_MODE | MR_ENABLE_EOP_INTR | MR_MONITOR_BSY); +NCR5380_write(MODE_REG, MR_BASE | MR_DMA_MODE | MR_ENABLE_EOP_INTR | MR_MONITOR_BSY); #elif defined(REAL_DMA_POLL) - NCR5380_write(MODE_REG, MR_BASE | MR_DMA_MODE); +NCR5380_write(MODE_REG, MR_BASE | MR_DMA_MODE); #else - /* - * Note : on my sample board, watch-dog timeouts occurred when interrupts - * were not disabled for the duration of a single DMA transfer, from - * before the setting of DMA mode to after transfer of the last byte. - */ + /* + * Note : on my sample board, watch-dog timeouts occurred when interrupts + * were not disabled for the duration of a single DMA transfer, from + * before the setting of DMA mode to after transfer of the last byte. + */ #if defined(PSEUDO_DMA) && !defined(UNSAFE) - cli(); +save_flags(flags); +cli(); #endif - /* KLL May need eop and parity in 53c400 */ - if (hostdata->flags & FLAG_NCR53C400) + /* KLL May need eop and parity in 53c400 */ +if (hostdata->flags & FLAG_NCR53C400) NCR5380_write(MODE_REG, MR_BASE | MR_DMA_MODE | MR_ENABLE_PAR_CHECK - | MR_ENABLE_PAR_INTR | MR_ENABLE_EOP_INTR | MR_DMA_MODE - | MR_MONITOR_BSY); - else + | MR_ENABLE_PAR_INTR | MR_ENABLE_EOP_INTR | MR_DMA_MODE + | MR_MONITOR_BSY); +else NCR5380_write(MODE_REG, MR_BASE | MR_DMA_MODE); -#endif /* def REAL_DMA */ +#endif /* def REAL_DMA */ #if (NDEBUG & NDEBUG_DMA) & 0 - printk("scsi%d : mode reg = 0x%X\n", instance->host_no, NCR5380_read(MODE_REG)); +printk("scsi%d : mode reg = 0x%X\n", instance->host_no, NCR5380_read(MODE_REG)); #endif /* @@ -2086,12 +2176,13 @@ * is the problem? */ - if (p & SR_IO) { +if (p & SR_IO) +{ #ifndef FOO - udelay(1); +udelay(1); #endif - NCR5380_write(START_DMA_INITIATOR_RECEIVE_REG, 0); - } else { +NCR5380_write(START_DMA_INITIATOR_RECEIVE_REG, 0); +} else { #ifndef FOO udelay(1); #endif @@ -2103,86 +2194,90 @@ #ifndef FOO udelay(1); #endif - } +} #if defined(REAL_DMA_POLL) - do { +do { tmp = NCR5380_read(BUS_AND_STATUS_REG); - } while ((tmp & BASR_PHASE_MATCH) && !(tmp & (BASR_BUSY_ERROR | - BASR_END_DMA_TRANSFER))); +} while ((tmp & BASR_PHASE_MATCH) && !(tmp & (BASR_BUSY_ERROR | + + BASR_END_DMA_TRANSFER))); /* - At this point, either we've completed DMA, or we have a phase mismatch, - or we've unexpectedly lost BUSY (which is a real error). + At this point, either we've completed DMA, or we have a phase mismatch, + or we've unexpectedly lost BUSY (which is a real error). - For write DMAs, we want to wait until the last byte has been - transferred out over the bus before we turn off DMA mode. Alas, there - seems to be no terribly good way of doing this on a 5380 under all - conditions. For non-scatter-gather operations, we can wait until REQ - and ACK both go false, or until a phase mismatch occurs. Gather-writes - are nastier, since the device will be expecting more data than we - are prepared to send it, and REQ will remain asserted. On a 53C8[01] we - could test LAST BIT SENT to assure transfer (I imagine this is precisely - why this signal was added to the newer chips) but on the older 538[01] - this signal does not exist. The workaround for this lack is a watchdog; - we bail out of the wait-loop after a modest amount of wait-time if - the usual exit conditions are not met. Not a terribly clean or - correct solution :-% - - Reads are equally tricky due to a nasty characteristic of the NCR5380. - If the chip is in DMA mode for an READ, it will respond to a target's - REQ by latching the SCSI data into the INPUT DATA register and asserting - ACK, even if it has _already_ been notified by the DMA controller that - the current DMA transfer has completed! If the NCR5380 is then taken - out of DMA mode, this already-acknowledged byte is lost. - - This is not a problem for "one DMA transfer per command" reads, because - the situation will never arise... either all of the data is DMA'ed - properly, or the target switches to MESSAGE IN phase to signal a - disconnection (either operation bringing the DMA to a clean halt). - However, in order to handle scatter-reads, we must work around the - problem. The chosen fix is to DMA N-2 bytes, then check for the - condition before taking the NCR5380 out of DMA mode. One or two extra - bytes are transferred via PIO as necessary to fill out the original - request. -*/ + For write DMAs, we want to wait until the last byte has been + transferred out over the bus before we turn off DMA mode. Alas, there + seems to be no terribly good way of doing this on a 5380 under all + conditions. For non-scatter-gather operations, we can wait until REQ + and ACK both go false, or until a phase mismatch occurs. Gather-writes + are nastier, since the device will be expecting more data than we + are prepared to send it, and REQ will remain asserted. On a 53C8[01] we + could test LAST BIT SENT to assure transfer (I imagine this is precisely + why this signal was added to the newer chips) but on the older 538[01] + this signal does not exist. The workaround for this lack is a watchdog; + we bail out of the wait-loop after a modest amount of wait-time if + the usual exit conditions are not met. Not a terribly clean or + correct solution :-% + + Reads are equally tricky due to a nasty characteristic of the NCR5380. + If the chip is in DMA mode for an READ, it will respond to a target's + REQ by latching the SCSI data into the INPUT DATA register and asserting + ACK, even if it has _already_ been notified by the DMA controller that + the current DMA transfer has completed! If the NCR5380 is then taken + out of DMA mode, this already-acknowledged byte is lost. + + This is not a problem for "one DMA transfer per command" reads, because + the situation will never arise... either all of the data is DMA'ed + properly, or the target switches to MESSAGE IN phase to signal a + disconnection (either operation bringing the DMA to a clean halt). + However, in order to handle scatter-reads, we must work around the + problem. The chosen fix is to DMA N-2 bytes, then check for the + condition before taking the NCR5380 out of DMA mode. One or two extra + bytes are transferred via PIO as necessary to fill out the original + request. + */ - if (p & SR_IO) { +if (p & SR_IO) { #ifdef READ_OVERRUNS - udelay(10); - if (((NCR5380_read(BUS_AND_STATUS_REG) & (BASR_PHASE_MATCH|BASR_ACK)) == - (BASR_PHASE_MATCH | BASR_ACK))) { - saved_data = NCR5380_read(INPUT_DATA_REGISTER); - overrun = 1; - } -#endif - } else { - int limit = 100; - while (((tmp = NCR5380_read(BUS_AND_STATUS_REG)) & BASR_ACK) || - (NCR5380_read(STATUS_REG) & SR_REQ)) { - if (!(tmp & BASR_PHASE_MATCH)) break; - if (--limit < 0) break; - } - } + udelay(10); + if (((NCR5380_read(BUS_AND_STATUS_REG) & (BASR_PHASE_MATCH | BASR_ACK)) == + (BASR_PHASE_MATCH | BASR_ACK))) { + saved_data = NCR5380_read(INPUT_DATA_REGISTER); + overrun = 1; + } +#endif +} else { + int limit = 100; + while (((tmp = NCR5380_read(BUS_AND_STATUS_REG)) & BASR_ACK) || + (NCR5380_read(STATUS_REG) & SR_REQ)) { + if (!(tmp & BASR_PHASE_MATCH)) + break; + if (--limit < 0) + break; + } +} #if (NDEBUG & NDEBUG_DMA) - printk("scsi%d : polled DMA transfer complete, basr 0x%X, sr 0x%X\n", - instance->host_no, tmp, NCR5380_read(STATUS_REG)); +printk("scsi%d : polled DMA transfer complete, basr 0x%X, sr 0x%X\n", + instance->host_no, tmp, NCR5380_read(STATUS_REG)); #endif - NCR5380_write(MODE_REG, MR_BASE); - NCR5380_write(INITIATOR_COMMAND_REG, ICR_BASE); +NCR5380_write(MODE_REG, MR_BASE); +NCR5380_write(INITIATOR_COMMAND_REG, ICR_BASE); - residue = NCR5380_dma_residual(instance); - c -= residue; - *count -= c; - *data += c; - *phase = NCR5380_read(STATUS_REG) & PHASE_MASK; +residue = NCR5380_dma_residual(instance); +c -= residue; +*count -= c; +*data += c; +*phase = NCR5380_read(STATUS_REG) & PHASE_MASK; #ifdef READ_OVERRUNS - if (*phase == p && (p & SR_IO) && residue == 0) { - if (overrun) { +if (*phase == p && (p & SR_IO) && residue == 0) +{ +if (overrun) { #if (NDEBUG & NDEBUG_DMA) printk("Got an input overrun, using saved byte\n"); #endif @@ -2190,849 +2285,846 @@ *data += 1; *count -= 1; cnt = toPIO = 1; - } else { +} else { printk("No overrun??\n"); cnt = toPIO = 2; - } +} #if (NDEBUG & NDEBUG_DMA) - printk("Doing %d-byte PIO to 0x%X\n", cnt, *data); +printk("Doing %d-byte PIO to 0x%X\n", cnt, *data); +#endif +NCR5380_transfer_pio(instance, phase, &cnt, data); +*count -= toPIO - cnt; +} #endif - NCR5380_transfer_pio(instance, phase, &cnt, data); - *count -= toPIO - cnt; - } -#endif #if (NDEBUG & NDEBUG_DMA) - printk("Return with data ptr = 0x%X, count %d, last 0x%X, next 0x%X\n", - *data, *count, *(*data+*count-1), *(*data+*count)); +printk("Return with data ptr = 0x%X, count %d, last 0x%X, next 0x%X\n", + *data, *count, *(*data + *count - 1), *(*data + *count)); #endif - return 0; - +return 0; + #elif defined(REAL_DMA) - return 0; -#else /* defined(REAL_DMA_POLL) */ - if (p & SR_IO) { +return 0; +#else /* defined(REAL_DMA_POLL) */ +if (p & SR_IO) { #ifdef DMA_WORKS_RIGHT - foo = NCR5380_pread(instance, d, c); + foo = NCR5380_pread(instance, d, c); #else int diff = 1; if (hostdata->flags & FLAG_NCR53C400) { - diff=0; + diff = 0; } - if (!(foo = NCR5380_pread(instance, d, c - diff))) { - /* - * We can't disable DMA mode after successfully transferring - * what we plan to be the last byte, since that would open up - * a race condition where if the target asserted REQ before - * we got the DMA mode reset, the NCR5380 would have latched - * an additional byte into the INPUT DATA register and we'd - * have dropped it. - * - * The workaround was to transfer one fewer bytes than we - * intended to with the pseudo-DMA read function, wait for - * the chip to latch the last byte, read it, and then disable - * pseudo-DMA mode. - * - * After REQ is asserted, the NCR5380 asserts DRQ and ACK. - * REQ is deasserted when ACK is asserted, and not reasserted - * until ACK goes false. Since the NCR5380 won't lower ACK - * until DACK is asserted, which won't happen unless we twiddle - * the DMA port or we take the NCR5380 out of DMA mode, we - * can guarantee that we won't handshake another extra - * byte. - */ - - if (!(hostdata->flags & FLAG_NCR53C400)) { - while (!(NCR5380_read(BUS_AND_STATUS_REG) & BASR_DRQ)); - /* Wait for clean handshake */ - while (NCR5380_read(STATUS_REG) & SR_REQ); - d[c - 1] = NCR5380_read(INPUT_DATA_REG); - } + /* + * We can't disable DMA mode after successfully transferring + * what we plan to be the last byte, since that would open up + * a race condition where if the target asserted REQ before + * we got the DMA mode reset, the NCR5380 would have latched + * an additional byte into the INPUT DATA register and we'd + * have dropped it. + * + * The workaround was to transfer one fewer bytes than we + * intended to with the pseudo-DMA read function, wait for + * the chip to latch the last byte, read it, and then disable + * pseudo-DMA mode. + * + * After REQ is asserted, the NCR5380 asserts DRQ and ACK. + * REQ is deasserted when ACK is asserted, and not reasserted + * until ACK goes false. Since the NCR5380 won't lower ACK + * until DACK is asserted, which won't happen unless we twiddle + * the DMA port or we take the NCR5380 out of DMA mode, we + * can guarantee that we won't handshake another extra + * byte. + */ + + if (!(hostdata->flags & FLAG_NCR53C400)) { + while (!(NCR5380_read(BUS_AND_STATUS_REG) & BASR_DRQ)); + /* Wait for clean handshake */ + while (NCR5380_read(STATUS_REG) & SR_REQ); + d[c - 1] = NCR5380_read(INPUT_DATA_REG); + } } #endif - } else { +} else { #ifdef DMA_WORKS_RIGHT - foo = NCR5380_pwrite(instance, d, c); + foo = NCR5380_pwrite(instance, d, c); #else - int timeout; + int timeout; #if (NDEBUG & NDEBUG_C400_PWRITE) printk("About to pwrite %d bytes\n", c); #endif if (!(foo = NCR5380_pwrite(instance, d, c))) { - /* - * Wait for the last byte to be sent. If REQ is being asserted for - * the byte we're interested, we'll ACK it and it will go false. - */ - if (!(hostdata->flags & FLAG_HAS_LAST_BYTE_SENT)) { - timeout = 20000; + /* + * Wait for the last byte to be sent. If REQ is being asserted for + * the byte we're interested, we'll ACK it and it will go false. + */ + if (!(hostdata->flags & FLAG_HAS_LAST_BYTE_SENT)) { + timeout = 20000; #if 1 #if 1 - while (!(NCR5380_read(BUS_AND_STATUS_REG) & - BASR_DRQ) && (NCR5380_read(BUS_AND_STATUS_REG) & - BASR_PHASE_MATCH)); + while (!(NCR5380_read(BUS_AND_STATUS_REG) & + BASR_DRQ) && (NCR5380_read(BUS_AND_STATUS_REG) & + BASR_PHASE_MATCH)); #else - if (NCR5380_read(STATUS_REG) & SR_REQ) { - for (; timeout && - !(NCR5380_read(BUS_AND_STATUS_REG) & BASR_ACK); - --timeout); - for (; timeout && (NCR5380_read(STATUS_REG) & SR_REQ); - --timeout); - } + if (NCR5380_read(STATUS_REG) & SR_REQ) { + for (; timeout && + !(NCR5380_read(BUS_AND_STATUS_REG) & BASR_ACK); + --timeout); + for (; timeout && (NCR5380_read(STATUS_REG) & SR_REQ); + --timeout); + } #endif - + #if (NDEBUG & NDEBUG_LAST_BYTE_SENT) - if (!timeout) - printk("scsi%d : timed out on last byte\n", - instance->host_no); + if (!timeout) + printk("scsi%d : timed out on last byte\n", + instance->host_no); #endif - if (hostdata->flags & FLAG_CHECK_LAST_BYTE_SENT) { - hostdata->flags &= ~FLAG_CHECK_LAST_BYTE_SENT; - if (NCR5380_read(TARGET_COMMAND_REG) & TCR_LAST_BYTE_SENT) { - hostdata->flags |= FLAG_HAS_LAST_BYTE_SENT; + if (hostdata->flags & FLAG_CHECK_LAST_BYTE_SENT) { + hostdata->flags &= ~FLAG_CHECK_LAST_BYTE_SENT; + if (NCR5380_read(TARGET_COMMAND_REG) & TCR_LAST_BYTE_SENT) { + hostdata->flags |= FLAG_HAS_LAST_BYTE_SENT; #if (NDEBUG & NDEBUG_LAST_BYTE_SENT) - printk("scsi%d : last bit sent works\n", - instance->host_no); + printk("scsi%d : last bit sent works\n", + instance->host_no); #endif - } - } - } else { + } + } + } else { #if (NDEBUG & NDEBUG_C400_PWRITE) - printk("Waiting for LASTBYTE\n"); + printk("Waiting for LASTBYTE\n"); #endif - while (!(NCR5380_read(TARGET_COMMAND_REG) & TCR_LAST_BYTE_SENT)); + while (!(NCR5380_read(TARGET_COMMAND_REG) & TCR_LAST_BYTE_SENT)); #if (NDEBUG & NDEBUG_C400_PWRITE) - printk("Got LASTBYTE\n"); + printk("Got LASTBYTE\n"); #endif - } + } #else - udelay (5); + udelay(5); #endif - } + } #endif - } - - NCR5380_write(MODE_REG, MR_BASE); - NCR5380_write(INITIATOR_COMMAND_REG, ICR_BASE); + } + NCR5380_write(MODE_REG, MR_BASE); + NCR5380_write(INITIATOR_COMMAND_REG, ICR_BASE); - if ((!(p & SR_IO)) && (hostdata->flags & FLAG_NCR53C400)) { + if ((!(p & SR_IO)) && (hostdata->flags & FLAG_NCR53C400)) { #if (NDEBUG & NDEBUG_C400_PWRITE) - printk("53C400w: Checking for IRQ\n"); + printk("53C400w: Checking for IRQ\n"); #endif - if (NCR5380_read(BUS_AND_STATUS_REG) & BASR_IRQ) { + if (NCR5380_read(BUS_AND_STATUS_REG) & BASR_IRQ) { #if (NDEBUG & NDEBUG_C400_PWRITE) - printk("53C400w: got it, reading reset interrupt reg\n"); + printk("53C400w: got it, reading reset interrupt reg\n"); #endif - NCR5380_read(RESET_PARITY_INTERRUPT_REG); - } else { - printk("53C400w: IRQ NOT THERE!\n"); + NCR5380_read(RESET_PARITY_INTERRUPT_REG); + } else { + printk("53C400w: IRQ NOT THERE!\n"); + } } - } - - *data = d + c; - *count = 0; - *phase = NCR5380_read(STATUS_REG) & PHASE_MASK; + *data = d + c; + *count = 0; + *phase = NCR5380_read(STATUS_REG) & PHASE_MASK; #if 0 - NCR5380_print_phase(instance); + NCR5380_print_phase(instance); #endif #if defined(PSEUDO_DMA) && !defined(UNSAFE) - sti(); -#endif /* defined(REAL_DMA_POLL) */ - return foo; -#endif /* def REAL_DMA */ + restore_flags(flags); +#endif /* defined(REAL_DMA_POLL) */ + return foo; +#endif /* def REAL_DMA */ } -#endif /* defined(REAL_DMA) | defined(PSEUDO_DMA) */ +#endif /* defined(REAL_DMA) | defined(PSEUDO_DMA) */ /* * Function : NCR5380_information_transfer (struct Scsi_Host *instance) * * Purpose : run through the various SCSI phases and do as the target - * directs us to. Operates on the currently connected command, - * instance->connected. + * directs us to. Operates on the currently connected command, + * instance->connected. * * Inputs : instance, instance for which we are doing commands * * Side effects : SCSI things happen, the disconnected queue will be - * modified if a command disconnects, *instance->connected will - * change. + * modified if a command disconnects, *instance->connected will + * change. * * XXX Note : we need to watch for bus free or a reset condition here - * to recover from an unexpected bus free condition. + * to recover from an unexpected bus free condition. */ - -static void NCR5380_information_transfer (struct Scsi_Host *instance) { - NCR5380_local_declare(); - struct NCR5380_hostdata *hostdata = (struct NCR5380_hostdata *) - instance->hostdata; - unsigned char msgout = NOP; - int sink = 0; - int len; + +static void NCR5380_information_transfer(struct Scsi_Host *instance) { + NCR5380_local_declare(); + struct NCR5380_hostdata *hostdata = (struct NCR5380_hostdata *) + instance->hostdata; + unsigned char msgout = NOP; + int sink = 0; + int len; #if defined(PSEUDO_DMA) || defined(REAL_DMA_POLL) - int transfersize; + int transfersize; #endif - unsigned char *data; - unsigned char phase, tmp, extended_msg[10], old_phase=0xff; - Scsi_Cmnd *cmd = (Scsi_Cmnd *) hostdata->connected; - NCR5380_setup(instance); - - while (1) { - tmp = NCR5380_read(STATUS_REG); - /* We only have a valid SCSI phase when REQ is asserted */ - if (tmp & SR_REQ) { - phase = (tmp & PHASE_MASK); - if (phase != old_phase) { - old_phase = phase; + unsigned char *data; + unsigned char phase, tmp, extended_msg[10], old_phase = 0xff; + Scsi_Cmnd *cmd = (Scsi_Cmnd *) hostdata->connected; + NCR5380_setup(instance); + + while (1) { + tmp = NCR5380_read(STATUS_REG); + /* We only have a valid SCSI phase when REQ is asserted */ + if (tmp & SR_REQ) { + phase = (tmp & PHASE_MASK); + if (phase != old_phase) { + old_phase = phase; #if (NDEBUG & NDEBUG_INFORMATION) - NCR5380_print_phase(instance); + NCR5380_print_phase(instance); #endif - } - - if (sink && (phase != PHASE_MSGOUT)) { - NCR5380_write(TARGET_COMMAND_REG, PHASE_SR_TO_TCR(tmp)); + } + if (sink && (phase != PHASE_MSGOUT)) { + NCR5380_write(TARGET_COMMAND_REG, PHASE_SR_TO_TCR(tmp)); - NCR5380_write(INITIATOR_COMMAND_REG, ICR_BASE | ICR_ASSERT_ATN | - ICR_ASSERT_ACK); - while (NCR5380_read(STATUS_REG) & SR_REQ); - NCR5380_write(INITIATOR_COMMAND_REG, ICR_BASE | - ICR_ASSERT_ATN); - sink = 0; - continue; - } - - switch (phase) { - case PHASE_DATAIN: - case PHASE_DATAOUT: + NCR5380_write(INITIATOR_COMMAND_REG, ICR_BASE | ICR_ASSERT_ATN | + ICR_ASSERT_ACK); + while (NCR5380_read(STATUS_REG) & SR_REQ); + NCR5380_write(INITIATOR_COMMAND_REG, ICR_BASE | + ICR_ASSERT_ATN); + sink = 0; + continue; + } + switch (phase) { + case PHASE_DATAIN: + case PHASE_DATAOUT: #if (NDEBUG & NDEBUG_NO_DATAOUT) - printk("scsi%d : NDEBUG_NO_DATAOUT set, attempted DATAOUT aborted\n", - instance->host_no); - sink = 1; - do_abort(instance); - cmd->result = DID_ERROR << 16; - cmd->done(cmd); - return; -#endif - /* - * If there is no room left in the current buffer in the - * scatter-gather list, move onto the next one. - */ - - if (!cmd->SCp.this_residual && cmd->SCp.buffers_residual) { - ++cmd->SCp.buffer; - --cmd->SCp.buffers_residual; - cmd->SCp.this_residual = cmd->SCp.buffer->length; - cmd->SCp.ptr = cmd->SCp.buffer->address; + printk("scsi%d : NDEBUG_NO_DATAOUT set, attempted DATAOUT aborted\n", + instance->host_no); + sink = 1; + do_abort(instance); + cmd->result = DID_ERROR << 16; + cmd->done(cmd); + return; +#endif + /* + * If there is no room left in the current buffer in the + * scatter-gather list, move onto the next one. + */ + + if (!cmd->SCp.this_residual && cmd->SCp.buffers_residual) { + ++cmd->SCp.buffer; + --cmd->SCp.buffers_residual; + cmd->SCp.this_residual = cmd->SCp.buffer->length; + cmd->SCp.ptr = cmd->SCp.buffer->address; #if (NDEBUG & NDEBUG_INFORMATION) - printk("scsi%d : %d bytes and %d buffers left\n", - instance->host_no, cmd->SCp.this_residual, - cmd->SCp.buffers_residual); -#endif - } - - /* - * The preferred transfer method is going to be - * PSEUDO-DMA for systems that are strictly PIO, - * since we can let the hardware do the handshaking. - * - * For this to work, we need to know the transfersize - * ahead of time, since the pseudo-DMA code will sit - * in an unconditional loop. - */ + printk("scsi%d : %d bytes and %d buffers left\n", + instance->host_no, cmd->SCp.this_residual, + cmd->SCp.buffers_residual); +#endif + } + /* + * The preferred transfer method is going to be + * PSEUDO-DMA for systems that are strictly PIO, + * since we can let the hardware do the handshaking. + * + * For this to work, we need to know the transfersize + * ahead of time, since the pseudo-DMA code will sit + * in an unconditional loop. + */ #if defined(PSEUDO_DMA) || defined(REAL_DMA_POLL) - /* KLL - * PSEUDO_DMA is defined here. If this is the g_NCR5380 - * driver then it will always be defined, so the - * FLAG_NO_PSEUDO_DMA is used to inhibit PDMA in the base - * NCR5380 case. I think this is a fairly clean solution. - * We supplement these 2 if's with the flag. - */ + /* KLL + * PSEUDO_DMA is defined here. If this is the g_NCR5380 + * driver then it will always be defined, so the + * FLAG_NO_PSEUDO_DMA is used to inhibit PDMA in the base + * NCR5380 case. I think this is a fairly clean solution. + * We supplement these 2 if's with the flag. + */ #ifdef NCR5380_dma_xfer_len - if (!cmd->device->borken && - !(hostdata->flags & FLAG_NO_PSEUDO_DMA) && - (transfersize = NCR5380_dma_xfer_len(instance, cmd)) != 0) { + if (!cmd->device->borken && + !(hostdata->flags & FLAG_NO_PSEUDO_DMA) && + (transfersize = NCR5380_dma_xfer_len(instance, cmd)) != 0) { #else - transfersize = cmd->transfersize; - -#ifdef LIMIT_TRANSFERSIZE /* If we have problems with interrupt service */ - if( transfersize > 512 ) - transfersize = 512; -#endif /* LIMIT_TRANSFERSIZE */ - - if (!cmd->device->borken && transfersize && - !(hostdata->flags & FLAG_NO_PSEUDO_DMA) && - cmd->SCp.this_residual && !(cmd->SCp.this_residual % - transfersize)) { - /* Limit transfers to 32K, for xx400 & xx406 - * pseudoDMA that transfers in 128 bytes blocks. */ - if (transfersize > 32*1024) - transfersize = 32*1024; -#endif - len = transfersize; - if (NCR5380_transfer_dma(instance, &phase, - &len, (unsigned char **) &cmd->SCp.ptr)) { - /* - * If the watchdog timer fires, all future accesses to this - * device will use the polled-IO. - */ - printk("scsi%d : switching target %d lun %d to slow handshake\n", - instance->host_no, cmd->target, cmd->lun); - cmd->device->borken = 1; - NCR5380_write(INITIATOR_COMMAND_REG, ICR_BASE | - ICR_ASSERT_ATN); - sink = 1; - do_abort(instance); - cmd->result = DID_ERROR << 16; - cmd->done(cmd); - /* XXX - need to source or sink data here, as appropriate */ - } else - cmd->SCp.this_residual -= transfersize - len; - } else -#endif /* defined(PSEUDO_DMA) || defined(REAL_DMA_POLL) */ - NCR5380_transfer_pio(instance, &phase, - (int *) &cmd->SCp.this_residual, (unsigned char **) - &cmd->SCp.ptr); - break; - case PHASE_MSGIN: - len = 1; - data = &tmp; - NCR5380_transfer_pio(instance, &phase, &len, &data); - cmd->SCp.Message = tmp; + transfersize = cmd->transfersize; - switch (tmp) { - /* - * Linking lets us reduce the time required to get the - * next command out to the device, hopefully this will - * mean we don't waste another revolution due to the delays - * required by ARBITRATION and another SELECTION. - * - * In the current implementation proposal, low level drivers - * merely have to start the next command, pointed to by - * next_link, done() is called as with unlinked commands. - */ +#ifdef LIMIT_TRANSFERSIZE /* If we have problems with interrupt service */ + if (transfersize > 512) + transfersize = 512; +#endif /* LIMIT_TRANSFERSIZE */ + + if (!cmd->device->borken && transfersize && + !(hostdata->flags & FLAG_NO_PSEUDO_DMA) && + cmd->SCp.this_residual && !(cmd->SCp.this_residual % + transfersize)) { + /* Limit transfers to 32K, for xx400 & xx406 + * pseudoDMA that transfers in 128 bytes blocks. */ + if (transfersize > 32 * 1024) + transfersize = 32 * 1024; +#endif + len = transfersize; + if (NCR5380_transfer_dma(instance, &phase, + &len, (unsigned char **) &cmd->SCp.ptr)) { + /* + * If the watchdog timer fires, all future accesses to this + * device will use the polled-IO. + */ + printk("scsi%d : switching target %d lun %d to slow handshake\n", + instance->host_no, cmd->target, cmd->lun); + cmd->device->borken = 1; + NCR5380_write(INITIATOR_COMMAND_REG, ICR_BASE | + ICR_ASSERT_ATN); + sink = 1; + do_abort(instance); + cmd->result = DID_ERROR << 16; + cmd->done(cmd); + /* XXX - need to source or sink data here, as appropriate */ + } else + cmd->SCp.this_residual -= transfersize - len; + } else +#endif /* defined(PSEUDO_DMA) || defined(REAL_DMA_POLL) */ + NCR5380_transfer_pio(instance, &phase, + (int *) &cmd->SCp.this_residual, (unsigned char **) + &cmd->SCp.ptr); + break; + case PHASE_MSGIN: + len = 1; + data = &tmp; + NCR5380_transfer_pio(instance, &phase, &len, &data); + cmd->SCp.Message = tmp; + + switch (tmp) { + /* + * Linking lets us reduce the time required to get the + * next command out to the device, hopefully this will + * mean we don't waste another revolution due to the delays + * required by ARBITRATION and another SELECTION. + * + * In the current implementation proposal, low level drivers + * merely have to start the next command, pointed to by + * next_link, done() is called as with unlinked commands. + */ #ifdef LINKED - case LINKED_CMD_COMPLETE: - case LINKED_FLG_CMD_COMPLETE: - /* Accept message by clearing ACK */ - NCR5380_write(INITIATOR_COMMAND_REG, ICR_BASE); - -#if (NDEBUG & NDEBUG_LINKED) - printk("scsi%d : target %d lun %d linked command complete.\n", - instance->host_no, cmd->target, cmd->lun); -#endif - /* - * Sanity check : A linked command should only terminate with - * one of these messages if there are more linked commands - * available. - */ - - if (!cmd->next_link) { - printk("scsi%d : target %d lun %d linked command complete, no next_link\n" - instance->host_no, cmd->target, cmd->lun); - sink = 1; - do_abort (instance); - return; - } - - initialize_SCp(cmd->next_link); - /* The next command is still part of this process */ - cmd->next_link->tag = cmd->tag; - cmd->result = cmd->SCp.Status | (cmd->SCp.Message << 8); -#if (NDEBUG & NDEBUG_LINKED) - printk("scsi%d : target %d lun %d linked request done, calling scsi_done().\n", - instance->host_no, cmd->target, cmd->lun); + case LINKED_CMD_COMPLETE: + case LINKED_FLG_CMD_COMPLETE: + /* Accept message by clearing ACK */ + NCR5380_write(INITIATOR_COMMAND_REG, ICR_BASE); + +#if (NDEBUG & NDEBUG_LINKED) + printk("scsi%d : target %d lun %d linked command complete.\n", + instance->host_no, cmd->target, cmd->lun); +#endif + /* + * Sanity check : A linked command should only terminate with + * one of these messages if there are more linked commands + * available. + */ + + if (!cmd->next_link) { + printk("scsi%d : target %d lun %d linked command complete, no next_link\n" + instance->host_no, cmd->target, cmd->lun); + sink = 1; + do_abort(instance); + return; + } + initialize_SCp(cmd->next_link); + /* The next command is still part of this process */ + cmd->next_link->tag = cmd->tag; + cmd->result = cmd->SCp.Status | (cmd->SCp.Message << 8); +#if (NDEBUG & NDEBUG_LINKED) + printk("scsi%d : target %d lun %d linked request done, calling scsi_done().\n", + instance->host_no, cmd->target, cmd->lun); #endif #ifdef NCR5380_STATS - collect_stats(hostdata, cmd); + collect_stats(hostdata, cmd); #endif - cmd->scsi_done(cmd); - cmd = hostdata->connected; - break; -#endif /* def LINKED */ - case ABORT: - case COMMAND_COMPLETE: - /* Accept message by clearing ACK */ - sink = 1; - NCR5380_write(INITIATOR_COMMAND_REG, ICR_BASE); - hostdata->connected = NULL; + cmd->scsi_done(cmd); + cmd = hostdata->connected; + break; +#endif /* def LINKED */ + case ABORT: + case COMMAND_COMPLETE: + /* Accept message by clearing ACK */ + sink = 1; + NCR5380_write(INITIATOR_COMMAND_REG, ICR_BASE); + hostdata->connected = NULL; #if (NDEBUG & NDEBUG_QUEUES) - printk("scsi%d : command for target %d, lun %d completed\n", - instance->host_no, cmd->target, cmd->lun); + printk("scsi%d : command for target %d, lun %d completed\n", + instance->host_no, cmd->target, cmd->lun); #endif - hostdata->busy[cmd->target] &= ~(1 << cmd->lun); + hostdata->busy[cmd->target] &= ~(1 << cmd->lun); - /* - * I'm not sure what the correct thing to do here is : - * - * If the command that just executed is NOT a request - * sense, the obvious thing to do is to set the result - * code to the values of the stored parameters. - * - * If it was a REQUEST SENSE command, we need some way - * to differentiate between the failure code of the original - * and the failure code of the REQUEST sense - the obvious - * case is success, where we fall through and leave the result - * code unchanged. - * - * The non-obvious place is where the REQUEST SENSE failed - */ - - if (cmd->cmnd[0] != REQUEST_SENSE) - cmd->result = cmd->SCp.Status | (cmd->SCp.Message << 8); - else if (cmd->SCp.Status != GOOD) - cmd->result = (cmd->result & 0x00ffff) | (DID_ERROR << 16); - -#ifdef AUTOSENSE - if ((cmd->cmnd[0] != REQUEST_SENSE) && - (cmd->SCp.Status == CHECK_CONDITION)) { -#if (NDEBUG & NDEBUG_AUTOSENSE) - printk("scsi%d : performing request sense\n", - instance->host_no); -#endif - cmd->cmnd[0] = REQUEST_SENSE; - cmd->cmnd[1] &= 0xe0; - cmd->cmnd[2] = 0; - cmd->cmnd[3] = 0; - cmd->cmnd[4] = sizeof(cmd->sense_buffer); - cmd->cmnd[5] = 0; - - cmd->SCp.buffer = NULL; - cmd->SCp.buffers_residual = 0; - cmd->SCp.ptr = (char *) cmd->sense_buffer; - cmd->SCp.this_residual = sizeof(cmd->sense_buffer); + /* + * I'm not sure what the correct thing to do here is : + * + * If the command that just executed is NOT a request + * sense, the obvious thing to do is to set the result + * code to the values of the stored parameters. + * + * If it was a REQUEST SENSE command, we need some way + * to differentiate between the failure code of the original + * and the failure code of the REQUEST sense - the obvious + * case is success, where we fall through and leave the result + * code unchanged. + * + * The non-obvious place is where the REQUEST SENSE failed + */ + + if (cmd->cmnd[0] != REQUEST_SENSE) + cmd->result = cmd->SCp.Status | (cmd->SCp.Message << 8); + else if (cmd->SCp.Status != GOOD) + cmd->result = (cmd->result & 0x00ffff) | (DID_ERROR << 16); - cli(); - LIST(cmd,hostdata->issue_queue); - cmd->host_scribble = (unsigned char *) - hostdata->issue_queue; - hostdata->issue_queue = (Scsi_Cmnd *) cmd; - sti(); +#ifdef AUTOSENSE + if ((cmd->cmnd[0] != REQUEST_SENSE) && + (cmd->SCp.Status == CHECK_CONDITION)) { + unsigned long flags; +#if (NDEBUG & NDEBUG_AUTOSENSE) + printk("scsi%d : performing request sense\n", + instance->host_no); +#endif + cmd->cmnd[0] = REQUEST_SENSE; + cmd->cmnd[1] &= 0xe0; + cmd->cmnd[2] = 0; + cmd->cmnd[3] = 0; + cmd->cmnd[4] = sizeof(cmd->sense_buffer); + cmd->cmnd[5] = 0; + + cmd->SCp.buffer = NULL; + cmd->SCp.buffers_residual = 0; + cmd->SCp.ptr = (char *) cmd->sense_buffer; + cmd->SCp.this_residual = sizeof(cmd->sense_buffer); + + save_flags(flags); + cli(); + LIST(cmd, hostdata->issue_queue); + cmd->host_scribble = (unsigned char *) + hostdata->issue_queue; + hostdata->issue_queue = (Scsi_Cmnd *) cmd; + restore_flags(flags); #if (NDEBUG & NDEBUG_QUEUES) - printk("scsi%d : REQUEST SENSE added to head of issue queue\n",instance->host_no); + printk("scsi%d : REQUEST SENSE added to head of issue queue\n", instance->host_no); #endif - } else { -#endif /* def AUTOSENSE */ + } else { +#endif /* def AUTOSENSE */ #ifdef NCR5380_STATS - collect_stats(hostdata, cmd); + collect_stats(hostdata, cmd); #endif - cmd->scsi_done(cmd); - } + cmd->scsi_done(cmd); + } - NCR5380_write(SELECT_ENABLE_REG, hostdata->id_mask); - /* - * Restore phase bits to 0 so an interrupted selection, - * arbitration can resume. - */ - NCR5380_write(TARGET_COMMAND_REG, 0); - - while ((NCR5380_read(STATUS_REG) & SR_BSY) && !hostdata->connected) - barrier(); - return; - case MESSAGE_REJECT: - /* Accept message by clearing ACK */ - NCR5380_write(INITIATOR_COMMAND_REG, ICR_BASE); - switch (hostdata->last_message) { - case HEAD_OF_QUEUE_TAG: - case ORDERED_QUEUE_TAG: - case SIMPLE_QUEUE_TAG: - cmd->device->tagged_queue = 0; - hostdata->busy[cmd->target] |= (1 << cmd->lun); - break; - default: - break; - } - case DISCONNECT: - /* Accept message by clearing ACK */ - NCR5380_write(INITIATOR_COMMAND_REG, ICR_BASE); - cmd->device->disconnect = 1; - cli(); - LIST(cmd,hostdata->disconnected_queue); - cmd->host_scribble = (unsigned char *) - hostdata->disconnected_queue; - hostdata->connected = NULL; - hostdata->disconnected_queue = cmd; - sti(); + NCR5380_write(SELECT_ENABLE_REG, hostdata->id_mask); + /* + * Restore phase bits to 0 so an interrupted selection, + * arbitration can resume. + */ + NCR5380_write(TARGET_COMMAND_REG, 0); + + while ((NCR5380_read(STATUS_REG) & SR_BSY) && !hostdata->connected) + barrier(); + return; + case MESSAGE_REJECT: + /* Accept message by clearing ACK */ + NCR5380_write(INITIATOR_COMMAND_REG, ICR_BASE); + switch (hostdata->last_message) { + case HEAD_OF_QUEUE_TAG: + case ORDERED_QUEUE_TAG: + case SIMPLE_QUEUE_TAG: + cmd->device->tagged_queue = 0; + hostdata->busy[cmd->target] |= (1 << cmd->lun); + break; + default: + break; + } + case DISCONNECT: { + unsigned long flags; + /* Accept message by clearing ACK */ + NCR5380_write(INITIATOR_COMMAND_REG, ICR_BASE); + cmd->device->disconnect = 1; + save_flags(flags); + cli(); + LIST(cmd, hostdata->disconnected_queue); + cmd->host_scribble = (unsigned char *) + hostdata->disconnected_queue; + hostdata->connected = NULL; + hostdata->disconnected_queue = cmd; + restore_flags(flags); #if (NDEBUG & NDEBUG_QUEUES) - printk("scsi%d : command for target %d lun %d was moved from connected to" - " the disconnected_queue\n", instance->host_no, - cmd->target, cmd->lun); -#endif - /* - * Restore phase bits to 0 so an interrupted selection, - * arbitration can resume. - */ - NCR5380_write(TARGET_COMMAND_REG, 0); - - /* Enable reselect interrupts */ - NCR5380_write(SELECT_ENABLE_REG, hostdata->id_mask); - /* Wait for bus free to avoid nasty timeouts */ - while ((NCR5380_read(STATUS_REG) & SR_BSY) && !hostdata->connected) - barrier(); + printk("scsi%d : command for target %d lun %d was moved from connected to" + " the disconnected_queue\n", instance->host_no, + cmd->target, cmd->lun); +#endif + /* + * Restore phase bits to 0 so an interrupted selection, + * arbitration can resume. + */ + NCR5380_write(TARGET_COMMAND_REG, 0); + + /* Enable reselect interrupts */ + NCR5380_write(SELECT_ENABLE_REG, hostdata->id_mask); + /* Wait for bus free to avoid nasty timeouts */ + while ((NCR5380_read(STATUS_REG) & SR_BSY) && !hostdata->connected) + barrier(); #if 0 - NCR5380_print_status(instance); + NCR5380_print_status(instance); #endif - return; - /* - * The SCSI data pointer is *IMPLICITLY* saved on a disconnect - * operation, in violation of the SCSI spec so we can safely - * ignore SAVE/RESTORE pointers calls. - * - * Unfortunately, some disks violate the SCSI spec and - * don't issue the required SAVE_POINTERS message before - * disconnecting, and we have to break spec to remain - * compatible. - */ - case SAVE_POINTERS: - case RESTORE_POINTERS: - /* Accept message by clearing ACK */ - NCR5380_write(INITIATOR_COMMAND_REG, ICR_BASE); - break; - case EXTENDED_MESSAGE: + return; + } + /* + * The SCSI data pointer is *IMPLICITLY* saved on a disconnect + * operation, in violation of the SCSI spec so we can safely + * ignore SAVE/RESTORE pointers calls. + * + * Unfortunately, some disks violate the SCSI spec and + * don't issue the required SAVE_POINTERS message before + * disconnecting, and we have to break spec to remain + * compatible. + */ + case SAVE_POINTERS: + case RESTORE_POINTERS: + /* Accept message by clearing ACK */ + NCR5380_write(INITIATOR_COMMAND_REG, ICR_BASE); + break; + case EXTENDED_MESSAGE: /* * Extended messages are sent in the following format : - * Byte - * 0 EXTENDED_MESSAGE == 1 - * 1 length (includes one byte for code, doesn't - * include first two bytes) - * 2 code - * 3..length+1 arguments + * Byte + * 0 EXTENDED_MESSAGE == 1 + * 1 length (includes one byte for code, doesn't + * include first two bytes) + * 2 code + * 3..length+1 arguments * * Start the extended message buffer with the EXTENDED_MESSAGE * byte, since print_msg() wants the whole thing. */ - extended_msg[0] = EXTENDED_MESSAGE; - /* Accept first byte by clearing ACK */ - NCR5380_write(INITIATOR_COMMAND_REG, ICR_BASE); + extended_msg[0] = EXTENDED_MESSAGE; + /* Accept first byte by clearing ACK */ + NCR5380_write(INITIATOR_COMMAND_REG, ICR_BASE); #if (NDEBUG & NDEBUG_EXTENDED) - printk("scsi%d : receiving extended message\n", - instance->host_no); + printk("scsi%d : receiving extended message\n", + instance->host_no); #endif - len = 2; - data = extended_msg + 1; - phase = PHASE_MSGIN; - NCR5380_transfer_pio(instance, &phase, &len, &data); + len = 2; + data = extended_msg + 1; + phase = PHASE_MSGIN; + NCR5380_transfer_pio(instance, &phase, &len, &data); #if (NDEBUG & NDEBUG_EXTENDED) - printk("scsi%d : length=%d, code=0x%02x\n", - instance->host_no, (int) extended_msg[1], - (int) extended_msg[2]); + printk("scsi%d : length=%d, code=0x%02x\n", + instance->host_no, (int) extended_msg[1], + (int) extended_msg[2]); #endif - if (!len && extended_msg[1] <= - (sizeof (extended_msg) - 1)) { - /* Accept third byte by clearing ACK */ - NCR5380_write(INITIATOR_COMMAND_REG, ICR_BASE); - len = extended_msg[1] - 1; - data = extended_msg + 3; - phase = PHASE_MSGIN; + if (!len && extended_msg[1] <= + (sizeof(extended_msg) - 1)) { + /* Accept third byte by clearing ACK */ + NCR5380_write(INITIATOR_COMMAND_REG, ICR_BASE); + len = extended_msg[1] - 1; + data = extended_msg + 3; + phase = PHASE_MSGIN; - NCR5380_transfer_pio(instance, &phase, &len, &data); + NCR5380_transfer_pio(instance, &phase, &len, &data); #if (NDEBUG & NDEBUG_EXTENDED) - printk("scsi%d : message received, residual %d\n", - instance->host_no, len); + printk("scsi%d : message received, residual %d\n", + instance->host_no, len); #endif - switch (extended_msg[2]) { - case EXTENDED_SDTR: - case EXTENDED_WDTR: - case EXTENDED_MODIFY_DATA_POINTER: - case EXTENDED_EXTENDED_IDENTIFY: - tmp = 0; - } - } else if (len) { - printk("scsi%d: error receiving extended message\n", - instance->host_no); - tmp = 0; - } else { - printk("scsi%d: extended message code %02x length %d is too long\n", - instance->host_no, extended_msg[2], extended_msg[1]); - tmp = 0; - } - /* Fall through to reject message */ - - /* - * If we get something weird that we aren't expecting, - * reject it. - */ - default: - if (!tmp) { - printk("scsi%d: rejecting message ", instance->host_no); - print_msg (extended_msg); - printk("\n"); - } else if (tmp != EXTENDED_MESSAGE) - printk("scsi%d: rejecting unknown message %02x from target %d, lun %d\n", - instance->host_no, tmp, cmd->target, cmd->lun); - else - printk("scsi%d: rejecting unknown extended message code %02x, length %d from target %d, lun %d\n", - instance->host_no, extended_msg[1], extended_msg[0], cmd->target, cmd->lun); - - msgout = MESSAGE_REJECT; - NCR5380_write(INITIATOR_COMMAND_REG, ICR_BASE | - ICR_ASSERT_ATN); - break; - } /* switch (tmp) */ - break; - case PHASE_MSGOUT: - len = 1; - data = &msgout; - hostdata->last_message = msgout; - NCR5380_transfer_pio(instance, &phase, &len, &data); - if (msgout == ABORT) { - hostdata->busy[cmd->target] &= ~(1 << cmd->lun); - hostdata->connected = NULL; - cmd->result = DID_ERROR << 16; + switch (extended_msg[2]) { + case EXTENDED_SDTR: + case EXTENDED_WDTR: + case EXTENDED_MODIFY_DATA_POINTER: + case EXTENDED_EXTENDED_IDENTIFY: + tmp = 0; + } + } else if (len) { + printk("scsi%d: error receiving extended message\n", + instance->host_no); + tmp = 0; + } else { + printk("scsi%d: extended message code %02x length %d is too long\n", + instance->host_no, extended_msg[2], extended_msg[1]); + tmp = 0; + } + /* Fall through to reject message */ + + /* + * If we get something weird that we aren't expecting, + * reject it. + */ + default: + if (!tmp) { + printk("scsi%d: rejecting message ", instance->host_no); + print_msg(extended_msg); + printk("\n"); + } else if (tmp != EXTENDED_MESSAGE) + printk("scsi%d: rejecting unknown message %02x from target %d, lun %d\n", + instance->host_no, tmp, cmd->target, cmd->lun); + else + printk("scsi%d: rejecting unknown extended message code %02x, length %d from target %d, lun %d\n", + instance->host_no, extended_msg[1], extended_msg[0], cmd->target, cmd->lun); + + msgout = MESSAGE_REJECT; + NCR5380_write(INITIATOR_COMMAND_REG, ICR_BASE | + ICR_ASSERT_ATN); + break; + } /* switch (tmp) */ + break; + case PHASE_MSGOUT: + len = 1; + data = &msgout; + hostdata->last_message = msgout; + NCR5380_transfer_pio(instance, &phase, &len, &data); + if (msgout == ABORT) { + hostdata->busy[cmd->target] &= ~(1 << cmd->lun); + hostdata->connected = NULL; + cmd->result = DID_ERROR << 16; #ifdef NCR5380_STATS - collect_stats(hostdata, cmd); + collect_stats(hostdata, cmd); #endif - cmd->scsi_done(cmd); - NCR5380_write(SELECT_ENABLE_REG, hostdata->id_mask); - return; - } - msgout = NOP; - break; - case PHASE_CMDOUT: - len = cmd->cmd_len; - data = cmd->cmnd; - /* - * XXX for performance reasons, on machines with a - * PSEUDO-DMA architecture we should probably - * use the dma transfer function. - */ - NCR5380_transfer_pio(instance, &phase, &len, - &data); + cmd->scsi_done(cmd); + NCR5380_write(SELECT_ENABLE_REG, hostdata->id_mask); + return; + } + msgout = NOP; + break; + case PHASE_CMDOUT: + len = cmd->cmd_len; + data = cmd->cmnd; + /* + * XXX for performance reasons, on machines with a + * PSEUDO-DMA architecture we should probably + * use the dma transfer function. + */ + NCR5380_transfer_pio(instance, &phase, &len, + &data); #ifdef USLEEP - if (!disconnect && should_disconnect(cmd->cmnd[0])) { - hostdata->time_expires = jiffies + USLEEP_SLEEP; + if (!disconnect && should_disconnect(cmd->cmnd[0])) { + hostdata->time_expires = jiffies + USLEEP_SLEEP; #if (NDEBUG & NDEBUG_USLEEP) - printk("scsi%d : issued command, sleeping until %ul\n", instance->host_no, - hostdata->time_expires); + printk("scsi%d : issued command, sleeping until %ul\n", instance->host_no, + hostdata->time_expires); #endif - NCR5380_set_timer (instance); - return; - } -#endif /* def USLEEP */ - break; - case PHASE_STATIN: - len = 1; - data = &tmp; - NCR5380_transfer_pio(instance, &phase, &len, &data); - cmd->SCp.Status = tmp; - break; - default: - printk("scsi%d : unknown phase\n", instance->host_no); + NCR5380_set_timer(instance); + return; + } +#endif /* def USLEEP */ + break; + case PHASE_STATIN: + len = 1; + data = &tmp; + NCR5380_transfer_pio(instance, &phase, &len, &data); + cmd->SCp.Status = tmp; + break; + default: + printk("scsi%d : unknown phase\n", instance->host_no); #ifdef NDEBUG - NCR5380_print(instance); + NCR5380_print(instance); #endif - } /* switch(phase) */ - } /* if (tmp * SR_REQ) */ + } /* switch(phase) */ + } /* if (tmp * SR_REQ) */ #ifdef USLEEP - else { - if (!disconnect && hostdata->time_expires && jiffies > - hostdata->time_expires) { - hostdata->time_expires = jiffies + USLEEP_SLEEP; + else { + if (!disconnect && hostdata->time_expires && jiffies > + hostdata->time_expires) { + hostdata->time_expires = jiffies + USLEEP_SLEEP; #if (NDEBUG & NDEBUG_USLEEP) - printk("scsi%d : poll timed out, sleeping until %ul\n", instance->host_no, - hostdata->time_expires); + printk("scsi%d : poll timed out, sleeping until %ul\n", instance->host_no, + hostdata->time_expires); #endif - NCR5380_set_timer (instance); - return; - } - } + NCR5380_set_timer(instance); + return; + } + } #endif - } /* while (1) */ + } /* while (1) */ } /* * Function : void NCR5380_reselect (struct Scsi_Host *instance) * * Purpose : does reselection, initializing the instance->connected - * field to point to the Scsi_Cmnd for which the I_T_L or I_T_L_Q - * nexus has been reestablished, - * + * field to point to the Scsi_Cmnd for which the I_T_L or I_T_L_Q + * nexus has been reestablished, + * * Inputs : instance - this instance of the NCR5380. * */ -static void NCR5380_reselect (struct Scsi_Host *instance) { - NCR5380_local_declare(); - struct NCR5380_hostdata *hostdata = (struct NCR5380_hostdata *) - instance->hostdata; - unsigned char target_mask; - unsigned char lun, phase; - int len; +static void NCR5380_reselect(struct Scsi_Host *instance) { + NCR5380_local_declare(); + struct NCR5380_hostdata *hostdata = (struct NCR5380_hostdata *) + instance->hostdata; + unsigned char target_mask; + unsigned char lun, phase; + int len; #ifdef SCSI2 - unsigned char tag; + unsigned char tag; #endif - unsigned char msg[3]; - unsigned char *data; - Scsi_Cmnd *tmp = NULL, *prev; - int abort = 0; - NCR5380_setup(instance); - - /* - * Disable arbitration, etc. since the host adapter obviously - * lost, and tell an interrupted NCR5380_select() to restart. - */ + unsigned char msg[3]; + unsigned char *data; + Scsi_Cmnd *tmp = NULL, *prev; + int abort = 0; + NCR5380_setup(instance); + + /* + * Disable arbitration, etc. since the host adapter obviously + * lost, and tell an interrupted NCR5380_select() to restart. + */ - NCR5380_write(MODE_REG, MR_BASE); - hostdata->restart_select = 1; + NCR5380_write(MODE_REG, MR_BASE); + hostdata->restart_select = 1; - target_mask = NCR5380_read(CURRENT_SCSI_DATA_REG) & ~(hostdata->id_mask); + target_mask = NCR5380_read(CURRENT_SCSI_DATA_REG) & ~(hostdata->id_mask); #if (NDEBUG & NDEBUG_RESELECTION) - printk("scsi%d : reselect\n", instance->host_no); + printk("scsi%d : reselect\n", instance->host_no); #endif - /* - * At this point, we have detected that our SCSI ID is on the bus, - * SEL is true and BSY was false for at least one bus settle delay - * (400 ns). - * - * We must assert BSY ourselves, until the target drops the SEL - * signal. - */ - - NCR5380_write(INITIATOR_COMMAND_REG, ICR_BASE | ICR_ASSERT_BSY); - - while (NCR5380_read(STATUS_REG) & SR_SEL); - NCR5380_write(INITIATOR_COMMAND_REG, ICR_BASE); - - /* - * Wait for target to go into MSGIN. - */ - - while (!(NCR5380_read(STATUS_REG) & SR_REQ)); - - len = 1; - data = msg; - phase = PHASE_MSGIN; - NCR5380_transfer_pio(instance, &phase, &len, &data); - - - if (!msg[0] & 0x80) { - printk("scsi%d : expecting IDENTIFY message, got ", - instance->host_no); - print_msg(msg); - abort = 1; - } else { - /* Accept message by clearing ACK */ - NCR5380_write(INITIATOR_COMMAND_REG, ICR_BASE); - lun = (msg[0] & 0x07); - /* - * We need to add code for SCSI-II to track which devices have - * I_T_L_Q nexuses established, and which have simple I_T_L - * nexuses so we can chose to do additional data transfer. - */ + * At this point, we have detected that our SCSI ID is on the bus, + * SEL is true and BSY was false for at least one bus settle delay + * (400 ns). + * + * We must assert BSY ourselves, until the target drops the SEL + * signal. + */ + + NCR5380_write(INITIATOR_COMMAND_REG, ICR_BASE | ICR_ASSERT_BSY); + + while (NCR5380_read(STATUS_REG) & SR_SEL); + NCR5380_write(INITIATOR_COMMAND_REG, ICR_BASE); + + /* + * Wait for target to go into MSGIN. + */ + + while (!(NCR5380_read(STATUS_REG) & SR_REQ)); + + len = 1; + data = msg; + phase = PHASE_MSGIN; + NCR5380_transfer_pio(instance, &phase, &len, &data); + + + if (!msg[0] & 0x80) { + printk("scsi%d : expecting IDENTIFY message, got ", + instance->host_no); + print_msg(msg); + abort = 1; + } else { + /* Accept message by clearing ACK */ + NCR5380_write(INITIATOR_COMMAND_REG, ICR_BASE); + lun = (msg[0] & 0x07); + + /* + * We need to add code for SCSI-II to track which devices have + * I_T_L_Q nexuses established, and which have simple I_T_L + * nexuses so we can chose to do additional data transfer. + */ #ifdef SCSI2 #error "SCSI-II tagged queueing is not supported yet" #endif - /* - * Find the command corresponding to the I_T_L or I_T_L_Q nexus we - * just reestablished, and remove it from the disconnected queue. - */ + /* + * Find the command corresponding to the I_T_L or I_T_L_Q nexus we + * just reestablished, and remove it from the disconnected queue. + */ - for (tmp = (Scsi_Cmnd *) hostdata->disconnected_queue, prev = NULL; - tmp; prev = tmp, tmp = (Scsi_Cmnd *) tmp->host_scribble) - if ((target_mask == (1 << tmp->target)) && (lun == tmp->lun) + for (tmp = (Scsi_Cmnd *) hostdata->disconnected_queue, prev = NULL; + tmp; prev = tmp, tmp = (Scsi_Cmnd *) tmp->host_scribble) + if ((target_mask == (1 << tmp->target)) && (lun == tmp->lun) #ifdef SCSI2 - && (tag == tmp->tag) + && (tag == tmp->tag) #endif -) { - if (prev) { - REMOVE(prev,prev->host_scribble,tmp,tmp->host_scribble); - prev->host_scribble = tmp->host_scribble; - } else { - REMOVE(-1,hostdata->disconnected_queue,tmp,tmp->host_scribble); - hostdata->disconnected_queue = (Scsi_Cmnd *) tmp->host_scribble; - } - tmp->host_scribble = NULL; - break; - } - - if (!tmp) { + ) { + if (prev) { + REMOVE(prev, prev->host_scribble, tmp, tmp->host_scribble); + prev->host_scribble = tmp->host_scribble; + } else { + REMOVE(-1, hostdata->disconnected_queue, tmp, tmp->host_scribble); + hostdata->disconnected_queue = (Scsi_Cmnd *) tmp->host_scribble; + } + tmp->host_scribble = NULL; + break; + } + if (!tmp) { #ifdef SCSI2 - printk("scsi%d : warning : target bitmask %02x lun %d tag %d not in disconnect_queue.\n", - instance->host_no, target_mask, lun, tag); + printk("scsi%d : warning : target bitmask %02x lun %d tag %d not in disconnect_queue.\n", + instance->host_no, target_mask, lun, tag); #else - printk("scsi%d : warning : target bitmask %02x lun %d not in disconnect_queue.\n", - instance->host_no, target_mask, lun); + printk("scsi%d : warning : target bitmask %02x lun %d not in disconnect_queue.\n", + instance->host_no, target_mask, lun); #endif - /* - * Since we have an established nexus that we can't do anything with, - * we must abort it. - */ - abort = 1; + /* + * Since we have an established nexus that we can't do anything with, + * we must abort it. + */ + abort = 1; + } } - } - if (abort) { - do_abort (instance); - } else { - hostdata->connected = tmp; + if (abort) { + do_abort(instance); + } else { + hostdata->connected = tmp; #if (NDEBUG & NDEBUG_RESELECTION) - printk("scsi%d : nexus established, target = %d, lun = %d, tag = %d\n", - instance->host_no, tmp->target, tmp->lun, tmp->tag); + printk("scsi%d : nexus established, target = %d, lun = %d, tag = %d\n", + instance->host_no, tmp->target, tmp->lun, tmp->tag); #endif - } + } } /* * Function : void NCR5380_dma_complete (struct Scsi_Host *instance) * * Purpose : called by interrupt handler when DMA finishes or a phase - * mismatch occurs (which would finish the DMA transfer). + * mismatch occurs (which would finish the DMA transfer). * * Inputs : instance - this instance of the NCR5380. * * Returns : pointer to the Scsi_Cmnd structure for which the I_T_L - * nexus has been reestablished, on failure NULL is returned. + * nexus has been reestablished, on failure NULL is returned. */ #ifdef REAL_DMA -static void NCR5380_dma_complete (NCR5380_instance *instance) { - NCR5380_local_declare(); - struct NCR5380_hostdata *hostdata = (struct NCR5380_hostdata * - instance->hostdata); - int transferred; - NCR5380_setup(instance); - - /* - * XXX this might not be right. - * - * Wait for final byte to transfer, ie wait for ACK to go false. - * - * We should use the Last Byte Sent bit, unfortunately this is - * not available on the 5380/5381 (only the various CMOS chips) - */ - - while (NCR5380_read(BUS_AND_STATUS_REG) & BASR_ACK); - - NCR5380_write(MODE_REG, MR_BASE); - NCR5380_write(INITIATOR_COMMAND_REG, ICR_BASE); - - /* - * The only places we should see a phase mismatch and have to send - * data from the same set of pointers will be the data transfer - * phases. So, residual, requested length are only important here. - */ - - if (!(hostdata->connected->SCp.phase & SR_CD)) { - transferred = instance->dmalen - NCR5380_dma_residual(); - hostdata->connected->SCp.this_residual -= transferred; - hostdata->connected->SCp.ptr += transferred; - } +static void NCR5380_dma_complete(NCR5380_instance * instance) { + NCR5380_local_declare(); + struct NCR5380_hostdata *hostdata = (struct NCR5380_hostdata * + instance->hostdata); + int transferred; + NCR5380_setup(instance); + + /* + * XXX this might not be right. + * + * Wait for final byte to transfer, ie wait for ACK to go false. + * + * We should use the Last Byte Sent bit, unfortunately this is + * not available on the 5380/5381 (only the various CMOS chips) + */ + + while (NCR5380_read(BUS_AND_STATUS_REG) & BASR_ACK); + + NCR5380_write(MODE_REG, MR_BASE); + NCR5380_write(INITIATOR_COMMAND_REG, ICR_BASE); + + /* + * The only places we should see a phase mismatch and have to send + * data from the same set of pointers will be the data transfer + * phases. So, residual, requested length are only important here. + */ + + if (!(hostdata->connected->SCp.phase & SR_CD)) { + transferred = instance->dmalen - NCR5380_dma_residual(); + hostdata->connected->SCp.this_residual -= transferred; + hostdata->connected->SCp.ptr += transferred; + } } -#endif /* def REAL_DMA */ +#endif /* def REAL_DMA */ /* * Function : int NCR5380_abort (Scsi_Cmnd *cmd) @@ -3040,44 +3132,46 @@ * Purpose : abort a command * * Inputs : cmd - the Scsi_Cmnd to abort, code - code to set the - * host byte of the result field to, if zero DID_ABORTED is - * used. + * host byte of the result field to, if zero DID_ABORTED is + * used. * * Returns : 0 - success, -1 on failure. * * XXX - there is no way to abort the command that is currently - * connected, you have to wait for it to complete. If this is - * a problem, we could implement longjmp() / setjmp(), setjmp() - * called where the loop started in NCR5380_main(). + * connected, you have to wait for it to complete. If this is + * a problem, we could implement longjmp() / setjmp(), setjmp() + * called where the loop started in NCR5380_main(). */ #ifndef NCR5380_abort static #endif -int NCR5380_abort (Scsi_Cmnd *cmd) { - NCR5380_local_declare(); - struct Scsi_Host *instance = cmd->host; - struct NCR5380_hostdata *hostdata = (struct NCR5380_hostdata *) - instance->hostdata; - Scsi_Cmnd *tmp, **prev; +int NCR5380_abort(Scsi_Cmnd * cmd) { + NCR5380_local_declare(); + unsigned long flags; + struct Scsi_Host *instance = cmd->host; + struct NCR5380_hostdata *hostdata = (struct NCR5380_hostdata *) + instance->hostdata; + Scsi_Cmnd *tmp, **prev; - printk("scsi%d : aborting command\n", instance->host_no); - print_Scsi_Cmnd (cmd); + printk("scsi%d : aborting command\n", instance->host_no); + print_Scsi_Cmnd(cmd); - NCR5380_print_status (instance); + NCR5380_print_status(instance); - printk("scsi%d : aborting command\n", instance->host_no); - print_Scsi_Cmnd (cmd); + printk("scsi%d : aborting command\n", instance->host_no); + print_Scsi_Cmnd(cmd); - NCR5380_print_status (instance); + NCR5380_print_status(instance); - cli(); - NCR5380_setup(instance); + save_flags(flags); + cli(); + NCR5380_setup(instance); #if (NDEBUG & NDEBUG_ABORT) - printk("scsi%d : abort called\n", instance->host_no); - printk(" basr 0x%X, sr 0x%X\n", - NCR5380_read(BUS_AND_STATUS_REG), NCR5380_read(STATUS_REG)); + printk("scsi%d : abort called\n", instance->host_no); + printk(" basr 0x%X, sr 0x%X\n", + NCR5380_read(BUS_AND_STATUS_REG), NCR5380_read(STATUS_REG)); #endif #if 0 @@ -3087,17 +3181,17 @@ * information transfer routine can exit cleanly. */ - if (hostdata->connected == cmd) { + if (hostdata->connected == cmd) { #if (NDEBUG & NDEBUG_ABORT) - printk("scsi%d : aborting connected command\n", instance->host_no); + printk("scsi%d : aborting connected command\n", instance->host_no); #endif - hostdata->aborted = 1; + hostdata->aborted = 1; /* * We should perform BSY checking, and make sure we haven't slipped * into BUS FREE. */ - NCR5380_write(INITIATOR_COMMAND_REG, ICR_ASSERT_ATN); + NCR5380_write(INITIATOR_COMMAND_REG, ICR_ASSERT_ATN); /* * Since we can't change phases until we've completed the current * handshake, we have to source or sink a byte of data if the current @@ -3107,65 +3201,65 @@ /* * Return control to the executing NCR drive so we can clear the * aborted flag and get back into our main loop. - */ - - return 0; - } + */ + + return 0; + } #endif /* * Case 2 : If the command hasn't been issued yet, we simply remove it - * from the issue queue. + * from the issue queue. */ #if (NDEBUG & NDEBUG_ABORT) - /* KLL */ - printk("scsi%d : abort going into loop.\n", instance->host_no); + /* KLL */ + printk("scsi%d : abort going into loop.\n", instance->host_no); #endif - for (prev = (Scsi_Cmnd **) &(hostdata->issue_queue), - tmp = (Scsi_Cmnd *) hostdata->issue_queue; - tmp; prev = (Scsi_Cmnd **) &(tmp->host_scribble), tmp = - (Scsi_Cmnd *) tmp->host_scribble) - if (cmd == tmp) { - REMOVE(5,*prev,tmp,tmp->host_scribble); - (*prev) = (Scsi_Cmnd *) tmp->host_scribble; - tmp->host_scribble = NULL; - tmp->result = DID_ABORT << 16; - sti(); + for (prev = (Scsi_Cmnd **) & (hostdata->issue_queue), + tmp = (Scsi_Cmnd *) hostdata->issue_queue; + tmp; prev = (Scsi_Cmnd **) & (tmp->host_scribble), tmp = + (Scsi_Cmnd *) tmp->host_scribble) + if (cmd == tmp) { + REMOVE(5, *prev, tmp, tmp->host_scribble); + (*prev) = (Scsi_Cmnd *) tmp->host_scribble; + tmp->host_scribble = NULL; + tmp->result = DID_ABORT << 16; + restore_flags(flags); #if (NDEBUG & NDEBUG_ABORT) - printk("scsi%d : abort removed command from issue queue.\n", - instance->host_no); + printk("scsi%d : abort removed command from issue queue.\n", + instance->host_no); #endif - tmp->done(tmp); - return SCSI_ABORT_SUCCESS; - } + tmp->done(tmp); + return SCSI_ABORT_SUCCESS; + } #if (NDEBUG & NDEBUG_ABORT) - /* KLL */ - else if (prev == tmp) printk("scsi%d : LOOP\n", instance->host_no); + /* KLL */ + else if (prev == tmp) + printk("scsi%d : LOOP\n", instance->host_no); #endif /* * Case 3 : If any commands are connected, we're going to fail the abort - * and let the high level SCSI driver retry at a later time or - * issue a reset. + * and let the high level SCSI driver retry at a later time or + * issue a reset. * - * Timeouts, and therefore aborted commands, will be highly unlikely + * Timeouts, and therefore aborted commands, will be highly unlikely * and handling them cleanly in this situation would make the common - * case of noresets less efficient, and would pollute our code. So, - * we fail. + * case of noresets less efficient, and would pollute our code. So, + * we fail. */ - if (hostdata->connected) { - sti(); + if (hostdata->connected) { + restore_flags(flags); #if (NDEBUG & NDEBUG_ABORT) - printk("scsi%d : abort failed, command connected.\n", instance->host_no); + printk("scsi%d : abort failed, command connected.\n", instance->host_no); #endif - return SCSI_ABORT_NOT_RUNNING; - } - + return SCSI_ABORT_NOT_RUNNING; + } /* * Case 4: If the command is currently disconnected from the bus, and - * there are no connected commands, we reconnect the I_T_L or - * I_T_L_Q nexus associated with it, go into message out, and send + * there are no connected commands, we reconnect the I_T_L or + * I_T_L_Q nexus associated with it, go into message out, and send * an abort message. * * This case is especially ugly. In order to reestablish the nexus, we @@ -3187,42 +3281,41 @@ * it from the disconnected queue. */ - for (tmp = (Scsi_Cmnd *) hostdata->disconnected_queue; tmp; - tmp = (Scsi_Cmnd *) tmp->host_scribble) - if (cmd == tmp) { - sti(); + for (tmp = (Scsi_Cmnd *) hostdata->disconnected_queue; tmp; + tmp = (Scsi_Cmnd *) tmp->host_scribble) + if (cmd == tmp) { + restore_flags(flags); #if (NDEBUG & NDEBUG_ABORT) - printk("scsi%d : aborting disconnected command.\n", instance->host_no); + printk("scsi%d : aborting disconnected command.\n", instance->host_no); #endif - - if (NCR5380_select (instance, cmd, (int) cmd->tag)) - return SCSI_ABORT_BUSY; + + if (NCR5380_select(instance, cmd, (int) cmd->tag)) + return SCSI_ABORT_BUSY; #if (NDEBUG & NDEBUG_ABORT) - printk("scsi%d : nexus reestablished.\n", instance->host_no); + printk("scsi%d : nexus reestablished.\n", instance->host_no); #endif - do_abort (instance); + do_abort(instance); - cli(); - for (prev = (Scsi_Cmnd **) &(hostdata->disconnected_queue), - tmp = (Scsi_Cmnd *) hostdata->disconnected_queue; - tmp; prev = (Scsi_Cmnd **) &(tmp->host_scribble), tmp = - (Scsi_Cmnd *) tmp->host_scribble) - if (cmd == tmp) { - REMOVE(5,*prev,tmp,tmp->host_scribble); - *prev = (Scsi_Cmnd *) tmp->host_scribble; - tmp->host_scribble = NULL; - tmp->result = DID_ABORT << 16; - sti(); - tmp->done(tmp); - return SCSI_ABORT_SUCCESS; + cli(); + for (prev = (Scsi_Cmnd **) & (hostdata->disconnected_queue), + tmp = (Scsi_Cmnd *) hostdata->disconnected_queue; + tmp; prev = (Scsi_Cmnd **) & (tmp->host_scribble), tmp = + (Scsi_Cmnd *) tmp->host_scribble) + if (cmd == tmp) { + REMOVE(5, *prev, tmp, tmp->host_scribble); + *prev = (Scsi_Cmnd *) tmp->host_scribble; + tmp->host_scribble = NULL; + tmp->result = DID_ABORT << 16; + restore_flags(flags); + tmp->done(tmp); + return SCSI_ABORT_SUCCESS; + } } - } - /* * Case 5 : If we reached this point, the command was not found in any of - * the queues. + * the queues. * * We probably reached this point because of an unlikely race condition * between the command completing successfully and the abortion code, @@ -3230,10 +3323,10 @@ * broke. */ - sti(); - printk("scsi%d : warning : SCSI command probably completed successfully\n" - " before abortion\n", instance->host_no); - return SCSI_ABORT_NOT_RUNNING; + restore_flags(flags); + printk("scsi%d : warning : SCSI command probably completed successfully\n" + " before abortion\n", instance->host_no); + return SCSI_ABORT_NOT_RUNNING; } @@ -3244,18 +3337,17 @@ * * Returns : SCSI_RESET_WAKEUP * - */ + */ #ifndef NCR5380_reset static #endif -int NCR5380_reset (Scsi_Cmnd *cmd, unsigned int dummy) { - NCR5380_local_declare(); - NCR5380_setup(cmd->host); +int NCR5380_reset(Scsi_Cmnd * cmd, unsigned int dummy) { + NCR5380_local_declare(); + NCR5380_setup(cmd->host); - NCR5380_print_status (cmd->host); - do_reset (cmd->host); + NCR5380_print_status(cmd->host); + do_reset(cmd->host); - return SCSI_RESET_WAKEUP; + return SCSI_RESET_WAKEUP; } - diff -u --recursive --new-file v2.1.101/linux/drivers/scsi/NCR53c406a.c linux/drivers/scsi/NCR53c406a.c --- v2.1.101/linux/drivers/scsi/NCR53c406a.c Tue Apr 14 14:29:21 1998 +++ linux/drivers/scsi/NCR53c406a.c Mon May 11 11:20:12 1998 @@ -976,7 +976,6 @@ int i; inb(INT_REG); /* clear the interrupt register */ - sti(); irqs = probe_irq_on(); /* Invalid command will cause an interrupt */ diff -u --recursive --new-file v2.1.101/linux/drivers/scsi/advansys.c linux/drivers/scsi/advansys.c --- v2.1.101/linux/drivers/scsi/advansys.c Fri May 8 23:14:49 1998 +++ linux/drivers/scsi/advansys.c Mon May 11 11:20:12 1998 @@ -5579,7 +5579,7 @@ asc_dvc_varp = &boardp->dvc_var.asc_dvc_var; scp->result = HOST_BYTE(DID_ABORT); - sti(); /* Enable interrupts for AscAbortSRB(). */ + /* sti(); - FIXME!!! Enable interrupts for AscAbortSRB() must be careful about io_lock. */ ASC_DBG1(1, "advansys_abort: before AscAbortSRB(), scp %x\n", (unsigned) scp); switch (AscAbortSRB(asc_dvc_varp, (ulong) scp)) { @@ -5849,9 +5849,9 @@ * Reset the target's SCSI bus. */ ASC_DBG(1, "advansys_reset: before AscResetSB()\n"); - sti(); /* Enable interrupts for AscResetSB(). */ + /* sti(); FIXME!!! Enable interrupts for AscResetSB(). */ status = AscResetSB(asc_dvc_varp); - cli(); + /* cli(); FIXME!!! */ switch (status) { case ASC_TRUE: ASC_DBG(1, "advansys_reset: AscResetSB() success\n"); @@ -5874,9 +5874,9 @@ ASC_DBG1(1, "advansys_reset: before AscResetDevice(), target %d\n", scp->target); - sti(); /* Enable interrupts for AscResetDevice(). */ + /* sti(); FIXME!!! Enable interrupts for AscResetDevice(). */ status = AscResetDevice(asc_dvc_varp, scp->target); - cli(); + /* cli(); FIXME!!! */ switch (status) { case ASC_TRUE: @@ -5888,9 +5888,9 @@ default: ASC_DBG(1, "advansys_reset: AscResetDevice() failed; Calling AscResetSB()\n"); - sti(); /* Enable interrupts for AscResetSB(). */ + /* sti(); FIXME!!! Enable interrupts for AscResetSB(). */ status = AscResetSB(asc_dvc_varp); - cli(); + /* cli(); */ switch (status) { case ASC_TRUE: ASC_DBG(1, "advansys_reset: AscResetSB() TRUE\n"); diff -u --recursive --new-file v2.1.101/linux/drivers/scsi/aha152x.c linux/drivers/scsi/aha152x.c --- v2.1.101/linux/drivers/scsi/aha152x.c Fri Apr 4 08:52:23 1997 +++ linux/drivers/scsi/aha152x.c Mon May 11 11:20:12 1998 @@ -1271,7 +1271,7 @@ HOSTDATA(shpnt)->aborting++; HOSTDATA(shpnt)->abortion_complete=0; - sti(); /* Hi Eric, guess what ;-) */ + restore_flags(flags); /* sleep until the abortion is complete */ while(!HOSTDATA(shpnt)->abortion_complete) @@ -1556,7 +1556,7 @@ intr(). To avoid race conditions, we have to return immediately afterwards. */ CLRBITS(DMACNTRL0, INTEN); - sti(); /* Yes, sti() really needs to be here */ + /* sti(); FIXME!!! Yes, sti() really needs to be here if we want to lock up */ /* disconnected target is trying to reconnect. Only possible, if we have disconnected nexuses and diff -u --recursive --new-file v2.1.101/linux/drivers/scsi/eata.c linux/drivers/scsi/eata.c --- v2.1.101/linux/drivers/scsi/eata.c Sat Apr 25 18:13:11 1998 +++ linux/drivers/scsi/eata.c Mon May 11 13:33:35 1998 @@ -1535,10 +1535,10 @@ #endif HD(j)->in_reset = TRUE; - sti(); - time = jiffies; - while ((jiffies - time) < (10 * HZ) && limit++ < 200000) udelay(100L); - cli(); + + /* Wait 2 seconds ???!!! */ + { unsigned long msec = 2 * 1000; while (--msec) udelay(1000); } + printk("%s: reset, interrupts disabled, loops %d.\n", BN(j), limit); for (i = 0; i < sh[j]->can_queue; i++) { diff -u --recursive --new-file v2.1.101/linux/drivers/scsi/fdomain.c linux/drivers/scsi/fdomain.c --- v2.1.101/linux/drivers/scsi/fdomain.c Sat May 2 14:19:53 1998 +++ linux/drivers/scsi/fdomain.c Mon May 11 11:20:12 1998 @@ -1191,7 +1191,7 @@ interruptions while this routine is running. */ - sti(); /* Yes, we really want sti() here */ + /* sti(); Yes, we really want sti() here if we want to lock up our machine */ outb( 0x00, Interrupt_Cntl_port ); diff -u --recursive --new-file v2.1.101/linux/drivers/scsi/g_NCR5380.c linux/drivers/scsi/g_NCR5380.c --- v2.1.101/linux/drivers/scsi/g_NCR5380.c Tue Apr 14 14:29:22 1998 +++ linux/drivers/scsi/g_NCR5380.c Mon May 11 11:20:12 1998 @@ -614,6 +614,7 @@ { int len = 0; NCR5380_local_declare(); + unsigned long flags; unsigned char status; int i; struct Scsi_Host *scsi_ptr; @@ -622,7 +623,8 @@ #ifdef NCR5380_STATS Scsi_Device *dev; extern const char *const scsi_device_types[MAX_SCSI_DEVICE_CODE]; -#endif +#endif + save_flags(flags); cli(); for (scsi_ptr = first_instance; scsi_ptr; scsi_ptr=scsi_ptr->next) @@ -721,7 +723,7 @@ len -= offset; if (len > length) len = length; - sti(); + restore_flags(flags); return len; } diff -u --recursive --new-file v2.1.101/linux/drivers/scsi/gdth.c linux/drivers/scsi/gdth.c --- v2.1.101/linux/drivers/scsi/gdth.c Thu Apr 23 20:21:35 1998 +++ linux/drivers/scsi/gdth.c Mon May 11 11:20:12 1998 @@ -2703,7 +2703,7 @@ timer_table[GDTH_TIMER].expires = jiffies + 30*HZ; timer_active |= 1<host_no != hostno; i++); shpnt = hosts[i]; @@ -2182,6 +2187,7 @@ return len; } + save_flags(flags); cli(); len += sprintf(buffer+len, "\n IBM-SCSI-Subsystem-Linux-Driver, Version %s\n\n\n", @@ -2263,7 +2269,7 @@ if (len > length) len = length; - sti(); + restore_flags(flags); return len; } diff -u --recursive --new-file v2.1.101/linux/drivers/scsi/ide-scsi.c linux/drivers/scsi/ide-scsi.c --- v2.1.101/linux/drivers/scsi/ide-scsi.c Thu May 7 22:51:51 1998 +++ linux/drivers/scsi/ide-scsi.c Thu May 14 09:07:33 1998 @@ -261,6 +261,7 @@ idescsi_pc_t *pc = (idescsi_pc_t *) rq->buffer; int log = test_bit(IDESCSI_LOG_CMD, &scsi->log); u8 *scsi_buf; + unsigned long flags; if (rq->cmd != IDESCSI_PC_RQ) { ide_end_request (uptodate, hwgroup); @@ -287,7 +288,9 @@ } else printk("\n"); } } + spin_lock_irqsave(&io_request_lock,flags); pc->done(pc->scsi_cmd); + spin_unlock_irqrestore(&io_request_lock,flags); idescsi_free_bh (rq->bh); kfree(pc); kfree(rq); scsi->pc = NULL; @@ -767,7 +770,9 @@ rq->buffer = (char *) pc; rq->bh = idescsi_dma_bh (drive, pc); rq->cmd = IDESCSI_PC_RQ; + spin_unlock(&io_request_lock); (void) ide_do_drive_cmd (drive, rq, ide_end); + spin_lock(&io_request_lock); return 0; abort: if (pc) kfree (pc); diff -u --recursive --new-file v2.1.101/linux/drivers/scsi/in2000.c linux/drivers/scsi/in2000.c --- v2.1.101/linux/drivers/scsi/in2000.c Tue Apr 14 14:29:22 1998 +++ linux/drivers/scsi/in2000.c Mon May 11 11:25:57 1998 @@ -858,7 +858,6 @@ struct Scsi_Host *instance; struct IN2000_hostdata *hostdata; Scsi_Cmnd *patch, *cmd; -unsigned long flags; uchar asr, sr, phs, id, lun, *ucp, msg; int i,j; unsigned long length; @@ -875,11 +874,6 @@ } hostdata = (struct IN2000_hostdata *)instance->hostdata; -/* OK - it should now be safe to re-enable system interrupts */ - - save_flags(flags); - sti(); - #ifdef PROC_STATISTICS hostdata->int_cnt++; #endif @@ -1014,7 +1008,6 @@ } write1_io(0, IO_LED_OFF); - restore_flags(flags); return; } @@ -1030,7 +1023,6 @@ if (!cmd && (sr != CSR_RESEL_AM && sr != CSR_TIMEOUT && sr != CSR_SELECT)) { printk("\nNR:wd-intr-1\n"); write1_io(0, IO_LED_OFF); - restore_flags(flags); return; } @@ -1092,10 +1084,12 @@ /* Respond to the specific WD3393 interrupt - there are quite a few! */ switch (sr) { + unsigned long flags; case CSR_TIMEOUT: DB(DB_INTR,printk("TIMEOUT")) + save_flags(flags); cli(); if (hostdata->state == S_RUNNING_LEVEL2) hostdata->connected = NULL; @@ -1114,7 +1108,7 @@ * are commands waiting to be executed. */ - sti(); + restore_flags(flags); in2000_execute(instance); break; @@ -1361,6 +1355,7 @@ /* Note: this interrupt will occur only after a LEVEL2 command */ case CSR_SEL_XFER_DONE: + save_flags(flags); cli(); /* Make sure that reselection is enabled at this point - it may @@ -1388,7 +1383,7 @@ * there are commands waiting to be executed. */ - sti(); + restore_flags(flags); in2000_execute(instance); } else { @@ -1447,6 +1442,7 @@ * so we treat it as a normal command-complete-disconnect. */ + save_flags(flags); cli(); /* Make sure that reselection is enabled at this point - it may @@ -1473,12 +1469,13 @@ * there are commands waiting to be executed. */ - sti(); + restore_flags(flags); in2000_execute(instance); break; case CSR_DISC: + save_flags(flags); cli(); /* Make sure that reselection is enabled at this point - it may @@ -1524,7 +1521,7 @@ * there are commands waiting to be executed. */ - sti(); + restore_flags(flags); in2000_execute(instance); break; @@ -1633,7 +1630,6 @@ } write1_io(0, IO_LED_OFF); - restore_flags(flags); DB(DB_INTR,printk("} ")) diff -u --recursive --new-file v2.1.101/linux/drivers/scsi/scsi.c linux/drivers/scsi/scsi.c --- v2.1.101/linux/drivers/scsi/scsi.c Thu May 7 22:51:51 1998 +++ linux/drivers/scsi/scsi.c Mon May 11 11:07:46 1998 @@ -1457,6 +1457,7 @@ memcpy ((void *) SCpnt->data_cmnd , (const void *) cmnd, 12); SCpnt->reset_chain = NULL; SCpnt->serial_number = 0; + SCpnt->serial_number_at_timeout = 0; SCpnt->bufflen = bufflen; SCpnt->buffer = buffer; SCpnt->flags = 0; @@ -1526,6 +1527,10 @@ return; } + /* Set the serial numbers back to zero */ + SCpnt->serial_number = 0; + SCpnt->serial_number_at_timeout = 0; + SCpnt->state = SCSI_STATE_BHQUEUE; SCpnt->owner = SCSI_OWNER_BH_HANDLER; SCpnt->bh_next = NULL; @@ -2300,6 +2305,8 @@ return(-ENOSYS); /* We do not yet support unplugging */ scan_scsis (HBA_ptr, 1, channel, id, lun); + if (HBA_ptr->select_queue_depths != NULL) + (HBA_ptr->select_queue_depths)(HBA_ptr, HBA_ptr->host_queue); return(length); } diff -u --recursive --new-file v2.1.101/linux/drivers/scsi/scsi_error.c linux/drivers/scsi/scsi_error.c --- v2.1.101/linux/drivers/scsi/scsi_error.c Thu May 7 22:51:51 1998 +++ linux/drivers/scsi/scsi_error.c Mon May 11 09:20:41 1998 @@ -201,6 +201,9 @@ } #endif + /* Set the serial_number_at_timeout to the current serial_number */ + SCpnt->serial_number_at_timeout = SCpnt->serial_number; + SCpnt->state = SCSI_STATE_TIMEOUT; SCpnt->owner = SCSI_OWNER_ERROR_HANDLER; diff -u --recursive --new-file v2.1.101/linux/drivers/scsi/scsi_obsolete.c linux/drivers/scsi/scsi_obsolete.c --- v2.1.101/linux/drivers/scsi/scsi_obsolete.c Tue Apr 14 14:29:23 1998 +++ linux/drivers/scsi/scsi_obsolete.c Mon May 11 09:20:42 1998 @@ -146,6 +146,10 @@ unsigned long flags; spin_lock_irqsave(&io_request_lock, flags); + + /* Set the serial_number_at_timeout to the current serial_number */ + SCpnt->serial_number_at_timeout = SCpnt->serial_number; + switch (SCpnt->internal_timeout & (IN_ABORT | IN_RESET | IN_RESET2 | IN_RESET3)) { case NORMAL_TIMEOUT: @@ -321,6 +325,7 @@ struct Scsi_Host * host = SCpnt->host; int result = SCpnt->result; SCpnt->serial_number = 0; + SCpnt->serial_number_at_timeout = 0; oldto = update_timeout(SCpnt, 0); #ifdef DEBUG_TIMEOUT diff -u --recursive --new-file v2.1.101/linux/drivers/scsi/scsiiom.c linux/drivers/scsi/scsiiom.c --- v2.1.101/linux/drivers/scsi/scsiiom.c Tue Apr 14 14:29:23 1998 +++ linux/drivers/scsi/scsiiom.c Mon May 11 11:31:02 1998 @@ -1426,12 +1426,13 @@ #ifdef DC390_DEBUG0 printk("RST_DETEC"); #endif - save_flags(flags); - sti(); - wlval = jiffies + HZ; - while( jiffies < wlval ); /* delay 1 sec */ + /* delay a second */ + { unsigned int msec = 1*1000; while (--msec) udelay(1000); } + + save_flags(flags); cli(); + ioport = pACB->IOPortBase; bval = DMA_IDLE_CMD; outb(bval,ioport+DMA_Cmd); diff -u --recursive --new-file v2.1.101/linux/drivers/scsi/seagate.c linux/drivers/scsi/seagate.c --- v2.1.101/linux/drivers/scsi/seagate.c Tue Apr 14 14:29:23 1998 +++ linux/drivers/scsi/seagate.c Mon May 11 11:27:58 1998 @@ -649,8 +649,6 @@ int temp; Scsi_Cmnd *SCtmp; -/* enable all other interrupts. */ - sti (); #if (DEBUG & PHASE_RESELECT) printk ("scsi%d : seagate_reconnect_intr() called\n", hostno); #endif @@ -1015,11 +1013,14 @@ */ #if defined(ARBITRATE) + { unsigned long flags; + save_flags (flags); cli (); WRITE_CONTROL (0); WRITE_DATA ((controller_type == SEAGATE) ? 0x80 : 0x40); WRITE_CONTROL (CMD_START_ARB); - sti (); + restore_flags (flags); + } while (!((status_read = STATUS) & (STAT_ARB_CMPL | STAT_SEL)) && (jiffies < clock) && !st0x_aborted) ; @@ -1054,19 +1055,25 @@ */ #ifdef OLDCNTDATASCEME #ifdef SWAPCNTDATA + { unsigned long flags; + save_flags(flags); cli(); WRITE_CONTROL (BASE_CMD | CMD_DRVR_ENABLE | CMD_SEL | (reselect ? CMD_ATTN : 0)); WRITE_DATA ((unsigned char) ((1 << target) | (controller_type == SEAGATE ? 0x80 : 0x40))); - sti(); + restore_flags(flags); + } #else + { unsigned long flags; + save_flags(flags); cli (); WRITE_DATA ((unsigned char) ((1 << target) | (controller_type == SEAGATE ? 0x80 : 0x40))); WRITE_CONTROL (BASE_CMD | CMD_DRVR_ENABLE | CMD_SEL | (reselect ? CMD_ATTN : 0)); - sti (); + restore_flags (flags); + } #endif #else tmp_data = (unsigned char) ((1 << target) | (controller_type == SEAGATE diff -u --recursive --new-file v2.1.101/linux/drivers/scsi/sr.c linux/drivers/scsi/sr.c --- v2.1.101/linux/drivers/scsi/sr.c Tue Apr 14 14:29:23 1998 +++ linux/drivers/scsi/sr.c Thu May 14 09:07:33 1998 @@ -880,6 +880,7 @@ unsigned char *buffer; int the_result, retries; Scsi_Cmnd * SCpnt; + unsigned long flags; buffer = (unsigned char *) scsi_malloc(512); SCpnt = scsi_allocate_device(NULL, scsi_CDs[i].device, 1); @@ -898,10 +899,12 @@ { struct semaphore sem = MUTEX_LOCKED; SCpnt->request.sem = &sem; + spin_lock_irqsave(&io_request_lock, flags); scsi_do_cmd (SCpnt, (void *) cmd, (void *) buffer, 512, sr_init_done, SR_TIMEOUT, MAX_RETRIES); + spin_unlock_irqrestore(&io_request_lock, flags); down(&sem); } diff -u --recursive --new-file v2.1.101/linux/drivers/scsi/sr_ioctl.c linux/drivers/scsi/sr_ioctl.c --- v2.1.101/linux/drivers/scsi/sr_ioctl.c Thu May 7 22:51:51 1998 +++ linux/drivers/scsi/sr_ioctl.c Thu May 14 09:07:33 1998 @@ -53,6 +53,7 @@ Scsi_Cmnd * SCpnt; Scsi_Device * SDev; int result, err = 0, retries = 0; + unsigned long flags; SDev = scsi_CDs[target].device; SCpnt = scsi_allocate_device(NULL, scsi_CDs[target].device, 1); @@ -63,9 +64,11 @@ { struct semaphore sem = MUTEX_LOCKED; SCpnt->request.sem = &sem; + spin_lock_irqsave(&io_request_lock, flags); scsi_do_cmd(SCpnt, (void *) sr_cmd, buffer, buflength, sr_ioctl_done, IOCTL_TIMEOUT, IOCTL_RETRIES); + spin_unlock_irqrestore(&io_request_lock, flags); down(&sem); SCpnt->request.sem = NULL; } diff -u --recursive --new-file v2.1.101/linux/drivers/scsi/u14-34f.c linux/drivers/scsi/u14-34f.c --- v2.1.101/linux/drivers/scsi/u14-34f.c Sat Apr 25 18:13:11 1998 +++ linux/drivers/scsi/u14-34f.c Mon May 11 11:29:38 1998 @@ -629,10 +629,8 @@ /* Issue OGM interrupt */ outb(CMD_OGM_INTR, sh[j]->io_port + REG_LCL_INTR); - sti(); - time = jiffies; - while ((jiffies - time) < HZ && limit++ < 20000) udelay(100L); - cli(); + /* Wait a second.. */ + { unsigned int msec = 1000; while (--msec) udelay(1000); } if (cpp->adapter_status || HD(j)->cp_stat[0] != FREE) { HD(j)->cp_stat[0] = FREE; @@ -1233,10 +1231,10 @@ #endif HD(j)->in_reset = TRUE; - sti(); - time = jiffies; - while ((jiffies - time) < (10 * HZ) && limit++ < 200000) udelay(100L); - cli(); + + /* Wait 2 seconds ???!!! */ + { unsigned int msec = 2*1000; while (--msec) udelay(1000); } + printk("%s: reset, interrupts disabled, loops %d.\n", BN(j), limit); for (i = 0; i < sh[j]->can_queue; i++) { diff -u --recursive --new-file v2.1.101/linux/drivers/scsi/wd33c93.c linux/drivers/scsi/wd33c93.c --- v2.1.101/linux/drivers/scsi/wd33c93.c Thu Mar 26 15:57:03 1998 +++ linux/drivers/scsi/wd33c93.c Mon May 11 11:31:41 1998 @@ -1766,9 +1766,12 @@ #endif - cli(); - reset_wd33c93(instance); - sti(); + { unsigned long flags; + save_flags(flags); + cli(); + reset_wd33c93(instance); + restore_flags(flags); + } printk("wd33c93-%d: chip=%s/%d no_sync=0x%x no_dma=%d",instance->host_no, (hostdata->chip==C_WD33C93)?"WD33c93": diff -u --recursive --new-file v2.1.101/linux/drivers/scsi/wd7000.c linux/drivers/scsi/wd7000.c --- v2.1.101/linux/drivers/scsi/wd7000.c Tue Apr 14 14:29:24 1998 +++ linux/drivers/scsi/wd7000.c Mon May 11 11:48:13 1998 @@ -851,18 +851,18 @@ save_flags (flags); cli (); while (busy) { /* someone else is allocating */ - sti (); /* Yes this is really needed here */ + spin_unlock_irq(&io_request_lock); for (now = jiffies; now == jiffies; ); /* wait a jiffy */ - cli (); + spin_lock_irq(&io_request_lock); } busy = 1; /* not busy now; it's our turn */ while (freescbs < needed) { timeout = jiffies + WAITnexttimeout; do { - sti (); /* Yes this is really needed here */ + spin_unlock_irq(&io_request_lock); for (now = jiffies; now == jiffies; ); /* wait a jiffy */ - cli (); + spin_lock_irq(&io_request_lock); } while (freescbs < needed && jiffies <= timeout); /* * If we get here with enough free Scbs, we can take them. diff -u --recursive --new-file v2.1.101/linux/drivers/sound/Config.in linux/drivers/sound/Config.in --- v2.1.101/linux/drivers/sound/Config.in Tue Apr 14 14:29:24 1998 +++ linux/drivers/sound/Config.in Thu May 14 10:33:17 1998 @@ -1,12 +1,23 @@ -dep_tristate 'ProAudioSpectrum 16 support' CONFIG_PAS $CONFIG_SOUND -if [ "$CONFIG_PAS" = "y" ]; then +# drivers/sound/Config.in +# +# 18 Apr 1998, Michael Elizabeth Chastain, +# More hacking for modularisation. +# +# See drivers/sound/README.CONFIG for more information. + + + +# Prompt user for primary drivers. + +dep_tristate 'ProAudioSpectrum 16 support' CONFIG_SOUND_PAS $CONFIG_SOUND +if [ "$CONFIG_SOUND_PAS" = "y" ]; then int 'PAS16 IRQ 3, 4, 5, 7, 9, 10, 11, 12, 14 or 15' CONFIG_PAS_IRQ 10 int 'PAS16 DMA 0, 1, 3, 5, 6 or 7' CONFIG_PAS_DMA 3 bool 'Enable PAS16 joystick port' CONFIG_PAS_JOYSTICK fi -dep_tristate '100% Sound Blaster compatibles (SB16/32/64, ESS, Jazz16) support' CONFIG_SB $CONFIG_SOUND -if [ "$CONFIG_SB" = "y" ]; then +dep_tristate '100% Sound Blaster compatibles (SB16/32/64, ESS, Jazz16) support' CONFIG_SOUND_SB $CONFIG_SOUND +if [ "$CONFIG_SOUND_SB" = "y" ]; then hex 'I/O base for SB Check from manual of the card' CONFIG_SB_BASE 220 int 'Sound Blaster IRQ Check from manual of the card' CONFIG_SB_IRQ 7 int 'Sound Blaster DMA 0, 1 or 3' CONFIG_SB_DMA 1 @@ -17,33 +28,33 @@ int 'SB MPU401 IRQ (Jazz16, SM Wave and ES1688) Check from manual of the card' CONFIG_SB_MPU_IRQ -1 fi -dep_tristate 'Generic OPL2/OPL3 FM synthesizer support' CONFIG_ADLIB $CONFIG_SOUND +dep_tristate 'Generic OPL2/OPL3 FM synthesizer support' CONFIG_SOUND_ADLIB $CONFIG_SOUND -dep_tristate 'Gravis Ultrasound support' CONFIG_GUS $CONFIG_SOUND -if [ "$CONFIG_GUS" != "n" ]; then +dep_tristate 'Gravis Ultrasound support' CONFIG_SOUND_GUS $CONFIG_SOUND +if [ "$CONFIG_SOUND_GUS" = "y" -o "$CONFIG_SOUND_GUS" = "m" ]; then bool '16 bit sampling option of GUS (_NOT_ GUS MAX)' CONFIG_GUS16 bool 'GUS MAX support' CONFIG_GUSMAX - if [ "$CONFIG_GUS" = "y" ]; then - hex 'I/O base for GUS 210, 220, 230, 240, 250 or 260' CONFIG_GUS_BASE 220 - int 'GUS IRQ 3, 5, 7, 9, 11, 12 or 15' CONFIG_GUS_IRQ 15 - int 'GUS DMA 1, 3, 5, 6 or 7' CONFIG_GUS_DMA 6 - int 'Second DMA channel for GUS 1, 3, 5, 6 or 7' CONFIG_GUS_DMA2 -1 - if [ "$CONFIG_GUS16" = "y" ]; then - hex 'I/O base for the 16 bit daughtercard of GUS 530, 604, E80 or F40' CONFIG_GUS16_BASE 530 - int 'GUS 16 bit daughtercard IRQ 3, 4, 5, 7, or 9' CONFIG_GUS16_IRQ 7 - int 'GUS DMA 0, 1 or 3' CONFIG_GUS16_DMA 3 - fi +fi +if [ "$CONFIG_SOUND_GUS" = "y" ]; then + hex 'I/O base for GUS 210, 220, 230, 240, 250 or 260' CONFIG_GUS_BASE 220 + int 'GUS IRQ 3, 5, 7, 9, 11, 12 or 15' CONFIG_GUS_IRQ 15 + int 'GUS DMA 1, 3, 5, 6 or 7' CONFIG_GUS_DMA 6 + int 'Second DMA channel for GUS 1, 3, 5, 6 or 7' CONFIG_GUS_DMA2 -1 + if [ "$CONFIG_GUS16" = "y" ]; then + hex 'I/O base for the 16 bit daughtercard of GUS 530, 604, E80 or F40' CONFIG_GUS16_BASE 530 + int 'GUS 16 bit daughtercard IRQ 3, 4, 5, 7, or 9' CONFIG_GUS16_IRQ 7 + int 'GUS DMA 0, 1 or 3' CONFIG_GUS16_DMA 3 fi fi -dep_tristate 'MPU-401 support (NOT for SB16)' CONFIG_MPU401 $CONFIG_SOUND -if [ "$CONFIG_MPU401" = "y" ]; then +dep_tristate 'MPU-401 support (NOT for SB16)' CONFIG_SOUND_MPU401 $CONFIG_SOUND +if [ "$CONFIG_SOUND_MPU401" = "y" ]; then hex 'I/O base for MPU401 Check from manual of the card' CONFIG_MPU_BASE 330 int 'MPU401 IRQ Check from manual of the card' CONFIG_MPU_IRQ 9 fi -dep_tristate 'PSS (AD1848, ADSP-2115, ESC614) support' CONFIG_PSS $CONFIG_SOUND -if [ "$CONFIG_PSS" = "y" ]; then +dep_tristate 'PSS (AD1848, ADSP-2115, ESC614) support' CONFIG_SOUND_PSS $CONFIG_SOUND +if [ "$CONFIG_SOUND_PSS" = "y" ]; then hex 'PSS I/O base 220 or 240' CONFIG_PSS_BASE 220 hex 'PSS audio I/O base 530, 604, E80 or F40' CONFIG_PSS_MSS_BASE 530 int 'PSS audio IRQ 7, 9, 10 or 11' CONFIG_PSS_MSS_IRQ 11 @@ -55,20 +66,20 @@ string ' Full pathname of DSPxxx.LD firmware file' CONFIG_PSS_BOOT_FILE fi fi -if [ "$CONFIG_PSS" = "m" ] || [ "$CONFIG_PSS" = "y" ]; then +if [ "$CONFIG_SOUND_PSS" = "y" -o "$CONFIG_SOUND_PSS" = "m" ]; then bool ' Enable PSS mixer (Beethoven ADSP-16 and other compatibile)' CONFIG_PSS_MIXER fi -dep_tristate 'Microsoft Sound System support' CONFIG_MSS $CONFIG_SOUND -if [ "$CONFIG_MSS" = "y" ]; then +dep_tristate 'Microsoft Sound System support' CONFIG_SOUND_MSS $CONFIG_SOUND +if [ "$CONFIG_SOUND_MSS" = "y" ]; then hex 'MSS/WSS I/O base 530, 604, E80 or F40' CONFIG_MSS_BASE 530 int 'MSS/WSS IRQ 7, 9, 10 or 11' CONFIG_MSS_IRQ 11 int 'MSS/WSS DMA 0, 1 or 3' CONFIG_MSS_DMA 3 int 'MSS/WSS second DMA (if possible) 0, 1 or 3' CONFIG_MSS_DMA2 -1 fi -dep_tristate 'Ensoniq SoundScape support' CONFIG_SSCAPE $CONFIG_SOUND -if [ "$CONFIG_SSCAPE" = "y" ]; then +dep_tristate 'Ensoniq SoundScape support' CONFIG_SOUND_SSCAPE $CONFIG_SOUND +if [ "$CONFIG_SOUND_SSCAPE" = "y" ]; then hex 'SoundScape MIDI I/O base 320, 330, 340 or 350' CONFIG_SSCAPE_BASE 330 int 'SoundScape MIDI IRQ ' CONFIG_SSCAPE_IRQ 9 int 'SoundScape initialization DMA 0, 1 or 3' CONFIG_SSCAPE_DMA 3 @@ -76,8 +87,8 @@ int 'SoundScape audio IRQ 7, 9, 10 or 11' CONFIG_SSCAPE_MSS_IRQ 11 fi -dep_tristate 'MediaTrix AudioTrix Pro support' CONFIG_TRIX $CONFIG_SOUND -if [ "$CONFIG_TRIX" = "y" ]; then +dep_tristate 'MediaTrix AudioTrix Pro support' CONFIG_SOUND_TRIX $CONFIG_SOUND +if [ "$CONFIG_SOUND_TRIX" = "y" ]; then hex 'OPL3-SA1 audio I/O base 530, 604, E80 or F40' CONFIG_TRIX_BASE 530 int 'OPL3-SA1 audio IRQ 7, 9, 10 or 11' CONFIG_TRIX_IRQ 11 int 'OPL3-SA1 audio DMA 0, 1 or 3' CONFIG_TRIX_DMA 0 @@ -93,9 +104,9 @@ fi fi -dep_tristate 'Support for OPTi MAD16 and/or Mozart based cards' CONFIG_MAD16 $CONFIG_SOUND -dep_tristate 'Support MIDI in older MAD16 based cards (requires SB)' CONFIG_MAD16_OLDCARD $CONFIG_MAD16 -if [ "$CONFIG_MAD16" = "y" ]; then +dep_tristate 'Support for OPTi MAD16 and/or Mozart based cards' CONFIG_SOUND_MAD16 $CONFIG_SOUND +dep_tristate 'Support MIDI in older MAD16 based cards (requires SB)' CONFIG_MAD16_OLDCARD $CONFIG_SOUND_MAD16 +if [ "$CONFIG_SOUND_MAD16" = "y" ]; then hex 'MAD16 audio I/O base 530, 604, E80 or F40' CONFIG_MAD16_BASE 530 int 'MAD16 audio IRQ 7, 9, 10 or 11' CONFIG_MAD16_IRQ 11 int 'MAD16 audio DMA 0, 1 or 3' CONFIG_MAD16_DMA 3 @@ -104,8 +115,8 @@ int 'MAD16 MIDI IRQ 5, 7, 9 or 10' CONFIG_MAD16_MPU_IRQ 9 fi -dep_tristate 'Support for Crystal CS4232 based (PnP) cards' CONFIG_CS4232 $CONFIG_SOUND -if [ "$CONFIG_CS4232" = "y" ]; then +dep_tristate 'Support for Crystal CS4232 based (PnP) cards' CONFIG_SOUND_CS4232 $CONFIG_SOUND +if [ "$CONFIG_SOUND_CS4232" = "y" ]; then hex 'CS4232 audio I/O base 530, 604, E80 or F40' CONFIG_CS4232_BASE 530 int 'CS4232 audio IRQ 5, 7, 9, 11, 12 or 15' CONFIG_CS4232_IRQ 11 int 'CS4232 audio DMA 0, 1 or 3' CONFIG_CS4232_DMA 0 @@ -114,8 +125,8 @@ int 'CS4232 MIDI IRQ 5, 7, 9, 11, 12 or 15' CONFIG_CS4232_MPU_IRQ 9 fi -dep_tristate 'Support for Turtle Beach Wave Front (Maui, Tropez) synthesizers' CONFIG_MAUI $CONFIG_SOUND -if [ "$CONFIG_MAUI" = "y" ]; then +dep_tristate 'Support for Turtle Beach Wave Front (Maui, Tropez) synthesizers' CONFIG_SOUND_MAUI $CONFIG_SOUND +if [ "$CONFIG_SOUND_MAUI" = "y" ]; then hex 'I/O base for Maui 210, 230, 260, 290, 300, 320, 338 or 330' CONFIG_MAUI_BASE 330 int 'Maui IRQ 5, 9, 12 or 15' CONFIG_MAUI_IRQ 9 bool ' Have OSWF.MOT firmware file' CONFIG_MAUI_HAVE_BOOT @@ -124,8 +135,17 @@ fi fi -dep_tristate 'Yamaha OPL3-SA1 audio controller' CONFIG_OPL3SA1 $CONFIG_SOUND -if [ "$CONFIG_OPL3SA1" = "y" ]; then +dep_tristate 'Support for Aztech Sound Galaxy (non-PnP) cards' CONFIG_SGALAXY $CONFIG_SOUND +if [ "$CONFIG_SGALAXY" = "y" ]; then + hex 'SGALAXY audio I/O base 530, 604, E80 or F40' CONFIG_SGALAXY_BASE 530 + int 'SGALAXY audio IRQ 5, 7, 9, 11, 12 or 15' CONFIG_SGALAXY_IRQ 11 + int 'SGALAXY audio DMA 0, 1 or 3' CONFIG_SGALAXY_DMA 0 + int 'SGALAXY second (duplex) DMA 0, 1 or 3' CONFIG_SGALAXY_DMA2 3 + hex 'SGALAXY SB I/O base 220 or 240' CONFIG_SGALAXY_SGBASE 220 +fi + +dep_tristate 'Yamaha OPL3-SA1 audio controller' CONFIG_SOUND_OPL3SA1 $CONFIG_SOUND +if [ "$CONFIG_SOUND_OPL3SA1" = "y" ]; then hex 'OPL3-SA1 audio I/O base 530, 604, E80 or F40' CONFIG_OPL3SA1_BASE 530 int 'OPL3-SA1 audio IRQ 7, 9, 10 or 11' CONFIG_OPL3SA1_IRQ 11 int 'OPL3-SA1 audio DMA 0, 1 or 3' CONFIG_OPL3SA1_DMA 0 @@ -134,88 +154,34 @@ int 'OPL3-SA1 MIDI IRQ 3, 4, 5, 7 or 9' CONFIG_OPL3SA1_MPU_IRQ 9 fi -dep_tristate 'SoftOSS software wave table engine' CONFIG_SOFTOSS $CONFIG_SOUND -if [ "$CONFIG_SOFTOSS" = "y" ]; then +dep_tristate 'SoftOSS software wave table engine' CONFIG_SOUND_SOFTOSS $CONFIG_SOUND +if [ "$CONFIG_SOUND_SOFTOSS" = "y" ]; then int 'Sampling rate for SoftOSS 8000 to 48000' CONFIG_SOFTOSS_RATE 22050 int 'Max # of concurrent voices for SoftOSS 4 to 32' CONFIG_SOFTOSS_VOICES 32 fi -dep_tristate 'FM synthesizer (YM3812/OPL-3) support' CONFIG_YM3812 $CONFIG_SOUND -dep_tristate 'Loopback MIDI device support' CONFIG_VMIDI $CONFIG_SOUND +dep_tristate 'FM synthesizer (YM3812/OPL-3) support' CONFIG_SOUND_YM3812 $CONFIG_SOUND -dep_tristate '6850 UART support' CONFIG_UART6850 $CONFIG_SOUND +dep_tristate 'Loopback MIDI device support' CONFIG_SOUND_VMIDI $CONFIG_SOUND + +dep_tristate '6850 UART support' CONFIG_SOUND_UART6850 $CONFIG_SOUND if [ "$CONFIG_UART6850" = "y" ]; then hex 'I/O base for UART 6850 MIDI port (Unknown)' CONFIG_U6850_BASE 0 int 'UART6850 IRQ (Unknown)' CONFIG_U6850_IRQ -1 fi +if [ "$CONFIG_ARM" = "y" ]; then + bool 'VIDC 16-bit sound' CONFIG_VIDC_SOUND +fi + -bool 'Additional low level drivers' CONFIG_LOWLEVEL_SOUND -if [ "$CONFIG_LOWLEVEL_SOUND" = "y" ]; then - dep_tristate 'ACI mixer (miroPCM12)' CONFIG_ACI_MIXER $CONFIG_SOUND - dep_tristate 'AWE32 synth' CONFIG_AWE32_SYNTH $CONFIG_SOUND - dep_tristate 'Gallant Audio Cards (SC-6000 and SC-6600 based)' CONFIG_AEDSP16 $CONFIG_SOUND - - if [ "$CONFIG_AEDSP16" = "y" -o "$CONFIG_AEDSP16" = "m" ]; then - hex ' I/O base for Audio Excel DSP 16 220 or 240' CONFIG_AEDSP16_BASE 220 - fi - - if [ "$CONFIG_AEDSP16" = "y" ]; then - comment 'SC-6600 Audio Cards have no jumper switches at all' - bool 'SC-6600 based audio cards (new Audio Excel DSP 16)' CONFIG_SC6600 - - if [ "$CONFIG_SB" = "y" -o "$CONFIG_SB" = "m" -a "$CONFIG_AEDSP16_MSS" != "y" ]; then - bool 'Audio Excel DSP 16 (SBPro emulation)' CONFIG_AEDSP16_SBPRO - if [ "$CONFIG_AEDSP16_SBPRO" = "y" ]; then - comment 'Audio Excel DSP 16 [Sound Blaster Pro]' - hex 'I/O base for Audio Excel DSP 16 220 or 240' \ - CONFIG_AEDSP16_BASE $CONFIG_SB_BASE - int 'Audio Excel DSP 16 IRQ 5, 7, 9, 10, 11' \ - CONFIG_AEDSP16_SB_IRQ $CONFIG_SB_IRQ - int 'Audio Excel DSP 16 DMA 0, 1 or 3' CONFIG_AEDSP16_SB_DMA $CONFIG_SB_DMA - fi - fi - - if [ "$CONFIG_MSS" = "y" -o "$CONFIG_MSS" = "m" -a "$CONFIG_AEDSP16_SBPRO" != "y" ]; then - bool 'Audio Excel DSP 16 (MSS emulation)' CONFIG_AEDSP16_MSS - if [ "$CONFIG_AEDSP16_MSS" = "y" ]; then - comment 'Audio Excel DSP 16 [Microsoft Sound System]' - hex 'I/O base for Audio Excel DSP 16 220 or 240' CONFIG_AEDSP16_BASE 220 - int 'Audio Excel DSP 16 IRQ 5, 7, 9, 10, 11' \ - CONFIG_AEDSP16_MSS_IRQ $CONFIG_MSS_IRQ - int 'Audio Excel DSP 16 DMA 0, 1 or 3' CONFIG_AEDSP16_MSS_DMA $CONFIG_MSS_DMA - fi - fi - - if [ "$CONFIG_MPU401" = "y" -o "$CONFIG_MPU401" = "m" ]; then - bool 'Audio Excel DSP 16 (MPU401 emulation)' CONFIG_AEDSP16_MPU401 - if [ "$CONFIG_AEDSP16_MPU401" = "y" ]; then - comment 'Audio Excel DSP 16 [MPU-401]' - if [ "$CONFIG_AEDSP16_SBPRO" != "y" \ - -a "$CONFIG_AEDSP16_MSS" != "y" ]; then - hex 'I/O base for Audio Excel DSP 16 220 or 240' CONFIG_AEDSP16_BASE 220 - fi - int 'MPU401 IRQ for Audio Excel DSP 16 5, 7, 9, 10 or 0 (disable)' \ - CONFIG_AEDSP16_MPU_IRQ $CONFIG_MPU_IRQ - fi - fi - fi - - if [ "$CONFIG_AEDSP16" = "y" -o "$CONFIG_AEDSP16" = "m" ]; then - comment 'SC-6600 Audio Cards have no jumper switches at all' - bool 'SC-6600 based audio cards (new Audio Excel DSP 16)' CONFIG_SC6600 - - if [ "$CONFIG_SC6600" = "y" ]; then - comment 'SC-6600 specific configuration' - bool 'Activate SC-6600 Joystick Interface' CONFIG_SC6600_JOY - int 'SC-6600 CDROM Interface (4=None, 3=IDE, 1=Panasonic, 0=?Sony?)' \ - CONFIG_SC6600_CDROM 4 - hex 'SC-6600 CDROM Interface I/O Address' CONFIG_SC6600_CDROMBASE 0 - fi - fi -fi +# Additional low level drivers. -if [ "$CONFIG_ARM" = "y" ]; then - bool 'VIDC 16-bit sound' CONFIG_VIDC_SOUND +mainmenu_option next_comment +comment 'Additional low level sound drivers' +dep_tristate 'Additional low level sound drivers' CONFIG_LOWLEVEL_SOUND $CONFIG_SOUND +if [ "$CONFIG_LOWLEVEL_SOUND" != "n" ]; then + source drivers/sound/lowlevel/Config.in fi +endmenu diff -u --recursive --new-file v2.1.101/linux/drivers/sound/Defines linux/drivers/sound/Defines --- v2.1.101/linux/drivers/sound/Defines Wed Apr 8 19:36:27 1998 +++ linux/drivers/sound/Defines Wed Dec 31 16:00:00 1969 @@ -1,407 +0,0 @@ -# This used to be a computer generated file, but it's not any more. -# Edit all you need! - -ifdef CONFIG_PSS -ifneq ($(CONFIG_MPU_EMU),Y) -CONFIG_MPU_EMU=y -endif -endif - -ifdef CONFIG_SSCAPE -ifneq ($(CONFIG_MPU_EMU),Y) -CONFIG_MPU_EMU=y -endif -endif - -ifdef CONFIG_CS4232 -ifneq ($(CONFIG_MPU_EMU),Y) -CONFIG_MPU_EMU=y -endif -endif - -ifdef CONFIG_MAUI -ifneq ($(CONFIG_MPU_EMU),Y) -CONFIG_MPU_EMU=y -endif -endif - -ifdef CONFIG_PSS -ifneq ($(CONFIG_AD1848),Y) -CONFIG_AD1848=y -endif -endif - -ifdef CONFIG_GUS16 -ifneq ($(CONFIG_AD1848),Y) -CONFIG_AD1848=y -endif -endif - -ifdef CONFIG_GUSMAX -ifneq ($(CONFIG_AD1848),Y) -CONFIG_AD1848=y -endif -endif - -ifdef CONFIG_MSS -ifneq ($(CONFIG_AD1848),Y) -CONFIG_AD1848=y -endif -endif - -ifdef CONFIG_SSCAPE -ifneq ($(CONFIG_AD1848),Y) -CONFIG_AD1848=y -endif -endif - -ifdef CONFIG_TRIX -ifneq ($(CONFIG_AD1848),Y) -CONFIG_AD1848=y -endif -endif - -ifdef CONFIG_MAD16 -ifneq ($(CONFIG_AD1848),Y) -CONFIG_AD1848=y -endif -endif - -ifdef CONFIG_CS4232 -ifneq ($(CONFIG_AD1848),Y) -CONFIG_AD1848=y -endif -endif - -ifdef CONFIG_OPL3SA1 -ifneq ($(CONFIG_AD1848),Y) -CONFIG_AD1848=y -endif -endif - -ifdef CONFIG_SB -ifneq ($(CONFIG_SBDSP),Y) -CONFIG_SBDSP=y -endif -endif - -ifdef CONFIG_TRIX -ifneq ($(CONFIG_SBDSP),Y) -CONFIG_SBDSP=y -endif -endif - -ifdef CONFIG_MAD16 -ifneq ($(CONFIG_SBDSP),Y) -CONFIG_SBDSP=y -endif -endif - - - -ifdef CONFIG_SB - ifeq ($(CONFIG_SB),m) - ifneq ($(CONFIG_UART401),Y) - CONFIG_UART401=m - endif - else - ifneq ($(CONFIG_UART401),Y) - CONFIG_UART401=y - endif - endif -endif - -ifdef CONFIG_TRIX -ifneq ($(CONFIG_UART401),Y) -CONFIG_UART401=y -endif -endif - -ifdef CONFIG_MAD16 -ifneq ($(CONFIG_UART401),Y) -CONFIG_UART401=y -endif -endif - -ifdef CONFIG_OPL3SA1 -ifneq ($(CONFIG_UART401),Y) -CONFIG_UART401=y -endif -endif - -ifdef CONFIG_PAS -ifneq ($(CONFIG_SEQUENCER),Y) -CONFIG_SEQUENCER=y -endif -endif - -ifdef CONFIG_SB -ifneq ($(CONFIG_SEQUENCER),Y) -CONFIG_SEQUENCER=y -endif -endif - -ifdef CONFIG_ADLIB -ifneq ($(CONFIG_SEQUENCER),Y) -CONFIG_SEQUENCER=y -endif -endif - -ifdef CONFIG_GUS -ifneq ($(CONFIG_SEQUENCER),Y) -CONFIG_SEQUENCER=y -endif -endif - -ifdef CONFIG_MPU401 -ifneq ($(CONFIG_SEQUENCER),Y) -CONFIG_SEQUENCER=y -endif -endif - -ifdef CONFIG_PSS -ifneq ($(CONFIG_SEQUENCER),Y) -CONFIG_SEQUENCER=y -endif -endif - -ifdef CONFIG_GUS16 -ifneq ($(CONFIG_SEQUENCER),Y) -CONFIG_SEQUENCER=y -endif -endif - -ifdef CONFIG_GUSMAX -ifneq ($(CONFIG_SEQUENCER),Y) -CONFIG_SEQUENCER=y -endif -endif - -ifdef CONFIG_MSS -ifneq ($(CONFIG_SEQUENCER),Y) -CONFIG_SEQUENCER=y -endif -endif - -ifdef CONFIG_SSCAPE -ifneq ($(CONFIG_SEQUENCER),Y) -CONFIG_SEQUENCER=y -endif -endif - -ifdef CONFIG_TRIX -ifneq ($(CONFIG_SEQUENCER),Y) -CONFIG_SEQUENCER=y -endif -endif - -ifdef CONFIG_MAD16 -ifneq ($(CONFIG_SEQUENCER),Y) -CONFIG_SEQUENCER=y -endif -endif - -ifdef CONFIG_CS4232 -ifneq ($(CONFIG_SEQUENCER),Y) -CONFIG_SEQUENCER=y -endif -endif - -ifdef CONFIG_MAUI -ifneq ($(CONFIG_SEQUENCER),Y) -CONFIG_SEQUENCER=y -endif -endif - -ifdef CONFIG_OPL3SA1 -ifneq ($(CONFIG_SEQUENCER),Y) -CONFIG_SEQUENCER=y -endif -endif - -ifdef CONFIG_SOFTOSS -ifneq ($(CONFIG_SEQUENCER),Y) -CONFIG_SEQUENCER=y -endif -endif - -ifdef CONFIG_YM3812_AUTO -ifneq ($(CONFIG_SEQUENCER),Y) -CONFIG_SEQUENCER=y -endif -endif - -ifdef CONFIG_VIDC_SOUND -ifneq ($(CONFIG_SEQUENCER),Y) -CONFIG_SEQUENCER=y -endif -endif - -ifdef CONFIG_PAS -ifneq ($(CONFIG_AUDIO),Y) -CONFIG_AUDIO=y -endif -endif - -ifdef CONFIG_SB -ifneq ($(CONFIG_AUDIO),Y) -CONFIG_AUDIO=y -endif -endif - -ifdef CONFIG_GUS -ifneq ($(CONFIG_AUDIO),Y) -CONFIG_AUDIO=y -endif -endif - -ifdef CONFIG_PSS -ifneq ($(CONFIG_AUDIO),Y) -CONFIG_AUDIO=y -endif -endif - -ifdef CONFIG_GUS16 -ifneq ($(CONFIG_AUDIO),Y) -CONFIG_AUDIO=y -endif -endif - -ifdef CONFIG_GUSMAX -ifneq ($(CONFIG_AUDIO),Y) -CONFIG_AUDIO=y -endif -endif - -ifdef CONFIG_MSS -ifneq ($(CONFIG_AUDIO),Y) -CONFIG_AUDIO=y -endif -endif - -ifdef CONFIG_SSCAPE -ifneq ($(CONFIG_AUDIO),Y) -CONFIG_AUDIO=y -endif -endif - -ifdef CONFIG_TRIX -ifneq ($(CONFIG_AUDIO),Y) -CONFIG_AUDIO=y -endif -endif - -ifdef CONFIG_MAD16 -ifneq ($(CONFIG_AUDIO),Y) -CONFIG_AUDIO=y -endif -endif - -ifdef CONFIG_CS4232 -ifneq ($(CONFIG_AUDIO),Y) -CONFIG_AUDIO=y -endif -endif - -ifdef CONFIG_OPL3SA1 -ifneq ($(CONFIG_AUDIO),Y) -CONFIG_AUDIO=y -endif -endif - -ifdef CONFIG_SOFTOSS -ifneq ($(CONFIG_AUDIO),Y) -CONFIG_AUDIO=y -endif -endif - -ifdef CONFIG_VIDC_SOUND -ifneq ($(CONFIG_AUDIO),Y) -CONFIG_AUDIO=y -endif -endif - -ifdef CONFIG_PAS -ifneq ($(CONFIG_MIDI),Y) -CONFIG_MIDI=y -endif -endif - -ifdef CONFIG_SB -ifneq ($(CONFIG_MIDI),Y) -CONFIG_MIDI=y -endif -endif - -ifdef CONFIG_GUS -ifneq ($(CONFIG_MIDI),Y) -CONFIG_MIDI=y -endif -endif - -ifdef CONFIG_MPU401 -ifneq ($(CONFIG_MIDI),Y) -CONFIG_MIDI=y -endif -endif - -ifdef CONFIG_PSS -ifneq ($(CONFIG_MIDI),Y) -CONFIG_MIDI=y -endif -endif - -ifdef CONFIG_GUS16 -ifneq ($(CONFIG_MIDI),Y) -CONFIG_MIDI=y -endif -endif - -ifdef CONFIG_GUSMAX -ifneq ($(CONFIG_MIDI),Y) -CONFIG_MIDI=y -endif -endif - -ifdef CONFIG_SSCAPE -ifneq ($(CONFIG_MIDI),Y) -CONFIG_MIDI=y -endif -endif - -ifdef CONFIG_TRIX -ifneq ($(CONFIG_MIDI),Y) -CONFIG_MIDI=y -endif -endif - -ifdef CONFIG_MAD16 -ifneq ($(CONFIG_MIDI),Y) -CONFIG_MIDI=y -endif -endif - -ifdef CONFIG_CS4232 -ifneq ($(CONFIG_MIDI),Y) -CONFIG_MIDI=y -endif -endif - -ifdef CONFIG_MAUI -ifneq ($(CONFIG_MIDI),Y) -CONFIG_MIDI=y -endif -endif - -ifdef CONFIG_OPL3SA1 -ifneq ($(CONFIG_MIDI),Y) -CONFIG_MIDI=y -endif -endif - -ifdef CONFIG_SOFTOSS -ifneq ($(CONFIG_MIDI),Y) -CONFIG_MIDI=y -endif -endif - diff -u --recursive --new-file v2.1.101/linux/drivers/sound/Makefile linux/drivers/sound/Makefile --- v2.1.101/linux/drivers/sound/Makefile Thu May 7 22:51:51 1998 +++ linux/drivers/sound/Makefile Thu May 14 10:33:17 1998 @@ -1,263 +1,177 @@ -BUILDCODE=s # Makefile for the Linux sound card driver # -# Note 2! The CFLAGS definitions are now inherited from the -# parent makes. (hopefully) -# -# -# -# -ifeq ($(ARCH),m68k) - L_TARGET := sound.a - L_OBJS := - M_OBJS := - ifeq ($(CONFIG_DMASOUND),y) - L_OBJS += dmasound.o - else - ifeq ($(CONFIG_DMASOUND),m) - M_OBJS += dmasound.o - endif - endif +# 18 Apr 1998, Michael Elizabeth Chastain, +# Rewritten to use lists instead of if-statements. - include $(TOPDIR)/Rules.make - clean: - rm -f core *.o *.a *.s -else +# My subdirectories. -include Defines +SUB_DIRS := +MOD_SUB_DIRS := +MOD_IN_SUB_DIRS := +ALL_SUB_DIRS := $(SUB_DIRS) lowlevel -ifndef TOPDIR -TOPDIR=/usr/src/linux +ifeq ($(CONFIG_LOWLEVEL_SOUND),y) + SUB_DIRS += lowlevel + MOD_IN_SUB_DIRS += lowlevel endif -SUB_DIRS := lowlevel -MOD_SUB_DIRS := $(SUB_DIRS) -ALL_SUB_DIRS := $(SUB_DIRS) - -L_TARGET := sound.a -M_OBJS := -L_OBJS := -ifeq ($(CONFIG_SOUND),y) - L_OBJS += soundcard.o dev_table.o sequencer.o sys_timer.o sound_timer.o lowlevel/lowlevel.o midi_synth.o midibuf.o sound_firmware.o audio.o dmabuf.o -else - ifeq ($(CONFIG_SOUND),m) - M_OBJS += sound.o - MIX_OBJS += sound_syms.o - endif -endif -ifeq ($(CONFIG_MIDI),y) - L_OBJS += midibuf.o - LX_OBJS += midi_synth.o -endif +# All of the (potential) objects that export symbols. +# This list comes from 'grep -l EXPORT_SYMBOL *.[hc]'. -#ifeq ($(CONFIG_AUDIO),y) -#L_OBJS += dmabuf.o -#endif +export-objs := ad1848.o mpu401.o opl3.o sb_card.o uart401.o \ + audio_syms.o midi_syms.o sequencer_syms.o sound_syms.o -ifeq ($(CONFIG_YM3812),y) -LX_OBJS += adlib_card.o opl3.o -else - ifeq ($(CONFIG_YM3812),m) - MX_OBJS += adlib_card.o opl3.o - endif -endif -ifeq ($(CONFIG_PAS),y) -L_OBJS += pas2.o -else - ifeq ($(CONFIG_PAS),m) - M_OBJS += pas2.o - endif -endif -ifeq ($(CONFIG_GUS),y) -L_OBJS += gus.o - ifeq ($(CONFIG_GUSMAX),y) - CONFIG_MSS = y - endif -else - ifeq ($(CONFIG_GUS),m) - M_OBJS += gus.o - endif - ifeq ($(CONFIG_GUSMAX),y) - ifneq ($(CONFIG_MSS),y) - CONFIG_MSS = m - endif - endif -endif +# Object file lists. -ifeq ($(CONFIG_SB),y) -L_OBJS += sb_audio.o sb_common.o sb_midi.o sb_mixer.o -LX_OBJS += sb_card.o -CONFIG_UART401 = y -else - ifeq ($(CONFIG_SB),m) - M_OBJS += sb.o - MIX_OBJS += sb_card.o - ifneq ($(CONFIG_UART401),y) - CONFIG_UART401 = m - endif - endif -endif +obj-y := +obj-m := +obj-n := +obj- := -ifeq ($(CONFIG_MSS),y) -LX_OBJS += ad1848.o -else - ifeq ($(CONFIG_MSS),m) - MX_OBJS += ad1848.o - endif -endif -ifeq ($(CONFIG_ADLIB),y) -LX_OBJS += adlib_card.o -else - ifeq ($(CONFIG_ADLIB),m) - MX_OBJS += adlib_card.o - endif -endif -ifeq ($(CONFIG_MPU401),y) -LX_OBJS += mpu401.o -else - ifeq ($(CONFIG_MPU401),m) - MX_OBJS += mpu401.o - else - ifeq ($(CONFIG_MPU_EMU),y) - LX_OBJS += mpu401.o - else - ifeq ($(CONFIG_MPU_EMU),m) - MX_OBJS += mpu401.o - endif - endif - endif -endif +# Each configuration option enables a list of files. -ifeq ($(CONFIG_UART401),y) -LX_OBJS += uart401.o -else - ifeq ($(CONFIG_UART401),m) - MX_OBJS += uart401.o - endif -endif +ifeq ($(ARCH),m68k) -ifeq ($(CONFIG_UART6850),y) -LX_OBJS += uart6850.o -else - ifeq ($(CONFIG_UART6850),m) - MX_OBJS += uart6850.o - endif -endif +obj-$(CONFIG_DMASOUND) += dmasound.o -ifeq ($(CONFIG_PSS),y) -L_OBJS += pss.o else - ifeq ($(CONFIG_PSS),m) - M_OBJS += pss.o - endif -endif -ifeq ($(CONFIG_SSCAPE),y) -L_OBJS += sscape.o -else - ifeq ($(CONFIG_SSCAPE),m) - M_OBJS += sscape.o - endif -endif +obj-$(CONFIG_SOUND) += sound.o +obj-$(CONFIG_SOUND_ADLIB) += adlib_card.o opl3.o +obj-$(CONFIG_SOUND_CS4232) += cs4232.o ad1848.o uart401.o +obj-$(CONFIG_SOUND_GUS) += gus.o ad1848.o +obj-$(CONFIG_SOUND_MAD16) += mad16.o ad1848.o sb.o uart401.o +obj-$(CONFIG_SOUND_MAUI) += maui.o mpu401.o +obj-$(CONFIG_SOUND_MPU401) += mpu401.o +obj-$(CONFIG_SOUND_MSS) += ad1848.o +obj-$(CONFIG_SOUND_OPL3SA1) += opl3sa.o ad1848.o uart401.o +obj-$(CONFIG_SOUND_PAS) += pas2.o sb.o uart401.o +obj-$(CONFIG_SOUND_PSS) += pss.o ad1848.o mpu401.o +obj-$(CONFIG_SOUND_SB) += sb.o uart401.o +obj-$(CONFIG_SOUND_SOFTOSS) += softoss2.o +obj-$(CONFIG_SOUND_SGALAXY) += sgalaxy.o +obj-$(CONFIG_SOUND_SSCAPE) += sscape.o ad1848.o mpu401.o +obj-$(CONFIG_SOUND_TRIX) += trix.o ad1848.o sb.o uart401.o +obj-$(CONFIG_SOUND_UART6850) += uart6850.c +obj-$(CONFIG_SOUND_VMIDI) += v_midi.o +obj-$(CONFIG_SOUND_YM3812) += adlib_card.o opl3.o +obj-$(CONFIG_VIDC_SOUND) += vidc_mod.o -ifeq ($(CONFIG_TRIX),y) -L_OBJS += trix.o -else - ifeq ($(CONFIG_TRIX),m) - M_OBJS += trix.o - endif endif -ifeq ($(CONFIG_MAD16),y) -L_OBJS += mad16.o -else - ifeq ($(CONFIG_MAD16),m) - M_OBJS += mad16.o sb.o uart401.o - MX_OBJS += sb_card.o ad1848.o - endif -endif -ifeq ($(CONFIG_CS4232),y) -LX_OBJS += cs4232.o -else - ifeq ($(CONFIG_CS4232),m) - MX_OBJS += cs4232.o - endif -endif -ifeq ($(CONFIG_MAUI),y) -L_OBJS += maui.o -else - ifeq ($(CONFIG_MAUI),m) - M_OBJS += maui.o - endif -endif +# Declare multi-part drivers. -ifeq ($(CONFIG_SOFTOSS),y) -L_OBJS += softoss.o softoss_rs.o -else - ifeq ($(CONFIG_SOFTOSS),m) - M_OBJS += softoss2.o - endif -endif +list-multi := sound.o gus.o pas2.o sb.o softoss2.o vidc_mod.o -ifeq ($(CONFIG_OPL3SA1),y) -L_OBJS += opl3sa.o -LX_OBJS += ad1848.o -else - ifeq ($(CONFIG_OPL3SA1),m) - M_OBJS += opl3sa.o - MX_OBJS += ad1848.o - endif -endif +sound-objs := \ + dev_table.o soundcard.o sound_firmware.o sound_syms.o \ + audio.o audio_syms.o dmabuf.o \ + midi_syms.o midi_synth.o midibuf.o \ + sequencer.o sequencer_syms.o sound_timer.o sys_timer.o + +gus-objs := gus_card.o gus_midi.o gus_vol.o gus_wave.o ics2101.o +pas2-objs := pas2_card.o pas2_midi.o pas2_mixer.o pas2_pcm.o +sb-objs := sb_audio.o sb_card.o sb_common.o sb_midi.o sb_mixer.o +softoss2-objs := softoss.o softoss_rs.o +vidc_mod-objs := vidc.o vidc_audio.o vidc_fill.o vidc_mixer.o vidc_synth.o -ifeq ($(CONFIG_VMIDI),y) -L_OBJS += v_midi.o -else - ifeq ($(CONFIG_VMIDI),m) - M_OBJS += v_midi.o - endif -endif -ifeq ($(CONFIG_VIDC_SOUND),y) - L_OBJS += vidc.o vidc_audio.o vidc_mixer.o vidc_synth.o vidc_fill.o + +# Extract lists of the multi-part drivers. +# The 'int-*' lists are the intermediate files used to build the multi's. + +multi-y := $(filter $(list-multi), $(obj-y)) +multi-m := $(filter $(list-multi), $(obj-m)) +int-y := $(sort $(foreach m, $(multi-y), $($(basename $(m))-objs))) +int-m := $(sort $(foreach m, $(multi-m), $($(basename $(m))-objs))) + + + +# Files that are both resident and modular: remove from modular. + +obj-m := $(filter-out $(obj-y), $(obj-m)) +int-m := $(filter-out $(int-y), $(int-m)) + + + +# Set flags for secondary drivers. +# I have to do this before I reduce obj-y to components. + +EXTRA_CFLAGS := $(sort \ + $(patsubst ad1848.o, -DCONFIG_SOUND_AD1848, \ + $(patsubst mpu401.o, -DCONFIG_SOUND_MPU_EMU, \ + $(patsubst sb.o, -DCONFIG_SOUND_SBDSP, \ + $(patsubst uart401.o, -DCONFIG_SOUND_UART401, \ + $(filter ad1848.o mpu401.o sb.o uart401.o, $(obj-y)) \ + ))))) + + + +# Take multi-part drivers out of obj-y and put components in. + +obj-y := $(filter-out $(list-multi), $(obj-y)) $(int-y) + + + +# Translate to Rules.make lists. + +L_TARGET := sound.a +MOD_LIST_NAME := SOUND_MODULES + +L_OBJS := $(sort $(filter-out $(export-objs), $(obj-y))) +LX_OBJS := $(sort $(filter $(export-objs), $(obj-y))) +M_OBJS := $(sort $(filter-out $(export-objs), $(obj-m))) +MX_OBJS := $(sort $(filter $(export-objs), $(obj-m))) +MI_OBJS := $(sort $(filter-out $(export-objs), $(int-m))) +MIX_OBJS := $(sort $(filter $(export-objs), $(int-m))) + +ifeq ($(CONFIG_LOWLEVEL_SOUND),y) + L_OBJS += lowlevel/lowlevel.o endif include $(TOPDIR)/Rules.make -softoss2.o: softoss.o softoss_rs.o - $(LD) -r -o softoss2.o softoss.o softoss_rs.o -pas2.o: pas2_card.o pas2_midi.o pas2_mixer.o pas2_pcm.o - $(LD) -r -o pas2.o pas2_card.o pas2_midi.o pas2_mixer.o pas2_pcm.o -sb.o: sb_audio.o sb_card.o sb_common.o sb_midi.o sb_mixer.o - $(LD) -r -o sb.o sb_audio.o sb_card.o sb_common.o sb_midi.o sb_mixer.o +# Link rules for multi-part drivers. + +sound.o: $(sound-objs) + $(LD) -r -o $@ $(sound-objs) + +gus.o: $(gus-objs) + $(LD) -r -o $@ $(gus-objs) + +pas2.o: $(pas2-objs) + $(LD) -r -o $@ $(pas2-objs) -lowlevel/lowlevel.o: - cd lowlevel; make +sb.o: $(sb-objs) + $(LD) -r -o $@ $(sb-objs) + +softoss2.o: $(softoss2-objs) + $(LD) -r -o $@ $(softoss2-objs) + +vidc_mod.o: $(vidc_mod-objs) + $(LD) -r -o $@ $(vidc_mod-objs) -sound.o: soundcard.o dev_table.o audio.o dmabuf.o sequencer.o sys_timer.o sound_timer.o lowlevel/lowlevel.o midi_synth.o midibuf.o sound_firmware.o sound_syms.o - $(LD) -r -o sound.o soundcard.o dev_table.o audio.o dmabuf.o \ - sequencer.o sys_timer.o sound_timer.o lowlevel/lowlevel.o \ - midi_synth.o midibuf.o sound_firmware.o sound_syms.o -gus.o: gus_card.o gus_midi.o gus_vol.o gus_wave.o ics2101.o - $(LD) -r -o gus.o gus_card.o gus_midi.o gus_vol.o gus_wave.o ics2101.o # Firmware files that need translation # # The translated files are protected by a file that keeps track # of what name was used to build them. If the name changes, they # will be forced to be remade. +# +# First make the utilities. bin2hex: bin2hex.c $(HOSTCC) -o bin2hex bin2hex.c @@ -265,53 +179,74 @@ hex2hex: hex2hex.c $(HOSTCC) -o hex2hex hex2hex.c -ifeq ($(CONFIG_MAUI_HAVE_BOOT),y) -CONFIG_MAUI_BOOT_FILE := $(patsubst "%", %, $(CONFIG_MAUI_BOOT_FILE)) + + +# Turtle Beach Maui / Tropez maui.o: maui_boot.h -maui_boot.h: $(CONFIG_MAUI_BOOT_FILE) bin2hex - bin2hex -i maui_os < "$(CONFIG_MAUI_BOOT_FILE)" > $@ +ifeq ($(CONFIG_MAUI_HAVE_BOOT),y) + maui_boot.h: $(patsubst "%", %, $(CONFIG_MAUI_BOOT_FILE)) bin2hex + bin2hex -i maui_os < $(CONFIG_MAUI_BOOT_FILE) > $@ +else + maui_boot.h: + ( \ + echo 'static unsigned char * maui_os = NULL;'; \ + echo 'static int maui_osLen = 0;'; \ + ) > $@ +endif @ ( \ - echo 'ifeq ($(strip $(CONFIG_MAUI_BOOT_FILE)),$$(strip $$(CONFIG_MAUI_BOOT_FILE)))'; \ + echo 'ifeq ($(strip $(CONFIG_MAUI_HAVE_BOOT) $(CONFIG_MAUI_BOOT_FILE)),$$(strip $$(CONFIG_MAUI_HAVE_BOOT) $$(CONFIG_MAUI_BOOT_FILE)))'; \ echo 'FILES_BOOT_UP_TO_DATE += $@'; \ echo 'endif' \ ) > .$@.boot -endif -ifeq ($(CONFIG_PSS_HAVE_BOOT),y) -CONFIG_PSS_BOOT_FILE := $(patsubst "%", %, $(CONFIG_PSS_BOOT_FILE)) +# PSS (ECHO-ADI2111) pss.o: pss_boot.h -pss_boot.h: $(CONFIG_PSS_BOOT_FILE) bin2hex - bin2hex pss_synth < "$(CONFIG_PSS_BOOT_FILE)" > $@ +ifeq ($(CONFIG_PSS_HAVE_BOOT),y) + pss_boot.h: $(patsubst "%", %, $(CONFIG_PSS_BOOT_FILE)) bin2hex + bin2hex pss_synth < $(CONFIG_PSS_BOOT_FILE) > $@ +else + pss_boot.h: + ( \ + echo 'static unsigned char * pss_synth = NULL;'; \ + echo 'static int pss_synthLen = 0;'; \ + ) > $@ +endif @ ( \ - echo 'ifeq ($(strip $(CONFIG_PSS_BOOT_FILE)),$$(strip $$(CONFIG_PSS_BOOT_FILE)))'; \ + echo 'ifeq ($(strip $(CONFIG_PSS_HAVE_BOOT) $(CONFIG_PSS_BOOT_FILE)),$$(strip $$(CONFIG_PSS_HAVE_BOOT) $$(CONFIG_PSS_BOOT_FILE)))'; \ echo 'FILES_BOOT_UP_TO_DATE += $@'; \ echo 'endif' \ ) > .$@.boot -endif -ifeq ($(CONFIG_TRIX_HAVE_BOOT),y) -CONFIG_TRIX_BOOT_FILE := $(patsubst "%", %, $(CONFIG_TRIX_BOOT_FILE)) +# MediaTrix AudioTrix Pro trix.o: trix_boot.h -trix_boot.h: $(CONFIG_TRIX_BOOT_FILE) hex2hex - hex2hex -i trix_boot < "$(CONFIG_TRIX_BOOT_FILE)" > $@ +ifeq ($(CONFIG_TRIX_HAVE_BOOT),y) + trix_boot.h: $(patsubst "%", %, $(CONFIG_TRIX_BOOT_FILE)) hex2hex + hex2hex -i trix_boot < $(CONFIG_TRIX_BOOT_FILE) > $@ +else + trix_boot.h: + ( \ + echo 'static unsigned char * trix_boot = NULL;'; \ + echo 'static int trix_boot_len = 0;'; \ + ) > $@ +endif @ ( \ - echo 'ifeq ($(strip $(CONFIG_TRIX_BOOT_FILE)),$$(strip $$(CONFIG_TRIX_BOOT_FILE)))'; \ + echo 'ifeq ($(strip $(CONFIG_TRIX_HAVE_BOOT) $(CONFIG_TRIX_BOOT_FILE)),$$(strip $$(CONFIG_TRIX_HAVE_BOOT) $$(CONFIG_TRIX_BOOT_FILE)))'; \ echo 'FILES_BOOT_UP_TO_DATE += $@'; \ echo 'endif' \ ) > .$@.boot -endif + # Find boot files whose source file names have changed and force rebuild. @@ -328,5 +263,4 @@ ifneq ($(FILES_BOOT_CHANGED),) $(FILES_BOOT_CHANGED): dummy -endif endif diff -u --recursive --new-file v2.1.101/linux/drivers/sound/README.CONFIG linux/drivers/sound/README.CONFIG --- v2.1.101/linux/drivers/sound/README.CONFIG Wed Dec 31 16:00:00 1969 +++ linux/drivers/sound/README.CONFIG Thu May 14 10:33:17 1998 @@ -0,0 +1,75 @@ +Sound Driver Configuration Notes +Michael Chastain, +18 Apr 1998 + +The Linux sound driver is derived from OSS/Free, a multi-platform +Unix sound driver by Hannu Savolainen. You can find out +more about OSS/Free and the commercial version, OSS/Linux, at +. + +OSS/Free comes with the configuration program 'configure.c'. We have +discarded that program in favor of a standard Linux configuration file +Config.in. + +Config.in defines a set of symbols with the form CONFIG_SOUND_*. +These are the -native symbols-. Here is a description: + + CONFIG_SOUND + + This is the master symbol. It controls whether the basic + sound-driver code is resident, modular, or not present at all. + + If the basic driver is resident, each primary and secondary + driver can be resident, modular, or not present. + + If the basic driver is modular, each primary and secondary driver + can be modular or not present. + + And if the basic driver is not present, all other drivers are + not present, too. + + Primary drivers + + These are symbols such as CONFIG_SOUND_SB, CONFIG_SOUND_SB_MODULE, + CONFIG_SOUND_TRIX, or CONFIG_SOUND_TRIX_MODULE. Each driver + that the user can directly select is a primary driver and has + the usual pair of symbols: one resident and one modular. + + Each primary driver can be either resident or modular. + + Secondary drivers + + Primary drivers require the support of secondary drivers, such + as ad1848.o and uart401.o. + + In Makefile, each primary driver has a list of required secondary + drivers. The secondary driver requirements are merged and a + single definition is emitted at the end. + + For each secondary driver: if any resident primary driver + requires it, that secondary driver will be resident. If no + resident primary driver requires it but some modular primary + driver requires it, then that secondary driver will be modular. + Otherwise that secondary driver will be not present. + + OSS/Free also contains tests for secondary drivers. The Makefile + defines symbols for these drivers in EXTRA_CFLAGS. + + CONFIG_AUDIO, CONFIG_MIDI, CONFIG_SEQUENCER + + These three drivers are like secondary drivers, but not quite. + They can not yet be separated into modules. They are always + linked into the basic sound driver, whether they are needed + or not. (This is in case a primary driver is added to the + system later, as a module, and needs these facilities. If it + were possible to modularise them, then they would get built as + additional modules at that time). + +The OSS/Free code does not use the native symbols directly, primarily +because it does not know about modules. I could edit the code, but that +would make it harder to upgrade to new versions of OSS/Free. Instead, +the OSS/Free code continues to use -legacy symbols-. + +legacy.h defines all the legacy symbols to 1. This is because, whenever +OSS/Free tests a symbol, the Makefile has already arranged for that +driver to be included. diff -u --recursive --new-file v2.1.101/linux/drivers/sound/ad1848.c linux/drivers/sound/ad1848.c --- v2.1.101/linux/drivers/sound/ad1848.c Wed Apr 8 19:36:27 1998 +++ linux/drivers/sound/ad1848.c Thu May 14 10:33:17 1998 @@ -105,7 +105,7 @@ -1, -1, -1, -1, -1, -1, -1, -1, -1 }; -#if defined(CONFIG_SEQUENCER) && !defined(EXCLUDE_TIMERS) +#if defined(CONFIG_SEQUENCER) && !defined(EXCLUDE_TIMERS) || defined(MODULE) static int timer_installed = -1; @@ -141,7 +141,7 @@ static void ad1848_halt_output(int dev); static void ad1848_trigger(int dev, int bits); -#if (defined(CONFIG_SEQUENCER) && !defined(EXCLUDE_TIMERS)) || defined(MODULE) +#if defined(CONFIG_SEQUENCER) && !defined(EXCLUDE_TIMERS) static int ad1848_tmr_install(int dev); static void ad1848_tmr_reprogram(int dev); @@ -1048,7 +1048,7 @@ restore_flags(flags); devc->xfer_count = 0; -#if (defined(CONFIG_SEQUENCER) && !defined(EXCLUDE_TIMERS)) || defined(MODULE) +#if defined(CONFIG_SEQUENCER) && !defined(EXCLUDE_TIMERS) if (dev == timer_installed && devc->timer_running) if ((fs & 0x01) != (old_fs & 0x01)) { @@ -1781,6 +1781,7 @@ } audio_devs[my_dev]->portc = portc; + audio_devs[my_dev]->mixer_dev = -1; memset((char *) portc, 0, sizeof(*portc)); nr_ad1848_devs++; @@ -1828,7 +1829,7 @@ } else if (irq < 0) irq2dev[-irq] = devc->dev_no = my_dev; -#if (defined(CONFIG_SEQUENCER) && !defined(EXCLUDE_TIMERS)) || defined(MODULE) +#if defined(CONFIG_SEQUENCER) && !defined(EXCLUDE_TIMERS) if (devc->model != MD_1848 && devc->model != MD_C930 && devc->irq_ok) ad1848_tmr_install(my_dev); @@ -2005,7 +2006,7 @@ if (devc->model != MD_1848 && alt_stat & 0x40) /* Timer interrupt */ { devc->timer_ticks++; -#if (defined(CONFIG_SEQUENCER) && !defined(EXCLUDE_TIMERS)) || defined(MODULE) +#if defined(CONFIG_SEQUENCER) && !defined(EXCLUDE_TIMERS) if (timer_installed == dev && devc->timer_running) sound_timer_interrupt(); #endif @@ -2405,7 +2406,7 @@ release_region(hw_config->io_base, 4); } -#if (defined(CONFIG_SEQUENCER) && !defined(EXCLUDE_TIMERS)) || defined(MODULE) +#if defined(CONFIG_SEQUENCER) && !defined(EXCLUDE_TIMERS) /* * Timer stuff (for /dev/music). @@ -2576,5 +2577,6 @@ if(loaded) unload_ms_sound(&hw_config); } + #endif #endif diff -u --recursive --new-file v2.1.101/linux/drivers/sound/adlib_card.c linux/drivers/sound/adlib_card.c --- v2.1.101/linux/drivers/sound/adlib_card.c Wed Apr 8 19:36:27 1998 +++ linux/drivers/sound/adlib_card.c Thu May 14 10:33:17 1998 @@ -16,7 +16,7 @@ #include "sound_config.h" #include "soundmodule.h" -#if defined(CONFIG_YM3812) || defined(MODULE) +#ifdef CONFIG_YM3812 void attach_adlib_card(struct address_info *hw_config) { diff -u --recursive --new-file v2.1.101/linux/drivers/sound/audio.c linux/drivers/sound/audio.c --- v2.1.101/linux/drivers/sound/audio.c Wed Apr 8 19:36:27 1998 +++ linux/drivers/sound/audio.c Thu May 14 10:33:17 1998 @@ -25,7 +25,7 @@ #include "sound_config.h" -#if defined(CONFIG_AUDIO) || defined(MODULE) +#ifdef CONFIG_AUDIO #include "ulaw.h" #include "coproc.h" diff -u --recursive --new-file v2.1.101/linux/drivers/sound/audio_syms.c linux/drivers/sound/audio_syms.c --- v2.1.101/linux/drivers/sound/audio_syms.c Wed Dec 31 16:00:00 1969 +++ linux/drivers/sound/audio_syms.c Thu May 14 10:33:17 1998 @@ -0,0 +1,21 @@ +/* + * Exported symbols for audio driver. + * __NO_VERSION__ because this is still part of sound.o. + */ + +#define __NO_VERSION__ +#include + +char audio_syms_symbol; + +#include "sound_config.h" +#include "sound_calls.h" + +EXPORT_SYMBOL(DMAbuf_start_dma); +EXPORT_SYMBOL(DMAbuf_open_dma); +EXPORT_SYMBOL(DMAbuf_close_dma); +EXPORT_SYMBOL(DMAbuf_inputintr); +EXPORT_SYMBOL(DMAbuf_outputintr); +EXPORT_SYMBOL(dma_ioctl); +EXPORT_SYMBOL(audio_open); +EXPORT_SYMBOL(audio_release); diff -u --recursive --new-file v2.1.101/linux/drivers/sound/cs4232.c linux/drivers/sound/cs4232.c --- v2.1.101/linux/drivers/sound/cs4232.c Wed Apr 8 19:36:27 1998 +++ linux/drivers/sound/cs4232.c Thu May 14 10:33:17 1998 @@ -34,7 +34,7 @@ #include "sound_config.h" #include "soundmodule.h" -#if defined(CONFIG_CS4232) || defined (MODULE) +#ifdef CONFIG_CS4232 #define KEY_PORT 0x279 /* Same as LPT1 status port */ #define CSN_NUM 0x99 /* Just a random number */ @@ -196,7 +196,6 @@ { int base = hw_config->io_base, irq = hw_config->irq; int dma1 = hw_config->dma, dma2 = hw_config->dma2; - int old_num_mixers = num_mixers; if (dma2 == -1) dma2 = dma1; @@ -208,7 +207,8 @@ 0, hw_config->osp); - if (num_mixers > old_num_mixers) + if (hw_config->slots[0] != -1 && + audio_devs[hw_config->slots[0]]->mixer_dev!=-1) { /* Assume the mixer map is as suggested in the CS4232 databook */ AD1848_REROUTE(SOUND_MIXER_LINE1, SOUND_MIXER_LINE); diff -u --recursive --new-file v2.1.101/linux/drivers/sound/dev_table.h linux/drivers/sound/dev_table.h --- v2.1.101/linux/drivers/sound/dev_table.h Wed Apr 8 19:36:27 1998 +++ linux/drivers/sound/dev_table.h Thu May 14 10:33:17 1998 @@ -379,13 +379,13 @@ struct driver_info sound_drivers[] = { -#if defined(CONFIG_PSS) && !defined(CONFIG_PSS_MODULE) +#ifdef CONFIG_SOUND_PSS {"PSS", 0, SNDCARD_PSS, "Echo Personal Sound System PSS (ESC614)", attach_pss, probe_pss, unload_pss}, {"PSSMPU", 0, SNDCARD_PSS_MPU, "PSS-MPU", attach_pss_mpu, probe_pss_mpu, unload_pss_mpu}, {"PSSMSS", 0, SNDCARD_PSS_MSS, "PSS-MSS", attach_pss_mss, probe_pss_mss, unload_pss_mss}, #endif -#if defined(CONFIG_GUS) && !defined(CONFIG_GUS_MODULE) +#ifdef CONFIG_SOUND_GUS #ifdef CONFIG_GUS16 {"GUS16", 0, SNDCARD_GUS16, "Ultrasound 16-bit opt.", attach_gus_db16, probe_gus_db16, unload_gus_db16}, #endif @@ -395,43 +395,55 @@ #endif #endif -#if defined(CONFIG_MSS) && !defined(CONFIG_MSS_MODULE) +#ifdef CONFIG_SOUND_MSS {"MSS", 0, SNDCARD_MSS, "MS Sound System", attach_ms_sound, probe_ms_sound, unload_ms_sound}, /* Compaq Deskpro XL */ {"DESKPROXL", 2, SNDCARD_DESKPROXL, "Compaq Deskpro XL", attach_ms_sound, probe_ms_sound, unload_ms_sound}, #endif -#ifdef CONFIG_MAD16 + +#ifdef CONFIG_SOUND_MAD16 {"MAD16", 0, SNDCARD_MAD16, "MAD16/Mozart (MSS)", attach_mad16, probe_mad16, unload_mad16}, {"MAD16MPU", 0, SNDCARD_MAD16_MPU, "MAD16/Mozart (MPU)", attach_mad16_mpu, probe_mad16_mpu, unload_mad16_mpu}, #endif -#ifdef CONFIG_CS4232 + +#ifdef CONFIG_SOUND_CS4232 {"CS4232", 0, SNDCARD_CS4232, "CS4232", attach_cs4232, probe_cs4232, unload_cs4232}, {"CS4232MPU", 0, SNDCARD_CS4232_MPU, "CS4232 MIDI", attach_cs4232_mpu, probe_cs4232_mpu, unload_cs4232_mpu}, #endif -#if defined(CONFIG_YM3812) && !defined(CONFIG_YM3812_MODULE) + +#ifdef CONFIG_SGALAXY + {"SGALAXY", 0, SNDCARD_SGALAXY, "Sound Galaxy WSS", attach_sgalaxy, probe_sgalaxy, unload_sgalaxy}, +#endif + +#ifdef CONFIG_SOUND_YM3812 {"OPL3", 0, SNDCARD_ADLIB, "OPL-2/OPL-3 FM", attach_adlib_card, probe_adlib, unload_adlib}, #endif -#if defined(CONFIG_PAS) && !defined(CONFIG_PAS_MODULE) + +#ifdef CONFIG_SOUND_PAS {"PAS16", 0, SNDCARD_PAS, "ProAudioSpectrum", attach_pas_card, probe_pas, unload_pas}, #endif -#if (defined(CONFIG_MPU401) || defined(CONFIG_MPU_EMU)) && defined(CONFIG_MIDI) && !defined(CONFIG_MPU401_MODULE) + +#if (defined(CONFIG_SOUND_MPU401) || defined(CONFIG_SOUND_MPU_EMU)) && defined(CONFIG_MIDI) {"MPU401", 0, SNDCARD_MPU401,"Roland MPU-401", attach_mpu401, probe_mpu401, unload_mpu401}, #endif -#if defined(CONFIG_UART401) && defined(CONFIG_MIDI) && !defined(CONFIG_UART401_MODULE) + +#if defined(CONFIG_SOUND_UART401) && defined(CONFIG_MIDI) {"UART401", 0, SNDCARD_UART401,"MPU-401 (UART)", attach_uart401, probe_uart401, unload_uart401}, #endif -#if defined(CONFIG_MAUI) && !defined(CONFIG_MAUI_MODULE) + +#if defined(CONFIG_SOUND_MAUI) {"MAUI", 0, SNDCARD_MAUI,"TB Maui", attach_maui, probe_maui, unload_maui}, #endif -#if defined(CONFIG_UART6850) && defined(CONFIG_MIDI) && !defined(CONFIG_UART6850_MODULE) + +#if defined(CONFIG_SOUND_UART6850) && defined(CONFIG_MIDI) {"MIDI6850", 0, SNDCARD_UART6850,"6860 UART Midi", attach_uart6850, probe_uart6850, unload_uart6850}, #endif -#if defined(CONFIG_SBDSP) && !defined(CONFIG_SBDSP_MODULE) +#ifdef CONFIG_SOUND_SBDSP {"SBLAST", 0, SNDCARD_SB, "Sound Blaster", attach_sb_card, probe_sb, unload_sb}, {"SBPNP", 6, SNDCARD_SBPNP, "Sound Blaster PnP", attach_sb_card, probe_sb, unload_sb}, @@ -440,29 +452,29 @@ #endif #endif -#ifdef CONFIG_SSCAPE +#ifdef CONFIG_SOUND_SSCAPE {"SSCAPE", 0, SNDCARD_SSCAPE, "Ensoniq SoundScape", attach_sscape, probe_sscape, unload_sscape}, {"SSCAPEMSS", 0, SNDCARD_SSCAPE_MSS, "MS Sound System (SoundScape)", attach_ss_ms_sound, probe_ss_ms_sound, unload_ss_ms_sound}, #endif -#ifdef CONFIG_OPL3SA1 +#ifdef CONFIG_SOUND_OPL3SA1 {"OPL3SA", 0, SNDCARD_OPL3SA1, "Yamaha OPL3-SA", attach_opl3sa_wss, probe_opl3sa_wss, unload_opl3sa_wss}, /* {"OPL3SASB", 0, SNDCARD_OPL3SA1_SB, "OPL3-SA (SB mode)", attach_opl3sa_sb, probe_opl3sa_sb, unload_opl3sa_sb}, */ {"OPL3SAMPU", 0, SNDCARD_OPL3SA1_MPU, "OPL3-SA MIDI", attach_opl3sa_mpu, probe_opl3sa_mpu, unload_opl3sa_mpu}, #endif -#if defined (CONFIG_TRIX) && !defined(CONFIG_TRIX_MODULE) +#ifdef CONFIG_SOUND_TRIX {"TRXPRO", 0, SNDCARD_TRXPRO, "MediaTrix AudioTrix Pro", attach_trix_wss, probe_trix_wss, unload_trix_wss}, {"TRXPROSB", 0, SNDCARD_TRXPRO_SB, "AudioTrix (SB mode)", attach_trix_sb, probe_trix_sb, unload_trix_sb}, {"TRXPROMPU", 0, SNDCARD_TRXPRO_MPU, "AudioTrix MIDI", attach_trix_mpu, probe_trix_mpu, unload_trix_mpu}, #endif -#if defined(CONFIG_SOFTOSS) && !defined(CONFIG_SOFTOSS_MODULE) +#ifdef CONFIG_SOUND_SOFTOSS {"SOFTSYN", 0, SNDCARD_SOFTOSS, "SoftOSS Virtual Wave Table", attach_softsyn_card, probe_softsyn, unload_softsyn}, #endif -#if defined(CONFIG_VMIDI) && defined(CONFIG_MIDI) && !defined(CONFIG_VMIDI_MODULE) +#if defined(CONFIG_SOUND_VMIDI) && defined(CONFIG_MIDI) {"VMIDI", 0, SNDCARD_VMIDI,"Loopback MIDI Device", attach_v_midi, probe_v_midi, unload_v_midi}, #endif #ifdef CONFIG_VIDC_SOUND @@ -484,7 +496,7 @@ struct card_info snd_installed_cards[] = { -#ifdef CONFIG_PSS +#ifdef CONFIG_SOUND_PSS {SNDCARD_PSS, {CONFIG_PSS_BASE, 0, -1, -1}, SND_DEFAULT_ENABLE}, #ifdef CONFIG_PSS_MPU_BASE {SNDCARD_PSS_MPU, {CONFIG_PSS_MPU_BASE, CONFIG_PSS_MPU_IRQ, 0, -1}, SND_DEFAULT_ENABLE}, @@ -493,7 +505,8 @@ {SNDCARD_PSS_MSS, {CONFIG_PSS_MSS_BASE, CONFIG_PSS_MSS_IRQ, CONFIG_PSS_MSS_DMA, -1}, SND_DEFAULT_ENABLE}, #endif #endif -#ifdef CONFIG_TRIX + +#ifdef CONFIG_SOUND_TRIX #ifndef CONFIG_TRIX_DMA2 #define CONFIG_TRIX_DMA2 CONFIG_TRIX_DMA #endif @@ -506,22 +519,23 @@ #endif #endif -#ifdef CONFIG_OPL3SA1 +#ifdef CONFIG_SOUND_OPL3SA1 {SNDCARD_OPL3SA1, {CONFIG_OPL3SA1_BASE, CONFIG_OPL3SA1_IRQ, CONFIG_OPL3SA1_DMA, CONFIG_OPL3SA1_DMA2}, SND_DEFAULT_ENABLE}, #ifdef CONFIG_OPL3SA1_MPU_BASE {SNDCARD_OPL3SA1_MPU, {CONFIG_OPL3SA1_MPU_BASE, CONFIG_OPL3SA1_MPU_IRQ, 0, -1}, SND_DEFAULT_ENABLE}, #endif #endif -#ifdef CONFIG_SOFTOSS +#ifdef CONFIG_SOUND_SOFTOSS {SNDCARD_SOFTOSS, {0, 0, -1, -1}, SND_DEFAULT_ENABLE}, #endif -#ifdef CONFIG_SSCAPE +#ifdef CONFIG_SOUND_SSCAPE {SNDCARD_SSCAPE, {CONFIG_SSCAPE_BASE, CONFIG_SSCAPE_IRQ, CONFIG_SSCAPE_DMA, -1}, SND_DEFAULT_ENABLE}, {SNDCARD_SSCAPE_MSS, {CONFIG_SSCAPE_MSS_BASE, CONFIG_SSCAPE_MSS_IRQ, CONFIG_SSCAPE_DMA, -1}, SND_DEFAULT_ENABLE}, #endif -#ifdef CONFIG_MAD16 + +#ifdef CONFIG_SOUND_MAD16 #ifndef CONFIG_MAD16_DMA2 #define CONFIG_MAD16_DMA2 CONFIG_MAD16_DMA #endif @@ -531,7 +545,7 @@ #endif #endif -#ifdef CONFIG_CS4232 +#ifdef CONFIG_SOUND_CS4232 #ifndef CONFIG_CS4232_DMA2 #define CONFIG_CS4232_DMA2 CONFIG_CS4232_DMA #endif @@ -541,8 +555,15 @@ {SNDCARD_CS4232, {CONFIG_CS4232_BASE, CONFIG_CS4232_IRQ, CONFIG_CS4232_DMA, CONFIG_CS4232_DMA2}, SND_DEFAULT_ENABLE}, #endif +#ifdef CONFIG_SGALAXY +#ifndef CONFIG_SGALAXY_DMA2 +#define CONFIG_SGALAXY_DMA2 CONFIG_SGALAXY_DMA +#endif + {SNDCARD_SGALAXY, {CONFIG_SGALAXY_BASE, CONFIG_SGALAXY_IRQ, CONFIG_SGALAXY_DMA, CONFIG_SGALAXY_DMA2, 0, NULL, CONFIG_SGALAXY_SGBASE}, SND_DEFAULT_ENABLE}, +#endif + -#ifdef CONFIG_MSS +#ifdef CONFIG_SOUND_MSS #ifndef CONFIG_MSS_DMA2 #define CONFIG_MSS_DMA2 -1 #endif @@ -552,17 +573,17 @@ #else {SNDCARD_MSS, {CONFIG_MSS_BASE, CONFIG_MSS_IRQ, CONFIG_MSS_DMA, CONFIG_MSS_DMA2}, SND_DEFAULT_ENABLE}, #endif + #ifdef MSS2_BASE {SNDCARD_MSS, {MSS2_BASE, MSS2_IRQ, MSS2_DMA, MSS2_DMA2}, SND_DEFAULT_ENABLE}, #endif #endif - -#ifdef CONFIG_PAS +#ifdef CONFIG_SOUND_PAS {SNDCARD_PAS, {CONFIG_PAS_BASE, CONFIG_PAS_IRQ, CONFIG_PAS_DMA, -1}, SND_DEFAULT_ENABLE}, #endif -#ifdef CONFIG_SB +#ifdef CONFIG_SOUND_SB #ifndef CONFIG_SB_DMA #define CONFIG_SB_DMA 1 #endif @@ -574,11 +595,12 @@ {SNDCARD_SB, {SB2_BASE, SB2_IRQ, SB2_DMA, SB2_DMA2}, SND_DEFAULT_ENABLE}, #endif #endif -#if defined(CONFIG_MAUI) + +#ifdef CONFIG_SOUND_MAUI {SNDCARD_MAUI, {CONFIG_MAUI_BASE, CONFIG_MAUI_IRQ, 0, -1}, SND_DEFAULT_ENABLE}, #endif -#if defined(CONFIG_MPU401) && defined(CONFIG_MIDI) +#if defined(CONFIG_SOUND_MPU401) && defined(CONFIG_MIDI) {SNDCARD_MPU401, {CONFIG_MPU_BASE, CONFIG_MPU_IRQ, 0, -1}, SND_DEFAULT_ENABLE}, #ifdef MPU2_BASE {SNDCARD_MPU401, {MPU2_BASE, MPU2_IRQ, 0, -1}, SND_DEFAULT_ENABLE}, @@ -588,17 +610,17 @@ #endif #endif -#if defined(CONFIG_UART6850) && defined(CONFIG_MIDI) +#if defined(CONFIG_SOUND_UART6850) && defined(CONFIG_MIDI) {SNDCARD_UART6850, {CONFIG_U6850_BASE, CONFIG_U6850_IRQ, 0, -1}, SND_DEFAULT_ENABLE}, #endif -#if defined(CONFIG_SB) +#ifdef CONFIG_SOUND_SB #if defined(CONFIG_MIDI) && defined(CONFIG_SB_MPU_BASE) {SNDCARD_SB16MIDI,{CONFIG_SB_MPU_BASE, CONFIG_SB_MPU_IRQ, 0, -1}, SND_DEFAULT_ENABLE}, #endif #endif -#ifdef CONFIG_GUS +#ifdef CONFIG_SOUND_GUS #ifndef CONFIG_GUS_DMA2 #define CONFIG_GUS_DMA2 CONFIG_GUS_DMA #endif @@ -608,11 +630,11 @@ {SNDCARD_GUS, {CONFIG_GUS_BASE, CONFIG_GUS_IRQ, CONFIG_GUS_DMA, CONFIG_GUS_DMA2}, SND_DEFAULT_ENABLE}, #endif -#if defined(CONFIG_YM3812) +#ifdef CONFIG_SOUND_YM3812 {SNDCARD_ADLIB, {FM_MONO, 0, 0, -1}, SND_DEFAULT_ENABLE}, #endif -#if defined(CONFIG_VMIDI) && defined(CONFIG_MIDI) +#if defined(CONFIG_SOUND_VMIDI) && defined(CONFIG_MIDI) {SNDCARD_VMIDI, {0, 0, 0, -1}, SND_DEFAULT_ENABLE}, #endif diff -u --recursive --new-file v2.1.101/linux/drivers/sound/dmabuf.c linux/drivers/sound/dmabuf.c --- v2.1.101/linux/drivers/sound/dmabuf.c Wed Apr 8 19:36:27 1998 +++ linux/drivers/sound/dmabuf.c Thu May 14 10:33:17 1998 @@ -1131,6 +1131,12 @@ * NOTE! This routine could be called several times. */ + /* drag in audio_syms.o */ + { + extern char audio_syms_symbol; + audio_syms_symbol = 0; + } + if (adev && adev->dmap_out == NULL) { if (adev->d == NULL) panic("OSS: audio_devs[%d]->d == NULL\n", dev); diff -u --recursive --new-file v2.1.101/linux/drivers/sound/gus_card.c linux/drivers/sound/gus_card.c --- v2.1.101/linux/drivers/sound/gus_card.c Tue Apr 14 14:29:24 1998 +++ linux/drivers/sound/gus_card.c Thu May 14 10:33:17 1998 @@ -26,7 +26,7 @@ #include "sound_config.h" #include "soundmodule.h" -#if defined(CONFIG_GUS) || defined(MODULE) +#ifdef CONFIG_GUS #include "gus_hw.h" @@ -57,7 +57,7 @@ if (hw_config->dma2 != -1 && hw_config->dma2 != hw_config->dma) if (sound_alloc_dma(hw_config->dma2, "GUS(2)")) printk(KERN_ERR "gus_card.c: Can't allocate DMA channel %d\n", hw_config->dma2); -#if defined(CONFIG_MIDI) +#ifdef CONFIG_MIDI gus_midi_init(hw_config); #endif } @@ -152,13 +152,13 @@ } if (src & (MIDI_TX_IRQ | MIDI_RX_IRQ)) { -#if defined(CONFIG_MIDI) +#ifdef CONFIG_MIDI gus_midi_interrupt(0); #endif } if (src & (GF1_TIMER1_IRQ | GF1_TIMER2_IRQ)) { -#if defined(CONFIG_SEQUENCER) || defined(CONFIG_SEQUENCER_MODULE) +#ifdef CONFIG_SEQUENCER if (gus_timer_enabled) sound_timer_interrupt(); gus_write8(0x45, 0); /* Ack IRQ */ @@ -187,7 +187,7 @@ void attach_gus_db16(struct address_info *hw_config) { -#if defined(CONFIG_GUS) || defined(MODULE) +#ifdef CONFIG_GUS gus_pcm_volume = 100; gus_wave_volume = 90; #endif diff -u --recursive --new-file v2.1.101/linux/drivers/sound/gus_midi.c linux/drivers/sound/gus_midi.c --- v2.1.101/linux/drivers/sound/gus_midi.c Mon Feb 23 18:12:09 1998 +++ linux/drivers/sound/gus_midi.c Thu May 14 10:33:17 1998 @@ -17,7 +17,8 @@ #include "gus_hw.h" -#if ( defined(CONFIG_GUS) && defined(CONFIG_MIDI) ) || defined (MODULE) +#ifdef CONFIG_GUS +#ifdef CONFIG_MIDI static int midi_busy = 0, input_opened = 0; static int my_dev; @@ -265,4 +266,5 @@ restore_flags(flags); } +#endif #endif diff -u --recursive --new-file v2.1.101/linux/drivers/sound/gus_vol.c linux/drivers/sound/gus_vol.c --- v2.1.101/linux/drivers/sound/gus_vol.c Mon Feb 23 18:12:09 1998 +++ linux/drivers/sound/gus_vol.c Thu May 14 10:33:17 1998 @@ -12,7 +12,7 @@ #include #include "sound_config.h" -#if defined(CONFIG_GUS) || defined(MODULE) +#ifdef CONFIG_GUS #include "gus_linearvol.h" #define GUS_VOLUME gus_wave_volume diff -u --recursive --new-file v2.1.101/linux/drivers/sound/gus_wave.c linux/drivers/sound/gus_wave.c --- v2.1.101/linux/drivers/sound/gus_wave.c Tue Apr 14 14:29:24 1998 +++ linux/drivers/sound/gus_wave.c Thu May 14 10:33:17 1998 @@ -25,7 +25,7 @@ #include #include "gus_hw.h" -#if defined(CONFIG_GUS) || defined(MODULE) +#ifdef CONFIG_GUS #define GUS_BANK_SIZE (((iw_mode) ? 256*1024*1024 : 256*1024)) @@ -3115,7 +3115,7 @@ hw_config->slots[0] = sdev; synth_devs[sdev] = &guswave_operations; sequencer_init(); -#if defined(CONFIG_SEQUENCER) || defined(MODULE) +#ifdef CONFIG_SEQUENCER gus_tmr_install(gus_base + 8); #endif } @@ -3442,7 +3442,7 @@ } } -#if defined(CONFIG_SEQUENCER) || defined(MODULE) +#ifdef CONFIG_SEQUENCER /* * Timer stuff diff -u --recursive --new-file v2.1.101/linux/drivers/sound/hex2hex.c linux/drivers/sound/hex2hex.c --- v2.1.101/linux/drivers/sound/hex2hex.c Tue Mar 17 22:18:14 1998 +++ linux/drivers/sound/hex2hex.c Thu May 14 10:33:17 1998 @@ -81,7 +81,7 @@ fprintf(stderr,"hex2hex: [-i] filename\n"); exit(1); } - varline = argv[1; + varline = argv[1]; l = loadhex(stdin, buf); printf("/*\n *\t Computer generated file. Do not edit.\n */\n"); diff -u --recursive --new-file v2.1.101/linux/drivers/sound/ics2101.c linux/drivers/sound/ics2101.c --- v2.1.101/linux/drivers/sound/ics2101.c Mon Feb 23 18:12:09 1998 +++ linux/drivers/sound/ics2101.c Thu May 14 10:33:17 1998 @@ -17,7 +17,7 @@ #include "sound_config.h" -#if defined(CONFIG_GUS) || defined(MODULE) +#ifdef CONFIG_GUS #include #include "gus_hw.h" diff -u --recursive --new-file v2.1.101/linux/drivers/sound/legacy.h linux/drivers/sound/legacy.h --- v2.1.101/linux/drivers/sound/legacy.h Wed Dec 31 16:00:00 1969 +++ linux/drivers/sound/legacy.h Thu May 14 10:33:17 1998 @@ -0,0 +1,48 @@ +#ifndef _SOUND_LEGACY_H_ +#define _SOUND_LEGACY_H_ + +/* + * Force on additional support + */ + +#define __SGNXPRO__ +#define DESKPROXL +/* #define SM_GAMES */ +#define SM_WAVE + +/* + * Define legacy options. + */ + +#define SELECTED_SOUND_OPTIONS 0x0 + +#define HAVE_MAUI_BOOT +#define PSS_HAVE_LD +#define INCLUDE_TRIX_BOOT + +#define CONFIG_CS4232 +#define CONFIG_GUS +#define CONFIG_MAD16 +#define CONFIG_MAUI +#define CONFIG_MPU401 +#define CONFIG_MSS +#define CONFIG_OPL3SA1 +#define CONFIG_PAS +#define CONFIG_PSS +#define CONFIG_SB +#define CONFIG_SOFTOSS +#define CONFIG_SSCAPE +#define CONFIG_TRIX +#define CONFIG_VMIDI +#define CONFIG_YM3812 + +#define CONFIG_AUDIO +#define CONFIG_MIDI +#define CONFIG_SEQUENCER + +#define CONFIG_AD1848 +#define CONFIG_MPU_EMU +#define CONFIG_SBDSP +#define CONFIG_UART401 + +#endif /* _SOUND_LEGACY_H */ diff -u --recursive --new-file v2.1.101/linux/drivers/sound/local.h.master linux/drivers/sound/local.h.master --- v2.1.101/linux/drivers/sound/local.h.master Wed Apr 8 19:36:27 1998 +++ linux/drivers/sound/local.h.master Wed Dec 31 16:00:00 1969 @@ -1,118 +0,0 @@ -/* Computer generated file. Please don't edit! */ - -#include - -#define KERNEL_COMPATIBLE_CONFIG - -#define SELECTED_SOUND_OPTIONS 0x00000000 - -#if \ - defined(CONFIG_PSS) || defined(CONFIG_SSCAPE) || \ - defined(CONFIG_CS4232) || defined(CONFIG_MAUI) || \ - defined(CONFIG_PSS_MODULE) || defined(CONFIG_SSCAPE_MODULE) || \ - defined(CONFIG_CS4232_MODULE) || defined(CONFIG_MAUI_MODULE) -# define CONFIG_MPU_EMU -#endif - -#if \ - defined(CONFIG_PSS) || defined(CONFIG_GUS16) || \ - defined(CONFIG_GUSMAX) || defined(CONFIG_MSS) || \ - defined(CONFIG_SSCAPE) || defined(CONFIG_TRIX) || \ - defined(CONFIG_MAD16) || defined(CONFIG_CS4232) || \ - defined(CONFIG_OPL3SA1) || \ - defined(CONFIG_PSS_MODULE) || defined(CONFIG_GUS16_MODULE) || \ - defined(CONFIG_GUSMAX_MODULE) || defined(CONFIG_MSS_MODULE) || \ - defined(CONFIG_SSCAPE_MODULE) || defined(CONFIG_TRIX_MODULE) || \ - defined(CONFIG_MAD16_MODULE) || defined(CONFIG_CS4232_MODULE) || \ - defined(CONFIG_OPL3SA1_MODULE) -# define CONFIG_AD1848 -#endif - -#if \ - defined(CONFIG_PAS) || defined(CONFIG_SB) || \ - defined(CONFIG_GUS) || defined(CONFIG_PSS) || \ - defined(CONFIG_GUS16) || defined(CONFIG_GUSMAX) || \ - defined(CONFIG_MSS) || defined(CONFIG_SSCAPE) || \ - defined(CONFIG_TRIX) || defined(CONFIG_MAD16) || \ - defined(CONFIG_CS4232) || defined(CONFIG_OPL3SA1) || \ - defined(CONFIG_SOFTOSS) || \ - defined(CONFIG_PAS_MODULE) || defined(CONFIG_SB_MODULE) || \ - defined(CONFIG_GUS_MODULE) || defined(CONFIG_PSS_MODULE) || \ - defined(CONFIG_GUS16_MODULE) || defined(CONFIG_GUSMAX_MODULE) || \ - defined(CONFIG_MSS_MODULE) || defined(CONFIG_SSCAPE_MODULE) || \ - defined(CONFIG_TRIX_MODULE) || defined(CONFIG_MAD16_MODULE) || \ - defined(CONFIG_CS4232_MODULE) || defined(CONFIG_OPL3SA1_MODULE) || \ - defined(CONFIG_SOFTOSS_MODULE) || defined(CONFIG_VIDC_SOUND) -# define CONFIG_AUDIO -#endif - -#if \ - defined(CONFIG_PAS) || defined(CONFIG_SB) || \ - defined(CONFIG_GUS) || defined(CONFIG_MPU401) || \ - defined(CONFIG_PSS) || defined(CONFIG_GUS16) || \ - defined(CONFIG_GUSMAX) || defined(CONFIG_SSCAPE) || \ - defined(CONFIG_TRIX) || defined(CONFIG_MAD16) || \ - defined(CONFIG_CS4232) || defined(CONFIG_MAUI) || \ - defined(CONFIG_OPL3SA1) || defined(CONFIG_SOFTOSS) || \ - defined(CONFIG_PAS_MODULE) || defined(CONFIG_SB_MODULE) || \ - defined(CONFIG_GUS_MODULE) || defined(CONFIG_MPU401_MODULE) || \ - defined(CONFIG_PSS_MODULE) || defined(CONFIG_GUS16_MODULE) || \ - defined(CONFIG_GUSMAX_MODULE) || defined(CONFIG_SSCAPE_MODULE) || \ - defined(CONFIG_TRIX_MODULE) || defined(CONFIG_MAD16_MODULE) || \ - defined(CONFIG_CS4232_MODULE) || defined(CONFIG_MAUI_MODULE) || \ - defined(CONFIG_OPL3SA1_MODULE) || defined(CONFIG_SOFTOSS_MODULE) -# define CONFIG_MIDI -#endif - -#if \ - defined(CONFIG_SB) || defined(CONFIG_TRIX) || \ - defined(CONFIG_MAD16) || \ - defined(CONFIG_SB_MODULE) || defined(CONFIG_TRIX_MODULE) || \ - defined(CONFIG_MAD16_MODULE) -# define CONFIG_SBDSP -#endif -#if \ - defined(CONFIG_SB_MODULE) || defined(CONFIG_TRIX_MODULE) || \ - defined(CONFIG_MAD16_MODULE) -# define CONFIG_SBDSP_MODULE -#endif - -#if \ - defined(CONFIG_SB) || defined(CONFIG_TRIX) || \ - defined(CONFIG_MAD16) || defined(CONFIG_SB_MODULE) || \ - defined(CONFIG_TRIX_MODULE) || defined(CONFIG_MAD16_MODULE) -# define CONFIG_UART401 -#endif - -#if \ - defined(CONFIG_SB_MODULE) || defined(CONFIG_TRIX_MODULE) || \ - defined(CONFIG_MAD16_MODULE) -#ifndef CONFIG_UART401_MODULE -#define CONFIG_UART401_MODULE -#endif -#endif - -#if \ - defined(CONFIG_PAS) || defined(CONFIG_SB) || \ - defined(CONFIG_ADLIB) || defined(CONFIG_GUS) || \ - defined(CONFIG_MPU401) || defined(CONFIG_PSS) || \ - defined(CONFIG_SSCAPE) || defined(CONFIG_TRIX) || \ - defined(CONFIG_MAD16) || defined(CONFIG_CS4232) || \ - defined(CONFIG_MAUI) || defined(CONFIG_OPL3SA1) || \ - defined(CONFIG_PAS_MODULE) || defined(CONFIG_SB_MODULE) || \ - defined(CONFIG_ADLIB_MODULE) || defined(CONFIG_GUS_MODULE) || \ - defined(CONFIG_MPU401_MODULE) || defined(CONFIG_PSS_MODULE) || \ - defined(CONFIG_SSCAPE_MODULE) || defined(CONFIG_TRIX_MODULE) || \ - defined(CONFIG_MAD16_MODULE) || defined(CONFIG_CS4232_MODULE) || \ - defined(CONFIG_MAUI_MODULE) || defined(CONFIG_OPL3SA1_MODULE) -# define CONFIG_SEQUENCER -#endif - -/* - * Force on additional support - */ - -#define SM_WAVE -#define __SGNXPRO__ -/* #define SM_GAMES */ -#define DESKPROXL diff -u --recursive --new-file v2.1.101/linux/drivers/sound/lowlevel/Config.tmpl linux/drivers/sound/lowlevel/Config.tmpl --- v2.1.101/linux/drivers/sound/lowlevel/Config.tmpl Tue Feb 17 13:12:47 1998 +++ linux/drivers/sound/lowlevel/Config.tmpl Wed Dec 31 16:00:00 1969 @@ -1,57 +0,0 @@ -bool 'Additional low level drivers' CONFIG_LOWLEVEL_SOUND - -if [ "$CONFIG_LOWLEVEL_SOUND" = "y" ]; then - bool 'ACI mixer (miroPCM12)' CONFIG_ACI_MIXER - bool 'AWE32 synth' CONFIG_AWE32_SYNTH - bool 'Gallant Audio Cards (SC-6000 and SC-6600 based)' CONFIG_AEDSP16 - - if [ "$CONFIG_AEDSP16" = "y" ]; then - comment 'SC-6600 Audio Cards have no jumper switches at all' - bool 'SC-6600 based audio cards (new Audio Excel DSP 16)' CONFIG_SC6600 - - if [ "$CONFIG_SB" = "y" -a "$CONFIG_AEDSP16_MSS" != "y" ]; then - bool 'Audio Excel DSP 16 (SBPro emulation)' CONFIG_AEDSP16_SBPRO - if [ "$CONFIG_AEDSP16_SBPRO" = "y" ]; then - comment 'Audio Excel DSP 16 [Sound Blaster Pro]' - hex 'I/O base for Audio Excel DSP 16 220 or 240' \ - CONFIG_AEDSP16_BASE $CONFIG_SB_BASE - int 'Audio Excel DSP 16 IRQ 5, 7, 9, 10, 11' \ - CONFIG_AEDSP16_SB_IRQ $CONFIG_SB_IRQ - int 'Audio Excel DSP 16 DMA 0, 1 or 3' CONFIG_AEDSP16_SB_DMA $CONFIG_SB_DMA - fi - fi - - if [ "$CONFIG_MSS" = "y" -a "$CONFIG_AEDSP16_SBPRO" != "y" ]; then - bool 'Audio Excel DSP 16 (MSS emulation)' CONFIG_AEDSP16_MSS - if [ "$CONFIG_AEDSP16_MSS" = "y" ]; then - comment 'Audio Excel DSP 16 [Microsoft Sound System]' - hex 'I/O base for Audio Excel DSP 16 220 or 240' CONFIG_AEDSP16_BASE 220 - int 'Audio Excel DSP 16 IRQ 5, 7, 9, 10, 11' \ - CONFIG_AEDSP16_MSS_IRQ $CONFIG_MSS_IRQ - int 'Audio Excel DSP 16 DMA 0, 1 or 3' CONFIG_AEDSP16_MSS_DMA $CONFIG_MSS_DMA - fi - fi - - if [ "$CONFIG_MPU401" = "y" ]; then - bool 'Audio Excel DSP 16 (MPU401 emulation)' CONFIG_AEDSP16_MPU401 - if [ "$CONFIG_AEDSP16_MPU401" = "y" ]; then - comment 'Audio Excel DSP 16 [MPU-401]' - if [ "$CONFIG_AEDSP16_SBPRO" != "y" \ - -a "$CONFIG_AEDSP16_MSS" != "y" ]; then - hex 'I/O base for Audio Excel DSP 16 220 or 240' CONFIG_AEDSP16_BASE 220 - fi - int 'MPU401 IRQ for Audio Excel DSP 16 5, 7, 9, 10 or 0 (disable)' \ - CONFIG_AEDSP16_MPU_IRQ $CONFIG_MPU_IRQ - fi - fi - - if [ "$CONFIG_SC6600" = "y" ]; then - comment 'SC-6600 specific configuration' - bool 'Activate SC-6600 Joystick Interface' CONFIG_SC6600_JOY - int 'SC-6600 CDROM Interface (4=None, 3=IDE, 1=Panasonic, 0=?Sony?)' \ - CONFIG_SC6600_CDROM 4 - hex 'SC-6600 CDROM Interface I/O Address' CONFIG_SC6600_CDROMBASE 0 - fi - - fi -fi diff -u --recursive --new-file v2.1.101/linux/drivers/sound/lowlevel/init.c linux/drivers/sound/lowlevel/init.c --- v2.1.101/linux/drivers/sound/lowlevel/init.c Sun Jan 4 10:40:16 1998 +++ linux/drivers/sound/lowlevel/init.c Thu May 14 10:34:02 1998 @@ -4,10 +4,9 @@ #include "lowlevel.h" #include +#include #include "../soundvers.h" -#ifdef CONFIG_LOWLEVEL_SOUND - #ifdef LOWLEVEL_MODULE char *lowlevel_version = SOUND_VERSION_STRING; #endif @@ -61,4 +60,6 @@ #endif } -#endif + +EXPORT_SYMBOL(sound_init_lowlevel_drivers); +EXPORT_SYMBOL(sound_unload_lowlevel_drivers); diff -u --recursive --new-file v2.1.101/linux/drivers/sound/mad16.c linux/drivers/sound/mad16.c --- v2.1.101/linux/drivers/sound/mad16.c Wed Apr 8 19:36:27 1998 +++ linux/drivers/sound/mad16.c Thu May 14 10:33:17 1998 @@ -74,7 +74,7 @@ #endif -#if defined(CONFIG_MAD16) || defined(MODULE) +#ifdef CONFIG_MAD16 #include "sb.h" @@ -407,11 +407,11 @@ mad_write(MC3_PORT, 0); /* Disable SB mode IRQ and DMA */ #ifdef MAD16_CDSEL if(MAD16_CDSEL & 0x20) - mad_write(MC4_PORT, 0x66); /* opl4 */ + mad_write(MC4_PORT, 0x62); /* opl4 */ else - mad_write(MC4_PORT, 0x56); /* opl3 */ + mad_write(MC4_PORT, 0x52); /* opl3 */ #else - mad_write(MC4_PORT, 0x56); + mad_write(MC4_PORT, 0x52); #endif mad_write(MC5_PORT, 0x3C); /* Init it into mode2 */ mad_write(MC6_PORT, 0x02); /* Enable WSS, Disable MPU and SB */ diff -u --recursive --new-file v2.1.101/linux/drivers/sound/maui.c linux/drivers/sound/maui.c --- v2.1.101/linux/drivers/sound/maui.c Wed Apr 8 19:36:27 1998 +++ linux/drivers/sound/maui.c Thu May 14 10:33:17 1998 @@ -29,7 +29,7 @@ #include "soundmodule.h" #include "sound_firmware.h" -#if defined(CONFIG_MAUI) || defined(MODULE) +#ifdef CONFIG_MAUI static int maui_base = 0x330; @@ -50,7 +50,7 @@ static int (*orig_load_patch) (int dev, int format, const char *addr, int offs, int count, int pmgr_flag) = NULL; -#ifdef CONFIG_MAUI_HAVE_BOOT +#ifdef HAVE_MAUI_BOOT #include "maui_boot.h" #else static unsigned char *maui_os = NULL; diff -u --recursive --new-file v2.1.101/linux/drivers/sound/midi_syms.c linux/drivers/sound/midi_syms.c --- v2.1.101/linux/drivers/sound/midi_syms.c Wed Dec 31 16:00:00 1969 +++ linux/drivers/sound/midi_syms.c Thu May 14 10:33:17 1998 @@ -0,0 +1,31 @@ +/* + * Exported symbols for midi driver. + * __NO_VERSION__ because this is still part of sound.o. + */ + +#define __NO_VERSION__ +#include + +char midi_syms_symbol; + +#include "sound_config.h" +#define _MIDI_SYNTH_C_ +#include "midi_synth.h" + +EXPORT_SYMBOL(do_midi_msg); +EXPORT_SYMBOL(midi_synth_open); +EXPORT_SYMBOL(midi_synth_close); +EXPORT_SYMBOL(midi_synth_ioctl); +EXPORT_SYMBOL(midi_synth_kill_note); +EXPORT_SYMBOL(midi_synth_start_note); +EXPORT_SYMBOL(midi_synth_set_instr); +EXPORT_SYMBOL(midi_synth_reset); +EXPORT_SYMBOL(midi_synth_hw_control); +EXPORT_SYMBOL(midi_synth_aftertouch); +EXPORT_SYMBOL(midi_synth_controller); +EXPORT_SYMBOL(midi_synth_panning); +EXPORT_SYMBOL(midi_synth_setup_voice); +EXPORT_SYMBOL(midi_synth_send_sysex); +EXPORT_SYMBOL(midi_synth_bender); +EXPORT_SYMBOL(midi_synth_load_patch); +EXPORT_SYMBOL(MIDIbuf_avail); diff -u --recursive --new-file v2.1.101/linux/drivers/sound/midi_synth.c linux/drivers/sound/midi_synth.c --- v2.1.101/linux/drivers/sound/midi_synth.c Mon Feb 23 18:12:09 1998 +++ linux/drivers/sound/midi_synth.c Thu May 14 10:33:17 1998 @@ -20,7 +20,7 @@ #include "sound_config.h" -#if defined(CONFIG_MIDI) || defined (MODULE) +#ifdef CONFIG_MIDI #define _MIDI_SYNTH_C_ @@ -31,7 +31,7 @@ {0}; static unsigned char prev_out_status[MAX_MIDI_DEV]; -#if !defined(CONFIG_SEQUENCER) && !defined(MODULE) +#ifndef CONFIG_SEQUENCER #define STORE(cmd) #else #define STORE(cmd) \ diff -u --recursive --new-file v2.1.101/linux/drivers/sound/midibuf.c linux/drivers/sound/midibuf.c --- v2.1.101/linux/drivers/sound/midibuf.c Wed Apr 8 19:36:27 1998 +++ linux/drivers/sound/midibuf.c Thu May 14 10:33:17 1998 @@ -411,6 +411,11 @@ void MIDIbuf_init(void) { + /* drag in midi_syms.o */ + { + extern char midi_syms_symbol; + midi_syms_symbol = 0; + } } int MIDIbuf_avail(int dev) diff -u --recursive --new-file v2.1.101/linux/drivers/sound/mpu401.c linux/drivers/sound/mpu401.c --- v2.1.101/linux/drivers/sound/mpu401.c Tue Mar 17 22:18:15 1998 +++ linux/drivers/sound/mpu401.c Thu May 14 10:33:17 1998 @@ -24,11 +24,11 @@ #include "sound_config.h" #include "soundmodule.h" -#if (defined(CONFIG_MPU401) || defined(CONFIG_MPU_EMU)) && defined(CONFIG_MIDI) || defined(MODULE) +#if (defined(CONFIG_MPU401) || defined(CONFIG_MPU_EMU)) && defined(CONFIG_MIDI) #include "coproc.h" -#if defined(CONFIG_SEQUENCER) || defined(MODULE) +#ifdef CONFIG_SEQUENCER static int timer_mode = TMR_INTERNAL, timer_caps = TMR_INTERNAL; #endif @@ -159,7 +159,7 @@ 0 /* Fx */ }; -#if !defined(CONFIG_SEQUENCER) && !defined(MODULE) +#ifndef CONFIG_SEQUENCER #define STORE(cmd) #else #define STORE(cmd) \ @@ -1216,7 +1216,7 @@ * Timer stuff ****************************************************/ -#if defined(CONFIG_SEQUENCER) || defined(MODULE) +#if defined(CONFIG_SEQUENCER) static volatile int timer_initialized = 0, timer_open = 0, tmr_running = 0; static volatile int curr_tempo, curr_timebase, hw_timebase; diff -u --recursive --new-file v2.1.101/linux/drivers/sound/opl3.c linux/drivers/sound/opl3.c --- v2.1.101/linux/drivers/sound/opl3.c Tue Mar 17 22:18:15 1998 +++ linux/drivers/sound/opl3.c Thu May 14 10:33:17 1998 @@ -32,7 +32,7 @@ #include "sound_config.h" #include "soundmodule.h" -#if defined(CONFIG_YM3812) || defined(MODULE) +#ifdef CONFIG_YM3812 #include "opl3.h" @@ -1209,11 +1209,10 @@ SOUND_LOCK_END; } -#else - -#endif #endif EXPORT_SYMBOL(opl3_init); EXPORT_SYMBOL(opl3_detect); MODULE_PARM(io, "i"); + +#endif diff -u --recursive --new-file v2.1.101/linux/drivers/sound/opl3sa.c linux/drivers/sound/opl3sa.c --- v2.1.101/linux/drivers/sound/opl3sa.c Wed Apr 8 19:36:27 1998 +++ linux/drivers/sound/opl3sa.c Thu May 14 10:33:17 1998 @@ -1,5 +1,5 @@ /* - * sound/Xopl3sa.c + * sound/opl3sa.c * * Low level driver for Yamaha YMF701B aka OPL3-SA chip * @@ -19,10 +19,12 @@ */ #include +#include #undef SB_OK #include "sound_config.h" +#include "soundmodule.h" #ifdef SB_OK #include "sb.h" static int sb_initialized = 0; @@ -293,6 +295,7 @@ struct address_info cfg; struct address_info mpu_cfg; +static int found_mpu; int init_module(void) { @@ -312,7 +315,7 @@ if (probe_opl3sa_wss(&cfg) == 0) return -ENODEV; - found_mpu=probe_opl3_mpu(&mpu_cfg); + found_mpu=probe_opl3sa_mpu(&mpu_cfg); attach_opl3sa_wss(&cfg); if(found_mpu) @@ -325,7 +328,7 @@ { if(found_mpu) unload_opl3sa_mpu(&mpu_cfg); - unload_opl3sa(&cfg); + unload_opl3sa_wss(&cfg); SOUND_LOCK_END; } diff -u --recursive --new-file v2.1.101/linux/drivers/sound/pas2_card.c linux/drivers/sound/pas2_card.c --- v2.1.101/linux/drivers/sound/pas2_card.c Tue Apr 14 14:29:24 1998 +++ linux/drivers/sound/pas2_card.c Thu May 14 10:33:17 1998 @@ -9,7 +9,7 @@ #include "sound_config.h" #include "soundmodule.h" -#if defined(CONFIG_PAS) || defined(MODULE) +#ifdef CONFIG_PAS static unsigned char dma_bits[] = { 4, 1, 2, 3, 0, 5, 6, 7 @@ -89,7 +89,7 @@ } if (status & 0x10) { -#if defined(CONFIG_MIDI) +#ifdef CONFIG_MIDI pas_midi_interrupt(); #endif status &= ~0x10; @@ -219,7 +219,7 @@ mix_write(0x80 | 5, 0x078B); mix_write(5, 0x078B); -#if !defined(DISABLE_SB_EMULATION) && (defined(CONFIG_SB) || defined(CONFIG_SB_MODULE)) +#if !defined(DISABLE_SB_EMULATION) && defined(CONFIG_SB) { struct address_info *sb_config; @@ -322,7 +322,7 @@ if ((pas_model = pas_read(0xFF88))) { - char temp[100]; + char temp[100]; sprintf(temp, "%s rev %d", pas_model_names[(int) pas_model], @@ -335,12 +335,12 @@ pas_pcm_init(hw_config); #endif -#if !defined(DISABLE_SB_EMULATION) && (defined(CONFIG_SB) || defined(CONFIG_SB_MODULE)) +#if !defined(DISABLE_SB_EMULATION) && defined(CONFIG_SB) sb_dsp_disable_midi(pas_sb_base); /* No MIDI capability */ #endif -#if defined(CONFIG_MIDI) +#ifdef CONFIG_MIDI pas_midi_init(); #endif pas_init_mixer(); diff -u --recursive --new-file v2.1.101/linux/drivers/sound/pas2_midi.c linux/drivers/sound/pas2_midi.c --- v2.1.101/linux/drivers/sound/pas2_midi.c Tue Dec 30 10:59:17 1997 +++ linux/drivers/sound/pas2_midi.c Thu May 14 10:33:17 1998 @@ -15,7 +15,8 @@ #include "sound_config.h" -#if ( defined(MODULE) || defined(CONFIG_PAS) ) && defined(CONFIG_MIDI) +#ifdef CONFIG_PAS +#ifdef CONFIG_MIDI static int midi_busy = 0, input_opened = 0; static int my_dev; @@ -274,4 +275,5 @@ pas_write(stat, 0x1B88); /* Acknowledge interrupts */ } +#endif #endif diff -u --recursive --new-file v2.1.101/linux/drivers/sound/pas2_mixer.c linux/drivers/sound/pas2_mixer.c --- v2.1.101/linux/drivers/sound/pas2_mixer.c Mon Jan 5 09:50:22 1998 +++ linux/drivers/sound/pas2_mixer.c Thu May 14 10:33:17 1998 @@ -19,7 +19,7 @@ #include "sound_config.h" -#if defined(CONFIG_PAS) || defined(MODULE) +#ifdef CONFIG_PAS #ifndef DEB #define DEB(what) /* (what) */ diff -u --recursive --new-file v2.1.101/linux/drivers/sound/pas2_pcm.c linux/drivers/sound/pas2_pcm.c --- v2.1.101/linux/drivers/sound/pas2_pcm.c Tue Dec 30 11:02:39 1997 +++ linux/drivers/sound/pas2_pcm.c Thu May 14 10:33:17 1998 @@ -15,7 +15,8 @@ #include "sound_config.h" -#if defined(MODULE) || ( defined(CONFIG_PAS) && defined(CONFIG_AUDIO) ) +#ifdef CONFIG_PAS +#ifdef CONFIG_AUDIO #ifndef DEB #define DEB(WHAT) @@ -458,4 +459,5 @@ } } +#endif #endif diff -u --recursive --new-file v2.1.101/linux/drivers/sound/pss.c linux/drivers/sound/pss.c --- v2.1.101/linux/drivers/sound/pss.c Wed Apr 8 19:36:27 1998 +++ linux/drivers/sound/pss.c Thu May 14 10:33:17 1998 @@ -32,7 +32,8 @@ #include "sound_firmware.h" #include "soundmodule.h" -#if (defined(CONFIG_PSS) && defined(CONFIG_AUDIO))||defined(MODULE) +#ifdef CONFIG_PSS +#ifdef CONFIG_AUDIO /* * PSS registers. @@ -80,11 +81,12 @@ #include "coproc.h" -#ifdef CONFIG_PSS_HAVE_BOOT +#ifdef PSS_HAVE_LD #include "pss_boot.h" #else -static unsigned char *pss_synth = NULL; static int pss_synthLen = 0; +static unsigned char *pss_synth = +NULL; #endif unsigned char pss_mixer = 1; @@ -1120,5 +1122,6 @@ unload_pss(&cfgpss); SOUND_LOCK_END; } +#endif #endif #endif diff -u --recursive --new-file v2.1.101/linux/drivers/sound/sb.h linux/drivers/sound/sb.h --- v2.1.101/linux/drivers/sound/sb.h Wed Apr 8 19:36:27 1998 +++ linux/drivers/sound/sb.h Thu May 14 10:33:17 1998 @@ -1,4 +1,5 @@ #include +#include "legacy.h" #ifdef CONFIG_SBDSP #define DSP_RESET (devc->base + 0x6) @@ -112,6 +113,7 @@ int input_opened; int midi_broken; void (*midi_input_intr) (int dev, unsigned char data); + void *midi_irq_cookie; /* IRQ cookie for the midi */ } sb_devc; int sb_dsp_command (sb_devc *devc, unsigned char val); @@ -131,4 +133,5 @@ int ess_read (sb_devc *devc, unsigned char reg); extern int acer; +extern sb_devc *last_sb; #endif diff -u --recursive --new-file v2.1.101/linux/drivers/sound/sb_audio.c linux/drivers/sound/sb_audio.c --- v2.1.101/linux/drivers/sound/sb_audio.c Wed Apr 8 19:36:27 1998 +++ linux/drivers/sound/sb_audio.c Thu May 14 10:33:17 1998 @@ -20,7 +20,7 @@ #include #include "sound_config.h" -#if defined(CONFIG_SBDSP) || defined(MODULE) +#ifdef CONFIG_SBDSP #include "sb_mixer.h" #include "sb.h" diff -u --recursive --new-file v2.1.101/linux/drivers/sound/sb_card.c linux/drivers/sound/sb_card.c --- v2.1.101/linux/drivers/sound/sb_card.c Wed Apr 8 19:36:27 1998 +++ linux/drivers/sound/sb_card.c Thu May 14 10:33:17 1998 @@ -17,7 +17,7 @@ #include "sound_config.h" #include "soundmodule.h" -#if defined(CONFIG_SBDSP) || defined (MODULE) +#ifdef CONFIG_SBDSP #include "sb_mixer.h" #include "sb.h" @@ -142,7 +142,6 @@ int acer = 0; #endif #endif -#endif EXPORT_SYMBOL(sb_dsp_init); EXPORT_SYMBOL(sb_dsp_detect); @@ -152,3 +151,5 @@ EXPORT_SYMBOL(probe_sb); EXPORT_SYMBOL(unload_sb); EXPORT_SYMBOL(sb_be_quiet); + +#endif diff -u --recursive --new-file v2.1.101/linux/drivers/sound/sb_common.c linux/drivers/sound/sb_common.c --- v2.1.101/linux/drivers/sound/sb_common.c Wed Apr 8 19:36:27 1998 +++ linux/drivers/sound/sb_common.c Thu May 14 10:33:17 1998 @@ -18,7 +18,7 @@ #include "sound_config.h" #include "sound_firmware.h" -#if defined(CONFIG_SBDSP) || defined(MODULE) +#ifdef CONFIG_SBDSP #ifndef CONFIG_AUDIO #error You will need to configure the sound driver with CONFIG_AUDIO option. @@ -57,6 +57,7 @@ #endif +sb_devc *last_sb = NULL; /* Last sb loaded */ int sb_dsp_command(sb_devc * devc, unsigned char val) { @@ -131,9 +132,9 @@ { src = sb_getmixer(devc, IRQ_STAT); /* Interrupt source register */ -#if defined(CONFIG_MIDI)&& (defined(CONFIG_UART401)||defined(CONFIG_UART401_MODULE)) +#if defined(CONFIG_MIDI)&& defined(CONFIG_UART401) if (src & 4) - uart401intr(devc->irq, NULL, NULL); /* MPU401 interrupt */ + uart401intr(devc->irq, devc->midi_irq_cookie, NULL); /* MPU401 interrupt */ #endif if (!(src & 3)) @@ -155,7 +156,7 @@ break; case IMODE_MIDI: -#if defined(CONFIG_MIDI) +#ifdef CONFIG_MIDI sb_midi_interrupt(devc); #endif break; @@ -790,6 +791,8 @@ } /* IRQ setup */ request_region(hw_config->io_base, 16, "soundblaster"); + last_sb = devc; + switch (devc->major) { case 1: /* SB 1.0 or 1.5 */ @@ -851,7 +854,7 @@ if (devc->major == 3 || devc->major == 4) sb_mixer_init(devc); -#if defined(CONFIG_MIDI) +#ifdef CONFIG_MIDI if (!(devc->caps & SB_NO_MIDI)) sb_dsp_midi_init(devc); #endif @@ -936,7 +939,9 @@ { free_irq(devc->irq, devc); sound_unload_mixerdev(devc->my_mixerdev); - sound_unload_mididev(devc->my_mididev); + /* We don't have to do this bit any more the UART401 is its own + master -- Krzystof Halasa */ + /* sound_unload_mididev(devc->my_mididev); */ sound_unload_audiodev(devc->my_dev); } kfree(devc); @@ -982,7 +987,7 @@ return val; } -#if defined(CONFIG_MIDI) +#ifdef CONFIG_MIDI /* * MPU401 MIDI initialization. @@ -1247,14 +1252,15 @@ void attach_sbmpu(struct address_info *hw_config) { -#if defined(CONFIG_MIDI) && (defined(CONFIG_UART401)||defined(CONFIG_UART401_MODULE)) +#if defined(CONFIG_MIDI) && defined(CONFIG_UART401) attach_uart401(hw_config); + last_sb->midi_irq_cookie=midi_devs[hw_config->slots[4]]; #endif } int probe_sbmpu(struct address_info *hw_config) { -#if defined(CONFIG_MIDI) && (defined(CONFIG_UART401)||defined(CONFIG_UART401_MODULE)) +#if defined(CONFIG_MIDI) && defined(CONFIG_UART401) sb_devc *devc = last_devc; if (last_devc == NULL) @@ -1312,7 +1318,7 @@ void unload_sbmpu(struct address_info *hw_config) { -#if defined(CONFIG_MIDI) && (defined(CONFIG_UART401)||defined(CONFIG_UART401_MODULE)) +#if defined(CONFIG_MIDI) && defined(CONFIG_UART401) unload_uart401(hw_config); #endif } diff -u --recursive --new-file v2.1.101/linux/drivers/sound/sb_mixer.c linux/drivers/sound/sb_mixer.c --- v2.1.101/linux/drivers/sound/sb_mixer.c Wed Apr 8 19:36:27 1998 +++ linux/drivers/sound/sb_mixer.c Thu May 14 10:33:17 1998 @@ -18,7 +18,7 @@ #include #include "sound_config.h" -#if defined(CONFIG_SBDSP) || defined(MODULE) +#ifdef CONFIG_SBDSP #define __SB_MIXER_C__ #include "sb.h" diff -u --recursive --new-file v2.1.101/linux/drivers/sound/sb_mixer.h linux/drivers/sound/sb_mixer.h --- v2.1.101/linux/drivers/sound/sb_mixer.h Wed Apr 8 19:36:27 1998 +++ linux/drivers/sound/sb_mixer.h Thu May 14 10:33:17 1998 @@ -18,6 +18,7 @@ * */ #include +#include "legacy.h" #ifdef CONFIG_SBDSP diff -u --recursive --new-file v2.1.101/linux/drivers/sound/sequencer.c linux/drivers/sound/sequencer.c --- v2.1.101/linux/drivers/sound/sequencer.c Wed Apr 8 19:36:27 1998 +++ linux/drivers/sound/sequencer.c Thu May 14 10:33:17 1998 @@ -24,7 +24,7 @@ #define SEQUENCER_C #include "sound_config.h" -#if defined(CONFIG_SEQUENCER) || defined(MODULE) +#ifdef CONFIG_SEQUENCER #include "softoss.h" int (*softsynthp) (int cmd, int parm1, int parm2, unsigned long parm3) = NULL; @@ -1694,6 +1694,12 @@ void sequencer_init(void) { + /* drag in sequencer_syms.o */ + { + extern char sequencer_syms_symbol; + sequencer_syms_symbol = 0; + } + if (sequencer_ok) return; #ifdef CONFIG_MIDI diff -u --recursive --new-file v2.1.101/linux/drivers/sound/sequencer_syms.c linux/drivers/sound/sequencer_syms.c --- v2.1.101/linux/drivers/sound/sequencer_syms.c Wed Dec 31 16:00:00 1969 +++ linux/drivers/sound/sequencer_syms.c Thu May 14 10:33:17 1998 @@ -0,0 +1,37 @@ +/* + * Exported symbols for sequencer driver. + * __NO_VERSION__ because this is still part of sound.o. + */ + +#define __NO_VERSION__ +#include + +char sequencer_syms_symbol; + +#include "sound_config.h" + +#include "sound_calls.h" + +EXPORT_SYMBOL(note_to_freq); +EXPORT_SYMBOL(compute_finetune); +EXPORT_SYMBOL(seq_copy_to_input); +EXPORT_SYMBOL(seq_input_event); +EXPORT_SYMBOL(sequencer_init); +EXPORT_SYMBOL(sequencer_timer); + +EXPORT_SYMBOL(sound_timer_init); +EXPORT_SYMBOL(sound_timer_interrupt); +EXPORT_SYMBOL(sound_timer_syncinterval); +EXPORT_SYMBOL(reprogram_timer); + +#include "softoss.h" + +EXPORT_SYMBOL(softsynthp); + +/* Tuning */ + +#define _SEQUENCER_C_ +#include "tuning.h" + +EXPORT_SYMBOL(cent_tuning); +EXPORT_SYMBOL(semitone_tuning); diff -u --recursive --new-file v2.1.101/linux/drivers/sound/sgalaxy.c linux/drivers/sound/sgalaxy.c --- v2.1.101/linux/drivers/sound/sgalaxy.c Wed Dec 31 16:00:00 1969 +++ linux/drivers/sound/sgalaxy.c Thu May 14 10:33:17 1998 @@ -0,0 +1,188 @@ +/* + * sound/sgalaxy.c + * + * Low level driver for Aztech Sound Galaxy cards. + * Copyright 1998 Artur Skawina + * + * Supported cards: + * Aztech Sound Galaxy Waverider Pro 32 - 3D + * Aztech Sound Galaxy Washington 16 + * + * Based on cs4232.c by Hannu Savolainen and Alan Cox. + */ +/* + * Copyright (C) by Hannu Savolainen 1993-1997 + * + * OSS/Free for Linux is distributed under the GNU GENERAL PUBLIC LICENSE (GPL) + * Version 2 (June 1991). See the "COPYING" file distributed with this software + * for more info. + */ + +#include +#include + +#include "sound_config.h" +#include "soundmodule.h" + +#if defined(CONFIG_SGALAXY) || defined (MODULE) + +static void sleep( unsigned howlong ) +{ + current->state = TASK_INTERRUPTIBLE; + current->timeout = jiffies + howlong; + schedule(); + current->timeout = 0; +} + +#define DPORT 0x80 + +/* Sound Blaster regs */ + +#define SBDSP_RESET 0x6 +#define SBDSP_READ 0xA +#define SBDSP_COMMAND 0xC +#define SBDSP_STATUS SBDSP_COMMAND +#define SBDSP_DATA_AVAIL 0xE + +static int sb_rst(int base) +{ + int i; + + outb( 1, base+SBDSP_RESET ); /* reset the DSP */ + outb( 0, base+SBDSP_RESET ); + + for ( i=0; i<500; i++ ) /* delay */ + inb(DPORT); + + for ( i=0; i<100000; i++ ) + { + if ( inb( base+SBDSP_DATA_AVAIL )&0x80 ) + break; + } + + if ( inb( base+SBDSP_READ )!=0xAA ) + return 0; + + return 1; +} + +static int sb_cmd( int base, unsigned char val ) +{ + int i; + + for ( i=100000; i; i-- ) + { + if ( (inb( base+SBDSP_STATUS )&0x80)==0 ) + { + outb( val, base+SBDSP_COMMAND ); + break; + } + } + return i; /* i>0 == success */ +} + + +#define ai_sgbase driver_use_1 + +int probe_sgalaxy( struct address_info *ai ) +{ + if ( check_region( ai->io_base, 8 ) ) + { + printk(KERN_ERR "sgalaxy: WSS IO port 0x%03x not available\n", ai->io_base); + return 0; + } + + if ( ad1848_detect( ai->io_base+4, NULL, ai->osp ) ) + return 1; /* The card is already active */ + + if ( check_region( ai->ai_sgbase, 0x10 ) ) + { + printk(KERN_ERR "sgalaxy: SB IO port 0x%03x not available\n", ai->ai_sgbase); + return 0; + } + + /* switch to MSS/WSS mode */ + + sb_rst( ai->ai_sgbase ); + + sb_cmd( ai->ai_sgbase, 9 ); + sb_cmd( ai->ai_sgbase, 0 ); + + sleep( HZ/10 ); + + if ( ad1848_detect( ai->io_base+4, NULL, ai->osp ) ) + return 1; + return 0; +} + +void attach_sgalaxy( struct address_info *ai ) +{ + int n; + + request_region( ai->ai_sgbase, 0x10, "SoundGalaxy SB" ); + + n=attach_ms_sound( ai ); + if (n!=-1 && audio_devs[n]->mixer_dev != -1 ) + { + AD1848_REROUTE( SOUND_MIXER_LINE1, SOUND_MIXER_LINE ); /* Line-in */ + AD1848_REROUTE( SOUND_MIXER_LINE2, SOUND_MIXER_SYNTH ); /* FM+Wavetable*/ + AD1848_REROUTE( SOUND_MIXER_LINE3, SOUND_MIXER_CD ); /* CD */ + } +} + +void unload_sgalaxy( struct address_info *ai ) +{ + unload_ms_sound( ai ); + release_region( ai->ai_sgbase, 0x10 ); +} + +#ifdef MODULE + +int io = -1; +int irq = -1; +int dma = -1; +int dma2 = -1; +int sgbase = -1; + +MODULE_PARM(io,"i"); +MODULE_PARM(irq,"i"); +MODULE_PARM(dma,"i"); +MODULE_PARM(dma2,"i"); +MODULE_PARM(sgbase,"i"); + +EXPORT_NO_SYMBOLS; + +struct address_info ai; + + +int init_module(void) +{ + if ( io==-1 || irq==-1 || dma==-1 || sgbase==-1 ) + { + printk(KERN_ERR "sgalaxy: io, irq, dma and sgbase must be set.\n"); + return -EINVAL; + } + + ai.io_base = io; + ai.irq = irq; + ai.dma = dma; + ai.dma2 = dma2; + ai.ai_sgbase = sgbase; + + if ( probe_sgalaxy( &ai )==0 ) + return -ENODEV; + + attach_sgalaxy( &ai ); + + SOUND_LOCK; + return 0; +} + +void cleanup_module(void) +{ + unload_sgalaxy( &ai ); + SOUND_LOCK_END; +} + +#endif +#endif diff -u --recursive --new-file v2.1.101/linux/drivers/sound/softoss.c linux/drivers/sound/softoss.c --- v2.1.101/linux/drivers/sound/softoss.c Wed Apr 8 19:36:27 1998 +++ linux/drivers/sound/softoss.c Thu May 14 10:33:17 1998 @@ -31,7 +31,7 @@ #include "sound_config.h" #include "soundmodule.h" -#if defined(CONFIG_SOFTOSS) || defined(MODULE) +#ifdef CONFIG_SOFTOSS #include "softoss.h" #include diff -u --recursive --new-file v2.1.101/linux/drivers/sound/softoss_rs.c linux/drivers/sound/softoss_rs.c --- v2.1.101/linux/drivers/sound/softoss_rs.c Wed Apr 8 19:36:27 1998 +++ linux/drivers/sound/softoss_rs.c Thu May 14 10:33:17 1998 @@ -18,7 +18,7 @@ #include "sound_config.h" -#if defined(CONFIG_SOFTOSS) || defined(MODULE) +#ifdef CONFIG_SOFTOSS #include "softoss.h" void softsynth_resample_loop(short *buf, int loops) diff -u --recursive --new-file v2.1.101/linux/drivers/sound/sound_config.h linux/drivers/sound/sound_config.h --- v2.1.101/linux/drivers/sound/sound_config.h Mon Feb 23 18:12:09 1998 +++ linux/drivers/sound/sound_config.h Thu May 14 10:33:17 1998 @@ -10,14 +10,18 @@ * for more info. */ -#include -#include "local.h.master" + +#ifndef _SOUND_CONFIG_H_ +#define _SOUND_CONFIG_H_ + #include +#include + +#include "legacy.h" #include "os.h" #include "soundvers.h" - #ifndef SND_DEFAULT_ENABLE #define SND_DEFAULT_ENABLE 1 #endif @@ -181,3 +185,5 @@ #define TIMER_ARMED 121234 #define TIMER_NOT_ARMED 1 + +#endif diff -u --recursive --new-file v2.1.101/linux/drivers/sound/sound_syms.c linux/drivers/sound/sound_syms.c --- v2.1.101/linux/drivers/sound/sound_syms.c Thu May 7 22:51:51 1998 +++ linux/drivers/sound/sound_syms.c Thu May 14 10:33:17 1998 @@ -7,28 +7,22 @@ #include #include "sound_config.h" -#define _MIDI_SYNTH_C_ -#include "midi_synth.h" -#define _SEQUENCER_C_ -#include "tuning.h" -#include -#include "sound_firmware.h" - -extern struct notifier_block *sound_locker; -extern void sound_notifier_chain_register(struct notifier_block *); +#include "sound_calls.h" +char sound_syms_symbol; EXPORT_SYMBOL(mixer_devs); EXPORT_SYMBOL(audio_devs); EXPORT_SYMBOL(num_mixers); EXPORT_SYMBOL(num_audiodevs); -EXPORT_SYMBOL(note_to_freq); -EXPORT_SYMBOL(compute_finetune); -EXPORT_SYMBOL(seq_copy_to_input); -EXPORT_SYMBOL(seq_input_event); -EXPORT_SYMBOL(sequencer_init); -EXPORT_SYMBOL(sequencer_timer); +EXPORT_SYMBOL(midi_devs); +EXPORT_SYMBOL(num_midis); +EXPORT_SYMBOL(synth_devs); +EXPORT_SYMBOL(num_synths); + +EXPORT_SYMBOL(sound_timer_devs); +EXPORT_SYMBOL(num_sound_timers); EXPORT_SYMBOL(sound_install_audiodrv); EXPORT_SYMBOL(sound_install_mixer); @@ -49,56 +43,19 @@ EXPORT_SYMBOL(load_mixer_volumes); -EXPORT_SYMBOL(DMAbuf_start_dma); -EXPORT_SYMBOL(DMAbuf_open_dma); -EXPORT_SYMBOL(DMAbuf_close_dma); -EXPORT_SYMBOL(DMAbuf_inputintr); -EXPORT_SYMBOL(DMAbuf_outputintr); -EXPORT_SYMBOL(dma_ioctl); - EXPORT_SYMBOL(conf_printf); EXPORT_SYMBOL(conf_printf2); -EXPORT_SYMBOL(sound_timer_init); -EXPORT_SYMBOL(sound_timer_interrupt); -EXPORT_SYMBOL(sound_timer_syncinterval); -EXPORT_SYMBOL(sound_timer_devs); +#include "sound_firmware.h" +EXPORT_SYMBOL(mod_firmware_load); + +extern int softoss_dev; +EXPORT_SYMBOL(softoss_dev); /* Locking */ +#include "soundmodule.h" EXPORT_SYMBOL(sound_locker); EXPORT_SYMBOL(sound_notifier_chain_register); - -/* MIDI symbols */ -EXPORT_SYMBOL(midi_devs); -EXPORT_SYMBOL(num_midis); -EXPORT_SYMBOL(synth_devs); -EXPORT_SYMBOL(num_synths); - -EXPORT_SYMBOL(do_midi_msg); -EXPORT_SYMBOL(midi_synth_open); -EXPORT_SYMBOL(midi_synth_close); -EXPORT_SYMBOL(midi_synth_ioctl); -EXPORT_SYMBOL(midi_synth_kill_note); -EXPORT_SYMBOL(midi_synth_start_note); -EXPORT_SYMBOL(midi_synth_set_instr); -EXPORT_SYMBOL(midi_synth_reset); -EXPORT_SYMBOL(midi_synth_hw_control); -EXPORT_SYMBOL(midi_synth_aftertouch); -EXPORT_SYMBOL(midi_synth_controller); -EXPORT_SYMBOL(midi_synth_panning); -EXPORT_SYMBOL(midi_synth_setup_voice); -EXPORT_SYMBOL(midi_synth_send_sysex); -EXPORT_SYMBOL(midi_synth_bender); -EXPORT_SYMBOL(midi_synth_load_patch); - -/* Firmware */ - -EXPORT_SYMBOL(mod_firmware_load); - -/* Tuning */ - -EXPORT_SYMBOL(cent_tuning); -EXPORT_SYMBOL(semitone_tuning); MODULE_DESCRIPTION("Sound subsystem"); MODULE_AUTHOR("Hannu Savolainen, et al."); diff -u --recursive --new-file v2.1.101/linux/drivers/sound/sound_timer.c linux/drivers/sound/sound_timer.c --- v2.1.101/linux/drivers/sound/sound_timer.c Tue Mar 17 22:18:15 1998 +++ linux/drivers/sound/sound_timer.c Thu May 14 10:33:17 1998 @@ -16,7 +16,7 @@ #include "sound_config.h" -#if defined(CONFIG_SEQUENCER) || defined(CONFIG_SEQUENCER_MODULE) +#if defined(CONFIG_SEQUENCER) static volatile int initialized = 0, opened = 0, tmr_running = 0; static volatile time_t tmr_offs, tmr_ctr; diff -u --recursive --new-file v2.1.101/linux/drivers/sound/soundcard.c linux/drivers/sound/soundcard.c --- v2.1.101/linux/drivers/sound/soundcard.c Wed Apr 8 19:36:27 1998 +++ linux/drivers/sound/soundcard.c Thu May 14 10:33:17 1998 @@ -38,11 +38,12 @@ #include #include -#define SOUND_CORE - #include "soundmodule.h" +struct notifier_block *sound_locker=(struct notifier_block *)0; +static int lock_depth = 0; #include + #ifdef MODULE #define modular 1 #else @@ -486,9 +487,12 @@ return -ENXIO; } in_use++; -#ifdef MODULE - SOUND_INC_USE_COUNT; + +#ifdef CONFIG_MODULES + notifier_call_chain(&sound_locker, 1, 0); + lock_depth++; #endif + return 0; } @@ -527,9 +531,12 @@ printk(KERN_ERR "Sound error: Releasing unknown device 0x%02x\n", dev); } in_use--; -#ifdef MODULE - SOUND_DEC_USE_COUNT; + +#ifdef CONFIG_MODULES + notifier_call_chain(&sound_locker, 0, 0); + lock_depth--; #endif + return 0; } @@ -662,18 +669,18 @@ DEB(printk("sound_poll(dev=%d)\n", dev)); switch (dev & 0x0f) { -#if defined(CONFIG_SEQUENCER) || defined(MODULE) +#ifdef CONFIG_SEQUENCER case SND_DEV_SEQ: case SND_DEV_SEQ2: return sequencer_poll(dev, file, wait); #endif -#if defined(CONFIG_MIDI) +#ifdef CONFIG_MIDI case SND_DEV_MIDIN: return MIDIbuf_poll(dev, file, wait); #endif -#if defined(CONFIG_AUDIO) || defined(MODULE) +#ifdef CONFIG_AUDIO case SND_DEV_DSP: case SND_DEV_DSP16: case SND_DEV_AUDIO: @@ -770,6 +777,12 @@ #endif soundcard_init(void) { + /* drag in sound_syms.o */ + { + extern char sound_syms_symbol; + sound_syms_symbol = 0; + } + #ifndef MODULE register_chrdev(sound_major, "sound", &sound_fops); chrdev_registered = 1; @@ -785,7 +798,7 @@ return; /* No cards detected */ #endif -#if defined(CONFIG_AUDIO) +#ifdef CONFIG_AUDIO if (num_audiodevs || modular) /* Audio devices present */ { audio_init_devices(); @@ -799,6 +812,8 @@ 0 }; +#ifdef MODULE + int init_module(void) { int err; @@ -833,9 +848,6 @@ return 0; } -#ifdef MODULE - - void cleanup_module(void) { int i; @@ -849,7 +861,7 @@ if (chrdev_registered) unregister_chrdev(sound_major, "sound"); -#if defined(CONFIG_SEQUENCER) || defined(MODULE) +#ifdef CONFIG_SEQUENCER sound_stop_timer(); #endif @@ -942,7 +954,7 @@ restore_flags(flags); } -#if defined(CONFIG_SEQUENCER) || defined(MODULE) +#ifdef CONFIG_SEQUENCER static void do_sequencer_timer(unsigned long dummy) { @@ -1022,12 +1034,6 @@ * Module and lock management */ -struct notifier_block *sound_locker=(struct notifier_block *)0; -static int lock_depth = 0; - -#define SOUND_INC_USE_COUNT do { notifier_call_chain(&sound_locker, 1, 0); lock_depth++; } while(0); -#define SOUND_DEC_USE_COUNT do { notifier_call_chain(&sound_locker, 0, 0); lock_depth--; } while(0); - /* * When a sound module is registered we need to bring it to the current * lock level... diff -u --recursive --new-file v2.1.101/linux/drivers/sound/soundmodule.h linux/drivers/sound/soundmodule.h --- v2.1.101/linux/drivers/sound/soundmodule.h Sun Jan 4 10:45:55 1998 +++ linux/drivers/sound/soundmodule.h Thu May 14 10:33:17 1998 @@ -5,23 +5,12 @@ extern struct notifier_block *sound_locker; extern void sound_notifier_chain_register(struct notifier_block *); -extern int lock_depth; #ifdef MODULE -#ifdef SOUND_CORE - -#define SOUND_INC_USE_COUNT do { notifier_call_chain(&sound_locker, 1, 0); lock_depth++; } while(0); -#define SOUND_DEC_USE_COUNT do { notifier_call_chain(&sound_locker, 0, 0); lock_depth--; } while(0); - -#else - - #define SOUND_LOCK sound_notifier_chain_register(&sound_notifier); #define SOUND_LOCK_END notifier_chain_unregister(&sound_locker, &sound_notifier) - - static int my_notifier_call(struct notifier_block *b, unsigned long foo, void *bar) { if(foo) @@ -38,6 +27,5 @@ 0 }; -#endif #endif #endif diff -u --recursive --new-file v2.1.101/linux/drivers/sound/sscape.c linux/drivers/sound/sscape.c --- v2.1.101/linux/drivers/sound/sscape.c Thu May 7 22:51:51 1998 +++ linux/drivers/sound/sscape.c Thu May 14 10:33:17 1998 @@ -22,7 +22,7 @@ #include "sound_config.h" #include "soundmodule.h" -#if defined(CONFIG_SSCAPE) || defined(MODULE) +#ifdef CONFIG_SSCAPE #include "coproc.h" diff -u --recursive --new-file v2.1.101/linux/drivers/sound/sys_timer.c linux/drivers/sound/sys_timer.c --- v2.1.101/linux/drivers/sound/sys_timer.c Tue Dec 30 11:02:39 1997 +++ linux/drivers/sound/sys_timer.c Thu May 14 10:33:17 1998 @@ -19,7 +19,7 @@ #include "sound_config.h" -#if defined(CONFIG_SEQUENCER) || defined(MODULE) +#ifdef CONFIG_SEQUENCER static volatile int opened = 0, tmr_running = 0; static volatile time_t tmr_offs, tmr_ctr; diff -u --recursive --new-file v2.1.101/linux/drivers/sound/trix.c linux/drivers/sound/trix.c --- v2.1.101/linux/drivers/sound/trix.c Wed Apr 8 19:36:28 1998 +++ linux/drivers/sound/trix.c Thu May 14 10:33:17 1998 @@ -23,15 +23,9 @@ #include "sb.h" #include "sound_firmware.h" -#if defined(CONFIG_TRIX) || defined (MODULE) +#ifdef CONFIG_TRIX -#if defined(CONFIG_UART401) || defined(CONFIG_UART401_MODULE) -#if defined(CONFIG_MIDI) -#define DO_MIDI -#endif -#endif - -#ifdef CONFIG_TRIX_HAVE_BOOT +#ifdef INCLUDE_TRIX_BOOT #include "trix_boot.h" #else static unsigned char *trix_boot = NULL; @@ -360,7 +354,7 @@ int probe_trix_mpu(struct address_info *hw_config) { -#ifdef DO_MIDI +#if defined(CONFIG_UART401) && defined(CONFIG_MIDI) unsigned char conf; static char irq_bits[] = { -1, -1, -1, 1, 2, 3, -1, 4, -1, 5 @@ -443,7 +437,7 @@ void unload_trix_mpu(struct address_info *hw_config) { -#ifdef DO_MIDI +#if defined(CONFIG_UART401) && defined(CONFIG_MIDI) unload_uart401(hw_config); #endif } diff -u --recursive --new-file v2.1.101/linux/drivers/sound/uart401.c linux/drivers/sound/uart401.c --- v2.1.101/linux/drivers/sound/uart401.c Wed Apr 8 19:36:28 1998 +++ linux/drivers/sound/uart401.c Thu May 14 10:33:17 1998 @@ -25,7 +25,8 @@ #include "sound_config.h" #include "soundmodule.h" -#if (defined(CONFIG_UART401)||defined(CONFIG_MIDI)) || defined(MODULE) +#ifdef CONFIG_UART401 +#ifdef CONFIG_MIDI typedef struct uart401_devc { @@ -475,13 +476,12 @@ SOUND_LOCK_END; } -#else - -#endif - #endif EXPORT_SYMBOL(attach_uart401); EXPORT_SYMBOL(probe_uart401); EXPORT_SYMBOL(unload_uart401); EXPORT_SYMBOL(uart401intr); + +#endif +#endif diff -u --recursive --new-file v2.1.101/linux/drivers/sound/uart6850.c linux/drivers/sound/uart6850.c --- v2.1.101/linux/drivers/sound/uart6850.c Wed Apr 8 19:36:28 1998 +++ linux/drivers/sound/uart6850.c Thu May 14 10:33:17 1998 @@ -24,8 +24,10 @@ */ #include "sound_config.h" + +#ifdef CONFIG_SOUND_UART6850 +#ifdef CONFIG_MIDI #include "soundmodule.h" -#if defined(CONFIG_UART6850) && defined(CONFIG_MIDI) || defined(MODULE) static int uart6850_base = 0x330; @@ -351,5 +353,6 @@ unload_uart6850(&cfg); SOUND_LOCK_END; } +#endif #endif #endif diff -u --recursive --new-file v2.1.101/linux/drivers/sound/v_midi.c linux/drivers/sound/v_midi.c --- v2.1.101/linux/drivers/sound/v_midi.c Tue Mar 17 22:18:15 1998 +++ linux/drivers/sound/v_midi.c Thu May 14 10:33:17 1998 @@ -21,13 +21,10 @@ #include #include - +#ifdef CONFIG_VMIDI #include "sound_config.h" #include "soundmodule.h" - -#if defined(CONFIG_VMIDI) || defined(MODULE) - #include "v_midi.h" static vmidi_devc *v_devc[2] = { NULL, NULL}; diff -u --recursive --new-file v2.1.101/linux/fs/buffer.c linux/fs/buffer.c --- v2.1.101/linux/fs/buffer.c Fri May 8 23:14:51 1998 +++ linux/fs/buffer.c Mon May 11 14:38:28 1998 @@ -38,6 +38,7 @@ #include #include #include +#include #include #include @@ -1729,7 +1730,7 @@ * Use gfp() for the hash table to decrease TLB misses, use * SLAB cache for buffer heads. */ -void buffer_init(void) +__initfunc(void buffer_init(void)) { int order = 5; /* Currently maximum order.. */ unsigned int nr_hash; diff -u --recursive --new-file v2.1.101/linux/fs/ext2/balloc.c linux/fs/ext2/balloc.c --- v2.1.101/linux/fs/ext2/balloc.c Fri May 8 23:14:52 1998 +++ linux/fs/ext2/balloc.c Fri May 8 22:55:06 1998 @@ -524,7 +524,11 @@ /* * Check quota for allocation of this block. */ - DQUOT_ALLOC_BLOCK(sb, inode, 1); + if(DQUOT_ALLOC_BLOCK(sb, inode, 1)) { + unlock_super(sb); + *err = -EDQUOT; + return 0; + } tmp = j + i * EXT2_BLOCKS_PER_GROUP(sb) + le32_to_cpu(es->s_first_data_block); @@ -560,7 +564,8 @@ for (k = 1; k < prealloc_goal && (j + k) < EXT2_BLOCKS_PER_GROUP(sb); k++) { - DQUOT_PREALLOC_BLOCK(sb, inode, 1); + if (DQUOT_PREALLOC_BLOCK(sb, inode, 1)) + break; if (ext2_set_bit (j + k, bh->b_data)) { DQUOT_FREE_BLOCK(sb, inode, 1); break; diff -u --recursive --new-file v2.1.101/linux/fs/ext2/ialloc.c linux/fs/ext2/ialloc.c --- v2.1.101/linux/fs/ext2/ialloc.c Fri May 8 23:14:53 1998 +++ linux/fs/ext2/ialloc.c Fri May 8 22:55:06 1998 @@ -405,7 +405,7 @@ return NULL; } bitmap_nr = load_inode_bitmap (sb, i); - if (bitmap_nr < 0) { + if (bitmap_nr < 0) { unlock_super (sb); iput(inode); *err = -EIO; @@ -493,7 +493,13 @@ inc_inode_version (inode, gdp, mode); unlock_super (sb); - DQUOT_ALLOC_INODE(sb, inode); + if(DQUOT_ALLOC_INODE(sb, inode)) { + sb->dq_op->drop(inode); + inode->i_nlink = 0; + iput(inode); + *err = -EDQUOT; + return NULL; + } ext2_debug ("allocating inode %lu\n", inode->i_ino); *err = 0; diff -u --recursive --new-file v2.1.101/linux/fs/filesystems.c linux/fs/filesystems.c --- v2.1.101/linux/fs/filesystems.c Mon Apr 6 17:41:01 1998 +++ linux/fs/filesystems.c Fri May 8 23:07:44 1998 @@ -42,6 +42,10 @@ extern int init_coda_fs(void); #endif +#ifdef CONFIG_DEVPTS_FS +extern int init_devpts_fs(void); +#endif + extern void device_setup(void); extern void binfmt_setup(void); extern void free_initmem(void); diff -u --recursive --new-file v2.1.101/linux/fs/isofs/inode.c linux/fs/isofs/inode.c --- v2.1.101/linux/fs/isofs/inode.c Mon Apr 6 17:41:01 1998 +++ linux/fs/isofs/inode.c Thu May 14 14:16:24 1998 @@ -132,20 +132,12 @@ #ifdef CONFIG_JOLIET if (!strcmp(this_char,"iocharset")) { - char *p; - int len; - - p = value; - while (*value && *value != ',') value++; - len = value - p; - if (len) { - popt->iocharset = kmalloc(len+1, GFP_KERNEL); - memcpy(popt->iocharset, p, len); - popt->iocharset[len] = 0; - } else { - popt->iocharset = NULL; + popt->iocharset = value; + while (*value && *value != ',') + value++; + if (value == popt->iocharset) return 0; - } + *value = 0; } else #endif if (!strcmp(this_char,"map") && value) { @@ -266,32 +258,28 @@ struct super_block *isofs_read_super(struct super_block *s, void *data, int silent) { - struct buffer_head * bh = NULL; + struct buffer_head * bh = NULL, *pri_bh = NULL; unsigned int blocksize; unsigned int blocksize_bits; kdev_t dev = s->s_dev; - struct hs_volume_descriptor * hdp; struct hs_primary_descriptor * h_pri = NULL; + struct iso_primary_descriptor * pri = NULL; + struct iso_supplementary_descriptor *sec = NULL; + struct iso_directory_record * rootp; int high_sierra; - int iso_blknum; + int iso_blknum, block; int joliet_level = 0; - struct iso9660_options opt; int orig_zonesize; - struct iso_primary_descriptor * pri = NULL; - struct iso_directory_record * rootp; - struct iso_supplementary_descriptor *sec = NULL; - struct iso_volume_descriptor * vdp; unsigned int vol_desc_start; struct inode * inode; - + struct iso9660_options opt; MOD_INC_USE_COUNT; + /* lock before any blocking operations */ + lock_super(s); - if (!parse_options((char *) data,&opt)) { - s->s_dev = 0; - MOD_DEC_USE_COUNT; - return NULL; - } + if (!parse_options((char *) data, &opt)) + goto out_unlock; #if 0 printk("map = %c\n", opt.map); @@ -303,6 +291,7 @@ printk("blocksize = %d\n", opt.blocksize); printk("gid = %d\n", opt.gid); printk("uid = %d\n", opt.uid); + printk("iocharset = %s\n", opt.iocharset); #endif /* @@ -333,8 +322,6 @@ set_blocksize(dev, opt.blocksize); - lock_super(s); - s->u.isofs_sb.s_high_sierra = high_sierra = 0; /* default is iso9660 */ vol_desc_start = isofs_get_last_session(dev); @@ -342,32 +329,25 @@ for (iso_blknum = vol_desc_start+16; iso_blknum < vol_desc_start+100; iso_blknum++) { - int b = iso_blknum << (ISOFS_BLOCK_BITS-blocksize_bits); + struct hs_volume_descriptor * hdp; + struct iso_volume_descriptor * vdp; - if (!(bh = bread(dev,b,opt.blocksize))) { - s->s_dev = 0; - printk("isofs_read_super: bread failed, dev " - "%s iso_blknum %d block %d\n", - kdevname(dev), iso_blknum, b); - unlock_super(s); - MOD_DEC_USE_COUNT; - return NULL; - } + block = iso_blknum << (ISOFS_BLOCK_BITS-blocksize_bits); + if (!(bh = bread(dev, block, opt.blocksize))) + goto out_no_read; vdp = (struct iso_volume_descriptor *)bh->b_data; hdp = (struct hs_volume_descriptor *)bh->b_data; if (strncmp (hdp->id, HS_STANDARD_ID, sizeof hdp->id) == 0) { if (isonum_711 (hdp->type) != ISO_VD_PRIMARY) - goto out; - if (isonum_711 (hdp->type) == ISO_VD_END) - goto out; + goto out_freebh; s->u.isofs_sb.s_high_sierra = 1; high_sierra = 1; opt.rock = 'n'; h_pri = (struct hs_primary_descriptor *)vdp; - break; + goto root_found; } if (strncmp (vdp->id, ISO_STANDARD_ID, sizeof vdp->id) == 0) { @@ -376,9 +356,13 @@ if (isonum_711 (vdp->type) == ISO_VD_PRIMARY) { if (pri == NULL) { pri = (struct iso_primary_descriptor *)vdp; + /* Save the buffer in case we need it ... */ + pri_bh = bh; + bh = NULL; } + } #ifdef CONFIG_JOLIET - } else if (isonum_711 (vdp->type) == ISO_VD_SUPPLEMENTARY) { + else if (isonum_711 (vdp->type) == ISO_VD_SUPPLEMENTARY) { sec = (struct iso_supplementary_descriptor *)vdp; if (sec->escape[0] == 0x25 && sec->escape[1] == 0x2f) { if (opt.joliet == 'y') { @@ -392,27 +376,31 @@ printk("ISO9660 Extensions: Microsoft Joliet Level %d\n", joliet_level); } - break; + goto root_found; } else { /* Unknown supplementary volume descriptor */ sec = NULL; } -#endif } +#endif /* Just skip any volume descriptors we don't recognize */ } brelse(bh); + bh = NULL; } - if ((pri == NULL) && (sec == NULL) && (h_pri == NULL)) { - if (!silent) - printk("Unable to identify CD-ROM format.\n"); - s->s_dev = 0; - unlock_super(s); - MOD_DEC_USE_COUNT; - return NULL; - } + /* + * If we fall through, either no volume descriptor was found, + * or else we passed a primary descriptor looking for others. + */ + if (!pri) + goto out_unknown_format; + brelse(bh); + bh = pri_bh; + pri_bh = NULL; +root_found: + brelse(pri_bh); s->u.isofs_sb.s_joliet_level = joliet_level; if (joliet_level && opt.rock == 'n') { @@ -425,10 +413,8 @@ if(high_sierra){ rootp = (struct iso_directory_record *) h_pri->root_directory_record; #ifndef IGNORE_WRONG_MULTI_VOLUME_SPECS - if (isonum_723 (h_pri->volume_set_size) != 1) { - printk("Multi-volume disks not supported.\n"); - goto out; - } + if (isonum_723 (h_pri->volume_set_size) != 1) + goto out_no_support; #endif IGNORE_WRONG_MULTI_VOLUME_SPECS s->u.isofs_sb.s_nzones = isonum_733 (h_pri->volume_space_size); s->u.isofs_sb.s_log_zone_size = isonum_723 (h_pri->logical_block_size); @@ -436,10 +422,8 @@ } else { rootp = (struct iso_directory_record *) pri->root_directory_record; #ifndef IGNORE_WRONG_MULTI_VOLUME_SPECS - if (isonum_723 (pri->volume_set_size) != 1) { - printk("Multi-volume disks not supported.\n"); - goto out; - } + if (isonum_723 (pri->volume_set_size) != 1) + goto out_no_support; #endif IGNORE_WRONG_MULTI_VOLUME_SPECS s->u.isofs_sb.s_nzones = isonum_733 (pri->volume_space_size); s->u.isofs_sb.s_log_zone_size = isonum_723 (pri->logical_block_size); @@ -454,20 +438,13 @@ /* * If the zone size is smaller than the hardware sector size, - * this is a fatal error. This would occur if the - * disc drive had sectors that were 2048 bytes, but the filesystem - * had blocks that were 512 bytes (which should only very rarely - * happen. + * this is a fatal error. This would occur if the disc drive + * had sectors that were 2048 bytes, but the filesystem had + * blocks that were 512 bytes (which should only very rarely + * happen.) */ - if( (blocksize != 0) - && (orig_zonesize < blocksize) ) - { - printk("Logical zone size(%d) < hardware blocksize(%u)\n", - orig_zonesize, blocksize); - goto out; - - } - + if(blocksize != 0 && orig_zonesize < blocksize) + goto out_bad_size; switch (s -> u.isofs_sb.s_log_zone_size) { case 512: s -> u.isofs_sb.s_log_zone_size = 9; break; @@ -475,8 +452,7 @@ case 2048: s -> u.isofs_sb.s_log_zone_size = 11; break; default: - printk("Bad logical zone size %ld\n", s -> u.isofs_sb.s_log_zone_size); - goto out; + goto out_bad_zone_size; } s->s_magic = ISOFS_SUPER_MAGIC; @@ -488,8 +464,6 @@ s->s_flags |= MS_RDONLY /* | MS_NODEV | MS_NOSUID */; - brelse(bh); - /* RDE: data zone now byte offset! */ s->u.isofs_sb.s_firstdatazone = ((isonum_733 (rootp->extent) + @@ -502,10 +476,9 @@ printk(KERN_DEBUG "First datazone:%ld Root inode number %d\n", s->u.isofs_sb.s_firstdatazone >> s -> u.isofs_sb.s_log_zone_size, s->u.isofs_sb.s_firstdatazone); - if(high_sierra) printk(KERN_DEBUG "Disc in High Sierra format.\n"); + if(high_sierra) + printk(KERN_DEBUG "Disc in High Sierra format.\n"); #endif - unlock_super(s); - /* set up enough so that it can read an inode */ /* * Force the blocksize to 512 for 512 byte sectors. The file @@ -544,27 +517,17 @@ s->u.isofs_sb.s_nls_iocharset = NULL; #ifdef CONFIG_JOLIET - if (joliet_level == 0) { - if (opt.iocharset) { - kfree(opt.iocharset); - opt.iocharset = NULL; - } - } else if (opt.utf8 == 0) { - char * p; - p = opt.iocharset ? opt.iocharset : "iso8859-1"; + if (joliet_level && opt.utf8 == 0) { + char * p = opt.iocharset ? opt.iocharset : "iso8859-1"; s->u.isofs_sb.s_nls_iocharset = load_nls(p); if (! s->u.isofs_sb.s_nls_iocharset) { /* Fail only if explicit charset specified */ - if (opt.iocharset) { - kfree(opt.iocharset); - goto out; - } else { - s->u.isofs_sb.s_nls_iocharset = load_nls_default(); - } + if (opt.iocharset) + goto out_freebh; + s->u.isofs_sb.s_nls_iocharset = load_nls_default(); } } #endif - s->s_dev = dev; s->s_op = &isofs_sops; s->u.isofs_sb.s_mapping = opt.map; s->u.isofs_sb.s_rock = (opt.rock == 'y' ? 2 : 0); @@ -605,31 +568,62 @@ } s->s_root = d_alloc_root(inode, NULL); - unlock_super(s); - - if (!(s->s_root)) { - s->s_dev = 0; - printk("get root inode failed\n"); -#ifdef CONFIG_JOLIET - if (s->u.isofs_sb.s_nls_iocharset) - unload_nls(s->u.isofs_sb.s_nls_iocharset); - if (opt.iocharset) kfree(opt.iocharset); -#endif - MOD_DEC_USE_COUNT; - return NULL; - } + if (!(s->s_root)) + goto out_no_root; - if(!check_disk_change(s->s_dev)) { + if(!check_disk_change(dev)) { + brelse(bh); + unlock_super(s); return s; } + /* + * Disk changed? Free the root dentry and clean up ... + */ + dput(s->s_root); + goto out_freechar; + + /* + * Display error message + */ +out_no_root: + printk(KERN_ERR "isofs_read_super: get root inode failed\n"); + goto out_iput; +out_bad_zone_size: + printk(KERN_WARNING "Bad logical zone size %ld\n", + s->u.isofs_sb.s_log_zone_size); + goto out_freebh; +out_bad_size: + printk(KERN_WARNING "Logical zone size(%d) < hardware blocksize(%u)\n", + orig_zonesize, blocksize); + goto out_freebh; +#ifndef IGNORE_WRONG_MULTI_VOLUME_SPECS +out_no_support: + printk(KERN_WARNING "Multi-volume disks not supported.\n"); + goto out_freebh; +#endif +out_unknown_format: + if (!silent) + printk(KERN_WARNING "Unable to identify CD-ROM format.\n"); + goto out_freebh; +out_no_read: + printk(KERN_WARNING "isofs_read_super: " + "bread failed, dev=%s, iso_blknum=%d, block=%d\n", + kdevname(dev), iso_blknum, block); + goto out_unlock; + + /* + * Cascaded error cleanup to ensure all resources are freed. + */ +out_iput: + iput(inode); +out_freechar: #ifdef CONFIG_JOLIET if (s->u.isofs_sb.s_nls_iocharset) unload_nls(s->u.isofs_sb.s_nls_iocharset); #endif - if (opt.iocharset) kfree(opt.iocharset); - - out: /* Kick out for various error conditions */ +out_freebh: brelse(bh); +out_unlock: s->s_dev = 0; unlock_super(s); MOD_DEC_USE_COUNT; diff -u --recursive --new-file v2.1.101/linux/fs/open.c linux/fs/open.c --- v2.1.101/linux/fs/open.c Fri May 8 23:14:53 1998 +++ linux/fs/open.c Fri May 8 22:55:06 1998 @@ -552,7 +552,7 @@ newattrs.ia_mode &= ~S_ISGID; newattrs.ia_valid |= ATTR_MODE; } - DQUOT_TRANSFER(dentry, newattrs); + error = DQUOT_TRANSFER(dentry, &newattrs); out: return error; } diff -u --recursive --new-file v2.1.101/linux/fs/proc/generic.c linux/fs/proc/generic.c --- v2.1.101/linux/fs/proc/generic.c Mon Jan 5 11:18:33 1998 +++ linux/fs/proc/generic.c Thu May 14 10:26:22 1998 @@ -154,14 +154,19 @@ break; } - n -= copy_to_user(buf, start, n); /* BUG ??? */ + /* This is a hack to allow mangling of file pos independent + * of actual bytes read. Simply place the data at page, + * return the bytes, and set `start' to the desired offset + * as an unsigned int. - Paul.Russell@rustcorp.com.au + */ + n -= copy_to_user(buf, start < page ? page : start, n); if (n == 0) { if (retval == 0) retval = -EFAULT; break; } - - *ppos += n; /* Move down the file */ + + *ppos += start < page ? (long)start : n; /* Move down the file */ nbytes -= n; buf += n; retval += n; diff -u --recursive --new-file v2.1.101/linux/fs/super.c linux/fs/super.c --- v2.1.101/linux/fs/super.c Fri May 8 23:14:53 1998 +++ linux/fs/super.c Fri May 8 23:04:31 1998 @@ -54,6 +54,10 @@ */ static struct semaphore mount_sem = MUTEX; +#ifdef CONFIG_BSD_PROCESS_ACCT +extern void acct_auto_close(kdev_t); +#endif + extern void wait_for_keypress(void); extern struct file_operations * get_blkfops(unsigned int major); diff -u --recursive --new-file v2.1.101/linux/include/asm-i386/current.h linux/include/asm-i386/current.h --- v2.1.101/linux/include/asm-i386/current.h Tue May 13 22:41:17 1997 +++ linux/include/asm-i386/current.h Mon May 11 09:39:36 1998 @@ -1,14 +1,13 @@ #ifndef _I386_CURRENT_H #define _I386_CURRENT_H -static inline unsigned long get_esp(void) +static inline struct task_struct * get_current(void) { - unsigned long esp; - __asm__("movl %%esp,%0":"=r" (esp)); - return esp; -} - -#define current ((struct task_struct *)(get_esp() & ~8191UL)) - + struct task_struct *current; + __asm__("andl %%esp,%0; ":"=r" (current) : "0" (~8191UL)); + return current; + } + +#define current get_current() #endif /* !(_I386_CURRENT_H) */ diff -u --recursive --new-file v2.1.101/linux/include/asm-ppc/serial.h linux/include/asm-ppc/serial.h --- v2.1.101/linux/include/asm-ppc/serial.h Fri May 8 23:14:56 1998 +++ linux/include/asm-ppc/serial.h Fri May 8 23:03:57 1998 @@ -2,6 +2,8 @@ * include/asm-ppc/serial.h */ +#include + /* * This assumes you have a 1.8432 MHz clock for your UART. * diff -u --recursive --new-file v2.1.101/linux/include/linux/capability.h linux/include/linux/capability.h --- v2.1.101/linux/include/linux/capability.h Thu May 7 22:51:55 1998 +++ linux/include/linux/capability.h Thu May 14 14:37:48 1998 @@ -305,7 +305,7 @@ #define cap_set_full(c) do { (c).cap = ~0; } while(0) #define cap_mask(c,mask) do { (c).cap &= (mask).cap; } while(0) -#define cap_is_fs_cap(c) ((c) & CAP_FS_MASK) +#define cap_is_fs_cap(c) (CAP_TO_MASK(c) & CAP_FS_MASK) #endif /* __KERNEL__ */ diff -u --recursive --new-file v2.1.101/linux/include/linux/fs.h linux/include/linux/fs.h --- v2.1.101/linux/include/linux/fs.h Fri May 8 23:14:56 1998 +++ linux/include/linux/fs.h Thu May 14 14:37:47 1998 @@ -40,8 +40,8 @@ #define NR_OPEN 1024 #define NR_SUPER 64 -#define BLOCK_SIZE 1024 #define BLOCK_SIZE_BITS 10 +#define BLOCK_SIZE (1< and + * Michael Neuling + * 2-Nov-1997: Changed types to __u16, etc. + * Removed IP_FW_F_TCPACK & IP_FW_F_BIDIR. + * Added inverse flags field. + * Removed multiple port specs. */ /* * Format of an IP firewall descriptor * * src, dst, src_mask, dst_mask are always stored in network byte order. - * flags and num_*_ports are stored in host byte order (of course). + * flags are stored in host byte order (of course). * Port numbers are stored in HOST byte order. */ -#ifndef _IP_FW_H -#define _IP_FW_H +#ifndef _IP_FWCHAINS_H +#define _IP_FWCHAINS_H -#ifdef __KERNEL__ #include #include #include #include #include -#endif +#define IP_FW_MAX_LABEL_LENGTH 8 +typedef char ip_chainlabel[IP_FW_MAX_LABEL_LENGTH+1]; struct ip_fw { - struct ip_fw *fw_next; /* Next firewall on chain */ struct in_addr fw_src, fw_dst; /* Source and destination IP addr */ struct in_addr fw_smsk, fw_dmsk; /* Mask for src and dest IP addr */ - struct in_addr fw_via; /* IP address of interface "via" */ - struct device *fw_viadev; /* device of interface "via" */ - __u16 fw_flg; /* Flags word */ - __u16 fw_nsp, fw_ndp; /* N'of src ports and # of dst ports */ - /* in ports array (dst ports follow */ - /* src ports; max of 10 ports in all; */ - /* count of 0 means match all ports) */ -#define IP_FW_MAX_PORTS 10 /* A reasonable maximum */ - __u16 fw_pts[IP_FW_MAX_PORTS]; /* Array of port numbers to match */ - unsigned long fw_pcnt,fw_bcnt; /* Packet and byte counters */ - __u8 fw_tosand, fw_tosxor; /* Revised packet priority */ + __u32 fw_mark; /* ID to stamp on packet */ + __u16 fw_proto; /* Protocol, 0 = ANY */ + __u16 fw_flg; /* Flags word */ + __u16 fw_invflg; /* Inverse flags */ + __u16 fw_spts[2]; /* Source port range. */ + __u16 fw_dpts[2]; /* Destination port range. */ + __u16 fw_redirpt; /* Port to redirect to. */ + __u16 fw_outputsize; /* Max amount to output to + NETLINK */ char fw_vianame[IFNAMSIZ]; /* name of interface "via" */ + __u8 fw_tosand, fw_tosxor; /* Revised packet priority */ }; -/* - * Values for "flags" field . - */ - -#define IP_FW_F_ALL 0x0000 /* This is a universal packet firewall*/ -#define IP_FW_F_TCP 0x0001 /* This is a TCP packet firewall */ -#define IP_FW_F_UDP 0x0002 /* This is a UDP packet firewall */ -#define IP_FW_F_ICMP 0x0003 /* This is a ICMP packet firewall */ -#define IP_FW_F_KIND 0x0003 /* Mask to isolate firewall kind */ -#define IP_FW_F_ACCEPT 0x0004 /* This is an accept firewall (as * - * opposed to a deny firewall)* - * */ -#define IP_FW_F_SRNG 0x0008 /* The first two src ports are a min * - * and max range (stored in host byte * - * order). * - * */ -#define IP_FW_F_DRNG 0x0010 /* The first two dst ports are a min * - * and max range (stored in host byte * - * order). * - * (ports[0] <= port <= ports[1]) * - * */ -#define IP_FW_F_PRN 0x0020 /* In verbose mode print this firewall*/ -#define IP_FW_F_BIDIR 0x0040 /* For bidirectional firewalls */ -#define IP_FW_F_TCPSYN 0x0080 /* For tcp packets-check SYN only */ -#define IP_FW_F_ICMPRPL 0x0100 /* Send back icmp unreachable packet */ -#define IP_FW_F_MASQ 0x0200 /* Masquerading */ -#define IP_FW_F_TCPACK 0x0400 /* For tcp-packets match if ACK is set*/ -#define IP_FW_F_REDIR 0x0800 /* Redirect to local port fw_pts[n] */ -#define IP_FW_F_ACCTIN 0x1000 /* Account incoming packets only. */ -#define IP_FW_F_ACCTOUT 0x2000 /* Account outgoing packets only. */ +struct ip_fwuser +{ + struct ip_fw ipfw; + ip_chainlabel label; +}; -#define IP_FW_F_MASK 0x3FFF /* All possible flag bits mask */ +/* Values for "fw_flg" field . */ +#define IP_FW_F_PRN 0x0001 /* Print packet if it matches */ +#define IP_FW_F_TCPSYN 0x0002 /* For tcp packets-check SYN only */ +#define IP_FW_F_FRAG 0x0004 /* Set if rule is a fragment rule */ +#define IP_FW_F_MARKABS 0x0008 /* Set the mark to fw_mark, not add. */ +#define IP_FW_F_WILDIF 0x0010 /* Need only match start of interface name. */ +#define IP_FW_F_NETLINK 0x0020 /* Redirect to netlink: 2.1.x only */ +#define IP_FW_F_MASK 0x002F /* All possible flag bits mask */ + +/* Values for "fw_invflg" field. */ +#define IP_FW_INV_SRCIP 0x0001 /* Invert the sense of fw_src. */ +#define IP_FW_INV_DSTIP 0x0002 /* Invert the sense of fw_dst. */ +#define IP_FW_INV_PROTO 0x0004 /* Invert the sense of fw_proto. */ +#define IP_FW_INV_SRCPT 0x0008 /* Invert the sense of source ports. */ +#define IP_FW_INV_DSTPT 0x0010 /* Invert the sense of destination ports. */ +#define IP_FW_INV_VIA 0x0020 /* Invert the sense of fw_vianame. */ +#define IP_FW_INV_SYN 0x0040 /* Invert the sense of IP_FW_F_TCPSYN. */ +#define IP_FW_INV_FRAG 0x0080 /* Invert the sense of IP_FW_F_FRAG. */ /* * New IP firewall options for [gs]etsockopt at the RAW IP level. * Unlike BSD Linux inherits IP options so you don't have to use - * a raw socket for this. Instead we check rights in the calls. - */ + * a raw socket for this. Instead we check rights in the calls. */ #define IP_FW_BASE_CTL 64 /* base for firewall socket options */ -#define IP_FW_COMMAND 0x00FF /* mask for command without chain */ -#define IP_FW_TYPE 0x0300 /* mask for type (chain) */ -#define IP_FW_SHIFT 8 /* shift count for type (chain) */ - -#define IP_FW_FWD 0 -#define IP_FW_IN 1 -#define IP_FW_OUT 2 -#define IP_FW_ACCT 3 -#define IP_FW_CHAINS 4 /* total number of ip_fw chains */ -#define IP_FW_MASQ 5 - -#define IP_FW_INSERT (IP_FW_BASE_CTL) -#define IP_FW_APPEND (IP_FW_BASE_CTL+1) -#define IP_FW_DELETE (IP_FW_BASE_CTL+2) -#define IP_FW_FLUSH (IP_FW_BASE_CTL+3) -#define IP_FW_ZERO (IP_FW_BASE_CTL+4) -#define IP_FW_POLICY (IP_FW_BASE_CTL+5) -#define IP_FW_CHECK (IP_FW_BASE_CTL+6) -#define IP_FW_MASQ_TIMEOUTS (IP_FW_BASE_CTL+7) - -#define IP_FW_INSERT_FWD (IP_FW_INSERT | (IP_FW_FWD << IP_FW_SHIFT)) -#define IP_FW_APPEND_FWD (IP_FW_APPEND | (IP_FW_FWD << IP_FW_SHIFT)) -#define IP_FW_DELETE_FWD (IP_FW_DELETE | (IP_FW_FWD << IP_FW_SHIFT)) -#define IP_FW_FLUSH_FWD (IP_FW_FLUSH | (IP_FW_FWD << IP_FW_SHIFT)) -#define IP_FW_ZERO_FWD (IP_FW_ZERO | (IP_FW_FWD << IP_FW_SHIFT)) -#define IP_FW_POLICY_FWD (IP_FW_POLICY | (IP_FW_FWD << IP_FW_SHIFT)) -#define IP_FW_CHECK_FWD (IP_FW_CHECK | (IP_FW_FWD << IP_FW_SHIFT)) - -#define IP_FW_INSERT_IN (IP_FW_INSERT | (IP_FW_IN << IP_FW_SHIFT)) -#define IP_FW_APPEND_IN (IP_FW_APPEND | (IP_FW_IN << IP_FW_SHIFT)) -#define IP_FW_DELETE_IN (IP_FW_DELETE | (IP_FW_IN << IP_FW_SHIFT)) -#define IP_FW_FLUSH_IN (IP_FW_FLUSH | (IP_FW_IN << IP_FW_SHIFT)) -#define IP_FW_ZERO_IN (IP_FW_ZERO | (IP_FW_IN << IP_FW_SHIFT)) -#define IP_FW_POLICY_IN (IP_FW_POLICY | (IP_FW_IN << IP_FW_SHIFT)) -#define IP_FW_CHECK_IN (IP_FW_CHECK | (IP_FW_IN << IP_FW_SHIFT)) - -#define IP_FW_INSERT_OUT (IP_FW_INSERT | (IP_FW_OUT << IP_FW_SHIFT)) -#define IP_FW_APPEND_OUT (IP_FW_APPEND | (IP_FW_OUT << IP_FW_SHIFT)) -#define IP_FW_DELETE_OUT (IP_FW_DELETE | (IP_FW_OUT << IP_FW_SHIFT)) -#define IP_FW_FLUSH_OUT (IP_FW_FLUSH | (IP_FW_OUT << IP_FW_SHIFT)) -#define IP_FW_ZERO_OUT (IP_FW_ZERO | (IP_FW_OUT << IP_FW_SHIFT)) -#define IP_FW_POLICY_OUT (IP_FW_POLICY | (IP_FW_OUT << IP_FW_SHIFT)) -#define IP_FW_CHECK_OUT (IP_FW_CHECK | (IP_FW_OUT << IP_FW_SHIFT)) - -#define IP_ACCT_INSERT (IP_FW_INSERT | (IP_FW_ACCT << IP_FW_SHIFT)) -#define IP_ACCT_APPEND (IP_FW_APPEND | (IP_FW_ACCT << IP_FW_SHIFT)) -#define IP_ACCT_DELETE (IP_FW_DELETE | (IP_FW_ACCT << IP_FW_SHIFT)) -#define IP_ACCT_FLUSH (IP_FW_FLUSH | (IP_FW_ACCT << IP_FW_SHIFT)) -#define IP_ACCT_ZERO (IP_FW_ZERO | (IP_FW_ACCT << IP_FW_SHIFT)) - -#define IP_FW_MASQ_INSERT (IP_FW_INSERT | (IP_FW_MASQ << IP_FW_SHIFT)) -#define IP_FW_MASQ_ADD (IP_FW_APPEND | (IP_FW_MASQ << IP_FW_SHIFT)) -#define IP_FW_MASQ_DEL (IP_FW_DELETE | (IP_FW_MASQ << IP_FW_SHIFT)) -#define IP_FW_MASQ_FLUSH (IP_FW_FLUSH | (IP_FW_MASQ << IP_FW_SHIFT)) - -#define IP_FW_MASQ_INSERT (IP_FW_INSERT | (IP_FW_MASQ << IP_FW_SHIFT)) -#define IP_FW_MASQ_ADD (IP_FW_APPEND | (IP_FW_MASQ << IP_FW_SHIFT)) -#define IP_FW_MASQ_DEL (IP_FW_DELETE | (IP_FW_MASQ << IP_FW_SHIFT)) -#define IP_FW_MASQ_FLUSH (IP_FW_FLUSH | (IP_FW_MASQ << IP_FW_SHIFT)) +#define IP_FW_APPEND (IP_FW_BASE_CTL) /* Takes ip_fwchange */ +#define IP_FW_REPLACE (IP_FW_BASE_CTL+1) /* Takes ip_fwnew */ +#define IP_FW_DELETE_NUM (IP_FW_BASE_CTL+2) /* Takes ip_fwdelnum */ +#define IP_FW_DELETE (IP_FW_BASE_CTL+3) /* Takes ip_fwchange */ +#define IP_FW_INSERT (IP_FW_BASE_CTL+4) /* Takes ip_fwnew */ +#define IP_FW_FLUSH (IP_FW_BASE_CTL+5) /* Takes ip_chainlabel */ +#define IP_FW_ZERO (IP_FW_BASE_CTL+6) /* Takes ip_chainlabel */ +#define IP_FW_CHECK (IP_FW_BASE_CTL+7) /* Takes ip_fwtest */ +#define IP_FW_MASQ_TIMEOUTS (IP_FW_BASE_CTL+8) /* Takes 3 ints */ +#define IP_FW_CREATECHAIN (IP_FW_BASE_CTL+9) /* Takes ip_chainlabel */ +#define IP_FW_DELETECHAIN (IP_FW_BASE_CTL+10) /* Takes ip_chainlabel */ +#define IP_FW_POLICY (IP_FW_BASE_CTL+11) /* Takes ip_fwpolicy */ +/* Masquerade controls */ +#define IP_FW_MASQ_INSERT (IP_FW_BASE_CTL+12) +#define IP_FW_MASQ_ADD (IP_FW_BASE_CTL+13) +#define IP_FW_MASQ_DEL (IP_FW_BASE_CTL+14) +#define IP_FW_MASQ_FLUSH (IP_FW_BASE_CTL+15) + +/* Builtin chain labels */ +#define IP_FW_LABEL_FORWARD "forward" +#define IP_FW_LABEL_INPUT "input" +#define IP_FW_LABEL_OUTPUT "output" + +/* Special targets */ +#define IP_FW_LABEL_MASQUERADE "MASQ" +#define IP_FW_LABEL_REDIRECT "REDIRECT" +#define IP_FW_LABEL_ACCEPT "ACCEPT" +#define IP_FW_LABEL_BLOCK "DENY" +#define IP_FW_LABEL_REJECT "REJECT" +#define IP_FW_LABEL_RETURN "RETURN" +#define IP_FW_LABEL_QUEUE "QUEUE" + +/* Files in /proc/net */ +#define IP_FW_PROC_CHAINS "ip_fwchains" +#define IP_FW_PROC_CHAIN_NAMES "ip_fwnames" + struct ip_fwpkt { @@ -192,6 +128,48 @@ char fwp_vianame[IFNAMSIZ]; /* interface name */ }; +/* The argument to IP_FW_DELETE and IP_FW_APPEND */ +struct ip_fwchange +{ + struct ip_fwuser fwc_rule; + ip_chainlabel fwc_label; +}; + +/* The argument to IP_FW_CHECK. */ +struct ip_fwtest +{ + struct ip_fwpkt fwt_packet; /* Packet to be tested */ + ip_chainlabel fwt_label; /* Block to start test in */ +}; + +/* The argument to IP_FW_DELETE_NUM */ +struct ip_fwdelnum +{ + __u32 fwd_rulenum; + ip_chainlabel fwd_label; +}; + +/* The argument to IP_FW_REPLACE and IP_FW_INSERT */ +struct ip_fwnew +{ + __u32 fwn_rulenum; + struct ip_fwuser fwn_rule; + ip_chainlabel fwn_label; +}; + +/* The argument to IP_FW_POLICY */ +struct ip_fwpolicy +{ + ip_chainlabel fwp_policy; + ip_chainlabel fwp_label; +}; +/* + * timeouts for ip masquerading + */ + +struct ip_fw_masq; + +/* Masquerading stuff */ #define IP_FW_MASQCTL_MAX 256 #define IP_MASQ_MOD_NMAX 32 @@ -206,11 +184,7 @@ } u; }; -/* - * timeouts for ip masquerading - */ -struct ip_fw_masq; /* * Main firewall chains definitions and global var's definitions. @@ -218,37 +192,18 @@ #ifdef __KERNEL__ -/* Modes used in the ip_fw_chk() routine. */ -#define IP_FW_MODE_FW 0x00 /* kernel firewall check */ -#define IP_FW_MODE_ACCT_IN 0x01 /* accounting (incoming) */ -#define IP_FW_MODE_ACCT_OUT 0x02 /* accounting (outgoing) */ -#define IP_FW_MODE_CHK 0x04 /* check requested by user */ - #include -#ifdef CONFIG_IP_FIREWALL -extern struct ip_fw *ip_fw_in_chain; -extern struct ip_fw *ip_fw_out_chain; -extern struct ip_fw *ip_fw_fwd_chain; -extern int ip_fw_in_policy; -extern int ip_fw_out_policy; -extern int ip_fw_fwd_policy; +#include +#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,1,0) +#include +extern void ip_fw_init(void) __init; +#else /* 2.0.x */ +extern void ip_fw_init(void); +#endif /* 2.1.x */ extern int ip_fw_ctl(int, void *, int); -#endif -#ifdef CONFIG_IP_ACCT -extern struct ip_fw *ip_acct_chain; -extern int ip_acct_ctl(int, void *, int); -#endif -#ifdef CONFIG_IP_MASQUERADE -extern int ip_masq_ctl(int, void *, int); -#endif #ifdef CONFIG_IP_MASQUERADE extern int ip_masq_ctl(int, void *, int); #endif - -extern int ip_fw_chk(struct iphdr *, struct device *, __u16 *, struct ip_fw *, int, int); -extern void ip_fw_init(void); #endif /* KERNEL */ - - -#endif /* _IP_FW_H */ +#endif /* _IP_FWCHAINS_H */ diff -u --recursive --new-file v2.1.101/linux/include/linux/joystick.h linux/include/linux/joystick.h --- v2.1.101/linux/include/linux/joystick.h Wed Apr 8 19:36:29 1998 +++ linux/include/linux/joystick.h Fri May 8 23:07:44 1998 @@ -2,9 +2,9 @@ #define _LINUX_JOYSTICK_H /* - * $Id: joystick.h,v 1.3 1998/03/30 11:10:40 mj Exp $ + * /usr/include/linux/joystick.h Version 1.0.9 * - * Copyright (C) 1997, 1998 Vojtech Pavlik + * Copyright (C) 1996-1998 Vojtech Pavlik */ #include @@ -13,26 +13,26 @@ * Version */ -#define JS_VERSION 0x00010007L /* 1.0.7 BCD */ +#define JS_VERSION 0x00010008L /* * IOCTL commands for joystick driver */ -#define JSIOCGVERSION _IOR('j', 0x01, __u32) /* get driver version */ +#define JSIOCGVERSION _IOR('j', 0x01, __u32) /* get driver version */ -#define JSIOCGAXES _IOR('j', 0x11, __u8) /* get number of axes */ -#define JSIOCGBUTTONS _IOR('j', 0x12, __u8) /* get number of buttons */ +#define JSIOCGAXES _IOR('j', 0x11, __u8) /* get number of axes */ +#define JSIOCGBUTTONS _IOR('j', 0x12, __u8) /* get number of buttons */ -#define JSIOCSCORR _IOW('j', 0x21, struct js_corr[4]) /* set correction values */ -#define JSIOCGCORR _IOR('j', 0x22, struct js_corr[4]) /* get correction values */ +#define JSIOCSCORR _IOW('j', 0x21, struct js_corr[4]) /* set correction values */ +#define JSIOCGCORR _IOR('j', 0x22, struct js_corr[4]) /* get correction values */ /* * Types and constants for get/set correction */ -#define JS_CORR_NONE 0x00 /* returns raw values */ -#define JS_CORR_BROKEN 0x01 /* broken line */ +#define JS_CORR_NONE 0x00 /* returns raw values */ +#define JS_CORR_BROKEN 0x01 /* broken line */ struct js_corr { __s32 coef[8]; @@ -46,13 +46,13 @@ #define JS_EVENT_BUTTON 0x01 /* button pressed/released */ #define JS_EVENT_AXIS 0x02 /* joystick moved */ -#define JS_EVENT_INIT 0x80 /* initial state of device */ +#define JS_EVENT_INIT 0x80 /* initial state of device at open time */ struct js_event { - __u32 time; /* time when event happened in miliseconds since open */ - __u16 value; /* new value */ - __u8 type; /* type of event, see above */ - __u8 number; /* axis/button number */ + __u32 time; /* event timestamp in miliseconds since open */ + __s16 value; /* value */ + __u8 type; /* type of event, see above */ + __u8 number; /* axis/button number */ }; /* @@ -62,16 +62,16 @@ #define JS_RETURN sizeof(struct JS_DATA_TYPE) #define JS_TRUE 1 #define JS_FALSE 0 -#define JS_X_0 0x01 /* bit mask for x-axis js0 */ -#define JS_Y_0 0x02 /* bit mask for y-axis js0 */ -#define JS_X_1 0x04 /* bit mask for x-axis js1 */ -#define JS_Y_1 0x08 /* bit mask for y-axis js1 */ -#define JS_MAX 2 /* max number of joysticks */ +#define JS_X_0 0x01 /* bit mask for x-axis js0 */ +#define JS_Y_0 0x02 /* bit mask for y-axis js0 */ +#define JS_X_1 0x04 /* bit mask for x-axis js1 */ +#define JS_Y_1 0x08 /* bit mask for y-axis js1 */ +#define JS_MAX 2 /* max number of joysticks */ struct JS_DATA_TYPE { - int buttons; /* immediate button state */ - int x; /* immediate x axis value */ - int y; /* immediate y axis value */ + int buttons; /* immediate button state */ + int x; /* immediate x axis value */ + int y; /* immediate y axis value */ }; diff -u --recursive --new-file v2.1.101/linux/include/linux/proc_fs.h linux/include/linux/proc_fs.h --- v2.1.101/linux/include/linux/proc_fs.h Fri May 8 23:14:56 1998 +++ linux/include/linux/proc_fs.h Thu May 14 14:37:57 1998 @@ -137,6 +137,8 @@ PROC_NET_DN_L2, PROC_NET_DN_SKT, PROC_NET_NETSTAT, + PROC_NET_IPFW_CHAINS, + PROC_NET_IPFW_CHAIN_NAMES, PROC_NET_LAST }; diff -u --recursive --new-file v2.1.101/linux/include/linux/quotaops.h linux/include/linux/quotaops.h --- v2.1.101/linux/include/linux/quotaops.h Fri May 8 23:14:56 1998 +++ linux/include/linux/quotaops.h Thu May 14 14:39:39 1998 @@ -37,108 +37,104 @@ /* * Operations supported for diskquotas. */ -#define DQUOT_INIT(inode) \ -if (inode->i_sb && inode->i_sb->dq_op) { \ - inode->i_sb->dq_op->initialize(inode, -1); \ -} - -#define DQUOT_DROP(inode) \ -if (IS_QUOTAINIT(inode)) { \ - if (inode->i_sb && inode->i_sb->dq_op) \ - inode->i_sb->dq_op->drop(inode); \ -} - -#define DQUOT_SAVE_DROP(inode) \ -if (IS_QUOTAINIT(inode)) { \ - inode->i_lock = 1; \ - if (inode->i_sb && inode->i_sb->dq_op) \ - inode->i_sb->dq_op->drop(inode); \ - unlock_inode(inode); \ - goto we_slept; \ -} - -#define DQUOT_PREALLOC_BLOCK(sb, inode, nr) \ -if (sb->dq_op) { \ - if (sb->dq_op->alloc_block(inode, fs_to_dq_blocks(nr, sb->s_blocksize), \ - current->euid, 0) == NO_QUOTA) \ - break; \ -} - -#define DQUOT_ALLOC_BLOCK(sb, inode, nr) \ -if (sb->dq_op) { \ - if (sb->dq_op->alloc_block(inode, fs_to_dq_blocks(nr, sb->s_blocksize), \ - current->euid, 1) == NO_QUOTA) { \ - unlock_super (sb); \ - *err = -EDQUOT; \ - return 0; \ - } \ -} - -#define DQUOT_ALLOC_INODE(sb, inode) \ -if (sb->dq_op) { \ - sb->dq_op->initialize (inode, -1); \ - if (sb->dq_op->alloc_inode (inode, 1, current->euid)) { \ - sb->dq_op->drop (inode); \ - inode->i_nlink = 0; \ - iput (inode); \ - *err = -EDQUOT; \ - return NULL; \ - } \ - inode->i_flags |= S_QUOTA; \ -} - -#define DQUOT_FREE_BLOCK(sb, inode, nr) \ -if (sb->dq_op) { \ - sb->dq_op->free_block(inode, fs_to_dq_blocks(nr, sb->s_blocksize)); \ -} - -#define DQUOT_FREE_INODE(sb, inode) \ -if (sb->dq_op) { \ - sb->dq_op->free_inode(inode, 1); \ -} - -#define DQUOT_TRANSFER(dentry, iattr) \ -if (dentry->d_inode->i_sb->dq_op) { \ - if (IS_QUOTAINIT(dentry->d_inode) == 0) \ - dentry->d_inode->i_sb->dq_op->initialize(dentry->d_inode, -1); \ - if (dentry->d_inode->i_sb->dq_op->transfer(dentry->d_inode, &iattr, 0, current->euid)) { \ - error = -EDQUOT; \ - goto out; \ - } \ - error = notify_change(dentry, &iattr); \ - if (error) \ - inode->i_sb->dq_op->transfer(dentry->d_inode, &iattr, 1, current->euid); \ -} else { \ - error = notify_change(dentry, &iattr); \ +extern __inline__ void DQUOT_INIT(struct inode *inode) +{ + if (inode->i_sb && inode->i_sb->dq_op) + inode->i_sb->dq_op->initialize(inode, -1); +} + +extern __inline__ void DQUOT_DROP(struct inode *inode) +{ + if (IS_QUOTAINIT(inode)) { + if (inode->i_sb && inode->i_sb->dq_op) + inode->i_sb->dq_op->drop(inode); + } +} + +extern __inline__ int DQUOT_PREALLOC_BLOCK(struct super_block *sb, struct inode *inode, int nr) +{ + if (sb->dq_op) { + if (sb->dq_op->alloc_block(inode, fs_to_dq_blocks(nr, sb->s_blocksize), + current->euid, 0) == NO_QUOTA) + return 1; + } + return 0; +} + +extern __inline__ int DQUOT_ALLOC_BLOCK(struct super_block *sb, struct inode *inode, int nr) +{ + if (sb->dq_op) { + if (sb->dq_op->alloc_block(inode, fs_to_dq_blocks(nr, sb->s_blocksize), + current->euid, 1) == NO_QUOTA) + return 1; + } + return 0; +} + +extern __inline__ int DQUOT_ALLOC_INODE(struct super_block *sb, struct inode *inode) +{ + if (sb->dq_op) { + sb->dq_op->initialize (inode, -1); + if (sb->dq_op->alloc_inode (inode, 1, current->euid)) + return 1; + } + inode->i_flags |= S_QUOTA; + return 0; +} + +extern __inline__ void DQUOT_FREE_BLOCK(struct super_block *sb, struct inode *inode, int nr) +{ + if (sb->dq_op) + sb->dq_op->free_block(inode, fs_to_dq_blocks(nr, sb->s_blocksize)); +} + +extern __inline__ void DQUOT_FREE_INODE(struct super_block *sb, struct inode *inode) +{ + if (sb->dq_op) + sb->dq_op->free_inode(inode, 1); +} + +extern __inline__ int DQUOT_TRANSFER(struct dentry *dentry, struct iattr *iattr) +{ + int error = -EDQUOT; + + if (dentry->d_inode->i_sb->dq_op) { + if (IS_QUOTAINIT(dentry->d_inode) == 0) + dentry->d_inode->i_sb->dq_op->initialize(dentry->d_inode, -1); + if (dentry->d_inode->i_sb->dq_op->transfer(dentry->d_inode, iattr, 0, current->euid)) + goto out; + error = notify_change(dentry, iattr); + if (error) + dentry->d_inode->i_sb->dq_op->transfer(dentry->d_inode, iattr, 1, current->euid); + } else { + error = notify_change(dentry, iattr); + } +out: + return error; } -#define DQUOT_SYNC(dev) \ -sync_dquots(dev, -1) - -#define DQUOT_OFF(dev) \ -quota_off(dev, -1) +#define DQUOT_SYNC(dev) sync_dquots(dev, -1) +#define DQUOT_OFF(dev) quota_off(dev, -1) #else /* * NO-OP when quota not configured. */ -#define DQUOT_INIT(inode) -#define DQUOT_DROP(inode) -#define DQUOT_SAVE_DROP(inode) -#define DQUOT_PREALLOC_BLOCK(sb, inode, nr) -#define DQUOT_ALLOC_BLOCK(sb, inode, nr) -#define DQUOT_ALLOC_INODE(sb, inode) -#define DQUOT_FREE_BLOCK(sb, inode, nr) -#define DQUOT_FREE_INODE(sb, inode) -#define DQUOT_SYNC(dev) -#define DQUOT_OFF(dev) +#define DQUOT_INIT(inode) do { } while(0) +#define DQUOT_DROP(inode) do { } while(0) +#define DQUOT_PREALLOC_BLOCK(sb, inode, nr) (0) +#define DQUOT_ALLOC_BLOCK(sb, inode, nr) (0) +#define DQUOT_ALLOC_INODE(sb, inode) (0) +#define DQUOT_FREE_BLOCK(sb, inode, nr) do { } while(0) +#define DQUOT_FREE_INODE(sb, inode) do { } while(0) +#define DQUOT_SYNC(dev) do { } while(0) +#define DQUOT_OFF(dev) do { } while(0) /* * Special case expands to a simple notify_change. */ -#define DQUOT_TRANSFER(dentry, iattr) \ -error = notify_change(dentry, &iattr) +#define DQUOT_TRANSFER(dentry, iattr) notify_change(dentry, iattr) #endif /* CONFIG_QUOTA */ #endif /* _LINUX_QUOTAOPS_ */ diff -u --recursive --new-file v2.1.101/linux/include/linux/skbuff.h linux/include/linux/skbuff.h --- v2.1.101/linux/include/linux/skbuff.h Mon Apr 6 17:41:01 1998 +++ linux/include/linux/skbuff.h Thu May 14 14:37:58 1998 @@ -96,7 +96,9 @@ unsigned char *tail; /* Tail pointer */ unsigned char *end; /* End pointer */ void (*destructor)(struct sk_buff *); /* Destruct function */ - +#ifdef CONFIG_IP_FIREWALL + __u32 fwmark; /* Label made by fwchains, used by pktsched */ +#endif #if defined(CONFIG_SHAPER) || defined(CONFIG_SHAPER_MODULE) __u32 shapelatency; /* Latency on frame */ __u32 shapeclock; /* Time it should go out */ diff -u --recursive --new-file v2.1.101/linux/include/linux/socket.h linux/include/linux/socket.h --- v2.1.101/linux/include/linux/socket.h Sat May 2 14:19:54 1998 +++ linux/include/linux/socket.h Thu May 14 10:26:22 1998 @@ -156,6 +156,7 @@ #define AF_ASH 18 /* Ash */ #define AF_ECONET 19 /* Acorn Econet */ #define AF_ATMSVC 20 /* ATM SVCs */ +#define AF_SNA 22 /* Linux SNA Project (nutters!) */ #define AF_MAX 32 /* For now.. */ /* Protocol families, same as address families. */ @@ -181,6 +182,7 @@ #define PF_PACKET AF_PACKET #define PF_ASH AF_ASH #define PF_ATMSVC AF_ATMSVC +#define PF_SNA AF_SNA #define PF_MAX AF_MAX diff -u --recursive --new-file v2.1.101/linux/include/net/ip.h linux/include/net/ip.h --- v2.1.101/linux/include/net/ip.h Sat May 2 14:19:54 1998 +++ linux/include/net/ip.h Thu May 14 14:40:52 1998 @@ -94,11 +94,6 @@ extern int ip_mr_input(struct sk_buff *skb); extern int ip_output(struct sk_buff *skb); extern int ip_mc_output(struct sk_buff *skb); -#ifdef CONFIG_IP_ACCT -extern int ip_acct_output(struct sk_buff *skb); -#else -#define ip_acct_output dev_queue_xmit -#endif extern void ip_fragment(struct sk_buff *skb, int (*out)(struct sk_buff*)); extern int ip_do_nat(struct sk_buff *skb); extern void ip_send_check(struct iphdr *ip); diff -u --recursive --new-file v2.1.101/linux/include/net/ip6_fib.h linux/include/net/ip6_fib.h --- v2.1.101/linux/include/net/ip6_fib.h Tue Mar 10 10:03:35 1998 +++ linux/include/net/ip6_fib.h Thu May 14 10:26:22 1998 @@ -141,7 +141,9 @@ extern void inet6_rt_notify(int event, struct rt6_info *rt); -extern void fib6_run_gc(unsigned long dummy); +extern void fib6_run_gc(unsigned long dummy); + +extern void fib6_gc_cleanup(void); #endif #endif diff -u --recursive --new-file v2.1.101/linux/include/net/ipv6.h linux/include/net/ipv6.h --- v2.1.101/linux/include/net/ipv6.h Thu May 7 22:51:55 1998 +++ linux/include/net/ipv6.h Thu May 14 14:41:01 1998 @@ -4,7 +4,7 @@ * Authors: * Pedro Roque * - * $Id: ipv6.h,v 1.10 1998/04/30 16:24:14 freitag Exp $ + * $Id: ipv6.h,v 1.11 1998/05/07 15:42:46 davem Exp $ * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License @@ -266,11 +266,16 @@ int optname, char *optval, int *optlen); +extern void ipv6_packet_init(void); -extern void ipv6_init(void); -extern void ipv6_cleanup(void); -#endif -#endif +extern void ipv6_netdev_notif_init(void); + +extern void ipv6_packet_cleanup(void); + +extern void ipv6_netdev_notif_cleanup(void); + +#endif /* __KERNEL__ */ +#endif /* _NET_IPV6_H */ diff -u --recursive --new-file v2.1.101/linux/include/net/ndisc.h linux/include/net/ndisc.h --- v2.1.101/linux/include/net/ndisc.h Thu May 7 22:51:55 1998 +++ linux/include/net/ndisc.h Thu May 14 14:41:01 1998 @@ -56,7 +56,8 @@ }; -extern void ndisc_init(struct net_proto_family *ops); +extern int ndisc_init(struct net_proto_family *ops); + extern void ndisc_cleanup(void); extern int ndisc_rcv(struct sk_buff *skb, @@ -91,7 +92,9 @@ /* * IGMP */ -extern void igmp6_init(struct net_proto_family *ops); +extern int igmp6_init(struct net_proto_family *ops); + +extern void igmp6_cleanup(void); extern int igmp6_event_query(struct sk_buff *skb, struct icmp6hdr *hdr, diff -u --recursive --new-file v2.1.101/linux/include/net/sock.h linux/include/net/sock.h --- v2.1.101/linux/include/net/sock.h Sat May 2 14:19:54 1998 +++ linux/include/net/sock.h Thu May 14 14:38:43 1998 @@ -126,12 +126,6 @@ unsigned char node[IPX_NODE_LEN]; #endif unsigned short type; -/* - * To handle asynchronous messages from the NetWare server, we have to - * know the connection this socket belongs to. - */ - struct ncp_server *ncp_server; - }; #endif diff -u --recursive --new-file v2.1.101/linux/kernel/sys.c linux/kernel/sys.c --- v2.1.101/linux/kernel/sys.c Fri May 8 23:14:57 1998 +++ linux/kernel/sys.c Fri May 8 23:03:57 1998 @@ -4,7 +4,6 @@ * Copyright (C) 1991, 1992 Linus Torvalds */ -#include #include #include #include diff -u --recursive --new-file v2.1.101/linux/net/802/hippi.c linux/net/802/hippi.c --- v2.1.101/linux/net/802/hippi.c Fri May 8 23:14:57 1998 +++ linux/net/802/hippi.c Fri May 8 23:03:57 1998 @@ -32,7 +32,6 @@ #include #include #include -#include #include #include #include diff -u --recursive --new-file v2.1.101/linux/net/README linux/net/README --- v2.1.101/linux/net/README Sun Sep 7 14:00:24 1997 +++ linux/net/README Thu May 14 10:26:22 1998 @@ -4,7 +4,7 @@ Code Section Bug Report Contact -------------------+------------------------------------------- 802 [other ] alan@lxorguk.ukuu.org.uk - [token ring ] pnorton@cts.com + [token ring ] p.norton@computer.org appletalk Jay.Schulist@spacs.k12.wi.us ax25 g4klx@g4klx.demon.co.uk core alan@lxorguk.ukuu.org.uk diff -u --recursive --new-file v2.1.101/linux/net/core/rtnetlink.c linux/net/core/rtnetlink.c --- v2.1.101/linux/net/core/rtnetlink.c Fri May 8 23:14:57 1998 +++ linux/net/core/rtnetlink.c Thu May 14 10:26:22 1998 @@ -348,6 +348,8 @@ } if (kind == 2 && nlh->nlmsg_flags&NLM_F_DUMP) { + int rlen; + if (link->dumpit == NULL) link = &(rtnetlink_links[PF_UNSPEC][type]); @@ -364,7 +366,10 @@ atomic_dec(&rtnl_rlockct); return -1; } - skb_pull(skb, NLMSG_ALIGN(nlh->nlmsg_len)); + rlen = NLMSG_ALIGN(nlh->nlmsg_len); + if (rlen > skb->len) + rlen = skb->len; + skb_pull(skb, rlen); return -1; } diff -u --recursive --new-file v2.1.101/linux/net/core/scm.c linux/net/core/scm.c --- v2.1.101/linux/net/core/scm.c Thu May 7 22:51:55 1998 +++ linux/net/core/scm.c Thu May 14 10:26:22 1998 @@ -50,7 +50,7 @@ creds->uid == current->suid) || capable(CAP_SETUID)) && ((creds->gid == current->gid || creds->gid == current->egid || creds->gid == current->sgid) || capable(CAP_SETGID))) { - return 0; + return 0; } return -EPERM; } diff -u --recursive --new-file v2.1.101/linux/net/core/skbuff.c linux/net/core/skbuff.c --- v2.1.101/linux/net/core/skbuff.c Wed Apr 1 20:11:55 1998 +++ linux/net/core/skbuff.c Thu May 14 10:26:22 1998 @@ -179,6 +179,9 @@ skb->ip_summed = 0; skb->security = 0; /* By default packets are insecure */ skb->dst = NULL; +#ifdef CONFIG_IP_FIREWALL_CHAINS + skb->fwmark = 0; +#endif memset(skb->cb, 0, sizeof(skb->cb)); skb->priority = 0; } diff -u --recursive --new-file v2.1.101/linux/net/ipv4/Config.in linux/net/ipv4/Config.in --- v2.1.101/linux/net/ipv4/Config.in Mon Feb 23 18:12:12 1998 +++ linux/net/ipv4/Config.in Thu May 14 10:26:23 1998 @@ -31,12 +31,10 @@ define_bool CONFIG_NETLINK_DEV y fi fi - bool 'IP: firewall packet logging' CONFIG_IP_FIREWALL_VERBOSE bool 'IP: transparent proxy support' CONFIG_IP_TRANSPARENT_PROXY bool 'IP: always defragment' CONFIG_IP_ALWAYS_DEFRAG fi fi -bool 'IP: accounting' CONFIG_IP_ACCT if [ "$CONFIG_IP_FIREWALL" = "y" ]; then bool 'IP: masquerading' CONFIG_IP_MASQUERADE if [ "$CONFIG_IP_MASQUERADE" != "n" ]; then diff -u --recursive --new-file v2.1.101/linux/net/ipv4/Makefile linux/net/ipv4/Makefile --- v2.1.101/linux/net/ipv4/Makefile Wed Dec 10 09:45:16 1997 +++ linux/net/ipv4/Makefile Thu May 14 10:26:23 1998 @@ -12,12 +12,16 @@ ip_input.o ip_fragment.o ip_forward.o ip_options.o \ ip_output.o ip_sockglue.o \ tcp.o tcp_input.o tcp_output.o tcp_timer.o tcp_ipv4.o\ - raw.o udp.o arp.o icmp.o devinet.o af_inet.o igmp.o ip_fw.o \ + raw.o udp.o arp.o icmp.o devinet.o af_inet.o igmp.o \ sysctl_net_ipv4.o fib_frontend.o fib_semantics.o fib_hash.o IPV4X_OBJS := MOD_LIST_NAME := IPV4_MODULES M_OBJS := + +ifeq ($(CONFIG_IP_FIREWALL),y) +IPV4_OBJS += ip_fw.o +endif ifeq ($(CONFIG_IP_MULTIPLE_TABLES),y) IPV4_OBJS += fib_rules.o diff -u --recursive --new-file v2.1.101/linux/net/ipv4/af_inet.c linux/net/ipv4/af_inet.c --- v2.1.101/linux/net/ipv4/af_inet.c Fri May 8 23:14:57 1998 +++ linux/net/ipv4/af_inet.c Thu May 14 10:26:23 1998 @@ -5,7 +5,7 @@ * * PF_INET protocol family socket handler. * - * Version: $Id: af_inet.c,v 1.72 1998/05/03 14:30:49 alan Exp $ + * Version: $Id: af_inet.c,v 1.74 1998/05/08 21:06:24 davem Exp $ * * Authors: Ross Biro, * Fred N. van Kempen, @@ -1129,9 +1129,10 @@ /* * Set the firewalling up */ -#if defined(CONFIG_IP_ACCT)||defined(CONFIG_IP_FIREWALL) +#if defined(CONFIG_IP_FIREWALL) ip_fw_init(); #endif + #ifdef CONFIG_IP_MASQUERADE ip_masq_init(); #endif diff -u --recursive --new-file v2.1.101/linux/net/ipv4/arp.c linux/net/ipv4/arp.c --- v2.1.101/linux/net/ipv4/arp.c Tue Mar 17 22:18:16 1998 +++ linux/net/ipv4/arp.c Thu May 14 10:26:23 1998 @@ -1,6 +1,6 @@ /* linux/net/inet/arp.c * - * Version: $Id: arp.c,v 1.65 1998/03/08 20:52:34 davem Exp $ + * Version: $Id: arp.c,v 1.66 1998/05/08 01:54:55 davem Exp $ * * Copyright (C) 1994 by Florian La Roche * @@ -135,8 +135,8 @@ arp_error_report, neigh_resolve_output, neigh_connected_output, - ip_acct_output, - ip_acct_output + dev_queue_xmit, + dev_queue_xmit }; static struct neigh_ops arp_hh_ops = @@ -147,8 +147,8 @@ arp_error_report, neigh_resolve_output, neigh_resolve_output, - ip_acct_output, - ip_acct_output + dev_queue_xmit, + dev_queue_xmit }; static struct neigh_ops arp_direct_ops = @@ -157,10 +157,10 @@ NULL, NULL, NULL, - ip_acct_output, - ip_acct_output, - ip_acct_output, - ip_acct_output + dev_queue_xmit, + dev_queue_xmit, + dev_queue_xmit, + dev_queue_xmit }; #if defined(CONFIG_AX25) || defined(CONFIG_AX25) || \ @@ -173,8 +173,8 @@ arp_error_report, neigh_compat_output, neigh_compat_output, - ip_acct_output, - ip_acct_output, + dev_queue_xmit, + dev_queue_xmit, }; #endif diff -u --recursive --new-file v2.1.101/linux/net/ipv4/devinet.c linux/net/ipv4/devinet.c --- v2.1.101/linux/net/ipv4/devinet.c Fri May 8 23:14:57 1998 +++ linux/net/ipv4/devinet.c Thu May 14 10:26:23 1998 @@ -1,7 +1,7 @@ /* * NET3 IP device support routines. * - * Version: $Id: devinet.c,v 1.21 1998/05/03 14:30:52 alan Exp $ + * Version: $Id: devinet.c,v 1.22 1998/05/08 21:06:26 davem Exp $ * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License diff -u --recursive --new-file v2.1.101/linux/net/ipv4/fib_frontend.c linux/net/ipv4/fib_frontend.c --- v2.1.101/linux/net/ipv4/fib_frontend.c Thu May 7 22:51:56 1998 +++ linux/net/ipv4/fib_frontend.c Thu May 14 10:26:23 1998 @@ -5,7 +5,7 @@ * * IPv4 Forwarding Information Base: FIB frontend. * - * Version: $Id: fib_frontend.c,v 1.9 1998/03/08 20:52:36 davem Exp $ + * Version: $Id: fib_frontend.c,v 1.10 1998/05/08 21:06:27 davem Exp $ * * Authors: Alexey Kuznetsov, * diff -u --recursive --new-file v2.1.101/linux/net/ipv4/ip_fw.c linux/net/ipv4/ip_fw.c --- v2.1.101/linux/net/ipv4/ip_fw.c Thu May 7 22:51:56 1998 +++ linux/net/ipv4/ip_fw.c Thu May 14 10:26:23 1998 @@ -1,96 +1,44 @@ /* - * IP firewalling code. This is taken from 4.4BSD. Please note the - * copyright message below. As per the GPL it must be maintained - * and the licenses thus do not conflict. While this port is subject - * to the GPL I also place my modifications under the original - * license in recognition of the original copyright. - * -- Alan Cox. + * This code is heavily based on the code in ip_fw.c; see that file for + * copyrights and attributions. This code is basically GPL. * - * $Id: ip_fw.c,v 1.35 1998/04/30 16:29:51 freitag Exp $ - * - * Ported from BSD to Linux, - * Alan Cox 22/Nov/1994. - * Zeroing /proc and other additions - * Jos Vos 4/Feb/1995. - * Merged and included the FreeBSD-Current changes at Ugen's request - * (but hey it's a lot cleaner now). Ugen would prefer in some ways - * we waited for his final product but since Linux 1.2.0 is about to - * appear it's not practical - Read: It works, it's not clean but please - * don't consider it to be his standard of finished work. - * Alan Cox 12/Feb/1995 - * Porting bidirectional entries from BSD, fixing accounting issues, - * adding struct ip_fwpkt for checking packets with interface address - * Jos Vos 5/Mar/1995. - * Established connections (ACK check), ACK check on bidirectional rules, - * ICMP type check. - * Wilfred Mollenvanger 7/7/1995. - * TCP attack protection. - * Alan Cox 25/8/95, based on information from bugtraq. - * ICMP type printk, IP_FW_F_APPEND - * Bernd Eckenfels 1996-01-31 - * Split blocking chain into input and output chains, add new "insert" and - * "append" commands to replace semi-intelligent "add" command, let "delete". - * only delete the first matching entry, use 0xFFFF (0xFF) as ports (ICMP - * types) when counting packets being 2nd and further fragments. - * Jos Vos 8/2/1996. - * Add support for matching on device names. - * Jos Vos 15/2/1996. - * Transparent proxying support. - * Willy Konynenberg 10/5/96. - * Make separate accounting on incoming and outgoing packets possible. - * Jos Vos 18/5/1996. - * Added trap out of bad frames. - * Alan Cox 17/11/1996 - * - * - * Masquerading functionality - * - * Copyright (c) 1994 Pauline Middelink - * - * The pieces which added masquerading functionality are totally - * my responsibility and have nothing to with the original authors - * copyright or doing. - * - * Parts distributed under GPL. - * - * Fixes: - * Pauline Middelink : Added masquerading. - * Alan Cox : Fixed an error in the merge. - * Thomas Quinot : Fixed port spoofing. - * Alan Cox : Cleaned up retransmits in spoofing. - * Alan Cox : Cleaned up length setting. - * Wouter Gadeyne : Fixed masquerading support of ftp PORT commands - * - * Juan Jose Ciarlante : Masquerading code moved to ip_masq.c - * Andi Kleen : Print frag_offsets and the ip flags properly. - * - * All the real work was done by ..... - * - */ - - -/* - * Copyright (c) 1993 Daniel Boulet - * Copyright (c) 1994 Ugen J.S.Antsilevich - * - * Redistribution and use in source forms, with and without modification, - * are permitted provided that this entire comment appears intact. - * - * Redistribution in binary form may occur without any restrictions. - * Obviously, it would be nice if you gave credit where credit is due - * but requiring it would be too onerous. - * - * This software is provided ``AS IS'' without any warranties of any kind. + * 15-Aug-1997: Major changes to allow graphs for firewall rules. + * Paul Russell and + * Michael Neuling + * 24-Aug-1997: Generalised protocol handling (not just TCP/UDP/ICMP). + * Added explicit RETURN from chains. + * Removed TOS mangling (done in ipchains 1.0.1). + * Fixed read & reset bug by reworking proc handling. + * Paul Russell + * 28-Sep-1997: Added packet marking for net sched code. + * Removed fw_via comparisons: all done on device name now, + * similar to changes in ip_fw.c in DaveM's CVS970924 tree. + * Paul Russell + * 2-Nov-1997: Moved types across to __u16, etc. + * Added inverse flags. + * Fixed fragment bug (in args to port_match). + * Changed mark to only one flag (MARKABS). + * 21-Nov-1997: Added ability to test ICMP code. + * 19-Jan-1998: Added wildcard interfaces. + * 6-Feb-1998: Merged 2.0 and 2.1 versions. + * Initialised ip_masq for 2.0.x version. + * Added explicit NETLINK option for 2.1.x version. + * Added packet and byte counters for policy matches. + * 26-Feb-1998: Fixed race conditions, added SMP support. + * 18-Mar-1998: Fix SMP, fix race condition fix. + * 1-May-1998: Remove caching of device pointer, added caching + * for proc output (no longer order n^2). */ #include + #include #include #include -#include #include #include #include +#include #include #include @@ -107,9 +55,9 @@ #include #include #include +#include #include #include -#include #ifdef CONFIG_IP_MASQUERADE #include @@ -119,223 +67,494 @@ #include #include +/* Understanding locking in this code: (thanks to Alan Cox for using + * little words to explain this to me). -- PR + * + * In UP, there can be two packets traversing the chains: + * 1) A packet from the current userspace context + * 2) A packet off the bh handlers (timer or net). + * + * For SMP (kernel v2.1+), multiply this by # CPUs. + * + * This means counters and backchains can get corrupted if no precautions + * are taken. + * + * To actually alter a chain on UP, we need only do a cli(), as this will + * stop a bh handler firing, as we are in the current userspace context + * (coming from a setsockopt()). + * + * On SMP, we need a write_lock_irqsave(), which is a simple cli() in + * UP. + * + * For backchains and counters, we use an array, indexed by + * [smp_processor_id()*2 + !in_interrupt()]; the array is of size + * [smp_num_cpus*2]. For v2.0, smp_num_cpus is effectively 1. So, + * confident of uniqueness, we modify counters even though we only + * have a read lock (to read the counters, you need a write lock, + * though). */ + +/* Why I didn't use straight locking... -- PR + * + * The backchains can be separated out of the ip_chains structure, and + * allocated as needed inside ip_fw_check(). + * + * The counters, however, can't. Trying to lock these means blocking + * interrupts every time we want to access them. This would suck HARD + * performance-wise. Not locking them leads to possible corruption, + * made worse on 32-bit machines (counters are 64-bit). */ + +/*#define DEBUG_IP_FIREWALL*/ +/*#define DEBUG_ALLOW_ALL*/ /* Useful for remote debugging */ +/*#define DEBUG_IP_FIREWALL_USER*/ +/*#define DEBUG_IP_FIREWALL_LOCKING*/ + +#ifdef CONFIG_IP_FIREWALL_NETLINK +static struct sock *ipfwsk; +#endif + +#define SLOT_NUMBER() (smp_processor_id()*2 + !in_interrupt()) +#define NUM_SLOTS (smp_num_cpus*2) + +#define SIZEOF_STRUCT_IP_CHAIN (sizeof(struct ip_chain) \ + + NUM_SLOTS*sizeof(struct ip_reent)) +#define SIZEOF_STRUCT_IP_FW_KERNEL (sizeof(struct ip_fwkernel) \ + + NUM_SLOTS*sizeof(struct ip_counters)) + +#ifdef DEBUG_IP_FIREWALL_LOCKING +static unsigned int fwc_rlocks, fwc_wlocks; +#define FWC_DEBUG_LOCK(d) \ +do { \ + FWC_DONT_HAVE_LOCK(d); \ + d |= (1 << SLOT_NUMBER()); \ +} while (0) + +#define FWC_DEBUG_UNLOCK(d) \ +do { \ + FWC_HAVE_LOCK(d); \ + d &= ~(1 << SLOT_NUMBER()); \ +} while (0) + +#define FWC_DONT_HAVE_LOCK(d) \ +do { \ + if ((d) & (1 << SLOT_NUMBER())) \ + printk("%s:%i: Got lock on %i already!\n", \ + __FILE__, __LINE__, SLOT_NUMBER()); \ +} while(0) + +#define FWC_HAVE_LOCK(d) \ +do { \ + if (!((d) & (1 << SLOT_NUMBER()))) \ + printk("%s:%i:No lock on %i!\n", \ + __FILE__, __LINE__, SLOT_NUMBER()); \ +} while (0) + +#else +#define FWC_DEBUG_LOCK(d) do { } while(0) +#define FWC_DEBUG_UNLOCK(d) do { } while(0) +#define FWC_DONT_HAVE_LOCK(d) do { } while(0) +#define FWC_HAVE_LOCK(d) do { } while(0) +#endif /*DEBUG_IP_FIRWALL_LOCKING*/ + +#define FWC_READ_LOCK(l) do { FWC_DEBUG_LOCK(fwc_rlocks); read_lock(l); } while (0) +#define FWC_WRITE_LOCK(l) do { FWC_DEBUG_LOCK(fwc_wlocks); write_lock(l); } while (0) +#define FWC_READ_LOCK_IRQ(l,f) do { FWC_DEBUG_LOCK(fwc_rlocks); read_lock_irqsave(l,f); } while (0) +#define FWC_WRITE_LOCK_IRQ(l,f) do { FWC_DEBUG_LOCK(fwc_wlocks); write_lock_irqsave(l,f); } while (0) +#define FWC_READ_UNLOCK(l) do { FWC_DEBUG_UNLOCK(fwc_rlocks); read_unlock(l); } while (0) +#define FWC_WRITE_UNLOCK(l) do { FWC_DEBUG_UNLOCK(fwc_wlocks); write_unlock(l); } while (0) +#define FWC_READ_UNLOCK_IRQ(l,f) do { FWC_DEBUG_UNLOCK(fwc_rlocks); read_unlock_irqrestore(l,f); } while (0) +#define FWC_WRITE_UNLOCK_IRQ(l,f) do { FWC_DEBUG_UNLOCK(fwc_wlocks); write_unlock_irqrestore(l,f); } while (0) + +struct ip_chain; + +struct ip_counters +{ + __u64 pcnt, bcnt; /* Packet and byte counters */ +}; + +struct ip_fwkernel +{ + struct ip_fw ipfw; + struct ip_fwkernel *next; /* where to go next if current + * rule doesn't match */ + struct ip_chain *branch; /* which branch to jump to if + * current rule matches */ + int simplebranch; /* Use this if branch == NULL */ + struct ip_counters counters[0]; /* Actually several of these */ +}; + +struct ip_reent +{ + struct ip_chain *prevchain; /* Pointer to referencing chain */ + struct ip_fwkernel *prevrule; /* Pointer to referencing rule */ + struct ip_counters counters; +}; + +struct ip_chain +{ + ip_chainlabel label; /* Defines the label for each block */ + struct ip_chain *next; /* Pointer to next block */ + struct ip_fwkernel *chain; /* Pointer to first rule in block */ + __u32 refcount; /* Number of refernces to block */ + int policy; /* Default rule for chain. Only * + * used in built in chains */ + struct ip_reent reent[0]; /* Actually several of these */ +}; + /* * Implement IP packet firewall */ #ifdef DEBUG_IP_FIREWALL -#define dprintf1(a) printk(a) -#define dprintf2(a1,a2) printk(a1,a2) -#define dprintf3(a1,a2,a3) printk(a1,a2,a3) -#define dprintf4(a1,a2,a3,a4) printk(a1,a2,a3,a4) +#define dprintf(format, args...) printk(format , ## args) #else -#define dprintf1(a) -#define dprintf2(a1,a2) -#define dprintf3(a1,a2,a3) -#define dprintf4(a1,a2,a3,a4) +#define dprintf(format, args...) #endif -#define print_ip(a) printk("%ld.%ld.%ld.%ld",(ntohl(a)>>24)&0xFF,\ - (ntohl(a)>>16)&0xFF,\ - (ntohl(a)>>8)&0xFF,\ - (ntohl(a))&0xFF); - -#ifdef DEBUG_IP_FIREWALL -#define dprint_ip(a) print_ip(a) +#ifdef DEBUG_IP_FIREWALL_USER +#define duprintf(format, args...) printk(format , ## args) #else -#define dprint_ip(a) +#define duprintf(format, args...) #endif -#if defined(CONFIG_IP_ACCT) || defined(CONFIG_IP_FIREWALL) +/* Lock around ip_fw_chains linked list structure */ +spinlock_t ip_fw_lock = SPIN_LOCK_UNLOCKED; -struct ip_fw *ip_fw_fwd_chain; -struct ip_fw *ip_fw_in_chain; -struct ip_fw *ip_fw_out_chain; -struct ip_fw *ip_acct_chain; -struct ip_fw *ip_masq_chain; - -static struct ip_fw **chains[] = - {&ip_fw_fwd_chain, &ip_fw_in_chain, &ip_fw_out_chain, &ip_acct_chain, - &ip_masq_chain - }; -#endif /* CONFIG_IP_ACCT || CONFIG_IP_FIREWALL */ - -#ifdef CONFIG_IP_FIREWALL -int ip_fw_fwd_policy=IP_FW_F_ACCEPT; -int ip_fw_in_policy=IP_FW_F_ACCEPT; -int ip_fw_out_policy=IP_FW_F_ACCEPT; +/* Head of linked list of fw rules */ +static struct ip_chain *ip_fw_chains; -static int *policies[] = - {&ip_fw_fwd_policy, &ip_fw_in_policy, &ip_fw_out_policy}; +#define IP_FW_INPUT_CHAIN ip_fw_chains +#define IP_FW_FORWARD_CHAIN (ip_fw_chains->next) +#define IP_FW_OUTPUT_CHAIN (ip_fw_chains->next->next) -#endif +/* Returns 1 if the port is matched by the range, 0 otherwise */ +extern inline int port_match(__u16 min, __u16 max, __u16 port, + int frag, int invert) +{ + if (frag) /* Fragments fail ANY port test. */ + return (min == 0 && max == 0xFFFF); + else return (port >= min && port <= max) ^ invert; +} -#ifdef CONFIG_IP_FIREWALL_NETLINK -struct sock *ipfwsk; -#endif +/* Returns whether matches rule or not. */ +static int ip_rule_match(struct ip_fwkernel *f, + const char *ifname, + struct iphdr *ip, + char tcpsyn, + __u16 src_port, __u16 dst_port, + char isfrag) +{ +#define FWINV(bool,invflg) ((bool) ^ !!(f->ipfw.fw_invflg & invflg)) + /* + * This is a bit simpler as we don't have to walk + * an interface chain as you do in BSD - same logic + * however. + */ -/* - * Returns 1 if the port is matched by the vector, 0 otherwise - */ + if (FWINV((ip->saddr&f->ipfw.fw_smsk.s_addr) != f->ipfw.fw_src.s_addr, + IP_FW_INV_SRCIP) + || FWINV((ip->daddr&f->ipfw.fw_dmsk.s_addr)!=f->ipfw.fw_dst.s_addr, + IP_FW_INV_DSTIP)) { + dprintf("Source or dest mismatch.\n"); + + dprintf("SRC: %u. Mask: %u. Target: %u.%s\n", ip->saddr, + f->ipfw.fw_smsk.s_addr, f->ipfw.fw_src.s_addr, + f->ipfw.fw_invflg & IP_FW_INV_SRCIP ? " (INV)" : ""); + dprintf("DST: %u. Mask: %u. Target: %u.%s\n", ip->daddr, + f->ipfw.fw_dmsk.s_addr, f->ipfw.fw_dst.s_addr, + f->ipfw.fw_invflg & IP_FW_INV_DSTIP ? " (INV)" : ""); + return 0; + } -extern inline int port_match(unsigned short *portptr,int nports,unsigned short port,int range_flag) -{ - if (!nports) - return 1; - if ( range_flag ) - { - if ( portptr[0] <= port && port <= portptr[1] ) - { - return( 1 ); - } - nports -= 2; - portptr += 2; + /* + * Look for a VIA device match + */ + if (f->ipfw.fw_flg & IP_FW_F_WILDIF) { + if (FWINV(strncmp(ifname, f->ipfw.fw_vianame, + strlen(f->ipfw.fw_vianame)) != 0, + IP_FW_INV_VIA)) { + dprintf("Wildcard interface mismatch.%s\n", + f->ipfw.fw_invflg & IP_FW_INV_VIA ? " (INV)" : ""); + return 0; /* Mismatch */ + } + } + else if (FWINV(strcmp(ifname, f->ipfw.fw_vianame) != 0, + IP_FW_INV_VIA)) { + dprintf("Interface name does not match.%s\n", + f->ipfw.fw_invflg & IP_FW_INV_VIA + ? " (INV)" : ""); + return 0; /* Mismatch */ } - while ( nports-- > 0 ) - { - if ( *portptr++ == port ) - { - return( 1 ); - } + + /* + * Ok the chain addresses match. + */ + + /* If we have a fragment rule but the packet is not a fragment + * the we return zero */ + if (FWINV((f->ipfw.fw_flg&IP_FW_F_FRAG) && !isfrag, IP_FW_INV_FRAG)) { + dprintf("Fragment rule but not fragment.%s\n", + f->ipfw.fw_invflg & IP_FW_INV_FRAG ? " (INV)" : ""); + return 0; } - return(0); -} -#if defined(CONFIG_IP_ACCT) || defined(CONFIG_IP_FIREWALL) + /* Fragment NEVER passes a SYN test, even an inverted one. */ + if (FWINV((f->ipfw.fw_flg&IP_FW_F_TCPSYN) && !tcpsyn, IP_FW_INV_SYN) + || (isfrag && (f->ipfw.fw_flg&IP_FW_F_TCPSYN))) { + dprintf("Rule requires SYN and packet has no SYN.%s\n", + f->ipfw.fw_invflg & IP_FW_INV_SYN ? " (INV)" : ""); + return 0; + } -#ifdef CONFIG_IP_FIREWALL_VERBOSE + if (f->ipfw.fw_proto) { + /* + * Specific firewall - packet's protocol + * must match firewall's. + */ -/* - * VERY ugly piece of code which actually makes kernel printf for - * matching packets. - */ + if (FWINV(ip->protocol!=f->ipfw.fw_proto, IP_FW_INV_PROTO)) { + dprintf("Packet protocol %hi does not match %hi.%s\n", + ip->protocol, f->ipfw.fw_proto, + f->ipfw.fw_invflg&IP_FW_INV_PROTO ? " (INV)":""); + return 0; + } + + /* For non TCP/UDP/ICMP, port range is max anyway. */ + if (!port_match(f->ipfw.fw_spts[0], + f->ipfw.fw_spts[1], + src_port, isfrag, + !!(f->ipfw.fw_invflg&IP_FW_INV_SRCPT)) + || !port_match(f->ipfw.fw_dpts[0], + f->ipfw.fw_dpts[1], + dst_port, isfrag, + !!(f->ipfw.fw_invflg + &IP_FW_INV_DSTPT))) { + dprintf("Port match failed.\n"); + return 0; + } + } -static char *chain_name(struct ip_fw *chain, int mode) -{ - switch (mode) { - case IP_FW_MODE_ACCT_IN: return "acct in"; - case IP_FW_MODE_ACCT_OUT: return "acct out"; + dprintf("Match succeeded.\n"); + return 1; +} + +static const char *branchname(struct ip_chain *branch,int simplebranch) +{ + if (branch) + return branch->label; + switch (simplebranch) + { + case FW_BLOCK: return IP_FW_LABEL_BLOCK; + case FW_ACCEPT: return IP_FW_LABEL_ACCEPT; + case FW_REJECT: return IP_FW_LABEL_REJECT; + case FW_REDIRECT: return IP_FW_LABEL_REDIRECT; + case FW_MASQUERADE: return IP_FW_LABEL_MASQUERADE; + case FW_SKIP: return "-"; + case FW_SKIP+1: return IP_FW_LABEL_RETURN; default: - if (chain == ip_fw_fwd_chain) - return "fw-fwd"; - else if (chain == ip_fw_in_chain) - return "fw-in"; - else - return "fw-out"; + return "UNKNOWN"; } } -static char *rule_name(struct ip_fw *f, int mode, char *buf) +/* + * VERY ugly piece of code which actually + * makes kernel printf for matching packets... + */ +static void dump_packet(const struct iphdr *ip, + const char *ifname, + struct ip_fwkernel *f, + const ip_chainlabel chainlabel, + __u16 src_port, + __u16 dst_port) { - if (mode == IP_FW_MODE_ACCT_IN || mode == IP_FW_MODE_ACCT_OUT) - return ""; + __u32 *opt = (__u32 *) (ip + 1); + int opti; + + if (f) + { + printk(KERN_INFO "Packet log: %s ",chainlabel); + + printk("%s ",branchname(f->branch,f->simplebranch)); + if (f->simplebranch==FW_REDIRECT) + printk("%d ",f->ipfw.fw_redirpt); + } + + printk("%s PROTO=%d %ld.%ld.%ld.%ld:%hu %ld.%ld.%ld.%ld:%hu" + " L=%hu S=0x%2.2hX I=%hu F=0x%4.4hX T=%hu", + ifname, ip->protocol, + (ntohl(ip->saddr)>>24)&0xFF, + (ntohl(ip->saddr)>>16)&0xFF, + (ntohl(ip->saddr)>>8)&0xFF, + (ntohl(ip->saddr))&0xFF, + src_port, + (ntohl(ip->daddr)>>24)&0xFF, + (ntohl(ip->daddr)>>16)&0xFF, + (ntohl(ip->daddr)>>8)&0xFF, + (ntohl(ip->daddr))&0xFF, + dst_port, + ntohs(ip->tot_len), ip->tos, ntohs(ip->id), + ntohs(ip->frag_off), ip->ttl); - if(f->fw_flg&IP_FW_F_ACCEPT) { - if(f->fw_flg&IP_FW_F_REDIR) { - sprintf(buf, "acc/r%d ", f->fw_pts[f->fw_nsp+f->fw_ndp]); - return buf; - } else if(f->fw_flg&IP_FW_F_MASQ) - return "acc/masq "; - else - return "acc "; - } else if(f->fw_flg&IP_FW_F_ICMPRPL) { - return "rej "; - } else { - return "deny "; - } + for (opti = 0; opti < (ip->ihl - sizeof(struct iphdr) / 4); opti++) + printk(" O=0x%8.8X", *opt++); + printk("\n"); } -static void print_packet(struct iphdr *ip, - u16 src_port, u16 dst_port, u16 icmp_type, - char *chain, char *rule, char *devname) +/* function for checking chain labels for user space. Makes sure that + * there are no special characters in the string */ +static int check_label(ip_chainlabel label) { - __u32 *opt = (__u32 *) (ip + 1); - int opti; - __u16 foff = ntohs(ip->frag_off); + unsigned int i; + + for (i = 0; i < IP_FW_MAX_LABEL_LENGTH + 1 && label[i]; i++) + if (label[i] <= ' ') + return 0; + if (i == IP_FW_MAX_LABEL_LENGTH+1) + return 0; + return 1; +} - printk(KERN_INFO "IP %s %s%s", chain, rule, devname); +/* This function returns a pointer to the first chain with a label + * that matches the one given. */ +static struct ip_chain *find_label(ip_chainlabel label) +{ + struct ip_chain *tmp; + FWC_HAVE_LOCK(fwc_rlocks | fwc_wlocks); + for (tmp = ip_fw_chains; tmp; tmp = tmp->next) + if (strcmp(tmp->label,label) == 0) + break; + return tmp; +} - switch(ip->protocol) - { - case IPPROTO_TCP: - printk(" TCP "); - break; - case IPPROTO_UDP: - printk(" UDP "); - break; - case IPPROTO_ICMP: - printk(" ICMP/%d ", icmp_type); - break; - default: - printk(" PROTO=%d ", ip->protocol); - break; +/* This function returns a boolean which when true sets answer to one + of the FW_*. */ +static int find_special(ip_chainlabel label, int *answer) +{ + if (label[0] == '\0') { + *answer = FW_SKIP; /* => pass-through rule */ + return 1; + } else if (strcmp(label,IP_FW_LABEL_ACCEPT) == 0) { + *answer = FW_ACCEPT; + return 1; + } else if (strcmp(label,IP_FW_LABEL_BLOCK) == 0) { + *answer = FW_BLOCK; + return 1; + } else if (strcmp(label,IP_FW_LABEL_REJECT) == 0) { + *answer = FW_REJECT; + return 1; +#ifdef CONFIG_IP_TRANSPARENT_PROXY + } else if (strcmp(label,IP_FW_LABEL_REDIRECT) == 0) { + *answer = FW_REDIRECT; + return 1; +#endif +#ifdef CONFIG_IP_MASQUERADE + } else if (strcmp(label,IP_FW_LABEL_MASQUERADE) == 0) { + *answer = FW_MASQUERADE; + return 1; +#endif + } else if (strcmp(label, IP_FW_LABEL_RETURN) == 0) { + *answer = FW_SKIP+1; + return 1; + } else { + return 0; } - print_ip(ip->saddr); - if(ip->protocol == IPPROTO_TCP || ip->protocol == IPPROTO_UDP) - printk(":%hu", src_port); - printk(" "); - print_ip(ip->daddr); - if(ip->protocol == IPPROTO_TCP || ip->protocol == IPPROTO_UDP) - printk(":%hu", dst_port); - printk(" L=%hu S=0x%2.2hX I=%hu FO=0x%4.4hX T=%hu", - ntohs(ip->tot_len), ip->tos, ntohs(ip->id), - foff & IP_OFFSET, ip->ttl); - if (foff & IP_DF) printk(" DF=1"); - if (foff & IP_MF) printk(" MF=1"); - for (opti = 0; opti < (ip->ihl - sizeof(struct iphdr) / 4); opti++) - printk(" O=0x%8.8X", *opt++); - printk("\n"); } + +/* This function cleans up the prevchain and prevrule. If the verbose + * flag is set then he names of the chains will be printed as it + * cleans up. */ +static void cleanup(struct ip_chain *chain, + const int verbose, + unsigned int slot) +{ + struct ip_chain *tmpchain = chain->reent[slot].prevchain; + if (verbose) + printk(KERN_ERR "Chain backtrace: "); + while (tmpchain) { + if (verbose) + printk("%s<-",chain->label); + chain->reent[slot].prevchain = NULL; + chain = tmpchain; + tmpchain = chain->reent[slot].prevchain; + } + if (verbose) + printk("%s\n",chain->label); +} + +static inline void +ip_fw_domatch(struct ip_fwkernel *f, + const struct iphdr *ip, + const char *rif, + const ip_chainlabel label, + struct sk_buff *skb, + unsigned int slot, + __u16 src_port, __u16 dst_port) +{ + f->counters[slot].bcnt+=ntohs(ip->tot_len); + f->counters[slot].pcnt++; + if (f->ipfw.fw_flg & IP_FW_F_PRN) { + dump_packet(ip,rif,f,label,src_port,dst_port); + } +/* This functionality is useless in stock 2.0.x series, but we don't + * discard the mark thing altogether, to avoid breaking ipchains (and, + * more importantly, the ipfwadm wrapper) --PR */ + if (f->ipfw.fw_flg & IP_FW_F_MARKABS) + skb->fwmark = f->ipfw.fw_mark; + else + skb->fwmark+=f->ipfw.fw_mark; +#ifdef CONFIG_IP_FIREWALL_NETLINK + if (f->ipfw.fw_flg & IP_FW_F_NETLINK) { + size_t len = min(f->ipfw.fw_outputsize, ntohs(ip->tot_len)) + + sizeof(skb->fwmark) + IFNAMSIZ; + struct sk_buff *outskb=alloc_skb(len, GFP_ATOMIC); + + duprintf("Sending packet out NETLINK (length = %u).\n", + (unsigned int)len); + if (outskb) { + /* Prepend mark & interface */ + skb_put(outskb, len); + *((__u32 *)outskb->data) = skb->fwmark; + strcpy(outskb->data+sizeof(__u32), rif); + memcpy(outskb->data+sizeof(__u32)+IFNAMSIZ, ip, + len-(sizeof(__u32)+IFNAMSIZ)); + netlink_broadcast(ipfwsk, outskb, 0, ~0, GFP_KERNEL); + } + else duprintf("netlink post failed - alloc_skb failed!\n"); + } #endif +} /* * Returns one of the generic firewall policies, like FW_ACCEPT. - * Also does accounting so you can feed it the accounting chain. * - * The modes is either IP_FW_MODE_FW (normal firewall mode), - * IP_FW_MODE_ACCT_IN or IP_FW_MODE_ACCT_OUT (accounting mode, - * steps through the entire chain and handles fragments - * differently), or IP_FW_MODE_CHK (handles user-level check, - * counters are not updated). + * The testing is either false for normal firewall mode or true for + * user checking mode (counters are not updated, TOS & mark not done). */ - - -int ip_fw_chk(struct iphdr *ip, struct device *rif, __u16 *redirport, struct ip_fw *chain, int policy, int mode) +static int +ip_fw_check(struct iphdr *ip, + const char *rif, + __u16 *redirport, + struct ip_chain *chain, + struct sk_buff *skb, + unsigned int slot, + int testing) { - struct ip_fw *f; struct tcphdr *tcp=(struct tcphdr *)((__u32 *)ip+ip->ihl); struct udphdr *udp=(struct udphdr *)((__u32 *)ip+ip->ihl); struct icmphdr *icmp=(struct icmphdr *)((__u32 *)ip+ip->ihl); __u32 src, dst; - __u16 src_port=0xFFFF, dst_port=0xFFFF, icmp_type=0xFF; - unsigned short f_prt=0, prt; - char notcpsyn=0, notcpack=0, match; - unsigned short offset; - int answer; - unsigned char tosand, tosxor; - - /* - * If the chain is empty follow policy. The BSD one - * accepts anything giving you a time window while - * flushing and rebuilding the tables. - */ - - src = ip->saddr; - dst = ip->daddr; - - /* - * This way we handle fragmented packets. - * we ignore all fragments but the first one - * so the whole packet can't be reassembled. - * This way we relay on the full info which - * stored only in first packet. - * - * Note that this theoretically allows partial packet - * spoofing. Not very dangerous but paranoid people may - * wish to play with this. It also allows the so called - * "fragment bomb" denial of service attack on some types - * of system. - */ + __u16 src_port = 0xFFFF, dst_port = 0xFFFF; + char tcpsyn=0; + __u16 offset; + unsigned char oldtos; + struct ip_fwkernel *f; + int ret = FW_SKIP+2; + + /* We handle fragments by dealing with the first fragment as + * if it was a normal packet. All other fragments are treated + * normally, except that they will NEVER match rules that ask + * things we don't know, ie. tcp syn flag or ports). If the + * rule is also a fragment-specific rule, non-fragments won't + * match it. */ offset = ntohs(ip->frag_off) & IP_OFFSET; @@ -346,33 +565,52 @@ * checks. */ - if (offset == 1 && ip->protocol == IPPROTO_TCP) - return FW_BLOCK; - - if (offset!=0 && !(mode & (IP_FW_MODE_ACCT_IN|IP_FW_MODE_ACCT_OUT)) && - (ip->protocol == IPPROTO_TCP || ip->protocol == IPPROTO_UDP || - ip->protocol == IPPROTO_ICMP)) - return FW_ACCEPT; - - /* - * Header fragment for TCP is too small to check the bits. - */ - - if(ip->protocol==IPPROTO_TCP && (ip->ihl<<2)+16 > ntohs(ip->tot_len)) + if (offset == 1 && ip->protocol == IPPROTO_TCP) { + if (!testing && net_ratelimit()) { + printk("Suspect TCP fragment.\n"); + dump_packet(ip,rif,NULL,NULL,0,0); + } return FW_BLOCK; - - /* - * Too short. - * - * But only too short for a packet with ports... + } + + /* Check for too-small packets (not non-first fragments). + * For each protocol, we assume that we can get the required + * information, eg. port number or ICMP type. If this fails, + * reject it. + * + * Sizes might as well be rounded up to 8 here, since either + * there are more fragments to come (which must be on 8-byte + * boundaries), or this is a bogus packet anyway. */ - - else if((ntohs(ip->tot_len)<8+(ip->ihl<<2))&&(ip->protocol==IPPROTO_TCP || ip->protocol==IPPROTO_UDP)) - return FW_BLOCK; - + if (offset == 0) { + unsigned int size_req; + switch (ip->protocol) { + case IPPROTO_TCP: + /* Don't care about things past flags word */ + size_req = 16; + break; + + case IPPROTO_UDP: + case IPPROTO_ICMP: + size_req = 8; + break; + + default: + size_req = 0; + } + if (ntohs(ip->tot_len) < (ip->ihl<<2)+size_req) { + if (!testing && net_ratelimit()) { + printk("Packet too short.\n"); + dump_packet(ip,rif,NULL,NULL,0,0); + } + return FW_BLOCK; + } + } + src = ip->saddr; dst = ip->daddr; - + oldtos = ip->tos; + /* * If we got interface from which packet came * we can use the address directly. This is unlike @@ -381,898 +619,1041 @@ * devices instead. */ - dprintf1("Packet "); + dprintf("Packet "); switch(ip->protocol) { case IPPROTO_TCP: - dprintf1("TCP "); - /* ports stay 0xFFFF if it is not the first fragment */ + dprintf("TCP "); if (!offset) { src_port=ntohs(tcp->source); dst_port=ntohs(tcp->dest); - if(!tcp->ack && !tcp->rst) - /* We do NOT have ACK, value TRUE */ - notcpack=1; - if(!tcp->syn || !notcpack) - /* We do NOT have SYN, value TRUE */ - notcpsyn=1; + + /* Connection initilisation can only + * be made when the syn bit is set and + * neither of the ack or reset is + * set. */ + if(tcp->syn && !(tcp->ack || tcp->rst)) + tcpsyn=1; } - prt=IP_FW_F_TCP; break; case IPPROTO_UDP: - dprintf1("UDP "); - /* ports stay 0xFFFF if it is not the first fragment */ + dprintf("UDP "); if (!offset) { src_port=ntohs(udp->source); dst_port=ntohs(udp->dest); } - prt=IP_FW_F_UDP; break; case IPPROTO_ICMP: - /* icmp_type stays 255 if it is not the first fragment */ - if (!offset) - icmp_type=(__u16)(icmp->type); - dprintf2("ICMP:%d ",icmp_type); - prt=IP_FW_F_ICMP; + if (!offset) { + src_port=(__u16)icmp->type; + dst_port=(__u16)icmp->code; + } + dprintf("ICMP "); break; default: - dprintf2("p=%d ",ip->protocol); - prt=IP_FW_F_ALL; + dprintf("p=%d ",ip->protocol); break; } #ifdef DEBUG_IP_FIREWALL - dprint_ip(ip->saddr); + print_ip(ip->saddr); - if (ip->protocol==IPPROTO_TCP || ip->protocol==IPPROTO_UDP) - /* This will print 65535 when it is not the first fragment! */ - dprintf2(":%d ", src_port); - dprint_ip(ip->daddr); - if (ip->protocol==IPPROTO_TCP || ip->protocol==IPPROTO_UDP) - /* This will print 65535 when it is not the first fragment! */ - dprintf2(":%d ",dst_port); - dprintf1("\n"); -#endif - - for (f=chain;f;f=f->fw_next) - { - /* - * This is a bit simpler as we don't have to walk - * an interface chain as you do in BSD - same logic - * however. - */ - - /* - * Match can become 0x01 (a "normal" match was found), - * 0x02 (a reverse match was found), and 0x03 (the - * IP addresses match in both directions). - * Now we know in which direction(s) we should look - * for a match for the TCP/UDP ports. Both directions - * might match (e.g., when both addresses are on the - * same network for which an address/mask is given), but - * the ports might only match in one direction. - * This was obviously wrong in the original BSD code. - */ - match = 0x00; - - if ((src&f->fw_smsk.s_addr)==f->fw_src.s_addr - && (dst&f->fw_dmsk.s_addr)==f->fw_dst.s_addr) - /* normal direction */ - match |= 0x01; - - if ((f->fw_flg & IP_FW_F_BIDIR) && - (dst&f->fw_smsk.s_addr)==f->fw_src.s_addr - && (src&f->fw_dmsk.s_addr)==f->fw_dst.s_addr) - /* reverse direction */ - match |= 0x02; - - if (!match) - continue; - - /* - * Look for a VIA device match - */ - if(f->fw_viadev) - { - if(rif!=f->fw_viadev) - continue; /* Mismatch */ - } - - /* This looks stupid, because we scan almost static - list, searching for static key. However, this way seems - to be only reasonable way of handling fw_via rules - (btw bsd makes the same thing). - - It will not affect performance if you will follow - the following simple rules: - - - if inteface is aliased, ALWAYS specify fw_viadev, - so that previous check will guarantee, that we will - not waste time when packet arrive on another interface. - - - avoid using fw_via.s_addr if fw_via.s_addr is owned - by an aliased interface. - - --ANK - */ - if (f->fw_via.s_addr && rif) { - struct in_ifaddr *ifa; - - if (rif->ip_ptr == NULL) - continue; /* Mismatch */ - - for (ifa = ((struct in_device*)(rif->ip_ptr))->ifa_list; - ifa; ifa = ifa->ifa_next) { - if (ifa->ifa_local == f->fw_via.s_addr) - goto ifa_ok; + if (offset) + dprintf(":fragment (%i) ", ((int)offset)<<2); + else if (ip->protocol==IPPROTO_TCP || ip->protocol==IPPROTO_UDP + || ip->protocol==IPPROTO_ICMP) + dprintf(":%hu:%hu", src_port, dst_port); + dprintf("\n"); +#endif + + if (!testing) FWC_READ_LOCK(&ip_fw_lock); + else FWC_HAVE_LOCK(fwc_rlocks); + + f = chain->chain; + do { + for (; f; f = f->next) { + if (ip_rule_match(f,rif,ip, + tcpsyn,src_port,dst_port,offset)) { + if (!testing) + ip_fw_domatch(f, ip, rif, chain->label, skb, + slot, src_port,dst_port); + break; } - continue; /* Mismatch */ - - ifa_ok: } - - /* - * Ok the chain addresses match. - */ - -#ifdef CONFIG_IP_ACCT - /* - * See if we're in accounting mode and only want to - * count incoming or outgoing packets. - */ - - if (mode & (IP_FW_MODE_ACCT_IN|IP_FW_MODE_ACCT_OUT) && - ((mode == IP_FW_MODE_ACCT_IN && f->fw_flg&IP_FW_F_ACCTOUT) || - (mode == IP_FW_MODE_ACCT_OUT && f->fw_flg&IP_FW_F_ACCTIN))) - continue; - -#endif - /* - * For all non-TCP packets and/or non-first fragments, - * notcpsyn and notcpack will always be FALSE, - * so the IP_FW_F_TCPSYN and IP_FW_F_TCPACK flags - * are actually ignored for these packets. - */ - - if((f->fw_flg&IP_FW_F_TCPSYN) && notcpsyn) - continue; - - if((f->fw_flg&IP_FW_F_TCPACK) && notcpack) - continue; - - f_prt=f->fw_flg&IP_FW_F_KIND; - if (f_prt!=IP_FW_F_ALL) - { - /* - * Specific firewall - packet's protocol - * must match firewall's. - */ - - if(prt!=f_prt) - continue; - - if((prt==IP_FW_F_ICMP && - ! port_match(&f->fw_pts[0], f->fw_nsp, - icmp_type,f->fw_flg&IP_FW_F_SRNG)) || - !(prt==IP_FW_F_ICMP || ((match & 0x01) && - port_match(&f->fw_pts[0], f->fw_nsp, src_port, - f->fw_flg&IP_FW_F_SRNG) && - port_match(&f->fw_pts[f->fw_nsp], f->fw_ndp, dst_port, - f->fw_flg&IP_FW_F_DRNG)) || ((match & 0x02) && - port_match(&f->fw_pts[0], f->fw_nsp, dst_port, - f->fw_flg&IP_FW_F_SRNG) && - port_match(&f->fw_pts[f->fw_nsp], f->fw_ndp, src_port, - f->fw_flg&IP_FW_F_DRNG)))) - { - continue; + if (f) { + if (f->branch) { + /* Do sanity check to see if we have + * already set prevchain and if so we + * must be in a loop */ + if (f->branch->reent[slot].prevchain) { + if (!testing) { + printk(KERN_ERR + "IP firewall: " + "Loop detected " + "at `%s'.\n", + f->branch->label); + cleanup(chain, 1, slot); + ret = FW_BLOCK; + } else { + cleanup(chain, 0, slot); + ret = FW_SKIP+1; + } + } + else { + f->branch->reent[slot].prevchain + = chain; + f->branch->reent[slot].prevrule + = f->next; + chain = f->branch; + f = chain->chain; + } + } + else if (f->simplebranch == FW_SKIP) + f = f->next; + else if (f->simplebranch == FW_SKIP+1) { + /* Just like falling off the chain */ + goto fall_off_chain; + } + else { + cleanup(chain, 0, slot); + ret = f->simplebranch; + } + } /* f == NULL */ + else { + fall_off_chain: + if (chain->reent[slot].prevchain) { + struct ip_chain *tmp = chain; + f = chain->reent[slot].prevrule; + chain = chain->reent[slot].prevchain; + tmp->reent[slot].prevchain = NULL; + } + else { + ret = chain->policy; + if (!testing) { + chain->reent[slot].counters.pcnt++; + chain->reent[slot].counters.bcnt + += ntohs(ip->tot_len); + } } } + } while (ret == FW_SKIP+2); -#ifdef CONFIG_IP_FIREWALL_VERBOSE - if (f->fw_flg & IP_FW_F_PRN) - { - char buf[16]; - - print_packet(ip, src_port, dst_port, icmp_type, - chain_name(chain, mode), - rule_name(f, mode, buf), - rif ? rif->name : "-"); - } -#endif - if (mode != IP_FW_MODE_CHK) { - f->fw_bcnt+=ntohs(ip->tot_len); - f->fw_pcnt++; - } - if (!(mode & (IP_FW_MODE_ACCT_IN|IP_FW_MODE_ACCT_OUT))) - break; - } /* Loop */ - - if (!(mode & (IP_FW_MODE_ACCT_IN|IP_FW_MODE_ACCT_OUT))) { - - /* - * We rely on policy defined in the rejecting entry or, if no match - * was found, we rely on the general policy variable for this type - * of firewall. - */ + if (!testing) FWC_READ_UNLOCK(&ip_fw_lock); - if (f!=NULL) { - policy=f->fw_flg; - tosand=f->fw_tosand; - tosxor=f->fw_tosxor; - } else { - tosand=0xFF; - tosxor=0x00; - } + /* Recalculate checksum if not going to reject, and TOS changed. */ + if (ip->tos != oldtos + && ret != FW_REJECT && ret != FW_BLOCK + && !testing) + ip_send_check(ip); - if (policy&IP_FW_F_ACCEPT) { - /* Adjust priority and recompute checksum */ - __u8 old_tos = ip->tos; - ip->tos = (old_tos & tosand) ^ tosxor; - if (ip->tos != old_tos) - ip_send_check(ip); #ifdef CONFIG_IP_TRANSPARENT_PROXY - if (policy&IP_FW_F_REDIR) { - if (redirport) - if ((*redirport = htons(f->fw_pts[f->fw_nsp+f->fw_ndp])) == 0) { - /* Wildcard redirection. - * Note that redirport will become - * 0xFFFF for non-TCP/UDP packets. - */ - *redirport = htons(dst_port); - } - answer = FW_REDIRECT; - } else -#endif -#ifdef CONFIG_IP_MASQUERADE - if (policy&IP_FW_F_MASQ) - answer = FW_MASQUERADE; - else + if (ret == FW_REDIRECT && redirport) { + if ((*redirport = htons(f->ipfw.fw_redirpt)) == 0) { + /* Wildcard redirection. + * Note that redirport will become + * 0xFFFF for non-TCP/UDP packets. + */ + *redirport = htons(dst_port); + } + } #endif - answer = FW_ACCEPT; - - } else if(policy&IP_FW_F_ICMPRPL) - answer = FW_REJECT; - else - answer = FW_BLOCK; -#ifdef CONFIG_IP_FIREWALL_NETLINK - if((policy&IP_FW_F_PRN) && (answer == FW_REJECT || answer == FW_BLOCK)) - { - struct sk_buff *skb=alloc_skb(128, GFP_ATOMIC); - if(skb) - { - int len=min(128,ntohs(ip->tot_len)); - skb_put(skb,len); - memcpy(skb->data,ip,len); - if(netlink_post(NETLINK_FIREWALL, skb)) - kfree_skb(skb); - } - } -#endif - return answer; - } else - /* we're doing accounting, always ok */ - return 0; +#ifdef DEBUG_ALLOW_ALL + return (testing ? ret : FW_ACCEPT); +#else + return ret; +#endif } +/* Must have write lock & interrupts off for any of these */ -static void zero_fw_chain(struct ip_fw *chainptr) +/* This function sets all the byte counters in a chain to zero. The + * input is a pointer to the chain required for zeroing */ +static int zero_fw_chain(struct ip_chain *chainptr) { - struct ip_fw *ctmp=chainptr; - while(ctmp) - { - ctmp->fw_pcnt=0L; - ctmp->fw_bcnt=0L; - ctmp=ctmp->fw_next; - } -} + struct ip_fwkernel *i; -static void free_fw_chain(struct ip_fw *volatile* chainptr) -{ - unsigned long flags; - save_flags(flags); - cli(); - while ( *chainptr != NULL ) - { - struct ip_fw *ftmp; - ftmp = *chainptr; - *chainptr = ftmp->fw_next; - kfree_s(ftmp,sizeof(*ftmp)); - } - restore_flags(flags); + FWC_HAVE_LOCK(fwc_wlocks); + for (i = chainptr->chain; i; i = i->next) + memset(i->counters, 0, sizeof(struct ip_counters)*NUM_SLOTS); + return 0; } -/* Volatiles to keep some of the compiler versions amused */ - -static int insert_in_chain(struct ip_fw *volatile* chainptr, struct ip_fw *frwl,int len) +static int clear_fw_chain(struct ip_chain *chainptr) { - struct ip_fw *ftmp; - unsigned long flags; + struct ip_fwkernel *i= chainptr->chain; - save_flags(flags); + FWC_HAVE_LOCK(fwc_wlocks); + chainptr->chain=NULL; - ftmp = kmalloc( sizeof(struct ip_fw), GFP_ATOMIC ); - if ( ftmp == NULL ) - { -#ifdef DEBUG_IP_FIREWALL - printk("ip_fw_ctl: malloc said no\n"); -#endif - return( ENOMEM ); + while (i) { + struct ip_fwkernel *tmp = i->next; + if (i->branch) + i->branch->refcount--; + kfree(i); + i = tmp; } + return 0; +} - memcpy(ftmp, frwl, len); - /* - * Allow the more recent "minimise cost" flag to be - * set. [Rob van Nieuwkerk] - */ - ftmp->fw_tosand |= 0x01; - ftmp->fw_tosxor &= 0xFE; - ftmp->fw_pcnt=0L; - ftmp->fw_bcnt=0L; - - cli(); - - if ((ftmp->fw_vianame)[0]) { - if (!(ftmp->fw_viadev = dev_get(ftmp->fw_vianame))) - ftmp->fw_viadev = (struct device *) -1; - } else - ftmp->fw_viadev = NULL; - - ftmp->fw_next = *chainptr; - *chainptr=ftmp; - restore_flags(flags); - return(0); -} - -static int append_to_chain(struct ip_fw *volatile* chainptr, struct ip_fw *frwl,int len) -{ - struct ip_fw *ftmp; - struct ip_fw *chtmp=NULL; - struct ip_fw *volatile chtmp_prev=NULL; - unsigned long flags; - - save_flags(flags); +static int replace_in_chain(struct ip_chain *chainptr, + struct ip_fwkernel *frwl, + __u32 position) +{ + struct ip_fwkernel *f = chainptr->chain; + + FWC_HAVE_LOCK(fwc_wlocks); - ftmp = kmalloc( sizeof(struct ip_fw), GFP_ATOMIC ); - if ( ftmp == NULL ) - { -#ifdef DEBUG_IP_FIREWALL - printk("ip_fw_ctl: malloc said no\n"); -#endif - return( ENOMEM ); - } + while (--position && f != NULL) f = f->next; + if (f == NULL) + return EINVAL; + + if (f->branch) f->branch->refcount--; + if (frwl->branch) frwl->branch->refcount++; - memcpy(ftmp, frwl, len); - /* - * Allow the more recent "minimise cost" flag to be - * set. [Rob van Nieuwkerk] - */ - ftmp->fw_tosand |= 0x01; - ftmp->fw_tosxor &= 0xFE; - ftmp->fw_pcnt=0L; - ftmp->fw_bcnt=0L; - - ftmp->fw_next = NULL; - - cli(); - - if ((ftmp->fw_vianame)[0]) { - if (!(ftmp->fw_viadev = dev_get(ftmp->fw_vianame))) - ftmp->fw_viadev = (struct device *) -1; - } else - ftmp->fw_viadev = NULL; - - chtmp_prev=NULL; - for (chtmp=*chainptr;chtmp!=NULL;chtmp=chtmp->fw_next) - chtmp_prev=chtmp; - - if (chtmp_prev) - chtmp_prev->fw_next=ftmp; - else - *chainptr=ftmp; - restore_flags(flags); - return(0); + frwl->next = f->next; + memcpy(f,frwl,sizeof(struct ip_fwkernel)); + kfree(frwl); + return 0; } -static int del_from_chain(struct ip_fw *volatile*chainptr, struct ip_fw *frwl) +static int append_to_chain(struct ip_chain *chainptr, struct ip_fwkernel *rule) { - struct ip_fw *ftmp,*ltmp; - unsigned short tport1,tport2,tmpnum; - char matches,was_found; - unsigned long flags; + struct ip_fwkernel *i; - save_flags(flags); - cli(); + FWC_HAVE_LOCK(fwc_wlocks); + /* Special case if no rules already present */ + if (chainptr->chain == NULL) { - ftmp=*chainptr; - - if ( ftmp == NULL ) - { -#ifdef DEBUG_IP_FIREWALL - printk("ip_fw_ctl: chain is empty\n"); -#endif - restore_flags(flags); - return( EINVAL ); + /* If pointer writes are atomic then turning off + * interupts is not necessary. */ + chainptr->chain = rule; + if (rule->branch) rule->branch->refcount++; + return 0; } - ltmp=NULL; - was_found=0; + /* Find the rule before the end of the chain */ + for (i = chainptr->chain; i->next; i = i->next); + i->next = rule; + if (rule->branch) rule->branch->refcount++; + return 0; +} - while( !was_found && ftmp != NULL ) - { - matches=1; - if (ftmp->fw_src.s_addr!=frwl->fw_src.s_addr - || ftmp->fw_dst.s_addr!=frwl->fw_dst.s_addr - || ftmp->fw_smsk.s_addr!=frwl->fw_smsk.s_addr - || ftmp->fw_dmsk.s_addr!=frwl->fw_dmsk.s_addr - || ftmp->fw_via.s_addr!=frwl->fw_via.s_addr - || ftmp->fw_flg!=frwl->fw_flg) - matches=0; - - tport1=ftmp->fw_nsp+ftmp->fw_ndp; - tport2=frwl->fw_nsp+frwl->fw_ndp; - if (tport1!=tport2) - matches=0; - else if (tport1!=0) - { - for (tmpnum=0;tmpnum < tport1 && tmpnum < IP_FW_MAX_PORTS;tmpnum++) - if (ftmp->fw_pts[tmpnum]!=frwl->fw_pts[tmpnum]) - matches=0; - } - if (strncmp(ftmp->fw_vianame, frwl->fw_vianame, IFNAMSIZ)) - matches=0; - if(matches) - { - was_found=1; - if (ltmp) - { - ltmp->fw_next=ftmp->fw_next; - kfree_s(ftmp,sizeof(*ftmp)); - ftmp=ltmp->fw_next; - } - else - { - *chainptr=ftmp->fw_next; - kfree_s(ftmp,sizeof(*ftmp)); - ftmp=*chainptr; - } - } - else - { - ltmp = ftmp; - ftmp = ftmp->fw_next; - } - } - restore_flags(flags); - if (was_found) +/* This function inserts a rule at the position of position in the + * chain refenced by chainptr. If position is 1 then this rule will + * become the new rule one. */ +static int insert_in_chain(struct ip_chain *chainptr, + struct ip_fwkernel *frwl, + __u32 position) +{ + struct ip_fwkernel *f = chainptr->chain; + + FWC_HAVE_LOCK(fwc_wlocks); + /* special case if the position is number 1 */ + if (position == 1) { + frwl->next = chainptr->chain; + if (frwl->branch) frwl->branch->refcount++; + chainptr->chain = frwl; return 0; - else - return(EINVAL); + } + position--; + while (--position && f != NULL) f = f->next; + if (f == NULL) + return EINVAL; + if (frwl->branch) frwl->branch->refcount++; + frwl->next = f->next; + + f->next = frwl; + return 0; } -#endif /* CONFIG_IP_ACCT || CONFIG_IP_FIREWALL */ +/* This function deletes the a rule from a given rulenum and chain. + * With rulenum = 1 is the first rule is deleted. */ -struct ip_fw *check_ipfw_struct(struct ip_fw *frwl, int len) +static int del_num_from_chain(struct ip_chain *chainptr, __u32 rulenum) { + struct ip_fwkernel *i=chainptr->chain,*tmp; + + FWC_HAVE_LOCK(fwc_wlocks); - if ( len != sizeof(struct ip_fw) ) - { -#ifdef DEBUG_IP_FIREWALL - printk("ip_fw_ctl: len=%d, want %d\n",len, sizeof(struct ip_fw)); -#endif - return(NULL); - } + if (!chainptr->chain) + return ENOENT; - if ( (frwl->fw_flg & ~IP_FW_F_MASK) != 0 ) - { -#ifdef DEBUG_IP_FIREWALL - printk("ip_fw_ctl: undefined flag bits set (flags=%x)\n", - frwl->fw_flg); -#endif - return(NULL); - } + /* Need a special case for the first rule */ + if (rulenum == 1) { + /* store temp to allow for freeing up of memory */ + tmp = chainptr->chain; + if (chainptr->chain->branch) chainptr->chain->branch->refcount--; + chainptr->chain = chainptr->chain->next; + kfree(tmp); /* free memory that is now unused */ + } else { + rulenum--; + while (--rulenum && i->next ) i = i->next; + if (!i->next) + return ENOENT; + tmp = i->next; + if (i->next->branch) + i->next->branch->refcount--; + i->next = i->next->next; + kfree(tmp); + } + return 0; +} -#ifndef CONFIG_IP_TRANSPARENT_PROXY - if (frwl->fw_flg & IP_FW_F_REDIR) { -#ifdef DEBUG_IP_FIREWALL - printk("ip_fw_ctl: unsupported flag IP_FW_F_REDIR\n"); -#endif - return(NULL); - } -#endif -#ifndef CONFIG_IP_MASQUERADE - if (frwl->fw_flg & IP_FW_F_MASQ) { -#ifdef DEBUG_IP_FIREWALL - printk("ip_fw_ctl: unsupported flag IP_FW_F_MASQ\n"); -#endif - return(NULL); - } -#endif +/* This function deletes the a rule from a given rule and chain. + * The rule that is deleted is the first occursance of that rule. */ +static int del_rule_from_chain(struct ip_chain *chainptr, + struct ip_fwkernel *frwl) +{ + struct ip_fwkernel *ltmp,*ftmp = chainptr->chain ; + int was_found; - if ( (frwl->fw_flg & IP_FW_F_SRNG) && frwl->fw_nsp < 2 ) - { -#ifdef DEBUG_IP_FIREWALL - printk("ip_fw_ctl: src range set but fw_nsp=%d\n", - frwl->fw_nsp); + FWC_HAVE_LOCK(fwc_wlocks); + + /* Sure, we should compare marks, but since the `ipfwadm' + * script uses it for an unholy hack... well, life is easier + * this way. We also mask it out of the flags word. --PR */ + for (ltmp=NULL, was_found=0; + !was_found && ftmp != NULL; + ltmp = ftmp,ftmp = ftmp->next) { + if (ftmp->ipfw.fw_src.s_addr!=frwl->ipfw.fw_src.s_addr + || ftmp->ipfw.fw_dst.s_addr!=frwl->ipfw.fw_dst.s_addr + || ftmp->ipfw.fw_smsk.s_addr!=frwl->ipfw.fw_smsk.s_addr + || ftmp->ipfw.fw_dmsk.s_addr!=frwl->ipfw.fw_dmsk.s_addr +#if 0 + || ftmp->ipfw.fw_flg!=frwl->ipfw.fw_flg +#else + || ((ftmp->ipfw.fw_flg & ~IP_FW_F_MARKABS) + != (frwl->ipfw.fw_flg & ~IP_FW_F_MARKABS)) #endif - return(NULL); - } + || ftmp->ipfw.fw_invflg!=frwl->ipfw.fw_invflg + || ftmp->ipfw.fw_proto!=frwl->ipfw.fw_proto +#if 0 + || ftmp->ipfw.fw_mark!=frwl->ipfw.fw_mark +#endif + || ftmp->ipfw.fw_redirpt!=frwl->ipfw.fw_redirpt + || ftmp->ipfw.fw_spts[0]!=frwl->ipfw.fw_spts[0] + || ftmp->ipfw.fw_spts[1]!=frwl->ipfw.fw_spts[1] + || ftmp->ipfw.fw_dpts[0]!=frwl->ipfw.fw_dpts[0] + || ftmp->ipfw.fw_dpts[1]!=frwl->ipfw.fw_dpts[1] + || ftmp->ipfw.fw_outputsize!=frwl->ipfw.fw_outputsize) { + duprintf("del_rule_from_chain: mismatch:" + "src:%u/%u dst:%u/%u smsk:%u/%u dmsk:%u/%u " + "flg:%hX/%hX invflg:%hX/%hX proto:%u/%u " + "mark:%u/%u " + "ports:%hu-%hu/%hu-%hu %hu-%hu/%hu-%hu " + "outputsize:%hu-%hu\n", + ftmp->ipfw.fw_src.s_addr, + frwl->ipfw.fw_src.s_addr, + ftmp->ipfw.fw_dst.s_addr, + frwl->ipfw.fw_dst.s_addr, + ftmp->ipfw.fw_smsk.s_addr, + frwl->ipfw.fw_smsk.s_addr, + ftmp->ipfw.fw_dmsk.s_addr, + frwl->ipfw.fw_dmsk.s_addr, + ftmp->ipfw.fw_flg, + frwl->ipfw.fw_flg, + ftmp->ipfw.fw_invflg, + frwl->ipfw.fw_invflg, + ftmp->ipfw.fw_proto, + frwl->ipfw.fw_proto, + ftmp->ipfw.fw_mark, + frwl->ipfw.fw_mark, + ftmp->ipfw.fw_spts[0], + frwl->ipfw.fw_spts[0], + ftmp->ipfw.fw_spts[1], + frwl->ipfw.fw_spts[1], + ftmp->ipfw.fw_dpts[0], + frwl->ipfw.fw_dpts[0], + ftmp->ipfw.fw_dpts[1], + frwl->ipfw.fw_dpts[1], + ftmp->ipfw.fw_outputsize, + frwl->ipfw.fw_outputsize); + continue; + } - if ( (frwl->fw_flg & IP_FW_F_DRNG) && frwl->fw_ndp < 2 ) - { -#ifdef DEBUG_IP_FIREWALL - printk("ip_fw_ctl: dst range set but fw_ndp=%d\n", - frwl->fw_ndp); -#endif - return(NULL); + if (strncmp(ftmp->ipfw.fw_vianame, + frwl->ipfw.fw_vianame, + IFNAMSIZ)) { + duprintf("del_rule_from_chain: if mismatch: %s/%s\n", + ftmp->ipfw.fw_vianame, + frwl->ipfw.fw_vianame); + continue; + } + if (ftmp->branch != frwl->branch) { + duprintf("del_rule_from_chain: branch mismatch: " + "%s/%s\n", + ftmp->branch?ftmp->branch->label:"(null)", + frwl->branch?frwl->branch->label:"(null)"); + continue; + } + if (ftmp->branch == NULL + && ftmp->simplebranch != frwl->simplebranch) { + duprintf("del_rule_from_chain: simplebranch mismatch: " + "%i/%i\n", + ftmp->simplebranch, frwl->simplebranch); + continue; + } + was_found = 1; + if (ftmp->branch) + ftmp->branch->refcount--; + if (ltmp) + ltmp->next = ftmp->next; + else + chainptr->chain = ftmp->next; + kfree(ftmp); + break; } - - if ( frwl->fw_nsp + frwl->fw_ndp > (frwl->fw_flg & IP_FW_F_REDIR ? IP_FW_MAX_PORTS - 1 : IP_FW_MAX_PORTS) ) - { -#ifdef DEBUG_IP_FIREWALL - printk("ip_fw_ctl: too many ports (%d+%d)\n", - frwl->fw_nsp,frwl->fw_ndp); -#endif - return(NULL); + + if (was_found) + return 0; + else { + duprintf("del_rule_from_chain: no matching rule found\n"); + return EINVAL; } - - return frwl; } +/* This function takes the label of a chain and deletes the first + * chain with that name. No special cases required for the built in + * chains as they have their refcount initilised to 1 so that they are + * never deleted. */ +static int del_chain(ip_chainlabel label) +{ + struct ip_chain *tmp,*tmp2; + FWC_HAVE_LOCK(fwc_wlocks); + /* Corner case: return EBUSY not ENOENT for first elem ("input") */ + if (strcmp(label, ip_fw_chains->label) == 0) + return EBUSY; + for (tmp = ip_fw_chains; tmp->next; tmp = tmp->next) + if(strcmp(tmp->next->label,label) == 0) + break; -#ifdef CONFIG_IP_ACCT + tmp2 = tmp->next; + if (!tmp2) + return ENOENT; -int ip_acct_ctl(int stage, void *m, int len) -{ - if ( stage == IP_ACCT_FLUSH ) - { - free_fw_chain(&ip_acct_chain); - return(0); - } - if ( stage == IP_ACCT_ZERO ) - { - zero_fw_chain(ip_acct_chain); - return(0); - } - if ( stage == IP_ACCT_INSERT || stage == IP_ACCT_APPEND || - stage == IP_ACCT_DELETE ) - { - struct ip_fw *frwl; + if (tmp2->refcount) + return EBUSY; - if (!(frwl=check_ipfw_struct(m,len))) - return (EINVAL); + if (tmp2->chain) + return ENOTEMPTY; + + tmp->next = tmp2->next; + kfree(tmp2); + return 0; +} + +/* This is a function to initilise a chain. Built in rules start with + * refcount = 1 so that they cannot be deleted. User defined rules + * start with refcount = 0 so they can be deleted. */ +static struct ip_chain *ip_init_chain(ip_chainlabel name, + __u32 ref, + int policy) +{ + unsigned int i; + struct ip_chain *label + = kmalloc(SIZEOF_STRUCT_IP_CHAIN, GFP_KERNEL); + if (label == NULL) + panic("Can't kmalloc for firewall chains.\n"); + strcpy(label->label,name); + label->next = NULL; + label->chain = NULL; + label->refcount = ref; + label->policy = policy; + for (i = 0; i < smp_num_cpus*2; i++) { + label->reent[i].counters.pcnt = label->reent[i].counters.bcnt + = 0; + label->reent[i].prevchain = NULL; + label->reent[i].prevrule = NULL; + } + + return label; +} + +/* This is a function for reating a new chain. The chains is not + * created if a chain of the same name already exists */ +static int create_chain(ip_chainlabel label) +{ + struct ip_chain *tmp; + + FWC_HAVE_LOCK(fwc_wlocks); + for (tmp = ip_fw_chains; tmp->next; tmp = tmp->next) + if (strcmp(tmp->label,label) == 0) + return EEXIST; + + if (strcmp(tmp->label,label) == 0) + return EEXIST; + + tmp->next = ip_init_chain(label, 0, FW_SKIP); /* refcount is + * zero since this is a + * user defined chain * + * and therefore can be + * deleted */ + return 0; +} + +/* This function simply changes the policy on one of the built in + * chains. checking must be done before this is call to ensure that + * chainptr is pointing to one of the three possible chains */ +static int change_policy(struct ip_chain *chainptr, int policy) +{ + FWC_HAVE_LOCK(fwc_wlocks); + chainptr->policy = policy; + return 0; +} + +/* This function takes an ip_fwuser and converts it to a ip_fwkernel. It also + * performs some checks in the structure. */ +static struct ip_fwkernel *convert_ipfw(struct ip_fwuser *fwuser, int *errno) +{ + struct ip_fwkernel *fwkern; + + if ( (fwuser->ipfw.fw_flg & ~IP_FW_F_MASK) != 0 ) { + duprintf("convert_ipfw: undefined flag bits set (flags=%x)\n", + fwuser->ipfw.fw_flg); + *errno = EINVAL; + return NULL; + } + +#if DEBUG_IP_FIREWALL_USER + /* These are sanity checks that don't really matter. + * We can get rid of these once testing is complete. + */ + if ((fwuser->ipfw.fw_flg & IP_FW_F_TCPSYN) + && ((fwuser->ipfw.fw_invflg & IP_FW_INV_PROTO) + || fwuser->ipfw.fw_proto != IPPROTO_TCP)) { + duprintf("convert_ipfw: TCP SYN flag set but proto != TCP!\n"); + *errno = EINVAL; + return NULL; + } + + if (strcmp(fwuser->label, IP_FW_LABEL_REDIRECT) != 0 + && fwuser->ipfw.fw_redirpt != 0) { + duprintf("convert_ipfw: Target not REDIR but redirpt != 0!\n"); + *errno = EINVAL; + return NULL; + } + + if ((!(fwuser->ipfw.fw_flg & IP_FW_F_FRAG) + && (fwuser->ipfw.fw_invflg & IP_FW_INV_FRAG)) + || (!(fwuser->ipfw.fw_flg & IP_FW_F_TCPSYN) + && (fwuser->ipfw.fw_invflg & IP_FW_INV_SYN))) { + duprintf("convert_ipfw: Can't have INV flag if flag unset!\n"); + *errno = EINVAL; + return NULL; + } + + if (((fwuser->ipfw.fw_invflg & IP_FW_INV_SRCPT) + && fwuser->ipfw.fw_spts[0] == 0 + && fwuser->ipfw.fw_spts[1] == 0xFFFF) + || ((fwuser->ipfw.fw_invflg & IP_FW_INV_DSTPT) + && fwuser->ipfw.fw_dpts[0] == 0 + && fwuser->ipfw.fw_dpts[1] == 0xFFFF) + || ((fwuser->ipfw.fw_invflg & IP_FW_INV_VIA) + && (fwuser->ipfw.fw_vianame)[0] == '\0') + || ((fwuser->ipfw.fw_invflg & IP_FW_INV_SRCIP) + && fwuser->ipfw.fw_smsk.s_addr == 0) + || ((fwuser->ipfw.fw_invflg & IP_FW_INV_DSTIP) + && fwuser->ipfw.fw_dmsk.s_addr == 0)) { + duprintf("convert_ipfw: INV flag makes rule unmatchable!\n"); + *errno = EINVAL; + return NULL; + } + + if ((fwuser->ipfw.fw_flg & IP_FW_F_FRAG) + && !(fwuser->ipfw.fw_invflg & IP_FW_INV_FRAG) + && (fwuser->ipfw.fw_spts[0] != 0 + || fwuser->ipfw.fw_spts[1] != 0xFFFF + || fwuser->ipfw.fw_dpts[0] != 0 + || fwuser->ipfw.fw_dpts[1] != 0xFFFF + || (fwuser->ipfw.fw_flg & IP_FW_F_TCPSYN))) { + duprintf("convert_ipfw: Can't test ports or SYN with frag!\n"); + *errno = EINVAL; + return NULL; + } +#endif + + if ((fwuser->ipfw.fw_spts[0] != 0 + || fwuser->ipfw.fw_spts[1] != 0xFFFF + || fwuser->ipfw.fw_dpts[0] != 0 + || fwuser->ipfw.fw_dpts[1] != 0xFFFF) + && ((fwuser->ipfw.fw_invflg & IP_FW_INV_PROTO) + || (fwuser->ipfw.fw_proto != IPPROTO_TCP + && fwuser->ipfw.fw_proto != IPPROTO_UDP + && fwuser->ipfw.fw_proto != IPPROTO_ICMP))) { + duprintf("convert_ipfw: Can only test ports for TCP/UDP/ICMP!\n"); + *errno = EINVAL; + return NULL; + } + + fwkern = kmalloc(SIZEOF_STRUCT_IP_FW_KERNEL, GFP_KERNEL); + if (!fwkern) { + duprintf("convert_ipfw: kmalloc failed!\n"); + *errno = ENOMEM; + return NULL; + } + memcpy(&fwkern->ipfw,&fwuser->ipfw,sizeof(struct ip_fw)); + + if (!find_special(fwuser->label, &fwkern->simplebranch)) { + fwkern->branch = find_label(fwuser->label); + if (!fwkern->branch) { + duprintf("convert_ipfw: chain doesn't exist `%s'.\n", + fwuser->label); + kfree(fwkern); + *errno = ENOENT; + return NULL; + } else if (fwkern->branch == IP_FW_INPUT_CHAIN + || fwkern->branch == IP_FW_FORWARD_CHAIN + || fwkern->branch == IP_FW_OUTPUT_CHAIN) { + duprintf("convert_ipfw: Can't branch to builtin chain `%s'.\n", + fwuser->label); + kfree(fwkern); + *errno = ENOENT; + return NULL; + } + } else + fwkern->branch = NULL; + memset(fwkern->counters, 0, sizeof(struct ip_counters)*NUM_SLOTS); + + /* Handle empty vianame by making it a wildcard */ + if ((fwkern->ipfw.fw_vianame)[0] == '\0') + fwkern->ipfw.fw_flg |= IP_FW_F_WILDIF; - switch (stage) - { - case IP_ACCT_INSERT: - return( insert_in_chain(&ip_acct_chain,frwl,len)); - case IP_ACCT_APPEND: - return( append_to_chain(&ip_acct_chain,frwl,len)); - case IP_ACCT_DELETE: - return( del_from_chain(&ip_acct_chain,frwl)); - default: - /* - * Should be panic but... (Why ??? - AC) - */ -#ifdef DEBUG_IP_FIREWALL - printk("ip_acct_ctl: unknown request %d\n",stage); -#endif - return(EINVAL); - } - } -#ifdef DEBUG_IP_FIREWALL - printk("ip_acct_ctl: unknown request %d\n",stage); -#endif - return(EINVAL); + fwkern->next = NULL; + return fwkern; } -#endif -#ifdef CONFIG_IP_FIREWALL -int ip_fw_ctl(int stage, void *m, int len) +int ip_fw_ctl(int cmd, void *m, int len) { - int cmd, fwtype; - - cmd = stage & IP_FW_COMMAND; - fwtype = (stage & IP_FW_TYPE) >> IP_FW_SHIFT; + int ret; + struct ip_chain *chain; + unsigned long flags; - if ( cmd == IP_FW_FLUSH ) - { - free_fw_chain(chains[fwtype]); - return(0); - } + FWC_WRITE_LOCK_IRQ(&ip_fw_lock, flags); - if ( cmd == IP_FW_ZERO ) - { - zero_fw_chain(*chains[fwtype]); - return(0); - } + switch (cmd) { + case IP_FW_FLUSH: + if (len != sizeof(ip_chainlabel) || !check_label(m)) + ret = EINVAL; + else if ((chain = find_label(m)) == NULL) + ret = ENOENT; + else ret = clear_fw_chain(chain); + break; - if ( cmd == IP_FW_POLICY ) - { - int *tmp_policy_ptr; - tmp_policy_ptr=(int *)m; - *policies[fwtype] = *tmp_policy_ptr; - return 0; - } + case IP_FW_ZERO: + if (len != sizeof(ip_chainlabel) || !check_label(m)) + ret = EINVAL; + else if ((chain = find_label(m)) == NULL) + ret = ENOENT; + else ret = zero_fw_chain(chain); + break; - if ( cmd == IP_FW_CHECK ) - { - struct device *viadev; - struct ip_fwpkt *ipfwp; + case IP_FW_CHECK: { + struct ip_fwtest *new = m; struct iphdr *ip; - if ( len != sizeof(struct ip_fwpkt) ) - { -#ifdef DEBUG_IP_FIREWALL - printk("ip_fw_ctl: length=%d, expected %d\n", - len, sizeof(struct ip_fwpkt)); -#endif - return( EINVAL ); - } + /* Don't need write lock. */ + FWC_WRITE_UNLOCK_IRQ(&ip_fw_lock, flags); + + if (len != sizeof(struct ip_fwtest) || !check_label(m)) + return EINVAL; - ipfwp = (struct ip_fwpkt *)m; - ip = &(ipfwp->fwp_iph); + /* Need readlock to do find_label */ + FWC_READ_LOCK(&ip_fw_lock); - if ( !(viadev = dev_get(ipfwp->fwp_vianame)) ) { -#ifdef DEBUG_IP_FIREWALL - printk("ip_fw_ctl: invalid device \"%s\"\n", ipfwp->fwp_vianame); -#endif - return(EINVAL); - } else if ( ip->ihl != sizeof(struct iphdr) / sizeof(int)) { -#ifdef DEBUG_IP_FIREWALL - printk("ip_fw_ctl: ip->ihl=%d, want %d\n",ip->ihl, - sizeof(struct iphdr)/sizeof(int)); -#endif - return(EINVAL); - } - - switch (ip_fw_chk(ip, viadev, NULL, *chains[fwtype], - *policies[fwtype], IP_FW_MODE_CHK)) - { - case FW_ACCEPT: - return(0); - case FW_REDIRECT: - return(ECONNABORTED); - case FW_MASQUERADE: - return(ECONNRESET); - case FW_REJECT: - return(ECONNREFUSED); - default: /* FW_BLOCK */ - return(ETIMEDOUT); + if ((chain = find_label(new->fwt_label)) == NULL) + ret = ENOENT; + else { + ip = &(new->fwt_packet.fwp_iph); + + if (ip->ihl != sizeof(struct iphdr) / sizeof(int)) { + duprintf("ip_fw_ctl: ip->ihl=%d, want %d\n", + ip->ihl, + sizeof(struct iphdr) / sizeof(int)); + ret = EINVAL; + } + else { + ret = ip_fw_check(ip, new->fwt_packet.fwp_vianame, + NULL, chain, + NULL, SLOT_NUMBER(), 1); + switch (ret) { + case FW_ACCEPT: + ret = 0; break; + case FW_REDIRECT: + ret = ECONNABORTED; break; + case FW_MASQUERADE: + ret = ECONNRESET; break; + case FW_REJECT: + ret = ECONNREFUSED; break; + /* Hack to help diag; these only get + returned when testing. */ + case FW_SKIP+1: + ret = ELOOP; break; + case FW_SKIP: + ret = ENFILE; break; + default: /* FW_BLOCK */ + ret = ETIMEDOUT; break; + } + } } + FWC_READ_UNLOCK(&ip_fw_lock); + return ret; } - if ( cmd == IP_FW_MASQ_TIMEOUTS ) - { + case IP_FW_MASQ_TIMEOUTS: { #ifdef CONFIG_IP_MASQUERADE struct ip_fw_masq *masq; - if ( len != sizeof(struct ip_fw_masq) ) - { -#ifdef DEBUG_IP_FIREWALL - printk("ip_fw_ctl (masq): length %d, expected %d\n", + if (len != sizeof(struct ip_fw_masq)) { + duprintf("ip_fw_ctl (masq): length %d, expected %d\n", len, sizeof(struct ip_fw_masq)); - -#endif - return( EINVAL ); - } - - masq = (struct ip_fw_masq *) m; - - if (masq->tcp_timeout) - { - ip_masq_expire->tcp_timeout = masq->tcp_timeout; + ret = EINVAL; } - - if (masq->tcp_fin_timeout) - { - ip_masq_expire->tcp_fin_timeout = masq->tcp_fin_timeout; - } - - if (masq->udp_timeout) - { - ip_masq_expire->udp_timeout = masq->udp_timeout; + else { + masq = (struct ip_fw_masq *)m; + if (masq->tcp_timeout) + ip_masq_expire->tcp_timeout + = masq->tcp_timeout; + + if (masq->tcp_fin_timeout) + ip_masq_expire->tcp_fin_timeout + = masq->tcp_fin_timeout; + + if (masq->udp_timeout) + ip_masq_expire->udp_timeout + = masq->udp_timeout; + ret = 0; } - - return 0; #else - return( EINVAL ); + ret = EINVAL; #endif } + break; -/* - * Here we really working hard-adding new elements - * to blocking/forwarding chains or deleting 'em - */ - - if ( cmd == IP_FW_INSERT || cmd == IP_FW_APPEND || cmd == IP_FW_DELETE ) - { - struct ip_fw *frwl; - int fwtype; - - frwl=check_ipfw_struct(m,len); - if (frwl==NULL) - return (EINVAL); - fwtype = (stage & IP_FW_TYPE) >> IP_FW_SHIFT; - - switch (cmd) - { - case IP_FW_INSERT: - return(insert_in_chain(chains[fwtype],frwl,len)); - case IP_FW_APPEND: - return(append_to_chain(chains[fwtype],frwl,len)); - case IP_FW_DELETE: - return(del_from_chain(chains[fwtype],frwl)); + case IP_FW_REPLACE: { + struct ip_fwkernel *ip_fwkern; + struct ip_fwnew *new = m; + + if (len != sizeof(struct ip_fwnew) + || !check_label(new->fwn_label)) + ret = EINVAL; + else if ((chain = find_label(new->fwn_label)) == NULL) + ret = ENOENT; + else if ((ip_fwkern = convert_ipfw(&new->fwn_rule, &ret)) + != NULL) + ret = replace_in_chain(chain, ip_fwkern, + new->fwn_rulenum); + } + break; + + case IP_FW_APPEND: { + struct ip_fwchange *new = m; + struct ip_fwkernel *ip_fwkern; + + if (len != sizeof(struct ip_fwchange) + || !check_label(new->fwc_label)) + ret = EINVAL; + else if ((chain = find_label(new->fwc_label)) == NULL) + ret = ENOENT; + else if ((ip_fwkern = convert_ipfw(&new->fwc_rule, &ret)) + != NULL) + ret = append_to_chain(chain, ip_fwkern); + } + break; + + case IP_FW_INSERT: { + struct ip_fwkernel *ip_fwkern; + struct ip_fwnew *new = m; + + if (len != sizeof(struct ip_fwnew) + || !check_label(new->fwn_label)) + ret = EINVAL; + else if ((chain = find_label(new->fwn_label)) == NULL) + ret = ENOENT; + else if ((ip_fwkern = convert_ipfw(&new->fwn_rule, &ret)) + != NULL) + ret = insert_in_chain(chain, ip_fwkern, + new->fwn_rulenum); + } + break; + + case IP_FW_DELETE: { + struct ip_fwchange *new = m; + struct ip_fwkernel *ip_fwkern; + + if (len != sizeof(struct ip_fwchange) + || !check_label(new->fwc_label)) + ret = EINVAL; + else if ((chain = find_label(new->fwc_label)) == NULL) + ret = ENOENT; + else if ((ip_fwkern = convert_ipfw(&new->fwc_rule, &ret)) + != NULL) + ret = del_rule_from_chain(chain, ip_fwkern); + } + break; + + case IP_FW_DELETE_NUM: { + struct ip_fwdelnum *new = m; + + if (len != sizeof(struct ip_fwdelnum) + || !check_label(new->fwd_label)) + ret = EINVAL; + else if ((chain = find_label(new->fwd_label)) == NULL) + ret = ENOENT; + else ret = del_num_from_chain(chain, new->fwd_rulenum); + } + break; + + case IP_FW_CREATECHAIN: { + if (len != sizeof(ip_chainlabel)) { + duprintf("create_chain: bad size %i\n", len); + ret = EINVAL; + } + else ret = create_chain(m); + } + break; + + case IP_FW_DELETECHAIN: { + if (len != sizeof(ip_chainlabel)) { + duprintf("delete_chain: bad size %i\n", len); + ret = EINVAL; + } + else ret = del_chain(m); + } + break; + + case IP_FW_POLICY: { + struct ip_fwpolicy *new = m; + + if (len != sizeof(struct ip_fwpolicy) + || !check_label(new->fwp_label)) + ret = EINVAL; + else if ((chain = find_label(new->fwp_label)) == NULL) + ret = ENOENT; + else if (chain != IP_FW_INPUT_CHAIN + && chain != IP_FW_FORWARD_CHAIN + && chain != IP_FW_OUTPUT_CHAIN) { + duprintf("change_policy: can't change policy on user" + " defined chain.\n"); + ret = EINVAL; + } + else { + int pol = FW_SKIP; + find_special(new->fwp_policy, &pol); + + switch(pol) { + case FW_MASQUERADE: + if (chain != IP_FW_FORWARD_CHAIN) { + ret = EINVAL; + break; + } + /* Fall thru... */ + case FW_BLOCK: + case FW_ACCEPT: + case FW_REJECT: + ret = change_policy(chain, pol); + break; default: - /* - * Should be panic but... (Why are BSD people panic obsessed ??) - */ -#ifdef DEBUG_IP_FIREWALL - printk("ip_fw_ctl: unknown request %d\n",stage); -#endif - return(EINVAL); + duprintf("change_policy: bad policy `%s'\n", + new->fwp_policy); + ret = EINVAL; + } } - } + break; + + } + default: + duprintf("ip_fw_ctl: unknown request %d\n",cmd); + ret = EINVAL; + } -#ifdef DEBUG_IP_FIREWALL - printk("ip_fw_ctl: unknown request %d\n",stage); -#endif - return(EINVAL); + FWC_WRITE_UNLOCK_IRQ(&ip_fw_lock, flags); + return ret; } -#endif /* CONFIG_IP_FIREWALL */ -#ifdef CONFIG_PROC_FS -#if defined(CONFIG_IP_FIREWALL) || defined(CONFIG_IP_ACCT) +/* Returns bytes used - doesn't NUL terminate */ +static int dump_rule(char *buffer, + const char *chainlabel, + const struct ip_fwkernel *rule) +{ + int len; + unsigned int i; + __u64 packets = 0, bytes = 0; + + FWC_HAVE_LOCK(fwc_wlocks); + for (i = 0; i < NUM_SLOTS; i++) { + packets += rule->counters[i].pcnt; + bytes += rule->counters[i].bcnt; + } + + len=sprintf(buffer, + "%9s " /* Chain name */ + "%08lX/%08lX->%08lX/%08lX " /* Source & Destination IPs */ + "%.16s " /* Interface */ + "%hX %hX " /* fw_flg and fw_invflg fields */ + "%hu " /* Protocol */ + "%-9u %-9u %-9u %-9u " /* Packet & byte counters */ + "%hu-%hu %hu-%hu " /* Source & Dest port ranges */ + "A%02X X%02X " /* TOS and and xor masks */ + "%08X " /* Redirection port */ + "%u " /* fw_mark field */ + "%hu " /* output size */ + "%9s\n", /* Target */ + chainlabel, + ntohl(rule->ipfw.fw_src.s_addr), + ntohl(rule->ipfw.fw_smsk.s_addr), + ntohl(rule->ipfw.fw_dst.s_addr), + ntohl(rule->ipfw.fw_dmsk.s_addr), + (rule->ipfw.fw_vianame)[0] ? rule->ipfw.fw_vianame : "-", + rule->ipfw.fw_flg, + rule->ipfw.fw_invflg, + rule->ipfw.fw_proto, + (__u32)(packets >> 32), (__u32)packets, + (__u32)(bytes >> 32), (__u32)bytes, + rule->ipfw.fw_spts[0], rule->ipfw.fw_spts[1], + rule->ipfw.fw_dpts[0], rule->ipfw.fw_dpts[1], + rule->ipfw.fw_tosand, rule->ipfw.fw_tosxor, + rule->ipfw.fw_redirpt, + rule->ipfw.fw_mark, + rule->ipfw.fw_outputsize, + branchname(rule->branch,rule->simplebranch)); + + duprintf("dump_rule: %i bytes done.\n", len); + return len; +} -static int ip_chain_procinfo(int stage, char *buffer, char **start, +/* File offset is actually in records, not bytes. */ +static int ip_chain_procinfo(char *buffer, char **start, off_t offset, int length, int reset) { - off_t pos=0, begin=0; - struct ip_fw *i; + struct ip_chain *i; + struct ip_fwkernel *j = ip_fw_chains->chain; unsigned long flags; - int len, p; + int len = 0; int last_len = 0; - + off_t upto = 0; - switch(stage) - { -#ifdef CONFIG_IP_FIREWALL - case IP_FW_IN: - i = ip_fw_in_chain; - len=sprintf(buffer, "IP firewall input rules, default %d\n", - ip_fw_in_policy); - break; - case IP_FW_OUT: - i = ip_fw_out_chain; - len=sprintf(buffer, "IP firewall output rules, default %d\n", - ip_fw_out_policy); - break; - case IP_FW_FWD: - i = ip_fw_fwd_chain; - len=sprintf(buffer, "IP firewall forward rules, default %d\n", - ip_fw_fwd_policy); - break; -#endif -#ifdef CONFIG_IP_ACCT - case IP_FW_ACCT: - i = ip_acct_chain; - len=sprintf(buffer,"IP accounting rules\n"); - break; -#endif - default: - /* this should never be reached, but safety first... */ - i = NULL; - len=0; - break; + duprintf("Offset starts at %lu\n", offset); + duprintf("ip_fw_chains is 0x%0lX\n", (unsigned long int)ip_fw_chains); + + /* Need a write lock to lock out ``readers'' which update counters. */ + FWC_WRITE_LOCK_IRQ(&ip_fw_lock, flags); + + for (i = ip_fw_chains; i; i = i->next) { + for (j = i->chain; j; j = j->next) { + if (upto == offset) break; + duprintf("Skipping rule in chain `%s'\n", + i->label); + upto++; + } + if (upto == offset) break; + } + + /* Don't init j first time, or once i = NULL */ + for (; i; (void)((i = i->next) && (j = i->chain))) { + duprintf("Dumping chain `%s'\n", i->label); + for (; j; j = j->next, upto++, last_len = len) + { + len += dump_rule(buffer+len, i->label, j); + if (len > length) { + duprintf("Dumped to %i (past %i). " + "Moving back to %i.\n", + len, length, last_len); + len = last_len; + goto outside; + } + else if (reset) + memset(j->counters, 0, + sizeof(struct ip_counters)*NUM_SLOTS); + } } +outside: + FWC_WRITE_UNLOCK_IRQ(&ip_fw_lock, flags); + buffer[len] = '\0'; + + duprintf("ip_chain_procinfo: Length = %i (of %i). Offset = %li.\n", + len, length, upto); + /* `start' hack - see fs/proc/generic.c line ~165 */ + *start=(char *)((unsigned int)upto-offset); + return len; +} - save_flags(flags); - cli(); - - while(i!=NULL) +static int ip_chain_name_procinfo(char *buffer, char **start, + off_t offset, int length, int reset) +{ + struct ip_chain *i; + int len = 0,last_len = 0; + off_t pos = 0,begin = 0; + unsigned long flags; + + /* Need a write lock to lock out ``readers'' which update counters. */ + FWC_WRITE_LOCK_IRQ(&ip_fw_lock, flags); + + for (i = ip_fw_chains; i; i = i->next) { - len+=sprintf(buffer+len,"%08lX/%08lX->%08lX/%08lX %.16s %08lX %X ", - ntohl(i->fw_src.s_addr),ntohl(i->fw_smsk.s_addr), - ntohl(i->fw_dst.s_addr),ntohl(i->fw_dmsk.s_addr), - (i->fw_vianame)[0] ? i->fw_vianame : "-", - ntohl(i->fw_via.s_addr),i->fw_flg); - /* 10 is enough for a 32 bit box but the counters are 64bit on - the Alpha and Ultrapenguin */ - len+=sprintf(buffer+len,"%u %u %-20lu %-20lu", - i->fw_nsp,i->fw_ndp, i->fw_pcnt,i->fw_bcnt); - for (p = 0; p < IP_FW_MAX_PORTS; p++) - len+=sprintf(buffer+len, " %u", i->fw_pts[p]); - len+=sprintf(buffer+len, " A%02X X%02X", i->fw_tosand, i->fw_tosxor); - buffer[len++]='\n'; - buffer[len]='\0'; + unsigned int j; + __u32 packetsHi = 0, packetsLo = 0, bytesHi = 0, bytesLo = 0; + + for (j = 0; j < NUM_SLOTS; j++) { + packetsLo += i->reent[j].counters.pcnt & 0xFFFFFFFF; + packetsHi += ((i->reent[j].counters.pcnt >> 32) + & 0xFFFFFFFF); + bytesLo += i->reent[j].counters.bcnt & 0xFFFFFFFF; + bytesHi += ((i->reent[j].counters.bcnt >> 32) + & 0xFFFFFFFF); + } + + /* print the label and the policy */ + len+=sprintf(buffer+len,"%s %s %i %u %u %u %u\n", + i->label,branchname(NULL, i->policy),i->refcount, + packetsHi, packetsLo, bytesHi, bytesLo); pos=begin+len; - if(posoffset+length) - { + else if(pos>offset+length) { len = last_len; break; } - else if(reset) - { - /* This needs to be done at this specific place! */ - i->fw_pcnt=0L; - i->fw_bcnt=0L; - } + last_len = len; - i=i->fw_next; } - restore_flags(flags); - *start=buffer+(offset-begin); + FWC_WRITE_UNLOCK_IRQ(&ip_fw_lock, flags); + + *start = buffer+(offset-begin); len-=(offset-begin); if(len>length) - len=length; + len=length; return len; } -#endif - -#ifdef CONFIG_IP_ACCT - -static int ip_acct_procinfo(char *buffer, char **start, off_t offset, - int length, int reset) -{ - return ip_chain_procinfo(IP_FW_ACCT, buffer,start, offset,length, - reset); -} - -#endif - -#ifdef CONFIG_IP_FIREWALL - -static int ip_fw_in_procinfo(char *buffer, char **start, off_t offset, - int length, int reset) -{ - return ip_chain_procinfo(IP_FW_IN, buffer,start,offset,length, - reset); -} - -static int ip_fw_out_procinfo(char *buffer, char **start, off_t offset, - int length, int reset) -{ - return ip_chain_procinfo(IP_FW_OUT, buffer,start,offset,length, - reset); -} - -static int ip_fw_fwd_procinfo(char *buffer, char **start, off_t offset, - int length, int reset) -{ - return ip_chain_procinfo(IP_FW_FWD, buffer,start,offset,length, - reset); -} -#endif -#endif - -#ifdef CONFIG_IP_FIREWALL /* * Interface to the generic firewall chains. */ - -int ipfw_input_check(struct firewall_ops *this, int pf, struct device *dev, void *phdr, void *arg, struct sk_buff **pskb) +int ipfw_input_check(struct firewall_ops *this, int pf, struct device *dev, + void *phdr, void *arg, struct sk_buff **pskb) { - return ip_fw_chk(phdr, dev, arg, ip_fw_in_chain, ip_fw_in_policy, IP_FW_MODE_FW); + return ip_fw_check(phdr, dev->name, + arg, IP_FW_INPUT_CHAIN, *pskb, SLOT_NUMBER(), 0); } -int ipfw_output_check(struct firewall_ops *this, int pf, struct device *dev, void *phdr, void *arg, struct sk_buff **pskb) +int ipfw_output_check(struct firewall_ops *this, int pf, struct device *dev, + void *phdr, void *arg, struct sk_buff **pskb) { - return ip_fw_chk(phdr, dev, arg, ip_fw_out_chain, ip_fw_out_policy, IP_FW_MODE_FW); + return ip_fw_check(phdr, dev->name, + arg, IP_FW_OUTPUT_CHAIN, *pskb, SLOT_NUMBER(), 0); } -int ipfw_forward_check(struct firewall_ops *this, int pf, struct device *dev, void *phdr, void *arg, struct sk_buff **pskb) +int ipfw_forward_check(struct firewall_ops *this, int pf, struct device *dev, + void *phdr, void *arg, struct sk_buff **pskb) { - return ip_fw_chk(phdr, dev, arg, ip_fw_fwd_chain, ip_fw_fwd_policy, IP_FW_MODE_FW); + return ip_fw_check(phdr, dev->name, + arg, IP_FW_FORWARD_CHAIN, *pskb, SLOT_NUMBER(), 0); } - + struct firewall_ops ipfw_ops= { NULL, @@ -1283,106 +1664,45 @@ 0 /* We don't even allow a fall through so we are last */ }; -#endif - -#if defined(CONFIG_IP_ACCT) || defined(CONFIG_IP_FIREWALL) - -int ipfw_device_event(struct notifier_block *this, unsigned long event, void *ptr) -{ - struct device *dev=ptr; - char *devname = dev->name; - unsigned long flags; - struct ip_fw *fw; - int chn; - - save_flags(flags); - cli(); - - if (event == NETDEV_UP) { - for (chn = 0; chn < IP_FW_CHAINS; chn++) - for (fw = *chains[chn]; fw; fw = fw->fw_next) - if ((fw->fw_vianame)[0] && !strncmp(devname, - fw->fw_vianame, IFNAMSIZ)) - fw->fw_viadev = dev; - } else if (event == NETDEV_DOWN) { - for (chn = 0; chn < IP_FW_CHAINS; chn++) - for (fw = *chains[chn]; fw; fw = fw->fw_next) - /* we could compare just the pointers ... */ - if ((fw->fw_vianame)[0] && !strncmp(devname, - fw->fw_vianame, IFNAMSIZ)) - fw->fw_viadev = (struct device *) -1; - } - - restore_flags(flags); - return NOTIFY_DONE; -} - -static struct notifier_block ipfw_dev_notifier={ - ipfw_device_event, - NULL, - 0 +#ifdef CONFIG_PROC_FS +static struct proc_dir_entry proc_net_ipfwchains_chain = { + PROC_NET_IPFW_CHAINS, sizeof(IP_FW_PROC_CHAINS)-1, + IP_FW_PROC_CHAINS, S_IFREG | S_IRUGO | S_IWUSR, 1, 0, 0, + 0, &proc_net_inode_operations, ip_chain_procinfo }; -#endif - -#ifdef CONFIG_PROC_FS -#ifdef CONFIG_IP_ACCT -static struct proc_dir_entry proc_net_ipacct = { - PROC_NET_IPACCT, 7, "ip_acct", - S_IFREG | S_IRUGO | S_IWUSR, 1, 0, 0, - 0, &proc_net_inode_operations, - ip_acct_procinfo +static struct proc_dir_entry proc_net_ipfwchains_chainnames = { + PROC_NET_IPFW_CHAIN_NAMES, sizeof(IP_FW_PROC_CHAIN_NAMES)-1, + IP_FW_PROC_CHAIN_NAMES, S_IFREG | S_IRUGO | S_IWUSR, 1, 0, 0, + 0, &proc_net_inode_operations, ip_chain_name_procinfo }; -#endif -#endif -#ifdef CONFIG_IP_FIREWALL -#ifdef CONFIG_PROC_FS -static struct proc_dir_entry proc_net_ipfwin = { - PROC_NET_IPFWIN, 8, "ip_input", - S_IFREG | S_IRUGO | S_IWUSR, 1, 0, 0, - 0, &proc_net_inode_operations, - ip_fw_in_procinfo -}; -static struct proc_dir_entry proc_net_ipfwout = { - PROC_NET_IPFWOUT, 9, "ip_output", - S_IFREG | S_IRUGO | S_IWUSR, 1, 0, 0, - 0, &proc_net_inode_operations, - ip_fw_out_procinfo -}; -static struct proc_dir_entry proc_net_ipfwfwd = { - PROC_NET_IPFWFWD, 10, "ip_forward", - S_IFREG | S_IRUGO | S_IWUSR, 1, 0, 0, - 0, &proc_net_inode_operations, - ip_fw_fwd_procinfo -}; -#endif #endif - __initfunc(void ip_fw_init(void)) { -#ifdef CONFIG_PROC_FS -#ifdef CONFIG_IP_ACCT - proc_net_register(&proc_net_ipacct); -#endif +#ifdef DEBUG_IP_FIRWALL_LOCKING + fwc_wlocks = fwc_rlocks = 0; #endif -#ifdef CONFIG_IP_FIREWALL + + IP_FW_INPUT_CHAIN = ip_init_chain(IP_FW_LABEL_INPUT, 1, FW_ACCEPT); + IP_FW_FORWARD_CHAIN = ip_init_chain(IP_FW_LABEL_FORWARD, 1, FW_ACCEPT); + IP_FW_OUTPUT_CHAIN = ip_init_chain(IP_FW_LABEL_OUTPUT, 1, FW_ACCEPT); if(register_firewall(PF_INET,&ipfw_ops)<0) panic("Unable to register IP firewall.\n"); + #ifdef CONFIG_PROC_FS - proc_net_register(&proc_net_ipfwin); - proc_net_register(&proc_net_ipfwout); - proc_net_register(&proc_net_ipfwfwd); -#endif + proc_net_register(&proc_net_ipfwchains_chain); + proc_net_register(&proc_net_ipfwchains_chainnames); #endif -#if defined(CONFIG_IP_ACCT) || defined(CONFIG_IP_FIREWALL) - /* Register for device up/down reports */ - register_netdevice_notifier(&ipfw_dev_notifier); -#endif #ifdef CONFIG_IP_FIREWALL_NETLINK ipfwsk = netlink_kernel_create(NETLINK_FIREWALL, NULL); + if (ipfwsk == NULL) + panic("ip_fw_init: cannot initialize netlink\n"); +#endif +#if defined(DEBUG_IP_FIREWALL) || defined(DEBUG_IP_FIREWALL_USER) + printk("Firewall graphs enabled! Untested kernel coming thru. \n"); #endif } diff -u --recursive --new-file v2.1.101/linux/net/ipv4/ip_input.c linux/net/ipv4/ip_input.c --- v2.1.101/linux/net/ipv4/ip_input.c Mon Apr 6 17:41:01 1998 +++ linux/net/ipv4/ip_input.c Thu May 14 10:26:23 1998 @@ -5,7 +5,7 @@ * * The Internet Protocol (IP) module. * - * Version: $Id: ip_input.c,v 1.29 1998/04/03 10:52:06 davem Exp $ + * Version: $Id: ip_input.c,v 1.30 1998/05/08 01:54:54 davem Exp $ * * Authors: Ross Biro, * Fred N. van Kempen, @@ -401,15 +401,6 @@ goto drop; ip_statistics.IpInReceives++; - - /* - * Account for the packet (even if the packet is - * not accepted by the firewall!). - */ - -#ifdef CONFIG_IP_ACCT - ip_fw_chk(iph,dev,NULL,ip_acct_chain,0,IP_FW_MODE_ACCT_IN); -#endif /* * RFC1122: 3.1.2.2 MUST silently discard any IP frame that fails the checksum. diff -u --recursive --new-file v2.1.101/linux/net/ipv4/ip_output.c linux/net/ipv4/ip_output.c --- v2.1.101/linux/net/ipv4/ip_output.c Sat May 2 14:19:55 1998 +++ linux/net/ipv4/ip_output.c Thu May 14 10:26:23 1998 @@ -5,7 +5,7 @@ * * The Internet Protocol (IP) output module. * - * Version: $Id: ip_output.c,v 1.56 1998/04/17 02:36:46 davem Exp $ + * Version: $Id: ip_output.c,v 1.57 1998/05/08 01:54:56 davem Exp $ * * Authors: Ross Biro, * Fred N. van Kempen, @@ -217,21 +217,6 @@ return ip_finish_output(skb); } - -#ifdef CONFIG_IP_ACCT -int ip_acct_output(struct sk_buff *skb) -{ - /* - * Count mapping we shortcut - */ - - ip_fw_chk(skb->nh.iph, skb->dev, NULL, ip_acct_chain, 0, IP_FW_MODE_ACCT_OUT); - - dev_queue_xmit(skb); - - return 0; -} -#endif /* Queues a packet to be sent, and starts the transmitter if necessary. * This routine also needs to put in the total length and compute the diff -u --recursive --new-file v2.1.101/linux/net/ipv4/ip_sockglue.c linux/net/ipv4/ip_sockglue.c --- v2.1.101/linux/net/ipv4/ip_sockglue.c Thu May 7 22:51:56 1998 +++ linux/net/ipv4/ip_sockglue.c Thu May 14 10:26:23 1998 @@ -5,7 +5,7 @@ * * The IP to API glue. * - * Version: $Id: ip_sockglue.c,v 1.32 1998/03/08 05:56:26 davem Exp $ + * Version: $Id: ip_sockglue.c,v 1.35 1998/05/08 21:06:28 davem Exp $ * * Authors: see ip.c * @@ -39,6 +39,8 @@ #include +#define MAX(a,b) ((a)>(b)?(a):(b)) + #define IP_CMSG_PKTINFO 1 #define IP_CMSG_TTL 2 #define IP_CMSG_TOS 4 @@ -227,8 +229,8 @@ int ip_setsockopt(struct sock *sk, int level, int optname, char *optval, int optlen) { int val=0,err; -#if defined(CONFIG_IP_FIREWALL) || defined(CONFIG_IP_ACCT) - struct ip_fw tmp_fw; +#if defined(CONFIG_IP_FIREWALL) + char tmp_fw[MAX(sizeof(struct ip_fwtest),sizeof(struct ip_fwnew))]; #endif #ifdef CONFIG_IP_MASQUERADE char masq_ctl[IP_FW_MASQCTL_MAX]; @@ -387,7 +389,7 @@ } if (!mreq.imr_ifindex) { - if (!mreq.imr_address.s_addr == INADDR_ANY) { + if (mreq.imr_address.s_addr == INADDR_ANY) { sk->ip_mc_index = 0; sk->ip_mc_addr = 0; return 0; @@ -432,28 +434,18 @@ return ip_ra_control(sk, val ? 1 : 0, NULL); #ifdef CONFIG_IP_FIREWALL - case IP_FW_INSERT_IN: - case IP_FW_INSERT_OUT: - case IP_FW_INSERT_FWD: - case IP_FW_APPEND_IN: - case IP_FW_APPEND_OUT: - case IP_FW_APPEND_FWD: - case IP_FW_DELETE_IN: - case IP_FW_DELETE_OUT: - case IP_FW_DELETE_FWD: - case IP_FW_CHECK_IN: - case IP_FW_CHECK_OUT: - case IP_FW_CHECK_FWD: - case IP_FW_FLUSH_IN: - case IP_FW_FLUSH_OUT: - case IP_FW_FLUSH_FWD: - case IP_FW_ZERO_IN: - case IP_FW_ZERO_OUT: - case IP_FW_ZERO_FWD: - case IP_FW_POLICY_IN: - case IP_FW_POLICY_OUT: - case IP_FW_POLICY_FWD: case IP_FW_MASQ_TIMEOUTS: + case IP_FW_APPEND: + case IP_FW_REPLACE: + case IP_FW_DELETE: + case IP_FW_DELETE_NUM: + case IP_FW_INSERT: + case IP_FW_FLUSH: + case IP_FW_ZERO: + case IP_FW_CHECK: + case IP_FW_CREATECHAIN: + case IP_FW_DELETECHAIN: + case IP_FW_POLICY: if(!capable(CAP_NET_ADMIN)) return -EACCES; if(optlen>sizeof(tmp_fw) || optlen<1) @@ -462,8 +454,7 @@ return -EFAULT; err=ip_fw_ctl(optname, &tmp_fw,optlen); return -err; /* -0 is 0 after all */ - -#endif +#endif /* CONFIG_IP_FIREWALL */ #ifdef CONFIG_IP_MASQUERADE case IP_FW_MASQ_ADD: case IP_FW_MASQ_DEL: @@ -477,21 +468,6 @@ err=ip_masq_ctl(optname, masq_ctl,optlen); return -err; /* -0 is 0 after all */ -#endif -#ifdef CONFIG_IP_ACCT - case IP_ACCT_INSERT: - case IP_ACCT_APPEND: - case IP_ACCT_DELETE: - case IP_ACCT_FLUSH: - case IP_ACCT_ZERO: - if(!capable(CAP_NET_ADMIN)) - return -EACCES; - if(optlen>sizeof(tmp_fw) || optlen<1) - return -EINVAL; - if(copy_from_user(&tmp_fw, optval,optlen)) - return -EFAULT; - err=ip_acct_ctl(optname, &tmp_fw,optlen); - return -err; /* -0 is 0 after all */ #endif default: return(-ENOPROTOOPT); diff -u --recursive --new-file v2.1.101/linux/net/ipv4/ipmr.c linux/net/ipv4/ipmr.c --- v2.1.101/linux/net/ipv4/ipmr.c Sat May 2 14:19:55 1998 +++ linux/net/ipv4/ipmr.c Thu May 14 10:26:23 1998 @@ -9,7 +9,7 @@ * as published by the Free Software Foundation; either version * 2 of the License, or (at your option) any later version. * - * Version: $Id: ipmr.c,v 1.34 1998/04/28 06:21:59 davem Exp $ + * Version: $Id: ipmr.c,v 1.35 1998/05/13 06:23:24 davem Exp $ * * Fixes: * Michael Chastain : Incorrect size of copying. @@ -321,7 +321,7 @@ nlh->nlmsg_len = NLMSG_LENGTH(sizeof(struct nlmsgerr)); skb_trim(skb, nlh->nlmsg_len); ((struct nlmsgerr*)NLMSG_DATA(nlh))->error = -ETIMEDOUT; - netlink_unicast(rtnl, skb, NETLINK_CB(skb).pid, MSG_DONTWAIT); + netlink_unicast(rtnl, skb, NETLINK_CB(skb).dst_pid, MSG_DONTWAIT); } else #endif kfree_skb(skb); diff -u --recursive --new-file v2.1.101/linux/net/ipv4/raw.c linux/net/ipv4/raw.c --- v2.1.101/linux/net/ipv4/raw.c Thu May 7 22:51:56 1998 +++ linux/net/ipv4/raw.c Thu May 14 10:26:23 1998 @@ -5,7 +5,7 @@ * * RAW - implementation of IP "raw" sockets. * - * Version: $Id: raw.c,v 1.35 1998/03/08 05:56:32 davem Exp $ + * Version: $Id: raw.c,v 1.36 1998/05/08 21:06:29 davem Exp $ * * Authors: Ross Biro, * Fred N. van Kempen, diff -u --recursive --new-file v2.1.101/linux/net/ipv4/route.c linux/net/ipv4/route.c --- v2.1.101/linux/net/ipv4/route.c Sat May 2 14:19:55 1998 +++ linux/net/ipv4/route.c Thu May 14 10:26:23 1998 @@ -5,7 +5,7 @@ * * ROUTE - implementation of the IP router. * - * Version: $Id: route.c,v 1.47 1998/04/28 06:22:01 davem Exp $ + * Version: $Id: route.c,v 1.50 1998/05/13 06:23:25 davem Exp $ * * Authors: Ross Biro, * Fred N. van Kempen, @@ -144,9 +144,9 @@ }; __u8 ip_tos2prio[16] = { - TC_PRIO_FILLER, TC_PRIO_BESTEFFORT, TC_PRIO_FILLER, + TC_PRIO_BESTEFFORT, TC_PRIO_FILLER, TC_PRIO_BULK, TC_PRIO_FILLER, @@ -221,7 +221,7 @@ r->u.dst.window, (int)r->u.dst.rtt, r->key.tos, r->u.dst.hh ? atomic_read(&r->u.dst.hh->hh_refcnt) : -1, - r->u.dst.hh ? (r->u.dst.hh->hh_output == ip_acct_output) : 0, + r->u.dst.hh ? (r->u.dst.hh->hh_output == dev_queue_xmit) : 0, r->rt_spec_dst); sprintf(buffer+len,"%-127s\n",temp); len += 128; @@ -816,7 +816,7 @@ rt->u.dst.window= 0; rt->u.dst.rtt = TCP_TIMEOUT_INIT; } -#ifdef CONFIG_NET_CLS_ROUTE +#if defined(CONFIG_NET_CLS_ROUTE) && defined(CONFIG_IP_MULTIPLE_TABLES) if (rt->u.dst.tclassid == 0) rt->u.dst.tclassid = fib_rules_tclass(res); #endif @@ -1637,7 +1637,7 @@ if (rtm->rtm_flags & RTM_F_NOTIFY) rt->rt_flags |= RTCF_NOTIFY; - NETLINK_CB(skb).pid = NETLINK_CB(in_skb).pid; + NETLINK_CB(skb).dst_pid = NETLINK_CB(in_skb).pid; err = rt_fill_info(skb, NETLINK_CB(in_skb).pid, nlh->nlmsg_seq, RTM_NEWROUTE, 0); if (err == 0) diff -u --recursive --new-file v2.1.101/linux/net/ipv4/tcp_ipv4.c linux/net/ipv4/tcp_ipv4.c --- v2.1.101/linux/net/ipv4/tcp_ipv4.c Fri May 8 23:14:57 1998 +++ linux/net/ipv4/tcp_ipv4.c Thu May 14 10:26:23 1998 @@ -5,7 +5,7 @@ * * Implementation of the Transmission Control Protocol(TCP). * - * Version: $Id: tcp_ipv4.c,v 1.146 1998/05/03 14:30:59 alan Exp $ + * Version: $Id: tcp_ipv4.c,v 1.147 1998/05/06 13:25:00 freitag Exp $ * * IPv4 specific functions * @@ -690,7 +690,7 @@ /* - * This routine does path mtu discovery as defined in RFC1197. + * This routine does path mtu discovery as defined in RFC1191. */ static inline void do_pmtu_discovery(struct sock *sk, struct iphdr *ip) { diff -u --recursive --new-file v2.1.101/linux/net/ipv4/udp.c linux/net/ipv4/udp.c --- v2.1.101/linux/net/ipv4/udp.c Thu May 7 22:51:56 1998 +++ linux/net/ipv4/udp.c Thu May 14 10:26:23 1998 @@ -5,7 +5,7 @@ * * The User Datagram Protocol (UDP). * - * Version: $Id: udp.c,v 1.55 1998/03/21 07:28:01 davem Exp $ + * Version: $Id: udp.c,v 1.56 1998/05/08 21:06:30 davem Exp $ * * Authors: Ross Biro, * Fred N. van Kempen, diff -u --recursive --new-file v2.1.101/linux/net/ipv6/addrconf.c linux/net/ipv6/addrconf.c --- v2.1.101/linux/net/ipv6/addrconf.c Fri May 8 23:14:57 1998 +++ linux/net/ipv6/addrconf.c Thu May 14 10:26:23 1998 @@ -5,7 +5,7 @@ * Authors: * Pedro Roque * - * $Id: addrconf.c,v 1.39 1998/05/03 14:31:04 alan Exp $ + * $Id: addrconf.c,v 1.41 1998/05/08 21:06:31 davem Exp $ * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License @@ -53,6 +53,7 @@ #include #include +#include /* Set to 3 to get tracing... */ #define ACONF_DEBUG 2 @@ -1157,13 +1158,6 @@ start_bh_atomic(); - /* Discard multicast list */ - - if (how == 1) - ipv6_mc_destroy_dev(idev); - else - ipv6_mc_down(idev); - /* Discard address list */ idev->addr_list = NULL; @@ -1186,6 +1180,13 @@ bifa = &ifa->lst_next; } } + + /* Discard multicast list */ + + if (how == 1) + ipv6_mc_destroy_dev(idev); + else + ipv6_mc_down(idev); /* Delete device from device hash table (if unregistered) */ diff -u --recursive --new-file v2.1.101/linux/net/ipv6/af_inet6.c linux/net/ipv6/af_inet6.c --- v2.1.101/linux/net/ipv6/af_inet6.c Fri May 8 23:14:57 1998 +++ linux/net/ipv6/af_inet6.c Thu May 14 10:26:23 1998 @@ -7,7 +7,7 @@ * * Adapted from linux/net/ipv4/af_inet.c * - * $Id: af_inet6.c,v 1.31 1998/05/03 14:31:06 alan Exp $ + * $Id: af_inet6.c,v 1.33 1998/05/08 21:06:32 davem Exp $ * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License @@ -412,7 +412,8 @@ #ifdef MODULE int ipv6_unload(void) { - return 0; + /* We keep internally 3 raw sockets */ + return __this_module.usecount - 3; } #endif @@ -423,6 +424,7 @@ #endif { struct sk_buff *dummy_skb; + int err; #ifdef MODULE if (!mod_member_present(&__this_module, can_unload)) @@ -443,8 +445,6 @@ #endif } - (void) sock_register(&inet6_family_ops); - /* * ipngwg API draft makes clear that the correct semantics * for TCP and UDP is to consider one TCP and UDP instance @@ -452,19 +452,26 @@ * able to communicate via both network protocols. */ - ipv6_init(); - - icmpv6_init(&inet6_family_ops); - - addrconf_init(); - - sit_init(); - - /* init v6 transport protocols */ +#if defined(MODULE) && defined(CONFIG_SYSCTL) + ipv6_sysctl_register(); +#endif + err = icmpv6_init(&inet6_family_ops); + if (err) + goto icmp_fail; + err = ndisc_init(&inet6_family_ops); + if (err) + goto ndisc_fail; + err = igmp6_init(&inet6_family_ops); + if (err) + goto igmp_fail; + ipv6_netdev_notif_init(); + ipv6_packet_init(); + ip6_route_init(); + addrconf_init(); + sit_init(); + /* Init v6 transport protocols. */ udpv6_init(); - /* add /proc entries here */ - tcpv6_init(); /* Create /proc/foo6 entries. */ @@ -475,22 +482,52 @@ proc_net_register(&proc_net_sockstat6); #endif + /* Now the userspace is allowed to create INET6 sockets. */ + (void) sock_register(&inet6_family_ops); + #ifdef MODULE return 0; +#else + return; +#endif + +igmp_fail: + ndisc_cleanup(); +ndisc_fail: + icmpv6_cleanup(); +icmp_fail: +#if defined(MODULE) && defined(CONFIG_SYSCTL) + ipv6_sysctl_unregister(); +#endif +#ifdef MODULE + return err; +#else + return; #endif } #ifdef MODULE void cleanup_module(void) { - sit_cleanup(); - ipv6_cleanup(); - sock_unregister(PF_INET6); + /* First of all disallow new sockets creation. */ + sock_unregister(AF_INET6); #ifdef CONFIG_PROC_FS proc_net_unregister(proc_net_raw6.low_ino); proc_net_unregister(proc_net_tcp6.low_ino); proc_net_unregister(proc_net_udp6.low_ino); proc_net_unregister(proc_net_sockstat6.low_ino); +#endif + /* Cleanup code parts. */ + sit_cleanup(); + ipv6_netdev_notif_cleanup(); + addrconf_cleanup(); + ip6_route_cleanup(); + ipv6_packet_cleanup(); + igmp6_cleanup(); + ndisc_cleanup(); + icmpv6_cleanup(); +#ifdef CONFIG_SYSCTL + ipv6_sysctl_unregister(); #endif } #endif /* MODULE */ diff -u --recursive --new-file v2.1.101/linux/net/ipv6/icmp.c linux/net/ipv6/icmp.c --- v2.1.101/linux/net/ipv6/icmp.c Thu May 7 22:51:56 1998 +++ linux/net/ipv6/icmp.c Thu May 14 10:26:23 1998 @@ -5,7 +5,7 @@ * Authors: * Pedro Roque * - * $Id: icmp.c,v 1.17 1998/05/01 10:31:41 davem Exp $ + * $Id: icmp.c,v 1.18 1998/05/07 15:42:59 davem Exp $ * * Based on net/ipv4/icmp.c * @@ -62,8 +62,7 @@ * ICMP socket for flow control. */ -struct inode icmpv6_inode; -struct socket *icmpv6_socket=&icmpv6_inode.u.socket_i; +struct socket *icmpv6_socket; int icmpv6_rcv(struct sk_buff *skb, struct device *dev, struct in6_addr *saddr, struct in6_addr *daddr, @@ -557,19 +556,23 @@ struct sock *sk; int err; - icmpv6_inode.i_mode = S_IFSOCK; - icmpv6_inode.i_sock = 1; - icmpv6_inode.i_uid = 0; - icmpv6_inode.i_gid = 0; - - icmpv6_socket->inode = &icmpv6_inode; - icmpv6_socket->state = SS_UNCONNECTED; - icmpv6_socket->type=SOCK_RAW; - - if((err=ops->create(icmpv6_socket, IPPROTO_ICMPV6))<0) { - printk(KERN_DEBUG + icmpv6_socket = sock_alloc(); + if (icmpv6_socket == NULL) { + printk(KERN_ERR "Failed to create the ICMP6 control socket.\n"); - return 1; + return -1; + } + icmpv6_socket->inode->i_uid = 0; + icmpv6_socket->inode->i_gid = 0; + icmpv6_socket->type = SOCK_RAW; + + if ((err = ops->create(icmpv6_socket, IPPROTO_ICMPV6)) < 0) { + printk(KERN_ERR + "Failed to initialize the ICMP6 control socket (err %d).\n", + err); + sock_release(icmpv6_socket); + icmpv6_socket = NULL; /* for safety */ + return err; } sk = icmpv6_socket->sk; @@ -578,18 +581,14 @@ inet6_add_protocol(&icmpv6_protocol); - ndisc_init(ops); - igmp6_init(ops); - return 0; + return 0; } void icmpv6_cleanup(void) { + sock_release(icmpv6_socket); + icmpv6_socket = NULL; /* For safety. */ inet6_del_protocol(&icmpv6_protocol); -#if 0 - ndisc_cleanup(); -#endif - igmp6_cleanup(); } static struct icmp6_err { diff -u --recursive --new-file v2.1.101/linux/net/ipv6/ip6_fib.c linux/net/ipv6/ip6_fib.c --- v2.1.101/linux/net/ipv6/ip6_fib.c Sat May 2 14:19:55 1998 +++ linux/net/ipv6/ip6_fib.c Thu May 14 10:26:23 1998 @@ -5,7 +5,7 @@ * Authors: * Pedro Roque * - * $Id: ip6_fib.c,v 1.13 1998/04/28 06:22:03 davem Exp $ + * $Id: ip6_fib.c,v 1.14 1998/05/07 15:43:03 davem Exp $ * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License @@ -1077,3 +1077,10 @@ ip6_fib_timer.expires = 0; } } + +#ifdef MODULE +void fib6_gc_cleanup(void) +{ + del_timer(&ip6_fib_timer); +} +#endif diff -u --recursive --new-file v2.1.101/linux/net/ipv6/ipv6_sockglue.c linux/net/ipv6/ipv6_sockglue.c --- v2.1.101/linux/net/ipv6/ipv6_sockglue.c Fri May 8 23:14:57 1998 +++ linux/net/ipv6/ipv6_sockglue.c Thu May 14 10:26:23 1998 @@ -7,7 +7,7 @@ * * Based on linux/net/ipv4/ip_sockglue.c * - * $Id: ipv6_sockglue.c,v 1.20 1998/05/03 14:31:07 alan Exp $ + * $Id: ipv6_sockglue.c,v 1.21 1998/05/07 15:43: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 @@ -220,31 +220,24 @@ extern void ipv6_sysctl_unregister(void); #endif -__initfunc(void ipv6_init(void)) +__initfunc(void ipv6_packet_init(void)) { dev_add_pack(&ipv6_packet_type); +} -#if defined(MODULE) && defined(CONFIG_SYSCTL) - ipv6_sysctl_register(); -#endif - +__initfunc(void ipv6_netdev_notif_init(void)) +{ register_netdevice_notifier(&ipv6_dev_notf); - - ip6_route_init(); } #ifdef MODULE -void ipv6_cleanup(void) +void ipv6_packet_cleanup(void) { - unregister_netdevice_notifier(&ipv6_dev_notf); dev_remove_pack(&ipv6_packet_type); -#ifdef CONFIG_SYSCTL - ipv6_sysctl_unregister(); -#endif - ip6_route_cleanup(); - icmpv6_cleanup(); - addrconf_cleanup(); } -#endif - +void ipv6_netdev_notif_cleanup(void) +{ + unregister_netdevice_notifier(&ipv6_dev_notf); +} +#endif diff -u --recursive --new-file v2.1.101/linux/net/ipv6/mcast.c linux/net/ipv6/mcast.c --- v2.1.101/linux/net/ipv6/mcast.c Thu May 7 22:51:56 1998 +++ linux/net/ipv6/mcast.c Thu May 14 10:26:23 1998 @@ -5,7 +5,7 @@ * Authors: * Pedro Roque * - * $Id: mcast.c,v 1.15 1998/04/30 16:24:28 freitag Exp $ + * $Id: mcast.c,v 1.16 1998/05/07 15:43:10 davem Exp $ * * Based on linux/ipv4/igmp.c and linux/ipv4/ip_sockglue.c * @@ -52,8 +52,7 @@ #define MDBG(x) #endif -static struct inode igmp6_inode; -static struct socket *igmp6_socket=&igmp6_inode.u.socket_i; +static struct socket *igmp6_socket; static void igmp6_join_group(struct ifmcaddr6 *ma); static void igmp6_leave_group(struct ifmcaddr6 *ma); @@ -598,7 +597,7 @@ } #endif -__initfunc(void igmp6_init(struct net_proto_family *ops)) +__initfunc(int igmp6_init(struct net_proto_family *ops)) { #ifdef CONFIG_PROC_FS struct proc_dir_entry *ent; @@ -606,18 +605,24 @@ struct sock *sk; int err; - igmp6_inode.i_mode = S_IFSOCK; - igmp6_inode.i_sock = 1; - igmp6_inode.i_uid = 0; - igmp6_inode.i_gid = 0; - - igmp6_socket->inode = &igmp6_inode; - igmp6_socket->state = SS_UNCONNECTED; + igmp6_socket = sock_alloc(); + if (igmp6_socket == NULL) { + printk(KERN_ERR + "Failed to create the IGMP6 control socket.\n"); + return -1; + } + igmp6_socket->inode->i_uid = 0; + igmp6_socket->inode->i_gid = 0; igmp6_socket->type = SOCK_RAW; - if((err=ops->create(igmp6_socket, IPPROTO_ICMPV6))<0) + if((err = ops->create(igmp6_socket, IPPROTO_ICMPV6)) < 0) { printk(KERN_DEBUG - "Failed to create the IGMP6 control socket.\n"); + "Failed to initialize the IGMP6 control socket (err %d).\n", + err); + sock_release(igmp6_socket); + igmp6_socket = NULL; /* For safety. */ + return err; + } sk = igmp6_socket->sk; sk->allocation = GFP_ATOMIC; @@ -628,11 +633,17 @@ ent = create_proc_entry("net/igmp6", 0, 0); ent->read_proc = igmp6_read_proc; #endif + + return 0; } +#ifdef MODULE void igmp6_cleanup(void) { + sock_release(igmp6_socket); + igmp6_socket = NULL; /* for safety */ #ifdef CONFIG_PROC_FS - remove_proc_entry("net/igmp6", 0); + remove_proc_entry("net/igmp6", 0); #endif } +#endif diff -u --recursive --new-file v2.1.101/linux/net/ipv6/ndisc.c linux/net/ipv6/ndisc.c --- v2.1.101/linux/net/ipv6/ndisc.c Thu May 7 22:51:56 1998 +++ linux/net/ipv6/ndisc.c Thu May 14 10:26:23 1998 @@ -74,8 +74,7 @@ #include #include -static struct inode ndisc_inode; -static struct socket *ndisc_socket=&ndisc_inode.u.socket_i; +static struct socket *ndisc_socket; static int ndisc_constructor(struct neighbour *neigh); static void ndisc_solicit(struct neighbour *neigh, struct sk_buff *skb); @@ -1134,23 +1133,29 @@ -__initfunc(void ndisc_init(struct net_proto_family *ops)) +__initfunc(int ndisc_init(struct net_proto_family *ops)) { struct sock *sk; int err; - ndisc_inode.i_mode = S_IFSOCK; - ndisc_inode.i_sock = 1; - ndisc_inode.i_uid = 0; - ndisc_inode.i_gid = 0; - - ndisc_socket->inode = &ndisc_inode; - ndisc_socket->state = SS_UNCONNECTED; - ndisc_socket->type = SOCK_RAW; + ndisc_socket = sock_alloc(); + if (ndisc_socket == NULL) { + printk(KERN_ERR + "Failed to create the NDISC control socket.\n"); + return -1; + } + ndisc_socket->inode->i_uid = 0; + ndisc_socket->inode->i_gid = 0; + ndisc_socket->type = SOCK_RAW; - if((err=ops->create(ndisc_socket, IPPROTO_ICMPV6))<0) + if((err = ops->create(ndisc_socket, IPPROTO_ICMPV6)) < 0) { printk(KERN_DEBUG - "Failed to create the NDISC control socket.\n"); + "Failed to initializee the NDISC control socket (err %d).\n", + err); + sock_release(ndisc_socket); + ndisc_socket = NULL; /* For safety. */ + return err; + } sk = ndisc_socket->sk; sk->allocation = GFP_ATOMIC; @@ -1174,9 +1179,10 @@ #ifdef CONFIG_SYSCTL neigh_sysctl_register(NULL, &nd_tbl.parms, NET_IPV6, NET_IPV6_NEIGH, "ipv6"); #endif + + return 0; } -#ifdef MODULE void ndisc_cleanup(void) { #ifdef CONFIG_PROC_FS @@ -1185,5 +1191,6 @@ #endif #endif neigh_table_clear(&nd_tbl); + sock_release(ndisc_socket); + ndisc_socket = NULL; /* For safety. */ } -#endif diff -u --recursive --new-file v2.1.101/linux/net/ipv6/route.c linux/net/ipv6/route.c --- v2.1.101/linux/net/ipv6/route.c Thu May 7 22:51:56 1998 +++ linux/net/ipv6/route.c Thu May 14 10:26:23 1998 @@ -5,7 +5,7 @@ * Authors: * Pedro Roque * - * $Id: route.c,v 1.28 1998/04/28 06:22:04 davem Exp $ + * $Id: route.c,v 1.30 1998/05/08 21:06:33 davem Exp $ * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License @@ -2173,5 +2173,6 @@ netlink_detach(NETLINK_ROUTE6); #endif rt6_ifdown(NULL); + fib6_gc_cleanup(); } #endif /* MODULE */ diff -u --recursive --new-file v2.1.101/linux/net/netlink/af_netlink.c linux/net/netlink/af_netlink.c --- v2.1.101/linux/net/netlink/af_netlink.c Fri May 8 23:14:57 1998 +++ linux/net/netlink/af_netlink.c Thu May 14 10:26:23 1998 @@ -720,7 +720,7 @@ if (err == 0) size = NLMSG_SPACE(sizeof(struct nlmsgerr)); else - size = NLMSG_SPACE(4 + nlh->nlmsg_len); + size = NLMSG_SPACE(4 + NLMSG_ALIGN(nlh->nlmsg_len)); skb = alloc_skb(size, GFP_KERNEL); if (!skb) diff -u --recursive --new-file v2.1.101/linux/net/netsyms.c linux/net/netsyms.c --- v2.1.101/linux/net/netsyms.c Fri May 8 23:14:57 1998 +++ linux/net/netsyms.c Thu May 14 10:35:55 1998 @@ -60,7 +60,8 @@ defined(CONFIG_EL2) || defined(CONFIG_NE2000) || \ defined(CONFIG_E2100) || defined(CONFIG_HPLAN_PLUS) || \ defined(CONFIG_HPLAN) || defined(CONFIG_AC3200) || \ - defined(CONFIG_ES3210) + defined(CONFIG_ES3210) || defined(CONFIG_ULTRA32) || \ + defined(CONFIG_LNE390) #include "../drivers/net/8390.h" #endif @@ -357,7 +358,8 @@ defined(CONFIG_EL2) || defined(CONFIG_NE2000) || \ defined(CONFIG_E2100) || defined(CONFIG_HPLAN_PLUS) || \ defined(CONFIG_HPLAN) || defined(CONFIG_AC3200) || \ - defined(CONFIG_ES3210) + defined(CONFIG_ES3210) || defined(CONFIG_ULTRA32) || \ + defined(CONFIG_LNE390) /* If 8390 NIC support is built in, we will need these. */ EXPORT_SYMBOL(ei_open); EXPORT_SYMBOL(ei_close); @@ -422,9 +424,6 @@ EXPORT_SYMBOL(netdev_register_fc); EXPORT_SYMBOL(netdev_unregister_fc); EXPORT_SYMBOL(netdev_fc_xoff); -#endif -#ifdef CONFIG_IP_ACCT -EXPORT_SYMBOL(ip_acct_output); #endif EXPORT_SYMBOL(dev_base); EXPORT_SYMBOL(dev_close); diff -u --recursive --new-file v2.1.101/linux/net/sched/Config.in linux/net/sched/Config.in --- v2.1.101/linux/net/sched/Config.in Sat May 2 14:19:55 1998 +++ linux/net/sched/Config.in Thu May 14 10:26:23 1998 @@ -1,6 +1,8 @@ # # Traffic control configuration. # +define_bool CONFIG_NETLINK y +define_bool CONFIG_RTNETLINK y tristate 'CBQ packet scheduler' CONFIG_NET_SCH_CBQ tristate 'CSZ packet scheduler' CONFIG_NET_SCH_CSZ #tristate 'H-PFQ packet scheduler' CONFIG_NET_SCH_HPFQ @@ -14,12 +16,12 @@ if [ "$CONFIG_NET_QOS" = "y" ]; then bool 'Rate estimator' CONFIG_NET_ESTIMATOR fi -if [ "$CONFIG_IP_MULTIPLE_TABLES" = "y" ]; then - bool 'Packet classifier API' CONFIG_NET_CLS -fi +bool 'Packet classifier API' CONFIG_NET_CLS if [ "$CONFIG_NET_CLS" = "y" ]; then bool 'Routing tables based classifier' CONFIG_NET_CLS_ROUTE -# bool 'Firewall based classifier' CONFIG_NET_CLS_FW + if [ "$CONFIG_IP_FIREWALL" = "y" ]; then + bool 'Firewall based classifier' CONFIG_NET_CLS_FW + fi tristate 'U32 classifier' CONFIG_NET_CLS_U32 if [ "$CONFIG_NET_QOS" = "y" ]; then tristate 'Special RSVP classifier' CONFIG_NET_CLS_RSVP diff -u --recursive --new-file v2.1.101/linux/net/sched/cls_api.c linux/net/sched/cls_api.c --- v2.1.101/linux/net/sched/cls_api.c Fri May 8 23:14:58 1998 +++ linux/net/sched/cls_api.c Thu May 14 10:26:23 1998 @@ -114,6 +114,7 @@ u32 protocol = TC_H_MIN(t->tcm_info); u32 prio = TC_H_MAJ(t->tcm_info); u32 nprio = prio; + u32 parent = t->tcm_parent; struct device *dev; struct Qdisc *q; struct tcf_proto **back, **chain; @@ -141,9 +142,10 @@ return -ENODEV; /* Find qdisc */ - if (!t->tcm_parent) + if (!parent) { q = dev->qdisc_sleeping; - else if ((q = qdisc_lookup(dev, TC_H_MAJ(t->tcm_parent))) == NULL) + parent = q->handle; + } else if ((q = qdisc_lookup(dev, TC_H_MAJ(t->tcm_parent))) == NULL) return -EINVAL; /* Is it classful? */ @@ -151,8 +153,8 @@ return -EINVAL; /* Do we search for filter, attached to class? */ - if (TC_H_MIN(t->tcm_parent)) { - cl = cops->get(q, t->tcm_parent); + if (TC_H_MIN(parent)) { + cl = cops->get(q, parent); if (cl == 0) return -ENOENT; } @@ -203,7 +205,7 @@ tp->prio = nprio ? : tcf_auto_prio(*back, prio); tp->q = q; tp->classify = tp_ops->classify; - tp->classid = t->tcm_parent; + tp->classid = parent; err = tp_ops->init(tp); if (err) { kfree(tp); diff -u --recursive --new-file v2.1.101/linux/net/sched/cls_fw.c linux/net/sched/cls_fw.c --- v2.1.101/linux/net/sched/cls_fw.c Sat May 2 14:19:55 1998 +++ linux/net/sched/cls_fw.c Thu May 14 10:26:23 1998 @@ -38,7 +38,6 @@ static int fw_classify(struct sk_buff *skb, struct tcf_proto *tp, struct tcf_result *res) { -#if 0 /* XXX skb->fwmark, where is it? -DaveM */ u32 clid = skb->fwmark; if (clid && (TC_H_MAJ(clid) == 0 || @@ -47,7 +46,6 @@ res->class = 0; return 0; } -#endif return -1; } @@ -81,7 +79,7 @@ return handle ? -EINVAL : 0; } -struct tcf_proto_ops fw_cls_ops = { +struct tcf_proto_ops cls_fw_ops = { NULL, "fw", fw_classify, diff -u --recursive --new-file v2.1.101/linux/net/sched/cls_rsvp.h linux/net/sched/cls_rsvp.h --- v2.1.101/linux/net/sched/cls_rsvp.h Sat May 2 14:19:55 1998 +++ linux/net/sched/cls_rsvp.h Thu May 14 10:26:23 1998 @@ -15,26 +15,26 @@ * (dst, protocol) are always specified, so that we are able to hash them. - * src may be exact, and may be wildcard, so that - we can keep hash table plus one wildcard entry. + * src may be exact, or may be wildcard, so that + we can keep a hash table plus one wildcard entry. * source port (or flow label) is important only if src is given. IMPLEMENTATION. - We use two level hash table: top level is keyed by - destination address and protocol ID, every bucket contains list of - "rsvp sessions", identified by destination address, protocol - and DPI(="Destination Port ID"): triple (key, mask, offset). + We use a two level hash table: The top level is keyed by + destination address and protocol ID, every bucket contains a list + of "rsvp sessions", identified by destination address, protocol and + DPI(="Destination Port ID"): triple (key, mask, offset). - Every bucket has smaller hash table keyed by source address + Every bucket has a smaller hash table keyed by source address (cf. RSVP flowspec) and one wildcard entry for wildcard reservations. - Every bucket is again list of "RSVP flows", selected by + Every bucket is again a list of "RSVP flows", selected by source address and SPI(="Source Port ID" here rather than "security parameter index"): triple (key, mask, offset). NOTE 1. All the packets with IPv6 extension headers (but AH and ESP) - and all fragmented packets go to best-effort traffic class. + and all fragmented packets go to the best-effort traffic class. NOTE 2. Two "port id"'s seems to be redundant, rfc2207 requires @@ -42,29 +42,28 @@ ah, esp (and udp,tcp) both *pi should coincide or one of them should be wildcard. - From the first sight, this redundancy is just waste of CPU - resources. But, DPI and SPI add possibility to assign different - priorities to GPIs. Look also note 4 about tunnels below. + At first sight, this redundancy is just a waste of CPU + resources. But DPI and SPI add the possibility to assign different + priorities to GPIs. Look also at note 4 about tunnels below. NOTE 3. One complication is the case of tunneled packets. - We implement it as the following: if the first lookup - matches special session with "tunnelhdr" value not zero, - flowid contains not true flow ID, but tunnel ID (1...255). + We implement it as following: if the first lookup + matches a special session with "tunnelhdr" value not zero, + flowid doesn't contain the true flow ID, but the tunnel ID (1...255). In this case, we pull tunnelhdr bytes and restart lookup - with tunnel ID added to list of keys. Simple and stupid 8)8) + with tunnel ID added to the list of keys. Simple and stupid 8)8) It's enough for PIMREG and IPIP. - NOTE 4. Two GPIs make possible to parse even GRE packets. + NOTE 4. Two GPIs make it possible to parse even GRE packets. F.e. DPI can select ETH_P_IP (and necessary flags to make tunnelhdr correct) in GRE protocol field and SPI matches GRE key. Is it not nice? 8)8) - Well, as result, despite of simplicity, we get pretty - powerful clsssification engine. - */ + Well, as result, despite its simplicity, we get a pretty + powerful classification engine. */ #include @@ -415,7 +414,7 @@ int err; if (opt == NULL) - return -EINVAL; + return handle ? -EINVAL : 0; if (rtattr_parse(tb, TCA_RSVP_MAX, RTA_DATA(opt), RTA_PAYLOAD(opt)) < 0) return -EINVAL; diff -u --recursive --new-file v2.1.101/linux/net/sched/cls_u32.c linux/net/sched/cls_u32.c --- v2.1.101/linux/net/sched/cls_u32.c Sat May 2 14:19:55 1998 +++ linux/net/sched/cls_u32.c Thu May 14 10:26:23 1998 @@ -12,16 +12,16 @@ * with a set of 32bit key/mask pairs at every node. * Nodes reference next level hash tables etc. * - * This scheme is the best universal classifier - * I managed to invent; it is not super-fast, but it is not slow - * (provided you programmed it correctly), and enough general. - * And its relative speed grows, when number of rules becomes larger. + * This scheme is the best universal classifier I managed to + * invent; it is not super-fast, but it is not slow (provided you + * program it correctly), and general enough. And its relative + * speed grows as the number of rules becomes larger. * - * Seems, it presents the best middle point between speed and - * managability both by human and by machine. + * It seems that it represents the best middle point between + * speed and manageability both by human and by machine. * - * It is especially useful for link sharing and link sharing, combined - * with QoS; pure RSVP need not such general approach and can use + * It is especially useful for link sharing combined with QoS; + * pure RSVP doesn't need such a general approach and can use * much simpler (and faster) schemes, sort of cls_rsvp.c. */ diff -u --recursive --new-file v2.1.101/linux/net/sched/estimator.c linux/net/sched/estimator.c --- v2.1.101/linux/net/sched/estimator.c Sat May 2 14:19:55 1998 +++ linux/net/sched/estimator.c Thu May 14 10:26:23 1998 @@ -31,21 +31,21 @@ #include /* - This text is NOT intended to be used for statistics collection, - its purpose is to provide base for statistical multiplexing + This code is NOT intended to be used for statistics collection, + its purpose is to provide a base for statistical multiplexing for controlled load service. - If you need only statistics, run user level daemon, which will - periodically read byte counters. + If you need only statistics, run a user level daemon which + periodically reads byte counters. - Unfortunately, rate estimation is not very easy task. - F.e. I did not find a simple way to estimate current peak rate + Unfortunately, rate estimation is not a very easy task. + F.e. I did not find a simple way to estimate the current peak rate and even failed to formulate the problem 8)8) - So that I preferred not to built estimator in scheduler, + So I preferred not to built an estimator into the scheduler, but run this task separately. Ideally, it should be kernel thread(s), but for now it runs - from timers, which puts apparent top bounds on number of rated - flows, but has minimal overhead on small, but enough + from timers, which puts apparent top bounds on the number of rated + flows, has minimal overhead on small, but is enough to handle controlled load service, sets of aggregates. We measure rate over A=(1<toplevel == TC_CBQ_MAXLEVEL && @@ -1000,8 +999,8 @@ q->quanta[prio]; } if (cl->quantum <= 0 || cl->quantum>32*cl->qdisc->dev->mtu) { - printk("Damn! %08x cl->quantum==%ld\n", cl->classid, cl->quantum); - cl->quantum = 1; + printk(KERN_WARNING "CBQ: class %08x has bad quantum==%ld, repaired.\n", cl->classid, cl->quantum); + cl->quantum = cl->qdisc->dev->mtu/2 + 1; } } } diff -u --recursive --new-file v2.1.101/linux/net/sched/sch_csz.c linux/net/sched/sch_csz.c --- v2.1.101/linux/net/sched/sch_csz.c Sat May 2 14:19:55 1998 +++ linux/net/sched/sch_csz.c Thu May 14 10:26:23 1998 @@ -49,12 +49,12 @@ CBQ presents a flexible universal algorithm for packet scheduling, but it has pretty poor delay characteristics. Round-robin scheduling and link-sharing goals - apparently contradict to minimization of network delay and jitter. + apparently contradict minimization of network delay and jitter. Moreover, correct handling of predictive flows seems to be impossible in CBQ. - CSZ presents more precise but less flexible and less efficient - approach. As I understand, the main idea is to create + CSZ presents a more precise but less flexible and less efficient + approach. As I understand it, the main idea is to create WFQ flows for each guaranteed service and to allocate the rest of bandwith to dummy flow-0. Flow-0 comprises the predictive services and the best effort traffic; @@ -62,22 +62,23 @@ priority band allocated for predictive services, and the rest --- to the best effort packets. - Note, that in CSZ flows are NOT limited to their bandwidth. - It is supposed, that flow passed admission control at the edge - of QoS network and it more need no shaping. Any attempt to improve - the flow or to shape it to a token bucket at intermediate hops - will introduce undesired delays and raise jitter. + Note that in CSZ flows are NOT limited to their bandwidth. It + is supposed that the flow passed admission control at the edge + of the QoS network and it doesn't need further shaping. Any + attempt to improve the flow or to shape it to a token bucket + at intermediate hops will introduce undesired delays and raise + jitter. At the moment CSZ is the only scheduler that provides true guaranteed service. Another schemes (including CBQ) do not provide guaranteed delay and randomize jitter. - There exists the statement (Sally Floyd), that delay - can be estimated by a IntServ compliant formulae. + There is a proof (Sally Floyd), that delay + can be estimated by a IntServ compliant formula. This result is true formally, but it is wrong in principle. It takes into account only round-robin delays, ignoring delays introduced by link sharing i.e. overlimiting. - Note, that temporary overlimits are inevitable because - real links are not ideal, and true algorithm must take it + Note that temporary overlimits are inevitable because + real links are not ideal, and the real algorithm must take this into account. ALGORITHM. @@ -92,14 +93,14 @@ --- Flow model. - Let $m_a$ is number of backlogged bits in flow $a$. - The flow is {\em active }, if $m_a > 0$. - This number is discontinuous function of time; + Let $m_a$ is the number of backlogged bits in flow $a$. + The flow is {\em active}, if $m_a > 0$. + This number is a discontinuous function of time; when a packet $i$ arrives: \[ m_a(t_i+0) - m_a(t_i-0) = L^i, \] - where $L^i$ is the length of arrived packet. + where $L^i$ is the length of the arrived packet. The flow queue is drained continuously until $m_a == 0$: \[ {d m_a \over dt} = - { B r_a \over \sum_{b \in A} r_b}. @@ -112,23 +113,23 @@ {d m_a \over dt} = - B r_a . \] More complicated hierarchical bandwidth allocation - policies are possible, but, unfortunately, basic - flows equation have simple solution only for proportional + policies are possible, but unfortunately, the basic + flow equations have a simple solution only for proportional scaling. --- Departure times. - We calculate time until the last bit of packet will be sent: + We calculate the time until the last bit of packet is sent: \[ E_a^i(t) = { m_a(t_i) - \delta_a(t) \over r_a }, \] where $\delta_a(t)$ is number of bits drained since $t_i$. We have to evaluate $E_a^i$ for all queued packets, - then find packet with minimal $E_a^i$ and send it. + then find the packet with minimal $E_a^i$ and send it. - It sounds good, but direct implementation of the algorithm + This sounds good, but direct implementation of the algorithm is absolutely infeasible. Luckily, if flow rates - are scaled proportionally, the equations have simple solution. + are scaled proportionally, the equations have a simple solution. The differential equation for $E_a^i$ is \[ @@ -149,7 +150,7 @@ $B \sum_{a \in A} r_a$ bits per round, that takes $\sum_{a \in A} r_a$ seconds. - Hence, $R(t)$ (round number) is monotonically increasing + Hence, $R(t)$ (round number) is a monotonically increasing linear function of time when $A$ is not changed \[ { d R(t) \over dt } = { 1 \over \sum_{a \in A} r_a } @@ -160,17 +161,17 @@ $F_a^i = R(t) + E_a^i(t)/B$ does not depend on time at all! $R(t)$ does not depend on flow, so that $F_a^i$ can be calculated only once on packet arrival, and we need not - recalculation of $E$ numbers and resorting queues. - Number $F_a^i$ is called finish number of the packet. - It is just value of $R(t)$, when the last bit of packet - will be sent out. + recalculate $E$ numbers and resorting queues. + The number $F_a^i$ is called finish number of the packet. + It is just the value of $R(t)$ when the last bit of packet + is sent out. Maximal finish number on flow is called finish number of flow and minimal one is "start number of flow". Apparently, flow is active if and only if $F_a \leq R$. - When packet of length $L_i$ bit arrives to flow $a$ at time $t_i$, - we calculate number $F_a^i$ as: + When a packet of length $L_i$ bit arrives to flow $a$ at time $t_i$, + we calculate $F_a^i$ as: If flow was inactive ($F_a < R$): $F_a^i = R(t) + {L_i \over B r_a}$ @@ -179,31 +180,30 @@ These equations complete the algorithm specification. - It looks pretty hairy, but there exists a simple + It looks pretty hairy, but there is a simple procedure for solving these equations. See procedure csz_update(), that is a generalization of - algorithm from S. Keshav's thesis Chapter 3 + the algorithm from S. Keshav's thesis Chapter 3 "Efficient Implementation of Fair Queeing". NOTES. * We implement only the simplest variant of CSZ, - when flow-0 is explicit 4band priority fifo. - It is bad, but we need "peek" operation in addition + when flow-0 is a explicit 4band priority fifo. + This is bad, but we need a "peek" operation in addition to "dequeue" to implement complete CSZ. - I do not want to make it, until it is not absolutely + I do not want to do that, unless it is absolutely necessary. * A primitive support for token bucket filtering - presents too. It directly contradicts to CSZ, but - though the Internet is on the globe ... :-) - yet "the edges of the network" really exist. + presents itself too. It directly contradicts CSZ, but + even though the Internet is on the globe ... :-) + "the edges of the network" really exist. BUGS. * Fixed point arithmetic is overcomplicated, suboptimal and even - wrong. Check it later. -*/ + wrong. Check it later. */ /* This number is arbitrary */ diff -u --recursive --new-file v2.1.101/linux/net/sched/sch_generic.c linux/net/sched/sch_generic.c --- v2.1.101/linux/net/sched/sch_generic.c Sat May 2 14:19:55 1998 +++ linux/net/sched/sch_generic.c Thu May 14 10:26:23 1998 @@ -37,7 +37,7 @@ struct Qdisc_head qdisc_head = { &qdisc_head }; /* Kick device. - Note, that this procedure can be called by watchdog timer, so that + Note, that this procedure can be called by a watchdog timer, so that we do not check dev->tbusy flag here. Returns: 0 - queue is empty. @@ -62,7 +62,7 @@ } /* Device kicked us out :( - It is possible in three cases: + This is possible in three cases: 1. fastroute is enabled 2. device cannot determine busy state @@ -79,7 +79,7 @@ /* Scan transmission queue and kick devices. Deficiency: slow devices (ppp) and fast ones (100Mb ethernet) - share one queue. It means, that if we have a lot of loaded ppp channels, + share one queue. This means that if we have a lot of loaded ppp channels, we will scan a long list on every 100Mb EOI. I have no idea how to solve it using only "anonymous" Linux mark_bh(). @@ -99,12 +99,12 @@ while (!dev->tbusy && (res = qdisc_restart(dev)) < 0) /* NOTHING */; - /* The explanation is necessary here. + /* An explanation is necessary here. qdisc_restart called dev->hard_start_xmit, if device is virtual, it could trigger one more - dev_queue_xmit and new device could appear - in active chain. In this case we cannot unlink - empty queue, because we lost back pointer. + dev_queue_xmit and a new device could appear + in the active chain. In this case we cannot unlink + the empty queue, because we lost the back pointer. No problem, we will unlink it during the next round. */ @@ -117,7 +117,7 @@ } } -/* Periodic watchdoc timer to recover of hard/soft device bugs. */ +/* Periodic watchdoc timer to recover from hard/soft device bugs. */ static void dev_do_watchdog(unsigned long dummy); @@ -141,8 +141,8 @@ /* "NOOP" scheduler: the best scheduler, recommended for all interfaces - in all curcumstances. It is difficult to invent anything more - fast or cheap. + under all circumstances. It is difficult to invent anything faster or + cheaper. */ static int diff -u --recursive --new-file v2.1.101/linux/net/sched/sch_red.c linux/net/sched/sch_red.c --- v2.1.101/linux/net/sched/sch_red.c Sat May 2 14:19:55 1998 +++ linux/net/sched/sch_red.c Thu May 14 10:26:23 1998 @@ -43,17 +43,17 @@ for Congestion Avoidance", 1993, IEEE/ACM Transactions on Networking. This file codes a "divisionless" version of RED algorithm - written down in Fig.17 of the paper. + as written down in Fig.17 of the paper. Short description. ------------------ - When new packet arrives we calculate average queue length: + When a new packet arrives we calculate the average queue length: avg = (1-W)*avg + W*current_queue_len, - W is filter time constant (choosen as 2^(-Wlog)), controlling - inertia of algorithm. To allow larger bursts, W should be + W is the filter time constant (choosen as 2^(-Wlog)), it controls + the inertia of the algorithm. To allow larger bursts, W should be decreased. if (avg > th_max) -> packet marked (dropped). @@ -67,7 +67,7 @@ max_P should be small (not 1), usually 0.01..0.02 is good value. max_P is chosen as a number, so that max_P/(th_max-th_min) - is negative power of two in order arithmetics to contain + is a negative power of two in order arithmetics to contain only shifts. @@ -78,9 +78,9 @@ Hard limit on queue length, should be chosen >qth_max to allow packet bursts. This parameter does not - affect algorithm behaviour and can be chosen + affect the algorithms behaviour and can be chosen arbitrarily high (well, less than ram size) - Really, this limit will never be achieved + Really, this limit will never be reached if RED works correctly. qth_min - bytes (should be < qth_max/2) @@ -162,18 +162,18 @@ /* The problem: ideally, average length queue recalcultion should - be done over constant clock intervals. It is too expensive, so that - calculation is driven by outgoing packets. - When queue is idle we have to model this clock by hands. + be done over constant clock intervals. This is too expensive, so that + the calculation is driven by outgoing packets. + When the queue is idle we have to model this clock by hand. SF+VJ proposed to "generate" m = idletime/(average_pkt_size/bandwidth) - dummy packets as burst after idle time, i.e. + dummy packets as a burst after idle time, i.e. q->qave *= (1-W)^m - It is apparently overcomplicated solution (f.e. we have to precompute - a table to make this calculation for reasonable time) - I believe, that a simpler model may be used here, + This is an apparently overcomplicated solution (f.e. we have to precompute + a table to make this calculation in reasonable time) + I believe that a simpler model may be used here, but it is field for experiments. */ q->qave >>= q->Stab[(us_idle>>q->Scell_log)&0xFF]; diff -u --recursive --new-file v2.1.101/linux/net/sched/sch_sfq.c linux/net/sched/sch_sfq.c --- v2.1.101/linux/net/sched/sch_sfq.c Sat May 2 14:19:55 1998 +++ linux/net/sched/sch_sfq.c Thu May 14 10:26:23 1998 @@ -55,9 +55,9 @@ Queuing using Deficit Round Robin", Proc. SIGCOMM 95. - It is not the thing that usually called (W)FQ nowadays. It does not - use any timestamp mechanism, but instead processes queues - in round-robin order. + This is not the thing that is usually called (W)FQ nowadays. + It does not use any timestamp mechanism, but instead + processes queues in round-robin order. ADVANTAGE: @@ -66,10 +66,10 @@ DRAWBACKS: - "Stochastic" -> It is not 100% fair. - When hash collisions occur, several flows are considred as one. + When hash collisions occur, several flows are considered as one. - "Round-robin" -> It introduces larger delays than virtual clock - based schemes, and should not be used for isolation interactive + based schemes, and should not be used for isolating interactive traffic from non-interactive. It means, that this scheduler should be used as leaf of CBQ or P3, which put interactive traffic to higher priority band. @@ -82,13 +82,12 @@ This implementation limits maximal queue length to 128; maximal mtu to 2^15-1; number of hash buckets to 1024. The only goal of this restrictions was that all data - fitted to one 4K page :-). Struct sfq_sched_data is - organized in anti-cache manner: all the data for bucket - scattered over different locations. It is not good, - but it allowed to put it into 4K. + fit into one 4K page :-). Struct sfq_sched_data is + organized in anti-cache manner: all the data for a bucket + are scattered over different locations. This is not good, + but it allowed me to put it into 4K. - It is easy to increase these values, but not in flight. -*/ + It is easy to increase these values, but not in flight. */ #define SFQ_DEPTH 128 #define SFQ_HASH_DIVISOR 1024 diff -u --recursive --new-file v2.1.101/linux/net/sched/sch_tbf.c linux/net/sched/sch_tbf.c --- v2.1.101/linux/net/sched/sch_tbf.c Sat May 2 14:19:55 1998 +++ linux/net/sched/sch_tbf.c Thu May 14 10:26:23 1998 @@ -48,12 +48,12 @@ Description. ------------ - Data flow obeys TBF with rate R and depth B, if for any - time interval t_i...t_f number of transmitted bits + A data flow obeys TBF with rate R and depth B, if for any + time interval t_i...t_f the number of transmitted bits does not exceed B + R*(t_f-t_i). Packetized version of this definition: - sequence of packets of sizes s_i served at moments t_i + The sequence of packets of sizes s_i served at moments t_i obeys TBF, if for any i<=k: s_i+....+s_k <= B + R*(t_k - t_i) @@ -61,7 +61,7 @@ Algorithm. ---------- - Let N(t_i) be B/R initially and N(t) grows continuously with time as: + Let N(t_i) be B/R initially and N(t) grow continuously with time as: N(t+delta) = min{B/R, N(t) + delta} @@ -73,13 +73,13 @@ - Actually, QoS requires two TBF to be applied to data stream. + Actually, QoS requires two TBF to be applied to a data stream. One of them controls steady state burst size, another - with rate P (peak rate) and depth M (equal to link MTU) - limits bursts at smaller time scale. + one with rate P (peak rate) and depth M (equal to link MTU) + limits bursts at a smaller time scale. - Apparently, P>R, and B>M. If P is infinity, this double - TBF is equivalent to single one. + It is easy to see that P>R, and B>M. If P is infinity, this double + TBF is equivalent to a single one. When TBF works in reshaping mode, latency is estimated as: @@ -89,22 +89,22 @@ NOTES. ------ - If TBF throttles, it starts watchdog timer, which will wake up it - when it will be ready to transmit. - Note, that minimal timer resolution is 1/HZ. - If no new packets will arrive during this period, - or device will not be awaken by EOI for previous packet, - tbf could stop its activity for 1/HZ. + If TBF throttles, it starts a watchdog timer, which will wake it up + when it is ready to transmit. + Note that the minimal timer resolution is 1/HZ. + If no new packets arrive during this period, + or if the device is not awaken by EOI for some previous packet, + TBF can stop its activity for 1/HZ. - It means, that with depth B, the maximal rate is + This means, that with depth B, the maximal rate is R_crit = B*HZ - F.e. for 10Mbit ethernet and HZ=100 minimal allowed B is ~10Kbytes. + F.e. for 10Mbit ethernet and HZ=100 the minimal allowed B is ~10Kbytes. - Note, that peak rate TBF is much more tough: with MTU 1500 - P_crit = 150Kbytes/sec. So that, if you need greater peak + Note that the peak rate TBF is much more tough: with MTU 1500 + P_crit = 150Kbytes/sec. So, if you need greater peak rates, use alpha with HZ=1000 :-) */ @@ -139,7 +139,7 @@ return 1; } - /* Drop action: undo the things that we just made, + /* Drop action: undo the things that we just did, * i.e. make tail drop */ @@ -230,14 +230,14 @@ add_timer(&q->wd_timer); } - /* Maybe, we have in queue a shorter packet, + /* Maybe we have a shorter packet in the queue, which can be sent now. It sounds cool, - but, however, wrong in principle. - We MUST NOT reorder packets in these curcumstances. + but, however, this is wrong in principle. + We MUST NOT reorder packets under these circumstances. - Really, if we splitted flow to independent - subflows, it would be very good solution. - It is main idea of all FQ algorithms + Really, if we split the flow into independent + subflows, it would be a very good solution. + This is the main idea of all FQ algorithms (cf. CSZ, HPFQ, HFCS) */ __skb_queue_head(&sch->q, skb); diff -u --recursive --new-file v2.1.101/linux/net/sched/sch_teql.c linux/net/sched/sch_teql.c --- v2.1.101/linux/net/sched/sch_teql.c Sat May 2 14:19:55 1998 +++ linux/net/sched/sch_teql.c Thu May 14 10:26:23 1998 @@ -38,8 +38,8 @@ How to setup it. ---------------- - After loading this module you will find new device teqlN - and new qdisc with the same name. To join a slave to equalizer + After loading this module you will find a new device teqlN + and new qdisc with the same name. To join a slave to the equalizer you should just set this qdisc on a device f.e. # tc qdisc add dev eth0 root teql0 @@ -50,20 +50,19 @@ Applicability. -------------- - 1. Slave devices MUST be active devices i.e. must raise tbusy - signal and generate EOI event. If you want to equalize virtual devices - sort of tunnels, use normal eql device. + 1. Slave devices MUST be active devices, i.e., they must raise the tbusy + signal and generate EOI events. If you want to equalize virtual devices + like tunnels, use a normal eql device. 2. This device puts no limitations on physical slave characteristics f.e. it will equalize 9600baud line and 100Mb ethernet perfectly :-) - Certainly, large difference in link speeds will make resulting eqalized - link unusable, because of huge packet reordering. I estimated upper - useful difference as ~10 times. - 3. If slave requires address resolution, only protocols using - neighbour cache (IPv4/IPv6) will work over equalized link. - Another protocols still are allowed to use slave device directly, + Certainly, large difference in link speeds will make the resulting + eqalized link unusable, because of huge packet reordering. + I estimate an upper useful difference as ~10 times. + 3. If the slave requires address resolution, only protocols using + neighbour cache (IPv4/IPv6) will work over the equalized link. + Other protocols are still allowed to use the slave device directly, which will not break load balancing, though native slave - traffic will have the highest priority. - */ + traffic will have the highest priority. */ struct teql_master { @@ -166,8 +165,10 @@ NEXT_SLAVE(prev) = NEXT_SLAVE(q); if (q == master->slaves) { master->slaves = NEXT_SLAVE(q); - if (q == master->slaves) + if (q == master->slaves) { master->slaves = NULL; + qdisc_reset(master->dev.qdisc); + } } skb_queue_purge(&dat->q); teql_neigh_release(xchg(&dat->ncache, NULL)); @@ -270,6 +271,7 @@ struct Qdisc *start, *q; int busy; int nores; + int len = skb->len; struct sk_buff *skb_res = NULL; dev->tbusy = 1; @@ -299,16 +301,18 @@ if (slave->hard_start_xmit(skb, slave) == 0) { master->slaves = NEXT_SLAVE(q); dev->tbusy = 0; + master->stats.tx_packets++; + master->stats.tx_bytes += len; return 0; } break; case 1: - nores = 1; - break; - default: master->slaves = NEXT_SLAVE(q); dev->tbusy = 0; return 0; + default: + nores = 1; + break; } __skb_pull(skb, skb->nh.raw - skb->data); } @@ -322,8 +326,10 @@ dev->tbusy = busy; if (busy) return 1; + master->stats.tx_errors++; drop: + master->stats.tx_dropped++; dev_kfree_skb(skb); return 0; } @@ -366,6 +372,7 @@ m->dev.mtu = mtu; m->dev.flags = (m->dev.flags&~FMASK) | flags; + m->dev.tbusy = 0; MOD_INC_USE_COUNT; return 0; }