Commit 7388b7aa authored by Linus Torvalds's avatar Linus Torvalds

Import 1.3.47

parent 4eeb9af8
...@@ -134,6 +134,12 @@ S: Computer Science Department ...@@ -134,6 +134,12 @@ S: Computer Science Department
S: Baltimore, Maryland 21218 S: Baltimore, Maryland 21218
S: USA S: USA
N: Axel Boldt
E: boldt@math.ucsb.edu
W: http://math-www.uni-paderborn.de/~axel/
D: Configuration help text support
D: Linux CD and Support Giveaway List
N: John Boyd N: John Boyd
E: boyd@cis.ohio-state.edu E: boyd@cis.ohio-state.edu
D: Co-author of wd7000 SCSI driver D: Co-author of wd7000 SCSI driver
...@@ -214,7 +220,7 @@ S: United Kingdom ...@@ -214,7 +220,7 @@ S: United Kingdom
N: Ray Dassen N: Ray Dassen
E: jdassen@wi.LeidenUniv.nl E: jdassen@wi.LeidenUniv.nl
U: http://www.wi.leidenuniv.nl/~jdassen/ W: http://www.wi.leidenuniv.nl/~jdassen/
D: Debian GNU/Linux: www.debian.org maintainer, FAQ co-maintainer, D: Debian GNU/Linux: www.debian.org maintainer, FAQ co-maintainer,
D: packages testing, nit-picking & fixing. Enjoying BugFree (TM) kernels. D: packages testing, nit-picking & fixing. Enjoying BugFree (TM) kernels.
S: Zuidsingel 10A S: Zuidsingel 10A
......
# LAST EDIT: Fri Oct 27 23:03:01 1995 by Axel Boldt (boldt@math.ucsb.edu) # LAST EDIT: Thu Nov 30 22:39:07 1995 by Axel Boldt (boldt@math.ucsb.edu)
# #
# This version of the Linux kernel configuration help texts # This version of the Linux kernel configuration help texts
# corresponds to the kernel versions 1.3.x. Be aware that these # corresponds to the kernel versions 1.3.x. Be aware that these
...@@ -9,7 +9,7 @@ ...@@ -9,7 +9,7 @@
# #
# Information about what a kernel is, what it does, how to patch and # Information about what a kernel is, what it does, how to patch and
# compile it and much more is contained in the Kernel-HOWTO, available # compile it and much more is contained in the Kernel-HOWTO, available
# via anonymous ftp from sunsite.unc.edu in the directory # via ftp (user: anonymous) from sunsite.unc.edu in the directory
# /pub/Linux/docs/HOWTO. # /pub/Linux/docs/HOWTO.
# #
# Format: description<nl>variable<nl>helptext<nl><nl>. The help texts # Format: description<nl>variable<nl>helptext<nl><nl>. The help texts
...@@ -21,10 +21,7 @@ ...@@ -21,10 +21,7 @@
# All this was shamelessly stolen from several different sources. Many # All this was shamelessly stolen from several different sources. Many
# thanks to all the contributors. Feel free to use these help texts # thanks to all the contributors. Feel free to use these help texts
# in your own kernel configuration tools. The texts are copyrighted # in your own kernel configuration tools. The texts are copyrighted
# (c) 1995 by Axel Boldt and governed by our beloved little Copyleft # (c) 1995 by Axel Boldt and governed by the GNU Public License.
# virus, the GNU Public License. This essentially means that you can
# do with them whatever you want unless you try to restrict someone
# else's right to do whatever they want.
# #
# Send comments to Axel Boldt <boldt@math.ucsb.edu>. # Send comments to Axel Boldt <boldt@math.ucsb.edu>.
...@@ -82,26 +79,26 @@ CONFIG_ST506 ...@@ -82,26 +79,26 @@ CONFIG_ST506
Use old (reliable) disk-only driver for primary i/f Use old (reliable) disk-only driver for primary i/f
CONFIG_BLK_DEV_HD CONFIG_BLK_DEV_HD
As you might have guessed, there are now two drivers for IDE As you might have guessed, there are now two drivers for IDE
harddrives around: the old reliable one and the new improved harddrives around: the old one and the new improved one. The old one
one. The new driver can also handle IDE/ATAPI CDROM drives (ATAPI = is not any longer more reliable than the new one. The new driver can
AT Attachment Packet Interface is a new protocol currently used for also handle IDE/ATAPI CDROM drives (ATAPI = AT Attachment Packet
controlling CDROM and tape drives, similar to the SCSI Interface is a new protocol currently used for controlling CDROM and
protocol. Some newer CDROM drives such as NEC 260 and MITSUMI tape drives, similar to the SCSI protocol. Some newer CDROM drives
triple/quad speed drives use it, but most MITSUMI CDROM drives such as NEC 260 and MITSUMI triple/quad speed drives use it, but
don't). The old driver supports up to two hard drives, while the new most MITSUMI CDROM drives don't). The old driver supports up to two
one can deal with any mix of up to eight hard drives and IDE/ATAPI hard drives, while the new one can deal with any mix of up to eight
CDROMs, two per IDE interface. Using the old driver makes sense if hard drives and IDE/ATAPI CDROMs, two per IDE interface. Using the
you have older MFM/RLL/ESDI drives, since it is smaller and these old driver makes sense if you have older MFM/RLL/ESDI drives, since
drives don't benefit from the additional features of the new it is smaller and these drives don't benefit from the additional
driver. If you have more than one IDE interface (=controller), you features of the new driver. If you have more than one IDE interface
can use the old driver on the first and the new one on the others, (=controller), you can use the old driver on the first and the new
if you like. In that case (or if you have just one interface and one on the others, if you like. In that case (or if you have just
don't want to use the new driver at all) you would say Y here, one interface and don't want to use the new driver at all) you would
thereby enlarging your kernel by about 4 kB. If you want to use the say Y here, thereby enlarging your kernel by about 4 kB. If you want
new driver exclusively, say N and answer Y to the following to use the new driver exclusively, say N and answer Y to the
question(s). Useful information about how to use large (>504MB) IDE following question(s). Useful information about how to use large
harddrives is contained in drivers/block/README.ide. If unsure, say (>504MB) IDE harddrives is contained in drivers/block/README.ide. If
N. unsure, say N.
Use new IDE driver for primary/secondary i/f Use new IDE driver for primary/secondary i/f
CONFIG_BLK_DEV_IDE CONFIG_BLK_DEV_IDE
...@@ -173,11 +170,11 @@ CONFIG_NET ...@@ -173,11 +170,11 @@ CONFIG_NET
Sun floppy controller support Sun floppy controller support
CONFIG_BLK_DEV_SUNFD CONFIG_BLK_DEV_SUNFD
This is support for floppy drives on Sun workstations. But this This is support for floppy drives on Sun Sparc workstations. Say Y
support does not exist at this time, so you might as well say N. if you have a floppy drive, otherwise N. Easy.
Alpha system type Alpha system type
CONFIG_ALPHA_JENSEN CONFIG_ALPHA_AVANTI
Find out what type of Alpha system you are running. If you can't Find out what type of Alpha system you are running. If you can't
find one of the given names, then try "Noname". For this question, find one of the given names, then try "Noname". For this question,
it suffices to give a unique prefix of the option you want to it suffices to give a unique prefix of the option you want to
...@@ -204,6 +201,19 @@ CONFIG_ALPHA_SRM ...@@ -204,6 +201,19 @@ CONFIG_ALPHA_SRM
##### Don't know what this is about. ##### Don't know what this is about.
##### #####
Echo console messages on /dev/ttyS1
CONFIG_SERIAL_ECHO
If you enable this option, all kernel messages that would usually go
to the console will also be sent to the device /dev/ttyS1 which
corresponds to a serial port; this could be useful if you attached
a terminal or printer to that port.
TGA Console Support
CONFIG_TGA_CONSOLE
#####
##### Has something to do with Alpha.
#####
PCI bios support PCI bios support
CONFIG_PCI CONFIG_PCI
Find out whether you have a PCI motherboard. PCI is the name of a Find out whether you have a PCI motherboard. PCI is the name of a
...@@ -216,12 +226,9 @@ CONFIG_PCI ...@@ -216,12 +226,9 @@ CONFIG_PCI
valuable information about which PCI hardware works under Linux and valuable information about which PCI hardware works under Linux and
which doesn't. If some of PCI devices don't work and you get a which doesn't. If some of PCI devices don't work and you get a
warning during boot time, please follow the instructions at the top of warning during boot time, please follow the instructions at the top of
include/linux/pci.h. Information regarding the buggy PCTech RZ 1000 IDE include/linux/pci.h. The buggy PCTech RZ 1000 IDE
harddrive controller which is used in some PCI systems is on the WWW harddrive controller which is used in some PCI systems is detected
at http://www.powerquest.com/hardware.html. (To browse the WWW, you and correctly handled by this driver.
need to have access to a machine on the Internet that has one of the
programs lynx, netscape or Mosaic). The new IDE driver detects this
controller and works around this bug, though.
PCI bridge optimization (experimental) PCI bridge optimization (experimental)
CONFIG_PCI_OPTIMIZE CONFIG_PCI_OPTIMIZE
...@@ -241,17 +248,19 @@ CONFIG_BLK_DEV_TRITON ...@@ -241,17 +248,19 @@ CONFIG_BLK_DEV_TRITON
System V IPC System V IPC
CONFIG_SYSVIPC CONFIG_SYSVIPC
InterProcessCommunication is a suite of library functions and system Inter Process Communication is a suite of library functions and system
calls which let processes (= running programs) synchronize and calls which let processes (= running programs) synchronize and
exchange information. It is generally considered to be a good thing, exchange information. It is generally considered to be a good thing,
and some programs won't run unless you enable this. You can find and some programs won't run unless you enable this. In particular,
documentation about IPC in ipc.info, which is contained in if you want to run the DOS emulator dosemu under Linux (read the
sunsite.unc.edu:/pub/Linux/docs/man/info.tar.gz (available via ftp, DOSEMU-HOWTO, available via ftp (user: anonymous) in
user: anonymous; extract with "tar xzvf filename"). These docs sunsite.unc.edu:/pub/Linux/docs/HOWTO), you'll need to say Y here. You
are in the info format which is used to document GNU software and can find documentation about IPC in ipc.info, which is contained in
can be read from within emacs ("Ctrl-h i") or with the program info sunsite.unc.edu:/pub/Linux/docs/man/info.tar.gz (extract with "tar
("man info"). Enabling this option enlarges your kernel by about xzvf filename"). These docs are in the info format which is used to
7kB. Just say Y. document GNU software and can be read from within emacs ("Ctrl-h i")
or with the program info ("man info"). Enabling this option enlarges
your kernel by about 7kB. Just say Y.
Kernel support for ELF binaries Kernel support for ELF binaries
CONFIG_BINFMT_ELF CONFIG_BINFMT_ELF
...@@ -291,27 +300,13 @@ CONFIG_KERNEL_ELF ...@@ -291,27 +300,13 @@ CONFIG_KERNEL_ELF
kernel in ELF by saying Y here and editing the variables CC kernel in ELF by saying Y here and editing the variables CC
and LD in the toplevel Makefile. and LD in the toplevel Makefile.
Use -m486 flag for 486-specific optimizations Use 486-specific optimizations (does NOT work on i386)
CONFIG_M486 CONFIG_M486
If you have a 486 as opposed to a 386 or Pentium CPU, say Y here: If you have a 486 or better, as opposed to a 386, say Y here:
things will be slightly faster. However, it is not required: the things will be slightly faster. However, it is not required: the
kernel will run on all CPUs with and without this option. If you are kernel will run on all CPUs without this option. If you are
not sure, say Y; apart from enlarging your kernel by about 6 kB, it not sure, say N; This option will make the kernel use some
won't hurt. instructions that are only available on 486+ machines.
SMP Kernel (experimental - gcc2.5.8 only: see Documentation/SMP.txt)
CONFIG_SMP
This is experimental support for multiprocessor Pentium machines
that agree with the Intel MP v1.1 specification. It can deal with up
to 32 processors. You can only compile it with gcc version 2.5.8
("gcc -v"). For details, see Documentation/SMP.ez in the kernel
source (this document has been formatted using the ez andrew word
processor, available via ftp (user: anonymous) from
sunsite.unc.edu:/pub/Linux/X11/andrew/auis63L3-wp.tgz) and
http://www.linux.org.uk/SMP/title.html on the WWW (to browse the
WWW, you need to have access to a machine on the Internet that has
one of the programs lynx, netscape or Mosaic). Please back up all
your harddrives before using kernels compiled with this option.
Set version information on all symbols for modules Set version information on all symbols for modules
CONFIG_MODVERSIONS CONFIG_MODVERSIONS
...@@ -384,8 +379,11 @@ CONFIG_IP_MULTICAST ...@@ -384,8 +379,11 @@ CONFIG_IP_MULTICAST
tables, require that this option be compiled in. You also need tables, require that this option be compiled in. You also need
multicasting if you intend to participate in the MBONE, a high multicasting if you intend to participate in the MBONE, a high
bandwidth network on top of the internet which carries audio and bandwidth network on top of the internet which carries audio and
video broadcasts. Information about the multicast capabilities of video broadcasts. More information about the MBONE is on the WWW at
the various network cards is contained in http://www.best.com/~prince/techinfo/mbone.html (to browse the WWW,
you need to have access to a machine on the Internet that has one of
the programs lynx, netscape or Mosaic). Information about the
multicast capabilities of the various network cards is contained in
drivers/net/README.multicast. For most people, it's safe to say N. drivers/net/README.multicast. For most people, it's safe to say N.
IP: firewalling IP: firewalling
...@@ -399,13 +397,14 @@ CONFIG_IP_FIREWALL ...@@ -399,13 +397,14 @@ CONFIG_IP_FIREWALL
sunsite.unc.edu:/pub/Linux/docs/HOWTO. Also, you will have to use sunsite.unc.edu:/pub/Linux/docs/HOWTO. Also, you will have to use
the ipfw tool from the net-tools package, available via ftp (user: the ipfw tool from the net-tools package, available via ftp (user:
anonymous) from anonymous) from
ftp.linux.org.uk:/pub/linux/Networking/PROGRAMS/NetTools. It allows ftp.linux.org.uk:/pub/linux/Networking/PROGRAMS/NetTools, or
selective blocking of internet traffic based on type, origin and preferably ipfwadm from ftp.xos.nl:/pub/linux/ipfwadm/. These
destination. You need to enable IP firewalling in order to be able programs allow selective blocking of internet traffic based on type,
to use IP masquerading (i.e. IP traffic from one of the local origin and destination. You need to enable IP firewalling in order
computers and destined for an outside host is changed by your box so to be able to use IP masquerading (i.e. IP traffic from one of the
that it appears to come from you). Chances are that you don't want local computers and destined for an outside host is changed by your
this, so say N. box so that it appears to come from you). Chances are that you don't
want this, so say N.
IP: accounting IP: accounting
CONFIG_IP_ACCT CONFIG_IP_ACCT
...@@ -487,7 +486,7 @@ CONFIG_INET_RARP ...@@ -487,7 +486,7 @@ CONFIG_INET_RARP
Since you asked: if there are diskless machines on your network that Since you asked: if there are diskless machines on your network that
know their hardware ethernet address but don't know their IP know their hardware ethernet address but don't know their IP
addresses upon startup, they send out a Reverse addresses upon startup, they send out a Reverse
AddressResolutionProtocol request to find out their own IP Address Resolution Protocol request to find out their own IP
addresses. If you want your Linux box to be able to *answer* such addresses. If you want your Linux box to be able to *answer* such
requests, say Y here; you'd use the program rarp ("man rarp"). If requests, say Y here; you'd use the program rarp ("man rarp"). If
you want to compile this as a module ( = code which can be inserted you want to compile this as a module ( = code which can be inserted
...@@ -503,13 +502,21 @@ CONFIG_INET_SNARL ...@@ -503,13 +502,21 @@ CONFIG_INET_SNARL
links, between machines of your IP network, say N. If in doubt, say links, between machines of your IP network, say N. If in doubt, say
Y. Y.
Disable Path MTU Discovery (normally enabled)
CONFIG_NO_PATH_MTU_DISCOVERY
MTU (maximal transfer unit) is the size of the chunks we send out
over the net. "Path MTU Discovery" means that, instead of always
sending very small chunks, we start out sending big ones and if we
then discover that some host along the way likes its chunks smaller,
we adjust to a smaller size. This is good, so say N.
Disable NAGLE algorithm (normally enabled) Disable NAGLE algorithm (normally enabled)
CONFIG_TCP_NAGLE_OFF CONFIG_TCP_NAGLE_OFF
The NAGLE algorithm works by requiring an acknowledgment before The NAGLE algorithm works by requiring an acknowledgment before
sending small IP frames (= packets). This keeps tiny packets from sending small IP frames (= packets). This keeps tiny telnet and
telnet and rlogin from congesting Wide Area Networks. You may wish rlogin packets from congesting Wide Area Networks. You may wish to
to disable it if you run your X-server from across the network, or disable it if you run your X-server from across the network, or if
if multiple byte key sequences are delayed. Most people strongly multiple byte key sequences are delayed. Most people strongly
recommend to say N here, though, thereby leaving NAGLE enabled. recommend to say N here, though, thereby leaving NAGLE enabled.
IP: Drop source routed frames IP: Drop source routed frames
...@@ -542,17 +549,19 @@ CONFIG_SKB_LARGE ...@@ -542,17 +549,19 @@ CONFIG_SKB_LARGE
The IPX protocol The IPX protocol
CONFIG_IPX CONFIG_IPX
This is support for the Novell networking protocol. You need it if This is support for the Novell networking protocol, IPX. You need it
you want to access Novell Netware servers from within the Linux DOS if you want to access Novell Netware servers from within the Linux
emulator dosemu (read the DOSEMU-HOWTO, available via ftp (user: DOS emulator dosemu (read the DOSEMU-HOWTO, available via ftp (user:
anonymous) in sunsite.unc.edu:/pub/Linux/docs/HOWTO). It's very anonymous) in sunsite.unc.edu:/pub/Linux/docs/HOWTO). To
limited and won't make your Linux box into a Novell server. It would turn your Linux box into a fully featured Netware file server and
enlarge your kernel by about 5 kB. General information about how to IPX router, say Y here and fetch lwared from
connect Linux, Windows machines and Macs is on the WWW at sunsite.unc.edu:/pub/Linux/system/Networking/daemons/. General
http://eats.com/linux_mac_win.html (to browse the WWW, you need to information about how to connect Linux, Windows machines and Macs is
have access to a machine on the Internet that has one of the on the WWW at http://eats.com/linux_mac_win.html (to browse the WWW,
programs lynx, netscape or Mosaic). Unless you have Novell computers you need to have access to a machine on the Internet that has one of
on your local network, say N. the programs lynx, netscape or Mosaic). This driver would enlarge
your kernel by about 5 kB. Unless you have Novell computers on your
local network, say N.
Appletalk DDP Appletalk DDP
CONFIG_ATALK CONFIG_ATALK
...@@ -617,22 +626,22 @@ CONFIG_NETROM ...@@ -617,22 +626,22 @@ CONFIG_NETROM
Kernel/User network link driver(ALPHA) Kernel/User network link driver(ALPHA)
CONFIG_NETLINK CONFIG_NETLINK
This driver will allow for two-way communication between certain This driver allows for two-way communication between certain parts
parts of the kernel or modules and user processes; the user of the kernel or modules and user processes; the user processes are
processes will be able to read from and write to special files in able to read from and write to character special files in the /dev
the /dev directory having major mode 18. So far, the kernel uses it directory having major mode 18. So far, the kernel uses it to
to publish some network related information if you enable "Routing publish some network related information if you enable "Routing
messages", below. Say Y if you want to experiment with it; this is messages", below. Say Y if you want to experiment with it; this is
ALPHA code, which means that it need not be completely stable; it ALPHA code, which means that it need not be completely stable; it
has nothing to do with the computer architecture of the same name. has nothing to do with the computer architecture of the same name.
Routing messages Routing messages
CONFIG_RTNETLINK CONFIG_RTNETLINK
If you enable this and create a special file with major number 18 If you enable this and create a character special file /dev/route
and minor number 0 with mknod ("man mknod"), you can read some with major number 18 and minor number 0 using mknod ("man mknod"),
network related information from that file. Everything you write to you can read some network related routing information from that
that file will be discarded. Say Y, because otherwise the network file. Everything you write to that file will be discarded. Say Y,
link driver is pointless. because otherwise the network link driver is pointless.
SCSI support? SCSI support?
CONFIG_SCSI CONFIG_SCSI
...@@ -753,6 +762,8 @@ CONFIG_SCSI_BUSLOGIC ...@@ -753,6 +762,8 @@ CONFIG_SCSI_BUSLOGIC
BusLogic FlashPoint SCSI Host Adapters are not supported by this driver. BusLogic FlashPoint SCSI Host Adapters are not supported by this driver.
If this driver does not work correctly without modification, please If this driver does not work correctly without modification, please
consult the author. This driver is not currently available as a module. consult the author. This driver is not currently available as a module.
You might want to read the SCSI-HOWTO, available via ftp (user:
anonymous) at sunsite.unc.edu:/pub/Linux/docs/HOWTO.
EATA-DMA (DPT,NEC&ATT for ISA,EISA,PCI) support EATA-DMA (DPT,NEC&ATT for ISA,EISA,PCI) support
CONFIG_SCSI_EATA_DMA CONFIG_SCSI_EATA_DMA
...@@ -948,7 +959,9 @@ CONFIG_DUMMY ...@@ -948,7 +959,9 @@ CONFIG_DUMMY
handy, the default is Y. It won't enlarge your kernel either. What a handy, the default is Y. It won't enlarge your kernel either. What a
deal. If you want to compile this as a module ( = code which can be deal. If you want to compile this as a module ( = code which can be
inserted in and removed from the running kernel whenever you want), inserted in and removed from the running kernel whenever you want),
say M here and read Documentation/modules.txt. say M here and read Documentation/modules.txt. If you want to use
more than one dummy device at a time, you need to compile it as a
module.
SLIP (serial line) support SLIP (serial line) support
CONFIG_SLIP CONFIG_SLIP
...@@ -1334,10 +1347,14 @@ CONFIG_EEXPRESS ...@@ -1334,10 +1347,14 @@ CONFIG_EEXPRESS
If you have a network (ethernet) card of this type, say Y and read If you have a network (ethernet) card of this type, say Y and read
the Ethernet-HOWTO, available via ftp (user: anonymous) in the Ethernet-HOWTO, available via ftp (user: anonymous) in
sunsite.unc.edu:/pub/Linux/docs/HOWTO. Note that the Intel sunsite.unc.edu:/pub/Linux/docs/HOWTO. Note that the Intel
EtherExpress card is generally regarded to be a very poor choice and EtherExpress16 card is generally regarded to be a very poor choice
the driver is not very reliable. If you want to compile this as a and the driver is not very reliable. (Roger Wolff
module ( = code which can be inserted in and removed from the (R.E.Wolff@et.tudelft.nl) is attempting to do something about
running kernel whenever you want), say M here and read this. At the moment he could use 1) one or more etherexpress16 cards
to test locally 2) Alpha testers: people to try new versions of the
driver to see if things improve...) If you want to compile this
driver as a module ( = code which can be inserted in and removed
from the running kernel whenever you want), say M here and read
Documentation/modules.txt as well as Documentation/modules.txt as well as
Documentation/networking/net-modules.txt. If you plan to use more Documentation/networking/net-modules.txt. If you plan to use more
than one network card under linux, read the than one network card under linux, read the
...@@ -1503,6 +1520,19 @@ CONFIG_DE4X5 ...@@ -1503,6 +1520,19 @@ CONFIG_DE4X5
Multiple-Ethernet-mini-HOWTO, available from Multiple-Ethernet-mini-HOWTO, available from
sunsite.unc.edu:/pub/Linux/docs/HOWTO/mini. sunsite.unc.edu:/pub/Linux/docs/HOWTO/mini.
ICL EtherTeam 16i/32 support
CONFIG_ETH16I
If you have a network (ethernet) card of this type, say Y and read
the Ethernet-HOWTO, available via ftp (user: anonymous) in
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). 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. If you plan to use more
than one network card under linux, read the
Multiple-Ethernet-mini-HOWTO, available from
sunsite.unc.edu:/pub/Linux/docs/HOWTO/mini.
Zenith Z-Note support Zenith Z-Note support
CONFIG_ZNET CONFIG_ZNET
The Zenith Z-Note notebook computer has a built-in network The Zenith Z-Note notebook computer has a built-in network
...@@ -1517,9 +1547,6 @@ CONFIG_NET_POCKET ...@@ -1517,9 +1547,6 @@ CONFIG_NET_POCKET
port ("pocket adaptors"). If you have one of those, say Y and read port ("pocket adaptors"). If you have one of those, say Y and read
the Ethernet-HOWTO, available via ftp (user: anonymous) from the Ethernet-HOWTO, available via ftp (user: anonymous) from
sunsite.unc.edu:/pub/Linux/docs/HOWTO. If you plan to use more than sunsite.unc.edu:/pub/Linux/docs/HOWTO. If you plan to use more than
#####
##### What should you say to CONFIG_PRINTER in order to use these?
#####
one network card under linux, read the Multiple-Ethernet-mini-HOWTO, one network card under linux, read the Multiple-Ethernet-mini-HOWTO,
available from sunsite.unc.edu:/pub/Linux/docs/HOWTO/mini. If you available from sunsite.unc.edu:/pub/Linux/docs/HOWTO/mini. If you
want to plug a network card into the PCMCIA slot of your laptop want to plug a network card into the PCMCIA slot of your laptop
...@@ -1530,9 +1557,11 @@ CONFIG_NET_POCKET ...@@ -1530,9 +1557,11 @@ CONFIG_NET_POCKET
will just cause this configure script to skip all the questions will just cause this configure script to skip all the questions
about this class of network devices. If you say Y, you will be about this class of network devices. If you say Y, you will be
asked for your specific device in the following questions. If you asked for your specific device in the following questions. If you
plan to use more than one network card under linux, read the plan to use more than one network device under linux, read the
Multiple-Ethernet-mini-HOWTO, available from Multiple-Ethernet-mini-HOWTO, available from
sunsite.unc.edu:/pub/Linux/docs/HOWTO/mini. sunsite.unc.edu:/pub/Linux/docs/HOWTO/mini. If you intend to use an
adaptor attaching to the parallel port as well as a parallel
printer, you should compile both drivers as modules (if possible).
AT-LAN-TEC/RealTek pocket adaptor support AT-LAN-TEC/RealTek pocket adaptor support
CONFIG_ATP CONFIG_ATP
...@@ -1542,7 +1571,9 @@ CONFIG_ATP ...@@ -1542,7 +1571,9 @@ CONFIG_ATP
sunsite.unc.edu:/pub/Linux/docs/HOWTO if you want to use this. If sunsite.unc.edu:/pub/Linux/docs/HOWTO if you want to use this. If
you plan to use more than one network card under linux, read the you plan to use more than one network card under linux, read the
Multiple-Ethernet-mini-HOWTO, available from Multiple-Ethernet-mini-HOWTO, available from
sunsite.unc.edu:/pub/Linux/docs/HOWTO/mini. sunsite.unc.edu:/pub/Linux/docs/HOWTO/mini. If you intend to use
this driver, you should have said N to the Parallel Printer support,
because the two drivers don't like each other.
D-Link DE600 pocket adaptor support D-Link DE600 pocket adaptor support
CONFIG_DE600 CONFIG_DE600
...@@ -1552,10 +1583,11 @@ CONFIG_DE600 ...@@ -1552,10 +1583,11 @@ CONFIG_DE600
sunsite.unc.edu:/pub/Linux/docs/HOWTO if you want to use this. If sunsite.unc.edu:/pub/Linux/docs/HOWTO if you want to use this. If
you want to compile this as a module ( = code which can be inserted you want to compile this as a module ( = code which can be inserted
in and removed from the running kernel whenever you want), say M in and removed from the running kernel whenever you want), say M
here and read Documentation/modules.txt. If you plan to use more here and read Documentation/modules.txt. If you intend to use this
than one network card under linux, read the pocket adaptor as well as a parallel printer, you should compile
Multiple-Ethernet-mini-HOWTO, available from both drivers as modules. If you plan to use more than one network
sunsite.unc.edu:/pub/Linux/docs/HOWTO/mini. card under linux, read the Multiple-Ethernet-mini-HOWTO, available
from sunsite.unc.edu:/pub/Linux/docs/HOWTO/mini.
D-Link DE620 pocket adaptor support D-Link DE620 pocket adaptor support
CONFIG_DE620 CONFIG_DE620
...@@ -1565,10 +1597,11 @@ CONFIG_DE620 ...@@ -1565,10 +1597,11 @@ CONFIG_DE620
sunsite.unc.edu:/pub/Linux/docs/HOWTO if you want to use this. If sunsite.unc.edu:/pub/Linux/docs/HOWTO if you want to use this. If
you want to compile this as a module ( = code which can be inserted you want to compile this as a module ( = code which can be inserted
in and removed from the running kernel whenever you want), say M in and removed from the running kernel whenever you want), say M
here and read Documentation/modules.txt. If you plan to use more here and read Documentation/modules.txt. If you intend to use this
than one network card under linux, read the pocket adaptor as well as a parallel printer, you should compile
Multiple-Ethernet-mini-HOWTO, available from both drivers as modules. If you plan to use more than one network
sunsite.unc.edu:/pub/Linux/docs/HOWTO/mini. card under linux, read the Multiple-Ethernet-mini-HOWTO, available
from sunsite.unc.edu:/pub/Linux/docs/HOWTO/mini.
Token Ring driver support Token Ring driver support
CONFIG_TR CONFIG_TR
...@@ -1673,17 +1706,17 @@ CONFIG_SBPCD2 ...@@ -1673,17 +1706,17 @@ CONFIG_SBPCD2
Aztech/Orchid/Okano/Wearnes (non IDE) CDROM support Aztech/Orchid/Okano/Wearnes (non IDE) CDROM support
CONFIG_AZTCD CONFIG_AZTCD
If you have a CDA268-01A, ORCHID CD-3110, OKANO/WEARNES CDD110 CDROM If you have a CDA268-01A, ORCHID CD-3110, OKANO/WEARNES CDD110 or
drive, say Y here and also to "ISO9660 cdrom filesystem support" Conrad TXC CDROM drive, say Y here and also to "ISO9660 cdrom
below. This is NOT for CDROM drives with IDE interface, such as filesystem support" below. This is NOT for CDROM drives with IDE
Aztech CDA269-031SE. (If you have one of those, you should have said interface, such as Aztech CDA269-031SE. (If you have one of those,
Y to the new IDE driver above.) You want to read you should have said Y to the new IDE driver above.) You want to
Documentation/cdrom/aztcd and include/linux/aztcd.h in the kernel read Documentation/cdrom/aztcd and include/linux/aztcd.h in the
source and the CDROM-HOWTO, available via ftp (user: anonymous) from kernel source and the CDROM-HOWTO, available via ftp (user:
sunsite.unc.edu:/pub/Linux/docs/HOWTO. If unsure, say N. If you anonymous) from sunsite.unc.edu:/pub/Linux/docs/HOWTO. If unsure,
want to compile this as a module ( = code which can be inserted in say N. If you want to compile this as a module ( = code which can
and removed from the running kernel whenever you want), say M here be inserted in and removed from the running kernel whenever you
and read Documentation/modules.txt. want), say M here and read Documentation/modules.txt.
Sony CDU535 CDROM driver support Sony CDU535 CDROM driver support
CONFIG_CDU535 CONFIG_CDU535
...@@ -1790,13 +1823,13 @@ CONFIG_EXT2_FS ...@@ -1790,13 +1823,13 @@ CONFIG_EXT2_FS
xiafs filesystem support xiafs filesystem support
CONFIG_XIA_FS CONFIG_XIA_FS
This filesystem (= method to organize files on a harddisk partition This is an old filesystem (= method to organize files on a harddisk
or a floppy disk) is only used rarely these days. This option would partition or a floppy disk) and not in use anymore. This option
enlarge your kernel by about 28 kB. Say N. If you want to compile would enlarge your kernel by about 28 kB. Let's all kill this beast:
this as a module ( = code which can be inserted in and removed from say N. If you want to compile this as a module ( = code which can
the running kernel whenever you want), say M here and read be inserted in and removed from the running kernel whenever you
Documentation/modules.txt. Note that the filesystem of your root want), say M here and read Documentation/modules.txt. Note that the
partition cannot be compiled as a module. filesystem of your root partition cannot be compiled as a module.
msdos fs support msdos fs support
CONFIG_MSDOS_FS CONFIG_MSDOS_FS
...@@ -1847,31 +1880,29 @@ CONFIG_PROC_FS ...@@ -1847,31 +1880,29 @@ CONFIG_PROC_FS
them. Also, you cannot read the files with less or more: you need to them. Also, you cannot read the files with less or more: you need to
use cat. The filesystem is explained in the Kernel Hacker's Guide, use cat. The filesystem is explained in the Kernel Hacker's Guide,
available via ftp (user: anonymous) in available via ftp (user: anonymous) in
sunsite.unc.edu:/pub/Linux/docs/LDP. This option will enlarge your sunsite.unc.edu:/pub/Linux/docs/LDP and also on the proc(8) manpage
kernel by about 18 kB. It's totally cool; for example, "cat ("man 8 proc"). This option will enlarge your kernel by about 18
/proc/interrupts" gives information about what the different IRQs kB. It's totally cool; for example, "cat /proc/interrupts" gives
are used for at the moment (there is a small number of Interrupt information about what the different IRQs are used for at the moment
ReQuest lines in your computer that are used by the periphery to (there is a small number of Interrupt ReQuest lines in your computer
gain the CPU's attention - often a source of trouble if two devices that are used by the periphery to gain the CPU's attention - often a
are mistakenly configured to use the same IRQ). Several programs source of trouble if two devices are mistakenly configured to use
depend on this, so everyone should say Y here. the same IRQ). Several programs depend on this, so everyone should
say Y here.
NFS filesystem support NFS filesystem support
CONFIG_NFS_FS CONFIG_NFS_FS
If you are connected to a network (using SLIP, PPP or ethernet, not If you are connected to some other (usually local) Unix computer
term [term is a program which gives you almost full Internet (using SLIP, PLIP, PPP or ethernet) and want to mount files
connectivity if you have a regular dial up shell account on some residing on that computer (the NFS server) using the Network
Internet connected Unix computer. Read the Term-HOWTO, available via File Sharing protocol, say Y. "Mounting files" means that the client
ftp (user: anonymous) on sunsite.unc.edu:/pub/Linux/docs/HOWTO]) and can access the files with usual UNIX commands as if they were
want to mount files residing on another UNIX computer (the NFS sitting on the client's harddisk. For this to work, the server must
server) using the NetworkFileSharing protocol, say Y. "Mounting run the programs nfsd and mountd (but does not need to have NFS
files" means that the client can access the files with usual UNIX filesystem support enabled). NFS is explained in the Network
commands as if they were sitting on the client's harddisk. For this Administrator's Guide, available via ftp (user: anonymous) in
to work, the server must run the programs nfsd and mountd (but does sunsite.unc.edu:/pub/Linux/docs/LDP, and on its man page: "man
not need to have NFS filesystem support enabled). NFS is explained nfs". There is also a NFS-FAQ in
in the Network Administrator's Guide, available via ftp (user:
anonymous) in sunsite.unc.edu:/pub/Linux/docs/LDP, and on its man
page: "man nfs". There is also a NFS-FAQ in
sunsite.unc.edu:/pub/Linux/docs/faqs which presumes that you know sunsite.unc.edu:/pub/Linux/docs/faqs which presumes that you know
the basics of NFS already. If you say Y here, you should have said Y the basics of NFS already. If you say Y here, you should have said Y
to TCP/IP networking also. This option would enlarge your kernel by to TCP/IP networking also. This option would enlarge your kernel by
...@@ -1881,6 +1912,18 @@ CONFIG_NFS_FS ...@@ -1881,6 +1912,18 @@ CONFIG_NFS_FS
here and read Documentation/modules.txt. If you don't know what all here and read Documentation/modules.txt. If you don't know what all
this is about, say N. this is about, say N.
Root file system on NFS
CONFIG_ROOT_NFS
If you want your Linux box to mount its whole root filesystem from
some other computer over the net via NFS (presumably because your
box doesn't have a harddisk), say Y here. You will then have to
specify the directory that should be remotely mounted with the
"root" kernel command line option. See the documentation of your
boot loader (lilo or loadlin) about how to pass options to the
kernel. The lilo procedure is also explained in the SCSI-HOWTO,
available via ftp (user: anonymous) in
sunsite.unc.edu:/pub/Linux/docs/HOWTO.) Most people say N here.
ISO9660 cdrom filesystem support ISO9660 cdrom filesystem support
CONFIG_ISO9660_FS CONFIG_ISO9660_FS
If you have a CDROM and want to do more with it than just listen to If you have a CDROM and want to do more with it than just listen to
...@@ -1909,23 +1952,25 @@ System V and Coherent filesystem support ...@@ -1909,23 +1952,25 @@ System V and Coherent filesystem support
CONFIG_SYSV_FS CONFIG_SYSV_FS
SCO, Xenix and Coherent are commercial Unix systems for intel SCO, Xenix and Coherent are commercial Unix systems for intel
machines. Enabling this option would allow you to read and write to machines. Enabling this option would allow you to read and write to
and from their floppies and harddisk partitions. You need this if and from their floppies and harddisk partitions. If you have a
you want to run iBCS2 (iBCS2 [Intel Binary Compatibility Standard] floppy or harddisk partition like that, it is probable that they
is a kernel module which lets you run SCO, Xenix, Wyse, Unix Ware, contain binaries from those other Unix systems; in order to run
Dell Unix and System V programs under Linux and is often needed to these binaries, you will want to install iBCS2 (iBCS2 [Intel Binary
run commercial software, most prominently WordPerfect. It's in Compatibility Standard] is a kernel module which lets you run SCO,
tsx-11.mit.edu:/pub/linux/BETA). If you only intend to mount files Xenix, Wyse, Unix Ware, Dell Unix and System V programs under Linux
from some other Unix over the network using NFS, you don't need this and is often needed to run commercial software, most prominently
(but you need nfs filesystem support obviously). Note that this WordPerfect. It's in tsx-11.mit.edu:/pub/linux/BETA). If you only
option is generally not needed for floppies, since a good portable intend to mount files from some other Unix over the network using
way to transport files between unixes (and even to other operating NFS, you don't need this (but you need nfs filesystem support
systems) is given by the tar program ("man tar"). Note also that obviously). Note that this option is generally not needed for
this option has nothing to do whatsoever with the option "System V floppies, since a good portable way to transport files between
IPC". Read about the System V filesystem in unixes (and even to other operating systems) is given by the tar
Documentation/filesystems/sysv-fs.txt. This option will enlarge your program ("man tar"). Note also that this option has nothing to do
kernel by about 34 kB. If you want to compile this as a module whatsoever with the option "System V IPC". Read about the System V
( = code which can be inserted in and removed from the running filesystem in Documentation/filesystems/sysv-fs.txt. This option
kernel whenever you want), say M here and read will enlarge your kernel by about 34 kB. If you want to compile this
as a module ( = code which can be inserted in and removed from the
running kernel whenever you want), say M here and read
Documentation/modules.txt. If you haven't heard about all of this Documentation/modules.txt. If you haven't heard about all of this
before, it's safe to say N. before, it's safe to say N.
...@@ -1947,14 +1992,17 @@ CONFIG_SMB_FS ...@@ -1947,14 +1992,17 @@ CONFIG_SMB_FS
the programs lynx, netscape or Mosaic). If you want to compile this the programs lynx, netscape or Mosaic). If you want to compile this
as a module ( = code which can be inserted in and removed from the as a module ( = code which can be inserted in and removed from the
running kernel whenever you want), say M here and read running kernel whenever you want), say M here and read
Documentation/modules.txt. Most people say N here. Documentation/modules.txt. Most people say N, however.
Cyclades async mux support Cyclades async mux support
CONFIG_CYCLADES CONFIG_CYCLADES
This is a card which gives you many serial ports. You would need This is a card which gives you many serial ports. You would need
something like this to connect more than two modems to your linux something like this to connect more than two modems to your linux
box, for instance in order to become a BBS. If you haven't heard box, for instance in order to become a BBS. If you want to compile
about it, it's safe to say N. this as a module ( = code which can be inserted in and removed from
the running kernel whenever you want), say M here and read
Documentation/modules.txt. If you haven't heard about it, it's safe
to say N.
Stallion multiport serial support Stallion multiport serial support
CONFIG_STALDRV CONFIG_STALDRV
...@@ -1989,9 +2037,10 @@ CONFIG_PRINTER ...@@ -1989,9 +2037,10 @@ CONFIG_PRINTER
running kernel whenever you want), say M here and read running kernel whenever you want), say M here and read
Documentation/modules.txt. If you intend to use PLIP (Parallel Line Documentation/modules.txt. If you intend to use PLIP (Parallel Line
Internet Protocol is mainly used to create a mini network by Internet Protocol is mainly used to create a mini network by
connecting the parallel ports of two local machines) and a parallel connecting the parallel ports of two local machines) or a ethernet
printer, you should compile both as modules because the drivers network pocket adaptor attaching to the parallel port and a parallel
don't like each other. printer as well, you should compile both drivers as modules because
the drivers don't like each other.
Logitech busmouse support Logitech busmouse support
CONFIG_BUSMOUSE CONFIG_BUSMOUSE
...@@ -2163,12 +2212,12 @@ CONFIG_PROFILE_SHIFT ...@@ -2163,12 +2212,12 @@ CONFIG_PROFILE_SHIFT
# LocalWords: cdrom harddisk diskless netboot nfs xzvf ATAPI MB harddrives ide # LocalWords: cdrom harddisk diskless netboot nfs xzvf ATAPI MB harddrives ide
# LocalWords: HD harddisks CDROMs IDECD NEC MITSUMI filesystem XT XD PCI bios # LocalWords: HD harddisks CDROMs IDECD NEC MITSUMI filesystem XT XD PCI bios
# LocalWords: ISA EISA Microchannel VESA BIOSes bussystem IPC SYSVIPC ipc Ctrl # LocalWords: ISA EISA Microchannel VESA BIOSes bussystem IPC SYSVIPC ipc Ctrl
# LocalWords: InterProcessCommunication BINFMT Linkable http ac uk jo html GCC # LocalWords: BINFMT Linkable http ac uk jo html GCC Sparc AVANTI CABRIOLET EB
# LocalWords: netscape gcc LD CC toplevel MODVERSIONS insmod rmmod modprobe IP # LocalWords: netscape gcc LD CC toplevel MODVERSIONS insmod rmmod modprobe IP
# LocalWords: genksyms INET loopback gatewaying ethernet internet PPP ARP Arp # LocalWords: genksyms INET loopback gatewaying ethernet internet PPP ARP Arp
# LocalWords: howto multicasting MULTICAST MBONE firewalling ipfw ACCT resp ip # LocalWords: howto multicasting MULTICAST MBONE firewalling ipfw ACCT resp ip
# LocalWords: proc acct IPIP encapsulator decapsulator klogd PCTCP RARP EXT PS # LocalWords: proc acct IPIP encapsulator decapsulator klogd PCTCP RARP EXT PS
# LocalWords: telneting AddressResolutionProtocol subnetted NAGLE rlogin NOSR # LocalWords: telneting subnetted NAGLE rlogin NOSR ttyS TGA techinfo mbone nl
# LocalWords: Mb SKB IPX Novell Netware dosemu Appletalk DDP ATALK tapedrive # LocalWords: Mb SKB IPX Novell Netware dosemu Appletalk DDP ATALK tapedrive
# LocalWords: SD CHR scsi thingy SG CD LUNs LUN jukebox Adaptec BusLogic EATA # LocalWords: SD CHR scsi thingy SG CD LUNs LUN jukebox Adaptec BusLogic EATA
# LocalWords: buslogic DMA DPT ATT eata dma PIO UltraStor fdomain umsdos ext # LocalWords: buslogic DMA DPT ATT eata dma PIO UltraStor fdomain umsdos ext
...@@ -2196,5 +2245,7 @@ CONFIG_PROFILE_SHIFT ...@@ -2196,5 +2245,7 @@ CONFIG_PROFILE_SHIFT
# LocalWords: Multisession STALDRV EasyIO EC EasyConnection ISTALLION ONboard # LocalWords: Multisession STALDRV EasyIO EC EasyConnection ISTALLION ONboard
# LocalWords: Brumby pci TNC cis ohio faq usenet NETLINK dev hydra ca Tyne mem # LocalWords: Brumby pci TNC cis ohio faq usenet NETLINK dev hydra ca Tyne mem
# LocalWords: carleton Deskstation DECstation SUNFD JENSEN Noname XXXM SLiRP # LocalWords: carleton Deskstation DECstation SUNFD JENSEN Noname XXXM SLiRP
# LocalWords: pppd Zilog ZS soundcards SRM bootloader SMP smp ez mainmenu rarp # LocalWords: pppd Zilog ZS soundcards SRM bootloader ez mainmenu rarp ipfwadm
# LocalWords: RTNETLINK mknod # LocalWords: RTNETLINK mknod xos MTU lwared Macs mac netatalk macs cs Wolff
# LocalWords: dartmouth flowerpt MultiMaster FlashPoint tudelft etherexpress
# LocalWords: ICL EtherTeam ETH IDESCSI TXC
VERSION = 1 VERSION = 1
PATCHLEVEL = 3 PATCHLEVEL = 3
SUBLEVEL = 46 SUBLEVEL = 47
ARCH = i386 ARCH = i386
......
...@@ -19,9 +19,9 @@ tristate 'Kernel support for ELF binaries' CONFIG_BINFMT_ELF ...@@ -19,9 +19,9 @@ tristate 'Kernel support for ELF binaries' CONFIG_BINFMT_ELF
if [ "$CONFIG_BINFMT_ELF" = "y" ]; then if [ "$CONFIG_BINFMT_ELF" = "y" ]; then
bool 'Compile kernel as ELF - if your GCC is ELF-GCC' CONFIG_KERNEL_ELF bool 'Compile kernel as ELF - if your GCC is ELF-GCC' CONFIG_KERNEL_ELF
fi fi
#bool 'Use -mpentium flag for Pentium-specific optimizations' CONFIG_M586 #bool 'Use Pentium-specific optimizations (does NOT work on i386)' CONFIG_M586
#if [ "$CONFIG_M586" = "n" ]; then #if [ "$CONFIG_M586" = "n" ]; then
bool 'Use -m486 flag for 486-specific optimizations' CONFIG_M486 bool 'Use 486-specific optimizations (does NOT work on i386)' CONFIG_M486
#fi #fi
mainmenu_option next_comment mainmenu_option next_comment
......
...@@ -41,6 +41,7 @@ CONFIG_BLK_DEV_IDECD=y ...@@ -41,6 +41,7 @@ CONFIG_BLK_DEV_IDECD=y
# Networking options # Networking options
# #
# CONFIG_FIREWALL is not set # CONFIG_FIREWALL is not set
# CONFIG_NET_ALIAS is not set
CONFIG_INET=y CONFIG_INET=y
# CONFIG_IP_FORWARD is not set # CONFIG_IP_FORWARD is not set
# CONFIG_IP_MULTICAST is not set # CONFIG_IP_MULTICAST is not set
...@@ -122,10 +123,6 @@ CONFIG_ISO9660_FS=y ...@@ -122,10 +123,6 @@ CONFIG_ISO9660_FS=y
# CONFIG_ATIXL_BUSMOUSE is not set # CONFIG_ATIXL_BUSMOUSE is not set
# CONFIG_QIC02_TAPE is not set # CONFIG_QIC02_TAPE is not set
# CONFIG_APM is not set # CONFIG_APM is not set
# CONFIG_APM_IGNORE_USER_SUSPEND is not set
# CONFIG_APM_DO_ENABLE is not set
CONFIG_APM_CPU_IDLE=y
# CONFIG_APM_DISPLAY_BLANK is not set
# #
# Sound # Sound
......
...@@ -19,7 +19,6 @@ M_OBJS := ...@@ -19,7 +19,6 @@ M_OBJS :=
L_OBJS := tty_io.o n_tty.o console.o keyboard.o serial.o \ L_OBJS := tty_io.o n_tty.o console.o keyboard.o serial.o \
tty_ioctl.o pty.o vt.o mem.o vc_screen.o random.o \ tty_ioctl.o pty.o vt.o mem.o vc_screen.o random.o \
defkeymap.o consolemap.o selection.o defkeymap.o consolemap.o selection.o
SYMTAB_OBJS :=
ifeq ($(CONFIG_CYCLADES),y) ifeq ($(CONFIG_CYCLADES),y)
L_OBJS += cyclades.o L_OBJS += cyclades.o
...@@ -98,8 +97,7 @@ L_OBJS += tpqic02.o ...@@ -98,8 +97,7 @@ L_OBJS += tpqic02.o
endif endif
ifdef CONFIG_APM ifdef CONFIG_APM
L_OBJS += apm_bios.o LX_OBJS += apm_bios.o
SYMTAB_OBJS += apm_bios.o
endif endif
ifdef M ifdef M
......
...@@ -41,6 +41,9 @@ ...@@ -41,6 +41,9 @@
* *
* New TIOCLINUX variants added. * New TIOCLINUX variants added.
* -- mj@k332.feld.cvut.cz, 19-Nov-95 * -- mj@k332.feld.cvut.cz, 19-Nov-95
*
* Restrict vt switching via ioctl()
* -- grif@cs.ucr.edu, 5-Dec-95
*/ */
#include <linux/config.h> #include <linux/config.h>
...@@ -97,6 +100,7 @@ int last_console = 0; ...@@ -97,6 +100,7 @@ int last_console = 0;
int kmsg_redirect = 0; int kmsg_redirect = 0;
struct tty_struct * redirect = NULL; struct tty_struct * redirect = NULL;
struct wait_queue * keypress_wait = NULL; struct wait_queue * keypress_wait = NULL;
char vt_dont_switch = 0;
static void initialize_tty_struct(struct tty_struct *tty); static void initialize_tty_struct(struct tty_struct *tty);
...@@ -523,7 +527,7 @@ void complete_change_console(unsigned int new_console) ...@@ -523,7 +527,7 @@ void complete_change_console(unsigned int new_console)
{ {
unsigned char old_vc_mode; unsigned char old_vc_mode;
if (new_console == fg_console) if ((new_console == fg_console) || (vt_dont_switch))
return; return;
if (!vc_cons_allocated(new_console)) if (!vc_cons_allocated(new_console))
return; return;
...@@ -594,7 +598,7 @@ void complete_change_console(unsigned int new_console) ...@@ -594,7 +598,7 @@ void complete_change_console(unsigned int new_console)
*/ */
void change_console(unsigned int new_console) void change_console(unsigned int new_console)
{ {
if (new_console == fg_console) if ((new_console == fg_console) || (vt_dont_switch))
return; return;
if (!vc_cons_allocated(new_console)) if (!vc_cons_allocated(new_console))
return; return;
......
...@@ -5,6 +5,7 @@ ...@@ -5,6 +5,7 @@
* *
* Dynamic diacritical handling - aeb@cwi.nl - Dec 1993 * Dynamic diacritical handling - aeb@cwi.nl - Dec 1993
* Dynamic keymap and string allocation - aeb@cwi.nl - May 1994 * Dynamic keymap and string allocation - aeb@cwi.nl - May 1994
* Restrict VT switching via ioctl() - grif@cs.ucr.edu - Dec 1995
*/ */
#include <linux/types.h> #include <linux/types.h>
...@@ -28,6 +29,7 @@ ...@@ -28,6 +29,7 @@
#include "diacr.h" #include "diacr.h"
#include "selection.h" #include "selection.h"
extern char vt_dont_switch;
extern struct tty_driver console_driver; extern struct tty_driver console_driver;
#define VT_IS_IN_USE(i) (console_driver.table[i] && console_driver.table[i]->count) #define VT_IS_IN_USE(i) (console_driver.table[i] && console_driver.table[i]->count)
...@@ -1094,7 +1096,16 @@ int vt_ioctl(struct tty_struct *tty, struct file * file, ...@@ -1094,7 +1096,16 @@ int vt_ioctl(struct tty_struct *tty, struct file * file,
return i; return i;
return con_get_unimap(ct, &(ud->entry_ct), list); return con_get_unimap(ct, &(ud->entry_ct), list);
} }
case VT_LOCKSWITCH:
if (!suser())
return -EPERM;
vt_dont_switch = 1;
return 0;
case VT_UNLOCKSWITCH:
if (!suser())
return -EPERM;
vt_dont_switch = 0;
return 0;
default: default:
return -ENOIOCTLCMD; return -ENOIOCTLCMD;
} }
......
...@@ -477,7 +477,12 @@ el2_get_8390_hdr(struct device *dev, struct e8390_pkt_hdr *hdr, int ring_page) ...@@ -477,7 +477,12 @@ el2_get_8390_hdr(struct device *dev, struct e8390_pkt_hdr *hdr, int ring_page)
unsigned long hdr_start = dev->mem_start + ((ring_page - EL2_MB1_START_PG)<<8); unsigned long hdr_start = dev->mem_start + ((ring_page - EL2_MB1_START_PG)<<8);
if (dev->mem_start) { /* Use the shared memory. */ if (dev->mem_start) { /* Use the shared memory. */
#ifdef notdef
/* Officially this is what we are doing, but the readl() is faster */
memcpy_fromio(hdr, hdr_start, sizeof(struct e8390_pkt_hdr)); memcpy_fromio(hdr, hdr_start, sizeof(struct e8390_pkt_hdr));
#else
((unsigned int*)hdr)[0] = readl(hdr_start);
#endif
return; return;
} }
......
...@@ -32,8 +32,6 @@ static const char *version = ...@@ -32,8 +32,6 @@ static const char *version =
Much of this code should have been cleaned up, but every attempt Much of this code should have been cleaned up, but every attempt
has broken some clone part. has broken some clone part.
Doesn't currently work on all shared memory cards.
Sources: Sources:
The National Semiconductor LAN Databook, and the 3Com 3c503 databook. The National Semiconductor LAN Databook, and the 3Com 3c503 databook.
*/ */
...@@ -512,8 +510,9 @@ static void ei_receive(struct device *dev) ...@@ -512,8 +510,9 @@ static void ei_receive(struct device *dev)
if (rx_pkt_count > high_water_mark) if (rx_pkt_count > high_water_mark)
high_water_mark = rx_pkt_count; high_water_mark = rx_pkt_count;
/* Bug alert! Reset ENISR_OVER to avoid spurious overruns! */ /* We used to also ack ENISR_OVER here, but that would sometimes mask
outb_p(ENISR_RX+ENISR_RX_ERR+ENISR_OVER, e8390_base+EN0_ISR); a real overrun, leaving the 8390 in a stopped state with rec'vr off. */
outb_p(ENISR_RX+ENISR_RX_ERR, e8390_base+EN0_ISR);
return; return;
} }
...@@ -550,7 +549,7 @@ static void ei_rx_overrun(struct device *dev) ...@@ -550,7 +549,7 @@ static void ei_rx_overrun(struct device *dev)
/* Remove packets right away. */ /* Remove packets right away. */
ei_receive(dev); ei_receive(dev);
outb_p(0xff, e8390_base+EN0_ISR); outb_p(ENISR_OVER, e8390_base+EN0_ISR);
/* Generic 8390 insns to start up again, same as in open_8390(). */ /* Generic 8390 insns to start up again, same as in open_8390(). */
outb_p(E8390_NODMA + E8390_PAGE0 + E8390_START, e8390_base + E8390_CMD); outb_p(E8390_NODMA + E8390_PAGE0 + E8390_START, e8390_base + E8390_CMD);
outb_p(E8390_TXCONFIG, e8390_base + EN0_TXCR); /* xmit on. */ outb_p(E8390_TXCONFIG, e8390_base + EN0_TXCR); /* xmit on. */
......
...@@ -17,6 +17,19 @@ ...@@ -17,6 +17,19 @@
********************** **********************
v2.22 (95/12/08)
- IRQ is always printed as a decimal, instead of a hex number.
- Replaced most remaining printk's with BUGMSG macros.
- Moved variables for VERIFY_ACK from the Outgoing struct into
the lp struct; Outgoing is really for packet-splitting info
only.
- Simplified INTMASK handling using a memory variable to keep a
"running total."
- Tracked down more (maybe the last?) "missed IRQ" messages caused
by TX-done IRQ's occurring WHILE arcnet??_send_packet was in
progress. These were pretty obscure and mostly harmless.
- Made an actual non-ALPHA release of the thing.
v2.21 ALPHA (95/11/29) v2.21 ALPHA (95/11/29)
- "Unknown protocol ID" messages now also indicate the station - "Unknown protocol ID" messages now also indicate the station
which sent the unrecognized packet, to aid in debugging network which sent the unrecognized packet, to aid in debugging network
...@@ -146,12 +159,15 @@ ...@@ -146,12 +159,15 @@
mainly a portability fix. This will confuse autoprobe a bit, so mainly a portability fix. This will confuse autoprobe a bit, so
test that too. test that too.
- What about cards with shared memory that can be "turned off?" - What about cards with shared memory that can be "turned off?"
- NFS mount freezes after several megabytes to SOSS for DOS. (or that have none at all, like the SMC PC500longboard)
unmount/remount fixes it. Is this arcnet-specific? I don't know.
- Some newer ARCnets support promiscuous mode, supposedly. If - Some newer ARCnets support promiscuous mode, supposedly. If
someone sends me information, I'll try to implement it. someone sends me information, I'll try to implement it.
- Dump Linux 1.2 support and its ugly #ifdefs. - Dump Linux 1.2 support and its ugly #ifdefs.
- Add support for the new 1.3.x IP header cache features. - Add support for the new 1.3.x IP header cache features.
- Support printk's priority levels.
- Make arcnetE_send_packet use arcnet_prepare_tx for loading the
packet into ARCnet memory.
- Move the SKB and memory dump code into separate functions.
- ATA protocol support?? - ATA protocol support??
- Banyan VINES TCP/IP support?? - Banyan VINES TCP/IP support??
...@@ -162,17 +178,17 @@ ...@@ -162,17 +178,17 @@
Donald Becker - it didn't work :) Donald Becker - it didn't work :)
- skeleton.c v0.05 dated 11/16/93 by Donald Becker - skeleton.c v0.05 dated 11/16/93 by Donald Becker
(from Linux Kernel 1.1.45) (from Linux Kernel 1.1.45)
- RFC's 1201 and 1051 - re: TCP/IP over ARCnet
- The official ARCnet data sheets (!) thanks to Ken Cornetet - The official ARCnet data sheets (!) thanks to Ken Cornetet
<kcornete@nyx10.cs.du.edu> <kcornete@nyx10.cs.du.edu>
- RFC's 1201 and 1051 - re: TCP/IP over ARCnet - net/inet/eth.c (from kernel 1.1.50) for header-building info.
- net/inet/eth.c (from kernel 1.1.50) for header-building info...
- Alternate Linux ARCnet source by V.Shergin <vsher@sao.stavropol.su> - Alternate Linux ARCnet source by V.Shergin <vsher@sao.stavropol.su>
- Textual information and more alternate source from Joachim Koenig - Textual information and more alternate source from Joachim Koenig
<jojo@repas.de> <jojo@repas.de>
*/ */
static const char *version = static const char *version =
"arcnet.c: v2.21 ALPHA 95/11/29 Avery Pennarun <apenwarr@foxnet.net>\n"; "arcnet.c: v2.22 95/12/08 Avery Pennarun <apenwarr@foxnet.net>\n";
...@@ -368,6 +384,8 @@ extern struct device *irq2dev_map[16]; ...@@ -368,6 +384,8 @@ extern struct device *irq2dev_map[16];
#define COMMAND (ioaddr+1) /* writable, returns random vals on read (?) */ #define COMMAND (ioaddr+1) /* writable, returns random vals on read (?) */
#define RESET (ioaddr+8) /* software reset writable */ #define RESET (ioaddr+8) /* software reset writable */
#define SETMASK outb(lp->intmask,INTMASK);
/* Time needed for various things (in clock ticks, 1/100 sec) */ /* Time needed for various things (in clock ticks, 1/100 sec) */
/* We mostly don't bother with these - watch out. */ /* We mostly don't bother with these - watch out. */
#define RESETtime 40 /* reset */ #define RESETtime 40 /* reset */
...@@ -396,12 +414,6 @@ extern struct device *irq2dev_map[16]; ...@@ -396,12 +414,6 @@ extern struct device *irq2dev_map[16];
#define RES2flag 0x40 /* unused */ #define RES2flag 0x40 /* unused */
#define NORXflag 0x80 /* receiver inhibited */ #define NORXflag 0x80 /* receiver inhibited */
#ifdef DETECT_RECONFIGS
#define RECON_flag RECONflag
#else
#define RECON_flag 0
#endif
/* in the command register, the following bits have these meanings: /* in the command register, the following bits have these meanings:
* 0-2 command * 0-2 command
* 3-4 page number (for enable rcv/xmt command) * 3-4 page number (for enable rcv/xmt command)
...@@ -530,26 +542,26 @@ struct Outgoing ...@@ -530,26 +542,26 @@ struct Outgoing
segnum, /* segment being sent */ segnum, /* segment being sent */
numsegs, /* number of segments */ numsegs, /* number of segments */
seglen; /* length of segment */ seglen; /* length of segment */
#ifdef VERIFY_ACK
short lastload_dest, /* can last loaded packet be acked? */
lasttrans_dest; /* can last TX'd packet be acked? */
#endif
}; };
/* Information that needs to be kept for each board. */ /* Information that needs to be kept for each board. */
struct arcnet_local { struct arcnet_local {
struct enet_statistics stats; struct enet_statistics stats;
u_char arcnum; /* arcnet number - our 8-bit address */
u_short sequence; /* sequence number (incs with each packet) */ u_short sequence; /* sequence number (incs with each packet) */
u_char recbuf, /* receive buffer # (0 or 1) */ u_char stationid, /* our 8-bit station address */
recbuf, /* receive buffer # (0 or 1) */
txbuf, /* transmit buffer # (2 or 3) */ txbuf, /* transmit buffer # (2 or 3) */
txready; /* buffer where a packet is ready to send */ txready, /* buffer where a packet is ready to send */
intmask; /* current value of INTMASK register */
short intx, /* in TX routine? */ short intx, /* in TX routine? */
in_txhandler, /* in TX_IRQ handler? */ in_txhandler, /* in TX_IRQ handler? */
sending; /* transmit in progress? */ sending; /* transmit in progress? */
short tx_left; /* segments of split packet left to TX */
#ifdef VERIFY_ACK
short lastload_dest, /* can last loaded packet be acked? */
lasttrans_dest; /* can last TX'd packet be acked? */
#endif
#if defined(DETECT_RECONFIGS) && defined(RECON_THRESHOLD) #if defined(DETECT_RECONFIGS) && defined(RECON_THRESHOLD)
time_t first_recon, /* time of "first" RECON message to count */ time_t first_recon, /* time of "first" RECON message to count */
...@@ -685,7 +697,7 @@ arcnet_probe(struct device *dev) ...@@ -685,7 +697,7 @@ arcnet_probe(struct device *dev)
printk(version); printk(version);
#if 1 #if 0
BUGLVL(D_NORMAL) BUGLVL(D_NORMAL)
{ {
printk("arcnet: ***\n"); printk("arcnet: ***\n");
...@@ -696,7 +708,7 @@ arcnet_probe(struct device *dev) ...@@ -696,7 +708,7 @@ arcnet_probe(struct device *dev)
printk("arcnet: ***\n"); printk("arcnet: ***\n");
} }
#else #else
BUGLVL(D_INIT) BUGLVL(D_EXTRA)
{ {
printk("arcnet: ***\n"); printk("arcnet: ***\n");
printk("arcnet: * Read README.arcnet for important release notes!\n"); printk("arcnet: * Read README.arcnet for important release notes!\n");
...@@ -707,7 +719,7 @@ arcnet_probe(struct device *dev) ...@@ -707,7 +719,7 @@ arcnet_probe(struct device *dev)
} }
#endif #endif
BUGMSG(D_INIT,"given: base %lXh, IRQ %Xh, shmem %lXh\n", BUGMSG(D_INIT,"given: base %lXh, IRQ %d, shmem %lXh\n",
dev->base_addr,dev->irq,dev->mem_start); dev->base_addr,dev->irq,dev->mem_start);
#ifndef MODULE #ifndef MODULE
...@@ -758,11 +770,9 @@ arcnet_probe(struct device *dev) ...@@ -758,11 +770,9 @@ arcnet_probe(struct device *dev)
if (!dev->base_addr || !dev->irq || !dev->mem_start if (!dev->base_addr || !dev->irq || !dev->mem_start
|| !dev->rmem_start) || !dev->rmem_start)
{ {
printk("%6s: loadable modules can't autoprobe!\n",dev->name); BUGMSG(D_NORMAL,"loadable modules can't autoprobe!\n");
printk("%6s: try using io=, irqnum=, and shmem= on the insmod line.\n", BUGMSG(D_NORMAL,"try using io=, irqnum=, and shmem= on the insmod line.\n");
dev->name); BUGMSG(D_NORMAL,"you may also need num= to change the device name. (ie. num=1 for arc1)\n");
printk("%6s: you may also need num= to change the device name. (ie. num=1 for arc1)\n",
dev->name);
return ENODEV; return ENODEV;
} }
#endif #endif
...@@ -771,8 +781,8 @@ arcnet_probe(struct device *dev) ...@@ -771,8 +781,8 @@ arcnet_probe(struct device *dev)
int irqval = request_irq(dev->irq, &arcnet_interrupt, 0, int irqval = request_irq(dev->irq, &arcnet_interrupt, 0,
"arcnet"); "arcnet");
if (irqval) { if (irqval) {
printk("%6s: unable to get IRQ %d (irqval=%d).\n", BUGMSG(D_NORMAL,"unable to get IRQ %d (irqval=%d).\n",
dev->name,dev->irq, irqval); dev->irq, irqval);
return EAGAIN; return EAGAIN;
} }
...@@ -782,8 +792,8 @@ arcnet_probe(struct device *dev) ...@@ -782,8 +792,8 @@ arcnet_probe(struct device *dev)
/* Grab the region so we can find another board if autoIRQ fails. */ /* Grab the region so we can find another board if autoIRQ fails. */
request_region(dev->base_addr, ARCNET_TOTAL_SIZE,"arcnet"); request_region(dev->base_addr, ARCNET_TOTAL_SIZE,"arcnet");
printk("%6s: ARCnet card found at %03lXh, IRQ %d, ShMem at %lXh.\n", BUGMSG(D_NORMAL,"ARCnet card found at %03lXh, IRQ %d, ShMem at %lXh.\n",
dev->name, dev->base_addr, dev->irq, dev->mem_start); dev->base_addr, dev->irq, dev->mem_start);
/* Initialize the device structure. */ /* Initialize the device structure. */
dev->priv = kmalloc(sizeof(struct arcnet_local), GFP_KERNEL); dev->priv = kmalloc(sizeof(struct arcnet_local), GFP_KERNEL);
...@@ -819,14 +829,12 @@ arcnet_probe(struct device *dev) ...@@ -819,14 +829,12 @@ arcnet_probe(struct device *dev)
arcnet_reset(dev); arcnet_reset(dev);
JIFFER(50); JIFFER(50);
BUGMSG(D_NORMAL,"We appear to be station %d (%02Xh)\n", BUGMSG(D_NORMAL,"We appear to be station %d (%02Xh)\n",
lp->arcnum,lp->arcnum); lp->stationid,lp->stationid);
if (lp->arcnum==0) if (lp->stationid==0)
printk("%6s: WARNING! Station address 0 is reserved for broadcasts!\n", BUGMSG(D_NORMAL,"WARNING! Station address 0 is reserved for broadcasts!\n");
dev->name); if (lp->stationid==255)
if (lp->arcnum==255) BUGMSG(D_NORMAL,"WARNING! Station address 255 may confuse DOS networking programs!\n");
printk("%6s: WARNING! Station address 255 may confuse DOS networking programs!\n", dev->dev_addr[0]=lp->stationid;
dev->name);
dev->dev_addr[0]=lp->arcnum;
lp->sequence=1; lp->sequence=1;
lp->recbuf=0; lp->recbuf=0;
...@@ -907,9 +915,6 @@ int arcnet_ioprobe(struct device *dev, short ioaddr) ...@@ -907,9 +915,6 @@ int arcnet_ioprobe(struct device *dev, short ioaddr)
/* if we do this, we're sure to get an IRQ since the card has /* if we do this, we're sure to get an IRQ since the card has
* just reset and the NORXflag is on until we tell it to start * just reset and the NORXflag is on until we tell it to start
* receiving. * receiving.
*
* However, this could, theoretically, cause a lockup. Maybe I'm just
* not very good at theory! :)
*/ */
outb(NORXflag,INTMASK); outb(NORXflag,INTMASK);
JIFFER(RESETtime); JIFFER(RESETtime);
...@@ -919,8 +924,8 @@ int arcnet_ioprobe(struct device *dev, short ioaddr) ...@@ -919,8 +924,8 @@ int arcnet_ioprobe(struct device *dev, short ioaddr)
outb(CFLAGScmd|RESETclear|CONFIGclear,COMMAND); outb(CFLAGScmd|RESETclear|CONFIGclear,COMMAND);
airq = autoirq_report(0); airq = autoirq_report(0);
BUGLVL(D_INIT) if (airq) if (airq)
printk("%6s: autoirq is %d\n", dev->name, airq); BUGMSG(D_INIT," autoirq is %d\n", airq);
/* if there was no autoirq AND the user hasn't set any defaults, /* if there was no autoirq AND the user hasn't set any defaults,
* give up. * give up.
...@@ -1014,7 +1019,8 @@ int arcnet_reset(struct device *dev) ...@@ -1014,7 +1019,8 @@ int arcnet_reset(struct device *dev)
int delayval,recbuf=lp->recbuf; int delayval,recbuf=lp->recbuf;
u_char *cardmem; u_char *cardmem;
outb(0,INTMASK); /* no IRQ's, please! */ lp->intmask=0;
SETMASK; /* no IRQ's, please! */
BUGMSG(D_INIT,"Resetting %s (status=%Xh)\n", BUGMSG(D_INIT,"Resetting %s (status=%Xh)\n",
dev->name,inb(STATUS)); dev->name,inb(STATUS));
...@@ -1034,7 +1040,7 @@ int arcnet_reset(struct device *dev) ...@@ -1034,7 +1040,7 @@ int arcnet_reset(struct device *dev)
BUGMSG(D_INIT,"reset failed: TESTvalue not present.\n"); BUGMSG(D_INIT,"reset failed: TESTvalue not present.\n");
return 1; return 1;
} }
lp->arcnum=cardmem[1]; /* save address for later use */ lp->stationid=cardmem[1]; /* save address for later use */
/* clear out status variables */ /* clear out status variables */
recbuf=lp->recbuf=0; recbuf=lp->recbuf=0;
...@@ -1051,7 +1057,11 @@ int arcnet_reset(struct device *dev) ...@@ -1051,7 +1057,11 @@ int arcnet_reset(struct device *dev)
EnableReceiver(); EnableReceiver();
/* re-enable interrupts */ /* re-enable interrupts */
outb(NORXflag|RECON_flag,INTMASK); lp->intmask|=NORXflag;
#ifdef DETECT_RECONFIGS
lp->intmask|=RECONflag;
#endif
SETMASK;
/* done! return success. */ /* done! return success. */
return 0; return 0;
...@@ -1094,7 +1104,7 @@ static int arcnetE_init(struct device *dev) ...@@ -1094,7 +1104,7 @@ static int arcnetE_init(struct device *dev)
ether_setup(dev); /* we're emulating ether here, not ARCnet */ ether_setup(dev); /* we're emulating ether here, not ARCnet */
dev->dev_addr[0]=0; dev->dev_addr[0]=0;
dev->dev_addr[5]=lp->arcnum; dev->dev_addr[5]=lp->stationid;
dev->mtu=512-sizeof(struct HardHeader)-dev->hard_header_len-1; dev->mtu=512-sizeof(struct HardHeader)-dev->hard_header_len-1;
dev->open=NULL; dev->open=NULL;
dev->stop=NULL; dev->stop=NULL;
...@@ -1114,7 +1124,7 @@ static int arcnetS_init(struct device *dev) ...@@ -1114,7 +1124,7 @@ static int arcnetS_init(struct device *dev)
arcnet_setup(dev); arcnet_setup(dev);
/* And now fill particular fields with arcnet values */ /* And now fill particular fields with arcnet values */
dev->dev_addr[0]=lp->arcnum; dev->dev_addr[0]=lp->stationid;
dev->hard_header_len=sizeof(struct S_ClientData); dev->hard_header_len=sizeof(struct S_ClientData);
dev->mtu=512-sizeof(struct HardHeader)-dev->hard_header_len dev->mtu=512-sizeof(struct HardHeader)-dev->hard_header_len
+ S_EXTRA_CLIENTDATA; + S_EXTRA_CLIENTDATA;
...@@ -1204,11 +1214,11 @@ arcnet_open(struct device *dev) ...@@ -1204,11 +1214,11 @@ arcnet_open(struct device *dev)
/* make sure we're ready to receive IRQ's. /* make sure we're ready to receive IRQ's.
* arcnet_reset sets this for us, but if we receive one before * arcnet_reset sets this for us, but if we receive one before
* START is set to 1, bad things happen. * START is set to 1, it could be ignored.
*/ */
outb(0,INTMASK); outb(0,INTMASK);
JIFFER(ACKtime); JIFFER(ACKtime);
outb(NORXflag|RECON_flag,INTMASK); SETMASK;
MOD_INC_USE_COUNT; MOD_INC_USE_COUNT;
return 0; return 0;
...@@ -1227,7 +1237,8 @@ arcnet_close(struct device *dev) ...@@ -1227,7 +1237,8 @@ arcnet_close(struct device *dev)
START=0; START=0;
/* Flush TX and disable RX */ /* Flush TX and disable RX */
outb(0,INTMASK); /* no IRQ's (except RESET, of course) */ lp->intmask=0;
SETMASK; /* no IRQ's (except RESET, of course) */
outb(NOTXcmd,COMMAND); /* stop transmit */ outb(NOTXcmd,COMMAND); /* stop transmit */
outb(NORXcmd,COMMAND); /* disable receive */ outb(NORXcmd,COMMAND); /* disable receive */
...@@ -1309,20 +1320,21 @@ arcnet_send_packet_bad(struct sk_buff *skb, struct device *dev) ...@@ -1309,20 +1320,21 @@ arcnet_send_packet_bad(struct sk_buff *skb, struct device *dev)
return 1; return 1;
} }
outb(0,INTMASK); lp->intmask &= ~TXFREEflag;
SETMASK;
if (status&TXFREEflag) /* transmit _DID_ finish */ if (status&TXFREEflag) /* transmit _DID_ finish */
{ {
BUGMSG(D_EXTRA,"tx timed out - missed IRQ? (status=%Xh, inTX=%d, inTXh=%d, tickssofar=%d)\n", BUGMSG(D_NORMAL,"tx timeout - missed IRQ? (status=%Xh, inTXh=%d, ticks=%d, mask=%Xh)\n",
status,lp->intx, status,lp->in_txhandler,tickssofar,
lp->in_txhandler,tickssofar); lp->intmask);
lp->stats.tx_errors++; lp->stats.tx_errors++;
} }
else else
{ {
BUGMSG(D_NORMAL,"tx timed out (status=%Xh, inTX=%d, inTXh=%d, tickssofar=%d)\n", BUGMSG(D_NORMAL,"tx timed out (status=%Xh, inTXh=%d, tickssofar=%d, intmask=%Xh)\n",
status,lp->intx, status,lp->in_txhandler,tickssofar,
lp->in_txhandler,tickssofar); lp->intmask);
lp->stats.tx_errors++; lp->stats.tx_errors++;
lp->stats.tx_aborted_errors++; lp->stats.tx_aborted_errors++;
...@@ -1340,8 +1352,6 @@ arcnet_send_packet_bad(struct sk_buff *skb, struct device *dev) ...@@ -1340,8 +1352,6 @@ arcnet_send_packet_bad(struct sk_buff *skb, struct device *dev)
lp->txready=0; lp->txready=0;
lp->sending=0; lp->sending=0;
outb(NORXflag|RECON_flag,INTMASK);
return 1; return 1;
} }
...@@ -1349,8 +1359,8 @@ arcnet_send_packet_bad(struct sk_buff *skb, struct device *dev) ...@@ -1349,8 +1359,8 @@ arcnet_send_packet_bad(struct sk_buff *skb, struct device *dev)
we are passed NULL. Caution: dev_tint() handles the cli()/sti() we are passed NULL. Caution: dev_tint() handles the cli()/sti()
itself. */ itself. */
if (skb == NULL) { if (skb == NULL) {
printk("%6s: tx passed null skb (status=%Xh, inTX=%d, tickssofar=%ld)\n", BUGMSG(D_NORMAL,"tx passed null skb (status=%Xh, inTX=%d, tickssofar=%ld)\n",
dev->name,inb(STATUS),lp->intx,jiffies-dev->trans_start); inb(STATUS),lp->intx,jiffies-dev->trans_start);
lp->stats.tx_errors++; lp->stats.tx_errors++;
dev_tint(dev); dev_tint(dev);
return 0; return 0;
...@@ -1358,9 +1368,10 @@ arcnet_send_packet_bad(struct sk_buff *skb, struct device *dev) ...@@ -1358,9 +1368,10 @@ arcnet_send_packet_bad(struct sk_buff *skb, struct device *dev)
if (lp->txready) /* transmit already in progress! */ if (lp->txready) /* transmit already in progress! */
{ {
printk("%6s: trying to start new packet while busy! (status=%Xh)\n", BUGMSG(D_NORMAL,"trying to start new packet while busy! (status=%Xh)\n",
dev->name,inb(STATUS)); inb(STATUS));
outb(0,INTMASK); lp->intmask &= ~TXFREEflag;
SETMASK;
outb(NOTXcmd,COMMAND); /* abort current send */ outb(NOTXcmd,COMMAND); /* abort current send */
arcnet_inthandler(dev); /* fake an interrupt */ arcnet_inthandler(dev); /* fake an interrupt */
lp->stats.tx_errors++; lp->stats.tx_errors++;
...@@ -1374,8 +1385,8 @@ arcnet_send_packet_bad(struct sk_buff *skb, struct device *dev) ...@@ -1374,8 +1385,8 @@ arcnet_send_packet_bad(struct sk_buff *skb, struct device *dev)
done with atomic_swap(1, dev->tbusy), but set_bit() works as well. */ done with atomic_swap(1, dev->tbusy), but set_bit() works as well. */
if (set_bit(0, (void*)&dev->tbusy) != 0) if (set_bit(0, (void*)&dev->tbusy) != 0)
{ {
printk("%6s: transmitter called with busy bit set! (status=%Xh, inTX=%d, tickssofar=%ld)\n", BUGMSG(D_NORMAL,"transmitter called with busy bit set! (status=%Xh, inTX=%d, tickssofar=%ld)\n",
dev->name,inb(STATUS),lp->intx,jiffies-dev->trans_start); inb(STATUS),lp->intx,jiffies-dev->trans_start);
lp->stats.tx_errors++; lp->stats.tx_errors++;
lp->stats.tx_fifo_errors++; lp->stats.tx_fifo_errors++;
return -EBUSY; return -EBUSY;
...@@ -1394,9 +1405,6 @@ arcnetA_send_packet(struct sk_buff *skb, struct device *dev) ...@@ -1394,9 +1405,6 @@ arcnetA_send_packet(struct sk_buff *skb, struct device *dev)
int ioaddr=dev->base_addr,bad; int ioaddr=dev->base_addr,bad;
struct Outgoing *out=&(lp->outgoing); struct Outgoing *out=&(lp->outgoing);
BUGMSG(D_DURING,"transmit requested (status=%Xh, inTX=%d)\n",
inb(STATUS),lp->intx);
lp->intx++; lp->intx++;
bad=arcnet_send_packet_bad(skb,dev); bad=arcnet_send_packet_bad(skb,dev);
...@@ -1415,9 +1423,9 @@ arcnetA_send_packet(struct sk_buff *skb, struct device *dev) ...@@ -1415,9 +1423,9 @@ arcnetA_send_packet(struct sk_buff *skb, struct device *dev)
BUGLVL(D_SKB) BUGLVL(D_SKB)
{ {
short i; short i;
for( i=0; i< skb->len; i++) for(i=0; i<skb->len; i++)
{ {
if( i%16 == 0 ) printk("\n[%04hX] ",i); if(i%16 == 0) printk("\n[%04hX] ",i);
printk("%02hX ",((unsigned char*)skb->data)[i]); printk("%02hX ",((unsigned char*)skb->data)[i]);
} }
printk("\n"); printk("\n");
...@@ -1425,16 +1433,14 @@ arcnetA_send_packet(struct sk_buff *skb, struct device *dev) ...@@ -1425,16 +1433,14 @@ arcnetA_send_packet(struct sk_buff *skb, struct device *dev)
out->hdr->sequence=(lp->sequence++); out->hdr->sequence=(lp->sequence++);
/*arcnet_go_tx(dev);*/ /* Make sure buffers are clear */
/* fits in one packet? */ /* fits in one packet? */
if (out->length-EXTRA_CLIENTDATA<=XMTU) if (out->length-EXTRA_CLIENTDATA<=XMTU)
{ {
BUGMSG(D_DURING,"not splitting %d-byte packet. (split_flag=%d)\n", BUGMSG(D_DURING,"not splitting %d-byte packet. (split_flag=%d)\n",
out->length,out->hdr->split_flag); out->length,out->hdr->split_flag);
BUGLVL(D_EXTRA) if (out->hdr->split_flag) if (out->hdr->split_flag)
printk("%6s: short packet has split_flag set?! (split_flag=%d)\n", BUGMSG(D_NORMAL,"short packet has split_flag set?! (split_flag=%d)\n",
dev->name,out->hdr->split_flag); out->hdr->split_flag);
out->numsegs=1; out->numsegs=1;
out->segnum=1; out->segnum=1;
arcnetAS_prepare_tx(dev, arcnetAS_prepare_tx(dev,
...@@ -1463,7 +1469,6 @@ arcnetA_send_packet(struct sk_buff *skb, struct device *dev) ...@@ -1463,7 +1469,6 @@ arcnetA_send_packet(struct sk_buff *skb, struct device *dev)
+ sizeof(struct ClientData); + sizeof(struct ClientData);
out->dataleft=out->length-sizeof(struct ClientData); out->dataleft=out->length-sizeof(struct ClientData);
out->numsegs=(out->dataleft+maxsegsize-1)/maxsegsize; out->numsegs=(out->dataleft+maxsegsize-1)/maxsegsize;
out->segnum=0; out->segnum=0;
BUGMSG(D_TX,"packet (%d bytes) split into %d fragments:\n", BUGMSG(D_TX,"packet (%d bytes) split into %d fragments:\n",
...@@ -1500,6 +1505,11 @@ arcnetA_send_packet(struct sk_buff *skb, struct device *dev) ...@@ -1500,6 +1505,11 @@ arcnetA_send_packet(struct sk_buff *skb, struct device *dev)
dev->trans_start=jiffies; dev->trans_start=jiffies;
lp->intx--; lp->intx--;
/* make sure we didn't ignore a TX IRQ while we were in here */
lp->intmask |= TXFREEflag;
SETMASK;
return 0; return 0;
} }
...@@ -1510,14 +1520,12 @@ static int ...@@ -1510,14 +1520,12 @@ static int
arcnetE_send_packet(struct sk_buff *skb, struct device *dev) arcnetE_send_packet(struct sk_buff *skb, struct device *dev)
{ {
struct arcnet_local *lp = (struct arcnet_local *)dev->priv; struct arcnet_local *lp = (struct arcnet_local *)dev->priv;
int bad; int ioaddr=dev->base_addr,bad;
union ArcPacket *arcpacket = union ArcPacket *arcpacket =
(union ArcPacket *)(dev->mem_start+512*(lp->txbuf^1)); (union ArcPacket *)(dev->mem_start+512*(lp->txbuf^1));
u_char *arcsoft,daddr; u_char *arcsoft,daddr;
short offset,length=skb->len+1; short offset,length=skb->len+1;
BUGMSG(D_DURING,"in arcnetE_send_packet (skb=%p)\n",skb);
lp->intx++; lp->intx++;
bad=arcnet_send_packet_bad(skb,dev); bad=arcnet_send_packet_bad(skb,dev);
...@@ -1531,11 +1539,12 @@ arcnetE_send_packet(struct sk_buff *skb, struct device *dev) ...@@ -1531,11 +1539,12 @@ arcnetE_send_packet(struct sk_buff *skb, struct device *dev)
if (length>XMTU) if (length>XMTU)
{ {
printk("%6s: MTU must be <= 493 for ethernet encap (length=%d).\n", BUGMSG(D_NORMAL,"MTU must be <= 493 for ethernet encap (length=%d).\n",
dev->name,length); length);
printk("%6s: transmit aborted.\n",dev->name); BUGMSG(D_NORMAL,"transmit aborted.\n");
dev_kfree_skb(skb,FREE_WRITE); dev_kfree_skb(skb,FREE_WRITE);
lp->intx--;
return 0; return 0;
} }
...@@ -1603,7 +1612,7 @@ arcnetE_send_packet(struct sk_buff *skb, struct device *dev) ...@@ -1603,7 +1612,7 @@ arcnetE_send_packet(struct sk_buff *skb, struct device *dev)
} }
#ifdef VERIFY_ACK #ifdef VERIFY_ACK
lp->outgoing.lastload_dest=daddr; lp->lastload_dest=daddr;
#endif #endif
lp->txready=lp->txbuf; /* packet is ready for sending */ lp->txready=lp->txbuf; /* packet is ready for sending */
...@@ -1618,6 +1627,11 @@ arcnetE_send_packet(struct sk_buff *skb, struct device *dev) ...@@ -1618,6 +1627,11 @@ arcnetE_send_packet(struct sk_buff *skb, struct device *dev)
dev->trans_start=jiffies; dev->trans_start=jiffies;
lp->intx--; lp->intx--;
/* make sure we didn't ignore a TX IRQ while we were in here */
lp->intmask |= TXFREEflag;
SETMASK;
return 0; return 0;
} }
...@@ -1633,9 +1647,6 @@ arcnetS_send_packet(struct sk_buff *skb, struct device *dev) ...@@ -1633,9 +1647,6 @@ arcnetS_send_packet(struct sk_buff *skb, struct device *dev)
lp->intx++; lp->intx++;
BUGMSG(D_DURING,"transmit requested (status=%Xh, inTX=%d)\n",
inb(STATUS),lp->intx);
bad=arcnet_send_packet_bad(skb,dev); bad=arcnet_send_packet_bad(skb,dev);
if (bad) if (bad)
{ {
...@@ -1652,15 +1663,12 @@ arcnetS_send_packet(struct sk_buff *skb, struct device *dev) ...@@ -1652,15 +1663,12 @@ arcnetS_send_packet(struct sk_buff *skb, struct device *dev)
short i; short i;
for(i=0; i<skb->len; i++) for(i=0; i<skb->len; i++)
{ {
if( i%16 == 0 ) printk("\n[%04hX] ",i); if (i%16 == 0) printk("\n[%04hX] ",i);
printk("%02hX ",((unsigned char*)skb->data)[i]); printk("%02hX ",((unsigned char*)skb->data)[i]);
} }
printk("\n"); printk("\n");
} }
/*if (lp->txready && inb(STATUS)&TXFREEflag)
arcnet_go_tx(dev);*/
/* fits in one packet? */ /* fits in one packet? */
if (length-S_EXTRA_CLIENTDATA<=XMTU) if (length-S_EXTRA_CLIENTDATA<=XMTU)
{ {
...@@ -1683,7 +1691,7 @@ arcnetS_send_packet(struct sk_buff *skb, struct device *dev) ...@@ -1683,7 +1691,7 @@ arcnetS_send_packet(struct sk_buff *skb, struct device *dev)
} }
else /* too big for one - not accepted */ else /* too big for one - not accepted */
{ {
printk("arcnetS: packet too long (length=%d)\n", BUGMSG(D_NORMAL,"packet too long (length=%d)\n",
length); length);
dev_kfree_skb(skb,FREE_WRITE); dev_kfree_skb(skb,FREE_WRITE);
lp->stats.tx_dropped++; lp->stats.tx_dropped++;
...@@ -1693,6 +1701,11 @@ arcnetS_send_packet(struct sk_buff *skb, struct device *dev) ...@@ -1693,6 +1701,11 @@ arcnetS_send_packet(struct sk_buff *skb, struct device *dev)
dev->trans_start=jiffies; dev->trans_start=jiffies;
lp->intx--; lp->intx--;
/* make sure we didn't ignore a TX IRQ while we were in here */
lp->intmask |= TXFREEflag;
SETMASK;
return 0; return 0;
} }
...@@ -1704,20 +1717,22 @@ arcnetS_send_packet(struct sk_buff *skb, struct device *dev) ...@@ -1704,20 +1717,22 @@ arcnetS_send_packet(struct sk_buff *skb, struct device *dev)
static void arcnetA_continue_tx(struct device *dev) static void arcnetA_continue_tx(struct device *dev)
{ {
struct arcnet_local *lp = (struct arcnet_local *)dev->priv; struct arcnet_local *lp = (struct arcnet_local *)dev->priv;
int maxsegsize=XMTU-4; int ioaddr=dev->base_addr,maxsegsize=XMTU-4;
struct Outgoing *out=&(lp->outgoing); struct Outgoing *out=&(lp->outgoing);
BUGMSG(D_DURING,"continue_tx called (status=%Xh, intx=%d, intxh=%d, intmask=%Xh\n",
inb(STATUS),lp->intx,lp->in_txhandler,lp->intmask);
if (lp->txready) if (lp->txready)
{ {
printk("%6s: continue_tx: called with packet in buffer!\n", BUGMSG(D_NORMAL,"continue_tx: called with packet in buffer!\n");
dev->name);
return; return;
} }
if (out->segnum>=out->numsegs) if (out->segnum>=out->numsegs)
{ {
printk("%6s: continue_tx: building segment %d of %d!\n", BUGMSG(D_NORMAL,"continue_tx: building segment %d of %d!\n",
dev->name,out->segnum+1,out->numsegs); out->segnum+1,out->numsegs);
} }
if (!out->segnum) /* first packet */ if (!out->segnum) /* first packet */
...@@ -1840,13 +1855,20 @@ arcnetAS_prepare_tx(struct device *dev,u_char *hdr,int hdrlen, ...@@ -1840,13 +1855,20 @@ arcnetAS_prepare_tx(struct device *dev,u_char *hdr,int hdrlen,
} }
#ifdef VERIFY_ACK #ifdef VERIFY_ACK
lp->outgoing.lastload_dest=daddr; lp->lastload_dest=daddr;
#endif #endif
lp->txready=lp->txbuf; /* packet is ready for sending */ lp->txready=lp->txbuf; /* packet is ready for sending */
} }
/* Actually start transmitting a packet that was placed in the card's /* Actually start transmitting a packet that was placed in the card's
* buffer by arcnetAS_prepare_tx. Returns 1 if a Tx is really started. * buffer by arcnetAS_prepare_tx. Returns 1 if a Tx is really started.
*
* This should probably always be called with the INTMASK register set to 0,
* so go_tx is not called recursively.
*
* The enable_irq flag determines whether to actually write INTMASK value
* to the card; TXFREEflag is always OR'ed into the memory variable either
* way.
*/ */
static int static int
arcnet_go_tx(struct device *dev,int enable_irq) arcnet_go_tx(struct device *dev,int enable_irq)
...@@ -1854,19 +1876,15 @@ arcnet_go_tx(struct device *dev,int enable_irq) ...@@ -1854,19 +1876,15 @@ arcnet_go_tx(struct device *dev,int enable_irq)
struct arcnet_local *lp=(struct arcnet_local *)dev->priv; struct arcnet_local *lp=(struct arcnet_local *)dev->priv;
int ioaddr=dev->base_addr; int ioaddr=dev->base_addr;
BUGMSG(D_DURING,"go_tx: status=%Xh\n", BUGMSG(D_DURING,"go_tx: status=%Xh, intmask=%Xh, txready=%d, sending=%d\n",
inb(STATUS)); inb(STATUS),lp->intmask,lp->txready,lp->sending);
outb(0,INTMASK);
if (lp->sending || !lp->txready) if (lp->sending || !lp->txready)
{ {
if (enable_irq) if (enable_irq && lp->sending)
{ {
if (lp->sending) lp->intmask |= TXFREEflag;
outb(TXFREEflag|NORXflag|RECON_flag,INTMASK); SETMASK;
else
outb(NORXflag|RECON_flag,INTMASK);
} }
return 0; return 0;
} }
...@@ -1879,12 +1897,13 @@ arcnet_go_tx(struct device *dev,int enable_irq) ...@@ -1879,12 +1897,13 @@ arcnet_go_tx(struct device *dev,int enable_irq)
lp->sending++; lp->sending++;
#ifdef VERIFY_ACK #ifdef VERIFY_ACK
lp->outgoing.lasttrans_dest=lp->outgoing.lastload_dest; lp->lasttrans_dest=lp->lastload_dest;
lp->outgoing.lastload_dest=0; lp->lastload_dest=0;
#endif #endif
if (enable_irq) lp->intmask |= TXFREEflag;
outb(TXFREEflag|NORXflag|RECON_flag,INTMASK);
if (enable_irq) SETMASK;
return 1; return 1;
} }
...@@ -1933,38 +1952,21 @@ arcnet_inthandler(struct device *dev) ...@@ -1933,38 +1952,21 @@ arcnet_inthandler(struct device *dev)
if (IF_INTERRUPT) if (IF_INTERRUPT)
{ {
printk("%6s: DRIVER PROBLEM! Nested arcnet interrupts!\n", BUGMSG(D_NORMAL,"DRIVER PROBLEM! Nested arcnet interrupts!\n");
dev->name);
return; /* don't even try. */ return; /* don't even try. */
} }
outb(0,INTMASK); outb(0,INTMASK);
INTERRUPT = 1; INTERRUPT = 1;
BUGMSG(D_DURING,"in arcnet_inthandler (status=%Xh)\n",inb(STATUS)); BUGMSG(D_DURING,"in arcnet_inthandler (status=%Xh, intmask=%Xh)\n",
inb(STATUS),lp->intmask);
#if 1 /* Whatever you do, don't set this to 0. */
do do
{ {
status = inb(STATUS); status = inb(STATUS);
didsomething=0; didsomething=0;
#if 0 /* no longer necessary - doing checking in arcnet_interrupt now */
if (!dev->start)
{
BUGMSG(D_DURING,"ARCnet not yet initialized. irq ignored. (status=%Xh)\n",
status);
if (!(status&NORXflag))
outb(NORXflag|RECON_flag,INTMASK);
/* using dev->interrupt here instead of INTERRUPT
* because if dev->start is 0, the other devices
* probably do not exist.
*/
dev->interrupt=0;
return;
}
#endif
/* RESET flag was enabled - card is resetting and if RX /* RESET flag was enabled - card is resetting and if RX
* is disabled, it's NOT because we just got a packet. * is disabled, it's NOT because we just got a packet.
*/ */
...@@ -1975,7 +1977,7 @@ arcnet_inthandler(struct device *dev) ...@@ -1975,7 +1977,7 @@ arcnet_inthandler(struct device *dev)
status); status);
} }
#ifdef DETECT_RECONFIGS #ifdef DETECT_RECONFIGS
if (status & RECONflag) if (status & (lp->intmask) & RECONflag)
{ {
outb(CFLAGScmd|CONFIGclear,COMMAND); outb(CFLAGScmd|CONFIGclear,COMMAND);
lp->stats.tx_carrier_errors++; lp->stats.tx_carrier_errors++;
...@@ -1991,8 +1993,7 @@ arcnet_inthandler(struct device *dev) ...@@ -1991,8 +1993,7 @@ arcnet_inthandler(struct device *dev)
jiffies-lp->last_recon > HZ*10) jiffies-lp->last_recon > HZ*10)
{ {
if (lp->network_down) if (lp->network_down)
printk("%6s: reconfiguration detected: cabling restored?\n", BUGMSG(D_NORMAL,"reconfiguration detected: cabling restored?\n");
dev->name);
lp->first_recon=lp->last_recon=jiffies; lp->first_recon=lp->last_recon=jiffies;
lp->num_recons=lp->network_down=0; lp->num_recons=lp->network_down=0;
...@@ -2020,8 +2021,7 @@ arcnet_inthandler(struct device *dev) ...@@ -2020,8 +2021,7 @@ arcnet_inthandler(struct device *dev)
&& lp->num_recons >= RECON_THRESHOLD) && lp->num_recons >= RECON_THRESHOLD)
{ {
lp->network_down=1; lp->network_down=1;
printk("%6s: many reconfigurations detected: cabling problem?\n", BUGMSG(D_NORMAL,"many reconfigurations detected: cabling problem?\n");
dev->name);
} }
else if (!lp->network_down else if (!lp->network_down
&& lp->last_recon-lp->first_recon > HZ*60) && lp->last_recon-lp->first_recon > HZ*60)
...@@ -2039,7 +2039,7 @@ arcnet_inthandler(struct device *dev) ...@@ -2039,7 +2039,7 @@ arcnet_inthandler(struct device *dev)
else if (lp->network_down && jiffies-lp->last_recon > HZ*10) else if (lp->network_down && jiffies-lp->last_recon > HZ*10)
{ {
if (lp->network_down) if (lp->network_down)
printk("%6s: cabling restored?\n",dev->name); BUGMSG(D_NORMAL,"cabling restored?\n");
lp->first_recon=lp->last_recon=0; lp->first_recon=lp->last_recon=0;
lp->num_recons=lp->network_down=0; lp->num_recons=lp->network_down=0;
...@@ -2049,7 +2049,7 @@ arcnet_inthandler(struct device *dev) ...@@ -2049,7 +2049,7 @@ arcnet_inthandler(struct device *dev)
#endif /* DETECT_RECONFIGS */ #endif /* DETECT_RECONFIGS */
/* RX is inhibited - we must have received something. */ /* RX is inhibited - we must have received something. */
if (status & NORXflag) if (status & lp->intmask & NORXflag)
{ {
int recbuf=lp->recbuf=!lp->recbuf; int recbuf=lp->recbuf=!lp->recbuf;
...@@ -2065,24 +2065,27 @@ arcnet_inthandler(struct device *dev) ...@@ -2065,24 +2065,27 @@ arcnet_inthandler(struct device *dev)
} }
/* it can only be an xmit-done irq if we're xmitting :) */ /* it can only be an xmit-done irq if we're xmitting :) */
if (status&TXFREEflag && !lp->in_txhandler && lp->sending) /*if (status&TXFREEflag && !lp->in_txhandler && lp->sending)*/
if (status & lp->intmask & TXFREEflag)
{ {
struct Outgoing *out=&(lp->outgoing); struct Outgoing *out=&(lp->outgoing);
int was_sending=lp->sending;
lp->intmask &= ~TXFREEflag;
lp->in_txhandler++; lp->in_txhandler++;
lp->sending--; if (was_sending) lp->sending--;
BUGMSG(D_DURING,"TX IRQ (stat=%Xh, numsegs=%d, segnum=%d, skb=%ph)\n", BUGMSG(D_DURING,"TX IRQ (stat=%Xh, numsegs=%d, segnum=%d, skb=%ph)\n",
status,out->numsegs,out->segnum,out->skb); status,out->numsegs,out->segnum,out->skb);
#ifdef VERIFY_ACK #ifdef VERIFY_ACK
if (!(status&TXACKflag)) if (was_sending && !(status&TXACKflag))
{ {
if (lp->outgoing.lasttrans_dest != 0) if (lp->lasttrans_dest != 0)
{ {
printk("%6s: transmit was not acknowledged! (status=%Xh, dest=%d)\n", BUGMSG(D_NORMAL,"transmit was not acknowledged! (status=%Xh, dest=%d)\n",
dev->name,status, status,lp->lasttrans_dest);
lp->outgoing.lasttrans_dest);
lp->stats.tx_errors++; lp->stats.tx_errors++;
lp->stats.tx_carrier_errors++; lp->stats.tx_carrier_errors++;
} }
...@@ -2090,7 +2093,7 @@ arcnet_inthandler(struct device *dev) ...@@ -2090,7 +2093,7 @@ arcnet_inthandler(struct device *dev)
{ {
BUGMSG(D_DURING,"broadcast was not acknowledged; that's normal (status=%Xh, dest=%d)\n", BUGMSG(D_DURING,"broadcast was not acknowledged; that's normal (status=%Xh, dest=%d)\n",
status, status,
lp->outgoing.lasttrans_dest); lp->lasttrans_dest);
} }
} }
#endif #endif
...@@ -2100,6 +2103,8 @@ arcnet_inthandler(struct device *dev) ...@@ -2100,6 +2103,8 @@ arcnet_inthandler(struct device *dev)
if (lp->intx) if (lp->intx)
{ {
BUGMSG(D_DURING,"TXDONE while intx! (status=%Xh, intx=%d)\n",
inb(STATUS),lp->intx);
lp->in_txhandler--; lp->in_txhandler--;
continue; continue;
} }
...@@ -2114,7 +2119,6 @@ arcnet_inthandler(struct device *dev) ...@@ -2114,7 +2119,6 @@ arcnet_inthandler(struct device *dev)
TBUSY=0; TBUSY=0;
mark_bh(NET_BH); mark_bh(NET_BH);
} }
lp->in_txhandler--; lp->in_txhandler--;
continue; continue;
} }
...@@ -2160,17 +2164,7 @@ arcnet_inthandler(struct device *dev) ...@@ -2160,17 +2164,7 @@ arcnet_inthandler(struct device *dev)
BUGMSG(D_DURING,"net_interrupt complete (status=%Xh, count=%d)\n\n", BUGMSG(D_DURING,"net_interrupt complete (status=%Xh, count=%d)\n\n",
inb(STATUS),boguscount); inb(STATUS),boguscount);
if (dev->start && (lp->sending || (lp->txready && !lp->intx))) SETMASK; /* put back interrupt mask */
outb(NORXflag|TXFREEflag|RECON_flag,INTMASK);
else
outb(NORXflag|RECON_flag,INTMASK);
#else /* Disable everything */
outb(RXcmd|(0<<3)|RXbcasts,COMMAND);
outb(NORXflag,INTMASK);
#endif
INTERRUPT=0; INTERRUPT=0;
} }
...@@ -2206,8 +2200,8 @@ arcnet_rx(struct device *dev,int recbuf) ...@@ -2206,8 +2200,8 @@ arcnet_rx(struct device *dev,int recbuf)
/* if source is 0, it's a "used" packet! */ /* if source is 0, it's a "used" packet! */
if (saddr==0) if (saddr==0)
{ {
printk("%6s: discarding old packet. (status=%Xh)\n", BUGMSG(D_NORMAL,"discarding old packet. (status=%Xh)\n",
dev->name,inb(STATUS)); inb(STATUS));
lp->stats.rx_errors++; lp->stats.rx_errors++;
return; return;
} }
...@@ -2249,8 +2243,8 @@ arcnet_rx(struct device *dev,int recbuf) ...@@ -2249,8 +2243,8 @@ arcnet_rx(struct device *dev,int recbuf)
break; break;
case ARC_P_LANSOFT: /* don't understand. fall through. */ case ARC_P_LANSOFT: /* don't understand. fall through. */
default: default:
printk("%6s: received unknown protocol %d (%Xh) from station %d.\n", BUGMSG(D_NORMAL,"received unknown protocol %d (%Xh) from station %d.\n",
dev->name,arcsoft[0],arcsoft[0],saddr); arcsoft[0],arcsoft[0],saddr);
lp->stats.rx_errors++; lp->stats.rx_errors++;
lp->stats.rx_crc_errors++; lp->stats.rx_crc_errors++;
break; break;
...@@ -2324,7 +2318,7 @@ arcnetA_rx(struct device *dev,u_char *buf, ...@@ -2324,7 +2318,7 @@ arcnetA_rx(struct device *dev,u_char *buf,
if (in->skb) /* already assembling one! */ if (in->skb) /* already assembling one! */
{ {
BUGMSG(D_EXTRA,"aborting assembly (seq=%d) for unsplit packet (splitflag=%d, seq=%d)\n", BUGMSG(D_NORMAL,"aborting assembly (seq=%d) for unsplit packet (splitflag=%d, seq=%d)\n",
in->sequence,arcsoft->split_flag, in->sequence,arcsoft->split_flag,
arcsoft->sequence); arcsoft->sequence);
kfree_skb(in->skb,FREE_WRITE); kfree_skb(in->skb,FREE_WRITE);
...@@ -2337,8 +2331,7 @@ arcnetA_rx(struct device *dev,u_char *buf, ...@@ -2337,8 +2331,7 @@ arcnetA_rx(struct device *dev,u_char *buf,
skb = alloc_skb(length, GFP_ATOMIC); skb = alloc_skb(length, GFP_ATOMIC);
if (skb == NULL) { if (skb == NULL) {
printk("%6s: Memory squeeze, dropping packet.\n", BUGMSG(D_NORMAL,"Memory squeeze, dropping packet.\n");
dev->name);
lp->stats.rx_dropped++; lp->stats.rx_dropped++;
return; return;
} }
...@@ -2383,8 +2376,8 @@ arcnetA_rx(struct device *dev,u_char *buf, ...@@ -2383,8 +2376,8 @@ arcnetA_rx(struct device *dev,u_char *buf,
} }
else else
{ {
printk("%6s: funny-shaped ARP packet. (%Xh, %Xh)\n", BUGMSG(D_NORMAL,"funny-shaped ARP packet. (%Xh, %Xh)\n",
dev->name,arp->ar_hln,arp->ar_pln); arp->ar_hln,arp->ar_pln);
lp->stats.rx_errors++; lp->stats.rx_errors++;
lp->stats.rx_crc_errors++; lp->stats.rx_crc_errors++;
} }
...@@ -2393,7 +2386,7 @@ arcnetA_rx(struct device *dev,u_char *buf, ...@@ -2393,7 +2386,7 @@ arcnetA_rx(struct device *dev,u_char *buf,
BUGLVL(D_SKB) BUGLVL(D_SKB)
{ {
short i; short i;
for( i=0; i< skb->len; i++) for(i=0; i< skb->len; i++)
{ {
if( i%16 == 0 ) printk("\n[%04hX] ",i); if( i%16 == 0 ) printk("\n[%04hX] ",i);
printk("%02hX ",((unsigned char*)skb->data)[i]); printk("%02hX ",((unsigned char*)skb->data)[i]);
...@@ -2433,8 +2426,8 @@ arcnetA_rx(struct device *dev,u_char *buf, ...@@ -2433,8 +2426,8 @@ arcnetA_rx(struct device *dev,u_char *buf,
if (in->skb && in->sequence!=arcsoft->sequence) if (in->skb && in->sequence!=arcsoft->sequence)
{ {
BUGMSG(D_EXTRA,"wrong seq number, aborting assembly (expected=%d, seq=%d, splitflag=%d)\n", BUGMSG(D_NORMAL,"wrong seq number, aborting assembly (saddr=%d, expected=%d, seq=%d, splitflag=%d)\n",
in->sequence,arcsoft->sequence, saddr,in->sequence,arcsoft->sequence,
arcsoft->split_flag); arcsoft->split_flag);
kfree_skb(in->skb,FREE_WRITE); kfree_skb(in->skb,FREE_WRITE);
in->skb=NULL; in->skb=NULL;
...@@ -2449,7 +2442,7 @@ arcnetA_rx(struct device *dev,u_char *buf, ...@@ -2449,7 +2442,7 @@ arcnetA_rx(struct device *dev,u_char *buf,
arcsoft->split_flag); arcsoft->split_flag);
if (in->skb) /* already assembling one! */ if (in->skb) /* already assembling one! */
{ {
BUGMSG(D_EXTRA,"aborting previous (seq=%d) assembly (splitflag=%d, seq=%d)\n", BUGMSG(D_NORMAL,"aborting previous (seq=%d) assembly (splitflag=%d, seq=%d)\n",
in->sequence,arcsoft->split_flag, in->sequence,arcsoft->split_flag,
arcsoft->sequence); arcsoft->sequence);
lp->stats.rx_errors++; lp->stats.rx_errors++;
...@@ -2463,7 +2456,7 @@ arcnetA_rx(struct device *dev,u_char *buf, ...@@ -2463,7 +2456,7 @@ arcnetA_rx(struct device *dev,u_char *buf,
if (in->numpackets>16) if (in->numpackets>16)
{ {
BUGMSG(D_EXTRA,"incoming packet more than 16 segments; dropping. (splitflag=%d)\n", BUGMSG(D_NORMAL,"incoming packet more than 16 segments; dropping. (splitflag=%d)\n",
arcsoft->split_flag); arcsoft->split_flag);
lp->stats.rx_errors++; lp->stats.rx_errors++;
lp->stats.rx_length_errors++; lp->stats.rx_length_errors++;
...@@ -2474,8 +2467,7 @@ arcnetA_rx(struct device *dev,u_char *buf, ...@@ -2474,8 +2467,7 @@ arcnetA_rx(struct device *dev,u_char *buf,
+ sizeof(struct ClientData), + sizeof(struct ClientData),
GFP_ATOMIC); GFP_ATOMIC);
if (skb == NULL) { if (skb == NULL) {
printk("%6s: (split) memory squeeze, dropping packet.\n", BUGMSG(D_NORMAL,"(split) memory squeeze, dropping packet.\n");
dev->name);
lp->stats.rx_dropped++; lp->stats.rx_dropped++;
return; return;
} }
...@@ -2504,7 +2496,7 @@ arcnetA_rx(struct device *dev,u_char *buf, ...@@ -2504,7 +2496,7 @@ arcnetA_rx(struct device *dev,u_char *buf,
*/ */
if (!in->skb) if (!in->skb)
{ {
BUGMSG(D_EXTRA,"can't continue split without starting first! (splitflag=%d, seq=%d)\n", BUGMSG(D_NORMAL,"can't continue split without starting first! (splitflag=%d, seq=%d)\n",
arcsoft->split_flag,arcsoft->sequence); arcsoft->split_flag,arcsoft->sequence);
lp->stats.rx_errors++; lp->stats.rx_errors++;
lp->stats.rx_missed_errors++; lp->stats.rx_missed_errors++;
...@@ -2517,7 +2509,7 @@ arcnetA_rx(struct device *dev,u_char *buf, ...@@ -2517,7 +2509,7 @@ arcnetA_rx(struct device *dev,u_char *buf,
/* harmless duplicate? ignore. */ /* harmless duplicate? ignore. */
if (packetnum<=in->lastpacket-1) if (packetnum<=in->lastpacket-1)
{ {
BUGMSG(D_EXTRA,"duplicate splitpacket ignored! (splitflag=%d)\n", BUGMSG(D_NORMAL,"duplicate splitpacket ignored! (splitflag=%d)\n",
arcsoft->split_flag); arcsoft->split_flag);
lp->stats.rx_errors++; lp->stats.rx_errors++;
lp->stats.rx_frame_errors++; lp->stats.rx_frame_errors++;
...@@ -2525,7 +2517,7 @@ arcnetA_rx(struct device *dev,u_char *buf, ...@@ -2525,7 +2517,7 @@ arcnetA_rx(struct device *dev,u_char *buf,
} }
/* "bad" duplicate, kill reassembly */ /* "bad" duplicate, kill reassembly */
BUGMSG(D_EXTRA,"out-of-order splitpacket, reassembly (seq=%d) aborted (splitflag=%d, seq=%d)\n", BUGMSG(D_NORMAL,"out-of-order splitpacket, reassembly (seq=%d) aborted (splitflag=%d, seq=%d)\n",
in->sequence,arcsoft->split_flag, in->sequence,arcsoft->split_flag,
arcsoft->sequence); arcsoft->sequence);
kfree_skb(in->skb,FREE_WRITE); kfree_skb(in->skb,FREE_WRITE);
...@@ -2555,8 +2547,8 @@ arcnetA_rx(struct device *dev,u_char *buf, ...@@ -2555,8 +2547,8 @@ arcnetA_rx(struct device *dev,u_char *buf,
{ {
if (!skb || !in->skb) if (!skb || !in->skb)
{ {
printk("%6s: ?!? done reassembling packet, no skb? (skb=%ph, in->skb=%ph)\n", BUGMSG(D_NORMAL,"?!? done reassembling packet, no skb? (skb=%ph, in->skb=%ph)\n",
dev->name,skb,in->skb); skb,in->skb);
} }
else else
{ {
...@@ -2600,7 +2592,7 @@ arcnetE_rx(struct device *dev,u_char *arcsoft, ...@@ -2600,7 +2592,7 @@ arcnetE_rx(struct device *dev,u_char *arcsoft,
skb = alloc_skb(length, GFP_ATOMIC); skb = alloc_skb(length, GFP_ATOMIC);
if (skb == NULL) { if (skb == NULL) {
printk("%6s: Memory squeeze, dropping packet.\n",dev->name); BUGMSG(D_NORMAL,"Memory squeeze, dropping packet.\n");
lp->stats.rx_dropped++; lp->stats.rx_dropped++;
return; return;
} }
...@@ -2653,7 +2645,7 @@ arcnetS_rx(struct device *dev,u_char *buf, ...@@ -2653,7 +2645,7 @@ arcnetS_rx(struct device *dev,u_char *buf,
skb = alloc_skb(length, GFP_ATOMIC); skb = alloc_skb(length, GFP_ATOMIC);
if (skb == NULL) { if (skb == NULL) {
printk("arcnetS: Memory squeeze, dropping packet.\n"); BUGMSG(D_NORMAL,"Memory squeeze, dropping packet.\n");
lp->stats.rx_dropped++; lp->stats.rx_dropped++;
return; return;
} }
...@@ -2780,8 +2772,8 @@ int arcnetA_header(struct sk_buff *skb,struct device *dev, ...@@ -2780,8 +2772,8 @@ int arcnetA_header(struct sk_buff *skb,struct device *dev,
head->protocol_id=ARC_P_ATALK; head->protocol_id=ARC_P_ATALK;
break; break;
default: default:
printk("%6s: I don't understand protocol %d (%Xh)\n", BUGMSG(D_NORMAL,"I don't understand protocol %d (%Xh)\n",
dev->name,type,type); type,type);
lp->stats.tx_errors++; lp->stats.tx_errors++;
lp->stats.tx_aborted_errors++; lp->stats.tx_aborted_errors++;
return 0; return 0;
...@@ -2850,7 +2842,7 @@ int arcnetS_header(struct sk_buff *skb,struct device *dev, ...@@ -2850,7 +2842,7 @@ int arcnetS_header(struct sk_buff *skb,struct device *dev,
BUGMSG(D_DURING,"S_header: ARP_RFC1051 packet.\n"); BUGMSG(D_DURING,"S_header: ARP_RFC1051 packet.\n");
break; break;
default: default:
printk("arcnetS: I don't understand protocol %d (%Xh)\n", BUGMSG(D_NORMAL,"I don't understand protocol %d (%Xh)\n",
type,type); type,type);
lp->stats.tx_errors++; lp->stats.tx_errors++;
lp->stats.tx_aborted_errors++; lp->stats.tx_aborted_errors++;
...@@ -2901,8 +2893,8 @@ int arcnetA_rebuild_header(void *buff,struct device *dev,unsigned long dst, ...@@ -2901,8 +2893,8 @@ int arcnetA_rebuild_header(void *buff,struct device *dev,unsigned long dst,
if(head->protocol_id != ARC_P_IP) if(head->protocol_id != ARC_P_IP)
{ {
printk("%6s: I don't understand protocol type %d (%Xh) addresses!\n", BUGMSG(D_NORMAL,"I don't understand protocol type %d (%Xh) addresses!\n",
dev->name,head->protocol_id,head->protocol_id); head->protocol_id,head->protocol_id);
lp->stats.tx_errors++; lp->stats.tx_errors++;
lp->stats.tx_aborted_errors++; lp->stats.tx_aborted_errors++;
head->daddr=0; head->daddr=0;
...@@ -2938,7 +2930,7 @@ int arcnetS_rebuild_header(void *buff,struct device *dev,unsigned long dst, ...@@ -2938,7 +2930,7 @@ int arcnetS_rebuild_header(void *buff,struct device *dev,unsigned long dst,
if(head->protocol_id != ARC_P_IP_RFC1051) if(head->protocol_id != ARC_P_IP_RFC1051)
{ {
printk("arcnetS: I don't understand protocol type %d (%Xh) addresses!\n", BUGMSG(D_NORMAL,"I don't understand protocol type %d (%Xh) addresses!\n",
head->protocol_id,head->protocol_id); head->protocol_id,head->protocol_id);
lp->stats.tx_errors++; lp->stats.tx_errors++;
lp->stats.tx_aborted_errors++; lp->stats.tx_aborted_errors++;
...@@ -2996,7 +2988,7 @@ unsigned short arcnetA_type_trans(struct sk_buff *skb,struct device *dev) ...@@ -2996,7 +2988,7 @@ unsigned short arcnetA_type_trans(struct sk_buff *skb,struct device *dev)
case ARC_P_NOVELL_EC: case ARC_P_NOVELL_EC:
return htons(ETH_P_802_3); return htons(ETH_P_802_3);
default: default:
BUGMSG(D_EXTRA,"received packet of unknown protocol id %d (%Xh)\n", BUGMSG(D_NORMAL,"received packet of unknown protocol id %d (%Xh)\n",
head->protocol_id,head->protocol_id); head->protocol_id,head->protocol_id);
lp->stats.rx_errors++; lp->stats.rx_errors++;
lp->stats.rx_crc_errors++; lp->stats.rx_crc_errors++;
...@@ -3037,7 +3029,7 @@ unsigned short arcnetS_type_trans(struct sk_buff *skb,struct device *dev) ...@@ -3037,7 +3029,7 @@ unsigned short arcnetS_type_trans(struct sk_buff *skb,struct device *dev)
case ARC_P_ARP_RFC1051: return htons(ETH_P_ARP); case ARC_P_ARP_RFC1051: return htons(ETH_P_ARP);
case ARC_P_ATALK: return htons(ETH_P_ATALK); /* untested appletalk */ case ARC_P_ATALK: return htons(ETH_P_ATALK); /* untested appletalk */
default: default:
BUGMSG(D_EXTRA,"received packet of unknown protocol id %d (%Xh)\n", BUGMSG(D_NORMAL,"received packet of unknown protocol id %d (%Xh)\n",
head->protocol_id,head->protocol_id); head->protocol_id,head->protocol_id);
lp->stats.rx_errors++; lp->stats.rx_errors++;
lp->stats.rx_crc_errors++; lp->stats.rx_crc_errors++;
......
...@@ -299,7 +299,12 @@ e21_get_8390_hdr(struct device *dev, struct e8390_pkt_hdr *hdr, int ring_page) ...@@ -299,7 +299,12 @@ e21_get_8390_hdr(struct device *dev, struct e8390_pkt_hdr *hdr, int ring_page)
mem_on(ioaddr, shared_mem, ring_page); mem_on(ioaddr, shared_mem, ring_page);
#ifdef notdef
/* Officially this is what we are doing, but the readl() is faster */
memcpy_fromio(hdr, shared_mem, sizeof(struct e8390_pkt_hdr)); memcpy_fromio(hdr, shared_mem, sizeof(struct e8390_pkt_hdr));
#else
((unsigned int*)hdr)[0] = readl(shared_mem);
#endif
/* Turn off memory access: we would need to reprogram the window anyway. */ /* Turn off memory access: we would need to reprogram the window anyway. */
mem_off(ioaddr); mem_off(ioaddr);
......
...@@ -34,6 +34,9 @@ ...@@ -34,6 +34,9 @@
#include <linux/netdevice.h> #include <linux/netdevice.h>
#include <linux/etherdevice.h> #include <linux/etherdevice.h>
#include <linux/trdevice.h> #include <linux/trdevice.h>
#ifdef CONFIG_NET_ALIAS
#include <linux/net_alias.h>
#endif
/* The network devices currently exist only in the socket namespace, so these /* The network devices currently exist only in the socket namespace, so these
entries are unused. The only ones that make sense are entries are unused. The only ones that make sense are
...@@ -293,6 +296,28 @@ void unregister_netdev(struct device *dev) ...@@ -293,6 +296,28 @@ void unregister_netdev(struct device *dev)
/* else */ /* else */
if (dev->start) if (dev->start)
printk("ERROR '%s' busy and not MOD_IN_USE.\n", dev->name); printk("ERROR '%s' busy and not MOD_IN_USE.\n", dev->name);
/*
* must jump over main_device+aliases
* avoid alias devices unregistration so that only
* net_alias module manages them
*/
#ifdef CONFIG_NET_ALIAS
if (dev_base == dev)
dev_base = net_alias_nextdev(dev);
else
{
while(d && (net_alias_nextdev(d) != dev)) /* skip aliases */
d = net_alias_nextdev(d);
if (d && (net_alias_nextdev(d) == dev))
{
/*
* critical: bypass by consider devices as blocks (maindev+aliases)
*/
net_alias_nextdev_set(d, net_alias_nextdev(dev));
}
#else
if (dev_base == dev) if (dev_base == dev)
dev_base = dev->next; dev_base = dev->next;
else else
...@@ -304,6 +329,7 @@ void unregister_netdev(struct device *dev) ...@@ -304,6 +329,7 @@ void unregister_netdev(struct device *dev)
{ {
d->next = dev->next; d->next = dev->next;
} }
#endif
else else
{ {
printk("unregister_netdev: '%s' not found\n", dev->name); printk("unregister_netdev: '%s' not found\n", dev->name);
......
...@@ -270,7 +270,12 @@ ultra_get_8390_hdr(struct device *dev, struct e8390_pkt_hdr *hdr, int ring_page) ...@@ -270,7 +270,12 @@ ultra_get_8390_hdr(struct device *dev, struct e8390_pkt_hdr *hdr, int ring_page)
unsigned long hdr_start = dev->mem_start + ((ring_page - START_PG)<<8); unsigned long hdr_start = dev->mem_start + ((ring_page - START_PG)<<8);
outb(ULTRA_MEMENB, dev->base_addr - ULTRA_NIC_OFFSET); /* shmem on */ outb(ULTRA_MEMENB, dev->base_addr - ULTRA_NIC_OFFSET); /* shmem on */
#ifdef notdef
/* Officially this is what we are doing, but the readl() is faster */
memcpy_fromio(hdr, hdr_start, sizeof(struct e8390_pkt_hdr)); memcpy_fromio(hdr, hdr_start, sizeof(struct e8390_pkt_hdr));
#else
((unsigned int*)hdr)[0] = readl(hdr_start);
#endif
outb(0x00, dev->base_addr - ULTRA_NIC_OFFSET); /* shmem off */ outb(0x00, dev->base_addr - ULTRA_NIC_OFFSET); /* shmem off */
} }
......
...@@ -129,6 +129,13 @@ int wd_probe1(struct device *dev, int ioaddr) ...@@ -129,6 +129,13 @@ int wd_probe1(struct device *dev, int ioaddr)
dev = init_etherdev(0, 0); dev = init_etherdev(0, 0);
} }
/* Check for semi-valid mem_start/end values if supplied. */
if ((dev->mem_start % 0x2000) || (dev->mem_end % 0x2000)) {
printk(KERN_WARNING "wd.c: user supplied mem_start or mem_end not on 8kB boundary - ignored.\n");
dev->mem_start = 0;
dev->mem_end = 0;
}
if (ei_debug && version_printed++ == 0) if (ei_debug && version_printed++ == 0)
printk(version); printk(version);
...@@ -246,7 +253,7 @@ int wd_probe1(struct device *dev, int ioaddr) ...@@ -246,7 +253,7 @@ int wd_probe1(struct device *dev, int ioaddr)
/* Snarf the interrupt now. There's no point in waiting since we cannot /* Snarf the interrupt now. There's no point in waiting since we cannot
share and the board will usually be enabled. */ share and the board will usually be enabled. */
if (request_irq(dev->irq, ei_interrupt, 0, "wd")) { if (request_irq(dev->irq, ei_interrupt, 0, model_name)) {
printk (" unable to get IRQ %d.\n", dev->irq); printk (" unable to get IRQ %d.\n", dev->irq);
return EAGAIN; return EAGAIN;
} }
...@@ -259,7 +266,7 @@ int wd_probe1(struct device *dev, int ioaddr) ...@@ -259,7 +266,7 @@ int wd_probe1(struct device *dev, int ioaddr)
} }
/* OK, were are certain this is going to work. Setup the device. */ /* OK, were are certain this is going to work. Setup the device. */
request_region(ioaddr, WD_IO_EXTENT,"wd"); request_region(ioaddr, WD_IO_EXTENT, model_name);
ei_status.name = model_name; ei_status.name = model_name;
ei_status.word16 = word16; ei_status.word16 = word16;
...@@ -352,7 +359,12 @@ wd_get_8390_hdr(struct device *dev, struct e8390_pkt_hdr *hdr, int ring_page) ...@@ -352,7 +359,12 @@ wd_get_8390_hdr(struct device *dev, struct e8390_pkt_hdr *hdr, int ring_page)
if (ei_status.word16) if (ei_status.word16)
outb(ISA16 | ei_status.reg5, wd_cmdreg+WD_CMDREG5); outb(ISA16 | ei_status.reg5, wd_cmdreg+WD_CMDREG5);
#ifdef notdef
/* Officially this is what we are doing, but the readl() is faster */
memcpy_fromio(hdr, hdr_start, sizeof(struct e8390_pkt_hdr)); memcpy_fromio(hdr, hdr_start, sizeof(struct e8390_pkt_hdr));
#else
((unsigned int*)hdr)[0] = readl(hdr_start);
#endif
} }
/* Block input and output are easy on shared memory ethercards, and trivial /* Block input and output are easy on shared memory ethercards, and trivial
......
...@@ -918,7 +918,7 @@ int aha152x_abort( Scsi_Cmnd *SCpnt) ...@@ -918,7 +918,7 @@ int aha152x_abort( Scsi_Cmnd *SCpnt)
ptr->host_scribble = NULL; ptr->host_scribble = NULL;
ptr->result = DID_ABORT << 16; ptr->result = DID_ABORT << 16;
ptr->done(ptr); ptr->scsi_done(ptr);
return SCSI_ABORT_SUCCESS; return SCSI_ABORT_SUCCESS;
} }
...@@ -942,7 +942,7 @@ int aha152x_abort( Scsi_Cmnd *SCpnt) ...@@ -942,7 +942,7 @@ int aha152x_abort( Scsi_Cmnd *SCpnt)
/* target entered bus free before COMMAND COMPLETE, nothing to abort */ /* target entered bus free before COMMAND COMPLETE, nothing to abort */
restore_flags(flags); restore_flags(flags);
current_SC->result = DID_ERROR << 16; current_SC->result = DID_ERROR << 16;
current_SC->done(current_SC); current_SC->scsi_done(current_SC);
current_SC = (Scsi_Cmnd *) NULL; current_SC = (Scsi_Cmnd *) NULL;
return SCSI_ABORT_SUCCESS; return SCSI_ABORT_SUCCESS;
} }
...@@ -1063,7 +1063,7 @@ int aha152x_reset(Scsi_Cmnd * __unused) ...@@ -1063,7 +1063,7 @@ int aha152x_reset(Scsi_Cmnd * __unused)
{ {
current_SC->host_scribble = NULL; current_SC->host_scribble = NULL;
current_SC->result = DID_RESET << 16; current_SC->result = DID_RESET << 16;
current_SC->done(current_SC); current_SC->scsi_done(current_SC);
current_SC=NULL; current_SC=NULL;
} }
...@@ -1083,7 +1083,7 @@ int aha152x_reset(Scsi_Cmnd * __unused) ...@@ -1083,7 +1083,7 @@ int aha152x_reset(Scsi_Cmnd * __unused)
ptr->host_scribble = NULL; ptr->host_scribble = NULL;
ptr->result = DID_RESET << 16; ptr->result = DID_RESET << 16;
ptr->done(ptr); ptr->scsi_done(ptr);
ptr = next; ptr = next;
} }
......
...@@ -23,6 +23,8 @@ ...@@ -23,6 +23,8 @@
#define CONST_XSENSE 0x08 #define CONST_XSENSE 0x08
#define CONST_CMND 0x10 #define CONST_CMND 0x10
#define CONST_MSG 0x20 #define CONST_MSG 0x20
#define CONST_HOST 0x40
#define CONST_DRIVER 0x80
static const char unknown[] = "UNKNOWN"; static const char unknown[] = "UNKNOWN";
...@@ -30,7 +32,8 @@ static const char unknown[] = "UNKNOWN"; ...@@ -30,7 +32,8 @@ static const char unknown[] = "UNKNOWN";
#ifdef CONSTANTS #ifdef CONSTANTS
#undef CONSTANTS #undef CONSTANTS
#endif #endif
#define CONSTANTS (CONST_COMMAND | CONST_STATUS | CONST_SENSE | CONST_XSENSE | CONST_CMND | CONST_MSG) #define CONSTANTS (CONST_COMMAND | CONST_STATUS | CONST_SENSE | CONST_XSENSE \
| CONST_CMND | CONST_MSG | CONST_HOST | CONST_DRIVER)
#endif #endif
#if (CONSTANTS & CONST_COMMAND) #if (CONSTANTS & CONST_COMMAND)
...@@ -568,6 +571,64 @@ void print_Scsi_Cmnd (Scsi_Cmnd *cmd) { ...@@ -568,6 +571,64 @@ void print_Scsi_Cmnd (Scsi_Cmnd *cmd) {
print_command (cmd->cmnd); print_command (cmd->cmnd);
} }
#if (CONSTANTS & CONST_HOST)
static const char * hostbyte_table[]={
"DID_OK", "DID_NO_CONNECT", "DID_BUS_BUSY", "DID_TIME_OUT", "DID_BAD_TARGET",
"DID_ABORT", "DID_PARITY", "DID_ERROR", "DID_RESET", "DID_BAD_INTR",NULL};
void print_hostbyte(int scsiresult)
{ static int maxcode=0;
int i;
if(!maxcode) {
for(i=0;hostbyte_table[i];i++) ;
maxcode=i-1;
}
printk("Hostbyte=0x%02x",host_byte(scsiresult));
if(host_byte(scsiresult)>maxcode) {
printk("is invalid ");
return;
}
printk("(%s) ",hostbyte_table[host_byte(scsiresult)]);
}
#else
void print_hostbyte(int scsiresult)
{ printk("Hostbyte=0x%02x ",hostbyte(scsiresult));
}
#endif
#if (CONSTANTS & CONST_DRIVER)
static const char * driverbyte_table[]={
"DRIVER_OK", "DRIVER_BUSY", "DRIVER_SOFT", "DRIVER_MEDIA", "DRIVER_ERROR",
"DRIVER_INVALID", "DRIVER_TIMEOUT", "DRIVER_HARD",NULL };
static const char * driversuggest_table[]={"SUGGEST_OK",
"SUGGEST_RETRY", "SUGGEST_ABORT", "SUGGEST_REMAP", "SUGGEST_DIE",
unknown,unknown,unknown, "SUGGEST_SENSE",NULL};
void print_driverbyte(int scsiresult)
{ static int driver_max=0,suggest_max=0;
int i,dr=driver_byte(scsiresult)&DRIVER_MASK,
su=(driver_byte(scsiresult)&SUGGEST_MASK)>>4;
if(!driver_max) {
for(i=0;driverbyte_table[i];i++) ;
driver_max=i;
for(i=0;driversuggest_table[i];i++) ;
suggest_max=i;
}
printk("Driverbyte=0x%02x",driver_byte(scsiresult));
printk("(%s,%s) ",
dr<driver_max ? driverbyte_table[dr]:"invalid",
su<suggest_max ? driversuggest_table[su]:"invalid");
}
#else
void print_driverbyte(int scsiresult)
{ printk("Driverbyte=0x%02x ",driver_byte(scsiresult));
}
#endif
/* /*
* Overrides for Emacs so that we almost follow Linus's tabbing style. * Overrides for Emacs so that we almost follow Linus's tabbing style.
* Emacs will notice this stuff at the end of the file and automatically * Emacs will notice this stuff at the end of the file and automatically
......
...@@ -65,6 +65,7 @@ static void scsi_times_out (Scsi_Cmnd * SCpnt, int pid); ...@@ -65,6 +65,7 @@ static void scsi_times_out (Scsi_Cmnd * SCpnt, int pid);
static int scan_scsis_single (int channel,int dev,int lun,int * max_scsi_dev , static int scan_scsis_single (int channel,int dev,int lun,int * max_scsi_dev ,
Scsi_Device ** SDpnt, Scsi_Cmnd * SCpnt, Scsi_Device ** SDpnt, Scsi_Cmnd * SCpnt,
struct Scsi_Host *shpnt, char * scsi_result); struct Scsi_Host *shpnt, char * scsi_result);
void scsi_build_commandblocks(Scsi_Device * SDpnt);
static unsigned char * dma_malloc_freelist = NULL; static unsigned char * dma_malloc_freelist = NULL;
...@@ -272,18 +273,6 @@ static int get_device_flags(unsigned char * response_data){ ...@@ -272,18 +273,6 @@ static int get_device_flags(unsigned char * response_data){
return 0; return 0;
} }
/*
* As the actual SCSI command runs in the background, we must set up a
* flag that tells scan_scsis() when the result it has is valid.
* scan_scsis can set the_result to -1, and watch for it to become the
* actual return code for that call. the scan_scsis_done function() is
* our user specified completion function that is passed on to the
* scsi_do_cmd() function.
*/
volatile int in_scan_scsis = 0;
static int the_result;
void scsi_make_blocked_list(void) { void scsi_make_blocked_list(void) {
int block_count = 0, index; int block_count = 0, index;
unsigned int flags; unsigned int flags;
...@@ -385,9 +374,10 @@ static void scan_scsis (struct Scsi_Host *shpnt, unchar hardcoded, ...@@ -385,9 +374,10 @@ static void scan_scsis (struct Scsi_Host *shpnt, unchar hardcoded,
int max_dev_lun; int max_dev_lun;
Scsi_Cmnd *SCpnt; Scsi_Cmnd *SCpnt;
in_scan_scsis++;
SCpnt = (Scsi_Cmnd *) scsi_init_malloc (sizeof (Scsi_Cmnd), GFP_ATOMIC | GFP_DMA); SCpnt = (Scsi_Cmnd *) scsi_init_malloc (sizeof (Scsi_Cmnd), GFP_ATOMIC | GFP_DMA);
SDpnt = (Scsi_Device *) scsi_init_malloc (sizeof (Scsi_Device), GFP_ATOMIC); SDpnt = (Scsi_Device *) scsi_init_malloc (sizeof (Scsi_Device), GFP_ATOMIC);
memset (SCpnt, 0, sizeof (Scsi_Cmnd));
/* Make sure we have something that is valid for DMA purposes */ /* Make sure we have something that is valid for DMA purposes */
scsi_result = ((!dma_malloc_freelist || !shpnt->unchecked_isa_dma) scsi_result = ((!dma_malloc_freelist || !shpnt->unchecked_isa_dma)
...@@ -398,9 +388,17 @@ static void scan_scsis (struct Scsi_Host *shpnt, unchar hardcoded, ...@@ -398,9 +388,17 @@ static void scan_scsis (struct Scsi_Host *shpnt, unchar hardcoded,
goto leave; goto leave;
} }
shpnt->host_queue = SCpnt; /* We need this so that commands can time out */ /* We must chain ourself in the host_queue, so commands can time out */
if(shpnt->host_queue)
shpnt->host_queue->prev = SCpnt;
SCpnt->next = shpnt->host_queue;
SCpnt->prev = NULL;
shpnt->host_queue = SCpnt;
if (hardcoded == 1) { if (hardcoded == 1) {
Scsi_Device *oldSDpnt=SDpnt;
struct Scsi_Device_Template * sdtpnt;
channel = hchannel; channel = hchannel;
if(channel > shpnt->max_channel) goto leave; if(channel > shpnt->max_channel) goto leave;
dev = hid; dev = hid;
...@@ -409,11 +407,31 @@ static void scan_scsis (struct Scsi_Host *shpnt, unchar hardcoded, ...@@ -409,11 +407,31 @@ static void scan_scsis (struct Scsi_Host *shpnt, unchar hardcoded,
if(lun >= shpnt->max_lun) goto leave; if(lun >= shpnt->max_lun) goto leave;
scan_scsis_single (channel, dev, lun, &max_dev_lun, scan_scsis_single (channel, dev, lun, &max_dev_lun,
&SDpnt, SCpnt, shpnt, scsi_result); &SDpnt, SCpnt, shpnt, scsi_result);
if(SDpnt!=oldSDpnt) {
/* it could happen the blockdevice hasn't yet been inited */
for(sdtpnt = scsi_devicelist; sdtpnt; sdtpnt = sdtpnt->next)
if(sdtpnt->init && sdtpnt->dev_noticed) (*sdtpnt->init)();
oldSDpnt->scsi_request_fn = NULL;
for(sdtpnt = scsi_devicelist; sdtpnt; sdtpnt = sdtpnt->next)
if(sdtpnt->attach) {
(*sdtpnt->attach)(oldSDpnt);
if(oldSDpnt->attached) scsi_build_commandblocks(oldSDpnt);}
resize_dma_pool();
for(sdtpnt = scsi_devicelist; sdtpnt; sdtpnt = sdtpnt->next) {
if(sdtpnt->finish && sdtpnt->nr_dev)
{(*sdtpnt->finish)();}
}
}
} }
else { else {
for (channel = 0; channel <= shpnt->max_channel; channel++) { for (channel = 0; channel <= shpnt->max_channel; channel++) {
for (dev = 0; dev < shpnt->max_id; ++dev) { for (dev = 0; dev < shpnt->max_id; ++dev) {
if (shpnt->this_id != dev) { if (shpnt->this_id != dev) {
/* /*
* We need the for so our continue, etc. work fine. We put this in * We need the for so our continue, etc. work fine. We put this in
* a variable so that we can override it during the scan if we * a variable so that we can override it during the scan if we
...@@ -421,19 +439,31 @@ static void scan_scsis (struct Scsi_Host *shpnt, unchar hardcoded, ...@@ -421,19 +439,31 @@ static void scan_scsis (struct Scsi_Host *shpnt, unchar hardcoded,
*/ */
max_dev_lun = (max_scsi_luns < shpnt->max_lun ? max_dev_lun = (max_scsi_luns < shpnt->max_lun ?
max_scsi_luns : shpnt->max_lun); max_scsi_luns : shpnt->max_lun);
for (lun = 0; lun < max_dev_lun; ++lun) { for (lun = 0; lun < max_dev_lun; ++lun) {
if (!scan_scsis_single (channel, dev, lun, &max_dev_lun, if (!scan_scsis_single (channel, dev, lun, &max_dev_lun,
&SDpnt, SCpnt, shpnt, scsi_result)) &SDpnt, SCpnt, shpnt, scsi_result))
break; /* break means don't probe for luns!=0 */ break; /* break means don't probe further for luns!=0 */
} /* for lun ends */ } /* for lun ends */
} /* if this_id != id ends */ } /* if this_id != id ends */
} /* for dev ends */ } /* for dev ends */
} /* for channel ends */ } /* for channel ends */
} /* if/else hardcoded */
leave:
shpnt->host_queue = NULL; /* No longer needed here */ leave:
{/* Unchain SCpnt from host_queue */
Scsi_Cmnd *prev,*next,*hqptr;
for(hqptr=shpnt->host_queue; hqptr!=SCpnt; hqptr=hqptr->next) ;
if(hqptr) {
prev=hqptr->prev;
next=hqptr->next;
if(prev)
prev->next=next;
else
shpnt->host_queue=next;
if(next) next->prev=prev;
}
}
/* Last device block does not exist. Free memory. */ /* Last device block does not exist. Free memory. */
if (SDpnt != NULL) if (SDpnt != NULL)
...@@ -446,14 +476,12 @@ static void scan_scsis (struct Scsi_Host *shpnt, unchar hardcoded, ...@@ -446,14 +476,12 @@ static void scan_scsis (struct Scsi_Host *shpnt, unchar hardcoded,
if (scsi_result != &scsi_result0[0] && scsi_result != NULL) if (scsi_result != &scsi_result0[0] && scsi_result != NULL)
scsi_free (scsi_result, 512); scsi_free (scsi_result, 512);
in_scan_scsis--;
}
} }
/* /*
* The worker for scan_scsis. * The worker for scan_scsis.
* Returning 0 means Please don't ask further for lun!=0, 1 means OK go on. * Returning 0 means Please don't ask further for lun!=0, 1 means OK go on.
* Global variables used : scsi_devices(linked list), the_result * Global variables used : scsi_devices(linked list)
*/ */
int scan_scsis_single (int channel, int dev, int lun, int *max_dev_lun, int scan_scsis_single (int channel, int dev, int lun, int *max_dev_lun,
Scsi_Device **SDpnt2, Scsi_Cmnd * SCpnt, struct Scsi_Host * shpnt, Scsi_Device **SDpnt2, Scsi_Cmnd * SCpnt, struct Scsi_Host * shpnt,
...@@ -490,7 +518,6 @@ int scan_scsis_single (int channel, int dev, int lun, int *max_dev_lun, ...@@ -490,7 +518,6 @@ int scan_scsis_single (int channel, int dev, int lun, int *max_dev_lun,
scsi_cmd[1] = lun << 5; scsi_cmd[1] = lun << 5;
scsi_cmd[2] = scsi_cmd[3] = scsi_cmd[4] = scsi_cmd[5] = 0; scsi_cmd[2] = scsi_cmd[3] = scsi_cmd[4] = scsi_cmd[5] = 0;
memset (SCpnt, 0, sizeof (Scsi_Cmnd));
SCpnt->host = SDpnt->host; SCpnt->host = SDpnt->host;
SCpnt->device = SDpnt; SCpnt->device = SDpnt;
SCpnt->target = SDpnt->id; SCpnt->target = SDpnt->id;
...@@ -507,8 +534,10 @@ int scan_scsis_single (int channel, int dev, int lun, int *max_dev_lun, ...@@ -507,8 +534,10 @@ int scan_scsis_single (int channel, int dev, int lun, int *max_dev_lun,
} }
#if defined(DEBUG) || defined(DEBUG_INIT) #if defined(DEBUG) || defined(DEBUG_INIT)
printk ("scsi: scan_scsis_single id %d lun %d. Return code %d\n", printk ("scsi: scan_scsis_single id %d lun %d. Return code 0x%08x\n",
dev, lun, SCpnt->result); dev, lun, SCpnt->result);
print_driverbyte(SCpnt->result); print_hostbyte(SCpnt->result);
printk("\n");
#endif #endif
if (SCpnt->result) { if (SCpnt->result) {
...@@ -546,13 +575,12 @@ int scan_scsis_single (int channel, int dev, int lun, int *max_dev_lun, ...@@ -546,13 +575,12 @@ int scan_scsis_single (int channel, int dev, int lun, int *max_dev_lun,
down (&sem); down (&sem);
} }
the_result = SCpnt->result;
#if defined(DEBUG) || defined(DEBUG_INIT) #if defined(DEBUG) || defined(DEBUG_INIT)
printk ("scsi: INQUIRY %s with code 0x%x\n", printk ("scsi: INQUIRY %s with code 0x%x\n",
the_result ? "failed" : "successful", the->result); SCpnt->result ? "failed" : "successful", SCpnt->result);
#endif #endif
if (the_result) if (SCpnt->result)
return 0; /* assume no peripheral if any sort of error */ return 0; /* assume no peripheral if any sort of error */
/* /*
...@@ -696,7 +724,7 @@ int scan_scsis_single (int channel, int dev, int lun, int *max_dev_lun, ...@@ -696,7 +724,7 @@ int scan_scsis_single (int channel, int dev, int lun, int *max_dev_lun,
SDpnt = (Scsi_Device *) scsi_init_malloc (sizeof (Scsi_Device), GFP_ATOMIC); SDpnt = (Scsi_Device *) scsi_init_malloc (sizeof (Scsi_Device), GFP_ATOMIC);
*SDpnt2=SDpnt; *SDpnt2=SDpnt;
if (!SDpnt) if (!SDpnt)
printk ("scsi: scan_scsis_single: No memory\n"); printk ("scsi: scan_scsis_single: Cannot malloc\n");
/* /*
...@@ -750,7 +778,7 @@ static void scsi_times_out (Scsi_Cmnd * SCpnt, int pid) ...@@ -750,7 +778,7 @@ static void scsi_times_out (Scsi_Cmnd * SCpnt, int pid)
switch (SCpnt->internal_timeout & (IN_ABORT | IN_RESET)) switch (SCpnt->internal_timeout & (IN_ABORT | IN_RESET))
{ {
case NORMAL_TIMEOUT: case NORMAL_TIMEOUT:
if (!in_scan_scsis) { {
#ifdef DEBUG_TIMEOUT #ifdef DEBUG_TIMEOUT
scsi_dump_status(); scsi_dump_status();
#endif #endif
...@@ -1460,7 +1488,7 @@ static void scsi_done (Scsi_Cmnd * SCpnt) ...@@ -1460,7 +1488,7 @@ static void scsi_done (Scsi_Cmnd * SCpnt)
printk ("Internal error %s %d \n", __FILE__, printk ("Internal error %s %d \n", __FILE__,
__LINE__); __LINE__);
} }
} } /* end WAS_SENSE */
else else
{ {
#ifdef DEBUG #ifdef DEBUG
...@@ -1734,8 +1762,7 @@ int scsi_abort (Scsi_Cmnd * SCpnt, int why, int pid) ...@@ -1734,8 +1762,7 @@ int scsi_abort (Scsi_Cmnd * SCpnt, int why, int pid)
SCpnt->internal_timeout |= IN_ABORT; SCpnt->internal_timeout |= IN_ABORT;
oldto = update_timeout(SCpnt, ABORT_TIMEOUT); oldto = update_timeout(SCpnt, ABORT_TIMEOUT);
if ((SCpnt->flags & IS_RESETTING) && if ((SCpnt->flags & IS_RESETTING) && SCpnt->device->soft_reset) {
SCpnt->device->soft_reset) {
/* OK, this command must have died when we did the /* OK, this command must have died when we did the
* reset. The device itself must have lied. * reset. The device itself must have lied.
*/ */
...@@ -1797,6 +1824,8 @@ int scsi_abort (Scsi_Cmnd * SCpnt, int why, int pid) ...@@ -1797,6 +1824,8 @@ int scsi_abort (Scsi_Cmnd * SCpnt, int why, int pid)
/* We should have already aborted this one. No /* We should have already aborted this one. No
* need to adjust timeout * need to adjust timeout
*/ */
SCpnt->internal_timeout &= ~IN_ABORT;
return 0;
case SCSI_ABORT_NOT_RUNNING: case SCSI_ABORT_NOT_RUNNING:
SCpnt->internal_timeout &= ~IN_ABORT; SCpnt->internal_timeout &= ~IN_ABORT;
update_timeout(SCpnt, 0); update_timeout(SCpnt, 0);
...@@ -1837,10 +1866,8 @@ int scsi_reset (Scsi_Cmnd * SCpnt, int bus_reset_flag) ...@@ -1837,10 +1866,8 @@ int scsi_reset (Scsi_Cmnd * SCpnt, int bus_reset_flag)
Scsi_Cmnd * SCpnt1; Scsi_Cmnd * SCpnt1;
struct Scsi_Host * host = SCpnt->host; struct Scsi_Host * host = SCpnt->host;
#ifdef DEBUG printk("SCSI bus is being reset for host %d.\n",
printk("Danger Will Robinson! - SCSI bus for host %d is being reset.\n",
host->host_no); host->host_no);
#endif
/* /*
* First of all, we need to make a recommendation to the low-level * First of all, we need to make a recommendation to the low-level
...@@ -1863,9 +1890,7 @@ int scsi_reset (Scsi_Cmnd * SCpnt, int bus_reset_flag) ...@@ -1863,9 +1890,7 @@ int scsi_reset (Scsi_Cmnd * SCpnt, int bus_reset_flag)
while(SCpnt1) { while(SCpnt1) {
if( SCpnt1->request.rq_status != RQ_INACTIVE if( SCpnt1->request.rq_status != RQ_INACTIVE
&& (SCpnt1->flags & (WAS_RESET | IS_RESETTING)) == 0 ) && (SCpnt1->flags & (WAS_RESET | IS_RESETTING)) == 0 )
{
break; break;
}
SCpnt1 = SCpnt1->next; SCpnt1 = SCpnt1->next;
} }
if( SCpnt1 == NULL ) { if( SCpnt1 == NULL ) {
...@@ -2154,7 +2179,7 @@ int scsi_free(void *obj, unsigned int len) ...@@ -2154,7 +2179,7 @@ int scsi_free(void *obj, unsigned int len)
unsigned long flags; unsigned long flags;
#ifdef DEBUG #ifdef DEBUG
printk("Sfree %p %d\n",obj, len); printk("scsi_free %p %d\n",obj, len);
#endif #endif
offset = -1; offset = -1;
...@@ -2167,20 +2192,20 @@ int scsi_free(void *obj, unsigned int len) ...@@ -2167,20 +2192,20 @@ int scsi_free(void *obj, unsigned int len)
break; break;
} }
if (page == (dma_sectors >> 3)) panic("Bad offset"); if (page == (dma_sectors >> 3)) panic("scsi_free:Bad offset");
sector = offset >> 9; sector = offset >> 9;
if(sector >= dma_sectors) panic ("Bad page"); if(sector >= dma_sectors) panic ("scsi_free:Bad page");
sector = (offset >> 9) & (sizeof(*dma_malloc_freelist) * 8 - 1); sector = (offset >> 9) & (sizeof(*dma_malloc_freelist) * 8 - 1);
nbits = len >> 9; nbits = len >> 9;
mask = (1 << nbits) - 1; mask = (1 << nbits) - 1;
if ((mask << sector) > 0xffff) panic ("Bad memory alignment"); if ((mask << sector) > 0xffff) panic ("scsi_free:Bad memory alignment");
save_flags(flags); save_flags(flags);
cli(); cli();
if((dma_malloc_freelist[page] & (mask << sector)) != (mask<<sector)) if((dma_malloc_freelist[page] & (mask << sector)) != (mask<<sector))
panic("Trying to free unused memory"); panic("scsi_free:Trying to free unused memory");
dma_free_sectors += nbits; dma_free_sectors += nbits;
dma_malloc_freelist[page] &= ~(mask << sector); dma_malloc_freelist[page] &= ~(mask << sector);
...@@ -2438,8 +2463,13 @@ int scsi_proc_info(char *buffer, char **start, off_t offset, int length, ...@@ -2438,8 +2463,13 @@ int scsi_proc_info(char *buffer, char **start, off_t offset, int length,
/* /*
* Usage: echo "scsi singledevice 0 1 2 3" >/proc/scsi/scsi * Usage: echo "scsi singledevice 0 1 2 3" >/proc/scsi/scsi
* with "0 1 2 3" replaced by your "Host Channel Id Lun". * with "0 1 2 3" replaced by your "Host Channel Id Lun".
* Consider this feature ALPHA, as you can easily hang your * Consider this feature BETA.
* scsi system (depending on your low level driver). * CAUTION: This is not for hotplugging your peripherals. As
* SCSI was not designed for this you could damage your
* hardware !
* However perhaps it is legal to switch on an
* already connected device. It is perhaps not
* guaranteed this device doesn't corrupt an ongoing data transfer.
*/ */
if(!buffer || length < 25 || strncmp("scsi", buffer, 4)) if(!buffer || length < 25 || strncmp("scsi", buffer, 4))
return(-EINVAL); return(-EINVAL);
......
...@@ -89,6 +89,7 @@ extern const unsigned char scsi_command_size[8]; ...@@ -89,6 +89,7 @@ extern const unsigned char scsi_command_size[8];
#define DRIVER_INVALID 0x05 #define DRIVER_INVALID 0x05
#define DRIVER_TIMEOUT 0x06 #define DRIVER_TIMEOUT 0x06
#define DRIVER_HARD 0x07 #define DRIVER_HARD 0x07
#define DRIVER_SENSE 0x08
#define SUGGEST_RETRY 0x10 #define SUGGEST_RETRY 0x10
#define SUGGEST_ABORT 0x20 #define SUGGEST_ABORT 0x20
...@@ -97,8 +98,6 @@ extern const unsigned char scsi_command_size[8]; ...@@ -97,8 +98,6 @@ extern const unsigned char scsi_command_size[8];
#define SUGGEST_SENSE 0x80 #define SUGGEST_SENSE 0x80
#define SUGGEST_IS_OK 0xff #define SUGGEST_IS_OK 0xff
#define DRIVER_SENSE 0x08
#define DRIVER_MASK 0x0f #define DRIVER_MASK 0x0f
#define SUGGEST_MASK 0xf0 #define SUGGEST_MASK 0xf0
...@@ -448,6 +447,8 @@ extern void proc_print_scsidevice(Scsi_Device *, char *, int *, int); ...@@ -448,6 +447,8 @@ extern void proc_print_scsidevice(Scsi_Device *, char *, int *, int);
extern void print_command(unsigned char *); extern void print_command(unsigned char *);
extern void print_sense(const char *, Scsi_Cmnd *); extern void print_sense(const char *, Scsi_Cmnd *);
extern void print_driverbyte(int scsiresult);
extern void print_hostbyte(int scsiresult);
extern void scsi_mark_host_bus_reset(struct Scsi_Host *Host); extern void scsi_mark_host_bus_reset(struct Scsi_Host *Host);
......
...@@ -59,7 +59,6 @@ struct symbol_table scsi_symbol_table = { ...@@ -59,7 +59,6 @@ struct symbol_table scsi_symbol_table = {
X(kernel_scsi_ioctl), X(kernel_scsi_ioctl),
X(need_isa_buffer), X(need_isa_buffer),
X(request_queueable), X(request_queueable),
X(in_scan_scsis),
#if defined(CONFIG_PROC_FS) #if defined(CONFIG_PROC_FS)
X(proc_print_scsidevice), X(proc_print_scsidevice),
#endif #endif
......
...@@ -1304,12 +1304,14 @@ static void sd_finish() ...@@ -1304,12 +1304,14 @@ static void sd_finish()
if (!rscsi_disks[i].capacity && if (!rscsi_disks[i].capacity &&
rscsi_disks[i].device) rscsi_disks[i].device)
{ {
i = sd_init_onedisk(i);
if (MODULE_FLAG if (MODULE_FLAG
&& !rscsi_disks[i].has_part_table) { && !rscsi_disks[i].has_part_table) {
sd_sizes[i << 4] = rscsi_disks[i].capacity; sd_sizes[i << 4] = rscsi_disks[i].capacity;
/* revalidate does sd_init_onedisk via MAYBE_REINIT*/
revalidate_scsidisk(MKDEV(MAJOR_NR, i << 4), 0); revalidate_scsidisk(MKDEV(MAJOR_NR, i << 4), 0);
} }
else
i=sd_init_onedisk(i);
rscsi_disks[i].has_part_table = 1; rscsi_disks[i].has_part_table = 1;
} }
......
...@@ -297,7 +297,8 @@ int mem_mmap(struct inode * inode, struct file * file, ...@@ -297,7 +297,8 @@ int mem_mmap(struct inode * inode, struct file * file,
dtmp += PAGE_SIZE; dtmp += PAGE_SIZE;
} }
invalidate(); invalidate_range(vma->vm_mm, vma->vm_start, vma->vm_end);
invalidate_range(src_vma->vm_mm, src_vma->vm_start, src_vma->vm_end);
return 0; return 0;
} }
......
...@@ -91,13 +91,13 @@ struct vfsmount *add_vfsmnt(kdev_t dev, const char *dev_name, const char *dir_na ...@@ -91,13 +91,13 @@ struct vfsmount *add_vfsmnt(kdev_t dev, const char *dev_name, const char *dir_na
lptr->mnt_sem.count = 1; lptr->mnt_sem.count = 1;
if (dev_name && !getname(dev_name, &tmp)) { if (dev_name && !getname(dev_name, &tmp)) {
if ((lptr->mnt_devname = if ((lptr->mnt_devname =
(char *) kmalloc(strlen(tmp), GFP_KERNEL)) != (char *)NULL) (char *) kmalloc(strlen(tmp)+1, GFP_KERNEL)) != (char *)NULL)
strcpy(lptr->mnt_devname, tmp); strcpy(lptr->mnt_devname, tmp);
putname(tmp); putname(tmp);
} }
if (dir_name && !getname(dir_name, &tmp)) { if (dir_name && !getname(dir_name, &tmp)) {
if ((lptr->mnt_dirname = if ((lptr->mnt_dirname =
(char *) kmalloc(strlen(tmp), GFP_KERNEL)) != (char *)NULL) (char *) kmalloc(strlen(tmp)+1, GFP_KERNEL)) != (char *)NULL)
strcpy(lptr->mnt_dirname, tmp); strcpy(lptr->mnt_dirname, tmp);
putname(tmp); putname(tmp);
} }
......
...@@ -26,32 +26,81 @@ ...@@ -26,32 +26,81 @@
* - invalidate_page(mm, vmaddr) invalidates one page * - invalidate_page(mm, vmaddr) invalidates one page
* - invalidate_range(mm, start, end) invalidates a range of pages * - invalidate_range(mm, start, end) invalidates a range of pages
* *
* ..but the i386 has somewhat limited invalidation capabilities. * ..but the i386 has somewhat limited invalidation capabilities,
* and page-granular invalidates are available only on i486 and up.
*/ */
#ifndef __SMP__ #define __invalidate() \
#define invalidate() \
__asm__ __volatile__("movl %%cr3,%%eax\n\tmovl %%eax,%%cr3": : :"ax") __asm__ __volatile__("movl %%cr3,%%eax\n\tmovl %%eax,%%cr3": : :"ax")
#ifdef __i486__
#define __invalidate_one(addr) \
__asm__ __volatile__("invlpg %0": :"m" (*(char *) addr))
#else #else
#include <asm/smp.h> #define __invalidate_one(addr) invalidate()
#define local_invalidate() \
__asm__ __volatile__("movl %%cr3,%%eax\n\tmovl %%eax,%%cr3": : :"ax")
#define invalidate() \
smp_invalidate();
#endif #endif
#ifndef __SMP__
#define invalidate() __invalidate()
#define invalidate_all() __invalidate()
static inline void invalidate_mm(struct mm_struct *mm)
{
if (mm == current->mm)
__invalidate();
}
static inline void invalidate_page(struct mm_struct *mm,
unsigned long addr)
{
if (mm == current->mm)
__invalidate_one(addr);
}
static inline void invalidate_range(struct mm_struct *mm,
unsigned long start, unsigned long end)
{
if (mm == current->mm)
__invalidate();
}
#else
/* /*
* We aren't very clever about this yet. On a 486+ we could actually do * We aren't very clever about this yet - SMP could certainly
* page-granularity invalidates for better performance in some cases. * avoid some global invalidates..
* And SMP could certainly avoid some global invalidates..
*/ */
#include <asm/smp.h>
#define local_invalidate() \
__invalidate()
#define invalidate() \
smp_invalidate()
#define invalidate_all() invalidate() #define invalidate_all() invalidate()
#define invalidate_mm(mm_struct) \
do { if ((mm_struct) == current->mm) invalidate(); } while (0) static inline void invalidate_mm(struct mm_struct *mm)
#define invalidate_page(mm_struct,addr) \ {
do { if ((mm_struct) == current->mm) invalidate(); } while (0) invalidate();
#define invalidate_range(mm_struct,start,end) \ }
do { if ((mm_struct) == current->mm) invalidate(); } while (0)
static inline void invalidate_page(struct mm_struct *mm,
unsigned long addr)
{
invalidate();
}
static inline void invalidate_range(struct mm_struct *mm,
unsigned long start, unsigned long end)
{
invalidate();
}
#endif
/* Certain architectures need to do special things when pte's /* Certain architectures need to do special things when pte's
* within a page table are directly modified. Thus, the following * within a page table are directly modified. Thus, the following
......
#ifndef _NET_ALIAS_H
#define _NET_ALIAS_H
#include <linux/types.h>
#include <linux/if.h>
#include <linux/netdevice.h>
#include <linux/inet.h>
#include <linux/in.h> /* for default IP behavior */
/*
* max. alias slot number allowed
*/
#define NET_ALIAS_MAX_SLOT 256
struct net_alias;
struct net_alias_info;
struct net_alias_type;
/*
* main alias structure
* note that *defines* dev & devname
*/
struct net_alias
{
struct device dev; /* alias device defn*/
char name[IFNAMSIZ]; /* device name defn */
unsigned hash; /* my hash value: for quick rehash */
unsigned slot; /* slot number */
void *data; /* private data */
struct device *main_dev; /* pointer to main device */
struct net_alias_type *nat; /* alias type bound */
struct net_alias *next; /* next alias (hashed linked list) */
};
/*
* alias structure pointed by main device
* it holds main device's alias hash table
*/
struct net_alias_info
{
int n_aliases; /* num aliases */
struct device *taildev; /* my last (alias) device */
struct net_alias *hash_tab[16]; /* hashed alias table */
};
/*
* net_alias_type class
* declares a generic (AF_ independent) structure that will
* manage generic to family-specific behavior.
*/
struct net_alias_type
{
int type; /* aliasing type: address family */
int n_attach; /* number of aliases attached */
char name[16]; /* af_name */
__u32 (*get_addr32) /* get __u32 addr 'representation'*/
(struct sockaddr*);
int (*addr_chk) /* address checking func: */
(struct device *, struct sockaddr *);
int (*alias_init_1) /* called after alias creation: */
(struct net_alias *alias, struct sockaddr *sa);
int (*alias_done_1) /* called before alias deletion */
(struct net_alias *alias);
int (*alias_print_1)
(char *buf, int len, struct net_alias *alias);
struct net_alias_type *next; /* link */
};
/*
* is dev an alias?
*/
static __inline__ int
net_alias_is(struct device *dev)
{
return (dev->my_alias != 0);
}
/*
* does dev have aliases?
*/
static __inline__ int
net_alias_has(struct device *dev)
{
return (dev->alias_info != 0);
}
extern void net_alias_init(void);
extern struct device * net_alias_dev_get(char *dev_name, int aliasing_ok, int *err, struct sockaddr *sa, void *data);
extern int net_alias_rehash(struct net_alias *alias, struct sockaddr *sa);
extern int net_alias_getinfo(char *buf, char **, off_t , int , int );
extern int net_alias_types_getinfo(char *buf, char **, off_t , int , int );
extern int register_net_alias_type(struct net_alias_type *nat, int type);
extern int unregister_net_alias_type(struct net_alias_type *nat);
extern struct device * net_alias_chk(struct device *dev, struct sockaddr *sa, int flags_1, int flags_0);
extern struct device * net_alias_chk32(struct device *dev, int family, __u32 addr32, int flags_1, int flags_0);
/*
* returns MY 'true' main device
* intended for alias devices
*/
static __inline__ struct device *net_alias_main_dev(struct device *dev)
{
return (net_alias_is(dev))? dev->my_alias->main_dev : dev;
}
/*
* returns NEXT 'true' device
* intended for true devices
*/
static __inline__ struct device *
net_alias_nextdev(struct device *dev)
{
return (dev->alias_info)? dev->alias_info->taildev->next : dev->next;
}
/*
* sets NEXT 'true' device
* intended for main devices (treat main device as block: dev+aliases).
*/
static __inline__ struct device *
net_alias_nextdev_set(struct device *dev, struct device *nextdev)
{
struct device *pdev = dev;
if (net_alias_has(dev))
{
pdev = dev->alias_info->taildev; /* point to last dev alias */
}
pdev->next = nextdev;
return nextdev;
}
/*
* addr_chk wrapper: check given generic address with (UP) aliases
*/
static __inline__ struct device *
net_alias_addr_chk(struct device *dev, struct sockaddr *sa)
{
return net_alias_chk(dev, sa, IFF_UP, 0);
}
/*
* addr_chk32 wrapper: check given u32 address with (UP) aliases
*/
static __inline__ struct device *
net_alias_addr_chk32(struct device *dev, int family, __u32 addr32)
{
return net_alias_chk32(dev, family, addr32, IFF_UP, 0);
}
#endif /* _NET_ALIAS_H */
...@@ -152,6 +152,8 @@ struct device ...@@ -152,6 +152,8 @@ struct device
unsigned long pkt_queue; /* Packets queued */ unsigned long pkt_queue; /* Packets queued */
struct device *slave; /* Slave device */ struct device *slave; /* Slave device */
struct net_alias_info *alias_info; /* main dev alias info */
struct net_alias *my_alias; /* alias devs */
/* Pointer to the interface buffers. */ /* Pointer to the interface buffers. */
......
...@@ -89,6 +89,8 @@ enum net_directory_inos { ...@@ -89,6 +89,8 @@ enum net_directory_inos {
PROC_NET_SOCKSTAT, PROC_NET_SOCKSTAT,
PROC_NET_RTCACHE, PROC_NET_RTCACHE,
PROC_NET_AX25_BPQETHER, PROC_NET_AX25_BPQETHER,
PROC_NET_ALIAS_TYPES,
PROC_NET_ALIASES,
PROC_NET_LAST PROC_NET_LAST
}; };
......
...@@ -44,8 +44,8 @@ struct rlimit { ...@@ -44,8 +44,8 @@ struct rlimit {
long rlim_max; long rlim_max;
}; };
#define PRIO_MIN (-99) #define PRIO_MIN (-20)
#define PRIO_MAX 14 #define PRIO_MAX 20
#define PRIO_PROCESS 0 #define PRIO_PROCESS 0
#define PRIO_PGRP 1 #define PRIO_PGRP 1
......
...@@ -48,5 +48,7 @@ struct vt_consize { ...@@ -48,5 +48,7 @@ struct vt_consize {
ushort v_ccol; /* number of pixel columns per character */ ushort v_ccol; /* number of pixel columns per character */
}; };
#define VT_RESIZEX 0x560A /* set kernel's idea of screensize + more */ #define VT_RESIZEX 0x560A /* set kernel's idea of screensize + more */
#define VT_LOCKSWITCH 0x560B /* disallow vt switching */
#define VT_UNLOCKSWITCH 0x560C /* allow vt switching */
#endif /* _LINUX_VT_H */ #endif /* _LINUX_VT_H */
#ifndef _IP_ALIAS_H
#define _IP_ALIAS_H
/*
* IP alias specific prototypes
*/
#include <linux/net_alias.h>
extern int ip_alias_init(void);
extern int ip_alias_done(void);
#endif /* _IP_ALIAS_H */
...@@ -445,7 +445,7 @@ static int shm_map (struct vm_area_struct *shmd) ...@@ -445,7 +445,7 @@ static int shm_map (struct vm_area_struct *shmd)
return -ENOMEM; return -ENOMEM;
set_pte(page_table, __pte(shm_sgn)); set_pte(page_table, __pte(shm_sgn));
} }
invalidate(); invalidate_range(shmd->vm_mm, shmd->vm_start, shmd->vm_end);
return 0; return 0;
} }
...@@ -680,7 +680,7 @@ int shm_swap (int prio, unsigned long limit) ...@@ -680,7 +680,7 @@ int shm_swap (int prio, unsigned long limit)
struct vm_area_struct *shmd; struct vm_area_struct *shmd;
unsigned long swap_nr; unsigned long swap_nr;
unsigned long id, idx; unsigned long id, idx;
int loop = 0, invalid = 0; int loop = 0;
int counter; int counter;
counter = shm_rss >> prio; counter = shm_rss >> prio;
...@@ -716,8 +716,6 @@ int shm_swap (int prio, unsigned long limit) ...@@ -716,8 +716,6 @@ int shm_swap (int prio, unsigned long limit)
if (--counter < 0) { /* failed */ if (--counter < 0) { /* failed */
failed: failed:
if (invalid)
invalidate();
swap_free (swap_nr); swap_free (swap_nr);
return 0; return 0;
} }
...@@ -766,7 +764,7 @@ int shm_swap (int prio, unsigned long limit) ...@@ -766,7 +764,7 @@ int shm_swap (int prio, unsigned long limit)
mem_map[MAP_NR(pte_page(pte))].count--; mem_map[MAP_NR(pte_page(pte))].count--;
if (shmd->vm_mm->rss > 0) if (shmd->vm_mm->rss > 0)
shmd->vm_mm->rss--; shmd->vm_mm->rss--;
invalid++; invalidate_range(shmd->vm_mm, shmd->vm_start, shmd->vm_end);
/* continue looping through circular list */ /* continue looping through circular list */
} while (0); } while (0);
if ((shmd = shmd->vm_next_share) == shp->attaches) if ((shmd = shmd->vm_next_share) == shp->attaches)
...@@ -776,8 +774,6 @@ int shm_swap (int prio, unsigned long limit) ...@@ -776,8 +774,6 @@ int shm_swap (int prio, unsigned long limit)
if (mem_map[MAP_NR(pte_page(page))].count != 1) if (mem_map[MAP_NR(pte_page(page))].count != 1)
goto check_table; goto check_table;
shp->shm_pages[idx] = swap_nr; shp->shm_pages[idx] = swap_nr;
if (invalid)
invalidate();
write_swap_page (swap_nr, (char *) pte_page(page)); write_swap_page (swap_nr, (char *) pte_page(page));
free_page(pte_page(page)); free_page(pte_page(page));
swap_successes++; swap_successes++;
......
...@@ -76,6 +76,9 @@ extern void __remqu (void); ...@@ -76,6 +76,9 @@ extern void __remqu (void);
#include "../drivers/net/slhc.h" #include "../drivers/net/slhc.h"
#endif #endif
#endif #endif
#ifdef CONFIG_NET_ALIAS
#include <linux/net_alias.h>
#endif
#endif #endif
#ifdef CONFIG_PCI #ifdef CONFIG_PCI
#include <linux/bios32.h> #include <linux/bios32.h>
...@@ -412,6 +415,10 @@ struct symbol_table symbol_table = { ...@@ -412,6 +415,10 @@ struct symbol_table symbol_table = {
/* Device callback registration */ /* Device callback registration */
X(register_netdevice_notifier), X(register_netdevice_notifier),
X(unregister_netdevice_notifier), X(unregister_netdevice_notifier),
#ifdef CONFIG_NET_ALIAS
X(register_net_alias_type),
X(unregister_net_alias_type),
#endif
#endif #endif
/* support for loadable net drivers */ /* support for loadable net drivers */
...@@ -452,11 +459,7 @@ struct symbol_table symbol_table = { ...@@ -452,11 +459,7 @@ struct symbol_table symbol_table = {
* So we add it here too. There is a duplicate set in scsi.c * So we add it here too. There is a duplicate set in scsi.c
* that is used when the entire scsi subsystem is a loadable * that is used when the entire scsi subsystem is a loadable
* module. * module.
*
* in_scan_scsis is a hack, and should go away once the new
* memory allocation code is in the NCR driver
*/ */
X(in_scan_scsis),
X(scsi_register_module), X(scsi_register_module),
X(scsi_unregister_module), X(scsi_unregister_module),
X(scsi_free), X(scsi_free),
......
...@@ -141,7 +141,8 @@ int filemap_swapout(struct vm_area_struct * vma, ...@@ -141,7 +141,8 @@ int filemap_swapout(struct vm_area_struct * vma,
unsigned long entry = SWP_ENTRY(SHM_SWP_TYPE, MAP_NR(page)); unsigned long entry = SWP_ENTRY(SHM_SWP_TYPE, MAP_NR(page));
set_pte(page_table, __pte(entry)); set_pte(page_table, __pte(entry));
invalidate(); /* Yuck, perhaps a slightly modified swapout parameter set? */
invalidate_page(vma->vm_mm, (offset + vma->vm_start - vma->vm_offset));
error = filemap_write_page(vma, offset, page); error = filemap_write_page(vma, offset, page);
if (pte_val(*page_table) == entry) if (pte_val(*page_table) == entry)
pte_clear(page_table); pte_clear(page_table);
...@@ -179,13 +180,14 @@ static inline int filemap_sync_pte(pte_t * ptep, struct vm_area_struct *vma, ...@@ -179,13 +180,14 @@ static inline int filemap_sync_pte(pte_t * ptep, struct vm_area_struct *vma,
if (!pte_dirty(pte)) if (!pte_dirty(pte))
return 0; return 0;
set_pte(ptep, pte_mkclean(pte)); set_pte(ptep, pte_mkclean(pte));
invalidate_page(vma->vm_mm, address);
page = pte_page(pte); page = pte_page(pte);
mem_map[MAP_NR(page)].count++; mem_map[MAP_NR(page)].count++;
} else { } else {
if (pte_none(pte)) if (pte_none(pte))
return 0; return 0;
pte_clear(ptep); pte_clear(ptep);
invalidate(); invalidate_page(vma->vm_mm, address);
if (!pte_present(pte)) { if (!pte_present(pte)) {
swap_free(pte_val(pte)); swap_free(pte_val(pte));
return 0; return 0;
...@@ -274,7 +276,7 @@ static int filemap_sync(struct vm_area_struct * vma, unsigned long address, ...@@ -274,7 +276,7 @@ static int filemap_sync(struct vm_area_struct * vma, unsigned long address,
address = (address + PGDIR_SIZE) & PGDIR_MASK; address = (address + PGDIR_SIZE) & PGDIR_MASK;
dir++; dir++;
} }
invalidate(); invalidate_range(vma->vm_mm, end - size, end);
return error; return error;
} }
......
...@@ -134,7 +134,7 @@ void clear_page_tables(struct task_struct * tsk) ...@@ -134,7 +134,7 @@ void clear_page_tables(struct task_struct * tsk)
} }
for (i = 0 ; i < USER_PTRS_PER_PGD ; i++) for (i = 0 ; i < USER_PTRS_PER_PGD ; i++)
free_one_pgd(page_dir + i); free_one_pgd(page_dir + i);
invalidate(); invalidate_mm(tsk->mm);
} }
/* /*
...@@ -153,12 +153,12 @@ void free_page_tables(struct task_struct * tsk) ...@@ -153,12 +153,12 @@ void free_page_tables(struct task_struct * tsk)
printk("%s trying to free kernel page-directory: not good\n", tsk->comm); printk("%s trying to free kernel page-directory: not good\n", tsk->comm);
return; return;
} }
invalidate_mm(tsk->mm);
SET_PAGE_DIR(tsk, swapper_pg_dir); SET_PAGE_DIR(tsk, swapper_pg_dir);
tsk->mm->pgd = swapper_pg_dir; /* or else... */ tsk->mm->pgd = swapper_pg_dir; /* or else... */
for (i = 0 ; i < PTRS_PER_PGD ; i++) for (i = 0 ; i < PTRS_PER_PGD ; i++)
free_one_pgd(page_dir + i); free_one_pgd(page_dir + i);
pgd_free(page_dir); pgd_free(page_dir);
invalidate();
} }
int new_page_tables(struct task_struct * tsk) int new_page_tables(struct task_struct * tsk)
...@@ -171,6 +171,7 @@ int new_page_tables(struct task_struct * tsk) ...@@ -171,6 +171,7 @@ int new_page_tables(struct task_struct * tsk)
page_dir = pgd_offset(&init_mm, 0); page_dir = pgd_offset(&init_mm, 0);
for (i = USER_PTRS_PER_PGD ; i < PTRS_PER_PGD ; i++) for (i = USER_PTRS_PER_PGD ; i < PTRS_PER_PGD ; i++)
new_pg[i] = page_dir[i]; new_pg[i] = page_dir[i];
invalidate_mm(tsk->mm);
SET_PAGE_DIR(tsk, new_pg); SET_PAGE_DIR(tsk, new_pg);
tsk->mm->pgd = new_pg; tsk->mm->pgd = new_pg;
return 0; return 0;
...@@ -285,7 +286,9 @@ int copy_page_range(struct mm_struct *dst, struct mm_struct *src, ...@@ -285,7 +286,9 @@ int copy_page_range(struct mm_struct *dst, struct mm_struct *src,
break; break;
address = (address + PGDIR_SIZE) & PGDIR_MASK; address = (address + PGDIR_SIZE) & PGDIR_MASK;
} }
invalidate(); /* Note that the src ptes get c-o-w treatment, so they change too. */
invalidate_range(src, vma->vm_start, vma->vm_end);
invalidate_range(dst, vma->vm_start, vma->vm_end);
return error; return error;
} }
...@@ -369,7 +372,7 @@ int zap_page_range(struct mm_struct *mm, unsigned long address, unsigned long si ...@@ -369,7 +372,7 @@ int zap_page_range(struct mm_struct *mm, unsigned long address, unsigned long si
address = (address + PGDIR_SIZE) & PGDIR_MASK; address = (address + PGDIR_SIZE) & PGDIR_MASK;
dir++; dir++;
} }
invalidate(); invalidate_range(mm, end - size, end);
return 0; return 0;
} }
...@@ -429,7 +432,7 @@ int zeromap_page_range(unsigned long address, unsigned long size, pgprot_t prot) ...@@ -429,7 +432,7 @@ int zeromap_page_range(unsigned long address, unsigned long size, pgprot_t prot)
address = (address + PGDIR_SIZE) & PGDIR_MASK; address = (address + PGDIR_SIZE) & PGDIR_MASK;
dir++; dir++;
} }
invalidate(); invalidate_range(current->mm, end - size, end);
return error; return error;
} }
...@@ -499,7 +502,7 @@ int remap_page_range(unsigned long from, unsigned long offset, unsigned long siz ...@@ -499,7 +502,7 @@ int remap_page_range(unsigned long from, unsigned long offset, unsigned long siz
from = (from + PGDIR_SIZE) & PGDIR_MASK; from = (from + PGDIR_SIZE) & PGDIR_MASK;
dir++; dir++;
} }
invalidate(); invalidate_range(current->mm, from - size, from);
return error; return error;
} }
...@@ -514,7 +517,7 @@ static void put_page(pte_t * page_table, pte_t pte) ...@@ -514,7 +517,7 @@ static void put_page(pte_t * page_table, pte_t pte)
return; return;
} }
/* no need for invalidate */ /* no need for invalidate */
*page_table = pte; set_pte(page_table, pte);
} }
/* /*
...@@ -547,7 +550,7 @@ unsigned long put_dirty_page(struct task_struct * tsk, unsigned long page, unsig ...@@ -547,7 +550,7 @@ unsigned long put_dirty_page(struct task_struct * tsk, unsigned long page, unsig
if (!pte_none(*pte)) { if (!pte_none(*pte)) {
printk("put_dirty_page: page already exists\n"); printk("put_dirty_page: page already exists\n");
pte_clear(pte); pte_clear(pte);
invalidate(); invalidate_page(tsk->mm, address);
} }
set_pte(pte, pte_mkwrite(pte_mkdirty(mk_pte(page, PAGE_COPY)))); set_pte(pte, pte_mkwrite(pte_mkdirty(mk_pte(page, PAGE_COPY))));
/* no need for invalidate */ /* no need for invalidate */
...@@ -610,17 +613,17 @@ void do_wp_page(struct task_struct * tsk, struct vm_area_struct * vma, ...@@ -610,17 +613,17 @@ void do_wp_page(struct task_struct * tsk, struct vm_area_struct * vma,
copy_page(old_page,new_page); copy_page(old_page,new_page);
set_pte(page_table, pte_mkwrite(pte_mkdirty(mk_pte(new_page, vma->vm_page_prot)))); set_pte(page_table, pte_mkwrite(pte_mkdirty(mk_pte(new_page, vma->vm_page_prot))));
free_page(old_page); free_page(old_page);
invalidate(); invalidate_page(vma->vm_mm, address);
return; return;
} }
set_pte(page_table, BAD_PAGE); set_pte(page_table, BAD_PAGE);
free_page(old_page); free_page(old_page);
oom(tsk); oom(tsk);
invalidate(); invalidate_page(vma->vm_mm, address);
return; return;
} }
set_pte(page_table, pte_mkdirty(pte_mkwrite(pte))); set_pte(page_table, pte_mkdirty(pte_mkwrite(pte)));
invalidate(); invalidate_page(vma->vm_mm, address);
if (new_page) if (new_page)
free_page(new_page); free_page(new_page);
return; return;
...@@ -842,7 +845,7 @@ static int try_to_share(unsigned long to_address, struct vm_area_struct * to_are ...@@ -842,7 +845,7 @@ static int try_to_share(unsigned long to_address, struct vm_area_struct * to_are
return 1; return 1;
/* ok, need to mark it read-only, so invalidate any possible old TB entry */ /* ok, need to mark it read-only, so invalidate any possible old TB entry */
set_pte(from_table, pte_wrprotect(from)); set_pte(from_table, pte_wrprotect(from));
invalidate(); invalidate_page(from_area->vm_mm, from_address);
return 1; return 1;
} }
......
...@@ -72,6 +72,7 @@ static inline void change_pmd_range(pgd_t * pgd, unsigned long address, ...@@ -72,6 +72,7 @@ static inline void change_pmd_range(pgd_t * pgd, unsigned long address,
static void change_protection(unsigned long start, unsigned long end, pgprot_t newprot) static void change_protection(unsigned long start, unsigned long end, pgprot_t newprot)
{ {
pgd_t *dir; pgd_t *dir;
unsigned long beg = start;
dir = pgd_offset(current->mm, start); dir = pgd_offset(current->mm, start);
while (start < end) { while (start < end) {
...@@ -79,7 +80,7 @@ static void change_protection(unsigned long start, unsigned long end, pgprot_t n ...@@ -79,7 +80,7 @@ static void change_protection(unsigned long start, unsigned long end, pgprot_t n
start = (start + PGDIR_SIZE) & PGDIR_MASK; start = (start + PGDIR_SIZE) & PGDIR_MASK;
dir++; dir++;
} }
invalidate(); invalidate_range(current->mm, beg, end);
return; return;
} }
......
...@@ -457,7 +457,7 @@ static inline int try_to_swap_out(struct task_struct * tsk, struct vm_area_struc ...@@ -457,7 +457,7 @@ static inline int try_to_swap_out(struct task_struct * tsk, struct vm_area_struc
return 0; return 0;
vma->vm_mm->rss--; vma->vm_mm->rss--;
set_pte(page_table, __pte(entry)); set_pte(page_table, __pte(entry));
invalidate(); invalidate_page(vma->vm_mm, address);
tsk->nswap++; tsk->nswap++;
write_swap_page(entry, (char *) page); write_swap_page(entry, (char *) page);
} }
...@@ -472,13 +472,13 @@ static inline int try_to_swap_out(struct task_struct * tsk, struct vm_area_struc ...@@ -472,13 +472,13 @@ static inline int try_to_swap_out(struct task_struct * tsk, struct vm_area_struc
} }
vma->vm_mm->rss--; vma->vm_mm->rss--;
set_pte(page_table, __pte(entry)); set_pte(page_table, __pte(entry));
invalidate(); invalidate_page(vma->vm_mm, address);
free_page(page); free_page(page);
return 1; return 1;
} }
vma->vm_mm->rss--; vma->vm_mm->rss--;
pte_clear(page_table); pte_clear(page_table);
invalidate(); invalidate_page(vma->vm_mm, address);
entry = mem_map[MAP_NR(page)].count; entry = mem_map[MAP_NR(page)].count;
free_page(page); free_page(page);
return entry; return entry;
......
...@@ -105,7 +105,7 @@ static void free_area_pages(unsigned long address, unsigned long size) ...@@ -105,7 +105,7 @@ static void free_area_pages(unsigned long address, unsigned long size)
address = (address + PGDIR_SIZE) & PGDIR_MASK; address = (address + PGDIR_SIZE) & PGDIR_MASK;
dir++; dir++;
} }
invalidate(); invalidate_all();
} }
static inline int alloc_area_pte(pte_t * pte, unsigned long address, unsigned long size) static inline int alloc_area_pte(pte_t * pte, unsigned long address, unsigned long size)
...@@ -166,7 +166,7 @@ static int alloc_area_pages(unsigned long address, unsigned long size) ...@@ -166,7 +166,7 @@ static int alloc_area_pages(unsigned long address, unsigned long size)
address = (address + PGDIR_SIZE) & PGDIR_MASK; address = (address + PGDIR_SIZE) & PGDIR_MASK;
dir++; dir++;
} }
invalidate(); invalidate_all();
return 0; return 0;
} }
...@@ -227,7 +227,7 @@ static int remap_area_pages(unsigned long address, unsigned long offset, unsigne ...@@ -227,7 +227,7 @@ static int remap_area_pages(unsigned long address, unsigned long offset, unsigne
address = (address + PGDIR_SIZE) & PGDIR_MASK; address = (address + PGDIR_SIZE) & PGDIR_MASK;
dir++; dir++;
} }
invalidate(); invalidate_all();
return 0; return 0;
} }
......
...@@ -4,6 +4,7 @@ ...@@ -4,6 +4,7 @@
mainmenu_option next_comment mainmenu_option next_comment
comment 'Networking options' comment 'Networking options'
bool 'Network firewalls' CONFIG_FIREWALL bool 'Network firewalls' CONFIG_FIREWALL
bool 'Network aliasing' CONFIG_NET_ALIAS
bool 'TCP/IP networking' CONFIG_INET bool 'TCP/IP networking' CONFIG_INET
if [ "$CONFIG_INET" = "y" ]; then if [ "$CONFIG_INET" = "y" ]; then
source net/ipv4/Config.in source net/ipv4/Config.in
......
...@@ -19,6 +19,10 @@ ifdef CONFIG_FIREWALL ...@@ -19,6 +19,10 @@ ifdef CONFIG_FIREWALL
O_OBJS += firewall.o O_OBJS += firewall.o
endif endif
ifdef CONFIG_NET_ALIAS
O_OBJS += net_alias.o
endif
endif endif
include $(TOPDIR)/Rules.make include $(TOPDIR)/Rules.make
......
...@@ -70,6 +70,9 @@ ...@@ -70,6 +70,9 @@
#include <net/arp.h> #include <net/arp.h>
#include <linux/proc_fs.h> #include <linux/proc_fs.h>
#include <linux/stat.h> #include <linux/stat.h>
#ifdef CONFIG_NET_ALIAS
#include <linux/net_alias.h>
#endif
/* /*
* The list of packet types we will receive (as opposed to discard) * The list of packet types we will receive (as opposed to discard)
...@@ -356,6 +359,19 @@ void dev_queue_xmit(struct sk_buff *skb, struct device *dev, int pri) ...@@ -356,6 +359,19 @@ void dev_queue_xmit(struct sk_buff *skb, struct device *dev, int pri)
return; return;
} }
/*
*
* If dev is an alias, switch to its main device.
* "arp" resolution has been made with alias device, so
* arp entries refer to alias, not main.
*
*/
#ifdef CONFIG_NET_ALIAS
if (net_alias_is(dev))
skb->dev = dev = net_alias_main_dev(dev);
#endif
save_flags(flags); save_flags(flags);
cli(); cli();
if (!where) /* Always keep order. It helps other hosts if (!where) /* Always keep order. It helps other hosts
...@@ -753,6 +769,13 @@ void dev_tint(struct device *dev) ...@@ -753,6 +769,13 @@ void dev_tint(struct device *dev)
struct sk_buff *skb; struct sk_buff *skb;
unsigned long flags; unsigned long flags;
/*
* aliases do not trasmit (by now :)
*/
#ifdef CONFIG_NET_ALIAS
if (net_alias_is(dev)) return;
#endif
save_flags(flags); save_flags(flags);
/* /*
* Work the queues in priority order * Work the queues in priority order
...@@ -984,9 +1007,20 @@ static int dev_ifsioc(void *arg, unsigned int getset) ...@@ -984,9 +1007,20 @@ static int dev_ifsioc(void *arg, unsigned int getset)
* See which interface the caller is talking about. * See which interface the caller is talking about.
*/ */
/*
*
* net_alias_dev_get(): dev_get() with added alias naming magic.
* only allow alias creation/deletion if (getset==SIOCSIFADDR)
*
*/
#ifdef CONFIG_NET_ALIAS
if ((dev = net_alias_dev_get(ifr.ifr_name, getset == SIOCSIFADDR, &err, NULL, NULL)) == NULL)
return(err);
#else
if ((dev = dev_get(ifr.ifr_name)) == NULL) if ((dev = dev_get(ifr.ifr_name)) == NULL)
return(-ENODEV); return(-ENODEV);
#endif
switch(getset) switch(getset)
{ {
case SIOCGIFFLAGS: /* Get interface flags */ case SIOCGIFFLAGS: /* Get interface flags */
...@@ -1079,6 +1113,16 @@ static int dev_ifsioc(void *arg, unsigned int getset) ...@@ -1079,6 +1113,16 @@ static int dev_ifsioc(void *arg, unsigned int getset)
} }
else else
{ {
/*
* if dev is an alias, must rehash to update
* address change
*/
#ifdef CONFIG_NET_ALIAS
if (net_alias_is(dev))
net_alias_rehash(dev->my_alias,&ifr.ifr_addr);
#endif
dev->pa_addr = (*(struct sockaddr_in *) dev->pa_addr = (*(struct sockaddr_in *)
&ifr.ifr_addr).sin_addr.s_addr; &ifr.ifr_addr).sin_addr.s_addr;
dev->family = ifr.ifr_addr.sa_family; dev->family = ifr.ifr_addr.sa_family;
...@@ -1382,6 +1426,18 @@ int net_dev_init(void) ...@@ -1382,6 +1426,18 @@ int net_dev_init(void)
dev_get_info dev_get_info
}); });
/*
* Initialise net_alias engine
*
* - register net_alias device notifier
* - register proc entries: /proc/net/alias_types
* /proc/net/aliases
*/
#ifdef CONFIG_NET_ALIAS
net_alias_init();
#endif
bh_base[NET_BH].routine = net_bh; bh_base[NET_BH].routine = net_bh;
enable_bh(NET_BH); enable_bh(NET_BH);
return 0; return 0;
......
/*
* NET_ALIAS device aliasing module.
*
* Version: @(#)net_alias.c 0.42 12/11/95
*
* Authors: Juan Jose Ciarlante, <jjciarla@raiz.uncu.edu.ar>
* Marcelo Fabian Roccasalva, <mfroccas@raiz.uncu.edu.ar>
*
* Features:
* - AF_ independent: net_alias_type objects
* - AF_INET optimized
* - ACTUAL alias devices inserted in dev chain
* - fast hashed alias address lookup
* - net_alias_type objs registration/unreg., module-ables.
* - /proc/net/aliases & /proc/net/alias_types entries
*
* FIXME:
* - User calls sleep/wake_up locking.
* - Define a way to select the "best" alias device for an incoming
* packet to allow xxx_rcv() device switching based ALSO on pkt's
* src address (this would require a routing query).
* Related stuff:
* IP: Test routing between aliases (possible ICMP redirects).
* IP: ARP proxy entries attached to aliases are not visible.
*
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version
* 2 of the License, or (at your option) any later version.
*
*/
#include <linux/types.h>
#include <linux/errno.h>
#include <linux/netdevice.h>
#include <linux/notifier.h>
#include <linux/if.h>
#include <linux/inet.h>
#include <linux/proc_fs.h>
#include <linux/stat.h>
#ifdef ALIAS_USER_LAND_DEBUG
#include "net_alias.h"
#include "user_stubs.h"
#endif
#include <linux/net_alias.h>
/*
* Only allow the following flags to pass from main device to aliases
*/
#define NET_ALIAS_IFF_MASK (IFF_UP|IFF_BROADCAST|IFF_RUNNING|IFF_NOARP|IFF_LOOPBACK|IFF_POINTOPOINT)
static struct net_alias_type * nat_getbytype(int type);
static int nat_attach_chg(struct net_alias_type *nat, int delta);
static int nat_bind(struct net_alias_type *nat,struct net_alias *alias, struct sockaddr *sa);
static int nat_unbind(struct net_alias_type *nat, struct net_alias *alias);
static int net_alias_devinit(struct device *dev);
static int net_alias_hard_start_xmit(struct sk_buff *skb, struct device *dev);
static int net_alias_devsetup(struct net_alias *alias, struct net_alias_type *nat, struct sockaddr *sa);
static struct net_alias **net_alias_slow_findp(struct net_alias_info *alias_info, struct net_alias *alias);
static struct device *net_alias_dev_create(struct device *main_dev, int slot, int *err, struct sockaddr *sa, void *data);
static struct device *net_alias_dev_delete(struct device *main_dev, int slot, int *err);
static void net_alias_free(struct device *dev);
/*
* net_alias_type base array, will hold net_alias_type objects.
*/
struct net_alias_type *nat_base[16];
/*
* get net_alias_type ptr by type
*/
static __inline__ struct net_alias_type *
nat_getbytype(int type)
{
struct net_alias_type *nat;
for(nat = nat_base[type & 0x0f]; nat ; nat = nat->next)
{
if (nat->type == type) return nat;
}
return NULL;
}
/*
* get addr32 representation (pre-hashing) of address.
* if NULL nat->get_addr32, assume sockaddr_in struct (IP-ish).
*/
static __inline__ __u32
nat_addr32(struct net_alias_type *nat, struct sockaddr *sa)
{
if (nat->get_addr32)
return nat->get_addr32(sa);
else
return (*(struct sockaddr_in *)sa).sin_addr.s_addr;
}
/*
* hashing code for alias_info->hash_tab entries
* 4 bytes -> 1/2 byte using xor condimented by af
*/
static __inline__ unsigned
HASH(__u32 addr, int af)
{
unsigned tmp = addr ^ (addr>>16); /* 4 -> 2 */
tmp ^= (tmp>>8); /* 2 -> 1 */
return (tmp^(tmp>>4)^af) & 0x0f; /* 1 -> 1/2 */
}
/*
* get hash key for supplied net alias type and address
* nat must be !NULL
* the purpose here is to map an net_alias_type and a generic
* address to a hash code.
*/
static __inline__ int
nat_hash_key(struct net_alias_type *nat, struct sockaddr *sa)
{
return HASH(nat_addr32(nat,sa), sa->sa_family);
}
/*
* change net_alias_type number of attachments (bindings)
*/
static int
nat_attach_chg(struct net_alias_type *nat, int delta)
{
unsigned long flags;
int n_at;
if (!nat) return -1;
save_flags(flags);
cli();
n_at = nat->n_attach + delta;
if (n_at < 0)
{
restore_flags(flags);
printk("net_alias: tried to set n_attach < 0 for (family==%d) nat object.\n",
nat->type);
return -1;
}
nat->n_attach = n_at;
restore_flags(flags);
return 0;
}
/*
* bind alias to its type (family) object and call initialization hook
*/
static __inline__ int
nat_bind(struct net_alias_type *nat,struct net_alias *alias, struct sockaddr *sa)
{
if (nat->alias_init_1) nat->alias_init_1(alias, sa);
return nat_attach_chg(nat, +1);
}
/*
* unbind alias from type object and call 'done' hook
*/
static __inline__ int
nat_unbind(struct net_alias_type *nat, struct net_alias *alias)
{
if (nat->alias_done_1) nat->alias_done_1(alias);
return nat_attach_chg(nat, -1);
}
/*
* compare device address with given. if NULL nat->addr_chk,
* compare dev->pa_addr with (sockaddr_in) 32 bits address (IP-ish)
*/
static __inline__ int nat_addr_chk(struct net_alias_type *nat,
struct device *dev, struct sockaddr *sa)
{
if (nat->addr_chk)
return nat->addr_chk(dev, sa);
else
return (dev->pa_addr == (*(struct sockaddr_in *)sa).sin_addr.s_addr);
}
/*
* alias device init()
* do nothing.
*/
static int
net_alias_devinit(struct device *dev)
{
#ifdef ALIAS_USER_LAND_DEBUG
printk("net_alias_devinit(%s) called.\n", dev->name);
#endif
return 0;
}
/*
* hard_start_xmit() should not be called.
* ignore ... but shout!.
*/
static int
net_alias_hard_start_xmit(struct sk_buff *skb, struct device *dev)
{
printk("net_alias: net_alias_hard_start_xmit() for %s called (ignored)!!\n", dev->name);
dev_kfree_skb(skb, FREE_WRITE);
return 0;
}
/*
* setups a new (alias) device
*/
static int
net_alias_devsetup(struct net_alias *alias, struct net_alias_type *nat,
struct sockaddr *sa)
{
struct device *main_dev;
struct device *dev;
int family;
int i;
/*
*
* generic device setup based on main_dev info
*
* FIXME: is NULL bitwise 0 for all Linux platforms?
*/
main_dev = alias->main_dev;
dev = &alias->dev;
memset(dev, '\0', sizeof(struct device));
family = (sa)? sa->sa_family : main_dev->family;
dev->alias_info = NULL; /* no aliasing recursion */
dev->my_alias = alias; /* point to alias */
dev->name = alias->name;
dev->type = main_dev->type;
dev->hard_header_len = main_dev->hard_header_len;
memcpy(dev->broadcast, main_dev->broadcast, MAX_ADDR_LEN);
memcpy(dev->dev_addr, main_dev->dev_addr, MAX_ADDR_LEN);
dev->addr_len = main_dev->addr_len;
dev->init = net_alias_devinit;
dev->hard_start_xmit = net_alias_hard_start_xmit;
dev->flags = main_dev->flags & NET_ALIAS_IFF_MASK & ~IFF_UP;
/*
* only makes sense if same family
*/
if (family == main_dev->family)
{
dev->metric = main_dev->metric;
dev->mtu = main_dev->mtu;
dev->pa_alen = main_dev->pa_alen;
dev->hard_header = main_dev->hard_header;
dev->rebuild_header = main_dev->rebuild_header;
}
/*
* Fill in the generic fields of the device structure.
* not actually used, avoids some dev.c #ifdef's
*/
for (i = 0; i < DEV_NUMBUFFS; i++)
skb_queue_head_init(&dev->buffs[i]);
dev->family = family;
return 0;
}
/*
* slow alias find (parse the whole hash_tab)
* returns: alias' pointer address
*/
static struct net_alias **
net_alias_slow_findp(struct net_alias_info *alias_info, struct net_alias *alias)
{
unsigned idx, n_aliases;
struct net_alias **aliasp;
/*
* for each alias_info's hash_tab entry, for every alias ...
*/
n_aliases = alias_info->n_aliases;
for (idx=0; idx < 16 ; idx++)
for (aliasp = &alias_info->hash_tab[idx];*aliasp;aliasp = &(*aliasp)->next)
if (*aliasp == alias)
return aliasp;
else
if (--n_aliases == 0) break; /* faster give up */
return NULL;
}
/*
* create alias device for main_dev with given slot num.
* if sa==NULL will create a same_family alias device
*/
static struct device *
net_alias_dev_create(struct device *main_dev, int slot, int *err, struct sockaddr *sa, void *data)
{
struct net_alias_info *alias_info;
struct net_alias *alias, **aliasp;
struct net_alias_type *nat;
struct device *dev;
unsigned long flags;
int family;
__u32 addr32;
/* FIXME: lock */
alias_info = main_dev->alias_info;
/*
* if NULL address given, take family from main_dev
*/
family = (sa)? sa->sa_family : main_dev->family;
/*
* check if wanted family has a net_alias_type object registered
*/
nat = nat_getbytype(family);
if (!nat)
{
printk("net_alias_dev_create(%s:%d): unregistered family==%d\n",
main_dev->name, slot, family);
/* *err = -EAFNOSUPPORT; */
*err = -EINVAL;
return NULL;
}
/*
* do not allow creation over downed devices
*/
*err = -EIO;
if (! (main_dev->flags & IFF_UP) )
return NULL;
/*
* if first alias, must also create alias_info
*/
*err = -ENOMEM;
if (!alias_info)
{
alias_info = kmalloc(sizeof(struct net_alias_info), GFP_KERNEL);
if (!alias_info) return NULL; /* ENOMEM */
memset(alias_info, 0, sizeof(struct net_alias_info));
}
if (!(alias = kmalloc(sizeof(struct net_alias), GFP_KERNEL)))
return NULL; /* ENOMEM */
/*
* FIXME: is NULL bitwise 0 for all Linux platforms?
*/
memset(alias, 0, sizeof(struct net_alias));
alias->slot = slot;
alias->main_dev = main_dev;
alias->nat = nat;
alias->next = NULL;
alias->data = data;
sprintf(alias->name, "%s:%d", main_dev->name, slot);
/*
* initialise alias' device structure
*/
net_alias_devsetup(alias, nat, sa);
dev = &alias->dev;
save_flags(flags);
cli();
/*
* bind alias to its object type
* nat_bind calls nat->alias_init_1
*/
nat_bind(nat, alias, sa);
/*
* if no address passed, take from device (could have been
* set by nat->alias_init_1)
*/
addr32 = (sa)? nat_addr32(nat, sa) : alias->dev.pa_addr;
/*
* store hash key in alias: will speed-up rehashing and deletion
*/
alias->hash = HASH(addr32, family);
/*
* insert alias in hashed linked list
*/
aliasp = &alias_info->hash_tab[alias->hash];
alias->next = *aliasp;
*aliasp = alias;
/*
* if first alias ...
*/
if (!alias_info->n_aliases++)
{
alias_info->taildev = main_dev;
main_dev->alias_info = alias_info;
}
/*
* add device at tail (just after last main_dev alias)
*/
dev->next = alias_info->taildev->next;
alias_info->taildev->next = dev;
alias_info->taildev = dev;
restore_flags(flags);
return dev;
}
/*
* delete one main_dev alias (referred by its slot num)
*/
static struct device *
net_alias_dev_delete(struct device *main_dev, int slot, int *err)
{
struct net_alias_info *alias_info;
struct net_alias *alias, **aliasp;
struct device *dev;
unsigned n_aliases;
unsigned long flags;
struct net_alias_type *nat;
struct device *prevdev;
/* FIXME: lock */
*err = -ENODEV;
if (main_dev == NULL) return NULL;
/*
* does main_dev have aliases?
*/
alias_info = main_dev->alias_info;
if (!alias_info) return NULL; /* ENODEV */
n_aliases = alias_info->n_aliases;
/*
* find device that holds the same slot number (could also
* be strcmp() ala dev_get).
*/
for (prevdev=main_dev, alias = NULL;prevdev->next && n_aliases; prevdev = prevdev->next)
{
if (!(alias = prevdev->next->my_alias))
{
printk("ERROR: net_alias_dev_delete(): incorrect non-alias device after maindev\n");
continue; /* or should give up? */
}
if (alias->slot == slot) break;
alias = NULL;
n_aliases--;
}
if (!alias) return NULL; /* ENODEV */
dev = &alias->dev;
/*
* find alias hashed entry
*/
for(aliasp = &alias_info->hash_tab[alias->hash]; *aliasp; aliasp = &(*aliasp)->next)
if(*aliasp == alias) break;
/*
* if not found (???), try a full search
*/
if (*aliasp != alias)
if ((aliasp = net_alias_slow_findp(alias_info, alias)))
printk("net_alias_dev_delete(%s): bad hashing recovered\n", alias->name);
else
{
printk("ERROR: net_alias_dev_delete(%s): unhashed alias!\n",alias->name);
return NULL; /* ENODEV */
}
nat = alias->nat;
save_flags(flags);
cli();
/*
* unbind alias from alias_type obj.
*/
nat_unbind(nat, alias);
/*
* is alias at tail?
*/
if ( dev == alias_info->taildev )
alias_info->taildev = prevdev;
/*
* unlink and close device
*/
prevdev->next = dev->next;
dev_close(dev);
/*
* unlink alias
*/
*aliasp = (*aliasp)->next;
if (--alias_info->n_aliases == 0) /* last alias */
main_dev->alias_info = NULL;
restore_flags(flags);
/*
* now free structures
*/
kfree_s(alias, sizeof(struct net_alias));
if (main_dev->alias_info == NULL)
kfree_s(alias_info, sizeof(struct net_alias_info));
/*
* deletion ok (*err=0), NULL device returned.
*/
*err = 0;
return NULL;
}
/*
* dev_get() with added alias naming magic.
*/
struct device *
net_alias_dev_get(char *dev_name, int aliasing_ok, int *err,
struct sockaddr *sa, void *data)
{
struct device *dev;
char *sptr,*eptr;
int slot = 0;
int delete = 0;
*err = -ENODEV;
if ((dev=dev_get(dev_name)))
return dev;
/*
* want alias naming magic?
*/
if (!aliasing_ok) return NULL;
if (!dev_name || !*dev_name)
return NULL;
/*
* find the first ':' , must be followed by, at least, 1 char
*/
for (sptr=dev_name ; *sptr ; sptr++) if(*sptr==':') break;
if (!*sptr || !*(sptr+1))
return NULL;
/*
* seems to be an alias name, fetch main device
*/
*sptr='\0';
if (!(dev=dev_get(dev_name)))
return NULL;
*sptr++=':';
/*
* fetch slot number
*/
slot = simple_strtoul(sptr,&eptr,10);
if (slot >= NET_ALIAS_MAX_SLOT)
return NULL;
/*
* if last char is '-', it is a deletion request
*/
if (eptr[0] == '-' && !eptr[1] ) delete++;
else if (eptr[0])
return NULL;
/*
* well... let's work.
*/
if (delete)
return net_alias_dev_delete(dev, slot, err);
else
return net_alias_dev_create(dev, slot, err, sa, data);
}
/*
* rehash alias with address supplied.
*/
int
net_alias_rehash(struct net_alias *alias, struct sockaddr *sa)
{
struct net_alias_info *alias_info;
struct net_alias **aliasp;
struct device *dev;
unsigned long flags;
struct net_alias_type *o_nat, *n_nat;
unsigned n_hash;
/*
* defensive ...
*/
if (!sa)
{
printk("ERROR: net_alias_rehash(): NULL sockaddr passed\n");
return -1;
}
/*
* defensive. should not happen.
*/
if (!(dev = alias->main_dev))
{
printk("ERROR: net_alias_rehash for %s: NULL maindev\n", alias->name);
return -1;
}
/*
* defensive. should not happen.
*/
if (!(alias_info=dev->alias_info))
{
printk("ERROR: net_alias_rehash for %s: NULL alias_info\n", alias->name);
return -1;
}
/*
* will the request also change device family?
*/
o_nat = alias->nat;
if (!o_nat)
{
printk("ERROR: net_alias_rehash(%s): unbound alias.\n", alias->name);
return -1;
}
/*
* point to new alias_type obj.
*/
if (o_nat->type == sa->sa_family)
n_nat = o_nat;
else
{
n_nat = nat_getbytype(sa->sa_family);
if (!n_nat)
{
printk("ERROR: net_alias_rehash(%s): unreg family==%d.\n", alias->name, sa->sa_family);
return -1;
}
}
/*
* new hash key. if same as old AND same type (family) return;
*/
n_hash = nat_hash_key(n_nat, sa);
if (n_hash == alias->hash && o_nat == n_nat )
return 0;
/*
* find alias in hashed list
*/
for (aliasp = &alias_info->hash_tab[alias->hash]; *aliasp; aliasp = &(*aliasp)->next)
if (*aliasp == alias) break;
/*
* not found (???). try a full search
*/
if(!*aliasp)
if ((aliasp = net_alias_slow_findp(alias_info, alias)))
printk("net_alias_rehash(%s): bad hashing recovered\n", alias->name);
else
{
printk("ERROR: net_alias_rehash(%s): unhashed alias!\n", alias->name);
return -1;
}
save_flags(flags);
cli();
/*
* if type (family) changed unlink from old type object (o_nat)
* will call o_nat->alias_done_1()
*/
if (o_nat != n_nat)
nat_unbind(o_nat, alias);
/*
* if diff hash key, change alias position in hashed list
*/
if (n_hash != alias->hash)
{
*aliasp = (*aliasp)->next;
alias->hash = n_hash;
aliasp = &alias_info->hash_tab[n_hash];
alias->next = *aliasp;
*aliasp = alias;
}
/*
* if type (family) changed link to new type object (n_nat)
* will call n_nat->alias_init_1()
*/
if (o_nat != n_nat)
nat_bind(n_nat, alias, sa);
restore_flags(flags);
return 0;
}
/*
* free all main device aliasing stuff
* will be called on dev_close(main_dev)
*/
static void
net_alias_free(struct device *main_dev)
{
struct net_alias_info *alias_info;
struct net_alias *alias;
struct net_alias_type *nat;
struct device *dev;
unsigned long flags;
/*
* do I really have aliases?
*/
if (!(alias_info = main_dev->alias_info)) return;
/*
* fast device link "short-circuit": set main_dev->next to
* device after last alias
*/
save_flags(flags);
cli();
dev = main_dev->next;
main_dev->next = alias_info->taildev->next;
main_dev->alias_info = NULL;
alias_info->taildev->next = NULL;
restore_flags(flags);
/*
* loop over alias devices, free and dev_close()
*/
while (dev)
{
if (net_alias_is(dev))
{
alias = dev->my_alias;
if (alias->main_dev == main_dev)
{
/*
* unbind alias from alias_type object
*/
nat = alias->nat;
if (nat)
{
nat_unbind(nat, alias);
} /* else error/printk ??? */
dev_close(dev);
dev = dev->next;
kfree_s(alias, sizeof(struct net_alias));
continue;
}
else
printk("net_alias_free(%s): '%s' is not my alias\n",
main_dev->name, alias->name);
}
else
printk("net_alias_free(%s): found a non-alias after device!\n",
main_dev->name);
dev = dev->next;
}
kfree_s(alias_info, sizeof(alias_info));
return;
}
/*
* implements /proc/net/alias_types entry
* shows net_alias_type objects registered.
*/
int net_alias_types_getinfo(char *buffer, char **start, off_t offset, int length, int dummy)
{
off_t pos=0, begin=0;
int len=0;
struct net_alias_type *nat;
unsigned idx;
len=sprintf(buffer,"type name n_attach\n");
for (idx=0 ; idx < 16 ; idx++)
for (nat = nat_base[idx]; nat ; nat = nat->next)
{
len += sprintf(buffer+len, "%-7d %-15s %-7d\n",
nat->type, nat->name,nat->n_attach);
pos=begin+len;
if(pos<offset)
{
len=0;
begin=pos;
}
if(pos>offset+length)
break;
}
*start=buffer+(offset-begin);
len-=(offset-begin);
if(len>length)
len=length;
return len;
}
/*
* implements /proc/net/aliases entry, shows alias devices.
* calls alias nat->alias_print_1 if not NULL and formats everything
* to a fixed rec. size without using local (stack) buffers
*
*/
#define NAT_REC_SIZE 64
int net_alias_getinfo(char *buffer, char **start, off_t offset, int length, int dummy)
{
off_t pos=0, begin=0;
int len=0;
int dlen;
struct net_alias_type *nat;
struct net_alias *alias;
struct device *dev;
len=sprintf(buffer,"%-*s\n",NAT_REC_SIZE-1,"device family address");
for (dev = dev_base; dev ; dev = dev->next)
if (net_alias_is(dev))
{
alias = dev->my_alias;
nat = alias->nat;
dlen=sprintf(buffer+len, "%-16s %-6d ", alias->name, alias->dev.family);
/*
* call alias_type specific print function.
*/
if (nat->alias_print_1)
dlen += nat->alias_print_1(buffer+len+dlen, NAT_REC_SIZE - dlen, alias);
else
dlen += sprintf(buffer+len+dlen, "-");
/*
* fill with spaces if needed
*/
if (dlen < NAT_REC_SIZE) memset(buffer+len+dlen, ' ', NAT_REC_SIZE - dlen);
/*
* truncate to NAT_REC_SIZE
*/
len += NAT_REC_SIZE;
buffer[len-1] = '\n';
pos=begin+len;
if(pos<offset)
{
len=0;
begin=pos;
}
if(pos>offset+length)
break;
}
*start=buffer+(offset-begin);
len-=(offset-begin);
if(len>length)
len=length;
return len;
}
/*
* notifier for devices events
*/
int net_alias_device_event(struct notifier_block *this, unsigned long event, void *ptr)
{
struct device *dev = ptr;
if (event == NETDEV_DOWN)
{
#ifdef ALIAS_USER_LAND_DEBUG
printk("net_alias: NETDEV_DOWN for %s received\n", dev->name);
#endif
if (net_alias_has(dev))
net_alias_free(dev);
}
if (event == NETDEV_UP)
{
#ifdef ALIAS_USER_LAND_DEBUG
printk("net_alias: NETDEV_UP for %s received\n", dev->name);
#endif
dev->alias_info = 0;
}
return NOTIFY_DONE;
}
/*
* returns alias device with specified address AND flags_1 on AND flags_0 off.
* intended for main devices.
* typically called on xxx_rcv() to check if packet's dest address is one
* of main_dev's alias address.
*/
struct device *
net_alias_chk(struct device *dev, struct sockaddr *sa,int flags_1, int flags_0)
{
struct net_alias_info *alias_info = dev->alias_info;
struct net_alias_type *nat;
struct net_alias *alias;
if (!alias_info) return NULL; /* has aliases? */
/*
* get alias_type object for sa->sa_family.
*/
nat = nat_getbytype(sa->sa_family);
if (!nat)
return 0;
for(alias = alias_info->hash_tab[nat_hash_key(nat,sa)];
alias; alias = alias->next)
{
if (alias->dev.family != sa->sa_family) continue;
/*
* nat_addr_chk will call type specific address cmp function.
*/
if (alias->dev.flags & flags_1 && !(alias->dev.flags & flags_0) &&
nat_addr_chk(nat,&alias->dev,sa))
return &alias->dev;
}
return NULL;
}
/*
* addr_chk enough for protocols whose addr is (fully) stored at pa_addr.
*/
struct device *
net_alias_chk32(struct device *dev, int family, __u32 addr32,
int flags_1, int flags_0)
{
struct net_alias_info *alias_info = dev->alias_info;
struct net_alias *alias;
if (!alias_info) return NULL; /* has aliases? */
for (alias=alias_info->hash_tab[HASH(addr32,family)];
alias; alias=alias->next)
{
if (alias->dev.family != family) continue;
/*
* "hard" (static) comparison between addr32 and pa_addr.
*/
if (alias->dev.flags & flags_1 && !(alias->dev.flags & flags_0) &&
addr32 == alias->dev.pa_addr)
return &alias->dev;
}
return NULL;
}
/*
* device event hook
*/
static struct notifier_block net_alias_dev_notifier = {
net_alias_device_event,
NULL,
0
};
/*
* net_alias initialisation
* called from net_dev_init().
*/
void net_alias_init(void)
{
/*
* register dev events notifier
*/
register_netdevice_notifier(&net_alias_dev_notifier);
/*
* register /proc/net entries
*/
#ifndef ALIAS_USER_LAND_DEBUG
proc_net_register(&(struct proc_dir_entry) {
PROC_NET_ALIAS_TYPES, 11, "alias_types",
S_IFREG | S_IRUGO, 1, 0, 0,
0, &proc_net_inode_operations,
net_alias_types_getinfo
});
proc_net_register(&(struct proc_dir_entry) {
PROC_NET_ALIASES, 7, "aliases",
S_IFREG | S_IRUGO, 1, 0, 0,
0, &proc_net_inode_operations,
net_alias_getinfo
});
#endif
}
/*
* net_alias type object registering func.
*/
int register_net_alias_type(struct net_alias_type *nat, int type)
{
unsigned hash;
unsigned long flags;
if (!nat)
{
printk("register_net_alias_type(): NULL arg\n");
return -EINVAL;
}
nat->type = type;
nat->n_attach = 0;
hash = nat->type & 0x0f;
save_flags(flags);
cli();
nat->next = nat_base[hash];
nat_base[hash] = nat;
restore_flags(flags);
return 0;
}
/*
* net_alias type object unreg.
*/
int unregister_net_alias_type(struct net_alias_type *nat)
{
struct net_alias_type **natp;
unsigned hash;
unsigned long flags;
if (!nat)
{
printk("unregister_net_alias_type(): NULL arg\n");
return -EINVAL;
}
/*
* only allow unregistration if it has no attachments
*/
if (nat->n_attach)
{
printk("unregister_net_alias_type(): has %d attachments. failed\n",
nat->n_attach);
return -EINVAL;
}
hash = nat->type & 0x0f;
save_flags(flags);
cli();
for (natp = &nat_base[hash]; *natp ; natp = &(*natp)->next)
{
if (nat==(*natp))
{
*natp = nat->next;
restore_flags(flags);
return 0;
}
}
restore_flags(flags);
printk("unregister_net_alias_type(type=%d): not found!\n", nat->type);
return -EINVAL;
}
...@@ -17,6 +17,9 @@ if [ "$CONFIG_IP_FORWARD" = "y" ]; then ...@@ -17,6 +17,9 @@ if [ "$CONFIG_IP_FORWARD" = "y" ]; then
bool 'IP: multicast routing(in progress)' CONFIG_IP_MROUTE bool 'IP: multicast routing(in progress)' CONFIG_IP_MROUTE
fi fi
fi fi
if [ "$CONFIG_NET_ALIAS" = "y" ]; then
tristate 'IP: aliasing support' CONFIG_IP_ALIAS
fi
comment '(it is safe to leave these untouched)' comment '(it is safe to leave these untouched)'
bool 'IP: PC/TCP compatibility mode' CONFIG_INET_PCTCP bool 'IP: PC/TCP compatibility mode' CONFIG_INET_PCTCP
tristate 'IP: Reverse ARP' CONFIG_INET_RARP tristate 'IP: Reverse ARP' CONFIG_INET_RARP
......
...@@ -36,6 +36,14 @@ else ...@@ -36,6 +36,14 @@ else
endif endif
endif endif
ifeq ($(CONFIG_IP_ALIAS),y)
IPV4_OBJS += ip_alias.o
else
ifeq ($(CONFIG_IP_ALIAS),m)
M_OBJS += ip_alias.o
endif
endif
ifdef CONFIG_INET ifdef CONFIG_INET
O_OBJS := $(IPV4_OBJS) O_OBJS := $(IPV4_OBJS)
endif endif
......
...@@ -88,6 +88,9 @@ ...@@ -88,6 +88,9 @@
#include <net/raw.h> #include <net/raw.h>
#include <net/icmp.h> #include <net/icmp.h>
#include <linux/ip_fw.h> #include <linux/ip_fw.h>
#ifdef CONFIG_IP_ALIAS
#include <net/ip_alias.h>
#endif
#define min(a,b) ((a)<(b)?(a):(b)) #define min(a,b) ((a)<(b)?(a):(b))
...@@ -1530,6 +1533,13 @@ void inet_proto_init(struct net_proto *pro) ...@@ -1530,6 +1533,13 @@ void inet_proto_init(struct net_proto *pro)
ip_mr_init(); ip_mr_init();
#endif #endif
/*
* Initialise AF_INET alias type (register net_alias_type)
*/
#if defined(CONFIG_IP_ALIAS)
ip_alias_init();
#endif
/* /*
* Create all the /proc entries. * Create all the /proc entries.
*/ */
......
...@@ -96,6 +96,9 @@ ...@@ -96,6 +96,9 @@
#include <net/netrom.h> #include <net/netrom.h>
#endif #endif
#endif #endif
#ifdef CONFIG_NET_ALIAS
#include <linux/net_alias.h>
#endif
#include <asm/system.h> #include <asm/system.h>
#include <asm/segment.h> #include <asm/segment.h>
...@@ -891,6 +894,19 @@ int arp_rcv(struct sk_buff *skb, struct device *dev, struct packet_type *pt) ...@@ -891,6 +894,19 @@ int arp_rcv(struct sk_buff *skb, struct device *dev, struct packet_type *pt)
* cache. * cache.
*/ */
/*
* try to switch to alias device whose address is tip, if any
*/
#ifdef CONFIG_NET_ALIAS
if (net_alias_has(dev))
{
struct device *adev;
adev = net_alias_chk32(dev,AF_INET,tip,IFF_UP,IFF_NOARP);
if (adev != NULL) dev = adev;
}
#endif
if (arp->ar_op == htons(ARPOP_REQUEST)) if (arp->ar_op == htons(ARPOP_REQUEST))
{ {
/* /*
...@@ -1019,7 +1035,15 @@ int arp_rcv(struct sk_buff *skb, struct device *dev, struct packet_type *pt) ...@@ -1019,7 +1035,15 @@ int arp_rcv(struct sk_buff *skb, struct device *dev, struct packet_type *pt)
entry->timer.data = (unsigned long)entry; entry->timer.data = (unsigned long)entry;
memcpy(entry->ha, sha, dev->addr_len); memcpy(entry->ha, sha, dev->addr_len);
entry->last_updated = entry->last_used = jiffies; entry->last_updated = entry->last_used = jiffies;
/*
* make entry point to 'correct' device
*/
#ifdef CONFIG_NET_ALIAS
entry->dev = dev;
#else
entry->dev = skb->dev; entry->dev = skb->dev;
#endif
skb_queue_head_init(&entry->skb); skb_queue_head_init(&entry->skb);
if (arp_lock == 1) if (arp_lock == 1)
{ {
......
#include <linux/module.h>
#include <linux/types.h>
#include <linux/errno.h>
#include <linux/netdevice.h>
#include <linux/if.h>
#include <linux/inet.h>
#ifdef ALIAS_USER_LAND_DEBUG
#include "net_alias.h"
#include "ip_alias.h"
#include "user_stubs.h"
#endif
#include <linux/net_alias.h>
#include <net/ip_alias.h>
/*
* AF_INET alias init
*/
static int
ip_alias_init_1(struct net_alias *alias, struct sockaddr *sa)
{
#ifdef ALIAS_USER_LAND_DEBUG
printk("alias_init(%s) called.\n", alias->name);
#endif
MOD_INC_USE_COUNT;
return 0;
}
/*
* AF_INET alias done
*/
static int
ip_alias_done_1(struct net_alias *alias)
{
#ifdef ALIAS_USER_LAND_DEBUG
printk("alias_done(%s) called.\n", alias->name);
#endif
MOD_DEC_USE_COUNT;
return 0;
}
/*
* print address info
*/
int
ip_alias_print_1(char *buf, int len, struct net_alias *alias)
{
char *p;
p = (char *) &alias->dev.pa_addr;
return sprintf(buf, "%d.%d.%d.%d",
(p[0] & 255), (p[1] & 255), (p[2] & 255), (p[3] & 255));
}
/*
* net_alias AF_INET type defn.
*/
struct net_alias_type ip_alias_type =
{
AF_INET, /* type */
0, /* n_attach */
"ip", /* name */
NULL, /* get_addr32() */
NULL, /* addr_chk() */
ip_alias_init_1, /* alias_init_1() */
ip_alias_done_1, /* alias_done_1() */
ip_alias_print_1, /* alias_print_1() */
NULL /* next */
};
/*
* ip_alias module initialization
*/
int ip_alias_init(void)
{
return register_net_alias_type(&ip_alias_type, AF_INET);
}
/*
* ip_alias module done
*/
int ip_alias_done(void)
{
return unregister_net_alias_type(&ip_alias_type);
}
#ifdef MODULE
int init_module(void)
{
if (ip_alias_init() != 0)
return -EIO;
return 0;
}
void cleanup_module(void)
{
if (ip_alias_done() != 0)
printk("ip_alias: can't remove module");
}
#endif /* MODULE */
...@@ -151,6 +151,9 @@ ...@@ -151,6 +151,9 @@
#include <linux/firewall.h> #include <linux/firewall.h>
#include <linux/mroute.h> #include <linux/mroute.h>
#include <net/netlink.h> #include <net/netlink.h>
#ifdef CONFIG_NET_ALIAS
#include <linux/net_alias.h>
#endif
extern int last_retran; extern int last_retran;
extern void sort_send(struct sock *sk); extern void sort_send(struct sock *sk);
...@@ -313,7 +316,18 @@ int ip_rcv(struct sk_buff *skb, struct device *dev, struct packet_type *pt) ...@@ -313,7 +316,18 @@ int ip_rcv(struct sk_buff *skb, struct device *dev, struct packet_type *pt)
* function entry. * function entry.
*/ */
/*
* also check device aliases address : will avoid
* a full lookup over device chain
*/
#ifdef CONFIG_NET_ALIAS
if ( iph->daddr == skb->dev->pa_addr ||
( net_alias_has(skb->dev) && net_alias_addr_chk32(skb->dev,AF_INET, iph->daddr )) ||
(brd = ip_chk_addr(iph->daddr)) != 0)
#else
if ( iph->daddr == skb->dev->pa_addr || (brd = ip_chk_addr(iph->daddr)) != 0) if ( iph->daddr == skb->dev->pa_addr || (brd = ip_chk_addr(iph->daddr)) != 0)
#endif
{ {
if (opt && opt->srr) if (opt && opt->srr)
{ {
......
...@@ -20,6 +20,8 @@ ...@@ -20,6 +20,8 @@
# 180995 Bernhard Kaindl (bkaindl@ping.at) - added dummy functions for # 180995 Bernhard Kaindl (bkaindl@ping.at) - added dummy functions for
# use with a config.in modified for make menuconfig. # use with a config.in modified for make menuconfig.
# #
# 301195 (boldt@math.ucsb.edu) - added help text support
#
# #
# Make sure we're really running bash. # Make sure we're really running bash.
...@@ -44,6 +46,37 @@ function mainmenu_name () { ...@@ -44,6 +46,37 @@ function mainmenu_name () {
: :
} }
#
# help prints the corresponding help text from Configure.help to stdout
#
# help variable
#
function help () {
if [ -f Documentation/Configure.help ]
then
#first escape regexp special characters in the argument:
var=$(echo "$1"|sed 's/[][\/.^$*]/\\&/g')
#now pick out the right help text:
text=$(sed -n "/^$var[ ]*\$/,\${
/^$var[ ]*\$/b
/^#.*/b;/^[ ]*\$/q
p
}" Documentation/Configure.help)
if [ -z "$text" ]
then
echo; echo " Sorry, no help available for this option yet.";echo
else
(echo; echo "$text"; echo) | more
fi
else
echo;
echo " Can't access the file Documentation/Configure.help which"
echo " should contain the help texts."
echo
fi
}
# #
# readln reads a line into $ans. # readln reads a line into $ans.
# #
...@@ -78,17 +111,17 @@ function comment () { ...@@ -78,17 +111,17 @@ function comment () {
# #
function define_bool () { function define_bool () {
case "$2" in case "$2" in
"y" | "Y") "y")
echo "$1=y" >>$CONFIG echo "$1=y" >>$CONFIG
echo "#define $1 1" >>$CONFIG_H echo "#define $1 1" >>$CONFIG_H
;; ;;
"m" | "M") "m")
echo "$1=m" >>$CONFIG echo "$1=m" >>$CONFIG
echo "#undef $1" >>$CONFIG_H echo "#undef $1" >>$CONFIG_H
;; ;;
"n" | "N") "n")
echo "# $1 is not set" >>$CONFIG echo "# $1 is not set" >>$CONFIG
echo "#undef $1" >>$CONFIG_H echo "#undef $1" >>$CONFIG_H
;; ;;
...@@ -102,18 +135,24 @@ function define_bool () { ...@@ -102,18 +135,24 @@ function define_bool () {
# bool question define # bool question define
# #
function bool () { function bool () {
ans=""
def=$(eval echo "\${$2:-'n'}") def=$(eval echo "\${$2:-'n'}")
case "$def" in case "$def" in
"y") defprompt="Y/n" "y") defprompt="Y/n/?"
;; ;;
"n") defprompt="N/y" "n") defprompt="N/y/?"
;; ;;
esac esac
while [ "$ans" != "y" -a "$ans" != "n" ]; do while :; do
readln "$1 ($2) [$defprompt] " "$def" readln "$1 ($2) [$defprompt] " "$def"
case "$ans" in
[yY] | [yY]es ) define_bool "$2" "y"
break;;
[nN] | [nN]o ) define_bool "$2" "n"
break;;
* ) help "$2"
;;
esac
done done
define_bool "$2" "$ans"
} }
# #
...@@ -122,20 +161,28 @@ function bool () { ...@@ -122,20 +161,28 @@ function bool () {
# tristate question define # tristate question define
# #
function tristate () { function tristate () {
ans=""
def=$(eval echo "\${$2:-'n'}") def=$(eval echo "\${$2:-'n'}")
case "$def" in case "$def" in
"y") defprompt="Y/m/n" "y") defprompt="Y/m/n/?"
;; ;;
"m") defprompt="M/n/y" "m") defprompt="M/n/y/?"
;; ;;
"n") defprompt="N/y/m" "n") defprompt="N/y/m/?"
;; ;;
esac esac
while [ "$ans" != "y" -a "$ans" != "n" -a "$ans" != "m" ]; do while :; do
readln "$1 ($2) [$defprompt] " "$def" readln "$1 ($2) [$defprompt] " "$def"
case "$ans" in
[yY] | [yY]es ) define_bool "$2" "y"
break ;;
[nN] | [nN]o ) define_bool "$2" "n"
break ;;
[mM] ) define_bool "$2" "m"
break ;;
* ) help "$2"
;;
esac
done done
define_bool "$2" "$ans"
} }
# #
...@@ -153,18 +200,32 @@ function dep_tristate () { ...@@ -153,18 +200,32 @@ function dep_tristate () {
if [ "$3" != "m" ]; then if [ "$3" != "m" ]; then
tristate "$1" "$2" tristate "$1" "$2"
else else
ans=""
case "$def" in case "$def" in
"y" | "m") defprompt="M/n" "y" | "m") defprompt="M/n/?"
def="m" def="m"
;; ;;
"n") defprompt="N/m" "n") defprompt="N/m/?"
;; ;;
esac esac
while [ "$ans" != "n" -a "$ans" != "m" ]; do while :; do
readln "$1 ($2) [$defprompt] " "$def" readln "$1 ($2) [$defprompt] " "$def"
case "$ans" in
[nN] | [nN]o ) define_bool "$2" "n"
break ;;
[mM] ) define_bool "$2" "m"
break ;;
[yY] | [yY]es ) echo
echo " This answer is not allowed, because it is not consistent with"
echo " your other choices."
echo " This driver depends on another one which you chose to compile"
echo " as a module. This means that you can either compile this one"
echo " as a module as well (with M) or leave it out altogether (N)."
echo
;;
* ) help "$2"
;;
esac
done done
define_bool "$2" "$ans"
fi fi
} }
...@@ -185,13 +246,17 @@ function define_int () { ...@@ -185,13 +246,17 @@ function define_int () {
# int question define default # int question define default
# #
function int () { function int () {
# Slimier hack to get bash to rescan a line.
ans="x"
def=$(eval echo "\${$2:-$3}") def=$(eval echo "\${$2:-$3}")
while [ $[$ans+0] != "$ans" ]; do while :; do
readln "$1 ($2) [$def] " "$def" readln "$1 ($2) [$def] " "$def"
done case "$ans" in
[1-9] | [1-9][0-9] | [1-9][0-9][0-9] | [1-9][0-9][0-9][0-9] )
define_int "$2" "$ans" define_int "$2" "$ans"
break;;
* ) help "$2"
;;
esac
done
} }
# #
...@@ -216,6 +281,7 @@ function choice () { ...@@ -216,6 +281,7 @@ function choice () {
# determine default answer: # determine default answer:
names="" names=""
set -- $choices set -- $choices
firstvar=$2
while [ -n "$2" ]; do while [ -n "$2" ]; do
if [ -n "$names" ]; then if [ -n "$names" ]; then
names="$names, $1" names="$names, $1"
...@@ -230,22 +296,24 @@ function choice () { ...@@ -230,22 +296,24 @@ function choice () {
val="" val=""
while [ -z "$val" ]; do while [ -z "$val" ]; do
ambg=n
readln "$question ($names) [$def] " "$def" readln "$question ($names) [$def] " "$def"
ans=$(echo $ans | tr a-z A-Z) ans=$(echo $ans | tr a-z A-Z)
set -- $choices set -- $choices
val=""
while [ -n "$1" ]; do while [ -n "$1" ]; do
name=$(echo $1 | tr a-z A-Z) name=$(echo $1 | tr a-z A-Z)
case "$name" in case "$name" in
${ans}*) "$ans"* )
if [ "$name" = "$ans" ]; then if [ "$name" = "$ans" ]; then
val="$2" val="$2"
break # stop on exact match break # stop on exact match
fi fi
if [ -n "$val" ]; then if [ -n "$val" ]; then
echo \ echo;echo \
" Sorry, \"$ans\" is ambiguous; please enter a longer string." " Sorry, \"$ans\" is ambiguous; please enter a longer string."
echo
val="" val=""
ambg=y
break break
else else
val="$2" val="$2"
...@@ -253,6 +321,9 @@ function choice () { ...@@ -253,6 +321,9 @@ function choice () {
esac esac
shift; shift shift; shift
done done
if [ "$val" = "" -a "$ambg" = "n" ]; then
help "$firstvar"
fi
done done
set -- $choices set -- $choices
while [ -n "$2" ]; do while [ -n "$2" ]; do
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment