From db3c909e1cc4fa34aa99c2d62ce3969f7377f894 Mon Sep 17 00:00:00 2001 From: Linus Torvalds Date: Fri, 23 Nov 2007 15:10:57 -0500 Subject: [PATCH] Import 1.3.99 --- CREDITS | 24 +- Documentation/Configure.help | 4 +- Documentation/SMP.txt | 2 +- Documentation/devices.tex | 13 +- Documentation/devices.txt | 10 +- Documentation/filesystems/affs.txt | 106 + Documentation/ioctl-number.txt | 98 + Documentation/isdn/INTERFACE | 10 +- Documentation/isdn/README | 10 +- Documentation/magic-number.txt | 61 + Documentation/networking/arcnet-hardware.txt | 6 +- Documentation/networking/framerelay.txt | 2 +- Documentation/nfsroot.txt | 8 +- Documentation/oops-tracing.txt | 4 +- Documentation/ramdisk.txt | 4 +- Documentation/rtc.txt | 5 +- MAGIC | 105 - MAINTAINERS | 26 +- Makefile | 2 +- README | 12 +- arch/alpha/config.in | 4 +- arch/alpha/kernel/bios32.c | 6 +- arch/i386/boot/Makefile | 1 + arch/i386/config.in | 9 +- arch/i386/kernel/irq.c | 2 +- arch/i386/kernel/setup.c | 5 +- arch/i386/kernel/signal.c | 10 - arch/i386/kernel/smp.c | 8 +- arch/i386/kernel/time.c | 2 +- arch/i386/kernel/traps.c | 9 +- arch/i386/math-emu/errors.c | 36 +- arch/i386/math-emu/fpu_emu.h | 1 + arch/i386/math-emu/fpu_entry.c | 51 +- arch/i386/math-emu/reg_ld_str.c | 44 +- arch/i386/math-emu/version.h | 6 +- arch/m68k/amiga/Makefile | 2 +- arch/m68k/amiga/amipart.c | 119 - arch/m68k/amiga/config.c | 2 - arch/m68k/atari/Makefile | 2 +- arch/m68k/atari/atafb.c | 2 +- arch/m68k/atari/atapart.c | 158 -- arch/m68k/atari/config.c | 2 - arch/m68k/config.in | 11 + arch/m68k/console/fbcon.c | 2 +- arch/m68k/defconfig | 2 +- arch/m68k/fpsp040/skeleton.S | 2 +- arch/m68k/ifpsp060/ilsp.doc | 2 +- arch/m68k/kernel/console.c | 2 +- arch/m68k/kernel/head.S | 63 +- arch/m68k/kernel/setup.c | 20 - arch/m68k/kernel/traps.c | 14 +- arch/m68k/mm/fault.c | 2 +- arch/m68k/mm/memory.c | 43 +- arch/mips/config.in | 4 +- arch/mips/kernel/head.S | 4 +- arch/mips/kernel/time.c | 2 +- arch/mips/mm/init.c | 2 +- arch/ppc/config.in | 4 +- arch/ppc/kernel/head.S | 4 +- arch/sparc/boot/README | 2 +- arch/sparc/kernel/head.S | 4 +- arch/sparc/kernel/irq.c | 2 +- arch/sparc/kernel/sparc-stub.c | 2 +- arch/sparc/kernel/sun4m_irq.c | 4 +- arch/sparc/kernel/switch.S | 2 +- arch/sparc/kernel/wof.S | 2 +- arch/sparc/mm/srmmu.c | 2 +- arch/sparc/prom/tree.c | 2 +- drivers/block/Config.in | 2 +- drivers/block/Makefile | 4 + drivers/block/README.ide | 2 +- drivers/block/amiflop.c | 13 +- drivers/block/ataflop.c | 8 + drivers/block/ll_rw_blk.c | 40 +- drivers/block/loop.c | 18 +- drivers/block/xd.c | 30 +- drivers/cdrom/aztcd.c | 2 +- drivers/char/ChangeLog | 2 +- drivers/char/console.c | 2 +- drivers/char/fbmem.c | 21 +- drivers/char/ftape/ftape-read.c | 4 +- drivers/char/ftape/kernel-interface.c | 2 +- drivers/char/istallion.c | 4 +- drivers/char/lp.c | 22 +- drivers/char/lp_m68k.c | 20 +- drivers/char/pcxx.c | 4 +- drivers/char/psaux.c | 2 +- drivers/char/pty.c | 2 + drivers/char/random.c | 6 +- drivers/char/rtc.c | 83 +- drivers/char/stallion.c | 6 +- drivers/char/vc_screen.c | 4 +- drivers/char/vga.c | 10 +- drivers/isdn/isdn_common.c | 2 +- drivers/isdn/isdn_net.c | 8 +- drivers/isdn/isdn_ppp.c | 4 +- drivers/net/3c501.c | 2 +- drivers/net/8390.c | 323 ++- drivers/net/8390.h | 11 +- drivers/net/Makefile | 8 + drivers/net/README.eql | 2 +- drivers/net/README.tunnel | 10 +- drivers/net/Space.c | 4 + drivers/net/arcnet.c | 4 +- drivers/net/dgrs.c | 12 +- drivers/net/dgrs_driver.c | 12 +- drivers/net/dlci.c | 4 - drivers/net/dummy.c | 2 +- drivers/net/eexpress.c | 2 +- drivers/net/eql.c | 2 +- drivers/net/eth16i.c | 2 +- drivers/net/hp100.h | 2 +- drivers/net/hydra.c | 655 +++++ drivers/net/hydra.h | 177 ++ drivers/net/ibmtr.c | 2 +- drivers/net/lance32.c | 53 +- drivers/net/loopback.c | 4 +- drivers/net/ne.c | 23 +- drivers/net/new_tunnel.c | 23 +- drivers/net/ppp.c | 2 +- drivers/net/sdla.c | 4 +- drivers/net/seeq8005.c | 2 +- drivers/net/seeq8005.h | 2 +- drivers/net/sk_g16.c | 4 +- drivers/net/slhc.c | 2 +- drivers/net/slip.c | 2 +- drivers/net/smc-ultra.c | 110 +- drivers/sbus/char/sunkeymap.map | 2 +- drivers/sbus/char/sunserial.c | 2 +- drivers/scsi/53c7,8xx.c | 2 +- drivers/scsi/ChangeLog | 6 +- drivers/scsi/Config.in | 2 +- drivers/scsi/README.st | 2 +- drivers/scsi/aha1542.c | 2 +- drivers/scsi/aic7xxx.c | 6 +- drivers/scsi/eata_dma.c | 721 ++--- drivers/scsi/eata_dma.h | 14 +- drivers/scsi/eata_generic.h | 71 +- drivers/scsi/eata_pio.c | 34 +- drivers/scsi/eata_pio.h | 2 +- drivers/scsi/fdomain.c | 2 +- drivers/scsi/hosts.c | 2 +- drivers/scsi/pas16.c | 2 +- drivers/scsi/scsi_debug.c | 2 +- drivers/scsi/sd.c | 92 +- drivers/scsi/seagate.c | 2 +- drivers/scsi/sr.c | 6 +- drivers/scsi/wd33c93.h | 2 +- drivers/sound/CHANGELOG | 2 +- drivers/sound/Readme.cards | 4 +- drivers/sound/ad1848.c | 4 +- drivers/sound/gus_wave.c | 4 +- drivers/sound/mpu401.c | 2 +- drivers/sound/sound_switch.c | 14 +- fs/Config.in | 5 +- fs/affs/Makefile | 4 +- fs/affs/amigaffs.c | 281 +- fs/affs/amigaffs.h | 206 -- fs/affs/bitmap.c | 332 +++ fs/affs/dir.c | 224 +- fs/affs/file.c | 564 +++- fs/affs/inode.c | 1137 +++++--- fs/affs/namei.c | 753 ++++- fs/affs/symlink.c | 208 +- fs/block_dev.c | 4 +- fs/buffer.c | 11 +- fs/ext/file.c | 4 +- fs/fat/dir.c | 7 + fs/fat/msbuffer.h | 4 +- fs/isofs/inode.c | 39 +- fs/isofs/rock.c | 2 +- fs/locks.c | 2 +- fs/nfs/nfsroot.c | 4 +- fs/super.c | 6 +- fs/sysv/file.c | 4 +- fs/ufs/ufs_super.c | 3 + fs/umsdos/namei.c | 2 +- fs/vfat/Makefile | 4 +- fs/vfat/namei.c | 16 +- fs/xiafs/file.c | 4 +- include/asm-i386/locks.h | 6 +- include/asm-m68k/atomic.h | 32 +- include/asm-m68k/bitops.h | 48 + include/asm-m68k/checksum.h | 48 - include/asm-m68k/elf.h | 5 - include/asm-m68k/pgtable.h | 9 +- include/asm-m68k/serial.h | 380 +++ include/asm-m68k/system.h | 1 + include/asm-mips/shmparam.h | 2 +- include/asm-sparc/floppy.h | 2 +- include/asm-sparc/head.h | 2 +- include/asm-sparc/kdebug.h | 2 +- include/asm-sparc/smp.h | 2 +- include/asm-sparc/system.h | 2 +- include/linux/a.out.h | 2 +- include/linux/affs_fs.h | 181 +- include/linux/affs_fs_i.h | 13 + include/linux/affs_fs_sb.h | 69 +- include/linux/affs_hardblocks.h | 70 + include/linux/amigaffs.h | 224 ++ include/linux/genhd.h | 2 +- include/linux/hdreg.h | 2 +- include/linux/if_arp.h | 10 +- include/linux/if_frad.h | 2 +- include/linux/in.h | 2 +- include/linux/isdn.h | 2 +- include/linux/isdnif.h | 4 +- include/linux/kernel.h | 9 +- include/linux/math_emu.h | 4 + include/linux/mc146818rtc.h | 18 + include/linux/mroute.h | 2 +- include/linux/msdos_fs.h | 15 + include/linux/netdevice.h | 6 +- include/linux/skbuff.h | 12 +- include/linux/string.h | 1 + include/net/netlink.h | 3 +- include/net/route.h | 125 +- drivers/net/slhc.h => include/net/slhc_vj.h | 0 include/net/sock.h | 2 +- include/net/tcp.h | 48 +- ipc/msg.c | 18 +- kernel/module.c | 18 +- kernel/sched.c | 11 +- mm/filemap.c | 3 +- mm/swapfile.c | 1 + net/Changes | 4 +- net/TUNABLE | 2 +- net/ax25/af_ax25.c | 12 +- net/ax25/ax25_out.c | 2 +- net/ax25/ax25_subr.c | 2 +- net/core/dev.c | 32 +- net/core/net_alias.c | 4 +- net/ethernet/eth.c | 2 +- net/ipv4/Config.in | 2 +- net/ipv4/arp.c | 2568 ++++++++++-------- net/ipv4/devinet.c | 43 +- net/ipv4/igmp.c | 2 +- net/ipv4/ip_forward.c | 4 +- net/ipv4/ip_fragment.c | 2 +- net/ipv4/ip_masq.c | 3 +- net/ipv4/ip_output.c | 6 +- net/ipv4/ip_sockglue.c | 6 +- net/ipv4/ipip.c | 30 +- net/ipv4/ipmr.c | 6 +- net/ipv4/packet.c | 4 +- net/ipv4/proc.c | 40 +- net/ipv4/raw.c | 2 +- net/ipv4/route.c | 180 +- net/ipv4/tcp.c | 4 +- net/ipv4/tcp_input.c | 12 +- net/ipv4/tcp_output.c | 62 + net/ipx/af_ipx.c | 32 +- net/netrom/af_netrom.c | 6 +- net/socket.c | 2 +- net/unix/af_unix.c | 5 +- scripts/Menuconfig | 2 +- scripts/tkcond.c | 2 +- scripts/tkparse.c | 2 +- 258 files changed, 8078 insertions(+), 4257 deletions(-) create mode 100644 Documentation/ioctl-number.txt create mode 100644 Documentation/magic-number.txt delete mode 100644 MAGIC delete mode 100644 arch/m68k/amiga/amipart.c delete mode 100644 arch/m68k/atari/atapart.c create mode 100644 drivers/net/hydra.c create mode 100644 drivers/net/hydra.h delete mode 100644 fs/affs/amigaffs.h create mode 100644 fs/affs/bitmap.c create mode 100644 include/asm-m68k/serial.h create mode 100644 include/linux/affs_hardblocks.h create mode 100644 include/linux/amigaffs.h rename drivers/net/slhc.h => include/net/slhc_vj.h (100%) diff --git a/CREDITS b/CREDITS index eab18ac49b01..73ac9b6fccdf 100644 --- a/CREDITS +++ b/CREDITS @@ -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 diff --git a/Documentation/Configure.help b/Documentation/Configure.help index a984a50baebb..3e049b06a793 100644 --- a/Documentation/Configure.help +++ b/Documentation/Configure.help @@ -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 diff --git a/Documentation/SMP.txt b/Documentation/SMP.txt index 783b3ff4afd5..2295187b98c8 100644 --- a/Documentation/SMP.txt +++ b/Documentation/SMP.txt @@ -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 diff --git a/Documentation/devices.tex b/Documentation/devices.tex index 48e985a82c1f..eb4e2e033539 100644 --- a/Documentation/devices.tex +++ b/Documentation/devices.tex @@ -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} diff --git a/Documentation/devices.txt b/Documentation/devices.txt index a2dad5f937b9..3ebcd42b5db1 100644 --- a/Documentation/devices.txt +++ b/Documentation/devices.txt @@ -2,7 +2,7 @@ Maintained by H. Peter Anvin - 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 diff --git a/Documentation/filesystems/affs.txt b/Documentation/filesystems/affs.txt index 996769f7b851..2e9153d1821f 100644 --- a/Documentation/filesystems/affs.txt +++ b/Documentation/filesystems/affs.txt @@ -1,3 +1,109 @@ +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 diff --git a/Documentation/ioctl-number.txt b/Documentation/ioctl-number.txt new file mode 100644 index 000000000000..5269bbea19cd --- /dev/null +++ b/Documentation/ioctl-number.txt @@ -0,0 +1,98 @@ +Ioctl Numbers +6 May 1996 +Michael Chastain + + +If you are adding new ioctl's to the kernel, you should use the _IO +macros defined in : + + _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 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 diff --git a/Documentation/isdn/INTERFACE b/Documentation/isdn/INTERFACE index 7e679564b92b..26e9e3295999 100644 --- a/Documentation/isdn/INTERFACE +++ b/Documentation/isdn/INTERFACE @@ -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 diff --git a/Documentation/isdn/README b/Documentation/isdn/README index 23418379bb4b..5d5e339ddb21 100644 --- a/Documentation/isdn/README +++ b/Documentation/isdn/README @@ -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 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 " Forces an interface to start dialing even if no packets are to be diff --git a/Documentation/magic-number.txt b/Documentation/magic-number.txt new file mode 100644 index 000000000000..085dfc204e92 --- /dev/null +++ b/Documentation/magic-number.txt @@ -0,0 +1,61 @@ +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 + + 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 diff --git a/Documentation/networking/arcnet-hardware.txt b/Documentation/networking/arcnet-hardware.txt index 891a8aa018fa..79d3837776d6 100644 --- a/Documentation/networking/arcnet-hardware.txt +++ b/Documentation/networking/arcnet-hardware.txt @@ -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 diff --git a/Documentation/networking/framerelay.txt b/Documentation/networking/framerelay.txt index 628d4d9e1823..0a0bc4bde4fb 100644 --- a/Documentation/networking/framerelay.txt +++ b/Documentation/networking/framerelay.txt @@ -1,6 +1,6 @@ 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. diff --git a/Documentation/nfsroot.txt b/Documentation/nfsroot.txt index c37b0ee6aae5..43d79a89bc5d 100644 --- a/Documentation/nfsroot.txt +++ b/Documentation/nfsroot.txt @@ -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// as it's + RARP will mount the directory /tftpboot// 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. diff --git a/Documentation/oops-tracing.txt b/Documentation/oops-tracing.txt index 5d8a42f20d76..ed003a110bbe 100644 --- a/Documentation/oops-tracing.txt +++ b/Documentation/oops-tracing.txt @@ -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 diff --git a/Documentation/ramdisk.txt b/Documentation/ramdisk.txt index 881b671fdf39..5b48c398714b 100644 --- a/Documentation/ramdisk.txt +++ b/Documentation/ramdisk.txt @@ -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 diff --git a/Documentation/rtc.txt b/Documentation/rtc.txt index ba9362faedfb..e290b4177750 100644 --- a/Documentation/rtc.txt +++ b/Documentation/rtc.txt @@ -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 #include #include -#include 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); diff --git a/MAGIC b/MAGIC deleted file mode 100644 index 0eef6fc78e2c..000000000000 --- a/MAGIC +++ /dev/null @@ -1,105 +0,0 @@ -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 - - 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 diff --git a/MAINTAINERS b/MAINTAINERS index 1b18d7655b48..53aedf80bc20 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -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 diff --git a/Makefile b/Makefile index 614339fb9e28..d99a63605089 100644 --- a/Makefile +++ b/Makefile @@ -1,6 +1,6 @@ VERSION = 1 PATCHLEVEL = 3 -SUBLEVEL = 98 +SUBLEVEL = 99 ARCH = i386 diff --git a/README b/README index d95913c5990e..817978321bd8 100644 --- a/README +++ b/README @@ -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 diff --git a/arch/alpha/config.in b/arch/alpha/config.in index 7bc03bf6efd7..a7b9757a1172 100644 --- a/arch/alpha/config.in +++ b/arch/alpha/config.in @@ -82,7 +82,9 @@ fi 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 diff --git a/arch/alpha/kernel/bios32.c b/arch/alpha/kernel/bios32.c index ad28cfed6f88..726d3edbee9f 100644 --- a/arch/alpha/kernel/bios32.c +++ b/arch/alpha/kernel/bios32.c @@ -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, diff --git a/arch/i386/boot/Makefile b/arch/i386/boot/Makefile index 02e8388c5115..aac33aa74c3a 100644 --- a/arch/i386/boot/Makefile +++ b/arch/i386/boot/Makefile @@ -90,6 +90,7 @@ dep: 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 diff --git a/arch/i386/config.in b/arch/i386/config.in index 8d04799902f2..8e1691b7fbdd 100644 --- a/arch/i386/config.in +++ b/arch/i386/config.in @@ -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 \ diff --git a/arch/i386/kernel/irq.c b/arch/i386/kernel/irq.c index 2bdd0a841c37..27ca35e39a78 100644 --- a/arch/i386/kernel/irq.c +++ b/arch/i386/kernel/irq.c @@ -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 diff --git a/arch/i386/kernel/setup.c b/arch/i386/kernel/setup.c index 03d2c77e581e..443c10d44797 100644 --- a/arch/i386/kernel/setup.c +++ b/arch/i386/kernel/setup.c @@ -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__ diff --git a/arch/i386/kernel/signal.c b/arch/i386/kernel/signal.c index 1f6fd8497edc..a98d2107f577 100644 --- a/arch/i386/kernel/signal.c +++ b/arch/i386/kernel/signal.c @@ -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__ diff --git a/arch/i386/kernel/smp.c b/arch/i386/kernel/smp.c index 12055a8ac9f4..8825530c38c1 100644 --- a/arch/i386/kernel/smp.c +++ b/arch/i386/kernel/smp.c @@ -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); diff --git a/arch/i386/kernel/time.c b/arch/i386/kernel/time.c index b80c2c8d029e..1b75c30d49b0 100644 --- a/arch/i386/kernel/time.c +++ b/arch/i386/kernel/time.c @@ -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); */ diff --git a/arch/i386/kernel/traps.c b/arch/i386/kernel/traps.c index 31210b5b3276..fe0e36d930c4 100644 --- a/arch/i386/kernel/traps.c +++ b/arch/i386/kernel/traps.c @@ -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) diff --git a/arch/i386/math-emu/errors.c b/arch/i386/math-emu/errors.c index 4e0335e5555f..37c5be76971c 100644 --- a/arch/i386/math-emu/errors.c +++ b/arch/i386/math-emu/errors.c @@ -3,9 +3,9 @@ | | | 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; } diff --git a/arch/i386/math-emu/fpu_emu.h b/arch/i386/math-emu/fpu_emu.h index 2cf14a61c7cb..dc249e55b316 100644 --- a/arch/i386/math-emu/fpu_emu.h +++ b/arch/i386/math-emu/fpu_emu.h @@ -57,6 +57,7 @@ #ifndef __ASSEMBLY__ +#include /* for struct _fpstate */ #include #include diff --git a/arch/i386/math-emu/fpu_entry.c b/arch/i386/math-emu/fpu_entry.c index b2777a722d19..ebe8b68d1bcf 100644 --- a/arch/i386/math-emu/fpu_entry.c +++ b/arch/i386/math-emu/fpu_entry.c @@ -1,11 +1,11 @@ /*---------------------------------------------------------------------------+ | 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. | @@ -20,7 +20,8 @@ +---------------------------------------------------------------------------*/ /*---------------------------------------------------------------------------+ - | 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 @@ -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; +} diff --git a/arch/i386/math-emu/reg_ld_str.c b/arch/i386/math-emu/reg_ld_str.c index efec9e010e91..2d6c0fbf03e3 100644 --- a/arch/i386/math-emu/reg_ld_str.c +++ b/arch/i386/math-emu/reg_ld_str.c @@ -3,9 +3,9 @@ | | | 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) diff --git a/arch/i386/math-emu/version.h b/arch/i386/math-emu/version.h index e0bb665f8d10..d966ab19350d 100644 --- a/arch/i386/math-emu/version.h +++ b/arch/i386/math-emu/version.h @@ -3,10 +3,10 @@ | | | | | 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" diff --git a/arch/m68k/amiga/Makefile b/arch/m68k/amiga/Makefile index 7f49061dca24..0e80259a5243 100644 --- a/arch/m68k/amiga/Makefile +++ b/arch/m68k/amiga/Makefile @@ -8,7 +8,7 @@ # 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 diff --git a/arch/m68k/amiga/amipart.c b/arch/m68k/amiga/amipart.c deleted file mode 100644 index 6a1625e96e49..000000000000 --- a/arch/m68k/amiga/amipart.c +++ /dev/null @@ -1,119 +0,0 @@ -/* - * 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 -#include -#include - -#include -#include - -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"); -} diff --git a/arch/m68k/amiga/config.c b/arch/m68k/amiga/config.c index 6637407d2803..1564b67a63e3 100644 --- a/arch/m68k/amiga/config.c +++ b/arch/m68k/amiga/config.c @@ -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; diff --git a/arch/m68k/atari/Makefile b/arch/m68k/atari/Makefile index b3643af7277b..c84cb6cde009 100644 --- a/arch/m68k/atari/Makefile +++ b/arch/m68k/atari/Makefile @@ -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 diff --git a/arch/m68k/atari/atafb.c b/arch/m68k/atari/atafb.c index 3320795e0eaa..75ecd1636612 100644 --- a/arch/m68k/atari/atafb.c +++ b/arch/m68k/atari/atafb.c @@ -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); diff --git a/arch/m68k/atari/atapart.c b/arch/m68k/atari/atapart.c deleted file mode 100644 index 72ba09b975d6..000000000000 --- a/arch/m68k/atari/atapart.c +++ /dev/null @@ -1,158 +0,0 @@ -/* - * 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 -#include -#include - -#include - -/* ++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"); -} - diff --git a/arch/m68k/atari/config.c b/arch/m68k/atari/config.c index fc7ad0cd65aa..3dd07ccd5466 100644 --- a/arch/m68k/atari/config.c +++ b/arch/m68k/atari/config.c @@ -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 diff --git a/arch/m68k/config.in b/arch/m68k/config.in index 86e1ef75ada9..ab023d289f7a 100644 --- a/arch/m68k/config.in +++ b/arch/m68k/config.in @@ -143,6 +143,17 @@ fi 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 diff --git a/arch/m68k/console/fbcon.c b/arch/m68k/console/fbcon.c index 77e81b2172dd..fdb4391aa81e 100644 --- a/arch/m68k/console/fbcon.c +++ b/arch/m68k/console/fbcon.c @@ -721,7 +721,7 @@ fail: * * 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. diff --git a/arch/m68k/defconfig b/arch/m68k/defconfig index 8f23f7ea3c9c..3650350eb5b7 100644 --- a/arch/m68k/defconfig +++ b/arch/m68k/defconfig @@ -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 diff --git a/arch/m68k/fpsp040/skeleton.S b/arch/m68k/fpsp040/skeleton.S index 7dbf253bea6a..b5a4a6e290b1 100644 --- a/arch/m68k/fpsp040/skeleton.S +++ b/arch/m68k/fpsp040/skeleton.S @@ -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 diff --git a/arch/m68k/ifpsp060/ilsp.doc b/arch/m68k/ifpsp060/ilsp.doc index 880273eb5b80..560ffdbbc9b5 100644 --- a/arch/m68k/ifpsp060/ilsp.doc +++ b/arch/m68k/ifpsp060/ilsp.doc @@ -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 diff --git a/arch/m68k/kernel/console.c b/arch/m68k/kernel/console.c index d922a14a968e..5075a5ae5feb 100644 --- a/arch/m68k/kernel/console.c +++ b/arch/m68k/kernel/console.c @@ -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) { diff --git a/arch/m68k/kernel/head.S b/arch/m68k/kernel/head.S index 8c90db20918c..b58587a941ba 100644 --- a/arch/m68k/kernel/head.S +++ b/arch/m68k/kernel/head.S @@ -14,6 +14,8 @@ ** 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 @@ -145,6 +147,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 */ @@ -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 */ diff --git a/arch/m68k/kernel/setup.c b/arch/m68k/kernel/setup.c index b15e3e4f254d..7424802ef990 100644 --- a/arch/m68k/kernel/setup.c +++ b/arch/m68k/kernel/setup.c @@ -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) { diff --git a/arch/m68k/kernel/traps.c b/arch/m68k/kernel/traps.c index 97e010dbae8f..4261e6096da1 100644 --- a/arch/m68k/kernel/traps.c +++ b/arch/m68k/kernel/traps.c @@ -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) diff --git a/arch/m68k/mm/fault.c b/arch/m68k/mm/fault.c index 4152bb418291..87e548937a18 100644 --- a/arch/m68k/mm/fault.c +++ b/arch/m68k/mm/fault.c @@ -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; } diff --git a/arch/m68k/mm/memory.c b/arch/m68k/mm/memory.c index 49aa454b9689..e7157b22102d 100644 --- a/arch/m68k/mm/memory.c +++ b/arch/m68k/mm/memory.c @@ -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 diff --git a/arch/mips/config.in b/arch/mips/config.in index d2acd3d42bbc..3c4fb8624885 100644 --- a/arch/mips/config.in +++ b/arch/mips/config.in @@ -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 diff --git a/arch/mips/kernel/head.S b/arch/mips/kernel/head.S index 6a5d51820ef0..a43761a27e38 100644 --- a/arch/mips/kernel/head.S +++ b/arch/mips/kernel/head.S @@ -49,8 +49,8 @@ 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 diff --git a/arch/mips/kernel/time.c b/arch/mips/kernel/time.c index ec2bb53cba1d..2583dfa516a5 100644 --- a/arch/mips/kernel/time.c +++ b/arch/mips/kernel/time.c @@ -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); } diff --git a/arch/mips/mm/init.c b/arch/mips/mm/init.c index 9da156c396f8..52feb57eb0bf 100644 --- a/arch/mips/mm/init.c +++ b/arch/mips/mm/init.c @@ -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); diff --git a/arch/ppc/config.in b/arch/ppc/config.in index d8717f80ef77..813fd20368a9 100644 --- a/arch/ppc/config.in +++ b/arch/ppc/config.in @@ -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 diff --git a/arch/ppc/kernel/head.S b/arch/ppc/kernel/head.S index dadbec4b7fe4..ba82353f22d6 100644 --- a/arch/ppc/kernel/head.S +++ b/arch/ppc/kernel/head.S @@ -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'. * diff --git a/arch/sparc/boot/README b/arch/sparc/boot/README index 48c93ddbe10d..189a72d29263 100644 --- a/arch/sparc/boot/README +++ b/arch/sparc/boot/README @@ -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 diff --git a/arch/sparc/kernel/head.S b/arch/sparc/kernel/head.S index c6cffe4258b7..8f4356f12b57 100644 --- a/arch/sparc/kernel/head.S +++ b/arch/sparc/kernel/head.S @@ -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 diff --git a/arch/sparc/kernel/irq.c b/arch/sparc/kernel/irq.c index edf500152b2d..90da45928ead 100644 --- a/arch/sparc/kernel/irq.c +++ b/arch/sparc/kernel/irq.c @@ -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.... * diff --git a/arch/sparc/kernel/sparc-stub.c b/arch/sparc/kernel/sparc-stub.c index 5e10f57c5ad1..6f9b4c5b5d46 100644 --- a/arch/sparc/kernel/sparc-stub.c +++ b/arch/sparc/kernel/sparc-stub.c @@ -13,7 +13,7 @@ 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 diff --git a/arch/sparc/kernel/sun4m_irq.c b/arch/sparc/kernel/sun4m_irq.c index 1832d72b3fa7..77e2bb4572c9 100644 --- a/arch/sparc/kernel/sun4m_irq.c +++ b/arch/sparc/kernel/sun4m_irq.c @@ -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] = { diff --git a/arch/sparc/kernel/switch.S b/arch/sparc/kernel/switch.S index 1153b5eabdf2..82eb2fb1055c 100644 --- a/arch/sparc/kernel/switch.S +++ b/arch/sparc/kernel/switch.S @@ -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) diff --git a/arch/sparc/kernel/wof.S b/arch/sparc/kernel/wof.S index 0aaf19999fd0..1b9ed110b270 100644 --- a/arch/sparc/kernel/wof.S +++ b/arch/sparc/kernel/wof.S @@ -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, diff --git a/arch/sparc/mm/srmmu.c b/arch/sparc/mm/srmmu.c index 6725145e7461..600dd1d337d6 100644 --- a/arch/sparc/mm/srmmu.c +++ b/arch/sparc/mm/srmmu.c @@ -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(); } diff --git a/arch/sparc/prom/tree.c b/arch/sparc/prom/tree.c index f5a0fb4c5f4d..510142d87cce 100644 --- a/arch/sparc/prom/tree.c +++ b/arch/sparc/prom/tree.c @@ -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 diff --git a/drivers/block/Config.in b/drivers/block/Config.in index 9488f1742d17..ddc581d35e0d 100644 --- a/drivers/block/Config.in +++ b/drivers/block/Config.in @@ -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 diff --git a/drivers/block/Makefile b/drivers/block/Makefile index caec304e9d2f..66514986cdfb 100644 --- a/drivers/block/Makefile +++ b/drivers/block/Makefile @@ -99,6 +99,10 @@ endif 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) diff --git a/drivers/block/README.ide b/drivers/block/README.ide index 781258153d95..7650bd760f01 100644 --- a/drivers/block/README.ide +++ b/drivers/block/README.ide @@ -485,7 +485,7 @@ In <41ip85$gf9@park.uvsc.edu>, Terry Lambert 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. diff --git a/drivers/block/amiflop.c b/drivers/block/amiflop.c index 0d580061b8cc..4cf9e7a19e56 100644 --- a/drivers/block/amiflop.c +++ b/drivers/block/amiflop.c @@ -21,7 +21,7 @@ * - 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 diff --git a/drivers/block/ataflop.c b/drivers/block/ataflop.c index 20de5095167d..a4a2a30f9e22 100644 --- a/drivers/block/ataflop.c +++ b/drivers/block/ataflop.c @@ -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 + diff --git a/drivers/block/ll_rw_blk.c b/drivers/block/ll_rw_blk.c index 36eb4bc0afe4..dd7201afe249 100644 --- a/drivers/block/ll_rw_blk.c +++ b/drivers/block/ll_rw_blk.c @@ -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 diff --git a/drivers/block/loop.c b/drivers/block/loop.c index 3c8bfa597469..68096f659e4a 100644 --- a/drivers/block/loop.c +++ b/drivers/block/loop.c @@ -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); diff --git a/drivers/block/xd.c b/drivers/block/xd.c index f1b8103f2a03..455a26bcf71e 100644 --- a/drivers/block/xd.c +++ b/drivers/block/xd.c @@ -17,6 +17,9 @@ * 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 */ + diff --git a/drivers/cdrom/aztcd.c b/drivers/cdrom/aztcd.c index 9c25513672f8..18e4f2319aee 100644 --- a/drivers/cdrom/aztcd.c +++ b/drivers/cdrom/aztcd.c @@ -150,7 +150,7 @@ 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 #include diff --git a/drivers/char/ChangeLog b/drivers/char/ChangeLog index d517ac47cd04..f2b9a26cf3d0 100644 --- a/drivers/char/ChangeLog +++ b/drivers/char/ChangeLog @@ -1,6 +1,6 @@ Wed Apr 24 14:02:04 1996 Theodore Ts'o - * 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 diff --git a/drivers/char/console.c b/drivers/char/console.c index 964efa10ec7a..f718e4531417 100644 --- a/drivers/char/console.c +++ b/drivers/char/console.c @@ -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); diff --git a/drivers/char/fbmem.c b/drivers/char/fbmem.c index 5756f0a2de78..488ea1a3c998 100644 --- a/drivers/char/fbmem.c +++ b/drivers/char/fbmem.c @@ -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; diff --git a/drivers/char/ftape/ftape-read.c b/drivers/char/ftape/ftape-read.c index 51615264f4dc..3d9b396ed2da 100644 --- a/drivers/char/ftape/ftape-read.c +++ b/drivers/char/ftape/ftape-read.c @@ -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); diff --git a/drivers/char/ftape/kernel-interface.c b/drivers/char/ftape/kernel-interface.c index e9981dcadb79..fcb2f46714d1 100644 --- a/drivers/char/ftape/kernel-interface.c +++ b/drivers/char/ftape/kernel-interface.c @@ -45,7 +45,7 @@ /* 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 */ diff --git a/drivers/char/istallion.c b/drivers/char/istallion.c index 2cb6fd0cd753..2cc26a90f576 100644 --- a/drivers/char/istallion.c +++ b/drivers/char/istallion.c @@ -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. diff --git a/drivers/char/lp.c b/drivers/char/lp.c index deb7c3544c01..1c4742fdd477 100644 --- a/drivers/char/lp.c +++ b/drivers/char/lp.c @@ -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(); diff --git a/drivers/char/lp_m68k.c b/drivers/char/lp_m68k.c index 42eeed3a571b..8610862399d9 100644 --- a/drivers/char/lp_m68k.c +++ b/drivers/char/lp_m68k.c @@ -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 diff --git a/drivers/char/pcxx.c b/drivers/char/pcxx.c index 2e5bd4ccd1f4..5666b2a406f9 100644 --- a/drivers/char/pcxx.c +++ b/drivers/char/pcxx.c @@ -38,7 +38,7 @@ 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 @@ -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 diff --git a/drivers/char/psaux.c b/drivers/char/psaux.c index 1e1a3e8666ba..363b59399860 100644 --- a/drivers/char/psaux.c +++ b/drivers/char/psaux.c @@ -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; } diff --git a/drivers/char/pty.c b/drivers/char/pty.c index 2066fa83ae3c..b004a33652a9 100644 --- a/drivers/char/pty.c +++ b/drivers/char/pty.c @@ -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; diff --git a/drivers/char/random.c b/drivers/char/random.c index 262d3201fab7..9873f8af7262 100644 --- a/drivers/char/random.c +++ b/drivers/char/random.c @@ -169,7 +169,7 @@ * 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 ] ); diff --git a/drivers/char/rtc.c b/drivers/char/rtc.c index 5e18b961aa3c..4d04711153cc 100644 --- a/drivers/char/rtc.c +++ b/drivers/char/rtc.c @@ -30,7 +30,7 @@ * */ -#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... */ @@ -56,8 +56,6 @@ #include #include -#include - /* * 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<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; diff --git a/drivers/char/stallion.c b/drivers/char/stallion.c index 2e0195b82d75..c58a1f205724 100644 --- a/drivers/char/stallion.c +++ b/drivers/char/stallion.c @@ -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(); diff --git a/drivers/char/vc_screen.c b/drivers/char/vc_screen.c index 52f9a4098e5a..df9af352a756 100644 --- a/drivers/char/vc_screen.c +++ b/drivers/char/vc_screen.c @@ -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; diff --git a/drivers/char/vga.c b/drivers/char/vga.c index ad6a150603ee..0fe5305efe1c 100644 --- a/drivers/char/vga.c +++ b/drivers/char/vga.c @@ -29,6 +29,10 @@ * Colour palette handling, by Simon Tatham * 17-Jun-95 * + * if 512 char mode is already enabled don't re-enable it, + * because it causes screen to flicker, by Mitja Horvat + * 5-May-96 + * */ #include @@ -308,6 +312,7 @@ int 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 */ diff --git a/drivers/isdn/isdn_common.c b/drivers/isdn/isdn_common.c index 761a8d9c4816..99600a679a67 100644 --- a/drivers/isdn/isdn_common.c +++ b/drivers/isdn/isdn_common.c @@ -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)) { diff --git a/drivers/isdn/isdn_net.c b/drivers/isdn/isdn_net.c index 6f9d76b36f32..ba93884f6084 100644 --- a/drivers/isdn/isdn_net.c +++ b/drivers/isdn/isdn_net.c @@ -46,7 +46,7 @@ * 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) diff --git a/drivers/isdn/isdn_ppp.c b/drivers/isdn/isdn_ppp.c index 994ed9a79760..eab7e4612719 100644 --- a/drivers/isdn/isdn_ppp.c +++ b/drivers/isdn/isdn_ppp.c @@ -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) diff --git a/drivers/net/3c501.c b/drivers/net/3c501.c index 623546f63ce3..4c8e7c940a99 100644 --- a/drivers/net/3c501.c +++ b/drivers/net/3c501.c @@ -68,7 +68,7 @@ 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. diff --git a/drivers/net/8390.c b/drivers/net/8390.c index 05c896301be1..aee0038087d3 100644 --- a/drivers/net/8390.c +++ b/drivers/net/8390.c @@ -16,28 +16,30 @@ 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 +static const char *version = + "8390.c:v1.10 9/23/94 Donald Becker (becker@cesdis.gsfc.nasa.gov)\n"; +#include #include #include #include @@ -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; diff --git a/drivers/net/8390.h b/drivers/net/8390.h index 56716e783068..9cc0ddc53409 100644 --- a/drivers/net/8390.h +++ b/drivers/net/8390.h @@ -13,7 +13,15 @@ #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. */ diff --git a/drivers/net/Makefile b/drivers/net/Makefile index bd81722a8330..7967de6b8670 100644 --- a/drivers/net/Makefile +++ b/drivers/net/Makefile @@ -466,6 +466,14 @@ else 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 diff --git a/drivers/net/README.eql b/drivers/net/README.eql index 6e492190c3b2..08cded5980d4 100644 --- a/drivers/net/README.eql +++ b/drivers/net/README.eql @@ -29,7 +29,7 @@ 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.--) diff --git a/drivers/net/README.tunnel b/drivers/net/README.tunnel index 455022738aeb..407635b71373 100644 --- a/drivers/net/README.tunnel +++ b/drivers/net/README.tunnel @@ -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 diff --git a/drivers/net/Space.c b/drivers/net/Space.c index c6c146ed7aae..edcb43178d74 100644 --- a/drivers/net/Space.c +++ b/drivers/net/Space.c @@ -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 diff --git a/drivers/net/arcnet.c b/drivers/net/arcnet.c index 0c2a69e7e514..ad2d8fa86dd1 100644 --- a/drivers/net/arcnet.c +++ b/drivers/net/arcnet.c @@ -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; diff --git a/drivers/net/dgrs.c b/drivers/net/dgrs.c index 96be192eaff0..a2d93ea55e12 100644 --- a/drivers/net/dgrs.c +++ b/drivers/net/dgrs.c @@ -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 @@ -373,13 +373,13 @@ again: /* * 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; diff --git a/drivers/net/dgrs_driver.c b/drivers/net/dgrs_driver.c index 96be192eaff0..a2d93ea55e12 100644 --- a/drivers/net/dgrs_driver.c +++ b/drivers/net/dgrs_driver.c @@ -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 @@ -373,13 +373,13 @@ again: /* * 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; diff --git a/drivers/net/dlci.c b/drivers/net/dlci.c index 2e21cdfc1381..157dd5a6e051 100644 --- a/drivers/net/dlci.c +++ b/drivers/net/dlci.c @@ -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); diff --git a/drivers/net/dummy.c b/drivers/net/dummy.c index 4cc00d9bffe9..1135fbb2e963 100644 --- a/drivers/net/dummy.c +++ b/drivers/net/dummy.c @@ -24,7 +24,7 @@ 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 */ diff --git a/drivers/net/eexpress.c b/drivers/net/eexpress.c index 1c2915a5e22f..ff1e11d123aa 100644 --- a/drivers/net/eexpress.c +++ b/drivers/net/eexpress.c @@ -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. */ diff --git a/drivers/net/eql.c b/drivers/net/eql.c index b1dd14e6c408..5c6e38d48f7b 100644 --- a/drivers/net/eql.c +++ b/drivers/net/eql.c @@ -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 diff --git a/drivers/net/eth16i.c b/drivers/net/eth16i.c index 501cc5f3dae4..ee484c387e50 100644 --- a/drivers/net/eth16i.c +++ b/drivers/net/eth16i.c @@ -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. */ diff --git a/drivers/net/hp100.h b/drivers/net/hp100.h index 9092280980ac..1ebca564d286 100644 --- a/drivers/net/hp100.h +++ b/drivers/net/hp100.h @@ -128,7 +128,7 @@ #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. */ diff --git a/drivers/net/hydra.c b/drivers/net/hydra.c new file mode 100644 index 000000000000..5e3b2cd6a4bf --- /dev/null +++ b/drivers/net/hydra.c @@ -0,0 +1,655 @@ +/* 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 +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include + +#include +#include +#include +#include + +#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(; len1hydra_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 + diff --git a/drivers/net/hydra.h b/drivers/net/hydra.h new file mode 100644 index 000000000000..0a0919eb7fe8 --- /dev/null +++ b/drivers/net/hydra.h @@ -0,0 +1,177 @@ +/* $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 + + diff --git a/drivers/net/ibmtr.c b/drivers/net/ibmtr.c index 5100d8c0880f..df0a857abc40 100644 --- a/drivers/net/ibmtr.c +++ b/drivers/net/ibmtr.c @@ -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 */ diff --git a/drivers/net/lance32.c b/drivers/net/lance32.c index da8418ac47b4..953f5eadd46d 100644 --- a/drivers/net/lance32.c +++ b/drivers/net/lance32.c @@ -13,7 +13,7 @@ * 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 #include @@ -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 broadcast + * 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 */ } diff --git a/drivers/net/loopback.c b/drivers/net/loopback.c index b709ff40c851..74181b54f93c 100644 --- a/drivers/net/loopback.c +++ b/drivers/net/loopback.c @@ -15,8 +15,8 @@ * 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 diff --git a/drivers/net/ne.c b/drivers/net/ne.c index 58fe093d4b2b..7d319f3ae037 100644 --- a/drivers/net/ne.c +++ b/drivers/net/ne.c @@ -23,6 +23,7 @@ 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"; diff --git a/drivers/net/new_tunnel.c b/drivers/net/new_tunnel.c index b0915a32c929..f3c7dcefccac 100644 --- a/drivers/net/new_tunnel.c +++ b/drivers/net/new_tunnel.c @@ -62,6 +62,7 @@ */ #include +#include /* for CONFIG_IP_FORWARD */ /* Only two headers!! :-) */ #include @@ -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); /* diff --git a/drivers/net/ppp.c b/drivers/net/ppp.c index 08625d50945f..865e8bb0e9c5 100644 --- a/drivers/net/ppp.c +++ b/drivers/net/ppp.c @@ -91,7 +91,7 @@ typedef struct sk_buff sk_buff; #include #include #include -#include "slhc.h" +#include #define fcstab ppp_crc16_table /* Name of the table in the kernel */ #include diff --git a/drivers/net/sdla.c b/drivers/net/sdla.c index 570da9249f0f..74147f052c9c 100644 --- a/drivers/net/sdla.c +++ b/drivers/net/sdla.c @@ -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) { diff --git a/drivers/net/seeq8005.c b/drivers/net/seeq8005.c index 2ba2e08abfc4..c4d48521d267 100644 --- a/drivers/net/seeq8005.c +++ b/drivers/net/seeq8005.c @@ -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 diff --git a/drivers/net/seeq8005.h b/drivers/net/seeq8005.h index b35d8e499df9..809ba6dc8fb9 100644 --- a/drivers/net/seeq8005.h +++ b/drivers/net/seeq8005.h @@ -119,7 +119,7 @@ #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 */ diff --git a/drivers/net/sk_g16.c b/drivers/net/sk_g16.c index 98fa799b663a..696acafefc30 100644 --- a/drivers/net/sk_g16.c +++ b/drivers/net/sk_g16.c @@ -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 diff --git a/drivers/net/slhc.c b/drivers/net/slhc.c index b2696a1a0ddd..5b868315e8c5 100644 --- a/drivers/net/slhc.c +++ b/drivers/net/slhc.c @@ -78,7 +78,7 @@ #include #include #include -#include "slhc.h" +#include #ifdef __alpha__ # include diff --git a/drivers/net/slip.c b/drivers/net/slip.c index 1b55ce4fc994..4d3c053bb22e 100644 --- a/drivers/net/slip.c +++ b/drivers/net/slip.c @@ -81,7 +81,7 @@ #ifdef CONFIG_INET #include #include -#include "slhc.h" +#include #endif #ifdef MODULE diff --git a/drivers/net/smc-ultra.c b/drivers/net/smc-ultra.c index b393828e1ef6..7ff1e2705e09 100644 --- a/drivers/net/smc-ultra.c +++ b/drivers/net/smc-ultra.c @@ -1,6 +1,8 @@ /* 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. @@ -12,8 +14,6 @@ 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 @@ -32,17 +32,18 @@ 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 @@ -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); @@ -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. */ /* Probe for the Ultra. This looks like a 8013 with the station address PROM at I/O ports +8 to +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) { diff --git a/drivers/sbus/char/sunkeymap.map b/drivers/sbus/char/sunkeymap.map index 3b03ef50c966..734419108f39 100644 --- a/drivers/sbus/char/sunkeymap.map +++ b/drivers/sbus/char/sunkeymap.map @@ -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" diff --git a/drivers/sbus/char/sunserial.c b/drivers/sbus/char/sunserial.c index c4c7797b3be0..fdea1b804e67 100644 --- a/drivers/sbus/char/sunserial.c +++ b/drivers/sbus/char/sunserial.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; diff --git a/drivers/scsi/53c7,8xx.c b/drivers/scsi/53c7,8xx.c index d4d2dae41f39..db25d92d7622 100644 --- a/drivers/scsi/53c7,8xx.c +++ b/drivers/scsi/53c7,8xx.c @@ -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. * */ diff --git a/drivers/scsi/ChangeLog b/drivers/scsi/ChangeLog index 050ac6d15450..5501be454e93 100644 --- a/drivers/scsi/ChangeLog +++ b/drivers/scsi/ChangeLog @@ -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. diff --git a/drivers/scsi/Config.in b/drivers/scsi/Config.in index f4e721188e44..7fbd8b3b03f6 100644 --- a/drivers/scsi/Config.in +++ b/drivers/scsi/Config.in @@ -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 diff --git a/drivers/scsi/README.st b/drivers/scsi/README.st index 71b41a1799fe..c7ebd6aa4e5a 100644 --- a/drivers/scsi/README.st +++ b/drivers/scsi/README.st @@ -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 diff --git a/drivers/scsi/aha1542.c b/drivers/scsi/aha1542.c index 9e580b287ede..08d9a31648a6 100644 --- a/drivers/scsi/aha1542.c +++ b/drivers/scsi/aha1542.c @@ -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. diff --git a/drivers/scsi/aic7xxx.c b/drivers/scsi/aic7xxx.c index fc0702b624f5..996b6252aaf7 100644 --- a/drivers/scsi/aic7xxx.c +++ b/drivers/scsi/aic7xxx.c @@ -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); diff --git a/drivers/scsi/eata_dma.c b/drivers/scsi/eata_dma.c index 43e75f949fb1..cb534f89ecfc 100644 --- a/drivers/scsi/eata_dma.c +++ b/drivers/scsi/eata_dma.c @@ -8,8 +8,15 @@ * * * 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 * @@ -19,8 +26,9 @@ * -provides rudimentary latency measurement * * possibilities via /proc/scsi/eata_dma/ * * * - * (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 * @@ -45,10 +53,11 @@ * 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 */ @@ -63,6 +72,7 @@ #include #include #include +#include #include #include #include @@ -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)); diff --git a/drivers/scsi/eata_dma.h b/drivers/scsi/eata_dma.h index 7aec03e5bb45..eaa4dc0907ec 100644 --- a/drivers/scsi/eata_dma.h +++ b/drivers/scsi/eata_dma.h @@ -1,11 +1,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 @@ -16,7 +17,7 @@ #define VER_MAJOR 2 #define VER_MINOR 5 -#define VER_SUB "8a" +#define VER_SUB "8d" /************************************************************************ @@ -47,6 +48,9 @@ #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 *); diff --git a/drivers/scsi/eata_generic.h b/drivers/scsi/eata_generic.h index b68e329b4842..8bbb63a46c11 100644 --- a/drivers/scsi/eata_generic.h +++ b/drivers/scsi/eata_generic.h @@ -1,9 +1,11 @@ /******************************************************** * 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 * ********************************************************/ @@ -56,35 +58,43 @@ #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 * @@ -122,13 +132,14 @@ #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 */ @@ -149,7 +160,7 @@ #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; diff --git a/drivers/scsi/eata_pio.c b/drivers/scsi/eata_pio.c index e6740c098154..829a70027edb 100644 --- a/drivers/scsi/eata_pio.c +++ b/drivers/scsi/eata_pio.c @@ -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 */ diff --git a/drivers/scsi/eata_pio.h b/drivers/scsi/eata_pio.h index 3c25bf51e497..b02a056a32f2 100644 --- a/drivers/scsi/eata_pio.h +++ b/drivers/scsi/eata_pio.h @@ -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 *); diff --git a/drivers/scsi/fdomain.c b/drivers/scsi/fdomain.c index 03585b00ca51..ab68e279ed1d 100644 --- a/drivers/scsi/fdomain.c +++ b/drivers/scsi/fdomain.c @@ -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) { diff --git a/drivers/scsi/hosts.c b/drivers/scsi/hosts.c index 9c2076c5c9dc..f35029d94ef9 100644 --- a/drivers/scsi/hosts.c +++ b/drivers/scsi/hosts.c @@ -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){ diff --git a/drivers/scsi/pas16.c b/drivers/scsi/pas16.c index 8100dba4c931..a08ff1e62d8f 100644 --- a/drivers/scsi/pas16.c +++ b/drivers/scsi/pas16.c @@ -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 */ diff --git a/drivers/scsi/scsi_debug.c b/drivers/scsi/scsi_debug.c index 536534672493..b623ae124526 100644 --- a/drivers/scsi/scsi_debug.c +++ b/drivers/scsi/scsi_debug.c @@ -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 ) diff --git a/drivers/scsi/sd.c b/drivers/scsi/sd.c index be690c0392d5..e68d085ee7aa 100644 --- a/drivers/scsi/sd.c +++ b/drivers/scsi/sd.c @@ -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; countuse_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; countuse_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; diff --git a/drivers/scsi/seagate.c b/drivers/scsi/seagate.c index 88aa97986e3b..9337be4e365a 100644 --- a/drivers/scsi/seagate.c +++ b/drivers/scsi/seagate.c @@ -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 diff --git a/drivers/scsi/sr.c b/drivers/scsi/sr.c index 783d9ba4e9d9..03565bea9b87 100644 --- a/drivers/scsi/sr.c +++ b/drivers/scsi/sr.c @@ -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) { diff --git a/drivers/scsi/wd33c93.h b/drivers/scsi/wd33c93.h index 5dcdc13af2b9..123590d5ee00 100644 --- a/drivers/scsi/wd33c93.h +++ b/drivers/scsi/wd33c93.h @@ -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 */ diff --git a/drivers/sound/CHANGELOG b/drivers/sound/CHANGELOG index 6acd80d28630..f760bdfaa93a 100644 --- a/drivers/sound/CHANGELOG +++ b/drivers/sound/CHANGELOG @@ -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. diff --git a/drivers/sound/Readme.cards b/drivers/sound/Readme.cards index 88317e606cc3..a096876255df 100644 --- a/drivers/sound/Readme.cards +++ b/drivers/sound/Readme.cards @@ -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. diff --git a/drivers/sound/ad1848.c b/drivers/sound/ad1848.c index 9c8478a1d59b..ac77f44a4fe1 100644 --- a/drivers/sound/ad1848.c +++ b/drivers/sound/ad1848.c @@ -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. */ diff --git a/drivers/sound/gus_wave.c b/drivers/sound/gus_wave.c index 7524fce04c12..81d5a48f24b9 100644 --- a/drivers/sound/gus_wave.c +++ b/drivers/sound/gus_wave.c @@ -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; } diff --git a/drivers/sound/mpu401.c b/drivers/sound/mpu401.c index 262ea9cda4e0..82ee5c16215b 100644 --- a/drivers/sound/mpu401.c +++ b/drivers/sound/mpu401.c @@ -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. */ diff --git a/drivers/sound/sound_switch.c b/drivers/sound/sound_switch.c index 413724a72f43..fe5b0300f386 100644 --- a/drivers/sound/sound_switch.c +++ b/drivers/sound/sound_switch.c @@ -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: diff --git a/fs/Config.in b/fs/Config.in index be203265ba29..999fb5f5dc05 100644 --- a/fs/Config.in +++ b/fs/Config.in @@ -34,7 +34,10 @@ fi 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 diff --git a/fs/affs/Makefile b/fs/affs/Makefile index fb272dcb7eaf..77cb4225f7ca 100644 --- a/fs/affs/Makefile +++ b/fs/affs/Makefile @@ -1,5 +1,5 @@ # -# 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 @@ -8,7 +8,7 @@ # 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 diff --git a/fs/affs/amigaffs.c b/fs/affs/amigaffs.c index 0a0ce359ec85..55a125f50f14 100644 --- a/fs/affs/amigaffs.c +++ b/fs/affs/amigaffs.c @@ -1,89 +1,57 @@ /* * linux/fs/affs/amigaffs.c * - * (C) 1996 Stefan Reinauer - Modified to compile as Module + * (c) 1996 Hans-Joachim Widmaier - Modified for larger blocks. * * (C) 1993 Ray Burr - Amiga FFS filesystem. * */ - -#include - -#include +#include +#include #include +#include +#include #include +#include -#include "amigaffs.h" +extern struct timezone sys_tz; /* * 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) +int +affs_find_next_hash_entry(int hsize, void *dir_data, ULONG *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) + 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 == hash_table_size) + if (i >= hsize) 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; + 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) +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); + 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"); @@ -96,57 +64,210 @@ int affs_get_file_name (int bsize, void *fh_data, char **name) return file_end->file_name[0]; } -/* Get the key number of the first extension block for the file - header pointed to by FH_DATA. */ +/* Find the predecessor in the hash chain */ -int affs_get_extension (int bsize, void *fh_data) +int +affs_fix_hash_pred(struct inode *startino, int startoffset, LONG key, LONG newkey) { - struct file_end *file_end; - int key; + struct buffer_head *bh = NULL; + ULONG nextkey; + LONG ptype, stype; + int retval; - file_end = GET_END_PTR (struct file_end, fh_data, bsize); - key = swap_long (file_end->extension); - return key; + 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. Returns non-zero if the block is not - consistent. */ + 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. */ -int affs_checksum_block (int bsize, void *data, int *ptype, int *stype) +ULONG +affs_checksum_block(int bsize, void *data, LONG *ptype, LONG *stype) { + ULONG sum; + ULONG *p; + + bsize /= 4; if (ptype) - *ptype = swap_long (((long *) data)[0]); + *ptype = htonl(((LONG *)data)[0]); if (stype) - *stype = swap_long (((long *) data)[bsize / 4 - 1]); - return 0; -} + *stype = htonl(((LONG *)data)[bsize - 1]); -static struct file_system_type affs_fs_type = { - affs_read_super, "affs", 1, NULL -}; + sum = 0; + p = data; + while (bsize--) + sum += htonl(*p++); + return sum; +} -int init_affs_fs(void) +void +affs_fix_checksum(int bsize, void *data, int cspos) { - return register_filesystem(&affs_fs_type); + ULONG ocs; + ULONG cs; + + cs = affs_checksum_block(bsize,data,NULL,NULL); + ocs = htonl (((ULONG *)data)[cspos]); + ocs -= cs; + ((ULONG *)data)[cspos] = htonl(ocs); } -#ifdef MODULE -int init_module(void) +void +secs_to_datestamp(int secs, struct DateStamp *ds) { - int status; + ULONG days; + ULONG minute; - if ((status = init_affs_fs()) == 0) - register_symtab(0); - return status; + 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); } -void cleanup_module(void) +int +prot_to_mode(ULONG prot) { - unregister_filesystem(&affs_fs_type); + 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; } -#endif +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; +} diff --git a/fs/affs/amigaffs.h b/fs/affs/amigaffs.h deleted file mode 100644 index 457a32c90a4b..000000000000 --- a/fs/affs/amigaffs.h +++ /dev/null @@ -1,206 +0,0 @@ -#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 diff --git a/fs/affs/bitmap.c b/fs/affs/bitmap.c new file mode 100644 index 000000000000..8a14c3e1f8f9 --- /dev/null +++ b/fs/affs/bitmap.c @@ -0,0 +1,332 @@ +/* + * linux/fs/affs/bitmap.c + * + * (c) 1996 Hans-Joachim Widmaier + */ + +/* bitmap.c contains the code that handles the inode and block bitmaps */ + +#include +#include +#include +#include +#include +#include +#include + +#include + +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; + } +} diff --git a/fs/affs/dir.c b/fs/affs/dir.c index 5668fed616c1..165e767173ef 100644 --- a/fs/affs/dir.c +++ b/fs/affs/dir.c @@ -1,6 +1,8 @@ /* * 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. @@ -8,25 +10,25 @@ * (C) 1991 Linus Torvalds - minix filesystem * * affs directory handling functions + * */ -#include - #include - +#include #include -#include #include #include #include #include -#include +#include +#include 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); -struct file_operations affs_dir_operations = { +static struct file_operations affs_dir_operations = { NULL, /* lseek - default */ - NULL, /* read */ + affs_dir_read, /* read */ NULL, /* write - bad */ affs_readdir, /* readdir */ NULL, /* select - default */ @@ -34,7 +36,7 @@ struct file_operations affs_dir_operations = { NULL, /* mmap */ NULL, /* no special open code */ NULL, /* no special release code */ - NULL /* fsync */ + file_fsync /* default fsync */ }; /* @@ -42,109 +44,153 @@ struct file_operations affs_dir_operations = { */ struct inode_operations affs_dir_inode_operations = { &affs_dir_operations, /* default directory file-ops */ - NULL, /* create */ + affs_create, /* create */ affs_lookup, /* lookup */ - NULL, /* link */ - NULL, /* unlink */ - NULL, /* symlink */ - NULL, /* mkdir */ - NULL, /* rmdir */ + affs_link, /* link */ + affs_unlink, /* unlink */ + affs_symlink, /* symlink */ + affs_mkdir, /* mkdir */ + affs_rmdir, /* rmdir */ NULL, /* mknod */ - NULL, /* rename */ + affs_rename, /* rename */ NULL, /* readlink */ NULL, /* follow_link */ + NULL, /* readpage */ + NULL, /* writepage */ NULL, /* bmap */ - NULL, /* truncate */ - NULL /* permission */ + affs_dir_truncate, /* truncate */ + NULL /* permissions */ }; -/* 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_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) +static int +affs_readdir(struct inode *inode, struct file *filp, void *dirent, filldir_t filldir) { - int i, j, chain_pos, hash_pos, reclen, ino; + 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; - void *dir_data; - void *fh_data; + struct inode *dir; -#ifdef DEBUG - printk ("AFFS: readdir: inode=%d f_pos=%d\n", - inode->i_ino, filp->f_pos); -#endif + 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; - 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; + 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++; + ++filp->f_pos; + stored++; } - /* 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; + if (filp->f_pos == 1) { + if (filldir(dirent,"..",2,filp->f_pos,affs_parent_ino(inode)) < 0) { + filp->f_pos |= 0x80000000; + return stored; } - ino = i; - if (!(fh_bh = affs_pread (inode, i, &fh_data))) { - brelse (dir_bh); - return 0; + 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); } - 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_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; } - filp->f_pos = ((hash_pos << 16) | chain_pos) + 2; + 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++; } - brelse (fh_bh); - j--; + 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"); } diff --git a/fs/affs/file.c b/fs/affs/file.c index 50f126e7ee49..585093ebcffe 100644 --- a/fs/affs/file.c +++ b/fs/affs/file.c @@ -1,6 +1,8 @@ /* * 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. @@ -12,7 +14,6 @@ #include #include - #include #include #include @@ -20,36 +21,31 @@ #include #include #include - #include - -#define NBUF 16 +#include +#include +#include +#include #define MIN(a,b) (((a)<(b))?(a):(b)) #define MAX(a,b) (((a)>(b))?(a):(b)) -#include -#include +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 } diff --git a/fs/affs/inode.c b/fs/affs/inode.c index 82ed07cce273..40417857358a 100644 --- a/fs/affs/inode.c +++ b/fs/affs/inode.c @@ -1,15 +1,19 @@ /* * linux/fs/affs/inode.c * - * (C) 1994 Geert Uytterhoeven - Modified for MultiUserFileSystem + * (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 +#include +#include +#include #include #include #include @@ -17,50 +21,80 @@ #include #include #include - -#include -#include #include - #include +#include +#include +#include +#include -#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 +extern int *blk_size[]; +extern struct timezone sys_tz; void affs_put_super(struct super_block *sb) { - lock_super(sb); + int i; -#ifdef LEAK_CHECK - printk("Outstanding mallocs:%d, outstanding buffers: %d\n", - check_malloc, check_bread); -#endif + 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 struct super_operations affs_sops = { +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, - NULL, /* notify_change */ - NULL, /* write_inode */ - NULL, /* put_inode */ + affs_notify_change, + affs_write_inode, + affs_put_inode, affs_put_super, - NULL, /* write_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 - - dir->i_sb->u.affs_sb.s_partition_offset); + 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"); @@ -71,361 +105,854 @@ int affs_parent_ino(struct inode *dir) 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; +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_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) + 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; - optp->offset = n; + *mount_opts |= SF_SETMODE; } - else if (!strcmp(this_opt,"size") && value) { - n = simple_strtoul (value, &end, 10); - if (end == value || *end != 0 || n <= 0) + 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; - optp->size = n; } - else if (!strcmp(this_opt,"root") && value) { - n = simple_strtoul (value, &end, 10); - if (end == value || *end != 0 || n <= 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; - optp->root = n; + if (*blocksize != 512 && *blocksize != 1024 && *blocksize != 2048 + && *blocksize != 4096) { + printk ("AFFS: Invalid blocksize (512, 1024, 2048, 4096 allowed).\n"); + return 0; + } } - else if (!strcmp(this_opt,"conv_symlinks")) { - optp->conv_links = 1; + /* 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; } - 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 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)) { + 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: bad mount options\n"); + printk("AFFS: error parsing options.\n"); + MOD_DEC_USE_COUNT; 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; - } + /* 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. + */ - 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 + 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; - bh = affs_sread (dev, root_block, &root_data); - if (!bh) { + if (size == 0) { s->s_dev = 0; unlock_super(s); - printk ("AFFS: unable to read superblock\n"); - return NULL; + 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); } - 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); + 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; } -#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 + /* Allocate space for bitmap pointers and read the bitmap */ - s->s_magic = AFFS_SUPER_MAGIC; + 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); - s->s_flags = MS_RDONLY | MS_NODEV | MS_NOSUID; + 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; + } - brelse(bh); + 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_blocksize = AFFS_BUFFER_SIZE; - s->s_mounted = iget (s, root_block - s->u.affs_sb.s_partition_offset); + 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 */ - brelse (bh); + 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) +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 */ + 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); } -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) +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 + 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; + } - 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 *)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; } - - 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; + 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; } - 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<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); + 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_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; - } + 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; } - 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); - + = (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)) - inode->i_op = &affs_file_inode_operations; - else if (S_ISDIR(inode->i_mode)) + 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; + } -#ifdef LEAK_CHECK -#undef malloc -#undef free_s -#undef bread -#undef brelse + 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; +} -void * leak_check_malloc(unsigned int size){ - void * tmp; - check_malloc++; - tmp = kmalloc(size, GFP_ATOMIC); - return tmp; +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; } -void leak_check_free_s(void * obj, int size){ - check_malloc--; - return kfree_s(obj, size); +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); } -struct buffer_head * leak_check_bread(int dev, int block, int size){ - check_bread++; - return bread(dev, block, size); +#ifdef MODULE + +int +init_module(void) +{ + int status; + if ((status = init_affs_fs()) == 0) + register_symtab(0); + return status; } -void leak_check_brelse(struct buffer_head * bh){ - check_bread--; - return brelse(bh); +void +cleanup_module(void) +{ + unregister_filesystem(&affs_fs_type); } #endif diff --git a/fs/affs/namei.c b/fs/affs/namei.c index 77c1a2b3344a..f213dc1eb9e8 100644 --- a/fs/affs/namei.c +++ b/fs/affs/namei.c @@ -1,187 +1,736 @@ /* * linux/fs/affs/namei.c * - * (C) 1993 Ray Burr - Modified for Amiga FFS filesystem. + * (c) 1996 Hans-Joachim Widmaier - Heavily hacked up. * - * (C) 1992 Eric Youngdale Modified for ISO9660 filesystem. + * (C) 1993 Ray Burr - Modified for Amiga FFS filesystem. * * (C) 1991 Linus Torvalds - minix filesystem */ #include #include +#include #include #include #include #include +#include #include #include +/* Simple toupper() for DOS\1 */ -static inline int namecompare(int len, int maxlen, - const char * name, const char * buffer) +static inline unsigned int +affs_toupper(unsigned int ch) { - if (len >= maxlen || !buffer[len]) { - return strncmp (name, buffer, len) == 0; - } - return 0; + 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; } /* - * 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) + +static int +affs_match(const char *name, int len, const char *compare, int dlen, int intl) { - if (!compare) return 0; + 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 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); + 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; } -/* Avoid pulling in ctype stuff. */ - -static int affs_toupper (int ch) +int +affs_hash_name(const char *name, int len, int intl, int hashsize) { - if (ch >= 'a' && ch <= 'z') - ch -= ('a' - 'A'); - return ch; -} + unsigned int i, x; -static int affs_hash_name (const char *name, int len) -{ - int i, x; + if (len > 30) + len = 30; x = len; for (i = 0; i < len; i++) - x = (x * 13 + affs_toupper (name[i])) & 0x7ff; - return x % 72; /* FIXME: Assumes 512 byte blocks. */ + 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, int *ino) +static struct buffer_head * +affs_find_entry(struct inode *dir, const char *name, int namelen, + unsigned long *ino) { struct buffer_head *bh; - void *dir_data; - int key; + int intl; + ULONG key; - *ino = 0; + pr_debug("AFFS: find_entry(%.*s)=\n",namelen,name); - bh = affs_pread (dir, dir->i_ino, &dir_data); + intl = AFFS_I2FSTYPE(dir); + bh = affs_bread(dir->i_dev,dir->i_ino,AFFS_I2BSIZE(dir)); if (!bh) return NULL; - if (affs_match (namelen, name, ".", 1)) { + if (affs_match(name,namelen,".",1,intl)) { *ino = dir->i_ino; return bh; } - if (affs_match (namelen, name, "..", 2)) { - *ino = affs_parent_ino (dir); + if (affs_match(name,namelen,"..",2,intl)) { + *ino = affs_parent_ino(dir); return bh; } - key = affs_get_key_entry (AFFS_I2BSIZE (dir), dir_data, - affs_hash_name (name, namelen)); + + key = AFFS_GET_HASHENTRY(bh->b_data,affs_hash_name(name,namelen,intl,AFFS_I2HSIZE(dir))); for (;;) { char *cname; int cnamelen; - brelse (bh); - if (key <= 0) - return NULL; - bh = affs_pread (dir, key, &dir_data); + affs_brelse(bh); + if (key == 0) { + bh = NULL; + break; + } + bh = affs_bread(dir->i_dev,key,AFFS_I2BSIZE(dir)); 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); + 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 +affs_lookup(struct inode *dir, const char *name, int len, struct inode **result) { - int ino; + int res; + unsigned long ino; struct buffer_head *bh; + pr_debug("AFFS: lookup(%.*s)\n",len,name); + *result = NULL; if (!dir) return -ENOENT; -#ifdef DEBUG - printk ("lookup: %d %d\n", dir->i_ino, len); -#endif + 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 (!S_ISDIR(dir->i_mode)) { + 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 -ENOENT; + return -EINVAL; } - if (!(bh = affs_find_entry(dir, name, len, &ino))) { - iput(dir); - return -ENOENT; + inode = affs_new_inode(dir); + if (!inode) { + iput (dir); + return -ENOSPC; } - brelse(bh); - if (!(*result = iget(dir->i_sb, ino))) { + 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); - return -EACCES; + inode->i_nlink = 0; + inode->i_dirt = 1; + iput(inode); + return -ENOSPC; } - iput (dir); + 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 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))) { + 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 -EACCES; + 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); - /* We need this backlink for the .. entry */ - - if (ino_back) (*result)->u.affs_i.i_backlink = ino_back; + 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; -#endif +} + +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; + } } diff --git a/fs/affs/symlink.c b/fs/affs/symlink.c index e54b387eded0..ee305dd8b54c 100644 --- a/fs/affs/symlink.c +++ b/fs/affs/symlink.c @@ -1,34 +1,28 @@ /* * linux/fs/affs/symlink.c * - * (C) 1995 Joerg Dorchain Modified for Amiga FFS filesystem - * based on: - * - * (C) 1992 Eric Youngdale Modified for ISO9660 filesystem. + * 1995 Hans-Joachim Widmaier - modified for AFFS. * * Copyright (C) 1991, 1992 Linus Torvalds * - * isofs symlink handling code. This is only used with the Rock Ridge - * extensions to iso9660 + * affs symlink handling code */ -#include - #include #include +#include #include #include -#include #include +#include -#include "amigaffs.h" +#include + +#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 **); -/* - * symlinks can't do much... - */ struct inode_operations affs_symlink_inode_operations = { NULL, /* no file-operations */ NULL, /* create */ @@ -47,21 +41,27 @@ struct inode_operations affs_symlink_inode_operations = { NULL /* permission */ }; -static int affs_follow_link(struct inode * dir, struct inode * inode, - int flag, int mode, struct inode ** res_inode) +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; + 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); - *res_inode = NULL; return -ENOENT; } if (!S_ISLNK(inode->i_mode)) { @@ -70,110 +70,108 @@ static int affs_follow_link(struct inode * dir, struct inode * inode, return 0; } if (current->link_count > 5) { - iput(dir); iput(inode); - *res_inode = NULL; + iput(dir); 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; + if (!(buffer = kmalloc(1024,GFP_KERNEL))) { + iput(inode); + iput(dir); + return -ENOSPC; } - - pnt = sy_data->symname; + 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(pnt,flag,mode,res_inode,dir); + error = open_namei(buffer,flag,mode,res_inode,dir); current->link_count--; - brelse(bh); + kfree(buffer); return error; } -static char *affs_conv_path(char *affs_path) +static int +affs_readlink(struct inode *inode, char *buffer, int buflen) { -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; -} + struct buffer_head *bh; + struct slink_front *lf; + int i, j; + char c; + char lc; - -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; + pr_debug("AFFS: readlink(ino=%lu,buflen=%d)\n",inode->i_ino,buflen); 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; + 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; - 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 (isymname,':')) { /* 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 = '/'; } - - brelse(bh); - + 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; } diff --git a/fs/block_dev.c b/fs/block_dev.c index e57e17ca8487..0ac60bcf7191 100644 --- a/fs/block_dev.c +++ b/fs/block_dev.c @@ -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. diff --git a/fs/buffer.c b/fs/buffer.c index c75c5ae1c4ff..a6000753719c 100644 --- a/fs/buffer.c +++ b/fs/buffer.c @@ -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 diff --git a/fs/ext/file.c b/fs/ext/file.c index 55152909b249..a00d0f41fa96 100644 --- a/fs/ext/file.c +++ b/fs/ext/file.c @@ -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. diff --git a/fs/fat/dir.c b/fs/fat/dir.c index 0e31a9571d6e..ec5fb06d9a9f 100644 --- a/fs/fat/dir.c +++ b/fs/fat/dir.c @@ -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); } diff --git a/fs/fat/msbuffer.h b/fs/fat/msbuffer.h index 5b386afe3689..9b9c6130a6ba 100644 --- a/fs/fat/msbuffer.h +++ b/fs/fat/msbuffer.h @@ -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 diff --git a/fs/isofs/inode.c b/fs/isofs/inode.c index 2d1d20ea26cb..20e89cf9fc13 100644 --- a/fs/isofs/inode.c +++ b/fs/isofs/inode.c @@ -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); } diff --git a/fs/isofs/rock.c b/fs/isofs/rock.c index 3df7f9aba22a..09963f0d88bf 100644 --- a/fs/isofs/rock.c +++ b/fs/isofs/rock.c @@ -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); diff --git a/fs/locks.c b/fs/locks.c index 5d7ecc4659f2..b8038e468ee5 100644 --- a/fs/locks.c +++ b/fs/locks.c @@ -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(). */ diff --git a/fs/nfs/nfsroot.c b/fs/nfs/nfsroot.c index 1c81c2341003..65814258b292 100644 --- a/fs/nfs/nfsroot.c +++ b/fs/nfs/nfsroot.c @@ -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; cmnt_dev = dev; diff --git a/fs/sysv/file.c b/fs/sysv/file.c index a7c775464dbf..92175ac7370a 100644 --- a/fs/sysv/file.c +++ b/fs/sysv/file.c @@ -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. diff --git a/fs/ufs/ufs_super.c b/fs/ufs/ufs_super.c index 371e3a7d3197..f260c105f5bb 100644 --- a/fs/ufs/ufs_super.c +++ b/fs/ufs/ufs_super.c @@ -13,6 +13,9 @@ /* * Kernel module support added on 96/04/26 by * Stefan Reinauer + * + * Module usage counts added on 96/04/29 by + * Gertjan van Wingerde */ #include diff --git a/fs/umsdos/namei.c b/fs/umsdos/namei.c index fcda9ab86a54..38682b53177e 100644 --- a/fs/umsdos/namei.c +++ b/fs/umsdos/namei.c @@ -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; diff --git a/fs/vfat/Makefile b/fs/vfat/Makefile index 5a3d41f35e52..354757b9ac7e 100644 --- a/fs/vfat/Makefile +++ b/fs/vfat/Makefile @@ -8,8 +8,8 @@ # 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 diff --git a/fs/vfat/namei.c b/fs/vfat/namei.c index 31d0c36fba35..25bb17b23ddf 100644 --- a/fs/vfat/namei.c +++ b/fs/vfat/namei.c @@ -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 + 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 +}; + 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; } diff --git a/fs/xiafs/file.c b/fs/xiafs/file.c index 8dd63f61a3b8..bd5f8d36ecfd 100644 --- a/fs/xiafs/file.c +++ b/fs/xiafs/file.c @@ -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. diff --git a/include/asm-i386/locks.h b/include/asm-i386/locks.h index bccac4eb4c81..357d309fa23c 100644 --- a/include/asm-i386/locks.h +++ b/include/asm-i386/locks.h @@ -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); diff --git a/include/asm-m68k/atomic.h b/include/asm-m68k/atomic.h index d65198fca729..8ea909203d7d 100644 --- a/include/asm-m68k/atomic.h +++ b/include/asm-m68k/atomic.h @@ -10,54 +10,32 @@ * 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; } diff --git a/include/asm-m68k/bitops.h b/include/asm-m68k/bitops.h index 5b618801c8c4..12c89df66ce4 100644 --- a/include/asm-m68k/bitops.h +++ b/include/asm-m68k/bitops.h @@ -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 diff --git a/include/asm-m68k/checksum.h b/include/asm-m68k/checksum.h index 4f9595ab1c61..eb9f6f74bfe8 100644 --- a/include/asm-m68k/checksum.h +++ b/include/asm-m68k/checksum.h @@ -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 */ diff --git a/include/asm-m68k/elf.h b/include/asm-m68k/elf.h index c6dc6569fd01..cb43d15743f1 100644 --- a/include/asm-m68k/elf.h +++ b/include/asm-m68k/elf.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 diff --git a/include/asm-m68k/pgtable.h b/include/asm-m68k/pgtable.h index 00c52e8745fd..7ec3d6f17cc2 100644 --- a/include/asm-m68k/pgtable.h +++ b/include/asm-m68k/pgtable.h @@ -14,7 +14,6 @@ do { \ __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 diff --git a/include/asm-m68k/serial.h b/include/asm-m68k/serial.h new file mode 100644 index 000000000000..a9a086fc3111 --- /dev/null +++ b/include/asm-m68k/serial.h @@ -0,0 +1,380 @@ +/* + * 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 +#include + +/* + * 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 */ diff --git a/include/asm-m68k/system.h b/include/asm-m68k/system.h index a7563e5ab7a1..242027ac9ca3 100644 --- a/include/asm-m68k/system.h +++ b/include/asm-m68k/system.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") diff --git a/include/asm-mips/shmparam.h b/include/asm-mips/shmparam.h index b2441c81a696..9c5a38a40039 100644 --- a/include/asm-mips/shmparam.h +++ b/include/asm-mips/shmparam.h @@ -39,7 +39,7 @@ #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 */ diff --git a/include/asm-sparc/floppy.h b/include/asm-sparc/floppy.h index 9fa5f63220eb..bf1f31afc7cb 100644 --- a/include/asm-sparc/floppy.h +++ b/include/asm-sparc/floppy.h @@ -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) { diff --git a/include/asm-sparc/head.h b/include/asm-sparc/head.h index 8e6aec9e65ff..06649881941a 100644 --- a/include/asm-sparc/head.h +++ b/include/asm-sparc/head.h @@ -90,7 +90,7 @@ #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 \ diff --git a/include/asm-sparc/kdebug.h b/include/asm-sparc/kdebug.h index ba71156665a4..346276959798 100644 --- a/include/asm-sparc/kdebug.h +++ b/include/asm-sparc/kdebug.h @@ -26,7 +26,7 @@ #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); diff --git a/include/asm-sparc/smp.h b/include/asm-sparc/smp.h index 1c5ab02a864b..e3d8ddb101a1 100644 --- a/include/asm-sparc/smp.h +++ b/include/asm-sparc/smp.h @@ -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]; diff --git a/include/asm-sparc/system.h b/include/asm-sparc/system.h index 4e9854d66d1f..5c2826d8c975 100644 --- a/include/asm-sparc/system.h +++ b/include/asm-sparc/system.h @@ -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. */ diff --git a/include/linux/a.out.h b/include/linux/a.out.h index 670349fc4ff6..b373e52d6378 100644 --- a/include/linux/a.out.h +++ b/include/linux/a.out.h @@ -129,7 +129,7 @@ enum machine_type { #ifdef linux #include -#ifdef __i386__ +#if defined(__i386__) || defined(__mc68000__) #define SEGMENT_SIZE 1024 #else #ifndef SEGMENT_SIZE diff --git a/include/linux/affs_fs.h b/include/linux/affs_fs.h index 68a8188fa59d..520935d2919a 100644 --- a/include/linux/affs_fs.h +++ b/include/linux/affs_fs.h @@ -1,101 +1,104 @@ - #ifndef _AFFS_FS_H #define _AFFS_FS_H - -#include /* * 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) +#include +#include #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 */ +#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 diff --git a/include/linux/affs_fs_i.h b/include/linux/affs_fs_i.h index 0e6298de4f98..62785ba3ea29 100644 --- a/include/linux/affs_fs_i.h +++ b/include/linux/affs_fs_i.h @@ -1,12 +1,25 @@ #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 diff --git a/include/linux/affs_fs_sb.h b/include/linux/affs_fs_sb.h index 377739d55665..8e708340169e 100644 --- a/include/linux/affs_fs_sb.h +++ b/include/linux/affs_fs_sb.h @@ -4,34 +4,63 @@ /* * super-block data in memory * - * Block numbers are for FFS-sized (normally 512 bytes) blocks. + * Block numbers are adjusted for their actual size * */ -/* Mount options */ +#include -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 */ +#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_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; + 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. */ }; -#endif - - - - - - +#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 diff --git a/include/linux/affs_hardblocks.h b/include/linux/affs_hardblocks.h new file mode 100644 index 000000000000..ea3cc5a328c6 --- /dev/null +++ b/include/linux/affs_hardblocks.h @@ -0,0 +1,70 @@ +#ifndef AFFS_HARDBLOCKS_H +#define AFFS_HARDBLOCKS_H + +/* Just the needed definitions for the RDB of an Amiga HD. */ + +#ifndef AMIGAFFS_H +#include +#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 */ diff --git a/include/linux/amigaffs.h b/include/linux/amigaffs.h new file mode 100644 index 000000000000..68a5dad7c85c --- /dev/null +++ b/include/linux/amigaffs.h @@ -0,0 +1,224 @@ +#ifndef AMIGAFFS_H +#define AMIGAFFS_H + +#include +#include + +/* 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 diff --git a/include/linux/genhd.h b/include/linux/genhd.h index a028fb2514ad..535cdefdc531 100644 --- a/include/linux/genhd.h +++ b/include/linux/genhd.h @@ -22,7 +22,7 @@ #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 diff --git a/include/linux/hdreg.h b/include/linux/hdreg.h index 4f49647cdf9b..4d33990c1ed1 100644 --- a/include/linux/hdreg.h +++ b/include/linux/hdreg.h @@ -8,7 +8,7 @@ #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 */ diff --git a/include/linux/if_arp.h b/include/linux/if_arp.h index 7f972a51b0e2..9e177e338c18 100644 --- a/include/linux/if_arp.h +++ b/include/linux/if_arp.h @@ -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 */ diff --git a/include/linux/if_frad.h b/include/linux/if_frad.h index 52afe58c8864..bacb44b9ad69 100644 --- a/include/linux/if_frad.h +++ b/include/linux/if_frad.h @@ -3,7 +3,7 @@ * 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 diff --git a/include/linux/in.h b/include/linux/in.h index c8e156e878cf..f839f98d451e 100644 --- a/include/linux/in.h +++ b/include/linux/in.h @@ -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 diff --git a/include/linux/isdn.h b/include/linux/isdn.h index 8e9c037fd770..bc33fa1771f4 100644 --- a/include/linux/isdn.h +++ b/include/linux/isdn.h @@ -184,7 +184,7 @@ typedef struct { #ifdef CONFIG_ISDN_PPP #ifdef CONFIG_ISDN_PPP_VJ -# include "/usr/src/linux/drivers/net/slhc.h" +# include #endif #include diff --git a/include/linux/isdnif.h b/include/linux/isdnif.h index ab8d35dd6033..875fc8148f9c 100644 --- a/include/linux/isdnif.h +++ b/include/linux/isdnif.h @@ -2,7 +2,7 @@ * * 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 { diff --git a/include/linux/kernel.h b/include/linux/kernel.h index e07049f6ad7a..cac9f5d12473 100644 --- a/include/linux/kernel.h +++ b/include/linux/kernel.h @@ -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) diff --git a/include/linux/math_emu.h b/include/linux/math_emu.h index 0d9606d9429c..b3708ef66b16 100644 --- a/include/linux/math_emu.h +++ b/include/linux/math_emu.h @@ -1,6 +1,10 @@ #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; diff --git a/include/linux/mc146818rtc.h b/include/linux/mc146818rtc.h index 55b535f3f846..2d438925d071 100644 --- a/include/linux/mc146818rtc.h +++ b/include/linux/mc146818rtc.h @@ -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 , 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 */ diff --git a/include/linux/mroute.h b/include/linux/mroute.h index 38aa312c3632..6772a60f8e60 100644 --- a/include/linux/mroute.h +++ b/include/linux/mroute.h @@ -112,7 +112,7 @@ struct igmpmsg }; /* - * Thats all usermode folks + * That's all usermode folks */ #ifdef __KERNEL__ diff --git a/include/linux/msdos_fs.h b/include/linux/msdos_fs.h index c5c5304024aa..ddc7ce9e6173 100644 --- a/include/linux/msdos_fs.h +++ b/include/linux/msdos_fs.h @@ -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 diff --git a/include/linux/netdevice.h b/include/linux/netdevice.h index 329787c3ba02..5b5919e58211 100644 --- a/include/linux/netdevice.h +++ b/include/linux/netdevice.h @@ -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. */ diff --git a/include/linux/skbuff.h b/include/linux/skbuff.h index 1ffa72947065..82b1c8103a90 100644 --- a/include/linux/skbuff.h +++ b/include/linux/skbuff.h @@ -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->datahead) - panic("skpush:under: %p:%d", __builtin_return_address(0),len); + { + __label__ here; + panic("skpush:under: %p:%d", &&here,len); +here: + } return skb->data; } diff --git a/include/linux/string.h b/include/linux/string.h index e9162b38c0b5..3b795a077c79 100644 --- a/include/linux/string.h +++ b/include/linux/string.h @@ -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 *); diff --git a/include/net/netlink.h b/include/net/netlink.h index b1412ea66a72..f907d4a6788f 100644 --- a/include/net/netlink.h +++ b/include/net/netlink.h @@ -2,7 +2,7 @@ #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 *); diff --git a/include/net/route.h b/include/net/route.h index b805f38bbb13..de59bda48cb4 100644 --- a/include/net/route.h +++ b/include/net/route.h @@ -62,120 +62,16 @@ #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 - -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; } diff --git a/drivers/net/slhc.h b/include/net/slhc_vj.h similarity index 100% rename from drivers/net/slhc.h rename to include/net/slhc_vj.h diff --git a/include/net/sock.h b/include/net/sock.h index e777d3cc5365..a9af984121a2 100644 --- a/include/net/sock.h +++ b/include/net/sock.h @@ -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. */ diff --git a/include/net/tcp.h b/include/net/tcp.h index fd0a4248a9a6..315ced5e3a2c 100644 --- a/include/net/tcp.h +++ b/include/net/tcp.h @@ -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) diff --git a/ipc/msg.c b/ipc/msg.c index 43a005d4bfa6..e62d9c4fa20c 100644 --- a/ipc/msg.c +++ b/ipc/msg.c @@ -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) { diff --git a/kernel/module.c b/kernel/module.c index edde5fbec3b3..4f7702b5c051 100644 --- a/kernel/module.c +++ b/kernel/module.c @@ -46,12 +46,6 @@ #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 */ diff --git a/kernel/sched.c b/kernel/sched.c index f58e7cea37ca..65aa995bd089 100644 --- a/kernel/sched.c +++ b/kernel/sched.c @@ -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<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 diff --git a/mm/filemap.c b/mm/filemap.c index f46751270a07..c3a1f86b26be 100644 --- a/mm/filemap.c +++ b/mm/filemap.c @@ -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; } diff --git a/mm/swapfile.c b/mm/swapfile.c index af842d892bcb..52f671555908 100644 --- a/mm/swapfile.c +++ b/mm/swapfile.c @@ -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; diff --git a/net/Changes b/net/Changes index 4bd4782336e5..170b25a8edaf 100644 --- a/net/Changes +++ b/net/Changes @@ -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]. diff --git a/net/TUNABLE b/net/TUNABLE index 28f98f6af632..bd6066126b72 100644 --- a/net/TUNABLE +++ b/net/TUNABLE @@ -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) diff --git a/net/ax25/af_ax25.c b/net/ax25/af_ax25.c index dd9f41ea1df5..f151fbbcd394 100644 --- a/net/ax25/af_ax25.c +++ b/net/ax25/af_ax25.c @@ -13,7 +13,7 @@ * 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 @@ -25,7 +25,7 @@ * 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 diff --git a/net/ax25/ax25_out.c b/net/ax25/ax25_out.c index 396c62c1e8d7..c81aabc16e08 100644 --- a/net/ax25/ax25_out.c +++ b/net/ax25/ax25_out.c @@ -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... */ diff --git a/net/ax25/ax25_subr.c b/net/ax25/ax25_subr.c index f06b1e4de86d..b2c837bb526a 100644 --- a/net/ax25/ax25_subr.c +++ b/net/ax25/ax25_subr.c @@ -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) { diff --git a/net/core/dev.c b/net/core/dev.c index d068ec47afe5..9598a098ce20 100644 --- a/net/core/dev.c +++ b/net/core/dev.c @@ -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; diff --git a/net/core/net_alias.c b/net/core/net_alias.c index 8870346e42c5..0a1785c1d5ae 100644 --- a/net/core/net_alias.c +++ b/net/core/net_alias.c @@ -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) diff --git a/net/ethernet/eth.c b/net/ethernet/eth.c index 8f4c003b6c8e..bc35bbb18bf8 100644 --- a/net/ethernet/eth.c +++ b/net/ethernet/eth.c @@ -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; diff --git a/net/ipv4/Config.in b/net/ipv4/Config.in index 7c88999a2502..fef49012e004 100644 --- a/net/ipv4/Config.in +++ b/net/ipv4/Config.in @@ -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 diff --git a/net/ipv4/arp.c b/net/ipv4/arp.c index 93fc8502e30f..5a127ab43d36 100644 --- a/net/ipv4/arp.c +++ b/net/ipv4/arp.c @@ -103,8 +103,8 @@ #include #endif #ifdef CONFIG_ARPD -#include -#endif /* CONFIG_ARPD */ +#include +#endif #include #include @@ -112,97 +112,157 @@ #include /* - * 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; inext) + 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;kdev->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; inext) + { +/* + * 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;kdev->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 +} diff --git a/net/ipv4/devinet.c b/net/ipv4/devinet.c index b761ba93f3c1..b10f205960cb 100644 --- a/net/ipv4/devinet.c +++ b/net/ipv4/devinet.c @@ -14,6 +14,8 @@ * Additional Authors: * Alan Cox, */ + +#include /* For CONFIG_IP_CLASSLESS */ #include #include @@ -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; } /* diff --git a/net/ipv4/igmp.c b/net/ipv4/igmp.c index f1dadbcee034..18383a84d86c 100644 --- a/net/ipv4/igmp.c +++ b/net/ipv4/igmp.c @@ -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) diff --git a/net/ipv4/ip_forward.c b/net/ipv4/ip_forward.c index 7e081403df0b..e71ab06f1dcc 100644 --- a/net/ipv4/ip_forward.c +++ b/net/ipv4/ip_forward.c @@ -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); diff --git a/net/ipv4/ip_fragment.c b/net/ipv4/ip_fragment.c index 919af64c8669..e5fc277aac09 100644 --- a/net/ipv4/ip_fragment.c +++ b/net/ipv4/ip_fragment.c @@ -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)) diff --git a/net/ipv4/ip_masq.c b/net/ipv4/ip_masq.c index 5b92ded4da74..e1ac232d903b 100644 --- a/net/ipv4/ip_masq.c +++ b/net/ipv4/ip_masq.c @@ -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); diff --git a/net/ipv4/ip_output.c b/net/ipv4/ip_output.c index 1bd4d37bd483..032563bb7388 100644 --- a/net/ipv4/ip_output.c +++ b/net/ipv4/ip_output.c @@ -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; } diff --git a/net/ipv4/ip_sockglue.c b/net/ipv4/ip_sockglue.c index 0fcb357304a1..157366716089 100644 --- a/net/ipv4/ip_sockglue.c +++ b/net/ipv4/ip_sockglue.c @@ -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); } diff --git a/net/ipv4/ipip.c b/net/ipv4/ipip.c index 200e561466d6..7b18ac107dce 100644 --- a/net/ipv4/ipip.c +++ b/net/ipv4/ipip.c @@ -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))protocol = htons(ETH_P_IP); + skb->ip_summed = 0; + netif_rx(skb); MOD_DEC_USE_COUNT; return(0); } diff --git a/net/ipv4/ipmr.c b/net/ipv4/ipmr.c index f4f2be1d93d1..c051043d88d8 100644 --- a/net/ipv4/ipmr.c +++ b/net/ipv4/ipmr.c @@ -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); diff --git a/net/ipv4/packet.c b/net/ipv4/packet.c index 9bec91e55269..de9844c26f51 100644 --- a/net/ipv4/packet.c +++ b/net/ipv4/packet.c @@ -5,7 +5,7 @@ * * 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. */ diff --git a/net/ipv4/proc.c b/net/ipv4/proc.c index 13e61b24fee4..5b9fc3c7e6e2 100644 --- a/net/ipv4/proc.c +++ b/net/ipv4/proc.c @@ -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(posoffset+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; } diff --git a/net/ipv4/raw.c b/net/ipv4/raw.c index 1f467fee28c2..191e00fbeb18 100644 --- a/net/ipv4/raw.c +++ b/net/ipv4/raw.c @@ -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 diff --git a/net/ipv4/route.c b/net/ipv4/route.c index 9f32196a478b..633cd2c4d9fd 100644 --- a/net/ipv4/route.c +++ b/net/ipv4/route.c @@ -320,42 +320,6 @@ static __inline__ struct device * get_gw_dev(__u32 gw) return NULL; } -/* - * 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); +} diff --git a/net/ipv4/tcp.c b/net/ipv4/tcp.c index f572acad4555..7fba12416051 100644 --- a/net/ipv4/tcp.c +++ b/net/ipv4/tcp.c @@ -172,7 +172,7 @@ * 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] diff --git a/net/ipv4/tcp_input.c b/net/ipv4/tcp_input.c index 17e81a215b93..37b2f8db1159 100644 --- a/net/ipv4/tcp_input.c +++ b/net/ipv4/tcp_input.c @@ -27,7 +27,7 @@ #include /* - * 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, diff --git a/net/ipv4/tcp_output.c b/net/ipv4/tcp_output.c index 760c225e5fc0..63517cd806bf 100644 --- a/net/ipv4/tcp_output.c +++ b/net/ipv4/tcp_output.c @@ -25,6 +25,68 @@ #include +/* + * 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.. */ diff --git a/net/ipx/af_ipx.c b/net/ipx/af_ipx.c index bb02473cff23..d4967b0679ab 100644 --- a/net/ipx/af_ipx.c +++ b/net/ipx/af_ipx.c @@ -44,6 +44,14 @@ * Revision 0.34: Module support. * Revision 0.35: Checksum support. , hooked in by * + * 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. * 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)); diff --git a/net/netrom/af_netrom.c b/net/netrom/af_netrom.c index b6ca49b29faf..ab1351396417 100644 --- a/net/netrom/af_netrom.c +++ b/net/netrom/af_netrom.c @@ -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) || diff --git a/net/socket.c b/net/socket.c index f5e9efb0a8da..653f9f615eaf 100644 --- a/net/socket.c +++ b/net/socket.c @@ -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, diff --git a/net/unix/af_unix.c b/net/unix/af_unix.c index eec7b1760235..4ed43a090d84 100644 --- a/net/unix/af_unix.c +++ b/net/unix/af_unix.c @@ -27,6 +27,7 @@ * 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; } diff --git a/scripts/Menuconfig b/scripts/Menuconfig index cfcf67f16a30..4bc4b9523fea 100644 --- a/scripts/Menuconfig +++ b/scripts/Menuconfig @@ -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 ] diff --git a/scripts/tkcond.c b/scripts/tkcond.c index d21170bf3e95..9cc10fa4f9f0 100644 --- a/scripts/tkcond.c +++ b/scripts/tkcond.c @@ -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; diff --git a/scripts/tkparse.c b/scripts/tkparse.c index 94181a12d611..2a000217c98e 100644 --- a/scripts/tkparse.c +++ b/scripts/tkparse.c @@ -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); -- 2.39.5