D: Moving all VFS access checks into the file systems
S: MIT Room E15-341
S: 20 Ames Street
-S: Cambridge, Massachusetts 02139
+S: Cambridge, Massachusetts 02139
S: USA
N: John Aycock
N: Randolph Bentson
E: bentson@grieg.seaslug.org
-D: author of driver for Cyclades Cyclom-Y async mux
+W: http://www.aa.net/~bentson/
+P: 1024/39ED5729 5C A8 7A F4 B2 7A D1 3E B5 3B 81 CF 47 30 11 71
+D: Author of driver for Cyclades Cyclom-Y async mux
S: 2322 37th Ave SW
S: Seattle, Washington 98126-2010
S: USA
S: The Netherlands
N: Hennus Bergman
-E: hennus@sky.ow.nl [My uucp-fed Linux box at home]
+E: hennus@cybercomm.nl
+W: http://www.cybercomm.nl/~hennus/
+P: 1024/77D50909 76 99 FD 31 91 E1 96 1C 90 BB 22 80 62 F6 BD 63
D: Author and maintainer of the QIC-02 tape driver
S: The Netherlands
D: Original author of the Linux networking code
N: Philip Blundell
-E: pjb27@cam.ac.uk
-E: pb@nexus.co.uk
-E: phil@tazenda.demon.co.uk
+E: Philip.Blundell@pobox.com
D: Device driver hacking (especially EtherExpress16/3C505 net cards)
D: Some Linux/ARM stuff
-S: Trinity College
-S: Cambridge, UK. CB2 1TQ
+S: 201 Gilbert Road
+S: Cambridge, UK. CB4 3PA
N: Thomas Bogendoerfer
-E: tsbogend@bigbug.franken.de
+E: tsbogend@alpha.franken.de
D: Lance32 driver
D: strace for Linux/Alpha
S: Baumgartenweg 5
S: Germany
N: Bill Bogstad
-E: bogstad@cs.jhu.edu
-D: Wrote /proc/self patch
-S: Johns Hopkins University
-S: Computer Science Department
-S: Baltimore, Maryland 21218
-S: USA
+E: bogstad@pobox.com
+D: wrote /proc/self hack, minor samba & dosemu patches
N: Axel Boldt
E: boldt@math.ucsb.edu
S: Fremont, California 94536
S: USA
-N: Chih-Jen Chang
+N: Chih-Jen Chang
E: chihjenc@scf.usc.edu
E: chihjen@iis.sinica.edu.tw
D: IGMP(Internet Group Management Protocol) version 2
N: Juan Jose Ciarlante
E: jjciarla@raiz.uncu.edu.ar
-E: irriga@impsat1.com.ar
+E: juanjo@irriga.uncu.edu.ar
D: Network driver alias support
D: IP masq hashing and app modules
+D: IP ip_dynaddr bits
S: Las Cuevas 2385 - Bo Guemes
S: Las Heras, Mendoza CP 5539
S: Argentina
N: Alan Cox
E: alan@lxorguk.ukuu.org.uk (linux related - except big patches)
-E: iialan@www.linux.org.uk (linux.org.uk/big patches)
+E: iialan@www.uk.linux.org (linux.org.uk/big patches)
E: alan@cymru.net (commercial CymruNET stuff)
-E: gw4pts@gw4pts.ampr.org (amateur radio stuff)
-E: GW4PTS@GB7SWN (packet radio)
-E: Please don't use iialan@iifeak.swan.ac.uk for Linux stuff
-S: c/o 3Com/I^2IT Limited
-S: The Innovation Centre
-S: University Of Wales
-S: Swansea, SA2 8PP
-S: Wales, UK
+E: Alan.Cox@linux.org (if others fail)
D: NET2Debugged/NET3 author
D: Network layer debugging
D: Initial AX.25 & IPX releases
D: Current 3c501 hacker. >>More 3c501 info/tricks wanted<<.
D: Watchdog timer drivers
D: Linux/SMP
+S: CymruNet Limited
+S: The Innovation Centre
+S: Singleton Park
+S: Swansea, SA2 8PP
+S: Wales, United Kingdom
N: Laurence Culhane
E: loz@holmes.demon.co.uk
N: Ray Dassen
E: jdassen@wi.LeidenUniv.nl
W: http://www.wi.leidenuniv.nl/~jdassen/
+P: 1024/672D05C1 DD 60 32 60 F7 90 64 80 E7 6F D4 E4 F8 C9 4A 58
D: Debian GNU/Linux: www.debian.org maintainer, FAQ co-maintainer,
D: packages testing, nit-picking & fixing. Enjoying BugFree (TM) kernels.
S: Zuidsingel 10A
N: David Davies
E: davies@wanton.lkg.dec.com
-S: Digital Equipment Corporation
-S: 550 King Street
-S: Littleton, MA 01460
-S: U.S.A.
D: Network driver author - depca, ewrk3 and de4x5
D: Wrote shared interrupt support
+S: Digital Equipment Corporation
+S: 550 King Street
+S: Littleton, Massachusetts 01460
+S: USA
N: Wayne Davison
E: davison@borland.com
N: Todd J. Derr
E: tjd@fore.com
-D: x86 VESA console blanking enhancements
-D: maintainer of dual-monitor patches for 1.0+
-D: MouseMan driver for selection
-S: Fore Systems, Inc.
-S: 5800 Corporate Drive
-S: Pittsburgh, Pennsylvania 15237-5829
+W: http://www.wordsmith.org/~tjd
+D: Random console hacks and other miscellaneous stuff
+S: 3000 FORE Drive
+S: Warrendale, Pennsylvania 15086
S: USA
N: Eddie C. Dost
D: SCSI code
D: Assorted snippets elsewhere
D: Boot sector "..." printing
-S: 2255 Spruce
+S: 2037 Walnut #6
S: Boulder, Colorado 80302
S: USA
S: Australia
N: Ralf Flaxa
-E: rf@lst.de
+E: rfflaxa@immd4.informatik.uni-erlangen.de
D: The Linux Support Team Erlangen
D: Creator of LST distribution
D: Author of installation tool LISA
E: philip@raptor.com
D: Kernel / timekeeping stuff
-N: Michael A. Griffith
-E: grif@cs.ucr.edu
-W: http://www.cs.ucr.edu/~grif
-D: Loopback speedup, qlogic scsi hacking, VT_LOCKSWITCH
-S: Department of Computer Science
-S: University of California, Riverside
-S: Riverside, California 92521-0304
-S: USA
-
N: Dmitry S. Gorodchanin
E: begemot@bgm.rosprint.net
D: RISCom/8 driver, misc kernel fixes.
E: jgotts@engin.umich.edu
D: kernel hacker
S: 8124 Constitution Apt. 7
-S: Sterling Heights, Michigan 48313
+S: Sterling Heights, Michigan 48313
+S: USA
+
+N: Michael A. Griffith
+E: grif@cs.ucr.edu
+W: http://www.cs.ucr.edu/~grif
+D: Loopback speedup, qlogic scsi hacking, VT_LOCKSWITCH
+S: Department of Computer Science
+S: University of California, Riverside
+S: Riverside, California 92521-0304
S: USA
N: Grant Guenther
S: Germany
N: Richard Henderson
-E: rth@tamu.edu
+E: richard@gnu.ai.mit.edu
+E: rth@cygnus.com
D: Alpha/ELF, gcc, binutils, and glibc
-S: 304 E. North Ave.
-S: Bryan, Texas 77801-3431
-S: USA
N: Sebastian Hetze
E: she@lunetix.de
S: USA
N: Bernhard Kaindl
+E: bkaindl@netway.at
E: edv@bartelt.via.at
D: Author of a menu based configuration tool, kmenu, which
D: is the predecessor of 'make menuconfig' and 'make xconfig'.
S: USA
N: Alain L. Knaff
-E: Alain.Knaff@imag.fr
+E: Alain.Knaff@poboxes.com
D: floppy driver
S: 19, rue Jean l'Aveugle
S: L-1148 Luxembourg-City
D: Promised to send money if I would put his name in the source tree.
S: PO Box 371
S: North Little Rock, Arkansas 72115
-S: US
+S: USA
N: Martin von Loewis
E: loewis@informatik.hu-berlin.de
E: imp@village.org
D: Linux/MIPS Deskstation support, Provided OI/OB for Linux
S: 8786 Niwot Rd
-S: Niwot, CO 80503
+S: Niwot, Colorado 80503
S: USA
N: H.J. Lu
D: SLS distribution
D: Initial implementation of VC's, pty's and select()
+N: Pat Mackinlay
+E: pat@it.com.au
+D: 8 bit XT hard disk driver
+D: Miscellaneous ST0x, TMC-8xx and other SCSI hacking
+S: 25 McMillan Street
+S: Victoria Park 6100
+S: Australia
+
N: James B. MacLean
E: macleajb@ednet.ns.ca
W: http://www.ednet.ns.ca/~macleajb/dosemu.html
S: Halifax, Nova Scotia
S: Canada B3J 3C8
-N: Pat Mackinlay
-E: pat@it.com.au
-D: 8 bit XT hard disk driver
-D: Miscellaneous ST0x, TMC-8xx and other SCSI hacking
-S: 25 McMillan Street
-S: Victoria Park 6100
-S: Australia
-
N: Martin Mares
E: mj@k332.feld.cvut.cz
W: http://atrey.karlin.mff.cuni.cz/~mj/
N: John A. Martin
E: jam@acm.org
+W: http://linux.wauug.org/~jam/
+P: 1024/04456D53 9D A3 6C 6B 88 80 8A 61 D7 06 22 4F 95 40 CE D2
+P: 1024/3B986635 5A61 7EE6 9E20 51FB 59FB 2DA5 3E18 DD55 3B98 6635
D: FSSTND contributor
D: Credit file compilator
D: DLCI/FRAD drivers for Sangoma SDLAs
S: Innovative Logic Corp
S: P.O. Box 1068
-S: Laurel, MD 20732
+S: Laurel, Maryland 20732
S: USA
N: Bradley McLean
S: Germany
N: Michael Meskes
-E: meskes@informatik.rwth-aachen.de
+E: meskes@topsystem.de
+P: 1024/04B6E8F5 6C 77 33 CA CC D6 22 03 AB AB 15 A3 AE AD 39 7D
D: Kernel hacker. Software watchdog daemon.
D: Maintainer of several Debian packages
-S: Lehrstuhl fuer angewandte Mathematik insb. Informatik
-S: RWTH-Aachen
-S: D-52056 Aachen
+S: topsystem Systemhaus GmbH
+S: Europark A2, Adenauerstr. 20
+S: D-52146 Wuerselen
S: Germany
N: Nigel Metheringham
D: IP Masquerading work and minor fixes
S: Planet Online
S: The White House, Melbourne Street, LEEDS
-S: LS2 7PS, UK
+S: LS2 7PS, United Kingdom
N: Craig Metz
-E: cmetz@tjhsst.edu
+E: cmetz@inner.net
D: Some of PAS 16 mixer & PCM support
-S: 12305 Country Ridge Lane
-S: Fairfax, Virginia 22033
-S: USA
N: William (Bill) Metzenthen
E: billm@suburbia.net
S: USA
N: Rick Miller
-E: rick@digalogsys.com
-D: Original Linux Device Registrar (Major/minor numbers), au-play, bwBASIC
+E: rdmiller@execpc.com
+D: Original Linux Device Registrar (Major/minor numbers)
+D: au-play, bwBASIC
S: S78 W16203 Woods Road
S: Muskego, Wisconsin 53150
S: USA
E: davidm@azstarnet.com
D: Linux/Alpha
S: 2552 E. Copper Street
-S: Tucson, AZ 85716-2406
+S: Tucson, Arizona 85716-2406
S: USA
N: Ian A. Murdock
S: Finland
N: Jonathan Naylor
-E: jsn@cs.nott.ac.uk
+E: g4klx@g4klx.demon.co.uk
E: g4klx@amsat.org
-E: G4KLX@GB7DAD (Packet Radio)
+W: http://zone.pspt.fi/~jsn/
D: AX.25 and NET/ROM protocol suites
S: 24 Castle View Drive
S: Cromford
D: IPX development and support
N: Avery Pennarun
-E: apenwarr@foxnet.net
+E: apenwarr@bond.net
D: ARCnet driver
D: "make xconfig" improvements
D: Various minor hacking
S: Germany
N: Joerg Reuter
-E: jreuter@poboxes.com
+E: jreuter@lykos.oche.de
E: dl1bke@db0pra.ampr.org (amateur radio)
-W: http://www.rat.de/jr
D: Z8530 SCC driver and DAMA Slave for AX.25
N: William E. Roadcap
-E: roadcapw@titus.org
+E: roadcapw@cfw.com
W: http://www.cfw.com/~roadcapw
D: Author of ncurses based configuration tool, Menuconfig.
S: 1407 Broad Street
-S: Waynesboro, Virginia 22980
+S: Waynesboro, Virginia 22980
S: USA
N: Florian La Roche
N: Thomas Sailer
E: sailer@ife.ee.ethz.ch
+E: HB9JNX@HB9W.CHE.EU (packet radio)
D: Baycom radio modem driver
S: Weinbergstrasse 76
S: 8408 Winterthur
D: SCSI debugging
D: Maintainer of the Debian Kernel packages
S: 14355 SW Allen Blvd., Suite #140
-S: Beaverton, OR 97008
+S: Beaverton, Oregon 97008
S: USA
N: Mike Shaver
E: leo@netlabs.net
W: http://www.netlabs.net/hp/leo/
D: Optics Storage 8000AT cdrom driver
-S: Cliffwood, NJ 07721
+S: Cliffwood, New Jersey 07721
S: USA
N: Henrik Storner
S: Spain
N: Linus Torvalds
-E: Linus.Torvalds@Helsinki.FI
+E: torvalds@transmeta.com
W: http://www.cs.helsinki.fi/~torvalds/
P: 1024/A86B35C5 96 54 50 29 EC 11 44 7A BE 67 3C 24 03 13 62 C8
-D: General kernel hacker
-S: Kalevankatu 55 B 37
-S: 00180 Helsinki
-S: Finland
+D: Original kernel hacker
+S: 3665 Benton Street #36
+S: Santa Clara, California 95051
+S: USA
N: Jeff Tranter
E: Jeff_Tranter@Mitel.COM
S: 2615 Australia
N: Winfried Trümper
-E: truemper@MI.Uni-Koeln.DE
+E: winni@xpilot.org
+W: http://www.shop.de/~winni/
D: German HOWTO, Enhanced German HOWTO, Crash-Kurs Linux (German)
-D: 1- or 5-days tutorials on Linux twice a year (free of charge)
-D: Linux-Workshop Köln (aka LUUG cologne, germany)
+D: Day and week tutorials on Linux twice a year (free of charge)
+D: Linux-Workshop Köln (aka LUUG Cologne, Germany)
S: Tacitusstr. 6
S: D-50968 Köln
S: Oncology Research Division Computing Facility
S: Roger Maris Cancer Center
S: 820 4th St. N.
-S: Fargo, North Dakota 58122
+S: Fargo, North Dakota 58122
S: USA
N: Hans-Joachim Widmaier
S: Finland
N: Roger E. Wolff
-E: R.E.Wolff@BitWizard.nl
+E: wolff@dutecai.et.tudelft.nl
D: Written kmalloc/kfree
D: Written Specialix IO8+ driver
S: Oosterstraat 23
(specific IP) support.
From version 0.50, dynamic configuration of max alias per device and
tx/rx stats for aliases added.
+ Also fixed inter-alias routing and arping problems.
Features
--------
# modprobe ip_alias.o
Also, dynamic loading is supported (kerneld).
- You should have the following line in /etc/conf.modules:
+ You should have the following line in /etc/conf.modules (not needed
+ for newer modutils):
alias net_alias-2 ip_alias
+ Module options
+ --------------
+ From 0.5x ip_alias module supports a new option ("no_sel" symbol).
+ If no_sel is set (default is 0), alias association (device selection) with
+ foreign addresses will be disabled.
+
+ You will get:
+ - Faster operation by avoiding completely routing lookups.
+ Due to the "logical nature" of aliasing, netdevice SELection can only be
+ done based on info from network layer. When packet dst address isn't
+ one of my addresses, I query the routing table to see which netdevice
+ would be selected for packet _source_ address. This option avoids
+ doing so, and you must consider using it if you *only* have same-net
+ aliases (common usage).
+
+ You will loose:
+ - Inter-alias routing
+ - Proxyarp over aliases
+
+ To activate:
+ # insmod ip_alias.o no_sel=1
+ or
+ # modprobe ip_alias.o no_sel=1
+ or
+ add the following line to /etc/conf.modules:
+ options ip_alias no_sel=1
+
+
o Alias creation.
Alias creation is done by 'magic' iface naming: eg. to create a
200.1.1.1 alias for eth0 ...
device family address
eth0:0 2 200.1.1.1
-o PROCfs dynamic configuration
+o PROCfs dynamic configuration (from v0.50)
You can now change the max aliases per device limit via
- /proc/sys/net/core/net_alias_max entry
+ /proc/sys/net/core/net_alias_max entry (default=256)
# cat /proc/sys/net/core/net_alias_max
256
# echo 1000 > /proc/sys/net/core/net_alias_max
Fake rx/tx stats are accounted:
- TX
When the packet is ``switched'' from logical alias device to
- physical device, tx counter gets incr.
+ physical device, tx counter gets incremented.
- RX
- When an incoming packet's address equals alias device's addr it
+ When an incoming packet's address equals alias network device's addr it
gets ``switched'' from physical to logical device, rx counter gets
incr.
will NOT pass down via alias device (so, no tx++ will occur).
Also NOTE that currently ifconfig does not handle the ``:'' of alias devices
- names, a little patch (attached) solves the problem.
+ names, a little patch solves the problem:
+--- ifconfig.c.dist Tue Apr 4 17:58:32 1995
++++ ifconfig.c Fri Oct 25 13:11:23 1996
+@@ -243,7 +243,12 @@
+ bp++;
+ if(strncmp(bp,ifname,strlen(ifname))==0 && bp[strlen(ifname)]==':')
+ {
+- bp=strchr(bp,':');
++ /*
++ * start bp at ifname end to prevent ':' ambiguity
++ * with alias devices (eg. eth0:0)
++ *
++ */
++ bp+=strlen(ifname);
+ bp++;
+ sscanf(bp,"%d %d %d %d %d %d %d %d %d %d %d",
+ &ife->stats.rx_packets,
Relationship with main device
-----------------------------
Please e-mail me:
Juan Jose Ciarlante <irriga@impsat1.com.ar> or <jjciarla@raiz.uncu.edu.ar>
-
+Acknowledments
+--------------
+Special thanks to Claudia for all her love an patience.
+Also thanks to Antonio Trevi~o <antonio@ecord.gov.ar> great human being
+and un*x guru.
+
; local variables:
; mode: indented-text
; mode: auto-fill
--- /dev/null
+IP dynamic address hack-port v0.03
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+This stuff allows diald ONESHOT connections to get established by
+dynamically changing packet source address (and socket's if local procs).
+It is implemented for TCP diald-box connections(1) and IP_MASQuerading(2).
+
+If enabled[*] and forwarding interface has changed:
+ 1) Socket (and packet) source address is rewritten ON RETRANSMISSIONS
+ while in SYN_SENT state (diald-box processes).
+ 2) Out-bounded MASQueraded source address changes ON OUTPUT (when
+ internal host does retransmission) until a packet from outside is
+ received by the tunnel.
+
+This is specially helpful for auto dialup links (diald), where the
+``actual'' outgoing address is unknown at the moment the link is
+going up. So, the *same* (local AND masqueraded) connections requests that
+bring the link up will be able to get established.
+
+[*] At boot, by default no address rewriting is attempted.
+ To enable:
+ # echo 1 > /proc/sys/net/ipv4/ip_dynaddr
+ To enable verbose mode:
+ # echo 2 > /proc/sys/net/ipv4/ip_dynaddr
+ To disable (default)
+ # echo 0 > /proc/sys/net/ipv4/ip_dynaddr
+
+Enjoy!
+
+-- Juanjo <jjciarla@raiz.uncu.edu.ar>
# CONFIG_HPFS_FS is not set
# CONFIG_SYSV_FS is not set
# CONFIG_UFS_FS is not set
-# CONFIG_AUTOFS_FS is not set
#
# Character devices
iret
#endif
-
ENTRY(lcall7)
pushfl # We get a different stack layout with call gates,
pushl %eax # which has to be cleaned up later..
#include <linux/smp.h>
#include <linux/user.h>
#include <linux/elfcore.h>
+#include <linux/delay.h>
#include <asm/semaphore.h>
/* platform dependent support */
X(dump_thread),
X(dump_fpu),
+ XNOVERS(__do_delay),
XNOVERS(down_failed),
XNOVERS(down_failed_interruptible),
XNOVERS(up_wakeup),
endif
L_TARGET = lib.a
-L_OBJS = checksum.o semaphore.o
+L_OBJS = checksum.o semaphore.o delay.o
include $(TOPDIR)/Rules.make
--- /dev/null
+#include <linux/linkage.h>
+
+/*
+ * BogoMips loop. Non-inlined because various x86's have so wildly
+ * varying results depending on the exact alignment.
+ */
+
+ENTRY(__do_delay)
+1: decl %eax
+ jns 1b
+ ret
+
+
+
return 0;
}
-static int read_full(struct inode * node, struct file * file, char * buf,int count)
-{
- file->f_pos += count;
- return count;
-}
-
static int write_full(struct inode * inode, struct file * file, const char * buf, int count)
{
return -ENOSPC;
#define write_kmem write_mem
#define mmap_kmem mmap_mem
#define zero_lseek null_lseek
+#define full_lseek null_lseek
#define write_zero write_null
+#define read_full read_null
static struct file_operations ram_fops = {
memory_lseek,
};
static struct file_operations full_fops = {
- memory_lseek,
+ full_lseek,
read_full,
write_full,
NULL, /* full_readdir */
if (on) {
if (!waitqueue_active(&tty->read_wait))
tty->minimum_to_wake = 1;
- if (filp->f_owner == 0) {
- if (tty->pgrp)
- filp->f_owner = -tty->pgrp;
- else
- filp->f_owner = current->pid;
+ if (filp->f_owner.pid == 0) {
+ filp->f_owner.pid = (-tty->pgrp) ? : current->pid;
+ filp->f_owner.uid = current->uid;
+ filp->f_owner.euid = current->euid;
}
} else {
if (!tty->fasync && !waitqueue_active(&tty->read_wait))
-/* EtherLink.c: A 3Com EtherLink PCI III/XL ethernet driver for linux. */
+/* EtherLinkXL.c: A 3Com EtherLink PCI III/XL ethernet driver for linux. */
/*
Written 1996-1997 by Donald Becker.
*/
static char *version =
-"3c59x.c:v0.43 9/2/97 Donald Becker http://cesdis.gsfc.nasa.gov/linux/drivers/vortex.html\n";
+"3c59x.c:v0.44 9/9/97 Donald Becker http://cesdis.gsfc.nasa.gov/linux/drivers/vortex.html\n";
-/* "Knobs" that turn on special features. */
+/* "Knobs" that adjust features and parameters. */
/* Set the copy breakpoint for the copy-only-tiny-frames scheme.
Setting to > 1512 effectively disables this feature. */
static const rx_copybreak = 200;
/* Allow setting MTU to a larger size, bypassing the normal ethernet setup. */
static const mtu = 1500;
+/* Maximum events (Rx packets, etc.) to handle at each interrupt. */
+static const max_interrupt_work = 12;
/* Enable the automatic media selection code -- usually set. */
#define AUTOMEDIA 1
#endif
#ifdef VORTEX_DEBUG
-int vortex_debug = VORTEX_DEBUG;
+static int vortex_debug = VORTEX_DEBUG;
#else
-int vortex_debug = 1;
+static int vortex_debug = 1;
#endif
+/* Set iff a MII transceiver on any interface requires mdio preamble. */
+static char mii_preamble_required = 0;
+
/* Caution! These entries must be consistent, with the EISA ones last. */
-static int product_ids[] = {0x5900, 0x5950, 0x5951, 0x5952, 0x9000, 0x9001,
- 0x9050, 0x9051, 0, 0};
+static const int product_ids[] = {
+ 0x5900, 0x5950, 0x5951, 0x5952, 0x9000, 0x9001, 0x9050, 0x9051, 0, 0};
static const char *product_names[] = {
"3c590 Vortex 10Mbps",
"3c595 Vortex 100baseTX",
};
enum Window4 { /* Window 4: Xcvr/media bits. */
- Wn4_NetDiag = 6, Wn4_PhysicalMgmt=8, Wn4_Media = 10,
+ Wn4_FIFODiag = 4, Wn4_NetDiag = 6, Wn4_PhysicalMgmt=8, Wn4_Media = 10,
};
enum Win4_Media_bits {
Media_SQE = 0x0008, /* Enable SQE error counting for AUI. */
int options, int card_idx);
static int vortex_probe1(struct device *dev);
static int vortex_open(struct device *dev);
+static void mdio_sync(int ioaddr, int bits);
static int mdio_read(int ioaddr, int phy_id, int location);
+#ifdef HAVE_PRIVATE_IOCTL
+static void mdio_write(int ioaddr, int phy_id, int location, int value);
+#endif
static void vortex_timer(unsigned long arg);
static int vortex_start_xmit(struct sk_buff *skb, struct device *dev);
static int boomerang_start_xmit(struct sk_buff *skb, struct device *dev);
static void update_stats(int addr, struct device *dev);
static struct enet_statistics *vortex_get_stats(struct device *dev);
static void set_rx_mode(struct device *dev);
+#ifdef HAVE_PRIVATE_IOCTL
+static int vortex_ioctl(struct device *dev, struct ifreq *rq, int cmd);
+#endif
#ifndef NEW_MULTICAST
static void set_multicast_list(struct device *dev, int num_addrs, void *addrs);
#endif
int phy, phy_idx = 0;
EL3WINDOW(4);
for (phy = 0; phy < 32 && phy_idx < sizeof(vp->phys); phy++) {
- int mii_status = mdio_read(ioaddr, phy, 0);
- if (mii_status != 0xffff && mii_status != 0x0000) {
+ int mii_status;
+ mdio_sync(ioaddr, 32);
+ mii_status = mdio_read(ioaddr, phy, 0);
+ if (mii_status != 0xffff) {
vp->phys[phy_idx++] = phy;
printk("%s: MII transceiver found at address %d.\n",
dev->name, phy);
+ mdio_sync(ioaddr, 32);
+ if ((mdio_read(ioaddr, phy, 1) & 0x0040) == 0)
+ mii_preamble_required = 1;
}
}
if (phy_idx == 0) {
dev->hard_start_xmit = &vortex_start_xmit;
dev->stop = &vortex_close;
dev->get_stats = &vortex_get_stats;
+#ifdef HAVE_PRIVATE_IOCTL
+ dev->do_ioctl = &vortex_ioctl;
+#endif
#ifdef NEW_MULTICAST
dev->set_multicast_list = &set_rx_mode;
#else
\f
/* Read and write the MII registers using software-generated serial
MDIO protocol. The maxium data clock rate is 2.5 Mhz. */
-#define mdio_delay(microsecs) udelay(microsecs)
+#define mdio_delay() udelay(1)
#define MDIO_SHIFT_CLK 0x01
#define MDIO_DIR_WRITE 0x04
#define MDIO_DATA_READ 0x02
#define MDIO_ENB_IN 0x00
+static void mdio_sync(int ioaddr, int bits)
+{
+ int mdio_addr = ioaddr + Wn4_PhysicalMgmt;
+
+ /* Establish sync by sending at least 32 logic ones. */
+ while (-- bits >= 0) {
+ outw(MDIO_DATA_WRITE1, mdio_addr);
+ mdio_delay();
+ outw(MDIO_DATA_WRITE1 | MDIO_SHIFT_CLK, mdio_addr);
+ mdio_delay();
+ }
+}
static int mdio_read(int ioaddr, int phy_id, int location)
{
int i;
int read_cmd = (0xf6 << 10) | (phy_id << 5) | location;
- unsigned short retval = 0;
+ unsigned int retval = 0;
int mdio_addr = ioaddr + Wn4_PhysicalMgmt;
+ if (mii_preamble_required)
+ mdio_sync(ioaddr, 32);
+
/* Shift the read command bits out. */
- for (i = 17; i >= 0; i--) {
+ for (i = 14; i >= 0; i--) {
int dataval = (read_cmd&(1<<i)) ? MDIO_DATA_WRITE1 : MDIO_DATA_WRITE0;
outw(dataval, mdio_addr);
- mdio_delay(1);
+ mdio_delay();
outw(dataval | MDIO_SHIFT_CLK, mdio_addr);
- mdio_delay(1);
- outw(dataval, mdio_addr);
- mdio_delay(1);
+ mdio_delay();
}
- outw(MDIO_ENB_IN | MDIO_SHIFT_CLK, mdio_addr);
- outw(MDIO_ENB_IN, mdio_addr);
-
- for (i = 16; i > 0; i--) {
- outw(MDIO_ENB_IN | MDIO_SHIFT_CLK, mdio_addr);
- mdio_delay(1);
- retval = (retval << 1) | ((inw(mdio_addr) & MDIO_DATA_READ) ? 1 : 0);
+ /* Read the two transition, 16 data, and wire-idle bits. */
+ for (i = 19; i > 0; i--) {
outw(MDIO_ENB_IN, mdio_addr);
- mdio_delay(1);
- }
- /* Clear out extra bits. Needed? */
- for (i = 16; i > 0; i--) {
+ mdio_delay();
+ retval = (retval << 1) | ((inw(mdio_addr) & MDIO_DATA_READ) ? 1 : 0);
outw(MDIO_ENB_IN | MDIO_SHIFT_CLK, mdio_addr);
- mdio_delay(1);
+ mdio_delay();
+ }
+ return retval>>1 & 0xffff;
+}
+
+static void mdio_write(int ioaddr, int phy_id, int location, int value)
+{
+ int write_cmd = 0x50020000 | (phy_id << 23) | (location << 18) | value;
+ int mdio_addr = ioaddr + Wn4_PhysicalMgmt;
+ int i;
+
+ if (mii_preamble_required)
+ mdio_sync(ioaddr, 32);
+
+ /* Shift the command bits out. */
+ for (i = 31; i >= 0; i--) {
+ int dataval = (write_cmd&(1<<i)) ? MDIO_DATA_WRITE1 : MDIO_DATA_WRITE0;
+ outw(dataval, mdio_addr);
+ mdio_delay();
+ outw(dataval | MDIO_SHIFT_CLK, mdio_addr);
+ mdio_delay();
+ }
+ /* Leave the interface idle. */
+ for (i = 1; i >= 0; i--) {
outw(MDIO_ENB_IN, mdio_addr);
- mdio_delay(1);
+ mdio_delay();
+ outw(MDIO_ENB_IN | MDIO_SHIFT_CLK, mdio_addr);
+ mdio_delay();
}
- return retval;
+
+ return;
}
\f
outl(config.i, ioaddr + Wn3_Config);
if (dev->if_port == XCVR_MII) {
- int mii_reg1, mii_reg25;
+ int mii_reg1, mii_reg5;
/* We cheat here: we know that we are using the 83840 transceiver
which summarizes the FD status in an extended register. */
EL3WINDOW(4);
/* Read BMSR (reg1) only to clear old status. */
mii_reg1 = mdio_read(ioaddr, vp->phys[0], 1);
- mii_reg25 = mdio_read(ioaddr, vp->phys[0], 0x19);
+ mii_reg5 = mdio_read(ioaddr, vp->phys[0], 5);
+ if (mii_reg5 == 0xffff || mii_reg5 == 0x0000)
+ ; /* No MII device or no link partner report */
+ else if ((mii_reg5 & 0x0100) != 0 /* 100baseTx-FD */
+ || (mii_reg5 & 0x00C0) == 0x0040) /* 10T-FD, but not 100-HD */
+ vp->full_duplex = 1;
if (vortex_debug > 1)
- printk("%s: MII #%d status %4.4x, duplex report %4.4x,"
+ printk("%s: MII #%d status %4.4x, link partner capability %4.4x,"
" setting %s-duplex.\n", dev->name, vp->phys[0],
- mii_reg1, mii_reg25, mii_reg25 & 0x0080 ? "full" : "half");
- if (mii_reg25 & 0x0080)
- vp->full_duplex = 1;
+ mii_reg1, mii_reg5, vp->full_duplex ? "full" : "half");
EL3WINDOW(3);
}
outw(AckIntr | IntLatch | TxAvailable | RxEarly | IntReq,
ioaddr + EL3_CMD);
outw(SetIntrEnb | IntLatch | TxAvailable | RxComplete | StatsFull
+ | AdapterFailure
| (vp->bus_master ? DMADone : 0) | UpComplete | DownComplete,
ioaddr + EL3_CMD);
case XCVR_MII:
{
int mii_reg1 = mdio_read(ioaddr, vp->phys[0], 1);
+ int mii_reg5 = mdio_read(ioaddr, vp->phys[0], 5);
if (vortex_debug > 1)
- printk("%s: MII #%d status register is %4.4x.\n",
- dev->name, vp->phys[0], mii_reg1);
+ printk("%s: MII #%d status register is %4.4x, "
+ "link partner capability %4.4x.\n",
+ dev->name, vp->phys[0], mii_reg1, mii_reg5);
if (mii_reg1 & 0x0004)
ok = 1;
break;
inw(ioaddr + EL3_STATUS));
/* Slight code bloat to be user friendly. */
if ((inb(ioaddr + TxStatus) & 0x88) == 0x88)
- printk("%s: Transmitter encountered 16 collisions -- network"
- " network cable problem?\n", dev->name);
+ printk("%s: Transmitter encountered 16 collisions --"
+ " network cable problem?\n", dev->name);
+ if (inw(ioaddr + EL3_STATUS) & IntLatch) {
+ printk("%s: Interrupt posted but not handled --"
+ " IRQ blocked by another device?\n", dev->name);
+ /* Bad idea here.. but we might as well handle a few events. */
+ vortex_interrupt IRQ(dev->irq, dev, 0);
+ }
#ifndef final_version
- printk(" Flags; bus-master %d, full %d; dirty %d current %d.\n",
- vp->full_bus_master_tx, vp->tx_full, vp->dirty_tx, vp->cur_tx);
- printk(" Down list %8.8x vs. %p.\n", inl(ioaddr + DownListPtr),
- &vp->tx_ring[0]);
- for (i = 0; i < TX_RING_SIZE; i++) {
- printk(" %d: %p length %8.8x status %8.8x\n", i,
- &vp->tx_ring[i],
- vp->tx_ring[i].length,
- vp->tx_ring[i].status);
+ if (vp->full_bus_master_tx) {
+ printk(" Flags; bus-master %d, full %d; dirty %d current %d.\n",
+ vp->full_bus_master_tx, vp->tx_full, vp->dirty_tx, vp->cur_tx);
+ printk(" Transmit list %8.8x vs. %p.\n", inl(ioaddr + DownListPtr),
+ &vp->tx_ring[vp->dirty_tx % TX_RING_SIZE]);
+ for (i = 0; i < TX_RING_SIZE; i++) {
+ printk(" %d: @%p length %8.8x status %8.8x\n", i,
+ &vp->tx_ring[i],
+ vp->tx_ring[i].length,
+ vp->tx_ring[i].status);
+ }
}
+#ifdef notdef
if (vp->full_bus_master_rx) {
printk(" Switching to non-bus-master receives.\n");
outw(SetStatusEnb | AdapterFailure|IntReq|StatsFull |
RxComplete | (vp->bus_master ? DMADone : 0),
ioaddr + EL3_CMD);
}
-#endif
/* Issue TX_RESET and TX_START commands. */
outw(TxReset, ioaddr + EL3_CMD);
for (i = 20; i >= 0 ; i--)
if ( ! (inw(ioaddr + EL3_STATUS) & CmdInProgress))
break;
+#endif
+#endif
if (vp->full_bus_master_tx) {
/* Change 6/25/97 Michael Sievers sieversm@mail.desy.de
The card has been resetted, but the Tx Ring is still full.
unsigned int dirty_tx = vp->dirty_tx;
+ if (vortex_debug > 0)
+ printk("%s: Freeing Tx ring entries:", dev->name);
while (vp->cur_tx - dirty_tx > 0) {
int entry = dirty_tx % TX_RING_SIZE;
if (inl(ioaddr + DownListPtr) ==
virt_to_bus(&vp->tx_ring[entry]))
break; /* It still hasn't been processed. */
if (vp->tx_skbuff[entry]) {
- if (vortex_debug > 0)
- printk("%s: Freeing Tx ring entry %d\n",dev->name,entry);
- dev_kfree_skb(vp->tx_skbuff[entry], FREE_WRITE);
- vp->tx_skbuff[entry] = 0;
+ if (vortex_debug > 0)
+ printk(" %d\n", entry);
+ dev_kfree_skb(vp->tx_skbuff[entry], FREE_WRITE);
+ vp->tx_skbuff[entry] = 0;
+ vp->stats.tx_dropped++;
}
+ if (vortex_debug > 0)
+ printk(".\n");
vp->stats.tx_errors++;
- vp->stats.tx_dropped++;
dirty_tx++;
}
vp->dirty_tx = dirty_tx;
printk("%s: Trying to send a packet, Tx index %d.\n",
dev->name, vp->cur_tx);
if (vp->tx_full) {
- if (vortex_debug >0)
- printk("%s: Tx Ring full, refusing to send buffer.\n",
- dev->name);
- return 1;
+ if (vortex_debug >0)
+ printk("%s: Tx Ring full, refusing to send buffer.\n",
+ dev->name);
+ return 1;
}
/* end change 06/25/97 M. Sievers */
vp->tx_skbuff[entry] = skb;
cli();
outw(DownStall, ioaddr + EL3_CMD);
/* Wait for the stall to complete. */
- for (i = 20; i >= 0 ; i--)
+ for (i = 60; i >= 0 ; i--)
if ( (inw(ioaddr + EL3_STATUS) & CmdInProgress) == 0)
break;
prev_entry->next = virt_to_bus(&vp->tx_ring[entry]);
struct vortex_private *lp;
int ioaddr, status;
int latency;
- int i = 0;
+ int i = max_interrupt_work;
if (dev->interrupt)
printk("%s: Re-entering the interrupt handler.\n", dev->name);
if (vortex_debug > 4)
printk("%s: interrupt, status %4.4x, timer %d.\n", dev->name,
status, latency);
- if ((status & 0xE000) != 0xE000) {
+#ifdef notdef
+ /* This code guard against bogus hangs, but fails with shared IRQs. */
+ if ((status & ~0xE000) == 0x0000) {
static int donedidthis=0;
/* Some interrupt controllers store a bogus interrupt from boot-time.
Ignore a single early interrupt, but don't hang the machine for
other interrupt problems. */
- if (donedidthis++ > 1) {
+ if (donedidthis++ > 100) {
printk("%s: Bogus interrupt, bailing. Status %4.4x, start=%d.\n",
dev->name, status, dev->start);
FREE_IRQ(dev->irq, dev);
}
}
+#endif
do {
if (vortex_debug > 5)
dev->tbusy = 0;
mark_bh(NET_BH);
}
+ if (status & TxComplete) { /* Really "TxError" for us. */
+ /* Presumably a tx-timeout. We must merely re-enable. */
+ if (vortex_debug > 0)
+ printk("%s: Host error, Tx status register %2.2x.\n",
+ dev->name, inb(TxStatus));
+ outw(TxEnable, ioaddr + EL3_CMD);
+ }
if (status & DownComplete) {
unsigned int dirty_tx = lp->dirty_tx;
/* lp->stats.tx_packets++; Counted below. */
dirty_tx++;
}
+ lp->dirty_tx = dirty_tx;
outw(AckIntr | DownComplete, ioaddr + EL3_CMD);
- if (lp->tx_full) {
+ if (lp->tx_full && (lp->cur_tx - dirty_tx <= TX_RING_SIZE - 1)) {
lp->tx_full= 0;
dev->tbusy = 0;
mark_bh(NET_BH);
}
- lp->dirty_tx = dirty_tx;
}
#ifdef VORTEX_BUS_MASTER
if (status & DMADone) {
printk(" %2.2x", inb(ioaddr+reg));
}
EL3WINDOW(7);
- outw(SetIntrEnb | TxAvailable | RxComplete
+ outw(SetIntrEnb | TxAvailable | RxComplete | AdapterFailure
| UpComplete | DownComplete, ioaddr + EL3_CMD);
DoneDidThat++;
}
}
if (status & AdapterFailure) {
- /* Adapter failure requires Rx reset and reinit. */
- outw(RxReset, ioaddr + EL3_CMD);
- /* Set the Rx filter to the current state. */
- set_rx_mode(dev);
- outw(RxEnable, ioaddr + EL3_CMD); /* Re-enable the receiver. */
- outw(AckIntr | AdapterFailure, ioaddr + EL3_CMD);
+ u16 fifo_diag;
+ EL3WINDOW(4);
+ fifo_diag = inw(ioaddr + Wn4_FIFODiag);
+ if (vortex_debug > 0)
+ printk("%s: Host error, FIFO diagnostic register %4.4x.\n",
+ dev->name, fifo_diag);
+ /* Adapter failure requires Tx/Rx reset and reinit. */
+ if (fifo_diag & 0x0400) {
+ int j;
+ outw(TxReset, ioaddr + EL3_CMD);
+ for (j = 20; j >= 0 ; j--)
+ if ( ! (inw(ioaddr + EL3_STATUS) & CmdInProgress))
+ break;
+ outw(TxEnable, ioaddr + EL3_CMD);
+ }
+ if (fifo_diag & 0x2000) {
+ outw(RxReset, ioaddr + EL3_CMD);
+ /* Set the Rx filter to the current state. */
+ set_rx_mode(dev);
+ outw(RxEnable, ioaddr + EL3_CMD); /* Re-enable the receiver. */
+ outw(AckIntr | AdapterFailure, ioaddr + EL3_CMD);
+ }
}
}
- if (++i > 10) {
+ if (--i < 0) {
printk("%s: Infinite loop in interrupt, status %4.4x. "
"Disabling functions (%4.4x).\n",
dev->name, status, SetStatusEnb | ((~status) & 0x7FE));
while ((rx_status = vp->rx_ring[entry].status) & RxDComplete) {
if (rx_status & RxDError) { /* Error, update stats. */
unsigned char rx_error = rx_status >> 16;
- if (vortex_debug > 4)
+ if (vortex_debug > 2)
printk(" Rx error: status %2.2x.\n", rx_error);
vp->stats.rx_errors++;
if (rx_error & 0x01) vp->stats.rx_over_errors++;
return;
}
+#ifdef HAVE_PRIVATE_IOCTL
+static int vortex_ioctl(struct device *dev, struct ifreq *rq, int cmd)
+{
+ struct vortex_private *vp = (struct vortex_private *)dev->priv;
+ int ioaddr = dev->base_addr;
+ u16 *data = (u16 *)&rq->ifr_data;
+ int phy = vp->phys[0] & 0x1f;
+
+ if (vortex_debug > 2)
+ printk("%s: In ioct(%-.6s, %#4.4x) %4.4x %4.4x %4.4x %4.4x.\n",
+ dev->name, rq->ifr_ifrn.ifrn_name, cmd,
+ data[0], data[1], data[2], data[3]);
+
+ switch(cmd) {
+ case SIOCDEVPRIVATE: /* Get the address of the PHY in use. */
+ data[0] = phy;
+ case SIOCDEVPRIVATE+1: /* Read the specified MII register. */
+ EL3WINDOW(4);
+ data[3] = mdio_read(ioaddr, data[0] & 0x1f, data[1] & 0x1f);
+ return 0;
+ case SIOCDEVPRIVATE+2: /* Write the specified MII register */
+ if (!suser())
+ return -EPERM;
+ mdio_write(ioaddr, data[0] & 0x1f, data[1] & 0x1f, data[2]);
+ return 0;
+ default:
+ return -EOPNOTSUPP;
+ }
+}
+#endif /* HAVE_PRIVATE_IOCTL */
+
/* This new version of set_rx_mode() supports v1.4 kernels.
The Vortex chip has no documented multicast filter, so the only
multicast setting is to receive all multicast frames. At least
}
if (tulip_debug > 0) /* Gurppp, should be >1 */
printk(KERN_INFO "%s: Setting %s-duplex based on MII"
- " Xcvr #%d parter capability of %4.4x.\n",
+ " Xcvr #%d partner capability of %4.4x.\n",
dev->name, full_duplex ? "full" : "half",
tp->phys[0], mii_reg5);
}
dep_tristate 'EATA ISA/EISA/PCI (DPT and generic EATA/DMA-compliant boards) support' CONFIG_SCSI_EATA $CONFIG_SCSI
if [ "$CONFIG_SCSI_EATA" != "n" ]; then
bool ' enable tagged command queueing' CONFIG_SCSI_EATA_TAGGED_QUEUE
- bool ' enable linked commands' CONFIG_SCSI_EATA_LINKED_COMMANDS
+ bool ' enable elevator sorting' CONFIG_SCSI_EATA_LINKED_COMMANDS
int ' maximum number of queued commands' CONFIG_SCSI_EATA_MAX_TAGS 16
fi
dep_tristate 'Future Domain 16xx SCSI support' CONFIG_SCSI_FUTURE_DOMAIN $CONFIG_SCSI
dep_tristate 'Trantor T128/T128F/T228 SCSI support' CONFIG_SCSI_T128 $CONFIG_SCSI
dep_tristate 'UltraStor 14F/34F support' CONFIG_SCSI_U14_34F $CONFIG_SCSI
if [ "$CONFIG_SCSI_U14_34F" != "n" ]; then
- bool ' enable linked commands' CONFIG_SCSI_U14_34F_LINKED_COMMANDS
+ bool ' enable elevator sorting' CONFIG_SCSI_U14_34F_LINKED_COMMANDS
int ' maximum number of queued commands' CONFIG_SCSI_U14_34F_MAX_TAGS 8
fi
dep_tristate 'UltraStor SCSI support' CONFIG_SCSI_ULTRASTOR $CONFIG_SCSI
long r_total; /* total reads */
long r_total512; /* 512 byte blocks read */
long r_bins[10]; /* binned reads */
- } stats[2][16][8]; /* channel, target, lun */
+ } stats[16][8]; /* channel, target, lun */
#endif /* AIC7XXX_PROC_STATS */
};
* These functions are not used yet, but when we do memory mapped
* IO, we'll use them then.
*
+ * For now we leave these commented out as the x86 inline assembly causes
+ * compiles to barf on DEC Alphas. Besides, they aren't even used yet, so
+ * they constitute wasted .text space right now.
***************************************************************************/
+
+/***************************************************************************
+
static inline unsigned char
aic_inb(struct aic7xxx_host *p, long port)
{
outsb(p->base + port, valp, size);
}
}
+ ***************************************************************************/
/*+F*************************************************************************
* Function:
aic7xxx_queue_cmd_complete(p, cmd);
#ifdef AIC7XXX_PROC_STATS
+ if ( (cmd->cmnd[0] != TEST_UNIT_READY) &&
+ (cmd->cmnd[0] != INQUIRY) )
{
int actual;
long *ptr;
int x;
- sp = &p->stats[cmd->channel & 0x01][cmd->target & 0x0F][cmd->lun & 0x07];
+ sp = &p->stats[((cmd->channel << 3) | cmd->target) & 0xf][cmd->lun & 0x7];
sp->xfers++;
if (cmd->request.cmd == WRITE)
#ifndef AIC7XXX_TAGGED_QUEUEING_BY_DEVICE
device->queue_depth = default_depth;
#else
- if (p->instance > NUMBER(aic7xxx_tag_info))
+ if (p->instance >= NUMBER(aic7xxx_tag_info))
{
device->queue_depth = default_depth;
}
scbq_init(&p->scb_data->free_scbs);
scbq_init(&p->waiting_scbs);
- for (i = 0; i <= NUMBER(p->device_status); i++)
+ for (i = 0; i < NUMBER(p->device_status); i++)
{
p->device_status[i].commands_sent = 0;
p->device_status[i].flags = 0;
*/
outb(p->qcntmask, p->base + QCNTMASK);
- outb(p->qfullcount, p->base + FIFODEPTH);
- outb(0, p->base + CMDOUTCNT);
+ if (p->flags & PAGE_ENABLED)
+ {
+ outb(p->qfullcount, p->base + FIFODEPTH);
+ outb(0, p->base + CMDOUTCNT);
+ }
/*
* We don't have any waiting selections or disconnected SCBs.
* a NULL entry to indicate that no prior hosts have
* been found/registered for that IRQ.
*/
- for (i = 0; i <= NUMBER(aic7xxx_boards); i++)
+ for (i = 0; i < NUMBER(aic7xxx_boards); i++)
{
aic7xxx_boards[i] = NULL;
}
scb = (p->scb_data->scb_array[aic7xxx_position(cmd)]);
base = p->base;
channel = cmd->channel ? 'B': 'A';
- tindex = (cmd->channel << 4) | cmd->target;
+ tindex = (cmd->channel << 3) | cmd->target;
#ifdef 0 /* AIC7XXX_DEBUG_ABORT */
if (scb != NULL)
* tab-width: 8
* End:
*/
-
CUR_SCBID {
size 1
}
+ ARG_1 {
+ size 1
+ mask SEND_MSG 0x80
+ mask SEND_SENSE 0x40
+ mask SEND_REJ 0x20
+ alias RETURN_1
+ }
/*
* Running count of commands placed in
* the QOUTFIFO. This is cleared by the
* kernel driver every FIFODEPTH commands.
+ *
+ * NOTE: these scratch RAM registers are *only* used on cards
+ * that enable SCB paging. The 2742 is unable to page. We
+ * won't use these on a 2742, and we can't init these registers
+ * in the kernel driver for 2742 cards because these locations are
+ * are used by the 2742 cards to control things like bus
+ * termination. Touching these memory locations is a no-no on all
+ * non-paging cards as far as we are concerned.
*/
CMDOUTCNT {
size 1
FIFODEPTH {
size 1
}
- ARG_1 {
- size 1
- mask SEND_MSG 0x80
- mask SEND_SENSE 0x40
- mask SEND_REJ 0x20
- alias RETURN_1
- }
/*
* These are reserved registers in the card's scratch ram. Some of
* the values are specified in the AHA2742 technical reference manual
size 1
bit RESET_SCSI 0x40
}
+ SCSICONF2 {
+ address 0x05b
+ size 1
+ bit RESET_SCSI 0x40
+ }
HOSTCONF {
address 0x05d
size 1
* o Modified from the EATA-DMA /proc support.
* o Additional support for device block statistics provided by
* Matthew Jacob.
+ * o Correction of overflow by Heinz Mauelshagen
+ * o Adittional corrections by Doug Ledford
*
* Dean W. Gehnert, deang@teleport.com, 05/01/96
*
* $Id: aic7xxx_proc.c,v 4.1 1997/06/97 08:23:42 deang Exp $
*-M*************************************************************************/
-#define BLS buffer + len + size
+#define BLS (&aic7xxx_buffer[size])
#define HDRB \
" < 512 512-1K 1-2K 2-4K 4-8K 8-16K 16-32K 32-64K 64-128K >128K"
proc_debug("aic7xxx_set_info(): %s\n", buffer);
return (-ENOSYS); /* Currently this is a no-op */
}
-
+
/*+F*************************************************************************
* Function:
* aic7xxx_proc_info
* Return information to handle /proc support for the driver.
*-F*************************************************************************/
int
-aic7xxx_proc_info(char *buffer, char **start, off_t offset, int length,
- int hostno, int inout)
+aic7xxx_proc_info ( char *buffer, char **start, off_t offset, int length,
+ int hostno, int inout)
{
struct Scsi_Host *HBAptr;
struct aic7xxx_host *p;
- int i;
- int found = FALSE;
- int size = 0;
- int len = 0;
- off_t begin = 0;
- off_t pos = 0;
+ static int aic7xxx_buffer_size = 0;
+ int found = FALSE;
+ static int size = 0;
+ unsigned char i;
+ static char *aic7xxx_buffer = NULL;
static char *bus_names[] = { "Single", "Twin", "Wide" };
static char *chip_names[] = { "AIC-777x", "AIC-785x", "AIC-786x",
"AIC-787x", "AIC-788x" };
+#ifdef AIC7XXX_PROC_STATS
+ struct aic7xxx_xferstats *sp;
+ unsigned char target, lun;
+#endif
HBAptr = NULL;
for (i=0; i < NUMBER(aic7xxx_boards); i++)
{
break;
}
-
+
while ((HBAptr->hostdata != NULL) && !found &&
((HBAptr = ((struct aic7xxx_host *) HBAptr->hostdata)->next) != NULL))
{
found = TRUE;
}
}
-
+
if (!found)
{
HBAptr = NULL;
}
}
}
-
+
if (HBAptr == NULL)
{
- size += sprintf(BLS, "Can't find adapter for host number %d\n", hostno);
- len += size; pos = begin + len; size = 0;
- goto stop_output;
+ size += sprintf( buffer, "Can't find adapter for host number %d\n", hostno);
+ if ( size > length) return size;
+ return length;
}
-
+
if (inout == TRUE) /* Has data been written to the file? */
{
return (aic7xxx_set_info(buffer, length, HBAptr));
}
-
+
p = (struct aic7xxx_host *) HBAptr->hostdata;
+ /* It takes roughly 1K of space to hold all relevant card info, not */
+ /* counting any proc stats, so we start out with a 1.5k buffer size and */
+ /* if proc_stats is defined, then we sweep the stats structure to see */
+ /* how many drives we will be printing out for and add 384 bytes per */
+ /* device with active stats. */
+
+ size = 1536;
+#ifdef AIC7XXX_PROC_STATS
+ for (target=0; target<16; target++)
+ {
+ for (lun=0; lun<8; lun++)
+ {
+ if (p->stats[target][lun].xfers != 0)
+ size += 384;
+ }
+ }
+#endif
+ if ( aic7xxx_buffer_size != size) {
+ if ( aic7xxx_buffer != NULL)
+ {
+ kfree ( aic7xxx_buffer);
+ aic7xxx_buffer_size = 0;
+ }
+ aic7xxx_buffer = kmalloc ( size, GFP_KERNEL);
+ }
+ if ( aic7xxx_buffer == NULL) {
+ size = sprintf ( buffer, "AIC7xxx - kmalloc error at line %d\n",
+ __LINE__);
+ return size;
+ }
+ aic7xxx_buffer_size = size;
+
+ size = 0;
size += sprintf(BLS, "Adaptec AIC7xxx driver version: ");
size += sprintf(BLS, "%s/", rcs_version(AIC7XXX_C_VERSION));
size += sprintf(BLS, "%s", rcs_version(AIC7XXX_H_VERSION));
#if 0
size += sprintf(BLS, "%s\n", rcs_version(AIC7XXX_SEQ_VER));
#endif
- if (size > 512)
- printk(KERN_CRIT "aic7xxx: possible overflow at first position\n");
- len += size; pos = begin + len; size = 0;
- if (pos < offset)
- {
- begin = pos;
- len = 0;
- }
-
size += sprintf(BLS, "\n");
size += sprintf(BLS, "Compile Options:\n");
#ifdef AIC7XXX_RESET_DELAY
- size += sprintf(BLS, " AIC7XXX_RESET_DELAY : %d\n", AIC7XXX_RESET_DELAY);
+ size += sprintf(BLS, " AIC7XXX_RESET_DELAY : %d\n",
+ AIC7XXX_RESET_DELAY);
#endif
#ifdef AIC7XXX_CMDS_PER_LUN
- size += sprintf(BLS, " AIC7XXX_CMDS_PER_LUN : %d\n", AIC7XXX_CMDS_PER_LUN);
+ size += sprintf(BLS, " AIC7XXX_CMDS_PER_LUN : %d\n",
+ AIC7XXX_CMDS_PER_LUN);
#endif
#ifdef AIC7XXX_TAGGED_QUEUEING
size += sprintf(BLS, " AIC7XXX_TAGGED_QUEUEING: Enabled\n");
#else
size += sprintf(BLS, " AIC7XXX_PROC_STATS : Disabled\n");
#endif
- if (size > 512)
- printk(KERN_CRIT "aic7xxx: possible overflow at second position\n");
- len += size; pos = begin + len; size = 0;
- if (pos < offset)
- {
- begin = pos;
- len = 0;
- }
- else if (pos >= offset + length)
- goto stop_output;
-
size += sprintf(BLS, "\n");
size += sprintf(BLS, "Adapter Configuration:\n");
size += sprintf(BLS, " SCSI Adapter: %s\n",
- board_names[p->chip_type]);
+ board_names[p->chip_type]);
size += sprintf(BLS, " (%s chipset)\n",
- chip_names[p->chip_class]);
- size += sprintf(BLS, " Host Bus: %s\n", bus_names[p->bus_type]);
+ chip_names[p->chip_class]);
+ size += sprintf(BLS, " Host Bus: %s\n",
+ bus_names[p->bus_type]);
size += sprintf(BLS, " Base IO: %#.4x\n", p->base);
size += sprintf(BLS, " Base IO Memory: 0x%x\n", p->mbase);
size += sprintf(BLS, " IRQ: %d\n", HBAptr->irq);
size += sprintf(BLS, " SCBs: Used %d, HW %d, Page %d\n",
- p->scb_data->numscbs, p->scb_data->maxhscbs, p->scb_data->maxscbs);
+ p->scb_data->numscbs, p->scb_data->maxhscbs, p->scb_data->maxscbs);
size += sprintf(BLS, " Interrupts: %d", p->isr_count);
if (p->chip_class == AIC_777x)
{
(p->flags & ULTRA_ENABLED) ? "En" : "Dis");
size += sprintf(BLS, " Target Disconnect: %sabled\n",
p->discenable ? "En" : "Dis");
- if (size > 512)
- printk(KERN_CRIT "aic7xxx: possible overflow at third position\n");
- len += size; pos = begin + len; size = 0;
- if (pos < offset)
- {
- begin = pos;
- len = 0;
- }
- else if (pos >= offset + length)
- goto stop_output;
-
+
#ifdef AIC7XXX_PROC_STATS
+ size += sprintf(BLS, "\n");
+ size += sprintf(BLS, "Statistics:\n");
+ for (target = 0; target < 16; target++)
{
- struct aic7xxx_xferstats *sp;
- int channel, target, lun;
-
- /*
- * XXX: Need to fix this to avoid overflow...
- * Fixed - gordo.
- */
- size += sprintf(BLS, "\n");
- size += sprintf(BLS, "Statistics:\n");
- for (channel = 0; channel < 2; channel++)
+ for (lun = 0; lun < 8; lun++)
{
- for (target = 0; target < 16; target++)
+ sp = &p->stats[target][lun];
+ if (sp->xfers == 0)
{
- for (lun = 0; lun < 8; lun++)
- {
- sp = &p->stats[channel][target][lun];
- if (sp->xfers == 0)
- {
- continue;
- }
- size += sprintf(BLS, "CHAN#%c (TGT %d LUN %d):\n",
- 'A' + channel, target, lun);
- size += sprintf(BLS, "nxfers %ld (%ld read;%ld written)\n",
- sp->xfers, sp->r_total, sp->w_total);
- size += sprintf(BLS, "blks(512) rd=%ld; blks(512) wr=%ld\n",
- sp->r_total512, sp->w_total512);
- size += sprintf(BLS, "%s\n", HDRB);
- size += sprintf(BLS, " Reads:");
- size += sprintf(BLS, "%6ld %6ld %6ld %6ld ", sp->r_bins[0],
- sp->r_bins[1], sp->r_bins[2], sp->r_bins[3]);
- size += sprintf(BLS, "%6ld %6ld %6ld %6ld ", sp->r_bins[4],
- sp->r_bins[5], sp->r_bins[6], sp->r_bins[7]);
- size += sprintf(BLS, "%6ld %6ld\n", sp->r_bins[8],
- sp->r_bins[9]);
- size += sprintf(BLS, "Writes:");
- size += sprintf(BLS, "%6ld %6ld %6ld %6ld ", sp->w_bins[0],
- sp->w_bins[1], sp->w_bins[2], sp->w_bins[3]);
- size += sprintf(BLS, "%6ld %6ld %6ld %6ld ", sp->w_bins[4],
- sp->w_bins[5], sp->w_bins[6], sp->w_bins[7]);
- size += sprintf(BLS, "%6ld %6ld\n", sp->w_bins[8],
- sp->w_bins[9]);
- size += sprintf(BLS, "\n");
- }
- if (size > 512)
- printk(KERN_CRIT "aic7xxx: possible overflow at loop %d:%d\n", target, lun);
- len += size; pos = begin + len; size = 0;
- if (pos < offset)
- {
- begin = pos;
- len = 0;
- }
- else if (pos >= offset + length)
- goto stop_output;
+ continue;
}
+ if (p->bus_type == AIC_TWIN)
+ size += sprintf(BLS, "CHAN#%c (TGT %d LUN %d):\n",
+ 'A' + (target >> 3), (target & 0x7), lun);
+ else
+ size += sprintf(BLS, "CHAN#%c (TGT %d LUN %d):\n",
+ 'A', target, lun);
+ size += sprintf(BLS, "nxfers %ld (%ld read;%ld written)\n",
+ sp->xfers, sp->r_total, sp->w_total);
+ size += sprintf(BLS, "blks(512) rd=%ld; blks(512) wr=%ld\n",
+ sp->r_total512, sp->w_total512);
+ size += sprintf(BLS, "%s\n", HDRB);
+ size += sprintf(BLS, " Reads:");
+ for (i=0; i<10; i++)
+ size += sprintf(BLS, "%6ld ", sp->r_bins[i]);
+ size += sprintf(BLS, "\n");
+ size += sprintf(BLS, "Writes:");
+ for (i=0; i<10; i++)
+ size += sprintf(BLS, "%6ld ", sp->w_bins[i]);
+ size += sprintf(BLS, "\n\n");
}
}
#endif /* AIC7XXX_PROC_STATS */
-stop_output:
- proc_debug("2pos: %ld offset: %ld len: %d\n", pos, offset, len);
- *start = buffer + (offset - begin); /* Start of wanted data */
- len -= (offset - begin); /* Start slop */
- if (len < 0)
- {
- len = 0; /* off end of file */
- }
- else if (len > length)
- {
- len = length; /* Ending slop */
+ if ( size >= aic7xxx_buffer_size )
+ printk(KERN_WARNING "aic7xxx: Overflow in aic7xxx_proc.c\n");
+
+ if ( offset > size - 1) {
+ kfree ( aic7xxx_buffer);
+ aic7xxx_buffer = NULL;
+ aic7xxx_buffer_size = length = 0;
+ *start = NULL;
+ } else {
+ *start = &aic7xxx_buffer[offset]; /* Start of wanted data */
+ if ( size - offset < length) length = size - offset;
}
- proc_debug("3pos: %ld offset: %ld len: %d\n", pos, offset, len);
- return (len);
+ return length;
}
/*
#define CUR_SCBID 0x58
-#define CMDOUTCNT 0x59
+#define ARG_1 0x59
+#define RETURN_1 0x59
+#define SEND_MSG 0x80
+#define SEND_SENSE 0x40
+#define SEND_REJ 0x20
#define SCSICONF 0x5a
-#define RESET_SCSI 0x40
-#define FIFODEPTH 0x5a
+#define CMDOUTCNT 0x5a
-#define ARG_1 0x5b
-#define RETURN_1 0x5b
-#define SEND_MSG 0x80
-#define SEND_SENSE 0x40
-#define SEND_REJ 0x20
+#define FIFODEPTH 0x5b
+
+#define SCSICONF2 0x5b
+#define RESET_SCSI 0x40
#define HOSTCONF 0x5d
0x50, 0x6a, 0x60, 0x00,
0xff, 0x90, 0x4a, 0x02,
0x00, 0xa1, 0xa1, 0x17,
- 0xff, 0x6c, 0x5b, 0x02,
- 0xff, 0x5b, 0x27, 0x1c,
+ 0xff, 0x6c, 0x59, 0x02,
+ 0xff, 0x59, 0x27, 0x1c,
0xff, 0x4a, 0x90, 0x02,
0x00, 0x65, 0xaa, 0x17,
0x00, 0x6a, 0x52, 0x17,
0x00, 0x65, 0xbb, 0x17,
0x10, 0x6a, 0x60, 0x00,
0x00, 0x65, 0x03, 0x10,
- 0xff, 0x5b, 0x90, 0x02,
+ 0xff, 0x59, 0x90, 0x02,
0xff, 0x58, 0xb3, 0x02,
0x10, 0x6a, 0x60, 0x00,
0x00, 0x65, 0x03, 0x10,
0x00, 0xb9, 0x77, 0x17,
0xff, 0xa2, 0xda, 0x1e,
0x71, 0x6a, 0x91, 0x00,
- 0x40, 0x5b, 0xda, 0x18,
+ 0x40, 0x59, 0xda, 0x18,
0xff, 0xb9, 0xb3, 0x02,
0x00, 0x65, 0xe7, 0x10,
0x20, 0xa0, 0xe0, 0x1a,
0x00, 0xa1, 0xa1, 0x17,
0xff, 0x49, 0x6d, 0x02,
0xff, 0x4a, 0x90, 0x02,
- 0xff, 0x5a, 0x64, 0x02,
- 0x00, 0x59, 0xe1, 0x1c,
- 0x01, 0x59, 0x59, 0x06,
+ 0xff, 0x5b, 0x64, 0x02,
+ 0x00, 0x5a, 0xe1, 0x1c,
+ 0x01, 0x5a, 0x5a, 0x06,
0xff, 0xb9, 0x9d, 0x02,
0x02, 0x6a, 0x91, 0x00,
0x08, 0xa0, 0xe7, 0x1e,
0xff, 0x66, 0x66, 0x06,
0xff, 0x64, 0xf7, 0x1a,
0x41, 0x6a, 0x91, 0x00,
- 0x20, 0x5b, 0xcd, 0x1c,
- 0x80, 0x5b, 0xcf, 0x18,
+ 0x20, 0x59, 0xcd, 0x1c,
+ 0x80, 0x59, 0xcf, 0x18,
0x10, 0x4c, 0x03, 0x00,
0x00, 0x65, 0xcf, 0x10,
0x04, 0xa0, 0xa0, 0x00,
0x07, 0x64, 0x64, 0x02,
0x00, 0x42, 0x42, 0x00,
0x00, 0x42, 0xa1, 0x17,
- 0xff, 0x6c, 0x5b, 0x02,
- 0xff, 0x5b, 0x28, 0x19,
- 0xff, 0x5b, 0x18, 0x1d,
- 0xff, 0x5b, 0x90, 0x02,
+ 0xff, 0x6c, 0x59, 0x02,
+ 0xff, 0x59, 0x28, 0x19,
+ 0xff, 0x59, 0x18, 0x1d,
+ 0xff, 0x59, 0x90, 0x02,
0x04, 0xa0, 0x2d, 0x1f,
0x00, 0x65, 0x2a, 0x11,
0xff, 0x06, 0x6a, 0x02,
0xe0, 0x4c, 0x2d, 0x19,
0x20, 0x12, 0x2d, 0x19,
0x20, 0x41, 0x41, 0x00,
- 0x5b, 0x6a, 0x3a, 0x17,
+ 0x59, 0x6a, 0x3a, 0x17,
0xff, 0x3f, 0x64, 0x02,
- 0x00, 0x5b, 0x65, 0x06,
+ 0x00, 0x59, 0x65, 0x06,
0x00, 0x65, 0x2d, 0x13,
- 0xff, 0x5b, 0x90, 0x02,
+ 0xff, 0x59, 0x90, 0x02,
0xff, 0x42, 0x64, 0x02,
0x00, 0xa1, 0x2d, 0x19,
0x20, 0xa0, 0x2d, 0x1f,
0x40, 0x41, 0x4e, 0x1b,
0x21, 0x6a, 0x91, 0x01,
0xff, 0x65, 0x90, 0x02,
- 0xff, 0x5b, 0x64, 0x02,
+ 0xff, 0x59, 0x64, 0x02,
0x00, 0xb9, 0x56, 0x19,
0x04, 0xa0, 0x60, 0x1b,
0x01, 0x65, 0x65, 0x06,
0x00, 0x65, 0x52, 0x19,
0x00, 0x6a, 0xad, 0x17,
0x0d, 0x6a, 0x3d, 0x00,
- 0x00, 0x5b, 0x77, 0x17,
+ 0x00, 0x59, 0x77, 0x17,
0xff, 0xa8, 0x5e, 0x1f,
0x10, 0xa0, 0xa0, 0x00,
0x08, 0xa0, 0x4e, 0x1f,
/*
* eata.c - Low-level driver for EATA/DMA SCSI host adapters.
+ *
+ * 12 Sep 1997 rev. 3.11 for linux 2.0.30 and 2.1.55
+ * Use of udelay inside the wait loops to avoid timeout
+ * problems with fast cpus.
+ * Removed check about useless calls to the interrupt service
+ * routine (reported on SMP systems only).
+ * At initialization time "sorted/unsorted" is displayed instead
+ * of "linked/unlinked" to reinforce the fact that "linking" is
+ * nothing but "elevator sorting" in the actual implementation.
*
* 17 May 1997 rev. 3.10 for linux 2.0.30 and 2.1.38
* Use of serial_number_at_timeout in abort and reset processing.
#include <linux/sched.h>
#include <linux/kernel.h>
#include <linux/ioport.h>
+#include <linux/delay.h>
#include <asm/io.h>
#include <asm/system.h>
#include <asm/byteorder.h>
#undef DEBUG_INTERRUPT
#undef DEBUG_STATISTICS
#undef DEBUG_RESET
+#undef DEBUG_SMP
#define MAX_ISA 4
#define MAX_VESA 0
#define READY 5
#define ABORTING 6
#define NO_DMA 0xff
-#define MAXLOOP 200000
+#define MAXLOOP 10000
#define TAG_MIXED 0
#define TAG_SIMPLE 1
#define TAG_HEAD 2
if (TLDEV(dev->type)) {
if (linked_comm && dev->queue_depth > 2)
- link_suffix = ", linked";
+ link_suffix = ", sorted";
else
- link_suffix = ", unlinked";
+ link_suffix = ", unsorted";
}
if (tagged_comm && dev->tagged_supported && TLDEV(dev->type)) {
static inline int wait_on_busy(unsigned int iobase, unsigned int loop) {
- while (inb(iobase + REG_AUX_STATUS) & ABSY_ASSERTED)
+ while (inb(iobase + REG_AUX_STATUS) & ABSY_ASSERTED) {
+ udelay(1L);
if (--loop == 0) return TRUE;
+ }
return FALSE;
}
for (p = start; p <= end; p++) {
- while (!(inb(iobase + REG_STATUS) & DRQ_ASSERTED))
+ while (!(inb(iobase + REG_STATUS) & DRQ_ASSERTED)) {
+ udelay(1L);
if (--loop == 0) return TRUE;
+ }
loop = MAXLOOP;
*p = inw(iobase);
HD(j)->in_reset = TRUE;
sti();
time = jiffies;
- while ((jiffies - time) < HZ && limit++ < 100000000);
+ while ((jiffies - time) < (10 * HZ) && limit++ < 200000) udelay(100L);
cli();
printk("%s: reset, interrupts disabled, loops %d.\n", BN(j), limit);
calls[irq]++;
+#if defined (DEBUG_SMP)
if (total_loops == 0)
printk("%s: ihdlr, irq %d, no command completed, calls %d.\n",
driver_name, irq, calls[irq]);
+#endif
if (do_trace) printk("%s: ihdlr, exit, irq %d, calls %d.\n",
driver_name, irq, calls[irq]);
int eata2x_abort(Scsi_Cmnd *);
int eata2x_reset(Scsi_Cmnd *, unsigned int);
-#define EATA_VERSION "3.10.00"
+#define EATA_VERSION "3.11.00"
#define EATA { \
int init_module(void) {
driver_template.usage_count = &mod_use_count_;
scsi_register_module(MODULE_SCSI_HA, &driver_template);
- return (driver_template.present == 0);
+ if (driver_template.present)
+ return 0;
+
+ scsi_unregister_module(MODULE_SCSI_HA, &driver_template);
+ return -1;
}
void cleanup_module( void) {
/*
* u14-34f.c - Low-level driver for UltraStor 14F/34F SCSI host adapters.
*
+ * 12 Sep 1997 rev. 3.11 for linux 2.0.30 and 2.1.55
+ * Use of udelay inside the wait loops to avoid timeout
+ * problems with fast cpus.
+ * Removed check about useless calls to the interrupt service
+ * routine (reported on SMP systems only).
+ * At initialization time "sorted/unsorted" is displayed instead
+ * of "linked/unlinked" to reinforce the fact that "linking" is
+ * nothing but "elevator sorting" in the actual implementation.
+ *
* 17 May 1997 rev. 3.10 for linux 2.0.30 and 2.1.38
* Use of serial_number_at_timeout in abort and reset processing.
* Use of the __initfunc and __initdata macro in setup code.
#include <linux/sched.h>
#include <linux/kernel.h>
#include <linux/ioport.h>
+#include <linux/delay.h>
#include <asm/io.h>
#include <asm/system.h>
#include <asm/byteorder.h>
#undef DEBUG_INTERRUPT
#undef DEBUG_STATISTICS
#undef DEBUG_RESET
+#undef DEBUG_SMP
#define MAX_ISA 3
#define MAX_VESA 1
#define READY 5
#define ABORTING 6
#define NO_DMA 0xff
-#define MAXLOOP 200000
+#define MAXLOOP 10000
#define REG_LCL_MASK 0
#define REG_LCL_INTR 1
if (TLDEV(dev->type)) {
if (linked_comm && dev->queue_depth > 2)
- link_suffix = ", linked";
+ link_suffix = ", sorted";
else
- link_suffix = ", unlinked";
+ link_suffix = ", unsorted";
}
if (dev->tagged_supported && TLDEV(dev->type) && dev->tagged_queue)
static inline int wait_on_busy(unsigned int iobase, unsigned int loop) {
- while (inb(iobase + REG_LCL_INTR) & BSY_ASSERTED)
+ while (inb(iobase + REG_LCL_INTR) & BSY_ASSERTED) {
+ udelay(1L);
if (--loop == 0) return TRUE;
+ }
return FALSE;
}
sti();
time = jiffies;
- while ((jiffies - time) < HZ && limit++ < 100000000);
+ while ((jiffies - time) < HZ && limit++ < 20000) udelay(100L);
cli();
if (cpp->adapter_status || HD(j)->cp_stat[0] != FREE) {
HD(j)->in_reset = TRUE;
sti();
time = jiffies;
- while ((jiffies - time) < HZ && limit++ < 100000000);
+ while ((jiffies - time) < (10 * HZ) && limit++ < 200000) udelay(100L);
cli();
printk("%s: reset, interrupts disabled, loops %d.\n", BN(j), limit);
calls[irq]++;
+#if defined (DEBUG_SMP)
if (total_loops == 0)
printk("%s: ihdlr, irq %d, no command completed, calls %d.\n",
driver_name, irq, calls[irq]);
+#endif
if (do_trace) printk("%s: ihdlr, exit, irq %d, calls %d.\n",
driver_name, irq, calls[irq]);
int u14_34f_reset(Scsi_Cmnd *, unsigned int);
int u14_34f_biosparam(Disk *, kdev_t, int *);
-#define U14_34F_VERSION "3.10.00"
+#define U14_34F_VERSION "3.11.00"
#define ULTRASTOR_14_34F { \
NULL, /* Ptr for modules */ \
static struct buffer_head *find_candidate(struct buffer_head *bh,
int *list_len, int size)
{
- int behind = 0;
+ int lookahead = 7;
if (!bh)
goto no_candidate;
try_to_free_buffer(bh,&bh,1);
if (!bh)
break;
+ lookahead = 7;
continue;
}
else if (buffer_locked(bh) &&
(bh->b_list == BUF_LOCKED || bh->b_list == BUF_LOCKED1)) {
- if (behind++ > 10) {
+ if (!--lookahead) {
(*list_len) = 0;
goto no_candidate;
}
{
struct buffer_head * bh;
struct buffer_head * candidate[BUF_DIRTY];
+ extern struct task_struct *bdflush_tsk;
unsigned int best_time, winner;
int buffers[BUF_DIRTY];
- int i;
+ int i, limit = ((min_free_pages + free_pages_low) >> 1);
int needed;
refilled = 1;
for user processes to use (and dirty) */
/* We are going to try to locate this much memory */
- needed =bdf_prm.b_un.nrefill * size;
+ needed = bdf_prm.b_un.nrefill * size;
while (nr_free_pages > min_free_pages*2 && needed > 0 &&
grow_buffers(GFP_BUFFER, size)) {
/* Dirty buffers should not overtake, wakeup_bdflush(1) calls
bdflush and sleeps, therefore kswapd does his important work. */
- if ((nr_buffers_type[BUF_DIRTY] > nr_buffers * bdf_prm.b_un.nfract/100) ||
- (nr_free_pages < min_free_pages))
+ if (nr_buffers_type[BUF_DIRTY] > nr_buffers * bdf_prm.b_un.nfract/100)
wakeup_bdflush(1);
/* Too bad, that was not enough. Try a little harder to grow some. */
- if (nr_free_pages > min_free_pages + 5) {
+ if (nr_free_pages > limit) {
if (grow_buffers(GFP_BUFFER, size)) {
needed -= PAGE_SIZE;
goto repeat;
};
}
+ /* If we are not bdflush we should wake up bdflush and try it again. */
+
+ if (current != bdflush_tsk) {
+ wakeup_bdflush(1);
+ needed -= PAGE_SIZE;
+ goto repeat;
+ }
+
+ /* We are bdflush: let's try our best */
+
+ /*
+ * In order to protect our reserved pages,
+ * return now if we got any buffers.
+ */
+ allow_interrupts();
+ if (free_list[BUFSIZE_INDEX(size)])
+ return;
+
/* and repeat until we find something good */
- wakeup_bdflush(1);
+ grow_buffers(GFP_BUFFER, size);
/* decrease needed even if there is no success */
needed -= PAGE_SIZE;
* This is critical. We can't swap out pages to get
* more buffer heads, because the swap-out may need
* more buffer-heads itself. Thus GFP_ATOMIC.
+ *
+ * This is no longer true, it is GFP_BUFFER again, the
+ * swapping code now knows not to perform I/O when that
+ * GFP level is specified... -DaveM
*/
/* we now use kmalloc() here instead of gfp as we want
to be able to easily release buffer heads - they
took up quite a bit of memory (tridge) */
- bh = (struct buffer_head *) kmalloc(sizeof(*bh),GFP_ATOMIC);
+ bh = (struct buffer_head *) kmalloc(sizeof(*bh),GFP_BUFFER);
if (bh) {
put_unused_buffer_head(bh);
nr_buffer_heads++;
asmlinkage long sys_fcntl(unsigned int fd, unsigned int cmd, unsigned long arg)
{
struct file * filp;
- struct task_struct *p;
- int task_found = 0;
if (fd >= NR_OPEN || !(filp = current->files->fd[fd]))
return -EBADF;
* current syscall conventions, the only way
* to fix this will be in libc.
*/
- return filp->f_owner;
+ return filp->f_owner.pid;
case F_SETOWN:
- /*
- * Add the security checks - AC. Without
- * this there is a massive Linux security
- * hole here - consider what happens if
- * you do something like
- *
- * fcntl(0,F_SETOWN,some_root_process);
- * getchar();
- *
- * and input a line!
- *
- * BTW: Don't try this for fun. Several Unix
- * systems I tried this on fall for the
- * trick!
- *
- * I had to fix this botch job as Linux
- * kill_fasync asserts priv making it a
- * free all user process killer!
- *
- * Changed to make the security checks more
- * liberal. -- TYT
- */
- if (current->pgrp == -arg || current->pid == arg)
- goto fasync_ok;
-
- for_each_task(p) {
- if ((p->pid == arg) || (p->pid == -arg) ||
- (p->pgrp == -arg)) {
- task_found++;
- if ((p->session != current->session) &&
- (p->uid != current->uid) &&
- (p->euid != current->euid) &&
- !suser())
- return -EPERM;
- break;
- }
- }
- if ((task_found == 0) && !suser())
- return -EINVAL;
- fasync_ok:
- filp->f_owner = arg;
+ filp->f_owner.pid = arg;
+ filp->f_owner.uid = current->uid;
+ filp->f_owner.euid = current->euid;
if (S_ISSOCK (filp->f_inode->i_mode))
sock_fcntl (filp, F_SETOWN, arg);
return 0;
}
}
+static void send_sigio(int sig, int pid, uid_t uid, uid_t euid)
+{
+ struct task_struct * p;
+
+ for_each_task(p) {
+ int match = p->pid;
+ if (pid < 0)
+ match = -p->pgrp;
+ if (pid != match)
+ continue;
+ if (!euid &&
+ (euid ^ p->suid) && (euid ^ p->uid) &&
+ (uid ^ p->suid) && (uid ^ p->uid))
+ continue;
+ p->signal |= 1 << (sig-1);
+ if (p->state == TASK_INTERRUPTIBLE && (p->signal & ~p->blocked))
+ wake_up_process(p);
+ }
+}
+
void kill_fasync(struct fasync_struct *fa, int sig)
{
while (fa) {
+ struct fown_struct * fown;
if (fa->magic != FASYNC_MAGIC) {
printk("kill_fasync: bad magic number in "
"fasync_struct!\n");
return;
}
- if (fa->fa_file->f_owner > 0)
- kill_proc(fa->fa_file->f_owner, sig, 1);
- else
- kill_pg(-fa->fa_file->f_owner, sig, 1);
+ fown = &fa->fa_file->f_owner;
+ if (fown->pid)
+ send_sigio(sig, fown->pid, fown->uid, fown->euid);
fa = fa->fa_next;
}
}
kdev_t dev = sb->s_dev;
int error;
+ MOD_INC_USE_COUNT;
+
if (smb_get_mount_data(&data, raw_data) != 0)
{
printk("smb_read_super: wrong data argument\n");
sb->s_dev = 0;
+ MOD_DEC_USE_COUNT;
return NULL;
}
fd = data.fd;
{
printk("smb_read_super: invalid file descriptor\n");
sb->s_dev = 0;
+ MOD_DEC_USE_COUNT;
return NULL;
}
if (!S_ISSOCK(filp->f_inode->i_mode))
{
printk("smb_read_super: not a socket!\n");
sb->s_dev = 0;
+ MOD_DEC_USE_COUNT;
return NULL;
}
/* We must malloc our own super-block info */
if (smb_sb == NULL)
{
printk("smb_read_super: could not alloc smb_sb_info\n");
+ sb->s_dev = 0;
+ MOD_DEC_USE_COUNT;
return NULL;
}
filp->f_count += 1;
printk("smb_read_super: get root inode failed\n");
goto fail;
}
- MOD_INC_USE_COUNT;
return sb;
fail:
filp->f_count -= 1;
smb_dont_catch_keepalive(server);
smb_kfree_s(SMB_SBP(sb), sizeof(struct smb_sb_info));
+ MOD_DEC_USE_COUNT;
return NULL;
}
(attr->ia_gid != SMB_SERVER(inode)->m.gid)))
return -EPERM;
- if (((attr->ia_valid & ATTR_MODE) &&
- (attr->ia_mode & ~(S_IFREG | S_IFDIR | S_IRWXU | S_IRWXG | S_IRWXO))))
- return -EPERM;
+ if (attr->ia_valid & ATTR_MODE) {
+ struct smb_dirent *fold = SMB_FINFO(inode);
+ struct smb_dirent finfo;
+
+ if (attr->ia_mode & ~(S_IFREG | S_IFDIR |
+ S_IRWXU | S_IRWXG | S_IRWXO))
+ return -EPERM;
+
+ memset((char *)&finfo, 0, sizeof(finfo));
+ finfo.attr = fold->attr;
+
+ if((attr->ia_mode & 0200) == 0)
+ finfo.attr |= aRONLY;
+ else
+ finfo.attr &= ~aRONLY;
+
+ if ((error = smb_proc_setattr(SMB_SERVER(inode),
+ inode, &finfo)) >= 0)
+ {
+ fold->attr = finfo.attr;
+ if ((attr->ia_mode & 0200) == 0)
+ inode->i_mode &= ~0222;
+ else
+ inode->i_mode |= 0222;
+ }
+ }
if ((attr->ia_valid & ATTR_SIZE) != 0)
{
goto fail;
}
- if ((attr->ia_valid & (ATTR_CTIME | ATTR_MTIME | ATTR_ATIME)) != 0)
- {
-
- struct smb_dirent finfo;
- finfo.attr = 0;
- finfo.f_size = inode->i_size;
- finfo.f_blksize = inode->i_blksize;
-
- if ((attr->ia_valid & ATTR_CTIME) != 0)
- finfo.f_ctime = attr->ia_ctime;
- else
- finfo.f_ctime = inode->i_ctime;
-
- if ((attr->ia_valid & ATTR_MTIME) != 0)
- finfo.f_mtime = attr->ia_mtime;
- else
- finfo.f_mtime = inode->i_mtime;
+ /* ATTR_CTIME and ATTR_ATIME can not be set via SMB, so ignore it. */
- if ((attr->ia_valid & ATTR_ATIME) != 0)
- finfo.f_atime = attr->ia_atime;
+ if (attr->ia_valid & ATTR_MTIME)
+ {
+ if (smb_make_open(inode, O_WRONLY) != 0)
+ error = -EACCES;
else
- finfo.f_atime = inode->i_atime;
-
- if ((error = smb_proc_setattr(SMB_SERVER(inode),
- inode, &finfo)) >= 0)
- {
- inode->i_ctime = finfo.f_ctime;
- inode->i_mtime = finfo.f_mtime;
- inode->i_atime = finfo.f_atime;
- }
+ inode->i_mtime = attr->ia_mtime;
}
fail:
smb_invalid_dir_cache(smb_info_ino(SMB_INOP(inode)->dir));
-
return error;
}
return local2utc(secs);
}
-
-/* Convert linear UNIX date to a MS-DOS time/date pair. */
-
-static void
-date_unix2dos(int unix_date, byte * date, byte * time)
-{
- int day, year, nl_day, month;
-
- unix_date = utc2local(unix_date);
- WSET(time, 0,
- (unix_date % 60) / 2 + (((unix_date / 60) % 60) << 5) +
- (((unix_date / 3600) % 24) << 11));
- day = unix_date / 86400 - 3652;
- year = day / 365;
- if ((year + 3) / 4 + 365 * year > day)
- year--;
- day -= (year + 3) / 4 + 365 * year;
- if (day == 59 && !(year & 3))
- {
- nl_day = day;
- month = 2;
- } else
- {
- nl_day = (year & 3) || day <= 59 ? day : day - 1;
- for (month = 0; month < 12; month++)
- if (day_n[month] > nl_day)
- break;
- }
- WSET(date, 0,
- nl_day - day_n[month - 1] + 1 + (month << 5) + (year << 9));
-}
-
-
-
/*****************************************************************************/
/* */
/* Support section. */
entry->f_mode = server->m.file_mode;
}
+ if (entry->attr & aRONLY)
+ entry->f_mode &= ~0222;
+
if ((entry->f_blksize != 0) && (entry->f_size != 0))
{
entry->f_blocks =
return 0;
}
-static int
-smb_proc_getattr_trans2(struct inode *dir, const char *name, int len,
- struct smb_dirent *entry)
-{
- struct smb_server *server = SMB_SERVER(dir);
- char param[SMB_MAXPATHLEN + 20];
- char *p;
- int result;
-
- unsigned char *resp_data = NULL;
- unsigned char *resp_param = NULL;
- int resp_data_len = 0;
- int resp_param_len = 0;
-
- WSET(param, 0, 1); /* Info level SMB_INFO_STANDARD */
- DSET(param, 2, 0);
- p = smb_encode_path(server, param + 6, SMB_INOP(dir), name, len);
-
- smb_lock_server(server);
- retry:
- result = smb_trans2_request(server, TRANSACT2_QPATHINFO,
- 0, NULL, p - param, param,
- &resp_data_len, &resp_data,
- &resp_param_len, &resp_param);
-
- if (server->rcls != 0)
- {
- smb_unlock_server(server);
- return -smb_errno(server->rcls, server->err);
- }
- if (result < 0)
- {
- if (smb_retry(server))
- {
- goto retry;
- }
- smb_unlock_server(server);
- return result;
- }
- if (resp_data_len < 22)
- {
- smb_unlock_server(server);
- return -ENOENT;
- }
- entry->f_ctime = date_dos2unix(WVAL(resp_data, 2),
- WVAL(resp_data, 0));
- entry->f_atime = date_dos2unix(WVAL(resp_data, 6),
- WVAL(resp_data, 4));
- entry->f_mtime = date_dos2unix(WVAL(resp_data, 10),
- WVAL(resp_data, 8));
- entry->f_size = DVAL(resp_data, 12);
- entry->attr = WVAL(resp_data, 20);
- smb_unlock_server(server);
-
- return 0;
-}
-
int
smb_proc_getattr(struct inode *dir, const char *name, int len,
struct smb_dirent *entry)
{
struct smb_server *server = SMB_SERVER(dir);
- int result = 0;
+ int result;
smb_init_dirent(server, entry);
-
- if (server->protocol >= PROTOCOL_LANMAN2)
- {
- result = smb_proc_getattr_trans2(dir, name, len, entry);
- }
- if ((server->protocol < PROTOCOL_LANMAN2) || (result < 0))
- {
- result = smb_proc_getattr_core(dir, name, len, entry);
- }
+ result = smb_proc_getattr_core(dir, name, len, entry);
smb_finish_dirent(server, entry);
entry->len = len;
return result;
}
-
-/* In core protocol, there is only 1 time to be set, we use
- entry->f_mtime, to make touch work. */
-static int
-smb_proc_setattr_core(struct smb_server *server,
- struct inode *i, struct smb_dirent *new_finfo)
+int
+smb_proc_setattr(struct smb_server *server,
+ struct inode *i, struct smb_dirent *new_finfo)
{
char *p;
char *buf;
buf = server->packet;
p = smb_setup_header(server, SMBsetatr, 8, 0);
WSET(buf, smb_vwv0, new_finfo->attr);
- DSET(buf, smb_vwv1, utc2local(new_finfo->f_mtime));
+ DSET(buf, smb_vwv1, 0);
+ DSET(buf, smb_vwv3, 0);
+ DSET(buf, smb_vwv5, 0);
+ WSET(buf, smb_vwv7, 0);
*p++ = 4;
p = smb_encode_path(server, p,
SMB_INOP(i)->dir, SMB_INOP(i)->finfo.name,
SMB_INOP(i)->finfo.len);
- p = smb_encode_ascii(p, "", 0);
smb_setup_bcc(server, p);
if ((result = smb_request_ok(server, SMBsetatr, 0, 0)) < 0)
return result;
}
-static int
-smb_proc_setattr_trans2(struct smb_server *server,
- struct inode *i, struct smb_dirent *new_finfo)
-{
- char param[SMB_MAXPATHLEN + 20];
- char data[26];
- char *p;
- int result;
-
- unsigned char *resp_data = NULL;
- unsigned char *resp_param = NULL;
- int resp_data_len = 0;
- int resp_param_len = 0;
-
- WSET(param, 0, 1); /* Info level SMB_INFO_STANDARD */
- DSET(param, 2, 0);
- p = smb_encode_path(server, param + 6,
- SMB_INOP(i)->dir, SMB_INOP(i)->finfo.name,
- SMB_INOP(i)->finfo.len);
-
- date_unix2dos(new_finfo->f_ctime, &(data[0]), &(data[2]));
- date_unix2dos(new_finfo->f_atime, &(data[4]), &(data[6]));
- date_unix2dos(new_finfo->f_mtime, &(data[8]), &(data[10]));
- DSET(data, 12, new_finfo->f_size);
- DSET(data, 16, new_finfo->f_blksize);
- WSET(data, 20, new_finfo->attr);
- WSET(data, 22, 0);
-
- smb_lock_server(server);
- retry:
- result = smb_trans2_request(server, TRANSACT2_SETPATHINFO,
- 26, data, p - param, param,
- &resp_data_len, &resp_data,
- &resp_param_len, &resp_param);
-
- if (server->rcls != 0)
- {
- smb_unlock_server(server);
- return -smb_errno(server->rcls, server->err);
- }
- if (result < 0)
- {
- if (smb_retry(server))
- {
- goto retry;
- }
- }
- smb_unlock_server(server);
- return 0;
-}
-
-int
-smb_proc_setattr(struct smb_server *server, struct inode *inode,
- struct smb_dirent *new_finfo)
-{
- int result;
-
- if (server->protocol >= PROTOCOL_LANMAN2)
- {
- result = smb_proc_setattr_trans2(server, inode, new_finfo);
- }
- if ((server->protocol < PROTOCOL_LANMAN2) || (result < 0))
- {
- result = smb_proc_setattr_core(server, inode, new_finfo);
- }
- return result;
-}
-
int
smb_proc_dskattr(struct super_block *super, struct smb_dskattr *attr)
{
result = -EIO;
goto fail;
}
- DDPRINTK("target: %X\n", *data + WVAL(inbuf, smb_drdisp));
+ DDPRINTK("target: %X\n",
+ (unsigned int) *data + WVAL(inbuf, smb_drdisp));
DDPRINTK("source: %X\n",
+ (unsigned int)
smb_base(inbuf) + WVAL(inbuf, smb_droff));
DDPRINTK("disp: %d, off: %d, cnt: %d\n",
WVAL(inbuf, smb_drdisp), WVAL(inbuf, smb_droff),
}
len = smb_len(buffer) + 4;
- DDPRINTK("smb_request: len = %d cmd = 0x%X\n", len, buffer[8]);
+ DPRINTK("smb_request: len = %d cmd = 0x%X\n", len, buffer[8]);
old_mask = current->blocked;
current->blocked |= ~(_S(SIGKILL) | _S(SIGSTOP));
unsigned short fs;
int result;
- DDPRINTK("smb_trans2_request: com=%d, ld=%d, lp=%d\n",
- trans2_command, ldata, lparam);
+ DPRINTK("smb_trans2_request: com=%d, ld=%d, lp=%d\n",
+ trans2_command, ldata, lparam);
if (server->state != CONN_VALID)
{
*
* Delay routines, using a pre-computed "loops_per_second" value.
*/
-
+
+#include <linux/linkage.h>
+
#ifdef __SMP__
#include <asm/smp.h>
#endif
+extern void __do_delay(void); /* Special register call calling convention */
+
extern __inline__ void __delay(int loops)
{
__asm__ __volatile__(
- ".align 2,0x90\n1:\tdecl %0\n\tjns 1b"
+ "call " SYMBOL_NAME_STR(__do_delay)
:/* no outputs */
:"a" (loops)
:"ax");
/*
* Flags that can be altered by MS_REMOUNT
*/
-#define MS_RMT_MASK (MS_RDONLY|MS_MANDLOCK|MS_NOATIME)
+#define MS_RMT_MASK (MS_RDONLY|MS_NOSUID|MS_NODEV|MS_NOEXEC|MS_SYNCHRONOUS|MS_MANDLOCK|MS_NOATIME)
/*
* Magic mount flag number. Has to be or-ed to the flag values.
} u;
};
+struct fown_struct {
+ int pid; /* pid or -pgrp where SIGIO should be sent */
+ uid_t uid, euid; /* uid/euid of process setting the owner */
+};
+
struct file {
mode_t f_mode;
loff_t f_pos;
unsigned short f_count;
unsigned long f_reada, f_ramax, f_raend, f_ralen, f_rawin;
struct file *f_next, *f_prev;
- int f_owner; /* pid or -pgrp where SIGIO should be sent */
+ struct fown_struct f_owner;
struct inode * f_inode;
struct file_operations * f_op;
unsigned long f_version;
struct sk_buff_head mfc_unresolved; /* Unresolved buffers */
int mfc_queuelen; /* Unresolved buffer counter */
unsigned char mfc_ttls[MAXVIFS]; /* TTL thresholds */
+ unsigned long mfc_packets; /* Packets on this entry */
+ unsigned long mfc_bytes; /* Bytes on this entry */
};
#define MFC_QUEUED 1
_INLINE_ void tty_insert_flip_char(struct tty_struct *tty,
unsigned char ch, char flag)
{
- if (tty->flip.count++ >= TTY_FLIPBUF_SIZE)
- return;
- *tty->flip.flag_buf_ptr++ = flag;
- *tty->flip.char_buf_ptr++ = ch;
+ if (tty->flip.count < TTY_FLIPBUF_SIZE) {
+ tty->flip.count++;
+ *tty->flip.flag_buf_ptr++ = flag;
+ *tty->flip.char_buf_ptr++ = ch;
+ }
}
_INLINE_ void tty_schedule_flip(struct tty_struct *tty)
* IP_ALIAS (AF_INET) aliasing definitions.
*
*
- * Version: @(#)ip_alias.h 0.43 12/20/95
+ * Version: @(#)ip_alias.h 0.50 4/20/97
*
* Author: Juan Jose Ciarlante, <jjciarla@raiz.uncu.edu.ar>
*
extern void ip_rt_update(int event, struct device *dev);
extern void ip_rt_redirect(__u32 src, __u32 dst, __u32 gw, struct device *dev);
extern struct rtable *ip_rt_slow_route(__u32 daddr, int local, struct device *dev);
+extern struct device *ip_rt_dev(__u32 addr);
extern int rt_get_info(char * buffer, char **start, off_t offset, int length, int dummy);
extern int rt_cache_get_info(char *buffer, char **start, off_t offset, int length, int dummy);
extern int ip_rt_ioctl(unsigned int cmd, void *arg);
if (smp_processor_id() == boot_cpu_id) return;
if (smp_blocked_interrupt_pending)
{
- long timeout_counter = loops_per_sec;
unsigned long saved_kernel_counter;
+ long timeout_counter;
saved_active_kernel_processor = active_kernel_processor;
saved_kernel_counter = kernel_counter;
kernel_counter = 0;
active_kernel_processor = boot_cpu_id;
+ timeout_counter = 6000000;
while (active_kernel_processor != saved_active_kernel_processor &&
--timeout_counter >= 0)
- barrier();
+ {
+ udelay(10);
+ barrier();
+ }
if (timeout_counter < 0)
panic("FORWARDED INTERRUPT TIMEOUT (AKP = %d, Saved AKP = %d)\n",
active_kernel_processor, saved_active_kernel_processor);
return;
not_on_freelist:
- printk("Ooops. page %p doesn't show on freelist.\n", page);
restore_flags(flags);
+ printk("Ooops. page %p doesn't show on freelist.\n", page);
}
can_do_io = 1;
if (wait)
stop = 0;
- if (priority == GFP_BUFFER) {
- /* bdflush() should do the rest if we fail */
- stop = 3;
+ if (priority == GFP_BUFFER)
can_do_io = 0;
- }
switch (state) {
do {
case 0:
interruptible_sleep_on(&kswapd_wait);
kswapd_awake = 1;
swapstats.wakeups++;
+ /* Protect our reserved pages: */
+ i = 0;
+ if (nr_free_pages <= min_free_pages)
+ i = (1+min_free_pages) - nr_free_pages;
/* Do the background pageout: */
- for (i=0; i < kswapd_ctl.maxpages; i++)
+ for (i += kswapd_ctl.maxpages; i > 0; i--)
try_to_free_page(GFP_KERNEL, 0,
- (nr_free_pages < min_free_pages));
+ (nr_free_pages <= min_free_pages));
}
}
{
/*
* net_alias_dev_rx32 returns main dev if it fails to found other.
+ * if successful, also incr. alias rx count.
*/
dev = net_alias_dev_rx32(dev, AF_INET, sip, tip);
* valid (RFC 1812).
* Alan Cox : Spoofing and junk icmp protections.
* Elliot Poger : Added support for SO_BINDTODEVICE.
+ * Willy Konynenberg : Transparent proxy adapted to new
+ * socket hash code.
*
*
* RFC1122 (Host Requirements -- Comm. Layer) Status:
* in udp.c or tcp.c...
*/
-/* This should work with the new hashes now. -DaveM */
-extern struct sock *tcp_v4_proxy_lookup(unsigned short num, unsigned long raddr,
- unsigned short rnum, unsigned long laddr,
- unsigned long paddr, unsigned short pnum,
- struct device *dev);
-extern struct sock *udp_v4_proxy_lookup(unsigned short num, unsigned long raddr,
- unsigned short rnum, unsigned long laddr,
- unsigned long paddr, unsigned short pnum,
- struct device *dev);
+extern struct sock *tcp_v4_lookup(u32 saddr, u16 sport, u32 daddr, u16 dport, struct device *dev);
+extern struct sock *udp_v4_lookup(u32 saddr, u16 sport, u32 daddr, u16 dport, struct device *dev);
int icmp_chkaddr(struct sk_buff *skb)
{
{
struct tcphdr *th = (struct tcphdr *)(((unsigned char *)iph)+(iph->ihl<<2));
- sk = tcp_v4_proxy_lookup(th->source, iph->daddr, th->dest,
- iph->saddr, 0, 0, skb->dev);
+ sk = tcp_v4_lookup(iph->saddr, th->source, iph->daddr, th->dest, skb->dev);
if (!sk) return 0;
if (sk->saddr != iph->saddr) return 0;
if (sk->daddr != iph->daddr) return 0;
{
struct udphdr *uh = (struct udphdr *)(((unsigned char *)iph)+(iph->ihl<<2));
- sk = udp_v4_proxy_lookup(uh->source, iph->daddr, uh->dest,
- iph->saddr, 0, 0, skb->dev);
+ sk = udp_v4_lookup(iph->saddr, uh->source, iph->daddr, uh->dest, skb->dev);
if (!sk) return 0;
if (sk->saddr != iph->saddr && ip_chk_addr(iph->saddr) != IS_MYADDR)
return 0;
* IP_ALIAS (AF_INET) aliasing module.
*
*
- * Version: @(#)ip_alias.c 0.43 12/20/95
+ * Version: @(#)ip_alias.c 0.50 6/14/97
*
* Author: Juan Jose Ciarlante, <jjciarla@raiz.uncu.edu.ar>
*
* Fixes:
* JJC : ip_alias_dev_select method.
+ * JJC : use ip_rt_dev instead of ip_rt_route
+ * JJC : new no_sel semantics
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
(p[0] & 255), (p[1] & 255), (p[2] & 255), (p[3] & 255));
}
+/*
+ * Called by net_alias module when no local alias address has been hit,
+ * to find out if an alias is a better candidate for handling given addr
+ */
struct device *ip_alias_dev_select(struct net_alias_type *this, struct device *main_dev, struct sockaddr *sa)
{
__u32 addr;
- struct rtable *rt;
- struct device *dev=NULL;
/*
* Defensive...
* net_alias module will check if returned device is main_dev's alias
*/
- rt = ip_rt_route(addr, 0, NULL);
- if(rt)
- {
- dev=rt->rt_dev;
- ip_rt_put(rt);
- }
- return dev;
+ /*
+ * Fixed arping caused by incorrectly using ip_rt_route(),
+ * ip_rt_dev() just returns routing device without hh generation.
+ */
+
+ return ip_rt_dev(addr);
}
/*
#ifdef MODULE
+/*
+ * If no_sel is set, alias association (device selection) with
+ * foreign addresses will be disabled.
+ * You will get:
+ * - faster operation by avoiding completely routing lookups
+ * You will loose:
+ * - inter-alias routing
+ * - proxyarp over aliases
+ */
+
+int no_sel = 0;
+
int init_module(void)
{
+ if (no_sel)
+ ip_alias_type.dev_select = NULL;
+
if (ip_alias_init() != 0)
return -EIO;
return 0;
* Try to select closest <src,dst> alias device, if any.
* net_alias_dev_rx32 returns main device if it
* fails to found other.
+ * If successful, also incr. alias rx count.
+ *
+ * Only makes sense for unicasts - Thanks ANK.
*/
#ifdef CONFIG_NET_ALIAS
- if (iph->daddr != skb->dev->pa_addr && net_alias_has(skb->dev)) {
+ if (skb->pkt_type == PACKET_HOST && iph->daddr != skb->dev->pa_addr && net_alias_has(skb->dev)) {
skb->dev = dev = net_alias_dev_rx32(skb->dev, AF_INET, iph->saddr, iph->daddr);
}
#endif
}
#endif
#ifdef CONFIG_IP_ACCT
- if(!offset)
- ip_fw_chk(iph, dev, NULL, ip_acct_chain, 0, IP_FW_MODE_ACCT_OUT);
+ ip_fw_chk(iph, dev, NULL, ip_acct_chain, 0, IP_FW_MODE_ACCT_OUT);
#endif
offset -= (maxfraglen-fragheaderlen);
fraglen = maxfraglen;
init_timer(&c->mfc_timer);
c->mfc_timer.data=(long)c;
c->mfc_timer.function=ipmr_cache_timer;
+ c->mfc_packets=0;
+ c->mfc_bytes=0;
return c;
}
struct sioc_sg_req sr;
struct sioc_vif_req vr;
struct vif_device *vif;
+ struct mfc_cache *cl;
switch(cmd)
{
if(err)
return err;
memcpy_fromfs(&sr,(void *)arg,sizeof(sr));
+ cl=ipmr_cache_find(sr.src.s_addr,sr.grp.s_addr);
+ if(cl==NULL)
+ {
+ sr.pktcnt=0;
+ sr.bytecnt=0;
+ sr.wrong_if=0;
+ }
+ else
+ {
+ sr.pktcnt=cl->mfc_packets;
+ sr.bytecnt=cl->mfc_bytes;
+ sr.wrong_if=0;
+ }
memcpy_tofs((void *)arg,&sr,sizeof(sr));
return 0;
default:
vif_table[vif].pkt_in++;
vif_table[vif].bytes_in+=skb->len;
+ cache->mfc_packets++;
+ cache->mfc_bytes+=skb->len;
/*
* Forward the frame
if(psend==-1)
kfree_skb(skb, FREE_WRITE);
else
- {
ipmr_queue_xmit(skb, &vif_table[psend], skb->dev, is_frag);
- }
}
/*
void ip_mr_init(void)
{
- printk(KERN_INFO "Linux IP multicast router 0.06.\n");
+ printk(KERN_INFO "Linux IP multicast router 0.07.\n");
register_netdevice_notifier(&ip_mr_notifier);
#ifdef CONFIG_PROC_FS
proc_net_register(&(struct proc_dir_entry) {
* Andi Kleen : Don't send multicast addresses to
* kerneld.
*
+ * Juan Jose Ciarlante : Added ip_rt_dev
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version
rt_free(rt);
}
+/*
+ * Return routing dev for given address.
+ * Called by ip_alias module to avoid using ip_rt_route and
+ * generating hhs.
+ */
+struct device * ip_rt_dev(__u32 addr)
+{
+ struct fib_node *f;
+ f = fib_lookup(addr, NULL);
+ if (f)
+ return f->fib_info->fib_dev;
+ return NULL;
+}
+
struct rtable * ip_rt_route(__u32 daddr, int local, struct device *dev)
{
struct rtable * rth;
* David S. Miller : New socket lookup architecture for ISS.
* This code is dedicated to John Dyson.
* Elliot Poger : Added support for SO_BINDTODEVICE.
+ * Willy Konynenberg : Transparent proxy adapted to new
+ * socket hash code.
*/
#include <linux/config.h>
}
#ifdef CONFIG_IP_TRANSPARENT_PROXY
-#define secondlist(hpnum, sk, fpass) \
-({ struct sock *s1; if((hpnum) && !(sk) && (fpass)--) \
- s1 = tcp_bound_hash[tcp_bhashfn(hpnum)]; \
- else \
- s1 = (sk); \
- s1; \
-})
-
-#define tcp_v4_proxy_loop_init(hnum, hpnum, sk, fpass) \
- secondlist((hpnum), tcp_bound_hash[tcp_bhashfn(hnum)],(fpass))
-
-#define tcp_v4_proxy_loop_next(hnum, hpnum, sk, fpass) \
- secondlist((hpnum),(sk)->bind_next,(fpass))
-
-struct sock *tcp_v4_proxy_lookup(unsigned short num, unsigned long raddr,
- unsigned short rnum, unsigned long laddr,
- unsigned long paddr, unsigned short pnum,
+/* I am not entirely sure this is fully equivalent to the old lookup code, but it does
+ * look reasonable. WFK
+ */
+struct sock *tcp_v4_proxy_lookup(u32 saddr, u16 sport, u32 daddr, u16 dport, u32 paddr, u16 rport,
struct device *dev)
{
- struct sock *s, *result = NULL;
- int badness = -1;
- unsigned short hnum = ntohs(num);
- unsigned short hpnum = ntohs(pnum);
- int firstpass = 1;
-
- /* This code must run only from NET_BH. */
- for(s = tcp_v4_proxy_loop_init(hnum, hpnum, s, firstpass);
- s != NULL;
- s = tcp_v4_proxy_loop_next(hnum, hpnum, s, firstpass)) {
- if(s->num == hnum || s->num == hpnum) {
- int score = 0;
- if(s->dead && (s->state == TCP_CLOSE))
- continue;
- if(s->rcv_saddr) {
- if((s->num != hpnum || s->rcv_saddr != paddr) &&
- (s->num != hnum || s->rcv_saddr != laddr))
- continue;
- score++;
- }
- if(s->daddr) {
- if(s->daddr != raddr)
- continue;
- score++;
- }
- if(s->dummy_th.dest) {
- if(s->dummy_th.dest != rnum)
- continue;
- score++;
- }
- if(s->bound_device) {
- if (s->bound_device != dev)
- continue;
- score++;
- }
- if(score == 4 && s->num == hnum) {
- result = s;
- break;
- } else if(score > badness && (s->num == hpnum || s->rcv_saddr)) {
- result = s;
- badness = score;
- }
- }
+ unsigned short hnum = ntohs(dport);
+ unsigned short hrnum = ntohs(rport);
+ struct sock *sk;
+
+ /* Optimize here for direct hit, only listening connections can
+ * have wildcards anyways. It is assumed that this code only
+ * gets called from within NET_BH.
+ */
+ sk = tcp_established_hash[tcp_hashfn(daddr, hnum, saddr, sport)];
+ for(; sk; sk = sk->next)
+ if(sk->daddr == saddr && /* remote address */
+ sk->dummy_th.dest == sport && /* remote port */
+ sk->num == hnum && /* local port */
+ sk->rcv_saddr == daddr && /* local address */
+ ((sk->bound_device==NULL) || (sk->bound_device==dev)) )
+ goto hit; /* You sunk my battleship! */
+ /* If we don't match on a bound socket, try to find one explicitly listening
+ * on the remote address (a proxy bind).
+ */
+ sk = tcp_v4_lookup_longway(daddr, hnum, dev);
+ /* If that didn't yield an exact match, look for a socket listening on the
+ * redirect port.
+ */
+ if (!sk || sk->rcv_saddr != daddr) {
+ sk = tcp_v4_lookup_longway(paddr, hrnum, dev);
}
- return result;
+hit:
+ return sk;
}
-
-#undef secondlist
-#undef tcp_v4_proxy_loop_init
-#undef tcp_v4_proxy_loop_next
-
#endif
/*
struct tcphdr *th = (struct tcphdr *)(skb->h.raw + iph->ihl*4);
struct sock *sk;
- sk = tcp_v4_proxy_lookup(th->dest, iph->saddr, th->source, iph->daddr,
- 0, 0, skb->dev);
+ sk = tcp_v4_lookup(iph->saddr, th->source, iph->daddr, th->dest,
+ skb->dev);
if (!sk)
return 0;
/* 0 means accept all LOCAL addresses here, not all the world... */
#endif
#ifdef CONFIG_IP_TRANSPARENT_PROXY
if (skb->redirport)
- sk = tcp_v4_proxy_lookup(th->dest, saddr, th->source, daddr,
- dev->pa_addr, skb->redirport, dev);
+ sk = tcp_v4_proxy_lookup(saddr, th->source, daddr, th->dest, dev->pa_addr, skb->redirport, dev);
else
#endif
sk = __tcp_v4_lookup(th, saddr, th->source, daddr, th->dest, dev);
tcp_set_state(sk, TCP_CLOSE);
sk->shutdown = SHUTDOWN_MASK;
#ifdef CONFIG_IP_TRANSPARENT_PROXY
- sk = tcp_v4_proxy_lookup(th->dest, saddr, th->source, daddr,
- dev->pa_addr, skb->redirport, dev);
-#else
- sk = NULL;
+ /* What to do here?
+ * For the non-proxy case, this code is effectively almost a no-op,
+ * due to the sk = NULL. Is that intentional? If so, why shouldn't we
+ * do the same for the proxy case and get rid of some useless code?
+ */
+ if (skb->redirport)
+ sk = tcp_v4_proxy_lookup(saddr, th->source, daddr, th->dest,
+ dev->pa_addr, skb->redirport, dev);
+ else
#endif
+ sk = NULL;
/* this is not really correct: we should check sk->users */
if (sk && sk->state==TCP_LISTEN)
{
skb2->raddr=rt->rt_gateway;
if (sk->state == TCP_SYN_SENT && sysctl_ip_dynaddr)
ip_rewrite_addrs (sk, skb2, dev);
+ skb_pull(skb2,((unsigned char *)skb2->ip_hdr)-skb2->data);
skb2->dev = dev;
skb2->arp=1;
if (rt->rt_hh)
* Last socket cache retained as it
* does have a high hit rate.
* Elliot Poger : Added support for SO_BINDTODEVICE.
+ * Willy Konynenberg : Transparent proxy adapted to new
+ * socket hash code.
*
*
* This program is free software; you can redistribute it and/or
}
#ifdef CONFIG_IP_TRANSPARENT_PROXY
-#define secondlist(hpnum, sk, fpass) \
-({ struct sock *s1; if(!(sk) && (fpass)--) \
- s1 = udp_hash[(hpnum) & (TCP_HTABLE_SIZE - 1)]; \
- else \
- s1 = (sk); \
- s1; \
-})
-
-#define udp_v4_proxy_loop_init(hnum, hpnum, sk, fpass) \
- secondlist((hpnum), udp_hash[(hnum)&(TCP_HTABLE_SIZE-1)],(fpass))
-
-#define udp_v4_proxy_loop_next(hnum, hpnum, sk, fpass) \
- secondlist((hpnum),(sk)->next,(fpass))
-
-struct sock *udp_v4_proxy_lookup(unsigned short num, unsigned long raddr,
- unsigned short rnum, unsigned long laddr,
- unsigned long paddr, unsigned short pnum,
+struct sock *udp_v4_proxy_lookup(u32 saddr, u16 sport, u32 daddr, u16 dport, u32 paddr, u16 rport,
struct device *dev)
{
- struct sock *s, *result = NULL;
+ struct sock *hh[3], *sk, *result = NULL;
+ int i;
int badness = -1;
- unsigned short hnum = ntohs(num);
- unsigned short hpnum = ntohs(pnum);
- int firstpass = 1;
+ unsigned short hnum = ntohs(dport);
+ unsigned short hpnum = ntohs(rport);
SOCKHASH_LOCK();
- for(s = udp_v4_proxy_loop_init(hnum, hpnum, s, firstpass);
- s != NULL;
- s = udp_v4_proxy_loop_next(hnum, hpnum, s, firstpass)) {
- if(s->num == hnum || s->num == hpnum) {
- int score = 0;
- if(s->dead && (s->state == TCP_CLOSE))
- continue;
- if(s->rcv_saddr) {
- if((s->num != hpnum || s->rcv_saddr != paddr) &&
- (s->num != hnum || s->rcv_saddr != laddr))
- continue;
- score++;
- }
- if(s->daddr) {
- if(s->daddr != raddr)
- continue;
- score++;
- }
- if(s->dummy_th.dest) {
- if(s->dummy_th.dest != rnum)
- continue;
- score++;
- }
- /* If this socket is bound to a particular interface,
- * did the packet come in on it? */
- if(s->bound_device) {
- if (s->bound_device != dev)
+ hh[0] = udp_hash[hnum & (UDP_HTABLE_SIZE - 1)];
+ hh[1] = udp_hash[hpnum & (UDP_HTABLE_SIZE - 1)];
+ for (i = 0; i < 2; i++) {
+ for(sk = hh[i]; sk != NULL; sk = sk->next) {
+ if(sk->num == hnum || sk->num == hpnum) {
+ int score = 0;
+ if(sk->dead && (sk->state == TCP_CLOSE))
continue;
- score++;
- }
- if(score == 4 && s->num == hnum) {
- result = s;
- break;
- } else if(score > badness && (s->num == hpnum || s->rcv_saddr)) {
- result = s;
+ if(sk->rcv_saddr) {
+ if((sk->num != hpnum || sk->rcv_saddr != paddr) &&
+ (sk->num != hnum || sk->rcv_saddr != daddr))
+ continue;
+ score++;
+ }
+ if(sk->daddr) {
+ if(sk->daddr != saddr)
+ continue;
+ score++;
+ }
+ if(sk->dummy_th.dest) {
+ if(sk->dummy_th.dest != sport)
+ continue;
+ score++;
+ }
+ /* If this socket is bound to a particular interface,
+ * did the packet come in on it? */
+ if(sk->bound_device) {
+ if (sk->bound_device != dev)
+ continue;
+ score++;
+ }
+ if(score == 4 && sk->num == hnum) {
+ result = sk;
+ break;
+ } else if(score > badness && (sk->num == hpnum || sk->rcv_saddr)) {
+ result = sk;
badness = score;
+ }
}
}
}
SOCKHASH_UNLOCK();
return result;
}
-
-#undef secondlist
-#undef udp_v4_proxy_loop_init
-#undef udp_v4_proxy_loop_next
-
#endif
static inline struct sock *udp_v4_mcast_next(struct sock *sk,
struct udphdr *uh = (struct udphdr *)(skb->h.raw + iph->ihl*4);
struct sock *sk;
- sk = udp_v4_proxy_lookup(uh->dest, iph->saddr, uh->source, iph->daddr,
- 0, 0, skb->dev);
+ sk = udp_v4_lookup(iph->saddr, uh->source, iph->daddr, uh->dest,
+ skb->dev);
if (!sk)
return 0;
/* 0 means accept all LOCAL addresses here, not all the world... */
#endif
#ifdef CONFIG_IP_TRANSPARENT_PROXY
if(skb->redirport)
- sk = udp_v4_proxy_lookup(uh->dest, saddr, uh->source,
- daddr, dev->pa_addr, skb->redirport, dev);
+ sk = udp_v4_proxy_lookup(saddr, uh->source, daddr, uh->dest,
+ dev->pa_addr, skb->redirport, dev);
else
#endif
sk = udp_v4_lookup(saddr, uh->source, daddr, uh->dest, dev);
X(init_etherdev),
X(ip_rt_route),
+ X(ip_rt_dev),
X(icmp_send),
X(ip_options_compile),
X(ip_rt_put),