@@ -122,6+122,14 @@ E: hennus@sky.ow.nl [My uucp-fed Linux box at home] D: Author and maintainer of the QIC-02 tape driver
S: The Netherlands
+N: Thomas Bogendoerfer
+E: tsbogend@bigbug.franken.de
+D: Lance32 driver
+D: strace for Linux/Alpha
+S: Baumgartenweg 5
+S: 91452 Wilhermsdorf
+S: Germany
+
N: Ross Biro
E: bir7@leland.Stanford.Edu
D: Original author of the Linux networking code
@@ -424,14+432,6 @@ S: 906-1001 Bay St. S: Toronto, Ontario, M5S 3A6
S: Canada
-N: Miquel van Smoorenburg
-E: miquels@cistron.nl
-D: Kernel and net hacker. Sysvinit, minicom. doing Debian stuff.
-S: Cistron Internet Services
-S: PO-Box 297
-S: 2400 AG, Alphen aan den Rijn
-S: The Netherlands
-
N: Danny ter Haar
E: dth@cistron.nl
D: /proc/procinfo, reboot on panic , kernel pre-patch tester ;)
@@ -1086,6+1086,14 @@ D: HPFS filesystem S: Richardson, Texas
S: USA
+N: Miquel van Smoorenburg
+E: miquels@cistron.nl
+D: Kernel and net hacker. Sysvinit, minicom. doing Debian stuff.
+S: Cistron Internet Services
+S: PO-Box 297
+S: 2400 AG, Alphen aan den Rijn
+S: The Netherlands
+
N: Scott Snyder
E: snyder@fnald0.fnal.gov
D: ATAPI cdrom driver
@@ -45,7+45,7 @@ CONFIG_EXPERIMENTAL internals are usually welcomed by the developers. Unless you intend
to help test and develop a feature or driver that falls into this
category, you should probably say N here, which will cause this
- configure script to present you with less choices. If you say Y here,
+ configure script to present you with fewer choices. If you say Y here,
you will be offered the choice of using features or drivers that are
currently considered to be in the alpha-test phase.
@@ -1261,7+1261,7 @@ CONFIG_SCSI_DTC3280 kernel whenever you want). If you want to compile it as a module,
say M here and read Documentation/modules.txt.
-EATA-DMA (DPT, NEC, ATT, Olivetti for ISA, EISA, PCI) support
+EATA-DMA (DPT, NEC, AT&T, SNI, AST, Olivetti, Alphatronix) support
CONFIG_SCSI_EATA_DMA
This is support for the EATA-DMA protocol compliant SCSI Host Adaptors
like the SmartCache III/IV, SmartRAID controller families and the DPT
@@ -14,7+14,7 @@ o Test for B stepping processors. o Clean up processor specific/independent split.
o Document it all. [PARTLY DONE]
o Halt other CPU's on reset/panic doesn't always work.
-o Dont waste page at 4K - dont need it now.(watch the GDT code).
+o Don't waste page at 4K - don't need it now.(watch the GDT code).
o Dump bootup pages once booted somehow.
o Clean up warnings/volatiles.
o Fix load_TR() for non contiguous processor ids
@@ -42,7+42,7 @@ foo \kill}% %
\title{{\bf Linux Allocated Devices}}
\author{Maintained by H. Peter Anvin $<$hpa@zytor.com$>$}
-\date{Last revised: April 20, 1996}
+\date{Last revised: May 5, 1996}
\maketitle
%
\noindent
@@ -156,6+156,7 @@ least not without contacting me first. \major{39}{}{char }{ML-16P experimental I/O board}
\major{ }{}{block}{Reserved for Linux/AP+}
\major{40}{}{char }{Matrox Meteor frame grabber}
+\major{ }{}{block}{Syquest EZ135 removable drive}
\major{41}{}{char }{Yet Another Micro Monitor}
\major{42}{}{}{Demo/sample use}
\major{43}{}{char }{isdn4linux virtual modem}
@@ -165,7+166,8 @@ least not without contacting me first. \major{47}{}{char }{Comtrol Rocketport serial card -- alternate devices}
\major{48}{}{char }{SDL RISCom serial card}
\major{49}{}{char }{SDL RISCom serial card -- alternate devices}
-\major{50}{--59}{}{Unallocated}
+\major{50}{}{char }{Reserved for GLINT}
+\major{51}{--59}{}{Unallocated}
\major{60}{--63}{}{Local/experimental use}
\major{64}{--119}{}{Unallocated}
\major{120}{--127}{}{Local/experimental use}
@@ -942,8+944,15 @@ networking device. \begin{devicelist}
\major{40}{}{char }{Matrox Meteor frame grabber}
\minor{0}{/dev/mmetfgrab}{Matrox Meteor frame grabber}
+\\
+\major{ }{}{block}{Syquest EZ135 removable drive}
+ \minor{0}{/dev/eza}{First EZ135 drive whole disk}
\end{devicelist}
+\noindent
+Partitions are handled the same way as for IDE disks (see major number
+3).
+
\begin{devicelist}
\major{41}{}{char }{Yet Another Micro Monitor}
\minor{0}{/dev/yamm}{Yet Another Micro Monitor}
Maintained by H. Peter Anvin <hpa@zytor.com>
- Last revised: April 20, 1996
+ Last revised: May 5, 1996
This list is the successor to Rick Miller's Linux Device List, which
he stopped maintaining when he got busy with other things in 1993. It
@@ -621,6+621,8 @@ least not without contacting me first. and "user level packet I/O." This board is also
accessible as a standard networking "eth" device.
+ block Reserved for Linux/AP+
+
39 char ML-16P experimental I/O board
0 = /dev/ml16pa-a0 First card, first analog channel
1 = /dev/ml16pa-a1 First card, second analog channel
@@ -643,7+645,11 @@ least not without contacting me first.
40 char Matrox Meteor frame grabber
0 = /dev/mmetfgrab Matrox Meteor frame grabber
- block Reserved for Linux/AP+
+ block Syquest EZ135 removable drive
+ 0 = /dev/eza First EZ135 drive, whole disk
+
+ Partitions are handled in the same way as IDE disks
+ (see major number 3).
41 char Yet Another Micro Monitor
0 = /dev/yamm Yet Another Micro Monitor
+Amiga filesystems Overview
+==========================
+
+Not all varieties of the Amiga filesystems are supported. The Amiga
+currently knows 6 different filesystems:
+
+DOS\0 The old or original filesystem, not really suited for
+ hard disks and normally not used on them, either.
+ Not supported.
+
+DOS\1 The original Fast File System. Supported.
+
+DOS\2 The old "international" filesystem. International means that
+ a bug has been fixed so that accented ("international") letters
+ in file names are case-insensitive, as they ought to be.
+ Not supported.
+
+DOS\3 The "international" Fast File System. Supported.
+
+DOS\4 The original filesystem with directory cache. The directory
+ cache speeds up directory accesses on floppies considerably,
+ but slowes down file creation/deletion. Doesn't make much
+ sense on hard disks. Not supported.
+
+DOS\5 The Fast File System with directory cache. Not supported.
+
+All of the above filesystems allow block sizes from 512 to 32K bytes.
+Supported block sizes are: 512, 1024, 2048 and 4096 bytes. Larger blocks
+speed up almost everything with the expense of wasted disk space. The speed
+gain above 4K seems not really worth the price, so you don't lose too
+much here, either.
+
+Mount options for the AFFS
+==========================
+
+protect If this option is set, the protection bits cannot be altered.
+
+uid[=uid] This sets the uid of the root directory (i. e. the mount point
+ to uid or to the uid of the current user, if the =uid is
+ ommitted.
+
+gid[=gid] Same as above, but for gid.
+
+setuid[=uid] This sets the owner of all files and directories in the file
+ system to uid or the uid of the current user, respectively.
+
+setgid[=gid] Same as above, but for gid.
+
+use_mp The uid and gid are taken from the now covered mount point
+ instead of the current user or value defined.
+
+mode=mode Sets the mode flags to the given (octal) value, regardles
+ of the original permissions. Directories will get an x
+ permission, if the corresponding r bit is set.
+ This is useful since most of the plain AmigaOS files
+ will map to 600.
+
+reserved=num Sets the number of reserved blocks at the start of the
+ partition to num. Default is 2.
+
+root=block Sets the block number of the root block. This schould never
+ be neccessary.
+
+bs=blksize Sets the blocksize to blksize. Valid block sizes are 512,
+ 1024, 2048 and 4096. Like the root option, this should
+ never be neccessary, as the affs can figure it out itself.
+
+quiet The file system will not return an error for disallowed
+ mode changes.
+
+Handling of the Users/Groups and protection flags
+=================================================
+
+Amiga -> Linux:
+
+The Amiga protection flags RWEDRWEDHSPARWED are handled as follows:
+
+ - R maps to r for user, group and others. On directories, R implies x.
+
+ - If both W and D are allowed, w will be set.
+
+ - If both R and S are set, x will be set.
+
+ - H, P and E are always retained and ignored under Linux.
+
+ - A is always reset when written.
+
+User id and group id will be used unless set[gu]id are given as mount
+options. Since most of the Amiga file systems are single user systems
+they will be owned by root.
+
+Linux -> Amiga:
+
+The Linux rwxrwxrwx file mode is handled as follows:
+
+ - r permission will set R for user, group and others.
+
+ - w permission will set W and D for user, group and others.
+
+ - x permission of the user will set S for plain files.
+
+ - All other flags (suid, sgid, ...) are ignored and will
+ not be retained.
+
+Newly created files and directories will get the user and group id
+of the current user and a mode according to the umask.
Linux can read, but not write, Amiga FFS partitions.
Mount options are
--- /dev/null
+Ioctl Numbers
+6 May 1996
+Michael Chastain
+<mec@duracef.shout.net>
+
+If you are adding new ioctl's to the kernel, you should use the _IO
+macros defined in <linux/ioctl.h>:
+
+ _IO an ioctl with no parameters
+ _IOW an ioctl with write parameters (from user's point of view)
+ _IOR an ioctl with read parameters (from user's point of view)
+ _IOWR an ioctl with both write and read parameters.
+
+'Write' and 'read' are from the user's point of view. This is like the
+system calls 'write' and 'read'. For example, a SET_FOO ioctl would be
+_IOW, although the kernel would actually read data from user space; a
+GET_FOO ioctl would be _IOR, although the kernel would actually write
+data to user space.
+
+The first argument to _IO, _IOW, _IOR, or _IOWR is an identifying letter
+or number from the table below. If you are writing a driver for a new
+device and need a letter, pick an unused letter. You can register the
+letter by patching this file and submitting the patch to Linus Torvalds.
+Or you can e-mail me at <mec@duracef.shout.net> and I'll register one
+for you.
+
+The second argument to _IO, _IOW, _IOR, or _IOWR is a sequence number
+to distinguish ioctls from each other. The third argument is a size
+of the structure going into the kernel or coming out of the kernel.
+
+Some devices use their major number as the identifier; this is not
+recommended. Some devices are even more irregular and don't follow
+the convention at all.
+
+Following the convention is good because:
+
+(1) Keeping the ioctl's globally unique helps error checking:
+ if a program calls an ioctl on the wrong device, it will get an
+ error rather than some unexpected behaviour.
+
+(2) The 'strace' build procedure automatically finds ioctl numbers
+ defined with _IO, _IOW, _IOR, or _IOWR.
+
+(3) 'strace' can decode numbers back into useful names when the
+ numbers are unique.
+
+(4) People looking for ioctls can grep for them more easily when
+ the convention is used to define the ioctl numbers.
+
+(5) When following the convention, the driver code can use generic
+ code to call verify_area to validate parameters.
+
+This table is current to Linux 1.3.98.
+
+Ioctl Include File Comments
+========================================================
+0x00 linux/fs.h only FIBMAP, FIGETBSZ
+0x00 linux/random.h codes in 0x010800NN
+0x00 linux/mc146818rtc.h conflict!
+0x02 linux/fd.h
+0x03 linux/hdreg.h
+0x04 linux/umsdos_fs.h
+0x06 linux/lp.h
+0x09 linux/md.h
+0x12 linux/fs.h
+0x20 linux/cm206.h
+0x22 linux/scc.h conflict!
+0x22 scsi/sg.h conflict!
+'A' linux/apm_bios.h
+'C' linux/soundcard.h
+'F' linux/fb.h
+'I' linux/isdn.h
+'K' linux/kd.h
+'L' linux/loop.h
+'M' linux/soundcard.h
+'P' linux/soundcard.h
+'Q' linux/soundcard.h
+'S' linux/cdrom.h conflict!
+'S' scsi/scsi.h conflict!
+'S' scsi/scsi_ioctl.h conflict!
+'T' linux/soundcard.h conflict!
+'T' asm/ioctls.h conflict!
+'V' linux/vt.h
+'Y' linux/cyclades.h codes in 0x004359NN
+'a' various, see http://lrcwww.epfl.ch/linux-atm/magic.html
+'c' linux/comstats.h
+'f' linux/ext2_fs.h
+'m' linux/mtio.h conflict!
+'m' linux/soundcard.h conflict!
+'n' linux/ncp_fs.h
+'r' linux/msdos_fs.h
+'s' linux/cdk.h
+'t' linux/if_ppp.h no conflict
+'t' linux/isdn_ppp.h no conflict
+'u' linux/smb_fs.h
+'v' linux/ext2_fs.h
+0x89 asm/sockios.h no conflict
+0x89 linux/sockios.h no conflict
@@ -48,7+48,7 @@ Description of the Interface between Linklevel and Hardwarelevel
To be preset by the HL-driver, if it supports sk_buff's. The driver
should put here the amount of additional space needed in sk-buff's for
- it's internal purposes. Drivers not supporting sk_buff's should put
+ its internal purposes. Drivers not supporting sk_buff's should put
initialize this field to 0.
void (*rcvcallb)(int, int, u_char*, int);
@@ -68,7+68,7 @@ Description of the Interface between Linklevel and Hardwarelevel
This field will be set by LL. The HL-driver delivers received data-
packets by calling this function. Upon calling, the HL-driver must
- already have it's private data pulled off the head of the sk_buff.
+ already have its private data pulled off the head of the sk_buff.
Parameter:
int driver-Id
@@ -83,8+83,8 @@ Description of the Interface between Linklevel and Hardwarelevel Parameter:
isdn_ctrl*
- The struct isdn_ctrl also defined in isdn_if. The exact meaning of it's
- fields is described together with the descriptions of the possible
+ The struct isdn_ctrl also defined in isdn_if. The exact meanings of its
+ fields are described together with the descriptions of the possible
events. Here is only a short description of the fields:
driver = driver Id.
@@ -196,7+196,7 @@ NOTE on writebuf and writebuf_skb: char id[20];
***CHANGE0.7: New since this version.
- This string has to be preset by the HL-driver. It's purpose is for
+ This string has to be preset by the HL-driver. Its purpose is for
identification of the driver by the user. Eg.: it is shown in the
status-info of /dev/isdninfo. Furthermore it is used as Id for binding
net-interfaces to a specific channel. If a string of length zero is
@@ -308,7+308,7 @@ README for the ISDN-subsystem 3.2.1 Teles driver.
The module teles.o can be configured during "insmod'ing" it by
- appending it's parameters to the insmod-commandline. The following
+ appending its parameters to the insmod-commandline. The following
syntax is accepted:
io=m0,i0,p0,d0[,m1,i1,p1,d1 ... ,mn,in,pn,dn] teles_id=idstring
@@ -323,7+323,7 @@ README for the ISDN-subsystem 3.2.2 ICN driver.
The module icn.o can be configured during "insmod'ing" it by
- appending it's parameters to the insmod-commandline. The following
+ appending its parameters to the insmod-commandline. The following
syntax is accepted:
portbase=p membase=m icn_id=idstring icn_id2=idstring2
@@ -347,7+347,7 @@ README for the ISDN-subsystem
4. Device-inodes
- The major and minor-numbers and it's names are described in
+ The major and minor-numbers and its names are described in
Documentation/devices.txt. The major-numbers are:
43 for the ISDN-tty's.
@@ -494,7+494,7 @@ README for the ISDN-subsystem cisco-h A special-mode for communicating with a Cisco, which is configured
to do "hdlc"
ethernet No stripping. Packets are sent with full MAC-header.
- The Ethernet-address of the interface is faked, from it's
+ The Ethernet-address of the interface is faked, from its
IP-address: fc:fc:i1:i2:i3:i4, where i1-4 are the IP-addr.-values.
syncppp Synchronous PPP
@@ -553,7+553,7 @@ README for the ISDN-subsystem
"isdnctrl sdelay <InterfaceName> secs."
This sets the minimum time an Interface has to be fully loaded, until
- it sends an dial-request to it's slave.
+ it sends a dial-request to its slave.
"isdnctrl dial <InterfaceName>"
Forces an interface to start dialing even if no packets are to be
--- /dev/null
+This file is a registry of magic numbers which are in use. When you
+add a magic number to a structure, you should also add it to this
+file, since it is best if the magic numbers used by various structures
+are unique.
+
+It is a *very* good idea to protect kernel data structures with magic
+numbers. This allows you to check at run time whether (a) a structure
+has been clobbered, or (b) you've passed the wrong structure to a
+routine. This last is especially useful --- particularly when you are
+passing pointers to structures via a void * pointer. The tty code,
+for example, does this frequently to pass driver-specific and line
+discipline-specific structures back and forth.
+
+The way to use magic numbers is to declare then at the beginning of
+the structure, like so:
+
+struct tty_ldisc {
+ int magic;
+ ...
+};
+
+Please follow this discipline when you are adding future enhancements
+to the kernel! It has saved me countless hours of debugging,
+especially in the screw cases where an array has been overrun and
+structures following the array have been overwritten. Using this
+discipline, these cases get detected quickly and safely.
+
+ Theodore Ts'o
+ 31-Mar-94
+
+The magic table is current to Linux 1.3.98.
+
+ Michael Chastain
+ <mec@duracef.shout.net>
+ 6 May 1996
+
+
+
+Magic Name Number Structure File
+===========================================================================
+RISCOM8_MAGIC 0x0907 struct riscom_port drivers/char/riscom8.h
+APM_BIOS_MAGIC 0x4101 struct apm_struct include/linux/apm_bios.h
+CYCLADES_MAGIC 0x4359 struct cyclades_port include/linux/cyclades.h
+FASYNC_MAGIC 0x4601 struct fasync_struct include/linux/fs.h
+PTY_MAGIC 0x5001 struct pty_struct drivers/char/pty.c
+PPP_MAGIC 0x5002 struct ppp_struct include/linux/if_ppp.h
+SERIAL_MAGIC 0x5301 struct async_struct include/linux/serial.h
+SLIP_MAGIC 0x5302 struct slip drivers/net/slip.h
+STRIP_MAGIC 0x5303 struct strip drivers/net/strip.c
+TTY_MAGIC 0x5401 struct tty_struct include/linux/tty.h
+TTY_DRIVER_MAGIC 0x5402 struct tty_driver include/linux/tty_driver.h
+TTY_LDISC_MAGIC 0x5403 struct tty_ldisc include/linux/tty_ldisc.h
+SCC_MAGIC 0x8530 struct scc_channel include/linux/scc.h
+ISDN_ASYNC_MAGIC 0x49344C01 modem_info include/linux/isdn.h
+ISDN_NET_MAGIC 0x49344C02 isdn_net_ndev include/linux/isdn.h
+STLI_BOARDMAGIC 0x4bc6c825 stlibrd_t include/linux/istallion.h
+STLI_PORTMAGIC 0xe671c7a1 stliport_t include/linux/istallion.h
+STL_PANELMAGIC 0x7ef621a1 stlpanel_t include/linux/stallion.h
+STL_BOARDMAGIC 0xa2267f52 stlbrd_t include/linux/stallion.h
+STL_PORTMAGIC 0x5a7182c9 stlport_t include/linux/stallion.h
+PCXX_MAGIC 0x5c6df104 struct channel drivers/char/pcxx.h
@@ -140,7+140,7 @@ And now to the cabling. What you can connect together: 5. An active hub to passive hub.
Remember, that you can not connect two passive hubs together. The power loss
-implied by such connection is too high for the net to operate reliably.
+implied by such a connection is too high for the net to operate reliably.
An example of a typical ARCnet network:
@@ -2256,9+2256,9 @@ to be used. The first 6 switches set the address, the 7th doesn't have any function, and the 8th switch is used to select "compatible" or "enhanced".
When I got my two cards, one of them had this switch set to "enhanced". That
card didn't work at all, it wasn't even recognized by the driver. The other
-card had this switch set to "compatible" and it behaved absolutely normal. I
+card had this switch set to "compatible" and it behaved absolutely normally. I
guess that the switch on one of the cards, must have been changed accidently
-when the card was taken out of it's former host. The question remains
+when the card was taken out of its former host. The question remains
unanswered, what is the purpose of the "enhanced" position?
[Avery's note: "enhanced" probably either disables shared memory (use IO
Frame Relay (FR) support for linux is built into a two tiered system of device
drivers. The upper layer implements RFC1490 FR specification, and uses the
-Data Link Connection Identifier (DLCI) as it's hardware address. Usually these
+Data Link Connection Identifier (DLCI) as its hardware address. Usually these
are assigned by your network supplier, they give you the number/numbers of
the Virtual Connections (VC) assigned to you.
@@ -160,7+160,7 @@ depend on what facilities are available: The other two kernel command line parameters cannot be substi-
tuted with rdev. Therefore, using this method the kernel will
by default use RARP and/or BOOTP, and if it gets an answer via
- RARP will mount the directory /tftpboot/<client-ip>/ as it's
+ RARP will mount the directory /tftpboot/<client-ip>/ as its
root. If it got a BOOTP answer the directory name in that answer
is used.
@@ -169,8+169,8 @@ depend on what facilities are available: When using LILO you can specify all necessary command line
parameters with the 'append=' command in the LILO configuration
file. However, to use the 'root=' command you also need to
- setup a dummy device as described in 3.1 above. How to use
- LILO and it's 'append=' command please refer to the LILO
+ set up a dummy device as described in 3.1 above. For how to use
+ LILO and its 'append=' command please refer to the LILO
documentation.
3.3) Using loadlin
@@ -187,7+187,7 @@ depend on what facilities are available: protocol. As far as I know no commercial bootroms already
support booting Linux over the network, but there are two
free implementations of a bootrom available on sunsite.unc.edu
- and it's mirrors. They are called 'netboot-nfs' and 'etherboot'.
+ and its mirrors. They are called 'netboot-nfs' and 'etherboot'.
Both contain everything you need to boot a diskless Linux client.
@@ -19,7+19,7 @@ happened in). Oh, it helps if the report happens on a kernel that is compiled with the
same compiler and similar setups.
-The other thing to do is disassemble the "Code:" part of the bugreprot:
+The other thing to do is disassemble the "Code:" part of the bug report:
ksymoops will do this too with the correct tools (and new version of
ksymoops), but if you don't have the tools you can just do a silly
program:
@@ -30,7+30,7 @@ program: and compile it with gcc -g and then do "disassemble str" (where the "XX"
stuff are the values reported by the Oops - you can just cut-and-paste
and do a replace of spaces to "\x" - that's what I do, as I'm too lazy
-to write a prigram to automate this all).
+to write a program to automate this all).
Finally, if you want to see where the code comes from, you can do
@@ -79,7+79,7 @@ starting at an offset of 400kB, you would use "ramdisk_start=400". load_ramdisk=N
==============
-This parameter tells the kernel whether it is to try and load a
+This parameter tells the kernel whether it is to try to load a
ramdisk image or not. Specifying "load_ramdisk=1" will tell the
kernel to load a floppy into the ramdisk. The default value is
zero, meaning that the kernel should not try to load a ramdisk.
@@ -194,7+194,7 @@ f) Put the ramdisk image onto the floppy, after the kernel. Use an offset dd if=/tmp/ram_image.gz of=/dev/fd0 bs=1k seek=400
g) Use "rdev" to set the boot device, ramdisk offset, prompt flag, etc.
- For ramdisk_start=400, load_ramdisk=1, ramdisk_start=400, one would
+ For prompt_ramdisk=1, load_ramdisk=1, ramdisk_start=400, one would
have 2^15 + 2^14 + 400 = 49552.
rdev /dev/fd0 /dev/fd0
@@ -9,7+9,7 @@ clock that keeps the date and time while your computer is turned off.
However it can also be used to generate signals from a slow 2Hz to a
relatively fast 8192Hz, in increments of powers of two. These signals
-are reported by interrupt number 8. (Oh! So *thats* what IRQ 8 is
+are reported by interrupt number 8. (Oh! So *that* is what IRQ 8 is
for...) It can also function as a 24hr alarm, raising IRQ 8 when the
alarm goes off. The alarm can also be programmed to only check any
subset of the three programmable values, meaning that it could be set to
@@ -88,13+88,12 @@ that will be using this driver. #include <fcntl.h>
#include <unistd.h>
#include <errno.h>
-#include <time.h>
void main(void) {
int i, fd, retval, irqcount = 0;
unsigned long tmp, data;
-struct tm rtc_tm;
+struct rtc_time rtc_tm;
fd = open ("/dev/rtc", O_RDONLY);
+++ /dev/null
-This file is a registry of magic numbers which are in use. When you
-add a magic number to a structure, you should also add it to this
-file, since it is best if the magic numbers used by various structures
-are unique.
-
-It is a *very* good idea to protect kernel data structures with magic
-numbers. This allows you to check at run time whether (a) a structure
-has been clobbered, or (b) you've passed the wrong structure to a
-routine. This last is especially useful --- particularly when you are
-passing pointers to structures via a void * pointer. The tty code,
-for example, does this frequently to pass driver-specific and line
-discipline-specific structures back and forth.
-
-The way to use magic numbers is to declare then at the beginning of
-the structure, like so:
-
-struct tty_ldisc {
- int magic;
- ...
-};
-
-Please follow this discipline when you are adding future enhancements
-to the kernel! It has saved me countless hours of debugging,
-especially in the screw cases where an array has been overrun and
-structures following the array have been overwritten. Using this
-discipline, these cases get detected quickly and safely.
-
-You should also register the magic number used by ioctls in the table
-below. This allows ioctls on inappropriate devices to fail, rather than
-doing something completely unexpected. The magic number is the first
-argument to the _IO family of macros (see include/linux/ioctl.h) or
-in general bits 8..15 of the ioctl number. Where ioctls are done on
-devices with a major device number, it is recommended that you use the
-major device number as the ioctl magic value (e.g. hd, lp).
-
- Theodore Ts'o
- 31-Mar-94
-
-The magic table is current to Linux 1.3.35.
-The ioctl table is current to Linux 1.3.35.
-For a complete list of kernel ioctl's, look for 'ioctl-list.X.Y.ZZ' on
-an ftp site, where 'X.Y.ZZ' is the kernel version for the ioctl list.
-
- Michael Chastain
- <mec@duracef.shout.net>
- 17-Oct-95
-
-
-
-
-Magic Name Number Structure File
-===========================================================================
-APM_BIOS_MAGIC 0x4101 struct apm_struct include/linux/apm_bios.h
-CYCLADES_MAGIC 0x4359 struct cyclades_port include/linux/cyclades.h
-FASYNC_MAGIC 0x4601 struct fasync_struct include/linux/fs.h
-PTY_MAGIC 0x5001 struct pty_struct drivers/char/pty.c
-PPP_MAGIC 0x5002 struct ppp_struct include/linux/if_ppp.h
-TTY_MAGIC 0x5401 struct tty_struct include/linux/tty.h
-TTY_DRIVER_MAGIC 0x5402 struct tty_driver include/linux/tty_driver.h
-TTY_LDISC_MAGIC 0x5403 struct tty_ldisc include/linux/tty_ldisc.h
-SERIAL_MAGIC 0x5301 struct async_struct include/linux/serial.h
-SLIP_MAGIC 0x5302 struct slip drivers/net/slip.h
-SCC_MAGIC 0x8530 struct scc_channel include/linux/scc.h
-RISCOM8_MAGIC 0x0907 struct riscom_port drivers/char/riscom8.h
-
-
-
-Ioctl Include File Comments
-========================================================
-0x00 linux/fs.h only FIBMAP, FIGETBSZ
-0x00 linux/random.h codes in 0x010800NN
-0x02 linux/fd.h
-0x03 linux/hdreg.h
-0x04 linux/umsdos_fs.h
-0x06 linux/lp.h
-0x09 linux/md.h
-0x12 linux/fs.h
-0x20 linux/cm206.h
-0x22 linux/scc.h
-'A' linux/apm_bios.h
-'C' linux/soundcard.h
-'I' linux/isdn.h
-'K' linux/kd.h
-'L' linux/loop.h
-'M' linux/soundcard.h
-'P' linux/soundcard.h
-'Q' linux/soundcard.h
-'S' linux/cdrom.h conflict!
-'S' linux/scsi.h conflict!
-'T' linux/soundcard.h conflict!
-'T' asm/termios.h conflict!
-'V' linux/vt.h
-'Y' linux/cyclades.h codes in 0x004359NN
-'a' various, see http://lrcwww.epfl.ch/linux-atm/magic.html
-'f' linux/ext2_fs.h
-'m' linux/mtio.h conflict!
-'m' linux/soundcard.h conflict!
-'n' linux/ncp_fs.h
-'s' linux/cdk.h
-'t' linux/if_ppp.h
-'u' linux/smb_fs.h
-'u' linux/smb_fs.h
-'v' linux/ext2_fs.h
-0x89 asm/socket.h no conflict
-0x89 linux/sockios.h no conflict
@@ -7,13+7,13 @@ trivial patch so apply some common sense. 1. Always _test_ your changes, however small, on at least 4 or
5 people, preferably many more.
-2. Try and release a few ALPHA test versions to the net. Announce
+2. Try to release a few ALPHA test versions to the net. Announce
them onto the kernel channel and await results. This is especially
- important for device drivers, because often thats the only way
+ important for device drivers, because often that's the only way
you will find things like the fact version 3 firmware needs
a magic fix you didn't know about, or some clown changed the
chips on a board and not its name. (Don't laugh! Look at the
- SMC etherpower for that).
+ SMC etherpower for that.)
3. Make sure your changes compile correctly in multiple
configurations.
@@ -30,7+30,7 @@ trivial patch so apply some common sense. your driver to get around a problem actual needs to become a
generalised kernel feature ready for next time.
- PLEASE try and include any credit lines you want added with the
+ PLEASE try to include any credit lines you want added with the
patch. It avoids people being missed off by mistake and makes
it easier to know who wants adding and who doesn't.
@@ -74,6+74,12 @@ M: net-patches@lxorguk.ukuu.org.uk L: linux-net@vger.rutgers.edu
S: Maintained
+8390 NETWORK DRIVERS [WD80x3/SMC-ELITE, SMC-ULTRA, NE2000, 3C503, etc.]
+P: Paul Gortmaker
+M gpg109@rsphy1.anu.edu.au
+L: linux-net@vger.rutgers.edu
+S: Maintained
+
ETHEREXPRESS NETWORK DRIVER
P: Philip Blundell
M: pjb27@cam.ac.uk
@@ -226,6+232,12 @@ M: longyear@netcom.com, Cc: longyear@sii.com L: linux-ppp@vger.rutgers.edu
S: Maintained
+REAL TIME CLOCK DRIVER
+P: Paul Gortmaker
+M gpg109@rsphy1.anu.edu.au
+L: linux-kernel@vger.rutgers.edu
+S: Maintained
+
STARMODE RADIO IP (STRIP) PROTOCOL DRIVER
P: Stuart Cheshire
M: cheshire@cs.stanford.edu
@@ -288,6+300,12 @@ M: roadcapw@cfw.com L: linux-kernel@vger.rutgers.edu
S: Maintained
+LANCE AND LANCE32 NETWORK DRIVER
+P: Thomas Bogendoerfer
+M: tsbogend@bigbug.franken.de
+L: linux-net@vger.rutgers.edu
+S: Maintained
+
REST:
P: Linus Torvalds
S: Buried alive in email
VERSION = 1
PATCHLEVEL = 3
-SUBLEVEL = 98
+SUBLEVEL = 99
ARCH = i386
@@ -24,9+24,9 @@ sometimes takes days or even weeks.
WHAT IS LINUX?
- Linux is a Unix clone for 386/486-based PCs written from scratch by
- Linus Torvalds with assistance from a loosely-knit team of hackers
- across the Net. It aims towards POSIX compliance.
+ Linux is a Unix clone written from scratch by Linus Torvalds with
+ assistance from a loosely-knit team of hackers across the Net.
+ It aims towards POSIX compliance.
It has all the features you would expect in a modern fully-fledged
Unix, including true multitasking, virtual memory, shared libraries,
@@ -36,6+36,12 @@ WHAT IS LINUX? It is distributed under the GNU General Public License - see the
accompanying COPYING file for more details.
+ON WHAT HARDWARE DOES IT RUN?
+
+ Linux was first developed for 386/486-based PCs. These days it also
+ runs on DEC Alphas, SUN Sparcs, M68000 machines (like Atari and Amiga),
+ MIPS and PowerPC.
+
DOCUMENTATION:
- there is a lot of documentation available both in electronic form on
bool 'Echo console messages on /dev/ttyS1' CONFIG_SERIAL_ECHO
if [ "$CONFIG_PCI" = "y" ]; then
bool 'TGA Console Support' CONFIG_TGA_CONSOLE
- bool 'PCI bridge optimization (experimental)' CONFIG_PCI_OPTIMIZE
+ if [ "$CONFIG_EXPERIMENTAL" = "y" ]; then
+ bool 'PCI bridge optimization (experimental)' CONFIG_PCI_OPTIMIZE
+ fi
fi
bool 'Networking support' CONFIG_NET
bool 'System V IPC' CONFIG_SYSVIPC
@@ -442,7+442,7 @@ unsigned long pcibios_init(unsigned long mem_start, }
/*
- * The SRM console *disables* the IDE interface, this code ensures its
+ * The SRM console *disables* the IDE interface, this code ensures it's
* enabled.
*
* This code bangs on a control register of the 87312 Super I/O chip
@@ -565,7+565,7 @@ static inline void common_fixup(long min_idsel, long max_idsel, long irqs_per_sl PCI_INTERRUPT_LINE, dev->irq);
#endif
/*
- * if its a VGA, enable its BIOS ROM at C0000
+ * if it's a VGA, enable its BIOS ROM at C0000
*/
if ((dev->class >> 8) == PCI_CLASS_DISPLAY_VGA) {
pcibios_write_config_dword(dev->bus->number, dev->devfn,
@@ -799,7+799,7 @@ static inline void sio_fixup(void) dev->bus->number, PCI_SLOT(dev->devfn), dev->vendor, dev->device,
slot, pin, pirq));
/*
- * if its a VGA, enable its BIOS ROM at C0000
+ * if it's a VGA, enable its BIOS ROM at C0000
*/
if ((dev->class >> 8) == PCI_CLASS_DISPLAY_VGA) {
pcibios_write_config_dword(dev->bus->number, dev->devfn,
clean:
rm -f bootsect setup
+ rm -f bbootsect
rm -f zImage tools/build compressed/vmlinux.out
rm -f bzImage tools/bbuild compressed/bvmlinux.out
@$(MAKE) -C compressed clean
@@ -26,14+26,15 @@ bool 'Networking support' CONFIG_NET bool 'Limit memory to low 16MB' CONFIG_MAX_16M
bool 'PCI bios support' CONFIG_PCI
if [ "$CONFIG_PCI" = "y" ]; then
- bool ' PCI bridge optimization (experimental)' CONFIG_PCI_OPTIMIZE
+ if [ "$CONFIG_EXPERIMENTAL" = "y" ]; then
+ bool ' PCI bridge optimization (experimental)' CONFIG_PCI_OPTIMIZE
+ fi
fi
bool 'System V IPC' CONFIG_SYSVIPC
tristate 'Kernel support for a.out binaries' CONFIG_BINFMT_AOUT
tristate 'Kernel support for ELF binaries' CONFIG_BINFMT_ELF
-if [ "$CONFIG_BINFMT_ELF" = "y" ]; then
- bool 'Compile kernel as ELF - if your GCC is ELF-GCC' CONFIG_KERNEL_ELF
-fi
+bool 'Compile kernel as ELF - if your GCC is ELF-GCC' CONFIG_KERNEL_ELF
+
choice 'Processor type' \
"386 CONFIG_M386 \
486 CONFIG_M486 \
@@ -370,7+370,7 @@ asmlinkage void do_fast_IRQ(int irq) {
struct irqaction * action = *(irq + irq_action);
#ifdef __SMP__
- /* IRQ 13 is allowed - thats a flush tlb */
+ /* IRQ 13 is allowed - that's a flush tlb */
if(smp_threads_ready && active_kernel_processor!=smp_processor_id() && irq!=13)
panic("fast_IRQ %d: active processor set wrongly(%d not %d).\n", irq, active_kernel_processor, smp_processor_id());
#endif
@@ -207,7+207,8 @@ void setup_arch(char **cmdline_p, static const char * i486model(unsigned int nr)
{
static const char *model[] = {
- "0", "DX","SX","DX/2","4","SX/2","6","DX/2-WB","DX/4","DX/4-WB"
+ "0","DX","SX","DX/2","4","SX/2","6","DX/2-WB","DX/4","DX/4-WB",
+ "10","11","12","13","Am5x85-WT","Am5x86-WB"
};
if (nr < sizeof(model)/sizeof(char *))
return model[nr];
@@ -325,7+326,7 @@ int get_cpuinfo(char * buffer) }
}
len += sprintf(buffer+len,
- "\nbogomips:\t: %lu.%02lu\n",
+ "\nbogomips\t: %lu.%02lu\n",
CD(loops_per_sec)/500000,
(CD(loops_per_sec)/5000) % 100);
#ifdef __SMP__
@@ -43,11+43,6 @@ asmlinkage int sys_sigsuspend(int restart, unsigned long oldmask, unsigned long }
}
-/*
- * FIXME. We don't currently restore emulator state
- */
-#define restore_i387_soft(x) do { } while (0)
-
static inline void restore_i387_hard(struct _fpstate *buf)
{
#ifdef __SMP__
@@ -122,11+117,6 @@ badframe: do_exit(SIGSEGV);
}
-/*
- * FIXME. We currently don't save 387 state if we use emulation
- */
-#define save_i387_soft(x) NULL
-
static inline struct _fpstate * save_i387_hard(struct _fpstate * buf)
{
#ifdef __SMP__
@@ -56,7+56,7 @@ int smp_threads_ready=0; /* Set when the idlers are all forked */ volatile int cpu_number_map[NR_CPUS]; /* which CPU maps to which logical number */
volatile int cpu_logical_map[NR_CPUS]; /* which logical number maps to which CPU */
volatile unsigned long cpu_callin_map[NR_CPUS] = {0,}; /* We always use 0 the rest is ready for parallel delivery */
-volatile unsigned long smp_invalidate_needed; /* Used for the invalidate map thats also checked in the spinlock */
+volatile unsigned long smp_invalidate_needed; /* Used for the invalidate map that's also checked in the spinlock */
struct cpuinfo_x86 cpu_data[NR_CPUS]; /* Per cpu bogomips and other parameters */
static unsigned int num_processors = 1; /* Internal processor count */
static unsigned long io_apic_addr = 0xFEC00000; /* Address of the I/O apic (not yet used) */
@@ -448,7+448,7 @@ static unsigned char trampoline_data[]={ /*
* Currently trivial. Write the real->protected mode
* bootstrap into the page concerned. The caller
- * has made sure its suitably aligned.
+ * has made sure it's suitably aligned.
*/
static void install_trampoline(unsigned char *mp)
@@ -1094,7+1094,7 @@ void smp_flush_tlb(void) /* printk("SMI-");*/
/*
- * The assignment is safe because its volatile so the compiler cannot reorder it,
+ * The assignment is safe because it's volatile so the compiler cannot reorder it,
* because the i586 has strict memory ordering and because only the kernel lock holder
* may issue a tlb flush. If you break any one of those three change this to an atomic
* bus locked or.
@@ -1104,7+1104,7 @@ void smp_flush_tlb(void)
/*
* Processors spinning on the lock will see this IRQ late. The smp_invalidate_needed map will
- * ensure they dont do a spurious flush tlb or miss one.
+ * ensure they don't do a spurious flush tlb or miss one.
*/
save_flags(flags);
@@ -267,7+267,7 @@ static inline void timer_interrupt(int irq, void *dev_id, struct pt_regs *regs) last_rtc_update = xtime.tv_sec - 600; /* do it again in 60 s */
/* As we return to user mode fire off the other CPU schedulers.. this is
basically because we don't yet share IRQ's around. This message is
- rigged to be safe on the 386 - basically its a hack, so don't look
+ rigged to be safe on the 386 - basically it's a hack, so don't look
closely for now.. */
/*smp_message_pass(MSG_ALL_BUT_SELF, MSG_RESCHEDULE, 0L, 0); */
@@ -255,18+255,11 @@ void math_error(void) */
__asm__ __volatile__("fnsave %0":"=m" (task->tss.i387.hard));
task->flags&=~PF_USEDFPU;
+ stts();
force_sig(SIGFPE, task);
task->tss.trap_no = 16;
task->tss.error_code = 0;
-
- /*
- * Give the process a clean slate next time they use
- * the FPU (and if they haven't accepted the SIGFPE before
- * that, it's their problem..)
- */
- stts();
- task->used_math = 0;
}
asmlinkage void do_coprocessor_error(struct pt_regs * regs, long error_code)
| |
| The error handling functions for wm-FPU-emu |
| |
- | Copyright (C) 1992,1993,1994 |
- | W. Metzenthen, 22 Parker St, Ormond, Vic 3163, |
- | Australia. E-mail billm@vaxc.cc.monash.edu.au |
+ | Copyright (C) 1992,1993,1994,1996 |
+ | W. Metzenthen, 22 Parker St, Ormond, Vic 3163, Australia |
+ | E-mail billm@jacobi.maths.monash.edu.au |
| |
| |
+---------------------------------------------------------------------------*/
@@ -82,7+82,7 @@ void FPU_illegal(void)
-void emu_printall()
+void emu_printall(void)
{
int i;
static const char *tag_desc[] = { "Valid", "Zero", "ERROR", "ERROR",
@@ -166,7+166,8 @@ printk(" CW: ic=%d rc=%ld%ld pc=%ld%ld iem=%d ef=%d%d%d%d%d%d\n", for ( i = 0; i < 8; i++ )
{
FPU_REG *r = &st(i);
- switch (r->tag)
+ char tagi = r->tag;
+ switch (tagi)
{
case TW_Empty:
continue;
@@ -190,22+191,13 @@ printk(" CW: ic=%d rc=%ld%ld pc=%ld%ld iem=%d ef=%d%d%d%d%d%d\n", r->exp - EXP_BIAS + 1);
break;
default:
- printk("Whoops! Error in errors.c ");
+ printk("Whoops! Error in errors.c: tag%d is %d ", i, tagi);
+ continue;
break;
}
- printk("%s\n", tag_desc[(int) (unsigned) r->tag]);
+ printk("%s\n", tag_desc[(int) (unsigned) tagi]);
}
-#ifdef OBSOLETE
- printk("[data] %c .%04lx %04lx %04lx %04lx e%+-6ld ",
- FPU_loaded_data.sign ? '-' : '+',
- (long)(FPU_loaded_data.sigh >> 16),
- (long)(FPU_loaded_data.sigh & 0xFFFF),
- (long)(FPU_loaded_data.sigl >> 16),
- (long)(FPU_loaded_data.sigl & 0xFFFF),
- FPU_loaded_data.exp - EXP_BIAS + 1);
- printk("%s\n", tag_desc[(int) (unsigned) FPU_loaded_data.tag]);
-#endif OBSOLETE
RE_ENTRANT_CHECK_ON;
}
@@ -365,12+357,8 @@ void exception(int n) /*
* The 80486 generates an interrupt on the next non-control FPU
* instruction. So we need some means of flagging it.
- * We use the ES (Error Summary) bit for this, assuming that
- * this is the way a real FPU does it (until I can check it out),
- * if not, then some method such as the following kludge might
- * be needed.
+ * We use the ES (Error Summary) bit for this.
*/
-/* regs[0].tag |= TW_FPU_Interrupt; */
}
RE_ENTRANT_CHECK_ON;
@@ -568,7+556,7 @@ asmlinkage int arith_overflow(FPU_REG *dest) return !(control_word & CW_Precision);
}
- return !(control_word & CW_Overflow);
+ return 0;
}
@@ -599,7+587,7 @@ asmlinkage int arith_underflow(FPU_REG *dest) return !(control_word & CW_Precision);
}
- return !(control_word & CW_Underflow);
+ return 0;
}
#ifndef __ASSEMBLY__
+#include <asm/sigcontext.h> /* for struct _fpstate */
#include <linux/math_emu.h>
#include <linux/linkage.h>
/*---------------------------------------------------------------------------+
| fpu_entry.c |
| |
- | The entry function for wm-FPU-emu |
+ | The entry functions for wm-FPU-emu |
| |
- | Copyright (C) 1992,1993,1994 |
- | W. Metzenthen, 22 Parker St, Ormond, Vic 3163, |
- | Australia. E-mail billm@vaxc.cc.monash.edu.au |
+ | Copyright (C) 1992,1993,1994,1996 |
+ | W. Metzenthen, 22 Parker St, Ormond, Vic 3163, Australia |
+ | E-mail billm@jacobi.maths.monash.edu.au |
| |
| See the files "README" and "COPYING" for further copyright and warranty |
| information. |
+---------------------------------------------------------------------------*/
/*---------------------------------------------------------------------------+
- | math_emulate() is the sole entry point for wm-FPU-emu |
+ | math_emulate(), restore_i387_soft() and save_i387_soft() are the only |
+ | entry points for wm-FPU-emu. |
+---------------------------------------------------------------------------*/
#include <linux/signal.h>
@@ -159,8+160,9 @@ asmlinkage void math_emulate(long arg) {
/* Make sure that the registers are compatible
with the assumptions of the emulator. */
- regs[i].exp = 0;
- regs[i].sigh = 0x80000000;
+ if ( !((regs[i].exp == EXP_UNDER) && (regs[i].sigh == 0)
+ && (regs[i].sigl == 0)) )
+ regs[i].sigh |= 0x80000000;
}
finit();
current->used_math = 1;
@@ -283,24+285,8 @@ do_another_FPU_instruction: /*
* We need to simulate the action of the kernel to FPU
* interrupts here.
- * Currently, the "real FPU" part of the kernel (0.99.10)
- * clears the exception flags, sets the registers to empty,
- * and passes information back to the interrupted process
- * via the cs selector and operand selector, so we do the same.
*/
do_the_FPU_interrupt:
- instruction_address.selector = status_word();
- operand_address.selector = tag_word();
- partial_status = 0;
- top = 0;
- {
- int r;
- for (r = 0; r < 8; r++)
- {
- regs[r].tag = TW_Empty;
- }
- }
-
FPU_EIP = FPU_ORIG_EIP; /* Point to current FPU instruction. */
RE_ENTRANT_CHECK_OFF;
@@ -688,3+674,22 @@ void math_abort(struct info * info, unsigned int signal) printk("ERROR: wm-FPU-emu math_abort failed!\n");
#endif PARANOID
}
+
+
+
+void restore_i387_soft(struct _fpstate *buf)
+{
+ fpu_addr_modes addr_modes = {{ 0, 0, PREFIX_DEFAULT }, 0};
+
+ frstor(addr_modes, (char *)buf);
+}
+
+
+struct _fpstate * save_i387_soft(struct _fpstate * buf)
+{
+ fpu_addr_modes addr_modes = {{ 0, 0, PREFIX_DEFAULT }, 0};
+
+ fsave(addr_modes, (char *)buf);
+
+ return buf;
+}
| |
| All of the functions which transfer data between user memory and FPU_REGs.|
| |
- | Copyright (C) 1992,1993,1994 |
- | W. Metzenthen, 22 Parker St, Ormond, Vic 3163, |
- | Australia. E-mail billm@vaxc.cc.monash.edu.au |
+ | Copyright (C) 1992,1993,1994,1996 |
+ | W. Metzenthen, 22 Parker St, Ormond, Vic 3163, Australia |
+ | E-mail billm@jacobi.maths.monash.edu.au |
| |
| |
+---------------------------------------------------------------------------*/
@@ -466,6+466,7 @@ int reg_store_double(double *dfloat, FPU_REG *st0_ptr)
if (st0_tag == TW_Valid)
{
+ int precision_loss;
int exp;
FPU_REG tmp;
@@ -474,8+475,6 @@ int reg_store_double(double *dfloat, FPU_REG *st0_ptr)
if ( exp < DOUBLE_Emin ) /* It may be a denormal */
{
- int precision_loss;
-
/* A denormal will always underflow. */
#ifndef PECULIAR_486
/* An 80486 is supposed to be able to generate
@@ -518,6+517,7 @@ int reg_store_double(double *dfloat, FPU_REG *st0_ptr) {
if ( tmp.sigl & 0x000007ff )
{
+ precision_loss = 1;
switch (control_word & CW_RC)
{
case RC_RND:
@@ -541,8+541,6 @@ int reg_store_double(double *dfloat, FPU_REG *st0_ptr)
if ( increment )
{
- set_precision_flag_up();
-
if ( tmp.sigl >= 0xfffff800 )
{
/* the sigl part overflows */
@@ -566,9+564,9 @@ int reg_store_double(double *dfloat, FPU_REG *st0_ptr) tmp.sigl += 0x00000800;
}
}
- else
- set_precision_flag_down();
}
+ else
+ precision_loss = 0;
l[0] = (tmp.sigl >> 11) | (tmp.sigh << 21);
l[1] = ((tmp.sigh >> 11) & 0xfffff);
@@ -590,6+588,13 @@ int reg_store_double(double *dfloat, FPU_REG *st0_ptr) }
else
{
+ if ( precision_loss )
+ {
+ if ( increment )
+ set_precision_flag_up();
+ else
+ set_precision_flag_down();
+ }
/* Add the exponent */
l[1] |= (((exp+DOUBLE_Ebias) & 0x7ff) << 20);
}
@@ -661,6+666,7 @@ int reg_store_single(float *single, FPU_REG *st0_ptr)
if (st0_tag == TW_Valid)
{
+ int precision_loss;
int exp;
FPU_REG tmp;
@@ -669,8+675,6 @@ int reg_store_single(float *single, FPU_REG *st0_ptr)
if ( exp < SINGLE_Emin )
{
- int precision_loss;
-
/* A denormal will always underflow. */
#ifndef PECULIAR_486
/* An 80486 is supposed to be able to generate
@@ -715,6+719,7 @@ int reg_store_single(float *single, FPU_REG *st0_ptr) unsigned long sigh = tmp.sigh;
unsigned long sigl = tmp.sigl;
+ precision_loss = 1;
switch (control_word & CW_RC)
{
case RC_RND:
@@ -740,8+745,6 @@ int reg_store_single(float *single, FPU_REG *st0_ptr)
if (increment)
{
- set_precision_flag_up();
-
if ( sigh >= 0xffffff00 )
{
/* The sigh part overflows */
@@ -758,10+761,11 @@ int reg_store_single(float *single, FPU_REG *st0_ptr) }
else
{
- set_precision_flag_down();
tmp.sigh &= 0xffffff00; /* Finish the truncation */
}
}
+ else
+ precision_loss = 0;
templ = (tmp.sigh >> 8) & 0x007fffff;
@@ -780,7+784,17 @@ int reg_store_single(float *single, FPU_REG *st0_ptr) templ = 0x7f800000;
}
else
- templ |= ((exp+SINGLE_Ebias) & 0xff) << 23;
+ {
+ if ( precision_loss )
+ {
+ if ( increment )
+ set_precision_flag_up();
+ else
+ set_precision_flag_down();
+ }
+ /* Add the exponent */
+ templ |= ((exp+SINGLE_Ebias) & 0xff) << 23;
+ }
}
}
else if (st0_tag == TW_Zero)
| |
| |
| Copyright (C) 1992,1993,1994,1996 |
- | W. Metzenthen, 22 Parker St, Ormond, Vic 3163, |
- | Australia. E-mail billm@jacobi.maths.monash.edu.au |
+ | W. Metzenthen, 22 Parker St, Ormond, Vic 3163, Australia |
+ | E-mail billm@jacobi.maths.monash.edu.au |
| |
| |
+---------------------------------------------------------------------------*/
-#define FPU_VERSION "wm-FPU-emu version 1.21"
+#define FPU_VERSION "wm-FPU-emu version 1.22"
# Note 2! The CFLAGS definitions are now in the main makefile...
O_TARGET := amiga.o
-O_OBJS := config.o amikeyb.o amiints.o amipart.o \
+O_OBJS := config.o amikeyb.o amiints.o \
chipram.o amisound.o amifb.o zorro.o
OX_OBJS = ksyms.o
+++ /dev/null
-/*
- * linux/amiga/amipart.c
- *
- * Amiga partition checking driver for 680x0 Linux
- *
- * This file is subject to the terms and conditions of the GNU General Public
- * License. See the file README.legal in the main directory of this archive
- * for more details.
- */
-
-#include <linux/fs.h>
-#include <linux/genhd.h>
-#include <linux/kernel.h>
-
-#include <asm/amigardb.h>
-#include <asm/machdep.h>
-
-extern int current_minor;
-
-static ulong checksum (ulong *ptr, int len)
-{
- ulong sum;
- int cnt;
-
- for (sum = 0, cnt = 0; cnt < len; cnt++)
- sum += ptr[cnt];
-
- return sum;
-}
-
-/* XXX */
-/* int current_minor = 0; */
-
-void amiga_check_partition(struct gendisk *hd, kdev_t dev)
-{
- int i, minor = current_minor, m_lim = current_minor + hd->max_p;
- struct buffer_head *bh;
- struct RigidDiskBlock *rdb;
- struct PartitionBlock *pb;
- ulong bnum, partsect;
-
- for (bnum = 0; bnum < RDB_LOCATION_LIMIT/2; bnum++) {
- if (!(bh = bread(dev,bnum,1024))) {
- printk (" unable to read block %ld\n", bnum);
- return;
- }
-#ifdef DEBUG
- printk ("block read, press mousebutton to continue\n");
- waitbut();
-#endif
- rdb = (struct RigidDiskBlock *)bh->b_data;
- if (rdb->rdb_ID == IDNAME_RIGIDDISK)
- break;
- rdb = (struct RigidDiskBlock *)&bh->b_data[512];
- if (rdb->rdb_ID == IDNAME_RIGIDDISK)
- break;
- brelse (bh);
- }
- if (bnum == RDB_LOCATION_LIMIT/2) {
- /* no RDB on the disk! */
- printk (" unable to find RigidDiskBlock\n");
- return;
- }
-
- /* checksum the RigidDiskBlock */
- if (checksum ((ulong *)rdb, rdb->rdb_SummedLongs) != 0) {
- printk (" RDB checksum bad\n");
- return;
- }
-
- printk(" %s%c:", hd->major_name, 'a'+(minor >> hd->minor_shift));
-
- partsect = rdb->rdb_PartitionList;
- brelse (bh);
-
- for (i = 1; minor < m_lim && partsect != 0xffffffff; minor++, i++)
- {
- ulong *env;
-
- if (!(bh = bread(dev,partsect/2,1024))) {
- printk (" block %ld read failed\n", partsect);
- return;
- }
-#ifdef DEBUG
- printk ("block read, press mousebutton to continue\n");
- waitbut();
-#endif
- pb = (struct PartitionBlock *)bh->b_data;
- if (partsect & 1)
- pb = (struct PartitionBlock *)&bh->b_data[512];
- if (pb->pb_ID != IDNAME_PARTITION) {
- printk (" block %ld Not a partition block (%#lx)\n",
- partsect, pb->pb_ID);
- brelse (bh);
- return;
- }
- if (checksum ((ulong *)pb, pb->pb_SummedLongs) != 0) {
- printk (" block %ld checksum bad\n", partsect);
- brelse (bh);
- return;
- }
-
- env = pb->pb_Environment;
-
- hd->part[minor].start_sect = env[DE_LOWCYL]
- * env[DE_NUMHEADS] * env[DE_BLKSPERTRACK];
- hd->part[minor].nr_sects = (env[DE_UPPERCYL]
- - env[DE_LOWCYL] + 1)
- * env[DE_NUMHEADS] * env[DE_BLKSPERTRACK];
-
- printk(" %s%c%d", hd->major_name,
- 'a'+(minor >> hd->minor_shift), i);
-
- partsect = pb->pb_Next;
- brelse (bh);
- }
-
- printk ("\n");
-}
@@ -49,7+49,6 @@ extern void a3000_gettod (int *, int *, int *, int *, int *, int *); extern void a2000_gettod (int *, int *, int *, int *, int *, int *);
extern int amiga_hwclk (int, struct hwclk_time *);
extern int amiga_set_clock_mmss (unsigned long);
-extern void amiga_check_partition (struct gendisk *hd, unsigned int dev);
extern void amiga_mksound( unsigned int count, unsigned int ticks );
#ifdef CONFIG_BLK_DEV_FD
extern int amiga_floppy_init (void);
@@ -288,7+287,6 @@ void config_amiga(void) }
mach_hwclk = amiga_hwclk;
mach_set_clock_mmss = amiga_set_clock_mmss;
- mach_check_partition = amiga_check_partition;
mach_mksound = amiga_mksound;
#ifdef CONFIG_BLK_DEV_FD
mach_floppy_init = amiga_floppy_init;
@@ -11,7+11,7 @@ EXTRA_CFLAGS := -Wa,-m68030
O_TARGET := atari.o
O_OBJS := config.o atakeyb.o ataints.o \
- atapart.o stdma.o atasound.o joystick.o stram.o atafb.o
+ stdma.o atasound.o joystick.o stram.o atafb.o
OX_OBJS = ksyms.o
include $(TOPDIR)/Rules.make
@@ -1399,7+1399,7 @@ static int falcon_encode_var( struct fb_var_screeninfo *var, if (hw->ste_mode || mon_type!=F_MON_VGA)
var->right_margin = prescale * (hw->hht + 2 - hw->hde) - hde_off;
else
- /* cant use this in ste_mode, because hbb is +1 off */
+ /* can't use this in ste_mode, because hbb is +1 off */
var->right_margin = prescale * (hw->hht + 2 - hw->hbb);
var->hsync_len = prescale * (hw->hht + 2 - hw->hss);
+++ /dev/null
-/*
- * linux/atari/atapart.c
- *
- * Atari partition checking driver for 680x0 Linux
- * Written by Andreas Schwab (schwab@ls5.informatik.uni-dortmund.de)
- *
- * 5/3/94 Roman Hodek:
- * Added some sanity checks
- * Linux device names start from 1 not 0, so I changed the initial value
- * for i to 1.
- *
- * 10/09/94 Guenther Kelleter:
- * Added support for ICD/Supra partition info.
- *
- * This file is subject to the terms and conditions of the GNU General Public
- * License. See the file README.legal in the main directory of this archive
- * for more details.
- */
-
-#include <linux/fs.h>
-#include <linux/genhd.h>
-#include <linux/kernel.h>
-
-#include <asm/atari_rootsec.h>
-
-/* ++guenther: this should be settable by the user ("make config")?.
- */
-#define ICD_PARTS
-
-extern int current_minor;
-
-void
-atari_check_partition (struct gendisk *hd, unsigned int dev)
-{
- int i, minor = current_minor, m_lim = current_minor + hd->max_p;
- struct buffer_head *bh;
- struct rootsector *rs;
- struct partition_info *pi;
- ulong extensect;
-#ifdef ICD_PARTS
- int part_fmt = 0; /* 0:unknown, 1:AHDI, 2:ICD/Supra */
-#endif
-
- bh = bread (dev, 0, 1024);
- if (!bh)
- {
- printk (" unable to read block 0\n");
- return;
- }
-
- rs = (struct rootsector *) bh->b_data;
- printk (" %s%c:", hd->major_name, 'a' + (minor >> hd->minor_shift));
-
- pi = &rs->part[0];
- for (i = 1; pi < &rs->part[4] && minor < m_lim; i++, minor++, pi++)
- {
- if (pi->flg & 1)
- /* active partition */
- {
- if (memcmp (pi->id, "XGM", 3) == 0)
- /* extension partition */
- {
- struct rootsector *xrs;
- struct buffer_head *xbh;
- ulong partsect;
-
-#ifdef ICD_PARTS
- part_fmt = 1;
-#endif
- partsect = extensect = pi->st;
- while (1)
- {
- xbh = bread (dev, partsect / 2, 1024);
- if (!xbh)
- {
- printk (" block %ld read failed\n", partsect);
- return;
- }
- if (partsect & 1)
- xrs = (struct rootsector *) &xbh->b_data[512];
- else
- xrs = (struct rootsector *) &xbh->b_data[0];
-
- /* ++roman: sanity check: bit 0 of flg field must be set */
- if (!(xrs->part[0].flg & 1)) {
- printk( "\nFirst sub-partition in extended partition is not valid!\n" );
- break;
- }
-
- hd->part[minor].start_sect = partsect + xrs->part[0].st;
- hd->part[minor].nr_sects = xrs->part[0].siz;
- printk (" %s%c%d", hd->major_name,
- 'a' + (minor >> hd->minor_shift), i);
-
- if (!(xrs->part[1].flg & 1)) {
- /* end of linked partition list */
- brelse( xbh );
- break;
- }
- if (memcmp( xrs->part[1].id, "XGM", 3 ) != 0) {
- printk( "\nID of extended partition is not XGM!\n" );
- brelse( xbh );
- break;
- }
-
- partsect = xrs->part[1].st + extensect;
- brelse (xbh);
- i++;
- minor++;
- if (minor >= m_lim) {
- printk( "\nMaximum number of partitions reached!\n" );
- break;
- }
- }
- }
- else
- {
- /* we don't care about other id's */
- hd->part[minor].start_sect = pi->st;
- hd->part[minor].nr_sects = pi->siz;
- printk (" %s%c%d", hd->major_name,
- 'a' + (minor >> hd->minor_shift), i);
-
- }
- }
- }
-#ifdef ICD_PARTS
- if ( part_fmt!=1 ) /* no extended partitions -> test ICD-format */
- {
- pi = &rs->icdpart[0];
- /* sanity check: no ICD format if first partition invalid */
- if (memcmp (pi->id, "GEM", 3) == 0 ||
- memcmp (pi->id, "BGM", 3) == 0 ||
- memcmp (pi->id, "RAW", 3) == 0 )
- {
- for (i = 1; pi < &rs->icdpart[8] && minor < m_lim; i++, minor++, pi++)
- {
- /* accept only GEM,BGM,RAW partitions */
- if (pi->flg & 1 &&
- (memcmp (pi->id, "GEM", 3) == 0 ||
- memcmp (pi->id, "BGM", 3) == 0 ||
- memcmp (pi->id, "RAW", 3) == 0) )
- {
- part_fmt = 2;
- hd->part[minor].start_sect = pi->st;
- hd->part[minor].nr_sects = pi->siz;
- printk (" %s%c%d", hd->major_name,
- 'a' + (minor >> hd->minor_shift), i);
- }
- }
- }
- }
-#endif
- brelse (bh);
-
- printk ("\n");
-}
-
@@ -60,7+60,6 @@ extern int atari_mste_hwclk (int, struct hwclk_time *); extern int atari_hwclk (int, struct hwclk_time *);
extern int atari_mste_set_clock_mmss (unsigned long);
extern int atari_set_clock_mmss (unsigned long);
-extern void atari_check_partition (struct gendisk *hd, unsigned int dev);
extern void atari_mksound( unsigned int count, unsigned int ticks );
extern void atari_reset( void );
#ifdef CONFIG_BLK_DEV_FD
@@ -214,7+213,6 @@ void config_atari(void) mach_disable_irq = atari_disable_irq;
mach_get_irq_list = atari_get_irq_list;
mach_gettimeoffset = atari_gettimeoffset;
- mach_check_partition = atari_check_partition;
mach_mksound = atari_mksound;
mach_reset = atari_reset;
#ifdef CONFIG_BLK_DEV_FD
if [ "$CONFIG_ATARI" = "y" ]; then
tristate 'Atari mouse support' CONFIG_ATARIMOUSE
fi
+if [ "$CONFIG_ATARI" = y ]; then
+ tristate 'Atari MFP serial support' CONFIG_ATARI_MFPSER
+ tristate 'Atari SCC serial support' CONFIG_ATARI_SCC
+ tristate 'Atari MIDI serial support' CONFIG_ATARI_MIDI
+fi
+if [ "$CONFIG_AMIGA" = y ]; then
+ tristate 'Amiga builtin serial support' CONFIG_AMIGA_BUILTIN_SERIAL
+ bool 'GVP IO-Extender support' CONFIG_GVPIOEXT
+ tristate 'Multiface Card III serial support' CONFIG_MULTIFACE_III_TTY
+fi
+bool 'Support for user serial device modules' CONFIG_USERIAL
bool 'Watchdog Timer Support' CONFIG_WATCHDOG
if [ "$CONFIG_WATCHDOG" != "n" ]; then
bool ' Disable watchdog shutdown on close' CONFIG_WATCHDOG_NOWAYOUT
*
* Not a great fan of assembler for the sake of it, but I think
* that these routines are at least 10 times faster than their C
- * equivalents for large blits, and thats important to the lowest level of
+ * equivalents for large blits, and that's important to the lowest level of
* a graphics driver. Question is whether some scheme with the blitter
* would be faster. I suspect not for simple text system - not much
* asynchrony.
@@ -17,7+17,7 @@ CONFIG_AMIGA=y # CONFIG_MAC is not set
CONFIG_FPSP_040=y
# CONFIG_IFPSP_060 is not set
-# CONFIG_NET is not set
+CONFIG_NET=y
CONFIG_SYSVIPC=y
CONFIG_BINFMT_AOUT=y
CONFIG_BINFMT_ELF=y
@@ -452,7+452,7 @@ Lmustsched: moveq #-1,%d0
movel %d0,%sp@(LOFF_ORIG_D0) | indicate stack frame not for syscall
bral SYMBOL_NAME(ret_from_exception) | deliver signals, reschedule etc..
-
+
|
| mem_write --- write to user or supervisor address space
@@ -126,7+126,7 @@ An example of using the "cmp2" instruction is as follows: Exception reporting:
--------------------
If the instruction being emulated is a divide and the source
-operand is a zero, then the library routine, as it's last
+operand is a zero, then the library routine, as its last
instruction, executes an implemented divide using a zero
source operand so that an "Integer Divide-by-Zero" exception
will be taken. Although the exception stack frame will not
@@ -2049,7+2049,7 @@ void console_print(const char * b) /* undraw cursor first */
hide_cursor(currcons);
- /* Contrived structure to try and emulate original need_wrap behaviour
+ /* Contrived structure to try to emulate original need_wrap behaviour
* Problems caused when we have need_wrap set on '\n' character */
while ((c = *(b++)) != 0) {
** 94/11/14 Andreas Schwab: put kernel at PAGESIZE
** 94/11/18 Andreas Schwab: remove identity mapping of STRAM for Atari
** ++ Bjoern & Roman: ATARI-68040 support for the Medusa
+** 96/04/26 G|nther Kelleter: fixed identity mapping for Falcon with
+** Magnum- and FX-alternate ram
**
** This file is subject to the terms and conditions of the GNU General Public
** License. See the file README.legal in the main directory of this archive
@@ -146,6+148,16 @@ ENTRY(_start) movew #0x2700,%sr
/*
+ * Setup initial stack pointer
+ */
+ lea %pc@(SYMBOL_NAME(_start)),%sp
+
+/* clear the fpu */
+ lea %pc@(mmu),%a0
+ clrl %a0@
+ frestore %a0@
+
+/*
* Copy bootinfo from position after BSS to final resting place
*/
lea %pc@(SYMBOL_NAME(_end)),%a0
@@ -651,8+663,8 @@ Lamimmu68040:
.word 0xf4d8 /* CINVA I/D */
.word 0xf518 /* pflusha */
- .long 0x4e7bc807 /* movec a5,srp */
- .long 0x4e7bc806 /* movec a5,urp */
+ .long 0x4e7bc807 /* movec a4,srp */
+ .long 0x4e7bc806 /* movec a4,urp */
movel #(TC_ENABLE+TC_PAGE4K),%d0
/* setup registers for jumping MMU enabling code */
@@ -723,12+735,36 @@ Lmapphysnotamiga: /* cleanup is needed; note it */
moveq #1,%d5
+ /* tt0 doesn't work if physical and virtual address of kernel is in
+ * the same 16M area (Falcon with Magnum/FX, kernel in alternate ram)
+ */
movel %a0,%d2
andl #0xff000000,%d2 /* logical address base */
+ jeq 1f
orw #0x8143,%d2 /* add in magic bits */
lea %pc@(mmu),%a0
movel %d2,%a0@
pmove %a0@,%tt0
+ jra Lnophys2
+1:
+ /* Transparent translation through kernel pointer table
+ * Requires that this code until after MMU enabling lies in
+ * the 256K page around %a0
+ */
+ movel %a0,%d2
+ moveq #ROOT_INDEX_SHIFT,%d1
+ lsrl %d1,%d2
+ movel %a4@(%d2:l:4),%d0
+ andw #0xfff0,%d0
+ movel %d0,%a1
+ movel %a0,%d2
+ andl #0x01ffffff,%d2
+ moveq #(ROOT_INDEX_SHIFT-7),%d1
+ lsrl %d1,%d2
+ movel %a0,%d0
+ addql #PAGEDESC,%d0
+ movel %a1@(%d2:l:4),%a2 /* save old_entry */
+ movel %d0,%a1@(%d2:l:4)
Lnophys2:
/*
@@ -832,11+868,28 @@ LdoneMMUenable: cmpl #MACH_ATARI,%d4
jne Lnoclean
+ movel %a3,%d2
+ andl #0xff000000,%d2
+ jeq 1f
/* clear transparent translation register */
lea %pc@(mmu),%a0
clrl %a0@
pmove %a0@,%tt0
jra Lnoclean
+1:
+ movel %a3,%d2
+ moveq #ROOT_INDEX_SHIFT,%d1
+ lsrl %d1,%d2
+ movel %a4@(%d2:l:4),%d0
+ andw #0xfff0,%d0
+ subl %a3,%d0 /* to virtual address */
+ movel %d0,%a0
+ movel %a3,%d2
+ andl #0x01ffffff,%d2
+ moveq #(ROOT_INDEX_SHIFT-7),%d1
+ lsrl %d1,%d2
+ movel %a2,%a0@(%d2:l:4) /* restore old entry */
+ jra Lnoclean
Lclean030:
movel %a0,%d2 /* a0 contains physical start address */
@@ -1177,7+1230,11 @@ showtest: rts
#endif
- .align 512 /*
+#ifdef __ELF__
+ .align 512
+#else
+ .align 9
+#endif /*
* MMU root-pointers need to be 512-byte
* aligned on the 680[46]0 - Jes
*/
@@ -62,7+62,6 @@ unsigned long (*mach_gettimeoffset) (void); void (*mach_gettod) (int*, int*, int*, int*, int*, int*);
int (*mach_hwclk) (int, struct hwclk_time*) = NULL;
int (*mach_set_clock_mmss) (unsigned long) = NULL;
-void (*mach_check_partition) (struct gendisk *, unsigned int);
void (*mach_mksound)( unsigned int count, unsigned int ticks );
void (*mach_reset)( void );
void (*waitbut)(void) = dummy_waitbut;
@@ -296,10+295,6 @@ int get_hardware_list(char *buffer) #endif
} /* boot_info.machtype */
-#if 0 /* ++1.3++ */
- len += get_serial_list (buffer + len);
-#endif /* ++1.3++ */
-
return(len);
}
@@ -324,21+319,6 @@ unsigned long arch_kbd_init(void) return mach_keyb_init();
}
-int rs_init(void)
-{
- return 0;
-}
-
-struct serial_struct;
-int register_serial(struct serial_struct *req)
-{
- return -1;
-}
-
-void unregister_serial(int line)
-{
-}
-
void arch_gettod(int *year, int *mon, int *day, int *hour,
int *min, int *sec)
{
@@ -392,7+392,7 @@ static inline void bus_error030 (struct frame *fp) }
printk ("BAD KERNEL BUSERR\n");
die_if_kernel("Oops",&fp->ptregs,0);
- send_sig(SIGSEGV, current, 1);
+ force_sig(SIGSEGV, current);
user_space_fault = 0;
}
} else {
@@ -447,7+447,7 @@ static inline void bus_error030 (struct frame *fp) !(ssw & RW) ? "write" : "read", addr,
fp->ptregs.pc);
die_if_kernel("Oops",&fp->ptregs,mmusr);
- send_sig(SIGSEGV, current, 1);
+ force_sig(SIGSEGV, current);
return;
} else {
#ifdef DEBUG
@@ -478,7+478,7 @@ static inline void bus_error030 (struct frame *fp) printk("Unknown SIGSEGV - 1\n");
#endif
die_if_kernel("Oops",&fp->ptregs,mmusr);
- send_sig(SIGSEGV, current, 1);
+ force_sig(SIGSEGV, current);
return;
}
@@ -576,7+576,7 @@ static inline void bus_error030 (struct frame *fp) printk("Unknown SIGSEGV - 2\n");
#endif
die_if_kernel("Oops",&fp->ptregs,mmusr);
- send_sig(SIGSEGV, current, 1);
+ force_sig(SIGSEGV, current);
return;
} else {
#ifdef DEBUG
@@ -609,7+609,7 @@ static inline void bus_error030 (struct frame *fp) printk("Unknown SIGSEGV - 3\n");
#endif
die_if_kernel("Oops",&fp->ptregs,mmusr);
- send_sig(SIGSEGV, current, 1);
+ force_sig(SIGSEGV, current);
return;
}
@@ -644,7+644,7 @@ asmlinkage void buserr_c(struct frame *fp) #if DEBUG
printk("Unknown SIGSEGV - 4\n");
#endif
- send_sig(SIGSEGV, current, 1);
+ force_sig(SIGSEGV, current);
}
}
@@ -871,7+871,7 @@ asmlinkage void trap_c(struct frame *fp) break;
}
- send_sig (sig, current, 1);
+ force_sig (sig, current);
}
asmlinkage void set_esp0 (unsigned long ssp)
@@ -93,7+93,7 @@ good_area: bad_area:
if (user_mode(regs)) {
/* User memory access */
- send_sig (SIGSEGV, current, 1);
+ force_sig (SIGSEGV, current);
return 1;
}
@@ -506,7+506,7 @@ void cache_push_v (unsigned long vaddr, int len) : : "i" (FLUSH_I)
: "d0");
}
-
+#if 1
void flush_cache_all(void)
{
if (m68k_is040or060 >= 4)
@@ -515,26+515,53 @@ void flush_cache_all(void) asm volatile ("movec %/cacr,%/d0\n\t"
"oriw %0,%/d0\n\t"
"movec %/d0,%/cacr"
- : : "i" (FLUSH_I)
+ : : "i" (FLUSH_I_AND_D)
: "d0");
}
-void flush_page_to_ram (unsigned long addr)
+void flush_cache_mm(struct mm_struct *mm){
+
+ if (mm == current->mm)
+ flush_cache_all();
+}
+
+void flush_cache_range(struct mm_struct *mm, unsigned long start,
+ unsigned long end){
+ if (mm == current->mm)
+ cache_push_v(start, end-start);
+}
+
+void flush_cache_page (struct vm_area_struct *vma, unsigned long vaddr)
{
- if (m68k_is040or060 == 4)
- pushv040(addr);
+ if (m68k_is040or060 >= 4)
+ pushv040(vaddr); /*
+ * the 040 always invalidates the I-cache when
+ * pushing its contents to ram.
+ */
+
+ /* 68030/68020 have no writeback cache; still need to clear icache. */
+ else /* 68030 or 68020 */
+ asm volatile ("movec %/cacr,%/d0\n\t"
+ "oriw %0,%/d0\n\t"
+ "movec %/d0,%/cacr"
+ : : "i" (FLUSH_I_AND_D)
+ : "d0");
+}
- else if (m68k_is040or060 == 6)
- push040(VTOP(addr)); /* someone mentioned that pushv060 doesn't work */
+void flush_page_to_ram (unsigned long vaddr)
+{
+ if (m68k_is040or060 >= 4)
+ pushcl040(VTOP(vaddr));
/* 68030/68020 have no writeback cache; still need to clear icache. */
else /* 68030 or 68020 */
asm volatile ("movec %/cacr,%/d0\n\t"
"oriw %0,%/d0\n\t"
"movec %/d0,%/cacr"
- : : "i" (FLUSH_I)
+ : : "i" (FLUSH_I_AND_D)
: "d0");
}
+#endif
#undef clear040
#undef push040
@@ -45,7+45,9 @@ bool 'Generate little endian code' CONFIG_CPU_LITTLE_ENDIAN bool 'Networking support' CONFIG_NET
#bool 'PCI bios support' CONFIG_PCI
#if [ "$CONFIG_PCI" = "y" ]; then
-# bool ' PCI bridge optimization (experimental)' CONFIG_PCI_OPTIMIZE
+# if [ "$CONFIG_EXPERIMENTAL" = "y" ]; then
+# bool ' PCI bridge optimization (experimental)' CONFIG_PCI_OPTIMIZE
+# fi
#fi
bool 'System V IPC' CONFIG_SYSVIPC
endmenu
eret
/*
* Workaround for R4000 bug. For explanation see MIPS
- * docs. Note that this that obscure that it wont almost
- * never happen. Well, but Mips writes about it's bugs.
+ * docs. Note that this is so obscure that it will almost
+ * never happen. Well, but Mips writes about its bugs.
*/
nop
eret
@@ -202,7+202,7 @@ static void timer_interrupt(int irq, struct pt_regs * regs) last_rtc_update = xtime.tv_sec - 600; /* do it again in 60 s */
/* As we return to user mode fire off the other CPU schedulers.. this is
basically because we don't yet share IRQ's around. This message is
- rigged to be safe on the 386 - basically its a hack, so don't look
+ rigged to be safe on the 386 - basically it's a hack, so don't look
closely for now.. */
smp_message_pass(MSG_ALL_BUT_SELF, MSG_RESCHEDULE, 0L, 0);
}
@@ -168,7+168,7 @@ void __copy_page(unsigned long from, unsigned long to) {
/*
* The page copied most is the COW empty_zero_page. Since we
- * know it's contents we can avoid the writeback reading of
+ * know its contents we can avoid the writeback reading of
* the page. Speeds up the standard case a lot.
*/
__zeropage(to);
@@ -29,7+29,9 @@ bool 'Networking support' CONFIG_NET y #bool 'Limit memory to low 16MB' CONFIG_MAX_16M n
bool 'PCI bios support' CONFIG_PCI y
if [ "$CONFIG_PCI" = "y" ]; then
- bool ' PCI bridge optimization (experimental)' CONFIG_PCI_OPTIMIZE n
+ if [ "$CONFIG_EXPERIMENTAL" = "y" ]; then
+ bool ' PCI bridge optimization (experimental)' CONFIG_PCI_OPTIMIZE n
+ fi
if [ "$CONFIG_BLK_DEV_IDE" = "y" ]; then
bool ' PCI Triton IDE Bus Master DMA support' CONFIG_BLK_DEV_TRITON y
fi
@@ -1287,8+1287,8 @@ _GLOBAL(flush_data_cache)
/*
* This routine switches between two different tasks. The process
- * state of one is saved on it's kernel stack. Then the state
- * of the other is restored from it's kernel stack. The memory
+ * state of one is saved on its kernel stack. Then the state
+ * of the other is restored from its kernel stack. The memory
* management hardware is updated to the second process's state.
* Finally, we can return to the second process, via the 'return'.
*
@@ -4,7+4,7 @@ is real ugly and it knows too much. It must be able to not only boot off of the root partition but also be able to netboot. This means
that it knows about RPC and NFS (bleech, yuck, eeewwwww!!) so that it
can remote mount the root directory to fetch the kernel. Also it must
-be able to ARP for it's IP address and who it's boot server is. I
+be able to ARP for its IP address and who its boot server is. I
think I'm getting sick.
Regardless for now I will concentrate on the low-level stuff necessary
@@ -497,7+497,7 @@ copy_prom_lvl14: std %g4, [%g3 + 0x8] ! Copy proms handler
/* Must determine whether we are on a sun4c MMU, SRMMU, or SUN4/400 MUTANT
- * MMU so we can remap ourselves properly. DONT TOUCH %l0 thru %l5 in these
+ * MMU so we can remap ourselves properly. DON'T TOUCH %l0 thru %l5 in these
* remapping routines, we need their values afterwards!
*/
/* Now check whether we are already mapped, if we
@@ -571,7+571,7 @@ srmmu_remap: /* Grrr, why does it seem like every other load/store
* on the sun4m is in some ASI space...
* Fine with me, let's get the pointer to the level 1
- * page table directory and fetch it's entry.
+ * page table directory and fetch its entry.
*/
lda [%g4] ASI_M_BYPASS, %o1 ! This is a level 1 ptr
srl %o1, 0x4, %o1 ! Clear low 4 bits
@@ -81,7+81,7 @@ void (*set_irq_udt)(int); * equally sucky but at least we'll never try to free statically allocated
* space or call kmalloc before kmalloc_init :(.
*
- * In fact its the timer10 that attaches first.. then timer14
+ * In fact it's the timer10 that attaches first.. then timer14
* then kmalloc_init is called.. then the tty interrupts attach.
* hmmm....
*
THIS SOFTWARE IS NOT COPYRIGHTED
HP offers the following for use in the public domain. HP makes no
- warranty with regard to the software or it's performance and the
+ warranty with regard to the software or its performance and the
user accepts the software "AS IS" with all faults.
HP DISCLAIMS ANY WARRANTIES, EXPRESS OR IMPLIED, WITH REGARD
@@ -41,10+41,10 @@ unsigned long *irq_rcvreg = &dummy; /* These tables only apply for interrupts greater than 15..
*
* any intr value below 0x10 is considered to be a soft-int
- * this may be useful or it may not.. but thats how I've done it.
+ * this may be useful or it may not.. but that's how I've done it.
* and it won't clash with what OBP is telling us about devices.
*
- * take an encoded intr value and lookup if its valid
+ * take an encoded intr value and lookup if it's valid
* then get the mask bits that match from irq_mask
*/
static unsigned char irq_xlate[32] = {
@@ -66,7+66,7 @@ C_LABEL(sparc_switch_to):
#ifdef __SMP__
/* Because of nasty register windows this is the only way
- * to start a processor into it's cpu_idle() thread.
+ * to start a processor into its cpu_idle() thread.
*/
.globl C_LABEL(sparc_cpusched)
@@ -130,7+130,7 @@ spwin_exist_uwins: /* Wow, user windows have to be dealt with, this is dirty
* and messy as all hell. And difficult to follow if you
* are approaching the infamous register window trap handling
- * problem for the first time. DONT LOOK!
+ * problem for the first time. DON'T LOOK!
*
* Note that how the execution path works out, the new %wim
* will be left for us in the global temporary register,
@@ -1834,7+1834,7 @@ unsigned long srmmu_paging_init(unsigned long start_mem, unsigned long end_mem) }
#endif
if(!num_contexts) {
- prom_printf("Something wrong, cant find cpu node in paging_init.\n");
+ prom_printf("Something wrong, can't find cpu node in paging_init.\n");
prom_halt();
}
@@ -83,7+83,7 @@ prom_getproperty(int node, char *prop, char *buffer, int bufsize) return prom_nodeops->no_getprop(node, prop, buffer);
}
-/* Acquire an integer property and return it's value. Returns -1
+/* Acquire an integer property and return its value. Returns -1
* on failure.
*/
int
@@ -42,7+42,7 @@ if [ "$CONFIG_BLK_DEV_HD_IDE" = "y" -o "$CONFIG_BLK_DEV_HD_ONLY" = "y" ]; then define_bool CONFIG_BLK_DEV_HD y
fi
-bool 'XT harddisk support' CONFIG_BLK_DEV_XD
+tristate 'XT harddisk support' CONFIG_BLK_DEV_XD
bool 'Multiple devices driver support' CONFIG_BLK_DEV_MD
if [ "$CONFIG_BLK_DEV_MD" = "y" ]; then
tristate ' Linear (append) mode' CONFIG_MD_LINEAR
ifeq ($(CONFIG_BLK_DEV_XD),y)
L_OBJS += xd.o
+else
+ ifeq ($(CONFIG_BLK_DEV_XD),m)
+ M_OBJS += xd.o
+ endif
endif
ifeq ($(CONFIG_BLK_DEV_MD),y)
@@ -485,7+485,7 @@ In <41ip85$gf9@park.uvsc.edu>, Terry Lambert <terry@cs.weber.edu> writes: I agreed that you might be able to concoct a benchmark that was affected,
but it has had no real world effect for me or a lot of other people. Disabling
IDE prefetch has the effect of a small increase in PCI bus busy at a time
-when the CPU is giving all it's CPU cycles to the IDE driver (because the
+when the CPU is giving all its CPU cycles to the IDE driver (because the
RZ1000 can't run DMA and the driver has to be in a PIO loop) and therefore
the CPU can't do much of anything else anyway.
* - added command line and machine based default for "silent" df0
*
* december 1995 adapted for 1.2.13pl4 by Joerg Dorchain
- * - works but I think its inefficient. (look in redo_fd_request)
+ * - works but I think it's inefficient. (look in redo_fd_request)
* But the changes were very efficient. (only three and a half lines)
*
* january 1995 added special ioctl for tracking down read/write problems
@@ -675,7+675,7 @@ unsigned char track, /* 0-80 */ len_desc;/* 2 */
unsigned short crc; /* on 68000 we got an alignment problem,
but this compiler solves it by adding silently
- adding a pad byte so data wont fit
+ adding a pad byte so data won't fit
and this cost about 3h to discover.... */
unsigned char gap1[22]; /* for longword-alignedness (0x4e) */
};
@@ -1780,3+1780,12 @@ int amiga_floppy_init(void)
return 0;
}
+
+#ifndef MODULE
+/*
+ * This is just a dummy function to keep fs/super.c happy.
+ */
+void floppy_eject(void)
+{
+}
+#endif
@@ -1945,4+1945,12 @@ void cleanup_module (void) timer_table[FLOPPY_TIMER].fn = 0;
kfree (DMABuffer);
}
+#else
+/*
+ * This is just a dummy function to keep fs/super.c happy.
+ */
+void floppy_eject(void)
+{
+}
#endif
+
@@ -206,18+206,18 @@ void set_device_ro(kdev_t dev,int flag) else ro_bits[major][minor >> 5] &= ~(1 << (minor & 31));
}
-static inline void drive_stat_acct(int cmd, unsigned long nr_sectors, short disk_index)
+static inline void drive_stat_acct(int cmd, unsigned long nr_sectors,
+ short disk_index)
{
kstat.dk_drive[disk_index]++;
if (cmd == READ) {
kstat.dk_drive_rio[disk_index]++;
kstat.dk_drive_rblk[disk_index] += nr_sectors;
- }
- else if (cmd == WRITE) {
+ } else if (cmd == WRITE) {
kstat.dk_drive_wio[disk_index]++;
kstat.dk_drive_wblk[disk_index] += nr_sectors;
} else
- printk("drive_stat_acct: cmd not R/W?\n");
+ printk(KERN_ERR "drive_stat_acct: cmd not R/W?\n");
}
/*
@@ -289,9+289,15 @@ static void make_request(int major,int rw, struct buffer_head * bh) if (blk_size[major])
if (blk_size[major][MINOR(bh->b_rdev)] < (sector + count)>>1) {
bh->b_state = 0;
- printk("attempt to access beyond end of device\n");
- printk("%s: rw=%d, want=%d, limit=%d\n", kdevname(bh->b_rdev),
- rw, (sector + count)>>1, blk_size[major][MINOR(bh->b_rdev)]);
+ /* This may well happen - the kernel calls bread()
+ without checking the size of the device, e.g.,
+ when mounting a device. */
+ printk(KERN_INFO
+ "attempt to access beyond end of device\n");
+ printk(KERN_INFO "%s: rw=%d, want=%d, limit=%d\n",
+ kdevname(bh->b_rdev), rw,
+ (sector + count)>>1,
+ blk_size[major][MINOR(bh->b_rdev)]);
return;
}
/* Uhhuh.. Nasty dead-lock possible here.. */
@@ -330,7+336,8 @@ static void make_request(int major,int rw, struct buffer_head * bh) max_req = (NR_REQUEST * 2) / 3;
break;
default:
- printk("make_request: bad block dev cmd, must be R/W/RA/WA\n");
+ printk(KERN_ERR "make_request: bad block dev cmd,"
+ " must be R/W/RA/WA\n");
unlock_buffer(bh);
return;
}
@@ -442,13+449,13 @@ void ll_rw_block(int rw, int nr, struct buffer_head * bh[]) bh++;
if (--nr <= 0)
return;
- };
+ }
dev = NULL;
if ((major = MAJOR(bh[0]->b_dev)) < MAX_BLKDEV)
dev = blk_dev + major;
if (!dev || !dev->request_fn) {
- printk(
+ printk(KERN_ERR
"ll_rw_block: Trying to read nonexistent block-device %s (%ld)\n",
kdevname(bh[0]->b_dev), bh[0]->b_blocknr);
goto sorry;
@@ -465,7+472,7 @@ void ll_rw_block(int rw, int nr, struct buffer_head * bh[]) /* Verify requested block sizes. */
for (i = 0; i < nr; i++) {
if (bh[i] && bh[i]->b_size != correct_size) {
- printk("ll_rw_block: device %s: "
+ printk(KERN_NOTICE "ll_rw_block: device %s: "
"only %d-char blocks implemented (%lu)\n",
kdevname(bh[0]->b_dev),
correct_size, bh[i]->b_size);
@@ -484,7+491,7 @@ void ll_rw_block(int rw, int nr, struct buffer_head * bh[]) }
if ((rw == WRITE || rw == WRITEA) && is_read_only(bh[0]->b_dev)) {
- printk("Can't write to read-only device %s\n",
+ printk(KERN_NOTICE "Can't write to read-only device %s\n",
kdevname(bh[0]->b_dev));
goto sorry;
}
@@ -519,7+526,8 @@ void ll_rw_swap_file(int rw, kdev_t dev, unsigned int *b, int nb, char *buf) struct semaphore sem = MUTEX_LOCKED;
if (major >= MAX_BLKDEV || !(blk_dev[major].request_fn)) {
- printk("ll_rw_swap_file: trying to swap nonexistent block-device\n");
+ printk(KERN_NOTICE "ll_rw_swap_file: trying to swap to"
+ " nonexistent block-device\n");
return;
}
switch (rw) {
@@ -527,7+535,8 @@ void ll_rw_swap_file(int rw, kdev_t dev, unsigned int *b, int nb, char *buf) break;
case WRITE:
if (is_read_only(dev)) {
- printk("Can't swap to read-only device %s\n",
+ printk(KERN_NOTICE
+ "Can't swap to read-only device %s\n",
kdevname(dev));
return;
}
@@ -547,7+556,8 @@ void ll_rw_swap_file(int rw, kdev_t dev, unsigned int *b, int nb, char *buf) if (major==MD_MAJOR &&
md_map (MINOR(dev), &rdev,
&rsector, buffersize >> 9)) {
- printk ("Bad md_map in ll_rw_page_size\n");
+ printk (KERN_ERR
+ "Bad md_map in ll_rw_page_size\n");
return;
}
#endif
@@ -133,12+133,12 @@ static void figure_loop_size(struct loop_device *lo) int size;
if (S_ISREG(lo->lo_inode->i_mode))
- size = (lo->lo_inode->i_size - lo->lo_offset) / 1024;
+ size = (lo->lo_inode->i_size - lo->lo_offset) / BLOCK_SIZE;
else {
- if (blk_size[MAJOR(lo->lo_device)])
- size = ((blk_size[MAJOR(lo->lo_device)]
- [MINOR(lo->lo_device)]) -
- (lo->lo_offset/1024));
+ kdev_t lodev = lo->lo_device;
+ if (blk_size[MAJOR(lodev)])
+ size = blk_size[MAJOR(lodev)][MINOR(lodev)] -
+ lo->lo_offset / BLOCK_SIZE;
else
size = MAX_DISK_SIZE;
}
@@ -307,11+307,15 @@ static int loop_clr_fd(struct loop_device *lo, kdev_t dev) static int loop_set_status(struct loop_device *lo, struct loop_info *arg)
{
struct loop_info info;
+ int err;
if (!lo->lo_inode)
return -ENXIO;
if (!arg)
return -EINVAL;
+ err = verify_area(VERIFY_READ, arg, sizeof(info));
+ if (err)
+ return err;
memcpy_fromfs(&info, arg, sizeof(info));
if ((unsigned int) info.lo_encrypt_key_size > LO_KEY_SIZE)
return -EINVAL;
@@ -349,11+353,15 @@ static int loop_set_status(struct loop_device *lo, struct loop_info *arg) static int loop_get_status(struct loop_device *lo, struct loop_info *arg)
{
struct loop_info info;
+ int err;
if (!lo->lo_inode)
return -ENXIO;
if (!arg)
return -EINVAL;
+ err = verify_area(VERIFY_WRITE, arg, sizeof(info));
+ if (err)
+ return err;
memset(&info, 0, sizeof(info));
info.lo_number = lo->lo_number;
info.lo_device = kdev_t_to_nr(lo->lo_inode->i_dev);
* interrupts enabled and Linus didn't want to enable them in that first
* phase. xd_geninit() is the place to do these kinds of things anyway,
* he says.
+ *
+ * Modularized: 04/10/96 by Todd Fries, tfries@umr.edu
+ *
*/
@@ -64,6+67,7 @@ XD_INFO xd_info[XD_MAXDRIVES];
static XD_SIGNATURE xd_sigs[] = {
{ 0x0000,"Override geometry handler",NULL,xd_override_init_drive,"n unknown" }, /* Pat Mackinlay, pat@it.com.au */
+ { 0x000B,"CRD18A Not an IBM rom. (C) Copyright Data Technology Corp. 05/31/88",xd_dtc_init_controller,xd_dtc_init_drive," DTC 5150X" }, /* Todd Fries, tfries@umr.edu */
{ 0x000B,"CXD23A Not an IBM ROM (C)Copyright Data Technology Corp 12/03/88",xd_dtc_init_controller,xd_dtc_init_drive," DTC 5150X" }, /* Pat Mackinlay, pat@it.com.au */
{ 0x0008,"07/15/86 (C) Copyright 1986 Western Digital Corp",xd_wd_init_controller,xd_wd_init_drive," Western Digital 1002AWX1" }, /* Ian Justman, citrus!ianj@csusac.ecs.csus.edu */
{ 0x0008,"06/24/88 (C) Copyright 1988 Western Digital Corp",xd_wd_init_controller,xd_wd_init_drive," Western Digital 1004A27X" }, /* Dave Thaler, thalerd@engin.umich.edu */
@@ -89,7+93,11 @@ static struct gendisk xd_gendisk = { 6, /* Bits to shift to get real from partition */
1 << 6, /* Number of partitions per real */
XD_MAXDRIVES, /* maximum number of real */
- xd_geninit, /* init function */
+#ifdef MODULE
+ NULL, /* called from init_module */
+#else
+ xd_geninit, /* init function */
+#endif
xd, /* hd struct */
xd_sizes, /* block sizes */
0, /* number */
@@ -727,3+735,23 @@ static void xd_setparam (u_char command,u_char drive,u_char heads,u_short cylind printk("xd_setparam: error setting characteristics for drive %d\n",drive);
}
+
+#ifdef MODULE
+int init_module(void)
+{
+ int error = xd_init();
+ if (!error)
+ {
+ printk(KERN_INFO "XD: Loaded as a module.\n");
+ xd_geninit(&(struct gendisk) { 0,0,0,0,0,0,0,0,0,0,0 });
+ }
+
+ return error;
+}
+
+void cleanup_module(void)
+{
+ unregister_blkdev(MAJOR_NR, "xd");
+}
+#endif /* MODULE */
+
Werner Zimmermann, April 29, 96
V2.40 Reorganized the placement of functions in the source code file
to reflect the layered approach; did not actually change code
- Werner Zimmermann, Mai 1, 96
+ Werner Zimmermann, May 1, 96
*/
#include <linux/module.h>
#include <linux/errno.h>
Wed Apr 24 14:02:04 1996 Theodore Ts'o <tytso@rsts-11.mit.edu>
- * random.c (add_timer_randomness): Use 2nd derivitive as well to
+ * random.c (add_timer_randomness): Use 2nd derivative as well to
better estimate entropy.
(rand_initialize): Explicitly initialize all the pointers
@@ -864,7+864,7 @@ static void csi_m(int currcons) toggle_meta = 0;
break;
case 11: /* ANSI X3.64-1979 (SCO-ish?)
- * Select first alternate font, let's
+ * Select first alternate font, lets
* chars < 32 be displayed as ROM chars.
*/
translate = set_translate(IBMPC_MAP);
@@ -45,6+45,10 @@ static inline int PROC_CONSOLE(void) if (!current->tty)
return fg_console;
+ if (current->tty->driver.type != TTY_DRIVER_TYPE_CONSOLE)
+ /* XXX Should report error here? */
+ return fg_console;
+
if (MINOR(current->tty->device) < 1)
return fg_console;
@@ -180,6+184,18 @@ fb_ioctl(struct inode *inode, struct file *file, unsigned int cmd, if (i) return i;
}
return (fb->fb_get_cmap(&cmap, 0, PROC_CONSOLE()));
+ case FBIOPAN_DISPLAY:
+ i = verify_area(VERIFY_WRITE, (void *) arg,
+ sizeof(struct fb_var_screeninfo));
+ if (i) return i;
+ memcpy_fromfs(&var, (void *) arg, sizeof(var));
+ i=fb->fb_pan_display(&var, PROC_CONSOLE());
+ memcpy_tofs((void *) arg, &var, sizeof(var));
+ fbidx=GET_FB_IDX(inode->i_rdev);
+ vidx=GET_FB_VAR_IDX(inode->i_rdev);
+ if (! i && vidx)
+ registered_fb_var[fbidx][vidx-1]=var;
+ return i;
default:
return (fb->fb_ioctl(inode, file, cmd, arg, PROC_CONSOLE()));
}
@@ -199,8+215,11 @@ fb_mmap(struct inode *inode, struct file *file, struct vm_area_struct * vma) vma->vm_offset += fix.smem_start;
if (vma->vm_offset & ~PAGE_MASK)
return -ENXIO;
- if (boot_info.cputype & CPU_68040)
+ if (m68k_is040or060) {
pgprot_val(vma->vm_page_prot) &= _CACHEMASK040;
+ /* Use write-through cache mode */
+ pgprot_val(vma->vm_page_prot) |= _PAGE_CACHE040W;
+ }
if (remap_page_range(vma->vm_start, vma->vm_offset,
vma->vm_end - vma->vm_start, vma->vm_page_prot))
return -EAGAIN;
@@ -606,8+606,8 @@ int _ftape_read(char *buff, int req_len) * get more than 29 Kb from it (As it only contains this much).
* This works only for sequential access, so random access should
* stay away from this `last' segment.
- * Note: ftape_seg_pos points to the next segment what will be
- * read, so it's one too hight here!
+ * Note: ftape_seg_pos points to the next segment that will be
+ * read, so it's one too high here!
*/
if (!eof_mark && ftape_seg_pos - 1 >= ftape_last_segment.id) {
TRACEi(5, "remaining of last segment:", remaining);
/* Global vars.
*/
-/* Allocating a 96Kb DMAable buffer in one chunk wont work due to
+/* Allocating a 96Kb DMAable buffer in one chunk won't work due to
* memory fragmentation. To avoid this, it is broken up into
* NR_BUFFERS chunks of 32Kbyte. --khp
*/
@@ -3386,7+3386,7 @@ static int stli_initecp(stlibrd_t *brdp) }
/*
- * The per-board operations structure is all setup, so now lets go
+ * The per-board operations structure is all set up, so now let's go
* and get the board operational. Firstly initialize board configuration
* registers. Then if we are using the higher 1Mb support then set up
* the memory mapping info so we can get at the boards shared memory.
@@ -3542,7+3542,7 @@ static int stli_initonb(stlibrd_t *brdp) }
/*
- * The per-board operations structure is all setup, so now lets go
+ * The per-board operations structure is all set up, so now let's go
* and get the board operational. Firstly initialize board configuration
* registers. Then if we are using the higher 1Mb support then set up
* the memory mapping info so we can get at the boards shared memory.
@@ -183,14+183,14 @@ static inline int lp_write_interrupt(unsigned int minor, const char * buf, int c if (lp_table[minor].runchars > LP_STAT(minor).maxrun)
LP_STAT(minor).maxrun = lp_table[minor].runchars;
status = LP_S(minor);
- if ((status & LP_OFFL) || !(status & LP_PSELECD)) {
- printk(KERN_INFO "lp%d off-line\n", minor);
- if (LP_F(minor) & LP_ABORT)
- return rc?rc:-EIO;
- } else if ((status & LP_POUTPA)) {
+ if ((status & LP_POUTPA)) {
printk(KERN_INFO "lp%d out of paper\n", minor);
if (LP_F(minor) & LP_ABORT)
return rc?rc:-ENOSPC;
+ } else if (!(status & LP_PSELECD)) {
+ printk(KERN_INFO "lp%d off-line\n", minor);
+ if (LP_F(minor) & LP_ABORT)
+ return rc?rc:-EIO;
} else if (!(status & LP_PERRORP)) {
printk(KERN_ERR "lp%d printer error\n", minor);
if (LP_F(minor) & LP_ABORT)
@@ -248,18+248,18 @@ static inline int lp_write_polled(unsigned int minor, const char * buf, int coun LP_STAT(minor).maxrun = lp_table[minor].runchars;
status = LP_S(minor);
- if ((status & LP_OFFL) || !(status & LP_PSELECD)) {
- printk(KERN_INFO "lp%d off-line\n", minor);
+ if (status & LP_POUTPA) {
+ printk(KERN_INFO "lp%d out of paper\n", minor);
if(LP_F(minor) & LP_ABORT)
- return temp-buf?temp-buf:-EIO;
+ return temp-buf?temp-buf:-ENOSPC;
current->state = TASK_INTERRUPTIBLE;
current->timeout = jiffies + LP_TIMEOUT_POLLED;
schedule();
} else
- if (status & LP_POUTPA) {
- printk(KERN_INFO "lp%d out of paper\n", minor);
+ if (!(status & LP_PSELECD)) {
+ printk(KERN_INFO "lp%d off-line\n", minor);
if(LP_F(minor) & LP_ABORT)
- return temp-buf?temp-buf:-ENOSPC;
+ return temp-buf?temp-buf:-EIO;
current->state = TASK_INTERRUPTIBLE;
current->timeout = jiffies + LP_TIMEOUT_POLLED;
schedule();
@@ -236,13+236,13 @@ static int lp_write_interrupt(struct inode *inode, struct file *file, been printed at all. */
if (lp_table[dev].lp_has_pout(dev)) {
- printk("lp%d: paper-out\n",dev);
+ printk(KERN_NOTICE "lp%d: paper-out\n",dev);
if (!rc) rc = -ENOSPC;
} else if (!lp_table[dev].lp_is_online(dev)) {
- printk("lp%d: off-line\n",dev);
+ printk(KERN_NOTICE "lp%d: off-line\n",dev);
if (!rc) rc = -EIO;
} else if (lp_table[dev].lp_is_busy(dev)) {
- printk("lp%d: on fire\n",dev);
+ printk(KERN_NOTICE "lp%d: on fire\n",dev);
if (!rc) rc = -EIO;
}
if (lp_table[dev].flags & LP_ABORT)
@@ -294,14+294,14 @@ static int lp_write_polled(struct inode *inode, struct file *file, #endif
} else { /* if printer timed out */
if (lp_table[dev].lp_has_pout(dev)) {
- printk("lp%d: out of paper\n",dev);
+ printk(KERN_NOTICE "lp%d: out of paper\n",dev);
if (lp_table[dev].flags & LP_ABORT)
return temp - buf ? temp-buf : -ENOSPC;
current->state = TASK_INTERRUPTIBLE;
current->timeout = jiffies + LP_TIMEOUT_POLLED;
schedule();
} else if (!lp_table[dev].lp_is_online(dev)) {
- printk("lp%d: off-line\n",dev);
+ printk(KERN_NOTICE "lp%d: off-line\n",dev);
if (lp_table[dev].flags & LP_ABORT)
return temp - buf ? temp-buf : -EIO;
current->state = TASK_INTERRUPTIBLE;
@@ -310,7+310,7 @@ static int lp_write_polled(struct inode *inode, struct file *file, } else
/* not offline or out of paper. on fire? */
if (lp_table[dev].lp_is_busy(dev)) {
- printk("lp%d: on fire\n",dev);
+ printk(KERN_NOTICE "lp%d: on fire\n",dev);
if (lp_table[dev].flags & LP_ABORT)
return temp - buf ? temp-buf : -EFAULT;
current->state = TASK_INTERRUPTIBLE;
@@ -447,7+447,7 @@ int lp_init(void)
#if WHICH_DRIVER == FORCE_POLLING
lp_irq = 0;
- printk("lp_init: lp using polling driver\n");
+ printk(KERN_INFO "lp_init: lp using polling driver\n");
#else
#ifdef CONFIG_AMIGA
@@ -462,13+462,13 @@ int lp_init(void) #endif
if (lp_irq)
- printk("lp_init: lp using interrupt\n");
+ printk(KERN_INFO "lp_init: lp using interrupt\n");
else
#if WHICH_DRIVER == PREFER_INTERRUPT
- printk("lp_init: lp using polling driver\n");
+ printk(KERN_INFO "lp_init: lp using polling driver\n");
#else
- printk("lp_init: cant get interrupt, and polling driver not configured\n");
+ printk(KERN_WARNING "lp_init: can't get interrupt, and polling driver not configured\n");
#endif
#endif
19200 = 57600
38400 = 115K
The driver supports the native 57.6K and 115K Baudrates under Linux, but
- some distributions like Slackware 3.0 dont like these high baudrates.
+ some distributions like Slackware 3.0 don't like these high baudrates.
*/
#include <linux/mm.h>
@@ -1602,7+1602,7 @@ static unsigned termios2digi_c(struct channel *ch, unsigned cflag) {
ch->digiext.digi_flags |= DIGI_FAST;
res |= FEP_HUPCL;
- /* This gets strange but if we dont do this we will get 78600
+ /* This gets strange but if we don't do this we will get 78600
* instead of 115200. 57600 is mapped to 50 baud yielding 57600 in
* FAST mode. 115200 is mapped to 75. We need to map it to 110 to
* do 115K
@@ -315,13+315,13 @@ static int open_aux(struct inode * inode, struct file * file) aux_count--;
return -EBUSY;
}
+ MOD_INC_USE_COUNT;
poll_aux_status();
outb_p(AUX_ENABLE,AUX_COMMAND); /* Enable Aux */
aux_write_dev(AUX_ENABLE_DEV); /* enable aux device */
aux_write_cmd(AUX_INTS_ON); /* enable controller ints */
poll_aux_status();
aux_ready = 0;
- MOD_INC_USE_COUNT;
return 0;
}
@@ -181,7+181,9 @@ static void pty_flush_buffer(struct tty_struct *tty)
int pty_open(struct tty_struct *tty, struct file * filp)
{
+#if PTY_SLAVE_WAITS_ON_OPEN
struct wait_queue wait = { current, NULL };
+#endif
int retval;
int line;
struct pty_struct *pty;
* fi
* dd if=/dev/urandom of=/etc/random-seed count=1
*
- * and the following lines in an approproate script which is run as
+ * and the following lines in an appropriate script which is run as
* the system is shutdown:
*
* # Carry a random seed from shut-down to start-up
@@ -574,7+574,7 @@ void add_blkdev_randomness(int major) #define HASH_TRANSFORM SHATransform
/*
- * SHA transform algorith, taken from code written by Peter Gutman,
+ * SHA transform algorithm, taken from code written by Peter Gutman,
* and apparently in the public domain.
*/
@@ -615,7+615,7 @@ void SHATransform(__u32 *digest, __u32 *data) E = digest[ 4 ];
memcpy( eData, data, 16*sizeof(__u32));
- /* Heavy mangling, in 4 sub-rounds of 20 interations each. */
+ /* Heavy mangling, in 4 sub-rounds of 20 iterations each. */
subRound( A, B, C, D, E, f1, K1, eData[ 0 ] );
subRound( E, A, B, C, D, f1, K1, eData[ 1 ] );
subRound( D, E, A, B, C, f1, K1, eData[ 2 ] );
*
*/
-#define RTC_VERSION "1.05"
+#define RTC_VERSION "1.06"
#define RTC_IRQ 8 /* Can't see this changing soon. */
#define RTC_IO_BASE 0x70 /* Or this... */
#include <asm/segment.h>
#include <asm/system.h>
-#include <time.h>
-
/*
* We sponge a minor off of the misc major. No need slurping
* up another valuable major dev number for this.
@@ -81,14+79,14 @@ static int rtc_ioctl(struct inode *inode, struct file *file, static int rtc_select(struct inode *inode, struct file *file,
int sel_type, select_table *wait);
-void get_rtc_time (struct tm *rtc_tm);
-void get_rtc_alm_time (struct tm *alm_tm);
+void get_rtc_time (struct rtc_time *rtc_tm);
+void get_rtc_alm_time (struct rtc_time *alm_tm);
void rtc_dropped_irq(unsigned long data);
-inline void set_rtc_irq_bit(unsigned char bit);
-inline void mask_rtc_irq_bit(unsigned char bit);
+void set_rtc_irq_bit(unsigned char bit);
+void mask_rtc_irq_bit(unsigned char bit);
-unsigned char rtc_is_updating(void);
+static inline unsigned char rtc_is_updating(void);
/*
* Bits in rtc_status. (7 bits of room for future expansion)
@@ -221,10+219,7 @@ static int rtc_ioctl(struct inode *inode, struct file *file, unsigned int cmd, * than 64Hz of interrupts on a multi-user machine.
*/
if ((rtc_freq > 64) && (!suser()))
- return -EPERM;
-
- if (rtc_freq == 0)
- return -EINVAL;
+ return -EACCES;
if (!(rtc_status & RTC_TIMER_ON)) {
rtc_status |= RTC_TIMER_ON;
@@ -247,39+242,39 @@ static int rtc_ioctl(struct inode *inode, struct file *file, unsigned int cmd, case RTC_ALM_READ: /* Read the present alarm time */
{
/*
- * This returns a struct tm. Reading >= 0xc0 means
- * "don't care" or "match all". Only the tm_hour,
+ * This returns a struct rtc_time. Reading >= 0xc0
+ * means "don't care" or "match all". Only the tm_hour,
* tm_min, and tm_sec values are filled in.
*/
int retval;
- struct tm alm_tm;
+ struct rtc_time alm_tm;
- retval = verify_area(VERIFY_WRITE, (struct tm*)arg, sizeof(struct tm));
+ retval = verify_area(VERIFY_WRITE, (struct rtc_time*)arg, sizeof(struct rtc_time));
if (retval != 0 )
return retval;
get_rtc_alm_time(&alm_tm);
- memcpy_tofs((struct tm*)arg, &alm_tm, sizeof(struct tm));
+ memcpy_tofs((struct rtc_time*)arg, &alm_tm, sizeof(struct rtc_time));
return 0;
}
case RTC_ALM_SET: /* Store a time into the alarm */
{
/*
- * This expects a struct tm. Writing 0xff means
+ * This expects a struct rtc_time. Writing 0xff means
* "don't care" or "match all". Only the tm_hour,
* tm_min and tm_sec are used.
*/
int retval;
unsigned char hrs, min, sec;
- struct tm alm_tm;
+ struct rtc_time alm_tm;
- retval = verify_area(VERIFY_READ, (struct tm*)arg, sizeof(struct tm));
+ retval = verify_area(VERIFY_READ, (struct rtc_time*)arg, sizeof(struct rtc_time));
if (retval != 0 )
return retval;
- memcpy_fromfs(&alm_tm, (struct tm*)arg, sizeof(struct tm));
+ memcpy_fromfs(&alm_tm, (struct rtc_time*)arg, sizeof(struct rtc_time));
hrs = alm_tm.tm_hour;
min = alm_tm.tm_min;
@@ -313,33+308,33 @@ static int rtc_ioctl(struct inode *inode, struct file *file, unsigned int cmd, case RTC_RD_TIME: /* Read the time/date from RTC */
{
int retval;
- struct tm rtc_tm;
+ struct rtc_time rtc_tm;
- retval = verify_area(VERIFY_WRITE, (struct tm*)arg, sizeof(struct tm));
+ retval = verify_area(VERIFY_WRITE, (struct rtc_time*)arg, sizeof(struct rtc_time));
if (retval !=0 )
return retval;
get_rtc_time(&rtc_tm);
- memcpy_tofs((struct tm*)arg, &rtc_tm, sizeof(struct tm));
+ memcpy_tofs((struct rtc_time*)arg, &rtc_tm, sizeof(struct rtc_time));
return 0;
}
case RTC_SET_TIME: /* Set the RTC */
{
int retval;
- struct tm rtc_tm;
+ struct rtc_time rtc_tm;
unsigned char mon, day, hrs, min, sec, leap_yr;
unsigned char save_control, save_freq_select;
unsigned int yrs;
unsigned long flags;
if (!suser())
- return -EPERM;
+ return -EACCES;
- retval = verify_area(VERIFY_READ, (struct tm*)arg, sizeof(struct tm));
+ retval = verify_area(VERIFY_READ, (struct rtc_time*)arg, sizeof(struct rtc_time));
if (retval !=0 )
return retval;
- memcpy_fromfs(&rtc_tm, (struct tm*)arg, sizeof(struct tm));
+ memcpy_fromfs(&rtc_tm, (struct rtc_time*)arg, sizeof(struct rtc_time));
yrs = rtc_tm.tm_year + 1900;
mon = rtc_tm.tm_mon + 1; /* tm_mon starts at zero */
@@ -424,7+419,7 @@ static int rtc_ioctl(struct inode *inode, struct file *file, unsigned int cmd, * than 64Hz of interrupts on a multi-user machine.
*/
if ((arg > 64) && (!suser()))
- return -EPERM;
+ return -EACCES;
while (arg > (1<<tmp))
tmp++;
@@ -432,7+427,7 @@ static int rtc_ioctl(struct inode *inode, struct file *file, unsigned int cmd, /*
* Check that the input was really a power of 2.
*/
- if ((arg != 0) && (arg != (1<<tmp)))
+ if (arg != (1<<tmp))
return -EINVAL;
rtc_freq = arg;
@@ -440,13+435,6 @@ static int rtc_ioctl(struct inode *inode, struct file *file, unsigned int cmd, save_flags(flags);
cli();
val = CMOS_READ(RTC_FREQ_SELECT) & 0xf0;
-
- if (arg == 0) {
- CMOS_WRITE(val, RTC_FREQ_SELECT);
- restore_flags(flags);
- return 0;
- }
-
val |= (16 - tmp);
CMOS_WRITE(val, RTC_FREQ_SELECT);
restore_flags(flags);
@@ -557,9+545,10 @@ int rtc_init(void) rtc_wait = NULL;
save_flags(flags);
cli();
- rtc_freq = CMOS_READ(RTC_FREQ_SELECT) & 0x0F;
+ /* Initialize periodic freq. to CMOS reset default, which is 1024Hz */
+ CMOS_WRITE(((CMOS_READ(RTC_FREQ_SELECT) & 0xF0) | 0x06), RTC_FREQ_SELECT);
restore_flags(flags);
- rtc_freq = (rtc_freq ? (65536/(1<<rtc_freq)) : 0);
+ rtc_freq = 1024;
return 0;
}
@@ -599,7+588,7 @@ void rtc_dropped_irq(unsigned long data) int get_rtc_status(char *buf)
{
char *p;
- struct tm tm;
+ struct rtc_time tm;
unsigned char batt, ctrl;
unsigned long flags;
@@ -650,7+639,7 @@ int get_rtc_status(char *buf) "DST_enable\t: %s\n"
"BCD\t\t: %s\n"
"24hr\t\t: %s\n"
- "sqare_wave\t: %s\n"
+ "square_wave\t: %s\n"
"alarm_IRQ\t: %s\n"
"update_IRQ\t: %s\n"
"periodic_IRQ\t: %s\n"
@@ -672,7+661,7 @@ int get_rtc_status(char *buf) /*
* Returns true if a clock update is in progress
*/
-inline unsigned char rtc_is_updating(void)
+static inline unsigned char rtc_is_updating(void)
{
unsigned long flags;
unsigned char uip;
@@ -684,7+673,7 @@ inline unsigned char rtc_is_updating(void) return uip;
}
-void get_rtc_time(struct tm *rtc_tm)
+void get_rtc_time(struct rtc_time *rtc_tm)
{
unsigned long flags, uip_watchdog = jiffies;
@@ -733,7+722,7 @@ void get_rtc_time(struct tm *rtc_tm)
/*
* Account for differences between how the RTC uses the values
- * and how they are defined in a struct tm;
+ * and how they are defined in a struct rtc_time;
*/
if (rtc_tm->tm_year <= 69)
rtc_tm->tm_year += 100;
@@ -741,7+730,7 @@ void get_rtc_time(struct tm *rtc_tm) rtc_tm->tm_mon--;
}
-void get_rtc_alm_time(struct tm *alm_tm)
+void get_rtc_alm_time(struct rtc_time *alm_tm)
{
unsigned long flags;
unsigned char ctrl;
@@ -775,7+764,7 @@ void get_rtc_alm_time(struct tm *alm_tm) * We also clear out any old irq data after an ioctl() that
* meddles the interrupt enable/disable bits.
*/
-inline void mask_rtc_irq_bit(unsigned char bit)
+void mask_rtc_irq_bit(unsigned char bit)
{
unsigned char val;
unsigned long flags;
@@ -790,7+779,7 @@ inline void mask_rtc_irq_bit(unsigned char bit) rtc_irq_data = 0;
}
-inline void set_rtc_irq_bit(unsigned char bit)
+void set_rtc_irq_bit(unsigned char bit)
{
unsigned char val;
unsigned long flags;
@@ -495,7+495,7 @@ void cleanup_module() /*
* Free up all allocated resources used by the ports. This includes
* memory and interrupts. As part of this process we will also do
- * a hangup on every open port - to try and flush out any processes
+ * a hangup on every open port - to try to flush out any processes
* hanging onto ports.
*/
i = tty_unregister_driver(&stl_serial);
@@ -2383,7+2383,7 @@ static int stl_mapirq(int irq) /*****************************************************************************/
/*
- * Try and find and initialize all the ports on a panel. We don't care
+ * Try to find and initialize all the ports on a panel. We don't care
* what sort of board these ports are on - since the port io registers
* are almost identical when dealing with ports.
*/
@@ -2861,7+2861,7 @@ static int stl_initbrds()
#ifdef CONFIG_PCI
/*
- * If the PCI BIOS support is compiled in then lets go looking for
+ * If the PCI BIOS support is compiled in then let's go looking for
* ECH-PCI boards.
*/
stl_findpcibrds();
@@ -149,7+149,7 @@ vcs_write(struct inode *inode, struct file *file, const char *buf, int count) org = screen_pos(cons, p, viewed);
while (count-- > 0) {
scr_writew((scr_readw(org) & 0xff00) |
- get_user(buf++), org);
+ get_user((const unsigned char*)buf++), org);
org++;
}
} else {
@@ -175,7+175,7 @@ vcs_write(struct inode *inode, struct file *file, const char *buf, int count) }
if (count > 0)
scr_writew((scr_readw(org) & 0xff00) |
- get_user(buf++), org);
+ get_user((const unsigned char*)buf++), org);
}
written = buf - buf0;
file->f_pos += written;
* Colour palette handling, by Simon Tatham
* 17-Jun-95 <sgt20@cam.ac.uk>
*
+ * if 512 char mode is already enabled don't re-enable it,
+ * because it causes screen to flicker, by Mitja Horvat
+ * 5-May-96 <mitja.horvat@guest.arnes.si>
+ *
*/
#include <linux/sched.h>
set_get_font(char * arg, int set, int ch512)
{
#ifdef CAN_LOAD_EGA_FONTS
+ static int ch512enabled = 0;
int i;
char *charmap;
int beg;
@@ -432,8+437,11 @@ set_get_font(char * arg, int set, int ch512) outb_p( 0x10, gr_port_val ); /* enable even-odd addressing */
outb_p( 0x06, gr_port_reg );
outb_p( beg, gr_port_val ); /* map starts at b800:0 or b000:0 */
- if (set) /* attribute controller */
+
+ /* if 512 char mode is already enabled don't re-enable it. */
+ if ((set)&&(ch512!=ch512enabled)) /* attribute controller */
{
+ ch512enabled=ch512;
/* 256-char: enable intensity bit
512-char: disable intensity bit */
inb_p( video_port_status ); /* clear address flip-flop */
@@ -489,7+489,7 @@ static int isdn_status_callback(isdn_ctrl * c) break;
if ((mi = dev->m_idx[i]) >= 0) {
/* Schedule CONNECT-Message to any tty, waiting for it and
- * set DCD-bit of it's modem-status.
+ * set DCD-bit of its modem-status.
*/
if (dev->mdm.info[mi].flags &
(ISDN_ASYNC_NORMAL_ACTIVE | ISDN_ASYNC_CALLOUT_ACTIVE)) {
* Correct ARP-handling for ETHERNET-encapsulation.
*
* Revision 1.2 1996/01/22 05:05:12 fritz
- * Changed returncode-logic for isdn_net_start_xmit() and it's
+ * Changed returncode-logic for isdn_net_start_xmit() and its
* helper-functions.
* Changed handling of buildheader for RAWIP and ETHERNET-encapsulation.
*
@@ -195,7+195,7 @@ isdn_net_autohup() /*
* Handle status-messages from ISDN-interfacecard.
* This function is called from within the main-status-dispatcher
- * isdn_status_callback, which itself is called from the lowlevel-driver.
+ * isdn_status_callback, which itself is called from the low-level driver.
* Return: 1 = Event handled, 0 = not for us or unknown Event.
*/
int
@@ -1200,7+1200,7 @@ isdn_net_rebuild_header(void *buff, struct device *dev, ulong dst, return 0;
}
/*
- * Try and get ARP to resolve the header.
+ * Try to get ARP to resolve the header.
*/
#ifdef CONFIG_INET
ret = arp_find((unsigned char *)&(eth->h_dest), dst, dev, dev->pa_addr,skb)? 1 : 0;
@@ -1775,7+1775,7 @@ isdn_net_force_dial(char *name) }
/*
- * Allocate a new network-interface and initialize it's data structures.
+ * Allocate a new network-interface and initialize its data structures.
*/
char *
isdn_net_new(char *name, struct device *master)
@@ -802,10+802,12 @@ int isdn_ppp_xmit(struct sk_buff *skb, struct device *dev) isdn_net_local *lp = nd->queue;
int proto = PPP_IP; /* 0x21 */
struct ippp_struct *ipt = ippp_table[lp->ppp_minor];
+#if defined(CONFIG_ISDN_PPP_VJ) || defined(CONFIG_ISDN_MPP)
struct ippp_struct *ipts = ippp_table[lp->netdev->local.ppp_minor];
+#endif
/* If packet is to be resent, it has already been processed and
- * therefore it's first bytes are already initialized. In this case
+ * therefore its first bytes are already initialized. In this case
* send it immediately ...
*/
if (*((unsigned long *)skb->data) != 0)
The combination of slow receive restart and no real multicast
filter makes the board unusable with a kernel compiled for IP
- multicasting in a real multicast environment. Thats down to the board,
+ multicasting in a real multicast environment. That's down to the board,
but even with no multicast programs running a multicast IP kernel is
in group 224.0.0.1 and you will therefore be listening to all multicasts.
One nv conference running over that ethernet and you can give up.
This is not a complete driver, it must be combined with board-specific
code such as ne.c, wd.c, 3c503.c, etc.
+ Seeing how at least eight drivers use this code, (not counting the
+ PCMCIA ones either) it is easy to break some card by what seems like
+ a simple innocent change. Please contact me or Donald if you think
+ you have found something that needs changing. -- PG
+
+
Changelog:
Paul Gortmaker : remove set_bit lock, other cleanups.
Paul Gortmaker : add ei_get_8390_hdr() so we can pass skb's to
ei_block_input() for eth_io_copy_and_sum().
+ Paul Gortmaker : exchange static int ei_pingpong for a #define,
+ also add better Tx error handling.
- */
-static const char *version =
- "8390.c:v1.10 9/23/94 Donald Becker (becker@cesdis.gsfc.nasa.gov)\n";
-
-/*
- Braindamage remaining:
- Much of this code should have been cleaned up, but every attempt
- has broken some clone part.
-
Sources:
The National Semiconductor LAN Databook, and the 3Com 3c503 databook.
+
*/
-#include <linux/module.h>
+static const char *version =
+ "8390.c:v1.10 9/23/94 Donald Becker (becker@cesdis.gsfc.nasa.gov)\n";
+#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/sched.h>
#include <linux/fs.h>
@@ -87,18+89,10 @@ int ei_debug = EI_DEBUG; #else
int ei_debug = 1;
#endif
-#ifdef EI_PINGPONG
-static int ei_pingpong = 1;
-#else
-static int ei_pingpong = 0;
-#endif
-
-/* Max number of packets received at one Intr.
- Currently this may only be examined by a kernel debugger. */
-static int high_water_mark = 0;
/* Index to functions. */
static void ei_tx_intr(struct device *dev);
+static void ei_tx_err(struct device *dev);
static void ei_receive(struct device *dev);
static void ei_rx_overrun(struct device *dev);
@@ -141,8+135,8 @@ static int ei_start_xmit(struct sk_buff *skb, struct device *dev) {
int e8390_base = dev->base_addr;
struct ei_device *ei_local = (struct ei_device *) dev->priv;
- int length, send_length;
-
+ int length, send_length, output_page;
+
/*
* We normally shouldn't be called if dev->tbusy is set, but the
* existing code does anyway. If it has been too long since the
@@ -161,6+155,12 @@ static int ei_start_xmit(struct sk_buff *skb, struct device *dev) return 1;
}
+ /*
+ * Note that if the Tx posted a TX_ERR interrupt, then the
+ * error will have been handled from the interrupt handler.
+ * and not here.
+ */
+
printk(KERN_DEBUG "%s: Tx timed out, %s TSR=%#2x, ISR=%#2x, t=%d.\n",
dev->name, (txsr & ENTSR_ABT) ? "excess collisions." :
(isr) ? "lost interrupt?" : "cable problem?", txsr, isr, tickssofar);
@@ -199,53+199,77 @@ static int ei_start_xmit(struct sk_buff *skb, struct device *dev)
send_length = ETH_ZLEN < length ? length : ETH_ZLEN;
- if (ei_local->pingpong) {
- int output_page;
- if (ei_local->tx1 == 0) {
- output_page = ei_local->tx_start_page;
- ei_local->tx1 = send_length;
- if (ei_debug && ei_local->tx2 > 0)
- printk("%s: idle transmitter tx2=%d, lasttx=%d, txing=%d.\n",
- dev->name, ei_local->tx2, ei_local->lasttx,
- ei_local->txing);
- } else if (ei_local->tx2 == 0) {
- output_page = ei_local->tx_start_page + 6;
- ei_local->tx2 = send_length;
- if (ei_debug && ei_local->tx1 > 0)
- printk("%s: idle transmitter, tx1=%d, lasttx=%d, txing=%d.\n",
- dev->name, ei_local->tx1, ei_local->lasttx,
- ei_local->txing);
- } else { /* We should never get here. */
- if (ei_debug)
- printk("%s: No Tx buffers free. irq=%d tx1=%d tx2=%d last=%d\n",
- dev->name, dev->interrupt, ei_local->tx1,
- ei_local->tx2, ei_local->lasttx);
- ei_local->irqlock = 0;
- dev->tbusy = 1;
- outb_p(ENISR_ALL, e8390_base + EN0_IMR);
- return 1;
- }
- ei_block_output(dev, length, skb->data, output_page);
- if (! ei_local->txing) {
- ei_local->txing = 1;
- NS8390_trigger_send(dev, send_length, output_page);
- dev->trans_start = jiffies;
- if (output_page == ei_local->tx_start_page)
- ei_local->tx1 = -1, ei_local->lasttx = -1;
- else
- ei_local->tx2 = -1, ei_local->lasttx = -2;
- } else
- ei_local->txqueue++;
-
- dev->tbusy = (ei_local->tx1 && ei_local->tx2);
- } else { /* No pingpong, just a single Tx buffer. */
- ei_block_output(dev, length, skb->data, ei_local->tx_start_page);
- ei_local->txing = 1;
- NS8390_trigger_send(dev, send_length, ei_local->tx_start_page);
- dev->trans_start = jiffies;
- dev->tbusy = 1;
+#ifdef EI_PINGPONG
+
+ /*
+ * We have two Tx slots available for use. Find the first free
+ * slot, and then perform some sanity checks. With two Tx bufs,
+ * you get very close to transmitting back-to-back packets. With
+ * only one Tx buf, the transmitter sits idle while you reload the
+ * card, leaving a substantial gap between each transmitted packet.
+ */
+
+ if (ei_local->tx1 == 0) {
+ output_page = ei_local->tx_start_page;
+ ei_local->tx1 = send_length;
+ if (ei_debug && ei_local->tx2 > 0)
+ printk("%s: idle transmitter tx2=%d, lasttx=%d, txing=%d.\n",
+ dev->name, ei_local->tx2, ei_local->lasttx, ei_local->txing);
+ } else if (ei_local->tx2 == 0) {
+ output_page = ei_local->tx_start_page + TX_1X_PAGES;
+ ei_local->tx2 = send_length;
+ if (ei_debug && ei_local->tx1 > 0)
+ printk("%s: idle transmitter, tx1=%d, lasttx=%d, txing=%d.\n",
+ dev->name, ei_local->tx1, ei_local->lasttx, ei_local->txing);
+ } else { /* We should never get here. */
+ if (ei_debug)
+ printk("%s: No Tx buffers free! irq=%d tx1=%d tx2=%d last=%d\n",
+ dev->name, dev->interrupt, ei_local->tx1, ei_local->tx2, ei_local->lasttx);
+ ei_local->irqlock = 0;
+ dev->tbusy = 1;
+ outb_p(ENISR_ALL, e8390_base + EN0_IMR);
+ return 1;
}
-
+
+ /*
+ * Okay, now upload the packet and trigger a send if the transmitter
+ * isn't already sending. If it is busy, the interrupt handler will
+ * trigger the send later, upon receiving a Tx done interrupt.
+ */
+
+ ei_block_output(dev, length, skb->data, output_page);
+ if (! ei_local->txing) {
+ ei_local->txing = 1;
+ NS8390_trigger_send(dev, send_length, output_page);
+ dev->trans_start = jiffies;
+ if (output_page == ei_local->tx_start_page) {
+ ei_local->tx1 = -1;
+ ei_local->lasttx = -1;
+ } else {
+ ei_local->tx2 = -1;
+ ei_local->lasttx = -2;
+ }
+ } else
+ ei_local->txqueue++;
+
+ dev->tbusy = (ei_local->tx1 && ei_local->tx2);
+
+#else /* EI_PINGPONG */
+
+ /*
+ * Only one Tx buffer in use. You need two Tx bufs to come close to
+ * back-to-back transmits. Expect a 20 -> 25% performance hit on
+ * reasonable hardware if you only use one Tx buffer.
+ */
+
+ ei_block_output(dev, length, skb->data, ei_local->tx_start_page);
+ ei_local->txing = 1;
+ NS8390_trigger_send(dev, send_length, ei_local->tx_start_page);
+ dev->trans_start = jiffies;
+ dev->tbusy = 1;
+
+#endif /* EI_PINGPONG */
+
/* Turn 8390 interrupts back on. */
ei_local->irqlock = 0;
outb_p(ENISR_ALL, e8390_base + EN0_IMR);
@@ -305,18+329,17 @@ void ei_interrupt(int irq, void *dev_id, struct pt_regs * regs) /* Push the next to-transmit packet through. */
if (interrupts & ENISR_TX) {
ei_tx_intr(dev);
- } else if (interrupts & ENISR_COUNTERS) {
+ } else if (interrupts & ENISR_TX_ERR) {
+ ei_tx_err(dev);
+ }
+
+ if (interrupts & ENISR_COUNTERS) {
ei_local->stat.rx_frame_errors += inb_p(e8390_base + EN0_COUNTER0);
ei_local->stat.rx_crc_errors += inb_p(e8390_base + EN0_COUNTER1);
ei_local->stat.rx_missed_errors+= inb_p(e8390_base + EN0_COUNTER2);
outb_p(ENISR_COUNTERS, e8390_base + EN0_ISR); /* Ack intr. */
}
- /* Ignore the transmit errs and reset intr for now. */
- if (interrupts & ENISR_TX_ERR) {
- outb_p(ENISR_TX_ERR, e8390_base + EN0_ISR); /* Ack intr. */
- }
-
/* Ignore any RDC interrupts that make it back to here. */
if (interrupts & ENISR_RDC) {
outb_p(ENISR_RDC, e8390_base + EN0_ISR);
@@ -340,6+363,43 @@ void ei_interrupt(int irq, void *dev_id, struct pt_regs * regs) return;
}
+/*
+ * A transmitter error has happened. Most likely excess collisions (which
+ * is a fairly normal condition). If the error is one where the Tx will
+ * have been aborted, we try and send another one right away, instead of
+ * letting the failed packet sit and collect dust in the Tx buffer. This
+ * is a much better solution as it avoids kernel based Tx timeouts, and
+ * an unnecessary card reset.
+ */
+
+static void ei_tx_err(struct device *dev)
+{
+ int e8390_base = dev->base_addr;
+ unsigned char txsr = inb_p(e8390_base+EN0_TSR);
+ unsigned char tx_was_aborted = txsr & (ENTSR_ABT+ENTSR_FU);
+
+#ifdef VERBOSE_ERROR_DUMP
+ printk(KERN_DEBUG "%s: transmitter error (%#2x): ", dev->name, txsr);
+ if (txsr & ENTSR_ABT)
+ printk("excess-collisions ");
+ if (txsr & ENTSR_ND)
+ printk("non-deferral ");
+ if (txsr & ENTSR_CRS)
+ printk("lost-carrier ");
+ if (txsr & ENTSR_FU)
+ printk("FIFO-underrun ");
+ if (txsr & ENTSR_CDH)
+ printk("lost-heartbeat ");
+ printk("\n");
+#endif
+
+ outb_p(ENISR_TX_ERR, e8390_base + EN0_ISR); /* Ack intr. */
+
+ if (tx_was_aborted)
+ ei_tx_intr(dev);
+
+}
+
/* We have finished a transmit: check for errors and then trigger the next
packet to be sent. */
static void ei_tx_intr(struct device *dev)
@@ -349,58+409,68 @@ static void ei_tx_intr(struct device *dev) struct ei_device *ei_local = (struct ei_device *) dev->priv;
outb_p(ENISR_TX, e8390_base + EN0_ISR); /* Ack intr. */
-
- if (ei_local->pingpong) {
- ei_local->txqueue--;
- if (ei_local->tx1 < 0) {
- if (ei_local->lasttx != 1 && ei_local->lasttx != -1)
- printk("%s: bogus last_tx_buffer %d, tx1=%d.\n",
- ei_local->name, ei_local->lasttx, ei_local->tx1);
- ei_local->tx1 = 0;
- dev->tbusy = 0;
- if (ei_local->tx2 > 0) {
- ei_local->txing = 1;
- NS8390_trigger_send(dev, ei_local->tx2, ei_local->tx_start_page + 6);
- dev->trans_start = jiffies;
- ei_local->tx2 = -1,
- ei_local->lasttx = 2;
- } else
- ei_local->lasttx = 20, ei_local->txing = 0;
- } else if (ei_local->tx2 < 0) {
- if (ei_local->lasttx != 2 && ei_local->lasttx != -2)
- printk("%s: bogus last_tx_buffer %d, tx2=%d.\n",
- ei_local->name, ei_local->lasttx, ei_local->tx2);
- ei_local->tx2 = 0;
- dev->tbusy = 0;
- if (ei_local->tx1 > 0) {
- ei_local->txing = 1;
- NS8390_trigger_send(dev, ei_local->tx1, ei_local->tx_start_page);
- dev->trans_start = jiffies;
- ei_local->tx1 = -1;
- ei_local->lasttx = 1;
- } else
- ei_local->lasttx = 10, ei_local->txing = 0;
- } else
- printk("%s: unexpected TX-done interrupt, lasttx=%d.\n",
- dev->name, ei_local->lasttx);
- } else {
- ei_local->txing = 0;
- dev->tbusy = 0;
- }
+
+#ifdef EI_PINGPONG
+
+ /*
+ * There are two Tx buffers, see which one finished, and trigger
+ * the send of another one if it exists.
+ */
+ ei_local->txqueue--;
+ if (ei_local->tx1 < 0) {
+ if (ei_local->lasttx != 1 && ei_local->lasttx != -1)
+ printk("%s: bogus last_tx_buffer %d, tx1=%d.\n",
+ ei_local->name, ei_local->lasttx, ei_local->tx1);
+ ei_local->tx1 = 0;
+ dev->tbusy = 0;
+ if (ei_local->tx2 > 0) {
+ ei_local->txing = 1;
+ NS8390_trigger_send(dev, ei_local->tx2, ei_local->tx_start_page + 6);
+ dev->trans_start = jiffies;
+ ei_local->tx2 = -1,
+ ei_local->lasttx = 2;
+ } else
+ ei_local->lasttx = 20, ei_local->txing = 0;
+ } else if (ei_local->tx2 < 0) {
+ if (ei_local->lasttx != 2 && ei_local->lasttx != -2)
+ printk("%s: bogus last_tx_buffer %d, tx2=%d.\n",
+ ei_local->name, ei_local->lasttx, ei_local->tx2);
+ ei_local->tx2 = 0;
+ dev->tbusy = 0;
+ if (ei_local->tx1 > 0) {
+ ei_local->txing = 1;
+ NS8390_trigger_send(dev, ei_local->tx1, ei_local->tx_start_page);
+ dev->trans_start = jiffies;
+ ei_local->tx1 = -1;
+ ei_local->lasttx = 1;
+ } else
+ ei_local->lasttx = 10, ei_local->txing = 0;
+ } else
+ printk("%s: unexpected TX-done interrupt, lasttx=%d.\n",
+ dev->name, ei_local->lasttx);
+
+#else /* EI_PINGPONG */
+ /*
+ * Single Tx buffer: mark it free so another packet can be loaded.
+ */
+ ei_local->txing = 0;
+ dev->tbusy = 0;
+#endif
/* Minimize Tx latency: update the statistics after we restart TXing. */
- if (status & ENTSR_COL) ei_local->stat.collisions++;
+ if (status & ENTSR_COL)
+ ei_local->stat.collisions++;
if (status & ENTSR_PTX)
- ei_local->stat.tx_packets++;
+ ei_local->stat.tx_packets++;
else {
- ei_local->stat.tx_errors++;
- if (status & ENTSR_ABT) ei_local->stat.tx_aborted_errors++;
- if (status & ENTSR_CRS) ei_local->stat.tx_carrier_errors++;
- if (status & ENTSR_FU) ei_local->stat.tx_fifo_errors++;
- if (status & ENTSR_CDH) ei_local->stat.tx_heartbeat_errors++;
- if (status & ENTSR_OWC) ei_local->stat.tx_window_errors++;
- }
-
+ ei_local->stat.tx_errors++;
+ if (status & ENTSR_ABT) ei_local->stat.tx_aborted_errors++;
+ if (status & ENTSR_CRS) ei_local->stat.tx_carrier_errors++;
+ if (status & ENTSR_FU) ei_local->stat.tx_fifo_errors++;
+ if (status & ENTSR_CDH) ei_local->stat.tx_heartbeat_errors++;
+ if (status & ENTSR_OWC) ei_local->stat.tx_window_errors++;
+ }
+
mark_bh (NET_BH);
}
@@ -410,7+480,8 @@ static void ei_receive(struct device *dev) {
int e8390_base = dev->base_addr;
struct ei_device *ei_local = (struct ei_device *) dev->priv;
- int rxing_page, this_frame, next_frame, current_offset;
+ unsigned char rxing_page, this_frame, next_frame;
+ unsigned short current_offset;
int rx_pkt_count = 0;
struct e8390_pkt_hdr rx_frame;
int num_rx_pages = ei_local->stop_page-ei_local->rx_start_page;
@@ -502,13+573,6 @@ static void ei_receive(struct device *dev) ei_local->current_page = next_frame;
outb_p(next_frame-1, e8390_base+EN0_BOUNDARY);
}
- /* If any worth-while packets have been received, netif_rx()
- has done a mark_bh(NET_BH) for us and will work on them
- when we get to the bottom-half routine. */
-
- /* Record the maximum Rx packet queue. */
- if (rx_pkt_count > high_water_mark)
- high_water_mark = rx_pkt_count;
/* We used to also ack ENISR_OVER here, but that would sometimes mask
a real overrun, leaving the 8390 in a stopped state with rec'vr off. */
@@ -607,7+671,6 @@ int ethdev_init(struct device *dev) return -ENOMEM;
memset(dev->priv, 0, sizeof(struct ei_device));
ei_local = (struct ei_device *)dev->priv;
- ei_local->pingpong = ei_pingpong;
}
dev->hard_start_xmit = &ei_start_xmit;
#define TX_2X_PAGES 12
#define TX_1X_PAGES 6
-#define TX_PAGES (ei_status.pingpong ? TX_2X_PAGES : TX_1X_PAGES)
+
+/* Should always use two Tx slots to get back-to-back transmits. */
+#define EI_PINGPONG
+
+#ifdef EI_PINGPONG
+#define TX_PAGES TX_2X_PAGES
+#else
+#define TX_PAGES TX_1X_PAGES
+#endif
#define ETHER_ADDR_LEN 6
@@ -56,7+64,6 @@ struct ei_device { unsigned txing:1; /* Transmit Active */
unsigned irqlock:1; /* 8390's intrs disabled when '1'. */
unsigned dmaing:1; /* Remote DMA Active */
- unsigned pingpong:1; /* Using the ping-pong driver */
unsigned char tx_start_page, rx_start_page, stop_page;
unsigned char current_page; /* Read pointer in buffer */
unsigned char interface_num; /* Net port (AUI, 10bT.) to use. */
endif
endif
+ifeq ($(CONFIG_HYDRA),y)
+L_OBJS += hydra.o
+else
+ ifeq ($(CONFIG_HYDRA),m)
+ M_OBJS += hydra.o
+ endif
+endif
+
ifeq ($(CONFIG_SDLA),y)
L_OBJS += sdla.o
else
my testing so far, the Livingston PortMaster 2e's load-balancing is a
good 1 to 2 KB/s slower than the test machine working with a 28.8 Kbps
and 14.4 Kbps connection. However, I am not sure that it really is
- the PortMaster, or if its Linux's TCP drivers. I'm told that Linux's
+ the PortMaster, or if it's Linux's TCP drivers. I'm told that Linux's
TCP implementation is pretty fast though.--)
@@ -6,7+6,7 @@ Protocol Tunneling: A network tunneling driver encapsulates packets of one
protocol type within packets of another protocol type. It sends
them out over the network to a relay (or destination) where the
-packet is unwrapped and is forwarded to it's ultimate destination.
+packet is unwrapped and is forwarded to its ultimate destination.
Packet tunneling is useful in situations where you want to route
packets of a non-standard protocol type over the common network.
A good example of this is 'IPX encapsulation', in which IPX packets
@@ -41,7+41,7 @@ only support IP encapsulated in IP. based on the Linux loopback driver written (in part) by Ross Biro,
Fred N. van Kempen, and Donald Becker. After the driver is
loaded, it can be set up as any other network interface, using
-ifconfig. The tunnel device is given it's own IP address, which
+ifconfig. The tunnel device is given its own IP address, which
can match that of the machine, and also is given a pointopoint
address. This pointopoint address is the address of the machine
providing the decapsulating endpoint for the IP tunnel. After
@@ -54,7+54,7 @@ network traffic from leaving the local endpoint. The decapsulating endpoint must have loaded the ipip.o
decapsulator module for it to understand IP-in-IP encapsulation.
This module takes any IP-in-IP packet that is destined for the local
-machine, unwraps it, and sends it on it's way, using standard
+machine, unwraps it, and sends it on its way, using standard
routing rules. The current implementation of IP decapsulation does
no checking on the packet, other than making sure wrapper is bound
for the local machine.
@@ -106,11+106,11 @@ tunnel interface is wrapped and sent to the pointopoint address and every incoming IP-in-IP packet bound for the local machine is
unwrapped and re-routed normally.
The only difference in the two machines setup shown above is that
-machine A set it's tunnel address to one existing on machine B's
+machine A set its tunnel address to one existing on machine B's
network, while B set a route to machine A's tunnel device address
through the tunnel. This is because machine A wants to have a new
address on network B, and machine B is simply acting as a proxy
-for machine A. Machine A needs it's tunnel address to be on network
+for machine A. Machine A needs its tunnel address to be on network
B so that when packets from machine B are unwrapped, the Linux
routing system knows that the address is a local one. Due to a
feature of Linux, any packets received locally, bound for another
@@ -77,6+77,7 @@ extern int sparc_lance_probe(struct device *); extern int atarilance_probe(struct device *);
extern int a2065_probe(struct device *);
extern int ariadne_probe(struct device *);
+extern int hydra_probe(struct device *);
/* Detachable devices ("pocket adaptors") */
extern int atp_init(struct device *);
@@ -203,6+204,9 @@ ethif_probe(struct device *dev) #ifdef CONFIG_ARIADNE /* Village Tronic Ariadne Ethernet Board */
&& ariadne_probe(dev)
#endif
+#ifdef CONFIG_HYDRA /* Hydra Systems Amiganet Ethernet board */
+ && hydra_probe(dev)
+#endif
#ifdef CONFIG_SUNLANCE
&& sparc_lance_probe(dev)
#endif
@@ -2678,7+2678,7 @@ int arcnetA_rebuild_header(void *buff,struct device *dev,unsigned long dst, }
/*
- * Try and get ARP to resolve the header.
+ * Try to get ARP to resolve the header.
*/
#ifdef CONFIG_INET
BUGMSG(D_DURING,"rebuild header from %d to %d; protocol %Xh\n",
@@ -3132,7+3132,7 @@ int arcnetS_rebuild_header(void *buff,struct device *dev,unsigned long dst, }
/*
- * Try and get ARP to resolve the header.
+ * Try to get ARP to resolve the header.
*/
#ifdef CONFIG_INET
return arp_find(&(head->daddr), dst, dev, dev->pa_addr, skb)? 1 : 0;
@@ -193,7+193,7 @@ check_board_dma(struct device *dev) ulong x;
/*
- * If Space.c says not to use DMA, or if its not a PLX based
+ * If Space.c says not to use DMA, or if it's not a PLX based
* PCI board, or if the expansion ROM space is not PCI
* configured, then return false.
*/
@@ -250,10+250,10 @@ check_board_dma(struct device *dev) * Initiate DMA using PLX part on PCI board. Spin the
* processor until completed. All addresses are physical!
*
- * If pciaddr is NULL, then its a chaining DMA, and lcladdr is
+ * If pciaddr is NULL, then it's a chaining DMA, and lcladdr is
* the address of the first DMA descriptor in the chain.
*
- * If pciaddr is not NULL, then its a single DMA.
+ * If pciaddr is not NULL, then it's a single DMA.
*
* In either case, "lcladdr" must have been fixed up to make
* sure the MSB isn't set using the S2DMA macro before passing
/*
* There are three modes here for doing the packet copy.
* If we have DMA, and the packet is "long", we use the
- * chaining mode of DMA. If its shorter, we use single
+ * chaining mode of DMA. If it's shorter, we use single
* DMA's. Otherwise, we use memcpy().
*/
if (priv->use_dma && priv->dmadesc_h && len > 64)
{
/*
- * If we can use DMA and its a long frame, copy it using
+ * If we can use DMA and it's a long frame, copy it using
* DMA chaining.
*/
DMACHAIN *ddp_h; /* Host virtual DMA desc. pointer */
@@ -451,7+451,7 @@ again: else if (priv->use_dma)
{
/*
- * If we can use DMA and its a shorter frame, copy it
+ * If we can use DMA and it's a shorter frame, copy it
* using single DMA transfers.
*/
uchar *phys_p;
@@ -193,7+193,7 @@ check_board_dma(struct device *dev) ulong x;
/*
- * If Space.c says not to use DMA, or if its not a PLX based
+ * If Space.c says not to use DMA, or if it's not a PLX based
* PCI board, or if the expansion ROM space is not PCI
* configured, then return false.
*/
@@ -250,10+250,10 @@ check_board_dma(struct device *dev) * Initiate DMA using PLX part on PCI board. Spin the
* processor until completed. All addresses are physical!
*
- * If pciaddr is NULL, then its a chaining DMA, and lcladdr is
+ * If pciaddr is NULL, then it's a chaining DMA, and lcladdr is
* the address of the first DMA descriptor in the chain.
*
- * If pciaddr is not NULL, then its a single DMA.
+ * If pciaddr is not NULL, then it's a single DMA.
*
* In either case, "lcladdr" must have been fixed up to make
* sure the MSB isn't set using the S2DMA macro before passing
/*
* There are three modes here for doing the packet copy.
* If we have DMA, and the packet is "long", we use the
- * chaining mode of DMA. If its shorter, we use single
+ * chaining mode of DMA. If it's shorter, we use single
* DMA's. Otherwise, we use memcpy().
*/
if (priv->use_dma && priv->dmadesc_h && len > 64)
{
/*
- * If we can use DMA and its a long frame, copy it using
+ * If we can use DMA and it's a long frame, copy it using
* DMA chaining.
*/
DMACHAIN *ddp_h; /* Host virtual DMA desc. pointer */
@@ -451,7+451,7 @@ again: else if (priv->use_dma)
{
/*
- * If we can use DMA and its a shorter frame, copy it
+ * If we can use DMA and it's a shorter frame, copy it
* using single DMA transfers.
*/
uchar *phys_p;
@@ -286,10+286,6 @@ int dlci_add(struct dlci_add *new) int err, i;
char buf[10];
- err = verify_area(VERIFY_READ, new, sizeof(*new));
- if (err)
- return(err);
-
err = verify_area(VERIFY_WRITE, new, sizeof(*new));
if (err)
return(err);
misguided packets.
Nick Holloway, 27th May 1994
- [I tweaked this explanation a little but thats all]
+ [I tweaked this explanation a little but that's all]
Alan Cox, 30th May 1994
*/
@@ -903,7+903,7 @@ static unsigned short eexp_hw_lasttxstat(struct device *dev)
/*
* This should never happen. It is called when some higher
- * routine detects the CU has stopped, to try and restart
+ * routine detects the CU has stopped, to try to restart
* it from the last packet we knew we were working on,
* or the idle loop if we had finished for the time.
*/
@@ -66,7+66,7 @@ static const char *version = * printk's trimmed out.
*
* Revision 3.6 1995/01/19 21:49:56 guru
- * This is working pretty well. I gained 1 K/s in speed.. now its just
+ * This is working pretty well. I gained 1 K/s in speed.. now it's just
* robustness and printk's to be diked out.
*
* Revision 3.5 1995/01/18 22:29:59 guru
@@ -400,7+400,7 @@ static int eth16i_probe1(struct device *dev, short ioaddr) /*
Now it seems that we have found a ethernet chip in this particular
ioaddr. The MB86985 chip has this feature, that when you read a
- certain register it will increase it's io base address to next
+ certain register it will increase its io base address to next
configurable slot. Now when we have found the chip, first thing is
to make sure that the chip's ioaddr will hold still here.
*/
#define HP100_EE_EN 0x1000 /* 0:Disable,1:Enable EEPROM writing */
#define HP100_BM_WRITE 0x0800 /* 0:Slave, 1:Bus Master for Tx data */
#define HP100_BM_READ 0x0400 /* 0:Slave, 1:Bus Master for Rx data */
-#define HP100_TRI_INT 0x0200 /* 0:Dont, 1:Do tri-state the int */
+#define HP100_TRI_INT 0x0200 /* 0:Don't, 1:Do tri-state the int */
#define HP100_MEM_EN 0x0040 /* Config program set this to */
/* 0:Disable, 1:Enable mem map. */
/* See MMAP_DIS. */
--- /dev/null
+/* Linux/68k Hydra Amiganet board driver v2.1 BETA */
+/* copyleft by Topi Kanerva (topi@susanna.oulu.fi) */
+/* also some code & lots of fixes by Timo Rossi (trossi@cc.jyu.fi) */
+
+/* The code is mostly based on the linux/68k Ariadne driver */
+/* copyrighted by Geert Uytterhoeven (Geert.Uytterhoeven@cs.kuleuven.ac.be) */
+/* and Peter De Schrijver (Peter.DeSchrijver@linux.cc.kuleuven.ac.be) */
+
+/* This file is subject to the terms and conditions of the GNU General */
+/* Public License. See the file README.legal in the main directory of the */
+/* Linux/68k distribution for more details. */
+
+/* The Amiganet is a Zorro-II board made by Hydra Systems. It contains a */
+/* NS8390 NIC (network interface controller) clone, 16 or 64K on-board RAM */
+/* and 10BASE-2 (thin coax) and AUI connectors. */
+
+
+#include <linux/kernel.h>
+#include <linux/sched.h>
+#include <linux/string.h>
+#include <linux/ptrace.h>
+#include <linux/errno.h>
+#include <linux/ioport.h>
+#include <linux/malloc.h>
+#include <linux/interrupt.h>
+#include <linux/netdevice.h>
+#include <linux/skbuff.h>
+
+#include <asm/bitops.h>
+#include <asm/io.h>
+#include <asm/irq.h>
+
+#include <asm/bootinfo.h>
+#include <asm/amigaints.h>
+#include <asm/amigahw.h>
+#include <asm/zorro.h>
+
+#include "hydra.h"
+
+
+#define HYDRA_DEBUG
+#undef HAVE_MULTICAST
+
+#define HYDRA_VERSION "v2.1 BETA"
+
+struct device *init_etherdev(struct device *dev, int sizeof_private, unsigned long *mem_startp);
+
+#undef HYDRA_DEBUG /* define this for (lots of) debugging information */
+
+#if 0 /* currently hardwired to one transmit buffer */
+ #define TX_RING_SIZE 5
+ #define RX_RING_SIZE 16
+#else
+ #define TX_RING_SIZE 1
+ #define RX_RING_SIZE 8
+#endif
+
+#define ETHER_MIN_LEN 64
+#define ETHER_MAX_LEN 1518
+#define ETHER_ADDR_LEN 6
+
+
+/*
+ * let's define here nice macros for writing and reading NIC registers
+ *
+ * the CIA accesses here are uses to make sure the minimum time
+ * requirement between NIC chip selects is met.
+ */
+#define WRITE_REG(reg, val) (ciaa.pra, ((u_char)(*(nicbase+(reg))=val)))
+#define READ_REG(reg) (ciaa.pra, ((u_char)(*(nicbase+(reg)))))
+
+/* mask value for the interrupts we use */
+#define NIC_INTS (ISR_PRX | ISR_PTX | ISR_RXE | ISR_TXE | ISR_OVW | ISR_CNT)
+
+/* only broadcasts, no promiscuous mode for now */
+#define NIC_RCRBITS (0)
+
+/*
+ * Private Device Data
+ */
+struct hydra_private
+ {
+ u_char *hydra_base;
+ u_char *hydra_nic_base;
+ u_short tx_page_start;
+ u_short rx_page_start;
+ u_short rx_page_stop;
+ u_short next_pkt;
+ struct enet_statistics stats;
+ };
+
+static int hydra_open(struct device *dev);
+static int hydra_start_xmit(struct sk_buff *skb, struct device *dev);
+static void hydra_interrupt(int irq, struct pt_regs *fp, void *data);
+static void __inline__ hydra_rx(struct device *dev, struct hydra_private *priv, u_char *nicbase);
+static int hydra_close(struct device *dev);
+static struct enet_statistics *hydra_get_stats(struct device *dev);
+#ifdef HAVE_MULTICAST
+static void set_multicast_list(struct device *dev, int num_addrs, void *addrs);
+#endif
+
+
+/* this is now coherent to the C version below, */
+/* compile the source with -D__USE_ASM__ if you */
+/* want it - it'll only be some 10% faster thou */
+
+#if defined (__GNUC__) && defined (__mc68000__) && defined (USE_ASM)
+
+static __inline__ void *memcpyw(u_short *dest, u_short *src, int len)
+ {
+ __asm__(" move.l %0,%/a1; move.l %1,%/a0; move.l %2,%/d0 \n\t"
+ " cmpi.l #2,%/d0 \n\t"
+ "1: bcs.s 2f \n\t"
+ " move.w %/a0@+,%/a1@+ \n\t"
+ " subq.l #2,%/d0 \n\t"
+ " bra.s 1b \n\t"
+ "2: cmpi.l #1,%/d0 \n\t"
+ " bne.s 3f \n\t"
+ " move.w %/a0@,%/d0 \n\t"
+ " swap.w %/d0 \n\t"
+ " move.b %/d0,%/a1@ \n\t"
+ "3: moveq #0,%/d0 \n\t"
+ :
+ : "g" (dest), "g" (src), "g" (len)
+ : "a1", "a0", "d0");
+ return;
+}
+
+#else
+
+/* hydra memory can only be read or written as words or longwords. */
+/* that will mean that we'll have to write a special memcpy for it. */
+/* this one here relies on the fact that _writes_ to hydra memory */
+/* are guaranteed to be of even length. (reads can be arbitrary) */
+
+static void memcpyw(u_short *dest, u_short *src, int len)
+{
+ if(len & 1)
+ len++;
+
+ while (len >= 2) {
+ *(dest++) = *(src++);
+ len -= 2;
+ }
+
+}
+
+#endif
+
+unsigned long hydra_probe(struct device *dev)
+ {
+ struct hydra_private *priv;
+ u_long board;
+ int key;
+ struct ConfigDev *cd;
+ int j;
+
+#ifdef HYDRA_DEBUG
+ printk("hydra_probe(%x)\n", dev);
+#endif
+
+ if ((key = zorro_find(MANUF_HYDRA_SYSTEMS, PROD_AMIGANET, 0, 0))) {
+ cd = zorro_get_board(key);
+ if((board = (u_long) cd->cd_BoardAddr))
+ {
+ for(j = 0; j < ETHER_ADDR_LEN; j++)
+ dev->dev_addr[j] = *((u_char *)ZTWO_VADDR(board + HYDRA_ADDRPROM + 2*j));
+
+ printk("%s: hydra at 0x%08x, address %02x:%02x:%02x:%02x:%02x:%02x (hydra.c " HYDRA_VERSION ")\n",
+ dev->name, (int)board, dev->dev_addr[0], dev->dev_addr[1], dev->dev_addr[2],
+ dev->dev_addr[3], dev->dev_addr[4], dev->dev_addr[5]);
+
+ init_etherdev(dev, 0, NULL);
+
+ dev->priv = kmalloc(sizeof(struct hydra_private), GFP_KERNEL);
+ priv = (struct hydra_private *)dev->priv;
+ memset(priv, 0, sizeof(struct hydra_private));
+
+ priv->hydra_base = (u_char *) ZTWO_VADDR(board);
+ priv->hydra_nic_base = (u_char *) ZTWO_VADDR(board) + HYDRA_NIC_BASE;
+
+ dev->open = &hydra_open;
+ dev->stop = &hydra_close;
+ dev->hard_start_xmit = &hydra_start_xmit;
+ dev->get_stats = &hydra_get_stats;
+#ifdef HAVE_MULTICAST
+ dev->set_multicast_list = &hydra_set_multicast_list;
+#endif
+ zorro_config_board(key, 0);
+ return(0);
+ }
+ }
+ return(ENODEV);
+ }
+
+
+static int hydra_open(struct device *dev)
+ {
+ struct hydra_private *priv = (struct hydra_private *)dev->priv;
+ static int interruptinstalled = 0;
+ u_char volatile *nicbase = priv->hydra_nic_base;
+#ifdef HAVE_MULTICAST
+ int i;
+#endif
+
+#ifdef HYDRA_DEBUG
+ printk("hydra_open(0x%x)\n", dev);
+#endif
+
+ /* first, initialize the private structure */
+ priv->tx_page_start = 0; /* these are 256 byte buffers for NS8390 */
+ priv->rx_page_start = 6;
+ priv->rx_page_stop = 62; /* these values are hard coded for now */
+
+ /* Reset the NS8390 NIC */
+ WRITE_REG(NIC_CR, CR_PAGE0 | CR_NODMA | CR_STOP);
+
+ /* be sure that the NIC is in stopped state */
+ while(!(READ_REG(NIC_ISR) & ISR_RST));
+
+ /* word transfer, big endian bytes, loopback, FIFO threshold 4 bytes */
+ WRITE_REG(NIC_DCR, DCR_WTS | DCR_BOS | DCR_LS | DCR_FT0);
+
+ /* clear remote byte count registers */
+ WRITE_REG(NIC_RBCR0, 0);
+ WRITE_REG(NIC_RBCR1, 0);
+
+ /* accept packets addressed to this card and also broadcast packets */
+ WRITE_REG(NIC_RCR, NIC_RCRBITS);
+
+ /* enable loopback mode 1 */
+ WRITE_REG(NIC_TCR, TCR_LB1);
+
+ /* initialize receive buffer ring */
+ WRITE_REG(NIC_PSTART, priv->rx_page_start);
+ WRITE_REG(NIC_PSTOP, priv->rx_page_stop);
+ WRITE_REG(NIC_BNDRY, priv->rx_page_start);
+
+ /* clear interrupts */
+ WRITE_REG(NIC_ISR, 0xff);
+
+ /* enable interrupts */
+ WRITE_REG(NIC_IMR, NIC_INTS);
+
+ /* set the ethernet hardware address */
+ WRITE_REG(NIC_CR, CR_PAGE1 | CR_NODMA | CR_STOP); /* goto page 1 */
+
+ WRITE_REG(NIC_PAR0, dev->dev_addr[0]);
+ WRITE_REG(NIC_PAR1, dev->dev_addr[1]);
+ WRITE_REG(NIC_PAR2, dev->dev_addr[2]);
+ WRITE_REG(NIC_PAR3, dev->dev_addr[3]);
+ WRITE_REG(NIC_PAR4, dev->dev_addr[4]);
+ WRITE_REG(NIC_PAR5, dev->dev_addr[5]);
+
+#ifdef HAVE_MULTICAST
+ /* clear multicast hash table */
+ for(i = 0; i < 8; i++)
+ WRITE_REG(NIC_MAR0 + 2*i, 0);
+#endif
+
+ priv->next_pkt = priv->rx_page_start+1; /* init our s/w variable */
+ WRITE_REG(NIC_CURR, priv->next_pkt); /* set the next buf for current */
+
+ /* goto page 0, start NIC */
+ WRITE_REG(NIC_CR, CR_PAGE0 | CR_NODMA | CR_START);
+
+ /* take interface out of loopback */
+ WRITE_REG(NIC_TCR, 0);
+
+ dev->tbusy = 0;
+ dev->interrupt = 0;
+ dev->start = 1;
+
+ if(!interruptinstalled) {
+ if(!add_isr(IRQ_AMIGA_PORTS, hydra_interrupt, 0, dev,
+ "Hydra Ethernet"))
+ return(-EAGAIN);
+ interruptinstalled = 1;
+ }
+
+ return(0);
+ }
+
+
+static int hydra_close(struct device *dev)
+{
+ struct hydra_private *priv = (struct hydra_private *)dev->priv;
+ u_char volatile *nicbase = priv->hydra_nic_base;
+ int n = 5000;
+
+ dev->start = 0;
+ dev->tbusy = 1;
+
+#ifdef HYDRA_DEBUG
+ printk("%s: Shutting down ethercard\n", dev->name);
+ printk("%s: %d packets missed\n", dev->name, priv->stats.rx_missed_errors);
+#endif
+
+ WRITE_REG(NIC_CR, CR_PAGE0 | CR_NODMA | CR_STOP);
+
+ /* wait for NIC to stop (what a nice timeout..) */
+ while(((READ_REG(NIC_ISR) & ISR_RST) == 0) && --n);
+
+ return(0);
+}
+
+
+static void hydra_interrupt(int irq, struct pt_regs *fp, void *data)
+ {
+ u_char volatile *nicbase;
+
+ struct device *dev = (struct device *) data;
+ struct hydra_private *priv;
+ u_short intbits;
+
+ if(dev == NULL)
+ {
+ printk("hydra_interrupt(): irq for unknown device\n");
+ return;
+ }
+
+/* this is not likely a problem - i think */
+ if(dev->interrupt)
+ printk("%s: re-entering the interrupt handler\n", dev->name);
+
+ dev->interrupt = 1;
+
+ priv = (struct hydra_private *) dev->priv;
+ nicbase = (u_char *) priv->hydra_nic_base;
+
+ /* select page 0 */
+ WRITE_REG(NIC_CR, CR_PAGE0 | CR_START | CR_NODMA);
+
+ intbits = READ_REG(NIC_ISR) & NIC_INTS;
+ if(intbits == 0)
+ {
+ dev->interrupt = 0;
+ return;
+ }
+
+ /* acknowledge all interrupts, by clearing the interrupt flag */
+ WRITE_REG(NIC_ISR, intbits);
+
+ if((intbits & ISR_PTX) && !(intbits & ISR_TXE))
+ {
+ dev->tbusy = 0;
+ mark_bh(NET_BH);
+ }
+
+ if((intbits & ISR_PRX) && !(intbits & ISR_RXE))/* packet received OK */
+ hydra_rx(dev, priv, nicbase);
+
+ if(intbits & ISR_TXE)
+ priv->stats.tx_errors++;
+
+ if(intbits & ISR_RXE)
+ priv->stats.rx_errors++;
+
+ if(intbits & ISR_CNT) {
+ /*
+ * read the tally counters and (currently) ignore the values
+ * might be useful because of bugs of some versions of the 8390 NIC
+ */
+#ifdef HYDRA_DEBUG
+ printk("hydra_interrupt(): ISR_CNT\n");
+#endif
+ (void)READ_REG(NIC_CNTR0);
+ (void)READ_REG(NIC_CNTR1);
+ (void)READ_REG(NIC_CNTR2);
+ }
+
+ if(intbits & ISR_OVW)
+ {
+ #ifdef HYDRA_DEBUG
+ WRITE_REG(NIC_CR, CR_PAGE1 | CR_START | CR_NODMA);
+/* another one just too much for me to comprehend - basically this could */
+/* only occur because of invalid access to hydra ram, thus invalidating */
+/* the interrupt bits read - in average usage these do not occur at all */
+ printk("hydra_interrupt(): overwrite warning, NIC_ISR %02x, NIC_CURR %02x\n",
+ intbits, READ_REG(NIC_CURR));
+ WRITE_REG(NIC_CR, CR_PAGE0 | CR_START | CR_NODMA);
+ #endif
+
+
+ /* overwrite warning occured, stop NIC & check the BOUNDARY pointer */
+ /* FIXME - real overwrite handling needed !! */
+
+ printk("hydra_interrupt(): overwrite warning, resetting NIC\n");
+ WRITE_REG(NIC_CR, CR_PAGE0 | CR_NODMA | CR_STOP);
+ while(!(READ_REG(NIC_ISR) & ISR_RST));
+ /* wait for NIC to reset */
+ WRITE_REG(NIC_DCR, DCR_WTS | DCR_BOS | DCR_LS | DCR_FT0);
+ WRITE_REG(NIC_RBCR0, 0);
+ WRITE_REG(NIC_RBCR1, 0);
+ WRITE_REG(NIC_RCR, NIC_RCRBITS);
+ WRITE_REG(NIC_TCR, TCR_LB1);
+ WRITE_REG(NIC_PSTART, priv->rx_page_start);
+ WRITE_REG(NIC_PSTOP, priv->rx_page_stop);
+ WRITE_REG(NIC_BNDRY, priv->rx_page_start);
+ WRITE_REG(NIC_ISR, 0xff);
+ WRITE_REG(NIC_IMR, NIC_INTS);
+/* currently this _won't_ reset my hydra, even though it is */
+/* basically the same code as in the board init - any ideas? */
+
+ priv->next_pkt = priv->rx_page_start+1; /* init our s/w variable */
+ WRITE_REG(NIC_CURR, priv->next_pkt); /* set the next buf for current */
+
+ WRITE_REG(NIC_CR, CR_PAGE0 | CR_NODMA | CR_START);
+
+ WRITE_REG(NIC_TCR, 0);
+ }
+
+ dev->interrupt = 0;
+ return;
+ }
+
+
+/*
+ * packet transmit routine
+ */
+static int hydra_start_xmit(struct sk_buff *skb, struct device *dev)
+ {
+ struct hydra_private *priv = (struct hydra_private *)dev->priv;
+ u_char volatile *nicbase = priv->hydra_nic_base;
+ int len, len1;
+
+ /* Transmitter timeout, serious problems. */
+
+ if(dev->tbusy)
+ {
+ int tickssofar = jiffies - dev->trans_start;
+ if(tickssofar < 20)
+ return(1);
+ WRITE_REG(NIC_CR, CR_STOP);
+ printk("%s: transmit timed out, status %4.4x, resetting.\n", dev->name, 0);
+ priv->stats.tx_errors++;
+
+
+ dev->tbusy = 0;
+ dev->trans_start = jiffies;
+
+ return(0);
+ }
+
+
+ if(skb == NULL)
+ {
+ dev_tint(dev);
+ return(0);
+ }
+
+ if((len = skb->len) <= 0)
+ return(0);
+
+ /* fill in a tx ring entry */
+
+#ifdef HYDRA_DEBUG
+ printk("TX pkt type 0x%04x from ", ((u_short *)skb->data)[6]);
+ {
+ int i;
+ u_char *ptr = &((u_char *)skb->data)[6];
+ for (i = 0; i < 6; i++)
+ printk("%02x", ptr[i]);
+ }
+ printk(" to ");
+ {
+ int i;
+ u_char *ptr = (u_char *)skb->data;
+ for (i = 0; i < 6; i++)
+ printk("%02x", ptr[i]);
+ }
+ printk(" data 0x%08x len %d\n", (int)skb->data, len);
+#endif
+
+ /*
+ * make sure that the packet size is at least the minimum
+ * allowed ethernet packet length.
+ * (possibly should also clear the unused space...)
+ * note: minimum packet length is 64, including CRC
+ */
+ len1 = len;
+ if(len < (ETHER_MIN_LEN-4))
+ len = (ETHER_MIN_LEN-1);
+
+ /* make sure we've got an even number of bytes to copy to hydra's mem */
+ if(len & 1) len++;
+
+ if((u_long)(priv->hydra_base + (priv->tx_page_start << 8)) < 0x80000000)
+ printk("weirdness: memcpyw(txbuf, skbdata, len): txbuf = %0x\n", (priv->hydra_base+(priv->tx_page_start<<8)));
+
+ /* copy the packet data to the transmit buffer
+ in the ethernet card RAM */
+ memcpyw((u_short *)(priv->hydra_base + (priv->tx_page_start << 8)),
+ (u_short *)skb->data, len);
+ /* clear the unused space */
+/* for(; len1<len; len1++)
+ (u_short)*(priv->hydra_base + (priv->tx_page_start<<8) + len1) = 0;
+*/
+ dev_kfree_skb(skb, FREE_WRITE);
+
+ priv->stats.tx_packets++;
+
+ cli();
+ /* make sure we are on the correct page */
+ WRITE_REG(NIC_CR, CR_PAGE0 | CR_NODMA | CR_START);
+
+ /* here we configure the transmit page start register etc */
+ /* notice that this code is hardwired to one transmit buffer */
+ WRITE_REG(NIC_TPSR, priv->tx_page_start);
+ WRITE_REG(NIC_TBCR0, len & 0xff);
+ WRITE_REG(NIC_TBCR1, len >> 8);
+
+ /* commit the packet to the wire */
+ WRITE_REG(NIC_CR, CR_PAGE0 | CR_START | CR_NODMA | CR_TXP);
+ sti();
+
+ dev->trans_start = jiffies;
+
+ return(0);
+ }
+
+
+static void __inline__ hydra_rx(struct device *dev, struct hydra_private *priv, u_char *nicbase)
+ {
+ u_short volatile *board_ram_ptr;
+ struct sk_buff *skb;
+ int hdr_next_pkt, pkt_len, len1, boundary;
+
+
+ /* remove packet(s) from the ring and commit them to TCP layer */
+ WRITE_REG(NIC_CR, CR_PAGE1 | CR_NODMA | CR_START); /* page 1 */
+ while(priv->next_pkt != READ_REG(NIC_CURR)) /* should read this only once? */
+ {
+ board_ram_ptr = (u_short *)(priv->hydra_base + (priv->next_pkt << 8));
+
+#ifdef HYDRA_DEBUG
+ printk("next_pkt = 0x%x, board_ram_ptr = 0x%x\n", priv->next_pkt, board_ram_ptr);
+#endif
+
+ /* the following must be done with two steps, or
+ GCC optimizes it to a byte access to Hydra memory,
+ which doesn't work... */
+ hdr_next_pkt = board_ram_ptr[0];
+ hdr_next_pkt >>= 8;
+
+ pkt_len = board_ram_ptr[1];
+ pkt_len = ((pkt_len >> 8) | ((pkt_len & 0xff) << 8));
+
+#ifdef HYDRA_DEBUG
+ printk("hydra_interrupt(): hdr_next_pkt = 0x%02x, len = %d\n", hdr_next_pkt, pkt_len);
+#endif
+
+ if(pkt_len >= ETHER_MIN_LEN && pkt_len <= ETHER_MAX_LEN)
+ {
+ /* note that board_ram_ptr is u_short */
+ /* CRC is not included in the packet length */
+
+ pkt_len -= 4;
+ skb = dev_alloc_skb(pkt_len+2);
+ if(skb == NULL)
+ {
+ printk("%s: memory squeeze, dropping packet.\n", dev->name);
+ priv->stats.rx_dropped++;
+ }
+ else
+ {
+ skb->dev = dev;
+ skb_reserve(skb, 2);
+
+ if(hdr_next_pkt < priv->next_pkt && hdr_next_pkt != priv->rx_page_start)
+ {
+ /* here, the packet is wrapped */
+ len1 = ((priv->rx_page_stop - priv->next_pkt)<<8)-4;
+
+ memcpyw((u_short *)skb_put(skb, len1), (u_short *)(board_ram_ptr+2), len1);
+ memcpyw((u_short *)skb_put(skb, pkt_len-len1), (u_short *)(priv->hydra_base+(priv->rx_page_start<<8)), pkt_len-len1);
+
+#ifdef HYDRA_DEBUG
+ printk("wrapped packet: %d/%d bytes\n", len1, pkt_len-len1);
+#endif
+ } /* ... here, packet is not wrapped */
+ else memcpyw((u_short *) skb_put(skb, pkt_len), (u_short *)(board_ram_ptr+2), pkt_len);
+ }
+ /* if(skb == NULL) ... */
+ }
+ else
+ {
+ WRITE_REG(NIC_CR, CR_PAGE1 | CR_START | CR_NODMA);
+ printk("hydra_interrupt(): invalid packet len: %d, NIC_CURR = %02x\n", pkt_len, READ_REG(NIC_CURR));
+/*
+this is the error i kept getting until i switched to 0.9.10. it still doesn't
+mean that the bug would have gone away - so be alarmed. the packet is likely
+being fetched from a wrong memory location - but why - dunno
+
+note-for-v2.1: not really problem anymore. hasn't been for a long time.
+*/
+
+ WRITE_REG(NIC_CR, CR_PAGE0 | CR_START | CR_NODMA);
+ /* should probably reset the NIC here ?? */
+
+ hydra_open(dev); /* FIXME - i shouldn't really be doing this. */
+ return;
+ }
+
+ /* now, update the next_pkt pointer */
+ if(hdr_next_pkt < priv->rx_page_stop) priv->next_pkt = hdr_next_pkt;
+ else printk("hydra_interrupt(): invalid next_pkt pointer %d\n", hdr_next_pkt);
+
+ /* update the boundary pointer */
+ boundary = priv->next_pkt - 1;
+ if(boundary < priv->rx_page_start)
+ boundary = priv->rx_page_stop - 1;
+
+ /* set NIC to page 0 to update the NIC_BNDRY register */
+ WRITE_REG(NIC_CR, CR_PAGE0 | CR_START | CR_NODMA);
+ WRITE_REG(NIC_BNDRY, boundary);
+
+ /* select page1 to access the NIC_CURR register */
+ WRITE_REG(NIC_CR, CR_PAGE1 | CR_START | CR_NODMA);
+
+
+ skb->protocol = eth_type_trans(skb, dev);
+ netif_rx(skb);
+ priv->stats.rx_packets++;
+
+ }
+ return;
+ }
+
+
+static struct enet_statistics *hydra_get_stats(struct device *dev)
+{
+ struct hydra_private *priv = (struct hydra_private *)dev->priv;
+#if 0
+ u_char *board = priv->hydra_base;
+
+ short saved_addr;
+#endif
+/* currently does nothing :) i'll finish this later */
+
+ return(&priv->stats);
+}
+
+#ifdef HAVE_MULTICAST
+static void set_multicast_list(struct device *dev, int num_addrs, void *addrs)
+ {
+ struct hydra_private *priv = (struct hydra_private *)dev->priv;
+ u_char *board = priv->hydra_base;
+
+ /* yes, this code is also waiting for someone to complete.. :) */
+ /* (personally i don't care about multicasts at all :) */
+ return;
+ }
+#endif
+
--- /dev/null
+/* $Linux: hydra.h,v 1.0 1994/10/26 02:03:47 cgd Exp $ */
+
+/*
+ * Copyright (c) 1994 Timo Rossi
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by Timo Rossi
+ * 4. The name of the author may not be used to endorse or promote products
+ * derived from this software without specific prior written permission
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+/*
+ * The Hydra Systems card uses the National Semiconductor
+ * 8390 NIC (Network Interface Controller) chip, located
+ * at card base address + 0xffe1. NIC registers are accessible
+ * only at odd byte addresses, so the register offsets must
+ * be multiplied by two.
+ *
+ * Card address PROM is located at card base + 0xffc0 (even byte addresses)
+ *
+ * RAM starts at the card base address, and is 16K or 64K.
+ * The current Amiga NetBSD hydra driver is hardwired for 16K.
+ * It seems that the RAM should be accessed as words or longwords only.
+ *
+ */
+
+/* adapted for Linux by Topi Kanerva 03/29/95
+ with original author's permission */
+
+#define HYDRA_NIC_BASE 0xffe1
+
+/* Page0 registers */
+
+#define NIC_CR 0 /* Command register */
+#define NIC_PSTART (1*2) /* Page start (write) */
+#define NIC_PSTOP (2*2) /* Page stop (write) */
+#define NIC_BNDRY (3*2) /* Boundary pointer */
+#define NIC_TSR (4*2) /* Transmit status (read) */
+#define NIC_TPSR (4*2) /* Transmit page start (write) */
+#define NIC_NCR (5*2) /* Number of collisions, read */
+#define NIC_TBCR0 (5*2) /* Transmit byte count low (write) */
+#define NIC_FIFO (6*2) /* FIFO reg. (read) */
+#define NIC_TBCR1 (6*2) /* Transmit byte count high (write) */
+#define NIC_ISR (7*2) /* Interrupt status register */
+#define NIC_RBCR0 (0xa*2) /* Remote byte count low (write) */
+#define NIC_RBCR1 (0xb*2) /* Remote byte count high (write) */
+#define NIC_RSR (0xc*2) /* Receive status (read) */
+#define NIC_RCR (0xc*2) /* Receive config (write) */
+#define NIC_CNTR0 (0xd*2) /* Frame alignment error count (read) */
+#define NIC_TCR (0xd*2) /* Transmit config (write) */
+#define NIC_CNTR1 (0xe*2) /* CRC error counter (read) */
+#define NIC_DCR (0xe*2) /* Data config (write) */
+#define NIC_CNTR2 (0xf*2) /* missed packet counter (read) */
+#define NIC_IMR (0xf*2) /* Interrupt mask reg. (write) */
+
+/* Page1 registers */
+
+#define NIC_PAR0 (1*2) /* Physical address */
+#define NIC_PAR1 (2*2)
+#define NIC_PAR2 (3*2)
+#define NIC_PAR3 (4*2)
+#define NIC_PAR4 (5*2)
+#define NIC_PAR5 (6*2)
+#define NIC_CURR (7*2) /* Current RX ring-buffer page */
+#define NIC_MAR0 (8*2) /* Multicast address */
+#define NIC_MAR1 (9*2)
+#define NIC_MAR2 (0xa*2)
+#define NIC_MAR3 (0xb*2)
+#define NIC_MAR4 (0xc*2)
+#define NIC_MAR5 (0xd*2)
+#define NIC_MAR6 (0xe*2)
+#define NIC_MAR7 (0xf*2)
+
+/* Command register definitions */
+
+#define CR_STOP 0x01 /* Stop -- software reset command */
+#define CR_START 0x02 /* Start */
+#define CR_TXP 0x04 /* Transmit packet */
+
+#define CR_RD0 0x08 /* Remote DMA cmd */
+#define CR_RD1 0x10
+#define CR_RD2 0x20
+
+#define CR_NODMA CR_RD2
+
+#define CR_PS0 0x40 /* Page select */
+#define CR_PS1 0x80
+
+#define CR_PAGE0 0
+#define CR_PAGE1 CR_PS0
+#define CR_PAGE2 CR_PS1
+
+/* Interrupt status reg. definitions */
+
+#define ISR_PRX 0x01 /* Packet received without errors */
+#define ISR_PTX 0x02 /* Packet transmitted without errors */
+#define ISR_RXE 0x04 /* Receive error */
+#define ISR_TXE 0x08 /* Transmit error */
+#define ISR_OVW 0x10 /* Ring buffer overrrun */
+#define ISR_CNT 0x20 /* Counter overflow */
+#define ISR_RDC 0x40 /* Remote DMA compile */
+#define ISR_RST 0x80 /* Reset status */
+
+/* Data config reg. definitions */
+
+#define DCR_WTS 0x01 /* Word transfer select */
+#define DCR_BOS 0x02 /* Byte order select */
+#define DCR_LAS 0x04 /* Long address select */
+#define DCR_LS 0x08 /* Loopback select */
+#define DCR_AR 0x10 /* Auto-init remote */
+#define DCR_FT0 0x20 /* FIFO threshold select */
+#define DCR_FT1 0x40
+
+/* Transmit config reg. definitions */
+
+#define TCR_CRC 0x01 /* Inhibit CRC */
+#define TCR_LB0 0x02 /* Loopback control */
+#define TCR_LB1 0x04
+#define TCR_ATD 0x08 /* Auto transmit disable */
+#define TCR_OFST 0x10 /* Collision offset enable */
+
+/* Transmit status reg. definitions */
+
+#define TSR_PTX 0x01 /* Packet transmitted */
+#define TSR_COL 0x04 /* Transmit collided */
+#define TSR_ABT 0x08 /* Transmit aborted */
+#define TSR_CRS 0x10 /* Carrier sense lost */
+#define TSR_FU 0x20 /* FIFO underrun */
+#define TSR_CDH 0x40 /* CD Heartbeat */
+#define TSR_OWC 0x80 /* Out of Window Collision */
+
+/* Receiver config register definitions */
+
+#define RCR_SEP 0x01 /* Save errored packets */
+#define RCR_AR 0x02 /* Accept runt packets */
+#define RCR_AB 0x04 /* Accept broadcast */
+#define RCR_AM 0x08 /* Accept multicast */
+#define RCR_PRO 0x10 /* Promiscuous mode */
+#define RCR_MON 0x20 /* Monitor mode */
+
+/* Receiver status register definitions */
+
+#define RSR_PRX 0x01 /* Packet received without error */
+#define RSR_CRC 0x02 /* CRC error */
+#define RSR_FAE 0x04 /* Frame alignment error */
+#define RSR_FO 0x08 /* FIFO overrun */
+#define RSR_MPA 0x10 /* Missed packet */
+#define RSR_PHY 0x20 /* Physical address */
+#define RSR_DIS 0x40 /* Received disabled */
+#define RSR_DFR 0x80 /* Deferring (jabber) */
+
+/* Hydra System card address PROM offset */
+
+#define HYDRA_ADDRPROM 0xffc0
+
+
@@ -333,7+333,7 @@ int tok_probe(struct device *dev) ti->mmio= t_mmio;
dev->priv = ti; /* this seems like the logical use of the
- field ... lets try some empirical tests
+ field ... let's try some empirical tests
using the token-info structure -- that
should fit with out future hope of multiple
adapter support as well /dwm */
* This driver is for PCnet32 and PCnetPCI based ethercards
*/
-static const char *version = "lance32.c:v0.02 17.3.96 tsbogend@bigbug.franken.de\n";
+static const char *version = "lance32.c:v0.10 28.4.96 tsbogend@bigbug.franken.de\n";
#include <linux/kernel.h>
#include <linux/sched.h>
@@ -55,6+55,11 @@ int lance32_debug = 1; * only tested on Alpha Noname Board
* v0.02: changed IRQ handling for new interrupt scheme (dev_id)
* tested on a ASUS SP3G
+ * v0.10: fixed a odd problem with the 79C794 in a Compaq Deskpro XL
+ * looks like the 974 doesn't like stopping and restarting in a
+ * short period of time; now we do a reinit of the lance; the
+ * bug was triggered by doing ifconfig eth0 <ip> broadcast <addr>
+ * and hangs the machine (thanks to Klaus Liedl for debugging)
*/
@@ -320,7+325,11 @@ lance32_open(struct device *dev) (u32) virt_to_bus(lp->rx_ring),
(u32) virt_to_bus(&lp->init_block));
+ lp->init_block.mode = 0x0000;
+ lp->init_block.filter[0] = 0x00000000;
+ lp->init_block.filter[1] = 0x00000000;
lance32_init_ring(dev);
+
/* Re-initialize the LANCE, and start it when done. */
outw(0x0001, ioaddr+LANCE_ADDR);
outw((short) (u32) virt_to_bus(&lp->init_block), ioaddr+LANCE_DATA);
@@ -404,12+413,9 @@ lance32_init_ring(struct device *dev) lp->tx_ring[i].status = 0;
}
- lp->init_block.mode = 0x0000;
lp->init_block.tlen_rlen = TX_RING_LEN_BITS | RX_RING_LEN_BITS;
for (i = 0; i < 6; i++)
lp->init_block.phys_addr[i] = dev->dev_addr[i];
- lp->init_block.filter[0] = 0x00000000;
- lp->init_block.filter[1] = 0x00000000;
lp->init_block.rx_ring = (u32)virt_to_bus(lp->rx_ring);
lp->init_block.tx_ring = (u32)virt_to_bus(lp->tx_ring);
}
@@ -417,11+423,21 @@ lance32_init_ring(struct device *dev) static void
lance32_restart(struct device *dev, unsigned int csr0_bits, int must_reinit)
{
+ int i;
+ int ioaddr = dev->base_addr;
+
lance32_purge_tx_ring(dev);
lance32_init_ring(dev);
- outw(0x0000, dev->base_addr + LANCE_ADDR);
- outw(csr0_bits, dev->base_addr + LANCE_DATA);
+ outw(0x0000, ioaddr + LANCE_ADDR);
+ /* ReInit Ring */
+ outw(0x0001, ioaddr + LANCE_DATA);
+ i = 0;
+ while (i++ < 100)
+ if (inw(ioaddr+LANCE_DATA) & 0x0100)
+ break;
+
+ outw(csr0_bits, ioaddr + LANCE_DATA);
}
static int
@@ -459,7+475,7 @@ lance32_start_xmit(struct sk_buff *skb, struct device *dev) printk("\n");
}
#endif
- lance32_restart(dev, 0x0043, 1);
+ lance32_restart(dev, 0x0042, 1);
dev->tbusy=0;
dev->trans_start = jiffies;
@@ -794,32+810,25 @@ lance32_get_stats(struct device *dev) static void lance32_set_multicast_list(struct device *dev)
{
short ioaddr = dev->base_addr;
-
- outw(0, ioaddr+LANCE_ADDR);
- outw(0x0004, ioaddr+LANCE_DATA); /* Temporarily stop the lance. */
+ struct lance32_private *lp = (struct lance32_private *)dev->priv;
if (dev->flags&IFF_PROMISC) {
/* Log any net taps. */
printk("%s: Promiscuous mode enabled.\n", dev->name);
- outw(15, ioaddr+LANCE_ADDR);
- outw(0x8000, ioaddr+LANCE_DATA); /* Set promiscuous mode */
+ lp->init_block.mode = 0x8000;
} else {
- short multicast_table[4];
- int i;
int num_addrs=dev->mc_count;
if(dev->flags&IFF_ALLMULTI)
num_addrs=1;
/* FIXIT: We don't use the multicast table, but rely on upper-layer filtering. */
- memset(multicast_table, (num_addrs == 0) ? 0 : -1, sizeof(multicast_table));
- for (i = 0; i < 4; i++) {
- outw(8 + i, ioaddr+LANCE_ADDR);
- outw(multicast_table[i], ioaddr+LANCE_DATA);
- }
- outw(15, ioaddr+LANCE_ADDR);
- outw(0x0000, ioaddr+LANCE_DATA); /* Unset promiscuous mode */
+ memset(lp->init_block.filter , (num_addrs == 0) ? 0 : -1, sizeof(lp->init_block.filter));
+ lp->init_block.mode = 0x0000;
}
+
+ outw(0, ioaddr+LANCE_ADDR);
+ outw(0x0004, ioaddr+LANCE_DATA); /* Temporarily stop the lance. */
- lance32_restart(dev, 0x0142, 0); /* Resume normal operation */
+ lance32_restart(dev, 0x0042, 0); /* Resume normal operation */
}
* Alan Cox : Rejig for NET3.029 snap #3
* Alan Cox : Fixed NET3.029 bugs and sped up
* Larry McVoy : Tiny tweak to double performance
- * Alan Cox : Backed out LMV's tweak - the linux mm cant
- * take it...
+ * Alan Cox : Backed out LMV's tweak - the linux mm
+ * can't take it...
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
Paul Gortmaker : new reset code, reset card after probe at boot.
Paul Gortmaker : multiple card support for module users.
Paul Gortmaker : Support for PCI ne2k clones, similar to lance.c
+ Paul Gortmaker : Allow users with bad cards to avoid full probe.
*/
@@ -78,6+79,7 @@ bad_clone_list[] = { {"NN1000", "NN2000", {0x08, 0x03, 0x08}}, /* Outlaw no-name clone. */
{"4-DIM8","4-DIM16", {0x00,0x00,0x4d,}}, /* Outlaw 4-Dimension cards. */
{"Con-Intl_8", "Con-Intl_16", {0x00, 0x00, 0x24}}, /* Connect Int'nl */
+ {"ET-100","ET-200", {0x00, 0x45, 0x54}}, /* YANG and YA clone */
{0,}
};
#endif
@@ -206,7+208,7 @@ static int ne_probe1(struct device *dev, int ioaddr) int wordlength = 2;
const char *name = NULL;
int start_page, stop_page;
- int neX000, ctron;
+ int neX000, ctron, bad_card;
int reg0 = inb_p(ioaddr);
static unsigned version_printed = 0;
@@ -232,6+234,14 @@ static int ne_probe1(struct device *dev, int ioaddr)
printk("NE*000 ethercard probe at %#3x:", ioaddr);
+ /* A user with a poor card that fails to ack the reset, or that
+ does not have a valid 0x57,0x57 signature can still use this
+ without having to recompile. Specifying an i/o address along
+ with an otherwise unused dev->mem_end value of "0xBAD" will
+ cause the driver to skip these parts of the probe. */
+
+ bad_card = ((dev->base_addr != 0) && (dev->mem_end == 0xbad));
+
/* Reset card. Who knows what dain-bramaged state it was left in. */
{ unsigned long reset_start_time = jiffies;
@@ -240,8+250,13 @@ static int ne_probe1(struct device *dev, int ioaddr)
while ((inb_p(ioaddr + EN0_ISR) & ENISR_RESET) == 0)
if (jiffies - reset_start_time > 2*HZ/100) {
- printk(" not found (no reset ack).\n");
- return ENODEV;
+ if (bad_card) {
+ printk(" (warning: no reset ack)");
+ break;
+ } else {
+ printk(" not found (no reset ack).\n");
+ return ENODEV;
+ }
}
outb_p(0xff, ioaddr + EN0_ISR); /* Ack all intr. */
@@ -297,7+312,7 @@ static int ne_probe1(struct device *dev, int ioaddr) ctron = (SA_prom[0] == 0x00 && SA_prom[1] == 0x00 && SA_prom[2] == 0x1d);
/* Set up the rest of the parameters. */
- if (neX000) {
+ if (neX000 || bad_card) {
name = (wordlength == 2) ? "NE2000" : "NE1000";
} else if (ctron) {
name = (wordlength == 2) ? "Ctron-8" : "Ctron-16";
*/
#include <linux/module.h>
+#include <linux/config.h> /* for CONFIG_IP_FORWARD */
/* Only two headers!! :-) */
#include <net/ip.h>
@@ -172,7+173,8 @@ static int tunnel_xmit(struct sk_buff *skb, struct device *dev) printk ( KERN_INFO "%s: Packet with no route!\n", dev->name);
dev->tbusy=0;
stats->tx_errors++;
- return(1);
+ dev_kfree_skb(skb, FREE_WRITE);
+ return 0;
}
/*
@@ -191,7+193,8 @@ static int tunnel_xmit(struct sk_buff *skb, struct device *dev) ip_rt_put(rt);
dev->tbusy=0;
stats->tx_errors++;
- return(1);
+ dev_kfree_skb(skb, FREE_WRITE);
+ return 0;
}
ip_rt_put(rt);
@@ -203,7+206,8 @@ static int tunnel_xmit(struct sk_buff *skb, struct device *dev) printk ( KERN_INFO "%s: Can't reach target gateway!\n", dev->name);
dev->tbusy=0;
stats->tx_errors++;
- return(1);
+ dev_kfree_skb(skb, FREE_WRITE);
+ return 0;
}
tdev = rt->rt_dev;
@@ -214,7+218,8 @@ static int tunnel_xmit(struct sk_buff *skb, struct device *dev) ip_rt_put(rt);
dev->tbusy=0;
stats->tx_errors++;
- return(1);
+ dev_kfree_skb(skb, FREE_WRITE);
+ return 0;
}
#ifdef TUNNEL_DEBUG
@@ -243,7+248,8 @@ printk("Required room: %d, Tunnel hlen: %d\n", max_headroom, TUNL_HLEN); ip_rt_put(rt);
dev->tbusy = 0;
stats->tx_dropped++;
- return(1);
+ dev_kfree_skb(skb, FREE_WRITE);
+ return 0;
}
new_skb->free = 1;
@@ -259,8+265,7 @@ printk("Required room: %d, Tunnel hlen: %d\n", max_headroom, TUNL_HLEN); */
new_skb->ip_hdr = (struct iphdr *) skb_put(new_skb, skb->len);
memcpy(new_skb->ip_hdr, skb->data, skb->len);
- /* Is this necessary? */
- memcpy(new_skb->proto_priv, skb->proto_priv, sizeof(skb->proto_priv));
+ memset(new_skb->proto_priv, 0, sizeof(skb->proto_priv));
/* Tack on our header */
new_skb->h.iph = (struct iphdr *) skb_push(new_skb, tunnel_hlen);
@@ -299,7+304,9 @@ printk("Required room: %d, Tunnel hlen: %d\n", max_headroom, TUNL_HLEN); * If ip_forward() made a copy, it will return 1 so we can free.
*/
- if (ip_forward(skb, dev, 0, target) == 1)
+#ifdef CONFIG_IP_FORWARD
+ if (ip_forward(skb, dev, 0, target))
+#endif
kfree_skb(skb, FREE_WRITE);
/*
@@ -91,7+91,7 @@ typedef struct sk_buff sk_buff; #include <linux/ip.h>
#include <linux/tcp.h>
#include <linux/if_arp.h>
-#include "slhc.h"
+#include <net/slhc_vj.h>
#define fcstab ppp_crc16_table /* Name of the table in the kernel */
#include <linux/ppp_defs.h>
@@ -955,7+955,7 @@ static int sdla_close(struct device *dev) }
memset(&intr, 0, sizeof(intr));
- /* lets start up the reception */
+ /* let's start up the reception */
switch(flp->type)
{
case SDLA_S502A:
@@ -1028,7+1028,7 @@ static int sdla_open(struct device *dev)
sdla_cmd(dev, SDLA_ENABLE_COMMUNICATIONS, 0, 0, NULL, 0, NULL, NULL);
- /* lets start up the reception */
+ /* let's start up the reception */
memset(&intr, 0, sizeof(intr));
switch(flp->type)
{
@@ -611,7+611,7 @@ static void set_multicast_list(struct device *dev)
{
/*
- * I _could_ do upto 6 addresses here, but wont (yet?)
+ * I _could_ do up to 6 addresses here, but won't (yet?)
*/
#if 0
#define SEEQCFG2_NO_PREAM (0x0080) /* 1= user supplies Xmit preamble bytes */
#define SEEQCFG2_ADDR_LEN (0x0100) /* 1= 2byte addresses */
#define SEEQCFG2_REC_CRC (0x0200) /* 0= received packets will have CRC stripped from them */
-#define SEEQCFG2_XMIT_NO_CRC (0x0400) /* dont xmit CRC with each packet (user supplies it) */
+#define SEEQCFG2_XMIT_NO_CRC (0x0400) /* don't xmit CRC with each packet (user supplies it) */
#define SEEQCFG2_LOOPBACK (0x0800)
#define SEEQCFG2_CTRLO (0x1000)
#define SEEQCFG2_RESET (0x8000) /* software Hard-reset bit */
@@ -112,7+112,7 @@ static const char *rcsid = "$Id: sk_g16.c,v 1.1 1994/06/30 16:25:15 root Exp $";
/*
* In POS3 are bits A14-A19 of the address bus. These bits can be set
- * to choose the RAM address. Thats why we only can choose the RAM address
+ * to choose the RAM address. That's why we only can choose the RAM address
* in 16KB steps.
*/
@@ -1441,7+1441,7 @@ static void SK_txintr(struct device *dev) /*
* Here I have a problem.
* I only know that there must be one or up to 15 collisions.
- * Thats why TX_MORE is set, because after 16 attempts TX_RTRY
+ * That's why TX_MORE is set, because after 16 attempts TX_RTRY
* will be set which means couldn't send packet aborted transfer.
*
* First I did not have this in but then I thought at minimum
#include <asm/segment.h>
#include <linux/mm.h>
#include <net/checksum.h>
-#include "slhc.h"
+#include <net/slhc_vj.h>
#ifdef __alpha__
# include <asm/unaligned.h>
#ifdef CONFIG_INET
#include <linux/ip.h>
#include <linux/tcp.h>
-#include "slhc.h"
+#include <net/slhc_vj.h>
#endif
#ifdef MODULE
/* smc-ultra.c: A SMC Ultra ethernet driver for linux. */
/*
- Written 1993,1994,1995 by Donald Becker.
+ This is a driver for the SMC Ultra and SMC EtherEZ ISA ethercards.
+
+ Written 1993-1996 by Donald Becker.
Copyright 1993 United States Government as represented by the
Director, National Security Agency.
Center of Excellence in Space Data and Information Sciences
Code 930.5, Goddard Space Flight Center, Greenbelt MD 20771
- This is a driver for the SMC Ultra and SMC EtherEZ ethercards.
-
This driver uses the cards in the 8390-compatible, shared memory mode.
Most of the run-time complexity is handled by the generic code in
8390.c. The code in this file is responsible for
transfers to avoid a bug in early version of the card that corrupted
data transferred by a AHA1542.
- This driver does not support the programmed-I/O data transfer mode of
- the EtherEZ. That support (if available) is smc-ez.c. Nor does it
- use the non-8390-compatible "Altego" mode. (No support currently planned.)
+ This driver now supports the programmed-I/O (PIO) data transfer mode of
+ the EtherEZ. It does not use the non-8390-compatible "Altego" mode.
+ That support (if available) is smc-ez.c.
Changelog:
Paul Gortmaker : multiple card support for module users.
+ Donald Becker : 4/17/96 PIO support, minor potential problems avoided.
*/
static const char *version =
- "smc-ultra.c:v1.12 1/18/95 Donald Becker (becker@cesdis.gsfc.nasa.gov)\n";
+ "smc-ultra.c:v1.99 4/17/96 Donald Becker (becker@cesdis.gsfc.nasa.gov)\n";
#include <linux/module.h>
@@ -73,6+74,12 @@ static void ultra_block_input(struct device *dev, int count, struct sk_buff *skb, int ring_offset);
static void ultra_block_output(struct device *dev, int count,
const unsigned char *buf, const start_page);
+static void ultra_pio_get_hdr(struct device *dev, struct e8390_pkt_hdr *hdr,
+ int ring_page);
+static void ultra_pio_input(struct device *dev, int count,
+ struct sk_buff *skb, int ring_offset);
+static void ultra_pio_output(struct device *dev, int count,
+ const unsigned char *buf, const start_page);
static int ultra_close_card(struct device *dev);
\f
@@ -81,8+88,11 @@ static int ultra_close_card(struct device *dev); #define ULTRA_CMDREG 0 /* Offset to ASIC command register. */
#define ULTRA_RESET 0x80 /* Board reset, in ULTRA_CMDREG. */
#define ULTRA_MEMENB 0x40 /* Enable the shared memory. */
+#define IOPD 0x02 /* I/O Pipe Data (16 bits), PIO operation. */
+#define IOPA 0x07 /* I/O Pipe Address for PIO operation. */
#define ULTRA_NIC_OFFSET 16 /* NIC register offset from the base_addr. */
#define ULTRA_IO_EXTENT 32
+#define EN0_ERWCNT 0x08 /* Early receive warning count. */
\f
/* Probe for the Ultra. This looks like a 8013 with the station
address PROM at I/O ports <base>+8 to <base>+13, with a checksum
@@ -123,7+133,7 @@ int ultra_probe1(struct device *dev, int ioaddr) unsigned char eeprom_irq = 0;
static unsigned version_printed = 0;
/* Values from various config regs. */
- unsigned char num_pages, irqreg, addr;
+ unsigned char num_pages, irqreg, addr, piomode;
unsigned char idreg = inb(ioaddr + 7);
unsigned char reg4 = inb(ioaddr + 4) & 0x7f;
@@ -162,8+172,9 @@ int ultra_probe1(struct device *dev, int ioaddr)
/* Enabled FINE16 mode to avoid BIOS ROM width mismatches @ reboot. */
outb(0x80 | inb(ioaddr + 0x0c), ioaddr + 0x0c);
- irqreg = inb(ioaddr + 0xd);
+ piomode = inb(ioaddr + 0x8);
addr = inb(ioaddr + 0xb);
+ irqreg = inb(ioaddr + 0xd);
/* Switch back to the station address register set so that the MS-DOS driver
can find the card after a warm boot. */
@@ -214,13+225,20 @@ int ultra_probe1(struct device *dev, int ioaddr) dev->mem_end = dev->rmem_end
= dev->mem_start + (ei_status.stop_page - START_PG)*256;
- printk(",%s IRQ %d memory %#lx-%#lx.\n", eeprom_irq ? "" : "assigned ",
- dev->irq, dev->mem_start, dev->mem_end-1);
-
+ if (piomode) {
+ printk(",%s IRQ %d programmed-I/O mode.\n",
+ eeprom_irq ? "EEPROM" : "assigned ", dev->irq);
+ ei_status.block_input = &ultra_pio_input;
+ ei_status.block_output = &ultra_pio_output;
+ ei_status.get_8390_hdr = &ultra_pio_get_hdr;
+ } else {
+ printk(",%s IRQ %d memory %#lx-%#lx.\n", eeprom_irq ? "" : "assigned ",
+ dev->irq, dev->mem_start, dev->mem_end-1);
+ ei_status.block_input = &ultra_block_input;
+ ei_status.block_output = &ultra_block_output;
+ ei_status.get_8390_hdr = &ultra_get_8390_hdr;
+ }
ei_status.reset_8390 = &ultra_reset_8390;
- ei_status.block_input = &ultra_block_input;
- ei_status.block_output = &ultra_block_output;
- ei_status.get_8390_hdr = &ultra_get_8390_hdr;
dev->open = &ultra_open;
dev->stop = &ultra_close_card;
NS8390_init(dev, 0);
@@ -236,9+254,16 @@ ultra_open(struct device *dev) if (request_irq(dev->irq, ei_interrupt, 0, ei_status.name, NULL))
return -EAGAIN;
- outb(ULTRA_MEMENB, ioaddr); /* Enable memory, 16 bit mode. */
+ outb(0x00, ioaddr); /* Disable shared memory for safety. */
outb(0x80, ioaddr + 5);
- outb(0x01, ioaddr + 6); /* Enable interrupts and memory. */
+ if (ei_status.block_input == &ultra_pio_input)
+ outb(0x11, ioaddr + 6); /* Enable interrupts and PIO. */
+ else
+ outb(0x01, ioaddr + 6); /* Enable interrupts and memory. */
+ /* Set the early receive warning level in window 0 high enough not
+ to receive ERW interrupts. */
+ outb_p(E8390_NODMA+E8390_PAGE0, dev->base_addr);
+ outb(0xff, dev->base_addr + EN0_ERWCNT);
ei_open(dev);
MOD_INC_USE_COUNT;
return 0;
@@ -253,7+278,12 @@ ultra_reset_8390(struct device *dev) if (ei_debug > 1) printk("resetting Ultra, t=%ld...", jiffies);
ei_status.txing = 0;
- outb(ULTRA_MEMENB, cmd_port);
+ outb(0x00, cmd_port); /* Disable shared memory for safety. */
+ outb(0x80, cmd_port + 5);
+ if (ei_status.block_input == &ultra_pio_input)
+ outb(0x11, cmd_port + 6); /* Enable interrupts and PIO. */
+ else
+ outb(0x01, cmd_port + 6); /* Enable interrupts and memory. */
if (ei_debug > 1) printk("reset done\n");
return;
@@ -266,7+296,6 @@ ultra_reset_8390(struct device *dev) static void
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);
outb(ULTRA_MEMENB, dev->base_addr - ULTRA_NIC_OFFSET); /* shmem on */
@@ -318,6+347,49 @@ ultra_block_output(struct device *dev, int count, const unsigned char *buf, outb(0x00, dev->base_addr - ULTRA_NIC_OFFSET); /* Disable memory. */
}
+/* The identical operations for programmed I/O cards.
+ The PIO model is trivial to use: the 16 bit start address is written
+ byte-sequentially to IOPA, with no intervening I/O operations, and the
+ data is read or written to the IOPD data port.
+ The only potential complication is that the address register is shared
+ must be always be rewritten between each read/write direction change.
+ This is no problem for us, as the 8390 code ensures that we are single
+ threaded. */
+static void ultra_pio_get_hdr(struct device *dev, struct e8390_pkt_hdr *hdr,
+ int ring_page)
+{
+ int ioaddr = dev->base_addr - ULTRA_NIC_OFFSET; /* ASIC addr */
+ outb(0x00, ioaddr + IOPA); /* Set the address, LSB first. */
+ outb(ring_page, ioaddr + IOPA);
+ insw(ioaddr + IOPD, hdr, sizeof(struct e8390_pkt_hdr)>>1);
+}
+
+static void ultra_pio_input(struct device *dev, int count,
+ struct sk_buff *skb, int ring_offset)
+{
+ int ioaddr = dev->base_addr - ULTRA_NIC_OFFSET; /* ASIC addr */
+ char *buf = skb->data;
+
+ /* For now set the address again, although it should already be correct. */
+ outb(ring_offset, ioaddr + IOPA); /* Set the address, LSB first. */
+ outb(ring_offset >> 8, ioaddr + IOPA);
+ insw(ioaddr + IOPD, buf, (count+1)>>1);
+#ifdef notdef
+ /* We don't need this -- skbuffs are padded to at least word alignment. */
+ if (count & 0x01) {
+ buf[count-1] = inb(ioaddr + IOPD);
+#endif
+}
+
+static void ultra_pio_output(struct device *dev, int count,
+ const unsigned char *buf, const start_page)
+{
+ int ioaddr = dev->base_addr - ULTRA_NIC_OFFSET; /* ASIC addr */
+ outb(0x00, ioaddr + IOPA); /* Set the address, LSB first. */
+ outb(start_page, ioaddr + IOPA);
+ outsw(ioaddr + IOPD, buf, (count+1)>>1);
+}
+
static int
ultra_close_card(struct device *dev)
{
@@ -273,7+273,7 @@ keycode 0x7e = # keycode 0x7f is special and it means 'all keys released' and is
# taken care of within the sun keyboard driver itself
keycode 0x7f =
-# Thats all folks...
+# That's all folks...
string F1 = "\033[[A"
string F2 = "\033[[B"
string F3 = "\033[[C"
@@ -467,7+467,7 @@ static _INLINE_ void transmit_chars(struct sun_serial *info) }
if((info->xmit_cnt <= 0) || info->tty->stopped) {
- /* Thats peculiar... */
+ /* That's peculiar... */
info->zs_channel->control = RES_Tx_P;
udelay(5);
goto clear_and_return;
@@ -345,7+345,7 @@ static Scsi_Host_Template *the_template = NULL; * 001c46d4 : 0x001c5ea0 0x000011f8
*
* Changed the print code in the phase_mismatch handler so
- * that we call print_lots to try and diagnose this.
+ * that we call print_lots to try to diagnose this.
*
*/
@@ -1233,7+1233,7 @@ Thu Jul 14 10:51:42 1994 Eric Youngdale (eric@esp22) * scsi.c (scan_scsis): Add new devices to end of linked list, not
to the beginning.
- * scsi.h (SCSI_SLEEP): Remove brain dead hack to try and save
+ * scsi.h (SCSI_SLEEP): Remove brain dead hack to try to save
the task state before sleeping.
Sat Jul 9 15:01:03 1994 Eric Youngdale (eric@esp22)
@@ -1724,7+1724,7 @@ Thu Aug 5 11:59:18 1993 * constants.c, constants.h: New files with ascii descriptions of
various conditions.
- * Makefile: Do not try and count the number of low-level drivers,
+ * Makefile: Do not try to count the number of low-level drivers,
just generate the list of .o files.
* aha1542.c: Replace 16 with sizeof(SCpnt->sense_buffer). Add tests
@@ -1819,7+1819,7 @@ Thu Jun 2 17:58:11 1993
* sr.c: Increase timeout to 500 from 250. Add entry for sync in
dispatch table (supply NULL). If we do not have a sectorsize,
- try and get it in the sd_open function. Add new function just to
+ try to get it in the sd_open function. Add new function just to
obtain sectorsize.
* sr.h: Add needs_sector_size semaphore.
@@ -21,7+21,7 @@ dep_tristate 'Adaptec AHA1740 support' CONFIG_SCSI_AHA1740 $CONFIG_SCSI dep_tristate 'Adaptec AHA274X/284X/294X support' CONFIG_SCSI_AIC7XXX $CONFIG_SCSI
dep_tristate 'BusLogic SCSI support' CONFIG_SCSI_BUSLOGIC $CONFIG_SCSI
dep_tristate 'DTC3180/3280 SCSI support' CONFIG_SCSI_DTC3280 $CONFIG_SCSI
-dep_tristate 'EATA-DMA (DPT, NEC, ATT, Olivetti) support' CONFIG_SCSI_EATA_DMA $CONFIG_SCSI
+dep_tristate 'EATA-DMA (DPT, NEC, AT&T, SNI, AST, Olivetti, Alphatronix) support' CONFIG_SCSI_EATA_DMA $CONFIG_SCSI
dep_tristate 'EATA-PIO (old DPT PM2001, PM2012A) support' CONFIG_SCSI_EATA_PIO $CONFIG_SCSI
dep_tristate 'UltraStor 14F/34F support' CONFIG_SCSI_U14_34F $CONFIG_SCSI
dep_tristate 'Future Domain 16xx SCSI support' CONFIG_SCSI_FUTURE_DOMAIN $CONFIG_SCSI
@@ -274,7+274,7 @@ MTIOCGET Returns some status information. The following ioctls use the structure mtlocation that contains both
the block number and the partition number. These ioctls are available
only for SCSI-2 tape drives and the block number is the
-device-indepent logical block number defined by the standard.
+device-independent logical block number defined by the standard.
MTGETLOC Returns the current block and partition number.
MTSETLOC Sets the tape to the block and partition specified by the
@@ -1214,7+1214,7 @@ int aha1542_reset(Scsi_Cmnd * SCpnt, unsigned int reset_flags) setup_mailboxes(SCpnt->host->io_port, SCpnt->host);
/*
- * Now try and pick up the pieces. Restart all commands
+ * Now try to pick up the pieces. Restart all commands
* that are currently active on the bus, and reset all of
* the datastructures. We have some time to kill while
* things settle down, so print a nice message.
@@ -4483,12+4483,12 @@ aic7xxx_abort_reset(Scsi_Cmnd *cmd, unsigned char errcode) * The target we select to send the message to may be entirely
* different than the target pointed to by the scb that timed
* out. If the command is in the QINFIFO or the waiting for
- * selection list, its not tying up the bus and isn't responsible
+ * selection list, it's not tying up the bus and isn't responsible
* for the delay so we pick off the active command which should
- * be the SCB selected by SCBPTR. If its disconnected or active,
+ * be the SCB selected by SCBPTR. If it's disconnected or active,
* we device reset the target scbp points to. Although it may
* be that this target is not responsible for the delay, it may
- * may also be that we're timing out on a command that just takes
+ * also be that we're timing out on a command that just takes
* too much time, so we try the bus device reset there first.
*/
active_scb = inb(SCBPTR + base);
* *
* The driver currently: *
* -supports all ISA based EATA-DMA boards *
+ * like PM2011, PM2021, PM2041, PM3021 *
* -supports all EISA based EATA-DMA boards *
+ * like PM2012B, PM2022, PM2122, PM2322, PM2042, *
+ * PM3122, PM3222, PM3332 *
* -supports all PCI based EATA-DMA boards *
+ * like PM2024, PM2124, PM2044, PM2144, PM3224, *
+ * PM3334 *
+ * -supports the Wide, Ultra Wide and Differential *
+ * versions of the boards *
* -supports multiple HBAs with & without IRQ sharing *
* -supports all SCSI channels on multi channel boards *
* -needs identical IDs on all channels of a HBA *
* -provides rudimentary latency measurement *
* possibilities via /proc/scsi/eata_dma/<hostnum> *
* *
- * (c)1993,94,95 Michael Neuffer *
- * neuffer@goofy.zdv.uni-mainz.de *
+ * (c)1993-96 Michael Neuffer *
+ * mike@i-Connect.Net *
+ * neuffer@mail.uni-mainz.de *
* *
* This program is free software; you can redistribute it *
* and/or modify it under the terms of the GNU General *
* very helpful and tried to give me all the infos and *
* support I need. *
* *
- * Thanks also to Greg Hosler who did a lot of testing and *
- * found quite a number of bugs during the development. *
+ * Thanks also to Simon Shapiro, Greg Hosler and Mike *
+ * Jagdis who did a lot of testing and found quite a number *
+ * of bugs during the development. *
************************************************************
- * last change: 95/04/27 OS: Linux 1.3.95 *
+ * last change: 95/05/05 OS: Linux 1.3.98 *
************************************************************/
/* Look in eata_dma.h for configuration and revision information */
#include <linux/bios32.h>
#include <linux/pci.h>
#include <linux/proc_fs.h>
+#include <linux/delay.h>
#include <asm/byteorder.h>
#include <asm/types.h>
#include <asm/io.h>
@@ -132,7+142,7 @@ int eata_release(struct Scsi_Host *sh) else reg_IRQ[sh->irq]--;
scsi_init_free((void *)status, 512);
- scsi_init_free((void *)dma_scratch, 512);
+ scsi_init_free((void *)dma_scratch - 4, 1024);
for (i = 0; i < sh->can_queue; i++){ /* Free all SG arrays */
if(SD(sh)->ccb[i].sg_list != NULL)
scsi_init_free((void *) SD(sh)->ccb[i].sg_list,
@@ -149,12+159,89 @@ int eata_release(struct Scsi_Host *sh) #endif
+inline void eata_latency_in(struct eata_ccb *cp, hostdata *hd)
+{
+ uint time;
+ time = jiffies - cp->timestamp;
+ if(hd->all_lat[1] > time)
+ hd->all_lat[1] = time;
+ if(hd->all_lat[2] < time)
+ hd->all_lat[2] = time;
+ hd->all_lat[3] += time;
+ hd->all_lat[0]++;
+ if((cp->rw_latency) == WRITE) { /* was WRITE */
+ if(hd->writes_lat[cp->sizeindex][1] > time)
+ hd->writes_lat[cp->sizeindex][1] = time;
+ if(hd->writes_lat[cp->sizeindex][2] < time)
+ hd->writes_lat[cp->sizeindex][2] = time;
+ hd->writes_lat[cp->sizeindex][3] += time;
+ hd->writes_lat[cp->sizeindex][0]++;
+ } else if((cp->rw_latency) == READ) {
+ if(hd->reads_lat[cp->sizeindex][1] > time)
+ hd->reads_lat[cp->sizeindex][1] = time;
+ if(hd->reads_lat[cp->sizeindex][2] < time)
+ hd->reads_lat[cp->sizeindex][2] = time;
+ hd->reads_lat[cp->sizeindex][3] += time;
+ hd->reads_lat[cp->sizeindex][0]++;
+ }
+}
+
+inline void eata_latency_out(struct eata_ccb *cp, Scsi_Cmnd *cmd)
+{
+ int x, z;
+ short *sho;
+ long *lon;
+ x = 0; /* just to keep GCC quiet */
+ cp->timestamp = jiffies; /* For latency measurements */
+ switch(cmd->cmnd[0]) {
+ case WRITE_6:
+ x = cmd->cmnd[4]/2;
+ cp->rw_latency = WRITE;
+ break;
+ case READ_6:
+ x = cmd->cmnd[4]/2;
+ cp->rw_latency = READ;
+ break;
+ case WRITE_10:
+ sho = (short *) &cmd->cmnd[7];
+ x = ntohs(*sho)/2;
+ cp->rw_latency = WRITE;
+ break;
+ case READ_10:
+ sho = (short *) &cmd->cmnd[7];
+ x = ntohs(*sho)/2;
+ cp->rw_latency = READ;
+ break;
+ case WRITE_12:
+ lon = (long *) &cmd->cmnd[6];
+ x = ntohl(*lon)/2;
+ cp->rw_latency = WRITE;
+ break;
+ case READ_12:
+ lon = (long *) &cmd->cmnd[6];
+ x = ntohl(*lon)/2;
+ cp->rw_latency = READ;
+ break;
+ default:
+ cp->rw_latency = OTHER;
+ break;
+ }
+ if (cmd->cmnd[0] == WRITE_6 || cmd->cmnd[0] == WRITE_10 ||
+ cmd->cmnd[0] == WRITE_12 || cmd->cmnd[0] == READ_6 ||
+ cmd->cmnd[0] == READ_10 || cmd->cmnd[0] == READ_12) {
+ for(z = 0; (x > (1 << z)) && (z <= 11); z++)
+ /* nothing */;
+ cp->sizeindex = z;
+ }
+}
+
+
void eata_int_handler(int irq, void *dev_id, struct pt_regs * regs)
{
uint i, result = 0;
uint hba_stat, scsi_stat, eata_stat;
Scsi_Cmnd *cmd;
- struct eata_ccb *cp;
+ struct eata_ccb *ccb;
struct eata_sp *sp;
uint base;
ulong flags;
@@ -173,16+260,16 @@ void eata_int_handler(int irq, void *dev_id, struct pt_regs * regs) int_counter++;
sp = &SD(sh)->sp;
- cp = sp->ccb;
+ ccb = sp->ccb;
- if(cp == NULL) {
+ if(ccb == NULL) {
eata_stat = inb((uint)sh->base + HA_RSTATUS);
printk("eata_dma: int_handler, Spurious IRQ %d "
"received. CCB pointer not set.\n", irq);
break;
}
- cmd = cp->cmd;
+ cmd = ccb->cmd;
base = (uint) cmd->host->base;
hba_stat = sp->hba_stat;
@@ -190,23+277,27 @@ void eata_int_handler(int irq, void *dev_id, struct pt_regs * regs)
if (sp->EOC == FALSE) {
eata_stat = inb(base + HA_RSTATUS);
- printk("eata_dma: int_handler, board: %x cmd %lx returned "
- "unfinished.\nEATA: %x HBA: %x SCSI: %x spadr %lx "
- "spadrirq %lx, irq%d\n", base, (long)cp, eata_stat,
- hba_stat, scsi_stat,(long)&status, (long)&status[irq],
- irq);
- DBG(DBG_DELAY, DEL2(800));
+ printk(KERN_WARNING "eata_dma: int_handler, board: %x cmd %lx "
+ "returned unfinished.\n"
+ "EATA: %x HBA: %x SCSI: %x spadr %lx spadrirq %lx, "
+ "irq%d\n", base, (long)ccb, eata_stat, hba_stat,
+ scsi_stat,(long)&status, (long)&status[irq], irq);
+ cmd->result = DID_ERROR << 16;
+ ccb->status = FREE;
+ cmd->scsi_done(cmd);
break;
}
- if (cp->status == LOCKED) {
- cp->status = FREE;
+ if (ccb->status == LOCKED) {
+ ccb->status = FREE;
eata_stat = inb(base + HA_RSTATUS);
printk("eata_dma: int_handler, freeing locked queueslot\n");
- DBG(DBG_INTR && DBG_DELAY, DEL2(800));
+ DBG(DBG_INTR && DBG_DELAY, DELAY(1));
break;
}
+ sp->EOC = FALSE; /* Clean out this flag */
+
eata_stat = inb(base + HA_RSTATUS);
DBG(DBG_INTR, printk("IRQ %d received, base %#.4x, pid %ld, "
"target: %x, lun: %x, ea_s: %#.2x, hba_s: "
@@ -215,52+306,22 @@ void eata_int_handler(int irq, void *dev_id, struct pt_regs * regs)
switch (hba_stat) {
case HA_NO_ERROR: /* NO Error */
- if (scsi_stat == CONDITION_GOOD
- && cmd->device->type == TYPE_DISK
- && (HD(cmd)->t_state[cp->cp_channel][cp->cp_id] == RESET))
- result = DID_BUS_BUSY << 16;
- else if (scsi_stat == GOOD) {
- HD(cmd)->t_state[cp->cp_channel][cp->cp_id] = OK;
- if(HD(cmd)->do_latency == TRUE && cp->timestamp) {
- uint time;
- time = jiffies - cp->timestamp;
- if((cp->rw_latency) == TRUE) { /* was WRITE */
- if(HD(cmd)->writes_lat[cp->sizeindex][1] > time)
- HD(cmd)->writes_lat[cp->sizeindex][1] = time;
- if(HD(cmd)->writes_lat[cp->sizeindex][2] < time)
- HD(cmd)->writes_lat[cp->sizeindex][2] = time;
- HD(cmd)->writes_lat[cp->sizeindex][3] += time;
- HD(cmd)->writes_lat[cp->sizeindex][0]++;
- } else {
- if(HD(cmd)->reads_lat[cp->sizeindex][1] > time)
- HD(cmd)->reads_lat[cp->sizeindex][1] = time;
- if(HD(cmd)->reads_lat[cp->sizeindex][2] < time)
- HD(cmd)->reads_lat[cp->sizeindex][2] = time;
- HD(cmd)->reads_lat[cp->sizeindex][3] += time;
- HD(cmd)->reads_lat[cp->sizeindex][0]++;
- }
- }
- }
- else if (scsi_stat == CHECK_CONDITION
- && cmd->device->type == TYPE_DISK
- && (cmd->sense_buffer[2] & 0xf) == RECOVERED_ERROR)
- result = DID_BUS_BUSY << 16;
- else
- result = DID_OK << 16;
- HD(cmd)->t_timeout[cp->cp_channel][cp->cp_id] = OK;
+ HD(cmd)->t_state[ccb->cp_channel][ccb->cp_id] = OK;
+ if(HD(cmd)->do_latency == TRUE && ccb->timestamp)
+ eata_latency_in(ccb, HD(cmd));
+ result = DID_OK << 16;
+ HD(cmd)->t_timeout[ccb->cp_channel][ccb->cp_id] = OK;
break;
case HA_ERR_SEL_TO: /* Selection Timeout */
- result = DID_BAD_TARGET << 16;
- break;
case HA_ERR_CMD_TO: /* Command Timeout */
- if (HD(cmd)->t_timeout[cp->cp_channel][cp->cp_id] > 1)
- result = DID_ERROR << 16;
- else {
- result = DID_TIME_OUT << 16;
- HD(cmd)->t_timeout[cp->cp_channel][cp->cp_id]++;
- }
+ result = DID_TIME_OUT << 16;
+ break;
+ case HA_BUS_RESET: /* SCSI Bus Reset Received */
+ result = DID_RESET << 16;
+ DBG(DBG_STATUS, printk(KERN_WARNING "scsi%d: BUS RESET "
+ "received on cmd %ld\n",
+ HD(cmd)->HBA_number, cmd->pid));
break;
- case HA_ERR_RESET: /* SCSI Bus Reset Received */
case HA_INIT_POWERUP: /* Initial Controller Power-up */
if (cmd->device->type != TYPE_TAPE)
result = DID_BUS_BUSY << 16;
@@ -268,15+329,39 @@ void eata_int_handler(int irq, void *dev_id, struct pt_regs * regs) result = DID_ERROR << 16;
for (i = 0; i < MAXTARGET; i++)
- HD(cmd)->t_state[cp->cp_channel][i] = RESET;
+ HD(cmd)->t_state[ccb->cp_channel][i] = RESET;
+ DBG(DBG_STATUS, printk(KERN_DEBUG "scsi%d: cmd pid %ld "
+ "returned with INIT_POWERUP\n",
+ HD(cmd)->HBA_number, cmd->pid));
+ break;
+ case HA_CP_ABORT_NA:
+ case HA_CP_ABORTED:
+ result = DID_ABORT << 16;
+ DBG(DBG_STATUS, printk(KERN_WARNING "scsi%d: aborted cmd "
+ "returned\n", HD(cmd)->HBA_number));
+ break;
+ case HA_CP_RESET_NA:
+ case HA_CP_RESET:
+ HD(cmd)->t_state[cmd->channel][cmd->target] = OK;
+ HD(cmd)->resetlevel[cmd->channel] = 0;
+ result = DID_RESET << 16;
+ DBG(DBG_STATUS, printk(KERN_WARNING "scsi%d: reseted cmd "
+ "pid %ldreturned\n",
+ HD(cmd)->HBA_number, cmd->pid));
+ case HA_SCSI_HUNG: /* SCSI Hung */
+ printk(KERN_ERR "scsi%d: SCSI hung\n", HD(cmd)->HBA_number);
+ result = DID_ERROR << 16;
+ break;
+ case HA_RSENSE_FAIL: /* Auto Request-Sense Failed */
+ DBG(DBG_STATUS, printk(KERN_ERR "scsi%d: Auto Request Sense "
+ "Failed\n", HD(cmd)->HBA_number));
+ result = DID_ERROR << 16;
break;
case HA_UNX_BUSPHASE: /* Unexpected Bus Phase */
case HA_UNX_BUS_FREE: /* Unexpected Bus Free */
case HA_BUS_PARITY: /* Bus Parity Error */
- case HA_SCSI_HUNG: /* SCSI Hung */
case HA_UNX_MSGRJCT: /* Unexpected Message Reject */
case HA_RESET_STUCK: /* SCSI Bus Reset Stuck */
- case HA_RSENSE_FAIL: /* Auto Request-Sense Failed */
case HA_PARITY_ERR: /* Controller Ram Parity */
default:
result = DID_ERROR << 16;
@@ -293,10+378,10 @@ void eata_int_handler(int irq, void *dev_id, struct pt_regs * regs) cmd->device->channel, cmd->device->id, cmd->device->lun,
cmd->pid, eata_stat, hba_stat, scsi_stat,
cmd->sense_buffer[2] & 0xf, cmd->result);
- DBG(DBG_INTR&&DBG_DELAY,DEL2(800));
+ DBG(DBG_INTR&&DBG_DELAY,DELAY(1));
#endif
- cp->status = FREE; /* now we can release the slot */
+ ccb->status = FREE; /* now we can release the slot */
cmd->scsi_done(cmd);
}
}
@@ -314,41+399,55 @@ inline int eata_send_command(u32 addr, u32 base, u8 command) return(FALSE);
/* And now the address in nice little byte chunks */
+#ifdef __LITTLE_ENDIAN
outb( addr & 0x000000ff, base + HA_WDMAADDR);
outb((addr & 0x0000ff00) >> 8, base + HA_WDMAADDR + 1);
outb((addr & 0x00ff0000) >> 16, base + HA_WDMAADDR + 2);
outb((addr & 0xff000000) >> 24, base + HA_WDMAADDR + 3);
+#else
+ outb((addr & 0xff000000) >> 24, base + HA_WDMAADDR);
+ outb((addr & 0x00ff0000) >> 16, base + HA_WDMAADDR + 1);
+ outb((addr & 0x0000ff00) >> 8, base + HA_WDMAADDR + 2);
+ outb((addr & 0x000000ff), base + HA_WDMAADDR + 3);
+#endif
outb(command, base + HA_WCOMMAND);
return(TRUE);
}
-#if 0
-inline int eata_send_immediate(u32 addr, u32 base, u8 cmnd, u8 cmnd2, u8 id,
- u8 lun)
+inline int eata_send_immediate(u32 base, u32 addr, u8 ifc, u8 code, u8 code2)
{
+ outb(0x0, base + HA_WDMAADDR - 1);
if(addr){
- outb( addr & 0x000000ff, base + HA_WDMAADDR);
- outb((addr & 0x0000ff00) >> 8, base + HA_WDMAADDR + 1);
+#ifdef __LITTLE_ENDIAN
+ outb( addr & 0x000000ff, base + HA_WDMAADDR);
+ outb((addr & 0x0000ff00) >> 8, base + HA_WDMAADDR + 1);
outb((addr & 0x00ff0000) >> 16, base + HA_WDMAADDR + 2);
outb((addr & 0xff000000) >> 24, base + HA_WDMAADDR + 3);
+#else
+ outb((addr & 0xff000000) >> 24, base + HA_WDMAADDR);
+ outb((addr & 0x00ff0000) >> 16, base + HA_WDMAADDR + 1);
+ outb((addr & 0x0000ff00) >> 8, base + HA_WDMAADDR + 2);
+ outb((addr & 0x000000ff), base + HA_WDMAADDR + 3);
+#endif
} else {
- outb(id, base + HA_WSUBCODE);
- outb(lun, base + HA_WSUBLUN);
+ outb(0x0, base + HA_WDMAADDR);
+ outb(0x0, base + HA_WDMAADDR + 1);
+ outb(code2, base + HA_WCODE2);
+ outb(code, base + HA_WCODE);
}
- outb(cmnd2, base + HA_WCOMMAND2);
- outb(cmnd, base + HA_WCOMMAND);
+ outb(ifc, base + HA_WIFC);
+ outb(EATA_CMD_IMMEDIATE, base + HA_WCOMMAND);
return(TRUE);
}
-#endif
int eata_queue(Scsi_Cmnd * cmd, void (* done) (Scsi_Cmnd *))
{
unsigned int i, x, y;
- u32 flags;
+ ulong flags;
hostdata *hd;
struct Scsi_Host *sh;
- struct eata_ccb *cp;
+ struct eata_ccb *ccb;
struct scatterlist *sl;
save_flags(flags);
@@ -359,6+458,15 @@ int eata_queue(Scsi_Cmnd * cmd, void (* done) (Scsi_Cmnd *)) hd = HD(cmd);
sh = cmd->host;
+#if 1
+ if (cmd->cmnd[0] == REQUEST_SENSE && cmd->sense_buffer[0] != 0) {
+ DBG(DBG_REQSENSE, printk(KERN_DEBUG "Tried to REQUEST SENSE\n"));
+ cmd->result = DID_OK << 16;
+ done(cmd);
+ return(0);
+ }
+#endif
+
/* check for free slot */
for (y = hd->last_ccb + 1, x = 0; x < sh->can_queue; x++, y++) {
if (y >= sh->can_queue)
@@ -378,52+486,19 @@ int eata_queue(Scsi_Cmnd * cmd, void (* done) (Scsi_Cmnd *)) restore_flags(flags);
return(0);
}
- cp = &hd->ccb[y];
+ ccb = &hd->ccb[y];
- memset(cp, 0, sizeof(struct eata_ccb) - sizeof(struct eata_sg_list *));
+ memset(ccb, 0, sizeof(struct eata_ccb) - sizeof(struct eata_sg_list *));
- cp->status = USED; /* claim free slot */
+ ccb->status = USED; /* claim free slot */
DBG(DBG_QUEUE, printk("eata_queue pid %ld, target: %x, lun: %x, y %d\n",
cmd->pid, cmd->target, cmd->lun, y));
- DBG(DBG_QUEUE && DBG_DELAY, DEL2(250));
+ DBG(DBG_QUEUE && DBG_DELAY, DELAY(1));
- if(hd->do_latency == TRUE) {
- int x, z;
- short *sho;
- long *lon;
- x = 0; /* just to keep GCC quiet */
- if (cmd->cmnd[0] == WRITE_6 || cmd->cmnd[0] == WRITE_10 ||
- cmd->cmnd[0] == WRITE_12 || cmd->cmnd[0] == READ_6 ||
- cmd->cmnd[0] == READ_10 || cmd->cmnd[0] == READ_12) {
-
- cp->timestamp = jiffies; /* For latency measurements */
- switch(cmd->cmnd[0]) {
- case WRITE_6:
- case READ_6:
- x = cmd->cmnd[4]/2;
- break;
- case WRITE_10:
- case READ_10:
- sho = (short *) &cmd->cmnd[7];
- x = ntohs(*sho)/2;
- break;
- case WRITE_12:
- case READ_12:
- lon = (long *) &cmd->cmnd[6];
- x = ntohl(*lon)/2;
- break;
- }
+ if(hd->do_latency == TRUE)
+ eata_latency_out(ccb, cmd);
- for(z = 0; (x > (1 << z)) && (z <= 11); z++)
- /* nothing */;
- cp->sizeindex = z;
- if (cmd->cmnd[0] == WRITE_6 || cmd->cmnd[0] == WRITE_10 ||
- cmd->cmnd[0] == WRITE_12){
- cp->rw_latency = TRUE;
- }
- }
- }
cmd->scsi_done = (void *)done;
switch (cmd->cmnd[0]) {
@@ -438,73+513,73 @@ int eata_queue(Scsi_Cmnd * cmd, void (* done) (Scsi_Cmnd *)) case WRITE_12: case WRITE_VERIFY_12: case SET_WINDOW:
case MEDIUM_SCAN: case SEND_VOLUME_TAG:
case 0xea: /* alternate number for WRITE LONG */
- cp->DataOut = TRUE; /* Output mode */
+ ccb->DataOut = TRUE; /* Output mode */
break;
case TEST_UNIT_READY:
default:
- cp->DataIn = TRUE; /* Input mode */
+ ccb->DataIn = TRUE; /* Input mode */
}
/* FIXME: This will will have to be changed once the midlevel driver
* allows different HBA IDs on every channel.
*/
if (cmd->target == sh->this_id)
- cp->Interpret = TRUE; /* Interpret command */
+ ccb->Interpret = TRUE; /* Interpret command */
if (cmd->use_sg) {
- cp->scatter = TRUE; /* SG mode */
- if (cp->sg_list == NULL) {
- cp->sg_list = kmalloc(sh->sg_tablesize * sizeof(struct eata_sg_list),
+ ccb->scatter = TRUE; /* SG mode */
+ if (ccb->sg_list == NULL) {
+ ccb->sg_list = kmalloc(sh->sg_tablesize * sizeof(struct eata_sg_list),
GFP_ATOMIC | GFP_DMA);
}
- if (cp->sg_list == NULL)
+ if (ccb->sg_list == NULL)
panic("eata_dma: Run out of DMA memory for SG lists !\n");
- cp->cp_dataDMA = htonl(virt_to_bus(cp->sg_list));
+ ccb->cp_dataDMA = htonl(virt_to_bus(ccb->sg_list));
- cp->cp_datalen = htonl(cmd->use_sg * sizeof(struct eata_sg_list));
+ ccb->cp_datalen = htonl(cmd->use_sg * sizeof(struct eata_sg_list));
sl=(struct scatterlist *)cmd->request_buffer;
for(i = 0; i < cmd->use_sg; i++, sl++){
- cp->sg_list[i].data = htonl(virt_to_bus(sl->address));
- cp->sg_list[i].len = htonl((u32) sl->length);
+ ccb->sg_list[i].data = htonl(virt_to_bus(sl->address));
+ ccb->sg_list[i].len = htonl((u32) sl->length);
}
} else {
- cp->scatter = FALSE;
- cp->cp_datalen = htonl(cmd->request_bufflen);
- cp->cp_dataDMA = htonl(virt_to_bus(cmd->request_buffer));
+ ccb->scatter = FALSE;
+ ccb->cp_datalen = htonl(cmd->request_bufflen);
+ ccb->cp_dataDMA = htonl(virt_to_bus(cmd->request_buffer));
}
- cp->Auto_Req_Sen = TRUE;
- cp->cp_reqDMA = htonl(virt_to_bus(cmd->sense_buffer));
- cp->reqlen = sizeof(cmd->sense_buffer);
+ ccb->Auto_Req_Sen = TRUE;
+ ccb->cp_reqDMA = htonl(virt_to_bus(cmd->sense_buffer));
+ ccb->reqlen = sizeof(cmd->sense_buffer);
- cp->cp_id = cmd->target;
- cp->cp_channel = cmd->channel;
- cp->cp_lun = cmd->lun;
- cp->cp_dispri = TRUE;
- cp->cp_identify = TRUE;
- memcpy(cp->cp_cdb, cmd->cmnd, cmd->cmd_len);
+ ccb->cp_id = cmd->target;
+ ccb->cp_channel = cmd->channel;
+ ccb->cp_lun = cmd->lun;
+ ccb->cp_dispri = TRUE;
+ ccb->cp_identify = TRUE;
+ memcpy(ccb->cp_cdb, cmd->cmnd, cmd->cmd_len);
- cp->cp_statDMA = htonl(virt_to_bus(&(hd->sp)));
+ ccb->cp_statDMA = htonl(virt_to_bus(&(hd->sp)));
- cp->cp_viraddr = cp; /* This will be passed thru, so we don't need to
+ ccb->cp_viraddr = ccb; /* This will be passed thru, so we don't need to
* convert it */
- cp->cmd = cmd;
+ ccb->cmd = cmd;
cmd->host_scribble = (char *)&hd->ccb[y];
- if(eata_send_command((u32) cp, (u32) sh->base, EATA_CMD_DMA_SEND_CP) == FALSE) {
+ if(eata_send_command((u32) ccb, (u32) sh->base, EATA_CMD_DMA_SEND_CP) == FALSE) {
cmd->result = DID_BUS_BUSY << 16;
DBG(DBG_QUEUE && DBG_ABNORM,
printk("eata_queue target %d, pid %ld, HBA busy, "
"returning DID_BUS_BUSY\n",cmd->target, cmd->pid));
done(cmd);
- cp->status = FREE;
+ ccb->status = FREE;
restore_flags(flags);
return(0);
}
DBG(DBG_QUEUE, printk("Queued base %#.4x pid: %ld target: %x lun: %x "
"slot %d irq %d\n", (s32)sh->base, cmd->pid,
cmd->target, cmd->lun, y, sh->irq));
- DBG(DBG_QUEUE && DBG_DELAY, DEL2(200));
+ DBG(DBG_QUEUE && DBG_DELAY, DELAY(1));
restore_flags(flags);
return(0);
}
@@ -521,26+596,26 @@ int eata_abort(Scsi_Cmnd * cmd) DBG(DBG_ABNORM, printk("eata_abort called pid: %ld target: %x lun: %x"
" reason %x\n", cmd->pid, cmd->target, cmd->lun,
cmd->abort_reason));
- DBG(DBG_ABNORM && DBG_DELAY, DEL2(500));
+ DBG(DBG_ABNORM && DBG_DELAY, DELAY(1));
while (inb((u32)(cmd->host->base) + HA_RAUXSTAT) & HA_ABUSY) {
if (--loop == 0) {
printk("eata_dma: abort, timeout error.\n");
+ DBG(DBG_ABNORM && DBG_DELAY, DELAY(1));
restore_flags(flags);
- DBG(DBG_ABNORM && DBG_DELAY, DEL2(500));
return (SCSI_ABORT_ERROR);
}
}
if (CD(cmd)->status == RESET) {
- restore_flags(flags);
printk("eata_dma: abort, command reset error.\n");
- DBG(DBG_ABNORM && DBG_DELAY, DEL2(500));
+ DBG(DBG_ABNORM && DBG_DELAY, DELAY(1));
+ restore_flags(flags);
return (SCSI_ABORT_ERROR);
}
if (CD(cmd)->status == LOCKED) {
- restore_flags(flags);
DBG(DBG_ABNORM, printk("eata_dma: abort, queue slot locked.\n"));
- DBG(DBG_ABNORM && DBG_DELAY, DEL2(500));
+ DBG(DBG_ABNORM && DBG_DELAY, DELAY(1));
+ restore_flags(flags);
return (SCSI_ABORT_NOT_RUNNING);
}
if (CD(cmd)->status == USED) {
@@ -557,11+632,11 @@ int eata_abort(Scsi_Cmnd * cmd) panic("eata_dma: abort: invalid slot status\n");
}
-int eata_reset(Scsi_Cmnd * cmd, int resetflags)
+int eata_reset(Scsi_Cmnd * cmd, unsigned int resetflags)
{
ushort x, z;
- ulong time, limit = 0;
- ulong loop = R_LIMIT;
+ ulong limit = 0;
+ ulong loop = loops_per_sec / 3;
ulong flags;
unchar success = FALSE;
Scsi_Cmnd *sp;
@@ -576,7+651,7 @@ int eata_reset(Scsi_Cmnd * cmd, int resetflags) if (HD(cmd)->state == RESET) {
printk("eata_reset: exit, already in reset.\n");
restore_flags(flags);
- DBG(DBG_ABNORM && DBG_DELAY, DEL2(500));
+ DBG(DBG_ABNORM && DBG_DELAY, DELAY(1));
return (SCSI_RESET_ERROR);
}
@@ -584,7+659,7 @@ int eata_reset(Scsi_Cmnd * cmd, int resetflags) if (--loop == 0) {
printk("eata_reset: exit, timeout error.\n");
restore_flags(flags);
- DBG(DBG_ABNORM && DBG_DELAY, DEL2(500));
+ DBG(DBG_ABNORM && DBG_DELAY, DELAY(1));
return (SCSI_RESET_ERROR);
}
@@ -602,17+677,17 @@ int eata_reset(Scsi_Cmnd * cmd, int resetflags) if (HD(cmd)->ccb[x].status == LOCKED) {
HD(cmd)->ccb[x].status = FREE;
printk("eata_reset: locked slot %d forced free.\n", x);
- DBG(DBG_ABNORM && DBG_DELAY, DEL2(500));
+ DBG(DBG_ABNORM && DBG_DELAY, DELAY(1));
continue;
}
sp = HD(cmd)->ccb[x].cmd;
HD(cmd)->ccb[x].status = RESET;
printk("eata_reset: slot %d in reset, pid %ld.\n", x, sp->pid);
- DBG(DBG_ABNORM && DBG_DELAY, DEL2(500));
+ DBG(DBG_ABNORM && DBG_DELAY, DELAY(1));
if (sp == NULL)
panic("eata_reset: slot %d, sp==NULL.\n", x);
- DBG(DBG_ABNORM && DBG_DELAY, DEL2(500));
+ DBG(DBG_ABNORM && DBG_DELAY, DELAY(1));
if (sp == cmd)
success = TRUE;
@@ -624,19+699,12 @@ int eata_reset(Scsi_Cmnd * cmd, int resetflags)
DBG(DBG_ABNORM, printk("eata_reset: board reset done, enabling interrupts.\n"));
HD(cmd)->state = RESET;
-
- restore_flags(flags);
-
- time = jiffies;
- while (jiffies < (time + (3 * HZ)) || limit++ < 10000000)
- /* As time goes by... */;
-
- save_flags(flags);
- cli();
+
+ DELAY(1);
DBG(DBG_ABNORM, printk("eata_reset: interrupts disabled, loops %ld.\n",
limit));
- DBG(DBG_ABNORM && DBG_DELAY, DEL2(500));
+ DBG(DBG_ABNORM && DBG_DELAY, DELAY(1));
for (x = 0; x < cmd->host->can_queue; x++) {
@@ -652,10+720,9 @@ int eata_reset(Scsi_Cmnd * cmd, int resetflags)
printk("eata_reset: slot %d locked, DID_RESET, pid %ld done.\n",
x, sp->pid);
- DBG(DBG_ABNORM && DBG_DELAY, DEL2(500));
- restore_flags(flags);
+ DBG(DBG_ABNORM && DBG_DELAY, DELAY(1));
+
sp->scsi_done(sp);
- cli();
}
HD(cmd)->state = FALSE;
@@ -663,11+730,11 @@ int eata_reset(Scsi_Cmnd * cmd, int resetflags)
if (success) {
DBG(DBG_ABNORM, printk("eata_reset: exit, success.\n"));
- DBG(DBG_ABNORM && DBG_DELAY, DEL2(500));
+ DBG(DBG_ABNORM && DBG_DELAY, DELAY(1));
return (SCSI_RESET_SUCCESS);
} else {
DBG(DBG_ABNORM, printk("eata_reset: exit, wakeup.\n"));
- DBG(DBG_ABNORM && DBG_DELAY, DEL2(500));
+ DBG(DBG_ABNORM && DBG_DELAY, DELAY(1));
return (SCSI_RESET_PUNT);
}
}
@@ -677,7+744,8 @@ int eata_reset(Scsi_Cmnd * cmd, int resetflags) *
* At the moment the algorithm is rather simple
*/
-static void eata_select_queue_depths(struct Scsi_Host *host, Scsi_Device *devicelist)
+static void eata_select_queue_depths(struct Scsi_Host *host,
+ Scsi_Device *devicelist)
{
Scsi_Device *device;
int devcount = 0;
@@ -745,13+813,34 @@ static void eata_select_queue_depths(struct Scsi_Host *host, Scsi_Device *device } else /* ISA forces us to limit the QS because of bounce buffers*/
device->queue_depth = 2; /* I know this is cruel */
- printk(KERN_INFO "scsi%d: queue depth for target %d on channel %d set "
- "to %d\n", host->host_no, device->id, device->channel,
+ printk(KERN_INFO "scsi%d: queue depth for target %d on channel %d "
+ "set to %d\n", host->host_no, device->id, device->channel,
device->queue_depth);
}
}
}
+int check_blink_state(long base)
+{
+ ushort loops = 10;
+ u32 blinkindicator;
+ u32 state = 0x12345678;
+ u32 oldstate = 0;
+
+ blinkindicator = htonl(0x54504442);
+ while ((loops--) && (state != oldstate)) {
+ oldstate = state;
+ state = inl((uint) base + 1);
+ }
+
+ DBG(DBG_BLINK, printk("Did Blink check. Status: %d\n",
+ (state == oldstate) && (state == blinkindicator)));
+
+ if ((state == oldstate) && (state == blinkindicator))
+ return(TRUE);
+ else
+ return (FALSE);
+}
char * get_board_data(u32 base, u32 irq, u32 id)
{
@@ -802,8+891,8 @@ char * get_board_data(u32 base, u32 irq, u32 id) while (fake_int_happened == FALSE && jiffies <= i)
barrier();
- DBG(DBG_INTR3, printk("fake_int_result: %#x hbastat %#x scsistat %#x,"
- " buff %p sp %p\n",
+ DBG(DBG_INTR3, printk(KERN_DEBUG "fake_int_result: %#x hbastat %#x "
+ "scsistat %#x, buff %p sp %p\n",
fake_int_result, (u32) (sp->hba_stat /*& 0x7f*/),
(u32) sp->scsi_stat, buff, sp));
@@ -811,38+900,17 @@ char * get_board_data(u32 base, u32 irq, u32 id) scsi_init_free((void *)sp, sizeof(struct eata_sp));
if ((fake_int_result & HA_SERROR) || jiffies > i){
+ printk(KERN_WARNING "eata_dma: trying to reset HBA at %x to clear "
+ "possible blink state\n", base);
/* hard reset the HBA */
inb((u32) (base) + HA_RSTATUS);
eata_send_command(0, base, EATA_CMD_RESET);
- i = jiffies;
- while (jiffies < (i + (3 * HZ)) && limit++ < 10000000)
- barrier();
+ DELAY(1);
return (NULL);
} else
return (buff);
}
-
-int check_blink_state(long base)
-{
- ushort loops = 10;
- u32 blinkindicator;
- u32 state = 0x12345678;
- u32 oldstate = 0;
-
- blinkindicator = htonl(0x54504442);
- while ((loops--) && (state != oldstate)) {
- oldstate = state;
- state = inl((uint) base + 1);
- }
-
- DBG(DBG_BLINK, printk("Did Blink check. Status: %d\n",
- (state == oldstate) && (state == blinkindicator)));
- if ((state == oldstate) && (state == blinkindicator))
- return(TRUE);
- else
- return (FALSE);
-}
int get_conf_PIO(u32 base, struct get_conf *buf)
{
@@ -857,6+925,10 @@ int get_conf_PIO(u32 base, struct get_conf *buf) while (inb(base + HA_RSTATUS) & HA_SBUSY)
if (--loop == 0)
return (FALSE);
+
+ fake_int_base = (struct eata_register *) base;
+ fake_int_result = FALSE;
+ fake_int_happened = FALSE;
DBG(DBG_PIO && DBG_PROBE,
printk("Issuing PIO READ CONFIG to HBA at %#x\n", base));
@@ -890,6+962,7 @@ int get_conf_PIO(u32 base, struct get_conf *buf) return (FALSE);
}
+
void print_config(struct get_conf *gc)
{
printk("LEN: %d ver:%d OCS:%d TAR:%d TRNXFR:%d MORES:%d DMAS:%d\n",
@@ -929,7+1002,7 @@ short register_HBA(u32 base, struct get_conf *gc, Scsi_Host_Template * tpnt, }
if(gc->HAA_valid == FALSE || ntohl(gc->len) < 0x22)
gc->MAX_CHAN = 0;
-
+
if (reg_IRQ[gc->IRQ] == FALSE) { /* Interrupt already registered ? */
if (!request_irq(gc->IRQ, (void *) eata_fake_int_handler, SA_INTERRUPT,
"eata_dma", NULL)){
@@ -948,13+1021,27 @@ short register_HBA(u32 base, struct get_conf *gc, Scsi_Host_Template * tpnt, } else
reg_IRQ[gc->IRQ]++;
}
-
+
+
+ /* If DMA is supported but DMA_valid isn't set to indicate that
+ * the channel number is given we must have pre 2.0 firmware (1.7?)
+ * which leaves us to guess since the "newer ones" also don't set the
+ * DMA_valid bit.
+ */
+ if (gc->DMA_support && !gc->DMA_valid && gc->DMA_channel) {
+ printk(KERN_WARNING "eata_dma: If you are using a pre 2.0 firmware "
+ "please update it !\n"
+ " You can get new firmware releases from ftp.dpt.com\n");
+ gc->DMA_channel = (base == 0x1f0 ? 3 /* DMA=5 */ : 2 /* DMA=6 */);
+ gc->DMA_valid = TRUE;
+ }
+
/* if gc->DMA_valid it must be an ISA HBA and we have to register it */
dma_channel = BUSMASTER;
if (gc->DMA_valid) {
if (request_dma(dma_channel = (8 - gc->DMA_channel) & 7, "eata_dma")) {
- printk("Unable to allocate DMA channel %d for ISA HBA at %#.4x.\n",
- dma_channel, base);
+ printk(KERN_WARNING "Unable to allocate DMA channel %d for ISA HBA"
+ " at %#.4x.\n", dma_channel, base);
reg_IRQ[gc->IRQ]--;
if (reg_IRQ[gc->IRQ] == 0)
free_irq(gc->IRQ, NULL);
@@ -963,23+1050,27 @@ short register_HBA(u32 base, struct get_conf *gc, Scsi_Host_Template * tpnt, return (FALSE);
}
}
-
-#if !(NEWSTUFF)
+
+ if (dma_channel != BUSMASTER) {
+ disable_dma(dma_channel);
+ clear_dma_ff(dma_channel);
+ set_dma_mode(dma_channel, DMA_MODE_CASCADE);
+ enable_dma(dma_channel);
+ }
+
if (bustype != IS_EISA && bustype != IS_ISA)
-#endif
buff = get_board_data(base, gc->IRQ, gc->scsi_id[3]);
if (buff == NULL) {
-#if !(NEWSTUFF)
if (bustype == IS_EISA || bustype == IS_ISA) {
bugs = bugs || BROKEN_INQUIRY;
} else {
-#endif
if (gc->DMA_support == FALSE)
- printk("HBA at %#.4x doesn't support DMA. Sorry\n", base);
+ printk(KERN_WARNING "HBA at %#.4x doesn't support DMA. "
+ "Sorry\n", base);
else
- printk("HBA at %#.4x does not react on INQUIRY. Sorry.\n",
- base);
+ printk(KERN_WARNING "HBA at %#.4x does not react on INQUIRY. "
+ "Sorry.\n", base);
if (gc->DMA_valid)
free_dma(dma_channel);
reg_IRQ[gc->IRQ]--;
@@ -988,14+1079,12 @@ short register_HBA(u32 base, struct get_conf *gc, Scsi_Host_Template * tpnt, if (gc->IRQ_TR == FALSE)
reg_IRQL[gc->IRQ] = FALSE;
return (FALSE);
-#if !(NEWSTUFF)
}
-#endif
}
-
+
if (gc->DMA_support == FALSE && buff != NULL)
- printk("HBA %.12sat %#.4x doesn't set the DMA_support flag correctly.\n",
- &buff[16], base);
+ printk(KERN_WARNING "HBA %.12sat %#.4x doesn't set the DMA_support "
+ "flag correctly.\n", &buff[16], base);
request_region(base, 9, "eata_dma"); /* We already checked the
* availability, so this
@@ -1004,8+1093,10 @@ short register_HBA(u32 base, struct get_conf *gc, Scsi_Host_Template * tpnt,
if(ntohs(gc->queuesiz) == 0) {
gc->queuesiz = ntohs(64);
- printk("Warning: Queue size has to be corrected. Assuming 64 queueslots\n"
- " This might be a PM2012B with a defective Firmware\n");
+ printk(KERN_WARNING "Warning: Queue size has to be corrected. Assuming"
+ " 64 queueslots\n"
+ " This might be a PM2012B with a defective Firmware\n"
+ " Contact DPT support@dpt.com for an upgrade\n");
}
size = sizeof(hostdata) + ((sizeof(struct eata_ccb) + sizeof(long))
@@ -1015,7+1106,45 @@ short register_HBA(u32 base, struct get_conf *gc, Scsi_Host_Template * tpnt,
sh = scsi_register(tpnt, size);
- if(sh == NULL) {
+ if(sh != NULL) {
+
+ hd = SD(sh);
+
+ memset(hd->reads, 0, sizeof(u32) * 26);
+
+ sh->select_queue_depths = eata_select_queue_depths;
+
+ hd->bustype = bustype;
+
+ /*
+ * If we are using a ISA board, we can't use extended SG,
+ * because we would need exessive amounts of memory for
+ * bounce buffers.
+ */
+ if (gc->SG_64K==TRUE && ntohs(gc->SGsiz)==64 && hd->bustype!=IS_ISA){
+ sh->sg_tablesize = SG_SIZE_BIG;
+ } else {
+ sh->sg_tablesize = ntohs(gc->SGsiz);
+ if (sh->sg_tablesize > SG_SIZE || sh->sg_tablesize == 0) {
+ if (sh->sg_tablesize == 0)
+ printk(KERN_WARNING "Warning: SG size had to be fixed.\n"
+ "This might be a PM2012 with a defective Firmware"
+ "\nContact DPT support@dpt.com for an upgrade\n");
+ sh->sg_tablesize = SG_SIZE;
+ }
+ }
+ hd->sgsize = sh->sg_tablesize;
+ }
+
+ if(sh != NULL) {
+ sh->can_queue = hd->queuesize = ntohs(gc->queuesiz);
+ sh->cmd_per_lun = 0;
+ }
+
+ if(sh == NULL) {
+ DBG(DBG_REGISTER, printk(KERN_NOTICE "eata_dma: couldn't register HBA"
+ " at%x \n", base));
+ scsi_unregister(sh);
if (gc->DMA_valid)
free_dma(dma_channel);
@@ -1026,64+1155,52 @@ short register_HBA(u32 base, struct get_conf *gc, Scsi_Host_Template * tpnt, reg_IRQL[gc->IRQ] = FALSE;
return (FALSE);
}
-
- hd = SD(sh);
-
- memset(hd->ccb, 0, sizeof(struct eata_ccb) * ntohs(gc->queuesiz));
- memset(hd->reads, 0, sizeof(u32) * 26);
+
hd->broken_INQUIRY = (bugs & BROKEN_INQUIRY);
if(hd->broken_INQUIRY == TRUE) {
- strcpy(SD(sh)->vendor, "DPT");
- strcpy(SD(sh)->name, "??????????");
- strcpy(SD(sh)->revision, "???.?");
+ strcpy(hd->vendor, "DPT");
+ strcpy(hd->name, "??????????");
+ strcpy(hd->revision, "???.?");
+ hd->firmware_revision = 0;
} else {
- strncpy(SD(sh)->vendor, &buff[8], 8);
- SD(sh)->vendor[8] = 0;
- strncpy(SD(sh)->name, &buff[16], 17);
- SD(sh)->name[17] = 0;
- SD(sh)->revision[0] = buff[32];
- SD(sh)->revision[1] = buff[33];
- SD(sh)->revision[2] = buff[34];
- SD(sh)->revision[3] = '.';
- SD(sh)->revision[4] = buff[35];
- SD(sh)->revision[5] = 0;
+ strncpy(hd->vendor, &buff[8], 8);
+ hd->vendor[8] = 0;
+ strncpy(hd->name, &buff[16], 17);
+ hd->name[17] = 0;
+ hd->revision[0] = buff[32];
+ hd->revision[1] = buff[33];
+ hd->revision[2] = buff[34];
+ hd->revision[3] = '.';
+ hd->revision[4] = buff[35];
+ hd->revision[5] = 0;
+ hd->firmware_revision = (buff[32] << 24) + (buff[33] << 16)
+ + (buff[34] << 8) + buff[35];
}
+ if (hd->firmware_revision >= (('0'<<24) + ('7'<<16) + ('G'<< 8) + '0'))
+ hd->immediate_support = 1;
+ else
+ hd->immediate_support = 0;
+
switch (ntohl(gc->len)) {
case 0x1c:
- SD(sh)->EATA_revision = 'a';
+ hd->EATA_revision = 'a';
break;
case 0x1e:
- SD(sh)->EATA_revision = 'b';
+ hd->EATA_revision = 'b';
break;
case 0x22:
- SD(sh)->EATA_revision = 'c';
+ hd->EATA_revision = 'c';
break;
case 0x24:
- SD(sh)->EATA_revision = 'z';
+ hd->EATA_revision = 'z';
default:
- SD(sh)->EATA_revision = '?';
+ hd->EATA_revision = '?';
}
- if(ntohl(gc->len) >= 0x22) {
- if (gc->is_PCI == TRUE)
- hd->bustype = IS_PCI;
- else if (gc->is_EISA == TRUE)
- hd->bustype = IS_EISA;
- else
- hd->bustype = IS_ISA;
- } else if(hd->broken_INQUIRY == FALSE) {
- if (buff[21] == '4')
- hd->bustype = IS_PCI;
- else if (buff[21] == '2')
- hd->bustype = IS_EISA;
- else
- hd->bustype = IS_ISA;
- } else
- hd->bustype = bustype;
-
+
if(ntohl(gc->len) >= 0x22) {
sh->max_id = gc->MAX_ID + 1;
sh->max_lun = gc->MAX_LUN + 1;
@@ -1092,6+1209,7 @@ short register_HBA(u32 base, struct get_conf *gc, Scsi_Host_Template * tpnt, sh->max_lun = 8;
}
+ hd->HBA_number = sh->host_no;
hd->channel = gc->MAX_CHAN;
sh->max_channel = gc->MAX_CHAN;
sh->unique_id = base;
@@ -1105,34+1223,7 @@ short register_HBA(u32 base, struct get_conf *gc, Scsi_Host_Template * tpnt, * SCSI midlevel code should support different HBA ids on every channel
*/
sh->this_id = gc->scsi_id[3];
-
- hd->queuesize = ntohs(gc->queuesiz);
- sh->can_queue = ntohs(gc->queuesiz);
- sh->cmd_per_lun = 0;
- sh->select_queue_depths = eata_select_queue_depths;
- /* FIXME:
- * SG should be allocated more dynamically
- */
- /*
- * If we are using a ISA board, we can't use extended SG,
- * because we would need excessive amounts of memory for
- * bounce buffers.
- */
- if (gc->SG_64K == TRUE && ntohs(gc->SGsiz) == 64 && hd->bustype != IS_ISA){
- sh->sg_tablesize = SG_SIZE_BIG;
- sh->use_clustering = TRUE;
- } else {
- sh->sg_tablesize = ntohs(gc->SGsiz);
- sh->use_clustering = TRUE;
- if (sh->sg_tablesize > SG_SIZE || sh->sg_tablesize == 0) {
- sh->sg_tablesize = SG_SIZE;
- if (ntohs(gc->SGsiz) == 0)
- printk("Warning: SG size had to be corrected.\n"
- "This might be a PM2012 with a defective Firmware\n");
- }
- }
-
if (gc->SECOND)
hd->primary = FALSE;
else
@@ -1150,6+1241,7 @@ short register_HBA(u32 base, struct get_conf *gc, Scsi_Host_Template * tpnt, hd->writes_lat[x][1] = 0xffffffff;
hd->reads_lat[x][1] = 0xffffffff;
}
+ hd->all_lat[1] = 0xffffffff;
hd->next = NULL; /* build a linked list of all HBAs */
hd->prev = last_HBA;
@@ -1164,6+1256,7 @@ short register_HBA(u32 base, struct get_conf *gc, Scsi_Host_Template * tpnt, }
+
void find_EISA(struct get_conf *buf, Scsi_Host_Template * tpnt)
{
u32 base;
@@ -1320,7+1413,7 @@ void find_PCI(struct get_conf *buf, Scsi_Host_Template * tpnt) continue; /* break; */
} else if (check_blink_state(base) == TRUE) {
printk("eata_dma: HBA is in BLINK state.\n"
- "Consult your HBAs Manual to correct this.\n");
+ "Consult your HBAs manual to correct this.\n");
}
}
}
@@ -1350,13+1443,15 @@ int eata_detect(Scsi_Host_Template * tpnt) tpnt->proc_dir = &proc_scsi_eata_dma;
status = scsi_init_malloc(512, GFP_ATOMIC | GFP_DMA);
- dma_scratch = scsi_init_malloc(512, GFP_ATOMIC | GFP_DMA);
+ dma_scratch = scsi_init_malloc(1024, GFP_ATOMIC | GFP_DMA);
if(status == NULL || dma_scratch == NULL) {
printk("eata_dma: can't allocate enough memory to probe for hosts !\n");
return(0);
}
+ dma_scratch += 4;
+
find_PCI(&gc, tpnt);
find_EISA(&gc, tpnt);
@@ -1364,41+1459,45 @@ int eata_detect(Scsi_Host_Template * tpnt) find_ISA(&gc, tpnt);
for (i = 0; i <= MAXIRQ; i++) { /* Now that we know what we have, we */
- if (reg_IRQ[i]){ /* exchange the interrupt handler which */
+ if (reg_IRQ[i] >= 1){ /* exchange the interrupt handler which */
free_irq(i, NULL); /* we used for probing with the real one */
- request_irq(i, (void *)(eata_int_handler), SA_INTERRUPT, "eata_dma", NULL);
+ request_irq(i, (void *)(eata_int_handler), SA_INTERRUPT,
+ "eata_dma", NULL);
}
}
+
HBA_ptr = first_HBA;
-
+
if (registered_HBAs != 0) {
- printk("EATA (Extended Attachment) driver version: %d.%d%s\n"
- "developed in co-operation with DPT\n"
- "(c) 1993-95 Michael Neuffer, neuffer@goofy.zdv.uni-mainz.de\n",
- VER_MAJOR, VER_MINOR, VER_SUB);
- printk("Registered HBAs:");
- printk("\nHBA no. Boardtype: Revis: EATA: Bus: BaseIO: IRQ: DMA: Ch: "
- "ID: Pr: QS: SG: CPL:\n");
- for (i = 1; i <= registered_HBAs; i++) {
- printk("scsi%-2d: %.10s v%s 2.0%c %s %#.4x %2d",
+ printk("EATA (Extended Attachment) driver version: %d.%d%s"
+ "\ndeveloped in co-operation with DPT\n"
+ "(c) 1993-96 Michael Neuffer, mike@i-Connect.Net\n",
+ VER_MAJOR, VER_MINOR, VER_SUB);
+ printk("Registered HBAs:");
+ printk("\nHBA no. Boardtype Revis EATA Bus BaseIO IRQ"
+ " DMA Ch ID Pr QS S/G IS\n");
+ for (i = 1; i <= registered_HBAs; i++) {
+ printk("scsi%-2d: %.12s v%s 2.0%c %s %#.4x %2d",
HBA_ptr->host_no, SD(HBA_ptr)->name, SD(HBA_ptr)->revision,
SD(HBA_ptr)->EATA_revision, (SD(HBA_ptr)->bustype == 'P')?
"PCI ":(SD(HBA_ptr)->bustype == 'E')?"EISA":"ISA ",
(u32) HBA_ptr->base, HBA_ptr->irq);
if(HBA_ptr->dma_channel != BUSMASTER)
- printk(" %2x ", HBA_ptr->dma_channel);
+ printk(" %2x ", HBA_ptr->dma_channel);
else
- printk(" %s", "BMST");
- printk(" %d %d %c %2d %2d %2d\n", SD(HBA_ptr)->channel,
- HBA_ptr->this_id, (SD(HBA_ptr)->primary == TRUE)?'Y':'N',
- HBA_ptr->can_queue, HBA_ptr->sg_tablesize, HBA_ptr->cmd_per_lun);
+ printk(" %s", "BMST");
+ printk(" %d %d %c %3d %3d %c\n",
+ SD(HBA_ptr)->channel+1, HBA_ptr->this_id,
+ (SD(HBA_ptr)->primary == TRUE)?'Y':'N',
+ HBA_ptr->can_queue, HBA_ptr->sg_tablesize,
+ (SD(HBA_ptr)->immediate_support == TRUE)?'Y':'N');
HBA_ptr = SD(HBA_ptr)->next;
}
} else {
scsi_init_free((void *)status, 512);
}
- scsi_init_free((void *)dma_scratch, 512);
+ scsi_init_free((void *)dma_scratch - 4, 1024);
DBG(DPT_DEBUG, DELAY(12));
/********************************************************
* Header file for eata_dma.c Linux EATA-DMA SCSI driver *
-* (c) 1993,94,95 Michael Neuffer *
+* (c) 1993-96 Michael Neuffer *
+* mike@i-Connect.Net *
+* neuffer@mail.uni-mainz.de *
*********************************************************
-* last change: 95/07/18 *
+* last change: 96/05/05 *
********************************************************/
-
#ifndef _EATA_DMA_H
#define _EATA_DMA_H
#define VER_MAJOR 2
#define VER_MINOR 5
-#define VER_SUB "8a"
+#define VER_SUB "8d"
/************************************************************************
#define DBG_INTR 0 /* Trace interrupt service routine. */
#define DBG_INTR2 0 /* Trace interrupt service routine. */
#define DBG_INTR3 0 /* Trace get_board_data interrupts. */
+#define DBG_REQSENSE 0 /* Trace request sense commands */
+#define DBG_RESET 0 /* Trace reset calls */
+#define DBG_STATUS 0 /* Trace status generation */
#define DBG_PROC 0 /* Debug proc-fs related statistics */
#define DBG_PROC_WRITE 0
#define DBG_REGISTER 0 /* */
@@ -65,7+69,7 @@ const char *eata_info(struct Scsi_Host *); int eata_command(Scsi_Cmnd *);
int eata_queue(Scsi_Cmnd *, void (* done)(Scsi_Cmnd *));
int eata_abort(Scsi_Cmnd *);
-int eata_reset(Scsi_Cmnd *);
+int eata_reset(Scsi_Cmnd *, unsigned int);
int eata_proc_info(char *, char **, off_t, int, int, int);
#ifdef MODULE
int eata_release(struct Scsi_Host *);
/********************************************************
* Header file for eata_dma.c and eata_pio.c *
* Linux EATA SCSI drivers *
-* (c) 1993,94,95 Michael Neuffer *
+* (c) 1993-96 Michael Neuffer *
+* mike@i-Connect.Net *
+* neuffer@mail.uni-mainz.de *
*********************************************************
-* last change: 95/11/07 *
+* last change: 95/05/05 *
********************************************************/
#define NEC_ID2 0xa3
#define NEC_ID3 0x82
+
+#define EATA_CP_SIZE 44
-#define EATA_CP_SIZE 44
-
-#define MAX_PCI_DEVICES 32 /* Maximum # Of Devices Per Bus */
-#define MAX_METHOD_2 16 /* Max Devices For Method 2 */
-#define MAX_PCI_BUS 16 /* Maximum # Of Busses Allowed */
+#define MAX_PCI_DEVICES 32 /* Maximum # Of Devices Per Bus */
+#define MAX_METHOD_2 16 /* Max Devices For Method 2 */
+#define MAX_PCI_BUS 16 /* Maximum # Of Busses Allowed */
-#define SG_SIZE 64
-#define SG_SIZE_BIG 252 /* max. 8096 elements, 64k */
+#define SG_SIZE 64
+#define SG_SIZE_BIG 252 /* max. 8096 elements, 64k */
#define TYPE_DISK_QUEUE 16
#define TYPE_TAPE_QUEUE 4
#define TYPE_ROM_QUEUE 4
#define TYPE_OTHER_QUEUE 2
-#define FREE 0
-#define OK 0
-#define NO_TIMEOUT 0
-#define USED 1
-#define TIMEOUT 2
-#define RESET 4
-#define LOCKED 8
+#define FREE 0
+#define OK 0
+#define NO_TIMEOUT 0
+#define USED 1
+#define TIMEOUT 2
+#define RESET 4
+#define LOCKED 8
+#define ABORTED 16
+
+#define READ 0
+#define WRITE 1
+#define OTHER 2
#define HD(cmd) ((hostdata *)&(cmd->host->hostdata))
#define CD(cmd) ((struct eata_ccb *)(cmd->host_scribble))
#define SD(host) ((hostdata *)&(host->hostdata))
-#define DELAY(x) { __u32 i; i = jiffies + (x * HZ); while (jiffies < i) barrier(); }
-#define DEL2(x) { __u32 i; for (i = 0; i < 0xffff * x; i++); }
+#define DELAY(x) { __u32 i; ulong flags; \
+ save_flags(flags); sti(); \
+ i = jiffies + (x * HZ); \
+ while (jiffies < i) barrier(); \
+ restore_flags(flags); }
/***********************************************
* EATA Command & Register definitions *
#define HA_WCOMMAND 0x07 /* command register offset */
-#define HA_WCOMMAND2 0x06 /* immediate command offset */
-#define HA_WSUBCODE 0x05
-#define HA_WSUBLUN 0x04
+#define HA_WIFC 0x06 /* immediate command offset */
+#define HA_WCODE 0x05
+#define HA_WCODE2 0x04
#define HA_WDMAADDR 0x02 /* DMA address LSB offset */
#define HA_RAUXSTAT 0x08 /* aux status register offset*/
#define HA_RSTATUS 0x07 /* status register offset */
#define HA_RDATA 0x00 /* data register (16bit) */
+#define HA_WDATA 0x00 /* data register (16bit) */
#define HA_ABUSY 0x01 /* aux busy bit */
#define HA_AIRQ 0x02 /* aux IRQ pending bit */
#define HA_NO_ERROR 0x00 /* No Error */
#define HA_ERR_SEL_TO 0x01 /* Selection Timeout */
#define HA_ERR_CMD_TO 0x02 /* Command Timeout */
-#define HA_ERR_RESET 0x03 /* SCSI Bus Reset Received */
+#define HA_BUS_RESET 0x03 /* SCSI Bus Reset Received */
#define HA_INIT_POWERUP 0x04 /* Initial Controller Power-up */
#define HA_UNX_BUSPHASE 0x05 /* Unexpected Bus Phase */
#define HA_UNX_BUS_FREE 0x06 /* Unexpected Bus Free */
@@ -247,7+258,8 @@ struct get_conf { /* Read Configuration Array */ ID_qest:1, /* Raidnum ID is questionable */
is_PCI:1, /* HBA is PCI */
is_EISA:1; /* HBA is EISA */
- __u8 unused[478];
+ __u8 RAIDNUM; /* unique HBA identifier */
+ __u8 unused[474];
};
struct eata_sg_list
@@ -322,27+334,34 @@ typedef struct hstd { __u8 name[18];
__u8 revision[6];
__u8 EATA_revision;
+ __u32 firmware_revision;
+ __u8 HBA_number;
__u8 bustype; /* bustype of HBA */
__u8 channel; /* # of avail. scsi channels */
__u8 state; /* state of HBA */
__u8 primary; /* true if primary */
- __u8 broken_INQUIRY:1; /* This is an EISA HBA with *
+ __u8 more_support:1, /* HBA supports MORE flag */
+ immediate_support:1, /* HBA supports IMMEDIATE CMDs*/
+ broken_INQUIRY:1; /* This is an EISA HBA with *
* broken INQUIRY */
__u8 do_latency; /* Latency measurement flag */
__u32 reads[13];
__u32 writes[13];
__u32 reads_lat[12][4];
__u32 writes_lat[12][4];
+ __u32 all_lat[4];
/* state of Target (RESET,..) */
__u8 t_state[MAXCHANNEL][MAXTARGET];
/* timeouts on target */
__u32 t_timeout[MAXCHANNEL][MAXTARGET];
+ __u8 resetlevel[MAXCHANNEL];
__u32 last_ccb; /* Last used ccb */
__u32 cplen; /* size of CP in words */
__u16 cppadlen; /* pad length of cp in words */
- int queuesize;
+ __u16 queuesize;
+ __u16 sgsize; /* # of entries in the SG list*/
+ __u16 devflags; /* bits set for detected devices */
__u8 hostid; /* SCSI ID of HBA */
- __u8 devflags; /* bits set for detected devices */
__u8 moresupport; /* HBA supports MORE flag */
struct Scsi_Host *next;
struct Scsi_Host *prev;
@@ -242,7+242,7 @@ void eata_pio_int_handler(int irq, void *dev_id, struct pt_regs * regs) eata_stat = inb(base + HA_RSTATUS);
printk(KERN_NOTICE "eata_pio: int_handler, freeing locked "
"queueslot\n");
- DBG(DBG_INTR&&DBG_DELAY,DEL2(800));
+ DBG(DBG_INTR&&DBG_DELAY,DELAY(1));
restore_flags(flags);
return;
}
@@ -251,7+251,7 @@ void eata_pio_int_handler(int irq, void *dev_id, struct pt_regs * regs) if (stat != 0x50)
printk(KERN_DEBUG "stat: %#.2x, result: %#.8x\n", stat,
cmd->result);
- DBG(DBG_INTR&&DBG_DELAY,DEL2(800));
+ DBG(DBG_INTR&&DBG_DELAY,DELAY(1));
#endif
cp->status = FREE; /* now we can release the slot */
@@ -322,7+322,7 @@ int eata_pio_queue(Scsi_Cmnd * cmd, void (*done) (Scsi_Cmnd *))
DBG(DBG_QUEUE, printk(KERN_DEBUG "eata_pio_queue pid %ld, target: %x, lun:"
" %x, y %d\n", cmd->pid, cmd->target, cmd->lun, y));
- DBG(DBG_QUEUE && DBG_DELAY, DEL2(250));
+ DBG(DBG_QUEUE && DBG_DELAY, DELAY(1));
cmd->scsi_done = (void *)done;
@@ -396,7+396,7 @@ int eata_pio_queue(Scsi_Cmnd * cmd, void (*done) (Scsi_Cmnd *)) DBG(DBG_QUEUE,printk(KERN_DEBUG "Queued base %#.4lx pid: %ld target: %x "
"lun: %x slot %d irq %d\n", (long)sh->base, cmd->pid,
cmd->target, cmd->lun, y, sh->irq));
- DBG(DBG_QUEUE && DBG_DELAY, DEL2(200));
+ DBG(DBG_QUEUE && DBG_DELAY, DELAY(1));
restore_flags(flags);
return (0);
@@ -413,14+413,14 @@ int eata_pio_abort(Scsi_Cmnd * cmd) DBG(DBG_ABNORM, printk(KERN_WARNING "eata_pio_abort called pid: %ld "
"target: %x lun: %x reason %x\n", cmd->pid,
cmd->target, cmd->lun, cmd->abort_reason));
- DBG(DBG_ABNORM && DBG_DELAY, DEL2(500));
+ DBG(DBG_ABNORM && DBG_DELAY, DELAY(1));
while (inb((uint)(cmd->host->base) + HA_RAUXSTAT) & HA_ABUSY)
if (--loop == 0) {
printk(KERN_WARNING "eata_pio: abort, timeout error.\n");
restore_flags(flags);
- DBG(DBG_ABNORM && DBG_DELAY, DEL2(500));
+ DBG(DBG_ABNORM && DBG_DELAY, DELAY(1));
return (SCSI_ABORT_ERROR);
}
if (CD(cmd)->status == FREE) {
@@ -436,21+436,21 @@ int eata_pio_abort(Scsi_Cmnd * cmd) if (CD(cmd)->status == RESET) {
restore_flags(flags);
printk(KERN_WARNING "eata_pio: abort, command reset error.\n");
- DBG(DBG_ABNORM && DBG_DELAY, DEL2(500));
+ DBG(DBG_ABNORM && DBG_DELAY, DELAY(1));
return (SCSI_ABORT_ERROR);
}
if (CD(cmd)->status == LOCKED) {
restore_flags(flags);
DBG(DBG_ABNORM, printk(KERN_WARNING "eata_pio: abort, queue slot "
"locked.\n"));
- DBG(DBG_ABNORM && DBG_DELAY, DEL2(500));
+ DBG(DBG_ABNORM && DBG_DELAY, DELAY(1));
return (SCSI_ABORT_NOT_RUNNING);
}
restore_flags(flags);
panic("eata_pio: abort: invalid slot status\n");
}
-int eata_pio_reset(Scsi_Cmnd * cmd, int dummy)
+int eata_pio_reset(Scsi_Cmnd * cmd, unsigned int dummy)
{
uint x, z, time, limit = 0;
ulong flags;
@@ -467,7+467,7 @@ int eata_pio_reset(Scsi_Cmnd * cmd, int dummy) if (HD(cmd)->state == RESET) {
printk(KERN_WARNING "eata_pio_reset: exit, already in reset.\n");
restore_flags(flags);
- DBG(DBG_ABNORM && DBG_DELAY, DEL2(500));
+ DBG(DBG_ABNORM && DBG_DELAY, DELAY(1));
return (SCSI_RESET_ERROR);
}
@@ -487,11+487,11 @@ int eata_pio_reset(Scsi_Cmnd * cmd, int dummy) HD(cmd)->ccb[x].status = RESET;
printk(KERN_WARNING "eata_pio_reset: slot %d in reset, pid %ld.\n", x,
sp->pid);
- DBG(DBG_ABNORM && DBG_DELAY, DEL2(500));
+ DBG(DBG_ABNORM && DBG_DELAY, DELAY(1));
if (sp == NULL)
panic("eata_pio_reset: slot %d, sp==NULL.\n", x);
- DBG(DBG_ABNORM && DBG_DELAY, DEL2(500));
+ DBG(DBG_ABNORM && DBG_DELAY, DELAY(1));
}
/* hard reset the HBA */
@@ -505,7+505,7 @@ int eata_pio_reset(Scsi_Cmnd * cmd, int dummy)
DBG(DBG_ABNORM, printk(KERN_WARNING "eata_pio_reset: interrupts disabled, "
"loops %d.\n", limit));
- DBG(DBG_ABNORM && DBG_DELAY, DEL2(500));
+ DBG(DBG_ABNORM && DBG_DELAY, DELAY(1));
for (x = 0; x < cmd->host->can_queue; x++) {
@@ -517,7+517,7 @@ int eata_pio_reset(Scsi_Cmnd * cmd, int dummy) sp->result = DID_RESET << 16;
/* This mailbox is terminated */
- printk(KERN_WARNING "eata_pio_reset: resetted ccb %d.\n",x);
+ printk(KERN_WARNING "eata_pio_reset: reset ccb %d.\n",x);
HD(cmd)->ccb[x].status = FREE;
restore_flags(flags);
@@ -530,11+530,11 @@ int eata_pio_reset(Scsi_Cmnd * cmd, int dummy)
if (success) { /* hmmm... */
DBG(DBG_ABNORM, printk(KERN_WARNING "eata_pio_reset: exit, success.\n"));
- DBG(DBG_ABNORM && DBG_DELAY, DEL2(500));
+ DBG(DBG_ABNORM && DBG_DELAY, DELAY(1));
return (SCSI_RESET_SUCCESS);
} else {
DBG(DBG_ABNORM, printk(KERN_WARNING "eata_pio_reset: exit, wakeup.\n"));
- DBG(DBG_ABNORM && DBG_DELAY, DEL2(500));
+ DBG(DBG_ABNORM && DBG_DELAY, DELAY(1));
return (SCSI_RESET_PUNT);
}
}
@@ -718,7+718,7 @@ int register_pio_HBA(long base, struct get_conf *gc, Scsi_Host_Template * tpnt) if (!gc->IRQ_TR)
reg_IRQL[gc->IRQ] = TRUE; /* IRQ is edge triggered */
} else {
- printk("Couldn't allocate IRQ %d, Sorry.", gc->IRQ);
+ printk("Couldn't allocate IRQ %d, Sorry.\n", gc->IRQ);
return (FALSE);
}
} else { /* More than one HBA on this IRQ */
@@ -65,7+65,7 @@ const char *eata_pio_info(struct Scsi_Host *); int eata_pio_command(Scsi_Cmnd *);
int eata_pio_queue(Scsi_Cmnd *, void (*done)(Scsi_Cmnd *));
int eata_pio_abort(Scsi_Cmnd *);
-int eata_pio_reset(Scsi_Cmnd *);
+int eata_pio_reset(Scsi_Cmnd *, unsigned int);
int eata_pio_proc_info(char *, char **, off_t, int, int, int);
#ifdef MODULE
int eata_pio_release(struct Scsi_Host *);
@@ -594,7+594,7 @@ static int fdomain_is_valid_port( int port ) #else
/* That should have worked, but appears to
- have problems. Lets assume it is an
+ have problems. Let's assume it is an
18c30 if the RAM is disabled. */
if (inb( port + Configuration2 ) & 0x02) {
@@ -332,7+332,7 @@ scsi_unregister(struct Scsi_Host * sh){
/* We call this when we come across a new host adapter. We only do this
* once we are 100% sure that we want to use this host adapter - it is a
- * pain to reverse this, so we try and avoid it
+ * pain to reverse this, so we try to avoid it
*/
struct Scsi_Host * scsi_register(Scsi_Host_Template * tpnt, int j){
@@ -311,7+311,7 @@ int pas16_hw_detect( unsigned short board_num )
/* Mediavision has some new model boards that return ID bits
* that indicate a SCSI interface, but they're not (LMS). We'll
- * put in an additional test to try and weed them out.
+ * put in an additional test to try to weed them out.
*/
outb( 0x01, io_port + WAIT_STATE ); /* 1 Wait state */
@@ -422,7+422,7 @@ int scsi_debug_queuecommand(Scsi_Cmnd * SCpnt, void (*done)(Scsi_Cmnd *)) do_done[i] = done;
}
else
- printk("scsi_debug_queuecommand: done cant be NULL\n");
+ printk("scsi_debug_queuecommand: done can't be NULL\n");
#ifdef IMMEDIATE
if( !scsi_debug_lockup )
@@ -128,7+128,7 @@ static int sd_open(struct inode * inode, struct file * filp)
if(!rscsi_disks[target].device->access_count)
sd_ioctl(inode, NULL, SCSI_IOCTL_DOORLOCK, 0);
- };
+ }
/*
* See if we are requesting a non-existent partition. Do this
@@ -250,8+250,8 @@ static void rw_intr (Scsi_Cmnd *SCpnt) memcpy(sgpnt[i].alt_address, sgpnt[i].address,
sgpnt[i].length);
scsi_free(sgpnt[i].address, sgpnt[i].length);
- };
- };
+ }
+ }
/* Free list of scatter-gather pointers */
scsi_free(SCpnt->buffer, SCpnt->sglist_len);
@@ -265,8+265,8 @@ static void rw_intr (Scsi_Cmnd *SCpnt) memcpy(SCpnt->request.buffer, SCpnt->buffer,
SCpnt->bufflen);
scsi_free(SCpnt->buffer, SCpnt->bufflen);
- };
- };
+ }
+ }
/*
* If multiple sectors are requested in one buffer, then
* they will have been finished off by the first command.
@@ -307,8+307,8 @@ static void rw_intr (Scsi_Cmnd *SCpnt) #endif
if (sgpnt[i].alt_address) {
scsi_free(sgpnt[i].address, sgpnt[i].length);
- };
- };
+ }
+ }
scsi_free(SCpnt->buffer, SCpnt->sglist_len); /* Free list of scatter-gather pointers */
} else {
#ifdef DEBUG
@@ -317,7+317,7 @@ static void rw_intr (Scsi_Cmnd *SCpnt) #endif
if (SCpnt->buffer != SCpnt->request.buffer)
scsi_free(SCpnt->buffer, SCpnt->bufflen);
- };
+ }
/*
* Now, if we were good little boys and girls, Santa left us a request
@@ -417,7+417,7 @@ static void do_sd_request (void) if (CURRENT != NULL && CURRENT->rq_status == RQ_INACTIVE) {
restore_flags(flags);
return;
- };
+ }
INIT_SCSI_REQUEST;
SDev = rscsi_disks[DEVICE_NR(CURRENT->rq_dev)].device;
@@ -468,11+468,11 @@ static void do_sd_request (void) restore_flags(flags);
/* This is a performance enhancement. We dig down into the request
- * list and try and find a queueable request (i.e. device not busy,
+ * list and try to find a queueable request (i.e. device not busy,
* and host able to accept another command. If we find one, then we
* queue it. This can make a big difference on systems with more than
* one disk drive. We want to have the interrupts off when monkeying
- * with the request list, because otherwise the kernel might try and
+ * with the request list, because otherwise the kernel might try to
* slip in a request in between somewhere.
*/
@@ -486,21+486,21 @@ static void do_sd_request (void) if(SCpnt) break;
req1 = req;
req = req->next;
- };
+ }
if (SCpnt && req->rq_status == RQ_INACTIVE) {
if (req == CURRENT)
CURRENT = CURRENT->next;
else
req1->next = req->next;
- };
+ }
restore_flags(flags);
- };
+ }
if (!SCpnt) return; /* Could not find anything to do */
/* Queue command */
requeue_sd_request(SCpnt);
- }; /* While */
+ } /* While */
}
static void requeue_sd_request (Scsi_Cmnd * SCpnt)
@@ -610,7+610,7 @@ static void requeue_sd_request (Scsi_Cmnd * SCpnt) if(((long) SCpnt->request.bh->b_data) > ISA_DMA_THRESHOLD)
bounce_buffer = (char *) scsi_malloc(bounce_size);
if(!bounce_buffer) contiguous = 0;
- };
+ }
if(contiguous && SCpnt->request.bh && SCpnt->request.bh->b_reqnext)
for(bh = SCpnt->request.bh, bhp = bh->b_reqnext; bhp; bh = bhp,
@@ -620,7+620,7 @@ static void requeue_sd_request (Scsi_Cmnd * SCpnt) contiguous = 0;
break;
}
- };
+ }
if (!SCpnt->request.bh || contiguous) {
/* case of page request (i.e. raw device), or unlinked buffer */
@@ -667,11+667,11 @@ static void requeue_sd_request (Scsi_Cmnd * SCpnt) ((unsigned long) bh->b_data-1) == ISA_DMA_THRESHOLD)) {
if (count < SCpnt->host->sg_tablesize) count++;
else break;
- };
+ }
this_count += (bh->b_size >> 9);
bhp = bh;
bh = bh->b_reqnext;
- };
+ }
#if 0
if(SCpnt->host->unchecked_isa_dma &&
((unsigned int) SCpnt->request.bh->b_data-1) == ISA_DMA_THRESHOLD) count--;
@@ -710,7+710,7 @@ static void requeue_sd_request (Scsi_Cmnd * SCpnt) ISA_DMA_THRESHOLD && (SCpnt->host->unchecked_isa_dma) &&
!sgpnt[count].alt_address) {
sgpnt[count].alt_address = sgpnt[count].address;
- /* We try and avoid exhausting the DMA pool, since it is
+ /* We try to avoid exhausting the DMA pool, since it is
* easier to control usage here. In other places we might
* have a more pressing need, and we would be screwed if
* we ran out */
@@ -719,7+719,7 @@ static void requeue_sd_request (Scsi_Cmnd * SCpnt) } else {
sgpnt[count].address =
(char *) scsi_malloc(sgpnt[count].length);
- };
+ }
/* If we start running low on DMA buffers, we abort the
* scatter-gather operation, and free all of the memory
* we have allocated. We want to ensure that all scsi
@@ -733,7+733,7 @@ static void requeue_sd_request (Scsi_Cmnd * SCpnt) if(sgpnt[count].alt_address)
scsi_free(sgpnt[count].address,
sgpnt[count].length);
- };
+ }
this_count = SCpnt->request.current_nr_sectors;
buff = SCpnt->request.buffer;
SCpnt->use_sg = 0;
@@ -742,9+742,8 @@ static void requeue_sd_request (Scsi_Cmnd * SCpnt) SCpnt->use_sg = count;
this_count = counted -= bh->b_size >> 9;
break;
- };
-
- };
+ }
+ }
/* Only cluster buffers if we know that we can supply DMA
* buffers large enough to satisfy the request. Do not cluster
@@ -766,21+765,21 @@ static void requeue_sd_request (Scsi_Cmnd * SCpnt) else {
tmp = NULL;
max_sg = SCpnt->use_sg;
- };
+ }
if(tmp){
scsi_free(sgpnt[count].address, sgpnt[count].length);
sgpnt[count].address = tmp;
count--;
continue;
- };
+ }
/* If we are allowed another sg chain, then increment
* counter so we can insert it. Otherwise we will end
up truncating */
if (SCpnt->use_sg < max_sg) SCpnt->use_sg++;
- }; /* contiguous buffers */
- }; /* for loop */
+ } /* contiguous buffers */
+ } /* for loop */
/* This is actually how many we are going to transfer */
this_count = counted;
@@ -795,7+794,7 @@ static void requeue_sd_request (Scsi_Cmnd * SCpnt) while(bh){
printk("[%p %lx] ", bh->b_data, bh->b_size);
bh = bh->b_reqnext;
- };
+ }
if(SCpnt->use_sg < 16)
for(count=0; count<SCpnt->use_sg; count++)
printk("{%d:%p %p %d} ", count,
@@ -803,15+802,15 @@ static void requeue_sd_request (Scsi_Cmnd * SCpnt) sgpnt[count].alt_address,
sgpnt[count].length);
panic("Ooops");
- };
+ }
if (SCpnt->request.cmd == WRITE)
for(count=0; count<SCpnt->use_sg; count++)
if(sgpnt[count].alt_address)
memcpy(sgpnt[count].address, sgpnt[count].alt_address,
sgpnt[count].length);
- }; /* Able to malloc sgpnt */
- }; /* Host adapter capable of scatter-gather */
+ } /* Able to malloc sgpnt */
+ } /* Host adapter capable of scatter-gather */
/* Now handle the possibility of DMA to addresses > 16Mb */
@@ -826,11+825,11 @@ static void requeue_sd_request (Scsi_Cmnd * SCpnt) this_count = SCpnt->request.current_nr_sectors;
buff = (char *) scsi_malloc(this_count << 9);
if(!buff) panic("Ran out of DMA buffers.");
- };
+ }
if (SCpnt->request.cmd == WRITE)
memcpy(buff, (char *)SCpnt->request.buffer, this_count << 9);
- };
- };
+ }
+ }
#ifdef DEBUG
printk("sd%c : %s %d/%d 512 byte blocks.\n",
'a' + devm,
@@ -845,12+844,12 @@ static void requeue_sd_request (Scsi_Cmnd * SCpnt) if(this_count & 1) panic("sd.c:Bad block number requested");
block = block >> 1;
this_count = this_count >> 1;
- };
+ }
if (rscsi_disks[dev].sector_size == 256){
block = block << 1;
this_count = this_count << 1;
- };
+ }
if (((this_count > 0xff) || (block > 0x1fffff)) && rscsi_disks[dev].ten)
{
@@ -906,7+905,7 @@ static int check_scsidisk_media_change(kdev_t full_dev){ !rscsi_disks[target].device) {
printk("SCSI disk request error: invalid device.\n");
return 0;
- };
+ }
if(!rscsi_disks[target].device->removable) return 0;
@@ -922,7+921,7 @@ static int check_scsidisk_media_change(kdev_t full_dev){ rscsi_disks[target].device->changed = 1;
return 1; /* This will force a flush, if called from
* check_disk_change */
- };
+ }
/*
* for removable scsi disk ( FLOPTICAL ) we have to recognise the
@@ -1033,7+1032,7 @@ static int sd_init_onedisk(int i) time1 = jiffies;
while(jiffies < time1 + HZ); /* Wait 1 second for next try */
printk( "." );
- };
+ }
} while(the_result && spintime && spintime+100*HZ > jiffies);
if (spintime) {
if (the_result)
@@ -1041,8+1040,7 @@ static int sd_init_onedisk(int i) else
printk( "ready\n" );
}
- }; /* !MODULE_FLAG */
-
+ } /* !MODULE_FLAG */
retries = 3;
do {
@@ -1153,7+1151,7 @@ static int sd_init_onedisk(int i) rscsi_disks[i].device = NULL;
sd_template.nr_dev--;
return i;
- };
+ }
}
{
/*
@@ -1399,7+1397,7 @@ int revalidate_scsidisk(kdev_t dev, int maxusage){ restore_flags(flags);
printk("Device busy for revalidation (usage=%d)\n", USAGE);
return -EBUSY;
- };
+ }
DEVICE_BUSY = 1;
restore_flags(flags);
@@ -1419,7+1417,7 @@ int revalidate_scsidisk(kdev_t dev, int maxusage){ * the partition table.
*/
blksize_size[MAJOR_NR][minor] = 1024;
- };
+ }
#ifdef MAYBE_REINIT
MAYBE_REINIT;
@@ -1461,7+1459,7 @@ static void sd_detach(Scsi_Device * SDp) sd_gendisk.part[minor].start_sect = 0;
sd_gendisk.part[minor].nr_sects = 0;
sd_sizes[minor] = 0;
- };
+ }
dpnt->has_part_table = 0;
dpnt->device = NULL;
@@ -303,7+303,7 @@ int seagate_st0x_detect (Scsi_Host_Template * tpnt) }
/* If the user specified the controller type from the command line,
- controller_type will be non-zero, so don't try and detect one */
+ controller_type will be non-zero, so don't try to detect one */
if (!controller_type) {
#ifdef OVERRIDE
@@ -603,11+603,11 @@ static void do_sr_request (void) restore_flags(flags);
/* This is a performance enhancement. We dig down into the request list and
- * try and find a queueable request (i.e. device not busy, and host able to
+ * try to find a queueable request (i.e. device not busy, and host able to
* accept another command. If we find one, then we queue it. This can
* make a big difference on systems with more than one disk drive. We want
* to have the interrupts off when monkeying with the request list, because
- * otherwise the kernel might try and slip in a request in between somewhere. */
+ * otherwise the kernel might try to slip in a request in between somewhere. */
if (!SCpnt && sr_template.nr_dev > 1){
struct request *req1;
@@ -789,7+789,7 @@ void requeue_sr_request (Scsi_Cmnd * SCpnt) if (((long) sgpnt[count].address) + sgpnt[count].length > ISA_DMA_THRESHOLD &&
SCpnt->host->unchecked_isa_dma) {
sgpnt[count].alt_address = sgpnt[count].address;
- /* We try and avoid exhausting the DMA pool, since it is easier
+ /* We try to avoid exhausting the DMA pool, since it is easier
* to control usage here. In other places we might have a more
* pressing need, and we would be screwed if we ran out */
if(dma_free_sectors < (sgpnt[count].length >> 9) + 5) {
@@ -259,7+259,7 @@ struct WD33C93_hostdata { /* defines for hostdata->level2 */
/* NOTE: only the first 3 are implemented so far */
-/* (The first 8 bits are reserved for compatibility. They function
+#define L2_NONE 1 /* no combination commands - we get lots of ints */
#define L2_SELECT 2 /* start with SEL_ATN_XFER, but never resume it */
#define L2_BASIC 3 /* resume after STATUS ints & RDP messages */
#define L2_DATA 4 /* resume after DATA_IN/OUT ints */
@@ -255,7+255,7 @@ Since 2.2
Since 2.1
- Preliminary support for SB16.
- - The SB16 mixer is supported in it's native mode.
+ - The SB16 mixer is supported in its native mode.
- Digitized voice capability up to 44.1 kHz/8 bit/mono
(16 bit and stereo support coming in the next release).
- Fixed some bugs in the digitized voice driver for PAS16.
@@ -893,10+893,10 @@ Cards not supported yet Please check which version of sound driver you are using before
complaining that your card is not supported. It's possible that you are
using a driver version which was released months before your card was
-introduced. Driver's release date is listed after it's version number
+introduced. Driver's release date is listed after its version number
in "cat /dev/sndstat" printout and in file linux/drivers/sound/soundvers.h.
-First of all. There is an easy way to make most soundcards to work
+First of all, there is an easy way to make most soundcards to work
with Linux. Just use the DOS based driver to initialize the card
to a _known_ state. Then use loadlin.exe to boot Linux. If Linux is configured
to use the same I/O, IRQ and DMA numbers than DOS, the card could work.
@@ -1187,7+1187,7 @@ ad1848_detect (int io_base, int *ad_flags, int *osp) * Check that the I/O address is in use.
*
* The bit 0x80 of the base I/O port is known to be 0 after the
- * chip has performed it's power on initialization. Just assume
+ * chip has performed its power-on initialization. Just assume
* this has happened before the OS is starting.
*
* If the I/O address is unused, it typically returns 0xff.
@@ -1233,7+1233,7 @@ ad1848_detect (int io_base, int *ad_flags, int *osp) }
/*
- * The indirect register I12 has some read only bits. Lets
+ * The indirect register I12 has some read only bits. Let's
* try to change them.
*/
@@ -359,7+359,7 @@ gus_write_addr (int reg, unsigned long address, int is16bit)
gus_write16 (reg, (unsigned short) ((address >> 7) & 0xffff));
gus_write16 (reg + 1, (unsigned short) ((address << 9) & 0xffff));
- /* Could writing twice fix problems with GUS_VOICE_POS() ? Lets try... */
+ /* Could writing twice fix problems with GUS_VOICE_POS() ? Let's try... */
gus_delay ();
gus_write16 (reg, (unsigned short) ((address >> 7) & 0xffff));
gus_write16 (reg + 1, (unsigned short) ((address << 9) & 0xffff));
@@ -3128,7+3128,7 @@ gus_wave_init (long mem_start, struct address_info *hw_config) sound_num_blocks++;;
if (samples == NULL)
{
- printk ("GUS Error: Cant allocate memory for instrument tables\n");
+ printk ("GUS Error: Can't allocate memory for instrument tables\n");
return mem_start;
}
@@ -1348,7+1348,7 @@ clocks2ticks (unsigned long clocks) /*
* The MPU-401 supports just a limited set of possible timebase values.
* Since the applications require more choices, the driver has to
- * program the HW to do it's best and to convert between the HW and
+ * program the HW to do its best and to convert between the HW and
* actual timebases.
*/
@@ -407,8+407,6 @@ sound_write_sw (int dev, struct fileinfo *file, const char *buf, int count) int
sound_open_sw (int dev, struct fileinfo *file)
{
- int retval;
-
DEB (printk ("sound_open_sw(dev=%d)\n", dev));
if ((dev >= SND_NDEVS) || (dev < 0))
@@ -438,25+436,37 @@ sound_open_sw (int dev, struct fileinfo *file) #ifdef CONFIG_SEQUENCER
case SND_DEV_SEQ:
case SND_DEV_SEQ2:
+ {
+ int retval;
+
if ((retval = sequencer_open (dev, file)) < 0)
return retval;
break;
+ }
#endif
#ifdef CONFIG_MIDI
case SND_DEV_MIDIN:
+ {
+ int retval;
+
if ((retval = MIDIbuf_open (dev, file)) < 0)
return retval;
break;
+ }
#endif
#ifdef CONFIG_AUDIO
case SND_DEV_DSP:
case SND_DEV_DSP16:
case SND_DEV_AUDIO:
+ {
+ int retval;
+
if ((retval = audio_open (dev, file)) < 0)
return retval;
break;
+ }
#endif
default:
tristate 'ISO9660 cdrom filesystem support' CONFIG_ISO9660_FS
tristate 'OS/2 HPFS filesystem support (read only)' CONFIG_HPFS_FS
tristate 'System V and Coherent filesystem support' CONFIG_SYSV_FS
-tristate 'AFFS filesystem support (read only)' CONFIG_AFFS_FS
+tristate 'Amiga FFS filesystem support (EXPERIMENTAL)' CONFIG_AFFS_FS
+if [ "$CONFIG_AFFS_FS" = "y" -o "$CONFIG_AFFS_FS" = "m" ]; then
+ define_bool CONFIG_AMIGA_PARTITION y
+fi
tristate 'UFS filesystem support (read only)' CONFIG_UFS_FS
if [ "$CONFIG_UFS_FS" != "n" ]; then
bool "BSD disklabel (FreeBSD partition tables) support" CONFIG_BSD_DISKLABEL
#
-# Makefile for the linux amiga fast filesystem routines.
+# Makefile for the linux affs-filesystem routines.
#
# Note! Dependencies are done automagically by 'make dep', which also
# removes any old dependencies. DON'T put your own dependencies here
# Note 2! The CFLAGS definitions are now in the main makefile...
O_TARGET := affs.o
-O_OBJS := namei.o inode.o file.o dir.o amigaffs.o symlink.o
+O_OBJS := namei.o inode.o file.o dir.o amigaffs.o bitmap.o symlink.o
M_OBJS := $(O_TARGET)
include $(TOPDIR)/Rules.make
-/*
- * linux/fs/affs/amigaffs.c
- *
- * (C) 1996 Stefan Reinauer - Modified to compile as Module
- *
- * (C) 1993 Ray Burr - Amiga FFS filesystem.
- *
- */
-
-
-#include <linux/module.h>
-
-#include <linux/fs.h>
-#include <linux/affs_fs.h>
-#include <linux/mm.h>
-
-#include "amigaffs.h"
-
-/*
- * Functions for accessing Amiga-FFS structures.
- *
- */
-
-/* Get key entry number ENTRY_POS from the header block pointed to
- by DATA. If ENTRY_POS is invalid, -1 is returned. This is
- used to get entries from file and directory headers as well
- as extension and root blocks. In the current FFS specs, these
- tables are defined to be the same size in all of these. */
-
-int affs_get_key_entry (int bsize, void *data, int entry_pos)
-{
- struct dir_front *dir_front = (struct dir_front *)data;
- int key, hash_table_size;
-
- hash_table_size = MIDBLOCK_LONGS (bsize);
- key = 0;
- if (entry_pos >= 0 && entry_pos < hash_table_size)
- key = swap_long (dir_front->hash_table[entry_pos]);
-
- return key;
-}
-
-/* Find the next used hash entry at or after *HASH_POS in a directory's hash
- table. *HASH_POS is assigned that entry's number. DIR_DATA points to
- the directory header block in memory. If there are no more entries,
- 0 is returned. Otherwise, the key number in the next used hash slot
- is returned. */
-
-int affs_find_next_hash_entry (int bsize, void *dir_data, int *hash_pos)
-{
- struct dir_front *dir_front = (struct dir_front *)dir_data;
- int i, hash_table_size;
-
- hash_table_size = MIDBLOCK_LONGS (bsize);
- if (*hash_pos < 0 || *hash_pos >= hash_table_size)
- return -1;
- for (i = *hash_pos; i < hash_table_size; i++)
- if (dir_front->hash_table[i] != 0)
- break;
- if (i == hash_table_size)
- return 0;
- *hash_pos = i;
- return swap_long (dir_front->hash_table[i]);
-}
-
-/* Get the hash_chain (next file header key in hash chain) entry from a
- file header block in memory pointed to by FH_DATA. */
-
-int affs_get_fh_hash_link (int bsize, void *fh_data)
-{
- struct file_end *file_end;
- int key;
-
- file_end = GET_END_PTR (struct file_end, fh_data, bsize);
- key = swap_long (file_end->hash_chain);
- return key;
-}
-
-/* Set *NAME to point to the file name in a file header block in memory
- pointed to by FH_DATA. The length of the name is returned. */
-
-int affs_get_file_name (int bsize, void *fh_data, char **name)
-{
- struct file_end *file_end;
-
- file_end = GET_END_PTR (struct file_end, fh_data, bsize);
- if (file_end->file_name[0] == 0
- || file_end->file_name[0] > 30) {
- printk ("affs_get_file_name: OOPS! bad filename\n");
- printk (" file_end->file_name[0] = %d\n",
- file_end->file_name[0]);
- *name = "***BAD_FILE***";
- return 14;
- }
- *name = (char *) &file_end->file_name[1];
- return file_end->file_name[0];
-}
-
-/* Get the key number of the first extension block for the file
- header pointed to by FH_DATA. */
-
-int affs_get_extension (int bsize, void *fh_data)
-{
- struct file_end *file_end;
- int key;
-
- file_end = GET_END_PTR (struct file_end, fh_data, bsize);
- key = swap_long (file_end->extension);
- return key;
-}
-
-/* Checksum a block, do various consistency checks and optionally return
- the blocks type number. DATA points to the block. If their pointers
- are non-null, *PTYPE and *STYPE are set to the primary and secondary
- block types respectively. Returns non-zero if the block is not
- consistent. */
-
-int affs_checksum_block (int bsize, void *data, int *ptype, int *stype)
-{
- if (ptype)
- *ptype = swap_long (((long *) data)[0]);
- if (stype)
- *stype = swap_long (((long *) data)[bsize / 4 - 1]);
- return 0;
-}
-
-static struct file_system_type affs_fs_type = {
- affs_read_super, "affs", 1, NULL
-};
-
-int init_affs_fs(void)
-{
- return register_filesystem(&affs_fs_type);
-}
-
-#ifdef MODULE
-int init_module(void)
-{
- int status;
-
- if ((status = init_affs_fs()) == 0)
- register_symtab(0);
- return status;
-}
-
-void cleanup_module(void)
-{
- unregister_filesystem(&affs_fs_type);
-}
-
-#endif
-
+/*
+ * linux/fs/affs/amigaffs.c
+ *
+ * (c) 1996 Hans-Joachim Widmaier - Modified for larger blocks.
+ *
+ * (C) 1993 Ray Burr - Amiga FFS filesystem.
+ *
+ */
+
+#include <linux/stat.h>
+#include <linux/sched.h>
+#include <linux/affs_fs.h>
+#include <linux/string.h>
+#include <linux/locks.h>
+#include <linux/mm.h>
+#include <linux/amigaffs.h>
+
+extern struct timezone sys_tz;
+
+/*
+ * Functions for accessing Amiga-FFS structures.
+ *
+ */
+
+/* Find the next used hash entry at or after *HASH_POS in a directory's hash
+ table. *HASH_POS is assigned that entry's number. DIR_DATA points to
+ the directory header block in memory. If there are no more entries,
+ 0 is returned. Otherwise, the key number in the next used hash slot
+ is returned. */
+
+int
+affs_find_next_hash_entry(int hsize, void *dir_data, ULONG *hash_pos)
+{
+ struct dir_front *dir_front = dir_data;
+ ULONG i;
+
+ for (i = *hash_pos; i < hsize; i++)
+ if (dir_front->hashtable[i] != 0)
+ break;
+ if (i >= hsize)
+ return 0;
+ *hash_pos = i;
+ return htonl(dir_front->hashtable[i]);
+}
+
+/* Set *NAME to point to the file name in a file header block in memory
+ pointed to by FH_DATA. The length of the name is returned. */
+
+int
+affs_get_file_name(int bsize, void *fh_data, char **name)
+{
+ struct file_end *file_end;
+
+ file_end = GET_END_PTR(struct file_end, fh_data, bsize);
+ if (file_end->file_name[0] == 0
+ || file_end->file_name[0] > 30) {
+ printk ("affs_get_file_name: OOPS! bad filename\n");
+ printk (" file_end->file_name[0] = %d\n",
+ file_end->file_name[0]);
+ *name = "***BAD_FILE***";
+ return 14;
+ }
+ *name = (char *) &file_end->file_name[1];
+ return file_end->file_name[0];
+}
+
+/* Find the predecessor in the hash chain */
+
+int
+affs_fix_hash_pred(struct inode *startino, int startoffset, LONG key, LONG newkey)
+{
+ struct buffer_head *bh = NULL;
+ ULONG nextkey;
+ LONG ptype, stype;
+ int retval;
+
+ nextkey = startino->i_ino;
+ retval = -ENOENT;
+ lock_super(startino->i_sb);
+ while (1) {
+ pr_debug("AFFS: fix_hash_pred(): next key=%d, offset=%d\n", nextkey, startoffset);
+ if (nextkey == 0)
+ break;
+ if (!(bh = affs_bread(startino->i_dev,nextkey,AFFS_I2BSIZE(startino))))
+ break;
+ if (affs_checksum_block(AFFS_I2BSIZE(startino),bh->b_data,&ptype,&stype)
+ || ptype != T_SHORT || (stype != ST_FILE && stype != ST_USERDIR &&
+ stype != ST_LINKFILE && stype != ST_LINKDIR &&
+ stype != ST_ROOT && stype != ST_SOFTLINK)) {
+ printk("AFFS: bad block found in link chain (ptype=%d, stype=%d)\n",
+ ptype,stype);
+ affs_brelse(bh);
+ break;
+ }
+ nextkey = htonl(((ULONG *)bh->b_data)[startoffset]);
+ if (nextkey == key) {
+ ((ULONG *)bh->b_data)[startoffset] = newkey;
+ affs_fix_checksum(AFFS_I2BSIZE(startino),bh->b_data,5);
+ mark_buffer_dirty(bh,1);
+ affs_brelse(bh);
+ retval = 0;
+ break;
+ }
+ affs_brelse(bh);
+ startoffset = AFFS_I2BSIZE(startino) / 4 - 4;
+ }
+ unlock_super(startino->i_sb);
+
+ return retval;
+}
+
+/* Remove inode from link chain */
+
+int
+affs_fix_link_pred(struct inode *startino, LONG key, LONG newkey)
+{
+ struct buffer_head *bh = NULL;
+ ULONG nextkey;
+ ULONG offset;
+ LONG etype = 0;
+ LONG ptype, stype;
+ int retval;
+
+ offset = AFFS_I2BSIZE(startino) / 4 - 10;
+ nextkey = startino->i_ino;
+ retval = -ENOENT;
+ lock_super(startino->i_sb);
+ while (1) {
+ if (nextkey == 0)
+ break;
+ pr_debug("AFFS: find_link_pred(): next key=%d\n", nextkey));
+ if (!(bh = affs_bread(startino->i_dev,nextkey,AFFS_I2BSIZE(startino))))
+ break;
+ if (affs_checksum_block(AFFS_I2BSIZE(startino),bh->b_data,&ptype,&stype)
+ || ptype != T_SHORT) {
+ affs_brelse(bh);
+ break;
+ }
+ if (!etype) {
+ if (stype != ST_FILE && stype != ST_USERDIR) {
+ affs_brelse(bh);
+ break;
+ }
+ if (stype == ST_FILE)
+ etype = ST_LINKFILE;
+ else
+ etype = ST_LINKDIR;
+ } else if (stype != etype) {
+ affs_brelse(bh);
+ retval = -EPERM;
+ break;
+ }
+ nextkey = htonl(((ULONG *)bh->b_data)[offset]);
+ if (nextkey == key) {
+ FILE_END(bh->b_data,startino)->link_chain = newkey;
+ affs_fix_checksum(AFFS_I2BSIZE(startino),bh->b_data,5);
+ mark_buffer_dirty(bh,1);
+ affs_brelse(bh);
+ retval = 0;
+ break;
+ }
+ affs_brelse(bh);
+ }
+ unlock_super(startino->i_sb);
+ return retval;
+}
+
+/* Checksum a block, do various consistency checks and optionally return
+ the blocks type number. DATA points to the block. If their pointers
+ are non-null, *PTYPE and *STYPE are set to the primary and secondary
+ block types respectively, *HASHSIZE is set to the size of the hashtable
+ (which lets us calculate the block size).
+ Returns non-zero if the block is not consistent. */
+
+ULONG
+affs_checksum_block(int bsize, void *data, LONG *ptype, LONG *stype)
+{
+ ULONG sum;
+ ULONG *p;
+
+ bsize /= 4;
+ if (ptype)
+ *ptype = htonl(((LONG *)data)[0]);
+ if (stype)
+ *stype = htonl(((LONG *)data)[bsize - 1]);
+
+ sum = 0;
+ p = data;
+ while (bsize--)
+ sum += htonl(*p++);
+ return sum;
+}
+
+void
+affs_fix_checksum(int bsize, void *data, int cspos)
+{
+ ULONG ocs;
+ ULONG cs;
+
+ cs = affs_checksum_block(bsize,data,NULL,NULL);
+ ocs = htonl (((ULONG *)data)[cspos]);
+ ocs -= cs;
+ ((ULONG *)data)[cspos] = htonl(ocs);
+}
+
+void
+secs_to_datestamp(int secs, struct DateStamp *ds)
+{
+ ULONG days;
+ ULONG minute;
+
+ secs -= sys_tz.tz_minuteswest * 60 +((8 * 365 + 2) * 24 * 60 * 60);
+ if (secs < 0)
+ secs = 0;
+ days = secs / 86400;
+ secs -= days * 86400;
+ minute = secs / 60;
+ secs -= minute * 60;
+
+ ds->ds_Days = htonl(days);
+ ds->ds_Minute = htonl(minute);
+ ds->ds_Tick = htonl(secs * 50);
+}
+
+int
+prot_to_mode(ULONG prot)
+{
+ int mode = 0;
+
+ if (AFFS_UMAYWRITE(prot))
+ mode |= S_IWUSR;
+ if (AFFS_UMAYREAD(prot))
+ mode |= S_IRUSR;
+ if (AFFS_UMAYEXECUTE(prot))
+ mode |= S_IXUSR;
+ if (AFFS_GMAYWRITE(prot))
+ mode |= S_IWGRP;
+ if (AFFS_GMAYREAD(prot))
+ mode |= S_IRGRP;
+ if (AFFS_GMAYEXECUTE(prot))
+ mode |= S_IXGRP;
+ if (AFFS_OMAYWRITE(prot))
+ mode |= S_IWOTH;
+ if (AFFS_OMAYREAD(prot))
+ mode |= S_IROTH;
+ if (AFFS_OMAYEXECUTE(prot))
+ mode |= S_IXOTH;
+
+ return mode;
+}
+
+ULONG
+mode_to_prot(int mode)
+{
+ ULONG prot = 0;
+
+ if (mode & S_IXUSR)
+ prot |= FIBF_SCRIPT;
+ if (mode & S_IRUSR)
+ prot |= FIBF_READ;
+ if (mode & S_IWUSR)
+ prot |= FIBF_WRITE | FIBF_DELETE;
+ if (mode & S_IRGRP)
+ prot |= FIBF_GRP_READ;
+ if (mode & S_IWGRP)
+ prot |= FIBF_GRP_WRITE;
+ if (mode & S_IROTH)
+ prot |= FIBF_OTR_READ;
+ if (mode & S_IWOTH)
+ prot |= FIBF_OTR_WRITE;
+
+ return prot;
+}
+++ /dev/null
-#ifndef AMIGAFFS_H
-#define AMIGAFFS_H
-
-/* Ugly macros to make the code pretty. */
-
-#define GET_END_PTR(st,p,sz) ((st *)((char *)(p)+((sz)-sizeof(st))))
-
-#define MIDBLOCK_LONGS(sz) ((sz - sizeof (struct dir_front) \
- - sizeof (struct dir_end)) / 4)
-
-static __inline__ unsigned long
-swap_long (unsigned long x)
-{
-#ifdef __i386__ /* bad check... should be endian check */
- unsigned char *px;
-
- px = (unsigned char *) &x;
- return ( (px[3] << 0)
- | (px[2] << 8)
- | (px[1] << 16)
- | (px[0] << 24));
-#else
- return x;
-#endif
-}
-
-typedef unsigned long ULONG;
-typedef unsigned short UWORD;
-typedef unsigned char UBYTE;
-
-typedef long LONG;
-typedef short WORD;
-typedef char BYTE;
-
-struct DateStamp
-{
- ULONG ds_Days;
- ULONG ds_Minute;
- ULONG ds_Tick;
-};
-
-#define T_SHORT 2
-#define T_LIST 16
-#define T_DATA 8
-
-#define ST_FILE -3
-#define ST_USERDIR 2
-#define ST_ROOT 1
-#define ST_SOFTLINK 3
-#define ST_LINKFILE -4
-#define ST_LINKDIR 4
-
-#define PROT_ARCHIVE (1<<4)
-#define PROT_READ (1<<3)
-#define PROT_WRITE (1<<2)
-#define PROT_EXECUTE (1<<1)
-#define PROT_DELETE (1<<0)
-
-#define PROT_OTR_READ (1<<15)
-#define PROT_OTR_WRITE (1<<14)
-#define PROT_OTR_EXECUTE (1<<13)
-#define PROT_OTR_DELETE (1<<12)
-
-#define PROT_GRP_READ (1<<11)
-#define PROT_GRP_WRITE (1<<10)
-#define PROT_GRP_EXECUTE (1<<9)
-#define PROT_GRP_DELETE (1<<8)
-
-struct ffs_root_front
-{
- LONG primary_type;
- ULONG spare1[2];
- ULONG hash_size;
- ULONG spare2;
- ULONG checksum;
-};
-
-struct ffs_root_end
-{
- LONG bm_flag;
- ULONG bm_keys[25];
- ULONG bm_extend;
- struct DateStamp dir_altered;
- UBYTE disk_name[40];
- struct DateStamp disk_altered;
- struct DateStamp disk_made;
- ULONG spare1[3];
- LONG secondary_type;
-};
-
-struct dir_front
-{
- LONG primary_type;
- ULONG own_key;
- ULONG spare1[3];
- ULONG checksum;
- ULONG hash_table[0];
-};
-
-struct dir_end
-{
- ULONG spare1;
- UWORD uid;
- UWORD gid;
- ULONG protect;
- ULONG spare2;
- UBYTE comment[92];
- struct DateStamp created;
- UBYTE dir_name[64];
- ULONG hash_chain;
- ULONG parent;
- ULONG spare3;
- LONG secondary_type;
-};
-
-struct file_front
-{
- LONG primary_type;
- ULONG own_key;
- ULONG block_count;
- ULONG unknown1;
- ULONG first_data;
- ULONG checksum;
- ULONG blocks[0];
-};
-
-struct file_end
-{
- ULONG spare1;
- UWORD uid;
- UWORD gid;
- ULONG protect;
- ULONG byte_size;
- UBYTE comment[92];
- struct DateStamp created;
- UBYTE file_name[64];
- ULONG hash_chain;
- ULONG parent;
- ULONG extension;
- LONG secondary_type;
-};
-
-struct data_front
-{
- LONG primary_type;
- ULONG header;
- ULONG seq_num;
- ULONG data_size;
- ULONG next_data;
- ULONG checksum;
-};
-
-struct symlink_front
-{
- LONG primary_type;
- ULONG own_key;
- LONG unused[3];
- ULONG checksum;
- UBYTE symname[0];
-};
-
-struct symlink_end
-{
- ULONG spare1;
- UWORD uid;
- UWORD gid;
- ULONG protect;
- ULONG spare2;
- UBYTE comment[92];
- struct DateStamp created;
- UBYTE link_name[64];
- ULONG hash_chain;
- ULONG parent;
- ULONG spare3;
- LONG secondary_type;
-};
-
-struct hardlink_front
-{
- LONG primary_type;
- ULONG own_key;
- LONG unused[3];
- ULONG checksum;
-};
-
-struct hardlink_end
-{
- ULONG spare1;
- UWORD uid;
- UWORD gid;
- ULONG protect;
- ULONG spare2;
- UBYTE comment[92];
- struct DateStamp created;
- UBYTE link_name[32];
- ULONG spare3;
- ULONG original;
- ULONG link_chain;
- ULONG spare4[5];
- ULONG hash_chain;
- ULONG parent;
- ULONG spare5;
- LONG secondary_type;
-};
-
-#endif
--- /dev/null
+/*
+ * linux/fs/affs/bitmap.c
+ *
+ * (c) 1996 Hans-Joachim Widmaier
+ */
+
+/* bitmap.c contains the code that handles the inode and block bitmaps */
+
+#include <linux/sched.h>
+#include <linux/affs_fs.h>
+#include <linux/stat.h>
+#include <linux/kernel.h>
+#include <linux/string.h>
+#include <linux/amigaffs.h>
+#include <linux/locks.h>
+
+#include <asm/bitops.h>
+
+static int nibblemap[] = { 0,1,1,2,1,2,2,3,1,2,2,3,2,3,3,4 };
+
+int
+affs_count_free_bits(int blocksize, const UBYTE *data)
+{
+ int free;
+ int i;
+
+ free = 0;
+ for (i = 0; i < blocksize; i++) {
+ free += nibblemap[data[i] & 0xF] + nibblemap[(data[i]>>4) & 0xF];
+ }
+
+ return free;
+}
+
+int
+affs_count_free_blocks(struct super_block *s)
+{
+ int free;
+ int i;
+
+ pr_debug("AFFS: count_free_blocks()\n");
+
+ free = 0;
+ if (s->u.affs_sb.s_flags & SF_BM_VALID) {
+ for (i = 0; i < s->u.affs_sb.s_bm_count; i++) {
+ free += s->u.affs_sb.s_bitmap[i].bm_free;
+ }
+ }
+ return free;
+}
+
+void
+affs_free_block(struct super_block *sb, LONG block)
+{
+ int bmap;
+ int bit;
+ ULONG blk;
+ struct affs_bm_info *bm;
+
+ pr_debug("AFFS: free_block(%d)\n",block);
+
+ blk = block - sb->u.affs_sb.s_reserved;
+ bmap = blk / (sb->s_blocksize * 8 - 32);
+ bit = blk % (sb->s_blocksize * 8 - 32);
+ bm = &sb->u.affs_sb.s_bitmap[bmap];
+ if (bmap >= sb->u.affs_sb.s_bm_count || bit >= bm->bm_size) {
+ printk("AFFS: free_block(): block %d outside partition.\n",block);
+ return;
+ }
+ blk = 0;
+ set_bit(bit & 31,&blk);
+
+ lock_super(sb);
+ if (set_bit(bit ^ BO_EXBITS,bm->bm_bh->b_data + 4))
+ printk("AFFS: free_block(): block %d is already free.\n",block);
+ else {
+ bm->bm_free++;
+ ((ULONG *)bm->bm_bh->b_data)[0] = ntohl(htonl(((ULONG *)bm->bm_bh->b_data)[0]) - blk);
+ mark_buffer_dirty(bm->bm_bh,1);
+ sb->s_dirt = 1;
+ }
+ unlock_super(sb);
+}
+
+static ULONG
+affs_balloc(struct inode *inode, int zone_no)
+{
+ ULONG w;
+ ULONG *bm;
+ int fb;
+ int i;
+ int fwb;
+ ULONG block;
+ struct affs_zone *zone;
+ struct super_block *sb;
+
+ sb = inode->i_sb;
+ zone = &sb->u.affs_sb.s_zones[zone_no];
+
+ if (!zone || !zone->z_bm || !zone->z_bm->bm_bh)
+ return 0;
+
+ pr_debug("AFFS: balloc(inode=%lu,zone=%d)\n",inode->i_ino,zone_no);
+
+ bm = (ULONG *)zone->z_bm->bm_bh->b_data;
+repeat:
+ fb = (zone->z_bm->bm_size + 31) >> 5;
+ for (i = zone->z_start; i <= fb; i++) {
+ if (bm[i])
+ goto found;
+ }
+ return 0;
+
+found:
+ fwb = zone->z_bm->bm_firstblk + (i - 1) * 32;
+ lock_super(sb);
+ zone->z_start = i;
+ w = htonl(bm[i]);
+ fb = find_first_one_bit(&w,32);
+ if (fb > 31 || !clear_bit(fb ^ BO_EXBITS,&bm[i])) {
+ unlock_super(sb);
+ printk("AFFS: balloc(): empty block disappeared somehow\n");
+ goto repeat;
+ }
+ block = fwb + fb;
+ zone->z_bm->bm_free--;
+
+ /* prealloc as much as possible within this word, but not for headers */
+
+ if (zone_no) {
+ while (inode->u.affs_i.i_pa_cnt < MAX_PREALLOC && ++fb < 32) {
+ fb = find_next_one_bit(&w,32,fb);
+ if (fb > 31)
+ break;
+ if (!clear_bit(fb ^ BO_EXBITS,&bm[i])) {
+ printk("AFFS: balloc(): empty block disappeared\n");
+ break;
+ }
+ inode->u.affs_i.i_data[inode->u.affs_i.i_pa_last++] = fwb + fb;
+ inode->u.affs_i.i_pa_last &= MAX_PREALLOC - 1;
+ inode->u.affs_i.i_pa_cnt++;
+ zone->z_bm->bm_free--;
+ }
+ }
+ w -= htonl(bm[i]);
+ bm[0] = ntohl(htonl(bm[0]) + w);
+ unlock_super(sb);
+ mark_buffer_dirty(zone->z_bm->bm_bh,1);
+
+ return block;
+}
+
+static void
+affs_find_new_zone(struct super_block *sb,struct affs_zone *z, int minfree, int start)
+{
+ struct affs_bm_info *bm;
+ int offs;
+ int zone;
+ int free;
+ int len;
+
+ pr_debug("AFFS: find_new_zone()\n");
+
+ lock_super(sb);
+
+ zone = start;
+ z->z_bm = NULL;
+ while (1) {
+ if (zone >= sb->u.affs_sb.s_num_zones) {
+ zone = 0;
+ continue;
+ }
+
+ if (!set_bit(zone,sb->u.affs_sb.s_zonemap)) {
+ bm = &sb->u.affs_sb.s_bitmap[zone >> (sb->s_blocksize_bits - 8)];
+ offs = zone * 256 & (sb->s_blocksize - 1);
+ len = bm->bm_size / 8 - offs;
+ if (len > 256)
+ len = 256;
+ offs += 4;
+ free = affs_count_free_bits(len,(char *)bm->bm_bh->b_data + offs);
+ if (free && (100 * free) / (len * 8) > minfree) {
+ z->z_bm = bm;
+ z->z_start = offs / 4;
+ z->z_ino = 0;
+ z->z_zone_no = zone;
+ pr_debug(" ++ found zone (%d) in bh %d at offset %d with %d free blocks\n",
+ zone,(zone >> (sb->s_blocksize_bits - 8)),offs,free);
+ break;
+ }
+ clear_bit(zone,sb->u.affs_sb.s_zonemap);
+ }
+
+ /* Skip to next possible zone */
+
+ pr_debug(" ++ Skipping to next zone\n");
+ if (++zone == start)
+ break;
+ }
+ unlock_super(sb);
+ return;
+}
+
+LONG
+affs_new_header(struct inode *inode)
+{
+ struct affs_zone *zone;
+ LONG block;
+ struct super_block *sb;
+ struct buffer_head *bh;
+
+ sb = inode->i_sb;
+ zone = &sb->u.affs_sb.s_zones[0];
+
+ /* We try up to 3 times to find a free block:
+ * If there is no more room in the current header zone,
+ * we try to get a new one and allocate the block there.
+ * If there is no zone with at least AFFS_HDR_MIN_FREE
+ * percent of free blocks, we try to find a zone with
+ * at least one free block.
+ */
+
+ if (!(block = affs_balloc(inode,0))) {
+ clear_bit(zone->z_zone_no,sb->u.affs_sb.s_zonemap);
+ affs_find_new_zone(sb,zone,AFFS_HDR_MIN_FREE,(sb->u.affs_sb.s_num_zones + 1) / 2);
+ if (!(block = affs_balloc(inode,0))) {
+ clear_bit(zone->z_zone_no,sb->u.affs_sb.s_zonemap);
+ affs_find_new_zone(sb,zone,0,(sb->u.affs_sb.s_num_zones + 1) / 2);
+ if (!(block = affs_balloc(inode,0)))
+ return 0;
+ }
+ }
+ if (!(bh = getblk(inode->i_dev,block,sb->s_blocksize))) {
+ printk("AFFS: balloc(): cannot read block %d\n",block);
+ return 0;
+ }
+ memset(bh->b_data,0,sb->s_blocksize);
+ mark_buffer_uptodate(bh,1);
+ mark_buffer_dirty(bh,1);
+ affs_brelse(bh);
+
+ return block;
+}
+
+LONG
+affs_new_data(struct inode *inode)
+{
+ int empty, old;
+ unsigned long oldest;
+ struct affs_zone *zone;
+ struct super_block *sb;
+ struct buffer_head *bh;
+ int i = 0;
+ LONG block;
+
+ pr_debug("AFFS: new_data(ino=%lu)\n",inode->i_ino);
+
+ sb = inode->i_sb;
+ lock_super(sb);
+ if (inode->u.affs_i.i_pa_cnt) {
+ inode->u.affs_i.i_pa_cnt--;
+ unlock_super(sb);
+ block = inode->u.affs_i.i_data[inode->u.affs_i.i_pa_next++];
+ inode->u.affs_i.i_pa_next &= MAX_PREALLOC - 1;
+ goto init_block;
+ }
+ unlock_super(sb);
+repeat:
+ oldest = jiffies;
+ old = 0;
+ empty = 0;
+ zone = &sb->u.affs_sb.s_zones[inode->u.affs_i.i_zone];
+ if (zone->z_ino == inode->i_ino) {
+ i = inode->u.affs_i.i_zone;
+ goto found;
+ }
+ for (i = 1; i < MAX_ZONES; i++) {
+ zone = &sb->u.affs_sb.s_zones[i];
+ if (!empty && zone->z_bm && !zone->z_ino)
+ empty = i;
+ if (zone->z_bm && zone->z_lru_time < oldest) {
+ old = i;
+ oldest = zone->z_lru_time;
+ }
+ }
+ if (empty)
+ i = empty;
+ else if (old)
+ i = old;
+ else
+ return affs_new_header(inode);
+
+ inode->u.affs_i.i_zone = i;
+ zone->z_ino = inode->i_ino;
+
+found:
+ zone = &sb->u.affs_sb.s_zones[i];
+ if (!(block = affs_balloc(inode,i))) { /* Zone is full */
+ clear_bit(zone->z_zone_no,sb->u.affs_sb.s_zonemap);
+ affs_find_new_zone(sb,zone,AFFS_DATA_MIN_FREE,sb->u.affs_sb.s_nextzone);
+ sb->u.affs_sb.s_nextzone = zone->z_zone_no + 1;
+ goto repeat;
+ }
+
+init_block:
+ if (!(bh = getblk(inode->i_dev,block,sb->s_blocksize))) {
+ printk("AFFS: balloc(): cannot read block %u\n",block);
+ return 0;
+ }
+ memset(bh->b_data,0,sb->s_blocksize);
+ mark_buffer_uptodate(bh,1);
+ mark_buffer_dirty(bh,1);
+ affs_brelse(bh);
+
+ return block;
+}
+
+void
+affs_make_zones(struct super_block *sb)
+{
+ int i, j;
+
+ pr_debug("AFFS: make_zones(): num_zones=%d\n",sb->u.affs_sb.s_num_zones);
+
+ j = (sb->u.affs_sb.s_num_zones + 1) / 2;
+
+ affs_find_new_zone(sb,&sb->u.affs_sb.s_zones[0],AFFS_HDR_MIN_FREE,j);
+ for (i = 1; i < MAX_ZONES; i++) {
+ affs_find_new_zone(sb,&sb->u.affs_sb.s_zones[i],AFFS_DATA_MIN_FREE,j);
+ j = sb->u.affs_sb.s_zones[i].z_zone_no + 1;
+ }
+}
-/*
- * linux/fs/affs/dir.c
- *
- * (C) 1993 Ray Burr - Modified for Amiga FFS filesystem.
- *
- * (C) 1992 Eric Youngdale Modified for ISO9660 filesystem.
- *
- * (C) 1991 Linus Torvalds - minix filesystem
- *
- * affs directory handling functions
- */
-
-#include <linux/errno.h>
-
-#include <asm/segment.h>
-
-#include <linux/fs.h>
-#include <linux/affs_fs.h>
-#include <linux/kernel.h>
-#include <linux/affs_fs.h>
-#include <linux/stat.h>
-#include <linux/string.h>
-#include <linux/sched.h>
-
-static int affs_readdir(struct inode *, struct file *, void *, filldir_t);
-
-struct file_operations affs_dir_operations = {
- NULL, /* lseek - default */
- NULL, /* read */
- NULL, /* write - bad */
- affs_readdir, /* readdir */
- NULL, /* select - default */
- NULL, /* ioctl - default */
- NULL, /* mmap */
- NULL, /* no special open code */
- NULL, /* no special release code */
- NULL /* fsync */
-};
-
-/*
- * directories can handle most operations...
- */
-struct inode_operations affs_dir_inode_operations = {
- &affs_dir_operations, /* default directory file-ops */
- NULL, /* create */
- affs_lookup, /* lookup */
- NULL, /* link */
- NULL, /* unlink */
- NULL, /* symlink */
- NULL, /* mkdir */
- NULL, /* rmdir */
- NULL, /* mknod */
- NULL, /* rename */
- NULL, /* readlink */
- NULL, /* follow_link */
- NULL, /* bmap */
- NULL, /* truncate */
- NULL /* permission */
-};
-
-/* This is used to speed up lookup. Without this we would need to
-make a linear search of the directory to find the file that the
-directory read just returned. This is a single element cache. */
-
-/* struct lookup_cache cache = {0,}; */
-
-static int affs_readdir(struct inode * inode, struct file * filp,
- void * dirent, filldir_t filldir)
-{
- int i, j, chain_pos, hash_pos, reclen, ino;
- char *name;
- struct buffer_head *dir_bh;
- struct buffer_head *fh_bh;
- void *dir_data;
- void *fh_data;
-
-#ifdef DEBUG
- printk ("AFFS: readdir: inode=%d f_pos=%d\n",
- inode->i_ino, filp->f_pos);
-#endif
-
- if (!inode || !S_ISDIR(inode->i_mode))
- return -EBADF;
-
- while ((unsigned long)filp->f_pos < 2) {
- if (filp->f_pos == 0) {
- if (filldir (dirent, ".", 1, filp->f_pos, inode->i_ino) < 0)
- return 0;
- } else {
- i = affs_parent_ino (inode);
- if (filldir (dirent, "..", 2, filp->f_pos, i) < 0)
- return 0;
- }
- filp->f_pos++;
- }
- /* No caching here. I've got 16 megs why should I care? :-) */
- chain_pos = (filp->f_pos - 2) & 0xffff;
- if (chain_pos == 0xffff)
- return 0;
- hash_pos = (filp->f_pos - 2) >> 16;
-#ifdef DEBUG
- printk ("AFFS: hash_pos=%d chain_pos=%d\n", hash_pos, chain_pos);
-#endif
- if (!(dir_bh = affs_pread(inode, inode->i_ino, &dir_data)))
- return 0;
- /* HASH_POS should already be on a used entry unless it is
- the first read of the directory. Will this break the
- dirtell thing somehow? */
- i = affs_find_next_hash_entry (AFFS_I2BSIZE (inode), dir_data,
- &hash_pos);
- j = chain_pos;
- for (;;) {
- if (i <= 0) {
-#ifdef DEBUG
- printk ("AFFS: bad f_pos in readdir\n");
-#endif
- brelse (dir_bh);
- return 0;
- }
- ino = i;
- if (!(fh_bh = affs_pread (inode, i, &fh_data))) {
- brelse (dir_bh);
- return 0;
- }
- i = affs_get_fh_hash_link (AFFS_I2BSIZE (inode), fh_data);
- if (j == 0) {
- j = 1;
- if (i <= 0) {
- hash_pos++;
- i = affs_find_next_hash_entry (AFFS_I2BSIZE (inode),
- dir_data, &hash_pos);
- if (i <= 0)
- chain_pos = 0xffff;
- else
- chain_pos = 0;
- } else
- chain_pos++;
- reclen = affs_get_file_name (AFFS_I2BSIZE (inode),
- fh_data, &name);
- if (filldir (dirent, name, reclen, filp->f_pos, ino) < 0) {
- brelse (fh_bh);
- brelse (dir_bh);
- return 0;
- }
- filp->f_pos = ((hash_pos << 16) | chain_pos) + 2;
- }
- brelse (fh_bh);
- j--;
- }
-}
+/*
+ * linux/fs/affs/dir.c
+ *
+ * (c) 1996 Hans-Joachim Widmaier - Modifications for larger blocks
+ * and hard links.
+ * (C) 1993 Ray Burr - Modified for Amiga FFS filesystem.
+ *
+ * (C) 1992 Eric Youngdale Modified for ISO9660 filesystem.
+ *
+ * (C) 1991 Linus Torvalds - minix filesystem
+ *
+ * affs directory handling functions
+ *
+ */
+
+#include <asm/segment.h>
+#include <linux/errno.h>
+#include <linux/fs.h>
+#include <linux/kernel.h>
+#include <linux/affs_fs.h>
+#include <linux/stat.h>
+#include <linux/string.h>
+#include <linux/mm.h>
+#include <linux/amigaffs.h>
+
+static int affs_readdir(struct inode *, struct file *, void *, filldir_t);
+static int affs_dir_read(struct inode * inode, struct file * filp, char * buf, int count);
+
+static struct file_operations affs_dir_operations = {
+ NULL, /* lseek - default */
+ affs_dir_read, /* read */
+ NULL, /* write - bad */
+ affs_readdir, /* readdir */
+ NULL, /* select - default */
+ NULL, /* ioctl - default */
+ NULL, /* mmap */
+ NULL, /* no special open code */
+ NULL, /* no special release code */
+ file_fsync /* default fsync */
+};
+
+/*
+ * directories can handle most operations...
+ */
+struct inode_operations affs_dir_inode_operations = {
+ &affs_dir_operations, /* default directory file-ops */
+ affs_create, /* create */
+ affs_lookup, /* lookup */
+ affs_link, /* link */
+ affs_unlink, /* unlink */
+ affs_symlink, /* symlink */
+ affs_mkdir, /* mkdir */
+ affs_rmdir, /* rmdir */
+ NULL, /* mknod */
+ affs_rename, /* rename */
+ NULL, /* readlink */
+ NULL, /* follow_link */
+ NULL, /* readpage */
+ NULL, /* writepage */
+ NULL, /* bmap */
+ affs_dir_truncate, /* truncate */
+ NULL /* permissions */
+};
+
+static int
+affs_dir_read(struct inode * inode, struct file * filp, char * buf, int count)
+{
+ return -EISDIR;
+}
+
+static int
+affs_readdir(struct inode *inode, struct file *filp, void *dirent, filldir_t filldir)
+{
+ int j, namelen;
+ LONG i;
+ ULONG hash_pos;
+ ULONG chain_pos;
+ unsigned long ino;
+ unsigned long old;
+ int stored;
+ char *name;
+ struct buffer_head *dir_bh;
+ struct buffer_head *fh_bh;
+ struct inode *dir;
+
+ pr_debug("AFFS: readdir(ino=%ld,f_pos=%lu)\n",inode->i_ino,filp->f_pos);
+
+
+ if (!inode || !S_ISDIR(inode->i_mode))
+ return -EBADF;
+
+ stored = 0;
+ dir_bh = NULL;
+ fh_bh = NULL;
+ dir = NULL;
+ old = filp->f_pos & 0x80000000;
+ filp->f_pos &= 0x7FFFFFFF;
+
+ if (filp->f_pos == 0) {
+ filp->private_data = (void *)0;
+ if (filldir(dirent,".",1,filp->f_pos,inode->i_ino) < 0) {
+ return 0;
+ }
+ ++filp->f_pos;
+ stored++;
+ }
+ if (filp->f_pos == 1) {
+ if (filldir(dirent,"..",2,filp->f_pos,affs_parent_ino(inode)) < 0) {
+ filp->f_pos |= 0x80000000;
+ return stored;
+ }
+ filp->f_pos = 2;
+ stored++;
+ }
+
+ /* Read original if this is a link */
+ ino = inode->u.affs_i.i_original ? inode->u.affs_i.i_original : inode->i_ino;
+ if (!(dir = iget(inode->i_sb,ino)))
+ return stored;
+
+ chain_pos = (filp->f_pos - 2) & 0xffff;
+ hash_pos = (filp->f_pos - 2) >> 16;
+ if (chain_pos == 0xffff) {
+ printk("AFFS: more than 65535 entries in chain\n");
+ chain_pos = 0;
+ hash_pos++;
+ filp->f_pos = ((hash_pos << 16) | chain_pos) + 2;
+ }
+ if (!(dir_bh = affs_bread(inode->i_dev,ino,AFFS_I2BSIZE(inode))))
+ goto readdir_done;
+
+ while (!stored || !old) {
+ while (hash_pos < AFFS_I2HSIZE(inode) &&
+ !((struct dir_front *)dir_bh->b_data)->hashtable[hash_pos])
+ hash_pos++;
+ if (hash_pos >= AFFS_I2HSIZE(inode))
+ goto readdir_done;
+
+ i = htonl(((struct dir_front *)dir_bh->b_data)->hashtable[hash_pos]);
+ j = chain_pos;
+ /* If the directory hasn't changed since the last call to readdir(),
+ * we can jump directly to where we left off.
+ */
+ if (filp->private_data && filp->f_version == dir->i_version) {
+ i = (ULONG)filp->private_data;
+ j = 0;
+ pd_debug("AFFS: readdir() left off=%lu\n",i);
+ }
+ filp->f_version = dir->i_version;
+ pd_debug("AFFS: hash_pos=%lu chain_pos=%lu\n", hash_pos, chain_pos);
+ while (i) {
+ if (!(fh_bh = affs_bread(inode->i_dev,i,AFFS_I2BSIZE(inode)))) {
+ printk("AFFS: readdir: Can't get block %d\n",i);
+ goto readdir_done;
+ }
+ ino = i;
+ i = htonl(FILE_END(fh_bh->b_data,inode)->hash_chain);
+ if (j == 0)
+ break;
+ affs_brelse(fh_bh);
+ fh_bh = NULL;
+ j--;
+ }
+ if (fh_bh) {
+ namelen = affs_get_file_name(AFFS_I2BSIZE(inode),fh_bh->b_data,&name);
+ pr_debug("AFFS: readdir(): filldir(..,\"%.*s\",ino=%lu), i=%lu\n",namelen,name,ino,i);
+ filp->private_data = (void *)ino;
+ if (filldir(dirent,name,namelen,filp->f_pos,ino) < 0)
+ goto readdir_done;
+ filp->private_data = (void *)i;
+ affs_brelse(fh_bh);
+ fh_bh = NULL;
+ stored++;
+ }
+ if (i == 0) {
+ hash_pos++;
+ chain_pos = 0;
+ } else
+ chain_pos++;
+ filp->f_pos = ((hash_pos << 16) | chain_pos) + 2;
+ }
+
+readdir_done:
+ filp->f_pos |= old;
+ affs_brelse(dir_bh);
+ affs_brelse(fh_bh);
+ iput(dir);
+ pr_debug("AFFS: readdir()=%d\n",stored);
+ return stored;
+}
+
+void
+affs_dir_truncate(struct inode *inode)
+{
+ printk("AFFS: dir_truncate()\n");
+}
/*
* linux/fs/affs/file.c
*
+ * (c) 1996 Hans-Joachim Widmaier - Rewritten
+ *
* (C) 1993 Ray Burr - Modified for Amiga FFS filesystem.
*
* (C) 1992 Eric Youngdale Modified for ISO9660 filesystem.
#include <asm/segment.h>
#include <asm/system.h>
-
#include <linux/sched.h>
#include <linux/affs_fs.h>
#include <linux/fcntl.h>
#include <linux/errno.h>
#include <linux/stat.h>
#include <linux/locks.h>
-
#include <linux/dirent.h>
-
-#define NBUF 16
+#include <linux/fs.h>
+#include <linux/amigaffs.h>
+#include <linux/mm.h>
+#include <linux/pagemap.h>
#define MIN(a,b) (((a)<(b))?(a):(b))
#define MAX(a,b) (((a)>(b))?(a):(b))
-#include <linux/fs.h>
-#include <linux/affs_fs.h>
+static int affs_file_read_ofs(struct inode *inode, struct file *filp, char *buf, int count);
+static int affs_file_write(struct inode *inode, struct file *filp, const char *buf, int count);
+static int affs_file_write_ofs(struct inode *inode, struct file *filp, const char *buf, int count);
+static void affs_release_file(struct inode *inode, struct file *filp);
-#include "amigaffs.h"
-
-int affs_file_read(struct inode *, struct file *, char *, int);
-
-/*
- * We have mostly NULL's here: the current defaults are ok for
- * the affs filesystem.
- */
-struct file_operations affs_file_operations = {
+static struct file_operations affs_file_operations = {
NULL, /* lseek - default */
- affs_file_read, /* read */
- NULL, /* write */
+ generic_file_read, /* read */
+ affs_file_write, /* write */
NULL, /* readdir - bad */
NULL, /* select - default */
NULL, /* ioctl - default */
generic_file_mmap, /* mmap */
NULL, /* no special open is needed */
- NULL, /* release */
- NULL /* can't fsync */
+ affs_release_file, /* release */
+ file_fsync /* brute force, but works */
};
struct inode_operations affs_file_inode_operations = {
@@ -65,75+61,229 @@ struct inode_operations affs_file_inode_operations = { NULL, /* rename */
NULL, /* readlink */
NULL, /* follow_link */
- NULL /* affs_bmap */, /* bmap */
- NULL, /* truncate */
- NULL /* permission */
+ generic_readpage, /* readpage */
+ NULL, /* writepage */
+ affs_bmap, /* bmap */
+ affs_truncate, /* truncate */
+ NULL, /* permission */
+ NULL /* smap */
};
-static int affs_smap(struct inode *inode, int block)
-{
- struct buffer_head *bh;
- int key;
- void *fh_data;
+static struct file_operations affs_file_operations_ofs = {
+ NULL, /* lseek - default */
+ affs_file_read_ofs, /* read */
+ affs_file_write_ofs, /* write */
+ NULL, /* readdir - bad */
+ NULL, /* select - default */
+ NULL, /* ioctl - default */
+ NULL, /* mmap */
+ NULL, /* no special open is needed */
+ NULL, /* release */
+ file_fsync /* brute force, but works */
+};
+
+struct inode_operations affs_file_inode_operations_ofs = {
+ &affs_file_operations_ofs, /* default file operations */
+ NULL, /* create */
+ NULL, /* lookup */
+ NULL, /* link */
+ NULL, /* unlink */
+ NULL, /* symlink */
+ NULL, /* mkdir */
+ NULL, /* rmdir */
+ NULL, /* mknod */
+ NULL, /* rename */
+ NULL, /* readlink */
+ NULL, /* follow_link */
+ NULL, /* readpage */
+ NULL, /* writepage */
+ NULL, /* bmap */
+ affs_truncate_ofs, /* truncate */
+ NULL, /* permission */
+ NULL /* smap */
+};
-/* FIXME */
-#define KEY_SLOTS_PER_BLOCK 72
+int
+affs_bmap(struct inode *inode, LONG block)
+{
+ struct buffer_head *bh;
+ LONG ext, key;
+ LONG ptype, stype;
-#ifdef DEBUG
- printk ("affs_smap: ino=%d block=%d\n", inode->i_ino, block);
-#endif
+ pr_debug("AFFS: bmap(%lu,%d)\n",inode->i_ino,block);
if (block < 0) {
- printk("affs_smap: block < 0");
+ printk("affs_bmap: block < 0\n");
return 0;
}
- key = inode->i_ino;
+ /* If this is a hard link, quietly exchange the inode with the original */
+
+ key = inode->u.affs_i.i_original ? inode->u.affs_i.i_original : inode->i_ino;
+
+ ext = block / AFFS_I2HSIZE(inode);
+ if (ext) {
+ if (ext > inode->u.affs_i.i_max_ext)
+ ext = inode->u.affs_i.i_max_ext;
+ if (ext)
+ key = inode->u.affs_i.i_ext[ext - 1];
+ block -= ext * AFFS_I2HSIZE(inode);
+ }
+
for (;;) {
- bh = affs_pread (inode, key, &fh_data);
+ bh = affs_bread(inode->i_dev,key,AFFS_I2BSIZE(inode));
if (!bh)
return 0;
- if (block < KEY_SLOTS_PER_BLOCK)
+ if (affs_checksum_block(AFFS_I2BSIZE(inode),bh->b_data,&ptype,&stype) ||
+ (ptype != T_SHORT && ptype != T_LIST) || stype != ST_FILE) {
+ affs_brelse(bh);
+ return 0;
+ }
+ if (block < AFFS_I2HSIZE(inode))
break;
- block -= KEY_SLOTS_PER_BLOCK;
- key = affs_get_extension (AFFS_I2BSIZE (inode), fh_data);
-#ifdef DEBUG
- printk ("affs_smap: reading extension block %d\n", key);
-#endif
- brelse (bh);
- }
- key = affs_get_key_entry (AFFS_I2BSIZE (inode), fh_data,
- (KEY_SLOTS_PER_BLOCK - 1) - block);
- brelse (bh);
-
-#ifdef DEBUG
- printk ("affs_smap: key=%d\n", key);
-#endif
+ block -= AFFS_I2HSIZE(inode);
+ key = htonl(FILE_END(bh->b_data,inode)->extension);
+ affs_brelse(bh);
+ if (ext < EXT_CACHE_SIZE - 1) {
+ inode->u.affs_i.i_ext[ext] = key;
+ inode->u.affs_i.i_max_ext = ++ext;
+ }
+ }
+ key = AFFS_GET_HASHENTRY(bh->b_data,(AFFS_I2HSIZE(inode) - 1) - block);
+ affs_brelse(bh);
return key;
}
-/*
- * affs_file_read() is also needed by the directory read-routine,
- * so it's not static. NOTE! reading directories directly is a bad idea,
- * but has to be supported for now for compatibility reasons with older
- * versions.
+struct buffer_head *
+affs_getblock(struct inode *inode, LONG block)
+{
+ struct buffer_head *bh;
+ struct buffer_head *ebh;
+ LONG key;
+ LONG ext;
+ LONG cnt, j, pt;
+
+ pr_debug("AFFS: getblock(%lu,%d)\n",inode->i_ino,block);
+
+ if (block < 0)
+ return NULL;
+ key = inode->i_ino;
+ pt = T_SHORT;
+
+ ext = block / AFFS_I2HSIZE(inode);
+ if (ext) {
+ if (ext > inode->u.affs_i.i_max_ext)
+ ext = inode->u.affs_i.i_max_ext;
+ if (ext) {
+ key = inode->u.affs_i.i_ext[ext - 1];
+ block -= ext * AFFS_I2HSIZE(inode);
+ pt = T_LIST;
+ }
+ }
+
+ for (;;) {
+ bh = affs_bread(inode->i_dev,key,AFFS_I2BSIZE(inode));
+ if (!bh)
+ return NULL;
+ if (affs_checksum_block(AFFS_I2BSIZE(inode),bh->b_data,&cnt,&j) ||
+ cnt != pt || j != ST_FILE) {
+ printk("AFFS: getblock(): inode %d is not a valid %s\n",key,
+ pt == T_SHORT ? "file header" : "extension block");
+ affs_brelse(bh);
+ return NULL;
+ }
+ j = htonl(((struct file_front *)bh->b_data)->block_count);
+ while (j < AFFS_I2HSIZE(inode) && j <= block) {
+ key = affs_new_data(inode);
+ if (!key)
+ break;
+ lock_super(inode->i_sb);
+ if (AFFS_BLOCK(bh->b_data,inode,j)) {
+ unlock_super(inode->i_sb);
+ printk("AFFS: getblock(): block already allocated\n");
+ affs_free_block(inode->i_sb,key);
+ j++;
+ continue;
+ }
+ unlock_super(inode->i_sb);
+ AFFS_BLOCK(bh->b_data,inode,j) = ntohl(key);
+ j++;
+ }
+ if (pt == T_SHORT)
+ ((struct file_front *)bh->b_data)->first_data =
+ AFFS_BLOCK(bh->b_data,inode,0);
+ ((struct file_front *)bh->b_data)->block_count = ntohl(j);
+ affs_fix_checksum(AFFS_I2BSIZE(inode),bh->b_data,5);
+ mark_buffer_dirty(bh,1);
+
+ if (block < j)
+ break;
+ if (j < AFFS_I2HSIZE(inode)) {
+ affs_brelse(bh);
+ return NULL;
+ }
+
+ block -= AFFS_I2HSIZE(inode);
+ key = htonl(FILE_END(bh->b_data,inode)->extension);
+ if (!key) {
+ key = affs_new_header(inode);
+ if (!key) {
+ affs_brelse(bh);
+ return NULL;
+ }
+ ebh = affs_bread(inode->i_dev,key,AFFS_I2BSIZE(inode));
+ if (!ebh) {
+ affs_free_block(inode->i_sb,key);
+ return NULL;
+ }
+ ((struct file_front *)ebh->b_data)->primary_type = ntohl(T_LIST);
+ ((struct file_front *)ebh->b_data)->own_key = ntohl(key);
+ FILE_END(ebh->b_data,inode)->secondary_type = ntohl(ST_FILE);
+ FILE_END(ebh->b_data,inode)->parent = ntohl(inode->i_ino);
+ affs_fix_checksum(AFFS_I2BSIZE(inode),ebh->b_data,5);
+ FILE_END(bh->b_data,inode)->extension = ntohl(key);
+ affs_fix_checksum(AFFS_I2BSIZE(inode),bh->b_data,5);
+ mark_buffer_dirty(bh,1);
+ affs_brelse(bh);
+ bh = ebh;
+ }
+ affs_brelse(bh);
+ pt = T_LIST;
+ if (ext < EXT_CACHE_SIZE - 1) {
+ inode->u.affs_i.i_ext[ext] = key;
+ inode->u.affs_i.i_max_ext = ++ext;
+ }
+ }
+ key = htonl(AFFS_BLOCK(bh->b_data,inode,block));
+ affs_brelse(bh);
+ if (!key)
+ return NULL;
+
+ return affs_bread(inode->i_dev,key,AFFS_I2BSIZE(inode));
+}
+
+/* This could be made static, regardless of what the former comment said.
+ * You cannot directly read affs directories.
*/
-int affs_file_read(struct inode * inode, struct file * filp,
- char * buf, int count)
+
+static int
+affs_file_read_ofs(struct inode *inode, struct file *filp, char *buf, int count)
{
char *start;
int left, offset, size, sector;
+ int blocksize;
struct buffer_head *bh;
void *data;
+ pr_debug("AFFS: file_read_ofs(ino=%lu,pos=%lu,%d)\n",inode->i_ino,(long)filp->f_pos,count);
+
if (!inode) {
printk("affs_file_read: inode = NULL\n");
return -EINVAL;
}
+ blocksize = AFFS_I2BSIZE(inode) - 24;
if (!(S_ISREG(inode->i_mode))) {
-#ifdef DEBUG
- printk("affs_file_read: mode = %07o\n",inode->i_mode);
-#endif
+ pr_debug("affs_file_read: mode = %07o\n",inode->i_mode);
return -EINVAL;
}
if (filp->f_pos >= inode->i_size || count <= 0)
@@ -141,34+291,296 @@ int affs_file_read(struct inode * inode, struct file * filp,
start = buf;
for (;;) {
- left = MIN (inode->i_size - filp->f_pos,
- count - (buf - start));
+ left = MIN (inode->i_size - filp->f_pos,count - (buf - start));
if (!left)
break;
- sector = affs_smap (inode, filp->f_pos >> AFFS_BLOCK_BITS);
+ sector = affs_bmap(inode,(ULONG)filp->f_pos / blocksize);
if (!sector)
break;
- offset = filp->f_pos & (AFFS_BLOCK_SIZE - 1);
- bh = affs_pread (inode, sector, &data);
+ offset = (ULONG)filp->f_pos % blocksize;
+ bh = affs_bread(inode->i_dev,sector,AFFS_I2BSIZE(inode));
if (!bh)
break;
- size = MIN (AFFS_BLOCK_SIZE - offset, left);
+ data = bh->b_data + 24;
+ size = MIN(blocksize - offset,left);
filp->f_pos += size;
- memcpy_tofs (buf, data + offset, size);
+ memcpy_tofs(buf,data + offset,size);
buf += size;
- brelse (bh);
+ affs_brelse(bh);
}
if (start == buf)
return -EIO;
return buf - start;
+}
+
+static int
+affs_file_write(struct inode *inode, struct file *filp, const char *buf, int count)
+{
+ off_t pos;
+ int written;
+ int c;
+ int blocksize;
+ struct buffer_head *bh;
+ struct inode *ino;
+ char *p;
+
+ pr_debug("AFFS: file_write(ino=%lu,pos=%lu,count=%d)\n",inode->i_ino,
+ (unsigned long)filp->f_pos,count);
-#if 0
- if (filp->f_pos == 0 && count > 0) {
- put_fs_byte ('X', buf++);
- filp->f_pos++;
- return 1;
+ ino = NULL;
+ if (!inode) {
+ printk("AFFS: file_write(): inode=NULL\n");
+ return -EINVAL;
+ }
+ if (inode->u.affs_i.i_original) {
+ ino = iget(inode->i_sb,inode->u.affs_i.i_original);
+ if (!ino) {
+ printk("AFFS: could not follow link from inode %lu to %d\n",
+ inode->i_ino,inode->u.affs_i.i_original);
+ return -EINVAL;
+ }
+ inode = ino;
+ }
+ if (!S_ISREG(inode->i_mode)) {
+ printk("AFFS: file_write(): mode=%07o\n",inode->i_mode);
+ iput(inode);
+ return -EINVAL;
+ }
+ if (filp->f_flags & O_APPEND) {
+ pos = inode->i_size;
+ } else
+ pos = filp->f_pos;
+ written = 0;
+ blocksize = AFFS_I2BSIZE(inode);
+
+ while (written < count) {
+ bh = affs_getblock(inode,pos / blocksize);
+ if (!bh) {
+ if (!written)
+ written = -ENOSPC;
+ break;
+ }
+ c = blocksize - (pos % blocksize);
+ if (c > count - written)
+ c = count - written;
+ if (c != blocksize && !buffer_uptodate(bh)) {
+ ll_rw_block(READ,1,&bh);
+ wait_on_buffer(bh);
+ if (!buffer_uptodate(bh)) {
+ affs_brelse(bh);
+ if (!written)
+ written = -EIO;
+ break;
+ }
+ }
+ p = (pos % blocksize) + bh->b_data;
+ memcpy_fromfs(p,buf,c);
+ update_vm_cache(inode,pos,p,c);
+ mark_buffer_uptodate(bh,1);
+ mark_buffer_dirty(bh,0);
+ affs_brelse(bh);
+ pos += c;
+ written += c;
+ buf += c;
+ }
+ if (pos > inode->i_size)
+ inode->i_size = pos;
+ inode->i_mtime = inode->i_ctime = CURRENT_TIME;
+ filp->f_pos = pos;
+ inode->i_dirt = 1;
+ iput(ino);
+ return written;
+}
+
+static int
+affs_file_write_ofs(struct inode *inode, struct file *filp, const char *buf, int count)
+{
+ pr_debug("AFFS: file_write_ofs(ino=%lu,pos=%lu,count=%d)\n",inode->i_ino,
+ (unsigned long)filp->f_pos,count);
+
+ return -ENOSPC;
+}
+
+void
+affs_truncate(struct inode *inode)
+{
+ struct buffer_head *bh;
+ struct inode *ino;
+ LONG first;
+ LONG block;
+ LONG key;
+ LONG *keyp;
+ LONG ekey;
+ LONG ptype, stype;
+ int freethis;
+ int ext;
+
+ pr_debug("AFFS: file_truncate(inode=%ld,size=%lu)\n",inode->i_ino,inode->i_size);
+
+ ino = NULL;
+ if (inode->u.affs_i.i_original) {
+ ino = iget(inode->i_sb,inode->u.affs_i.i_original);
+ if (!ino) {
+ printk("AFFS: truncate(): cannot follow link from %lu to %u\n",
+ inode->i_ino,inode->u.affs_i.i_original);
+ return;
+ }
+ inode = ino;
+ }
+ first = (inode->i_size + AFFS_I2BSIZE(inode) - 1) / AFFS_I2BSIZE(inode);
+ ekey = inode->i_ino;
+ ext = 0;
+
+ while (ekey) {
+ if (!(bh = affs_bread(inode->i_dev,ekey,AFFS_I2BSIZE(inode)))) {
+ printk("AFFS: truncate(): Can't read block %d\n",ekey);
+ break;
+ }
+ ptype = htonl(((struct file_front *)bh->b_data)->primary_type);
+ stype = htonl(FILE_END(bh->b_data,inode)->secondary_type);
+ if (ekey == inode->i_ino && ptype == T_SHORT && stype == ST_LINKFILE &&
+ LINK_END(bh->b_data,inode)->original == 0) {
+ pr_debug("AFFS: truncate(): dumping link\n");
+ affs_brelse(bh);
+ break;
+ }
+ if (stype != ST_FILE || (ptype != T_SHORT && ptype != T_LIST)) {
+ printk("AFFS: truncate(): bad block (ptype=%d, stype=%d)\n",
+ ptype,stype);
+ affs_brelse(bh);
+ break;
+ }
+ /* Do not throw away file header */
+ freethis = first == 0 && ekey != inode->i_ino;
+ for ( block = first; block < AFFS_I2HSIZE(inode); block++) {
+ keyp = &AFFS_BLOCK(bh->b_data,inode,block);
+ key = htonl(*keyp);
+ if (key) {
+ *keyp = 0;
+ affs_free_block(inode->i_sb,key);
+ } else {
+ block = AFFS_I2HSIZE(inode);
+ break;
+ }
+ }
+ keyp = &GET_END_PTR(struct file_end,bh->b_data,AFFS_I2BSIZE(inode))->extension;
+ key = htonl(*keyp);
+ if (first <= AFFS_I2HSIZE(inode)) {
+ ((struct file_front *)bh->b_data)->block_count = htonl(first);
+ first = 0;
+ *keyp = 0;
+ } else {
+ first -= AFFS_I2HSIZE(inode);
+ }
+ if (freethis) { /* Don't bother fixing checksum */
+ affs_brelse(bh);
+ affs_free_block(inode->i_sb,ekey);
+ } else {
+ affs_fix_checksum(AFFS_I2BSIZE(inode),bh->b_data,5);
+ mark_buffer_dirty(bh,1);
+ affs_brelse(bh);
+ }
+ ekey = key;
+ }
+ inode->u.affs_i.i_max_ext = 0; /* invalidate cache */
+ iput(ino);
+}
+
+void
+affs_truncate_ofs(struct inode *inode)
+{
+ struct buffer_head *bh;
+ struct inode *ino;
+ LONG first;
+ LONG block;
+ LONG key;
+ LONG *keyp;
+ LONG ekey;
+ LONG ptype, stype;
+ int freethis;
+ int blocksize;
+
+ pr_debug("AFFS: file_truncate_ofs(inode=%ld,size=%lu)\n",inode->i_ino,inode->i_size);
+
+ ino = NULL;
+ if (inode->u.affs_i.i_original) {
+ ino = iget(inode->i_sb,inode->u.affs_i.i_original);
+ if (!ino) {
+ printk("AFFS: truncate(): cannot follow link from %lu to %u\n",
+ inode->i_ino,inode->u.affs_i.i_original);
+ return;
+ }
+ inode = ino;
+ }
+ blocksize = AFFS_I2BSIZE(inode) - 24;
+ first = (inode->i_size + blocksize - 1) / blocksize;
+ ekey = inode->i_ino;
+
+ while (ekey) {
+ if (!(bh = affs_bread(inode->i_dev,ekey,AFFS_I2BSIZE(inode)))) {
+ printk("AFFS: truncate(): Can't read block %d\n",ekey);
+ break;
+ }
+ ptype = htonl(((struct file_front *)bh->b_data)->primary_type);
+ stype = htonl(FILE_END(bh->b_data,inode)->secondary_type);
+ if (ekey == inode->i_ino && ptype == T_SHORT && stype == ST_LINKFILE &&
+ LINK_END(bh->b_data,inode)->original == 0) {
+ pr_debug("AFFS: truncate(): dumping link\n");
+ affs_brelse(bh);
+ break;
+ }
+ if (stype != ST_FILE || (ptype != T_SHORT && ptype != T_LIST)) {
+ printk("AFFS: truncate(): bad block (ptype=%d, stype=%d)\n",
+ ptype,stype);
+ affs_brelse(bh);
+ break;
+ }
+ /* Do not throw away file header */
+ freethis = first == 0 && ekey != inode->i_ino;
+ for ( block = first; block < AFFS_I2HSIZE(inode); block++) {
+ keyp = &((struct file_front *)bh->b_data)->
+ blocks[AFFS_I2HSIZE(inode) - 1 - block];
+ key = htonl(*keyp);
+ if (key) {
+ *keyp = 0;
+ affs_free_block(inode->i_sb,key);
+ } else {
+ block = AFFS_I2HSIZE(inode);
+ break;
+ }
+ }
+ keyp = &GET_END_PTR(struct file_end,bh->b_data,AFFS_I2BSIZE(inode))->extension;
+ key = htonl(*keyp);
+ if (first <= AFFS_I2HSIZE(inode)) {
+ ((struct file_front *)bh->b_data)->block_count = htonl(first);
+ first = 0;
+ *keyp = 0;
+ } else {
+ first -= AFFS_I2HSIZE(inode);
+ }
+ if (freethis) { /* Don't bother fixing checksum */
+ affs_brelse(bh);
+ affs_free_block(inode->i_sb,ekey);
+ } else {
+ affs_fix_checksum(AFFS_I2BSIZE(inode),bh->b_data,5);
+ mark_buffer_dirty(bh,1);
+ affs_brelse(bh);
+ }
+ ekey = key;
+ }
+ inode->u.affs_i.i_max_ext = 0; /* invalidate cache */
+ iput(ino);
+}
+
+static void
+affs_release_file(struct inode *inode, struct file *filp)
+{
+ if (filp->f_mode & 2) { /* Free preallocated blocks */
+ while (inode->u.affs_i.i_pa_cnt) {
+ affs_free_block(inode->i_sb,
+ inode->u.affs_i.i_data[inode->u.affs_i.i_pa_next++]);
+ inode->u.affs_i.i_pa_next &= MAX_PREALLOC - 1;
+ inode->u.affs_i.i_pa_cnt--;
+ }
}
- else
- return 0;
-#endif
}
-/*
- * linux/fs/affs/inode.c
- *
- * (C) 1994 Geert Uytterhoeven - Modified for MultiUserFileSystem
- *
- * (C) 1993 Ray Burr - Modified for Amiga FFS filesystem.
- *
- * (C) 1992 Eric Youngdale Modified for ISO9660 filesystem.
- *
- * (C) 1991 Linus Torvalds - minix filesystem
- */
-
-#include <linux/stat.h>
-#include <linux/sched.h>
-#include <linux/affs_fs.h>
-#include <linux/kernel.h>
-#include <linux/mm.h>
-#include <linux/string.h>
-#include <linux/locks.h>
-
-#include <asm/system.h>
-#include <asm/segment.h>
-#include <linux/errno.h>
-
-#include <linux/genhd.h>
-
-#include "amigaffs.h"
-
-extern int check_cdrom_media_change(int, int);
-
-#ifdef LEAK_CHECK
-static int check_malloc = 0;
-static int check_bread = 0;
-#endif
-
-void affs_put_super(struct super_block *sb)
-{
- lock_super(sb);
-
-#ifdef LEAK_CHECK
- printk("Outstanding mallocs:%d, outstanding buffers: %d\n",
- check_malloc, check_bread);
-#endif
- sb->s_dev = 0;
- unlock_super(sb);
- return;
-}
-
-static struct super_operations affs_sops = {
- affs_read_inode,
- NULL, /* notify_change */
- NULL, /* write_inode */
- NULL, /* put_inode */
- affs_put_super,
- NULL, /* write_super */
- affs_statfs,
- NULL /* remount */
-};
-
-int affs_parent_ino(struct inode *dir)
-{
- int root_ino = (dir->i_sb->u.affs_sb.s_root_block
- - dir->i_sb->u.affs_sb.s_partition_offset);
-
- if (!S_ISDIR (dir->i_mode)) {
- printk ("affs_parent_ino: argument is not a directory\n");
- return root_ino;
- }
- if (dir->i_ino == root_ino)
- return root_ino;
- return dir->u.affs_i.i_parent;
-}
-
-static int parse_options(char *options, struct affs_options *optp)
-{
- char *this_opt,*value,*end;
- int n;
-
- optp->offset = 0;
- optp->size = 0;
- optp->root = 0;
- optp->conv_links = 0;
-
- if (!options)
- return 1;
- for (this_opt = strtok(options,","); this_opt; this_opt = strtok(NULL,",")) {
- if ((value = strchr(this_opt,'='))) *value++ = 0;
-
- if (!strcmp(this_opt,"offset") && value) {
- n = simple_strtoul (value, &end, 10);
- if (end == value || *end != 0)
- return 0;
- optp->offset = n;
- }
- else if (!strcmp(this_opt,"size") && value) {
- n = simple_strtoul (value, &end, 10);
- if (end == value || *end != 0 || n <= 0)
- return 0;
- optp->size = n;
- }
- else if (!strcmp(this_opt,"root") && value) {
- n = simple_strtoul (value, &end, 10);
- if (end == value || *end != 0 || n <= 0)
- return 0;
- optp->root = n;
- }
- else if (!strcmp(this_opt,"conv_symlinks")) {
- optp->conv_links = 1;
- }
- else return 0;
- }
- return 1;
-}
-
-/* Is this The Right Way? Should I be locking something? */
-
-static int get_device_size (dev_t dev)
-{
- struct gendisk *gd_p;
- int dev_size = 0;
-
- for (gd_p = gendisk_head ; gd_p ; gd_p=gd_p->next) {
- if (gd_p->major != MAJOR(dev))
- continue;
- dev_size = gd_p->part[MINOR(dev)].nr_sects;
- break;
- }
- return dev_size;
-}
-
-struct super_block *affs_read_super(struct super_block *s,void *data,
- int silent)
-{
- struct buffer_head *bh;
- int dev = s->s_dev;
- int root_block;
- int ptype, stype;
- void *root_data;
- struct affs_options *optp;
-
- optp = &s->u.affs_sb.s_options;
-
- if (!parse_options((char *) data, optp)) {
- s->s_dev = 0;
- printk ("AFFS: bad mount options\n");
- return NULL;
- }
-
- lock_super(s);
-
- root_block = 0;
- if (optp->size) {
- s->u.affs_sb.s_partition_size = optp->size;
- }
- else {
- int size = get_device_size (dev);
- if (size == 0) {
- s->s_dev = 0;
- unlock_super(s);
- printk ("affs_read_super: could not"
- "determine device size\n");
- }
- s->u.affs_sb.s_partition_size = size;
- }
-
- s->u.affs_sb.s_partition_offset = optp->offset;
- root_block = optp->root;
-
- if (!root_block)
- root_block = (s->u.affs_sb.s_partition_offset
- + s->u.affs_sb.s_partition_size / 2
- + (s->u.affs_sb.s_partition_size & 1));
- s->u.affs_sb.s_root_block = root_block;
-
- s->u.affs_sb.s_block_size = AFFS_BLOCK_SIZE;
-
-#if 0
- printk ("affs_read_super: dev=0x%04x offset=%d "
- "size=%d root=%d blocksize=%d\n",
- dev,
- s->u.affs_sb.s_partition_offset,
- s->u.affs_sb.s_partition_size,
- s->u.affs_sb.s_root_block,
- s->u.affs_sb.s_block_size);
-#endif
-
- bh = affs_sread (dev, root_block, &root_data);
- if (!bh) {
- s->s_dev = 0;
- unlock_super(s);
- printk ("AFFS: unable to read superblock\n");
- return NULL;
- }
-
- if (affs_checksum_block (AFFS_BLOCK_SIZE, root_data, &ptype, &stype)
- || ptype != T_SHORT || stype != ST_ROOT) {
- printk ("AFFS: invalid root block %d on device 0x%04x\n",
- root_block, dev);
- goto out;
- }
-
-#if 1
-{
- char *name;
- int len;
- char buf[33];
- len = affs_get_file_name (AFFS_BLOCK_SIZE, root_data, &name);
- memcpy (buf,name,len);
- buf[len] = 0;
-#if 0
- printk ("affs_read_super: volume name \"%s\"\n", buf);
-#endif
-}
-#endif
-
- s->s_magic = AFFS_SUPER_MAGIC;
-
- s->s_flags = MS_RDONLY | MS_NODEV | MS_NOSUID;
-
- brelse(bh);
-
- /* set up enough so that it can read an inode */
- s->s_dev = dev;
- s->s_op = &affs_sops;
- s->s_blocksize = AFFS_BUFFER_SIZE;
- s->s_mounted = iget (s, root_block - s->u.affs_sb.s_partition_offset);
-
- unlock_super(s);
-
- if (!(s->s_mounted)) {
- s->s_dev = 0;
- printk("AFFS: get root inode failed\n");
- return NULL;
- }
-
- return s;
-
- out: /* Kick out for various error conditions */
- brelse (bh);
- s->s_dev = 0;
- unlock_super(s);
- return NULL;
-}
-
-void affs_statfs (struct super_block *sb, struct statfs *buf, int bufsiz)
-{
-#ifdef DEBUG
- printk ("AFFS: affs_statfs called\n");
-#endif
- put_fs_long(AFFS_SUPER_MAGIC, &buf->f_type);
- put_fs_long(sb->u.affs_sb.s_block_size, &buf->f_bsize);
- put_fs_long(sb->u.affs_sb.s_partition_size, &buf->f_blocks);
- put_fs_long(0, &buf->f_bfree);
- put_fs_long(0, &buf->f_bavail);
- put_fs_long(0, &buf->f_files);
- put_fs_long(0, &buf->f_ffree);
- /* Don't know what value to put in buf->f_fsid */
-}
-
-static int prot_table[9][2] = {
- {PROT_OTR_EXECUTE, PROT_OTR_EXECUTE}, /* other: 1 = allowed */
- {PROT_OTR_WRITE, PROT_OTR_WRITE},
- {PROT_OTR_READ, PROT_OTR_READ},
- {PROT_GRP_EXECUTE, PROT_GRP_EXECUTE}, /* group: 1 = allowed */
- {PROT_GRP_WRITE, PROT_GRP_WRITE},
- {PROT_GRP_READ, PROT_GRP_READ},
- {PROT_EXECUTE, 0}, /* owner: 0 = allowed */
- {PROT_WRITE, 0},
- {PROT_READ, 0}
-};
-
-void affs_read_inode(struct inode * inode)
-{
- struct buffer_head *bh;
- int block;
- void *fh_data;
- struct file_front *file_front;
- struct file_end *file_end;
- int i;
- struct hardlink_end *link_end;
- int link;
-
-#ifdef DEBUG
- printk ("AFFS: entering affs_read_inode\n");
-#endif
-
- inode->i_nlink = 1; /* at least */
- do {
- link = 0;
- block = inode->i_ino;
- if (!(bh=affs_pread (inode, block, &fh_data))) {
- printk("AFFS: unable to read i-node block %d\n", block);
- return;
- }
-
- file_front = (struct file_front *) fh_data;
- file_end = GET_END_PTR (struct file_end, fh_data, /* coincidently the same as dir_end */
- AFFS_I2BSIZE (inode));
-
- /* don't use bitmap data for mode, uid & gid of the rootblock */
- if (block == inode->i_sb->u.affs_sb.s_root_block) {
- inode->u.affs_i.i_protect = 0;
- inode->u.affs_i.i_parent = block;
-
- inode->i_mode = S_IRWXUGO | S_IFDIR | S_ISVTX ; /* drwxrwxrwt */
- inode->i_nlink = 2; /* at least ..... */
-
- inode->i_size = 0; /* some different idea ? */
-
- inode->i_uid = 0;
- inode->i_gid = 0;
- }
- else {
-
- inode->u.affs_i.i_protect = file_end->protect;
- inode->u.affs_i.i_parent = swap_long (file_end->parent);
-
- inode->i_mode = 0;
- for (i = 0; i < 9; i++)
- if ((prot_table[i][0] & inode->u.affs_i.i_protect) == prot_table[i][1])
- inode->i_mode |= 1<<i;
- switch(swap_long(file_end->secondary_type)) {
- case ST_USERDIR:
- inode->i_mode |= ((inode->i_mode & 0444)>>2) | S_IFDIR;
-
- inode->i_nlink++; /* There are always at least 2. It is
- hard to figure out what is correct*/
- inode->i_size = 0;
- break;
- case ST_SOFTLINK:
- inode->i_mode |= S_IFLNK;
- inode->i_size = 0;
- break;
- case ST_LINKFILE: /* doing things very easy (not really correct) */
- case ST_LINKDIR: /* code is _very_ inefficient (see below) */
-
- /* Where is struct link_end defined?
- ... I don't know what is going on
- here, someone else should
- probably spend some time on this */
- link_end = (struct hardlink_end *)file_end;
- inode->i_ino = link_end->original;
- inode->i_nlink += 2; /* It's hard to say what's correct */
- brelse(bh);
- link = 1;
- break;
- default:
- printk("affs: unknown secondary type %ld; assuming file\n",
- file_end->secondary_type);
- case ST_FILE:
- inode->i_mode |= S_IFREG;
- inode->i_size = swap_long (file_end->byte_size);
- break;
- }
- if (file_end->uid == 0xffff)
- inode->i_uid = 0; /* root uid */
- else if (file_end->uid == 0x0000) {
- umode_t mode;
- inode->i_uid = -1; /* unknown uid */
-
- /*
- * change the mode of the inode to duplicate the
- * perms of the user in the group and other fields;
- * the assumption is that this isn't a MultiUser
- * filesystem/file, so the permissions should be
- * the same for all users
- */
- mode = (inode->i_mode >> 6) & 7;
- inode->i_mode |= (mode << 3) | (mode);
- } else
- inode->i_uid = file_end->uid;
- if (file_end->gid == 0xffff)
- inode->i_gid = 0; /* root gid */
- else if (file_end->gid == 0x0000)
- inode->i_gid = -1; /* unknown gid */
- else
- inode->i_gid = file_end->gid;
- }
- }
- while (link);
-
-#ifdef DEBUG
- printk ("AFFS: read inode %d: size=%d\n", block, inode->i_size);
-#endif
- inode->i_mtime = inode->i_atime = inode->i_ctime
- = (swap_long (file_end->created.ds_Days) * (24 * 60 * 60)
- + swap_long (file_end->created.ds_Minute) * 60
- + swap_long (file_end->created.ds_Tick) / 50
- + ((8 * 365 + 2) * 24 * 60 * 60));
-
- brelse(bh);
-
- inode->i_op = NULL;
- if (S_ISREG(inode->i_mode))
- inode->i_op = &affs_file_inode_operations;
- else if (S_ISDIR(inode->i_mode))
- inode->i_op = &affs_dir_inode_operations;
- else if (S_ISLNK(inode->i_mode))
- inode->i_op = &affs_symlink_inode_operations;
-}
-
-
-#ifdef LEAK_CHECK
-#undef malloc
-#undef free_s
-#undef bread
-#undef brelse
-
-void * leak_check_malloc(unsigned int size){
- void * tmp;
- check_malloc++;
- tmp = kmalloc(size, GFP_ATOMIC);
- return tmp;
-}
-
-void leak_check_free_s(void * obj, int size){
- check_malloc--;
- return kfree_s(obj, size);
-}
-
-struct buffer_head * leak_check_bread(int dev, int block, int size){
- check_bread++;
- return bread(dev, block, size);
-}
-
-void leak_check_brelse(struct buffer_head * bh){
- check_bread--;
- return brelse(bh);
-}
-
-#endif
+/*
+ * linux/fs/affs/inode.c
+ *
+ * (c) 1996 Hans-Joachim Widmaier - Modified for larger blocks.
+ *
+ * (C) 1993 Ray Burr - Modified for Amiga FFS filesystem.
+ *
+ * (C) 1992 Eric Youngdale Modified for ISO9660 filesystem.
+ *
+ * (C) 1991 Linus Torvalds - minix filesystem
+ */
+
+#include <linux/module.h>
+#include <linux/errno.h>
+#include <linux/fs.h>
+#include <linux/malloc.h>
+#include <linux/stat.h>
+#include <linux/sched.h>
+#include <linux/affs_fs.h>
+#include <linux/kernel.h>
+#include <linux/mm.h>
+#include <linux/string.h>
+#include <linux/locks.h>
+#include <linux/errno.h>
+#include <linux/genhd.h>
+#include <linux/major.h>
+#include <linux/amigaffs.h>
+#include <asm/system.h>
+#include <asm/segment.h>
+
+extern int *blk_size[];
+extern struct timezone sys_tz;
+
+void affs_put_super(struct super_block *sb)
+{
+ int i;
+
+ pr_debug("affs_put_super()\n");
+
+ lock_super(sb);
+ if (!(sb->s_flags & MS_RDONLY)) {
+ for (i = 0; i < sb->u.affs_sb.s_bm_count; i++)
+ affs_brelse(sb->u.affs_sb.s_bitmap[i].bm_bh);
+ ROOT_END_S(sb->u.affs_sb.s_root_bh->b_data,sb)->bm_flag = htonl(1);
+ secs_to_datestamp(CURRENT_TIME,
+ &ROOT_END_S(sb->u.affs_sb.s_root_bh->b_data,sb)->disk_altered);
+ affs_fix_checksum(sb->s_blocksize,sb->u.affs_sb.s_root_bh->b_data,5);
+ mark_buffer_dirty(sb->u.affs_sb.s_root_bh,1);
+ }
+ if (sb->u.affs_sb.s_flags & SF_PREFIX)
+ kfree(sb->u.affs_sb.s_prefix);
+ kfree(sb->u.affs_sb.s_bitmap);
+ affs_brelse(sb->u.affs_sb.s_root_bh);
+ set_blocksize(sb->s_dev,BLOCK_SIZE);
+ sb->s_dev = 0;
+ unlock_super(sb);
+ MOD_DEC_USE_COUNT;
+ return;
+}
+
+static void affs_write_super(struct super_block *sb)
+{
+ int i, clean = 2;
+
+ if (!(sb->s_flags & MS_RDONLY)) {
+ for (i = 0, clean = 1; i < sb->u.affs_sb.s_bm_count; i++) {
+ if (buffer_dirty(sb->u.affs_sb.s_bitmap[i].bm_bh)) {
+ clean = 0;
+ break;
+ }
+ }
+ ROOT_END_S(sb->u.affs_sb.s_root_bh->b_data,sb)->bm_flag = htonl(clean);
+ secs_to_datestamp(CURRENT_TIME,
+ &ROOT_END_S(sb->u.affs_sb.s_root_bh->b_data,sb)->disk_altered);
+ affs_fix_checksum(sb->s_blocksize,sb->u.affs_sb.s_root_bh->b_data,5);
+ mark_buffer_dirty(sb->u.affs_sb.s_root_bh,1);
+ sb->s_dirt = !clean; /* redo until bitmap synced */
+ } else
+ sb->s_dirt = 0;
+
+ pr_debug("AFFS: write_super() at %d, clean=%d\n",CURRENT_TIME,clean);
+}
+
+static struct super_operations affs_sops = {
+ affs_read_inode,
+ affs_notify_change,
+ affs_write_inode,
+ affs_put_inode,
+ affs_put_super,
+ affs_write_super,
+ affs_statfs,
+ NULL /* remount */
+};
+
+int affs_parent_ino(struct inode *dir)
+{
+ int root_ino = (dir->i_sb->u.affs_sb.s_root_block);
+
+ if (!S_ISDIR (dir->i_mode)) {
+ printk ("affs_parent_ino: argument is not a directory\n");
+ return root_ino;
+ }
+ if (dir->i_ino == root_ino)
+ return root_ino;
+ return dir->u.affs_i.i_parent;
+}
+
+
+static int
+parse_options(char *options, uid_t *uid, gid_t *gid, int *mode,
+ int *reserved, int *root, int *blocksize, char **prefix,
+ char *volume, unsigned long *mount_opts)
+{
+ char *this_char, *value;
+ int f;
+
+ /* Fill in defaults */
+
+ *uid = 0;
+ *gid = 0;
+ *reserved = 2;
+ *root = -1;
+ *blocksize = -1;
+ *prefix = "/";
+ volume[0] = ':';
+ volume[1] = 0;
+ *mount_opts = 0;
+ if (!options)
+ return 1;
+ for (this_char = strtok(options,","); this_char; this_char = strtok(NULL,",")) {
+ f = 0;
+ if ((value = strchr(this_char,'=')) != NULL)
+ *value++ = 0;
+ if (!strcmp(this_char,"protect")) {
+ if (value) {
+ printk("AFFS: option protect does not take an argument\n");
+ return 0;
+ }
+ *mount_opts |= SF_IMMUTABLE;
+ }
+ else if (!strcmp(this_char,"verbose")) {
+ if (value) {
+ printk("AFFS: option verbose does not take an argument\n");
+ return 0;
+ }
+ *mount_opts |= SF_VERBOSE;
+ }
+ else if ((f = !strcmp(this_char,"uid")) || !strcmp(this_char,"setuid")) {
+ if (!value)
+ *uid = current->uid;
+ else if (!*value) {
+ printk("AFFS: argument for uid option missing\n");
+ return 0;
+ } else {
+ *uid = simple_strtoul(value,&value,0);
+ if (*value)
+ return 0;
+ if (!f)
+ *mount_opts |= SF_SETUID;
+ }
+ }
+ else if ((f = !strcmp(this_char,"gid")) || !strcmp(this_char,"setgid")) {
+ if (!value)
+ *gid = current->gid;
+ else if (!*value) {
+ printk("AFFS: argument for gid option missing\n");
+ return 0;
+ } else {
+ *gid = simple_strtoul(value,&value,0);
+ if (*value)
+ return 0;
+ if (!f)
+ *mount_opts |= SF_SETGID;
+ }
+ }
+ else if (!strcmp(this_char,"prefix")) {
+ if (!value) {
+ printk("AFFS: The prefix option requires an argument\n");
+ return 0;
+ }
+ *prefix = kmalloc(strlen(value) + 1,GFP_KERNEL);
+ if (!*prefix)
+ return 0;
+ strcpy(*prefix,value);
+ *mount_opts |= SF_PREFIX;
+ }
+ else if (!strcmp(this_char,"volume")) {
+ if (!value) {
+ printk("AFFS: The volume option requires an argument\n");
+ return 0;
+ }
+ if (strlen(value) > 30)
+ value[30] = 0;
+ strcpy(volume,value);
+ }
+ else if (!strcmp(this_char,"mode")) {
+ if (!value || !*value) {
+ printk("AFFS: The mode option requires an argument\n");
+ return 0;
+ }
+ *mode = simple_strtoul(value,&value,8) & 0777;
+ if (*value)
+ return 0;
+ *mount_opts |= SF_SETMODE;
+ }
+ else if (!strcmp(this_char,"reserved")) {
+ if (!value || !*value) {
+ printk("AFFS: The reserved option requires an argument\n");
+ return 0;
+ }
+ *reserved = simple_strtoul(value,&value,0);
+ if (*value)
+ return 0;
+ }
+ else if (!strcmp(this_char,"root")) {
+ if (!value || !*value) {
+ printk("AFFS: The root option requires an argument\n");
+ return 0;
+ }
+ *root = simple_strtoul(value,&value,0);
+ if (*value)
+ return 0;
+ }
+ else if (!strcmp(this_char,"bs")) {
+ if (!value || !*value) {
+ printk("AFFS: The bs option requires an argument\n");
+ return 0;
+ }
+ *blocksize = simple_strtoul(value,&value,0);
+ if (*value)
+ return 0;
+ if (*blocksize != 512 && *blocksize != 1024 && *blocksize != 2048
+ && *blocksize != 4096) {
+ printk ("AFFS: Invalid blocksize (512, 1024, 2048, 4096 allowed).\n");
+ return 0;
+ }
+ }
+ /* Silently ignore the quota options */
+ else if (!strcmp (this_char, "grpquota")
+ || !strcmp (this_char, "noquota")
+ || !strcmp (this_char, "quota")
+ || !strcmp (this_char, "usrquota"))
+ ;
+ else {
+ printk("AFFS: Unrecognized mount option %s\n",
+ this_char);
+ return 0;
+ }
+ }
+ return 1;
+}
+
+struct super_block *
+affs_read_super(struct super_block *s,void *data, int silent)
+{
+ struct buffer_head *bh = NULL;
+ struct buffer_head *bb;
+ kdev_t dev = s->s_dev;
+ int root_block;
+ int size;
+ ULONG chksum;
+ ULONG *bm;
+ LONG ptype, stype;
+ int mapidx = 0;
+ int num_bm;
+ int i;
+ int key;
+ int blocksize;
+ uid_t uid;
+ gid_t gid;
+ int mode, reserved;
+ int zm_size;
+ unsigned long mount_flags;
+ ULONG offset;
+
+ pr_debug("affs_read_super(%s)\n",(const char *)data);
+
+ MOD_INC_USE_COUNT;
+
+ if (!parse_options(data,&uid,&gid,&mode,&reserved,&root_block,
+ &blocksize,&s->u.affs_sb.s_prefix,s->u.affs_sb.s_volume,&mount_flags)) {
+ s->s_dev = 0;
+ printk("AFFS: error parsing options.\n");
+ MOD_DEC_USE_COUNT;
+ return NULL;
+ }
+ lock_super(s);
+
+ /* Get the size of the device in 512-byte blocks.
+ * If we later see that the partition uses bigger
+ * blocks, we will have to change it.
+ */
+
+ size = 2 * blk_size[MAJOR(dev)][MINOR(dev)];
+ s->u.affs_sb.s_bitmap = NULL;
+ s->u.affs_sb.s_root_bh = NULL;
+ s->u.affs_sb.s_flags = mount_flags;
+ s->u.affs_sb.s_mode = mode;
+ s->u.affs_sb.s_uid = uid;
+ s->u.affs_sb.s_gid = gid;
+
+ if (size == 0) {
+ s->s_dev = 0;
+ unlock_super(s);
+ printk("affs_read_super: could not determine device size\n");
+ goto out;
+ }
+ s->u.affs_sb.s_partition_size = size;
+ s->u.affs_sb.s_reserved = reserved;
+
+ /* Try to find root block. It's location may depend on the block size. */
+
+ s->u.affs_sb.s_hashsize = 0;
+ if (blocksize > 0) {
+ chksum = blocksize;
+ num_bm = blocksize;
+ } else {
+ chksum = 512;
+ num_bm = 4096;
+ }
+ for (blocksize = chksum; blocksize <= num_bm; blocksize <<= 1, size >>= 1) {
+ if (root_block < 0)
+ if (MAJOR(dev) == FLOPPY_MAJOR)
+ s->u.affs_sb.s_root_block = size/4;
+ else
+ s->u.affs_sb.s_root_block = (reserved + size - 1) / 2;
+ else
+ s->u.affs_sb.s_root_block = root_block;
+ pr_debug("Trying bs=%d bytes, root at %d, size=%d blocks (%d reserved)\n",
+ blocksize,s->u.affs_sb.s_root_block,size,reserved);
+ set_blocksize(dev,blocksize);
+ bh = affs_bread(dev,s->u.affs_sb.s_root_block,blocksize);
+ if (!bh) {
+ printk("AFFS: unable to read root block\n");
+ goto out;
+ }
+ if (!affs_checksum_block(blocksize,bh->b_data,&ptype,&stype) &&
+ ptype == T_SHORT && stype == ST_ROOT) {
+ s->s_blocksize = blocksize;
+ s->u.affs_sb.s_hashsize = blocksize / 4 - 56;
+ break;
+ }
+ affs_brelse(bh);
+ bh = NULL;
+ }
+ if (!s->u.affs_sb.s_hashsize) {
+ affs_brelse(bh);
+ if (!silent)
+ printk("AFFS: Can't find a valid root block on device %s\n",kdevname(dev));
+ goto out;
+ }
+ root_block = s->u.affs_sb.s_root_block;
+
+ s->u.affs_sb.s_partition_size = size;
+ s->s_blocksize_bits = blocksize == 512 ? 9 :
+ blocksize == 1024 ? 10 :
+ blocksize == 2048 ? 11 : 12;
+
+ /* Find out which kind of FS we have */
+ bb = affs_bread(dev,0,s->s_blocksize);
+ if (bb) {
+ chksum = htonl(*(ULONG *)bb->b_data);
+ switch (chksum) {
+ case MUFS_FS:
+ case MUFS_INTLFFS:
+ s->u.affs_sb.s_flags |= SF_MUFS;
+ /* fall thru */
+ case FS_INTLFFS:
+ s->u.affs_sb.s_flags |= SF_INTL;
+ break;
+ case MUFS_FFS:
+ s->u.affs_sb.s_flags |= SF_MUFS;
+ break;
+ case FS_FFS:
+ break;
+ case MUFS_OFS:
+ s->u.affs_sb.s_flags |= SF_MUFS;
+ /* fall thru */
+ case FS_OFS:
+ s->u.affs_sb.s_flags |= SF_OFS;
+ break;
+ case MUFS_INTLOFS:
+ s->u.affs_sb.s_flags |= SF_MUFS;
+ /* fall thru */
+ case FS_INTLOFS:
+ s->u.affs_sb.s_flags |= SF_INTL | SF_OFS;
+ break;
+ case FS_DCOFS:
+ case FS_DCFFS:
+ case MUFS_DCOFS:
+ case MUFS_DCFFS:
+ if (!silent)
+ printk("AFFS: Unsupported filesystem on device %s: %08X\n",
+ kdevname(dev),chksum);
+ if (0)
+ default:
+ printk("AFFS: Unknown filesystem on device %s: %08X\n",
+ kdevname(dev),chksum);
+ affs_brelse(bb);
+ goto out;
+ }
+ affs_brelse(bb);
+ } else {
+ printk("AFFS: Can't get boot block.\n");
+ goto out;
+ }
+ if (mount_flags & SF_VERBOSE) {
+ chksum = ntohl(chksum);
+ printk("AFFS: Mounting volume \"%*s\": Type=%.3s\\%c, Blocksize=%d\n",
+ GET_END_PTR(struct root_end,bh->b_data,blocksize)->disk_name[0],
+ &GET_END_PTR(struct root_end,bh->b_data,blocksize)->disk_name[1],
+ (char *)&chksum,((char *)&chksum)[3] + '0',blocksize);
+ }
+
+ s->s_magic = AFFS_SUPER_MAGIC;
+ s->s_flags = MS_NODEV | MS_NOSUID;
+
+ /* Keep super block in cache */
+ if (!(s->u.affs_sb.s_root_bh = affs_bread(dev,root_block,s->s_blocksize))) {
+ printk("AFFS: Can't read root block a second time\n");
+ goto out;
+ }
+
+ /* Allocate space for bitmap pointers and read the bitmap */
+
+ size = s->u.affs_sb.s_partition_size - reserved;
+ num_bm = (size + s->s_blocksize * 8 - 32 - 1) / (s->s_blocksize * 8 - 32);
+ zm_size = (num_bm * (1 << (s->s_blocksize_bits - 8)) + 7) / 8;
+ ptype = num_bm * sizeof(struct affs_bm_info) + zm_size +
+ MAX_ZONES * sizeof(struct affs_zone);
+ if (!(s->u.affs_sb.s_bitmap = kmalloc(ptype,GFP_KERNEL))) {
+ printk("AFFS: Can't get memory for bitmap info.\n");
+ goto out;
+ }
+ memset(s->u.affs_sb.s_bitmap,0,ptype);
+
+ if( (ULONG)((UBYTE *)bh->b_data + s->s_blocksize - 200) == 0 ) {
+ if (!(s->s_flags & MS_RDONLY)) {
+ printk("AFFS: Bitmap invalid - mounting %s read only.\n",kdevname(dev));
+ s->s_flags |= MS_RDONLY;
+ }
+ affs_brelse(bh);
+ bh = NULL;
+ goto nobitmap;
+ }
+
+ pr_debug("AFFS: %d bitmap blocks\n",num_bm);
+
+ key = root_block;
+ ptype = s->s_blocksize / 4 - 49;
+ stype = ptype + 25;
+ offset = s->u.affs_sb.s_reserved;
+ while (bh) {
+ bm = (ULONG *)bh->b_data;
+ for (i = ptype; i < stype && bm[i]; i++, mapidx++) {
+ if (mapidx >= num_bm) {
+ printk("AFFS: Not enough bitmap space!?\n");
+ goto out;
+ }
+ bb = affs_bread(s->s_dev,htonl(bm[i]),s->s_blocksize);
+ if (bb) {
+ if (affs_checksum_block(s->s_blocksize,bb->b_data,NULL,NULL) /*&&
+ !(s->s_flags & MS_RDONLY)*/) {
+ printk("AFFS: Bitmap (%d,key=%lu) invalid - mounting %s read only.\n",
+ mapidx, htonl(bm[i]),
+ kdevname(dev));
+ s->s_flags |= MS_RDONLY;
+ }
+ if (size <= s->s_blocksize * 8 - 32) { /* last bitmap */
+ ptype = size / 32 + 1; /* word number */
+ key = size & 0x1F; /* used bits */
+ if (key) {
+ chksum = ntohl(0x7FFFFFFF >> (31 - key));
+ ((ULONG *)bb->b_data)[ptype] &= chksum;
+ affs_fix_checksum(s->s_blocksize,bb->b_data,0);
+ /* no need to mark buffer as dirty */
+ }
+ ptype = (size + 31) & ~0x1F;
+ size = 0;
+ if (!(s->s_flags & MS_RDONLY))
+ s->u.affs_sb.s_flags |= SF_BM_VALID;
+ } else {
+ ptype = s->s_blocksize * 8 - 32;
+ size -= ptype;
+ }
+ s->u.affs_sb.s_bitmap[mapidx].bm_firstblk = offset;
+ s->u.affs_sb.s_bitmap[mapidx].bm_size = ptype;
+ s->u.affs_sb.s_bitmap[mapidx].bm_bh = bb;
+ s->u.affs_sb.s_bitmap[mapidx].bm_free =
+ affs_count_free_bits(ptype/8,bb->b_data + 4);
+ offset += ptype;
+ } else {
+ printk("AFFS: Can't read bitmap.\n");
+ goto out;
+ }
+ }
+ key = htonl(bm[stype]); /* Next block of bitmap pointers */
+ ptype = 0;
+ stype = s->s_blocksize / 4 - 1;
+ affs_brelse(bh);
+ if (key) {
+ if (!(bh = affs_bread(s->s_dev,key,s->s_blocksize))) {
+ printk("AFFS: Can't read bitmap extension.\n");
+ goto out;
+ }
+ } else
+ bh = NULL;
+ }
+ if (mapidx != num_bm) {
+ printk("AFFS: Got only %d bitmap blocks, expected %d\n",
+ mapidx, num_bm);
+ goto out;
+ }
+ s->u.affs_sb.s_num_zones = ((num_bm - 1) << (s->s_blocksize_bits - 8))+
+ (s->u.affs_sb.s_bitmap[num_bm - 1].bm_size + 2047) / 2048;
+nobitmap:
+ s->u.affs_sb.s_bm_count = mapidx;
+ s->u.affs_sb.s_zones = (struct affs_zone *)&s->u.affs_sb.s_bitmap[num_bm];
+ s->u.affs_sb.s_zonemap = (char *)&s->u.affs_sb.s_zones[MAX_ZONES];
+
+ /* set up enough so that it can read an inode */
+
+ s->s_dev = dev;
+ s->s_op = &affs_sops;
+ s->s_mounted = iget(s,root_block);
+ unlock_super(s);
+
+ if (!(s->s_mounted)) {
+ s->s_dev = 0;
+ printk("AFFS: get root inode failed\n");
+ MOD_DEC_USE_COUNT;
+ return NULL;
+ }
+
+ /* If the fs is mounted r/w, create data zones, else free bitmaps. */
+
+ if (!(s->s_flags & MS_RDONLY)) {
+ ROOT_END(s->u.affs_sb.s_root_bh->b_data,s->s_mounted)->bm_flag = 0;
+ secs_to_datestamp(CURRENT_TIME,&ROOT_END(s->u.affs_sb.s_root_bh->b_data,
+ s->s_mounted)->disk_altered);
+ affs_fix_checksum(s->s_blocksize,s->u.affs_sb.s_root_bh->b_data,5);
+ mark_buffer_dirty(s->u.affs_sb.s_root_bh,1);
+ affs_make_zones(s);
+ } else {
+ for (i = 0; i < s->u.affs_sb.s_bm_count; i++) {
+ affs_brelse(s->u.affs_sb.s_bitmap[i].bm_bh);
+ s->u.affs_sb.s_bitmap[i].bm_bh = NULL;
+ }
+ }
+
+
+ pr_debug("AFFS: s_flags=%lX\n", s->s_flags);
+ return s;
+
+ out: /* Kick out for various error conditions */
+ affs_brelse (bh);
+ affs_brelse(s->u.affs_sb.s_root_bh);
+ if (s->u.affs_sb.s_bitmap) {
+ for (i = 0; i < mapidx; i++)
+ affs_brelse(s->u.affs_sb.s_bitmap[i].bm_bh);
+ kfree(s->u.affs_sb.s_bitmap);
+ }
+ s->s_dev = 0;
+ unlock_super(s);
+ MOD_DEC_USE_COUNT;
+ return NULL;
+}
+
+void
+affs_statfs(struct super_block *sb, struct statfs *buf, int bufsiz)
+{
+ ULONG free;
+ struct statfs tmp;
+
+ pr_debug("AFFS: statfs() partsize=%d, reserved=%d\n",
+ sb->u.affs_sb.s_partition_size, sb->u.affs_sb.s_reserved);
+
+ free = affs_count_free_blocks(sb);
+ tmp.f_type = AFFS_SUPER_MAGIC;
+ tmp.f_bsize = sb->s_blocksize;
+ tmp.f_blocks = sb->u.affs_sb.s_partition_size - sb->u.affs_sb.s_reserved;
+ tmp.f_bfree = free;
+ tmp.f_bavail = free;
+ tmp.f_files = 0;
+ tmp.f_ffree = 0;
+ memcpy_tofs(buf,&tmp,bufsiz);
+}
+
+void
+affs_read_inode(struct inode *inode)
+{
+ struct buffer_head *bh, *lbh;
+ struct file_front *file_front;
+ struct file_end *file_end;
+ LONG block;
+ ULONG prot;
+ LONG ptype, stype;
+ unsigned short id;
+
+ pr_debug("AFFS: read_inode(%lu)\n",inode->i_ino);
+ lbh = NULL;
+ block = inode->i_ino;
+ if (!(bh = affs_bread(inode->i_dev,block,AFFS_I2BSIZE(inode)))) {
+ printk("AFFS: unable to read i-node block %d\n",block);
+ return;
+ }
+ if (affs_checksum_block(AFFS_I2BSIZE(inode),bh->b_data,&ptype,&stype) || ptype != T_SHORT) {
+ printk("AFFS: read_inode(): checksum or type (ptype=%d) error on inode %d\n",
+ ptype, block);
+ affs_brelse(bh);
+ return;
+ }
+
+ file_front = (struct file_front *)bh->b_data;
+ file_end = GET_END_PTR(struct file_end, bh->b_data,AFFS_I2BSIZE(inode));
+ prot = (htonl(file_end->protect) & ~0x10) ^ FIBF_OWNER;
+
+ inode->u.affs_i.i_protect = prot;
+ inode->u.affs_i.i_parent = htonl(file_end->parent);
+ inode->u.affs_i.i_original = 0;
+ inode->u.affs_i.i_zone = 0;
+ inode->u.affs_i.i_hlink = 0;
+ inode->u.affs_i.i_pa_cnt = 0;
+ inode->u.affs_i.i_pa_next = 0;
+ inode->u.affs_i.i_pa_last = 0;
+ inode->u.affs_i.i_ext[0] = 0;
+ inode->u.affs_i.i_max_ext = 0;
+ inode->i_nlink = 1;
+ inode->i_mode = 0;
+
+ if (inode->i_sb->u.affs_sb.s_flags & SF_SETMODE)
+ inode->i_mode = inode->i_sb->u.affs_sb.s_mode;
+ else
+ inode->i_mode = prot_to_mode(prot);
+
+ if (inode->i_sb->u.affs_sb.s_flags & SF_SETUID)
+ inode->i_uid = inode->i_sb->u.affs_sb.s_uid;
+ else {
+ id = htons(file_end->owner_uid);
+ if (inode->i_sb->u.affs_sb.s_flags & SF_MUFS) {
+ if (id == 0 || id == 0xFFFF)
+ id ^= ~0;
+ }
+ inode->i_uid = id;
+ }
+ if (inode->i_sb->u.affs_sb.s_flags & SF_SETGID)
+ inode->i_gid = inode->i_sb->u.affs_sb.s_gid;
+ else {
+ id = htons(file_end->owner_gid);
+ if (inode->i_sb->u.affs_sb.s_flags & SF_MUFS) {
+ if (id == 0 || id == 0xFFFF)
+ id ^= ~0;
+ }
+ inode->i_gid = id;
+ }
+
+ switch (htonl(file_end->secondary_type)) {
+ case ST_ROOT:
+ inode->i_uid = inode->i_sb->u.affs_sb.s_uid;
+ inode->i_gid = inode->i_sb->u.affs_sb.s_gid;
+ case ST_USERDIR:
+ if (htonl(file_end->secondary_type) == ST_USERDIR ||
+ inode->i_sb->u.affs_sb.s_flags & SF_SETMODE) {
+ if (inode->i_mode & S_IRUSR)
+ inode->i_mode |= S_IXUSR;
+ if (inode->i_mode & S_IRGRP)
+ inode->i_mode |= S_IXGRP;
+ if (inode->i_mode & S_IROTH)
+ inode->i_mode |= S_IXOTH;
+ inode->i_mode |= S_IFDIR;
+ } else
+ inode->i_mode = S_IRUGO | S_IXUGO | S_IWUSR | S_IFDIR;
+ inode->i_size = 0;
+ break;
+ case ST_LINKDIR:
+ inode->u.affs_i.i_original = htonl(file_end->original);
+ inode->u.affs_i.i_hlink = 1;
+ inode->i_mode |= S_IFDIR;
+ inode->i_size = 0;
+ break;
+ case ST_LINKFILE:
+ inode->u.affs_i.i_original = htonl(file_end->original);
+ inode->u.affs_i.i_hlink = 1;
+ if (!(lbh = affs_bread(inode->i_dev,inode->u.affs_i.i_original,
+ AFFS_I2BSIZE(inode)))) {
+ affs_brelse(bh);
+ printk("AFFS: unable to read i-node block %ld\n",inode->i_ino);
+ return;
+ }
+ file_end = GET_END_PTR(struct file_end,lbh->b_data,AFFS_I2BSIZE(inode));
+ case ST_FILE:
+ inode->i_mode |= S_IFREG;
+ inode->i_size = htonl(file_end->byte_size);
+ break;
+ case ST_SOFTLINK:
+ inode->i_mode |= S_IFLNK;
+ inode->i_size = 0;
+ break;
+ }
+
+ inode->i_mtime = inode->i_atime = inode->i_ctime
+ = (htonl(file_end->created.ds_Days) * (24 * 60 * 60) +
+ htonl(file_end->created.ds_Minute) * 60 +
+ htonl(file_end->created.ds_Tick) / 50 +
+ ((8 * 365 + 2) * 24 * 60 * 60)) +
+ sys_tz.tz_minuteswest * 60;
+ affs_brelse(bh);
+ affs_brelse(lbh);
+
+ inode->i_op = NULL;
+ if (S_ISREG(inode->i_mode)) {
+ if (inode->i_sb->u.affs_sb.s_flags & SF_OFS)
+ inode->i_op = &affs_file_inode_operations_ofs;
+ else
+ inode->i_op = &affs_file_inode_operations;
+ } else if (S_ISDIR(inode->i_mode))
+ inode->i_op = &affs_dir_inode_operations;
+ else if (S_ISLNK(inode->i_mode))
+ inode->i_op = &affs_symlink_inode_operations;
+}
+
+void
+affs_write_inode(struct inode *inode)
+{
+ struct buffer_head *bh;
+ struct file_end *file_end;
+ short uid, gid;
+
+ pr_debug("AFFS: write_inode(%lu)\n",inode->i_ino);
+
+ inode->i_dirt = 0;
+ if (!inode->i_nlink)
+ return;
+ if (!(bh = bread(inode->i_dev,inode->i_ino,AFFS_I2BSIZE(inode)))) {
+ printk("AFFS: Unable to read block of inode %ld on %s\n",
+ inode->i_ino,kdevname(inode->i_dev));
+ return;
+ }
+ file_end = GET_END_PTR(struct file_end, bh->b_data,AFFS_I2BSIZE(inode));
+ if (file_end->secondary_type == htonl(ST_ROOT)) {
+ secs_to_datestamp(inode->i_mtime,&ROOT_END(bh->b_data,inode)->disk_altered);
+ } else {
+ file_end->protect = ntohl(inode->u.affs_i.i_protect ^ FIBF_OWNER);
+ file_end->byte_size = ntohl(inode->i_size);
+ secs_to_datestamp(inode->i_mtime,&file_end->created);
+ if (!(inode->i_ino == inode->i_sb->u.affs_sb.s_root_block)) {
+ uid = inode->i_uid;
+ gid = inode->i_gid;
+ if (inode->i_sb->u.affs_sb.s_flags & SF_MUFS) {
+ if (inode->i_uid == 0 || inode->i_uid == 0xFFFF)
+ uid = inode->i_uid ^ ~0;
+ if (inode->i_gid == 0 || inode->i_gid == 0xFFFF)
+ gid = inode->i_gid ^ ~0;
+ }
+ if (!(inode->i_sb->u.affs_sb.s_flags & SF_SETUID))
+ file_end->owner_gid = ntohs(uid);
+ if (!(inode->i_sb->u.affs_sb.s_flags & SF_SETGID))
+ file_end->owner_gid = ntohs(gid);
+ }
+ }
+ affs_fix_checksum(AFFS_I2BSIZE(inode),bh->b_data,5);
+ mark_buffer_dirty(bh,1);
+ brelse(bh);
+}
+
+int
+affs_notify_change(struct inode *inode, struct iattr *attr)
+{
+ int error;
+
+ pr_debug("AFFS: notify_change(%lu,0x%x)\n",
+ inode->i_ino,attr->ia_valid);
+
+ error = inode_change_ok(inode,attr);
+ if (error)
+ return error;
+
+ if (((attr->ia_valid & ATTR_UID) && (inode->i_sb->u.affs_sb.s_flags & SF_SETUID)) ||
+ ((attr->ia_valid & ATTR_GID) && (inode->i_sb->u.affs_sb.s_flags & SF_SETGID)) ||
+ ((attr->ia_valid & ATTR_MODE) &&
+ (inode->i_sb->u.affs_sb.s_flags & (SF_SETMODE | SF_IMMUTABLE))))
+ error = -EPERM;
+
+ if (error)
+ return (inode->i_sb->u.affs_sb.s_flags & SF_QUIET) ? 0 : error;
+
+ if (attr->ia_valid & ATTR_MODE)
+ inode->u.affs_i.i_protect = mode_to_prot(attr->ia_mode);
+
+ inode_setattr(inode,attr);
+
+ return 0;
+}
+
+void
+affs_put_inode(struct inode *inode)
+{
+ pr_debug("AFFS: put_inode(ino=%lu, nlink=%u)\n",
+ inode->i_ino,inode->i_nlink);
+ if (inode->i_nlink) {
+ return;
+ }
+ inode->i_size = 0;
+ if (S_ISREG(inode->i_mode) && !inode->u.affs_i.i_hlink)
+ affs_truncate(inode);
+ affs_free_block(inode->i_sb,inode->i_ino);
+ clear_inode(inode);
+}
+
+struct inode *
+affs_new_inode(const struct inode *dir)
+{
+ struct inode *inode;
+ struct super_block *sb;
+ ULONG block;
+
+ if (!dir || !(inode = get_empty_inode()))
+ return NULL;
+
+ sb = dir->i_sb;
+ inode->i_sb = sb;
+ inode->i_flags = sb->s_flags;
+
+ if (!(block = affs_new_header((struct inode *)dir))) {
+ iput(inode);
+ return NULL;
+ }
+
+ inode->i_count = 1;
+ inode->i_nlink = 1;
+ inode->i_dev = sb->s_dev;
+ inode->i_uid = current->fsuid;
+ inode->i_gid = current->fsgid;
+ inode->i_dirt = 1;
+ inode->i_ino = block;
+ inode->i_op = NULL;
+ inode->i_blocks = 0;
+ inode->i_size = 0;
+ inode->i_mode = 0;
+ inode->i_blksize = 0;
+ inode->i_mtime = inode->i_atime = inode->i_ctime = CURRENT_TIME;
+
+ inode->u.affs_i.i_original = 0;
+ inode->u.affs_i.i_parent = dir->i_ino;
+ inode->u.affs_i.i_zone = 0;
+ inode->u.affs_i.i_hlink = 0;
+ inode->u.affs_i.i_pa_cnt = 0;
+ inode->u.affs_i.i_pa_next = 0;
+ inode->u.affs_i.i_pa_last = 0;
+ inode->u.affs_i.i_ext[0] = 0;
+ inode->u.affs_i.i_max_ext = 0;
+
+ insert_inode_hash(inode);
+
+ return inode;
+}
+
+int
+affs_add_entry(struct inode *dir, struct inode *link, struct inode *inode,
+ const char *name, int len, LONG type)
+{
+ struct buffer_head *dir_bh;
+ struct buffer_head *inode_bh;
+ struct buffer_head *link_bh;
+ ULONG hash;
+
+ pr_debug("AFFS: add_entry(dir=%lu,inode=%lu,\"%*s\",type=%ld\n",
+ dir->i_ino,inode->i_ino, len,name,type);
+
+ dir_bh = affs_bread(dir->i_dev,dir->i_ino,AFFS_I2BSIZE(dir));
+ inode_bh = affs_bread(inode->i_dev,inode->i_ino,AFFS_I2BSIZE(inode));
+ link_bh = NULL;
+ if (!dir_bh || !inode_bh) {
+ affs_brelse(dir_bh);
+ affs_brelse(inode_bh);
+ return -ENOSPC;
+ }
+ if (link) {
+ link_bh = affs_bread(link->i_dev,link->i_ino,AFFS_I2BSIZE(link));
+ if (!link_bh) {
+ affs_brelse(dir_bh);
+ affs_brelse(inode_bh);
+ return -EINVAL;
+ }
+ }
+ ((struct dir_front *)inode_bh->b_data)->primary_type = ntohl(T_SHORT);
+ ((struct dir_front *)inode_bh->b_data)->own_key = ntohl(inode->i_ino);
+
+ if (len > 30) /* truncate name quietly */
+ len = 30;
+ DIR_END(inode_bh->b_data,inode)->dir_name[0] = len;
+ strncpy(DIR_END(inode_bh->b_data,inode)->dir_name + 1,name,len);
+ DIR_END(inode_bh->b_data,inode)->secondary_type = ntohl(type);
+ DIR_END(inode_bh->b_data,inode)->parent = ntohl(dir->i_ino);
+ hash = affs_hash_name(name,len,AFFS_I2FSTYPE(dir),AFFS_I2HSIZE(dir));
+
+ lock_super(inode->i_sb);
+ DIR_END(inode_bh->b_data,inode)->hash_chain =
+ ((struct dir_front *)dir_bh->b_data)->hashtable[hash];
+ ((struct dir_front *)dir_bh->b_data)->hashtable[hash] = ntohl(inode->i_ino);
+ if (link_bh) {
+ LINK_END(inode_bh->b_data,inode)->original = ntohl(link->i_ino);
+ LINK_END(inode_bh->b_data,inode)->link_chain =
+ FILE_END(link_bh->b_data,link)->link_chain;
+ FILE_END(link_bh->b_data,link)->link_chain = ntohl(inode->i_ino);
+ affs_fix_checksum(AFFS_I2BSIZE(link),link_bh->b_data,5);
+ link->i_version = ++event;
+ link->i_dirt = 1;
+ mark_buffer_dirty(link_bh,1);
+ }
+ affs_fix_checksum(AFFS_I2BSIZE(inode),inode_bh->b_data,5);
+ affs_fix_checksum(AFFS_I2BSIZE(dir),dir_bh->b_data,5);
+ dir->i_version = ++event;
+ dir->i_mtime = dir->i_atime = dir->i_ctime = CURRENT_TIME;
+ unlock_super(inode->i_sb);
+
+ dir->i_dirt = 1;
+ inode->i_dirt = 1;
+ mark_buffer_dirty(dir_bh,1);
+ mark_buffer_dirty(inode_bh,1);
+ affs_brelse(dir_bh);
+ affs_brelse(inode_bh);
+ affs_brelse(link_bh);
+
+ return 0;
+}
+
+static struct file_system_type affs_fs_type = {
+ affs_read_super,
+ "affs",
+ 1,
+ NULL
+};
+
+int
+init_affs_fs(void)
+{
+ return register_filesystem(&affs_fs_type);
+}
+
+#ifdef MODULE
+
+int
+init_module(void)
+{
+ int status;
+ if ((status = init_affs_fs()) == 0)
+ register_symtab(0);
+ return status;
+}
+
+void
+cleanup_module(void)
+{
+ unregister_filesystem(&affs_fs_type);
+}
+
+#endif
-/*
- * linux/fs/affs/namei.c
- *
- * (C) 1993 Ray Burr - Modified for Amiga FFS filesystem.
- *
- * (C) 1992 Eric Youngdale Modified for ISO9660 filesystem.
- *
- * (C) 1991 Linus Torvalds - minix filesystem
- */
-
-#include <linux/sched.h>
-#include <linux/affs_fs.h>
-#include <linux/kernel.h>
-#include <linux/string.h>
-#include <linux/stat.h>
-#include <linux/fcntl.h>
-#include <asm/segment.h>
-
-#include <linux/errno.h>
-
-
-static inline int namecompare(int len, int maxlen,
- const char * name, const char * buffer)
-{
- if (len >= maxlen || !buffer[len]) {
- return strncmp (name, buffer, len) == 0;
- }
- return 0;
-}
-
-/*
- * ok, we cannot use strncmp, as the name is not in our data space.
- * Thus we'll have to use affs_match. No big problem. Match also makes
- * some sanity tests.
- *
- * NOTE! unlike strncmp, affs_match returns 1 for success, 0 for failure.
- */
-static int affs_match(int len,const char * name, char * compare, int dlen)
-{
- if (!compare) return 0;
-
- /* "" means "." ---> so paths like "/usr/lib//libc.a" work */
- if (!len && dlen == 1 && compare[0] == '.')
- return 1;
-
-#if 0
- if (len <= 2) printk("Match: %d %d %s %d %d \n",len,dlen,compare,de->name[0], dlen);
-#endif
-
- return namecompare(len,dlen,name,compare);
-}
-
-/* Avoid pulling in ctype stuff. */
-
-static int affs_toupper (int ch)
-{
- if (ch >= 'a' && ch <= 'z')
- ch -= ('a' - 'A');
- return ch;
-}
-
-static int affs_hash_name (const char *name, int len)
-{
- int i, x;
-
- x = len;
- for (i = 0; i < len; i++)
- x = (x * 13 + affs_toupper (name[i])) & 0x7ff;
- return x % 72; /* FIXME: Assumes 512 byte blocks. */
-}
-
-static struct buffer_head *affs_find_entry(struct inode *dir,
- const char *name, int namelen, int *ino)
-{
- struct buffer_head *bh;
- void *dir_data;
- int key;
-
- *ino = 0;
-
- bh = affs_pread (dir, dir->i_ino, &dir_data);
- if (!bh)
- return NULL;
-
- if (affs_match (namelen, name, ".", 1)) {
- *ino = dir->i_ino;
- return bh;
- }
- if (affs_match (namelen, name, "..", 2)) {
- *ino = affs_parent_ino (dir);
- return bh;
- }
- key = affs_get_key_entry (AFFS_I2BSIZE (dir), dir_data,
- affs_hash_name (name, namelen));
-
- for (;;) {
- char *cname;
- int cnamelen;
-
- brelse (bh);
- if (key <= 0)
- return NULL;
- bh = affs_pread (dir, key, &dir_data);
- if (!bh)
- return NULL;
- cnamelen = affs_get_file_name (AFFS_I2BSIZE (dir),
- dir_data, &cname);
- if (affs_match (namelen, name, cname, cnamelen))
- break;
- key = affs_get_fh_hash_link (AFFS_I2BSIZE (dir), dir_data);
- }
-
- *ino = key;
-
- return bh;
-}
-
-int affs_lookup(struct inode * dir,const char * name, int len,
- struct inode ** result)
-{
- int ino;
- struct buffer_head *bh;
-
- *result = NULL;
- if (!dir)
- return -ENOENT;
-
-#ifdef DEBUG
- printk ("lookup: %d %d\n", dir->i_ino, len);
-#endif
-
- if (!S_ISDIR(dir->i_mode)) {
- iput(dir);
- return -ENOENT;
- }
- if (!(bh = affs_find_entry(dir, name, len, &ino))) {
- iput(dir);
- return -ENOENT;
- }
- brelse(bh);
- if (!(*result = iget(dir->i_sb, ino))) {
- iput(dir);
- return -EACCES;
- }
- iput (dir);
- return 0;
-
-#if 0
- ino = 0;
- while(cache.lock);
- cache.lock = 1;
- if (dir->i_dev == cache.dev &&
- dir->i_ino == cache.dir &&
- len == cache.dlen &&
- affs_match(len, name, cache.filename, cache.dlen))
- {
- ino = cache.ino;
- ino_back = dir->i_ino;
- /* These two cases are special, but since they are at the start
- of the directory, we can just as easily search there */
- if (cache.dlen == 1 && cache.filename[0] == '.') ino = 0;
- if (cache.dlen == 2 && cache.filename[0] == '.' &&
- cache.filename[1] == '.') ino = 0;
- };
- cache.lock = 0;
-
- if (!ino) {
- if (!(bh = affs_find_entry(dir,name,len, &ino, &ino_back))) {
- iput(dir);
- return -ENOENT;
- }
- brelse(bh);
- };
-
- if (!(*result = iget(dir->i_sb,ino))) {
- iput(dir);
- return -EACCES;
- }
-
- /* We need this backlink for the .. entry */
-
- if (ino_back) (*result)->u.affs_i.i_backlink = ino_back;
-
- iput(dir);
- return 0;
-#endif
-}
+/*
+ * linux/fs/affs/namei.c
+ *
+ * (c) 1996 Hans-Joachim Widmaier - Heavily hacked up.
+ *
+ * (C) 1993 Ray Burr - Modified for Amiga FFS filesystem.
+ *
+ * (C) 1991 Linus Torvalds - minix filesystem
+ */
+
+#include <linux/sched.h>
+#include <linux/affs_fs.h>
+#include <linux/amigaffs.h>
+#include <linux/kernel.h>
+#include <linux/string.h>
+#include <linux/stat.h>
+#include <linux/fcntl.h>
+#include <linux/locks.h>
+#include <asm/segment.h>
+
+#include <linux/errno.h>
+
+/* Simple toupper() for DOS\1 */
+
+static inline unsigned int
+affs_toupper(unsigned int ch)
+{
+ return ch >= 'a' && ch <= 'z' ? ch -= ('a' - 'A') : ch;
+}
+
+/* International toupper() for DOS\3 */
+
+static inline unsigned int
+affs_intl_toupper(unsigned int ch)
+{
+ return (ch >= 'a' && ch <= 'z') || (ch >= 0xE0
+ && ch <= 0xFE && ch != 0xF7) ?
+ ch - ('a' - 'A') : ch;
+}
+
+/*
+ * NOTE! unlike strncmp, affs_match returns 1 for success, 0 for failure.
+ */
+
+static int
+affs_match(const char *name, int len, const char *compare, int dlen, int intl)
+{
+ if (!compare)
+ return 0;
+
+ if (len > 30)
+ len = 30;
+ if (dlen > 30)
+ dlen = 30;
+
+ /* "" means "." ---> so paths like "/usr/lib//libc.a" work */
+ if (!len && dlen == 1 && compare[0] == '.')
+ return 1;
+ if (dlen != len)
+ return 0;
+ if (intl) {
+ while (dlen--) {
+ if (affs_intl_toupper(*name & 0xFF) != affs_intl_toupper(*compare & 0xFF))
+ return 0;
+ name++;
+ compare++;
+ }
+ } else {
+ while (dlen--) {
+ if (affs_toupper(*name & 0xFF) != affs_toupper(*compare & 0xFF))
+ return 0;
+ name++;
+ compare++;
+ }
+ }
+ return 1;
+}
+
+int
+affs_hash_name(const char *name, int len, int intl, int hashsize)
+{
+ unsigned int i, x;
+
+ if (len > 30)
+ len = 30;
+
+ x = len;
+ for (i = 0; i < len; i++)
+ if (intl)
+ x = (x * 13 + affs_intl_toupper(name[i] & 0xFF)) & 0x7ff;
+ else
+ x = (x * 13 + affs_toupper(name[i] & 0xFF)) & 0x7ff;
+
+ return x % hashsize;
+}
+
+static struct buffer_head *
+affs_find_entry(struct inode *dir, const char *name, int namelen,
+ unsigned long *ino)
+{
+ struct buffer_head *bh;
+ int intl;
+ ULONG key;
+
+ pr_debug("AFFS: find_entry(%.*s)=\n",namelen,name);
+
+ intl = AFFS_I2FSTYPE(dir);
+ bh = affs_bread(dir->i_dev,dir->i_ino,AFFS_I2BSIZE(dir));
+ if (!bh)
+ return NULL;
+
+ if (affs_match(name,namelen,".",1,intl)) {
+ *ino = dir->i_ino;
+ return bh;
+ }
+ if (affs_match(name,namelen,"..",2,intl)) {
+ *ino = affs_parent_ino(dir);
+ return bh;
+ }
+
+ key = AFFS_GET_HASHENTRY(bh->b_data,affs_hash_name(name,namelen,intl,AFFS_I2HSIZE(dir)));
+
+ for (;;) {
+ char *cname;
+ int cnamelen;
+
+ affs_brelse(bh);
+ if (key == 0) {
+ bh = NULL;
+ break;
+ }
+ bh = affs_bread(dir->i_dev,key,AFFS_I2BSIZE(dir));
+ if (!bh)
+ break;
+ cnamelen = affs_get_file_name(AFFS_I2BSIZE(dir),bh->b_data,&cname);
+ if (affs_match(name,namelen,cname,cnamelen,intl))
+ break;
+ key = htonl(FILE_END(bh->b_data,dir)->hash_chain);
+ }
+ pr_debug("%lu\n",key);
+ *ino = key;
+ return bh;
+}
+
+int
+affs_lookup(struct inode *dir, const char *name, int len, struct inode **result)
+{
+ int res;
+ unsigned long ino;
+ struct buffer_head *bh;
+
+ pr_debug("AFFS: lookup(%.*s)\n",len,name);
+
+ *result = NULL;
+ if (!dir)
+ return -ENOENT;
+
+ res = -ENOENT;
+ if (S_ISDIR(dir->i_mode)) {
+ if ((bh = affs_find_entry(dir,name,len,&ino))) {
+ if (FILE_END(bh->b_data,dir)->original)
+ ino = htonl(FILE_END(bh->b_data,dir)->original);
+ affs_brelse(bh);
+ if ((*result = iget(dir->i_sb,ino)))
+ res = 0;
+ else
+ res = -EACCES;
+ }
+ }
+ iput(dir);
+ return res;
+}
+
+int
+affs_unlink(struct inode *dir, const char *name, int len)
+{
+ int retval;
+ struct buffer_head *bh;
+ unsigned long ino;
+ struct inode *inode;
+
+ pr_debug("AFFS: unlink(dir=%ld,\"%.*s\")\n",dir->i_ino,len,name);
+
+ bh = NULL;
+ inode = NULL;
+ retval = -ENOENT;
+ if (!(bh = affs_find_entry(dir,name,len,&ino))) {
+ goto unlink_done;
+ }
+ if (!(inode = iget(dir->i_sb,ino))) {
+ goto unlink_done;
+ }
+ if (S_ISDIR(inode->i_mode)) {
+ retval = -EPERM;
+ goto unlink_done;
+ }
+
+ if ((retval = affs_fix_hash_pred(dir,affs_hash_name(name,len,AFFS_I2FSTYPE(dir),
+ AFFS_I2HSIZE(dir)) + 6,ino,
+ FILE_END(bh->b_data,dir)->hash_chain)))
+ goto unlink_done;
+
+ if ((retval = affs_fixup(bh,inode)))
+ goto unlink_done;
+
+ inode->i_nlink=0;
+ inode->i_dirt=1;
+ inode->i_ctime = dir->i_ctime = dir->i_mtime = CURRENT_TIME;
+ dir->i_version = ++event;
+ dir->i_dirt=1;
+unlink_done:
+ affs_brelse(bh);
+ iput(inode);
+ iput(dir);
+ return retval;
+}
+
+int
+affs_create(struct inode *dir, const char *name, int len, int mode, struct inode **result)
+{
+ struct inode *inode;
+ int error;
+
+ pr_debug("AFFS: create(%lu,\"%.*s\",0%o)\n",dir->i_ino,len,name,mode);
+
+
+ *result = NULL;
+
+ if (!dir || !dir->i_sb) {
+ iput(dir);
+ return -EINVAL;
+ }
+ inode = affs_new_inode(dir);
+ if (!inode) {
+ iput (dir);
+ return -ENOSPC;
+ }
+ inode->i_op = &affs_file_inode_operations;
+ inode->i_mode = mode;
+ error = affs_add_entry(dir,NULL,inode,name,len,ST_FILE);
+ if (error) {
+ iput(dir);
+ inode->i_nlink = 0;
+ inode->i_dirt = 1;
+ iput(inode);
+ return -ENOSPC;
+ }
+ inode->u.affs_i.i_protect = mode_to_prot(inode->i_mode);
+
+ iput(dir);
+ *result = inode;
+
+ return 0;
+}
+
+int
+affs_mkdir(struct inode *dir, const char *name, int len, int mode)
+{
+ struct inode *inode;
+ struct buffer_head *bh;
+ unsigned long i;
+ int error;
+
+ pr_debug("AFFS: mkdir(%lu,\"%.*s\",0%o)\n",dir->i_ino,len,name,mode);
+
+ if (!dir || !dir->i_sb) {
+ iput(dir);
+ return -EINVAL;
+ }
+ bh = affs_find_entry(dir,name,len,&i);
+ if (bh) {
+ affs_brelse(bh);
+ iput(dir);
+ return -EEXIST;
+ }
+ inode = affs_new_inode(dir);
+ if (!inode) {
+ iput (dir);
+ return -ENOSPC;
+ }
+ inode->i_op = &affs_dir_inode_operations;
+ error = affs_add_entry(dir,NULL,inode,name,len,ST_USERDIR);
+ if (error) {
+ iput(dir);
+ inode->i_nlink = 0;
+ inode->i_dirt = 1;
+ iput(inode);
+ return error;
+ }
+ inode->i_mode = S_IFDIR | (mode & 0777 & ~current->fs->umask);
+ inode->u.affs_i.i_protect = mode_to_prot(inode->i_mode);
+
+ iput(dir);
+ iput(inode);
+
+ return 0;
+}
+
+static int
+empty_dir(struct buffer_head *bh, int hashsize)
+{
+ while (--hashsize >= 0) {
+ if (((struct dir_front *)bh->b_data)->hashtable[hashsize])
+ return 0;
+ }
+ return 1;
+}
+
+int
+affs_rmdir(struct inode *dir, const char *name, int len)
+{
+ int retval;
+ unsigned long ino;
+ struct inode *inode;
+ struct buffer_head *bh;
+
+ pr_debug("AFFS: rmdir(dir=%lu,\"%.*s\")\n",dir->i_ino,len,name);
+
+ inode = NULL;
+ retval = -ENOENT;
+ if (!(bh = affs_find_entry(dir,name,len,&ino))) {
+ goto rmdir_done;
+ }
+ if (!(inode = iget(dir->i_sb,ino))) {
+ goto rmdir_done;
+ }
+ retval = -EPERM;
+ if (!fsuser() && current->fsuid != inode->i_uid &&
+ current->fsuid != dir->i_uid)
+ goto rmdir_done;
+ if (inode->i_dev != dir->i_dev)
+ goto rmdir_done;
+ if (inode == dir) /* we may not delete ".", but "../dir" is ok */
+ goto rmdir_done;
+ if (!S_ISDIR(inode->i_mode)) {
+ retval = -ENOTDIR;
+ goto rmdir_done;
+ }
+ if (!empty_dir(bh,AFFS_I2HSIZE(inode))) {
+ retval = -ENOTEMPTY;
+ goto rmdir_done;
+ }
+ if (inode->i_count > 1) {
+ retval = -EBUSY;
+ goto rmdir_done;
+ }
+ if ((retval = affs_fix_hash_pred(dir,affs_hash_name(name,len,AFFS_I2FSTYPE(dir),
+ AFFS_I2HSIZE(dir)) + 6,ino,
+ FILE_END(bh->b_data,dir)->hash_chain)))
+ goto rmdir_done;
+
+ if ((retval = affs_fixup(bh,inode)))
+ goto rmdir_done;
+
+ inode->i_nlink=0;
+ inode->i_dirt=1;
+ inode->i_ctime = dir->i_ctime = dir->i_mtime = CURRENT_TIME;
+ dir->i_version = ++event;
+ dir->i_dirt=1;
+rmdir_done:
+ iput(dir);
+ iput(inode);
+ affs_brelse(bh);
+ return retval;
+}
+
+int
+affs_symlink(struct inode *dir, const char *name, int len, const char *symname)
+{
+ struct buffer_head *bh;
+ struct inode *inode;
+ char *p;
+ unsigned long tmp;
+ int i, maxlen;
+ char c, lc;
+
+ pr_debug("AFFS: symlink(%lu,\"%.*s\" -> \"%s\")\n",dir->i_ino,len,name,symname);
+ printk("AFFS: symlink(%lu,\"%.*s\" -> \"%s\")\n",dir->i_ino,len,name,symname);
+
+ maxlen = 4 * AFFS_I2HSIZE(dir) - 1;
+ inode = affs_new_inode(dir);
+ if (!inode) {
+ iput(dir);
+ return -ENOSPC;
+ }
+ inode->i_op = &affs_symlink_inode_operations;
+ inode->i_mode = S_IFLNK | 0777;
+ inode->u.affs_i.i_protect = mode_to_prot(inode->i_mode);
+ bh = affs_bread(inode->i_dev,inode->i_ino,AFFS_I2BSIZE(inode));
+ if (!bh) {
+ iput(dir);
+ inode->i_nlink = 0;
+ inode->i_dirt = 1;
+ iput(inode);
+ return -EIO;
+ }
+ i = 0;
+ p = ((struct slink_front *)bh->b_data)->symname;
+ lc = '/';
+ if (*symname == '/') {
+ while (*symname == '/')
+ symname++;
+ while (inode->i_sb->u.affs_sb.s_volume[i]) /* Cannot overflow */
+ *p++ = inode->i_sb->u.affs_sb.s_volume[i++];
+ }
+ while (i < maxlen && (c = *symname++)) {
+ if (c == '.' && lc == '/' && *symname == '.' && symname[1] == '/') {
+ *p++ = '/';
+ i++;
+ symname += 2;
+ lc = '/';
+ } else if (c == '.' && lc == '/' && *symname == '/') {
+ symname++;
+ lc = '/';
+ } else {
+ *p++ = c;
+ lc = c;
+ i++;
+ }
+ if (lc == '/')
+ while (*symname == '/')
+ symname++;
+ }
+ *p = 0;
+ mark_buffer_dirty(bh,1);
+ affs_brelse(bh);
+ inode->i_dirt = 1;
+ bh = affs_find_entry(dir,name,len,&tmp);
+ if (bh) {
+ inode->i_nlink = 0;
+ iput(inode);
+ affs_brelse(bh);
+ iput(dir);
+ return -EEXIST;
+ }
+ i = affs_add_entry(dir,NULL,inode,name,len,ST_SOFTLINK);
+ if (i) {
+ inode->i_nlink = 0;
+ inode->i_dirt = 1;
+ iput(inode);
+ affs_brelse(bh);
+ iput(dir);
+ return i;
+ }
+ iput(dir);
+ iput(inode);
+
+ return 0;
+}
+
+int
+affs_link(struct inode *oldinode, struct inode *dir, const char *name, int len)
+{
+ struct inode *inode;
+ struct buffer_head *bh;
+ unsigned long i;
+ int error;
+
+ pr_debug("AFFS: link(%lu,%lu,\"%.*s\")\n",oldinode->i_ino,dir->i_ino,len,name);
+
+ bh = affs_find_entry(dir,name,len,&i);
+ if (bh) {
+ affs_brelse(bh);
+ iput(oldinode);
+ iput(dir);
+ return -EEXIST;
+ }
+ if (oldinode->u.affs_i.i_hlink) {
+ i = oldinode->u.affs_i.i_original;
+ iput(oldinode);
+ oldinode = iget(dir->i_sb,i);
+ if (!oldinode) {
+ printk("AFFS: link(): original does not exist.\n");
+ iput(dir);
+ return -ENOENT;
+ }
+ }
+ inode = affs_new_inode(dir);
+ if (!inode) {
+ iput(oldinode);
+ iput(dir);
+ return -ENOSPC;
+ }
+ inode->i_op = oldinode->i_op;
+ inode->i_mode = oldinode->i_mode;
+ inode->i_uid = oldinode->i_uid;
+ inode->i_gid = oldinode->i_gid;
+ inode->u.affs_i.i_protect = mode_to_prot(inode->i_mode);
+ inode->u.affs_i.i_original = oldinode->i_ino;
+ inode->u.affs_i.i_hlink = 1;
+
+ if (S_ISDIR(oldinode->i_mode))
+ error = affs_add_entry(dir,oldinode,inode,name,len,ST_LINKDIR);
+ else
+ error = affs_add_entry(dir,oldinode,inode,name,len,ST_LINKFILE);
+ if (error) {
+ inode->i_nlink = 0;
+ inode->i_dirt = 1;
+ }
+ iput(dir);
+ iput(inode);
+ iput(oldinode);
+
+ return error;
+}
+
+static int
+subdir(struct inode * new_inode, struct inode * old_inode)
+{
+ int ino;
+ int result;
+
+ new_inode->i_count++;
+ result = 0;
+ for (;;) {
+ if (new_inode == old_inode) {
+ result = 1;
+ break;
+ }
+ if (new_inode->i_dev != old_inode->i_dev)
+ break;
+ ino = new_inode->i_ino;
+ if (affs_lookup(new_inode,"..",2,&new_inode))
+ break;
+ if (new_inode->i_ino == ino)
+ break;
+ }
+ iput(new_inode);
+ return result;
+}
+
+/* I'm afraid this might not be race proof. Maybe next time. */
+
+int
+affs_rename(struct inode *old_dir, const char *old_name, int old_len,
+ struct inode *new_dir, const char *new_name, int new_len)
+{
+ struct inode *old_inode;
+ struct inode *new_inode;
+ struct buffer_head *old_bh;
+ struct buffer_head *new_bh;
+ unsigned long old_ino;
+ unsigned long new_ino;
+ int retval;
+
+ pr_debug("AFFS: rename(old=%lu,\"%*s\" to new=%lu,\"%*s\")\n",old_dir->i_ino,old_len,old_name,
+ new_dir->i_ino,new_len,new_name);
+
+ if (new_len > 30)
+ new_len = 30;
+ goto start_up;
+retry:
+ affs_brelse(old_bh);
+ affs_brelse(new_bh);
+ iput(new_inode);
+ iput(old_inode);
+ current->counter = 0;
+ schedule();
+start_up:
+ old_inode = new_inode = NULL;
+ old_bh = new_bh = NULL;
+ retval = -ENOENT;
+
+ old_bh = affs_find_entry(old_dir,old_name,old_len,&old_ino);
+ if (!old_bh)
+ goto end_rename;
+ old_inode = __iget(old_dir->i_sb,old_ino,0);
+ if (!old_inode)
+ goto end_rename;
+ new_bh = affs_find_entry(new_dir,new_name,new_len,&new_ino);
+ if (new_bh) {
+ new_inode = __iget(new_dir->i_sb,new_ino,0);
+ if (!new_inode) { /* What does this mean? */
+ affs_brelse(new_bh);
+ new_bh = NULL;
+ }
+ }
+ if (new_inode == old_inode) { /* Won't happen */
+ retval = 0;
+ goto end_rename;
+ }
+ if (new_inode && S_ISDIR(new_inode->i_mode)) {
+ retval = -EISDIR;
+ if (!S_ISDIR(old_inode->i_mode))
+ goto end_rename;
+ retval = -EINVAL;
+ if (subdir(new_dir,old_inode))
+ goto end_rename;
+ retval = -ENOTEMPTY;
+ if (!empty_dir(new_bh,AFFS_I2HSIZE(new_inode)))
+ goto end_rename;
+ retval = -EBUSY;
+ if (new_inode->i_count > 1)
+ goto end_rename;
+ }
+ if (S_ISDIR(old_inode->i_mode)) {
+ retval = -ENOTDIR;
+ if (new_inode && !S_ISDIR(new_inode->i_mode))
+ goto end_rename;
+ retval = -EINVAL;
+ if (subdir(new_dir,old_inode))
+ goto end_rename;
+ if (affs_parent_ino(old_inode) != old_dir->i_ino)
+ goto end_rename;
+ }
+ /* Unlink destination if existant */
+ if (new_inode) {
+ if ((retval = affs_fix_hash_pred(new_dir,affs_hash_name(new_name,new_len,
+ AFFS_I2FSTYPE(new_dir),AFFS_I2HSIZE(new_dir)) + 6,
+ new_ino,
+ FILE_END(new_bh->b_data,new_dir)->hash_chain)))
+ goto retry;
+ if ((retval = affs_fixup(new_bh,new_inode)))
+ goto retry;
+ mark_buffer_dirty(new_bh,1);
+ new_dir->i_version = ++event;
+ new_dir->i_dirt = 1;
+ new_inode->i_nlink = 0;
+ new_inode->i_dirt = 1;
+ }
+ retval = affs_fix_hash_pred(old_dir,affs_hash_name(old_name,old_len,AFFS_I2FSTYPE(old_dir),
+ AFFS_I2HSIZE(old_dir)) + 6,old_ino,
+ FILE_END(old_bh->b_data,old_dir)->hash_chain);
+ if (retval)
+ goto retry;
+
+ retval = affs_add_entry(new_dir,NULL,old_inode,new_name,new_len,
+ htonl(FILE_END(old_bh->b_data,old_dir)->secondary_type));
+
+ new_dir->i_ctime = new_dir->i_mtime = old_dir->i_ctime = old_dir->i_mtime = CURRENT_TIME;
+ new_dir->i_version = ++event;
+ old_dir->i_version = ++event;
+ new_dir->i_dirt = 1;
+ old_dir->i_dirt = 1;
+ mark_buffer_dirty(old_bh,1);
+
+end_rename:
+ affs_brelse(old_bh);
+ affs_brelse(new_bh);
+ iput(new_inode);
+ iput(old_inode);
+ iput(old_dir);
+ iput(new_dir);
+
+ return retval;
+}
+
+int
+affs_fixup(struct buffer_head *bh, struct inode *inode)
+{
+ ULONG key, link_key;
+ LONG type;
+ struct buffer_head *nbh;
+ struct inode *ofinode;
+
+ type = htonl(FILE_END(bh->b_data,inode)->secondary_type);
+ if (type == ST_LINKFILE || type == ST_LINKDIR) {
+ key = htonl(LINK_END(bh->b_data,inode)->original);
+ LINK_END(bh->b_data,inode)->original = 0;
+ if (!key) {
+ printk("AFFS: fixup(): hard link without original: ino=%lu\n",inode->i_ino);
+ return -ENOENT;
+ }
+ if (!(ofinode = iget(inode->i_sb,key)))
+ return -ENOENT;
+ type = affs_fix_link_pred(ofinode,inode->i_ino,
+ FILE_END(bh->b_data,inode)->link_chain);
+ iput(ofinode);
+ return type;
+ } else if (type == ST_FILE || type == ST_USERDIR) {
+ if ((key = htonl(FILE_END(bh->b_data,inode)->link_chain))) {
+ /* Get first link, turn it to a file */
+ if (!(ofinode = iget(inode->i_sb,key))) {
+ printk("AFFS: fixup(): cannot read inode %u\n",key);
+ return -ENOENT;
+ }
+ if (!ofinode->u.affs_i.i_hlink) {
+ printk("AFFS: fixup(): first link to %lu (%u) is not a link?\n",
+ inode->i_ino,key);
+ iput(ofinode);
+ return -ENOENT;
+ }
+ if (!(nbh = affs_bread(inode->i_dev,key,AFFS_I2BSIZE(inode)))) {
+ printk("AFFS: fixup(): cannot read block %u\n",key);
+ iput(ofinode);
+ return -ENOENT;
+ }
+ lock_super(inode->i_sb);
+ memcpy(nbh->b_data + 8,bh->b_data + 8,AFFS_I2BSIZE(inode) - 208);
+ FILE_END(nbh->b_data,inode)->byte_size = FILE_END(bh->b_data,inode)->
+ byte_size;
+ FILE_END(nbh->b_data,inode)->extension = FILE_END(bh->b_data,inode)->
+ extension;
+ FILE_END(nbh->b_data,inode)->secondary_type = FILE_END(bh->b_data,inode)->
+ secondary_type;
+ FILE_END(nbh->b_data,inode)->original = 0;
+
+ ofinode->u.affs_i.i_original = 0;
+ ofinode->u.affs_i.i_hlink = 0;
+ ofinode->i_size = inode->i_size;
+ ofinode->i_uid = inode->i_uid;
+ ofinode->i_gid = inode->i_gid;
+ ofinode->i_dirt = 1;
+ link_key = ofinode->i_ino;
+
+ /* Let all remaining links point to the new file */
+ while (1) {
+ affs_fix_checksum(AFFS_I2BSIZE(inode),nbh->b_data,5);
+ mark_buffer_dirty(nbh,1);
+ key = htonl(FILE_END(nbh->b_data,inode)->link_chain);
+ affs_brelse(nbh);
+ iput(ofinode);
+ if (!key || !(nbh = affs_bread(inode->i_dev,key,AFFS_I2BSIZE(inode))))
+ break;
+ if ((ofinode = iget(inode->i_sb,key))) {
+ if (!ofinode->u.affs_i.i_hlink)
+ printk("AFFS: fixup() inode %u in link chain is "
+ "not a link\n",key);
+ ofinode->u.affs_i.i_original = link_key;
+ ofinode->i_dirt = 1;
+ FILE_END(nbh->b_data,inode)->original = htonl(link_key);
+ } else
+ printk("AFFS: fixup(): cannot get inode %u\n",key);
+ }
+ /* Turn old inode to a link */
+ inode->u.affs_i.i_hlink = 1;
+ unlock_super(inode->i_sb);
+ }
+ return 0;
+ } else if (type == ST_SOFTLINK) {
+ return 0;
+ } else {
+ printk("AFFS: fixup(): secondary type=%d\n",type);
+ return -EBADF;
+ }
+}
-/*
- * linux/fs/affs/symlink.c
- *
- * (C) 1995 Joerg Dorchain Modified for Amiga FFS filesystem
- * based on:
- *
- * (C) 1992 Eric Youngdale Modified for ISO9660 filesystem.
- *
- * Copyright (C) 1991, 1992 Linus Torvalds
- *
- * isofs symlink handling code. This is only used with the Rock Ridge
- * extensions to iso9660
- */
-
-#include <asm/segment.h>
-
-#include <linux/errno.h>
-#include <linux/sched.h>
-#include <linux/fs.h>
-#include <linux/stat.h>
-#include <linux/malloc.h>
-#include <linux/affs_fs.h>
-
-#include "amigaffs.h"
-
-static int affs_readlink(struct inode *, char *, int);
-static int affs_follow_link(struct inode *, struct inode *, int, int, struct inode **);
-
-/*
- * symlinks can't do much...
- */
-struct inode_operations affs_symlink_inode_operations = {
- NULL, /* no file-operations */
- NULL, /* create */
- NULL, /* lookup */
- NULL, /* link */
- NULL, /* unlink */
- NULL, /* symlink */
- NULL, /* mkdir */
- NULL, /* rmdir */
- NULL, /* mknod */
- NULL, /* rename */
- affs_readlink, /* readlink */
- affs_follow_link, /* follow_link */
- NULL, /* bmap */
- NULL, /* truncate */
- NULL /* permission */
-};
-
-static int affs_follow_link(struct inode * dir, struct inode * inode,
- int flag, int mode, struct inode ** res_inode)
-{
- int error;
- char * pnt;
- struct buffer_head *bh;
- struct symlink_front *sy_data;
-
- if (!dir) {
- dir = current->fs->root;
- dir->i_count++;
- }
- if (!inode) {
- iput(dir);
- *res_inode = NULL;
- return -ENOENT;
- }
- if (!S_ISLNK(inode->i_mode)) {
- iput(dir);
- *res_inode = inode;
- return 0;
- }
- if (current->link_count > 5) {
- iput(dir);
- iput(inode);
- *res_inode = NULL;
- return -ELOOP;
- }
- if (!(bh = affs_pread(inode,inode->i_ino,(void **)&sy_data))) {
- printk("affs: unable to read block %ld",inode->i_ino);
- return 0;
- }
-
- pnt = sy_data->symname;
- iput(inode);
- current->link_count++;
- error = open_namei(pnt,flag,mode,res_inode,dir);
- current->link_count--;
- brelse(bh);
- return error;
-}
-
-static char *affs_conv_path(char *affs_path)
-{
-static char unix_path[1024]="/";
-int up,ap;
-char dp,slash;
-
-
-dp=1;
-slash=1;
-ap=0;
-up=1;
-if (affs_path[0] == 0)
- unix_path[up++]='.';
-while ((up < 1020) && (affs_path[ap]!=0))
- {
- switch (affs_path[ap]) {
- case ':':
- if (dp == 0) {
- slash=0;
- unix_path[up++]=':';
- }
- else {
- dp=0;
- slash=1;
- unix_path[up++]='/';
- }
- break;
- case '/':
- if (slash==0) {
- slash=1;
- unix_path[up++]='/';
- }
- else {
- unix_path[up++]='.';
- unix_path[up++]='.';
- unix_path[up++]='/';
- }
- break;
- default:
- slash=0;
- unix_path[up++]=affs_path[ap];
- break;
- }
- ap++;
- }
-unix_path[up]=0;
-return unix_path+dp;
-}
-
-
-static int affs_readlink(struct inode * inode, char * buffer, int buflen)
-{
- char * pnt;
- int i;
- char c;
- struct buffer_head *bh;
- struct symlink_front *sy_data;
-
- if (!S_ISLNK(inode->i_mode)) {
- iput(inode);
- return -EINVAL;
- }
-
- if (buflen > 1023)
- buflen = 1023;
-
- if (!(bh = affs_pread(inode,inode->i_ino,(void **)&sy_data))) {
- printk("affs: unable to read block %ld\n",inode->i_ino);
- return -ENOENT;
- }
-
- iput(inode);
-
- pnt = sy_data->symname;
- if (inode->i_sb->u.affs_sb.s_options.conv_links != 0)
- pnt = affs_conv_path(pnt);
-
- i = 0;
-
- while (i<buflen && (c = pnt[i])) {
- i++;
- put_fs_byte(c,buffer++);
- }
-
- brelse(bh);
-
- return i;
-}
+/*
+ * linux/fs/affs/symlink.c
+ *
+ * 1995 Hans-Joachim Widmaier - modified for AFFS.
+ *
+ * Copyright (C) 1991, 1992 Linus Torvalds
+ *
+ * affs symlink handling code
+ */
+
+#include <linux/errno.h>
+#include <linux/sched.h>
+#include <linux/malloc.h>
+#include <linux/fs.h>
+#include <linux/stat.h>
+#include <linux/affs_fs.h>
+#include <linux/amigaffs.h>
+
+#include <asm/segment.h>
+
+#define MIN(a,b) (((a) < (b)) ? (a) : (b))
+
+static int affs_readlink(struct inode *, char *, int);
+static int affs_follow_link(struct inode *, struct inode *, int, int, struct inode **);
+
+struct inode_operations affs_symlink_inode_operations = {
+ NULL, /* no file-operations */
+ NULL, /* create */
+ NULL, /* lookup */
+ NULL, /* link */
+ NULL, /* unlink */
+ NULL, /* symlink */
+ NULL, /* mkdir */
+ NULL, /* rmdir */
+ NULL, /* mknod */
+ NULL, /* rename */
+ affs_readlink, /* readlink */
+ affs_follow_link, /* follow_link */
+ NULL, /* bmap */
+ NULL, /* truncate */
+ NULL /* permission */
+};
+
+static int
+affs_follow_link(struct inode *dir, struct inode *inode, int flag, int mode,
+ struct inode **res_inode)
+{
+ struct buffer_head *bh;
+ struct slink_front *lf;
+ char *buffer;
+ int error;
+ int i, j;
+ char c;
+ char lc;
+
+ pr_debug("AFFS: follow_link(ino=%lu)\n",inode->i_ino);
+
+ *res_inode = NULL;
+ if (!dir) {
+ dir = current->fs->root;
+ dir->i_count++;
+ }
+ if (!inode) {
+ iput(dir);
+ return -ENOENT;
+ }
+ if (!S_ISLNK(inode->i_mode)) {
+ iput(dir);
+ *res_inode = inode;
+ return 0;
+ }
+ if (current->link_count > 5) {
+ iput(inode);
+ iput(dir);
+ return -ELOOP;
+ }
+ if (!(buffer = kmalloc(1024,GFP_KERNEL))) {
+ iput(inode);
+ iput(dir);
+ return -ENOSPC;
+ }
+ bh = affs_bread(inode->i_dev,inode->i_ino,AFFS_I2BSIZE(inode));
+ i = 0;
+ j = 0;
+ if (!bh) {
+ printk("AFFS: unable to read i-node block %lu\n",inode->i_ino);
+ kfree(buffer);
+ iput(inode);
+ iput(dir);
+ return -EIO;
+ }
+ lf = (struct slink_front *)bh->b_data;
+ lc = 0;
+ if (strchr(lf->symname,':')) { /* Handle assign or volume name */
+ while (i < 1023 && (c = inode->i_sb->u.affs_sb.s_prefix[i]))
+ buffer[i++] = c;
+ while (i < 1023 && lf->symname[j] != ':')
+ buffer[i++] = lf->symname[j++];
+ if (i < 1023)
+ buffer[i++] = '/';
+ j++;
+ lc = '/';
+ }
+ while (i < 1023 && (c = lf->symname[j])) {
+ if (c == '/' && lc == '/' && i < 1020) { /* parent dir */
+ buffer[i++] = '.';
+ buffer[i++] = '.';
+ }
+ buffer[i++] = c;
+ lc = c;
+ j++;
+ }
+ buffer[i] = '\0';
+ affs_brelse(bh);
+ iput(inode);
+ current->link_count++;
+ error = open_namei(buffer,flag,mode,res_inode,dir);
+ current->link_count--;
+ kfree(buffer);
+ return error;
+}
+
+static int
+affs_readlink(struct inode *inode, char *buffer, int buflen)
+{
+ struct buffer_head *bh;
+ struct slink_front *lf;
+ int i, j;
+ char c;
+ char lc;
+
+ pr_debug("AFFS: readlink(ino=%lu,buflen=%d)\n",inode->i_ino,buflen);
+
+ if (!S_ISLNK(inode->i_mode)) {
+ iput(inode);
+ return -EINVAL;
+ }
+ bh = affs_bread(inode->i_dev,inode->i_ino,AFFS_I2BSIZE(inode));
+ i = 0;
+ j = 0;
+ if (!bh) {
+ printk("AFFS: unable to read i-node block %lu\n",inode->i_ino);
+ goto symlink_end;
+ }
+ lf = (struct slink_front *)bh->b_data;
+ lc = 0;
+
+ if (strchr(lf->symname,':')) { /* Handle assign or volume name */
+ while (i < buflen && (c = inode->i_sb->u.affs_sb.s_prefix[i])) {
+ put_user(c,buffer++);
+ i++;
+ }
+ while (i < buflen && (c = lf->symname[j]) != ':') {
+ put_user(c,buffer++);
+ i++, j++;
+ }
+ if (i < buflen) {
+ put_user('/',buffer++);
+ i++, j++;
+ }
+ lc = '/';
+ }
+ while (i < buflen && (c = lf->symname[j])) {
+ if (c == '/' && lc == '/' && (i + 3 < buflen)) { /* parent dir */
+ put_user('.',buffer++);
+ put_user('.',buffer++);
+ i += 2;
+ }
+ put_user(c,buffer++);
+ lc = c;
+ i++, j++;
+ }
+symlink_end:
+ iput(inode);
+ affs_brelse(bh);
+ return i;
+}
@@ -225,9+225,9 @@ int block_read(struct inode * inode, struct file * filp, char * buf, int count) if (block + blocks > size)
blocks = size - block;
- /* We do this in a two stage process. We first try and request
+ /* We do this in a two stage process. We first try to request
as many blocks as we can, then we wait for the first one to
- complete, and then we try and wrap up as many as are actually
+ complete, and then we try to wrap up as many as are actually
done. This routine is rather generic, in that it can be used
in a filesystem by substituting the appropriate function in
for getblk.
@@ -86,7+86,7 @@ union bdflush_param{ activate bdflush */
int ndirty; /* Maximum number of dirty blocks to write out per
wake-cycle */
- int nrefill; /* Number of clean buffers to try and obtain
+ int nrefill; /* Number of clean buffers to try to obtain
each time we call refill */
int nref_dirt; /* Dirty buffer threshold for activating bdflush
when trying to refill buffers. */
@@ -572,7+572,7 @@ void refill_freelist(int size) now so as to ensure that there are still clean buffers available
for user processes to use (and dirty) */
- /* We are going to try and locate this much memory */
+ /* We are going to try to locate this much memory */
needed =bdf_prm.b_un.nrefill * size;
while (nr_free_pages > min_free_pages*2 && needed > 0 &&
@@ -592,7+592,7 @@ void refill_freelist(int size) if(needed <= 0) return;
};
- /* OK, we cannot grow the buffer cache, now try and get some
+ /* OK, we cannot grow the buffer cache, now try to get some
from the lru list */
/* First set the candidate pointers to usable buffers. This
@@ -885,8+885,7 @@ struct buffer_head * bread(kdev_t dev, int block, int size) struct buffer_head * bh;
if (!(bh = getblk(dev, block, size))) {
- printk("VFS: bread: READ error on device %s\n",
- kdevname(dev));
+ printk("VFS: bread: impossible error\n");
return NULL;
}
if (buffer_uptodate(bh))
@@ -1867,7+1866,7 @@ static void wakeup_bdflush(int wait)
/*
- * Here we attempt to write back old buffers. We also try and flush inodes
+ * Here we attempt to write back old buffers. We also try to flush inodes
* and supers as well, since this function is essentially "update", and
* otherwise there would be no way of ensuring that these quantities ever
* get written back. Ideally, we would have a timestamp on the inodes
@@ -113,9+113,9 @@ static int ext_file_read(struct inode * inode, struct file * filp, char * buf, i blocks = size - block;
}
- /* We do this in a two stage process. We first try and request
+ /* We do this in a two stage process. We first try to request
as many blocks as we can, then we wait for the first one to
- complete, and then we try and wrap up as many as are actually
+ complete, and then we try to wrap up as many as are actually
done. This routine is rather generic, in that it can be used
in a filesystem by substituting the appropriate function in
for getblk.
@@ -380,6+380,7 @@ static int vfat_ioctl_fill( int fat_dir_ioctl(struct inode * inode, struct file * filp,
unsigned int cmd, unsigned long arg)
{
+ int err;
/*
* We want to provide an interface for Samba to be able
* to get the short filename for a given long filename.
@@ -389,6+390,9 @@ int fat_dir_ioctl(struct inode * inode, struct file * filp, switch (cmd) {
case VFAT_IOCTL_READDIR_BOTH: {
struct dirent *d1 = (struct dirent *)arg;
+ err = verify_area(VERIFY_WRITE, d1, sizeof (*d1));
+ if (err)
+ return err;
put_user(0, &d1->d_reclen);
return fat_readdirx(inode,filp,(void *)arg,
vfat_ioctl_fill, NULL, 0, 1, 1);
@@ -396,6+400,9 @@ int fat_dir_ioctl(struct inode * inode, struct file * filp, case VFAT_IOCTL_READDIR_SHORT: {
struct dirent *d1 = (struct dirent *)arg;
put_user(0, &d1->d_reclen);
+ err = verify_area(VERIFY_WRITE, d1, sizeof (*d1));
+ if (err)
+ return err;
return fat_readdirx(inode,filp,(void *)arg,
vfat_ioctl_fill, NULL, 1, 0, 1);
}
@@ -17,8+17,8 @@ void fat_ll_rw_block (struct super_block *sb, int opr, /* These macros exist to avoid modifying all the code */
/* They should be removed one day I guess */
-/* The versioning mechanism of the modules system define those macros */
-/* This remove some warnings */
+/* The versioning mechanism of the modules system defines those macros */
+/* This removes some warnings */
#ifdef brelse
#undef brelse
#endif
@@ -88,15+88,15 @@ static int parse_options(char *options, struct iso9660_options * popt) if (strncmp(this_char,"norock",6) == 0) {
popt->rock = 'n';
continue;
- };
+ }
if (strncmp(this_char,"unhide",6) == 0) {
popt->unhide = 'y';
continue;
- };
+ }
if (strncmp(this_char,"cruft",5) == 0) {
popt->cruft = 'y';
continue;
- };
+ }
if ((value = strchr(this_char,'=')) != NULL)
*value++ = 0;
if (!strcmp(this_char,"map") && value) {
@@ -134,7+134,7 @@ static int parse_options(char *options, struct iso9660_options * popt) if(*vpnt < '0' || *vpnt > '9') break;
ivalue = ivalue * 10 + (*vpnt - '0');
vpnt++;
- };
+ }
if (*vpnt) return 0;
switch(*this_char) {
case 'b':
@@ -241,8+241,8 @@ struct super_block *isofs_read_super(struct super_block *s,void *data, while (i != 1){
blocksize_bits++;
i >>=1;
- };
- };
+ }
+ }
set_blocksize(dev, opt.blocksize);
lock_super(s);
@@ -251,15+251,15 @@ struct super_block *isofs_read_super(struct super_block *s,void *data,
vol_desc_start = isofs_get_last_session(dev);
- for (iso_blknum = vol_desc_start+16; iso_blknum < vol_desc_start+100; iso_blknum++) {
-#if 0
- printk("isofs.inode: iso_blknum=%d\n", iso_blknum);
-#endif 0
- if (!(bh = bread(dev, iso_blknum << (ISOFS_BLOCK_BITS-blocksize_bits), opt.blocksize))) {
+ for (iso_blknum = vol_desc_start+16;
+ iso_blknum < vol_desc_start+100; iso_blknum++) {
+ int b = iso_blknum << (ISOFS_BLOCK_BITS-blocksize_bits);
+
+ if (!(bh = bread(dev,b,opt.blocksize))) {
s->s_dev = 0;
printk("isofs_read_super: bread failed, dev "
- "%s iso_blknum %d\n",
- kdevname(dev), iso_blknum);
+ "%s iso_blknum %d block %d\n",
+ kdevname(dev), iso_blknum, b);
unlock_super(s);
MOD_DEC_USE_COUNT;
return NULL;
@@ -280,7+280,7 @@ struct super_block *isofs_read_super(struct super_block *s,void *data, opt.rock = 'n';
h_pri = (struct hs_primary_descriptor *)vdp;
break;
- };
+ }
if (strncmp (vdp->id, ISO_STANDARD_ID, sizeof vdp->id) == 0) {
if (isonum_711 (vdp->type) != ISO_VD_PRIMARY)
@@ -290,7+290,7 @@ struct super_block *isofs_read_super(struct super_block *s,void *data,
pri = (struct iso_primary_descriptor *)vdp;
break;
- };
+ }
brelse(bh);
}
@@ -301,8+301,7 @@ struct super_block *isofs_read_super(struct super_block *s,void *data, unlock_super(s);
MOD_DEC_USE_COUNT;
return NULL;
- };
-
+ }
if(high_sierra){
rootp = (struct iso_directory_record *) h_pri->root_directory_record;
@@ -311,7+310,7 @@ struct super_block *isofs_read_super(struct super_block *s,void *data, printk("Multi-volume disks not (yet) supported.\n");
goto out;
#endif
- };
+ }
s->u.isofs_sb.s_nzones = isonum_733 (h_pri->volume_space_size);
s->u.isofs_sb.s_log_zone_size = isonum_723 (h_pri->logical_block_size);
s->u.isofs_sb.s_max_size = isonum_733(h_pri->volume_space_size);
@@ -322,7+321,7 @@ struct super_block *isofs_read_super(struct super_block *s,void *data, printk("Multi-volume disks not (yet) supported.\n");
goto out;
#endif
- };
+ }
s->u.isofs_sb.s_nzones = isonum_733 (pri->volume_space_size);
s->u.isofs_sb.s_log_zone_size = isonum_723 (pri->logical_block_size);
s->u.isofs_sb.s_max_size = isonum_733(pri->volume_space_size);
@@ -793,7+792,7 @@ int isofs_lookup_grandparent(struct inode * parent, int extent) if(!(bh = bread(parent->i_dev,block,bufsize))) {
kfree(cpnt);
return -1;
- };
+ }
memcpy((char *)cpnt+frag1, bh->b_data, offset);
}
@@ -319,7+319,7 @@ int parse_rock_ridge_inode(struct iso_directory_record * de, break;
case SIG('T','F'):
/* Some RRIP writers incorrectly place ctime in the TF_CREATE field.
- Try and handle this correctly for either case. */
+ Try to handle this correctly for either case. */
cnt = 0; /* Rock ridge never appears on a High Sierra disk */
if(rr->u.TF.flags & TF_CREATE)
inode->i_ctime = iso_date(rr->u.TF.times[cnt++].time, 0);
@@ -639,7+639,7 @@ static int flock_lock_file(struct file *filp, struct file_lock *caller, locks_free_lock(new_fl);
return (-ERESTARTSYS);
}
- /* Try to avoid deadlocks due to pathalogical programs that
+ /* Try to avoid deadlocks due to pathological programs that
* mix calls to flock() and fcntl(). Return EAGAIN, because
* EDEADLOCK isn't a documented return value for flock().
*/
@@ -292,7+292,7 @@ static int root_rarp_recv(struct sk_buff *skb, struct device *dev, struct packet unsigned long sip, tip;
unsigned char *sha, *tha; /* s for "source", t for "target" */
- /* If this test doesn't pass, its not IP, or we should ignore it anyway */
+ /* If this test doesn't pass, it's not IP, or we should ignore it anyway */
if (rarp->ar_hln != dev->addr_len || dev->type != ntohs(rarp->ar_hrd)) {
kfree_skb(skb, FREE_READ);
return 0;
@@ -763,9+763,9 @@ static int root_bootp_string(char *dest, char *src, int len, int max) */
static void root_do_bootp_ext(u8 *ext)
{
+#ifdef NFSROOT_BOOTP_DEBUG
u8 *c;
-#ifdef NFSROOT_BOOTP_DEBUG
printk("BOOTP: Got extension %02x",*ext);
for(c=ext+2; c<ext+2+ext[1]; c++)
printk(" %02x", *c);
@@ -92,9+92,9 @@ struct vfsmount *add_vfsmnt(kdev_t dev, const char *dev_name, const char *dir_na struct vfsmount *lptr;
char *tmp;
- if ((lptr = (struct vfsmount *)
- kmalloc(sizeof(struct vfsmount), GFP_KERNEL)) == (struct vfsmount *)NULL)
- return ((struct vfsmount *)NULL);
+ lptr = (struct vfsmount *)kmalloc(sizeof(struct vfsmount), GFP_KERNEL);
+ if (!lptr)
+ return NULL;
memset(lptr, 0, sizeof(struct vfsmount));
lptr->mnt_dev = dev;
@@ -114,9+114,9 @@ int sysv_file_read(struct inode * inode, struct file * filp, char * buf, int cou blocks = size - block;
}
- /* We do this in a two stage process. We first try and request
+ /* We do this in a two stage process. We first try to request
as many blocks as we can, then we wait for the first one to
- complete, and then we try and wrap up as many as are actually
+ complete, and then we try to wrap up as many as are actually
done. This routine is rather generic, in that it can be used
in a filesystem by substituting the appropriate function in
for getblk.
/*
* Kernel module support added on 96/04/26 by
* Stefan Reinauer <stepan@home.culture.mipt.ru>
+ *
+ * Module usage counts added on 96/04/29 by
+ * Gertjan van Wingerde <gertjan@cs.vu.nl>
*/
#include <linux/module.h>
@@ -433,7+433,7 @@ static int umsdos_symlink_x( in unused entry of the EMD file. The other is to have a separate
file dedicated to hold all symbolic links data.
- Lets go for simplicity...
+ Let's go for simplicity...
*/
struct inode *inode;
int ret;
# Note 2! The CFLAGS definitions are now in the main makefile...
O_TARGET := vfat.o
-O_OBJS := namei.o
-OX_OBJS :=
+O_OBJS :=
+OX_OBJS := namei.o
M_OBJS := $(O_TARGET)
include $(TOPDIR)/Rules.make
@@ -1569,12+1569,26 @@ static struct file_system_type vfat_fs_type = { vfat_read_super, "vfat", 1, NULL
};
+static struct symbol_table vfat_syms = {
+#include <linux/symtab_begin.h>
+ X(vfat_create),
+ X(vfat_unlink),
+ X(vfat_mkdir),
+ X(vfat_rmdir),
+ X(vfat_rename),
+ X(vfat_put_super),
+ X(vfat_read_super),
+ X(vfat_read_inode),
+ X(vfat_lookup),
+#include <linux/symtab_end.h>
+};
+
int init_vfat_fs(void)
{
int status;
if ((status = register_filesystem(&vfat_fs_type)) == 0)
- status = register_symtab(0);
+ status = register_symtab(&vfat_syms);
return status;
}
@@ -106,9+106,9 @@ xiafs_file_read(struct inode * inode, struct file * filp, char * buf, int count) zones = f_zones - zone_nr;
}
- /* We do this in a two stage process. We first try and request
+ /* We do this in a two stage process. We first try to request
as many blocks as we can, then we wait for the first one to
- complete, and then we try and wrap up as many as are actually
+ complete, and then we try to wrap up as many as are actually
done. This routine is rather generic, in that it can be used
in a filesystem by substituting the appropriate function in
for getblk.
@@ -21,7+21,7 @@ extern __inline__ void prim_spin_lock(struct spinlock *sp) while(lock_set_bit(0,&sp->lock))
{
/*
- * Failed, but thats cos we own it!
+ * Failed, but that's cos we own it!
*/
if(sp->cpu==processor)
@@ -45,7+45,7 @@ extern __inline__ void prim_spin_lock(struct spinlock *sp) }
/*
* Someone wrote the line, we go 'I' and get
- * the cache entry. Now try and regrab
+ * the cache entry. Now try to regrab
*/
}
sp->users++;sp->cpu=processor;
@@ -117,7+117,7 @@ extern __inline__ void spinunlock(struct spinlock *sp) extern __inline__ void spintestlock(struct spinlock *sp)
{
/*
- * We do no sanity checks, its legal to optimistically
+ * We do no sanity checks, it's legal to optimistically
* get a lower lock.
*/
prim_spin_lock_nb(sp);
* We do not have SMP m68k systems, so we don't have to deal with that.
*/
-/*
- * Make sure gcc doesn't try to be clever and move things around
- * on us. We need to use _exactly_ the address the user gave us,
- * not some alias that contains the same information.
- */
-#define __atomic_fool_gcc(x) (*(struct { int a[100]; } *)x)
-
typedef int atomic_t;
static __inline__ void atomic_add(atomic_t i, atomic_t *v)
{
- __asm__ __volatile__(
- "addl %1,%0"
- :"=m" (__atomic_fool_gcc(v))
- :"ir" (i), "0" (__atomic_fool_gcc(v)));
+ __asm__ __volatile__("addl %1,%0" : : "m" (*v), "id" (i));
}
static __inline__ void atomic_sub(atomic_t i, atomic_t *v)
{
- __asm__ __volatile__(
- "subl %1,%0"
- :"=m" (__atomic_fool_gcc(v))
- :"ir" (i), "0" (__atomic_fool_gcc(v)));
+ __asm__ __volatile__("subl %1,%0" : : "m" (*v), "id" (i));
}
static __inline__ void atomic_inc(atomic_t *v)
{
- __asm__ __volatile__(
- "addql #1,%0"
- :"=m" (__atomic_fool_gcc(v))
- :"0" (__atomic_fool_gcc(v)));
+ __asm__ __volatile__("addql #1,%0" : : "m" (*v));
}
static __inline__ void atomic_dec(atomic_t *v)
{
- __asm__ __volatile__(
- "subql #1,%0"
- :"=m" (__atomic_fool_gcc(v))
- :"0" (__atomic_fool_gcc(v)));
+ __asm__ __volatile__("subql #1,%0" : : "m" (*v));
}
static __inline__ int atomic_dec_and_test(atomic_t *v)
{
char c;
- __asm__ __volatile__(
- "subql #1,%0; seq %1"
- :"=m" (__atomic_fool_gcc(v)), "=d" (c)
- :"0" (__atomic_fool_gcc(v)));
+ __asm__ __volatile__("subql #1,%1; seq %0" : "=d" (c) : "m" (*v));
return c != 0;
}
@@ -111,6+111,54 @@ extern __inline__ unsigned long ffz(unsigned long word) return res ^ 31;
}
+extern __inline__ int find_first_one_bit(void * vaddr, unsigned size)
+{
+ unsigned long *p = vaddr, *addr = vaddr;
+ int res;
+ unsigned long num;
+
+ if (!size)
+ return 0;
+
+ while (!*p++)
+ {
+ if (size <= 32)
+ return (p - addr) << 5;
+ size -= 32;
+ }
+
+ num = *--p;
+ __asm__ __volatile__ ("bfffo %1{#0,#0},%0"
+ : "=d" (res) : "d" (num & -num));
+ return ((p - addr) << 5) + (res ^ 31);
+}
+
+extern __inline__ int find_next_one_bit (void *vaddr, int size,
+ int offset)
+{
+ unsigned long *addr = vaddr;
+ unsigned long *p = addr + (offset >> 5);
+ int set = 0, bit = offset & 31UL, res;
+
+ if (offset >= size)
+ return size;
+
+ if (bit) {
+ unsigned long num = *p & (~0UL << bit);
+
+ /* Look for one in first longword */
+ __asm__ __volatile__ ("bfffo %1{#0,#0},%0"
+ : "=d" (res) : "d" (num & -num));
+ if (res < 32)
+ return (offset & ~31UL) + (res ^ 31);
+ set = 32 - bit;
+ p++;
+ }
+ /* No one yet, search remaining full bytes for a one */
+ res = find_first_one_bit (p, size - 32 * (p - addr));
+ return (offset + set + res);
+}
+
/* Bitmap functions for the minix filesystem */
extern __inline__ int
@@ -108,7+108,6 @@ static inline unsigned int csum_fold(unsigned int sum) * in icmp.c
*/
-#if 1
static inline unsigned short
ip_compute_csum(unsigned char * buff, int len)
{
@@ -124,52+123,5 @@ ip_compute_csum(unsigned char * buff, int len) : "0" (csum_partial(buff, len, 0)));
return ~sum;
}
-#else
-static inline unsigned short
-ip_compute_csum(unsigned char * buff, int len)
-{
- unsigned long sum = 0;
-
- /* Do the first multiple of 4 bytes and convert to 16 bits. */
- if (len > 3)
- {
- int dummy;
- __asm__ ("subql #1,%2\n\t"
- "1:\t"
- "movel %1@+,%/d0\n\t"
- "addxl %/d0,%0\n\t"
- "dbra %2,1b\n\t"
- "movel %0,%/d0\n\t"
- "swap %/d0\n\t"
- "addxw %/d0,%0\n\t"
- "clrw %/d0\n\t"
- "addxw %/d0,%0"
- : "=d" (sum), "=a" (buff), "=d" (dummy)
- : "0" (sum), "1" (buff), "2" (len >> 2)
- : "d0");
- }
- if (len & 2)
- {
- __asm__ ("addw %1@+,%0\n\t"
- "addxw %2,%0"
- : "=d" (sum), "=a" (buff)
- : "d" (0), "0" (sum), "1" (buff));
- }
- if (len & 1)
- {
- __asm__ ("movew %1@,%/d0\n\t"
- "clrb %/d0\n\t"
- "addw %/d0,%0\n\t"
- "clrw %/d0\n\t"
- "addxw %/d0,%0"
- : "=d" (sum)
- : "a" (buff), "0" (sum)
- : "d0");
- }
-
- sum =~sum;
- return(sum & 0xffff);
-}
-#endif
#endif /* _M68K_CHECKSUM_H */
@@ -12,11+12,6 @@ typedef unsigned long elf_greg_t; #define ELF_NGREG 20 /* d1-d7/a0-a6/d0/usp/orig_d0/sr/pc/fmtvec */
typedef elf_greg_t elf_gregset_t[ELF_NGREG];
-/* XXX temporary */
-/*
-typedef unsigned long elf_fpregset_t;
-*/
-
typedef struct user_m68kfp_struct elf_fpregset_t;
#endif
__asm__ __volatile__("pflusha\n"::); \
} while (0)
-#if 1
static inline void __flush_tlb_one(unsigned long addr)
{
if (m68k_is040or060) {
@@ -24,9+23,6 @@ static inline void __flush_tlb_one(unsigned long addr) } else
__asm__ __volatile__("pflush #0,#0,(%0)" : : "a" (addr));
}
-#else
-#define __flush_tlb_one(addr) __flush_tlb()
-#endif
#define flush_tlb() __flush_tlb()
#define flush_tlb_all() flush_tlb()
@@ -573,15+569,14 @@ extern inline void update_mmu_cache(struct vm_area_struct * vma,
/*
* I don't know what is going on here, but since these were changed,
- * swapping haven't been working on the 68040.
+ * swapping hasn't been working on the 68040.
*/
-#if 0
#define SWP_TYPE(entry) (((entry) >> 2) & 0x7f)
+#if 0
#define SWP_OFFSET(entry) ((entry) >> 9)
#define SWP_ENTRY(type,offset) (((type) << 2) | ((offset) << 9))
#else
-#define SWP_TYPE(entry) (((entry) & 0x1fc) >> 2)
#define SWP_OFFSET(entry) ((entry) >> PAGE_SHIFT)
#define SWP_ENTRY(type,offset) (((type) << 2) | ((offset) << PAGE_SHIFT))
#endif
--- /dev/null
+/*
+ * include/linux/serial.h
+ *
+ * Copyright (C) 1992 by Theodore Ts'o.
+ *
+ * Redistribution of this file is permitted under the terms of the GNU
+ * Public License (GPL)
+ */
+
+#ifndef _M68K_SERIAL_H
+#define _M68K_SERIAL_H
+
+
+/* m68k serial port types are numbered from 100 to avoid interference
+ * with the PC types (1..4)
+ */
+#define PORT_UNKNOWN 0
+#define PORT_8250 1
+#define PORT_16450 2
+#define PORT_16550 3
+#define PORT_16550A 4
+#define PORT_CIRRUS 5
+#define SER_SCC_NORM 100 /* standard SCC channel */
+#define SER_SCC_DMA 101 /* SCC channel with DMA support */
+#define SER_MFP_CTRL 102 /* standard MFP port with modem control signals */
+#define SER_MFP_BARE 103 /* MFP port without modem controls */
+#define SER_MIDI 104 /* Atari MIDI */
+#define SER_AMIGA 105 /* Amiga built-in serial port */
+#define SER_IOEXT 106 /* Amiga GVP IO-Extender (16c552) */
+#define SER_MFC_III 107 /* Amiga BSC Multiface Card III (MC68681) */
+
+
+struct serial_struct {
+ int type;
+ int line;
+ int port;
+ int irq;
+ int flags;
+ int xmit_fifo_size;
+ int custom_divisor;
+ int baud_base;
+ unsigned short close_delay;
+ char reserved_char[2];
+ int hub6;
+ unsigned short closing_wait; /* time to wait before closing */
+ unsigned short closing_wait2; /* no longer used... */
+ int reserved[4];
+};
+
+/*
+ * For the close wait times, 0 means wait forever for serial port to
+ * flush its output. 65535 means don't wait at all.
+ */
+#define ASYNC_CLOSING_WAIT_INF 0
+#define ASYNC_CLOSING_WAIT_NONE 65535
+
+/* This function tables does the abstraction from the underlying
+ * hardware:
+ *
+ * init(): Initialize the port as necessary, set RTS and DTR and
+ * enable interrupts. It does not need to set the speed and other
+ * parameters, because change_speed() is called, too.
+ * deinit(): Stop and shutdown the port (e.g. disable interrupts, ...)
+ * enab_tx_int(): Enable or disable the Tx Buffer Empty interrupt
+ * independently from other interrupt sources. If the int is
+ * enabled, the transmitter should also be restarted, i.e. if there
+ * are any chars to be sent, they should be put into the Tx
+ * register. The real en/disabling of the interrupt may be a no-op
+ * if there is no way to do this or it is too complex. This Tx ints
+ * are just disabled to save some interrupts if the transmitter is
+ * stopped anyway. But the restarting must be implemented!
+ * check_custom_divisor(): Check the given custom divisor for legality
+ * and return 0 if OK, non-zero otherwise.
+ * change_speed(): Set port speed, character size, number of stop
+ * bits and parity from the termios structure. If the user wants
+ * to set the speed with a custom divisor, he is required to
+ * check the baud_base first!
+ * throttle(): Set or clear the RTS line according to 'status'.
+ * set_break(): Set or clear the 'Send a Break' flag.
+ * get_serial_info(): Fill in the baud_base and custom_divisor
+ * fields of a serial_struct. It may also modify other fields, if
+ * needed.
+ * get_modem_info(): Return the status of RTS, DTR, DCD, RI, DSR and CTS.
+ * set_modem_info(): Set the status of RTS and DTR according to
+ * 'new_dtr' and 'new_rts', resp. 0 = clear, 1 = set, -1 = don't change
+ * ioctl(): Process any port-specific ioctl's. This pointer may be
+ * NULL, if the port has no own ioctl's.
+ * stop_receive(): Turn off the Rx part of the port, so no more characters
+ * will be received. This is called before shutting the port down.
+ * trans_empty(): Return !=0 if there are no more characters still to be
+ * sent out (Tx buffer register and FIFOs empty)
+ * check_open(): Is called before the port is opened. The driver can check
+ * if that's ok and return an error code, or keep track of the opening
+ * even before init() is called. Use deinit() for matching closing of the
+ * port.
+ *
+ */
+
+struct async_struct;
+
+typedef struct {
+ void (*init)( struct async_struct *info );
+ void (*deinit)( struct async_struct *info, int leave_dtr );
+ void (*enab_tx_int)( struct async_struct *info, int enab_flag );
+ int (*check_custom_divisor)( struct async_struct *info, int baud_base,
+ int divisor );
+ void (*change_speed)( struct async_struct *info );
+ void (*throttle)( struct async_struct *info, int status );
+ void (*set_break)( struct async_struct *info, int break_flag );
+ void (*get_serial_info)( struct async_struct *info,
+ struct serial_struct *retinfo );
+ unsigned int (*get_modem_info)( struct async_struct *info );
+ int (*set_modem_info)( struct async_struct *info, int new_dtr,
+ int new_rts );
+ int (*ioctl)( struct tty_struct *tty, struct file *file,
+ struct async_struct *info, unsigned int cmd,
+ unsigned long arg );
+ void (*stop_receive)( struct async_struct *info );
+ int (*trans_empty)( struct async_struct *info );
+ int (*check_open)( struct async_struct *info, struct tty_struct *tty,
+ struct file *file );
+} SERIALSWITCH;
+
+/*
+ * Definitions for async_struct (and serial_struct) flags field
+ */
+#define ASYNC_HUP_NOTIFY 0x0001 /* Notify getty on hangups and closes
+ on the callout port */
+#define ASYNC_FOURPORT 0x0002 /* Set OU1, OUT2 per AST Fourport settings */
+#define ASYNC_SAK 0x0004 /* Secure Attention Key (Orange book) */
+#define ASYNC_SPLIT_TERMIOS 0x0008 /* Separate termios for dialin/callout */
+
+#define ASYNC_SPD_MASK 0x0030
+#define ASYNC_SPD_HI 0x0010 /* Use 56000 instead of 38400 bps */
+
+#define ASYNC_SPD_VHI 0x0020 /* Use 115200 instead of 38400 bps */
+#define ASYNC_SPD_CUST 0x0030 /* Use user-specified divisor */
+
+#define ASYNC_SKIP_TEST 0x0040 /* Skip UART test during autoconfiguration */
+#define ASYNC_AUTO_IRQ 0x0080 /* Do automatic IRQ during autoconfiguration */
+#define ASYNC_SESSION_LOCKOUT 0x0100 /* Lock out cua opens based on session */
+#define ASYNC_PGRP_LOCKOUT 0x0200 /* Lock out cua opens based on pgrp */
+#define ASYNC_CALLOUT_NOHUP 0x0400 /* Don't do hangups for cua device */
+
+#define ASYNC_FLAGS 0x0FFF /* Possible legal async flags */
+#define ASYNC_USR_MASK 0x0430 /* Legal flags that non-privileged
+ * users can set or reset */
+
+/* Internal flags used only by drivers/char/m68kserial.c */
+#define ASYNC_INITIALIZED 0x80000000 /* Serial port was initialized */
+#define ASYNC_CALLOUT_ACTIVE 0x40000000 /* Call out device is active */
+#define ASYNC_NORMAL_ACTIVE 0x20000000 /* Normal device is active */
+#define ASYNC_BOOT_AUTOCONF 0x10000000 /* Autoconfigure port on bootup */
+#define ASYNC_CLOSING 0x08000000 /* Serial port is closing */
+#define ASYNC_CTS_FLOW 0x04000000 /* Do CTS flow control */
+#define ASYNC_CHECK_CD 0x02000000 /* i.e., CLOCAL */
+
+/*
+ * Serial input interrupt line counters -- external structure
+ * Four lines can interrupt: CTS, DSR, RI, DCD
+ */
+struct serial_icounter_struct {
+ int cts, dsr, rng, dcd;
+ int reserved[16];
+};
+
+
+#ifdef __KERNEL__
+/*
+ * This is our internal structure for each serial port's state.
+ *
+ * Many fields are paralleled by the structure used by the serial_struct
+ * structure.
+ *
+ * For definitions of the flags field, see tty.h
+ */
+
+#include <linux/termios.h>
+#include <linux/tqueue.h>
+
+/*
+ * Counters of the input lines (CTS, DSR, RI, CD) interrupts
+ */
+struct async_icount {
+ __u32 cts, dsr, rng, dcd;
+};
+
+struct async_struct {
+ int magic;
+ int baud_base;
+ int port;
+ int irq;
+ int flags; /* defined in tty.h */
+ int hub6; /* HUB6 plus one */
+ int type;
+ struct tty_struct *tty;
+ int read_status_mask;
+ int ignore_status_mask;
+ int timeout;
+ int xmit_fifo_size;
+ int custom_divisor;
+ int x_char; /* xon/xoff character */
+ int close_delay;
+ unsigned short closing_wait;
+ unsigned short closing_wait2;
+ int IER; /* Interrupt Enable Register */
+ int MCR; /* Modem control register */
+ int MCR_noint; /* MCR with interrupts off */
+ unsigned long event;
+ unsigned long last_active;
+ int line;
+ int count; /* # of fd on device */
+ int blocked_open; /* # of blocked opens */
+ long session; /* Session of opening process */
+ long pgrp; /* pgrp of opening process */
+ unsigned char *xmit_buf;
+ int xmit_head;
+ int xmit_tail;
+ int xmit_cnt;
+ struct tq_struct tqueue;
+ struct tq_struct tqueue_hangup;
+ struct termios normal_termios;
+ struct termios callout_termios;
+ struct wait_queue *open_wait;
+ struct wait_queue *close_wait;
+ struct wait_queue *delta_msr_wait;
+ struct async_icount icount; /* kernel counters for the 4 input interrupts */
+ struct async_struct *next_port; /* For the linked list */
+ struct async_struct *prev_port;
+ void *board_base; /* board-base address for use with
+ boards carrying several UART's,
+ like some Amiga boards. */
+ unsigned short nr_uarts; /* UART-counter, that indicates
+ how manu UART's there are on
+ the board. If the board has a
+ IRQ-register, this can be used
+ to check if any of the uarts,
+ on the board has requested an
+ interrupt, instead of checking
+ IRQ-registers on all UART's */
+ SERIALSWITCH *sw; /* functions to manage this port */
+};
+
+#define SERIAL_MAGIC 0x5301
+
+/*
+ * The size of the serial xmit buffer is 1 page, or 4096 bytes
+ */
+#define SERIAL_XMIT_SIZE 4096
+
+/*
+ * Events are used to schedule things to happen at timer-interrupt
+ * time, instead of at rs interrupt time.
+ */
+#define RS_EVENT_WRITE_WAKEUP 0
+
+/* number of characters left in xmit buffer before we ask for more */
+#define WAKEUP_CHARS 256
+
+/* Export to allow PCMCIA to use this - Dave Hinds */
+extern int register_serial(struct serial_struct *req);
+extern void unregister_serial(int line);
+extern struct async_struct rs_table[];
+extern task_queue tq_serial;
+
+
+/*
+ * This routine is used by the interrupt handler to schedule
+ * processing in the software interrupt portion of the driver.
+ */
+static __inline__ void rs_sched_event(struct async_struct *info, int event)
+{
+ info->event |= 1 << event;
+ queue_task_irq(&info->tqueue, &tq_serial);
+ mark_bh(SERIAL_BH);
+}
+
+static __inline__ void rs_receive_char( struct async_struct *info,
+ int ch, int err )
+{
+ struct tty_struct *tty = info->tty;
+
+ if (tty->flip.count >= TTY_FLIPBUF_SIZE)
+ return;
+ tty->flip.count++;
+ if (err == TTY_BREAK) {
+ if (info->flags & ASYNC_SAK)
+ do_SAK(tty);
+ }
+ *tty->flip.flag_buf_ptr++ = err;
+ *tty->flip.char_buf_ptr++ = ch;
+ queue_task_irq(&tty->flip.tqueue, &tq_timer);
+}
+
+static __inline__ int rs_get_tx_char( struct async_struct *info )
+{
+ unsigned char ch;
+
+ if (info->x_char) {
+ ch = info->x_char;
+ info->x_char = 0;
+ return( ch );
+ }
+
+ if (info->xmit_cnt <= 0 || info->tty->stopped || info->tty->hw_stopped)
+ return( -1 );
+
+ ch = info->xmit_buf[info->xmit_tail++];
+ info->xmit_tail &= SERIAL_XMIT_SIZE - 1;
+ if (--info->xmit_cnt < WAKEUP_CHARS)
+ rs_sched_event(info, RS_EVENT_WRITE_WAKEUP);
+ return( ch );
+}
+
+static __inline__ int rs_no_more_tx( struct async_struct *info )
+{
+ return( info->xmit_cnt <= 0 ||
+ info->tty->stopped ||
+ info->tty->hw_stopped );
+}
+
+static __inline__ void rs_dcd_changed( struct async_struct *info, int dcd )
+
+{
+ /* update input line counter */
+ info->icount.dcd++;
+ wake_up_interruptible(&info->delta_msr_wait);
+
+ if (info->flags & ASYNC_CHECK_CD) {
+#if (defined(SERIAL_DEBUG_OPEN) || defined(SERIAL_DEBUG_INTR))
+ printk("ttyS%d CD now %s...", info->line,
+ dcd ? "on" : "off");
+#endif
+ if (dcd) {
+ wake_up_interruptible(&info->open_wait);
+ } else if (!((info->flags & ASYNC_CALLOUT_ACTIVE) &&
+ (info->flags & ASYNC_CALLOUT_NOHUP))) {
+#ifdef SERIAL_DEBUG_OPEN
+ printk("scheduling hangup...");
+#endif
+ queue_task_irq(&info->tqueue_hangup,
+ &tq_scheduler);
+ }
+ }
+}
+
+
+void rs_stop( struct tty_struct *tty );
+void rs_start( struct tty_struct *tty );
+
+static __inline__ void rs_check_cts( struct async_struct *info, int cts )
+{
+ /* update input line counter */
+ info->icount.cts++;
+ wake_up_interruptible(&info->delta_msr_wait);
+
+ if ((info->flags & ASYNC_CTS_FLOW) && info->tty)
+ if (info->tty->hw_stopped) {
+ if (cts) {
+#if (defined(SERIAL_DEBUG_INTR) || defined(SERIAL_DEBUG_FLOW))
+ printk("CTS tx start...");
+#endif
+ info->tty->hw_stopped = 0;
+ rs_start( info->tty );
+ rs_sched_event(info, RS_EVENT_WRITE_WAKEUP);
+ return;
+ }
+ } else {
+ if (!cts) {
+ info->tty->hw_stopped = 1;
+ rs_stop( info->tty );
+ }
+ }
+
+}
+
+
+#endif /* __KERNEL__ */
+
+#endif /* _M68K_SERIAL_H */
@@ -64,6+64,7 @@ struct __xchg_dummy { unsigned long a[100]; }; #endif /* machine compilation types */
#define cli() __asm__ __volatile__ ("oriw #0x0700,%/sr": : : "memory")
#define nop() __asm__ __volatile__ ("nop"::)
+#define mb() __asm__ __volatile__ ("" : : :"memory")
#define save_flags(x) \
__asm__ __volatile__("movew %/sr,%0":"=d" (x) : /* no input */ :"memory")
#define SHMALL /* max shm system wide (pages) */ \
(1<<(_SHM_IDX_BITS+_SHM_ID_BITS))
/*
- * This constant is very large but the ABI in it's wisdom says ...
+ * This constant is very large but the ABI in its wisdom says ...
*/
#define SHMLBA 0x40000 /* attach addr a multiple of this */
#define SHMSEG SHMMNI /* max shared segs per process */
@@ -290,7+290,7 @@ static int sun_floppy_init(void) /* We certainly don't have a floppy controller. */
goto no_sun_fdc;
}
- /* Well, try and find one. */
+ /* Well, try to find one. */
tnode = prom_getchild(prom_root_node);
fd_node = prom_searchsiblings(tnode, "obio");
if(fd_node != 0) {
#define NMI_TRAP \
rd %wim, %l3; b linux_trap_nmi_sun4c; mov %psr, %l0; nop;
-/* Window overflows/underflows are special and we need to try and be as
+/* Window overflows/underflows are special and we need to try to be as
* efficient as possible here....
*/
#define WINDOW_SPILL \
#ifndef __ASSEMBLY__
/* The debug vector is passed in %o1 at boot time. It is a pointer to
- * a structure in the debuggers address space. Here is it's format.
+ * a structure in the debuggers address space. Here is its format.
*/
typedef unsigned int (*debugger_funct)(void);
@@ -26,7+26,7 @@ extern struct prom_cpuinfo linux_cpus[NCPUS]; /* Per processor Sparc parameters we need. */
struct cpuinfo_sparc {
- unsigned long udelay_val; /* thats it */
+ unsigned long udelay_val; /* that's it */
};
extern struct cpuinfo_sparc cpu_data[NR_CPUS];
@@ -40,7+40,7 @@ extern struct linux_romvec *romvec; #define halt() romvec->pv_halt()
/* When a context switch happens we must flush all user windows so that
- * the windows of the current process are flushed onto it's stack. This
+ * the windows of the current process are flushed onto its stack. This
* way the windows are all clean for the next process and the stack
* frames are up to date.
*/
@@ -129,7+129,7 @@ enum machine_type {
#ifdef linux
#include <asm/page.h>
-#ifdef __i386__
+#if defined(__i386__) || defined(__mc68000__)
#define SEGMENT_SIZE 1024
#else
#ifndef SEGMENT_SIZE
-
-#ifndef _AFFS_FS_H
-#define _AFFS_FS_H
-
-#include <linux/types.h>
-/*
- * The affs filesystem constants/structures
- */
-
-#define AFFS_BLOCK_BITS 9
-#define AFFS_BLOCK_SIZE 512
-
-#define AFFS_BUFFER_BITS 9
-#define AFFS_BUFFER_SIZE 512
-
-#define AFFS_BLOCK_NUMBER(X) (X<<1)
-
-#define AFFS_SUPER_MAGIC 0xadff
-
-/* Get the filesystem block size given an inode. */
-#define AFFS_I2BSIZE(inode) ((inode)->i_sb->u.affs_sb.s_block_size)
-
-/* Read the device block that contains filesystem block ("sector"). */
-
-static inline struct buffer_head *affs_sread(int dev,int sector,void **start)
-{
- struct buffer_head *bh;
- int mask;
-
- bh = bread (dev, sector >> (BLOCK_SIZE_BITS - AFFS_BLOCK_BITS), 1024);
- if (!bh)
- return NULL;
- mask = (1 << (BLOCK_SIZE_BITS - AFFS_BLOCK_BITS)) - 1;
- *start = bh->b_data + ((sector & mask) << AFFS_BLOCK_BITS);
- return bh;
-}
-
-/* Use affs_sread() to read a "sector", but take the filesystems partition
- offset into account. */
-
-static inline struct buffer_head *affs_pread(struct inode *inode,
- int sector, void **start)
-{
- int offset = inode->i_sb->u.affs_sb.s_partition_offset;
- return affs_sread (inode->i_dev, sector + offset, start);
-}
-
-/* amigaffs.c prototypes */
-
-extern int affs_get_key_entry (int bsize, void *data, int entry_pos);
-extern int affs_find_next_hash_entry (int bsize, void *dir_data, int *hash_pos);
-extern int affs_get_fh_hash_link (int bsize, void *fh_data);
-extern int affs_get_file_name (int bsize, void *fh_data, char **name);
-extern int affs_get_extension (int bsize, void *fh_data);
-extern int affs_checksum_block (int bsize, void *data, int *ptype, int *stype);
-
-/* The stuff that follows may be totally unneeded. I have not checked to see
- which prototypes we are still using. */
-
-extern int affs_open(struct inode * inode, struct file * filp);
-extern void affs_release(struct inode * inode, struct file * filp);
-extern int affs_lookup(struct inode * dir,const char * name, int len,
- struct inode ** result);
-extern unsigned long affs_count_free_inodes(struct super_block *sb);
-extern int affs_new_block(int dev);
-extern int affs_free_block(int dev, int block);
-extern int affs_bmap(struct inode *,int);
-
-extern void affs_put_super(struct super_block *);
-extern struct super_block *affs_read_super(struct super_block *,void *,int);
-extern void affs_read_inode(struct inode *);
-extern void affs_put_inode(struct inode *);
-extern void affs_statfs(struct super_block *, struct statfs *, int);
-extern int affs_parent_ino(struct inode *dir);
-extern int affs_lseek(struct inode *, struct file *, off_t, int);
-extern int affs_read(struct inode *, struct file *, char *, int);
-extern int affs_file_read(struct inode *, struct file *, char *, int);
-extern int init_affs_fs(void);
-
-extern struct inode_operations affs_file_inode_operations;
-extern struct inode_operations affs_dir_inode_operations;
-extern struct inode_operations affs_symlink_inode_operations;
-extern struct inode_operations affs_chrdev_inode_operations;
-extern struct inode_operations affs_blkdev_inode_operations;
-
-extern struct file_operations affs_file_operations;
-extern struct file_operations affs_dir_operations;
-
-/* The following macros are used to check for memory leaks. */
-#ifdef LEAK_CHECK
-#define free_s leak_check_free_s
-#define malloc leak_check_malloc
-#define bread leak_check_bread
-#define brelse leak_check_brelse
-extern void * leak_check_malloc(unsigned int size);
-extern void leak_check_free_s(void * obj, int size);
-extern struct buffer_head * leak_check_bread(int dev, int block, int size);
-extern void leak_check_brelse(struct buffer_head * bh);
-#endif /* LEAK_CHECK */
-
-#endif
+#ifndef _AFFS_FS_H
+#define _AFFS_FS_H
+/*
+ * The affs filesystem constants/structures
+ */
+
+#include <linux/types.h>
+#include <linux/amigaffs.h>
+
+#define AFFS_SUPER_MAGIC 0xadff
+
+/* Get the filesystem block size given an inode. */
+#define AFFS_I2BSIZE(inode) ((inode)->i_sb->s_blocksize)
+
+/* Get the filesystem hash table size given an inode. */
+#define AFFS_I2HSIZE(inode) ((inode)->i_sb->u.affs_sb.s_hashsize)
+
+/* Get the block number bits given an inode */
+#define AFFS_I2BITS(inode) ((inode)->i_sb->s_blocksize_bits)
+
+/* Get the fs type given an inode */
+#define AFFS_I2FSTYPE(inode) ((inode)->i_sb->u.affs_sb.s_flags & SF_INTL)
+
+/* --- Prototypes ----------------------------------------------------------------------------- */
+
+/* amigaffs.c */
+
+extern int affs_get_key_entry(int bsize, void *data, int entry_pos);
+extern int affs_find_next_hash_entry(int bsize, void *dir_data, ULONG *hash_pos);
+extern int affs_get_file_name(int bsize, void *fh_data, char **name);
+extern ULONG affs_checksum_block(int bsize, void *data, LONG *ptype, LONG *stype);
+extern void affs_fix_checksum(int bsize, void *data, int cspos);
+extern void secs_to_datestamp(int secs, struct DateStamp *ds);
+extern int prot_to_mode(ULONG prot);
+extern ULONG mode_to_prot(int mode);
+extern int affs_fix_hash_pred(struct inode *startino, int startoffset,
+ LONG key, LONG newkey);
+extern int affs_fix_link_pred(struct inode *startino, LONG key, LONG newkey);
+
+/* bitmap. c */
+
+extern int affs_count_free_blocks(struct super_block *s);
+extern int affs_count_free_bits(int blocksize, const UBYTE *data);
+extern void affs_free_block(struct super_block *sb, LONG block);
+extern LONG affs_new_header(struct inode *inode);
+extern LONG affs_new_data(struct inode *inode);
+extern void affs_make_zones(struct super_block *sb);
+
+/* namei.c */
+
+extern int affs_hash_name(const char *name, int len, int intl, int hashsize);
+extern int affs_lookup(struct inode *dir,const char *name, int len,
+ struct inode **result);
+extern int affs_unlink(struct inode *dir, const char *name, int len);
+extern int affs_create(struct inode *dir, const char *name, int len, int mode,
+ struct inode **result);
+extern int affs_mkdir(struct inode *dir, const char *name, int len, int mode);
+extern int affs_rmdir(struct inode *dir, const char *name, int len);
+extern int affs_link(struct inode *oldinode, struct inode *dir,
+ const char *name, int len);
+extern int affs_symlink(struct inode *dir, const char *name, int len,
+ const char *symname);
+extern int affs_fixup(struct buffer_head *bh, struct inode *inode);
+extern int affs_rename(struct inode *old_dir, const char *old_name, int old_len,
+ struct inode *new_dir, const char *new_name, int new_len);
+
+/* inode.c */
+
+extern struct buffer_head *affs_bread(kdev_t dev, int block, int size);
+extern void affs_brelse(struct buffer_head *buf);
+extern void affs_put_super(struct super_block *);
+extern int affs_parent_ino(struct inode *dir);
+extern struct super_block *affs_read_super(struct super_block *,void *, int);
+extern void affs_statfs(struct super_block *, struct statfs *, int bufsiz);
+extern void affs_read_inode(struct inode *);
+extern void affs_write_inode(struct inode *);
+extern int affs_notify_change(struct inode *inode, struct iattr *attr);
+extern void affs_put_inode(struct inode *);
+extern struct inode *affs_new_inode(const struct inode *dir);
+extern int affs_add_entry(struct inode *dir, struct inode *link, struct inode *inode,
+ const char *name, int len, LONG type);
+
+/* file.c */
+
+extern int affs_bmap(struct inode *inode, int block);
+extern struct buffer_head *affs_getblock(struct inode *inode, int block);
+extern void affs_truncate(struct inode *);
+extern void affs_truncate_ofs(struct inode *);
+
+/* dir.c */
+
+extern void affs_dir_truncate(struct inode *);
+
+/* jump tables */
+
+extern struct inode_operations affs_file_inode_operations;
+extern struct inode_operations affs_file_inode_operations_ofs;
+extern struct inode_operations affs_dir_inode_operations;
+extern struct inode_operations affs_symlink_inode_operations;
+extern struct inode_operations affs_chrdev_inode_operations;
+extern struct inode_operations affs_blkdev_inode_operations;
+
+extern int init_affs_fs(void);
+#endif
#ifndef _AFFS_FS_I
#define _AFFS_FS_I
+#define EXT_CACHE_SIZE 16
+#define MAX_PREALLOC 8 /* MUST be a power of 2 */
+
/*
* affs fs inode data in memory
*/
struct affs_inode_info {
int i_protect; /* unused attribute bits */
int i_parent; /* parent ino */
+ int i_original; /* if != 0, this is the key of the original */
+ __u32 i_ext[EXT_CACHE_SIZE]; /* extension block numbers */
+ __u32 i_data[MAX_PREALLOC]; /* preallocated blocks */
+ short i_max_ext; /* last known extension block */
+ short i_pa_cnt; /* number of preallocated blocks */
+ short i_pa_next; /* Index of next block in i_data[] */
+ short i_pa_last; /* Index of next free slot in i_data[] */
+ short i_zone; /* write zone */
+ unsigned char i_hlink; /* This is a fake */
+ unsigned char i_pad;
};
#endif
-#ifndef _AFFS_FS_SB
-#define _AFFS_FS_SB
-
-/*
- * super-block data in memory
- *
- * Block numbers are for FFS-sized (normally 512 bytes) blocks.
- *
- */
-
-/* Mount options */
-
-struct affs_options {
- int offset;
- int size;
- int root;
- int nocase:1; /* Ignore case in filenames. */
- int conv_links:1; /* convert pathnames symlinks point to */
-};
-
-struct affs_sb_info {
- int s_partition_offset; /* Offset to start in blocks. */
- int s_partition_size; /* Partition size in blocks. */
- int s_root_block; /* Absolute FFS root block number. */
- int s_block_size; /* Block size in bytes. */
- char s_volume_name[42];
- struct affs_options s_options;
-};
-
-#endif
-
-
-
-
-
-
-
+#ifndef _AFFS_FS_SB
+#define _AFFS_FS_SB
+
+/*
+ * super-block data in memory
+ *
+ * Block numbers are adjusted for their actual size
+ *
+ */
+
+#include <linux/amigaffs.h>
+
+#define MAX_ZONES 8
+#define AFFS_DATA_MIN_FREE 30 /* Percentage of free blocks needed for a data zone */
+#define AFFS_HDR_MIN_FREE 10 /* Same for header blocks */
+
+struct affs_bm_info {
+ struct buffer_head *bm_bh; /* Buffer for bitmap. */
+ int bm_free; /* Free blocks. */
+ int bm_size; /* Size in bits, rounded to multiple of 32. */
+ int bm_firstblk; /* Block number of first bit in this map */
+};
+
+struct affs_zone {
+ unsigned long z_ino; /* Associated inode number */
+ struct affs_bm_info *z_bm; /* Zone lies in this bitmap */
+ int z_start; /* Index of first word in bitmap */
+ int z_zone_no; /* Zone number */
+ unsigned long z_lru_time; /* Time of last usage */
+};
+
+struct affs_sb_info {
+ int s_partition_size; /* Partition size in blocks. */
+ int s_root_block; /* FFS root block number. */
+ int s_hashsize; /* Size of hash table. */
+ unsigned long s_flags; /* See below. */
+ short s_uid; /* uid to override */
+ short s_gid; /* gid to override */
+ umode_t s_mode; /* mode to override */
+ int s_reserved; /* Number of reserved blocks. */
+ struct buffer_head *s_root_bh; /* Cached root block. */
+ struct affs_bm_info *s_bitmap; /* Bitmap infos. */
+ int s_bm_count; /* Number of bitmap blocks. */
+ int s_nextzone; /* Next zone to look for free blocks. */
+ int s_num_zones; /* Total number of zones. */
+ struct affs_zone *s_zones; /* The zones themselfes. */
+ char *s_zonemap; /* Bitmap for zones. */
+ char *s_prefix; /* Prefix for volumes and assignes. */
+ int s_prefix_len; /* Length of prefix. */
+ char s_volume[32]; /* Volume prefix for absolute symlinks. */
+};
+
+#define SF_INTL 0x0001 /* International filesystem. */
+#define SF_BM_VALID 0x0002 /* Bitmap is valid. */
+#define SF_IMMUTABLE 0x0004 /* Protection bits cannot be changed */
+#define SF_QUIET 0x0008 /* chmod errors will be not reported */
+#define SF_SETUID 0x0010 /* Ignore Amiga uid */
+#define SF_SETGID 0x0020 /* Ignore Amiga gid */
+#define SF_SETMODE 0x0040 /* Ignore Amiga protection bits */
+#define SF_USE_MP 0x0080 /* Use uid and gid from mount point */
+#define SF_MUFS 0x0100 /* Use MUFS uid/gid mapping */
+#define SF_OFS 0x0200 /* Old filesystem */
+#define SF_PREFIX 0x0400 /* Buffer for prefix is allocated */
+#define SF_VERBOSE 0x0800 /* Talk about fs when mounting */
+
+#endif
--- /dev/null
+#ifndef AFFS_HARDBLOCKS_H
+#define AFFS_HARDBLOCKS_H
+
+/* Just the needed definitions for the RDB of an Amiga HD. */
+
+#ifndef AMIGAFFS_H
+#include <linux/amigaffs.h>
+#endif
+
+struct RigidDiskBlock {
+ ULONG rdb_ID;
+ ULONG rdb_SummedLongs;
+ LONG rdb_ChkSum;
+ ULONG rdb_HostID;
+ ULONG rdb_BlockBytes;
+ ULONG rdb_Flags;
+ ULONG rdb_BadBlockList;
+ ULONG rdb_PartitionList;
+ ULONG rdb_FileSysHeaderList;
+ ULONG rdb_DriveInit;
+ ULONG rdb_Reserved1[6];
+ ULONG rdb_Cylinders;
+ ULONG rdb_Sectors;
+ ULONG rdb_Heads;
+ ULONG rdb_Interleave;
+ ULONG rdb_Park;
+ ULONG rdb_Reserved2[3];
+ ULONG rdb_WritePreComp;
+ ULONG rdb_ReducedWrite;
+ ULONG rdb_StepRate;
+ ULONG rdb_Reserved3[5];
+ ULONG rdb_RDBBlocksLo;
+ ULONG rdb_RDBBlocksHi;
+ ULONG rdb_LoCylinder;
+ ULONG rdb_HiCylinder;
+ ULONG rdb_CylBlocks;
+ ULONG rdb_AutoParkSeconds;
+ ULONG rdb_HighRDSKBlock;
+ ULONG rdb_Reserved4;
+ char rdb_DiskVendor[8];
+ char rdb_DiskProduct[16];
+ char rdb_DiskRevision[4];
+ char rdb_ControllerVendor[8];
+ char rdb_ControllerProduct[16];
+ char rdb_ControllerRevision[4];
+ ULONG rdb_Reserved5[10];
+};
+
+#define IDNAME_RIGIDDISK 0x5244534B /* "RDSK" */
+
+struct PartitionBlock {
+ ULONG pb_ID;
+ ULONG pb_SummedLongs;
+ LONG pb_ChkSum;
+ ULONG pb_HostID;
+ ULONG pb_Next;
+ ULONG pb_Flags;
+ ULONG pb_Reserved1[2];
+ ULONG pb_DevFlags;
+ UBYTE pb_DriveName[32];
+ ULONG pb_Reserved2[15];
+ ULONG pb_Environment[17];
+ ULONG pb_EReserved[15];
+};
+
+#define IDNAME_PARTITION 0x50415254 /* "PART" */
+
+#define RDB_ALLOCATION_LIMIT 16
+
+#endif /* AFFS_HARDBLOCKS_H */
--- /dev/null
+#ifndef AMIGAFFS_H
+#define AMIGAFFS_H
+
+#include <asm/byteorder.h>
+#include <linux/types.h>
+
+/* Ugly macros make the code more pretty. */
+
+#define GET_END_PTR(st,p,sz) ((st *)((char *)(p)+((sz)-sizeof(st))))
+#define AFFS_GET_HASHENTRY(data,hashkey) htonl(((struct dir_front *)data)->hashtable[hashkey])
+#define AFFS_BLOCK(data,ino,blk) ((struct file_front *)data)->blocks[AFFS_I2HSIZE(ino)-1-blk]
+
+#define FILE_END(p,i) GET_END_PTR(struct file_end,p,AFFS_I2BSIZE(i))
+#define ROOT_END(p,i) GET_END_PTR(struct root_end,p,AFFS_I2BSIZE(i))
+#define DIR_END(p,i) GET_END_PTR(struct dir_end,p,AFFS_I2BSIZE(i))
+#define LINK_END(p,i) GET_END_PTR(struct hlink_end,p,AFFS_I2BSIZE(i))
+#define ROOT_END_S(p,s) GET_END_PTR(struct root_end,p,(s)->s_blocksize)
+
+/* Only for easier debugging if need be */
+#define affs_bread bread
+#define affs_brelse brelse
+
+#ifdef __LITTLE_ENDIAN
+#define BO_EXBITS 0x18UL
+#elif defined(__BIG_ENDIAN)
+#define BO_EXBITS 0x00UL
+#else
+#error Endianess must be known for affs to work.
+#endif
+
+/* The following constants will be checked against the values read native */
+
+#define FS_OFS 0x444F5300
+#define FS_FFS 0x444F5301
+#define FS_INTLOFS 0x444F5302
+#define FS_INTLFFS 0x444F5303
+#define FS_DCOFS 0x444F5304
+#define FS_DCFFS 0x444F5305
+#define MUFS_FS 0x6d754653 /* 'muFS' */
+#define MUFS_OFS 0x6d754600 /* 'muF\0' */
+#define MUFS_FFS 0x6d754601 /* 'muF\1' */
+#define MUFS_INTLOFS 0x6d754602 /* 'muF\2' */
+#define MUFS_INTLFFS 0x6d754603 /* 'muF\3' */
+#define MUFS_DCOFS 0x6d754604 /* 'muF\4' */
+#define MUFS_DCFFS 0x6d754605 /* 'muF\5' */
+
+typedef __u32 ULONG;
+typedef __u16 UWORD;
+typedef __u8 UBYTE;
+
+typedef __s32 LONG;
+typedef __s16 WORD;
+typedef __s8 BYTE;
+
+struct DateStamp
+{
+ ULONG ds_Days;
+ ULONG ds_Minute;
+ ULONG ds_Tick;
+};
+
+#define T_SHORT 2
+#define T_LIST 16
+#define T_DATA 8
+
+#define ST_LINKFILE -4
+#define ST_FILE -3
+#define ST_ROOT 1
+#define ST_USERDIR 2
+#define ST_SOFTLINK 3
+#define ST_LINKDIR 4
+
+struct root_front
+{
+ LONG primary_type;
+ ULONG spare1[2];
+ ULONG hash_size;
+ ULONG spare2;
+ ULONG checksum;
+ ULONG hashtable[0];
+};
+
+struct root_end
+{
+ LONG bm_flag;
+ ULONG bm_keys[25];
+ ULONG bm_extend;
+ struct DateStamp dir_altered;
+ UBYTE disk_name[40];
+ struct DateStamp disk_altered;
+ struct DateStamp disk_made;
+ ULONG spare1[3];
+ LONG secondary_type;
+};
+
+struct dir_front
+{
+ LONG primary_type;
+ ULONG own_key;
+ ULONG spare1[3];
+ ULONG checksum;
+ ULONG hashtable[0];
+};
+
+struct dir_end
+{
+ ULONG spare1;
+ UWORD owner_uid;
+ UWORD owner_gid;
+ ULONG protect;
+ ULONG spare2;
+ UBYTE comment[92];
+ struct DateStamp created;
+ UBYTE dir_name[32];
+ ULONG spare3[2];
+ ULONG link_chain;
+ ULONG spare4[5];
+ ULONG hash_chain;
+ ULONG parent;
+ ULONG spare5;
+ LONG secondary_type;
+};
+
+struct file_front
+{
+ LONG primary_type;
+ ULONG own_key;
+ ULONG block_count;
+ ULONG unknown1;
+ ULONG first_data;
+ ULONG checksum;
+ ULONG blocks[0];
+};
+
+struct file_end
+{
+ ULONG spare1;
+ UWORD owner_uid;
+ UWORD owner_gid;
+ ULONG protect;
+ ULONG byte_size;
+ UBYTE comment[92];
+ struct DateStamp created;
+ UBYTE file_name[32];
+ ULONG spare2;
+ ULONG original; /* not really in file_end */
+ ULONG link_chain;
+ ULONG spare3[5];
+ ULONG hash_chain;
+ ULONG parent;
+ ULONG extension;
+ LONG secondary_type;
+};
+
+struct hlink_front
+{
+ LONG primary_type;
+ ULONG own_key;
+ ULONG spare1[3];
+ ULONG checksum;
+};
+
+struct hlink_end
+{
+ ULONG spare1;
+ UWORD owner_uid;
+ UWORD owner_gid;
+ ULONG protect;
+ UBYTE comment[92];
+ struct DateStamp created;
+ UBYTE link_name[32];
+ ULONG spare2;
+ ULONG original;
+ ULONG link_chain;
+ ULONG spare3[5];
+ ULONG hash_chain;
+ ULONG parent;
+ ULONG spare4;
+ LONG secondary_type;
+};
+
+struct slink_front
+{
+ LONG primary_type;
+ ULONG own_key;
+ ULONG spare1[3];
+ ULONG checksum;
+ UBYTE symname[288]; /* depends on block size */
+};
+
+/* Permission bits */
+
+#define FIBF_OTR_READ 0x8000
+#define FIBF_OTR_WRITE 0x4000
+#define FIBF_OTR_EXECUTE 0x2000
+#define FIBF_OTR_DELETE 0x1000
+#define FIBF_GRP_READ 0x0800
+#define FIBF_GRP_WRITE 0x0400
+#define FIBF_GRP_EXECUTE 0x0200
+#define FIBF_GRP_DELETE 0x0100
+
+#define FIBF_SCRIPT 0x0040
+#define FIBF_PURE 0x0020 /* no use under linux */
+#define FIBF_ARCHIVE 0x0010 /* never set, always cleared on write */
+#define FIBF_READ 0x0008 /* 0 means allowed */
+#define FIBF_WRITE 0x0004 /* 0 means allowed */
+#define FIBF_EXECUTE 0x0002 /* 0 means allowed, ignored under linux */
+#define FIBF_DELETE 0x0001 /* 0 means allowed */
+
+#define FIBF_OWNER 0x000F /* Bits pertaining to owner */
+
+#define AFFS_UMAYWRITE(prot) (((prot) & (FIBF_WRITE|FIBF_DELETE)) == (FIBF_WRITE|FIBF_DELETE))
+#define AFFS_UMAYREAD(prot) ((prot) & FIBF_READ)
+#define AFFS_UMAYEXECUTE(prot) (((prot) & (FIBF_SCRIPT|FIBF_READ)) == (FIBF_SCRIPT|FIBF_READ))
+#define AFFS_GMAYWRITE(prot) (((prot)&(FIBF_GRP_WRITE|FIBF_GRP_DELETE))==\
+ (FIBF_GRP_WRITE|FIBF_GRP_DELETE))
+#define AFFS_GMAYREAD(prot) ((prot) & FIBF_GRP_READ)
+#define AFFS_GMAYEXECUTE(prot) (((prot)&(FIBF_SCRIPT|FIBF_GRP_READ))==(FIBF_SCRIPT|FIBF_GRP_READ))
+#define AFFS_OMAYWRITE(prot) (((prot)&(FIBF_OTR_WRITE|FIBF_OTR_DELETE))==\
+ (FIBF_OTR_WRITE|FIBF_OTR_DELETE))
+#define AFFS_OMAYREAD(prot) ((prot) & FIBF_OTR_READ)
+#define AFFS_OMAYEXECUTE(prot) (((prot)&(FIBF_SCRIPT|FIBF_OTR_READ))==(FIBF_SCRIPT|FIBF_OTR_READ))
+
+#endif
#endif
/* These two have identical behaviour; use the second one if DOS fdisk gets
- confused about extended/logical partitions starting past cylinder 1023. */
+ confused about extended/logical partitions starting past cylinder 1023. */
#define DOS_EXTENDED_PARTITION 5
#define LINUX_EXTENDED_PARTITION 0x85
#define HD_IRQ 14 /* the standard disk interrupt */
-/* ide.c has it's own port definitions in "ide.h" */
+/* ide.c has its own port definitions in "ide.h" */
/* Hd controller regs. Ref: IBM AT Bios-listing */
#define HD_DATA 0x1f0 /* _CTL when writing */
@@ -111,18+111,16 @@ struct arphdr
#define ARPD_UPDATE 0x01
#define ARPD_LOOKUP 0x02
+#define ARPD_FLUSH 0x03
struct arpd_request
{
unsigned short req; /* request type */
__u32 ip; /* ip address of entry */
- __u32 mask; /* netmask - used for proxy */
+ unsigned long dev; /* Device entry is tied to */
+ unsigned long stamp;
+ unsigned long updated;
unsigned char ha[MAX_ADDR_LEN]; /* Hardware address */
- unsigned long last_used; /* For expiry */
- unsigned long last_updated; /* For expiry */
- unsigned int flags; /* Control status */
- struct device *dev; /* Device entry is tied to */
- int loc; /* Debugging call location */
};
#endif /* _LINUX_IF_ARP_H */
* created for each DLCI associated with a FRAD. The FRAD driver
* is not truly a network device, but the lower level device
* handler. This allows other FRAD manufacturers to use the DLCI
- * code, including it's RFC1490 encapsulation along side the current
+ * code, including its RFC1490 encapsulation alongside the current
* implementation for the Sangoma cards.
*
* Version: @(#)if_ifrad.h 0.15 31 Mar 96
@@ -129,7+129,7 @@ struct sockaddr_in {
/*
* IPv6 definitions as we start to include them. This is just
- * a beginning dont get excited 8)
+ * a beginning -- don't get excited 8)
*/
struct in_addr6
@@ -184,7+184,7 @@ typedef struct { #ifdef CONFIG_ISDN_PPP
#ifdef CONFIG_ISDN_PPP_VJ
-# include "/usr/src/linux/drivers/net/slhc.h"
+# include <net/slhc_vj.h>
#endif
#include <linux/ppp_defs.h>
*
* Linux ISDN subsystem
*
- * Definition of the interface between the subsystem and it's lowlevel-drivers.
+ * Definition of the interface between the subsystem and its low-level drivers.
*
* Copyright 1994,95,96 by Fritz Elfert (fritz@wuemaus.franken.de)
* Copyright 1995,96 Thinking Objects Software GmbH Wuerzburg
@@ -136,7+136,7 @@ typedef struct { * The interface-struct itself (initialized at load-time of lowlevel-driver)
*
* See Documentation/isdn/INTERFACE for a description, how the communication
- * between the ISDN subsystem and it's drivers is done.
+ * between the ISDN subsystem and its drivers is done.
*
*/
typedef struct {
@@ -57,8+57,13 @@ extern int kill_sl(int sess, int sig, int priv); asmlinkage int printk(const char * fmt, ...)
__attribute__ ((format (printf, 1, 2)));
-#define pr_debug(show,fmt,arg...) \
- do { if (show) printk(KERN_DEBUG fmt,##arg); } while (0)
+#if DEBUG
+#define pr_debug(fmt,arg...) \
+ printk(KERN_DEBUG fmt,##arg)
+#else
+#define pr_debug(fmt,arg...) \
+ do { } while (0)
+#endif
#define pr_info(fmt,arg...) \
printk(KERN_INFO fmt,##arg)
#ifndef _LINUX_MATH_EMU_H
#define _LINUX_MATH_EMU_H
+
+void restore_i387_soft(struct _fpstate *buf);
+struct _fpstate * save_i387_soft(struct _fpstate * buf);
+
struct fpu_reg {
char sign;
char tag;
@@ -124,4+124,22 @@ outb_p((val),RTC_PORT(1)); \ #define RTC_IRQP_READ 0x0b /* Read periodic IRQ rate (Hz) */
#define RTC_IRQP_SET 0x0c /* Set periodic IRQ rate (Hz) */
+/*
+ * The struct used to pass data via the above ioctl. Similar to the
+ * struct tm in <time.h>, but it needs to be here so that the kernel
+ * source is self contained, allowing cross-compiles, etc. etc.
+ */
+
+struct rtc_time {
+ int tm_sec;
+ int tm_min;
+ int tm_hour;
+ int tm_mday;
+ int tm_mon;
+ int tm_year;
+ int tm_wday;
+ int tm_yday;
+ int tm_isdst;
+};
+
#endif /* _MC146818RTC_H */
@@ -112,7+112,7 @@ struct igmpmsg };
/*
- * Thats all usermode folks
+ * That's all usermode folks
*/
#ifdef __KERNEL__
@@ -256,6+256,21 @@ extern int msdos_rename(struct inode *old_dir,const char *old_name,int old_len, /* fatfs_syms.c */
extern int init_fat_fs(void);
+/* vfat/namei.c - these are for dmsdos */
+extern int vfat_create(struct inode *dir,const char *name,int len,int mode,
+ struct inode **result);
+extern int vfat_unlink(struct inode *dir,const char *name,int len);
+extern int vfat_mkdir(struct inode *dir,const char *name,int len,int mode);
+extern int vfat_rmdir(struct inode *dir,const char *name,int len);
+extern int vfat_rename(struct inode *old_dir,const char *old_name,int old_len,
+ struct inode *new_dir,const char *new_name,int new_len);
+extern void vfat_put_super(struct super_block *sb);
+extern struct super_block *vfat_read_super(struct super_block *sb,void *data,
+ int silent);
+extern void vfat_read_inode(struct inode *inode);
+extern int vfat_lookup(struct inode *dir,const char *name,int len,
+ struct inode **result);
+
#endif /* __KERNEL__ */
#endif
@@ -71,7+71,7 @@ struct hh_cache * any address resolution module,
* not only ARP.
*/
- unsigned int hh_refcnt; /* number of users */
+ int hh_refcnt; /* number of users */
unsigned short hh_type; /* protocol identifier, f.e ETH_P_IP */
char hh_uptodate; /* hh_data is valid */
char hh_data[16]; /* cached hardware header */
@@ -218,7+218,7 @@ extern struct packet_type *ptype_base[16];
extern int ip_addr_match(unsigned long addr1, unsigned long addr2);
extern int ip_chk_addr(unsigned long addr);
-extern struct device *ip_dev_check(unsigned long daddr);
+extern struct device *ip_dev_bynet(unsigned long daddr, unsigned long mask);
extern unsigned long ip_my_addr(void);
extern unsigned long ip_get_mask(unsigned long addr);
extern struct device *ip_dev_find(unsigned long addr);
@@ -246,7+246,7 @@ extern void dev_init(void); extern int dev_lockct;
/*
- * These two dont currently need to be interrupt safe
+ * These two don't currently need to be interrupt-safe
* but they may do soon. Do it properly anyway.
*/
@@ -392,7+392,11 @@ extern __inline__ unsigned char *skb_put(struct sk_buff *skb, int len) skb->tail+=len;
skb->len+=len;
if(skb->tail>skb->end)
- panic("skput:over: %p:%d", __builtin_return_address(0),len);
+ {
+ __label__ here;
+ panic("skput:over: %p:%d", &&here,len);
+here:
+ }
return tmp;
}
@@ -401,7+405,11 @@ extern __inline__ unsigned char *skb_push(struct sk_buff *skb, int len) skb->data-=len;
skb->len+=len;
if(skb->data<skb->head)
- panic("skpush:under: %p:%d", __builtin_return_address(0),len);
+ {
+ __label__ here;
+ panic("skpush:under: %p:%d", &&here,len);
+here:
+ }
return skb->data;
}
@@ -17,6+17,7 @@ extern char * strncpy(char *,const char *,size_t); extern char * strcat(char *, const char *);
extern char * strncat(char *, const char *, size_t);
extern char * strchr(const char *,int);
+extern char * strrchr(const char *,int);
extern char * strpbrk(const char *,const char *);
extern char * strtok(char *,const char *);
extern char * strstr(const char *,const char *);
#define __NET_NETLINK_H
#define NET_MAJOR 36 /* Major 18 is reserved for networking */
-#define MAX_LINKS 8 /* 18,0 for route updates, 18,1 for SKIP, 18,2 debug tap 18,3 PPP reserved */
+#define MAX_LINKS 9 /* 18,0 for route updates, 18,1 for SKIP, 18,2 debug tap 18,3 PPP reserved */
/* 4-7 are psi0-psi3 */
#define MAX_QBYTES 32768 /* Maximum bytes in the queue */
@@ -19,6+19,7 @@ extern int init_netlink(void); #define NETLINK_USERSOCK 2 /* Reserved for user mode socket protocols */
#define NETLINK_FIREWALL 3 /* Firewalling hook */
#define NETLINK_PSI 4 /* PSI devices - 4 to 7 */
+#define NETLINK_ARPD 8
#ifdef CONFIG_RTNETLINK
extern void ip_netlink_msg(unsigned long, __u32, __u32, __u32, short, short, char *);
#define RTF_LOCAL 0x8000
#endif
-/*
- * Semaphores.
- */
-#if defined(__alpha__)
-
-static __inline__ void ATOMIC_INCR(unsigned int * addr)
-{
- unsigned tmp;
-
- __asm__ __volatile__(
- "1:\n\
- ldl_l %1,%2\n\
- addl %1,1,%1\n\
- stl_c %1,%0\n\
- beq %1,1b\n"
- : "m=" (*addr), "r=&" (tmp)
- : "m"(*addr));
-}
-
-static __inline__ void ATOMIC_DECR(unsigned int * addr)
-{
- unsigned tmp;
-
- __asm__ __volatile__(
- "1:\n\
- ldl_l %1,%2\n\
- subl %1,1,%1\n\
- stl_c %1,%0\n\
- beq %1,1b\n"
- : "m=" (*addr), "r=&" (tmp)
- : "m"(*addr));
-}
-
-static __inline__ int ATOMIC_DECR_AND_CHECK (unsigned int * addr)
-{
- unsigned tmp;
- int result;
-
- __asm__ __volatile__(
- "1:\n\
- ldl_l %1,%3\n\
- subl %1,1,%1\n\
- mov %1,%2\n\
- stl_c %1,%0\n\
- beq %1,1b\n"
- : "m=" (*addr), "r=&" (tmp), "r=&"(result)
- : "m"(*addr));
- return result;
-}
-
-#elif defined(__i386__)
-#include <asm/bitops.h>
-
-extern __inline__ void ATOMIC_INCR(void * addr)
-{
- __asm__ __volatile__(
- "incl %0"
- :"=m" (ADDR));
-}
-
-extern __inline__ void ATOMIC_DECR(void * addr)
-{
- __asm__ __volatile__(
- "decl %0"
- :"=m" (ADDR));
-}
-
-/*
- * It is DECR that is ATOMIC, not CHECK!
- * If you want to do atomic checks, use cli()/sti(). --ANK
- */
-
-extern __inline__ unsigned long ATOMIC_DECR_AND_CHECK(void * addr)
-{
- unsigned long retval;
- __asm__ __volatile__(
- "decl %0\nmovl %0,%1"
- : "=m" (ADDR), "=r"(retval));
- return retval;
-}
-
-
-#else
-
-static __inline__ void ATOMIC_INCR(unsigned int * addr)
-{
- (*(__volatile__ unsigned int*)addr)++;
-}
-
-static __inline__ void ATOMIC_DECR(unsigned int * addr)
-{
- (*(__volatile__ unsigned int*)addr)--;
-}
-
-static __inline__ int ATOMIC_DECR_AND_CHECK (unsigned int * addr)
-{
- ATOMIC_DECR(addr);
- return *(volatile unsigned int*)addr;
-}
-
-#endif
-
-
-
struct rtable
{
struct rtable *rt_next;
__u32 rt_dst;
__u32 rt_src;
__u32 rt_gateway;
- unsigned rt_refcnt;
- unsigned rt_use;
+ atomic_t rt_refcnt;
+ atomic_t rt_use;
unsigned long rt_window;
- unsigned long rt_lastuse;
+ atomic_t rt_lastuse;
struct hh_cache *rt_hh;
struct device *rt_dev;
unsigned short rt_flags;
@@ -185,6+81,7 @@ struct rtable };
extern void ip_rt_flush(struct device *dev);
+extern void ip_rt_update(int event, struct device *dev);
extern void ip_rt_redirect(__u32 src, __u32 dst, __u32 gw, struct device *dev);
extern struct rtable *ip_rt_slow_route(__u32 daddr, int local);
extern int rt_get_info(char * buffer, char **start, off_t offset, int length, int dummy);
@@ -196,23+93,23 @@ extern void ip_rt_check_expire(void); extern void ip_rt_advice(struct rtable **rp, int advice);
extern void ip_rt_run_bh(void);
-extern int ip_rt_lock;
+extern atomic_t ip_rt_lock;
extern unsigned ip_rt_bh_mask;
extern struct rtable *ip_rt_hash_table[RT_HASH_DIVISOR];
extern __inline__ void ip_rt_fast_lock(void)
{
- ATOMIC_INCR(&ip_rt_lock);
+ atomic_inc(&ip_rt_lock);
}
extern __inline__ void ip_rt_fast_unlock(void)
{
- ATOMIC_DECR(&ip_rt_lock);
+ atomic_dec(&ip_rt_lock);
}
extern __inline__ void ip_rt_unlock(void)
{
- if (!ATOMIC_DECR_AND_CHECK(&ip_rt_lock) && ip_rt_bh_mask)
+ if (atomic_dec_and_test(&ip_rt_lock) && ip_rt_bh_mask)
ip_rt_run_bh();
}
@@ -227,7+124,7 @@ extern __inline__ void ip_rt_put(struct rtable * rt) #ifndef MODULE
{
if (rt)
- ATOMIC_DECR(&rt->rt_refcnt);
+ atomic_dec(&rt->rt_refcnt);
}
#else
;
@@ -248,8+145,8 @@ extern __inline__ struct rtable * ip_rt_route(__u32 daddr, int local) if (rth->rt_dst == daddr)
{
rth->rt_lastuse = jiffies;
- ATOMIC_INCR(&rth->rt_use);
- ATOMIC_INCR(&rth->rt_refcnt);
+ atomic_inc(&rth->rt_use);
+ atomic_inc(&rth->rt_refcnt);
ip_rt_unlock();
return rth;
}
@@ -488,7+488,7 @@ extern struct sk_buff *sock_alloc_send_skb(struct sock *skb, * protocols can't normally use this as they need to fit buffers in
* and play with them.
*
- * Inlined as its very short and called for pretty much every
+ * Inlined as it's very short and called for pretty much every
* packet ever received.
*/
@@ -192,50+192,7 @@ static __inline__ int tcp_old_window(struct sock * sk) return sk->window - (sk->acked_seq - sk->lastwin_seq);
}
-static __inline__ int tcp_new_window(struct sock * sk)
-{
- int window = sock_rspace(sk);
-
- if (window > 1024)
- window &= ~0x3FF; /* make free space a multiple of 1024 */
-
- if (sk->window_clamp && sk->window_clamp < window)
- window = sk->window_clamp;
-
- /*
- * RFC 1122 says:
- *
- * "the suggested [SWS] avoidance algorithm for the receiver is to keep
- * RECV.NEXT + RCV.WIN fixed until:
- * RCV.BUFF - RCV.USER - RCV.WINDOW >= min(1/2 RCV.BUFF, MSS)"
- *
- * Experiments against BSD and Solaris machines show that following
- * these rules results in the BSD and Solaris machines making very
- * bad guesses about how much data they can have in flight.
- *
- * Instead we follow the BSD lead and offer a window that gives
- * the size of the current free space, truncated to a multiple
- * of 1024 bytes. If the window is smaller than
- * min(sk->mss, MAX_WINDOW/2)
- * then we advertise the window as having size 0, unless this
- * would shrink the window we offered last time.
- * This results in as much as double the throughput as the original
- * implementation.
- */
-
- if (sk->mss == 0)
- sk->mss = sk->mtu;
-
- /* BSD style SWS avoidance
- * Note that RFC1122 only says we must do silly window avoidance,
- * it does not require that we use the suggested algorithm.
- */
-
- if (window < min(sk->mss, MAX_WINDOW/2))
- window = 0;
-
- return window;
-}
+extern int tcp_new_window(struct sock *);
/*
* Return true if we should raise the window when we
@@ -247,7+204,8 @@ static __inline__ int tcp_new_window(struct sock * sk) */
static __inline__ int tcp_raise_window(struct sock * sk)
{
- return tcp_new_window(sk) >= 2*tcp_old_window(sk);
+ int new = tcp_new_window(sk);
+ return new && (new >= 2*tcp_old_window(sk));
}
static __inline__ unsigned short tcp_select_window(struct sock *sk)
@@ -159,7+159,8 @@ static int real_msgsnd (int msqid, struct msgbuf *msgp, size_t msgsz, int msgflg * Take care of missing kerneld, especially in case of multiple daemons
*/
#define KERNELD_TIMEOUT 1 * (HZ)
-#define DROP_TIMER if ((msgflg & IPC_KERNELD) && kd_timer.next && kd_timer.prev) del_timer(&kd_timer)
+#define DROP_TIMER del_timer(&kd_timer)
+/*#define DROP_TIMER if ((msgflg & IPC_KERNELD) && kd_timer.next && kd_timer.prev) del_timer(&kd_timer)*/
static void kd_timeout(unsigned long msgid)
{
@@ -185,7+186,7 @@ static void kd_timeout(unsigned long msgid)
static int real_msgrcv (int msqid, struct msgbuf *msgp, size_t msgsz, long msgtyp, int msgflg)
{
- struct timer_list kd_timer;
+ struct timer_list kd_timer = { NULL, NULL, 0, 0, 0};
struct msqid_ds *msq;
struct ipc_perm *ipcp;
struct msg *tmsg, *leastp = NULL;
@@ -229,16+230,20 @@ static int real_msgrcv (int msqid, struct msgbuf *msgp, size_t msgsz, long msgty * msgtyp < 0 => get message with least type must be < abs(msgtype).
*/
while (!nmsg) {
- if (msq->msg_perm.seq != (unsigned int) msqid / MSGMNI)
+ if (msq->msg_perm.seq != (unsigned int) msqid / MSGMNI) {
+ DROP_TIMER;
return -EIDRM;
+ }
if ((msgflg & IPC_KERNELD) == 0) {
/*
* Non-root processes may receive from kerneld!
* i.e. no permission check if called from the kernel
* otoh we don't want user level non-root snoopers...
*/
- if (ipcperms (ipcp, S_IRUGO))
+ if (ipcperms (ipcp, S_IRUGO)) {
+ DROP_TIMER;
return -EACCES;
+ }
}
if (msgtyp == 0)
nmsg = msq->msg_first;
@@ -267,8+272,10 @@ static int real_msgrcv (int msqid, struct msgbuf *msgp, size_t msgsz, long msgty
if (nmsg) { /* done finding a message */
DROP_TIMER;
- if ((msgsz < nmsg->msg_ts) && !(msgflg & MSG_NOERROR))
+ if ((msgsz < nmsg->msg_ts) && !(msgflg & MSG_NOERROR)) {
+ DROP_TIMER;
return -E2BIG;
+ }
msgsz = (msgsz > nmsg->msg_ts)? nmsg->msg_ts : msgsz;
if (nmsg == msq->msg_first)
msq->msg_first = nmsg->msg_next;
@@ -315,6+322,7 @@ static int real_msgrcv (int msqid, struct msgbuf *msgp, size_t msgsz, long msgty memcpy_tofs (msgp->mtext, nmsg->msg_spot, msgsz);
}
kfree(nmsg);
+ DROP_TIMER;
return msgsz;
} else { /* did not find a message */
if (msgflg & IPC_NOWAIT) {
#ifdef CONFIG_MODULES /* a *big* #ifdef block... */
-#ifdef DEBUG_MODULE
-#define PRINTK(a) printk a
-#else
-#define PRINTK(a) /* */
-#endif
-
static struct module kernel_module;
static struct module *module_list = &kernel_module;
@@ -127,8+121,8 @@ sys_create_module(char *module_name, unsigned long size) * (long *) addr = 0; /* set use count to zero */
module_list = mp; /* link it in */
- PRINTK(("module `%s' (%lu pages @ 0x%08lx) created\n",
- mp->name, (unsigned long) mp->size, (unsigned long) mp->addr));
+ pr_debug("module `%s' (%lu pages @ 0x%08lx) created\n",
+ mp->name, (unsigned long) mp->size, (unsigned long) mp->addr);
return (unsigned long) addr;
}
@@ -167,8+161,8 @@ sys_init_module(char *module_name, char *code, unsigned codesize,
if ((error = get_mod_name(module_name, name)) != 0)
return error;
- PRINTK(("initializing module `%s', %d (0x%x) bytes\n",
- name, codesize, codesize));
+ pr_debug("initializing module `%s', %d (0x%x) bytes\n",
+ name, codesize, codesize);
memcpy_fromfs(&rt, routines, sizeof rt);
if ((mp = find_module(name)) == NULL)
return -ENOENT;
@@ -185,8+179,8 @@ sys_init_module(char *module_name, char *code, unsigned codesize, memcpy_fromfs((char *)mp->addr + sizeof (long), code, codesize);
memset((char *)mp->addr + sizeof (long) + codesize, 0,
mp->size * PAGE_SIZE - (codesize + sizeof (long)));
- PRINTK(( "module init entry = 0x%08lx, cleanup entry = 0x%08lx\n",
- (unsigned long) rt.init, (unsigned long) rt.cleanup));
+ pr_debug("module init entry = 0x%08lx, cleanup entry = 0x%08lx\n",
+ (unsigned long) rt.init, (unsigned long) rt.cleanup);
mp->cleanup = rt.cleanup;
/* update kernel symbol table */
@@ -121,8+121,7 @@ static inline void add_to_runqueue(struct task_struct * p) init_task.prev_run = p;
#ifdef __SMP__
/* this is safe only if called with cli()*/
- while(set_bit(31,&smp_process_available));
-#if 0
+ while(set_bit(31,&smp_process_available))
{
while(test_bit(31,&smp_process_available))
{
@@ -133,7+132,6 @@ static inline void add_to_runqueue(struct task_struct * p) }
}
}
-#endif
smp_process_available++;
clear_bit(31,&smp_process_available);
if ((0!=p->pid) && smp_threads_ready)
@@ -242,6+240,11 @@ static inline int goodness(struct task_struct * p, struct task_struct * prev, in /* We are not permitted to run a task someone else is running */
if (p->processor != NO_PROC_ID)
return -1000;
+#ifdef PAST_2_0
+ /* This process is locked to a processor group */
+ if (p->processor_mask && !(p->processor_mask & (1<<this_cpu))
+ return -1000;
+#endif
#endif
/*
@@ -340,7+343,7 @@ asmlinkage void schedule(void) * This is safe as we do not permit re-entry of schedule()
*/
prev->processor = NO_PROC_ID;
-#define idle_task (task[this_cpu])
+#define idle_task (task[cpu_number_map[this_cpu]])
#else
#define idle_task (&init_task)
#endif
@@ -779,7+779,8 @@ static unsigned long filemap_nopage(struct vm_area_struct * area, unsigned long free_page(page);
return new_page;
}
- flush_page_to_ram(page);
+ if (page)
+ flush_page_to_ram(page);
return page;
}
@@ -187,6+187,7 @@ static inline int unuse_pte(struct vm_area_struct * vma, unsigned long address, return 1;
}
set_pte(dir, pte_mkwrite(pte_mkdirty(mk_pte(page, vma->vm_page_prot))));
+ flush_tlb_page(vma, address);
++vma->vm_mm->rss;
swap_free(pte_val(pte));
return 1;
@@ -376,7+376,7 @@ o TCP socket cache gets things wrong very very occasionally under high load. [TRYING THINGS]
o AX.25/NetROM needs more locking.
o NFS flow control is needed with the new multirequest NFS support.
-o Need to be able to turn off the intelligent arp refreshing as its not so
+o Need to be able to turn off the intelligent arp refreshing as it's not so
hot over AX.25 and upsets some people with very dumb ISDN bridges.
o Matti Arnio's TCP problem.
o Should unix domain connect never block ?
@@ -435,7+435,7 @@ working out how to do it so it runs like greased lightning. Quite a big problem. [See the LiS project]
10. Frame Relay/WAN/ISDN drivers [I'm working on the sonix EuroISDN board
-driver but thats for an internal project and its general release is still
+driver but that's for an internal project and its general release is still
a maybe (so is finishing it ;))][Jim Freeman is working on Frame Relay as is
Mike McLagan][Friz Elfert is doing the isdn4linux kit].
@@ -35,7+35,7 @@ MAX_WINDOW Offered maximum window (tunable) MAX_HEADER Largest physical header (tunable)
MAX_ADDR_LEN Largest physical address (tunable)
SOCK_ARRAY_SIZE IP socket array hash size (tunable)
-ARP_RES_TIME Time we try and resolve (tunable)
+ARP_RES_TIME Time we try to resolve (tunable)
ARP_DEAD_RES_TIME Time the entry stays dead (tunable)
ARP_MAX_TRIES Maximum tries (tunable)
ARP_TIMEOUT Timeout on an ARP (tunable)
* 2 of the License, or (at your option) any later version.
*
* History
- * AX.25 006 Alan(GW4PTS) Nearly died of shock - its working 8-)
+ * AX.25 006 Alan(GW4PTS) Nearly died of shock - it's working 8-)
* AX.25 007 Alan(GW4PTS) Removed the silliest bugs
* AX.25 008 Alan(GW4PTS) Cleaned up, fixed a few state machine problems, added callbacks
* AX.25 009 Alan(GW4PTS) Emergency patch kit to fix memory corruption
* Correct receive on SOCK_DGRAM.
* AX.25 013 Alan(GW4PTS) Send DM to all unknown frames, missing initialiser fixed
* Leave spare SSID bits set (DAMA etc) - thanks for bug report,
- * removed device registration (its not used or needed). Clean up for
+ * removed device registration (it's not used or needed). Clean up for
* gcc 2.5.8. PID to AX25_P_
* AX.25 014 Alan(GW4PTS) Cleanup and NET3 merge
* AX.25 015 Alan(GW4PTS) Internal test version.
@@ -409,7+409,7 @@ static void ax25_destroy_timer(unsigned long data) * Once it is removed from the queue no interrupt or bottom half will
* touch it and we are (fairly 8-) ) safe.
*/
-void ax25_destroy_socket(ax25_cb *ax25) /* Not static as its used by the timer */
+void ax25_destroy_socket(ax25_cb *ax25) /* Not static as it's used by the timer */
{
struct sk_buff *skb;
unsigned long flags;
@@ -1893,7+1893,7 @@ static int ax25_rcv(struct sk_buff *skb, struct device *dev, ax25_address *dev_a */
static int kiss_rcv(struct sk_buff *skb, struct device *dev, struct packet_type *ptype)
{
- skb->sk = NULL; /* Initially we don't know who its for */
+ skb->sk = NULL; /* Initially we don't know who it's for */
if ((*skb->data & 0x0F) != 0) {
kfree_skb(skb, FREE_READ); /* Not a KISS data frame */
@@ -1914,7+1914,7 @@ static int bpq_rcv(struct sk_buff *skb, struct device *dev, struct packet_type * ax25_address *port_call;
int len;
- skb->sk = NULL; /* Initially we don't know who its for */
+ skb->sk = NULL; /* Initially we don't know who it's for */
if ((port_call = ax25_bpq_get_addr(dev)) == NULL) {
kfree_skb(skb, FREE_READ); /* We have no port callsign */
@@ -2546,7+2546,7 @@ int ax25_rebuild_header(unsigned char *bp, struct device *dev, unsigned long des if (mode == 'V' || mode == 'v' || (mode == ' ' && ax25_dev_get_value(dev, AX25_VALUES_IPDEFMODE) == 'V'))
{
/*
- * This is a workaround to try and keep the device locking
+ * This is a workaround to try to keep the device locking
* straight until skb->free=0 is abolished post 1.4.
*
* We clone the buffer and release the original thereby
@@ -389,7+389,7 @@ void dama_enquiry_response(ax25_cb *ax25)
/* The FLEXNET DAMA master implementation refuses to send us ANY */
/* I frame for this connection if we send a REJ here, probably */
- /* due to it's frame collector scheme? A simple RR or RNR will */
+ /* due to its frame collector scheme? A simple RR or RNR will */
/* invoke the retransmission, and in fact REJs are superfluous */
/* in DAMA mode anyway... */
@@ -248,7+248,7 @@ void ax25_send_control(ax25_cb *ax25, int frametype, int poll_bit, int type) /*
* Send a 'DM' to an unknown connection attempt, or an invalid caller.
*
- * Note: src here is the sender, thus its the target of the DM
+ * Note: src here is the sender, thus it's the target of the DM
*/
void ax25_return_dm(struct device *dev, ax25_address *src, ax25_address *dest, ax25_digi *digi)
{
@@ -291,13+291,7 @@ int dev_close(struct device *dev) * Flush the multicast chain
*/
dev_mc_discard(dev);
- /*
- * Blank the IP addresses
- */
- dev->pa_addr = 0;
- dev->pa_dstaddr = 0;
- dev->pa_brdaddr = 0;
- dev->pa_mask = 0;
+
/*
* Purge any queued packets when we down the link
*/
@@ -1082,6+1076,17 @@ static int dev_ifsioc(void *arg, unsigned int getset) }
else
{
+ u32 new_pa_addr = (*(struct sockaddr_in *)
+ &ifr.ifr_addr).sin_addr.s_addr;
+ u16 new_family = ifr.ifr_addr.sa_family;
+
+ if (new_family == dev->family &&
+ new_pa_addr == dev->pa_addr) {
+ ret =0;
+ break;
+ }
+ if (dev->flags & IFF_UP)
+ notifier_call_chain(&netdev_chain, NETDEV_DOWN, dev);
/*
* if dev is an alias, must rehash to update
@@ -1092,16+1097,19 @@ static int dev_ifsioc(void *arg, unsigned int getset) if (net_alias_is(dev))
net_alias_dev_rehash(dev ,&ifr.ifr_addr);
#endif
- dev->pa_addr = (*(struct sockaddr_in *)
- &ifr.ifr_addr).sin_addr.s_addr;
- dev->family = ifr.ifr_addr.sa_family;
+ dev->pa_addr = new_pa_addr;
+ dev->family = new_family;
#ifdef CONFIG_INET
/* This is naughty. When net-032e comes out It wants moving into the net032
code not the kernel. Till then it can sit here (SIGH) */
- dev->pa_mask = ip_get_mask(dev->pa_addr);
+ if (!dev->pa_mask)
+ dev->pa_mask = ip_get_mask(dev->pa_addr);
#endif
- dev->pa_brdaddr = dev->pa_addr | ~dev->pa_mask;
+ if (!dev->pa_brdaddr)
+ dev->pa_brdaddr = dev->pa_addr | ~dev->pa_mask;
+ if (dev->flags & IFF_UP)
+ notifier_call_chain(&netdev_chain, NETDEV_UP, dev);
ret = 0;
}
break;
@@ -1122,7+1122,7 @@ net_alias_dev_rcv_sel(struct device *main_dev, struct sockaddr *sa_src, struct s if (main_dev == NULL) return NULL;
/*
- * if not aliased, dont bother any more
+ * if not aliased, don't bother any more
*/
if ((alias_info = main_dev->alias_info) == NULL)
@@ -1194,7+1194,7 @@ net_alias_dev_rcv_sel32(struct device *main_dev, int family, __u32 src, __u32 ds if (main_dev == NULL) return NULL;
/*
- * if not aliased, dont bother any more
+ * if not aliased, don't bother any more
*/
if ((alias_info = main_dev->alias_info) == NULL)
@@ -154,7+154,7 @@ int eth_rebuild_header(void *buff, struct device *dev, unsigned long dst, }
/*
- * Try and get ARP to resolve the header.
+ * Try to get ARP to resolve the header.
*/
#ifdef CONFIG_INET
return arp_find(eth->h_dest, dst, dev, dev->pa_addr, skb)? 1 : 0;
@@ -22,7+22,7 @@ if [ "$CONFIG_NET_ALIAS" = "y" ]; then tristate 'IP: aliasing support' CONFIG_IP_ALIAS
fi
if [ "$CONFIG_EXPERIMENTAL" = "y" ]; then
- if [ "$CONFIG_KERNELD" = "y" ]; then
+ if [ "$CONFIG_NETLINK" = "y" ]; then
bool 'IP: ARP daemon support (EXPERIMENTAL)' CONFIG_ARPD
fi
fi
#include <linux/net_alias.h>
#endif
#ifdef CONFIG_ARPD
-#include <linux/kerneld.h>
-#endif /* CONFIG_ARPD */
+#include <net/netlink.h>
+#endif
#include <asm/system.h>
#include <asm/segment.h>
#include <stdarg.h>
/*
- * This structure defines the ARP mapping cache. As long as we make changes
- * in this structure, we keep interrupts off. But normally we can copy the
- * hardware address and the device pointer in a local variable and then
- * make any "long calls" to send a packet out.
+ * Configurable Parameters
*/
-struct arp_table
-{
- struct arp_table *next; /* Linked entry list */
- unsigned long last_used; /* For expiry */
- unsigned long last_updated; /* For expiry */
- unsigned int flags; /* Control status */
- u32 ip; /* ip address of entry */
- u32 mask; /* netmask - used for generalised proxy arps (tridge) */
- unsigned char ha[MAX_ADDR_LEN]; /* Hardware address */
- struct device *dev; /* Device the entry is tied to */
+/*
+ * After that time, an unused entry is deleted from the arp table.
+ * RFC1122 recommends set it to 60*HZ, if your site uses proxy arp
+ * and dynamic routing.
+ */
- /*
- * The following entries are only used for unresolved hw addresses.
- */
-
- struct timer_list timer; /* expire timer */
- int retries; /* remaining retries */
- struct sk_buff_head skb; /* list of queued packets */
- struct hh_cache *hh;
-};
+#ifndef CONFIG_ARPD
+#define ARP_TIMEOUT (600*HZ)
+#else
+#define ARP_TIMEOUT (60*HZ)
+#define ARPD_TIMEOUT (600*HZ)
+#endif
+
+/*
+ * How often is ARP cache checked for expire.
+ * It is useless to set ARP_CHECK_INTERVAL > ARP_TIMEOUT
+ */
+#define ARP_CHECK_INTERVAL (60*HZ)
/*
- * Configurable Parameters (don't touch unless you know what you are doing
+ * Soft limit on ARP cache size.
+ * Note that this number should be greater, than
+ * number of simultaneously opened sockets, else
+ * hardware header cache will be not efficient.
*/
+#if RT_CACHE_DEBUG >= 2
+#define ARP_MAXSIZE 4
+#else
+#ifdef CONFIG_ARPD
+#define ARP_MAXSIZE 64
+#else
+#define ARP_MAXSIZE 256
+#endif /* CONFIG_ARPD */
+#endif
+
/*
* If an arp request is send, ARP_RES_TIME is the timeout value until the
* next request is send.
* RFC1122: OK. Throttles ARPing, as per 2.3.2.1. (MUST)
* The recommended minimum timeout is 1 second per destination.
- * This timeout is prolongated to ARP_DEAD_RES_TIME, if
- * destination does not respond.
+ *
*/
#define ARP_RES_TIME (5*HZ)
-#define ARP_DEAD_RES_TIME (60*HZ)
/*
- * The number of times an arp request is send, until the host is
- * considered temporarily unreachable.
+ * The number of times an broadcast arp request is send, until
+ * the host is considered temporarily unreachable.
*/
#define ARP_MAX_TRIES 3
/*
- * After that time, an unused entry is deleted from the arp table.
+ * The entry is reconfirmed by sending point-to-point ARP
+ * request after ARP_CONFIRM_INTERVAL.
+ * RFC1122 recommends 60*HZ.
+ *
+ * Warning: there exist nodes, that answer only broadcast
+ * ARP requests (Cisco-4000 in hot standby mode?)
+ * Now arp code should work with such nodes, but
+ * it still will generate redundant broadcast requests, so that
+ * this interval should be enough long.
*/
-#define ARP_TIMEOUT (600*HZ)
+#define ARP_CONFIRM_INTERVAL (300*HZ)
/*
- * How often is the function 'arp_check_retries' called.
- * An unused entry is invalidated in the time between ARP_TIMEOUT and
- * (ARP_TIMEOUT+ARP_CHECK_INTERVAL).
+ * We wait for answer to unicast request for ARP_CONFIRM_TIMEOUT.
*/
-#define ARP_CHECK_INTERVAL (60*HZ)
+#define ARP_CONFIRM_TIMEOUT ARP_RES_TIME
/*
- * The entry is reconfirmed by sending point-to-point ARP
- * request after ARP_CONFIRM_INTERVAL. If destinations does not respond
- * for ARP_CONFIRM_TIMEOUT, normal broadcast resolution scheme is started.
+ * The number of times an unicast arp request is retried, until
+ * the cache entry is considered suspicious.
+ * Value 0 means that no unicast pings will be sent.
+ * RFC1122 recommends 2.
*/
-#define ARP_CONFIRM_INTERVAL (300*HZ)
-#define ARP_CONFIRM_TIMEOUT ARP_RES_TIME
+#define ARP_MAX_PINGS 1
+
+/*
+ * When a host is dead, but someone tries to connect it,
+ * we do not remove corresponding cache entry (it would
+ * be useless, it will be created again immediately)
+ * Instead we prolongate interval between broadcasts
+ * to ARP_DEAD_RES_TIME.
+ * This interval should be not very long.
+ * (When the host will be up again, we will notice it only
+ * when ARP_DEAD_RES_TIME expires, or when the host will arp us.
+ */
+
+#define ARP_DEAD_RES_TIME (60*HZ)
+
+/*
+ * This structure defines the ARP mapping cache.
+ */
+
+struct arp_table
+{
+ struct arp_table *next; /* Linked entry list */
+ unsigned long last_used; /* For expiry */
+ unsigned long last_updated; /* For expiry */
+ unsigned int flags; /* Control status */
+ u32 ip; /* ip address of entry */
+ u32 mask; /* netmask - used for generalised proxy arps (tridge) */
+ unsigned char ha[MAX_ADDR_LEN]; /* Hardware address */
+ struct device *dev; /* Device the entry is tied to */
+ struct hh_cache *hh; /* Hardware headers chain */
+
+ /*
+ * The following entries are only used for unresolved hw addresses.
+ */
+
+ struct timer_list timer; /* expire timer */
+ int retries; /* remaining retries */
+ struct sk_buff_head skb; /* list of queued packets */
+};
+
+
+static atomic_t arp_size = 0;
+
+#ifdef CONFIG_ARPD
+static int arpd_not_running;
+static int arpd_stamp;
+#endif
-static unsigned int arp_lock;
static unsigned int arp_bh_mask;
#define ARP_BH_BACKLOG 1
+/*
+ * Backlog for ARP updates.
+ */
static struct arp_table *arp_backlog;
-/* If we have arpd configured, assume that we will be running arpd and keep
- the internal cache small */
-#ifdef CONFIG_ARPD
-#define ARP_MAXSIZE 256
-#endif /* CONFIG_ARPD */
+/*
+ * Backlog for incomplete entries.
+ */
+static struct arp_table *arp_req_backlog;
-static unsigned int arp_size = 0;
static void arp_run_bh(void);
static void arp_check_expire (unsigned long);
+static int arp_update (u32 sip, char *sha, struct device * dev,
+ struct arp_table *ientry, int grat);
static struct timer_list arp_timer =
{ NULL, NULL, ARP_CHECK_INTERVAL, 0L, &arp_check_expire };
@@ -216,12+276,10 @@ static struct timer_list arp_timer =
/*
* The size of the hash table. Must be a power of two.
- * Maybe we should remove hashing in the future for arp and concentrate
- * on Patrick Schaaf's Host-Cache-Lookup...
*/
-#define ARP_TABLE_SIZE 16
-#define FULL_ARP_TABLE_SIZE (ARP_TABLE_SIZE+1)
+#define ARP_TABLE_SIZE 16
+#define FULL_ARP_TABLE_SIZE (ARP_TABLE_SIZE+1)
struct arp_table *arp_tables[FULL_ARP_TABLE_SIZE] =
{
@@ -238,22+296,47 @@ struct arp_table *arp_tables[FULL_ARP_TABLE_SIZE] = #define HASH(paddr) (htonl(paddr) & (ARP_TABLE_SIZE - 1))
/*
- * Lock/unlock arp_table chains.
+ * ARP cache semaphore.
+ *
+ * Every time when someone wants to traverse arp table,
+ * he MUST call arp_fast_lock.
+ * It will guarantee that arp cache list will not change
+ * by interrupts and the entry that you found will not
+ * disappear unexpectedly.
+ *
+ * If you want to modify arp cache lists, you MUST
+ * call arp_fast_lock, and check that you are the only
+ * owner of semaphore (arp_lock == 1). If it is not the case
+ * you can defer your operation or forgot it,
+ * but DO NOT TOUCH lists.
+ *
+ * However, you are allowed to change arp entry contents.
+ *
+ * Assumptions:
+ * -- interrupt code MUST have lock/unlock balanced,
+ * you cannot lock cache on interrupt and defer unlocking
+ * to callback.
+ * In particular, it means that lock/unlock are allowed
+ * to be non-atomic. They are made atomic, but it was not
+ * necessary.
+ * -- nobody is allowed to sleep while
+ * it keeps arp locked. (route cache has similar locking
+ * scheme, but allows sleeping)
+ *
*/
-static __inline__ void arp_fast_lock(void)
-{
- ATOMIC_INCR(&arp_lock);
-}
+static atomic_t arp_lock;
-static __inline__ void arp_fast_unlock(void)
+#define ARP_LOCKED() (arp_lock != 1)
+
+static __inline__ void arp_fast_lock(void)
{
- ATOMIC_DECR(&arp_lock);
+ atomic_inc(&arp_lock);
}
static __inline__ void arp_unlock(void)
{
- if (!ATOMIC_DECR_AND_CHECK(&arp_lock) && arp_bh_mask)
+ if (atomic_dec_and_test(&arp_lock) && arp_bh_mask)
arp_run_bh();
}
@@ -306,7+389,7 @@ static struct arp_table * arp_dequeue(struct arp_table **q) * Purge all linked skb's of the entry.
*/
-static void arp_release_entry(struct arp_table *entry)
+static void arp_purge_send_q(struct arp_table *entry)
{
struct sk_buff *skb;
unsigned long flags;
@@ -328,6+411,7 @@ static void arp_release_entry(struct arp_table *entry) /*
* Release the entry and all resources linked to it: skb's, hh's, timer
* and certainly memory.
+ * The entry should be already removed from lists.
*/
static void arp_free_entry(struct arp_table *entry)
@@ -336,280+420,416 @@ static void arp_free_entry(struct arp_table *entry) struct hh_cache *hh, *next;
del_timer(&entry->timer);
+ arp_purge_send_q(entry);
save_flags(flags);
cli();
- arp_release_entry(entry);
+ hh = entry->hh;
+ entry->hh = NULL;
+ restore_flags(flags);
- for (hh = entry->hh; hh; hh = next)
+ for ( ; hh; hh = next)
{
next = hh->hh_next;
- hh->hh_arp = NULL;
hh->hh_uptodate = 0;
- if (!--hh->hh_refcnt)
+ hh->hh_next = NULL;
+ hh->hh_arp = NULL;
+ if (atomic_dec_and_test(&hh->hh_refcnt))
kfree_s(hh, sizeof(struct(struct hh_cache)));
}
- restore_flags(flags);
kfree_s(entry, sizeof(struct arp_table));
- --arp_size;
+ atomic_dec(&arp_size);
return;
}
/*
- * How many users has this entry?
+ * Hardware header cache.
+ *
+ * BEWARE! Hardware header cache has no locking, so that
+ * it requires especially careful handling.
+ * It is the only part of arp+route, where a list
+ * should be traversed with masked interrupts.
+ * Luckily, this list contains one element 8), as rule.
+ */
+
+/*
+ * How many users has this entry?
+ * The answer is reliable only when interrupts are masked.
*/
static __inline__ int arp_count_hhs(struct arp_table * entry)
{
- struct hh_cache *hh, **hhp;
+ struct hh_cache *hh;
int count = 0;
- hhp = &entry->hh;
- while ((hh=*hhp) != NULL)
- {
- if (hh->hh_refcnt == 1)
- {
- *hhp = hh->hh_next;
- kfree_s(hh, sizeof(struct hh_cache));
- continue;
- }
+ for (hh = entry->hh; hh; hh = hh->hh_next)
count += hh->hh_refcnt-1;
- hhp = &hh->hh_next;
- }
return count;
}
-
/*
- * Force the expiry of an entry in the internal cache so the memory
- * can be used for a new request or for loading a query from arpd.
- * I'm not really sure what the best algorithm should be, so I just
- * search for the oldest. NOTE: make sure the cache is locked before
- * jumping into this function! If someone wants to do something
- * other than searching the whole cache, by all means do so!
+ * Signal to device layer, that hardware address may be changed.
*/
-#ifdef CONFIG_ARPD
-static int arp_force_expire(void)
+static __inline__ void arp_update_hhs(struct arp_table * entry)
{
- int i;
- struct arp_table *entry = NULL;
- struct arp_table **pentry = NULL;
- struct arp_table **oldest_entry = NULL, **last_resort = NULL;
- unsigned long oldest_used = ~0;
-
-#if RT_CACHE_DEBUG >= 2
- printk("Looking for something to force expire.\n");
-#endif
- for (i = 0; i < ARP_TABLE_SIZE; i++)
- {
- pentry = &arp_tables[i];
+ struct hh_cache *hh;
- while ((entry = *pentry) != NULL)
- {
- if (entry->last_used < oldest_used)
- {
- if (arp_count_hhs(entry) == 0)
- {
- oldest_entry = pentry;
- }
- last_resort = pentry;
- oldest_used = entry->last_used;
- }
- pentry = &entry->next; /* go to next entry */
- }
- }
- if (oldest_entry == NULL)
- {
- if (last_resort == NULL)
- return -1;
- oldest_entry = last_resort;
- }
-
- entry = *oldest_entry;
- *oldest_entry = (*oldest_entry)->next;
-#if RT_CACHE_DEBUG >= 2
- printk("Force expiring %08x\n", entry->ip);
-#endif
- arp_free_entry(entry);
- return 0;
+ for (hh=entry->hh; hh; hh=hh->hh_next)
+ entry->dev->header_cache_update(hh, entry->dev, entry->ha);
}
-#endif /* CONFIG_ARPD */
+/*
+ * Invalidate all hh's, so that higher level will not try to use it.
+ */
-static void arpd_update(struct arp_table * entry, int loc)
+static __inline__ void arp_invalidate_hhs(struct arp_table * entry)
{
-#ifdef CONFIG_ARPD
- static struct arpd_request arpreq;
-
- arpreq.req = ARPD_UPDATE;
- arpreq.ip = entry->ip;
- arpreq.mask = entry->mask;
- memcpy (arpreq.ha, entry->ha, MAX_ADDR_LEN);
- arpreq.loc = loc;
- arpreq.last_used = entry->last_used;
- arpreq.last_updated = entry->last_updated;
- arpreq.flags = entry->flags;
- arpreq.dev = entry->dev;
-
- kerneld_send(KERNELD_ARP, 0, sizeof(arpreq),
- (char *) &arpreq, NULL);
-#endif /* CONFIG_ARPD */
+ struct hh_cache *hh;
+
+ for (hh=entry->hh; hh; hh=hh->hh_next)
+ hh->hh_uptodate = 0;
}
-/*
- * Allocate memory for a new entry. If we are at the maximum limit
- * of the internal ARP cache, arp_force_expire() an entry. NOTE:
- * arp_force_expire() needs the cache to be locked, so therefore
- * arp_add_entry() should only be called with the cache locked too!
+/*
+ * Atomic attaching new hh entry.
+ * Return 1, if entry has been freed, rather than attached.
*/
-static struct arp_table * arp_add_entry(void)
+static int arp_set_hh(struct hh_cache **hhp, struct hh_cache *hh)
{
- struct arp_table * entry;
+ unsigned long flags;
+ struct hh_cache *hh1;
+ struct arp_table *entry;
-#ifdef CONFIG_ARPD
- if (arp_size >= ARP_MAXSIZE)
+ atomic_inc(&hh->hh_refcnt);
+
+ save_flags(flags);
+ cli();
+ if ((hh1 = *hhp) == NULL)
{
- if (arp_force_expire() < 0)
- return NULL;
+ *hhp = hh;
+ restore_flags(flags);
+ return 0;
}
-#endif /* CONFIG_ARPD */
- entry = (struct arp_table *)
- kmalloc(sizeof(struct arp_table),GFP_ATOMIC);
+ entry = (struct arp_table*)hh->hh_arp;
- if (entry != NULL)
- ++arp_size;
- return entry;
+ /*
+ * An hh1 entry is already attached to this point.
+ * Is it not linked to arp entry? Link it!
+ */
+ if (!hh1->hh_arp && entry)
+ {
+ atomic_inc(&hh1->hh_refcnt);
+ hh1->hh_next = entry->hh;
+ entry->hh = hh1;
+ hh1->hh_arp = (void*)entry;
+ restore_flags(flags);
+
+ if (entry->flags & ATF_COM)
+ entry->dev->header_cache_update(hh1, entry->dev, entry->ha);
+#if RT_CACHE_DEBUG >= 1
+ printk("arp_set_hh: %08x is reattached. Good!\n", entry->ip);
+#endif
+ }
+#if RT_CACHE_DEBUG >= 1
+ else if (entry)
+ printk("arp_set_hh: %08x rr1 ok!\n", entry->ip);
+#endif
+ restore_flags(flags);
+ if (atomic_dec_and_test(&hh->hh_refcnt))
+ kfree_s(hh, sizeof(struct hh_cache));
+ return 1;
}
+static __inline__ struct hh_cache * arp_alloc_hh(int htype)
+{
+ struct hh_cache *hh;
+ hh = kmalloc(sizeof(struct hh_cache), GFP_ATOMIC);
+ if (hh)
+ {
+ memset(hh, 0, sizeof(struct hh_cache));
+ hh->hh_type = htype;
+ }
+ return hh;
+}
/*
- * Lookup ARP entry by (addr, dev) pair in the arpd.
+ * Test if a hardware address is all zero
*/
-static struct arp_table * arpd_lookup(u32 addr, unsigned short flags,
- struct device * dev,
- int loc)
+static __inline__ int empty(unsigned char * addr, int len)
{
+ while (len > 0)
+ {
+ if (*addr)
+ return 0;
+ len--;
+ addr++;
+ }
+ return 1;
+}
+
+
#ifdef CONFIG_ARPD
- static struct arpd_request arpreq, retreq;
- struct arp_table * entry;
- int rv, i;
-
- arpreq.req = ARPD_LOOKUP;
- arpreq.ip = addr;
- arpreq.loc = loc;
-
- rv = kerneld_send(KERNELD_ARP,
- sizeof(retreq) | KERNELD_WAIT,
- sizeof(arpreq),
- (char *) &arpreq,
- (char *) &retreq);
- /* don't worry about rv != 0 too much, it's probably
- because arpd isn't running or an entry couldn't
- be found */
-
- if (rv != 0)
- return NULL;
- if (dev != retreq.dev)
- return NULL;
- if (! memcmp (retreq.ha, "\0\0\0\0\0\0", 6))
- return NULL;
- arp_fast_lock();
- entry = arp_add_entry();
- arp_unlock();
+/*
+ * Send ARPD message.
+ */
+static void arpd_send(int req, u32 addr, struct device * dev, char *ha,
+ unsigned long updated)
+{
+ int retval;
+ struct sk_buff *skb;
+ struct arpd_request *arpreq;
- if (entry == NULL)
- return NULL;
-
- entry->next = NULL;
- entry->last_used = retreq.last_used;
- entry->last_updated = retreq.last_updated;
- entry->flags = retreq.flags;
- entry->ip = retreq.ip;
- entry->mask = retreq.mask;
- memcpy (entry->ha, retreq.ha, MAX_ADDR_LEN);
- arpreq.dev = entry->dev;
-
- skb_queue_head_init(&entry->skb);
- entry->hh = NULL;
- entry->retries = 0;
+ if (arpd_not_running)
+ return;
-#if RT_CACHE_DEBUG >= 2
- printk("Inserting arpd entry %08x\n in local cache.", entry->ip);
-#endif
- i = HASH(entry->ip);
- arp_fast_lock();
- entry->next = arp_tables[i]->next;
- arp_tables[i]->next = entry;
- arp_unlock();
- return entry;
-#endif /* CONFIG_ARPD */
- return NULL;
-}
+ skb = alloc_skb(sizeof(struct arpd_request), GFP_ATOMIC);
+ if (skb == NULL)
+ return;
+ skb->free=1;
+ arpreq=(struct arpd_request *)skb_put(skb, sizeof(struct arpd_request));
+ arpreq->req = req;
+ arpreq->ip = addr;
+ arpreq->dev = (unsigned long)dev;
+ arpreq->stamp = arpd_stamp;
+ arpreq->updated = updated;
+ if (ha)
+ memcpy(arpreq->ha, ha, sizeof(arpreq->ha));
+
+ retval = netlink_post(NETLINK_ARPD, skb);
+ if (retval)
+ {
+ kfree_skb(skb, FREE_WRITE);
+ if (retval == -EUNATCH)
+ arpd_not_running = 1;
+ }
+}
/*
- * Invalidate all hh's, so that higher level will not try to use it.
+ * Send ARPD update message.
*/
-static __inline__ void arp_invalidate_hhs(struct arp_table * entry)
+static __inline__ void arpd_update(struct arp_table * entry)
{
- struct hh_cache *hh;
-
- for (hh=entry->hh; hh; hh=hh->hh_next)
- hh->hh_uptodate = 0;
+ if (arpd_not_running)
+ return;
+ arpd_send(ARPD_UPDATE, entry->ip, entry->dev, entry->ha,
+ entry->last_updated);
}
/*
- * Signal to device layer, that hardware address may be changed.
+ * Send ARPD lookup request.
*/
-static __inline__ void arp_update_hhs(struct arp_table * entry)
+static __inline__ void arpd_lookup(u32 addr, struct device * dev)
{
- struct hh_cache *hh;
-
- for (hh=entry->hh; hh; hh=hh->hh_next)
- entry->dev->header_cache_update(hh, entry->dev, entry->ha);
+ if (arpd_not_running)
+ return;
+ arpd_send(ARPD_LOOKUP, addr, dev, NULL, 0);
}
/*
- * Check if there are too old entries and remove them. If the ATF_PERM
- * flag is set, they are always left in the arp cache (permanent entry).
- * If an entry was not be confirmed for ARP_CONFIRM_INTERVAL,
- * declare it invalid and send point-to-point ARP request.
- * If it will not be confirmed for ARP_CONFIRM_TIMEOUT,
- * give it to shred by arp_expire_entry.
+ * Send ARPD flush message.
*/
-static void arp_check_expire(unsigned long dummy)
+static __inline__ void arpd_flush(struct device * dev)
{
- int i;
- unsigned long now = jiffies;
+ if (arpd_not_running)
+ return;
+ arpd_send(ARPD_FLUSH, 0, dev, NULL, 0);
+}
- del_timer(&arp_timer);
- if (!arp_lock)
+static int arpd_callback(struct sk_buff *skb)
+{
+ struct device * dev;
+ struct arpd_request *retreq;
+
+ arpd_not_running = 0;
+
+ if (skb->len != sizeof(struct arpd_request))
+ {
+ kfree_skb(skb, FREE_READ);
+ return -EINVAL;
+ }
+
+ retreq = (struct arpd_request *)skb->data;
+ dev = (struct device*)retreq->dev;
+
+ if (retreq->stamp != arpd_stamp || !dev)
+ {
+ kfree_skb(skb, FREE_READ);
+ return -EINVAL;
+ }
+
+ if (!retreq->updated || empty(retreq->ha, sizeof(retreq->ha)))
+ {
+/*
+ * Invalid mapping: drop it and send ARP broadcast.
+ */
+ arp_send(ARPOP_REQUEST, ETH_P_ARP, retreq->ip, dev, dev->pa_addr, NULL,
+ dev->dev_addr, NULL);
+ }
+ else
{
arp_fast_lock();
+ arp_update(retreq->ip, retreq->ha, dev, NULL, 0);
+ arp_unlock();
+
+/*
+ * Old mapping: we cannot trust it, send ARP broadcast to confirm it.
+ * If it will answer, the entry will be updated,
+ * if not ... we are lost. We will use it for ARP_CONFIRM_INTERVAL.
+ */
+ if (jiffies - retreq->updated < ARPD_TIMEOUT)
+ arp_send(ARPOP_REQUEST, ETH_P_ARP, retreq->ip, dev, dev->pa_addr, NULL,
+ dev->dev_addr, NULL);
+ }
+
+ kfree_skb(skb, FREE_READ);
+ return sizeof(struct arpd_request);
+}
+
+#else
+
+static __inline__ void arpd_update(struct arp_table * entry)
+{
+ return;
+}
+
+#endif /* CONFIG_ARPD */
+
+
+
+
+/*
+ * ARP expiration routines.
+ */
+
+/*
+ * Force the expiry of an entry in the internal cache so the memory
+ * can be used for a new request.
+ */
+
+static int arp_force_expire(void)
+{
+ int i;
+ struct arp_table *entry, **pentry;
+ struct arp_table **oldest_entry = NULL;
+ unsigned long oldest_used = ~0;
+ unsigned long flags;
+ unsigned long now = jiffies;
+ int result = 0;
+
+ static last_index;
+
+ if (ARP_LOCKED())
+ return 0;
+
+ save_flags(flags);
+
+ if (last_index >= ARP_TABLE_SIZE)
+ last_index = 0;
+
+ for (i = 0; i < ARP_TABLE_SIZE; i++, last_index++)
+ {
+ pentry = &arp_tables[last_index & (ARP_TABLE_SIZE-1)];
+
+ while ((entry = *pentry) != NULL)
+ {
+ if (!(entry->flags & ATF_PERM))
+ {
+ int users;
+ cli();
+ users = arp_count_hhs(entry);
+
+ if (!users && now - entry->last_used > ARP_TIMEOUT)
+ {
+ *pentry = entry->next;
+ restore_flags(flags);
+#if RT_CACHE_DEBUG >= 2
+ printk("arp_force_expire: %08x expired\n", entry->ip);
+#endif
+ arp_free_entry(entry);
+ result++;
+ if (arp_size < ARP_MAXSIZE)
+ goto done;
+ continue;
+ }
+ restore_flags(flags);
+ if (!users && entry->last_used < oldest_used)
+ {
+ oldest_entry = pentry;
+ oldest_used = entry->last_used;
+ }
+ }
+ pentry = &entry->next;
+ }
+ }
+
+done:
+ if (result || !oldest_entry)
+ return result;
+
+ entry = *oldest_entry;
+ *oldest_entry = entry->next;
+#if RT_CACHE_DEBUG >= 2
+ printk("arp_force_expire: expiring %08x\n", entry->ip);
+#endif
+ arp_free_entry(entry);
+ return 1;
+}
+
+/*
+ * Check if there are too old entries and remove them. If the ATF_PERM
+ * flag is set, they are always left in the arp cache (permanent entry).
+ * If an entry was not be confirmed for ARP_CONFIRM_INTERVAL,
+ * send point-to-point ARP request.
+ * If it will not be confirmed for ARP_CONFIRM_TIMEOUT,
+ * give it to shred by arp_expire_entry.
+ */
+
+static void arp_check_expire(unsigned long dummy)
+{
+ int i;
+ unsigned long now = jiffies;
+
+ del_timer(&arp_timer);
+
+#ifdef CONFIG_ARPD
+ arpd_not_running = 0;
+#endif
+
+ ip_rt_check_expire();
+
+ arp_fast_lock();
+
+ if (!ARP_LOCKED())
+ {
for (i = 0; i < ARP_TABLE_SIZE; i++)
{
- struct arp_table *entry;
- struct arp_table **pentry;
+ struct arp_table *entry, **pentry;
pentry = &arp_tables[i];
while ((entry = *pentry) != NULL)
{
+ if (entry->flags & ATF_PERM)
+ {
+ pentry = &entry->next;
+ continue;
+ }
+
cli();
if (now - entry->last_used > ARP_TIMEOUT
- && !(entry->flags & ATF_PERM)
&& !arp_count_hhs(entry))
{
*pentry = entry->next;
@@ -618,17+838,15 @@ static void arp_check_expire(unsigned long dummy) printk("arp_expire: %08x expired\n", entry->ip);
#endif
arp_free_entry(entry);
+ continue;
}
- else if (entry->last_updated
- && now - entry->last_updated > ARP_CONFIRM_INTERVAL
- && !(entry->flags & ATF_PERM))
+ sti();
+ if (entry->last_updated
+ && now - entry->last_updated > ARP_CONFIRM_INTERVAL
+ && !(entry->flags & ATF_PERM))
{
struct device * dev = entry->dev;
- pentry = &entry->next;
- entry->flags &= ~ATF_COM;
- arp_invalidate_hhs(entry);
- sti();
- entry->retries = ARP_MAX_TRIES+1;
+ entry->retries = ARP_MAX_TRIES+ARP_MAX_PINGS;
del_timer(&entry->timer);
entry->timer.expires = jiffies + ARP_CONFIRM_TIMEOUT;
add_timer(&entry->timer);
@@ -639,14+857,12 @@ static void arp_check_expire(unsigned long dummy) printk("arp_expire: %08x requires confirmation\n", entry->ip);
#endif
}
- else
- pentry = &entry->next; /* go to next entry */
+ pentry = &entry->next; /* go to next entry */
}
}
- arp_unlock();
}
- ip_rt_check_expire();
+ arp_unlock();
/*
* Set the timer again.
@@ -669,34+885,46 @@ static void arp_expire_request (unsigned long arg) unsigned long hash;
unsigned long flags;
+ arp_fast_lock();
+
save_flags(flags);
cli();
+ del_timer(&entry->timer);
/*
- * Since all timeouts are handled with interrupts enabled, there is a
- * small chance, that this entry has just been resolved by an incoming
- * packet. This is the only race condition, but it is handled...
+ * If arp table is locked, defer expire processing.
*/
-
- if (entry->flags & ATF_COM)
+ if (ARP_LOCKED())
{
+#if RT_CACHE_DEBUG >= 1
+ printk(KERN_DEBUG "arp_expire_request: %08x deferred\n", entry->ip);
+#endif
+ entry->timer.expires = jiffies + HZ/10;
+ add_timer(&entry->timer);
restore_flags(flags);
+ arp_unlock();
return;
}
- if (arp_lock)
+ /*
+ * Since all timeouts are handled with interrupts enabled, there is a
+ * small chance, that this entry has just been resolved by an incoming
+ * packet. This is the only race condition, but it is handled...
+ *
+ * One exception: if entry is COMPLETE but old,
+ * it means that point-to-point ARP ping has been failed
+ * (It really occurs with Cisco 4000 routers)
+ * We should reconfirm it.
+ */
+
+ if ((entry->flags & ATF_COM) && entry->last_updated
+ && jiffies - entry->last_updated <= ARP_CONFIRM_INTERVAL)
{
-#if RT_CACHE_DEBUG >= 1
- printk("arp_expire_request: %08x postponed\n", entry->ip);
-#endif
- del_timer(&entry->timer);
- entry->timer.expires = jiffies + HZ/10;
- add_timer(&entry->timer);
restore_flags(flags);
+ arp_unlock();
return;
}
- arp_fast_lock();
restore_flags(flags);
if (entry->last_updated && --entry->retries > 0)
@@ -707,29+935,47 @@ static void arp_expire_request (unsigned long arg) printk("arp_expire_request: %08x timed out\n", entry->ip);
#endif
/* Set new timer. */
- del_timer(&entry->timer);
entry->timer.expires = jiffies + ARP_RES_TIME;
add_timer(&entry->timer);
- arp_send(ARPOP_REQUEST, ETH_P_ARP, entry->ip, dev, dev->pa_addr,
- NULL, dev->dev_addr, NULL);
+ arp_send(ARPOP_REQUEST, ETH_P_ARP, entry->ip, dev, dev->pa_addr,
+ entry->retries > ARP_MAX_TRIES ? entry->ha : NULL,
+ dev->dev_addr, NULL);
arp_unlock();
return;
}
- arp_release_entry(entry);
+ /*
+ * The host is really dead.
+ */
+
+ arp_purge_send_q(entry);
cli();
if (arp_count_hhs(entry))
{
+ /*
+ * The host is dead, but someone refers to it.
+ * It is useless to drop this entry just now,
+ * it will be born again, so that
+ * we keep it, but slow down retransmitting
+ * to ARP_DEAD_RES_TIME.
+ */
+
struct device *dev = entry->dev;
#if RT_CACHE_DEBUG >= 2
printk("arp_expire_request: %08x is dead\n", entry->ip);
#endif
- arp_release_entry(entry);
entry->retries = ARP_MAX_TRIES;
+ entry->flags &= ~ATF_COM;
+ arp_invalidate_hhs(entry);
restore_flags(flags);
+
+ /*
+ * Declare the entry dead.
+ */
entry->last_updated = 0;
- del_timer(&entry->timer);
+ arpd_update(entry);
+
entry->timer.expires = jiffies + ARP_DEAD_RES_TIME;
add_timer(&entry->timer);
arp_send(ARPOP_REQUEST, ETH_P_ARP, entry->ip, dev, dev->pa_addr,
@@ -739,30+985,65 @@ static void arp_expire_request (unsigned long arg) }
restore_flags(flags);
+ entry->last_updated = 0;
+ arpd_update(entry);
+
hash = HASH(entry->ip);
pentry = &arp_tables[hash];
while (*pentry != NULL)
{
- if (*pentry == entry)
+ if (*pentry != entry)
{
- cli();
- *pentry = entry->next;
- restore_flags(flags);
+ pentry = &(*pentry)->next;
+ continue;
+ }
+ *pentry = entry->next;
#if RT_CACHE_DEBUG >= 2
- printk("arp_expire_request: %08x is killed\n", entry->ip);
+ printk("arp_expire_request: %08x is killed\n", entry->ip);
#endif
- arp_free_entry(entry);
- arp_unlock();
- return;
- }
- pentry = &(*pentry)->next;
+ arp_free_entry(entry);
}
- printk("arp_expire_request: bug: ARP entry is lost!\n");
arp_unlock();
}
+
+/*
+ * Allocate memory for a new entry. If we are at the maximum limit
+ * of the internal ARP cache, arp_force_expire() an entry. NOTE:
+ * arp_force_expire() needs the cache to be locked, so therefore
+ * arp_alloc_entry() should only be called with the cache locked too!
+ */
+
+static struct arp_table * arp_alloc_entry(void)
+{
+ struct arp_table * entry;
+
+
+ if (arp_size >= ARP_MAXSIZE)
+ arp_force_expire();
+
+ entry = (struct arp_table *)
+ kmalloc(sizeof(struct arp_table),GFP_ATOMIC);
+
+ if (entry != NULL)
+ {
+ atomic_inc(&arp_size);
+ memset(entry, 0, sizeof(struct arp_table));
+
+ entry->mask = DEF_ARP_NETMASK;
+ init_timer(&entry->timer);
+ entry->timer.function = arp_expire_request;
+ entry->timer.data = (unsigned long)entry;
+ entry->last_updated = entry->last_used = jiffies;
+ skb_queue_head_init(&entry->skb);
+ }
+ return entry;
+}
+
+
+
/*
* Purge a device from the ARP queue
*/
@@ -774,15+1055,17 @@ int arp_device_event(struct notifier_block *this, unsigned long event, void *ptr
if (event != NETDEV_DOWN)
return NOTIFY_DONE;
- /*
- * This is a bit OTT - maybe we need some arp semaphores instead.
- */
-#if RT_CACHE_DEBUG >= 1
- if (arp_lock)
- printk("arp_device_event: bug\n");
+#ifdef CONFIG_ARPD
+ arpd_flush(dev);
+ arpd_stamp++;
#endif
+
arp_fast_lock();
+#if RT_CACHE_DEBUG >= 1
+ if (ARP_LOCKED())
+ printk("arp_device_event: impossible\n");
+#endif
for (i = 0; i < FULL_ARP_TABLE_SIZE; i++)
{
@@ -805,104+1088,29 @@ int arp_device_event(struct notifier_block *this, unsigned long event, void *ptr }
+
/*
- * Create and send an arp packet. If (dest_hw == NULL), we create a broadcast
- * message.
+ * This will try to retransmit everything on the queue.
*/
-void arp_send(int type, int ptype, u32 dest_ip,
- struct device *dev, u32 src_ip,
- unsigned char *dest_hw, unsigned char *src_hw,
- unsigned char *target_hw)
+static void arp_send_q(struct arp_table *entry)
{
struct sk_buff *skb;
- struct arphdr *arp;
- unsigned char *arp_ptr;
- /*
- * No arp on this interface.
- */
-
- if (dev->flags&IFF_NOARP)
- return;
+ unsigned long flags;
/*
- * Allocate a buffer
+ * Empty the entire queue, building its data up ready to send
*/
- skb = alloc_skb(sizeof(struct arphdr)+ 2*(dev->addr_len+4)
- + dev->hard_header_len, GFP_ATOMIC);
- if (skb == NULL)
+ if(!(entry->flags&ATF_COM))
{
- printk("ARP: no memory to send an arp packet\n");
- return;
- }
- skb_reserve(skb, dev->hard_header_len);
- arp = (struct arphdr *) skb_put(skb,sizeof(struct arphdr) + 2*(dev->addr_len+4));
- skb->arp = 1;
- skb->dev = dev;
- skb->free = 1;
- skb->protocol = htons (ETH_P_IP);
-
- /*
- * Fill the device header for the ARP frame
- */
-
- dev->hard_header(skb,dev,ptype,dest_hw?dest_hw:dev->broadcast,src_hw?src_hw:NULL,skb->len);
-
- /* Fill out the arp protocol part. */
- arp->ar_hrd = htons(dev->type);
-#ifdef CONFIG_AX25
-#ifdef CONFIG_NETROM
- arp->ar_pro = (dev->type == ARPHRD_AX25 || dev->type == ARPHRD_NETROM) ? htons(AX25_P_IP) : htons(ETH_P_IP);
-#else
- arp->ar_pro = (dev->type != ARPHRD_AX25) ? htons(ETH_P_IP) : htons(AX25_P_IP);
-#endif
-#else
- arp->ar_pro = htons(ETH_P_IP);
-#endif
- arp->ar_hln = dev->addr_len;
- arp->ar_pln = 4;
- arp->ar_op = htons(type);
-
- arp_ptr=(unsigned char *)(arp+1);
-
- memcpy(arp_ptr, src_hw, dev->addr_len);
- arp_ptr+=dev->addr_len;
- memcpy(arp_ptr, &src_ip,4);
- arp_ptr+=4;
- if (target_hw != NULL)
- memcpy(arp_ptr, target_hw, dev->addr_len);
- else
- memset(arp_ptr, 0, dev->addr_len);
- arp_ptr+=dev->addr_len;
- memcpy(arp_ptr, &dest_ip, 4);
-
- dev_queue_xmit(skb, dev, 0);
-}
-
-/*
- * This will try to retransmit everything on the queue.
- */
-
-static void arp_send_q(struct arp_table *entry)
-{
- struct sk_buff *skb;
-
- unsigned long flags;
-
- /*
- * Empty the entire queue, building its data up ready to send
- */
-
- if(!(entry->flags&ATF_COM))
- {
- printk("arp_send_q: incomplete entry for %s\n",
- in_ntoa(entry->ip));
- /* Can't flush the skb, because RFC1122 says to hang on to */
- /* at least one from any unresolved entry. --MS */
- /* What's happened is that someone has 'unresolved' the entry
- as we got to use it - this 'can't happen' -- AC */
+ printk("arp_send_q: incomplete entry for %s\n",
+ in_ntoa(entry->ip));
+ /* Can't flush the skb, because RFC1122 says to hang on to */
+ /* at least one from any unresolved entry. --MS */
+ /* What's happened is that someone has 'unresolved' the entry
+ as we got to use it - this 'can't happen' -- AC */
return;
}
@@ -927,435+1135,137 @@ static void arp_send_q(struct arp_table *entry) }
-/*
- * Delete an ARP mapping entry in the cache.
- */
-
-static void arp_destroy(struct arp_table * entry)
+static int
+arp_update (u32 sip, char *sha, struct device * dev,
+ struct arp_table *ientry, int grat)
{
- struct arp_table *entry1;
- struct arp_table **pentry;
+ struct arp_table * entry;
+ unsigned long hash;
- if (entry->flags & ATF_PUBL)
- pentry = &arp_proxy_list;
- else
- pentry = &arp_tables[HASH(entry->ip)];
+ hash = HASH(sip);
+
+ for (entry=arp_tables[hash]; entry; entry = entry->next)
+ if (entry->ip == sip && entry->dev == dev)
+ break;
- while ((entry1 = *pentry) != NULL)
+ if (entry)
{
- if (entry1 == entry)
+/*
+ * Entry found; update it only if it is not a permanent entry.
+ */
+ if (!(entry->flags & ATF_PERM))
{
- *pentry = entry1->next;
del_timer(&entry->timer);
- arp_free_entry(entry);
- return;
+ entry->last_updated = jiffies;
+ if (memcmp(entry->ha, sha, dev->addr_len)!=0)
+ {
+ memcpy(entry->ha, sha, dev->addr_len);
+ if (entry->flags & ATF_COM)
+ arp_update_hhs(entry);
+ }
+ arpd_update(entry);
}
- pentry = &entry1->next;
- }
-}
+ if (!(entry->flags & ATF_COM))
+ {
/*
- * Receive an arp request by the device layer. Maybe I rewrite it, to
- * use the incoming packet for the reply. The time for the current
- * "overhead" isn't that high...
+ * This entry was incomplete. Delete the retransmit timer
+ * and switch to complete status.
*/
-
-int arp_rcv(struct sk_buff *skb, struct device *dev, struct packet_type *pt)
-{
-/*
- * We shouldn't use this type conversion. Check later.
+ entry->flags |= ATF_COM;
+ arp_update_hhs(entry);
+/*
+ * Send out waiting packets. We might have problems, if someone is
+ * manually removing entries right now -- entry might become invalid
+ * underneath us.
*/
-
- struct arphdr *arp = (struct arphdr *)skb->h.raw;
- unsigned char *arp_ptr= (unsigned char *)(arp+1);
- struct arp_table *entry;
- struct arp_table *proxy_entry;
- unsigned long hash, grat=0;
- unsigned char ha[MAX_ADDR_LEN]; /* So we can enable ints again. */
- unsigned char *sha,*tha;
- u32 sip,tip;
-
-/*
- * The hardware length of the packet should match the hardware length
- * of the device. Similarly, the hardware types should match. The
- * device should be ARP-able. Also, if pln is not 4, then the lookup
- * is not from an IP number. We can't currently handle this, so toss
- * it.
- */
- if (arp->ar_hln != dev->addr_len ||
- dev->type != ntohs(arp->ar_hrd) ||
- dev->flags & IFF_NOARP ||
- arp->ar_pln != 4)
- {
- kfree_skb(skb, FREE_READ);
- return 0;
- /* Should this be an error/printk? Seems like something */
- /* you'd want to know about. Unless it's just !IFF_NOARP. -- MS */
+ arp_send_q(entry);
+ }
+ return 1;
}
/*
- * Another test.
- * The logic here is that the protocol being looked up by arp should
- * match the protocol the device speaks. If it doesn't, there is a
- * problem, so toss the packet.
+ * No entry found. Need to add a new entry to the arp table.
*/
-/* Again, should this be an error/printk? -- MS */
-
- switch (dev->type)
- {
-#ifdef CONFIG_AX25
- case ARPHRD_AX25:
- if(arp->ar_pro != htons(AX25_P_IP))
- {
- kfree_skb(skb, FREE_READ);
- return 0;
- }
- break;
-#endif
-#ifdef CONFIG_NETROM
- case ARPHRD_NETROM:
- if(arp->ar_pro != htons(AX25_P_IP))
- {
- kfree_skb(skb, FREE_READ);
- return 0;
- }
- break;
-#endif
- case ARPHRD_ETHER:
- case ARPHRD_ARCNET:
- case ARPHRD_METRICOM:
- if(arp->ar_pro != htons(ETH_P_IP))
- {
- kfree_skb(skb, FREE_READ);
- return 0;
- }
- break;
+ entry = ientry;
- case ARPHRD_IEEE802:
- if(arp->ar_pro != htons(ETH_P_IP))
- {
- kfree_skb(skb, FREE_READ);
- return 0;
- }
- break;
+ if (grat && !entry)
+ return 0;
- default:
- printk("ARP: dev->type mangled!\n");
- kfree_skb(skb, FREE_READ);
+ if (!entry)
+ {
+ entry = arp_alloc_entry();
+ if (!entry)
return 0;
+
+ entry->ip = sip;
+ entry->flags = ATF_COM;
+ memcpy(entry->ha, sha, dev->addr_len);
+ entry->dev = dev;
}
-/*
- * Extract fields
- */
+ entry->last_updated = entry->last_used = jiffies;
+ arpd_update(entry);
- sha=arp_ptr;
- arp_ptr += dev->addr_len;
- memcpy(&sip, arp_ptr, 4);
- arp_ptr += 4;
- tha=arp_ptr;
- arp_ptr += dev->addr_len;
- memcpy(&tip, arp_ptr, 4);
-
-/*
- * Check for bad requests for 127.x.x.x and requests for multicast
- * addresses. If this is one such, delete it.
- */
- if (LOOPBACK(tip) || MULTICAST(tip))
+ if (!ARP_LOCKED())
{
- kfree_skb(skb, FREE_READ);
+ entry->next = arp_tables[hash];
+ arp_tables[hash] = entry;
return 0;
}
+#if RT_CACHE_DEBUG >= 2
+ printk("arp_update: %08x backlogged\n", entry->ip);
+#endif
+ arp_enqueue(&arp_backlog, entry);
+ arp_bh_mask |= ARP_BH_BACKLOG;
+ return 0;
+}
-/*
- * Process entry. The idea here is we want to send a reply if it is a
- * request for us or if it is a request for someone else that we hold
- * a proxy for. We want to add an entry to our cache if it is a reply
- * to us or if it is a request for our address.
- * (The assumption for this last is that if someone is requesting our
- * address, they are probably intending to talk to us, so it saves time
- * if we cache their address. Their address is also probably not in
- * our cache, since ours is not in their cache.)
- *
- * Putting this another way, we only care about replies if they are to
- * us, in which case we add them to the cache. For requests, we care
- * about those for us and those for our proxies. We reply to both,
- * and in the case of requests for us we add the requester to the arp
- * cache.
- */
+
+
+static __inline__ struct arp_table *arp_lookup(u32 paddr, struct device * dev)
+{
+ struct arp_table *entry;
+
+ for (entry = arp_tables[HASH(paddr)]; entry != NULL; entry = entry->next)
+ if (entry->ip == paddr && (!dev || entry->dev == dev))
+ return entry;
+ return NULL;
+}
/*
- * try to switch to alias device whose addr is tip or closest to sip.
+ * Find an arp mapping in the cache. If not found, return false.
*/
-#ifdef CONFIG_NET_ALIAS
- if (tip != dev->pa_addr && net_alias_has(skb->dev))
- {
- /*
- * net_alias_dev_rcv_sel32 returns main dev if it fails to found other.
- */
- dev = net_alias_dev_rcv_sel32(dev, AF_INET, sip, tip);
+int arp_query(unsigned char *haddr, u32 paddr, struct device * dev)
+{
+ struct arp_table *entry;
- if (dev->type != ntohs(arp->ar_hrd) || dev->flags & IFF_NOARP)
+ arp_fast_lock();
+
+ entry = arp_lookup(paddr, dev);
+
+ if (entry != NULL)
+ {
+ entry->last_used = jiffies;
+ if (entry->flags & ATF_COM)
{
- kfree_skb(skb, FREE_READ);
- return 0;
+ memcpy(haddr, entry->ha, dev->addr_len);
+ arp_unlock();
+ return 1;
}
}
-#endif
+ arp_unlock();
+ return 0;
+}
- if (arp->ar_op == htons(ARPOP_REQUEST))
- {
-/*
- * Only reply for the real device address or when it's in our proxy tables
- */
- if (tip != dev->pa_addr)
- {
-/*
- * To get in here, it is a request for someone else. We need to
- * check if that someone else is one of our proxies. If it isn't,
- * we can toss it.
- */
- arp_fast_lock();
- for (proxy_entry=arp_proxy_list;
- proxy_entry;
- proxy_entry = proxy_entry->next)
- {
- /* we will respond to a proxy arp request
- if the masked arp table ip matches the masked
- tip. This allows a single proxy arp table
- entry to be used on a gateway machine to handle
- all requests for a whole network, rather than
- having to use a huge number of proxy arp entries
- and having to keep them uptodate.
- */
- if (proxy_entry->dev == dev &&
- !((proxy_entry->ip^tip)&proxy_entry->mask))
- break;
-
- }
- if (proxy_entry)
- {
- memcpy(ha, proxy_entry->ha, dev->addr_len);
- arp_unlock();
- arp_send(ARPOP_REPLY,ETH_P_ARP,sip,dev,tip,sha,ha, sha);
- kfree_skb(skb, FREE_READ);
- return 0;
- }
- else
- {
- arp_unlock();
- }
- }
- else
- {
-/*
- * To get here, it must be an arp request for us. We need to reply.
- */
- arp_send(ARPOP_REPLY,ETH_P_ARP,sip,dev,tip,sha,dev->dev_addr,sha);
- }
- grat = 1;
- goto gratuitous;
- }
-/*
- * It is now an arp reply.
- */
- if(ip_chk_addr(tip)!=IS_MYADDR)
- {
-/*
- * Replies to other machines get tossed.
- */
- kfree_skb(skb, FREE_READ);
- return 0;
- }
-/*
- * Now all replies are handled. Next, anything that falls through to here
- * needs to be added to the arp cache, or have its entry updated if it is
- * there.
- */
-
-gratuitous:
-
- arp_fast_lock();
-
-
- hash = HASH(sip);
- for (entry=arp_tables[hash]; entry; entry=entry->next)
- if (entry->ip == sip && entry->dev == dev)
- break;
-
- if (entry)
- {
-/*
- * Entry found; update it only if it is not a permanent entry.
- */
- if (!(entry->flags & ATF_PERM))
- {
- if(memcmp(entry->ha, sha,dev->addr_len)!=0)
- {
- memcpy(entry->ha, sha, dev->addr_len);
- if(entry->flags & ATF_COM)
- arp_update_hhs(entry);
- }
- entry->last_updated = jiffies;
- arpd_update(entry, __LINE__);
- }
- if (!(entry->flags & ATF_COM))
- {
-/*
- * This entry was incomplete. Delete the retransmit timer
- * and switch to complete status.
- */
- del_timer(&entry->timer);
- entry->flags |= ATF_COM;
- arp_update_hhs(entry);
-/*
- * Send out waiting packets. We might have problems, if someone is
- * manually removing entries right now -- entry might become invalid
- * underneath us.
- */
- arp_send_q(entry);
- }
- }
- else
- {
-/*
- * No entry found. Need to add a new entry to the arp table.
- */
-
- if (grat)
- goto end;
-
- entry = arp_add_entry();
- if(entry == NULL)
- {
- arp_unlock();
-#if RT_CACHE_DEBUG >= 2
- printk("ARP: no memory for new arp entry\n");
-#endif
- kfree_skb(skb, FREE_READ);
- return 0;
- }
-
- entry->mask = DEF_ARP_NETMASK;
- entry->ip = sip;
- entry->flags = ATF_COM;
- entry->hh = NULL;
- init_timer(&entry->timer);
- entry->timer.function = arp_expire_request;
- entry->timer.data = (unsigned long)entry;
- memcpy(entry->ha, sha, dev->addr_len);
- entry->last_updated = entry->last_used = jiffies;
- arpd_update(entry, __LINE__);
-/*
- * make entry point to 'correct' device
- */
-
-#ifdef CONFIG_NET_ALIAS
- entry->dev = dev;
-#else
- entry->dev = skb->dev;
-#endif
- skb_queue_head_init(&entry->skb);
- if (arp_lock == 1)
- {
- entry->next = arp_tables[hash];
- arp_tables[hash] = entry;
- }
- else
- {
-#if RT_CACHE_DEBUG >= 2
- printk("arp_rcv: %08x backlogged\n", entry->ip);
-#endif
- arp_enqueue(&arp_backlog, entry);
- arp_bh_mask |= ARP_BH_BACKLOG;
- }
- }
-
-/*
- * Replies have been sent, and entries have been added. All done.
- */
-
-end:
- kfree_skb(skb, FREE_READ);
- arp_unlock();
- return 0;
-}
-
-/*
- * Lookup ARP entry by (addr, dev) pair.
- * Flags: ATF_PUBL - search for proxy entries
- * ATF_NETMASK - search for proxy network entry.
- * NOTE: should be called with locked ARP tables.
- */
-
-static struct arp_table *arp_lookup(u32 paddr, unsigned short flags, struct device * dev)
-{
- struct arp_table *entry;
-
- if (!(flags & ATF_PUBL))
- {
- for (entry = arp_tables[HASH(paddr)];
- entry != NULL; entry = entry->next)
- if (entry->ip == paddr && (!dev || entry->dev == dev))
- break;
- return entry;
- }
-
- if (!(flags & ATF_NETMASK))
- {
- for (entry = arp_proxy_list;
- entry != NULL; entry = entry->next)
- if (entry->ip == paddr && (!dev || entry->dev == dev))
- break;
- return entry;
- }
-
- for (entry=arp_proxy_list; entry != NULL; entry = entry->next)
- if (!((entry->ip^paddr)&entry->mask) &&
- (!dev || entry->dev == dev))
- break;
- return entry;
-}
-
-/*
- * Find an arp mapping in the cache. If not found, return false.
- */
-
-int arp_query(unsigned char *haddr, u32 paddr, struct device * dev)
-{
- struct arp_table *entry;
-
- arp_fast_lock();
-
- entry = arp_lookup(paddr, 0, dev);
- if (entry == NULL)
- entry = arpd_lookup(paddr, 0, dev, __LINE__);
-
- if (entry != NULL)
- {
- entry->last_used = jiffies;
- if (entry->flags & ATF_COM)
- {
- memcpy(haddr, entry->ha, dev->addr_len);
- arpd_update(entry, __LINE__);
- arp_unlock();
- return 1;
- }
- }
- arpd_update(entry, __LINE__);
- arp_unlock();
- return 0;
-}
-
-
-static int arp_set_predefined(int addr_hint, unsigned char * haddr, __u32 paddr, struct device * dev)
+static int arp_set_predefined(int addr_hint, unsigned char * haddr, u32 paddr, struct device * dev)
{
switch (addr_hint)
{
case IS_MYADDR:
- printk("ARP: arp called for own IP address\n");
+ printk(KERN_DEBUG "ARP: arp called for own IP address\n");
memcpy(haddr, dev->dev_addr, dev->addr_len);
return 1;
#ifdef CONFIG_IP_MULTICAST
@@ -1387,325+1297,221 @@ static int arp_set_predefined(int addr_hint, unsigned char * haddr, __u32 paddr, }
/*
- * Find an arp mapping in the cache. If not found, post a request.
+ * Create a new unresolved entry.
*/
-int arp_find(unsigned char *haddr, u32 paddr, struct device *dev,
- u32 saddr, struct sk_buff *skb)
+struct arp_table * arp_new_entry(u32 paddr, struct device *dev, struct hh_cache *hh, struct sk_buff *skb)
{
struct arp_table *entry;
- unsigned long hash;
-
- if (arp_set_predefined(ip_chk_addr(paddr), haddr, paddr, dev))
- {
- if (skb)
- skb->arp = 1;
- return 0;
- }
-
- hash = HASH(paddr);
- arp_fast_lock();
-
- /*
- * Find an entry
- */
- entry = arp_lookup(paddr, 0, dev);
- if (entry == NULL)
- entry = arpd_lookup(paddr, 0, dev, __LINE__);
-
- if (entry != NULL) /* It exists */
- {
- if (!(entry->flags & ATF_COM))
- {
- /*
- * A request was already send, but no reply yet. Thus
- * queue the packet with the previous attempt
- */
-
- if (skb != NULL)
- {
- if (entry->last_updated)
- {
- skb_queue_tail(&entry->skb, skb);
- skb_device_unlock(skb);
- }
- /*
- * If last_updated==0 host is dead, so
- * drop skb's and set socket error.
- */
- else
- {
-#if 0
- /*
- * FIXME: ICMP HOST UNREACHABLE should be
- * sent in this situation. --ANK
- */
- if (skb->sk)
- {
- skb->sk->err = EHOSTDOWN;
- skb->sk->error_report(skb->sk);
- }
-#else
- icmp_send(skb, ICMP_DEST_UNREACH, ICMP_HOST_UNREACH, 0, dev);
-#endif
- dev_kfree_skb(skb, FREE_WRITE);
- }
- }
- arp_unlock();
- return 1;
- }
- /*
- * Update the record
- */
-
- entry->last_used = jiffies;
- memcpy(haddr, entry->ha, dev->addr_len);
- arpd_update(entry, __LINE__);
- if (skb)
- skb->arp = 1;
- arp_unlock();
- return 0;
- }
+ entry = arp_alloc_entry();
- /*
- * Create a new unresolved entry.
- */
-
- entry = arp_add_entry();
if (entry != NULL)
{
- entry->last_updated = entry->last_used = jiffies;
- entry->flags = 0;
entry->ip = paddr;
- entry->mask = DEF_ARP_NETMASK;
- memset(entry->ha, 0, dev->addr_len);
entry->dev = dev;
- entry->hh = NULL;
- arpd_update(entry, __LINE__);
- init_timer(&entry->timer);
- entry->timer.function = arp_expire_request;
- entry->timer.data = (unsigned long)entry;
+ if (hh)
+ {
+ entry->hh = hh;
+ atomic_inc(&hh->hh_refcnt);
+ hh->hh_arp = (void*)entry;
+ }
entry->timer.expires = jiffies + ARP_RES_TIME;
- skb_queue_head_init(&entry->skb);
+
if (skb != NULL)
{
skb_queue_tail(&entry->skb, skb);
skb_device_unlock(skb);
}
- if (arp_lock == 1)
+
+ if (!ARP_LOCKED())
{
+ unsigned long hash = HASH(paddr);
entry->next = arp_tables[hash];
arp_tables[hash] = entry;
add_timer(&entry->timer);
entry->retries = ARP_MAX_TRIES;
+#ifdef CONFIG_ARPD
+ if (!arpd_not_running)
+ arpd_lookup(paddr, dev);
+ else
+#endif
+ arp_send(ARPOP_REQUEST, ETH_P_ARP, paddr, dev, dev->pa_addr, NULL,
+ dev->dev_addr, NULL);
}
else
{
#if RT_CACHE_DEBUG >= 2
- printk("arp_find: %08x backlogged\n", entry->ip);
+ printk("arp_new_entry: %08x backlogged\n", entry->ip);
#endif
- arp_enqueue(&arp_backlog, entry);
+ arp_enqueue(&arp_req_backlog, entry);
arp_bh_mask |= ARP_BH_BACKLOG;
}
}
- else if (skb != NULL)
- dev_kfree_skb(skb, FREE_WRITE);
- arp_unlock();
-
- /*
- * If we didn't find an entry, we will try to send an ARP packet.
- */
-
- arp_send(ARPOP_REQUEST, ETH_P_ARP, paddr, dev, saddr, NULL,
- dev->dev_addr, NULL);
-
- return 1;
+ return entry;
}
/*
- * Write the contents of the ARP cache to a PROCfs file.
+ * Find an arp mapping in the cache. If not found, post a request.
*/
-#define HBUFFERLEN 30
-
-int arp_get_info(char *buffer, char **start, off_t offset, int length, int dummy)
+int arp_find(unsigned char *haddr, u32 paddr, struct device *dev,
+ u32 saddr, struct sk_buff *skb)
{
- int len=0;
- off_t pos=0;
- int size;
struct arp_table *entry;
- char hbuffer[HBUFFERLEN];
- int i,j,k;
- const char hexbuf[] = "0123456789ABCDEF";
-
- size = sprintf(buffer,"IP address HW type Flags HW address Mask Device\n");
+ unsigned long hash;
- pos+=size;
- len+=size;
+ if (arp_set_predefined(ip_chk_addr(paddr), haddr, paddr, dev))
+ {
+ if (skb)
+ skb->arp = 1;
+ return 0;
+ }
+ hash = HASH(paddr);
arp_fast_lock();
- for(i=0; i<FULL_ARP_TABLE_SIZE; i++)
+ /*
+ * Find an entry
+ */
+ entry = arp_lookup(paddr, dev);
+
+ if (entry != NULL) /* It exists */
{
- for(entry=arp_tables[i]; entry!=NULL; entry=entry->next)
+ if (entry->flags & ATF_COM)
{
-/*
- * Convert hardware address to XX:XX:XX:XX ... form.
- */
-#ifdef CONFIG_AX25
-#ifdef CONFIG_NETROM
- if (entry->dev->type == ARPHRD_AX25 || entry->dev->type == ARPHRD_NETROM)
- strcpy(hbuffer,ax2asc((ax25_address *)entry->ha));
- else {
-#else
- if(entry->dev->type==ARPHRD_AX25)
- strcpy(hbuffer,ax2asc((ax25_address *)entry->ha));
- else {
-#endif
-#endif
+ entry->last_used = jiffies;
+ memcpy(haddr, entry->ha, dev->addr_len);
+ if (skb)
+ skb->arp = 1;
+ arp_unlock();
+ return 0;
+ }
- for(k=0,j=0;k<HBUFFERLEN-3 && j<entry->dev->addr_len;j++)
+ /*
+ * A request was already send, but no reply yet. Thus
+ * queue the packet with the previous attempt
+ */
+
+ if (skb != NULL)
+ {
+ if (entry->last_updated)
{
- hbuffer[k++]=hexbuf[ (entry->ha[j]>>4)&15 ];
- hbuffer[k++]=hexbuf[ entry->ha[j]&15 ];
- hbuffer[k++]=':';
+ skb_queue_tail(&entry->skb, skb);
+ skb_device_unlock(skb);
}
- hbuffer[--k]=0;
-
-#ifdef CONFIG_AX25
+ /*
+ * If last_updated==0 host is dead, so
+ * drop skb's and set socket error.
+ */
+ else
+ {
+ icmp_send(skb, ICMP_DEST_UNREACH, ICMP_HOST_UNREACH, 0, dev);
+ dev_kfree_skb(skb, FREE_WRITE);
}
-#endif
- size = sprintf(buffer+len,
- "%-17s0x%-10x0x%-10x%s",
- in_ntoa(entry->ip),
- (unsigned int)entry->dev->type,
- entry->flags,
- hbuffer);
-#if RT_CACHE_DEBUG < 2
- size += sprintf(buffer+len+size,
- " %-17s %s\n",
- entry->mask==DEF_ARP_NETMASK ?
- "*" : in_ntoa(entry->mask), entry->dev->name);
-#else
- size += sprintf(buffer+len+size,
- " %-17s %s\t%ld\t%1d\n",
- entry->mask==DEF_ARP_NETMASK ?
- "*" : in_ntoa(entry->mask), entry->dev->name,
- entry->hh ? entry->hh->hh_refcnt : -1,
- entry->hh ? entry->hh->hh_uptodate : 0);
-#endif
-
- len += size;
- pos += size;
-
- if (pos <= offset)
- len=0;
- if (pos >= offset+length)
- goto done;
}
+ arp_unlock();
+ return 1;
}
-done:
+
+ entry = arp_new_entry(paddr, dev, NULL, skb);
+
+ if (skb != NULL && !entry)
+ dev_kfree_skb(skb, FREE_WRITE);
+
arp_unlock();
-
- *start = buffer+len-(pos-offset); /* Start of wanted data */
- len = pos-offset; /* Start slop */
- if (len>length)
- len = length; /* Ending slop */
- return len;
+ return 1;
}
-
+/*
+ * Binding hardware header cache entry.
+ * It is the only really complicated part of arp code.
+ * We have no locking for hh records, so that
+ * all possible race conditions should be resolved by
+ * cli()/sti() pairs.
+ *
+ * Important note: hhs never disapear from lists, if ARP_LOCKED,
+ * this fact allows to scan hh lists with enabled interrupts,
+ * but results in generating duplicate hh entries.
+ * It is harmless. (and I've never seen such event)
+ *
+ * Returns 0, if hh has been just created, so that
+ * caller should fill it.
+ */
int arp_bind_cache(struct hh_cache ** hhp, struct device *dev, unsigned short htype, u32 paddr)
{
struct arp_table *entry;
- struct hh_cache *hh = *hhp;
+ struct hh_cache *hh;
int addr_hint;
unsigned long flags;
- if (hh)
- return 1;
+ save_flags(flags);
if ((addr_hint = ip_chk_addr(paddr)) != 0)
{
unsigned char haddr[MAX_ADDR_LEN];
- if (hh)
+ if (*hhp)
return 1;
- hh = kmalloc(sizeof(struct hh_cache), GFP_ATOMIC);
+ hh = arp_alloc_hh(htype);
if (!hh)
return 1;
arp_set_predefined(addr_hint, haddr, paddr, dev);
- hh->hh_uptodate = 0;
- hh->hh_refcnt = 1;
- hh->hh_arp = NULL;
- hh->hh_next = NULL;
- hh->hh_type = htype;
- *hhp = hh;
dev->header_cache_update(hh, dev, haddr);
- return 0;
+ return arp_set_hh(hhp, hh);
}
- save_flags(flags);
-
arp_fast_lock();
- entry = arp_lookup(paddr, 0, dev);
- if (entry == NULL)
- entry = arpd_lookup(paddr, 0, dev, __LINE__);
+ entry = arp_lookup(paddr, dev);
if (entry)
{
- cli();
for (hh = entry->hh; hh; hh=hh->hh_next)
if (hh->hh_type == htype)
break;
+
if (hh)
{
- hh->hh_refcnt++;
- *hhp = hh;
- restore_flags(flags);
+ arp_set_hh(hhp, hh);
arp_unlock();
return 1;
}
- restore_flags(flags);
}
- hh = kmalloc(sizeof(struct hh_cache), GFP_ATOMIC);
+ hh = arp_alloc_hh(htype);
if (!hh)
{
arp_unlock();
return 1;
}
- hh->hh_uptodate = 0;
- hh->hh_refcnt = 1;
- hh->hh_arp = NULL;
- hh->hh_next = NULL;
- hh->hh_type = htype;
-
if (entry)
{
- dev->header_cache_update(hh, dev, entry->ha);
- *hhp = hh;
+
cli();
hh->hh_arp = (void*)entry;
+ hh->hh_next = entry->hh;
entry->hh = hh;
- hh->hh_refcnt++;
+ atomic_inc(&hh->hh_refcnt);
restore_flags(flags);
+
+ if (entry->flags & ATF_COM)
+ dev->header_cache_update(hh, dev, entry->ha);
+
+ if (arp_set_hh(hhp, hh))
+ {
+ arp_unlock();
+ return 0;
+ }
+
entry->last_used = jiffies;
- arpd_update(entry, __LINE__);
arp_unlock();
return 0;
}
-
- /*
- * Create a new unresolved entry.
- */
-
- entry = arp_add_entry();
+ entry = arp_new_entry(paddr, dev, hh, NULL);
if (entry == NULL)
{
kfree_s(hh, sizeof(struct hh_cache));
@@ -1713,91+1519,74 @@ int arp_bind_cache(struct hh_cache ** hhp, struct device *dev, unsigned short ht return 1;
}
- entry->last_updated = entry->last_used = jiffies;
- entry->flags = 0;
- entry->ip = paddr;
- entry->mask = DEF_ARP_NETMASK;
- memset(entry->ha, 0, dev->addr_len);
- entry->dev = dev;
- entry->hh = hh;
- arpd_update(entry, __LINE__);
- ATOMIC_INCR(&hh->hh_refcnt);
- init_timer(&entry->timer);
- entry->timer.function = arp_expire_request;
- entry->timer.data = (unsigned long)entry;
- entry->timer.expires = jiffies + ARP_RES_TIME;
- skb_queue_head_init(&entry->skb);
-
- if (arp_lock == 1)
- {
- unsigned long hash = HASH(paddr);
- cli();
- entry->next = arp_tables[hash];
- arp_tables[hash] = entry;
- hh->hh_arp = (void*)entry;
- entry->retries = ARP_MAX_TRIES;
- restore_flags(flags);
-
- add_timer(&entry->timer);
- arp_send(ARPOP_REQUEST, ETH_P_ARP, paddr, dev, dev->pa_addr, NULL, dev->dev_addr, NULL);
- }
- else
+ if (!arp_set_hh(hhp, hh))
{
-#if RT_CACHE_DEBUG >= 1
- printk("arp_cache_bind: %08x backlogged\n", entry->ip);
-#endif
- arp_enqueue(&arp_backlog, entry);
- arp_bh_mask |= ARP_BH_BACKLOG;
+ arp_unlock();
+ return 0;
}
- *hhp = hh;
arp_unlock();
- return 0;
+ return 1;
}
static void arp_run_bh()
{
unsigned long flags;
struct arp_table *entry, *entry1;
+ struct device * dev;
+ unsigned long hash;
struct hh_cache *hh;
- __u32 sip;
+ u32 sip;
save_flags(flags);
cli();
- if (!arp_lock)
+ arp_fast_lock();
+
+ while (arp_bh_mask)
{
- arp_fast_lock();
+ arp_bh_mask &= ~ARP_BH_BACKLOG;
while ((entry = arp_dequeue(&arp_backlog)) != NULL)
{
- unsigned long hash;
- sti();
+ restore_flags(flags);
+ if (arp_update(entry->ip, entry->ha, entry->dev, entry, 0))
+ arp_free_entry(entry);
+ cli();
+ }
+
+ cli();
+ while ((entry = arp_dequeue(&arp_req_backlog)) != NULL)
+ {
+ restore_flags(flags);
+
+ dev = entry->dev;
sip = entry->ip;
hash = HASH(sip);
- /* It's possible, that an entry with the same pair
- * (addr,type) was already created. Our entry is older,
- * so it should be discarded.
- */
- for (entry1=arp_tables[hash]; entry1; entry1=entry1->next)
- if (entry1->ip==sip && entry1->dev == entry->dev)
+ for (entry1 = arp_tables[hash]; entry1; entry1 = entry1->next)
+ if (entry1->ip == sip && entry1->dev == dev)
break;
if (!entry1)
{
- struct device * dev = entry->dev;
cli();
entry->next = arp_tables[hash];
arp_tables[hash] = entry;
- for (hh=entry->hh; hh; hh=hh->hh_next)
- hh->hh_arp = (void*)entry;
- sti();
- del_timer(&entry->timer);
+ restore_flags(flags);
entry->timer.expires = jiffies + ARP_RES_TIME;
- add_timer(&entry->timer);
entry->retries = ARP_MAX_TRIES;
- arp_send(ARPOP_REQUEST, ETH_P_ARP, entry->ip, dev, dev->pa_addr, NULL, dev->dev_addr, NULL);
+ entry->last_used = jiffies;
+ if (!(entry->flags & ATF_COM))
+ {
+ add_timer(&entry->timer);
+#ifdef CONFIG_ARPD
+ if (!arpd_not_running)
+ arpd_lookup(sip, dev);
+ else
+#endif
+ arp_send(ARPOP_REQUEST, ETH_P_ARP, sip, dev, dev->pa_addr, NULL, dev->dev_addr, NULL);
+ }
#if RT_CACHE_DEBUG >= 1
- printk("arp_run_bh: %08x reinstalled\n", sip);
+ printk(KERN_DEBUG "arp_run_bh: %08x reinstalled\n", sip);
#endif
}
else
@@ -1824,59+1613,353 @@ static void arp_run_bh() while ((skb = skb_dequeue(&entry->skb)) != NULL)
{
skb_device_lock(skb);
- sti();
+ restore_flags(flags);
skb_queue_tail(&entry1->skb, skb);
skb_device_unlock(skb);
cli();
}
- sti();
+ restore_flags(flags);
-#if RT_CACHE_DEBUG >= 1
- printk("arp_run_bh: entry %08x was born dead\n", entry->ip);
-#endif
arp_free_entry(entry);
- if (entry1->flags & ATF_COM)
- {
- arp_update_hhs(entry1);
- arp_send_q(entry1);
- }
+ if (entry1->flags & ATF_COM)
+ {
+ arp_update_hhs(entry1);
+ arp_send_q(entry1);
+ }
+ }
+ cli();
+ }
+ cli();
+ }
+ arp_unlock();
+ restore_flags(flags);
+}
+
+
+/*
+ * Interface to link layer: send routine and receive handler.
+ */
+
+/*
+ * Create and send an arp packet. If (dest_hw == NULL), we create a broadcast
+ * message.
+ */
+
+void arp_send(int type, int ptype, u32 dest_ip,
+ struct device *dev, u32 src_ip,
+ unsigned char *dest_hw, unsigned char *src_hw,
+ unsigned char *target_hw)
+{
+ struct sk_buff *skb;
+ struct arphdr *arp;
+ unsigned char *arp_ptr;
+
+ /*
+ * No arp on this interface.
+ */
+
+ if (dev->flags&IFF_NOARP)
+ return;
+
+ /*
+ * Allocate a buffer
+ */
+
+ skb = alloc_skb(sizeof(struct arphdr)+ 2*(dev->addr_len+4)
+ + dev->hard_header_len, GFP_ATOMIC);
+ if (skb == NULL)
+ {
+ printk("ARP: no memory to send an arp packet\n");
+ return;
+ }
+ skb_reserve(skb, dev->hard_header_len);
+ arp = (struct arphdr *) skb_put(skb,sizeof(struct arphdr) + 2*(dev->addr_len+4));
+ skb->arp = 1;
+ skb->dev = dev;
+ skb->free = 1;
+ skb->protocol = htons (ETH_P_IP);
+
+ /*
+ * Fill the device header for the ARP frame
+ */
+
+ dev->hard_header(skb,dev,ptype,dest_hw?dest_hw:dev->broadcast,src_hw?src_hw:NULL,skb->len);
+
+ /* Fill out the arp protocol part. */
+ arp->ar_hrd = htons(dev->type);
+#ifdef CONFIG_AX25
+#ifdef CONFIG_NETROM
+ arp->ar_pro = (dev->type == ARPHRD_AX25 || dev->type == ARPHRD_NETROM) ? htons(AX25_P_IP) : htons(ETH_P_IP);
+#else
+ arp->ar_pro = (dev->type != ARPHRD_AX25) ? htons(ETH_P_IP) : htons(AX25_P_IP);
+#endif
+#else
+ arp->ar_pro = htons(ETH_P_IP);
+#endif
+ arp->ar_hln = dev->addr_len;
+ arp->ar_pln = 4;
+ arp->ar_op = htons(type);
+
+ arp_ptr=(unsigned char *)(arp+1);
+
+ memcpy(arp_ptr, src_hw, dev->addr_len);
+ arp_ptr+=dev->addr_len;
+ memcpy(arp_ptr, &src_ip,4);
+ arp_ptr+=4;
+ if (target_hw != NULL)
+ memcpy(arp_ptr, target_hw, dev->addr_len);
+ else
+ memset(arp_ptr, 0, dev->addr_len);
+ arp_ptr+=dev->addr_len;
+ memcpy(arp_ptr, &dest_ip, 4);
+
+ dev_queue_xmit(skb, dev, 0);
+}
+
+
+/*
+ * Receive an arp request by the device layer.
+ */
+
+int arp_rcv(struct sk_buff *skb, struct device *dev, struct packet_type *pt)
+{
+/*
+ * We shouldn't use this type conversion. Check later.
+ */
+
+ struct arphdr *arp = (struct arphdr *)skb->h.raw;
+ unsigned char *arp_ptr= (unsigned char *)(arp+1);
+ unsigned char *sha,*tha;
+ u32 sip,tip;
+
+/*
+ * The hardware length of the packet should match the hardware length
+ * of the device. Similarly, the hardware types should match. The
+ * device should be ARP-able. Also, if pln is not 4, then the lookup
+ * is not from an IP number. We can't currently handle this, so toss
+ * it.
+ */
+ if (arp->ar_hln != dev->addr_len ||
+ dev->type != ntohs(arp->ar_hrd) ||
+ dev->flags & IFF_NOARP ||
+ arp->ar_pln != 4)
+ {
+ kfree_skb(skb, FREE_READ);
+ return 0;
+ /* Should this be an error/printk? Seems like something */
+ /* you'd want to know about. Unless it's just !IFF_NOARP. -- MS */
+ }
+
+/*
+ * Another test.
+ * The logic here is that the protocol being looked up by arp should
+ * match the protocol the device speaks. If it doesn't, there is a
+ * problem, so toss the packet.
+ */
+/* Again, should this be an error/printk? -- MS */
+
+ switch (dev->type)
+ {
+#ifdef CONFIG_AX25
+ case ARPHRD_AX25:
+ if(arp->ar_pro != htons(AX25_P_IP))
+ {
+ kfree_skb(skb, FREE_READ);
+ return 0;
+ }
+ break;
+#endif
+#ifdef CONFIG_NETROM
+ case ARPHRD_NETROM:
+ if(arp->ar_pro != htons(AX25_P_IP))
+ {
+ kfree_skb(skb, FREE_READ);
+ return 0;
+ }
+ break;
+#endif
+ case ARPHRD_ETHER:
+ case ARPHRD_ARCNET:
+ case ARPHRD_METRICOM:
+ if(arp->ar_pro != htons(ETH_P_IP))
+ {
+ kfree_skb(skb, FREE_READ);
+ return 0;
+ }
+ break;
+
+ case ARPHRD_IEEE802:
+ if(arp->ar_pro != htons(ETH_P_IP))
+ {
+ kfree_skb(skb, FREE_READ);
+ return 0;
+ }
+ break;
+
+ default:
+ printk("ARP: dev->type mangled!\n");
+ kfree_skb(skb, FREE_READ);
+ return 0;
+ }
+
+/*
+ * Extract fields
+ */
+
+ sha=arp_ptr;
+ arp_ptr += dev->addr_len;
+ memcpy(&sip, arp_ptr, 4);
+ arp_ptr += 4;
+ tha=arp_ptr;
+ arp_ptr += dev->addr_len;
+ memcpy(&tip, arp_ptr, 4);
+
+/*
+ * Check for bad requests for 127.x.x.x and requests for multicast
+ * addresses. If this is one such, delete it.
+ */
+ if (LOOPBACK(tip) || MULTICAST(tip))
+ {
+ kfree_skb(skb, FREE_READ);
+ return 0;
+ }
+
+/*
+ * Process entry. The idea here is we want to send a reply if it is a
+ * request for us or if it is a request for someone else that we hold
+ * a proxy for. We want to add an entry to our cache if it is a reply
+ * to us or if it is a request for our address.
+ * (The assumption for this last is that if someone is requesting our
+ * address, they are probably intending to talk to us, so it saves time
+ * if we cache their address. Their address is also probably not in
+ * our cache, since ours is not in their cache.)
+ *
+ * Putting this another way, we only care about replies if they are to
+ * us, in which case we add them to the cache. For requests, we care
+ * about those for us and those for our proxies. We reply to both,
+ * and in the case of requests for us we add the requester to the arp
+ * cache.
+ */
+
+/*
+ * try to switch to alias device whose addr is tip or closest to sip.
+ */
+
+#ifdef CONFIG_NET_ALIAS
+ if (tip != dev->pa_addr && net_alias_has(skb->dev))
+ {
+ /*
+ * net_alias_dev_rcv_sel32 returns main dev if it fails to found other.
+ */
+ dev = net_alias_dev_rcv_sel32(dev, AF_INET, sip, tip);
+
+ if (dev->type != ntohs(arp->ar_hrd) || dev->flags & IFF_NOARP)
+ {
+ kfree_skb(skb, FREE_READ);
+ return 0;
+ }
+ }
+#endif
+
+ if (arp->ar_op == htons(ARPOP_REQUEST))
+ {
+
+/*
+ * Only reply for the real device address or when it's in our proxy tables
+ */
+ if (tip != dev->pa_addr)
+ {
+ struct arp_table *proxy_entry;
+
+/*
+ * To get in here, it is a request for someone else. We need to
+ * check if that someone else is one of our proxies. If it isn't,
+ * we can toss it.
+ *
+ * Make "longest match" lookup, a la routing.
+ */
+
+ arp_fast_lock();
+
+ for (proxy_entry = arp_proxy_list; proxy_entry;
+ proxy_entry = proxy_entry->next)
+ {
+ if (proxy_entry->dev == dev &&
+ !((proxy_entry->ip^tip)&proxy_entry->mask))
+ break;
+ }
+
+ if (proxy_entry && (proxy_entry->mask || ((dev->pa_addr^tip)&dev->pa_mask)))
+ {
+ char ha[MAX_ADDR_LEN];
+ struct rtable * rt;
+
+ /* Unlock arp tables to make life for
+ * ip_rt_route easy. Note, that we are obliged
+ * to make local copy of hardware address.
+ */
+
+ memcpy(ha, proxy_entry->ha, dev->addr_len);
+ arp_unlock();
+
+ rt = ip_rt_route(tip, 0);
+ if (rt && rt->rt_dev != dev)
+ arp_send(ARPOP_REPLY,ETH_P_ARP,sip,dev,tip,sha,ha,sha);
+ ip_rt_put(rt);
+
}
- cli();
+ else
+ arp_unlock();
}
- arp_bh_mask &= ~ARP_BH_BACKLOG;
+ else
+ arp_send(ARPOP_REPLY,ETH_P_ARP,sip,dev,tip,sha,dev->dev_addr,sha);
+
+/*
+ * Handle gratuitous arp.
+ */
+ arp_fast_lock();
+ arp_update(sip, sha, dev, NULL, 1);
arp_unlock();
+ kfree_skb(skb, FREE_READ);
+ return 0;
}
- restore_flags(flags);
+
+ arp_fast_lock();
+ arp_update(sip, sha, dev, NULL, ip_chk_addr(tip) != IS_MYADDR);
+ arp_unlock();
+ kfree_skb(skb, FREE_READ);
+ return 0;
}
+
+
/*
- * Test if a hardware address is all zero
+ * User level interface (ioctl, /proc)
*/
-static inline int empty(unsigned char * addr, int len)
-{
- while (len > 0) {
- if (*addr)
- return 0;
- len--;
- addr++;
- }
- return 1;
-}
-
/*
* Set (create) an ARP cache entry.
*/
static int arp_req_set(struct arpreq *r, struct device * dev)
{
- struct arp_table *entry;
+ struct arp_table *entry, **entryp;
struct sockaddr_in *si;
- struct rtable *rt;
- struct device *dev1;
unsigned char *ha;
u32 ip;
+ u32 mask = DEF_ARP_NETMASK;
+ unsigned long flags;
+
+ /*
+ * Extract netmask (if supplied).
+ */
+
+ if (r->arp_flags&ATF_NETMASK)
+ {
+ si = (struct sockaddr_in *) &r->arp_netmask;
+ mask = si->sin_addr.s_addr;
+ }
/*
* Extract destination.
@@ -1885,112+1968,89 @@ static int arp_req_set(struct arpreq *r, struct device * dev) si = (struct sockaddr_in *) &r->arp_pa;
ip = si->sin_addr.s_addr;
- /*
- * Is it reachable ?
- */
- if (ip_chk_addr(ip) == IS_MYADDR)
- dev1 = dev_get("lo");
- else {
- rt = ip_rt_route(ip, 0);
- if (!rt)
- return -ENETUNREACH;
- dev1 = rt->rt_dev;
- ip_rt_put(rt);
+ if (r->arp_flags&ATF_PUBL)
+ {
+ if (!mask && ip)
+ return -EINVAL;
+ if (!dev)
+ dev = dev_getbytype(r->arp_ha.sa_family);
}
-
- /* good guess about the device if it isn't a ATF_PUBL entry */
- if (!dev) {
- if (dev1->flags&(IFF_LOOPBACK|IFF_NOARP))
- return -ENODEV;
- dev = dev1;
+ else
+ {
+ if (ip_chk_addr(ip))
+ return -EINVAL;
+ if (!dev)
+ {
+ struct rtable * rt;
+ rt = ip_rt_route(ip, 0);
+ if (!rt)
+ return -ENETUNREACH;
+ dev = rt->rt_dev;
+ ip_rt_put(rt);
+ }
}
+ if (!dev || (dev->flags&(IFF_LOOPBACK|IFF_NOARP)))
+ return -ENODEV;
- /* this needs to be checked only for dev=dev1 but it doesn't hurt */
if (r->arp_ha.sa_family != dev->type)
return -EINVAL;
- if (((r->arp_flags & ATF_PUBL) && dev == dev1) ||
- (!(r->arp_flags & ATF_PUBL) && dev != dev1))
- return -EINVAL;
-
+ arp_fast_lock();
#if RT_CACHE_DEBUG >= 1
- if (arp_lock)
+ if (ARP_LOCKED())
printk("arp_req_set: bug\n");
#endif
- arp_fast_lock();
-
- /*
- * Is there an existing entry for this address?
- */
- /*
- * Find the entry
- */
-
- entry = arp_lookup(ip, r->arp_flags & ~ATF_NETMASK, dev);
- if (entry == NULL)
- entry = arpd_lookup(ip, r->arp_flags & ~ATF_NETMASK, dev, __LINE__);
+ if (!(r->arp_flags & ATF_PUBL))
+ entryp = &arp_tables[HASH(ip)];
+ else
+ entryp = &arp_proxy_list;
- if (entry)
+ while ((entry = *entryp) != NULL)
{
- arp_destroy(entry);
- entry = NULL;
+ if (entry->ip == ip && entry->mask == mask && entry->dev == dev)
+ break;
+ if ((entry->mask & mask) != mask)
+ {
+ entry = NULL;
+ break;
+ }
+ entryp = &entry->next;
}
/*
- * Do we need to create a new entry
+ * Do we need to create a new entry?
*/
if (entry == NULL)
{
- entry = arp_add_entry();
+ entry = arp_alloc_entry();
if (entry == NULL)
{
arp_unlock();
return -ENOMEM;
}
entry->ip = ip;
- entry->hh = NULL;
- init_timer(&entry->timer);
- entry->timer.function = arp_expire_request;
- entry->timer.data = (unsigned long)entry;
+ entry->dev = dev;
+ entry->mask = mask;
+ entry->flags = r->arp_flags;
- if (r->arp_flags & ATF_PUBL)
- {
- cli();
- entry->next = arp_proxy_list;
- arp_proxy_list = entry;
- sti();
- }
- else
- {
- unsigned long hash = HASH(ip);
- cli();
- entry->next = arp_tables[hash];
- arp_tables[hash] = entry;
- sti();
- }
- skb_queue_head_init(&entry->skb);
+ entry->next = (*entryp)->next;
+ *entryp = entry;
}
- /*
- * We now have a pointer to an ARP entry. Update it!
- */
+
ha = r->arp_ha.sa_data;
- if ((r->arp_flags & ATF_COM) && empty(ha, dev->addr_len))
+ if (empty(ha, dev->addr_len))
ha = dev->dev_addr;
+
+ save_flags(flags);
+ cli();
memcpy(entry->ha, ha, dev->addr_len);
entry->last_updated = entry->last_used = jiffies;
- arpd_update(entry, __LINE__);
- entry->flags = r->arp_flags | ATF_COM;
- if ((entry->flags & ATF_PUBL) && (entry->flags & ATF_NETMASK))
- {
- si = (struct sockaddr_in *) &r->arp_netmask;
- entry->mask = si->sin_addr.s_addr;
- }
- else
- entry->mask = DEF_ARP_NETMASK;
- entry->dev = dev;
+ entry->flags |= ATF_COM;
+ restore_flags(flags);
+ arpd_update(entry);
arp_update_hhs(entry);
arp_unlock();
return 0;
@@ -2006,77+2066,88 @@ static int arp_req_get(struct arpreq *r, struct device *dev) {
struct arp_table *entry;
struct sockaddr_in *si;
+ u32 mask = DEF_ARP_NETMASK;
+
+ if (r->arp_flags&ATF_NETMASK)
+ {
+ si = (struct sockaddr_in *) &r->arp_netmask;
+ mask = si->sin_addr.s_addr;
+ }
si = (struct sockaddr_in *) &r->arp_pa;
+ arp_fast_lock();
#if RT_CACHE_DEBUG >= 1
- if (arp_lock)
- printk("arp_req_set: bug\n");
+ if (ARP_LOCKED())
+ printk("arp_req_set: impossible\n");
#endif
- arp_fast_lock();
- entry = arp_lookup(si->sin_addr.s_addr, r->arp_flags|ATF_NETMASK, dev);
- if (entry == NULL)
- entry = arpd_lookup(si->sin_addr.s_addr,
- r->arp_flags|ATF_NETMASK, dev, __LINE__);
+ if (!(r->arp_flags & ATF_PUBL))
+ entry = arp_tables[HASH(si->sin_addr.s_addr)];
+ else
+ entry = arp_proxy_list;
- if (entry == NULL)
+ for ( ; entry ;entry = entry->next)
{
- arp_unlock();
- return -ENXIO;
+ if (entry->ip == si->sin_addr.s_addr
+ && (!dev || entry->dev == dev)
+ && (!(r->arp_flags&ATF_NETMASK) || entry->mask == mask))
+ {
+ memcpy(r->arp_ha.sa_data, entry->ha, entry->dev->addr_len);
+ r->arp_ha.sa_family = entry->dev->type;
+ r->arp_flags = entry->flags;
+ strncpy(r->arp_dev, entry->dev->name, sizeof(r->arp_dev));
+ arp_unlock();
+ return 0;
+ }
}
- /*
- * We found it; copy into structure.
- */
-
- memcpy(r->arp_ha.sa_data, &entry->ha, entry->dev->addr_len);
- r->arp_ha.sa_family = entry->dev->type;
- r->arp_flags = entry->flags;
- strncpy(r->arp_dev, entry->dev->name, 16);
arp_unlock();
- return 0;
+ return -ENXIO;
}
static int arp_req_delete(struct arpreq *r, struct device * dev)
{
- struct arp_table *entry;
- struct sockaddr_in *si;
+ struct sockaddr_in *si;
+ struct arp_table *entry, **entryp;
+ int retval = -ENXIO;
+ u32 mask = DEF_ARP_NETMASK;
+
+ if (r->arp_flags&ATF_NETMASK)
+ {
+ si = (struct sockaddr_in *) &r->arp_netmask;
+ mask = si->sin_addr.s_addr;
+ }
si = (struct sockaddr_in *) &r->arp_pa;
+
+ arp_fast_lock();
#if RT_CACHE_DEBUG >= 1
- if (arp_lock)
- printk("arp_req_delete: bug\n");
+ if (ARP_LOCKED())
+ printk("arp_req_delete: impossible\n");
#endif
- arp_fast_lock();
if (!(r->arp_flags & ATF_PUBL))
- {
- for (entry = arp_tables[HASH(si->sin_addr.s_addr)];
- entry != NULL; entry = entry->next)
- if (entry->ip == si->sin_addr.s_addr
- && (!dev || entry->dev == dev))
- {
- arp_destroy(entry);
- arp_unlock();
- return 0;
- }
- }
+ entryp = &arp_tables[HASH(si->sin_addr.s_addr)];
else
+ entryp = &arp_proxy_list;
+
+ while ((entry = *entryp) != NULL)
{
- for (entry = arp_proxy_list;
- entry != NULL; entry = entry->next)
- if (entry->ip == si->sin_addr.s_addr
- && (!dev || entry->dev == dev))
- {
- arp_destroy(entry);
- arp_unlock();
- return 0;
- }
+ if (entry->ip == si->sin_addr.s_addr
+ && (!dev || entry->dev == dev)
+ && (!(r->arp_flags&ATF_NETMASK) || entry->mask == mask))
+ {
+ *entryp = entry->next;
+ arp_free_entry(entry);
+ retval = 0;
+ continue;
+ }
+ entryp = &entry->next;
}
arp_unlock();
- return -ENXIO;
+ return retval;
}
/*
@@ -2119,8+2190,11 @@ int arp_ioctl(unsigned int cmd, void *arg)
if (r.arp_pa.sa_family != AF_INET)
return -EPFNOSUPPORT;
- if (((struct sockaddr_in *)&r.arp_pa)->sin_addr.s_addr == 0)
- return -EINVAL;
+
+ if (!(r.arp_flags & ATF_PUBL))
+ r.arp_flags &= ~ATF_NETMASK;
+ if (!(r.arp_flags & ATF_NETMASK))
+ ((struct sockaddr_in *)&r.arp_netmask)->sin_addr.s_addr=DEF_ARP_NETMASK;
if (r.arp_dev[0])
{
@@ -2132,14+2206,6 @@ int arp_ioctl(unsigned int cmd, void *arg) else if (r.arp_ha.sa_family != dev->type)
return -EINVAL;
}
- else
- {
- if ((r.arp_flags & ATF_PUBL) &&
- ((cmd == SIOCSARP) || (cmd == OLD_SIOCSARP))) {
- if ((dev = dev_getbytype(r.arp_ha.sa_family)) == NULL)
- return -ENODEV;
- }
- }
switch(cmd)
{
@@ -2199,6+2265,99 @@ int arp_ioctl(unsigned int cmd, void *arg) return 0;
}
+/*
+ * Write the contents of the ARP cache to a PROCfs file.
+ */
+
+#define HBUFFERLEN 30
+
+int arp_get_info(char *buffer, char **start, off_t offset, int length, int dummy)
+{
+ int len=0;
+ off_t pos=0;
+ int size;
+ struct arp_table *entry;
+ char hbuffer[HBUFFERLEN];
+ int i,j,k;
+ const char hexbuf[] = "0123456789ABCDEF";
+
+ size = sprintf(buffer,"IP address HW type Flags HW address Mask Device\n");
+
+ pos+=size;
+ len+=size;
+
+ arp_fast_lock();
+
+ for(i=0; i<FULL_ARP_TABLE_SIZE; i++)
+ {
+ for(entry=arp_tables[i]; entry!=NULL; entry=entry->next)
+ {
+/*
+ * Convert hardware address to XX:XX:XX:XX ... form.
+ */
+#ifdef CONFIG_AX25
+#ifdef CONFIG_NETROM
+ if (entry->dev->type == ARPHRD_AX25 || entry->dev->type == ARPHRD_NETROM)
+ strcpy(hbuffer,ax2asc((ax25_address *)entry->ha));
+ else {
+#else
+ if(entry->dev->type==ARPHRD_AX25)
+ strcpy(hbuffer,ax2asc((ax25_address *)entry->ha));
+ else {
+#endif
+#endif
+
+ for(k=0,j=0;k<HBUFFERLEN-3 && j<entry->dev->addr_len;j++)
+ {
+ hbuffer[k++]=hexbuf[ (entry->ha[j]>>4)&15 ];
+ hbuffer[k++]=hexbuf[ entry->ha[j]&15 ];
+ hbuffer[k++]=':';
+ }
+ hbuffer[--k]=0;
+
+#ifdef CONFIG_AX25
+ }
+#endif
+ size = sprintf(buffer+len,
+ "%-17s0x%-10x0x%-10x%s",
+ in_ntoa(entry->ip),
+ (unsigned int)entry->dev->type,
+ entry->flags,
+ hbuffer);
+#if RT_CACHE_DEBUG < 2
+ size += sprintf(buffer+len+size,
+ " %-17s %s\n",
+ entry->mask==DEF_ARP_NETMASK ?
+ "*" : in_ntoa(entry->mask), entry->dev->name);
+#else
+ size += sprintf(buffer+len+size,
+ " %-17s %s\t%d\t%1d\n",
+ entry->mask==DEF_ARP_NETMASK ?
+ "*" : in_ntoa(entry->mask), entry->dev->name,
+ entry->hh ? entry->hh->hh_refcnt : -1,
+ entry->hh ? entry->hh->hh_uptodate : 0);
+#endif
+
+ len += size;
+ pos += size;
+
+ if (pos <= offset)
+ len=0;
+ if (pos >= offset+length)
+ goto done;
+ }
+ }
+done:
+ arp_unlock();
+
+ *start = buffer+len-(pos-offset); /* Start of wanted data */
+ len = pos-offset; /* Start slop */
+ if (len>length)
+ len = length; /* Ending slop */
+ return len;
+}
+
+
/*
* Called once on startup.
@@ -2237,5+2396,8 @@ void arp_init (void) arp_get_info
});
#endif
-}
+#ifdef CONFIG_ARPD
+ netlink_attach(NETLINK_ARPD, arpd_callback);
+#endif
+}
* Additional Authors:
* Alan Cox, <gw4pts@gw4pts.ampr.org>
*/
+
+#include <linux/config.h> /* For CONFIG_IP_CLASSLESS */
#include <asm/segment.h>
#include <asm/system.h>
@@ -76,7+78,9 @@ unsigned long ip_get_mask(unsigned long addr) int ip_chk_addr(unsigned long addr)
{
struct device *dev;
+#ifndef CONFIG_IP_CLASSLESS
unsigned long mask;
+#endif
/*
* Accept both `all ones' and `all zeros' as BROADCAST.
@@ -90,6+94,7 @@ int ip_chk_addr(unsigned long addr) addr == htonl(0x7FFFFFFFL))
return IS_BROADCAST;
+#ifndef CONFIG_IP_CLASSLESS
mask = ip_get_mask(addr);
/*
@@ -98,6+103,10 @@ int ip_chk_addr(unsigned long addr)
if ((addr & mask) == htonl(0x7F000000L))
return IS_MYADDR;
+#else
+ if ((addr & htonl(0x7F000000L)) == htonl(0x7F000000L))
+ return IS_MYADDR;
+#endif
/*
* OK, now check the interface addresses. We could
@@ -139,6+148,7 @@ int ip_chk_addr(unsigned long addr) return IS_BROADCAST;
}
+#ifndef CONFIG_IP_CLASSLESS
/*
* Nope. Check for Network broadcast.
*/
@@ -150,6+160,7 @@ int ip_chk_addr(unsigned long addr) if ((addr & ~mask) == ~mask)
return IS_BROADCAST;
}
+#endif
}
if(IN_MULTICAST(ntohl(addr)))
return IS_MULTICAST;
@@ -181,36+192,34 @@ unsigned long ip_my_addr(void)
/*
* Find an interface that can handle addresses for a certain address.
- *
- * This needs optimising, since it's relatively trivial to collapse
- * the two loops into one.
*/
-
-struct device * ip_dev_check(unsigned long addr)
+
+struct device * ip_dev_bynet(unsigned long addr, unsigned long mask)
{
struct device *dev;
+ struct device *best_dev = NULL;
+ __u32 best_mask = mask;
for (dev = dev_base; dev; dev = dev->next)
{
if (!(dev->flags & IFF_UP))
continue;
- if (!(dev->flags & IFF_POINTOPOINT))
- continue;
- if (addr != dev->pa_dstaddr)
- continue;
- return dev;
- }
- for (dev = dev_base; dev; dev = dev->next)
- {
- if (!(dev->flags & IFF_UP))
- continue;
if (dev->flags & IFF_POINTOPOINT)
+ {
+ if (addr == dev->pa_dstaddr)
+ return dev;
continue;
+ }
if (dev->pa_mask & (addr ^ dev->pa_addr))
continue;
- return dev;
+ if (mask == dev->pa_mask)
+ return dev;
+ if (best_dev && (best_mask & dev->pa_mask) != best_mask)
+ continue;
+ best_dev = dev;
+ best_mask = dev->pa_mask;
}
- return NULL;
+ return best_dev;
}
/*
@@ -215,7+215,7 @@ extern __inline__ int random(void) }
/*
- * Inlined as its only called once.
+ * Inlined as it's only called once.
*/
static void igmp_start_timer(struct ip_mc_list *im,unsigned char max_resp_time)
@@ -216,7+216,7 @@ int ip_forward(struct sk_buff *skb, struct device *dev, int is_frag, #ifndef CONFIG_IP_NO_ICMP_REDIRECT
if (dev == dev2 &&
!((iph->saddr^dev->pa_addr)&dev->pa_mask) &&
- /* The daddr!=raddr test isn't obvious - what its doing
+ /* The daddr!=raddr test isn't obvious - what it's doing
is avoiding sending a frame the receiver will not
believe anyway.. */
iph->daddr != raddr/*ANK*/ && !opt->srr)
@@ -247,7+247,7 @@ int ip_forward(struct sk_buff *skb, struct device *dev, int is_frag, #ifdef CONFIG_IP_MASQUERADE
/*
* If this fragment needs masquerading, make it so...
- * (Dont masquerade de-masqueraded fragments)
+ * (Don't masquerade de-masqueraded fragments)
*/
if (!(is_frag&IPFWD_MASQUERADED) && fw_res==FW_MASQUERADE)
ip_fw_masquerade(&skb, dev2);
@@ -754,7+754,7 @@ void ip_fragment(struct sock *sk, struct sk_buff *skb, struct device *dev, int i ip_options_fragment(skb);
/*
- * Added AC : If we are fragmenting a fragment thats not the
+ * Added AC : If we are fragmenting a fragment that's not the
* last fragment then keep MF on each bit
*/
if (left > 0 || (is_frag & 1))
@@ -539,7+539,7 @@ void ip_fw_masquerade(struct sk_buff **skb_ptr, struct device *dev)
/*
* Check if it's an masqueraded port, look it up,
- * and send it on it's way...
+ * and send it on its way...
*
* Better not have many hosts using the designated portrange
* as 'normal' ports, or you'll be spending many time in
@@ -639,7+639,6 @@ int ip_fw_demasquerade(struct sk_buff **skb_p, struct device *dev) */
if (iph->protocol==IPPROTO_UDP)
{
- unsigned long timeout;
recalc_check((struct udphdr *)portptr,iph->saddr,iph->daddr,size);
ip_masq_set_expire(ms, 0);
ip_masq_set_expire(ms, ip_masq_expire->udp_timeout);
@@ -224,7+224,7 @@ int ip_build_header(struct sk_buff *skb, __u32 saddr, __u32 daddr, * release route, so that...
*/
if (rt)
- ATOMIC_INCR(&rt->rt_refcnt);
+ atomic_inc(&rt->rt_refcnt);
}
else
rt = ip_rt_route(daddr, skb->localroute);
@@ -1059,7+1059,8 @@ void ip_netlink_msg(unsigned long msg, __u32 daddr, __u32 gw, __u32 mask, short nrt->rtmsg_flags=flags;
nrt->rtmsg_metric=metric;
strcpy(nrt->rtmsg_device,name);
- netlink_post(NETLINK_ROUTE, skb);
+ if (netlink_post(NETLINK_ROUTE, skb))
+ kfree_skb(skb, FREE_WRITE);
}
#endif
@@ -1085,6+1086,7 @@ static int ip_rt_event(struct notifier_block *this, unsigned long event, void *p ip_mc_allhost(dev);
#endif
ip_netlink_msg(RTMSG_NEWDEVICE, 0,0,0,0,0,dev->name);
+ ip_rt_update(NETDEV_UP, dev);
}
return NOTIFY_DONE;
}
@@ -181,7+181,7 @@ int ip_setsockopt(struct sock *sk, int level, int optname, char *optval, int opt case IP_TOS: /* This sets both TOS and Precedence */
if (val<0 || val>63) /* Reject setting of unused bits */
return -EINVAL;
- if ((val&3) > 4 && !suser()) /* Only root can set Prec>4 */
+ if ((val&7) > 4 && !suser()) /* Only root can set Prec>4 */
return -EPERM;
sk->ip_tos=val;
switch (val & 0x38) {
@@ -297,7+297,7 @@ int ip_setsockopt(struct sock *sk, int level, int optname, char *optval, int opt {
dev=rt->rt_dev;
route_src = rt->rt_src;
- ATOMIC_DECR(&rt->rt_use);
+ atomic_dec(&rt->rt_use);
ip_rt_put(rt);
}
}
@@ -350,7+350,7 @@ int ip_setsockopt(struct sock *sk, int level, int optname, char *optval, int opt if((rt=ip_rt_route(mreq.imr_multiaddr.s_addr,0))!=NULL)
{
dev=rt->rt_dev;
- ATOMIC_DECR(&rt->rt_use);
+ atomic_dec(&rt->rt_use);
route_src = rt->rt_src;
ip_rt_put(rt);
}
@@ -74,39+74,15 @@ int ipip_rcv(struct sk_buff *skb, struct device *dev, struct options *opt, skb->h.iph=(struct iphdr *)skb->data;
skb->ip_hdr=(struct iphdr *)skb->data;
memset(skb->proto_priv, 0, sizeof(struct options));
- if (skb->ip_hdr->ihl > 5)
- {
- if (ip_options_compile(NULL, skb))
- return 0;
- }
-
-#ifdef CONFIG_FIREWALL
- /*
- * Check the firewall [well spotted Olaf]
- */
-
- if((err=call_in_firewall(PF_INET, skb->dev, skb->ip_hdr))<FW_ACCEPT)
- {
- if(err==FW_REJECT)
- icmp_send(skb,ICMP_DEST_UNREACH, ICMP_PORT_UNREACH, 0 , dev);
- kfree_skb(skb, FREE_READ);
- return 0;
- }
-#endif
/*
* If you want to add LZ compressed IP or things like that here,
* and in drivers/net/tunnel.c are the places to add.
*/
- /* skb=lzw_uncompress(skb); */
-
- /*
- * Feed to IP forward.
- */
-
- if(ip_forward(skb, dev, 0, daddr))
- kfree_skb(skb, FREE_READ);
+ skb->protocol = htons(ETH_P_IP);
+ skb->ip_summed = 0;
+ netif_rx(skb);
MOD_DEC_USE_COUNT;
return(0);
}
@@ -397,7+397,7 @@ int ipmr_mfc_modify(int action, struct mfcctl *mfc) return 0;
}
/*
- * Unsolicited update - thats ok add anyway.
+ * Unsolicited update - that's ok, add anyway.
*/
@@ -420,7+420,7 @@ int ipmr_mfc_modify(int action, struct mfcctl *mfc) /*
* Socket options and virtual interface manipulation. The whole
* virtual interface system is a complete heap, but unfortunately
- * thats how BSD mrouted happens to think. Maybe one day with a proper
+ * that's how BSD mrouted happens to think. Maybe one day with a proper
* MOSPF/PIM router set up we can clean this up.
*/
@@ -487,7+487,7 @@ int ip_mroute_setsockopt(struct sock *sk,int optname,char *optval,int optlen) {
if(dev->flags&IFF_MULTICAST)
{
- /* Most ethernet cards dont know
+ /* Most ethernet cards don't know
how to do this yet.. */
dev->flags|=IFF_ALLMULTI;
dev_mc_upload(dev);
*
* PACKET - implements raw packet sockets.
*
- * Doesn't belong in IP but its currently too hooked into ip
+ * Doesn't belong in IP but it's currently too hooked into ip
* to separate.
*
* Version: @(#)packet.c 1.0.6 05/25/93
@@ -176,7+176,7 @@ static int packet_sendmsg(struct sock *sk, struct msghdr *msg, int len,
/*
* If the write buffer is full, then tough. At this level the user gets to
- * deal with the problem - do your own algorithmic backoffs. Thats far
+ * deal with the problem - do your own algorithmic backoffs. That's far
* more flexible.
*/
@@ -68,11+68,15 @@ get__netinfo(struct proto *pro, char *buffer, int format, char **start, off_t of unsigned short destp, srcp;
int len=0;
off_t pos=0;
- off_t begin=0;
+ off_t begin;
+ char tmpbuf[129];
s_array = pro->sock_array;
- len += sprintf(buffer, "sl local_address rem_address st tx_queue "
- "rx_queue tr tm->when uid inode\n");
+ if (offset < 128)
+ len += sprintf(buffer, "%-127s\n",
+ " sl local_address rem_address st tx_queue "
+ "rx_queue tr tm->when retrnsmt uid timeout inode");
+ pos = 128;
/*
* This was very pretty but didn't work when a socket is destroyed
* at the wrong moment (eg a syn recv socket getting a reset), or
@@ -85,6+89,12 @@ get__netinfo(struct proto *pro, char *buffer, int format, char **start, off_t of sp = s_array[i];
while(sp != NULL)
{
+ pos += 128;
+ if (pos < offset)
+ {
+ sp = sp->next;
+ continue;
+ }
dest = sp->daddr;
src = sp->saddr;
destp = sp->dummy_th.dest;
@@ -109,8+119,8 @@ get__netinfo(struct proto *pro, char *buffer, int format, char **start, off_t of timer_active=timer_active2;
timer_expires=sp->timer.expires;
}
- len += sprintf(buffer+len, "%2d: %08lX:%04X %08lX:%04X"
- " %02X %08X:%08X %02X:%08lX %08X %d %d %ld\n",
+ sprintf(tmpbuf, "%4d: %08lX:%04X %08lX:%04X"
+ " %02X %08X:%08X %02X:%08lX %08X %5d %8d %ld",
i, src, srcp, dest, destp, sp->state,
format==0?sp->write_seq-sp->rcv_ack_seq:sp->wmem_alloc,
format==0?sp->acked_seq-sp->copied_seq:sp->rmem_alloc,
@@ -121,32+131,28 @@ get__netinfo(struct proto *pro, char *buffer, int format, char **start, off_t of SOCK_INODE(sp->socket)->i_ino : 0);
if (timer_active1) add_timer(&sp->retransmit_timer);
if (timer_active2) add_timer(&sp->timer);
+ len += sprintf(buffer+len, "%-127s\n", tmpbuf);
/*
* All sockets with (port mod SOCK_ARRAY_SIZE) = i
* are kept in sock_array[i], so we must follow the
* 'next' link to get them all.
*/
- sp = sp->next;
- pos=begin+len;
- if(pos<offset)
- {
- len=0;
- begin=pos;
- }
- if(pos>offset+length)
+ if(len >= length)
break;
+ sp = sp->next;
}
sti(); /* We only turn interrupts back on for a moment,
but because the interrupt queues anything built
up before this will clear before we jump back
and cli(), so it's not as bad as it looks */
- if(pos>offset+length)
+ if(len>= length)
break;
}
- *start=buffer+(offset-begin);
- len-=(offset-begin);
+ begin = len - (pos - offset);
+ *start = buffer + begin;
+ len -= begin;
if(len>length)
- len=length;
+ len = length;
return len;
}
@@ -198,7+198,7 @@ static void raw_getrawfrag(const void *p, __u32 saddr, char *to, unsigned int of if(!iph->saddr)
iph->saddr=saddr;
iph->check=0;
- iph->tot_len=htons(fraglen); /* This is right as you cant frag
+ iph->tot_len=htons(fraglen); /* This is right as you can't frag
RAW packets */
/*
* Deliberate breach of modularity to keep
@@ -321,42+321,6 @@ static __inline__ struct device * get_gw_dev(__u32 gw) }
/*
- * Used by 'rt_add()' when we can't get the netmask any other way..
- *
- * If the lower byte or two are zero, we guess the mask based on the
- * number of zero 8-bit net numbers, otherwise we use the "default"
- * masks judging by the destination address and our device netmask.
- */
-
-static __u32 unsigned long default_mask(__u32 dst)
-{
- dst = ntohl(dst);
- if (IN_CLASSA(dst))
- return htonl(IN_CLASSA_NET);
- if (IN_CLASSB(dst))
- return htonl(IN_CLASSB_NET);
- return htonl(IN_CLASSC_NET);
-}
-
-
-/*
- * If no mask is specified then generate a default entry.
- */
-
-static __u32 guess_mask(__u32 dst, struct device * dev)
-{
- __u32 mask;
-
- if (!dst)
- return 0;
- mask = default_mask(dst);
- if ((dst ^ dev->pa_addr) & mask)
- return mask;
- return dev->pa_mask;
-}
-
-
-/*
* Check if a mask is acceptable.
*/
@@ -527,50+491,6 @@ static __inline__ void fib_add_1(short flags, __u32 dst, __u32 mask, struct fib_info * fi;
int logmask;
- if (flags & RTF_HOST)
- mask = 0xffffffff;
- /*
- * If mask is not specified, try to guess it.
- */
- else if (!mask)
- {
- if (!((dst ^ dev->pa_addr) & dev->pa_mask))
- {
- mask = dev->pa_mask;
- flags &= ~RTF_GATEWAY;
- if (flags & RTF_DYNAMIC)
- {
- printk("Dynamic route to my own net rejected\n");
- return;
- }
- }
- else
- mask = guess_mask(dst, dev);
- dst &= mask;
- }
-
- /*
- * A gateway must be reachable and not a local address
- */
-
- if (gw == dev->pa_addr)
- flags &= ~RTF_GATEWAY;
-
- if (flags & RTF_GATEWAY)
- {
- /*
- * Don't try to add a gateway we can't reach..
- * Tunnel devices are exempt from this rule.
- */
-
- if ((dev != get_gw_dev(gw)) && dev->type!=ARPHRD_TUNNEL)
- return;
-
- flags |= RTF_GATEWAY;
- }
- else
- gw = 0;
-
/*
* Allocate an entry and fill it in.
*/
@@ -632,7+552,7 @@ static __inline__ void fib_add_1(short flags, __u32 dst, __u32 mask, if (fz->fz_nent >= RTZ_HASHING_LIMIT && !fz->fz_hash_table && logmask<32)
{
struct fib_node ** ht;
-#if RT_CACHE_DEBUG
+#if RT_CACHE_DEBUG >= 2
printk("fib_add_1: hashing for zone %d started\n", logmask);
#endif
ht = kmalloc(RTZ_HASH_DIVISOR*sizeof(struct rtable*), GFP_KERNEL);
@@ -747,7+667,12 @@ static int rt_flush_list(struct fib_node ** fp, struct device *dev) struct fib_node *f;
while ((f = *fp) != NULL) {
- if (f->fib_info->fib_dev != dev) {
+/*
+ * "Magic" device route is allowed to point to loopback,
+ * discard it too.
+ */
+ if (f->fib_info->fib_dev != dev &&
+ (dev != &loopback_dev || f->fib_dst != dev->pa_addr)) {
fp = &f->fib_next;
continue;
}
@@ -797,7+722,7 @@ static __inline__ void fib_flush_1(struct device *dev) *
* We preserve the old format but pad the buffers out. This means that
* we can spin over the other entries as we read them. Remember the
- * gated BGP4 code could need to read 60,000+ routes on occasion (thats
+ * gated BGP4 code could need to read 60,000+ routes on occasion (that's
* about 7Mb of data). To do that ok we will need to also cache the
* last route we got to (reads will generally be following on from
* one another without gaps).
@@ -961,12+886,9 @@ static void rt_free(struct rtable * rt) {
struct hh_cache * hh = rt->rt_hh;
rt->rt_hh = NULL;
- if (hh && !--hh->hh_refcnt)
- {
- restore_flags(flags);
- kfree_s(hh, sizeof(struct hh_cache));
- }
restore_flags(flags);
+ if (hh && atomic_dec_and_test(&hh->hh_refcnt))
+ kfree_s(hh, sizeof(struct hh_cache));
kfree_s(rt, sizeof(struct rt_table));
return;
}
@@ -1000,12+922,9 @@ static __inline__ void rt_kick_free_queue(void) #endif
*rtp = rt->rt_next;
rt->rt_hh = NULL;
- if (hh && !--hh->hh_refcnt)
- {
- sti();
- kfree_s(hh, sizeof(struct hh_cache));
- }
sti();
+ if (hh && atomic_dec_and_test(&hh->hh_refcnt))
+ kfree_s(hh, sizeof(struct hh_cache));
kfree_s(rt, sizeof(struct rt_table));
#if RT_CACHE_DEBUG >= 2
printk("rt_kick_free_queue: %08x is free\n", daddr);
@@ -1017,7+936,8 @@ static __inline__ void rt_kick_free_queue(void) }
}
-void ip_rt_run_bh() {
+void ip_rt_run_bh()
+{
unsigned long flags;
save_flags(flags);
cli();
@@ -1409,7+1329,7 @@ static void rt_cache_add(unsigned hash, struct rtable * rth) else
{
if (rtg->rt_hh)
- ATOMIC_INCR(&rtg->rt_hh->hh_refcnt);
+ atomic_inc(&rtg->rt_hh->hh_refcnt);
rth->rt_hh = rtg->rt_hh;
ip_rt_put(rtg);
}
@@ -1570,7+1490,7 @@ struct rtable * ip_rt_slow_route (__u32 daddr, int local) {
rt_free(rth);
#if RT_CACHE_DEBUG >= 1
- printk("rt_cache: route to %08x was born dead\n", daddr);
+ printk(KERN_DEBUG "rt_cache: route to %08x was born dead\n", daddr);
#endif
}
@@ -1581,7+1501,7 @@ struct rtable * ip_rt_slow_route (__u32 daddr, int local) void ip_rt_put(struct rtable * rt)
{
if (rt)
- ATOMIC_DECR(&rt->rt_refcnt);
+ atomic_dec(&rt->rt_refcnt);
}
struct rtable * ip_rt_route(__u32 daddr, int local)
@@ -1595,8+1515,8 @@ struct rtable * ip_rt_route(__u32 daddr, int local) if (rth->rt_dst == daddr)
{
rth->rt_lastuse = jiffies;
- ATOMIC_INCR(&rth->rt_use);
- ATOMIC_INCR(&rth->rt_refcnt);
+ atomic_inc(&rth->rt_use);
+ atomic_inc(&rth->rt_refcnt);
ip_rt_unlock();
return rth;
}
@@ -1671,42+1591,49 @@ int ip_rt_new(struct rtentry *r) }
}
- /*
- * Ignore faulty masks
- */
-
- if (bad_mask(mask, daddr))
- mask=0;
-
- /*
- * Set the mask to nothing for host routes.
- */
-
- if (flags & RTF_HOST)
+ if (flags & RTF_HOST)
mask = 0xffffffff;
else if (mask && r->rt_genmask.sa_family != AF_INET)
return -EAFNOSUPPORT;
- /*
- * You can only gateway IP via IP..
- */
-
if (flags & RTF_GATEWAY)
{
if (r->rt_gateway.sa_family != AF_INET)
return -EAFNOSUPPORT;
+
+ /*
+ * Don't try to add a gateway we can't reach..
+ * Tunnel devices are exempt from this rule.
+ */
+
if (!dev)
dev = get_gw_dev(gw);
+ else if (dev != get_gw_dev(gw) && dev->type != ARPHRD_TUNNEL)
+ return -EINVAL;
+ if (!dev)
+ return -ENETUNREACH;
}
- else if (!dev)
- dev = ip_dev_check(daddr);
+ else
+ {
+ gw = 0;
+ if (!dev)
+ dev = ip_dev_bynet(daddr, mask);
+ if (!dev)
+ return -ENETUNREACH;
+ if (!mask)
+ {
+ if (((daddr ^ dev->pa_addr) & dev->pa_mask) == 0)
+ mask = dev->pa_mask;
+ }
+ }
- /*
- * Unknown device.
- */
-
- if (dev == NULL)
- return -ENETUNREACH;
+#ifndef CONFIG_IP_CLASSLESS
+ if (!mask)
+ mask = ip_get_mask(daddr);
+#endif
+
+ if (bad_mask(mask, daddr))
+ return -EINVAL;
/*
* Add the route
@@ -1783,3+1710,10 @@ void ip_rt_advice(struct rtable **rp, int advice) return;
}
+void ip_rt_update(int event, struct device *dev)
+{
+ if (event == NETDEV_UP)
+ rt_add(RTF_HOST|RTF_UP, dev->pa_addr, ~0, 0, dev, 0, 0, 0, 0);
+ else if (event == NETDEV_DOWN)
+ rt_del(dev->pa_addr, ~0, dev, 0, RTF_HOST|RTF_UP, 0);
+}
* ack if stat is TCP_CLOSED.
* Alan Cox : Look up device on a retransmit - routes may
* change. Doesn't yet cope with MSS shrink right
- * but its a start!
+ * but it's a start!
* Marc Tamsky : Closing in closing fixes.
* Mike Shaver : RFC1122 verifications.
* Alan Cox : rcv_saddr errors.
@@ -1962,7+1962,7 @@ static int tcp_connect(struct sock *sk, struct sockaddr_in *usin, int addr_len) /*
* SKIP devices set their MTU to 65535. This is so they can take packets
* unfragmented to security process then fragment. They could lie to the
- * TCP layer about a suitable MTU, but its easier to let skip sort it out
+ * TCP layer about a suitable MTU, but it's easier to let skip sort it out
* simply because the final package we want unfragmented is going to be
*
* [IPHDR][IPSP][Security data][Modified TCP data][Security data]
#include <net/tcp.h>
/*
- * Policy code extracted so its now separate
+ * Policy code extracted so it's now separate
*/
/*
@@ -344,7+344,7 @@ static void tcp_conn_request(struct sock *sk, struct sk_buff *skb, * flurry of syns from eating up all our memory.
*
* BSD does some funnies here and allows 3/2 times the
- * set backlog as a fudge factor. Thats just too gross.
+ * set backlog as a fudge factor. That's just too gross.
*/
if (sk->ack_backlog >= sk->max_ack_backlog)
@@ -502,7+502,7 @@ static void tcp_conn_request(struct sock *sk, struct sk_buff *skb, /*
* SKIP devices set their MTU to 65535. This is so they can take packets
* unfragmented to security process then fragment. They could lie to the
- * TCP layer about a suitable MTU, but its easier to let skip sort it out
+ * TCP layer about a suitable MTU, but it's easier to let skip sort it out
* simply because the final package we want unfragmented is going to be
*
* [IPHDR][IPSP][Security data][Modified TCP data][Security data]
@@ -607,7+607,7 @@ static int tcp_ack(struct sock *sk, struct tcphdr *th, u32 ack, int len) */
if(sk->zapped)
- return(1); /* Dead, cant ack any more so why bother */
+ return(1); /* Dead, can't ack any more so why bother */
/*
* We have dropped back to keepalive timeouts. Thus we have
@@ -1736,7+1736,7 @@ int tcp_rcv(struct sk_buff *skb, struct device *dev, struct options *opt,
/*
* Retransmitted SYN for our socket. This is uninteresting. If sk->state==TCP_LISTEN
- * then its a new connection
+ * then it's a new connection
*/
if (sk->state == TCP_SYN_RECV && th->syn && skb->seq+1 == sk->acked_seq)
@@ -1759,7+1759,7 @@ int tcp_rcv(struct sk_buff *skb, struct device *dev, struct options *opt, /* We got an ack, but it's not a good ack */
if(!tcp_ack(sk,th,skb->ack_seq,len))
{
- /* Reset the ack - its an ack from a
+ /* Reset the ack - it's an ack from a
different connection [ th->rst is checked in tcp_send_reset()] */
tcp_statistics.TcpAttemptFails++;
tcp_send_reset(daddr, saddr, th,
#include <linux/interrupt.h>
/*
+ * RFC 1122 says:
+ *
+ * "the suggested [SWS] avoidance algorithm for the receiver is to keep
+ * RECV.NEXT + RCV.WIN fixed until:
+ * RCV.BUFF - RCV.USER - RCV.WINDOW >= min(1/2 RCV.BUFF, MSS)"
+ *
+ * Experiments against BSD and Solaris machines show that following
+ * these rules results in the BSD and Solaris machines making very
+ * bad guesses about how much data they can have in flight.
+ *
+ * Instead we follow the BSD lead and offer a window that gives
+ * the size of the current free space, truncated to a multiple
+ * of 1024 bytes. If the window is smaller than
+ * min(sk->mss, MAX_WINDOW/2)
+ * then we advertise the window as having size 0, unless this
+ * would shrink the window we offered last time.
+ * This results in as much as double the throughput as the original
+ * implementation.
+ *
+ * We do BSD style SWS avoidance -- note that RFC1122 only says we
+ * must do silly window avoidance, it does not require that we use
+ * the suggested algorithm.
+ *
+ * The "rcvbuf" and "rmem_alloc" values are shifted by 1, because
+ * they also contain buffer handling overhead etc, so the window
+ * we actually use is essentially based on only half those values.
+ */
+int tcp_new_window(struct sock * sk)
+{
+ unsigned long window;
+ unsigned long minwin, maxwin;
+
+ /* Get minimum and maximum window values.. */
+ minwin = sk->mss;
+ if (!minwin)
+ minwin = sk->mtu;
+ maxwin = sk->window_clamp;
+ if (!maxwin)
+ maxwin = MAX_WINDOW;
+ if (minwin > maxwin/2)
+ minwin = maxwin/2;
+
+ /* Get current rcvbuf size.. */
+ window = sk->rcvbuf/2;
+ if (window < minwin) {
+ sk->rcvbuf = minwin*2;
+ window = minwin;
+ }
+
+ /* Check rcvbuf against used and minimum window */
+ window -= sk->rmem_alloc/2;
+ if ((long)(window - minwin) < 0) /* SWS avoidance */
+ window = 0;
+
+ if (window > 1023)
+ window &= ~1023;
+ if (window > maxwin)
+ window = maxwin;
+ return window;
+}
+
+/*
* Get rid of any delayed acks, we sent one already..
*/
static __inline__ void clear_delayed_acks(struct sock * sk)
* Revision 0.34: Module support. <Jim Freeman>
* Revision 0.35: Checksum support. <Neil Turton>, hooked in by <Alan Cox>
*
+ * Protect the module by a MOD_INC_USE_COUNT/MOD_DEC_USE_COUNT
+ * pair. Also, now usage count is managed this way
+ * -Count one if the auto_interface mode is on
+ * -Count one per configured interface
+ *
+ * Jacques Gelinas (jacques@solucorp.qc.ca)
+ *
+ *
* Portions Copyright (c) 1995 Caldera, Inc. <greg@caldera.com>
* Neither Greg Page nor Caldera, Inc. admit liability nor provide
* warranty for any of this software. This material is provided
@@ -105,7+113,14 @@ static ipx_interface *ipx_internal_net = NULL; static int
ipxcfg_set_auto_create(char val)
{
- ipxcfg_auto_create_interfaces = val;
+ if (ipxcfg_auto_create_interfaces != val){
+ if (val){
+ MOD_INC_USE_COUNT;
+ }else{
+ MOD_DEC_USE_COUNT;
+ }
+ ipxcfg_auto_create_interfaces = val;
+ }
return 0;
}
@@ -336,6+351,7 @@ ipxitf_down(ipx_interface *intrfc) /* sockets still dangling
* - must be closed from user space
*/
+ MOD_DEC_USE_COUNT;
return;
}
@@ -803,6+819,7 @@ ipxitf_insert(ipx_interface *intrfc)
if (ipxcfg_auto_select_primary && (ipx_primary_net == NULL))
ipx_primary_net = intrfc;
+ MOD_INC_USE_COUNT;
return;
}
@@ -1015,7+1032,7 @@ ipxitf_auto_create(struct device *dev, unsigned short dlink_type) }
static int
-ipxitf_ioctl(unsigned int cmd, void *arg)
+ipxitf_ioctl_real(unsigned int cmd, void *arg)
{
int err;
switch(cmd)
@@ -1080,6+1097,15 @@ ipxitf_ioctl(unsigned int cmd, void *arg) }
}
+static int
+ipxitf_ioctl(unsigned int cmd, void *arg)
+{
+ int ret;
+ MOD_INC_USE_COUNT;
+ ret = ipxitf_ioctl_real (cmd,arg);
+ MOD_DEC_USE_COUNT;
+ return ret;
+}
/*******************************************************************************************************************\
* *
* Routing tables for the IPX socket layer *
@@ -1312,7+1338,7 @@ static int ipxrtr_route_packet(ipx_socket *sk, struct sockaddr_ipx *usipx, struc * Apply checksum. Not allowed on 802.3 links.
*/
- if(sk->no_check || intrfc->if_dlink_type!=IPX_FRAME_8023)
+ if(sk->no_check || intrfc->if_dlink_type==IPX_FRAME_8023)
ipx->ipx_checksum=0xFFFF;
else
ipx->ipx_checksum=ipx_set_checksum(ipx, len+sizeof(ipx_packet));
@@ -235,7+235,7 @@ static void nr_destroy_timer(unsigned long data) * Once it is removed from the queue no interrupt or bottom half will
* touch it and we are (fairly 8-) ) safe.
*/
-void nr_destroy_socket(struct sock *sk) /* Not static as its used by the timer */
+void nr_destroy_socket(struct sock *sk) /* Not static as it's used by the timer */
{
struct sk_buff *skb;
unsigned long flags;
@@ -954,7+954,7 @@ int nr_rx_frame(struct sk_buff *skb, struct device *dev) unsigned short frametype, window, timeout;
- skb->sk = NULL; /* Initially we don't know who its for */
+ skb->sk = NULL; /* Initially we don't know who it's for */
/*
* skb->data points to the netrom frame start
@@ -980,7+980,7 @@ int nr_rx_frame(struct sk_buff *skb, struct device *dev) #endif
/*
- * Find an existing socket connection, based on circuit ID, if its
+ * Find an existing socket connection, based on circuit ID, if it's
* a Connect Request base it on their circuit ID.
*/
if (((frametype & 0x0F) != NR_CONNREQ && (sk = nr_find_socket(circuit_index, circuit_id)) != NULL) ||
@@ -395,7+395,7 @@ static int sock_write(struct inode *inode, struct file *file, const char *ubuf,
/*
* With an ioctl arg may well be a user mode pointer, but we don't know what to do
- * with it - thats up to the protocol still.
+ * with it - that's up to the protocol still.
*/
int sock_ioctl(struct inode *inode, struct file *file, unsigned int cmd,
* Marty Leisner : Fixes to fd passing
* Nick Nevin : recvmsg bugfix.
* Alan Cox : Started proper garbage collector
+ * Heiko EiBfeldt : Missing verify_area check
*
* Known differences from reference BSD that was tested:
*
@@ -352,7+353,7 @@ static int unix_release(struct socket *sock, struct socket *peer) if(skpair!=NULL)
skpair->protinfo.af_unix.locks--; /* It may now die */
sk->protinfo.af_unix.other=NULL; /* No pair */
- unix_destroy_socket(sk); /* Try and flush out this socket. Throw our buffers at least */
+ unix_destroy_socket(sk); /* Try to flush out this socket. Throw out buffers at least */
/*
* FIXME: BSD difference: In BSD all sockets connected to use get ECONNRESET and we die on the spot. In
@@ -1222,6+1223,8 @@ static int unix_ioctl(struct socket *sock, unsigned int cmd, unsigned long arg) if((skb=skb_peek(&sk->receive_queue))!=NULL)
amount=skb->len;
err=verify_area(VERIFY_WRITE,(void *)arg,sizeof(unsigned long));
+ if(err)
+ return err;
put_fs_long(amount,(unsigned long *)arg);
return 0;
}
@@ -1110,7+1110,7 @@ $DIALOG --backtitle "$backtitle" \ #
# Check kernel version of previous menuconfig build.
# If it's different then we should tell the sound driver
-# to rebuild it's Config.in file.
+# to rebuild its Config.in file.
#
rebuildsound=TRUE
if [ -e .menuconfig ]
@@ -449,7+449,7 @@ void fix_conditionals(struct kconfig * scfg) {
/*
* Now search the condition list for a known configuration variable
- * that has conditions of it's own.
+ * that has conditions of its own.
*/
if(cnd->op != op_kvariable) continue;
if(cnd->variable.cfg->cond == NULL) continue;
@@ -662,7+662,7 @@ int main(int argc, char * argv[]) * Input file is now parsed. Next we need to go through and attach
* the correct conditions to each of the actual menu items and kill
* the if/else/endif tokens from the list. We also flag the menu items
- * that have other things that depend upon it's setting.
+ * that have other things that depend upon its setting.
*/
fix_conditionals(config);