diff -u --recursive --new-file v2.1.9/linux/CREDITS linux/CREDITS
--- v2.1.9/linux/CREDITS	Tue Nov 12 15:56:01 1996
+++ linux/CREDITS	Wed Nov 13 08:11:16 1996
@@ -713,6 +713,10 @@
 S: L-4505 Differdange
 S: Luxembourg
 
+N: Gerd Knorr
+E: kraxel@cs.tu-berlin.de
+D: SCSI CD-ROM driver hacking, minor bug fixes
+
 N: Harald Koenig
 E: koenig@tat.physik.uni-tuebingen.de
 D: XFree86 (S3), DCF77, some kernel hacks and fixes
diff -u --recursive --new-file v2.1.9/linux/Documentation/Changes linux/Documentation/Changes
--- v2.1.9/linux/Documentation/Changes	Tue Nov 12 15:56:01 1996
+++ linux/Documentation/Changes	Wed Nov 13 08:22:15 1996
@@ -1,58 +1,39 @@
 Intro
 =====
 
-This document contains a list of the latest stable releases of the most
-important packages for Linux as well as instructions for newcomers to
-the 2.0.x series of kernels.  By glancing through it, you should be
-able to find out what you need to upgrade in order to successfully run
-the latest kernels.
-
-   It was originally based on material from the linux-kernel mailing
-list, Jared Mauch's web page "Software Victims of the 1.3 Kernel
-Development" (http://www2.nether.net/~jared/victim.html), and Axel
-Boldt's (boldt@math.ucsb.edu) Configure.help file, among other sources,
-and was originally written and maintained by Alessandro Sigala
-(ssigala@globalnet.it).
-
-   There is now a web page based on this material, thanks to John
-Taylor.  Check out http://www.cviog.uga.edu/LinuxBleed.html if you
-prefer a HTML-ized shopping list.
-
-   Para aquellos que prefieran una version en castellano de este
-documento, consultad la traduccion de Alfredo Sanjuan en
-http://slug.ctv.es/~alfredo/Cambios.html (Spanish translation).
-
-   Akik magyarul szeretnenek olvasni az uj kernellel kapcsolatos
-valtozasokrol, az alabbi cimen megtalaljak Nyitrai Tamas forditasat:
-http://www.datanet.hu/generations/linux/newkernel.html (Hungarian
-translation).
-
-   Tamas also maintains a version of this file at
-http://www.datanet.hu/generations/linux/Changes.html (English version).
-
-   For people who prefer Japanese (thanks to Mitsuhiro Kojima): Kono
-bunshou no nihongo ban wa
-http://jf.gee.kyoto-u.ac.jp/JF/v2.0/Changes-2.0.html ni arimasu.
+This document is designed to provide a list of the minimum levels of
+software necessary to run the 2.1.x kernels, as well as provide brief
+instructions regarding any other "Gotchas" users may encounter when
+trying life on the Bleeding Edge.  If upgrading from a pre-2.0.x
+kernel, please consult the Changes file included with 2.0.x kernels for
+additional information; most of that information will not be repeated
+here.  Basically, this document assumes that your system is already
+functional and running at least 2.0.x.
+
+   It is originally based on my "Changes" file for 2.0.x kernels and
+therefore owes credit to the same people as that file (Jared Mauch,
+Axel Boldt, Alessandro Sigala, and countless other users all over the
+'net).  Please feel free to submit changes, corrections, gripes,
+flames, money, etc. to me (gt1355b@prism.gatech.edu).  If you do so,
+you don't need to bother doing so in the form of a diff, as this is
+generated by texinfo so a diff is useless anyway (though I can
+incorporate one by hand if you insist upon sending it that way ;-).
 
-   Voyez le site http://www.linux-kheops.com/traduc/kernels/ pour la
-traduction francais (merci, David Bourgin).  (French translation)
-
-Last updated: November 5, 1996.
+Last updated: November 13, 1996.
 Current Author: Chris Ricker (gt1355b@prism.gatech.edu).
 
-Current Releases
-****************
+Current Minimal Requirements
+****************************
+
+   Upgrade to at *least* these software revisions before thinking you've
+encountered a bug!
 
 - Kernel modules	 2.0.0
-- PPP daemon		 2.2.0f
-- Dynamic linker (ld.so) 1.7.14
-- GNU CC		 2.7.2.1
+- Gnu C 		 2.7.2.1
 - Binutils		 2.7.0.3
-- Linux C Library	 Stable:  5.2.18, Beta:  5.4.10
+- Linux C Library	 5.4.12
 - Linux C++ Library	 2.7.2.1
-- Termcap		 2.0.8
 - Procps		 1.01
-- Gpm			 1.10
 - SysVinit		 2.64
 - Util-linux		 2.5
 - Mount                  2.5p
@@ -62,525 +43,27 @@
 Upgrade notes
 *************
 
-Network errors with recent kernels
-==================================
-
-   Many default network scripts are set up to add a route to the
-localhost at 127.0.0.1 at startup.  However, they do this incorrectly.
-To fix the error, which is now spotted by the kernel (causing many
-daemons to quit working), look for a line like `route add -net
-127.0.0.1' in your network configuration files and change it to `route
-add -net 127.0.0.0'.
-
-   This error is present in all Red Hat distributions through Red Hat
-3.03 (and derivative distributions like Caldera).  If you're running
-one of these, edit /etc/sysconfig/network-scripts/ifup-lo, changing the
-line `route add -net $(IPADDR)' to `route add -net 127.0.0.0' and you
-should be fine.
-
-   People have also reported problems due to the naming of the dummy
-network interface driver.  If the dummy driver is compiled into the
-kernel, its name is "dummy."  If the dummy driver is compiled as a
-module, its name is "dummy0."  Furthermore, more than one dummy driver
-can be loaded if compiled as a module.  Each subsequent loading of the
-driver adds a new dummy interface whose name is incremented by one
-("dummy1," "dummy2," etc.).
-
-Booting Changes
-===============
-
-   The boot support in 2.0.x (for arch/i386) has been enhanced so that
-it now can load bigger kernels (bzImage) and that the loaders now can
-load an initial ramdisk (initrd). For initrd see
-Documentation/initrd.txt. For building bigger kernels use one of the
-following make targets: bzImage, bzlilo, bzdisk (equivalent to make
-targets zImage, zlilo, and zdisk respectively). If you want or need to
-use the new features you'll need to upgrade your bootloaders.  Lilo can
-be found at ftp://lrcftp.epfl.ch/pub/linux/local/lilo/lilo.19.tar.gz.
-LOADLIN is at
-ftp://sunsite.unc.edu/pub/Linux/system/Linux-boot/lodlin16.tgz.  If
-you're using more unusual loaders like SysLinux or etherboot, the
-latest versions are 1.3 and 2.0, respectively.
-
-   Ramdisk support does not work with the latest kernels if ramdisk=0
-option is present.  Many older distributions (mainly Slackware) have
-this option in their lilo.config file.  Comment it out and re-run lilo
-if you need ramdisks.
-
-   The definition of SIOCSARP in /usr/include/linux/sockios.h was
-changed.  This means bootpd has to be re-compiled in order to work.
-
-   The kernel reboot method is now, by default, a cold reboot so that
-the kernel will work on systems that don't support other methods.  If
-you want to be able to do a warm reboot, add a reboot=warm option to
-lilo.conf.
-
-The Linux C Library
-===================
-
-   The latest stable Linux C Library release is 5.2.18.  If you upgrade
-to this from 5.0.9 or earlier, be sure to read the
-`release.libc-5.2.18' file, since GNU make and a few other fairly
-important utils can be broken by the upgrade.
-
-   The current (beta) Linux C Library release is 5.3.12. In this
-release there are some important changes that may cause troubles to
-buggy programs (programs that call free() on a pointer not returned by
-malloc() work with previous libc, but not with this release) so read the
-`release.libc-5.3.12' file carefully!  In the latest libc releases a
-dirent bug, which erroneously defined d->reclen to d->namlen if USE_GNU
-was defined, has been fixed.  Unfortunately, some GNU packages depend
-on this bug.  GNU make 3.xx is one of them.  To fix that you need to
-patch and recompile those programs (a patch for make is included in the
-file `release.libc-.5.3.9', and the address to obtain a precompiled
-binary is at the end of this file).
-
-   Also, the libc-5.3.x line has a known security hole relating to
-rlogin.  Libc-5.3.12 fixes this, so if you're going to run an
-experimental libc, be sure to upgrade to 5.3.12.  Libc-5.4.10 is
-currently available as well, but it may have problems, so caveat emptor.
-
-   If you're getting an error message that is something to the effect of
-
-   `fcntl_setlk() called by process 123 with broken flock() emulation'
-
-   then you need to upgrade to at least libc-5.2.18 as well.  A proper
-(in other words, BSD-style ;-) flock system call was added to 2.0.x,
-and older libc's will now give this error.  It doesn't *really* matter,
-so you can just ignore it. If it really annoys you, upgrade libc (and
-recompile any static binaries you might have that are linked against
-the old libc).  If you're feeling lazy, just comment out
-
-   `                printk(KERN_WARNING
-"fcntl_setlk() called by process %d with broken flock()
-  emulation\n",                        current->pid);'
-
-   in linux/fs/locks.c and recompile.  If you're still running a.out,
-there's an unofficial libc-4.7.6 release out to which you can upgrade
-to fix this problem.  Libc is available from
-ftp://sunsite.unc.edu/pub/Linux/GCC/.
-
-GCC Signal 11 error
-===================
-
-   Many people have been reporting messages like the following,
-especially when compiling a new kernel:
-
-   `gcc:  Internal compiler error:  program cc1 got fatal signal 11'.
-
-   This is NOT a kernel bug.  Rather, these messages are generally
-caused by hardware problems.  See http://www.bitwizard.nl/sig11/ for
-the sig11 FAQ.
-
-   On the other hand, if you're using a gcc patched for Pentium
-optimization and are getting these errors, downgrade to a standard GNU
-gcc before assuming your hardware (or the kernel) is to blame.
-
-   On a related note, if you get random OOPses that don't seem to be
-related to anything and you have a motherboard with APM support, try
-disabling the APM support and/or compiling the kernel with APM support.
-
-Procps utilities
-================
-
-   Due to changes in the structure of the /proc filesystem, you need to
-upgrade procps to the latest release, currently 1.01.  Otherwise,
-you'll get floating point errors with some ps commands or other similar
-surprises.  Grab
-ftp://sunsite.unc.edu/pub/Linux/system/Status/ps/procps-1.01.tgz.
-
-Kernel Modules
-==============
-
-   Almost all drivers in 2.0.x can be modules, and kerneld is now
-incorporated into the kernel.  To take advantage of this, you'll need
-the latest version of the module support apps. These are available at
-http://www.pi.se/blox/modules/modules-2.0.0.tar.gz.  Note: If you try to
-load a module and get a message like
-
-   `gcc2_compiled, undefined Failed to load module!  The symbols from
-kernel 1.3.foo don't match 1.3.foo'
-
-   where `foo' is a number for a recent kernel, then it's definitely
-time to upgrade module utilities.
-
-   Another little tip: you can't have both a.out *and* ELF support
-compiled as modules.  Otherwise, you get a nice Catch-22 when you try
-to run insmod to install a.out/ELF support so you can run insmod ;-).
-If you have an all-ELF system, but need a.out for the occasional legacy
-app, then you can do a.out support as a module.  Otherwise, you should
-probably leave it in the kernel, and if you haven't gone ELF yet, you
-can probably say no to ELF support.  Similarly, any partitions that you
-have to mount at startup have to have their necessary file system and
-device drivers compiled into the kernel, so don't get grandiose ideas
-about going completely modular and then forget to compile ext2fs
-support and ide/SCSI drive support into your kernel ;-).
-
-Kernel messages
-===============
-
-   Kernel messages without a specific log level use the kernel's
-default log level.  In 1.2 kernels, the default log level was 6
-(information), while in 2.0.x kernels it is 4 (warning).  Adjust your
-configuration of syslogd appropriately (or edit printk.c in the kernel
-source ;-).
-
-PPP driver
-==========
-
-   You need to be running a pppd from ppp-2.2.0.tar.gz or greater.  The
-latest stable release is 2.2.0f and is available at
-ftp://sunsite.unc.edu/pub/Linux/system/Network/serial/ppp/ppp-2.2.0f.tar.gz.
-
-Named pipes (SysVinit)
-======================
-
-   Linux's handling of named pipes changed (it now does it The Right Way
-instead of the SunOS way ;-).  This broke some programs that depended
-on the SunOS behavior, most notably SysVinit.  If you're running 2.59
-or earlier, you will probably get a weird error on shutdown in which
-your computer shuts down fine but "INIT: error reading initrequest" or
-words to that effect scroll across your screen hundreds of times.  To
-fix, upgrade to
-ftp://sunsite.unc.edu/pub/Linux/system/Daemons/init/sysvinit-2.64.tar.gz.
-
-   If you're trying to run NCSA httpd, you might have problems with
-pre-spawning daemons.  Upgrade to the latest release (1.5.2), available
-from http://hoohoo.ncsa.uiuc.edu/ or check out Apache
-(http://www.apache.org/).
-
-   The new named pipe behavior also causes problems with Hylafax.  If
-you're running the hylafax daemon, it will just keep eating up CPU time
-until you have no idle time free.  To fix this, edit port.h included
-with the Hylafax distribution and change the line
-
-   CONFIG_OPENFIFO="O_RDONLY"
-
-   to
-
-   CONFIG_OPENFIFO="O_RDWR"
-
-   A similar method (finding all named pipes opened read-only and
-changing them to read-write) will fix any program that is broken
-because of this change.
-
-File Locking (Sendmail)
-=======================
-
-   As of pre2.0.6 (aka 1.99.6), mixed-style file locking is no longer
-allowed.  For example, a file cannot be simultaneously locked with
-`flock' and `fcntl'.  See Documentation/locks.txt for all the gory
-details.  Among the programs this has impacted are older sendmails.  If
-you get a message that sendmail cannot lock aliases.dir (or other
-files), you'll need to upgrade to at least 8.7.x. The latest sendmail
-is at ftp://ftp.cs.berkeley.edu/ucb/src/sendmail/sendmail.8.8.2.tar.gz.
-
-Uugetty
-=======
-
-   Older uugettys will not allow use of a bidirectional serial line.  To
-fix this problem, upgrade to
-ftp://sunsite.unc.edu/pub/Linux/system/Serial/getty_ps-2.0.7i.tar.gz.
-
-Kbd
-===
-
-   For those of you needing non-ASCII character/font support, you should
-upgrade to ftp.funet.fi:/pub/OS/Linux/PEOPLE/Linus/kbd-0.91.tar.gz.
-
-Mount
-=====
-
-   The mount util is distributed as part of util-linux, which is
-currently at release 2.5.  Some may find, especially when using the
-loop or xiafs file system, NFS, or automounting, that they need to
-upgrade to the latest release of mount, available from
-ftp://ftp.win.tue.nl/pub/linux/util/mount-2.5p.tar.gz.
-
-Console
-=======
-
-   The Linux console type has changed.  If your setup is old enough
-that you have problems, you'll need to update your termcap.  To fix,
-add linux to one of the types in /etc/termcap or snoop around
-http://www.ccil.org/~esr/ncurses.html (reputedly the latest universal
-termcap maintainer).  You may also need to update terminfo by running
-the following as root:
-
-   ln -s /usr/lib/terminfo/l/linux /usr/lib/terminfo/c/console
-
-   Better yet, just get the latest official Linux termcap from
-ftp://sunsite.unc.edu/pub/Linux/GCC/termcap-2.0.8.tar.gz.  If you
-upgrade to this release read the `README' file contained into the
-package to get some important information about the `tgetent' function
-changes!  Note that there is now a fixed version at
-ftp://sunsite.unc.edu/pub/Linux/GCC/termcap-2.0.8.fix.  If some of your
-apps complain that termcap entries are too long and you don't need some
-of the more esoteric terms in the standard 2.0.8 termcap, just download
-termcap-2.0.8.fix and move it to /etc/termcap.
-
-   Also, the console driver is now responsible for keeping track of
-correspondence between character codes and glyph bitmaps.  If you
-encounter problems, try `loadunimap def' to get back the default
-correspondence.
-
-Hdparm
-======
-
-   Hdparm has been upgraded to take advantage of the latest features of
-the kernel drivers.  The latest non-beta version can be found at
-ftp://sunsite.unc.edu/pub/Linux/kernel/patches/diskdrives/hdparm-3.1.tar.gz.
-
-IP Accounting
-=============
-
-   All IP packets coming in or going out via one of the network
-interfaces are now passing the accounting chain.  So, packets being
-forwarded are passing this chain twice.  Since pre2.0.7 (aka 1.99.7),
-accounting rules can be defined so that they will only match in one
-direction (either incoming or outgoing).
-
-   There also exists a possibility to match on device names and/or
-device addresses, so that only packets coming in/going out via that
-device (network interface) match with a rule.  You'll need to get
-ipfwadm from ftp://ftp.xos.nl/pub/linux/ipfwadm/ipfwadm-2.3.0.tar.gz to
-use this.
-
-IP Firewalls
-============
-
-   The IP firewall code has been changed drastically for 2.0.x. There
-are now 3 categories of firewall rules: one for incoming packets, one
-for outgoing packets, and one for packets being forwarded.  There also
-exists a possibility to match on device names and/or device addresses,
-so that only packets coming in/going out via that device (network
-interface) match with a rule.  This is especially useful to prevent
-spoofing.  You'll need to get
-ftp://ftp.xos.nl/pub/linux/ipfwadm/ipfwadm-2.3.0.tar.gz to use this.
-
-IP Masquerading
-===============
-
-   IP masquerading is now part of the standard kernel.  However, you
-always need to load separate modules (ip_masq_ftp.o and/or
-ip_masq_irc.o) if you are going to use FTP or IRC in combination with
-masquerading.  You'll need to get
-ftp://ftp.xos.nl/pub/linux/ipfwadm/ipfwadm-2.3.0.tar.gz to use this.
-
-ISDN support
-============
-
-   The new kernels support ISDN.  You'll need ISDN utils available from
-ftp://ftp.franken.de/pub/isdn4linux/v2.0/isdn4k-utils-2.0.tar.gz to try
-this.
-
-Frame Relay
-===========
-
-   Frame relay support for Linux is now available as well.  Currently,
-only Sangoma cards are supported, but the interface is such that others
-will be as drivers become available.  To use this, grab
-ftp://linux.invlogic.com/pub/fr/frad-0.15.tgz (soon to be
-frad-0.20.tgz).  Another package of interest is
-ftp://linux.invlogic.com/pub/routing/routing.tgz (which allows Linux to
-make routing decisions based on packet source).
-
-Networking
-==========
-
-   Some of the /proc/net entries have changed.  You'll need to upgrade
-to the latest net-tools in
-ftp://ftp.inka.de/pub/comp/Linux/networking/NetTools/, where the latest
-is currently net-tools-1.32-alpha.tar.gz.  See
-http://www.inka.de/sites/lina/linux/NetTools/index_en.html for more
-information.  Note that there is currently no ipfw (which is part of
-net-tools) which works with 2.0.x kernels.  If you need its functions,
-learn how to use ipfwadm or patch ipfw to get it to work (ipfw's current
-maintainer does not currently have time to fix it).
-
-Xntpd
-=====
-
-   Older versions of xntpd will not work with the latest kernels.
-Upgrade to xntp3.5f.tar.Z, available from
-ftp://louie.udel.edu/pub/ntp/xntp3.5f.tar.Z.
-
-Sound driver
-============
-
-   The sound driver was upgraded in the 2.0.x kernels, breaking vplay.
-To fix this problem, get a new version of the sndkit from
-ftp://ftp.best.com/pub/front/tasd/snd-util-3.5.tar.gz.  Some users
-report that various other sound utils (cdd2wav-sbpcd, for example) need
-to be recompiled before they will work with the new kernels.
-
-Tcsh
-====
-
-   If tcsh acts funny, get the source from
-ftp://anise.ee.cornell.edu/pub/tcsh and add #define SYSMALLOC in
-config_f.h before recompiling tcsh.  Binaries can be found in
-ftp://sunsite.unc.edu/pub/Linux/system/Shells/ and a corrected one will
-probably wind up there eventually.
-
-Make
-====
-
-   If make no longer works, you need to read the release notes for the
-libc you upgraded to.  The latest libc and release notes can be found at
-ftp://tsx-11.mit.edu/pub/linux/packages/GCC.  This is NOT an error due
-to the kernel, though many people have mistakenly thought it is.  When
-you upgrade to libc-5.3.9, you have to patch make to get it to work.
-All of this is documented in the release notes with libc.  Upgrading
-libc can also break xterm support.  If it does, you need to recompile
-xterm.
-
-Loop device
-===========
-
-   2.0.x kernels include loop device support which lets you mount a
-file as a file system, which can allow for all sorts of cool things
-like encrypted file systems and such.  To use it, you'll need a
-modified version of mount from
-ftp://ftp.win.tue.nl/pub/linux/util/mount-2.5k.tar.gz; preliminary work
-on encrypted file system support can be found in
-ftp.funet.fi:/pub/Linux/BETA/loop/des.1.tar.gz.
-
-Multiple device
-===============
-
-   Multiple device support (allowing you to group several partitions
-into one logical device) has also been added.  Check out
-ftp://sweet-smoke.ufr-info-p7.ibp.fr/pub/Linux/md035.tar.gz to try this
-out.
-
-Arp
-===
-
-   Arp daemon support has been added.  Check out
-http://www.loran.com/~layes/arpd/index.html for more info and
-http://www.loran.com/~layes/arpd/arpd-1.0.2.tar.gz for a copy of arpd.
-
-Quota
-=====
-
-   Quota support has also been added.  You need to get quotas-1.55 from
-ftp://ftp.funet.fi/pub/Linux/kernel/src/subsystems/quota/all.tar.gz. You
-may need to copy its mntent.h over to /usr/include/mntent.h to get it to
-compile.
-
-Process Accounting
-==================
-
-   Process accounting support has also been integrated into the new
-kernels. To use this feature, you'll need to get
-ftp://iguana.hut.fi/pub/linux/Kernel/process_accounting/acct_1.3.73.tar.gz.
-
-Bdflush and Updated
+General Information
 ===================
 
-   Bdflush has also been integrated into the new kernels, so those of
-you using it on older systems no longer need to hunt for the patches to
-implement it once you upgrade to 2.0.x.  You do still need to run the
-update daemon, however.  You should probably upgrade to the latest
-updated, currently
-ftp://sunsite.unc.edu/pub/Linux/system/Daemons/updated-1.2.tar.gz.  This
-(and later) versions will not spawn a bdflush daemon, since that is now
-done by the kernel (kflushd).  If you upgrade, be sure to leave update
-in your init scripts and remove bdflush.
-
-APM support
-===========
-
-   Advanced Power Management (APM) support has been added to the kernel
-as well.  APM, which is primarily of use in laptops, provides access to
-battery status information and may help to conserve battery power.  The
-support files can be found in
-ftp://tsx-11.mit.edu/pub/linux/packages/laptops/apm/apmd-2.4.tar.gz
-
-iBCS and Dosemu
-===============
-
-   For a version of iBCS that works with 2.0.x kernels, grab
-ftp://tsx-11.mit.edu/pub/linux/BETA/ibcs2/ibcs-2.0-960610.tar.gz
+   <CTRL><ALT><DEL> now performs a cold reboot instead of a warm reboot
+for increased hardware compatibility.  If you want a warm reboot and
+know it works on your hardware, add a "reboot=warm" command line option
+in Lilo.
 
-   For a version of Dosemu that works (well, at least as well as DOS
-ever works ;-), get
-ftp://tsx-11.mit.edu/pub/linux/ALPHA/dosemu/Development/dosemu-0.64.0.3.tgz
-or check out http://www.ednet.ns.ca/auto/rddc. Be sure to follow the
-instructions in README.newkernels about patching your include files, or
-it will not compile.
-
-Mtools and Fdutils
-==================
-
-   The floppy ioctl numbering scheme has changed for 2.0.x.  For
-backwards compatibility, the old system was supported through 1.3.x and
-will generate a warning in 2.0.  In 2.1.x, the old scheme will
-disappear entirely.
-
-   To avoid trouble (or at least annoying messages), you'll need to
-recompile any programs which emit floppy ioctls, including mtools and
-fdutils.  For mtools, get
-ftp://sunsite.unc.edu/pub/Linux/utils/disk-management/mtools-3.0.src.tar.gz
-and for fdutils, get
-ftp://sunsite.unc.edu/pub/Linux/system/Misc/fdutils-4.3.src.tar.gz.
-
-   In the future, fdformat might disappear entirely, so get used to
-using superformat instead.
-
-Cyclades Serial Driver
-======================
-
-   The Cyclades driver has been changed so that the minor numbers start
-at 0 instead of 32 (for example, ttyC0 should be major 19, minor 0 for
-2.0.x kernels; in older kernels, it would have been major 19, minor
-32).  Use mknod or a sufficiently new version of MAKEDEV to fix this.
-
-NCR 53c810 SCSI Driver
-======================
-
-   Drivers for this card are now included in the standard linux source.
-However, they require Perl to be installed before they will compile.
-As far as I know, this is the only code in the kernel source that
-requires Perl to compile.  If your kernel compile fails and you happen
-to have included this driver in your configuration, make sure you have
-Perl installed.
-
-Perl
+Libc
 ====
 
-   While we're on the subject, changes made for the 2.0.x series cause
-the connect() Perl (both 4 and 5) call to time out while connecting to
-remote systems.  The problem is not actually in the connect() call;
-rather, the optional bind() call usually used with connect() causes the
-problem.  Remove the bind() call and your Perl scripts should connect.
-
-   Also, Perl scripts using the readdir call now misbehave if you're
-using an old version of Perl, due to changes in libc.  Upgrade to a
-more current Perl to avoid any unpleasantness.
-
-Groff
-=====
-
-   Those of you running Slackware may experience weirdness with man
-pages due to changes in groff.  If your man pages display <AD> for -
-when present at the end of a line, try setting an appropriate value
-(many have reported success with "latin1", for example) for the
-environmental variable LESSCHARSET.  Another, and probably better,
-solution is to edit the file /usr/lib/man.config and change all
-`-Tlatin1' options to `-Tascii'.  An alternate solution, for those of
-you who can't reformat your man files in .../cat* directories is to
-edit /usr/lib/man.config, setting the PAGER to `PAGER
-(LESSCHARSET=latin1;export LESSCHARSET;/usr/bin/less -is)'.
-
-E2fsprogs
-=========
-
-   e2fsprogs 1.02 will work with the latest kernels, but it cannot be
-compiled on them.  If you need (or want) to compile your own copy,
-you'll need to get the latest version, currently available at
-ftp://tsx-11.mit.edu/pub/linux/packages/ext2fs/e2fsprogs-1.06.tar.gz.
+   Linux-2.1.x is ELF-only.  You can still compile a.out apps if you
+really want, but your kernel must be compiled ELF.  If you can't
+currently compile ELF, consult the ELF howto at
+http://sunsite.unc.edu/mdw/HOWTO/ELF-HOWTO.html and upgrade your system
+accordingly.
+
+   For modules to work, you need to be running libc-5.4.7 or greater.
+Since updates to libc fix other problems as well (security flaws, for
+example) and since 5.4.7 is missing a few needed symbols, try to get
+the latest 5.4.x you can.  Currently, that is libc-5.4.12.
 
 How to know the version of the installed programs
 *************************************************
@@ -589,13 +72,10 @@
 installed programs and libraries.  The SysVinit version display
 requires that you be logged in as root.
 
-GNU CC: gcc -v and gcc --version
-PPP: pppd -h (wrong but it show the version)
-Libc: ls -l /lib/libc.so.5
-Libc++: ls -l /usr/lib/libg++.so
+Gnu C: gcc -v or gcc --version
+Libc: ls -l /lib/libc.so.*
+Libc++: ls -l /usr/lib/libg++.so.*
 Binutils: ld -v
-ldd: ldd -v and ldd -V
-termcap: ls -l /lib/libtermcap.so.*
 modules: insmod -V
 procps: ps --version
 SysVinit: cat /proc/`cat /var/run/syslog.pid`/environ|strings|awk '$1 ~
@@ -611,8 +91,8 @@
 Installation notes:
 ftp://tsx-11.mit.edu:/pub/linux/packages/GCC/release.binutils-2.7.0.3
 
-GNU CC
-======
+Gnu C
+=====
 
 ftp://sunsite.unc.edu/pub/Linux/GCC/gcc-2.7.2.1.bin.tar.gz
 Installation notes:
@@ -626,15 +106,10 @@
 Installation notes for 5.2.18:
 ftp://sunsite.unc.edu/pub/Linux/GCC/release.libc-5.2.18
 
-The latest 5.4.10 release:
-ftp://sunsite.unc.edu/pub/Linux/GCC/libc-5.4.10.bin.tar.gz
-Installation notes for 5.4.10:
-ftp://sunsite.unc.edu/pub/Linux/GCC/release.libc-5.4.10
-
-Patched make sources:
-ftp://sunsite.unc.edu/pub/Linux/devel/make/make-3.74.patched.tar.gz
-Patched make binary:
-ftp://sunsite.unc.edu/pub/Linux/devel/make/make-3.74-direntfix-elf.tgz
+The latest 5.4.12 release (when it gets there):
+ftp://sunsite.unc.edu/pub/Linux/GCC/libc-5.4.12.bin.tar.gz
+Installation notes for 5.4.12:
+ftp://sunsite.unc.edu/pub/Linux/GCC/release.libc-5.4.12
 
 Linux C++ Library
 =================
@@ -648,34 +123,16 @@
 
 ftp://sunsite.unc.edu/pub/Linux/GCC/ld.so-1.7.14.tar.gz
 
-Termcap Library
-===============
-
-ftp://sunsite.unc.edu/pub/Linux/GCC/termcap-2.0.8.tar.gz
-
 Modules utilities
 =================
 
-The latest public release:
 ftp://sunsite.unc.edu/pub/Linux/kernel/modules-2.0.0.tar.gz
 
-PPP Daemon and utilities
-========================
-
-The latest public release:
-ftp://sunsite.unc.edu/pub/Linux/system/Network/serial/ppp/ppp-2.2.0f.tar.gz
-
 Procps utilities
 ================
 
 ftp://sunsite.unc.edu/pub/Linux/system/Status/ps/procps-1.01.tgz
 
-Gpm mouse utilities
-===================
-
-ftp://iride.unipv.it/pub/gpm/gpm-1.10.tar.gz
-ftp://sunsite.unc.edu/pub/Linux/system/Daemons/gpm-1.10.tar.gz
-
 SysVinit utilities
 ==================
 
@@ -686,16 +143,6 @@
 
 ftp://sunsite.unc.edu/pub/Linux/system/Misc/util-linux-2.5.tar.gz
 
-Mtools
-======
-
-ftp://sunsite.unc.edu/pub/Linux/utils/disk-management/mtools-3.0.src.tar.gz
-
-Fdutils
-=======
-
-ftp://sunsite.unc.edu/pub/Linux/system/Misc/fdutils-4.3.src.tar.gz
-
 Other Info
 ==========
 
@@ -708,20 +155,14 @@
 your favorite Red Hat mirror site before installing the non-RPM
 version.  Remember, you might need to use the -force option to get the
 upgrade to install.  Almost everything you need is available in
-ftp://ftp.redhat.com/pub/current/i386/updates/2.0-kernel/ and its
-mirrors.
+ftp://ftp.redhat.com/pub/contrib/
 
    For others, David Bourgin has put together a package of everything
-necessary to quickly and easily upgrade to 2.0.x.  See
-ftp://ftp.wsc.com/pub/freeware/linux/update.linux/ for more information
-and the files.  This package also includes many bug-fixes, such as the
-latest sendmail. There's also an alternate lightweight termcap in the
-same directory that works well for many people.
-
-Please send info about any other packages that 2.0.x "broke" or about
-any new features of 2.0.x that require extra or new packages for use to
-Chris Ricker (gt1355b@prism.gatech.edu).  I generate this from a
-modified texinfo setup, so you don't need to bother generating a diff
-against the current version before you send the additional information
-to me.
+necessary to quickly and easily upgrade to 2.1.x.  See
+ftp://ftp.wsc.com/pub/freeware/linux/update.linux/kernel-v2.1.x/ for
+more information and the files.
+
+Please send info about any other packages that 2.1.x "broke" or about
+any new features of 2.1.x that require extra or new packages for use to
+Chris Ricker (gt1355b@prism.gatech.edu).
 
diff -u --recursive --new-file v2.1.9/linux/Documentation/Configure.help linux/Documentation/Configure.help
--- v2.1.9/linux/Documentation/Configure.help	Tue Nov 12 15:56:01 1996
+++ linux/Documentation/Configure.help	Wed Nov 13 08:11:17 1996
@@ -1243,6 +1243,13 @@
   say M here and read Documentation/modules.txt and
   Documentation/scsi.txt .
 
+Enable vendor-specific extentions (for SCSI CDROM)
+CONFIG_BLK_DEV_SR_VENDOR
+  This enables the usage of vendor specific SCSI commands. This is
+  required for some stuff which is newer than the SCSI-II standard,
+  most important is the multisession CD support. You'll probably want
+  to say y here, unless you have a _real old_ CD-ROM drive.
+
 SCSI generic support
 CONFIG_CHR_DEV_SG
   If you want to use SCSI scanners, synthesizers or CD-writers or just
diff -u --recursive --new-file v2.1.9/linux/Documentation/devices.tex linux/Documentation/devices.tex
--- v2.1.9/linux/Documentation/devices.tex	Mon Sep  2 08:41:25 1996
+++ linux/Documentation/devices.tex	Fri Nov 15 13:01:14 1996
@@ -42,7 +42,7 @@
 %
 \title{{\bf Linux Allocated Devices}}
 \author{Maintained by H. Peter Anvin $<$hpa@zytor.com$>$}
-\date{Last revised: July 9, 1996}
+\date{Last revised: November 13, 1996}
 \maketitle
 %
 \noindent
@@ -179,7 +179,11 @@
 \major{52}{}{char }{Spellcaster DataComm/BRI ISDN card}
 \major{53}{}{char }{BDM interface for remote debugging MC683xx microcontrollers}
 \major{54}{}{char }{Electrocardiognosis Holter serial card}
-\major{55}{--59}{}{Unallocated}
+\major{55}{}{char }{DSP56001 digital signal processor}
+\major{56}{}{char }{Apple Desktop Bus}
+\major{57}{}{char }{Hayes ESP serial card}
+\major{58}{}{char }{Hayes ESP serial card -- alternate devices}
+\major{59}{}{}{Unallocated}
 \major{60}{--63}{}{Local/experimental use}
 \major{64}{--119}{}{Unallocated}
 \major{120}{--127}{}{Local/experimental use}
@@ -453,6 +457,7 @@
 	\minor{5}{/dev/atarimouse}{Atari mouse}
 	\minor{6}{/dev/sunmouse}{Sun mouse}
 	\minor{7}{/dev/amigamouse1}{Second Amiga mouse}
+	\minor{8}{/dev/smouse}{Simple serial mouse driver}
 	\minor{128}{/dev/beep}{Fancy beep device}
 	\minor{129}{/dev/modreq}{Kernel module load request}
 	\minor{130}{/dev/watchdog}{Watchdog timer port}
@@ -1116,7 +1121,35 @@
 heart monitoring equipment.
 
 \begin{devicelist}
-\major{55}{--59}{}{Unallocated}
+\major{55}{}{char }{DSP56001 digital signal processor}
+	\minor{0}{/dev/dsp56k}{First DSP56001}
+\end{devicelist}
+
+\begin{devicelist}
+\major{56}{}{char }{Apple Desktop Bus}
+	\minor{0}{/dev/adb}{ADB bus control}
+\end{devicelist}
+
+\noindent
+Additional devices will be added to this number, all starting with
+{\file /dev/adb}.
+
+\begin{devicelist}
+\major{57}{}{char }{Hayes ESP serial card}
+	\minor{0}{/dev/ttyP0}{First ESP port}
+	\minor{1}{/dev/ttyP1}{Second ESP port}
+	\minordots
+\end{devicelist}
+
+\begin{devicelist}
+\major{58}{}{char }{Hayes ESP serial card -- alternate devices}
+	\minor{0}{/dev/cup0}{Callout device corresponding to {\file ttyP0}}
+	\minor{1}{/dev/cup1}{Callout device corresponding to {\file ttyP1}}
+	\minordots
+\end{devicelist}
+
+\begin{devicelist}
+\major{59}{}{}{Unallocated}
 \end{devicelist}
 
 \begin{devicelist}
@@ -1182,9 +1215,9 @@
 \link{/dev/ramdisk}{ram0}{symbolic}{Backward compatibility}
 \link{/dev/ftape}{rft0}{symbolic}{Backward compatibility}
 \link{/dev/scd?}{sr?}{hard}{Alternate name for CD-ROMs}
-%\link{/dev/fd?H*}{fd?D*}{hard}{Compatible floppy formats}
-%\link{/dev/fd?E*}{fd?D*}{hard}{Compatible floppy formats}
-%\link{/dev/fd?E*}{fd?H*}{hard}{Compatible floppy formats}
+\link{/dev/fd?D*}{fd?u*}{hard}{Backward compatibility}
+\link{/dev/fd?H*}{fd?u*}{hard}{Backward compatibility}
+\link{/dev/fd?E*}{fd?u*}{hard}{Backward compatibility}
 \end{nodelist}
 
 \subsection{Locally defined links}
diff -u --recursive --new-file v2.1.9/linux/Documentation/devices.txt linux/Documentation/devices.txt
--- v2.1.9/linux/Documentation/devices.txt	Wed Jul 10 13:11:44 1996
+++ linux/Documentation/devices.txt	Fri Nov 15 13:01:14 1996
@@ -2,7 +2,7 @@
 
 	     Maintained by H. Peter Anvin <hpa@zytor.com>
 
-		     Last revised: July 9, 1996
+		   Last revised: November 13, 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
@@ -269,6 +269,7 @@
 		  5 = /dev/atarimouse	Atari mouse
 		  6 = /dev/sunmouse	Sun mouse
 		  7 = /dev/amigamouse1	Second Amiga mouse
+		  8 = /dev/smouse	Simple serial mouse driver
 		128 = /dev/beep		Fancy beep device
 		129 = /dev/modreq	Kernel module load request
 		130 = /dev/watchdog	Watchdog timer port
@@ -785,7 +786,26 @@
 		<mseritan@ottonel.pub.ro> to transfer data from Holter
 		24-hour heart monitoring equipment.
 
- 55-59		UNALLOCATED
+ 55 char	DSP56001 digital signal processor
+		  0 = /dev/dsp56k	First DSP56001
+
+ 56 char	Apple Desktop Bus
+		  0 = /dev/adb		ADB bus control
+
+		Additional devices will be added to this number, all
+		starting with /dev/adb.
+
+ 57 char	Hayes ESP serial card
+		  0 = /dev/ttyP0	First ESP port
+		  1 = /dev/ttyP1	Second ESP port
+		      ...
+
+ 58 char	Hayes ESP serial card - alternate devices
+		  0 = /dev/cup0		Callout device corresponding to ttyP0
+		  1 = /dev/cup1		Callout device corresponding to ttyP1
+		      ...
+
+ 59		UNALLOCATED
 
  60-63		LOCAL/EXPERIMENTAL USE
 		Allocated for local/experimental use.  For devices not
diff -u --recursive --new-file v2.1.9/linux/Makefile linux/Makefile
--- v2.1.9/linux/Makefile	Tue Nov 12 15:56:02 1996
+++ linux/Makefile	Wed Nov 13 11:07:40 1996
@@ -1,6 +1,6 @@
 VERSION = 2
 PATCHLEVEL = 1
-SUBLEVEL = 9
+SUBLEVEL = 10
 
 ARCH = i386
 
@@ -285,6 +285,7 @@
 	if [ -f BLOCK_MODULES ]; then inst_mod BLOCK_MODULES block; fi; \
 	if [ -f NET_MODULES   ]; then inst_mod NET_MODULES   net;   fi; \
 	if [ -f IPV4_MODULES  ]; then inst_mod IPV4_MODULES  ipv4;  fi; \
+	if [ -f IPV6_MODULES  ]; then inst_mod IPV6_MODULES  ipv6;  fi; \
 	if [ -f SCSI_MODULES  ]; then inst_mod SCSI_MODULES  scsi;  fi; \
 	if [ -f FS_MODULES    ]; then inst_mod FS_MODULES    fs;    fi; \
 	if [ -f CDROM_MODULES ]; then inst_mod CDROM_MODULES cdrom; fi; \
diff -u --recursive --new-file v2.1.9/linux/arch/alpha/defconfig linux/arch/alpha/defconfig
--- v2.1.9/linux/arch/alpha/defconfig	Wed Oct 16 10:48:06 1996
+++ linux/arch/alpha/defconfig	Thu Nov 14 18:40:20 1996
@@ -102,6 +102,7 @@
 CONFIG_BLK_DEV_SD=y
 # CONFIG_CHR_DEV_ST is not set
 CONFIG_BLK_DEV_SR=y
+# CONFIG_BLK_DEV_SR_VENDOR is not set
 # CONFIG_CHR_DEV_SG is not set
 
 #
@@ -123,9 +124,9 @@
 # CONFIG_SCSI_AM53C974 is not set
 # CONFIG_SCSI_BUSLOGIC is not set
 # CONFIG_SCSI_DTC3280 is not set
-# CONFIG_SCSI_EATA is not set
 # CONFIG_SCSI_EATA_DMA is not set
 # CONFIG_SCSI_EATA_PIO is not set
+# CONFIG_SCSI_EATA is not set
 # CONFIG_SCSI_FUTURE_DOMAIN is not set
 # CONFIG_SCSI_GENERIC_NCR5380 is not set
 # CONFIG_SCSI_NCR53C406A is not set
@@ -193,6 +194,7 @@
 CONFIG_ISO9660_FS=y
 # CONFIG_HPFS_FS is not set
 # CONFIG_SYSV_FS is not set
+# CONFIG_AFFS_FS is not set
 # CONFIG_UFS_FS is not set
 
 #
diff -u --recursive --new-file v2.1.9/linux/arch/alpha/lib/strlen_user.S linux/arch/alpha/lib/strlen_user.S
--- v2.1.9/linux/arch/alpha/lib/strlen_user.S	Sun Nov 10 20:12:08 1996
+++ linux/arch/alpha/lib/strlen_user.S	Fri Nov 15 15:43:56 1996
@@ -1,5 +1,5 @@
 /*
- * arch/alpha/lib/strlen_user.S
+ * arch/alpha/lib/__strlen_user.S
  *
  * Just like strlen except returns -EFAULT if an exception occurs
  * before the terminator is found.
@@ -13,7 +13,7 @@
 	99: x,##y;			\
 	.section __ex_table,"a";	\
 	.gprel32 99b;			\
-	lda zero, $exception-99b(v0); 	\
+	lda zero, $exception-99b(zero);	\
 	.text
 
 
@@ -21,12 +21,12 @@
 	.set noat
 	.text
 
-	.globl strlen_user
-	.ent strlen_user
+	.globl __strlen_user
+	.ent __strlen_user
 	.frame sp, 0, ra
 
 	.align 3
-strlen_user:
+__strlen_user:
 	.prologue 0
 
 	EX( ldq_u t0, 0(a0) )	# load first quadword (a0 may be misaligned)
@@ -34,7 +34,7 @@
 	insqh   t1, a0, t1
 	andnot  a0, 7, v0
 	or      t1, t0, t0
-	nop			# dual issue the next two on ev5
+	subq	a0, 1, a0	# return "1+strlen" (0 for exception)
 	cmpbge  zero, t0, t1	# t1 <- bitmask: bit i == 1 <==> i-th byte == 0
 	bne     t1, $found
 
@@ -58,8 +58,10 @@
 	nop			# dual issue next two on ev4 and ev5
 
 	subq    v0, a0, v0
+	ret
 
 $exception:
+	mov	zero, v0
 	ret
 
-	.end strlen_user
+	.end __strlen_user
diff -u --recursive --new-file v2.1.9/linux/arch/i386/boot/Makefile linux/arch/i386/boot/Makefile
--- v2.1.9/linux/arch/i386/boot/Makefile	Fri Sep 20 18:43:03 1996
+++ linux/arch/i386/boot/Makefile	Wed Nov 13 07:54:31 1996
@@ -25,7 +25,7 @@
 
 bzImage: $(CONFIGURE) bbootsect setup compressed/bvmlinux tools/bbuild
 	if hash $(ENCAPS) 2> /dev/null; then \
-	  $(OBJDUMP) $(OBJDUMP_FLAGS) -o $(IMAGE_OFFSET) compressed/bvmlinux > compressed/bvmlinux.out; \
+	  $(OBJDUMP) $(OBJDUMP_FLAGS) -o $(BZIMAGE_OFFSET) compressed/bvmlinux > compressed/bvmlinux.out; \
 	else \
 	  $(OBJCOPY) compressed/bvmlinux compressed/bvmlinux.out; \
 	fi
diff -u --recursive --new-file v2.1.9/linux/arch/i386/kernel/ksyms.c linux/arch/i386/kernel/ksyms.c
--- v2.1.9/linux/arch/i386/kernel/ksyms.c	Tue Oct 29 19:58:02 1996
+++ linux/arch/i386/kernel/ksyms.c	Thu Nov 14 18:20:31 1996
@@ -20,6 +20,7 @@
 	X(dump_thread),
 	X(dump_fpu),
 	X(ioremap),
+	X(iounmap),
 	XNOVERS(__down_failed),
 	XNOVERS(__up_wakeup),
 #ifdef __SMP__
diff -u --recursive --new-file v2.1.9/linux/drivers/block/floppy.c linux/drivers/block/floppy.c
--- v2.1.9/linux/drivers/block/floppy.c	Sun Nov 10 20:12:08 1996
+++ linux/drivers/block/floppy.c	Thu Nov 14 09:14:46 1996
@@ -1013,7 +1013,7 @@
 		FDCS->reset = 1;
 		return;
 	}
-	if ((long) raw_cmd->kernel_data % 512){
+	if (((unsigned long) raw_cmd->kernel_data) % 512){
 		printk("non aligned address: %p\n", raw_cmd->kernel_data);
 		cont->done(0);
 		FDCS->reset=1;
@@ -2541,7 +2541,8 @@
 		}
 		/* 64 kb boundaries */
 		if (CROSS_64KB(CURRENT->buffer, max_size << 9))
-			max_size = (K_64 - ((long) CURRENT->buffer) % K_64)>>9;
+			max_size = (K_64 - 
+				    ((unsigned long)CURRENT->buffer) % K_64)>>9;
 		direct = transfer_size(ssize,max_sector,max_size) - sector_t;
 		/*
 		 * We try to read tracks, but if we get too many errors, we
diff -u --recursive --new-file v2.1.9/linux/drivers/block/ide-cd.c linux/drivers/block/ide-cd.c
--- v2.1.9/linux/drivers/block/ide-cd.c	Tue Nov 12 15:56:05 1996
+++ linux/drivers/block/ide-cd.c	Wed Nov 13 08:46:17 1996
@@ -2647,8 +2647,8 @@
 	return nslots;
 }
 
-
-void ide_cdrom_setup (ide_drive_t *drive)
+static
+int ide_cdrom_setup (ide_drive_t *drive)
 {
 	struct cdrom_info *info = drive->driver_data;
 	int nslots;
@@ -2750,8 +2750,12 @@
 
 	nslots = ide_cdrom_probe_capabilities (drive);
 
-	if (ide_cdrom_register (drive, nslots))
-		printk ("%s: Can't register\n", drive->name);
+	if (ide_cdrom_register (drive, nslots)) {
+		printk ("%s: ide_cdrom_setup failed to register device with the cdrom driver.\n", drive->name);
+		info->devinfo.handle = NULL;
+		return 1;
+	}
+	return 0;
 }
 
 /* Forwarding functions to generic routines. */
@@ -2765,13 +2769,22 @@
 
 int ide_cdrom_open (struct inode *ip, struct file *fp, ide_drive_t *drive)
 {
-	return cdrom_fops.open (ip, fp);
+	int rc;
+
+	MOD_INC_USE_COUNT;
+	rc = cdrom_fops.open (ip, fp);
+	if (rc) {
+		drive->usage--;
+		MOD_DEC_USE_COUNT;
+	}
+	return rc;
 }
 
 void ide_cdrom_release (struct inode *inode, struct file *file,
 			ide_drive_t *drive)
 {
 	cdrom_fops.release (inode, file);
+	MOD_DEC_USE_COUNT;
 }
 
 int ide_cdrom_check_media_change (ide_drive_t *drive)
@@ -2785,6 +2798,7 @@
 int ide_cdrom_cleanup(ide_drive_t *drive)
 {
 	struct cdrom_info *info = drive->driver_data;
+	struct cdrom_device_info *devinfo = &info->devinfo;
 
 	if (ide_unregister_subdriver (drive))
 		return 1;
@@ -2792,6 +2806,8 @@
 		kfree (info->sector_buffer);
 	if (info->toc != NULL)
 		kfree (info->toc);
+	if (devinfo->handle == drive && unregister_cdrom (devinfo))
+		printk ("%s: ide_cdrom_cleanup failed to unregister device from the cdrom driver.\n", drive->name);
 	kfree (info);
 	drive->driver_data = NULL;
 	return 0;
@@ -2860,10 +2876,17 @@
 			kfree (info);
 			continue;
 		}
-		failed--;
 		memset (info, 0, sizeof (struct cdrom_info));
 		drive->driver_data = info;
-		ide_cdrom_setup (drive);
+		DRIVER(drive)->busy++;
+		if (ide_cdrom_setup (drive)) {
+			DRIVER(drive)->busy--;
+			if (ide_cdrom_cleanup (drive))
+				printk ("%s: ide_cdrom_cleanup failed in ide_cdrom_init\n", drive->name);
+			continue;
+		}
+		DRIVER(drive)->busy--;
+		failed--;
 	}
 	ide_register_module(&ide_cdrom_module);
 	MOD_DEC_USE_COUNT;
diff -u --recursive --new-file v2.1.9/linux/drivers/cdrom/Makefile linux/drivers/cdrom/Makefile
--- v2.1.9/linux/drivers/cdrom/Makefile	Tue Nov 12 15:56:05 1996
+++ linux/drivers/cdrom/Makefile	Wed Nov 13 11:04:35 1996
@@ -90,11 +90,11 @@
 
 ifeq ($(CONFIG_CM206),y)
 L_OBJS += cm206.o
-C = 1 
+USE_GENERIC_CD=1
 else
   ifeq ($(CONFIG_CM206),m)
   M_OBJS += cm206.o
-  CM = 1
+    USE_MODULAR_GENERIC_CD=1
   endif
 endif #CONFIG_CM206
 
@@ -127,6 +127,14 @@
   M_OBJS += isp16.o
   endif
 endif #CONFIG_ISP16_CDI
+
+ifeq ($(CONFIG_BLK_DEV_SR),y)
+USE_GENERIC_CD=1
+else
+  ifeq ($(CONFIG_BLK_DEV_SR),m)
+    USE_MODULAR_GENERIC_CD=1
+  endif
+endif #SCSI CDROM DRIVER
 
 ifeq ($(CONFIG_BLK_DEV_IDECD),y)
 USE_GENERIC_CD=1
diff -u --recursive --new-file v2.1.9/linux/drivers/cdrom/cdrom.c linux/drivers/cdrom/cdrom.c
--- v2.1.9/linux/drivers/cdrom/cdrom.c	Tue Nov 12 15:56:06 1996
+++ linux/drivers/cdrom/cdrom.c	Wed Nov 13 08:16:13 1996
@@ -268,13 +268,11 @@
    meaningful format indicated above.
  */
 
-#undef current                          /* set in sched.h */
-
 static
 void sanitize_format(union cdrom_addr *addr,
-                     u_char * current, u_char requested)
+                     u_char * curr, u_char requested)
 {
-        if (*current == requested)
+        if (*curr == requested)
                 return;                 /* nothing to be done! */
         if (requested == CDROM_LBA) {
                 addr->lba = (int) addr->msf.frame +
@@ -287,7 +285,7 @@
                 addr->msf.second = lba % 60;
                 addr->msf.minute = lba / 60;
         }
-        *current = requested;
+        *curr = requested;
 }
 
 /* All checking and format change makes this code really hard to read!
diff -u --recursive --new-file v2.1.9/linux/drivers/cdrom/mcd.c linux/drivers/cdrom/mcd.c
--- v2.1.9/linux/drivers/cdrom/mcd.c	Tue Oct 29 19:58:04 1996
+++ linux/drivers/cdrom/mcd.c	Thu Nov 14 09:31:08 1996
@@ -61,6 +61,10 @@
 	07 July 1995 Modifications by Andrew J. Kroll
 
 	Bjorn Ekwall <bj0rn@blox.se> added unregister_blkdev to mcd_init()
+
+	Michael K. Johnson <johnsonm@redhat.com> added retries on open
+	for slow drives which take a while to recognize that they contain
+	a CD.
 */
 
 #include <linux/module.h>
@@ -1095,6 +1099,7 @@
 mcd_open(struct inode *ip, struct file *fp)
 {
 	int st;
+	int count = 0;
 
 	if (mcdPresent == 0)
 		return -ENXIO;			/* no hardware */
@@ -1106,9 +1111,16 @@
 
 	mcd_invalidate_buffers();
 
-	st = statusCmd();			/* check drive status */
-	if (st == -1)
-		return -EIO;			/* drive doesn't respond */
+	do {
+		st = statusCmd();		/* check drive status */
+		if (st == -1)
+			return -EIO;		/* drive doesn't respond */
+		if ((st & MST_READY) == 0) {	/* no disk? wait a sec... */
+			current->state = TASK_INTERRUPTIBLE;
+			current->timeout = jiffies + HZ;
+			schedule();
+		}
+	} while (((st & MST_READY) == 0) && count++ < MCD_RETRY_ATTEMPTS);
 
 	if ((st & MST_READY) == 0)		/* no disk in drive */
 	{
diff -u --recursive --new-file v2.1.9/linux/drivers/char/ChangeLog linux/drivers/char/ChangeLog
--- v2.1.9/linux/drivers/char/ChangeLog	Sun Nov 10 20:12:10 1996
+++ linux/drivers/char/ChangeLog	Thu Nov 14 09:28:45 1996
@@ -1,3 +1,9 @@
+Thu Nov 14 00:06:09 1996  Theodore Ts'o  <tytso@rsts-11.mit.edu>
+
+	* serial.c (autoconfig): Fix autoconfiguration problems;
+		info->flags wasn't getting initialized from the state
+		structure.  Put in more paranoid test for the 16750.
+
 Fri Nov  8 20:19:50 1996  Theodore Ts'o  <tytso@rsts-11.mit.edu>
 
 	* n_tty.c (n_tty_flush_buffer): Only call driver->unthrottle() if
diff -u --recursive --new-file v2.1.9/linux/drivers/char/serial.c linux/drivers/char/serial.c
--- v2.1.9/linux/drivers/char/serial.c	Sun Nov 10 20:12:11 1996
+++ linux/drivers/char/serial.c	Thu Nov 14 09:28:45 1996
@@ -50,7 +50,7 @@
 #include <asm/bitops.h>
 
 static char *serial_name = "Serial driver";
-static char *serial_version = "4.20";
+static char *serial_version = "4.21";
 
 DECLARE_TASK_QUEUE(tq_serial);
 
@@ -2687,7 +2687,7 @@
 	(void)serial_inp(info, UART_IIR);
 	(void)serial_inp(info, UART_MSR);
 	
-	timeout = jiffies+2*HZ/100;
+	timeout = jiffies+ ((2*HZ)/100);
 	while (timeout >= jiffies) {
 		if (rs_irq_triggered)
 			break;
@@ -2758,7 +2758,9 @@
 	if (!state->port)
 		return;
 	info = &scr_info;	/* This is just for serial_{in,out} */
-	info->port = state->port; 
+	info->magic = SERIAL_MAGIC;
+	info->port = state->port;
+	info->flags = state->flags;
 
 	save_flags(flags); cli();
 	
@@ -2848,8 +2850,13 @@
 		serial_outp(info, UART_FCR,
 			    UART_FCR_ENABLE_FIFO | UART_FCR7_64BYTE);
 		scratch = serial_in(info, UART_IIR) >> 5;
-		if (scratch == 7)
-			state->type = PORT_16750;
+		if (scratch == 7) {
+			serial_outp(info, UART_LCR, 0);
+			serial_outp(info, UART_FCR, UART_FCR_ENABLE_FIFO);
+			scratch = serial_in(info, UART_IIR) >> 5;
+			if (scratch == 7)
+				state->type = PORT_16750;
+		}
 		serial_outp(info, UART_FCR, UART_FCR_ENABLE_FIFO);
 	}
 	serial_outp(info, UART_LCR, scratch2);
diff -u --recursive --new-file v2.1.9/linux/drivers/isdn/teles/proto.h linux/drivers/isdn/teles/proto.h
--- v2.1.9/linux/drivers/isdn/teles/proto.h	Thu Jan  1 02:00:00 1970
+++ linux/drivers/isdn/teles/proto.h	Fri Nov 15 12:51:02 1996
@@ -0,0 +1,18 @@
+/* $Id: proto.h,v 1.1 1996/09/23 01:53:52 fritz Exp $
+ *
+ * not much now - just the l3 proto discriminator
+ *
+ * $Log: proto.h,v $
+ * Revision 1.1  1996/09/23 01:53:52  fritz
+ * Bugfix: discard unknown frames (non-EDSS1 and non-1TR6).
+ *
+ */
+
+#ifndef	PROTO_H
+#define	PROTO_H
+
+#define	PROTO_EURO		0x08
+#define	PROTO_DIS_N0	0x40
+#define	PROTO_DIS_N1	0x41
+
+#endif
diff -u --recursive --new-file v2.1.9/linux/drivers/net/tulip.c linux/drivers/net/tulip.c
--- v2.1.9/linux/drivers/net/tulip.c	Fri Nov  1 17:13:18 1996
+++ linux/drivers/net/tulip.c	Wed Nov 13 11:22:23 1996
@@ -17,7 +17,8 @@
 static char *version =
 "tulip.c:v0.10 8/11/95 becker@cesdis.gsfc.nasa.gov\n"
 "        +0.72 4/17/96 "
-"http://www.dsl.tutics.tut.ac.jp/~linux/tulip\n";
+"http://www.dsl.tutics.tut.ac.jp/~linux/tulip\n"
+"        +0.01 10/24/96 mjacob@feral.com (2.1.7)\n";
 
 /* A few user-configurable values. */
 
@@ -334,6 +335,7 @@
 	int setup_frame[48];	/* Pseudo-Tx frame to init address table. */
 	void (*port_select)(struct device *dev);
 	int (*port_fail)(struct device *dev);
+	struct device *next_module;
 	char *signature;
 	unsigned int cur_rx, cur_tx;		/* The next free ring entry */
 	unsigned int dirty_rx, dirty_tx;	/* The ring entries to be free()ed. */
@@ -367,7 +369,6 @@
 static void tulip_interrupt(int irq, void *dev_id, struct pt_regs *regs);
 static int tulip_close(struct device *dev);
 static struct enet_statistics *tulip_get_stats(struct device *dev);
-static struct device *tulip_alloc(struct device *dev);
 static void set_multicast_list(struct device *dev);
 
 #define	generic21140_fail	NULL
@@ -379,6 +380,11 @@
 static int generic21040_fail(struct device *dev);
 static int generic21041_fail(struct device *dev);
 
+#ifdef MODULE
+/* A list of all installed Tulip devices, for removing the driver module. */
+static struct device *root_tulip_dev = NULL;
+#endif
+
 static struct {
 	void (*port_select)(struct device *dev);
 	int (*port_fail)(struct device *dev);
@@ -436,7 +442,6 @@
 
 #ifdef MODULE
 static int if_port=TULIP_AUTO_PORT;
-static size_t alloc_size;
 #ifdef TULIP_FULL_DUPLEX
 static int full_duplex=1;
 #else
@@ -1132,6 +1137,7 @@
 			*setup_frm++ = eaddrs[2];
 		} while (++i < 15);
 
+#ifndef	__alpha__
 		/* Now add this frame to the Tx list. */
 		{
 			unsigned long flags;
@@ -1152,46 +1158,8 @@
 			/* Trigger an immediate transmit demand. */
 			tio_write(TPOLL_TRIGGER, CSR1);
 		}
-	}
-}
-
-static struct device *tulip_alloc(struct device *dev)
-{
-	struct tulip_private *tp;
-	char *buff;
-#ifndef	MODULE
-	size_t alloc_size;
 #endif
-	if (!dev || dev->priv) {
-		struct device *olddev = dev;
-
-		alloc_size = sizeof(struct device)
-			+ sizeof(struct tulip_private)
-			+ ETHNAMSIZ;
-		alloc_size = ROUND_UP(alloc_size, 8);
-
-		buff = (char *)kmalloc(alloc_size, GFP_KERNEL);
-		dev = (struct device *)buff;
-		if (dev == NULL) {
-			printk("tulip_alloc: kmalloc failed.\n");
-			return(NULL);
-		}
-		tp = (struct tulip_private *)(buff + sizeof(struct device));
-		memset(buff, 0, alloc_size);
-		dev->priv = (void *)tp;
-		dev->name = (char *)(buff + sizeof(struct device)
-							 + sizeof(struct tulip_private));
-		if (olddev) {
-			dev->next = olddev->next;
-			olddev->next = dev;
-		}
-	} else {
-		alloc_size = ROUND_UP(sizeof(struct tulip_private), 8);
-		tp = (struct tulip_private *)kmalloc(alloc_size, GFP_KERNEL);
-		memset((void *)tp, 0, alloc_size);
-		dev->priv = (void *)tp;
 	}
-	return(dev);
 }
 
 int
@@ -1200,6 +1168,7 @@
 {
 	/* See note below on the Znyx 315 etherarray. */
 	static unsigned char last_phys_addr[6] = {0x00, 'L', 'i', 'n', 'u', 'x'};
+	static int last_irq;
 	char detect_mesg[80], *mesgp=detect_mesg;
 	struct tulip_private *tp = (struct tulip_private *)dev->priv;
 	int i;
@@ -1269,11 +1238,13 @@
 		for (i = 0; i < ETH_ALEN - 1; i++)
 			dev->dev_addr[i] = last_phys_addr[i];
 		dev->dev_addr[i] = last_phys_addr[i] + 1;
+		irq = last_irq;
 	}
 	for (i = 0; i < ETH_ALEN - 1; i++)
 		mesgp += sprintf(mesgp, "%2.2x:", dev->dev_addr[i]);
 	mesgp += sprintf(mesgp, "%2.2x, IRQ %d\n",
 					 last_phys_addr[i] = dev->dev_addr[i], irq);
+	last_irq = irq;
 
 	/* copy ethernet address */
 	if (card_type(tp, device_id,
@@ -1295,21 +1266,20 @@
 	dev->set_multicast_list = &set_multicast_list;
 
 #ifdef	MODULE
-    ether_setup(dev);
 	if (if_port == TULIP_AUTO_PORT)
 		if_port = TULIP_PORT;
 	else
 		tp->port_fix = 1;
 	dev->if_port = if_port;
 	tp->full_duplex = full_duplex;
+	tp->next_module = root_tulip_dev;
+	root_tulip_dev = dev;
 #else
 #ifdef TULIP_FULL_DUPLEX
 	tp->full_duplex = 1;
 #endif
-    init_etherdev(dev, 0);
 	dev->if_port = TULIP_PORT;
 #endif
-
 #ifdef	TULIP_FIX_PORT
 	tp->port_fix = 1;
 #endif
@@ -1340,14 +1310,13 @@
 
     if (!pcibios_present()) return(-ENODEV);
 
-	for (pci_index = 0; pci_index < 8; pci_index++) {
+	for (pci_index = 0; pci_index < 0xff; pci_index++) {
 		/* Search for the PCI_DEVICE_ID_DEV_TULIP* chips */
-		for (cno = 0; pci_chips[cno] != PCI_DEVICE_ID_NONE; cno ++)
+		for (cno = 0; pci_chips[cno] != PCI_DEVICE_ID_NONE; cno++) {
 			if (pcibios_find_device(PCI_VENDOR_ID_DEC,
 									pci_chips[cno],
 									pci_index, &pci_bus,
 									&pci_device_fn) == 0) {
-				struct device *dp;
 
 				/* get IO address */
 				pcibios_read_config_dword(pci_bus, pci_device_fn,
@@ -1355,19 +1324,14 @@
 										  &pci_ioaddr);
 				/* Remove I/O space marker in bit 0. */
 				pci_ioaddr &= ~3;
-				for (dp = tulip_head; dp != NULL; dp = dp->next)
-					if (dp->base_addr == pci_ioaddr) break;
-				if (dp) continue;
 				/* get IRQ */
-				pcibios_read_config_byte(pci_bus, pci_device_fn,
-										 PCI_INTERRUPT_LINE, &pci_irq);
-#ifdef	MODULE
-				/* compare requested IRQ/IO address */
-				if (dev && dev->base_addr &&
-					dev->base_addr != pci_ioaddr) continue;
-#else
-				if ((dev = tulip_alloc(dev)) == NULL) break;
-#endif
+				pcibios_read_config_byte(pci_bus, pci_device_fn, PCI_INTERRUPT_LINE, &pci_irq);
+				dev = init_etherdev(NULL, 
+					ROUND_UP(sizeof(struct device) +
+						sizeof (struct tulip_private) +
+						ETHNAMSIZ, 8));
+
+				if (dev == NULL) break;
 				if (!tulip_head) {
 					printk(version);
 					tulip_head = dev;
@@ -1394,56 +1358,48 @@
 											  PCI_LATENCY_TIMER, 100);
 				}
 				if (tulip_hwinit(dev, pci_ioaddr, pci_irq,
-								 pci_chips[cno]) < 0) continue;
-				num ++;
-#ifdef	MODULE
-				return(0);
-#endif
+								 pci_chips[cno]) < 0) {
+					continue;
+				}
+				num++;
 #ifdef	TULIP_MAX_CARDS
 				if (num >= TULIP_MAX_CARDS) return(0);
 #endif
 		}
 	}
+	}
 	return(num > 0 ? 0: -ENODEV);
 }
 
 #ifdef MODULE
-#ifdef __alpha__
-#if 1
-static int io = 0xb000;
-#else
-static int io = 0x10400;
-#endif
-#else
-static int io = 0xfc80;
-#endif
 
-static struct device *mod_dev;
+/* The parameters that may be passed in... */
+/* This driver does nothing with options yet.  It will later be used to
+   pass the full-duplex flag, etc. */
+int debug = -1;
 
-int init_module(void)
+int
+init_module(void)
 {
-	if ((mod_dev = tulip_alloc(0)) == NULL) return(-EIO);
-
-	mod_dev->base_addr = io;
-	mod_dev->irq = 0;
-	mod_dev->init = &tulip_probe;
-
-	if (register_netdev(mod_dev)) {
-		printk("tulip: register_netdev() returned non-zero.\n");
-		kfree_s(mod_dev, alloc_size);
-		return -EIO;
-	}
-	return(0);
+	root_tulip_dev = NULL;
+	return tulip_probe(NULL);
 }
 
 void
 cleanup_module(void)
 {
-	release_region(mod_dev->base_addr, TULIP_TOTAL_SIZE);
-	unregister_netdev(mod_dev);
-	kfree_s(mod_dev, alloc_size);
-}
+	struct device *next_dev;
 
+	/* No need to check MOD_IN_USE, as sys_delete_module() checks. */
+	while (root_tulip_dev) {
+		next_dev =
+		   ((struct tulip_private *) root_tulip_dev->priv)->next_module;
+		unregister_netdev(root_tulip_dev);
+		release_region(root_tulip_dev->base_addr, TULIP_TOTAL_SIZE);
+		kfree(root_tulip_dev);
+		root_tulip_dev = next_dev;
+	}
+}
 #endif /* MODULE */
 
 
diff -u --recursive --new-file v2.1.9/linux/drivers/scsi/Config.in linux/drivers/scsi/Config.in
--- v2.1.9/linux/drivers/scsi/Config.in	Sun Nov 10 20:12:12 1996
+++ linux/drivers/scsi/Config.in	Wed Nov 13 08:11:17 1996
@@ -3,6 +3,9 @@
 dep_tristate 'SCSI disk support' CONFIG_BLK_DEV_SD $CONFIG_SCSI
 dep_tristate 'SCSI tape support' CONFIG_CHR_DEV_ST $CONFIG_SCSI
 dep_tristate 'SCSI CD-ROM support' CONFIG_BLK_DEV_SR $CONFIG_SCSI
+if [ "$CONFIG_BLK_DEV_SR" != "n" ]; then
+  bool '  Enable vendor-specific extentions (for SCSI CDROM)' CONFIG_BLK_DEV_SR_VENDOR
+fi
 dep_tristate 'SCSI generic support' CONFIG_CHR_DEV_SG $CONFIG_SCSI
 
 comment 'Some SCSI devices (e.g. CD jukebox) support multiple LUNs'
diff -u --recursive --new-file v2.1.9/linux/drivers/scsi/Makefile linux/drivers/scsi/Makefile
--- v2.1.9/linux/drivers/scsi/Makefile	Sat Oct  5 16:58:34 1996
+++ linux/drivers/scsi/Makefile	Wed Nov 13 08:11:17 1996
@@ -58,8 +58,12 @@
   endif
 endif
 
+ifeq ($(CONFIG_BLK_DEV_SR_VENDOR),y)
+SR_VENDOR = sr_vendor.o
+endif
+
 ifeq ($(CONFIG_BLK_DEV_SR),y)
-L_OBJS += sr.o sr_ioctl.o
+L_OBJS += sr.o sr_ioctl.o $(SR_VENDOR)
 else
   ifeq ($(CONFIG_BLK_DEV_SR),m)
   M_OBJS += sr_mod.o
@@ -376,8 +380,8 @@
 		scsicam.o scsi_proc.o
 	$(LD) $(LD_RFLAG) -r -o $@ $(MX_OBJS) hosts.o scsi.o scsi_ioctl.o constants.o scsicam.o scsi_proc.o
 
-sr_mod.o: sr.o sr_ioctl.o
-	$(LD) $(LD_RFLAG) -r -o $@ sr.o sr_ioctl.o
+sr_mod.o: sr.o sr_ioctl.o $(SR_VENDOR)
+	$(LD) $(LD_RFLAG) -r -o $@ sr.o sr_ioctl.o $(SR_VENDOR)
 
 sd_mod.o: sd.o sd_ioctl.o
 	$(LD) $(LD_RFLAG) -r -o $@ sd.o sd_ioctl.o
diff -u --recursive --new-file v2.1.9/linux/drivers/scsi/advansys.c linux/drivers/scsi/advansys.c
--- v2.1.9/linux/drivers/scsi/advansys.c	Wed Oct  9 08:55:21 1996
+++ linux/drivers/scsi/advansys.c	Fri Nov 15 02:45:57 1996
@@ -1,4 +1,4 @@
-/* $Id: advansys.c,v 1.24 1996/10/05 00:58:14 bobf Exp bobf $ */
+/* $Id: advansys.c,v 1.29 1996/11/15 00:45:07 bobf Exp bobf $ */
 /*
  * advansys.c - Linux Host Driver for AdvanSys SCSI Adapters
  * 
@@ -19,9 +19,9 @@
 
 /*
  * The driver has been used in the following kernels:
- * v1.2.13, v1.3.57, v2.0.21, v2.1.0
+ *  v1.2.13, v1.3.57, v2.0.25, v2.1.9
  */
-#define ASC_VERSION "1.8"    /* AdvanSys Driver Version */
+#define ASC_VERSION "2.0"    /* AdvanSys Driver Version */
 
 /*
 
@@ -54,10 +54,10 @@
 
      Connectivity Products:
         ABP510/5150 - Bus-Master ISA (240 CDB) (Footnote 1)
-        ABP5140 - Bus-Master ISA PnP (16 CDB) (Footnote 1)
-        ABP5142 - Bus-Master ISA PnP with floppy (16 CDB)
+        ABP5140 - Bus-Master ISA PnP (16 CDB) (Footnote 1, 3)
+        ABP5142 - Bus-Master ISA PnP with floppy (16 CDB) (Footnote 4)
         ABP920 - Bus-Master PCI (16 CDB)
-        ABP930 - Bus-Master PCI (16 CDB)
+        ABP930 - Bus-Master PCI (16 CDB) (Footnote 5)
         ABP930U - Bus-Master PCI Ultra (16 CDB)
         ABP960 - Bus-Master PCI MAC/PC (16 CDB) (Footnote 2)
         ABP960U - Bus-Master PCI MAC/PC Ultra (16 CDB)
@@ -80,9 +80,11 @@
        1. This board has been shipped by HP with the 4020i CD-R drive.
           The board has no BIOS so it cannot control a boot device, but
           it can control any secondary SCSI device.
-   
        2. This board has been sold by Iomega as a Jaz Jet PCI adapter.
-  
+       3. This board has been sold by SIIG as the i540 SpeedMaster.
+       4. This board has been sold by SIIG as the i542 SpeedMaster.
+       5. This board has been sold by SIIG as the Fast SCSI Pro PCI.
+
   B. Linux v1.2.X - Directions for Adding the AdvanSys Driver
 
      These directions apply to v1.2.13. For versions that follow v1.2.13.
@@ -454,26 +456,34 @@
          5. Add request response time statistics and other information to
             the adapter /proc file: /proc/scsi/advansys[0...].
 
+     1.9 (10/21/96):
+         1. Add conditionally compiled code (ASC_QUEUE_FLOW_CONTROL) to
+            make use of mid-level SCSI driver device queue depth flow
+            control mechanism. This will eliminate aborts caused by a
+            device being unable to keep up with requests and eliminate
+            repeat busy or QUEUE FULL status returned by a device.
+         2. Incorporate miscellaneous Asc Library bug fixes.
+         3. To allow the driver to work in kernels with broken module
+            support set 'cmd_per_lun' if the driver is compile as a
+            module. This change affects kernels v1.3.89 to present.
+         4. Remove PCI BIOS address from the driver banner. The PCI BIOS
+            is relocated by the motherboard BIOS and its new address can
+            not be determined by the driver.
+         5. Add mid-level SCSI queue depth information to the adapter
+            /proc file: /proc/scsi/advansys[0...].
+
+     2.0 (11/14/96):
+         1. Change allocation of global structures used for device
+            initialization to guarantee they are in DMA-able memory.
+            Previously when the driver was loaded as a module these
+            structures might not have been in DMA-able memory, causing
+            device initialization to fail.
+
   I. Known Problems or Issues
 
-         1. If a large "Device Queue Size" is set in the adapter
-            BIOS and a device supports the queue depth and the device
-            is heavily loaded, requests may be sent to the device
-            faster than they can be executed causing the requests to
-            queue up in the low-level driver on a wait queue. This may
-            lead to time-out abort requests by the mid-level driver.
-            
-            The short term solution is to set a smaller "Device Queue
-            Size" in the adapter BIOS. Response times can be monitored
-            per device by reading the /proc/scsi/advansys/[0...] file.
-            
-            The long term solution is to modify the mid-level driver to
-            institute a flow control mechanism between the two levels.
-            The low-level driver would notify the mid-level driver when
-            a device is falling behind on executing requests. This would
-            prevent the mid-level driver from sending more requests until
-            the low-level driver has notified it that the device has caught
-            up on request execution.
+         1. Remove conditional constants (ASC_QUEUE_FLOW_CONTROL) around
+            the queue depth flow control code when mid-level SCSI changes
+            are included in Linux.
 
   J. Credits
 
@@ -570,7 +580,7 @@
 
 #define ASC_LIB_VERSION_MAJOR  1
 #define ASC_LIB_VERSION_MINOR  22
-#define ASC_LIB_SERIAL_NUMBER  89
+#define ASC_LIB_SERIAL_NUMBER  91
 
 typedef unsigned char uchar;
 
@@ -645,7 +655,6 @@
 #define ASC_PCI_ID2FUNC( id )   (((id) >> 8) & 0x7)
 #define ASC_PCI_MKID( bus, dev, func ) ((((dev) & 0x1F) << 11) | (((func) & 0x7) << 8) | ((bus) & 0xFF))
 
-#define  Asc_DvcLib_Status   int
 #define  ASC_DVCLIB_CALL_DONE     (1)
 #define  ASC_DVCLIB_CALL_FAILED   (0)
 #define  ASC_DVCLIB_CALL_ERROR    (-1)
@@ -853,7 +862,7 @@
 #define SCSI_SENKEY_MEDIUM_ERR    0x03
 #define SCSI_SENKEY_HW_ERR        0x04
 #define SCSI_SENKEY_ILLEGAL       0x05
-#define SCSI_SENKEY_ATTENSION     0x06
+#define SCSI_SENKEY_ATTENTION     0x06
 #define SCSI_SENKEY_PROTECTED     0x07
 #define SCSI_SENKEY_BLANK         0x08
 #define SCSI_SENKEY_V_UNIQUE      0x09
@@ -1379,7 +1388,6 @@
 #define ASC_IERR_SCAM                 0x0800
 #define ASC_IERR_SET_SDTR             0x1000
 #define ASC_IERR_RW_LRAM              0x8000
-#define ASC_DVCLIB_STATUS             0x00
 #define ASC_DEF_IRQ_NO  10
 #define ASC_MAX_IRQ_NO  15
 #define ASC_MIN_IRQ_NO  10
@@ -2138,7 +2146,7 @@
 #define ASC_INFO_SIZE			128			/* advansys_info() line size */
 
 /* /proc/scsi/advansys/[0...] related definitions */
-#define ASC_PRTBUF_SIZE			1024
+#define ASC_PRTBUF_SIZE			2048
 #define ASC_PRTLINE_SIZE		160
 
 #define ASC_PRT_NEXT() \
@@ -2310,7 +2318,11 @@
 #endif /* ADVANSYS_STATS */
 
 #define ASC_CEILING(val, unit) (((val) + ((unit) - 1))/(unit))
-#define ASC_TENTHS(num, den) ((((num) * 10)/(den)) - (10 * ((num)/(den))))
+
+/* If the result wraps when calculating tenths, return 0. */
+#define ASC_TENTHS(num, den) \
+	(((10 * ((num)/(den))) > (((num) * 10)/(den))) ? \
+	0 : ((((num) * 10)/(den)) - (10 * ((num)/(den)))))
 
 /*
  * Display a message to the console.
@@ -2490,9 +2502,6 @@
 	ulong 	sg_cnt;			/* # scatter-gather I/O requests received */
 	ulong 	sg_elem;		/* # scatter-gather elements */
 	ulong 	sg_xfer;		/* # scatter-gather transfer 512-bytes */
-	/* Device SCSI Command Queuing Statistics */
-	ASC_SCSI_BIT_ID_TYPE queue_full;
-	ushort	queue_full_cnt[ASC_MAX_TID+1];
 };
 #endif /* ADVANSYS_STATS */
 
@@ -2529,9 +2538,19 @@
 	asc_queue_t			 waiting;		  	/* Waiting command queue */
 	asc_queue_t			 done;				/* Done command queue */
 	ASC_SCSI_BIT_ID_TYPE init_tidmask;		/* Target initialized mask */
+	/* The following three structures must be in DMA-able memory. */
+	ASC_SCSI_REQ_Q		 scsireqq;
+	ASC_CAP_INFO		 cap_info;
+	ASC_SCSI_INQUIRY	 inquiry;
+	Scsi_Device			 *device[ASC_MAX_TID+1]; /* Mid-Level Scsi Device */
+	ushort				 reqcnt[ASC_MAX_TID+1]; /* Starvation request count */
+#if ASC_QUEUE_FLOW_CONTROL
+	ushort				 nerrcnt[ASC_MAX_TID+1]; /* No error request count */
+#endif /* ASC_QUEUE_FLOW_CONTROL */
+	ASC_SCSI_BIT_ID_TYPE queue_full;		/* Queue full mask */
+	ushort	queue_full_cnt[ASC_MAX_TID+1];	/* Queue full count */
 	ASCEEP_CONFIG		 eep_config;		/* EEPROM configuration */
 	ulong				 last_reset;		/* Saved time of last reset */
-	ushort				 rcnt[ASC_MAX_TID+1]; /* Starvation Request Count */
 #if LINUX_VERSION_CODE >= ASC_LINUX_VERSION(1,3,0)
 	/* /proc/scsi/advansys/[0...] */
 	char				 *prtbuf;			/* Statistics Print Buffer */
@@ -2616,13 +2635,6 @@
 STATIC uchar overrun_buf[ASC_OVERRUN_BSIZE] = { 0 };
 
 /*
- * Global structures used for device initialization.
- */
-STATIC ASC_SCSI_REQ_Q	 asc_scsireqq = { { 0 } };
-STATIC ASC_CAP_INFO		 asc_cap_info = { 0 };
-STATIC ASC_SCSI_INQUIRY	 asc_inquiry = { { 0 } };
-
-/*
  * Global structures required to issue a command.
  */
 STATIC ASC_SCSI_Q asc_scsi_q = { { 0 } };
@@ -3124,6 +3136,7 @@
 			memset(boardp, 0, sizeof(asc_board_t));
 			boardp->id = asc_board_count - 1;
 			asc_dvc_varp = &boardp->asc_dvc_var;
+			asc_dvc_varp->drv_ptr = (ulong) boardp;
 			asc_dvc_varp->cfg = &boardp->asc_dvc_cfg;
 			asc_dvc_varp->cfg->overrun_buf = &overrun_buf[0];
 			asc_dvc_varp->iop_base = iop;
@@ -3179,9 +3192,9 @@
 			/*
 			 * Get the board configuration.
 			 *
-			 * AscInitGetConfig() may change the board's bus_type value.
-			 * The asc_bus[bus] value should no longer be used. If the
-			 * bus_type field must be referenced only use the bit-wise
+			 * NOTE: AscInitGetConfig() may change the board's bus_type
+			 * value. The asc_bus[bus] value should no longer be used. If
+			 * the bus_type field must be referenced only use the bit-wise
 			 * AND operator "&".
 			 */
 			ASC_DBG(2, "advansys_detect: AscInitGetConfig()\n");
@@ -3312,7 +3325,7 @@
 			 */
 
 			/* AscInitSetConfig() will set the IRQ for non-PCI boards. */
-			if (asc_dvc_varp->bus_type != ASC_IS_PCI) {
+			if ((asc_dvc_varp->bus_type & ASC_IS_PCI) == 0) {
 				shp->irq = asc_dvc_varp->irq_no;
 			}
 
@@ -3351,16 +3364,33 @@
 			 */
 			shp->select_queue_depths = advansys_select_queue_depths;
 
-			shp->cmd_per_lun = 0; /* 'cmd_per_lun' is no longer used. */
+#ifdef MODULE
+			/*
+			 * Following v1.3.89, 'cmd_per_lun' is no longer needed
+			 * and should be set to zero. But because of a bug introduced
+			 * in v1.3.89 if the driver is compiled as a module and
+			 * 'cmd_per_lun' is zero, the Mid-Level SCSI function
+			 * 'allocate_device' will panic. To allow the driver to
+			 * work as a module in these kernels set 'cmd_per_lun' to 1.
+			 */
+			shp->cmd_per_lun = 1;
+#else /* MODULE */
+			shp->cmd_per_lun = 0;
+#endif /* MODULE */
 #endif /* version >= v1.3.89 */
 
 			/*
-			 * Maximum number of scatter-gather elements adapter can handle.
-			 *
-			 * Set a conservative 'sg_tablesize' value to prevent memory
-			 * allocation failures.
+			 * Set the maximum number of scatter-gather elements adapter
+			 * can handle.
 			 */
+
 #ifdef MODULE
+			/*
+			 * If the driver is compiled as a module, set a conservative
+			 * 'sg_tablesize' value to prevent memory allocation failures.
+			 * Memory allocation errors are more likely to occur at module
+			 * load time, then at driver initialization time.
+			 */
 			shp->sg_tablesize = 8;
 #else /* MODULE */
 			/*
@@ -3539,25 +3569,28 @@
 			ASC_VERSION, busname, boardp->asc_dvc_var.max_total_qng,
 			(unsigned) shp->base, shp->io_port,
 			shp->io_port + (shp->n_io_port - 1), shp->irq, shp->dma_channel);
+	} else if (asc_dvc_varp->bus_type & ASC_IS_PCI) {
+		if ((asc_dvc_varp->bus_type & ASC_IS_PCI_ULTRA)
+			== ASC_IS_PCI_ULTRA) {
+			busname = "PCI Ultra";
+		} else {
+			busname = "PCI";
+		}
+		sprintf(info,
+			"AdvanSys SCSI %s: %s %u CDB: IO %X-%X, IRQ %u",
+			ASC_VERSION, busname, boardp->asc_dvc_var.max_total_qng,
+			shp->io_port, shp->io_port + (shp->n_io_port - 1), shp->irq);
 	} else {
 		if (asc_dvc_varp->bus_type & ASC_IS_VL) {
 			busname = "VL";
 		} else if (asc_dvc_varp->bus_type & ASC_IS_EISA) {
 			busname = "EISA";
-		} else if (asc_dvc_varp->bus_type & ASC_IS_PCI) {
-			if ((asc_dvc_varp->bus_type & ASC_IS_PCI_ULTRA)
-				== ASC_IS_PCI_ULTRA) {
-				busname = "PCI Ultra";
-			} else {
-				busname = "PCI";
-			}
 		} else {
 			busname = "?";
 			ASC_PRINT2(
 "advansys_info: board %d: unknown bus type %d\n",
 				boardp->id, asc_dvc_varp->bus_type);
 		}
-		/* No DMA channel for non-ISA busses. */
 		sprintf(info,
 			"AdvanSys SCSI %s: %s %u CDB: BIOS %X, IO %X-%X, IRQ %u",
 			ASC_VERSION, busname, boardp->asc_dvc_var.max_total_qng,
@@ -4429,6 +4462,11 @@
 		if (device->host != shp) {
 			continue;
 		}
+		/*
+		 * Save a pointer to the device and set its initial/maximum
+		 * queue depth.
+		 */
+		boardp->device[device->id] = device;
 		device->queue_depth = boardp->asc_dvc_var.max_dvc_qng[device->id];
 		ASC_DBG3(1, "advansys_select_queue_depths: shp %x, id %d, depth %d\n",
 			(unsigned) shp, device->id, device->queue_depth);
@@ -4516,6 +4554,7 @@
 {
 	asc_board_t		*boardp;
 	ASC_DVC_VAR		*asc_dvc_varp;
+	Scsi_Device		*device;
 	int				ret;
 
 	ASC_ASSERT(interrupts_enabled() == ASC_FALSE);
@@ -4524,6 +4563,7 @@
 
 	boardp = ASC_BOARDP(scp->host);
 	asc_dvc_varp = &boardp->asc_dvc_var;
+	device = boardp->device[scp->target];
 
 	/*
 	 * If this is the first command, then initialize the device. If
@@ -4557,25 +4597,26 @@
 	asc_scsi_q.q1.target_id = ASC_TID_TO_TARGET_ID(scp->target);
 	asc_scsi_q.q1.target_lun = scp->lun;
 	asc_scsi_q.q2.target_ix = ASC_TIDLUN_TO_IX(scp->target, scp->lun);
-#if LINUX_VERSION_CODE < ASC_LINUX_VERSION(2,1,0)
+#if LINUX_VERSION_CODE < ASC_LINUX_VERSION(2,0,0)
 	asc_scsi_q.q1.sense_addr = (ulong) &scp->sense_buffer[0];
-#else /* version >= v2.1.0 */
+#else /* version >= v2.0.0 */
 	asc_scsi_q.q1.sense_addr = virt_to_bus(&scp->sense_buffer[0]);
-#endif /* version >= v2.1.0 */
+#endif /* version >= v2.0.0 */
 	asc_scsi_q.q1.sense_len = sizeof(scp->sense_buffer);
 
 	/*
-	 * If there are more than five outstanding commands for the
-	 * current target, then every tenth command send an ORDERED
-	 * request. This heuristic tries to retain the benefit of
-	 * request sorting while preventing request starvation.
+	 * If there are any outstanding requests for the current target,
+	 * then every 255th request send an ORDERED request. This heuristic
+	 * tries to retain the benefit of request sorting while preventing
+	 * request starvation. 255 is the max number of tags or pending commands
+	 * a device may have outstanding.
 	 *
 	 * The request count is incremented below for every successfully
 	 * started request.
 	 * 
 	 */
-	if ((asc_dvc_varp->cur_dvc_qng[scp->target] > 5) &&
-	    (boardp->rcnt[scp->target] % 10) == 0) {
+	if ((asc_dvc_varp->cur_dvc_qng[scp->target] > 0) &&
+	    (boardp->reqcnt[scp->target] % 255) == 0) {
 		asc_scsi_q.q2.tag_code = M2_QTAG_MSG_ORDERED;
 	} else {
 		asc_scsi_q.q2.tag_code = M2_QTAG_MSG_SIMPLE;
@@ -4590,11 +4631,11 @@
 		 * CDB request of single contiguous buffer.
 		 */
 		ASC_STATS(scp->host, cont_cnt);
-#if LINUX_VERSION_CODE < ASC_LINUX_VERSION(2,1,0)
+#if LINUX_VERSION_CODE < ASC_LINUX_VERSION(2,0,0)
 		asc_scsi_q.q1.data_addr = (ulong) scp->request_buffer;
-#else /* version >= v2.1.0 */
+#else /* version >= v2.0.0 */
 		asc_scsi_q.q1.data_addr = virt_to_bus(scp->request_buffer);
-#endif /* version >= v2.1.0 */
+#endif /* version >= v2.0.0 */
 		asc_scsi_q.q1.data_cnt = scp->request_bufflen;
 		ASC_STATS_ADD(scp->host, cont_xfer,
 					  ASC_CEILING(scp->request_bufflen, 512));
@@ -4636,11 +4677,11 @@
 		 */
 		slp = (struct scatterlist *) scp->request_buffer;
 		for (sgcnt = 0; sgcnt < scp->use_sg; sgcnt++, slp++) {
-#if LINUX_VERSION_CODE < ASC_LINUX_VERSION(2,1,0)
+#if LINUX_VERSION_CODE < ASC_LINUX_VERSION(2,0,0)
 			asc_sg_head.sg_list[sgcnt].addr = (ulong) slp->address;
-#else /* version >= v2.1.0 */
+#else /* version >= v2.0.0 */
 			asc_sg_head.sg_list[sgcnt].addr = virt_to_bus(slp->address);
-#endif /* version >= v2.1.0 */
+#endif /* version >= v2.0.0 */
 			asc_sg_head.sg_list[sgcnt].bytes = slp->length;
 			ASC_STATS_ADD(scp->host, sg_xfer, ASC_CEILING(slp->length, 512));
 		}
@@ -4658,21 +4699,55 @@
 		ASC_STATS(scp->host, asc_noerror);
 		/*
 		 * Increment monotonically increasing per device successful
-		 * request count. Wrapping of 'rcnt' doesn't matter.
+		 * request counter. Wrapping doesn't matter.
 		 */
-		boardp->rcnt[scp->target]++;
+		boardp->reqcnt[scp->target]++;
+
+#if ASC_QUEUE_FLOW_CONTROL
+		/*
+		 * Conditionally increment the device queue depth.
+		 *
+	 	 * If no error occurred and there have been 100 consecutive
+		 * successfull requests and the current queue depth is less
+		 * than the maximum queue depth, then increment the current
+		 * queue depth.
+		 */
+		if (boardp->nerrcnt[scp->target]++ > 100) {
+			boardp->nerrcnt[scp->target] = 0;
+			if ((device->queue_curr_depth < device->queue_depth) &&
+			    (!(boardp->queue_full & ASC_TIX_TO_TARGET_ID(scp->target)) ||
+				 (boardp->queue_full_cnt[scp->target] >
+				  device->queue_curr_depth))) {
+				device->queue_curr_depth++;
+			}
+		}
+#endif /* ASC_QUEUE_FLOW_CONTROL */
 		asc_enqueue(&boardp->active, scp, ASC_BACK);
 		ASC_DBG(1, "asc_execute_scsi_cmnd: AscExeScsiQueue(), ASC_NOERROR\n");
 		break;
 	case ASC_BUSY:
 		/* Caller must enqueue request and retry later. */
 		ASC_STATS(scp->host, asc_busy);
+#if ASC_QUEUE_FLOW_CONTROL
+		/*
+		 * Clear consecutive no error counter and if possbile decrement
+		 * queue depth.
+		 */
+		boardp->nerrcnt[scp->target] = 0;
+		if (device->queue_curr_depth > 1) {
+			device->queue_curr_depth--;
+		}
+#endif /* ASC_QUEUE_FLOW_CONTROL */
 		break;
 	case ASC_ERROR:
 		ASC_PRINT2(
 "asc_execute_scsi_cmnd: board %d: AscExeScsiQueue() ASC_ERROR, err_code %x\n",
 			boardp->id, asc_dvc_varp->err_code);
 		ASC_STATS(scp->host, asc_error);
+#if ASC_QUEUE_FLOW_CONTROL
+		/* Clear consecutive no error counter. */
+		boardp->nerrcnt[scp->target] = 0;
+#endif /* ASC_QUEUE_FLOW_CONTROL */
 		scp->result = HOST_BYTE(DID_ERROR);
 		asc_enqueue(&boardp->done, scp, ASC_BACK);
 		break;
@@ -4681,6 +4756,10 @@
 "asc_execute_scsi_cmnd: board %d: AscExeScsiQueue() unknown, err_code %x\n",
 			boardp->id, asc_dvc_varp->err_code);
 		ASC_STATS(scp->host, asc_unknown);
+#if ASC_QUEUE_FLOW_CONTROL
+		/* Clear consecutive no error counter. */
+		boardp->nerrcnt[scp->target] = 0;
+#endif /* ASC_QUEUE_FLOW_CONTROL */
 		scp->result = HOST_BYTE(DID_ERROR);
 		asc_enqueue(&boardp->done, scp, ASC_BACK);
 		break;
@@ -4836,6 +4915,9 @@
 asc_init_dev(ASC_DVC_VAR *asc_dvc_varp, Scsi_Cmnd *scp)
 {
 	asc_board_t				*boardp;
+	ASC_SCSI_REQ_Q			*scsireqq;
+	ASC_CAP_INFO			*cap_info;
+	ASC_SCSI_INQUIRY		*inquiry;
 	int						found;
 	ASC_SCSI_BIT_ID_TYPE	save_use_tagged_qng;
 	ASC_SCSI_BIT_ID_TYPE	save_can_tagged_qng;
@@ -4852,9 +4934,11 @@
 	boardp = ASC_BOARDP(scp->host);
 
 	/* Set-up AscInitPollTarget() arguments. */
-	memset(&asc_scsireqq, 0, sizeof(ASC_SCSI_REQ_Q));
-	memset(&asc_cap_info, 0, sizeof(ASC_CAP_INFO));
-	memset(&asc_inquiry, 0, sizeof(ASC_SCSI_INQUIRY));
+	scsireqq = &boardp->scsireqq;
+	memset(scsireqq, 0, sizeof(ASC_SCSI_REQ_Q));
+	cap_info = &boardp->cap_info;
+	memset(cap_info, 0, sizeof(ASC_CAP_INFO));
+	inquiry = &boardp->inquiry;
 
 	/*
 	 * XXX - AscInitPollBegin() re-initializes these fields to
@@ -4872,24 +4956,24 @@
 		return ASC_FALSE;
 	}
 
-	asc_scsireqq.sense_ptr = &asc_scsireqq.sense[0];
-	asc_scsireqq.r1.sense_len = ASC_MIN_SENSE_LEN;
-	asc_scsireqq.r1.target_id = ASC_TID_TO_TARGET_ID(scp->target);
-	asc_scsireqq.r1.target_lun = 0;
-	asc_scsireqq.r2.target_ix = ASC_TIDLUN_TO_IX(scp->target, 0);
+	scsireqq->sense_ptr = &scsireqq->sense[0];
+	scsireqq->r1.sense_len = ASC_MIN_SENSE_LEN;
+	scsireqq->r1.target_id = ASC_TID_TO_TARGET_ID(scp->target);
+	scsireqq->r1.target_lun = 0;
+	scsireqq->r2.target_ix = ASC_TIDLUN_TO_IX(scp->target, 0);
 
 	found = ASC_FALSE;
 	ASC_DBG(2, "asc_init_dev: AscInitPollTarget()\n");
-	switch (ret = AscInitPollTarget(asc_dvc_varp, &asc_scsireqq,
-		&asc_inquiry, &asc_cap_info)) {
+	switch (ret = AscInitPollTarget(asc_dvc_varp, scsireqq, inquiry,
+		cap_info)) {
 	case ASC_TRUE:
 		found = ASC_TRUE;
 #ifdef ADVANSYS_DEBUG
 		tidmask = ASC_TIX_TO_TARGET_ID(scp->target);
 		ASC_DBG2(1, "asc_init_dev: lba %lu, blk_size %lu\n",
-			asc_cap_info.lba, asc_cap_info.blk_size);
+			cap_info->lba, cap_info->blk_size);
 		ASC_DBG1(1, "asc_init_dev: peri_dvc_type %x\n",
-			asc_inquiry.byte0.peri_dvc_type);
+			inquiry->byte0.peri_dvc_type);
 		if (asc_dvc_varp->use_tagged_qng & tidmask) {
 			ASC_DBG1(1, "asc_init_dev: command queuing enabled: %d\n",
 				asc_dvc_varp->max_dvc_qng[scp->target]);
@@ -5677,7 +5761,7 @@
 	for (i = 0; i <= ASC_MAX_TID; i++) {
 		if (boardp->asc_dvc_cfg.chip_scsi_id == i) {
 			continue;
-		} else if (boardp->init_tidmask & (1 << i)) {
+		} else if (boardp->init_tidmask & ASC_TIX_TO_TARGET_ID(i)) {
 			len = asc_prt_line(cp, leftlen, " %d,", i);
 			ASC_PRT_NEXT();
 		}
@@ -5733,7 +5817,7 @@
 	ASC_PRT_NEXT();
 	for (i = 0; i <= ASC_MAX_TID; i++) {
 		len = asc_prt_line(cp, leftlen, " %d:%c",
-			i, (ep->disc_enable & (1 << i)) ? 'Y' : 'N');
+			i, (ep->disc_enable & ASC_TIX_TO_TARGET_ID(i)) ? 'Y' : 'N');
 		ASC_PRT_NEXT();
 	}
 	len = asc_prt_line(cp, leftlen, "\n");
@@ -5744,7 +5828,7 @@
 	ASC_PRT_NEXT();
 	for (i = 0; i <= ASC_MAX_TID; i++) {
 		len = asc_prt_line(cp, leftlen, " %d:%c",
-			i, (ep->use_cmd_qng & (1 << i)) ? 'Y' : 'N');
+			i, (ep->use_cmd_qng & ASC_TIX_TO_TARGET_ID(i)) ? 'Y' : 'N');
 		ASC_PRT_NEXT();
 	}
 	len = asc_prt_line(cp, leftlen, "\n");
@@ -5755,7 +5839,7 @@
 	ASC_PRT_NEXT();
 	for (i = 0; i <= ASC_MAX_TID; i++) {
 		len = asc_prt_line(cp, leftlen, " %d:%c",
-			i, (ep->start_motor & (1 << i)) ? 'Y' : 'N');
+			i, (ep->start_motor & ASC_TIX_TO_TARGET_ID(i)) ? 'Y' : 'N');
 		ASC_PRT_NEXT();
 	}
 	len = asc_prt_line(cp, leftlen, "\n");
@@ -5766,7 +5850,7 @@
 	ASC_PRT_NEXT();
 	for (i = 0; i <= ASC_MAX_TID; i++) {
 		len = asc_prt_line(cp, leftlen, " %d:%c",
-			i, (ep->init_sdtr & (1 << i)) ? 'Y' : 'N');
+			i, (ep->init_sdtr & ASC_TIX_TO_TARGET_ID(i)) ? 'Y' : 'N');
 		ASC_PRT_NEXT();
 	}
 	len = asc_prt_line(cp, leftlen, "\n");
@@ -5794,9 +5878,15 @@
 STATIC int
 asc_prt_driver_conf(struct Scsi_Host *shp, char *cp, int cplen)
 {
+	asc_board_t			*boardp;
 	int					leftlen;
 	int					totlen;
 	int					len;
+#if LINUX_VERSION_CODE >= ASC_LINUX_VERSION(1,3,89)
+	int					i;
+#endif /* version >= v1.3.89 */
+
+	boardp = ASC_BOARDP(shp);
 
 	leftlen = cplen;
 	totlen = len = 0;
@@ -5843,6 +5933,55 @@
 		ASC_BOARDP(shp)->flags, ASC_BOARDP(shp)->last_reset, jiffies);
 	ASC_PRT_NEXT();
 
+#if LINUX_VERSION_CODE >= ASC_LINUX_VERSION(1,3,89)
+	len = asc_prt_line(cp, leftlen,
+" queue_depth:     ");
+	ASC_PRT_NEXT();
+	for (i = 0; i <= ASC_MAX_TID; i++) {
+		if ((boardp->asc_dvc_cfg.chip_scsi_id == i) ||
+		    ((boardp->init_tidmask & ASC_TIX_TO_TARGET_ID(i)) == 0)) {
+			continue;
+		}
+		len = asc_prt_line(cp, leftlen, " %d:%d",
+			i, boardp->device[i]->queue_depth);
+		ASC_PRT_NEXT();
+	}
+	len = asc_prt_line(cp, leftlen, "\n");
+	ASC_PRT_NEXT();
+#endif /* version >= v1.3.89 */
+
+#if ASC_QUEUE_FLOW_CONTROL
+	len = asc_prt_line(cp, leftlen,
+" queue_curr_depth:");
+	ASC_PRT_NEXT();
+	for (i = 0; i <= ASC_MAX_TID; i++) {
+		if ((boardp->asc_dvc_cfg.chip_scsi_id == i) ||
+		    ((boardp->init_tidmask & ASC_TIX_TO_TARGET_ID(i)) == 0)) {
+			continue;
+		}
+		len = asc_prt_line(cp, leftlen, " %d:%d",
+			i, boardp->device[i]->queue_curr_depth);
+		ASC_PRT_NEXT();
+	}
+	len = asc_prt_line(cp, leftlen, "\n");
+	ASC_PRT_NEXT();
+
+	len = asc_prt_line(cp, leftlen,
+" queue_count:     ");
+	ASC_PRT_NEXT();
+	for (i = 0; i <= ASC_MAX_TID; i++) {
+		if ((boardp->asc_dvc_cfg.chip_scsi_id == i) ||
+		    ((boardp->init_tidmask & ASC_TIX_TO_TARGET_ID(i)) == 0)) {
+			continue;
+		}
+		len = asc_prt_line(cp, leftlen, " %d:%d",
+			i, boardp->device[i]->queue_count);
+		ASC_PRT_NEXT();
+	}
+	len = asc_prt_line(cp, leftlen, "\n");
+	ASC_PRT_NEXT();
+#endif /* ASC_QUEUE_FLOW_CONTROL */
+
  	return totlen;
 }
 
@@ -5867,9 +6006,6 @@
 	ASC_DVC_VAR			*v;
 	ASC_DVC_CFG			*c;
 	int					i;
-#ifdef ADVANSYS_STATS
-	struct asc_stats	*s;
-#endif /* ADVANSYS_STATS */
 
 	boardp = ASC_BOARDP(shp);
 	v = &boardp->asc_dvc_var;
@@ -5903,11 +6039,11 @@
 	ASC_PRT_NEXT();
 	for (i = 0; i <= ASC_MAX_TID; i++) {
 		if ((boardp->asc_dvc_cfg.chip_scsi_id == i) ||
-		    ((boardp->init_tidmask & (1 << i)) == 0)) {
+		    ((boardp->init_tidmask & ASC_TIX_TO_TARGET_ID(i)) == 0)) {
 			continue;
 		}
 		len = asc_prt_line(cp, leftlen, " %d:%c",
-			i, (v->sdtr_done & (1 << i)) ? 'Y' : 'N');
+			i, (v->sdtr_done & ASC_TIX_TO_TARGET_ID(i)) ? 'Y' : 'N');
 		ASC_PRT_NEXT();
 	}
 	len = asc_prt_line(cp, leftlen, "\n");
@@ -5918,11 +6054,11 @@
 	ASC_PRT_NEXT();
 	for (i = 0; i <= ASC_MAX_TID; i++) {
 		if ((boardp->asc_dvc_cfg.chip_scsi_id == i) ||
-		    ((boardp->init_tidmask & (1 << i)) == 0)) {
+		    ((boardp->init_tidmask & ASC_TIX_TO_TARGET_ID(i)) == 0)) {
 			continue;
 		}
 		len = asc_prt_line(cp, leftlen, " %d:%c",
-			i, (v->use_tagged_qng & (1 << i)) ? 'Y' : 'N');
+			i, (v->use_tagged_qng & ASC_TIX_TO_TARGET_ID(i)) ? 'Y' : 'N');
 		ASC_PRT_NEXT();
 	}
 	len = asc_prt_line(cp, leftlen, "\n");
@@ -5934,7 +6070,7 @@
 	ASC_PRT_NEXT();
 	for (i = 0; i <= ASC_MAX_TID; i++) {
 		if ((boardp->asc_dvc_cfg.chip_scsi_id == i) ||
-		    ((boardp->init_tidmask & (1 << i)) == 0)) {
+		    ((boardp->init_tidmask & ASC_TIX_TO_TARGET_ID(i)) == 0)) {
 			continue;
 		}
 		len = asc_prt_line(cp, leftlen, " %d:%u", i, v->cur_dvc_qng[i]);
@@ -5949,7 +6085,7 @@
 	ASC_PRT_NEXT();
 	for (i = 0; i <= ASC_MAX_TID; i++) {
 		if ((boardp->asc_dvc_cfg.chip_scsi_id == i) ||
-		    ((boardp->init_tidmask & (1 << i)) == 0)) {
+		    ((boardp->init_tidmask & ASC_TIX_TO_TARGET_ID(i)) == 0)) {
 			continue;
 		}
 		len = asc_prt_line(cp, leftlen, " %d:%u", i, v->max_dvc_qng[i]);
@@ -5958,21 +6094,18 @@
 	len = asc_prt_line(cp, leftlen, "\n");
 	ASC_PRT_NEXT();
 
-#ifdef ADVANSYS_STATS
-	s = &boardp->asc_stats;
-
 	/* Indicate whether the device has returned queue full status. */
 	len = asc_prt_line(cp, leftlen,
 " Command Queue Full:      ");
 	ASC_PRT_NEXT();
 	for (i = 0; i <= ASC_MAX_TID; i++) {
 		if ((boardp->asc_dvc_cfg.chip_scsi_id == i) ||
-		    ((boardp->init_tidmask & (1 << i)) == 0)) {
+		    ((boardp->init_tidmask & ASC_TIX_TO_TARGET_ID(i)) == 0)) {
 			continue;
 		}
-		if (s->queue_full & (1 << i)) {
+		if (boardp->queue_full & ASC_TIX_TO_TARGET_ID(i)) {
 			len = asc_prt_line(cp, leftlen, " %d:Y-%d",
-				i, s->queue_full_cnt[i]);
+				i, boardp->queue_full_cnt[i]);
 		} else {
 			len = asc_prt_line(cp, leftlen, " %d:N", i);
 		}
@@ -5980,7 +6113,6 @@
 	}
 	len = asc_prt_line(cp, leftlen, "\n");
 	ASC_PRT_NEXT();
-#endif /* ADVANSYS_STATS */
 
  	return totlen;
 }
@@ -6103,11 +6235,11 @@
 {
 	ulong bus_addr;
 
-#if LINUX_VERSION_CODE < ASC_LINUX_VERSION(2,1,0)
+#if LINUX_VERSION_CODE < ASC_LINUX_VERSION(2,0,0)
 	bus_addr = (ulong) buf_addr;
-#else /* version >= v2.1.0 */
+#else /* version >= v2.0.0 */
 	bus_addr = virt_to_bus(buf_addr);
-#endif /* version >= v2.1.0 */
+#endif /* version >= v2.0.0 */
 	return bus_addr;
 }
 
@@ -6119,11 +6251,11 @@
 
 	buf_size = buf_len;
 	asc_sg_head_ptr->entry_cnt = 1;
-#if LINUX_VERSION_CODE < ASC_LINUX_VERSION(2,1,0)
+#if LINUX_VERSION_CODE < ASC_LINUX_VERSION(2,0,0)
 	asc_sg_head_ptr->sg_list[0].addr = (ulong) buf_addr;
-#else /* version >= v2.1.0 */
+#else /* version >= v2.0.0 */
 	asc_sg_head_ptr->sg_list[0].addr = virt_to_bus(buf_addr);
-#endif /* version >= v2.1.0 */
+#endif /* version >= v2.0.0 */
 	asc_sg_head_ptr->sg_list[0].bytes = buf_size;
 	return buf_size;
 }
@@ -6280,8 +6412,6 @@
 /*
  * Return the BIOS address of the adapter at the specified
  * I/O port and with the specified bus type.
- *
- * This function was formerly supplied by the library.
  */
 ushort
 AscGetChipBiosAddress(
@@ -6292,13 +6422,15 @@
     ushort  cfg_lsw ;
     ushort  bios_addr ;
 
-    /*
-     *   We can't get the BIOS address for PCI
-     */
-    if ( bus_type & ASC_IS_PCI )
-    {
-        return( 0 );
-    }
+	/*
+	 * The PCI BIOS is re-located by the motherboard BIOS. Because
+	 * of this the driver can not determine where a PCI BIOS is
+	 * loaded and executes.
+	 */
+	if ( bus_type & ASC_IS_PCI )
+	{
+		return( 0 );
+	}
 
     if( ( bus_type & ASC_IS_EISA ) != 0 )
     {
@@ -7173,6 +7305,8 @@
 						asc_dvc->sdtr_done |= target_id;
 						asc_dvc->init_sdtr |= target_id;
 						asc_dvc->pci_fix_asyn_xfer &= ~target_id;
+						sdtr_data = AscCalSDTRData(asc_dvc,
+							sdtr_xmsg.xfer_period, sdtr_xmsg.req_ack_offset);
 						AscSetChipSDTR(iop_base, sdtr_data, tid_no);
 					} else {
 						q_cntl |= QC_MSG_OUT;
@@ -7180,6 +7314,8 @@
 									  sdtr_xmsg.xfer_period,
 									  sdtr_xmsg.req_ack_offset);
 						asc_dvc->pci_fix_asyn_xfer &= ~target_id;
+						sdtr_data = AscCalSDTRData(asc_dvc,
+							sdtr_xmsg.xfer_period, sdtr_xmsg.req_ack_offset);
 						AscSetChipSDTR(iop_base, sdtr_data, tid_no);
 						asc_dvc->sdtr_done |= target_id;
 						asc_dvc->init_sdtr |= target_id;
@@ -7273,24 +7409,23 @@
 									 (ushort) ((ushort) ASCV_MAX_DVC_QNG_BEG + (ushort) tid_no),
 									 cur_dvc_qng);
 				}
-#ifdef ADVANSYS_STATS
 				{
-					asc_board_t		*boardp;
-					int				i;
-					for (i = 0; i < ASC_NUM_BOARD_SUPPORTED; i++) {
-						if (asc_host[i] == NULL) {
-							continue;
-						}
-						boardp = ASC_BOARDP(asc_host[i]);
-						if (&boardp->asc_dvc_var == asc_dvc) {
-							boardp->asc_stats.queue_full |= target_id;
-							boardp->asc_stats.queue_full_cnt[tid_no] =
-							  cur_dvc_qng;
-							break;
-						}
-					}
+				asc_board_t		*boardp;
+				boardp = (asc_board_t *) asc_dvc->drv_ptr;
+
+				/*
+				 * Set the device queue depth to the number of
+				 * active requests when the QUEUE FULL condition
+				 * was encountered.
+				 */
+				boardp->queue_full |= target_id;
+				boardp->queue_full_cnt[tid_no] = cur_dvc_qng;
+#if ASC_QUEUE_FLOW_CONTROL
+				if (boardp->device[tid_no]->queue_curr_depth > cur_dvc_qng) {
+					boardp->device[tid_no]->queue_curr_depth = cur_dvc_qng;
+				}
+#endif /* ASC_QUEUE_FLOW_CONTROL */
 				}
-#endif
 			}
 		}
 		AscWriteLramWord(iop_base, ASCV_HALTCODE_W, 0);
@@ -7608,8 +7743,10 @@
 	scsiq->r3.host_stat = 0;
 	scsiq->r3.done_stat = 0;
 	scsiq->r2.vm_id = 0;
-	scsiq->cdbptr = (uchar dosfar *) scsiq->cdb;
 	scsiq->r1.data_cnt = buf_len;
+	scsiq->cdbptr = (uchar dosfar *) scsiq->cdb;
+	scsiq->sense_ptr = (uchar dosfar *) scsiq->sense ;
+	scsiq->r1.sense_len = ASC_MIN_SENSE_LEN ;
 	scsiq->r2.tag_code = (uchar) M2_QTAG_MSG_SIMPLE;
 	scsiq->r2.flag = (uchar) ASC_FLAG_SCSIQ_REQ;
 	scsiq->r2.srb_ptr = (ulong) scsiq;
@@ -7622,6 +7759,12 @@
 		}
 		scsiq->r1.data_addr = phy_addr;
 	}
+	if ((phy_addr = AscGetOnePhyAddr(asc_dvc,
+                       (uchar dosfar *) scsiq->sense_ptr,
+                       (ulong) scsiq->r1.sense_len )) == 0L) {
+		return (ERR);
+	}
+	scsiq->r1.sense_addr = phy_addr ;
 	return (0);
 }
 
@@ -8718,21 +8861,22 @@
 {
 	ruchar             *period_table;
 	int                 max_index;
+	int                 min_index;
 	int                 i;
 	period_table = asc_dvc->sdtr_period_tbl;
 	max_index = (int) asc_dvc->max_sdtr_index;
+	min_index = ( int )asc_dvc->host_init_sdtr_index ;
 	if (
-		   (syn_time >= period_table[0])
-		   && (syn_time <= period_table[max_index])
+		   (syn_time <= period_table[max_index])
 	  ) {
-		for (i = 0; i < (max_index - 1); i++) {
+		for (i = min_index; i < (max_index - 1); i++) {
 			if (syn_time <= period_table[i]) {
-				return (i);
+				return ((uchar) i);
 			}
 		}
-		return (max_index);
+		return ((uchar) max_index);
 	} else {
-		return (max_index + 1);
+		return ((uchar) (max_index + 1));
 	}
 }
 
@@ -9537,20 +9681,20 @@
 	asc_dvc->no_scam = 0;
 	asc_dvc->unit_not_ready = 0;
 	asc_dvc->queue_full_or_busy = 0;
+	asc_dvc->redo_scam = 0 ;
+	asc_dvc->res2 = 0 ;
+	asc_dvc->host_init_sdtr_index = 0 ;
+	asc_dvc->res7 = 0 ;
+	asc_dvc->res8 = 0 ;
+	asc_dvc->cfg->can_tagged_qng = 0 ;
+	asc_dvc->cfg->cmd_qng_enabled = 0;
 	asc_dvc->dvc_cntl = ASC_DEF_DVC_CNTL;
 	asc_dvc->init_sdtr = ASC_SCSI_WIDTH_BIT_SET;
 	asc_dvc->max_total_qng = ASC_DEF_MAX_TOTAL_QNG;
 	asc_dvc->scsi_reset_wait = 3;
 	asc_dvc->start_motor = ASC_SCSI_WIDTH_BIT_SET;
 	asc_dvc->max_dma_count = AscGetMaxDmaCount(asc_dvc->bus_type);
-	asc_dvc->redo_scam = 0;
-	asc_dvc->res2 = 0;
-	asc_dvc->host_init_sdtr_index = 0;
-	asc_dvc->res7 = 0;
-	asc_dvc->res8 = 0;
 	asc_dvc->cfg->disc_enable = ASC_SCSI_WIDTH_BIT_SET;
-	asc_dvc->cfg->can_tagged_qng = 0;
-	asc_dvc->cfg->cmd_qng_enabled = 0;
 	asc_dvc->cfg->chip_scsi_id = ASC_DEF_CHIP_SCSI_ID;
 	asc_dvc->cfg->lib_serial_no = ASC_LIB_SERIAL_NUMBER;
 	asc_dvc->cfg->lib_version = (ASC_LIB_VERSION_MAJOR << 8) |
@@ -9839,6 +9983,9 @@
 		scsiq_req->r3.host_stat = scsi_done_q->d3.host_stat;
 		scsiq_req->r3.scsi_stat = scsi_done_q->d3.scsi_stat;
 		scsiq_req->r3.scsi_msg = scsi_done_q->d3.scsi_msg;
+		ASC_DBG4(1, "AscInitPollIsrCallBack: done_stat %x, host_stat %x, scsi_stat %x, scsi_msg %x\n",
+			scsi_done_q->d3.done_stat, scsi_done_q->d3.host_stat,
+			scsi_done_q->d3.scsi_stat, scsi_done_q->d3.scsi_msg);
 		if ((scsi_done_q->d3.scsi_stat == SS_CHK_CONDITION) &&
 			(scsi_done_q->d3.host_stat == 0)) {
 			cp_sen_len = (uchar) ASC_MIN_SENSE_LEN;
@@ -10170,21 +10317,12 @@
 	int                 support_read_cap;
 	int                 tmp_disable_init_sdtr;
 	int                 sta;
-	ulong               phy_addr;
 	dvc_found = 0;
 	tmp_disable_init_sdtr = FALSE;
 	tid_bits = scsiq->r1.target_id;
 	lun = scsiq->r1.target_lun;
 	tid_no = ASC_TIX_TO_TID(scsiq->r2.target_ix);
 	if (
-		   (phy_addr = AscGetOnePhyAddr(asc_dvc,
-										(uchar dosfar *) scsiq->sense_ptr,
-										(ulong) scsiq->r1.sense_len)) == 0L
-	  ) {
-		return (ERR);
-	}
-	scsiq->r1.sense_addr = phy_addr;
-	if (
 		   ((asc_dvc->init_sdtr & tid_bits) != 0)
 		   && ((asc_dvc->sdtr_done & tid_bits) == 0)
 	  ) {
@@ -10301,7 +10439,7 @@
 	int                 status;
 	int                 retry = 0;
 
-	ASC_DBG1(1, "PollQueueDone: timeout_sec %d", timeout_sec);
+	ASC_DBG1(1, "PollQueueDone: timeout_sec %d\n", timeout_sec);
 	do {
 		ASC_DBG(1, "PollQueueDone: before AscExeScsiQueue\n");
 		if ((status = AscExeScsiQueue(asc_dvc,
@@ -10309,6 +10447,7 @@
 			ASC_DBG(1, "PollQueueDone: before AscPollQDone\n");
 			if ((status = AscPollQDone(asc_dvc, scsiq,
 									   timeout_sec)) != 1) {
+				ASC_DBG1(1, "PollQueueDone: status %x\n", status);
 				if (status == 0x80) {
 					if (retry++ > ASC_MAX_INIT_BUSY_RETRY) {
 						break;
@@ -10324,14 +10463,18 @@
 				scsiq->r3.host_stat = 0;
 				scsiq->r3.scsi_stat = 0;
 				scsiq->r3.scsi_msg = 0;
+				ASC_DBG(1, "PollQueueDone: before AscAbortSRB()\n");
 				AscAbortSRB(asc_dvc, (ulong) scsiq);
 			}
+			ASC_DBG1(1, "PollQueueDone: status %x\n", status);
 			ASC_DBG1(1, "PollQueueDone: done_stat %x\n", scsiq->r3.done_stat);
 			return (scsiq->r3.done_stat);
 		}
+		ASC_DBG1(1, "PollQueueDone: status %x\n", status);
 		DvcSleepMilliSecond(5);
 	} while (((status == 0) || (status == 0x80)) &&
 			  retry++ < ASC_MAX_INIT_BUSY_RETRY);
+	ASC_DBG1(1, "PollQueueDone: status %x\n", status);
 	ASC_DBG(1, "PollQueueDone: done_stat QD_WITH_ERROR\n");
 	return (scsiq->r3.done_stat = QD_WITH_ERROR);
 }
@@ -10430,12 +10573,12 @@
 	ASC_REQ_SENSE dosfar *sen;
 	retry = 0;
 	tid_bits = scsiq->r1.target_id;
-	while (retry++ < 2) {
+	while (retry++ < 4) {
 		PollScsiTestUnitReady(asc_dvc, scsiq);
 		if (scsiq->r3.done_stat == 0x01) {
 			return (1);
 		} else if (scsiq->r3.done_stat == QD_WITH_ERROR) {
-			DvcSleepMilliSecond(100);
+			DvcSleepMilliSecond(200);
 			sen = (ASC_REQ_SENSE dosfar *) scsiq->sense_ptr;
 			if ((scsiq->r3.scsi_stat == SS_CHK_CONDITION) &&
 				((sen->err_code & 0x70) != 0)) {
@@ -10451,9 +10594,10 @@
 					} else {
 						DvcSleepMilliSecond(5000);
 					}
-				} else if (sen->sense_key == SCSI_SENKEY_ATTENSION) {
-					DvcSleepMilliSecond(500);
+				} else if (sen->sense_key == SCSI_SENKEY_ATTENTION) {
+					DvcSleepMilliSecond( ( ulong )( 500L*retry ) ) ;
 				} else {
+					DvcSleepMilliSecond( 500 ) ;
 					break;
 				}
 			} else {
@@ -10485,6 +10629,7 @@
 	while (TRUE) {
 		if (asc_dvc->err_code != 0) {
 			scsiq->r3.done_stat = QD_WITH_ERROR;
+			ASC_DBG1(1, "AscPollQDone: err_code %x\n", asc_dvc->err_code);
 			sta = ERR;
 			break;
 		}
@@ -10497,10 +10642,12 @@
 		}
 		DvcSleepMilliSecond(10);
 		if (loop++ > loop_end) {
+			ASC_DBG(1, "AscPollQDone: loop finished\n");
 			sta = 0;
 			break;
 		}
 		if (AscIsChipHalted(iop_base)) {
+			ASC_DBG(1, "AscPollQDone: AscIsChipHalted()\n");
 #if !CC_ASCISR_CHECK_INT_PENDING
 			AscAckInterrupt(iop_base);
 #endif
@@ -10508,6 +10655,7 @@
 			loop = 0;
 		} else {
 			if (AscIsIntPending(iop_base)) {
+				ASC_DBG(1, "AscPollQDone: AscIsIntPending()\n");
 #if !CC_ASCISR_CHECK_INT_PENDING
 				AscAckInterrupt(iop_base);
 #endif
diff -u --recursive --new-file v2.1.9/linux/drivers/scsi/scsi.c linux/drivers/scsi/scsi.c
--- v2.1.9/linux/drivers/scsi/scsi.c	Fri Nov  1 17:13:18 1996
+++ linux/drivers/scsi/scsi.c	Thu Nov 14 18:20:31 1996
@@ -642,26 +642,6 @@
     scsi_result[1] |= 0x80;     /* removable */
   }
 
-  if (!strncmp (scsi_result + 8, "NEC", 3)) {
-    if (!strncmp (scsi_result + 16, "CD-ROM DRIVE:84 ", 16) ||
-        !strncmp (scsi_result + 16, "CD-ROM DRIVE:25", 15))
-      SDpnt->manufacturer = SCSI_MAN_NEC_OLDCDR;
-    else
-      SDpnt->manufacturer = SCSI_MAN_NEC;
-  }
-  else if (!strncmp (scsi_result + 8, "TOSHIBA", 7))
-    SDpnt->manufacturer = SCSI_MAN_TOSHIBA;
-  else if (!strncmp (scsi_result + 8, "SONY", 4))
-    SDpnt->manufacturer = SCSI_MAN_SONY;
-  else if (!strncmp (scsi_result + 8, "PIONEER", 7))
-    SDpnt->manufacturer = SCSI_MAN_PIONEER;
-  else if (!strncmp (scsi_result + 8, "MATSHITA", 8))
-    SDpnt->manufacturer = SCSI_MAN_MATSHITA;
-  else if (!strncmp (scsi_result + 8, "HP", 2))
-    SDpnt->manufacturer = SCSI_MAN_HP;
-  else
-    SDpnt->manufacturer = SCSI_MAN_UNKNOWN;
-
   memcpy (SDpnt->vendor, scsi_result + 8, 8);
   memcpy (SDpnt->model, scsi_result + 16, 16);
   memcpy (SDpnt->rev, scsi_result + 32, 4);
diff -u --recursive --new-file v2.1.9/linux/drivers/scsi/scsi.h linux/drivers/scsi/scsi.h
--- v2.1.9/linux/drivers/scsi/scsi.h	Wed Oct 16 10:48:22 1996
+++ linux/drivers/scsi/scsi.h	Wed Nov 13 08:11:17 1996
@@ -123,19 +123,6 @@
  */
 
 /*
- *      Manufacturers list
- */
-
-#define SCSI_MAN_UNKNOWN     0
-#define SCSI_MAN_NEC         1
-#define SCSI_MAN_TOSHIBA     2
-#define SCSI_MAN_NEC_OLDCDR  3
-#define SCSI_MAN_SONY        4
-#define SCSI_MAN_PIONEER     5
-#define SCSI_MAN_MATSHITA    6
-#define SCSI_MAN_HP          7
-
-/*
  *  As the scsi do command functions are intelligent, and may need to
  *  redo a command, we need to keep track of the last command
  *  executed on each one.
diff -u --recursive --new-file v2.1.9/linux/drivers/scsi/sd.c linux/drivers/scsi/sd.c
--- v2.1.9/linux/drivers/scsi/sd.c	Tue Oct 29 19:58:13 1996
+++ linux/drivers/scsi/sd.c	Thu Nov 14 15:16:45 1996
@@ -37,6 +37,7 @@
 #include <linux/interrupt.h>
 
 #include <asm/system.h>
+#include <asm/io.h>
 
 #define MAJOR_NR SCSI_DISK_MAJOR
 #include <linux/blk.h>
@@ -660,10 +661,10 @@
      * a bounce buffer if we are straddling the 16Mb line 
      */ 
     if (contiguous && SCpnt->request.bh &&
-	((long) SCpnt->request.bh->b_data) 
+      virt_to_phys(SCpnt->request.bh->b_data) 
 	+ (SCpnt->request.nr_sectors << 9) - 1 > ISA_DMA_THRESHOLD 
 	&& SCpnt->host->unchecked_isa_dma) {
-	if(((long) SCpnt->request.bh->b_data) > ISA_DMA_THRESHOLD)
+      if(virt_to_phys(SCpnt->request.bh->b_data) > ISA_DMA_THRESHOLD)
 	    bounce_buffer = (char *) scsi_malloc(bounce_size);
 	if(!bounce_buffer) contiguous = 0;
     }
@@ -720,7 +721,7 @@
 	    if(!bhp || !CONTIGUOUS_BUFFERS(bhp,bh) ||
 	       !CLUSTERABLE_DEVICE(SCpnt) ||
 	       (SCpnt->host->unchecked_isa_dma &&
-		((unsigned long) bh->b_data-1) == ISA_DMA_THRESHOLD)) {
+		virt_to_phys(bh->b_data-1) == ISA_DMA_THRESHOLD)) {
 		if (count < SCpnt->host->sg_tablesize) count++;
 		else break;
 	    }
@@ -730,7 +731,7 @@
 	}
 #if 0
 	if(SCpnt->host->unchecked_isa_dma &&
-	   ((unsigned int) SCpnt->request.bh->b_data-1) == ISA_DMA_THRESHOLD) count--;
+	 virt_to_phys(SCpnt->request.bh->b_data-1) == ISA_DMA_THRESHOLD) count--;
 #endif
 	SCpnt->use_sg = count;  /* Number of chains */
 	/* scsi_malloc can only allocate in chunks of 512 bytes */
@@ -762,7 +763,7 @@
 		sgpnt[count].length += bh->b_size;
 		counted += bh->b_size >> 9;
 		
-		if (((long) sgpnt[count].address) + sgpnt[count].length - 1 > 
+		if (virt_to_phys(sgpnt[count].address) + sgpnt[count].length - 1 >
 		    ISA_DMA_THRESHOLD && (SCpnt->host->unchecked_isa_dma) &&
 		    !sgpnt[count].alt_address) {
 		    sgpnt[count].alt_address = sgpnt[count].address;
@@ -809,7 +810,7 @@
 		   && CLUSTERABLE_DEVICE(SCpnt)) {
 		    char * tmp;
 		    
-		    if (((long) sgpnt[count].address) + sgpnt[count].length +
+		  if (virt_to_phys(sgpnt[count].address) + sgpnt[count].length +
 			bhp->b_size - 1 > ISA_DMA_THRESHOLD && 
 			(SCpnt->host->unchecked_isa_dma) &&
 			!sgpnt[count].alt_address) continue;
@@ -871,7 +872,7 @@
     /* Now handle the possibility of DMA to addresses > 16Mb */
     
     if(SCpnt->use_sg == 0){
-	if (((long) buff) + (this_count << 9) - 1 > ISA_DMA_THRESHOLD && 
+      if (virt_to_phys(buff) + (this_count << 9) - 1 > ISA_DMA_THRESHOLD && 
 	    (SCpnt->host->unchecked_isa_dma)) {
 	    if(bounce_buffer)
 		buff = bounce_buffer;
diff -u --recursive --new-file v2.1.9/linux/drivers/scsi/sr.c linux/drivers/scsi/sr.c
--- v2.1.9/linux/drivers/scsi/sr.c	Wed Oct 16 10:48:22 1996
+++ linux/drivers/scsi/sr.c	Wed Nov 13 08:11:17 1996
@@ -17,6 +17,9 @@
  *	 Modified by Thomas Quinot thomas@melchior.cuivre.fdn.fr to
  *	 provide auto-eject.
  *
+ *          Modified by Gerd Knorr <kraxel@cs.tu-berlin.de> to support the
+ *          generic cdrom interface
+ *
  */
 
 #include <linux/module.h>
@@ -28,7 +31,9 @@
 #include <linux/string.h>
 #include <linux/errno.h>
 #include <linux/cdrom.h>
+#include <linux/ucdrom.h>
 #include <linux/interrupt.h>
+#include <linux/config.h>
 #include <asm/system.h>
 
 #define MAJOR_NR SCSI_CDROM_MAJOR
@@ -49,53 +54,48 @@
 static void sr_detach(Scsi_Device *);
 
 struct Scsi_Device_Template sr_template = {NULL, "cdrom", "sr", NULL, TYPE_ROM, 
-					       SCSI_CDROM_MAJOR, 0, 0, 0, 1,
-					       sr_detect, sr_init,
-					       sr_finish, sr_attach, sr_detach};
+                                           SCSI_CDROM_MAJOR, 0, 0, 0, 1,
+                                           sr_detect, sr_init,
+                                           sr_finish, sr_attach, sr_detach};
 
 Scsi_CD * scsi_CDs = NULL;
 static int * sr_sizes;
 
 static int * sr_blocksizes;
 
-static int sr_open(struct inode *, struct file *);
+static int sr_open(struct cdrom_device_info*, int);
 void get_sectorsize(int);
-void sr_photocd(struct inode *);
-
-extern int sr_ioctl(struct inode *, struct file *, unsigned int, unsigned long);
 
 void requeue_sr_request (Scsi_Cmnd * SCpnt);
-static int check_cdrom_media_change(kdev_t);
+static int sr_media_change(struct cdrom_device_info*, int);
 
-static void sr_release(struct inode * inode, struct file * file)
+static void sr_release(struct cdrom_device_info *cdi)
 {
-	sync_dev(inode->i_rdev);
-	if(! --scsi_CDs[MINOR(inode->i_rdev)].device->access_count)
-	{
-	    sr_ioctl(inode, NULL, SCSI_IOCTL_DOORUNLOCK, 0);
-	    if (scsi_CDs[MINOR(inode->i_rdev)].auto_eject)
-		sr_ioctl(inode, NULL, CDROMEJECT, 0);
-	}
-	if (scsi_CDs[MINOR(inode->i_rdev)].device->host->hostt->usage_count)
-	    (*scsi_CDs[MINOR(inode->i_rdev)].device->host->hostt->usage_count)--;
+	sync_dev(cdi->dev);
+	scsi_CDs[MINOR(cdi->dev)].device->access_count--;
+	if (scsi_CDs[MINOR(cdi->dev)].device->host->hostt->usage_count)
+	    (*scsi_CDs[MINOR(cdi->dev)].device->host->hostt->usage_count)--;
 	if(sr_template.usage_count) (*sr_template.usage_count)--;
 }
 
-static struct file_operations sr_fops = 
-{
-	NULL,			/* lseek - default */
-	block_read,		/* read - general block-dev read */
-	block_write,		/* write - general block-dev write */
-	NULL,			/* readdir - bad */
-	NULL,			/* select */
-	sr_ioctl,		/* ioctl */
-	NULL,			/* mmap */
-	sr_open,       	/* special open code */
-	sr_release,		/* release */
-	NULL,			/* fsync */
-	NULL,			/* fasync */
-	check_cdrom_media_change,  /* Disk change */
-	NULL			/* revalidate */
+static struct cdrom_device_ops sr_dops = {
+        sr_open,                      /* open */
+        sr_release,                   /* release */
+        sr_drive_status,              /* drive status */
+        sr_disk_status,               /* disc status */
+        sr_media_change,              /* media changed */
+        sr_tray_move,                 /* tray move */
+        sr_lock_door,                 /* lock door */
+        NULL,                         /* select speed */
+        NULL,                         /* select disc */
+        sr_get_last_session,          /* get last session */
+        sr_get_mcn,                   /* get universal product code */
+        sr_reset,                     /* hard reset */
+        sr_audio_ioctl,               /* audio ioctl */
+        sr_dev_ioctl,                 /* device-specific ioctl */
+        CDC_CLOSE_TRAY | CDC_OPEN_TRAY| CDC_LOCK |
+        CDC_MULTI_SESSION | CDC_MCN | CDC_MEDIA_CHANGED | CDC_PLAY_AUDIO,
+        0
 };
 
 /*
@@ -108,38 +108,38 @@
  * an inode for that to work, and we do not always have one.
  */
 
-int check_cdrom_media_change(kdev_t full_dev){
-	int retval, target;
-	struct inode inode;
-	int flag = 0;
-    
-	target =  MINOR(full_dev);
-    
-	if (target >= sr_template.nr_dev) {
-		printk("CD-ROM request error: invalid device.\n");
-		return 0;
-	};
-    
-	inode.i_rdev = full_dev;  /* This is all we really need here */
-	retval = sr_ioctl(&inode, NULL, SCSI_IOCTL_TEST_UNIT_READY, 0);
+int sr_media_change(struct cdrom_device_info *cdi, int slot){
+	int retval;
+
+        if (CDSL_CURRENT != slot) {
+                /* no changer support */
+                return -EINVAL;
+        }
+        
+	retval = scsi_ioctl(scsi_CDs[MINOR(cdi->dev)].device,
+                            SCSI_IOCTL_TEST_UNIT_READY, 0);
     
-	if(retval){ /* Unable to test, unit probably not ready.  This usually
+	if(retval){
+                /* Unable to test, unit probably not ready.  This usually
 		 * means there is no disc in the drive.  Mark as changed,
 		 * and we will figure it out later once the drive is
 		 * available again.  */
 	
-	scsi_CDs[target].device->changed = 1;
-	return 1; /* This will force a flush, if called from
-		   * check_disk_change */
+                scsi_CDs[MINOR(cdi->dev)].device->changed = 1;
+                return 1; /* This will force a flush, if called from
+                           * check_disk_change */
 	};
     
-	retval = scsi_CDs[target].device->changed;
-	if(!flag) {
-	scsi_CDs[target].device->changed = 0;
-	/* If the disk changed, the capacity will now be different,
-	 * so we force a re-read of this information */
-	if (retval) scsi_CDs[target].needs_sector_size = 1;
-	};
+	retval = scsi_CDs[MINOR(cdi->dev)].device->changed;
+        scsi_CDs[MINOR(cdi->dev)].device->changed = 0;
+        /* If the disk changed, the capacity will now be different,
+         * so we force a re-read of this information */
+        if (retval) {
+#ifdef CONFIG_BLK_DEV_SR_VENDOR
+                sr_cd_check(cdi);
+#endif
+                scsi_CDs[MINOR(cdi->dev)].needs_sector_size = 1;
+        }
 	return retval;
 }
 
@@ -361,317 +361,26 @@
     }
 }
 
-/*
- * Here I tried to implement support for multisession-CD's
- * 
- * Much of this has do be done with vendor-specific SCSI-commands, because
- * multisession is newer than the SCSI-II standard.
- * So I have to complete it step by step. Useful information is welcome.
- *
- * Actually works:
- *   - NEC:     Detection and support of multisession CD's. Special handling
- *              for XA-disks is not necessary.
- *     
- *   - TOSHIBA: setting density is done here now, mounting PhotoCD's should
- *              work now without running the program "set_density"
- *              Multisession CD's are supported too.
- *
- *   Gerd Knorr <kraxel@cs.tu-berlin.de> 
- */
-/*
- * 19950704 operator@melchior.cuivre.fdn.fr (Thomas Quinot)
- *
- *   - SONY:	Same as Nec.
- *
- *   - PIONEER: works with SONY code (may be others too ?)
- *
- * 19961011
- *
- *   - HP:      reportedly working.
- */
-
-void sr_photocd(struct inode *inode)
-{
-    unsigned long   sector,min,sec,frame;
-    unsigned char   buf[40];    /* the buffer for the ioctl */
-    Scsi_Ioctl_Command *sic = (Scsi_Ioctl_Command *) buf;
-#define CLEAR_CMD_BUFFER memset (buf, 0, sizeof buf);
-    unsigned char   *cmd;       /* the scsi-command */
-    unsigned char   *send;      /* the data we send to the drive ... */
-    unsigned char   *rec;       /* ... and get back */
-    int             rc,is_xa,no_multi;
-    
-    if (scsi_CDs[MINOR(inode->i_rdev)].xa_flags & 0x02) {
-#ifdef DEBUG
-	printk(KERN_DEBUG "sr_photocd: CDROM and/or driver do not support multisession CD's");
-#endif
-	return;
-    }
-    
-    if (!suser()) {
-	/* I'm not the superuser, so SCSI_IOCTL_SEND_COMMAND isn't allowed
-         * for me. That's why mpcd_sector will be initialized with zero,
-         * because I'm not able to get the right value. Necessary only if
-         * access_count is 1, else no disk change happened since the last
-         * call of this function and we can keep the old value.
-	 */
-	if (1 == scsi_CDs[MINOR(inode->i_rdev)].device->access_count) {
-	    scsi_CDs[MINOR(inode->i_rdev)].mpcd_sector = 0;
-	    scsi_CDs[MINOR(inode->i_rdev)].xa_flags &= ~0x01;
-	}
-	return;
-    }
-    
-    sector   = 0;
-    is_xa    = 0;
-    no_multi = 0;
-    cmd = rec = sic->data;
-    
-    switch(scsi_CDs[MINOR(inode->i_rdev)].device->manufacturer) {
-	
-    case SCSI_MAN_NEC:
-#ifdef DEBUG
-	printk(KERN_DEBUG "sr_photocd: use NEC code\n");
-#endif
-	CLEAR_CMD_BUFFER;
-	sic->inlen  = 0x0;   /* we send nothing...     */
-	sic->outlen = 0x16;  /* and receive 0x16 bytes */
-	cmd[0] = 0xde;
-	cmd[1] = 0x03;
-	cmd[2] = 0xb0;
-	rc = kernel_scsi_ioctl(scsi_CDs[MINOR(inode->i_rdev)].device,
-			   SCSI_IOCTL_SEND_COMMAND, sic);
-	if (rc != 0) {
-            if (rc != 0x28000002) /* drop "not ready" */
-                printk(KERN_WARNING"sr_photocd: ioctl error (NEC): 0x%x\n",rc);
-	    break;
-	}
-	if (rec[14] != 0 && rec[14] != 0xb0) {
-	    printk(KERN_INFO"sr_photocd: (NEC) Hmm, seems the CDROM doesn't support multisession CD's\n");
-	    no_multi = 1;
-	    break;
-	}
-	min   = (unsigned long) rec[15]/16*10 + (unsigned long) rec[15]%16;
-	sec   = (unsigned long) rec[16]/16*10 + (unsigned long) rec[16]%16;
-	frame = (unsigned long) rec[17]/16*10 + (unsigned long) rec[17]%16;
-	sector = min*CD_SECS*CD_FRAMES + sec*CD_FRAMES + frame;
-	is_xa  = (rec[14] == 0xb0);
-	break;
-	
-    case SCSI_MAN_TOSHIBA:
-#ifdef DEBUG
-	printk(KERN_DEBUG "sr_photocd: use TOSHIBA code\n");
-#endif
-	
-	/* we request some disc information (is it a XA-CD ?,
-	 * where starts the last session ?) */
-	CLEAR_CMD_BUFFER;
-	sic->inlen  = 0; /* we send nothing...  */
-	sic->outlen = 4; /* and receive 4 bytes */
-	cmd[0]                  = (unsigned char) 0x00c7;
-	cmd[1]                  = (unsigned char) 3;
-	rc = kernel_scsi_ioctl(scsi_CDs[MINOR(inode->i_rdev)].device,
-			       SCSI_IOCTL_SEND_COMMAND, sic);
-	if (rc != 0) {
-	    if (rc == 0x28000002) {
-		/* Got a "not ready" - error. No chance to find out if this is
-		 * because there is no CD in the drive or because the drive
-		 * don't knows multisession CD's. So I need to do an extra
-                 * check... */
-		if (!kernel_scsi_ioctl(scsi_CDs[MINOR(inode->i_rdev)].device,
-				       SCSI_IOCTL_TEST_UNIT_READY, NULL)) {
-		    printk(KERN_INFO "sr_photocd: (TOSHIBA) Hmm, seems the CDROM doesn't support multisession CD's\n");
-		    no_multi = 1;
-		}
-	    } else
-		printk(KERN_WARNING"sr_photocd: ioctl error (TOSHIBA #1): 0x%x\n",rc);
-	    break; /* if the first ioctl fails, we don't call the second one */
-	}
-	is_xa  = (rec[0] == 0x20);
-	min    = (unsigned long) rec[1]/16*10 + (unsigned long) rec[1]%16;
-	sec    = (unsigned long) rec[2]/16*10 + (unsigned long) rec[2]%16;
-	frame  = (unsigned long) rec[3]/16*10 + (unsigned long) rec[3]%16;
-	sector = min*CD_SECS*CD_FRAMES + sec*CD_FRAMES + frame;
-	if (sector)
-	    sector -= CD_BLOCK_OFFSET;
-	
-	/* now we do a get_density... */
-	CLEAR_CMD_BUFFER;
-	sic->inlen  = 0;  /* we send nothing...  */
-	sic->outlen = 12; /* and receive 12 bytes */
-	cmd[0]                  = (unsigned char) MODE_SENSE;
-	cmd[2]                  = (unsigned char) 1;
-	cmd[4]                  = (unsigned char) 12;
-	rc = kernel_scsi_ioctl(scsi_CDs[MINOR(inode->i_rdev)].device,
-			       SCSI_IOCTL_SEND_COMMAND, sic);
-	if (rc != 0) {
-	    printk(KERN_WARNING "sr_photocd: ioctl error (TOSHIBA #2): 0x%x\n",rc);
-	    break;
-	}
-#ifdef DEBUG
-	printk(KERN_DEBUG "sr_photocd: get_density: 0x%x\n",rec[4]);
-#endif
-	
-	/* ...and only if necessary a set_density */
-	if ((rec[4] != 0x81 && is_xa) || (rec[4] != 0 && !is_xa)) {
-#ifdef DEBUG
-	    printk(KERN_DEBUG "sr_photocd: doing set_density\n");
-#endif
-	    CLEAR_CMD_BUFFER;
-	    sic->inlen  = 12; /* we send 12 bytes... */
-	    sic->outlen = 0;  /* and receive nothing */
-	    cmd[0]                  = (unsigned char) MODE_SELECT;
-	    cmd[1]                  = (unsigned char) (1 << 4);
-	    cmd[4]                  = (unsigned char) 12;
-            send = &cmd[6]; 		/* this is a 6-Byte command    */
-            send[ 3]                = (unsigned char) 0x08; /* data for cmd */
-            /* density 0x81 for XA, 0 else */
-            send[ 4]                = (is_xa) ? 
-                                    (unsigned char) 0x81 : (unsigned char) 0;  
-            send[10]                = (unsigned char) 0x08;
-	    rc = kernel_scsi_ioctl(scsi_CDs[MINOR(inode->i_rdev)].device,
-				   SCSI_IOCTL_SEND_COMMAND, sic);
-	    if (rc != 0) {
-		printk(KERN_WARNING "sr_photocd: ioctl error (TOSHIBA #3): 0x%x\n",rc);
-	    }
-	    /* The set_density command may have changed the
-             * sector size or capacity. */
-	    scsi_CDs[MINOR(inode->i_rdev)].needs_sector_size = 1;
-	}
-	break;
-
-    case SCSI_MAN_SONY: /* Thomas QUINOT <thomas@melchior.cuivre.fdn.fr> */
-    case SCSI_MAN_PIONEER:
-    case SCSI_MAN_MATSHITA:
-#ifdef DEBUG
-	printk(KERN_DEBUG "sr_photocd: use SONY/PIONEER/MATSHITA code\n");
-#endif
-	get_sectorsize(MINOR(inode->i_rdev));	/* spinup (avoid timeout) */
-	CLEAR_CMD_BUFFER;
-	sic->inlen  = 0x0;  /* we send nothing...     */
-	sic->outlen = 0x0c; /* and receive 0x0c bytes */
-        
-	cmd[0] = READ_TOC;
-	cmd[8] = 0x0c;
-	cmd[9] = 0x40;
-	rc = kernel_scsi_ioctl(scsi_CDs[MINOR(inode->i_rdev)].device,
-			       SCSI_IOCTL_SEND_COMMAND, sic);
-	
-	if (rc != 0) {
-            if (rc != 0x28000002) /* drop "not ready" */
-                printk(KERN_WARNING "sr_photocd: ioctl error (SONY/PIONEER/MATSHITA): 0x%x\n",rc);
-	    break;
-	}
-	if ((rec[0] << 8) + rec[1] != 0x0a) {
-	    printk(KERN_INFO "sr_photocd: (SONY/PIONEER/MATSHITA) Hmm, seems the CDROM doesn't support multisession CD's\n");
-	    no_multi = 1;
-	    break;
-	}
-	sector = rec[11] + (rec[10] << 8) + (rec[9] << 16) + (rec[8] << 24);
-	is_xa = !!sector;
-	break;
-    case SCSI_MAN_HP:
-#define DEBUG
-#ifdef DEBUG
-        printk(KERN_DEBUG "sr_photocd: use HP code\n");
-#endif
-        CLEAR_CMD_BUFFER;
-	sic->inlen  = 0x0; /* we send nothing...  */
-	sic->outlen = 0x4; /* and receive 4 bytes */
-        cmd[0] = 0x43; /* Read TOC */
-        cmd[8] = 0x04;
-        cmd[9] = 0x40;
-        rc = kernel_scsi_ioctl(scsi_CDs[MINOR(inode->i_rdev)].device,
-                               SCSI_IOCTL_SEND_COMMAND, sic);
-        if (rc != 0) {
-            if (rc != 0x28000002) /* drop "not ready" */
-                printk(KERN_WARNING "sr_photocd: ioctl error (HP-1): 0x%x\n",rc);
-	break;
-        }
-		
-        if ((rc = rec[2]) == 0) {
-          printk (KERN_WARNING "sr_photocd: (HP) No finished session");
-          break;
-        }
-        CLEAR_CMD_BUFFER;
-	sic->inlen  = 0x0;  /* we send nothing...     */
-	sic->outlen = 0x0c; /* and receive 0x0c bytes */
-        cmd[0] = 0x43; /* Read TOC */
-        cmd[6] = rc & 0x7f;  /* number of last session */
-        cmd[8] = 0x0c;
-        cmd[9] = 0x40;
-        rc = kernel_scsi_ioctl(scsi_CDs[MINOR(inode->i_rdev)].device,
-                               SCSI_IOCTL_SEND_COMMAND, sic);
-        if (rc != 0) {
-            if (rc != 0x28000002) /* drop "not ready" */
-                printk(KERN_WARNING "sr_photocd: ioctl error (HP-2): 0x%x\n",rc);
-            break;
-        }
-#undef STRICT_HP
-#ifdef STRICT_HP
-        sector = rec[11] + (rec[10] << 8) + (rec[9] << 16);
-        /* HP documentation states that Logical Start Address is
-           returned as three (!) bytes, and that rec[8] is
-           reserved. This is strange, because a LBA usually is
-           4 bytes long. */
-#else
-	sector = rec[11] + (rec[10] << 8) + (rec[9] << 16) + (rec[8] << 24);
-#endif
-        is_xa = !!sector;
-        break;
-    case SCSI_MAN_NEC_OLDCDR:
-    case SCSI_MAN_UNKNOWN:
-    default:
-	sector = 0;
-	no_multi = 1;
-	break; }
-    
-#ifdef DEBUG
-    if (sector)
-        printk (KERN_DEBUG "sr_photocd: multisession CD detected. start: %lu\n",sector);
-#endif
-#undef DEBUG
-
-    scsi_CDs[MINOR(inode->i_rdev)].mpcd_sector = sector;
-    if (is_xa)
-	scsi_CDs[MINOR(inode->i_rdev)].xa_flags |= 0x01;
-    else
-	scsi_CDs[MINOR(inode->i_rdev)].xa_flags &= ~0x01;
-    if (no_multi)
-	scsi_CDs[MINOR(inode->i_rdev)].xa_flags |= 0x02;
-    return;
-}
-
-static int sr_open(struct inode * inode, struct file * filp)
+static int sr_open(struct cdrom_device_info *cdi, int purpose)
 {
-    if(MINOR(inode->i_rdev) >= sr_template.nr_dev || 
-       !scsi_CDs[MINOR(inode->i_rdev)].device) return -ENXIO;   /* No such device */
-
-    if (filp->f_mode & 2)  
-	return -EROFS;
+    check_disk_change(cdi->dev);
 
-    check_disk_change(inode->i_rdev);
-    
-    if(!scsi_CDs[MINOR(inode->i_rdev)].device->access_count++)
-	sr_ioctl(inode, NULL, SCSI_IOCTL_DOORLOCK, 0);
-    if (scsi_CDs[MINOR(inode->i_rdev)].device->host->hostt->usage_count)
-	(*scsi_CDs[MINOR(inode->i_rdev)].device->host->hostt->usage_count)++;
+    scsi_CDs[MINOR(cdi->dev)].device->access_count++;
+    if (scsi_CDs[MINOR(cdi->dev)].device->host->hostt->usage_count)
+	(*scsi_CDs[MINOR(cdi->dev)].device->host->hostt->usage_count)++;
     if(sr_template.usage_count) (*sr_template.usage_count)++;
-    
-    sr_photocd(inode);
-    
+
     /* If this device did not have media in the drive at boot time, then
      * we would have been unable to get the sector size.  Check to see if
      * this is the case, and try again.
      */
 
-    if(scsi_CDs[MINOR(inode->i_rdev)].needs_sector_size)
-	get_sectorsize(MINOR(inode->i_rdev));
+    if(scsi_CDs[MINOR(cdi->dev)].needs_sector_size)
+	get_sectorsize(MINOR(cdi->dev));
 
     return 0;
 }
 
-
 /*
  * do_sr_request() is the request handler function for the sr driver.
  * Its function in life is to take block device requests, and
@@ -1079,6 +788,19 @@
     
     SDp->scsi_request_fn = do_sr_request;
     scsi_CDs[i].device = SDp;
+    
+    scsi_CDs[i].cdi.ops        = &sr_dops;
+    scsi_CDs[i].cdi.handle     = &scsi_CDs[i];
+    scsi_CDs[i].cdi.dev        = MKDEV(MAJOR_NR,i);
+    scsi_CDs[i].cdi.mask       = 0;
+    scsi_CDs[i].cdi.speed      = 1;
+    scsi_CDs[i].cdi.capacity   = 1;
+    register_cdrom(&scsi_CDs[i].cdi, "sr");
+            
+#ifdef CONFIG_BLK_DEV_SR_VENDOR
+    sr_vendor_init(i);
+#endif
+
     sr_template.nr_dev++;
     if(sr_template.nr_dev > sr_template.dev_max)
 	panic ("scsi_devices corrupt (sr)");
@@ -1184,7 +906,7 @@
     if(sr_template.dev_noticed == 0) return 0;
 
     if(!sr_registered) {
-	if (register_blkdev(MAJOR_NR,"sr",&sr_fops)) {
+	if (register_blkdev(MAJOR_NR,"sr",&cdrom_fops)) {
 	    printk("Unable to get major %d for SCSI-CD\n",MAJOR_NR);
 	    return 1;
 	}
@@ -1193,7 +915,8 @@
 
     
     if (scsi_CDs) return 0;
-    sr_template.dev_max = sr_template.dev_noticed + SR_EXTRA_DEVS;
+    sr_template.dev_max =
+            sr_template.dev_noticed + SR_EXTRA_DEVS;
     scsi_CDs = (Scsi_CD *) scsi_init_malloc(sr_template.dev_max * sizeof(Scsi_CD), GFP_ATOMIC);
     memset(scsi_CDs, 0, sr_template.dev_max * sizeof(Scsi_CD));
 
@@ -1222,6 +945,7 @@
 	scsi_CDs[i].capacity = 0x1fffff;
 	scsi_CDs[i].sector_size = 2048;  /* A guess, just in case */
 	scsi_CDs[i].needs_sector_size = 1;
+	scsi_CDs[i].device->changed = 1; /* force recheck CD type */
 #if 0
 	/* seems better to leave this for later */
 	get_sectorsize(i);
@@ -1230,7 +954,6 @@
 	scsi_CDs[i].use = 1;
 	scsi_CDs[i].ten = 1;
 	scsi_CDs[i].remap = 1;
-	scsi_CDs[i].auto_eject = 0; /* Default is not to eject upon unmount. */
 	sr_sizes[i] = scsi_CDs[i].capacity >> (BLOCK_SIZE_BITS - 9);
     }
     
@@ -1266,6 +989,7 @@
 	     * Reset things back to a sane state so that one can re-load a new
 	     * driver (perhaps the same one).
 	     */
+            unregister_cdrom(&(cpnt->cdi));
 	    cpnt->device = NULL;
 	    cpnt->capacity = 0;
 	    SDp->attached--;
@@ -1281,14 +1005,14 @@
 #ifdef MODULE
 
 int init_module(void) {
-    sr_template.usage_count = &mod_use_count_;
-    return scsi_register_module(MODULE_SCSI_DEV, &sr_template);
+        sr_template.usage_count = &mod_use_count_;
+        return scsi_register_module(MODULE_SCSI_DEV, &sr_template);
 }
 
 void cleanup_module( void) 
 {
     scsi_unregister_module(MODULE_SCSI_DEV, &sr_template);
-    unregister_blkdev(SCSI_CDROM_MAJOR, "sr");
+    unregister_blkdev(MAJOR_NR, "sr");
     sr_registered--;
     if(scsi_CDs != NULL) {
 	scsi_init_free((char *) scsi_CDs,
diff -u --recursive --new-file v2.1.9/linux/drivers/scsi/sr.h linux/drivers/scsi/sr.h
--- v2.1.9/linux/drivers/scsi/sr.h	Sat Nov 11 13:22:17 1995
+++ linux/drivers/scsi/sr.h	Thu Nov 14 15:26:48 1996
@@ -17,24 +17,45 @@
 #ifndef _SR_H
 #define _SR_H
 
+#include <linux/config.h>
+
 #include "scsi.h"
 
 typedef struct
 	{
 	unsigned 	capacity;		/* size in blocks 			*/
 	unsigned 	sector_size;		/* size in bytes 			*/
-	Scsi_Device  	*device;		
-	unsigned long   mpcd_sector;            /* for reading multisession-CD's        */
-	char            xa_flags;               /* some flags for handling XA-CD's      */
+	Scsi_Device  	*device;
+        unsigned int    vendor;                 /* vendor code, see sr_vendor.c         */
+	unsigned long   ms_offset;              /* for reading multisession-CD's        */
 	unsigned char	sector_bit_size;	/* sector size = 2^sector_bit_size	*/
 	unsigned char	sector_bit_shift;	/* sectors/FS block = 2^sector_bit_shift*/
 	unsigned 	needs_sector_size:1;   	/* needs to get sector size */
 	unsigned 	ten:1;			/* support ten byte commands		*/
 	unsigned 	remap:1;		/* support remapping			*/
 	unsigned 	use:1;			/* is this device still supportable	*/
-	unsigned	auto_eject:1;		/* auto-eject medium on last release.	*/
+	unsigned        xa_flag:1;              /* CD has XA sectors */
+	struct cdrom_device_info cdi;
 	} Scsi_CD;
 	
 extern Scsi_CD * scsi_CDs;
+
+int sr_do_ioctl(int, unsigned char*, void*, unsigned);
+
+int sr_lock_door(struct cdrom_device_info*, int);
+int sr_tray_move(struct cdrom_device_info*, int);
+int sr_drive_status(struct cdrom_device_info*, int);
+int sr_disk_status(struct cdrom_device_info*);
+int sr_get_last_session(struct cdrom_device_info*, struct cdrom_multisession*);
+int sr_get_mcn(struct cdrom_device_info*, struct cdrom_mcn*);
+int sr_reset(struct cdrom_device_info*);
+int sr_audio_ioctl(struct cdrom_device_info*, unsigned int, void*);
+int sr_dev_ioctl(struct cdrom_device_info*, unsigned int, unsigned long);
+
+/* vendor-specific */
+#ifdef CONFIG_BLK_DEV_SR_VENDOR
+void sr_vendor_init(int minor);
+int sr_cd_check(struct cdrom_device_info*);
+#endif
 
 #endif
diff -u --recursive --new-file v2.1.9/linux/drivers/scsi/sr_ioctl.c linux/drivers/scsi/sr_ioctl.c
--- v2.1.9/linux/drivers/scsi/sr_ioctl.c	Tue Oct 29 19:58:13 1996
+++ linux/drivers/scsi/sr_ioctl.c	Thu Nov 14 15:27:26 1996
@@ -9,13 +9,13 @@
 #include <linux/blk.h>
 #include "scsi.h"
 #include "hosts.h"
-#include "sr.h"
 #include <scsi/scsi_ioctl.h>
 
 #include <linux/cdrom.h>
+#include <linux/ucdrom.h>
+#include "sr.h"
 
 extern void get_sectorsize(int);
-extern void sr_photocd(struct inode *);
 
 #define IOCTL_RETRIES 3
 /* The CDROM is fairly slow, so we need a little extra time */
@@ -38,7 +38,7 @@
    error code is.  Normally the UNIT_ATTENTION code will automatically
    clear after one error */
 
-static int do_ioctl(int target, unsigned char * sr_cmd, void * buffer, unsigned buflength)
+int sr_do_ioctl(int target, unsigned char * sr_cmd, void * buffer, unsigned buflength)
 {
     Scsi_Cmnd * SCpnt;
     int result;
@@ -88,17 +88,134 @@
     return result;
 }
 
-int sr_ioctl(struct inode * inode, struct file * file, unsigned int cmd, unsigned long arg)
+/* ---------------------------------------------------------------------- */
+/* interface to cdrom.c                                                   */
+
+int sr_tray_move(struct cdrom_device_info *cdi, int pos)
 {
-    u_char  sr_cmd[10];
-    
-    kdev_t dev = inode->i_rdev;
-    int result, target, err;
-    
-    target = MINOR(dev);
+        u_char  sr_cmd[10];
+        
+        sr_cmd[0] = START_STOP;
+        sr_cmd[1] = ((scsi_CDs[MINOR(cdi->dev)].device -> lun) << 5);
+        sr_cmd[2] = sr_cmd[3] = sr_cmd[5] = 0;
+        sr_cmd[4] = (pos == 0) ? 0x03 /* close */ : 0x02 /* eject */;
+	
+        return sr_do_ioctl(MINOR(cdi->dev), sr_cmd, NULL, 255);
+}
+
+int sr_lock_door(struct cdrom_device_info *cdi, int lock)
+{
+        return scsi_ioctl (scsi_CDs[MINOR(cdi->dev)].device,
+                           lock ? SCSI_IOCTL_DOORLOCK : SCSI_IOCTL_DOORUNLOCK,
+                           0);
+}
+
+int sr_drive_status(struct cdrom_device_info *cdi, int slot)
+{
+        if (CDSL_CURRENT != slot) {
+                /* we have no changer support */
+                return -EINVAL;
+        }
+
+        if (!scsi_ioctl(scsi_CDs[MINOR(cdi->dev)].device,
+                        SCSI_IOCTL_TEST_UNIT_READY,0))
+                return CDS_DISC_OK;
+
+#if 0
+        /* Enable this if you want to try auto-close. Is'nt enabled by
+         * default because it does'nt work perfectly (no way to
+         * difference between "tray open" and "tray closed, no disk"),
+         * and for caddy drives this is useless anyway. */
+        return CDS_TRAY_OPEN;
+#else
+        return CDS_NO_DISC;
+#endif
+}
+
+int sr_disk_status(struct cdrom_device_info *cdi)
+{
+	struct cdrom_tochdr    toc_h;
+	struct cdrom_tocentry  toc_e;
+        int                    i;
+
+        if (scsi_ioctl(scsi_CDs[MINOR(cdi->dev)].device,SCSI_IOCTL_TEST_UNIT_READY,0))
+                return CDS_NO_DISC;
+
+        /* if the xa-bit is on, we tell it is XA... */
+        if (scsi_CDs[MINOR(cdi->dev)].xa_flag)
+                return CDS_XA_2_1;
+        
+        /* ...else we look for data tracks */
+        if (sr_audio_ioctl(cdi, CDROMREADTOCHDR, &toc_h))
+                return CDS_NO_INFO;
+        for (i = toc_h.cdth_trk0; i <= toc_h.cdth_trk1; i++) {
+                toc_e.cdte_track  = i;
+                toc_e.cdte_format = CDROM_LBA;
+                if (sr_audio_ioctl(cdi, CDROMREADTOCENTRY, &toc_e))
+                        return CDS_NO_INFO;
+                if (toc_e.cdte_ctrl & CDROM_DATA_TRACK)
+                        return CDS_DATA_1;
+#if 0
+                if (i == toc_h.cdth_trk0 && toc_e.cdte_addr.lba > 100)
+                        /* guess: looks like a "hidden track" CD */
+                        return CDS_DATA_1;
+#endif
+        }
+        return CDS_AUDIO;
+}
+
+int sr_get_last_session(struct cdrom_device_info *cdi,
+                        struct cdrom_multisession* ms_info)
+{
+        ms_info->addr.lba=scsi_CDs[MINOR(cdi->dev)].ms_offset;
+        ms_info->xa_flag=scsi_CDs[MINOR(cdi->dev)].xa_flag;
+
+	return 0;
+}
+
+int sr_get_mcn(struct cdrom_device_info *cdi,struct cdrom_mcn *mcn)
+{
+        u_char  sr_cmd[10];
+	char * buffer;
+        int result;
+        	
+	sr_cmd[0] = SCMD_READ_SUBCHANNEL;
+	sr_cmd[1] = ((scsi_CDs[MINOR(cdi->dev)].device->lun) << 5);
+	sr_cmd[2] = 0x40;    /* I do want the subchannel info */
+	sr_cmd[3] = 0x02;    /* Give me medium catalog number info */
+	sr_cmd[4] = sr_cmd[5] = 0;
+	sr_cmd[6] = 0;
+	sr_cmd[7] = 0;
+	sr_cmd[8] = 24;
+	sr_cmd[9] = 0;
+	
+	buffer = (unsigned char*) scsi_malloc(512);
+	if(!buffer) return -ENOMEM;
+	
+	result = sr_do_ioctl(MINOR(cdi->dev), sr_cmd, buffer, 24);
+	
+	memcpy (mcn->medium_catalog_number, buffer + 9, 13);
+        mcn->medium_catalog_number[13] = 0;
+
+	scsi_free(buffer, 512);
+	
+	return result;
+}
+
+int sr_reset(struct cdrom_device_info *cdi)
+{
+	invalidate_buffers(cdi->dev);
+	return 0;        
+}
+
+/* ----------------------------------------------------------------------- */
+
+int sr_audio_ioctl(struct cdrom_device_info *cdi, unsigned int cmd, void* arg)
+{
+    u_char  sr_cmd[10];    
+    int result, target;
     
-    if (target >= sr_template.nr_dev ||
-	!scsi_CDs[target].device) return -ENXIO;
+    target = MINOR(cdi->dev);
     
     switch (cmd) 
     {
@@ -112,8 +229,8 @@
 	sr_cmd[8] = 0;
 	sr_cmd[9] = 0;
 	
-	result = do_ioctl(target, sr_cmd, NULL, 255);
-	return result;
+	result = sr_do_ioctl(target, sr_cmd, NULL, 255);
+        break;
 	
     case CDROMRESUME:
 	
@@ -124,86 +241,69 @@
 	sr_cmd[8] = 1;
 	sr_cmd[9] = 0;
 	
-	result = do_ioctl(target, sr_cmd, NULL, 255);
-	
-	return result;
+	result = sr_do_ioctl(target, sr_cmd, NULL, 255);	
+        break;
 	
     case CDROMPLAYMSF:
     {
-	struct cdrom_msf msf;
-
-        err = verify_area (VERIFY_READ, (void *) arg, sizeof (msf));
-        if (err) return err;
+	struct cdrom_msf* msf = (struct cdrom_msf*)arg;
 
-	copy_from_user(&msf, (void *) arg, sizeof(msf));
-	
 	sr_cmd[0] = SCMD_PLAYAUDIO_MSF;
 	sr_cmd[1] = scsi_CDs[target].device->lun << 5;
 	sr_cmd[2] = 0;
-	sr_cmd[3] = msf.cdmsf_min0;
-	sr_cmd[4] = msf.cdmsf_sec0;
-	sr_cmd[5] = msf.cdmsf_frame0;
-	sr_cmd[6] = msf.cdmsf_min1;
-	sr_cmd[7] = msf.cdmsf_sec1;
-	sr_cmd[8] = msf.cdmsf_frame1;
+	sr_cmd[3] = msf->cdmsf_min0;
+	sr_cmd[4] = msf->cdmsf_sec0;
+	sr_cmd[5] = msf->cdmsf_frame0;
+	sr_cmd[6] = msf->cdmsf_min1;
+	sr_cmd[7] = msf->cdmsf_sec1;
+	sr_cmd[8] = msf->cdmsf_frame1;
 	sr_cmd[9] = 0;
 	
-	result = do_ioctl(target, sr_cmd, NULL, 255);
-	return result;
+	result = sr_do_ioctl(target, sr_cmd, NULL, 255);
+        break;
     }
 
     case CDROMPLAYBLK:
     {
-	struct cdrom_blk blk;
-
-        err = verify_area (VERIFY_READ, (void *) arg, sizeof (blk));
-        if (err) return err;
+	struct cdrom_blk* blk = (struct cdrom_blk*)arg;
 
-	copy_from_user(&blk, (void *) arg, sizeof(blk));
-	
 	sr_cmd[0] = SCMD_PLAYAUDIO10;
 	sr_cmd[1] = scsi_CDs[target].device->lun << 5;
-	sr_cmd[2] = blk.from >> 24;
-	sr_cmd[3] = blk.from >> 16;
-	sr_cmd[4] = blk.from >> 8;
-	sr_cmd[5] = blk.from;
+	sr_cmd[2] = blk->from >> 24;
+	sr_cmd[3] = blk->from >> 16;
+	sr_cmd[4] = blk->from >> 8;
+	sr_cmd[5] = blk->from;
 	sr_cmd[6] = 0;
-	sr_cmd[7] = blk.len >> 8;
-	sr_cmd[8] = blk.len;
+	sr_cmd[7] = blk->len >> 8;
+	sr_cmd[8] = blk->len;
 	sr_cmd[9] = 0;
 	
-	result = do_ioctl(target, sr_cmd, NULL, 255);
-	return result;
+	result = sr_do_ioctl(target, sr_cmd, NULL, 255);
+        break;
     }
 		
     case CDROMPLAYTRKIND:
     {
-	struct cdrom_ti ti;
+	struct cdrom_ti* ti = (struct cdrom_ti*)arg;
 
-        err = verify_area (VERIFY_READ, (void *) arg, sizeof (ti));
-        if (err) return err;
-
-	copy_from_user(&ti, (void *) arg, sizeof(ti));
-	
 	sr_cmd[0] = SCMD_PLAYAUDIO_TI;
 	sr_cmd[1] = scsi_CDs[target].device->lun << 5;
 	sr_cmd[2] = 0;
 	sr_cmd[3] = 0;
-	sr_cmd[4] = ti.cdti_trk0;
-	sr_cmd[5] = ti.cdti_ind0;
+	sr_cmd[4] = ti->cdti_trk0;
+	sr_cmd[5] = ti->cdti_ind0;
 	sr_cmd[6] = 0;
-	sr_cmd[7] = ti.cdti_trk1;
-	sr_cmd[8] = ti.cdti_ind1;
+	sr_cmd[7] = ti->cdti_trk1;
+	sr_cmd[8] = ti->cdti_ind1;
 	sr_cmd[9] = 0;
 	
-	result = do_ioctl(target, sr_cmd, NULL, 255);
-	
-	return result;
+	result = sr_do_ioctl(target, sr_cmd, NULL, 255);
+        break;
     }
 	
     case CDROMREADTOCHDR:
     {
-	struct cdrom_tochdr tochdr;
+	struct cdrom_tochdr* tochdr = (struct cdrom_tochdr*)arg;
 	char * buffer;
 	
 	sr_cmd[0] = SCMD_READ_TOC;
@@ -217,36 +317,25 @@
 	buffer = (unsigned char *) scsi_malloc(512);
 	if(!buffer) return -ENOMEM;
 	
-	result = do_ioctl(target, sr_cmd, buffer, 12);
+	result = sr_do_ioctl(target, sr_cmd, buffer, 12);
 	
-	tochdr.cdth_trk0 = buffer[2];
-	tochdr.cdth_trk1 = buffer[3];
+	tochdr->cdth_trk0 = buffer[2];
+	tochdr->cdth_trk1 = buffer[3];
 	
 	scsi_free(buffer, 512);
-	
-	err = verify_area (VERIFY_WRITE, (void *) arg, sizeof (struct cdrom_tochdr));
-	if (err)
-	    return err;
-	copy_to_user ((void *) arg, &tochdr, sizeof (struct cdrom_tochdr));
-	
-	return result;
+        break;
     }
 	
     case CDROMREADTOCENTRY:
     {
-	struct cdrom_tocentry tocentry;
+	struct cdrom_tocentry* tocentry = (struct cdrom_tocentry*)arg;
 	unsigned char * buffer;
 	
-        err = verify_area (VERIFY_READ, (void *) arg, sizeof (struct cdrom_tocentry));
-        if (err) return err;
-
-	copy_from_user (&tocentry, (void *) arg, sizeof (struct cdrom_tocentry));
-	
 	sr_cmd[0] = SCMD_READ_TOC;
 	sr_cmd[1] = ((scsi_CDs[target].device->lun) << 5) |
-          (tocentry.cdte_format == CDROM_MSF ? 0x02 : 0);
+          (tocentry->cdte_format == CDROM_MSF ? 0x02 : 0);
 	sr_cmd[2] = sr_cmd[3] = sr_cmd[4] = sr_cmd[5] = 0;
-	sr_cmd[6] = tocentry.cdte_track;
+	sr_cmd[6] = tocentry->cdte_track;
 	sr_cmd[7] = 0;             /* MSB of length (12)  */
 	sr_cmd[8] = 12;            /* LSB of length */
 	sr_cmd[9] = 0;
@@ -254,28 +343,21 @@
 	buffer = (unsigned char *) scsi_malloc(512);
 	if(!buffer) return -ENOMEM;
 	
-	result = do_ioctl (target, sr_cmd, buffer, 12);
+	result = sr_do_ioctl (target, sr_cmd, buffer, 12);
 	
-        tocentry.cdte_ctrl = buffer[5] & 0xf;	
-        tocentry.cdte_adr = buffer[5] >> 4;
-        tocentry.cdte_datamode = (tocentry.cdte_ctrl & 0x04) ? 1 : 0;
-	if (tocentry.cdte_format == CDROM_MSF) {
-	    tocentry.cdte_addr.msf.minute = buffer[9];
-	    tocentry.cdte_addr.msf.second = buffer[10];
-	    tocentry.cdte_addr.msf.frame = buffer[11];
-	}
-	else
-	    tocentry.cdte_addr.lba = (((((buffer[8] << 8) + buffer[9]) << 8)
+        tocentry->cdte_ctrl = buffer[5] & 0xf;	
+        tocentry->cdte_adr = buffer[5] >> 4;
+        tocentry->cdte_datamode = (tocentry->cdte_ctrl & 0x04) ? 1 : 0;
+	if (tocentry->cdte_format == CDROM_MSF) {
+	    tocentry->cdte_addr.msf.minute = buffer[9];
+	    tocentry->cdte_addr.msf.second = buffer[10];
+	    tocentry->cdte_addr.msf.frame = buffer[11];
+	} else
+	    tocentry->cdte_addr.lba = (((((buffer[8] << 8) + buffer[9]) << 8)
                                        + buffer[10]) << 8) + buffer[11];
 	
 	scsi_free(buffer, 512);
-	
-	err = verify_area (VERIFY_WRITE, (void *) arg, sizeof (struct cdrom_tocentry));
-	if (err)
-	    return err;
-	copy_to_user ((void *) arg, &tocentry, sizeof (struct cdrom_tocentry));
-	
-	return result;
+        break;
     }
 	
     case CDROMSTOP:
@@ -284,8 +366,8 @@
 	sr_cmd[2] = sr_cmd[3] = sr_cmd[5] = 0;
 	sr_cmd[4] = 0;
 	
-	result = do_ioctl(target, sr_cmd, NULL, 255);
-	return result;
+	result = sr_do_ioctl(target, sr_cmd, NULL, 255);
+        break;
 	
     case CDROMSTART:
 	sr_cmd[0] = START_STOP;
@@ -293,59 +375,13 @@
 	sr_cmd[2] = sr_cmd[3] = sr_cmd[5] = 0;
 	sr_cmd[4] = 1;
 	
-	result = do_ioctl(target, sr_cmd, NULL, 255);
-	return result;
-	
-    case CDROMCLOSETRAY:
-	sr_cmd[0] = START_STOP;
-	sr_cmd[1] = ((scsi_CDs[target].device -> lun) << 5);
-	sr_cmd[2] = sr_cmd[3] = sr_cmd[5] = 0;
-	sr_cmd[4] = 0x03;
-	
-        if ((result = do_ioctl(target, sr_cmd, NULL, 255)))
-          return result;
-
-        /* Gather information about newly inserted disc */
-        check_disk_change (inode->i_rdev);
-        sr_ioctl (inode, NULL, SCSI_IOCTL_DOORLOCK, 0);
-        sr_photocd (inode);
-
-        if (scsi_CDs[MINOR(inode->i_rdev)].needs_sector_size)
-          get_sectorsize (MINOR(inode->i_rdev));
-
-        return 0;
-
-    case CDROMEJECT:
-        /*
-         * Allow 0 for access count for auto-eject feature.
-         */
-	if (scsi_CDs[target].device -> access_count > 1)
-	    return -EBUSY;
+	result = sr_do_ioctl(target, sr_cmd, NULL, 255);
+        break;
 	
-	sr_ioctl (inode, NULL, SCSI_IOCTL_DOORUNLOCK, 0);
-	sr_cmd[0] = START_STOP;
-	sr_cmd[1] = ((scsi_CDs[target].device -> lun) << 5) | 1;
-	sr_cmd[2] = sr_cmd[3] = sr_cmd[5] = 0;
-	sr_cmd[4] = 0x02;
-	
-	if (!(result = do_ioctl(target, sr_cmd, NULL, 255)))
-	    scsi_CDs[target].device -> changed = 1;
-	
-	return result;
-	
-    case CDROMEJECT_SW:
-        scsi_CDs[target].auto_eject = !!arg;
-        return 0;
-
     case CDROMVOLCTRL:
     {
 	char * buffer, * mask;
-	struct cdrom_volctrl volctrl;
-	
-        err = verify_area (VERIFY_READ, (void *) arg, sizeof (struct cdrom_volctrl));
-        if (err) return err;
-
-	copy_from_user (&volctrl, (void *) arg, sizeof (struct cdrom_volctrl));
+	struct cdrom_volctrl* volctrl = (struct cdrom_volctrl*)arg;
 	
 	/* First we get the current params so we can just twiddle the volume */
 	
@@ -359,10 +395,10 @@
 	buffer = (unsigned char *) scsi_malloc(512);
 	if(!buffer) return -ENOMEM;
 	
-	if ((result = do_ioctl (target, sr_cmd, buffer, 28))) {
+	if ((result = sr_do_ioctl (target, sr_cmd, buffer, 28))) {
 	    printk ("Hosed while obtaining audio mode page\n");
 	    scsi_free(buffer, 512);
-	    return result;
+            break;
 	}
 	
 	sr_cmd[0] = MODE_SENSE;
@@ -375,23 +411,24 @@
 	mask = (unsigned char *) scsi_malloc(512);
 	if(!mask) {
 	    scsi_free(buffer, 512);
-	    return -ENOMEM;
+	    result = -ENOMEM;
+            break;
 	};
 
-	if ((result = do_ioctl (target, sr_cmd, mask, 28))) {
+	if ((result = sr_do_ioctl (target, sr_cmd, mask, 28))) {
 	    printk ("Hosed while obtaining mask for audio mode page\n");
 	    scsi_free(buffer, 512);
 	    scsi_free(mask, 512);
-	    return result;
+	    break;
 	}
 	
 	/* Now mask and substitute our own volume and reuse the rest */
 	buffer[0] = 0;  /* Clear reserved field */
 	
-	buffer[21] = volctrl.channel0 & mask[21];
-	buffer[23] = volctrl.channel1 & mask[23];
-	buffer[25] = volctrl.channel2 & mask[25];
-	buffer[27] = volctrl.channel3 & mask[27];
+	buffer[21] = volctrl->channel0 & mask[21];
+	buffer[23] = volctrl->channel1 & mask[23];
+	buffer[25] = volctrl->channel2 & mask[25];
+	buffer[27] = volctrl->channel3 & mask[27];
 	
 	sr_cmd[0] = MODE_SELECT;
 	sr_cmd[1] = ((scsi_CDs[target].device -> lun) << 5) | 0x10;    /* Params are SCSI-2 */
@@ -399,19 +436,16 @@
 	sr_cmd[4] = 28;
 	sr_cmd[5] = 0;
 	
-	result = do_ioctl (target, sr_cmd, buffer, 28);
+	result = sr_do_ioctl (target, sr_cmd, buffer, 28);
 	scsi_free(buffer, 512);
 	scsi_free(mask, 512);
-	return result;
+        break;
     }
 	
     case CDROMVOLREAD:
     {
 	char * buffer;
-	struct cdrom_volctrl volctrl;
-	
-        err = verify_area (VERIFY_WRITE, (void *) arg, sizeof (struct cdrom_volctrl));
-        if (err) return err;
+	struct cdrom_volctrl* volctrl = (struct cdrom_volctrl*)arg;
 	
 	/* Get the current params */
 	
@@ -425,27 +459,24 @@
 	buffer = (unsigned char *) scsi_malloc(512);
 	if(!buffer) return -ENOMEM;
 	
-	if ((result = do_ioctl (target, sr_cmd, buffer, 28))) {
+	if ((result = sr_do_ioctl (target, sr_cmd, buffer, 28))) {
 	    printk ("(CDROMVOLREAD) Hosed while obtaining audio mode page\n");
 	    scsi_free(buffer, 512);
-	    return result;
+            break;
 	}
 
-	volctrl.channel0 = buffer[21];
-	volctrl.channel1 = buffer[23];
-	volctrl.channel2 = buffer[25];
-	volctrl.channel3 = buffer[27];
-
-	copy_to_user ((void *) arg, &volctrl, sizeof (struct cdrom_volctrl));
+	volctrl->channel0 = buffer[21];
+	volctrl->channel1 = buffer[23];
+	volctrl->channel2 = buffer[25];
+	volctrl->channel3 = buffer[27];
 
 	scsi_free(buffer, 512);
-
-	return 0;
+        break;
     }
 	
     case CDROMSUBCHNL:
     {
-	struct cdrom_subchnl subchnl;
+	struct cdrom_subchnl* subchnl = (struct cdrom_subchnl*)arg;
 	char * buffer;
 	
 	sr_cmd[0] = SCMD_READ_SUBCHANNEL;
@@ -461,98 +492,46 @@
 	buffer = (unsigned char*) scsi_malloc(512);
 	if(!buffer) return -ENOMEM;
 	
-	result = do_ioctl(target, sr_cmd, buffer, 16);
+	result = sr_do_ioctl(target, sr_cmd, buffer, 16);
 	
-	subchnl.cdsc_audiostatus = buffer[1];
-	subchnl.cdsc_format = CDROM_MSF;
-	subchnl.cdsc_ctrl = buffer[5] & 0xf;
-	subchnl.cdsc_trk = buffer[6];
-	subchnl.cdsc_ind = buffer[7];
-	
-	subchnl.cdsc_reladdr.msf.minute = buffer[13];
-	subchnl.cdsc_reladdr.msf.second = buffer[14];
-	subchnl.cdsc_reladdr.msf.frame = buffer[15];
-	subchnl.cdsc_absaddr.msf.minute = buffer[9];
-	subchnl.cdsc_absaddr.msf.second = buffer[10];
-	subchnl.cdsc_absaddr.msf.frame = buffer[11];
+	subchnl->cdsc_audiostatus = buffer[1];
+	subchnl->cdsc_format = CDROM_MSF;
+	subchnl->cdsc_ctrl = buffer[5] & 0xf;
+	subchnl->cdsc_trk = buffer[6];
+	subchnl->cdsc_ind = buffer[7];
+	
+	subchnl->cdsc_reladdr.msf.minute = buffer[13];
+	subchnl->cdsc_reladdr.msf.second = buffer[14];
+	subchnl->cdsc_reladdr.msf.frame = buffer[15];
+	subchnl->cdsc_absaddr.msf.minute = buffer[9];
+	subchnl->cdsc_absaddr.msf.second = buffer[10];
+	subchnl->cdsc_absaddr.msf.frame = buffer[11];
 	
 	scsi_free(buffer, 512);
-	
-	err = verify_area (VERIFY_WRITE, (void *) arg, sizeof (struct cdrom_subchnl));
-	if (err)
-	    return err;
-	copy_to_user ((void *) arg, &subchnl, sizeof (struct cdrom_subchnl));
-	return result;
+        break;
     }
-	
-    case CDROM_GET_UPC:
-    {
-	struct cdrom_mcn mcn;
-	char * buffer;
-	
-	sr_cmd[0] = SCMD_READ_SUBCHANNEL;
-	sr_cmd[1] = ((scsi_CDs[target].device->lun) << 5);
-	sr_cmd[2] = 0x40;    /* I do want the subchannel info */
-	sr_cmd[3] = 0x02;    /* Give me medium catalog number info */
-	sr_cmd[4] = sr_cmd[5] = 0;
-	sr_cmd[6] = 0;
-	sr_cmd[7] = 0;
-	sr_cmd[8] = 24;
-	sr_cmd[9] = 0;
-	
-	buffer = (unsigned char*) scsi_malloc(512);
-	if(!buffer) return -ENOMEM;
-	
-	result = do_ioctl(target, sr_cmd, buffer, 24);
-	
-	memcpy (mcn.medium_catalog_number, buffer + 9, 13);
-        mcn.medium_catalog_number[13] = 0;
-
-	scsi_free(buffer, 512);
-	
-	err = verify_area (VERIFY_WRITE, (void *) arg, sizeof (struct cdrom_mcn));
-	if (err)
-	    return err;
-	copy_to_user ((void *) arg, &mcn, sizeof (struct cdrom_mcn));
-	return result;
+    default:
+        return -EINVAL;
     }
+
+    if (result)
+        printk("DEBUG: sr_audio: result for ioctl %x: %x\n",cmd,result);
+    
+    return result;
+}
 	
+int sr_dev_ioctl(struct cdrom_device_info *cdi,
+                 unsigned int cmd, unsigned long arg)
+{
+    int target, err;
+    
+    target = MINOR(cdi->dev);
+    
+    switch (cmd) {
     case CDROMREADMODE2:
 	return -EINVAL;
     case CDROMREADMODE1:
-	return -EINVAL;
-	
-	/* block-copy from ../block/sbpcd.c with some adjustments... */
-    case CDROMMULTISESSION: /* tell start-of-last-session to user */
-    {
-	struct cdrom_multisession  ms_info;
-	long                       lba;
-	
-	err = verify_area(VERIFY_READ, (void *) arg,
-			  sizeof(struct cdrom_multisession));
-	if (err) return (err);
-	
-	copy_from_user(&ms_info, (void *) arg, sizeof(struct cdrom_multisession));
-	
-	if (ms_info.addr_format==CDROM_MSF) { /* MSF-bin requested */
-	    lba = scsi_CDs[target].mpcd_sector+CD_BLOCK_OFFSET;
-	    ms_info.addr.msf.minute = lba / (CD_SECS*CD_FRAMES);
-	    lba %= CD_SECS*CD_FRAMES;
-	    ms_info.addr.msf.second = lba / CD_FRAMES;
-	    ms_info.addr.msf.frame  = lba % CD_FRAMES;
-	} else if (ms_info.addr_format==CDROM_LBA) /* lba requested */
-	    ms_info.addr.lba=scsi_CDs[target].mpcd_sector;
-	else return (-EINVAL);
-	
-	ms_info.xa_flag=scsi_CDs[target].xa_flags & 0x01;
-	
-	err=verify_area(VERIFY_WRITE,(void *) arg,
-			sizeof(struct cdrom_multisession));
-	if (err) return (err);
-	
-	copy_to_user((void *) arg, &ms_info, sizeof(struct cdrom_multisession));
-	return (0);
-    }
+	return -EINVAL;	
 	
     case BLKRAGET:
 	if (!arg)
@@ -560,24 +539,20 @@
 	err = verify_area(VERIFY_WRITE, (int *) arg, sizeof(int));
 	if (err)
 		return err;
-	put_user(read_ahead[MAJOR(inode->i_rdev)], (int *) arg);
+	put_user(read_ahead[MAJOR(cdi->dev)], (int *) arg);
 	return 0;
 
     case BLKRASET:
 	if(!suser())
         	return -EACCES;
-	if(!(inode->i_rdev))
+	if(!(cdi->dev))
         	return -EINVAL;
 	if(arg > 0xff)
         	return -EINVAL;
-	read_ahead[MAJOR(inode->i_rdev)] = arg;
+	read_ahead[MAJOR(cdi->dev)] = arg;
 	return 0;
 
-    RO_IOCTLS(dev,arg);
-
-    case CDROMRESET:
-	invalidate_buffers(inode->i_rdev);
-	return 0;
+    RO_IOCTLS(cdi->dev,arg);
 
     default:
 	return scsi_ioctl(scsi_CDs[target].device,cmd,(void *) arg);
diff -u --recursive --new-file v2.1.9/linux/drivers/scsi/sr_vendor.c linux/drivers/scsi/sr_vendor.c
--- v2.1.9/linux/drivers/scsi/sr_vendor.c	Thu Jan  1 02:00:00 1970
+++ linux/drivers/scsi/sr_vendor.c	Wed Nov 13 08:11:17 1996
@@ -0,0 +1,273 @@
+/* -*-linux-c-*-
+ *
+ * vendor-specific code for SCSI CD-ROM's goes here.
+ *
+ * This is needed becauce most of the new features (multisession and
+ * the like) are to new to be included into the SCSI-II standard (to
+ * be exact: there is'nt anything in my draft copy).
+ *
+ *   Gerd Knorr <kraxel@cs.tu-berlin.de> 
+ */
+
+#include <linux/errno.h>
+#include <linux/string.h>
+
+#include <linux/blk.h>
+#include "scsi.h"
+#include "hosts.h"
+#include <scsi/scsi_ioctl.h>
+
+#include <linux/cdrom.h>
+#include <linux/ucdrom.h>
+#include "sr.h"
+
+/* here are some constants to sort the vendors into groups */
+
+#define VENDOR_CAN_NOT_HANDLE  1   /* don't know how to handle */
+#define VENDOR_NEC             2
+#define VENDOR_TOSHIBA         3
+#define VENDOR_SONY_LIKE       4   /* much drives are Sony compatible */
+#define VENDOR_HP              5
+
+#define DEBUG
+
+void
+sr_vendor_init(int minor)
+{
+	char *vendor = scsi_CDs[minor].device->vendor;
+	char *model  = scsi_CDs[minor].device->model;
+		
+	if (!strncmp (vendor, "NEC", 3)) {
+		scsi_CDs[minor].vendor = VENDOR_NEC;
+		if (!strncmp (model,"CD-ROM DRIVE:25", 15) ||
+		    !strncmp (model,"CD-ROM DRIVE:36", 15)  ||
+		    !strncmp (model,"CD-ROM DRIVE:83", 15)  ||
+		    !strncmp (model,"CD-ROM DRIVE:84 ",16))
+			/* these can't handle multisession, may hang */
+			scsi_CDs[minor].cdi.mask |= CDC_MULTI_SESSION;
+
+	} else if (!strncmp (vendor, "TOSHIBA", 7)) {
+		scsi_CDs[minor].vendor = VENDOR_TOSHIBA;
+		
+	} else if (!strncmp (vendor, "HP", 2)) {
+		scsi_CDs[minor].vendor = VENDOR_HP;
+		
+	} else {
+		/* most drives can handled like sony ones, so we take
+		 * it as default */
+		scsi_CDs[minor].vendor = VENDOR_SONY_LIKE;
+	}
+}
+
+
+
+/*
+ * support for XA/multisession-CD's
+ * 
+ *   - NEC:     Detection and support of multisession CD's.
+ *     
+ *   - TOSHIBA: Detection and support of multisession CD's.
+ *              Some XA-Sector tweaking, required for older drives.
+ *
+ *   - SONY:	Detection and support of multisession CD's.
+ *              added by Thomas Quinot <operator@melchior.cuivre.fdn.fr>
+ *
+ *   - PIONEER, HITACHI, PLEXTOR, MATSHITA: known to work with SONY code.
+ *
+ *   - HP:	Much like SONY, but a little different... (Thomas)
+ *              HP-Writers only ???
+ */
+
+#define BCD_TO_BIN(x)    ((((int)x & 0xf0) >> 4)*10 + ((int)x & 0x0f))
+
+int sr_cd_check(struct cdrom_device_info *cdi)
+{
+	unsigned long   sector,min,sec,frame;
+	unsigned char   *buffer;    /* the buffer for the ioctl */
+	unsigned char   cmd[12];    /* the scsi-command */
+	int             rc,is_xa,no_multi,minor;
+
+	minor = MINOR(cdi->dev);
+	
+	buffer = (unsigned char *) scsi_malloc(512);
+	if(!buffer) return -ENOMEM;
+	
+	sector   = 0;         /* the multisession sector offset goes here  */
+	is_xa    = 0;         /* flag: the CD uses XA-Sectors              */
+	no_multi = 0;         /* flag: the drive can't handle multisession */
+	rc       = 0;
+    
+	switch(scsi_CDs[minor].vendor) {
+	
+	case VENDOR_NEC:
+		memset(cmd,0,12);
+		cmd[0] = 0xde;
+		cmd[1] = (scsi_CDs[minor].device->lun << 5) | 0x03;
+		cmd[2] = 0xb0;
+		rc = sr_do_ioctl(minor, cmd, buffer, 0x16);
+		if (rc != 0)
+			break;
+		if (buffer[14] != 0 && buffer[14] != 0xb0) {
+			printk(KERN_INFO "sr (nec): Hmm, seems the cdrom doesn't support multisession CD's\n");
+			no_multi = 1;
+			break;
+		}
+		min    = BCD_TO_BIN(buffer[15]);
+		sec    = BCD_TO_BIN(buffer[16]);
+		frame  = BCD_TO_BIN(buffer[17]);
+		sector = min*CD_SECS*CD_FRAMES + sec*CD_FRAMES + frame;
+		is_xa  = (buffer[14] == 0xb0);
+		break;
+		
+	case VENDOR_TOSHIBA:
+		/* we request some disc information (is it a XA-CD ?,
+		 * where starts the last session ?) */
+		memset(cmd,0,12);
+		cmd[0] = 0xc7;
+		cmd[1] = (scsi_CDs[minor].device->lun << 5) | 3;
+		rc = sr_do_ioctl(minor, cmd, buffer, 4);
+		if (rc == 0x28000002 &&
+		    !scsi_ioctl(scsi_CDs[minor].device,
+				SCSI_IOCTL_TEST_UNIT_READY, NULL)) {
+			printk(KERN_INFO "sr (toshiba): Hmm, seems the drive doesn't support multisession CD's\n");
+		    no_multi = 1;
+		    break;
+		}
+		if (rc != 0)
+			break;
+		min    = BCD_TO_BIN(buffer[1]);
+		sec    = BCD_TO_BIN(buffer[2]);
+		frame  = BCD_TO_BIN(buffer[3]);
+		sector = min*CD_SECS*CD_FRAMES + sec*CD_FRAMES + frame;
+		if (sector)
+			sector -= CD_BLOCK_OFFSET;
+		is_xa  = (buffer[0] == 0x20);
+#if 0
+		/* this is required for some CD's:
+		 *   - Enhanced-CD (Hardware tells wrong XA-flag)
+		 *   - these broken non-XA multisession CD's
+		 */
+		if (is_xa == 0 && sector != 0) {
+			printk(KERN_WARNING "Warning: multisession offset "
+			       "found, setting XA-flag\n");
+			is_xa = 1;
+		}
+#endif
+		/* now the XA-Sector tweaking: set_density... */
+		memset(cmd,0,12);
+		cmd[0] = MODE_SELECT;
+		cmd[1] = (scsi_CDs[minor].device->lun << 5)
+			| (1 << 4);
+		cmd[4] = 12;
+		memset(buffer,0,12);
+		buffer[ 3] = 0x08;
+		buffer[ 4] = 0x83;
+		buffer[10] = 0x08;
+		rc = sr_do_ioctl(minor, cmd, buffer, 12);
+		if (rc != 0) {
+			break;
+		}
+#if 0
+		/* shoult'nt be required any more */
+		scsi_CDs[minor].needs_sector_size = 1;
+#endif
+		break;
+
+	case VENDOR_HP:
+		cmd[0] = READ_TOC;
+		cmd[1] = (scsi_CDs[minor].device->lun << 5);
+		cmd[8] = 0x04;
+		cmd[9] = 0x40;
+		rc = sr_do_ioctl(minor, cmd, buffer, 12);	
+		if (rc != 0) {
+			break;
+		}
+		if ((rc = buffer[2]) == 0) {
+			printk (KERN_WARNING
+				"sr (hp): No finished session\n");
+			break;
+		}
+
+		cmd[0] = READ_TOC; /* Read TOC */
+		cmd[1] = (scsi_CDs[minor].device->lun << 5);
+		cmd[6] = rc & 0x7f;  /* number of last session */
+		cmd[8] = 0x0c;
+		cmd[9] = 0x40;
+		rc = sr_do_ioctl(minor, cmd, buffer, 12);	
+		if (rc != 0) {
+			break;
+		}
+
+#undef STRICT_HP
+#ifdef STRICT_HP
+		sector = buffer[11] + (buffer[10] << 8) + (buffer[9] << 16);
+		/* HP documentation states that Logical Start Address is
+		   returned as three (!) bytes, and that buffer[8] is
+		   reserved. This is strange, because a LBA usually is
+		   4 bytes long. */
+#else
+		sector = buffer[11] + (buffer[10] << 8) +
+			(buffer[9] << 16) + (buffer[8] << 24);
+#endif
+		is_xa = !!sector;
+		break;
+
+	case VENDOR_SONY_LIKE:
+		/* Thomas QUINOT <thomas@melchior.cuivre.fdn.fr> */
+#ifdef DEBUG
+		printk(KERN_DEBUG
+		       "sr: use \"Sony group\" multisession code\n");
+#endif
+		memset(cmd,0,12);
+		cmd[0] = READ_TOC;
+		cmd[1] = (scsi_CDs[minor].device->lun << 5);
+		cmd[8] = 12;
+		cmd[9] = 0x40;
+		rc = sr_do_ioctl(minor, cmd, buffer, 12);	
+		if (rc != 0) {
+			break;
+		}
+		if ((buffer[0] << 8) + buffer[1] != 0x0a) {
+			printk(KERN_INFO "sr (sony): Hmm, seems the drive doesn't support multisession CD's\n");
+			no_multi = 1;
+			break;
+		}
+		sector = buffer[11] + (buffer[10] << 8) +
+			(buffer[9] << 16) + (buffer[8] << 24);
+		if (buffer[6] <= 1) {
+			/* ignore sector offsets from first track */
+			sector = 0;
+		}
+		is_xa = !!sector;
+		break;
+		
+	case VENDOR_CAN_NOT_HANDLE:
+		sector = 0;
+		no_multi = 1;
+		break;
+
+	default:
+		/* should not happen */
+		printk(KERN_WARNING
+		       "sr: unknown vendor code (%i), not initialized ?\n",
+		       scsi_CDs[minor].vendor);
+		sector = 0;
+		no_multi = 1;
+		break;
+	}
+    
+#ifdef DEBUG
+	if (sector)
+		printk(KERN_DEBUG
+		       "sr: multisession CD detected, offset: %lu\n",sector);
+#endif
+
+	scsi_CDs[minor].ms_offset = sector;
+	scsi_CDs[minor].xa_flag = is_xa;
+	if (no_multi)
+		cdi->mask |= CDC_MULTI_SESSION;
+	
+	scsi_free(buffer, 512);
+
+	return rc;
+}
diff -u --recursive --new-file v2.1.9/linux/fs/binfmt_elf.c linux/fs/binfmt_elf.c
--- v2.1.9/linux/fs/binfmt_elf.c	Tue Oct 29 19:58:19 1996
+++ linux/fs/binfmt_elf.c	Fri Nov 15 15:27:47 1996
@@ -144,20 +144,14 @@
 	__put_user((unsigned long)argc,--sp);
 	current->mm->arg_start = (unsigned long) p;
 	while (argc-->0) {
-		char c;
 		__put_user(p,argv++);
-		do {
-			get_user(c,p++);
-		} while (c);
+		p += strlen_user(p);
 	}
 	__put_user(NULL, argv);
 	current->mm->arg_end = current->mm->env_start = (unsigned long) p;
 	while (envc-->0) {
-		char c;
 		__put_user(p,envp++);
-		do {
-			get_user(c,p++);
-		} while (c);
+		p += strlen_user(p);
 	}
 	__put_user(NULL, envp);
 	current->mm->env_end = (unsigned long) p;
diff -u --recursive --new-file v2.1.9/linux/fs/buffer.c linux/fs/buffer.c
--- v2.1.9/linux/fs/buffer.c	Tue Oct 29 19:58:20 1996
+++ linux/fs/buffer.c	Fri Nov 15 12:54:08 1996
@@ -35,6 +35,7 @@
 #include <asm/system.h>
 #include <asm/uaccess.h>
 #include <asm/io.h>
+#include <asm/bitops.h>
 
 #define NR_SIZES 5
 static char buffersize_index[17] =
@@ -169,7 +170,7 @@
 	   there to be dirty buffers on any of the other lists. */
 		bh = lru_list[BUF_DIRTY];
 		if (!bh)
-			break;
+			goto repeat2;
 		for (i = nr_buffers_type[BUF_DIRTY]*2 ; i-- > 0 ; bh = next) {
 			if (bh->b_list != BUF_DIRTY)
 				goto repeat;
@@ -1865,6 +1866,32 @@
 		 return reassign_cluster(dev, b[0], size);
 }
 
+unsigned long generate_cluster_swab32(kdev_t dev, int b[], int size)
+{
+	int i, offset;
+	
+	for (i = 0, offset = 0 ; offset < PAGE_SIZE ; i++, offset += size) {
+		if(i && le32_to_cpu(b[i])-1 !=
+		   le32_to_cpu(b[i-1])) return 0;  /* No need to cluster */
+		if(find_buffer(dev, le32_to_cpu(b[i]), size)) return 0;
+	};
+
+	/* OK, we have a candidate for a new cluster */
+	
+	/* See if one size of buffer is over-represented in the buffer cache,
+	   if so reduce the numbers of buffers */
+	if(maybe_shrink_lav_buffers(size))
+	 {
+		 int retval;
+		 retval = try_to_generate_cluster(dev, le32_to_cpu(b[0]), size);
+		 if(retval) return retval;
+	 };
+	
+	if (nr_free_pages > min_free_pages*2) 
+		 return try_to_generate_cluster(dev, le32_to_cpu(b[0]), size);
+	else
+		 return reassign_cluster(dev, le32_to_cpu(b[0]), size);
+}
 
 /* ===================== Init ======================= */
 
diff -u --recursive --new-file v2.1.9/linux/fs/exec.c linux/fs/exec.c
--- v2.1.9/linux/fs/exec.c	Tue Oct 29 19:58:20 1996
+++ linux/fs/exec.c	Fri Nov 15 15:19:29 1996
@@ -178,27 +178,23 @@
 
 /*
  * count() counts the number of arguments/envelopes
- *
- * We also do some limited EFAULT checking: this isn't complete, but
- * it does cover most cases. I'll have to do this correctly some day..
  */
 static int count(char ** argv)
 {
-	int error, i = 0;
-	char ** tmp, *p;
+	int i = 0;
 
-	if ((tmp = argv) != NULL) {
-		error = verify_area(VERIFY_READ, tmp, sizeof(char *));
-		if (error)
-			return error;
+	if (argv != NULL) {
 		for (;;) {
-			get_user(p,tmp++);
+			char * p;
+			int error;
+
+			error = get_user(p,argv);
+			if (error)
+				return error;
 			if (!p)
 				break;
+			argv++;
 			i++;
-			error = verify_area(VERIFY_READ, p, 1);
-			if (error)
-				return error;
 		}
 	}
 	return i;
@@ -224,60 +220,51 @@
 unsigned long copy_strings(int argc,char ** argv,unsigned long *page,
 		unsigned long p, int from_kmem)
 {
-	char *tmp, *tmp1, *pag = NULL;
-	int len, offset = 0;
-	unsigned long old_fs, new_fs;
+	char *str;
+	unsigned long old_fs;
 
 	if (!p)
 		return 0;	/* bullet-proofing */
-	new_fs = get_ds();
 	old_fs = get_fs();
 	if (from_kmem==2)
-		set_fs(new_fs);
+		set_fs(KERNEL_DS);
 	while (argc-- > 0) {
+		int len;
+		unsigned long pos;
+
 		if (from_kmem == 1)
-			set_fs(new_fs);
-		get_user(tmp, argv+argc);
-		if (!tmp)
+			set_fs(KERNEL_DS);
+		get_user(str, argv+argc);
+		if (!str)
 			panic("VFS: argc is wrong");
-		tmp1 = tmp;
 		if (from_kmem == 1)
 			set_fs(old_fs);
-		for (;;) {
-			char c;
-			get_user(c,tmp++);
-			if (!c)
-				break;
-		}
-		len = tmp - tmp1;
+		len = strlen_user(str);	/* includes the '\0' */
 		if (p < len) {	/* this shouldn't happen - 128kB */
 			set_fs(old_fs);
 			return 0;
 		}
+		p -= len;
+		pos = p;
 		while (len) {
-			--p; --tmp; --len;
-			if (--offset < 0) {
-				offset = p % PAGE_SIZE;
+			char *pag;
+			int offset, bytes_to_copy;
+
+			offset = pos % PAGE_SIZE;
+			if (!(pag = (char *) page[pos/PAGE_SIZE]) &&
+			    !(pag = (char *) page[pos/PAGE_SIZE] =
+			      (unsigned long *) get_free_page(GFP_USER))) {
 				if (from_kmem==2)
 					set_fs(old_fs);
-				if (!(pag = (char *) page[p/PAGE_SIZE]) &&
-				    !(pag = (char *) page[p/PAGE_SIZE] =
-				      (unsigned long *) get_free_page(GFP_USER))) 
-					return 0;
-				if (from_kmem==2)
-					set_fs(new_fs);
-
-			}
-			if (len == 0 || offset == 0)
-				get_user(*(pag + offset), tmp);
-			else {
-			  int bytes_to_copy = (len > offset) ? offset : len;
-			  tmp -= bytes_to_copy;
-			  p -= bytes_to_copy;
-			  offset -= bytes_to_copy;
-			  len -= bytes_to_copy;
-			  copy_from_user(pag + offset, tmp, bytes_to_copy + 1);
+				return 0;
 			}
+			bytes_to_copy = PAGE_SIZE - offset;
+			if (bytes_to_copy > len)
+				bytes_to_copy = len;
+			copy_from_user(pag + offset, str, bytes_to_copy);
+			pos += bytes_to_copy;
+			str += bytes_to_copy;
+			len -= bytes_to_copy;
 		}
 	}
 	if (from_kmem==2)
diff -u --recursive --new-file v2.1.9/linux/fs/ext2/balloc.c linux/fs/ext2/balloc.c
--- v2.1.9/linux/fs/ext2/balloc.c	Thu Jan  4 14:14:20 1996
+++ linux/fs/ext2/balloc.c	Thu Nov 14 10:27:37 1996
@@ -7,6 +7,8 @@
  * Universite Pierre et Marie Curie (Paris VI)
  *
  *  Enhanced block allocation by Stephen Tweedie (sct@dcs.ed.ac.uk), 1993
+ *  Big-endian to little-endian byte-swapping/bitmaps by
+ *        David S. Miller (davem@caip.rutgers.edu), 1995
  */
 
 /*
@@ -32,6 +34,7 @@
 #include <linux/locks.h>
 
 #include <asm/bitops.h>
+#include <asm/byteorder.h>
 
 #define in_range(b, first, len)		((b) >= (first) && (b) <= (first) + (len) - 1)
 
@@ -71,12 +74,12 @@
 	struct buffer_head * bh;
 	
 	gdp = get_group_desc (sb, block_group, NULL);
-	bh = bread (sb->s_dev, gdp->bg_block_bitmap, sb->s_blocksize);
+	bh = bread (sb->s_dev, le32_to_cpu(gdp->bg_block_bitmap), sb->s_blocksize);
 	if (!bh)
 		ext2_panic (sb, "read_block_bitmap",
 			    "Cannot read block bitmap - "
 			    "block_group = %d, block_bitmap = %lu",
-			    block_group, (unsigned long) gdp->bg_block_bitmap);
+			    block_group, (unsigned long) le32_to_cpu(gdp->bg_block_bitmap));
 	sb->u.ext2_sb.s_block_bitmap_number[bitmap_nr] = block_group;
 	sb->u.ext2_sb.s_block_bitmap[bitmap_nr] = bh;
 }
@@ -185,8 +188,8 @@
 	}
 	lock_super (sb);
 	es = sb->u.ext2_sb.s_es;
-	if (block < es->s_first_data_block || 
-	    (block + count) > es->s_blocks_count) {
+	if (block < le32_to_cpu(es->s_first_data_block) || 
+	    (block + count) > le32_to_cpu(es->s_blocks_count)) {
 		ext2_error (sb, "ext2_free_blocks",
 			    "Freeing blocks not in datazone - "
 			    "block = %lu, count = %lu", block, count);
@@ -196,9 +199,9 @@
 
 	ext2_debug ("freeing block %lu\n", block);
 
-	block_group = (block - es->s_first_data_block) /
+	block_group = (block - le32_to_cpu(es->s_first_data_block)) /
 		      EXT2_BLOCKS_PER_GROUP(sb);
-	bit = (block - es->s_first_data_block) % EXT2_BLOCKS_PER_GROUP(sb);
+	bit = (block - le32_to_cpu(es->s_first_data_block)) % EXT2_BLOCKS_PER_GROUP(sb);
 	if (bit + count > EXT2_BLOCKS_PER_GROUP(sb))
 		ext2_panic (sb, "ext2_free_blocks",
 			    "Freeing blocks across group boundary - "
@@ -209,11 +212,11 @@
 	gdp = get_group_desc (sb, block_group, &bh2);
 
 	if (test_opt (sb, CHECK_STRICT) &&
-	    (in_range (gdp->bg_block_bitmap, block, count) ||
-	     in_range (gdp->bg_inode_bitmap, block, count) ||
-	     in_range (block, gdp->bg_inode_table,
+	    (in_range (le32_to_cpu(gdp->bg_block_bitmap), block, count) ||
+	     in_range (le32_to_cpu(gdp->bg_inode_bitmap), block, count) ||
+	     in_range (block, le32_to_cpu(gdp->bg_inode_table),
 		       sb->u.ext2_sb.s_itb_per_group) ||
-	     in_range (block + count - 1, gdp->bg_inode_table,
+	     in_range (block + count - 1, le32_to_cpu(gdp->bg_inode_table),
 		       sb->u.ext2_sb.s_itb_per_group)))
 		ext2_panic (sb, "ext2_free_blocks",
 			    "Freeing blocks in system zones - "
@@ -221,15 +224,17 @@
 			    block, count);
 
 	for (i = 0; i < count; i++) {
-		if (!clear_bit (bit + i, bh->b_data))
+		if (!ext2_clear_bit (bit + i, bh->b_data))
 			ext2_warning (sb, "ext2_free_blocks",
 				      "bit already cleared for block %lu", 
 				      block);
 		else {
 			if (sb->dq_op)
 				sb->dq_op->free_block(inode, fs_to_dq_blocks(1, sb->s_blocksize));
-			gdp->bg_free_blocks_count++;
-			es->s_free_blocks_count++;
+			gdp->bg_free_blocks_count =
+				cpu_to_le16(le16_to_cpu(gdp->bg_free_blocks_count)+1);
+			es->s_free_blocks_count =
+				cpu_to_le32(le32_to_cpu(es->s_free_blocks_count)+1);
 		}
 	}
 	
@@ -276,7 +281,7 @@
 	}
 	lock_super (sb);
 	es = sb->u.ext2_sb.s_es;
-	if (es->s_free_blocks_count <= es->s_r_blocks_count &&
+	if (le32_to_cpu(es->s_free_blocks_count) <= le32_to_cpu(es->s_r_blocks_count) &&
 	    (!fsuser() && (sb->u.ext2_sb.s_resuid != current->fsuid) &&
 	     (sb->u.ext2_sb.s_resgid == 0 ||
 	      !in_group_p (sb->u.ext2_sb.s_resgid)))) {
@@ -290,12 +295,13 @@
 	/*
 	 * First, test whether the goal block is free.
 	 */
-	if (goal < es->s_first_data_block || goal >= es->s_blocks_count)
-		goal = es->s_first_data_block;
-	i = (goal - es->s_first_data_block) / EXT2_BLOCKS_PER_GROUP(sb);
+	if (goal < le32_to_cpu(es->s_first_data_block) ||
+	    goal >= le32_to_cpu(es->s_blocks_count))
+		goal = le32_to_cpu(es->s_first_data_block);
+	i = (goal - le32_to_cpu(es->s_first_data_block)) / EXT2_BLOCKS_PER_GROUP(sb);
 	gdp = get_group_desc (sb, i, &bh2);
-	if (gdp->bg_free_blocks_count > 0) {
-		j = ((goal - es->s_first_data_block) % EXT2_BLOCKS_PER_GROUP(sb));
+	if (le16_to_cpu(gdp->bg_free_blocks_count) > 0) {
+		j = ((goal - le32_to_cpu(es->s_first_data_block)) % EXT2_BLOCKS_PER_GROUP(sb));
 #ifdef EXT2FS_DEBUG
 		if (j)
 			goal_attempts++;
@@ -305,7 +311,7 @@
 
 		ext2_debug ("goal is at %d:%d.\n", i, j);
 
-		if (!test_bit(j, bh->b_data)) {
+		if (!ext2_test_bit(j, bh->b_data)) {
 #ifdef EXT2FS_DEBUG
 			goal_hits++;
 			ext2_debug ("goal bit allocated.\n");
@@ -322,7 +328,7 @@
 			 * next 64-bit boundary is simple..
 			 */
 			int end_goal = (j + 63) & ~63;
-			j = find_next_zero_bit(bh->b_data, end_goal, j);
+			j = ext2_find_next_zero_bit(bh->b_data, end_goal, j);
 			if (j < end_goal)
 				goto got_block;
 		}
@@ -345,7 +351,8 @@
 			j = k;
 			goto search_back;
 		}
-		k = find_next_zero_bit ((unsigned long *) bh->b_data, 
+
+		k = ext2_find_next_zero_bit ((unsigned long *) bh->b_data, 
 					EXT2_BLOCKS_PER_GROUP(sb),
 					j);
 		if (k < EXT2_BLOCKS_PER_GROUP(sb)) {
@@ -365,7 +372,7 @@
 		if (i >= sb->u.ext2_sb.s_groups_count)
 			i = 0;
 		gdp = get_group_desc (sb, i, &bh2);
-		if (gdp->bg_free_blocks_count > 0)
+		if (le16_to_cpu(gdp->bg_free_blocks_count) > 0)
 			break;
 	}
 	if (k >= sb->u.ext2_sb.s_groups_count) {
@@ -379,7 +386,7 @@
 	if (j < EXT2_BLOCKS_PER_GROUP(sb))
 		goto search_back;
 	else
-		j = find_first_zero_bit ((unsigned long *) bh->b_data,
+		j = ext2_find_first_zero_bit ((unsigned long *) bh->b_data,
 					 EXT2_BLOCKS_PER_GROUP(sb));
 	if (j >= EXT2_BLOCKS_PER_GROUP(sb)) {
 		ext2_error (sb, "ext2_new_block",
@@ -394,7 +401,7 @@
 	 * bitmap.  Now search backwards up to 7 bits to find the
 	 * start of this group of free blocks.
 	 */
-	for (k = 0; k < 7 && j > 0 && !test_bit (j - 1, bh->b_data); k++, j--);
+	for (k = 0; k < 7 && j > 0 && !ext2_test_bit (j - 1, bh->b_data); k++, j--);
 	
 got_block:
 
@@ -410,17 +417,17 @@
 			return 0;
 		}
 
-	tmp = j + i * EXT2_BLOCKS_PER_GROUP(sb) + es->s_first_data_block;
+	tmp = j + i * EXT2_BLOCKS_PER_GROUP(sb) + le32_to_cpu(es->s_first_data_block);
 
 	if (test_opt (sb, CHECK_STRICT) &&
-	    (tmp == gdp->bg_block_bitmap ||
-	     tmp == gdp->bg_inode_bitmap ||
-	     in_range (tmp, gdp->bg_inode_table, sb->u.ext2_sb.s_itb_per_group)))
+	    (tmp == le32_to_cpu(gdp->bg_block_bitmap) ||
+	     tmp == le32_to_cpu(gdp->bg_inode_bitmap) ||
+	     in_range (tmp, le32_to_cpu(gdp->bg_inode_table), sb->u.ext2_sb.s_itb_per_group)))
 		ext2_panic (sb, "ext2_new_block",
 			    "Allocating block in system zone - "
 			    "block = %u", tmp);
 
-	if (set_bit (j, bh->b_data)) {
+	if (ext2_set_bit (j, bh->b_data)) {
 		ext2_warning (sb, "ext2_new_block",
 			      "bit already set for block %d", j);
 		if (sb->dq_op)
@@ -442,15 +449,19 @@
 			if (sb->dq_op)
 				if (sb->dq_op->alloc_block(inode, fs_to_dq_blocks(1, sb->s_blocksize)))
 					break;
-			if (set_bit (j + k, bh->b_data)) {
+			if (ext2_set_bit (j + k, bh->b_data)) {
 				if (sb->dq_op)
 					sb->dq_op->free_block(inode, fs_to_dq_blocks(1, sb->s_blocksize));
-				break;
+ 				break;
 			}
 			(*prealloc_count)++;
 		}	
-		gdp->bg_free_blocks_count -= *prealloc_count;
-		es->s_free_blocks_count -= *prealloc_count;
+		gdp->bg_free_blocks_count =
+			cpu_to_le16(le16_to_cpu(gdp->bg_free_blocks_count) -
+			       *prealloc_count);
+		es->s_free_blocks_count =
+			cpu_to_le32(le32_to_cpu(es->s_free_blocks_count) -
+			       *prealloc_count);
 		ext2_debug ("Preallocated a further %lu bits.\n",
 			    *prealloc_count);
 	}
@@ -464,7 +475,7 @@
 		wait_on_buffer (bh);
 	}
 
-	if (j >= es->s_blocks_count) {
+	if (j >= le32_to_cpu(es->s_blocks_count)) {
 		ext2_error (sb, "ext2_new_block",
 			    "block >= blocks count - "
 			    "block_group = %d, block=%d", i, j);
@@ -484,9 +495,9 @@
 	ext2_debug ("allocating block %d. "
 		    "Goal hits %d of %d.\n", j, goal_hits, goal_attempts);
 
-	gdp->bg_free_blocks_count--;
+	gdp->bg_free_blocks_count = cpu_to_le16(le16_to_cpu(gdp->bg_free_blocks_count) - 1);
 	mark_buffer_dirty(bh2, 1);
-	es->s_free_blocks_count--;
+	es->s_free_blocks_count = cpu_to_le32(le32_to_cpu(es->s_free_blocks_count) - 1);
 	mark_buffer_dirty(sb->u.ext2_sb.s_sbh, 1);
 	sb->s_dirt = 1;
 	unlock_super (sb);
@@ -510,20 +521,20 @@
 	gdp = NULL;
 	for (i = 0; i < sb->u.ext2_sb.s_groups_count; i++) {
 		gdp = get_group_desc (sb, i, NULL);
-		desc_count += gdp->bg_free_blocks_count;
+		desc_count += le16_to_cpu(gdp->bg_free_blocks_count);
 		bitmap_nr = load_block_bitmap (sb, i);
 		x = ext2_count_free (sb->u.ext2_sb.s_block_bitmap[bitmap_nr],
 				     sb->s_blocksize);
 		printk ("group %d: stored = %d, counted = %lu\n",
-			i, gdp->bg_free_blocks_count, x);
+			i, le16_to_cpu(gdp->bg_free_blocks_count), x);
 		bitmap_count += x;
 	}
 	printk("ext2_count_free_blocks: stored = %lu, computed = %lu, %lu\n",
-	       es->s_free_blocks_count, desc_count, bitmap_count);
+	       le32_to_cpu(es->s_free_blocks_count), desc_count, bitmap_count);
 	unlock_super (sb);
 	return bitmap_count;
 #else
-	return sb->u.ext2_sb.s_es->s_free_blocks_count;
+	return le32_to_cpu(sb->u.ext2_sb.s_es->s_free_blocks_count);
 #endif
 }
 
@@ -531,7 +542,7 @@
 				struct super_block * sb,
 				unsigned char * map)
 {
-	return test_bit ((block - sb->u.ext2_sb.s_es->s_first_data_block) %
+	return ext2_test_bit ((block - le32_to_cpu(sb->u.ext2_sb.s_es->s_first_data_block)) %
 			 EXT2_BLOCKS_PER_GROUP(sb), map);
 }
 
@@ -554,48 +565,48 @@
 		      EXT2_DESC_PER_BLOCK(sb);
 	for (i = 0; i < sb->u.ext2_sb.s_groups_count; i++) {
 		gdp = get_group_desc (sb, i, NULL);
-		desc_count += gdp->bg_free_blocks_count;
+		desc_count += le16_to_cpu(gdp->bg_free_blocks_count);
 		bitmap_nr = load_block_bitmap (sb, i);
 		bh = sb->u.ext2_sb.s_block_bitmap[bitmap_nr];
 
-		if (!test_bit (0, bh->b_data))
+		if (!ext2_test_bit (0, bh->b_data))
 			ext2_error (sb, "ext2_check_blocks_bitmap",
 				    "Superblock in group %d is marked free", i);
 
 		for (j = 0; j < desc_blocks; j++)
-			if (!test_bit (j + 1, bh->b_data))
+			if (!ext2_test_bit (j + 1, bh->b_data))
 				ext2_error (sb, "ext2_check_blocks_bitmap",
 					    "Descriptor block #%d in group "
 					    "%d is marked free", j, i);
 
-		if (!block_in_use (gdp->bg_block_bitmap, sb, bh->b_data))
+		if (!block_in_use (le32_to_cpu(gdp->bg_block_bitmap), sb, bh->b_data))
 			ext2_error (sb, "ext2_check_blocks_bitmap",
 				    "Block bitmap for group %d is marked free",
 				    i);
 
-		if (!block_in_use (gdp->bg_inode_bitmap, sb, bh->b_data))
+		if (!block_in_use (le32_to_cpu(gdp->bg_inode_bitmap), sb, bh->b_data))
 			ext2_error (sb, "ext2_check_blocks_bitmap",
 				    "Inode bitmap for group %d is marked free",
 				    i);
 
 		for (j = 0; j < sb->u.ext2_sb.s_itb_per_group; j++)
-			if (!block_in_use (gdp->bg_inode_table + j, sb, bh->b_data))
+			if (!block_in_use (le32_to_cpu(gdp->bg_inode_table) + j, sb, bh->b_data))
 				ext2_error (sb, "ext2_check_blocks_bitmap",
 					    "Block #%d of the inode table in "
 					    "group %d is marked free", j, i);
 
 		x = ext2_count_free (bh, sb->s_blocksize);
-		if (gdp->bg_free_blocks_count != x)
+		if (le16_to_cpu(gdp->bg_free_blocks_count) != x)
 			ext2_error (sb, "ext2_check_blocks_bitmap",
 				    "Wrong free blocks count for group %d, "
 				    "stored = %d, counted = %lu", i,
-				    gdp->bg_free_blocks_count, x);
+				    le16_to_cpu(gdp->bg_free_blocks_count), x);
 		bitmap_count += x;
 	}
-	if (es->s_free_blocks_count != bitmap_count)
+	if (le32_to_cpu(es->s_free_blocks_count) != bitmap_count)
 		ext2_error (sb, "ext2_check_blocks_bitmap",
 			    "Wrong free blocks count in super block, "
 			    "stored = %lu, counted = %lu",
-			    (unsigned long) es->s_free_blocks_count, bitmap_count);
+			    (unsigned long) le32_to_cpu(es->s_free_blocks_count), bitmap_count);
 	unlock_super (sb);
 }
diff -u --recursive --new-file v2.1.9/linux/fs/ext2/dir.c linux/fs/ext2/dir.c
--- v2.1.9/linux/fs/ext2/dir.c	Tue Oct 29 19:58:42 1996
+++ linux/fs/ext2/dir.c	Thu Nov 14 10:27:37 1996
@@ -13,6 +13,9 @@
  *  Copyright (C) 1991, 1992  Linus Torvalds
  *
  *  ext2 directory handling functions
+ *
+ *  Big-endian to little-endian byte-swapping/bitmaps by
+ *        David S. Miller (davem@caip.rutgers.edu), 1995
  */
 
 #include <asm/uaccess.h>
@@ -77,23 +80,24 @@
 {
 	const char * error_msg = NULL;
 
-	if (de->rec_len < EXT2_DIR_REC_LEN(1))
+	if (le16_to_cpu(de->rec_len) < EXT2_DIR_REC_LEN(1))
 		error_msg = "rec_len is smaller than minimal";
-	else if (de->rec_len % 4 != 0)
+	else if (le16_to_cpu(de->rec_len) % 4 != 0)
 		error_msg = "rec_len % 4 != 0";
-	else if (de->rec_len < EXT2_DIR_REC_LEN(de->name_len))
+	else if (le16_to_cpu(de->rec_len) < EXT2_DIR_REC_LEN(le16_to_cpu(de->name_len)))
 		error_msg = "rec_len is too small for name_len";
-	else if (dir && ((char *) de - bh->b_data) + de->rec_len >
+	else if (dir && ((char *) de - bh->b_data) + le16_to_cpu(de->rec_len) >
 		 dir->i_sb->s_blocksize)
 		error_msg = "directory entry across blocks";
-	else if (dir && de->inode > dir->i_sb->u.ext2_sb.s_es->s_inodes_count)
+	else if (dir && le32_to_cpu(de->inode) > le32_to_cpu(dir->i_sb->u.ext2_sb.s_es->s_inodes_count))
 		error_msg = "inode out of bounds";
 
 	if (error_msg != NULL)
 		ext2_error (dir->i_sb, function, "bad entry in directory #%lu: %s - "
 			    "offset=%lu, inode=%lu, rec_len=%d, name_len=%d",
-			    dir->i_ino, error_msg, offset, (unsigned long) de->inode,
-			    de->rec_len, de->name_len);
+			    dir->i_ino, error_msg, offset,
+			    (unsigned long) le32_to_cpu(de->inode),
+			    le16_to_cpu(de->rec_len), le16_to_cpu(de->name_len));
 	return error_msg == NULL ? 1 : 0;
 }
 
@@ -161,9 +165,9 @@
 				 * least that it is non-zero.  A
 				 * failure will be detected in the
 				 * dirent test below. */
-				if (de->rec_len < EXT2_DIR_REC_LEN(1))
+				if (le16_to_cpu(de->rec_len) < EXT2_DIR_REC_LEN(1))
 					break;
-				i += de->rec_len;
+				i += le16_to_cpu(de->rec_len);
 			}
 			offset = i;
 			filp->f_pos = (filp->f_pos & ~(sb->s_blocksize - 1))
@@ -183,8 +187,8 @@
 				brelse (bh);
 				return stored;
 			}
-			offset += de->rec_len;
-			if (de->inode) {
+			offset += le16_to_cpu(de->rec_len);
+			if (le32_to_cpu(de->inode)) {
 				/* We might block in the next section
 				 * if the data destination is
 				 * currently swapped out.  So, use a
@@ -192,16 +196,17 @@
 				 * not the directory has been modified
 				 * during the copy operation. */
 				unsigned long version;
-				dcache_add(inode, de->name, de->name_len, de->inode);
+				dcache_add(inode, de->name, le16_to_cpu(de->name_len),
+					   le32_to_cpu(de->inode));
 				version = inode->i_version;
-				error = filldir(dirent, de->name, de->name_len, filp->f_pos, de->inode);
+				error = filldir(dirent, de->name, le16_to_cpu(de->name_len), filp->f_pos, le32_to_cpu(de->inode));
 				if (error)
 					break;
 				if (version != inode->i_version)
 					goto revalidate;
 				stored ++;
 			}
-			filp->f_pos += de->rec_len;
+			filp->f_pos += le16_to_cpu(de->rec_len);
 		}
 		offset = 0;
 		brelse (bh);
diff -u --recursive --new-file v2.1.9/linux/fs/ext2/fsync.c linux/fs/ext2/fsync.c
--- v2.1.9/linux/fs/ext2/fsync.c	Tue Oct 29 19:58:42 1996
+++ linux/fs/ext2/fsync.c	Thu Nov 14 10:27:37 1996
@@ -10,6 +10,9 @@
  *  linux/fs/minix/truncate.c   Copyright (C) 1991, 1992  Linus Torvalds
  * 
  *  ext2fs fsync primitive
+ *
+ *  Big-endian to little-endian byte-swapping/bitmaps by
+ *        David S. Miller (davem@caip.rutgers.edu), 1995
  */
 
 #include <asm/uaccess.h>
@@ -27,7 +30,7 @@
 #define blocksize (EXT2_BLOCK_SIZE(inode->i_sb))
 #define addr_per_block (EXT2_ADDR_PER_BLOCK(inode->i_sb))
 
-static int sync_block (struct inode * inode, u32 * block, int wait)
+static __inline__ int sync_block (struct inode * inode, u32 * block, int wait)
 {
 	struct buffer_head * bh;
 	int tmp;
@@ -55,7 +58,35 @@
 	return 0;
 }
 
-static int sync_iblock (struct inode * inode, u32 * iblock, 
+static __inline__ int sync_block_swab32 (struct inode * inode, u32 * block, int wait)
+{
+	struct buffer_head * bh;
+	int tmp;
+	
+	if (!le32_to_cpu(*block))
+		return 0;
+	tmp = le32_to_cpu(*block);
+	bh = get_hash_table (inode->i_dev, le32_to_cpu(*block), blocksize);
+	if (!bh)
+		return 0;
+	if (le32_to_cpu(*block) != tmp) {
+		brelse (bh);
+		return 1;
+	}
+	if (wait && buffer_req(bh) && !buffer_uptodate(bh)) {
+		brelse (bh);
+		return -1;
+	}
+	if (wait || !buffer_uptodate(bh) || !buffer_dirty(bh)) {
+		brelse (bh);
+		return 0;
+	}
+	ll_rw_block (WRITE, 1, &bh);
+	bh->b_count--;
+	return 0;
+}
+
+static __inline__ int sync_iblock (struct inode * inode, u32 * iblock, 
 			struct buffer_head ** bh, int wait) 
 {
 	int rc, tmp;
@@ -78,8 +109,31 @@
 	return 0;
 }
 
+static __inline__ int sync_iblock_swab32 (struct inode * inode, u32 * iblock, 
+			       struct buffer_head ** bh, int wait) 
+{
+	int rc, tmp;
+	
+	*bh = NULL;
+	tmp = le32_to_cpu(*iblock);
+	if (!tmp)
+		return 0;
+	rc = sync_block_swab32 (inode, iblock, wait);
+	if (rc)
+		return rc;
+	*bh = bread (inode->i_dev, tmp, blocksize);
+	if (tmp != le32_to_cpu(*iblock)) {
+		brelse (*bh);
+		*bh = NULL;
+		return 1;
+	}
+	if (!*bh)
+		return -1;
+	return 0;
+}
+
 
-static int sync_direct (struct inode * inode, int wait)
+static __inline__ int sync_direct (struct inode * inode, int wait)
 {
 	int i;
 	int rc, err = 0;
@@ -94,7 +148,7 @@
 	return err;
 }
 
-static int sync_indirect (struct inode * inode, u32 * iblock, int wait)
+static __inline__ int sync_indirect (struct inode * inode, u32 * iblock, int wait)
 {
 	int i;
 	struct buffer_head * ind_bh;
@@ -105,9 +159,32 @@
 		return rc;
 	
 	for (i = 0; i < addr_per_block; i++) {
-		rc = sync_block (inode, 
-				 ((u32 *) ind_bh->b_data) + i,
-				 wait);
+		rc = sync_block_swab32 (inode, 
+					((u32 *) ind_bh->b_data) + i,
+					wait);
+		if (rc > 0)
+			break;
+		if (rc)
+			err = rc;
+	}
+	brelse (ind_bh);
+	return err;
+}
+
+static __inline__ int sync_indirect_swab32 (struct inode * inode, u32 * iblock, int wait)
+{
+	int i;
+	struct buffer_head * ind_bh;
+	int rc, err = 0;
+
+	rc = sync_iblock_swab32 (inode, iblock, &ind_bh, wait);
+	if (rc || !ind_bh)
+		return rc;
+	
+	for (i = 0; i < addr_per_block; i++) {
+		rc = sync_block_swab32 (inode, 
+					((u32 *) ind_bh->b_data) + i,
+					wait);
 		if (rc > 0)
 			break;
 		if (rc)
@@ -117,7 +194,7 @@
 	return err;
 }
 
-static int sync_dindirect (struct inode * inode, u32 * diblock, int wait)
+static __inline__ int sync_dindirect (struct inode * inode, u32 * diblock, int wait)
 {
 	int i;
 	struct buffer_head * dind_bh;
@@ -128,9 +205,32 @@
 		return rc;
 	
 	for (i = 0; i < addr_per_block; i++) {
-		rc = sync_indirect (inode,
-				    ((u32 *) dind_bh->b_data) + i,
-				    wait);
+		rc = sync_indirect_swab32 (inode,
+					   ((u32 *) dind_bh->b_data) + i,
+					   wait);
+		if (rc > 0)
+			break;
+		if (rc)
+			err = rc;
+	}
+	brelse (dind_bh);
+	return err;
+}
+
+static __inline__ int sync_dindirect_swab32 (struct inode * inode, u32 * diblock, int wait)
+{
+	int i;
+	struct buffer_head * dind_bh;
+	int rc, err = 0;
+
+	rc = sync_iblock_swab32 (inode, diblock, &dind_bh, wait);
+	if (rc || !dind_bh)
+		return rc;
+	
+	for (i = 0; i < addr_per_block; i++) {
+		rc = sync_indirect_swab32 (inode,
+					   ((u32 *) dind_bh->b_data) + i,
+					   wait);
 		if (rc > 0)
 			break;
 		if (rc)
@@ -140,7 +240,7 @@
 	return err;
 }
 
-static int sync_tindirect (struct inode * inode, u32 * tiblock, int wait)
+static __inline__ int sync_tindirect (struct inode * inode, u32 * tiblock, int wait)
 {
 	int i;
 	struct buffer_head * tind_bh;
@@ -151,9 +251,9 @@
 		return rc;
 	
 	for (i = 0; i < addr_per_block; i++) {
-		rc = sync_dindirect (inode,
-				     ((u32 *) tind_bh->b_data) + i,
-				     wait);
+		rc = sync_dindirect_swab32 (inode,
+					    ((u32 *) tind_bh->b_data) + i,
+					    wait);
 		if (rc > 0)
 			break;
 		if (rc)
diff -u --recursive --new-file v2.1.9/linux/fs/ext2/ialloc.c linux/fs/ext2/ialloc.c
--- v2.1.9/linux/fs/ext2/ialloc.c	Sat May  4 10:06:18 1996
+++ linux/fs/ext2/ialloc.c	Thu Nov 14 10:27:37 1996
@@ -8,6 +8,8 @@
  *
  *  BSD ufs-inspired inode and directory allocation by 
  *  Stephen Tweedie (sct@dcs.ed.ac.uk), 1993
+ *  Big-endian to little-endian byte-swapping/bitmaps by
+ *        David S. Miller (davem@caip.rutgers.edu), 1995
  */
 
 /*
@@ -33,6 +35,7 @@
 #include <linux/locks.h>
 
 #include <asm/bitops.h>
+#include <asm/byteorder.h>
 
 static struct ext2_group_desc * get_group_desc (struct super_block * sb,
 						unsigned int block_group,
@@ -70,12 +73,12 @@
 	struct buffer_head * bh;
 
 	gdp = get_group_desc (sb, block_group, NULL);
-	bh = bread (sb->s_dev, gdp->bg_inode_bitmap, sb->s_blocksize);
+	bh = bread (sb->s_dev, le32_to_cpu(gdp->bg_inode_bitmap), sb->s_blocksize);
 	if (!bh)
 		ext2_panic (sb, "read_inode_bitmap",
 			    "Cannot read inode bitmap - "
 			    "block_group = %lu, inode_bitmap = %lu",
-			    block_group, (unsigned long) gdp->bg_inode_bitmap);
+			    block_group, (unsigned long) le32_to_cpu(gdp->bg_inode_bitmap));
 	sb->u.ext2_sb.s_inode_bitmap_number[bitmap_nr] = block_group;
 	sb->u.ext2_sb.s_inode_bitmap[bitmap_nr] = bh;
 }
@@ -188,7 +191,7 @@
 	sb = inode->i_sb;
 	lock_super (sb);
 	if (inode->i_ino < EXT2_FIRST_INO(sb) ||
-	    inode->i_ino > sb->u.ext2_sb.s_es->s_inodes_count) {
+	    inode->i_ino > le32_to_cpu(sb->u.ext2_sb.s_es->s_inodes_count)) {
 		ext2_error (sb, "free_inode",
 			    "reserved inode or nonexistent inode");
 		unlock_super (sb);
@@ -199,16 +202,19 @@
 	bit = (inode->i_ino - 1) % EXT2_INODES_PER_GROUP(sb);
 	bitmap_nr = load_inode_bitmap (sb, block_group);
 	bh = sb->u.ext2_sb.s_inode_bitmap[bitmap_nr];
-	if (!clear_bit (bit, bh->b_data))
+	if (!ext2_clear_bit (bit, bh->b_data))
 		ext2_warning (sb, "ext2_free_inode",
 			      "bit already cleared for inode %lu", inode->i_ino);
 	else {
 		gdp = get_group_desc (sb, block_group, &bh2);
-		gdp->bg_free_inodes_count++;
+		gdp->bg_free_inodes_count =
+			cpu_to_le16(le16_to_cpu(gdp->bg_free_inodes_count) + 1);
 		if (S_ISDIR(inode->i_mode))
-			gdp->bg_used_dirs_count--;
+			gdp->bg_used_dirs_count =
+				cpu_to_le16(le16_to_cpu(gdp->bg_used_dirs_count) - 1);
 		mark_buffer_dirty(bh2, 1);
-		es->s_free_inodes_count++;
+		es->s_free_inodes_count =
+			cpu_to_le32(le32_to_cpu(es->s_free_inodes_count) + 1);
 		mark_buffer_dirty(sb->u.ext2_sb.s_sbh, 1);
 		inode->i_dirt = 0;
 	}
@@ -273,14 +279,14 @@
 	
 	*err = -ENOSPC;
 	if (S_ISDIR(mode)) {
-		avefreei = es->s_free_inodes_count /
+		avefreei = le32_to_cpu(es->s_free_inodes_count) /
 			sb->u.ext2_sb.s_groups_count;
 /* I am not yet convinced that this next bit is necessary.
 		i = dir->u.ext2_i.i_block_group;
 		for (j = 0; j < sb->u.ext2_sb.s_groups_count; j++) {
 			tmp = get_group_desc (sb, i, &bh2);
-			if ((tmp->bg_used_dirs_count << 8) < 
-			    tmp->bg_free_inodes_count) {
+			if ((le16_to_cpu(tmp->bg_used_dirs_count) << 8) < 
+			    le16_to_cpu(tmp->bg_free_inodes_count)) {
 				gdp = tmp;
 				break;
 			}
@@ -291,11 +297,11 @@
 		if (!gdp) {
 			for (j = 0; j < sb->u.ext2_sb.s_groups_count; j++) {
 				tmp = get_group_desc (sb, j, &bh2);
-				if (tmp->bg_free_inodes_count &&
-					tmp->bg_free_inodes_count >= avefreei) {
+				if (le16_to_cpu(tmp->bg_free_inodes_count) &&
+					le16_to_cpu(tmp->bg_free_inodes_count) >= avefreei) {
 					if (!gdp || 
-					    (tmp->bg_free_blocks_count >
-					     gdp->bg_free_blocks_count)) {
+					    (le16_to_cpu(tmp->bg_free_blocks_count) >
+					     le16_to_cpu(gdp->bg_free_blocks_count))) {
 						i = j;
 						gdp = tmp;
 					}
@@ -310,7 +316,7 @@
 		 */
 		i = dir->u.ext2_i.i_block_group;
 		tmp = get_group_desc (sb, i, &bh2);
-		if (tmp->bg_free_inodes_count)
+		if (le16_to_cpu(tmp->bg_free_inodes_count))
 			gdp = tmp;
 		else
 		{
@@ -323,7 +329,7 @@
 				if (i >= sb->u.ext2_sb.s_groups_count)
 					i -= sb->u.ext2_sb.s_groups_count;
 				tmp = get_group_desc (sb, i, &bh2);
-				if (tmp->bg_free_inodes_count) {
+				if (le16_to_cpu(tmp->bg_free_inodes_count)) {
 					gdp = tmp;
 					break;
 				}
@@ -338,7 +344,7 @@
 				if (++i >= sb->u.ext2_sb.s_groups_count)
 					i = 0;
 				tmp = get_group_desc (sb, i, &bh2);
-				if (tmp->bg_free_inodes_count) {
+				if (le16_to_cpu(tmp->bg_free_inodes_count)) {
 					gdp = tmp;
 					break;
 				}
@@ -353,10 +359,10 @@
 	}
 	bitmap_nr = load_inode_bitmap (sb, i);
 	bh = sb->u.ext2_sb.s_inode_bitmap[bitmap_nr];
-	if ((j = find_first_zero_bit ((unsigned long *) bh->b_data,
+	if ((j = ext2_find_first_zero_bit ((unsigned long *) bh->b_data,
 				      EXT2_INODES_PER_GROUP(sb))) <
 	    EXT2_INODES_PER_GROUP(sb)) {
-		if (set_bit (j, bh->b_data)) {
+		if (ext2_set_bit (j, bh->b_data)) {
 			ext2_warning (sb, "ext2_new_inode",
 				      "bit already set for inode %d", j);
 			goto repeat;
@@ -367,7 +373,7 @@
 			wait_on_buffer (bh);
 		}
 	} else {
-		if (gdp->bg_free_inodes_count != 0) {
+		if (le16_to_cpu(gdp->bg_free_inodes_count) != 0) {
 			ext2_error (sb, "ext2_new_inode",
 				    "Free inodes count corrupted in group %d",
 				    i);
@@ -378,7 +384,7 @@
 		goto repeat;
 	}
 	j += i * EXT2_INODES_PER_GROUP(sb) + 1;
-	if (j < EXT2_FIRST_INO(sb) || j > es->s_inodes_count) {
+	if (j < EXT2_FIRST_INO(sb) || j > le32_to_cpu(es->s_inodes_count)) {
 		ext2_error (sb, "ext2_new_inode",
 			    "reserved inode or inode > inodes count - "
 			    "block_group = %d,inode=%d", i, j);
@@ -386,11 +392,14 @@
 		iput (inode);
 		return NULL;
 	}
-	gdp->bg_free_inodes_count--;
+	gdp->bg_free_inodes_count =
+		cpu_to_le16(le16_to_cpu(gdp->bg_free_inodes_count) - 1);
 	if (S_ISDIR(mode))
-		gdp->bg_used_dirs_count++;
+		gdp->bg_used_dirs_count =
+			cpu_to_le16(le16_to_cpu(gdp->bg_used_dirs_count) + 1);
 	mark_buffer_dirty(bh2, 1);
-	es->s_free_inodes_count--;
+	es->s_free_inodes_count =
+		cpu_to_le32(le32_to_cpu(es->s_free_inodes_count) - 1);
 	mark_buffer_dirty(sb->u.ext2_sb.s_sbh, 1);
 	sb->s_dirt = 1;
 	inode->i_mode = mode;
@@ -463,20 +472,20 @@
 	gdp = NULL;
 	for (i = 0; i < sb->u.ext2_sb.s_groups_count; i++) {
 		gdp = get_group_desc (sb, i, NULL);
-		desc_count += gdp->bg_free_inodes_count;
+		desc_count += le16_to_cpu(gdp->bg_free_inodes_count);
 		bitmap_nr = load_inode_bitmap (sb, i);
 		x = ext2_count_free (sb->u.ext2_sb.s_inode_bitmap[bitmap_nr],
 				     EXT2_INODES_PER_GROUP(sb) / 8);
 		printk ("group %d: stored = %d, counted = %lu\n",
-			i, gdp->bg_free_inodes_count, x);
+			i, le16_to_cpu(gdp->bg_free_inodes_count), x);
 		bitmap_count += x;
 	}
 	printk("ext2_count_free_inodes: stored = %lu, computed = %lu, %lu\n",
-		es->s_free_inodes_count, desc_count, bitmap_count);
+		le32_to_cpu(es->s_free_inodes_count), desc_count, bitmap_count);
 	unlock_super (sb);
 	return desc_count;
 #else
-	return sb->u.ext2_sb.s_es->s_free_inodes_count;
+	return le32_to_cpu(sb->u.ext2_sb.s_es->s_free_inodes_count);
 #endif
 }
 
@@ -495,21 +504,22 @@
 	gdp = NULL;
 	for (i = 0; i < sb->u.ext2_sb.s_groups_count; i++) {
 		gdp = get_group_desc (sb, i, NULL);
-		desc_count += gdp->bg_free_inodes_count;
+		desc_count += le16_to_cpu(gdp->bg_free_inodes_count);
 		bitmap_nr = load_inode_bitmap (sb, i);
 		x = ext2_count_free (sb->u.ext2_sb.s_inode_bitmap[bitmap_nr],
 				     EXT2_INODES_PER_GROUP(sb) / 8);
-		if (gdp->bg_free_inodes_count != x)
+		if (le16_to_cpu(gdp->bg_free_inodes_count) != x)
 			ext2_error (sb, "ext2_check_inodes_bitmap",
 				    "Wrong free inodes count in group %d, "
 				    "stored = %d, counted = %lu", i,
-				    gdp->bg_free_inodes_count, x);
+				    le16_to_cpu(gdp->bg_free_inodes_count), x);
 		bitmap_count += x;
 	}
-	if (es->s_free_inodes_count != bitmap_count)
+	if (le32_to_cpu(es->s_free_inodes_count) != bitmap_count)
 		ext2_error (sb, "ext2_check_inodes_bitmap",
 			    "Wrong free inodes count in super block, "
 			    "stored = %lu, counted = %lu",
-			    (unsigned long) es->s_free_inodes_count, bitmap_count);
+			    (unsigned long) le32_to_cpu(es->s_free_inodes_count),
+			    bitmap_count);
 	unlock_super (sb);
 }
diff -u --recursive --new-file v2.1.9/linux/fs/ext2/inode.c linux/fs/ext2/inode.c
--- v2.1.9/linux/fs/ext2/inode.c	Tue Oct 29 19:58:42 1996
+++ linux/fs/ext2/inode.c	Thu Nov 14 10:27:37 1996
@@ -13,6 +13,8 @@
  *  Copyright (C) 1991, 1992  Linus Torvalds
  *
  *  Goal-directed block allocation by Stephen Tweedie (sct@dcs.ed.ac.uk), 1993
+ *  Big-endian to little-endian byte-swapping/bitmaps by
+ *        David S. Miller (davem@caip.rutgers.edu), 1995
  */
 
 #include <asm/uaccess.h>
@@ -52,7 +54,7 @@
 
 	if (!bh)
 		return 0;
-	tmp = ((u32 *) bh->b_data)[nr];
+	tmp = le32_to_cpu(((u32 *) bh->b_data)[nr]);
 	brelse (bh);
 	return tmp;
 }
@@ -115,7 +117,7 @@
 		ext2_debug ("preallocation miss (%lu/%lu).\n",
 			    alloc_hits, ++alloc_attempts);
 		if (S_ISREG(inode->i_mode))
-			result = ext2_new_block (inode, goal,
+			result = ext2_new_block (inode, goal, 
 				 &inode->u.ext2_i.i_prealloc_count,
 				 &inode->u.ext2_i.i_prealloc_block, err);
 		else
@@ -224,7 +226,7 @@
 		if (!goal)
 			goal = (inode->u.ext2_i.i_block_group * 
 				EXT2_BLOCKS_PER_GROUP(inode->i_sb)) +
-			       inode->i_sb->u.ext2_sb.s_es->s_first_data_block;
+			       le32_to_cpu(inode->i_sb->u.ext2_sb.s_es->s_first_data_block);
 	}
 
 	ext2_debug ("goal = %d.\n", goal);
@@ -272,10 +274,10 @@
 	}
 	p = (u32 *) bh->b_data + nr;
 repeat:
-	tmp = *p;
+	tmp = le32_to_cpu(*p);
 	if (tmp) {
 		result = getblk (bh->b_dev, tmp, blocksize);
-		if (tmp == *p) {
+		if (tmp == le32_to_cpu(*p)) {
 			brelse (bh);
 			return result;
 		}
@@ -293,8 +295,8 @@
 		goal = inode->u.ext2_i.i_next_alloc_goal;
 	if (!goal) {
 		for (tmp = nr - 1; tmp >= 0; tmp--) {
-			if (((u32 *) bh->b_data)[tmp]) {
-				goal = ((u32 *)bh->b_data)[tmp];
+			if (le32_to_cpu(((u32 *) bh->b_data)[tmp])) {
+				goal = le32_to_cpu(((u32 *)bh->b_data)[tmp]);
 				break;
 			}
 		}
@@ -307,12 +309,12 @@
 		return NULL;
 	}
 	result = getblk (bh->b_dev, tmp, blocksize);
-	if (*p) {
+	if (le32_to_cpu(*p)) {
 		ext2_free_blocks (inode, tmp, 1);
 		brelse (result);
 		goto repeat;
 	}
-	*p = tmp;
+	*p = le32_to_cpu(tmp);
 	mark_buffer_dirty(bh, 1);
 	if (IS_SYNC(inode) || inode->u.ext2_i.i_osync) {
 		ll_rw_block (WRITE, 1, &bh);
@@ -348,15 +350,15 @@
 	  p = (u32 *) bh->b_data + nr + i;
 	  
 	  /* All blocks in cluster must already be allocated */
-	  if(*p == 0) goto out;
+	  if(le32_to_cpu(*p) == 0) goto out;
 	  
 	  /* See if aligned correctly */
-	  if(i==0) firstblock = *p;
-	  else if(*p != firstblock + i) goto out;
+	  if(i==0) firstblock = le32_to_cpu(*p);
+	  else if(le32_to_cpu(*p) != firstblock + i) goto out;
 	}
 	
 	p = (u32 *) bh->b_data + nr;
-	result = generate_cluster(bh->b_dev, (int *) p, blocksize);
+	result = generate_cluster_swab32(bh->b_dev, (int *) p, blocksize);
 
       out:
 	brelse(bh);
@@ -506,7 +508,7 @@
 	if ((inode->i_ino != EXT2_ROOT_INO && inode->i_ino != EXT2_ACL_IDX_INO &&
 	     inode->i_ino != EXT2_ACL_DATA_INO &&
 	     inode->i_ino < EXT2_FIRST_INO(inode->i_sb)) ||
-	    inode->i_ino > inode->i_sb->u.ext2_sb.s_es->s_inodes_count) {
+	    inode->i_ino > le32_to_cpu(inode->i_sb->u.ext2_sb.s_es->s_inodes_count)) {
 		ext2_error (inode->i_sb, "ext2_read_inode",
 			    "bad inode number: %lu", inode->i_ino);
 		return;
@@ -527,7 +529,7 @@
 	 */
 	offset = ((inode->i_ino - 1) % EXT2_INODES_PER_GROUP(inode->i_sb)) *
 		EXT2_INODE_SIZE(inode->i_sb);
-	block = gdp[desc].bg_inode_table +
+	block = le32_to_cpu(gdp[desc].bg_inode_table) +
 		(offset >> EXT2_BLOCK_SIZE_BITS(inode->i_sb));
 	if (!(bh = bread (inode->i_dev, block, inode->i_sb->s_blocksize)))
 		ext2_panic (inode->i_sb, "ext2_read_inode",
@@ -536,27 +538,27 @@
 	offset &= (EXT2_BLOCK_SIZE(inode->i_sb) - 1);
 	raw_inode = (struct ext2_inode *) (bh->b_data + offset);
 
-	inode->i_mode = raw_inode->i_mode;
-	inode->i_uid = raw_inode->i_uid;
-	inode->i_gid = raw_inode->i_gid;
-	inode->i_nlink = raw_inode->i_links_count;
-	inode->i_size = raw_inode->i_size;
-	inode->i_atime = raw_inode->i_atime;
-	inode->i_ctime = raw_inode->i_ctime;
-	inode->i_mtime = raw_inode->i_mtime;
-	inode->u.ext2_i.i_dtime = raw_inode->i_dtime;
+	inode->i_mode = le16_to_cpu(raw_inode->i_mode);
+	inode->i_uid = le16_to_cpu(raw_inode->i_uid);
+	inode->i_gid = le16_to_cpu(raw_inode->i_gid);
+	inode->i_nlink = le16_to_cpu(raw_inode->i_links_count);
+	inode->i_size = le32_to_cpu(raw_inode->i_size);
+	inode->i_atime = le32_to_cpu(raw_inode->i_atime);
+	inode->i_ctime = le32_to_cpu(raw_inode->i_ctime);
+	inode->i_mtime = le32_to_cpu(raw_inode->i_mtime);
+	inode->u.ext2_i.i_dtime = le32_to_cpu(raw_inode->i_dtime);
 	inode->i_blksize = PAGE_SIZE;	/* This is the optimal IO size (for stat), not the fs block size */
-	inode->i_blocks = raw_inode->i_blocks;
+	inode->i_blocks = le32_to_cpu(raw_inode->i_blocks);
 	inode->i_version = ++event;
 	inode->u.ext2_i.i_new_inode = 0;
-	inode->u.ext2_i.i_flags = raw_inode->i_flags;
-	inode->u.ext2_i.i_faddr = raw_inode->i_faddr;
+	inode->u.ext2_i.i_flags = le32_to_cpu(raw_inode->i_flags);
+	inode->u.ext2_i.i_faddr = le32_to_cpu(raw_inode->i_faddr);
 	inode->u.ext2_i.i_frag_no = raw_inode->i_frag;
 	inode->u.ext2_i.i_frag_size = raw_inode->i_fsize;
 	inode->u.ext2_i.i_osync = 0;
-	inode->u.ext2_i.i_file_acl = raw_inode->i_file_acl;
-	inode->u.ext2_i.i_dir_acl = raw_inode->i_dir_acl;
-	inode->u.ext2_i.i_version = raw_inode->i_version;
+	inode->u.ext2_i.i_file_acl = le32_to_cpu(raw_inode->i_file_acl);
+	inode->u.ext2_i.i_dir_acl = le32_to_cpu(raw_inode->i_dir_acl);
+	inode->u.ext2_i.i_version = le32_to_cpu(raw_inode->i_version);
 	inode->u.ext2_i.i_block_group = block_group;
 	inode->u.ext2_i.i_next_alloc_block = 0;
 	inode->u.ext2_i.i_next_alloc_goal = 0;
@@ -564,9 +566,12 @@
 		ext2_error (inode->i_sb, "ext2_read_inode",
 			    "New inode has non-zero prealloc count!");
 	if (S_ISCHR(inode->i_mode) || S_ISBLK(inode->i_mode))
-		inode->i_rdev = to_kdev_t(raw_inode->i_block[0]);
+		inode->i_rdev = to_kdev_t(le32_to_cpu(raw_inode->i_block[0]));
+	else if (S_ISLNK(inode->i_mode) && !inode->i_blocks)
+		for (block = 0; block < EXT2_N_BLOCKS; block++)
+			inode->u.ext2_i.i_data[block] = raw_inode->i_block[block];
 	else for (block = 0; block < EXT2_N_BLOCKS; block++)
-		inode->u.ext2_i.i_data[block] = raw_inode->i_block[block];
+		inode->u.ext2_i.i_data[block] = le32_to_cpu(raw_inode->i_block[block]);
 	brelse (bh);
 	inode->i_op = NULL;
 	if (inode->i_ino == EXT2_ACL_IDX_INO ||
@@ -606,7 +611,7 @@
 
 	if ((inode->i_ino != EXT2_ROOT_INO &&
 	     inode->i_ino < EXT2_FIRST_INO(inode->i_sb)) ||
-	    inode->i_ino > inode->i_sb->u.ext2_sb.s_es->s_inodes_count) {
+	    inode->i_ino > le32_to_cpu(inode->i_sb->u.ext2_sb.s_es->s_inodes_count)) {
 		ext2_error (inode->i_sb, "ext2_write_inode",
 			    "bad inode number: %lu", inode->i_ino);
 		return 0;
@@ -627,7 +632,7 @@
 	 */
 	offset = ((inode->i_ino - 1) % EXT2_INODES_PER_GROUP(inode->i_sb)) *
 		EXT2_INODE_SIZE(inode->i_sb);
-	block = gdp[desc].bg_inode_table +
+	block = le32_to_cpu(gdp[desc].bg_inode_table) +
 		(offset >> EXT2_BLOCK_SIZE_BITS(inode->i_sb));
 	if (!(bh = bread (inode->i_dev, block, inode->i_sb->s_blocksize)))
 		ext2_panic (inode->i_sb, "ext2_write_inode",
@@ -636,27 +641,30 @@
 	offset &= EXT2_BLOCK_SIZE(inode->i_sb) - 1;
 	raw_inode = (struct ext2_inode *) (bh->b_data + offset);
 
-	raw_inode->i_mode = inode->i_mode;
-	raw_inode->i_uid = inode->i_uid;
-	raw_inode->i_gid = inode->i_gid;
-	raw_inode->i_links_count = inode->i_nlink;
-	raw_inode->i_size = inode->i_size;
-	raw_inode->i_atime = inode->i_atime;
-	raw_inode->i_ctime = inode->i_ctime;
-	raw_inode->i_mtime = inode->i_mtime;
-	raw_inode->i_blocks = inode->i_blocks;
-	raw_inode->i_dtime = inode->u.ext2_i.i_dtime;
-	raw_inode->i_flags = inode->u.ext2_i.i_flags;
-	raw_inode->i_faddr = inode->u.ext2_i.i_faddr;
+	raw_inode->i_mode = cpu_to_le16(inode->i_mode);
+	raw_inode->i_uid = cpu_to_le16(inode->i_uid);
+	raw_inode->i_gid = cpu_to_le16(inode->i_gid);
+	raw_inode->i_links_count = cpu_to_le16(inode->i_nlink);
+	raw_inode->i_size = cpu_to_le32(inode->i_size);
+	raw_inode->i_atime = cpu_to_le32(inode->i_atime);
+	raw_inode->i_ctime = cpu_to_le32(inode->i_ctime);
+	raw_inode->i_mtime = cpu_to_le32(inode->i_mtime);
+	raw_inode->i_blocks = cpu_to_le32(inode->i_blocks);
+	raw_inode->i_dtime = cpu_to_le32(inode->u.ext2_i.i_dtime);
+	raw_inode->i_flags = cpu_to_le32(inode->u.ext2_i.i_flags);
+	raw_inode->i_faddr = cpu_to_le32(inode->u.ext2_i.i_faddr);
 	raw_inode->i_frag = inode->u.ext2_i.i_frag_no;
 	raw_inode->i_fsize = inode->u.ext2_i.i_frag_size;
-	raw_inode->i_file_acl = inode->u.ext2_i.i_file_acl;
-	raw_inode->i_dir_acl = inode->u.ext2_i.i_dir_acl;
-	raw_inode->i_version = inode->u.ext2_i.i_version;
+	raw_inode->i_file_acl = cpu_to_le32(inode->u.ext2_i.i_file_acl);
+	raw_inode->i_dir_acl = cpu_to_le32(inode->u.ext2_i.i_dir_acl);
+	raw_inode->i_version = cpu_to_le32(inode->u.ext2_i.i_version);
 	if (S_ISCHR(inode->i_mode) || S_ISBLK(inode->i_mode))
-		raw_inode->i_block[0] = kdev_t_to_nr(inode->i_rdev);
+		raw_inode->i_block[0] = cpu_to_le32(kdev_t_to_nr(inode->i_rdev));
+	else if (S_ISLNK(inode->i_mode) && !inode->i_blocks)
+		for (block = 0; block < EXT2_N_BLOCKS; block++)
+			raw_inode->i_block[block] = inode->u.ext2_i.i_data[block];
 	else for (block = 0; block < EXT2_N_BLOCKS; block++)
-		raw_inode->i_block[block] = inode->u.ext2_i.i_data[block];
+		raw_inode->i_block[block] = cpu_to_le32(inode->u.ext2_i.i_data[block]);
 	mark_buffer_dirty(bh, 1);
 	inode->i_dirt = 0;
 	if (do_sync) {
diff -u --recursive --new-file v2.1.9/linux/fs/ext2/namei.c linux/fs/ext2/namei.c
--- v2.1.9/linux/fs/ext2/namei.c	Tue Oct 29 19:58:42 1996
+++ linux/fs/ext2/namei.c	Thu Nov 14 10:27:38 1996
@@ -11,6 +11,9 @@
  *  linux/fs/minix/namei.c
  *
  *  Copyright (C) 1991, 1992  Linus Torvalds
+ *
+ *  Big-endian to little-endian byte-swapping/bitmaps by
+ *        David S. Miller (davem@caip.rutgers.edu), 1995
  */
 
 #include <asm/uaccess.h>
@@ -38,15 +41,15 @@
 static int ext2_match (int len, const char * const name,
 		       struct ext2_dir_entry * de)
 {
-	if (!de || !de->inode || len > EXT2_NAME_LEN)
+	if (!de || !le32_to_cpu(de->inode) || len > EXT2_NAME_LEN)
 		return 0;
 	/*
 	 * "" means "." ---> so paths like "/usr/lib//libc.a" work
 	 */
-	if (!len && de->name_len == 1 && (de->name[0] == '.') &&
+	if (!len && le16_to_cpu(de->name_len) == 1 && (de->name[0] == '.') &&
 	   (de->name[1] == '\0'))
 		return 1;
-	if (len != de->name_len)
+	if (len != le16_to_cpu(de->name_len))
 		return 0;
 	return !memcmp(name, de->name, len);
 }
@@ -121,7 +124,7 @@
 			if (!ext2_check_dir_entry ("ext2_find_entry", dir,
 						   de, bh, offset))
 				goto failure;
-			if (de->inode != 0 && ext2_match (namelen, name, de)) {
+			if (le32_to_cpu(de->inode) != 0 && ext2_match (namelen, name, de)) {
 				for (i = 0; i < NAMEI_RA_SIZE; ++i) {
 					if (bh_use[i] != bh)
 						brelse (bh_use[i]);
@@ -129,9 +132,9 @@
 				*res_dir = de;
 				return bh;
 			}
-			offset += de->rec_len;
+			offset += le16_to_cpu(de->rec_len);
 			de = (struct ext2_dir_entry *)
-				((char *) de + de->rec_len);
+				((char *) de + le16_to_cpu(de->rec_len));
 		}
 
 		brelse (bh);
@@ -188,7 +191,7 @@
 		iput (dir);
 		return -ENOENT;
 	}
-	ino = de->inode;
+	ino = le32_to_cpu(de->inode);
 	dcache_add(dir, name, len, ino);
 	brelse (bh);
 	if (!(*result = iget (dir->i_sb, ino))) {
@@ -265,8 +268,8 @@
 				ext2_debug ("creating next block\n");
 
 				de = (struct ext2_dir_entry *) bh->b_data;
-				de->inode = 0;
-				de->rec_len = sb->s_blocksize;
+				de->inode = le32_to_cpu(0);
+				de->rec_len = le16_to_cpu(sb->s_blocksize);
 				dir->i_size = offset + sb->s_blocksize;
 				dir->i_dirt = 1;
 			} else {
@@ -282,24 +285,24 @@
 			brelse (bh);
 			return NULL;
 		}
-		if (de->inode != 0 && ext2_match (namelen, name, de)) {
+		if (le32_to_cpu(de->inode) != 0 && ext2_match (namelen, name, de)) {
 				*err = -EEXIST;
 				brelse (bh);
 				return NULL;
 		}
-		if ((de->inode == 0 && de->rec_len >= rec_len) ||
-		    (de->rec_len >= EXT2_DIR_REC_LEN(de->name_len) + rec_len)) {
-			offset += de->rec_len;
-			if (de->inode) {
+		if ((le32_to_cpu(de->inode) == 0 && le16_to_cpu(de->rec_len) >= rec_len) ||
+		    (le16_to_cpu(de->rec_len) >= EXT2_DIR_REC_LEN(le16_to_cpu(de->name_len)) + rec_len)) {
+			offset += le16_to_cpu(de->rec_len);
+			if (le32_to_cpu(de->inode)) {
 				de1 = (struct ext2_dir_entry *) ((char *) de +
-					EXT2_DIR_REC_LEN(de->name_len));
-				de1->rec_len = de->rec_len -
-					EXT2_DIR_REC_LEN(de->name_len);
-				de->rec_len = EXT2_DIR_REC_LEN(de->name_len);
+					EXT2_DIR_REC_LEN(le16_to_cpu(de->name_len)));
+				de1->rec_len = cpu_to_le16(le16_to_cpu(de->rec_len) -
+					EXT2_DIR_REC_LEN(le16_to_cpu(de->name_len)));
+				de->rec_len = cpu_to_le16(EXT2_DIR_REC_LEN(le16_to_cpu(de->name_len)));
 				de = de1;
 			}
-			de->inode = 0;
-			de->name_len = namelen;
+			de->inode = cpu_to_le32(0);
+			de->name_len = cpu_to_le16(namelen);
 			memcpy (de->name, name, namelen);
 			/*
 			 * XXX shouldn't update any times until successful
@@ -320,8 +323,8 @@
 			*err = 0;
 			return bh;
 		}
-		offset += de->rec_len;
-		de = (struct ext2_dir_entry *) ((char *) de + de->rec_len);
+		offset += le16_to_cpu(de->rec_len);
+		de = (struct ext2_dir_entry *) ((char *) de + le16_to_cpu(de->rec_len));
 	}
 	brelse (bh);
 	return NULL;
@@ -346,13 +349,15 @@
 			return -EIO;
 		if (de == dir)  {
 			if (pde)
-				pde->rec_len += dir->rec_len;
-			dir->inode = 0;
+				pde->rec_len =
+					cpu_to_le16(le16_to_cpu(pde->rec_len) +
+						    le16_to_cpu(dir->rec_len));
+			dir->inode = le32_to_cpu(0);
 			return 0;
 		}
-		i += de->rec_len;
+		i += le16_to_cpu(de->rec_len);
 		pde = de;
-		de = (struct ext2_dir_entry *) ((char *) de + de->rec_len);
+		de = (struct ext2_dir_entry *) ((char *) de + le16_to_cpu(de->rec_len));
 	}
 	return -ENOENT;
 }
@@ -384,9 +389,9 @@
 		iput (dir);
 		return err;
 	}
-	de->inode = inode->i_ino;
+	de->inode = cpu_to_le32(inode->i_ino);
 	dir->i_version = ++event;
-	dcache_add(dir, de->name, de->name_len, de->inode);
+	dcache_add(dir, de->name, le16_to_cpu(de->name_len), le32_to_cpu(de->inode));
 	mark_buffer_dirty(bh, 1);
 	if (IS_SYNC(dir)) {
 		ll_rw_block (WRITE, 1, &bh);
@@ -453,9 +458,9 @@
 		iput (dir);
 		return err;
 	}
-	de->inode = inode->i_ino;
+	de->inode = cpu_to_le32(inode->i_ino);
 	dir->i_version = ++event;
-	dcache_add(dir, de->name, de->name_len, de->inode);
+	dcache_add(dir, de->name, le16_to_cpu(de->name_len), le32_to_cpu(de->inode));
 	mark_buffer_dirty(bh, 1);
 	if (IS_SYNC(dir)) {
 		ll_rw_block (WRITE, 1, &bh);
@@ -507,14 +512,14 @@
 	}
 	inode->i_blocks = inode->i_sb->s_blocksize / 512;
 	de = (struct ext2_dir_entry *) dir_block->b_data;
-	de->inode = inode->i_ino;
-	de->name_len = 1;
-	de->rec_len = EXT2_DIR_REC_LEN(de->name_len);
+	de->inode = cpu_to_le32(inode->i_ino);
+	de->name_len = cpu_to_le16(1);
+	de->rec_len = cpu_to_le16(EXT2_DIR_REC_LEN(le16_to_cpu(de->name_len)));
 	strcpy (de->name, ".");
-	de = (struct ext2_dir_entry *) ((char *) de + de->rec_len);
-	de->inode = dir->i_ino;
-	de->rec_len = inode->i_sb->s_blocksize - EXT2_DIR_REC_LEN(1);
-	de->name_len = 2;
+	de = (struct ext2_dir_entry *) ((char *) de + le16_to_cpu(de->rec_len));
+	de->inode = cpu_to_le32(dir->i_ino);
+	de->rec_len = cpu_to_le16(inode->i_sb->s_blocksize - EXT2_DIR_REC_LEN(1));
+	de->name_len = cpu_to_le16(2);
 	strcpy (de->name, "..");
 	inode->i_nlink = 2;
 	mark_buffer_dirty(dir_block, 1);
@@ -531,9 +536,9 @@
 		iput (inode);
 		return err;
 	}
-	de->inode = inode->i_ino;
+	de->inode = cpu_to_le32(inode->i_ino);
 	dir->i_version = ++event;
-	dcache_add(dir, de->name, de->name_len, de->inode);
+	dcache_add(dir, de->name, le16_to_cpu(de->name_len), le32_to_cpu(de->inode));
 	mark_buffer_dirty(bh, 1);
 	if (IS_SYNC(dir)) {
 		ll_rw_block (WRITE, 1, &bh);
@@ -567,16 +572,16 @@
 		return 1;
 	}
 	de = (struct ext2_dir_entry *) bh->b_data;
-	de1 = (struct ext2_dir_entry *) ((char *) de + de->rec_len);
-	if (de->inode != inode->i_ino || !de1->inode || 
+	de1 = (struct ext2_dir_entry *) ((char *) de + le16_to_cpu(de->rec_len));
+	if (le32_to_cpu(de->inode) != inode->i_ino || !le32_to_cpu(de1->inode) || 
 	    strcmp (".", de->name) || strcmp ("..", de1->name)) {
 	    	ext2_warning (inode->i_sb, "empty_dir",
 			      "bad directory (dir #%lu) - no `.' or `..'",
 			      inode->i_ino);
 		return 1;
 	}
-	offset = de->rec_len + de1->rec_len;
-	de = (struct ext2_dir_entry *) ((char *) de1 + de1->rec_len);
+	offset = le16_to_cpu(de->rec_len) + le16_to_cpu(de1->rec_len);
+	de = (struct ext2_dir_entry *) ((char *) de1 + le16_to_cpu(de1->rec_len));
 	while (offset < inode->i_size ) {
 		if ((void *) de >= (void *) (bh->b_data + sb->s_blocksize)) {
 			brelse (bh);
@@ -595,12 +600,12 @@
 			brelse (bh);
 			return 1;
 		}
-		if (de->inode) {
+		if (le32_to_cpu(de->inode)) {
 			brelse (bh);
 			return 0;
 		}
-		offset += de->rec_len;
-		de = (struct ext2_dir_entry *) ((char *) de + de->rec_len);
+		offset += le16_to_cpu(de->rec_len);
+		de = (struct ext2_dir_entry *) ((char *) de + le16_to_cpu(de->rec_len));
 	}
 	brelse (bh);
 	return 1;
@@ -626,7 +631,7 @@
 	if (!bh)
 		goto end_rmdir;
 	retval = -EPERM;
-	if (!(inode = iget (dir->i_sb, de->inode)))
+	if (!(inode = iget (dir->i_sb, le32_to_cpu(de->inode))))
 		goto end_rmdir;
 	if (inode->i_sb->dq_op)
 		inode->i_sb->dq_op->initialize (inode, -1);
@@ -634,7 +639,7 @@
 		retval = -EBUSY;
 		goto end_rmdir;
 	}
-	if (de->inode != inode->i_ino) {
+	if (le32_to_cpu(de->inode) != inode->i_ino) {
 		iput(inode);
 		brelse(bh);
 		current->counter = 0;
@@ -654,7 +659,7 @@
 	down(&inode->i_sem);
 	if (!empty_dir (inode))
 		retval = -ENOTEMPTY;
-	else if (de->inode != inode->i_ino)
+	else if (le32_to_cpu(de->inode) != inode->i_ino)
 		retval = -ENOENT;
 	else {
 		if (inode->i_count > 1) {
@@ -714,7 +719,7 @@
 	bh = ext2_find_entry (dir, name, len, &de);
 	if (!bh)
 		goto end_unlink;
-	if (!(inode = iget (dir->i_sb, de->inode)))
+	if (!(inode = iget (dir->i_sb, le32_to_cpu(de->inode))))
 		goto end_unlink;
 	if (inode->i_sb->dq_op)
 		inode->i_sb->dq_op->initialize (inode, -1);
@@ -723,7 +728,7 @@
 		goto end_unlink;
 	if (IS_APPEND(inode) || IS_IMMUTABLE(inode))
 		goto end_unlink;
-	if (de->inode != inode->i_ino) {
+	if (le32_to_cpu(de->inode) != inode->i_ino) {
 		iput(inode);
 		brelse(bh);
 		current->counter = 0;
@@ -829,9 +834,9 @@
 		iput (dir);
 		return err;
 	}
-	de->inode = inode->i_ino;
+	de->inode = cpu_to_le32(inode->i_ino);
 	dir->i_version = ++event;
-	dcache_add(dir, de->name, de->name_len, de->inode);
+	dcache_add(dir, de->name, le16_to_cpu(de->name_len), le32_to_cpu(de->inode));
 	mark_buffer_dirty(bh, 1);
 	if (IS_SYNC(dir)) {
 		ll_rw_block (WRITE, 1, &bh);
@@ -878,9 +883,9 @@
 		iput (oldinode);
 		return err;
 	}
-	de->inode = oldinode->i_ino;
+	de->inode = cpu_to_le32(oldinode->i_ino);
 	dir->i_version = ++event;
-	dcache_add(dir, de->name, de->name_len, de->inode);
+	dcache_add(dir, de->name, le16_to_cpu(de->name_len), le32_to_cpu(de->inode));
 	mark_buffer_dirty(bh, 1);
 	if (IS_SYNC(dir)) {
 		ll_rw_block (WRITE, 1, &bh);
@@ -921,11 +926,11 @@
 
 #define PARENT_INO(buffer) \
 	((struct ext2_dir_entry *) ((char *) buffer + \
-	((struct ext2_dir_entry *) buffer)->rec_len))->inode
+	le16_to_cpu(((struct ext2_dir_entry *) buffer)->rec_len)))->inode
 
 #define PARENT_NAME(buffer) \
 	((struct ext2_dir_entry *) ((char *) buffer + \
-	((struct ext2_dir_entry *) buffer)->rec_len))->name
+	le16_to_cpu(((struct ext2_dir_entry *) buffer)->rec_len)))->name
 
 /*
  * rename uses retrying to avoid race-conditions: at least they should be
@@ -973,7 +978,7 @@
 	retval = -ENOENT;
 	if (!old_bh)
 		goto end_rename;
-	old_inode = __iget (old_dir->i_sb, old_de->inode, 0); /* don't cross mnt-points */
+	old_inode = __iget (old_dir->i_sb, le32_to_cpu(old_de->inode), 0); /* don't cross mnt-points */
 	if (!old_inode)
 		goto end_rename;
 	if (must_be_dir && !S_ISDIR(old_inode->i_mode))
@@ -987,7 +992,7 @@
 		goto end_rename;
 	new_bh = ext2_find_entry (new_dir, new_name, new_len, &new_de);
 	if (new_bh) {
-		new_inode = __iget (new_dir->i_sb, new_de->inode, 0); /* no mntp cross */
+		new_inode = __iget (new_dir->i_sb, le32_to_cpu(new_de->inode), 0); /* no mntp cross */
 		if (!new_inode) {
 			brelse (new_bh);
 			new_bh = NULL;
@@ -1029,7 +1034,7 @@
 		dir_bh = ext2_bread (old_inode, 0, 0, &retval);
 		if (!dir_bh)
 			goto end_rename;
-		if (PARENT_INO(dir_bh->b_data) != old_dir->i_ino)
+		if (le32_to_cpu(PARENT_INO(dir_bh->b_data)) != old_dir->i_ino)
 			goto end_rename;
 		retval = -EMLINK;
 		if (!new_inode && new_dir->i_nlink >= EXT2_LINK_MAX)
@@ -1044,17 +1049,17 @@
 	/*
 	 * sanity checking before doing the rename - avoid races
 	 */
-	if (new_inode && (new_de->inode != new_inode->i_ino))
+	if (new_inode && (le32_to_cpu(new_de->inode) != new_inode->i_ino))
 		goto try_again;
-	if (new_de->inode && !new_inode)
+	if (le32_to_cpu(new_de->inode) && !new_inode)
 		goto try_again;
-	if (old_de->inode != old_inode->i_ino)
+	if (le32_to_cpu(old_de->inode) != old_inode->i_ino)
 		goto try_again;
 	/*
 	 * ok, that's it
 	 */
-	new_de->inode = old_inode->i_ino;
-	dcache_add(new_dir, new_de->name, new_de->name_len, new_de->inode);
+	new_de->inode = le32_to_cpu(old_inode->i_ino);
+	dcache_add(new_dir, new_de->name, le16_to_cpu(new_de->name_len), le32_to_cpu(new_de->inode));
 	retval = ext2_delete_entry (old_de, old_bh);
 	if (retval == -ENOENT)
 		goto try_again;
@@ -1069,7 +1074,7 @@
 	old_dir->i_ctime = old_dir->i_mtime = CURRENT_TIME;
 	old_dir->i_dirt = 1;
 	if (dir_bh) {
-		PARENT_INO(dir_bh->b_data) = new_dir->i_ino;
+		PARENT_INO(dir_bh->b_data) = le32_to_cpu(new_dir->i_ino);
 		dcache_add(old_inode, "..", 2, new_dir->i_ino);
 		mark_buffer_dirty(dir_bh, 1);
 		old_dir->i_nlink--;
diff -u --recursive --new-file v2.1.9/linux/fs/ext2/super.c linux/fs/ext2/super.c
--- v2.1.9/linux/fs/ext2/super.c	Tue Oct 29 19:58:42 1996
+++ linux/fs/ext2/super.c	Thu Nov 14 10:27:38 1996
@@ -11,6 +11,9 @@
  *  linux/fs/minix/inode.c
  *
  *  Copyright (C) 1991, 1992  Linus Torvalds
+ *
+ *  Big-endian to little-endian byte-swapping/bitmaps by
+ *        David S. Miller (davem@caip.rutgers.edu), 1995
  */
 
 #include <linux/module.h>
@@ -39,7 +42,8 @@
 
 	if (!(sb->s_flags & MS_RDONLY)) {
 		sb->u.ext2_sb.s_mount_state |= EXT2_ERROR_FS;
-		sb->u.ext2_sb.s_es->s_state |= EXT2_ERROR_FS;
+		sb->u.ext2_sb.s_es->s_state =
+			cpu_to_le16(le16_to_cpu(sb->u.ext2_sb.s_es->s_state) | EXT2_ERROR_FS);
 		mark_buffer_dirty(sb->u.ext2_sb.s_sbh, 1);
 		sb->s_dirt = 1;
 	}
@@ -47,14 +51,14 @@
 	vsprintf (error_buf, fmt, args);
 	va_end (args);
 	if (test_opt (sb, ERRORS_PANIC) ||
-	    (sb->u.ext2_sb.s_es->s_errors == EXT2_ERRORS_PANIC &&
+	    (le16_to_cpu(sb->u.ext2_sb.s_es->s_errors) == EXT2_ERRORS_PANIC &&
 	     !test_opt (sb, ERRORS_CONT) && !test_opt (sb, ERRORS_RO)))
 		panic ("EXT2-fs panic (device %s): %s: %s\n",
 		       kdevname(sb->s_dev), function, error_buf);
 	printk (KERN_CRIT "EXT2-fs error (device %s): %s: %s\n",
 		kdevname(sb->s_dev), function, error_buf);
 	if (test_opt (sb, ERRORS_RO) ||
-	    (sb->u.ext2_sb.s_es->s_errors == EXT2_ERRORS_RO &&
+	    (le16_to_cpu(sb->u.ext2_sb.s_es->s_errors) == EXT2_ERRORS_RO &&
 	     !test_opt (sb, ERRORS_CONT) && !test_opt (sb, ERRORS_PANIC))) {
 		printk ("Remounting filesystem read-only\n");
 		sb->s_flags |= MS_RDONLY;
@@ -68,7 +72,8 @@
 
 	if (!(sb->s_flags & MS_RDONLY)) {
 		sb->u.ext2_sb.s_mount_state |= EXT2_ERROR_FS;
-		sb->u.ext2_sb.s_es->s_state |= EXT2_ERROR_FS;
+		sb->u.ext2_sb.s_es->s_state =
+			cpu_to_le16(le16_to_cpu(sb->u.ext2_sb.s_es->s_state) | EXT2_ERROR_FS);
 		mark_buffer_dirty(sb->u.ext2_sb.s_sbh, 1);
 		sb->s_dirt = 1;
 	}
@@ -102,7 +107,7 @@
 
 	lock_super (sb);
 	if (!(sb->s_flags & MS_RDONLY)) {
-		sb->u.ext2_sb.s_es->s_state = sb->u.ext2_sb.s_mount_state;
+		sb->u.ext2_sb.s_es->s_state = le16_to_cpu(sb->u.ext2_sb.s_mount_state);
 		mark_buffer_dirty(sb->u.ext2_sb.s_sbh, 1);
 	}
 	sb->s_dev = 0;
@@ -270,7 +275,7 @@
 static void ext2_setup_super (struct super_block * sb,
 			      struct ext2_super_block * es)
 {
-	if (es->s_rev_level > EXT2_MAX_SUPP_REV) {
+	if (le32_to_cpu(es->s_rev_level) > EXT2_MAX_SUPP_REV) {
 			printk ("EXT2-fs warning: revision level too high, "
 				"forcing read/only mode\n");
 			sb->s_flags |= MS_RDONLY;
@@ -282,19 +287,20 @@
 		else if ((sb->u.ext2_sb.s_mount_state & EXT2_ERROR_FS))
 			printk ("EXT2-fs warning: mounting fs with errors, "
 				"running e2fsck is recommended\n");
-		else if (es->s_max_mnt_count >= 0 &&
-		         es->s_mnt_count >= (unsigned short) es->s_max_mnt_count)
+		else if ((__s16) le16_to_cpu(es->s_max_mnt_count) >= 0 &&
+		         le16_to_cpu(es->s_mnt_count) >=
+			 (unsigned short) (__s16) le16_to_cpu(es->s_max_mnt_count))
 			printk ("EXT2-fs warning: maximal mount count reached, "
 				"running e2fsck is recommended\n");
-		else if (es->s_checkinterval &&
-			(es->s_lastcheck + es->s_checkinterval <= CURRENT_TIME))
+		else if (le32_to_cpu(es->s_checkinterval) &&
+			(le32_to_cpu(es->s_lastcheck) + le32_to_cpu(es->s_checkinterval) <= CURRENT_TIME))
 			printk ("EXT2-fs warning: checktime reached, "
 				"running e2fsck is recommended\n");
-		es->s_state &= ~EXT2_VALID_FS;
-		if (!es->s_max_mnt_count)
-			es->s_max_mnt_count = EXT2_DFL_MAX_MNT_COUNT;
-		es->s_mnt_count++;
-		es->s_mtime = CURRENT_TIME;
+		es->s_state = cpu_to_le16(le16_to_cpu(es->s_state) & ~EXT2_VALID_FS);
+		if (!(__s16) le16_to_cpu(es->s_max_mnt_count))
+			es->s_max_mnt_count = (__s16) cpu_to_le16(EXT2_DFL_MAX_MNT_COUNT);
+		es->s_mnt_count=cpu_to_le16(le16_to_cpu(es->s_mnt_count) + 1);
+		es->s_mtime = cpu_to_le32(CURRENT_TIME);
 		mark_buffer_dirty(sb->u.ext2_sb.s_sbh, 1);
 		sb->s_dirt = 1;
 		if (test_opt (sb, DEBUG))
@@ -317,7 +323,7 @@
 {
 	int i;
 	int desc_block = 0;
-	unsigned long block = sb->u.ext2_sb.s_es->s_first_data_block;
+	unsigned long block = le32_to_cpu(sb->u.ext2_sb.s_es->s_first_data_block);
 	struct ext2_group_desc * gdp = NULL;
 
 	ext2_debug ("Checking group descriptors");
@@ -326,32 +332,32 @@
 	{
 		if ((i % EXT2_DESC_PER_BLOCK(sb)) == 0)
 			gdp = (struct ext2_group_desc *) sb->u.ext2_sb.s_group_desc[desc_block++]->b_data;
-		if (gdp->bg_block_bitmap < block ||
-		    gdp->bg_block_bitmap >= block + EXT2_BLOCKS_PER_GROUP(sb))
+		if (le32_to_cpu(gdp->bg_block_bitmap) < block ||
+		    le32_to_cpu(gdp->bg_block_bitmap) >= block + EXT2_BLOCKS_PER_GROUP(sb))
 		{
 			ext2_error (sb, "ext2_check_descriptors",
 				    "Block bitmap for group %d"
 				    " not in group (block %lu)!",
-				    i, (unsigned long) gdp->bg_block_bitmap);
+				    i, (unsigned long) le32_to_cpu(gdp->bg_block_bitmap));
 			return 0;
 		}
-		if (gdp->bg_inode_bitmap < block ||
-		    gdp->bg_inode_bitmap >= block + EXT2_BLOCKS_PER_GROUP(sb))
+		if (le32_to_cpu(gdp->bg_inode_bitmap) < block ||
+		    le32_to_cpu(gdp->bg_inode_bitmap) >= block + EXT2_BLOCKS_PER_GROUP(sb))
 		{
 			ext2_error (sb, "ext2_check_descriptors",
 				    "Inode bitmap for group %d"
 				    " not in group (block %lu)!",
-				    i, (unsigned long) gdp->bg_inode_bitmap);
+				    i, (unsigned long) le32_to_cpu(gdp->bg_inode_bitmap));
 			return 0;
 		}
-		if (gdp->bg_inode_table < block ||
-		    gdp->bg_inode_table + sb->u.ext2_sb.s_itb_per_group >=
+		if (le32_to_cpu(gdp->bg_inode_table) < block ||
+		    le32_to_cpu(gdp->bg_inode_table) + sb->u.ext2_sb.s_itb_per_group >=
 		    block + EXT2_BLOCKS_PER_GROUP(sb))
 		{
 			ext2_error (sb, "ext2_check_descriptors",
 				    "Inode table for group %d"
 				    " not in group (block %lu)!",
-				    i, (unsigned long) gdp->bg_inode_table);
+				    i, (unsigned long) le32_to_cpu(gdp->bg_inode_table));
 			return 0;
 		}
 		block += EXT2_BLOCKS_PER_GROUP(sb);
@@ -399,7 +405,7 @@
 	 */
 	es = (struct ext2_super_block *) bh->b_data;
 	sb->u.ext2_sb.s_es = es;
-	sb->s_magic = es->s_magic;
+	sb->s_magic = le16_to_cpu(es->s_magic);
 	if (sb->s_magic != EXT2_SUPER_MAGIC) {
 		if (!silent)
 			printk ("VFS: Can't find an ext2 filesystem on dev "
@@ -412,22 +418,22 @@
 		MOD_DEC_USE_COUNT;
 		return NULL;
 	}
-	if (es->s_rev_level > EXT2_GOOD_OLD_REV) {
-		if (es->s_feature_incompat & ~EXT2_FEATURE_INCOMPAT_SUPP) {
+	if (le32_to_cpu(es->s_rev_level) > EXT2_GOOD_OLD_REV) {
+		if (le32_to_cpu(es->s_feature_incompat) & ~EXT2_FEATURE_INCOMPAT_SUPP) {
 			printk("EXT2-fs: %s: couldn't mount because of "
 			       "unsupported optional features.\n", 
 			       kdevname(dev));
 			goto failed_mount;
 		}
 		if (!(sb->s_flags & MS_RDONLY) &&
-		    (es->s_feature_ro_compat & ~EXT2_FEATURE_RO_COMPAT_SUPP)) {
+		    (le32_to_cpu(es->s_feature_ro_compat) & ~EXT2_FEATURE_RO_COMPAT_SUPP)) {
 			printk("EXT2-fs: %s: couldn't mount RDWR because of "
 			       "unsupported optional features.\n", 
 			       kdevname(dev));
 			goto failed_mount;
 		}
 	}
-	sb->s_blocksize_bits = sb->u.ext2_sb.s_es->s_log_block_size + 10;
+	sb->s_blocksize_bits = le32_to_cpu(sb->u.ext2_sb.s_es->s_log_block_size) + 10;
 	sb->s_blocksize = 1 << sb->s_blocksize_bits;
 	if (sb->s_blocksize != BLOCK_SIZE && 
 	    (sb->s_blocksize == 1024 || sb->s_blocksize == 2048 ||  
@@ -446,17 +452,17 @@
 		}
 		es = (struct ext2_super_block *) (((char *)bh->b_data) + offset);
 		sb->u.ext2_sb.s_es = es;
-		if (es->s_magic != EXT2_SUPER_MAGIC) {
+		if (es->s_magic != le16_to_cpu(EXT2_SUPER_MAGIC)) {
 			printk ("EXT2-fs: Magic mismatch, very weird !\n");
 			goto failed_mount;
 		}
 	}
-	if (es->s_rev_level == EXT2_GOOD_OLD_REV) {
+	if (le32_to_cpu(es->s_rev_level) == EXT2_GOOD_OLD_REV) {
 		sb->u.ext2_sb.s_inode_size = EXT2_GOOD_OLD_INODE_SIZE;
 		sb->u.ext2_sb.s_first_ino = EXT2_GOOD_OLD_FIRST_INO;
 	} else {
-		sb->u.ext2_sb.s_inode_size = es->s_inode_size;
-		sb->u.ext2_sb.s_first_ino = es->s_first_ino;
+		sb->u.ext2_sb.s_inode_size = le16_to_cpu(es->s_inode_size);
+		sb->u.ext2_sb.s_first_ino = le32_to_cpu(es->s_first_ino);
 		if (sb->u.ext2_sb.s_inode_size != EXT2_GOOD_OLD_INODE_SIZE) {
 			printk ("EXT2-fs: unsupported inode size: %d\n",
 				sb->u.ext2_sb.s_inode_size);
@@ -464,15 +470,15 @@
 		}
 	}
 	sb->u.ext2_sb.s_frag_size = EXT2_MIN_FRAG_SIZE <<
-				   es->s_log_frag_size;
+				   (__s32) le32_to_cpu(es->s_log_frag_size);
 	if (sb->u.ext2_sb.s_frag_size)
 		sb->u.ext2_sb.s_frags_per_block = sb->s_blocksize /
 						  sb->u.ext2_sb.s_frag_size;
 	else
 		sb->s_magic = 0;
-	sb->u.ext2_sb.s_blocks_per_group = es->s_blocks_per_group;
-	sb->u.ext2_sb.s_frags_per_group = es->s_frags_per_group;
-	sb->u.ext2_sb.s_inodes_per_group = es->s_inodes_per_group;
+	sb->u.ext2_sb.s_blocks_per_group = le32_to_cpu(es->s_blocks_per_group);
+	sb->u.ext2_sb.s_frags_per_group = le32_to_cpu(es->s_frags_per_group);
+	sb->u.ext2_sb.s_inodes_per_group = le32_to_cpu(es->s_inodes_per_group);
 	sb->u.ext2_sb.s_inodes_per_block = sb->s_blocksize /
 					   EXT2_INODE_SIZE(sb);
 	sb->u.ext2_sb.s_itb_per_group = sb->u.ext2_sb.s_inodes_per_group /
@@ -483,12 +489,12 @@
 	if (resuid != EXT2_DEF_RESUID)
 		sb->u.ext2_sb.s_resuid = resuid;
 	else
-		sb->u.ext2_sb.s_resuid = es->s_def_resuid;
+		sb->u.ext2_sb.s_resuid = le16_to_cpu(es->s_def_resuid);
 	if (resgid != EXT2_DEF_RESGID)
 		sb->u.ext2_sb.s_resgid = resgid;
 	else
-		sb->u.ext2_sb.s_resgid = es->s_def_resgid;
-	sb->u.ext2_sb.s_mount_state = es->s_state;
+		sb->u.ext2_sb.s_resgid = le16_to_cpu(es->s_def_resgid);
+	sb->u.ext2_sb.s_mount_state = le16_to_cpu(es->s_state);
 	sb->u.ext2_sb.s_rename_lock = 0;
 	sb->u.ext2_sb.s_rename_wait = NULL;
 	sb->u.ext2_sb.s_addr_per_block_bits =
@@ -531,8 +537,8 @@
 		goto failed_mount;
 	}
 
-	sb->u.ext2_sb.s_groups_count = (es->s_blocks_count -
-				        es->s_first_data_block +
+	sb->u.ext2_sb.s_groups_count = (le32_to_cpu(es->s_blocks_count) -
+				        le32_to_cpu(es->s_first_data_block) +
 				       EXT2_BLOCKS_PER_GROUP(sb) - 1) /
 				       EXT2_BLOCKS_PER_GROUP(sb);
 	db_count = (sb->u.ext2_sb.s_groups_count + EXT2_DESC_PER_BLOCK(sb) - 1) /
@@ -596,7 +602,7 @@
 static void ext2_commit_super (struct super_block * sb,
 			       struct ext2_super_block * es)
 {
-	es->s_wtime = CURRENT_TIME;
+	es->s_wtime = cpu_to_le32(CURRENT_TIME);
 	mark_buffer_dirty(sb->u.ext2_sb.s_sbh, 1);
 	sb->s_dirt = 0;
 }
@@ -621,9 +627,9 @@
 
 		ext2_debug ("setting valid to 0\n");
 
-		if (es->s_state & EXT2_VALID_FS) {
-			es->s_state &= ~EXT2_VALID_FS;
-			es->s_mtime = CURRENT_TIME;
+		if (le16_to_cpu(es->s_state) & EXT2_VALID_FS) {
+			es->s_state = cpu_to_le16(le16_to_cpu(es->s_state) & ~EXT2_VALID_FS);
+			es->s_mtime = cpu_to_le32(CURRENT_TIME);
 		}
 		ext2_commit_super (sb, es);
 	}
@@ -653,15 +659,15 @@
 	if ((*flags & MS_RDONLY) == (sb->s_flags & MS_RDONLY))
 		return 0;
 	if (*flags & MS_RDONLY) {
-		if (es->s_state & EXT2_VALID_FS ||
+		if (le16_to_cpu(es->s_state) & EXT2_VALID_FS ||
 		    !(sb->u.ext2_sb.s_mount_state & EXT2_VALID_FS))
 			return 0;
 		/*
 		 * OK, we are remounting a valid rw partition rdonly, so set
 		 * the rdonly flag and then mark the partition as valid again.
 		 */
-		es->s_state = sb->u.ext2_sb.s_mount_state;
-		es->s_mtime = CURRENT_TIME;
+		es->s_state = cpu_to_le16(sb->u.ext2_sb.s_mount_state);
+		es->s_mtime = cpu_to_le32(CURRENT_TIME);
 		mark_buffer_dirty(sb->u.ext2_sb.s_sbh, 1);
 		sb->s_dirt = 1;
 		ext2_commit_super (sb, es);
@@ -672,7 +678,7 @@
 		 * store the current valid flag.  (It may have been changed 
 		 * by e2fsck since we originally mounted the partition.)
 		 */
-		sb->u.ext2_sb.s_mount_state = es->s_state;
+		sb->u.ext2_sb.s_mount_state = le16_to_cpu(es->s_state);
 		sb->s_flags &= ~MS_RDONLY;
 		ext2_setup_super (sb, es);
 	}
@@ -722,18 +728,18 @@
 				     1 /* block bitmap */ +
 				     1 /* inode bitmap */ +
 				     sb->u.ext2_sb.s_itb_per_group /* inode table */;
-		overhead = sb->u.ext2_sb.s_es->s_first_data_block +
+		overhead = le32_to_cpu(sb->u.ext2_sb.s_es->s_first_data_block) +
 			   sb->u.ext2_sb.s_groups_count * overhead_per_group;
 	}
 
 	tmp.f_type = EXT2_SUPER_MAGIC;
 	tmp.f_bsize = sb->s_blocksize;
-	tmp.f_blocks = sb->u.ext2_sb.s_es->s_blocks_count - overhead;
+	tmp.f_blocks = le32_to_cpu(sb->u.ext2_sb.s_es->s_blocks_count) - overhead;
 	tmp.f_bfree = ext2_count_free_blocks (sb);
-	tmp.f_bavail = tmp.f_bfree - sb->u.ext2_sb.s_es->s_r_blocks_count;
-	if (tmp.f_bfree < sb->u.ext2_sb.s_es->s_r_blocks_count)
+	tmp.f_bavail = tmp.f_bfree - le32_to_cpu(sb->u.ext2_sb.s_es->s_r_blocks_count);
+	if (tmp.f_bfree < le32_to_cpu(sb->u.ext2_sb.s_es->s_r_blocks_count))
 		tmp.f_bavail = 0;
-	tmp.f_files = sb->u.ext2_sb.s_es->s_inodes_count;
+	tmp.f_files = le32_to_cpu(sb->u.ext2_sb.s_es->s_inodes_count);
 	tmp.f_ffree = ext2_count_free_inodes (sb);
 	tmp.f_namelen = EXT2_NAME_LEN;
 	copy_to_user(buf, &tmp, bufsiz);
diff -u --recursive --new-file v2.1.9/linux/fs/ext2/truncate.c linux/fs/ext2/truncate.c
--- v2.1.9/linux/fs/ext2/truncate.c	Mon Dec 11 06:56:35 1995
+++ linux/fs/ext2/truncate.c	Thu Nov 14 10:27:38 1996
@@ -11,6 +11,9 @@
  *  linux/fs/minix/truncate.c
  *
  *  Copyright (C) 1991, 1992  Linus Torvalds
+ *
+ *  Big-endian to little-endian byte-swapping/bitmaps by
+ *        David S. Miller (davem@caip.rutgers.edu), 1995
  */
 
 /*
@@ -140,7 +143,7 @@
 		if (i < indirect_block)
 			goto repeat;
 		ind = i + (u32 *) ind_bh->b_data;
-		tmp = *ind;
+		tmp = le32_to_cpu(*ind);
 		if (!tmp)
 			continue;
 		bh = get_hash_table (inode->i_dev, tmp,
@@ -149,12 +152,12 @@
 			brelse (bh);
 			goto repeat;
 		}
-		if ((bh && bh->b_count != 1) || tmp != *ind) {
+		if ((bh && bh->b_count != 1) || tmp != le32_to_cpu(*ind)) {
 			retry = 1;
 			brelse (bh);
 			continue;
 		}
-		*ind = 0;
+		*ind = cpu_to_le32(0);
 		mark_buffer_dirty(ind_bh, 1);
 		bforget(bh);
 		if (free_count == 0) {
@@ -175,7 +178,7 @@
 		ext2_free_blocks (inode, block_to_free, free_count);
 	ind = (u32 *) ind_bh->b_data;
 	for (i = 0; i < addr_per_block; i++)
-		if (*(ind++))
+		if (le32_to_cpu(*(ind++)))
 			break;
 	if (i >= addr_per_block)
 		if (ind_bh->b_count != 1)
@@ -195,6 +198,93 @@
 	return retry;
 }
 
+static int trunc_indirect_swab32 (struct inode * inode, int offset, u32 * p)
+{
+	int i, tmp;
+	struct buffer_head * bh;
+	struct buffer_head * ind_bh;
+	u32 * ind;
+	unsigned long block_to_free = 0;
+	unsigned long free_count = 0;
+	int retry = 0;
+	int addr_per_block = EXT2_ADDR_PER_BLOCK(inode->i_sb);
+	int blocks = inode->i_sb->s_blocksize / 512;
+	int indirect_block = INDIRECT_BLOCK;
+
+	tmp = le32_to_cpu(*p);
+	if (!tmp)
+		return 0;
+	ind_bh = bread (inode->i_dev, tmp, inode->i_sb->s_blocksize);
+	if (tmp != le32_to_cpu(*p)) {
+		brelse (ind_bh);
+		return 1;
+	}
+	if (!ind_bh) {
+		*p = cpu_to_le32(0);
+		return 0;
+	}
+repeat:
+	for (i = indirect_block ; i < addr_per_block ; i++) {
+		if (i < 0)
+			i = 0;
+		if (i < indirect_block)
+			goto repeat;
+		ind = i + (u32 *) ind_bh->b_data;
+		tmp = le32_to_cpu(*ind);
+		if (!tmp)
+			continue;
+		bh = get_hash_table (inode->i_dev, tmp,
+				     inode->i_sb->s_blocksize);
+		if (i < indirect_block) {
+			brelse (bh);
+			goto repeat;
+		}
+		if ((bh && bh->b_count != 1) || tmp != le32_to_cpu(*ind)) {
+			retry = 1;
+			brelse (bh);
+			continue;
+		}
+		*ind = cpu_to_le32(0);
+		mark_buffer_dirty(ind_bh, 1);
+		bforget(bh);
+		if (free_count == 0) {
+			block_to_free = tmp;
+			free_count++;
+		} else if (free_count > 0 && block_to_free == tmp - free_count)
+			free_count++;
+		else {
+			ext2_free_blocks (inode, block_to_free, free_count);
+			block_to_free = tmp;
+			free_count = 1;
+		}
+/*		ext2_free_blocks (inode, tmp, 1); */
+		inode->i_blocks -= blocks;
+		inode->i_dirt = 1;
+	}
+	if (free_count > 0)
+		ext2_free_blocks (inode, block_to_free, free_count);
+	ind = (u32 *) ind_bh->b_data;
+	for (i = 0; i < addr_per_block; i++)
+		if (le32_to_cpu(*(ind++)))
+			break;
+	if (i >= addr_per_block)
+		if (ind_bh->b_count != 1)
+			retry = 1;
+		else {
+			tmp = le32_to_cpu(*p);
+			*p = cpu_to_le32(0);
+			inode->i_blocks -= blocks;
+			inode->i_dirt = 1;
+			ext2_free_blocks (inode, tmp, 1);
+		}
+	if (IS_SYNC(inode) && buffer_dirty(ind_bh)) {
+		ll_rw_block (WRITE, 1, &ind_bh);
+		wait_on_buffer (ind_bh);
+	}
+	brelse (ind_bh);
+	return retry;
+}
+
 static int trunc_dindirect (struct inode * inode, int offset,
 			    u32 * p)
 {
@@ -226,16 +316,16 @@
 		if (i < dindirect_block)
 			goto repeat;
 		dind = i + (u32 *) dind_bh->b_data;
-		tmp = *dind;
+		tmp = le32_to_cpu(*dind);
 		if (!tmp)
 			continue;
-		retry |= trunc_indirect (inode, offset + (i * addr_per_block),
-					  dind);
+		retry |= trunc_indirect_swab32 (inode, offset + (i * addr_per_block),
+						dind);
 		mark_buffer_dirty(dind_bh, 1);
 	}
 	dind = (u32 *) dind_bh->b_data;
 	for (i = 0; i < addr_per_block; i++)
-		if (*(dind++))
+		if (le32_to_cpu(*(dind++)))
 			break;
 	if (i >= addr_per_block)
 		if (dind_bh->b_count != 1)
@@ -255,6 +345,65 @@
 	return retry;
 }
 
+static int trunc_dindirect_swab32 (struct inode * inode, int offset,
+				   u32 * p)
+{
+	int i, tmp;
+	struct buffer_head * dind_bh;
+	u32 * dind;
+	int retry = 0;
+	int addr_per_block = EXT2_ADDR_PER_BLOCK(inode->i_sb);
+	int blocks = inode->i_sb->s_blocksize / 512;
+	int dindirect_block = DINDIRECT_BLOCK;
+
+	tmp = le32_to_cpu(*p);
+	if (!tmp)
+		return 0;
+	dind_bh = bread (inode->i_dev, tmp, inode->i_sb->s_blocksize);
+	if (tmp != le32_to_cpu(*p)) {
+		brelse (dind_bh);
+		return 1;
+	}
+	if (!dind_bh) {
+		*p = cpu_to_le32(0);
+		return 0;
+	}
+repeat:
+	for (i = dindirect_block ; i < addr_per_block ; i++) {
+		if (i < 0)
+			i = 0;
+		if (i < dindirect_block)
+			goto repeat;
+		dind = i + (u32 *) dind_bh->b_data;
+		tmp = le32_to_cpu(*dind);
+		if (!tmp)
+			continue;
+		retry |= trunc_indirect_swab32 (inode, offset + (i * addr_per_block),
+						dind);
+		mark_buffer_dirty(dind_bh, 1);
+	}
+	dind = (u32 *) dind_bh->b_data;
+	for (i = 0; i < addr_per_block; i++)
+		if (le32_to_cpu(*(dind++)))
+			break;
+	if (i >= addr_per_block)
+		if (dind_bh->b_count != 1)
+			retry = 1;
+		else {
+			tmp = le32_to_cpu(*p);
+			*p = cpu_to_le32(0);
+			inode->i_blocks -= blocks;
+			inode->i_dirt = 1;
+			ext2_free_blocks (inode, tmp, 1);
+		}
+	if (IS_SYNC(inode) && buffer_dirty(dind_bh)) {
+		ll_rw_block (WRITE, 1, &dind_bh);
+		wait_on_buffer (dind_bh);
+	}
+	brelse (dind_bh);
+	return retry;
+}
+
 static int trunc_tindirect (struct inode * inode)
 {
 	int i, tmp;
@@ -287,14 +436,14 @@
 		if (i < tindirect_block)
 			goto repeat;
 		tind = i + (u32 *) tind_bh->b_data;
-		retry |= trunc_dindirect(inode, EXT2_NDIR_BLOCKS +
-			addr_per_block + (i + 1) * addr_per_block * addr_per_block,
-			tind);
+		retry |= trunc_dindirect_swab32(inode, EXT2_NDIR_BLOCKS +
+			 addr_per_block + (i + 1) * addr_per_block * addr_per_block,
+			 tind);
 		mark_buffer_dirty(tind_bh, 1);
 	}
 	tind = (u32 *) tind_bh->b_data;
 	for (i = 0; i < addr_per_block; i++)
-		if (*(tind++))
+		if (le32_to_cpu(*(tind++)))
 			break;
 	if (i >= addr_per_block)
 		if (tind_bh->b_count != 1)
diff -u --recursive --new-file v2.1.9/linux/include/asm-alpha/bitops.h linux/include/asm-alpha/bitops.h
--- v2.1.9/linux/include/asm-alpha/bitops.h	Wed May 29 18:47:38 1996
+++ linux/include/asm-alpha/bitops.h	Thu Nov 14 10:28:59 1996
@@ -160,4 +160,14 @@
 #define find_first_zero_bit(addr, size) \
 	find_next_zero_bit((addr), (size), 0)
 
+#ifdef __KERNEL__
+
+#define ext2_set_bit                 set_bit
+#define ext2_clear_bit               clear_bit
+#define ext2_test_bit                test_bit
+#define ext2_find_first_zero_bit     find_first_zero_bit
+#define ext2_find_next_zero_bit      find_next_zero_bit
+
+#endif /* __KERNEL__ */
+
 #endif /* _ALPHA_BITOPS_H */
diff -u --recursive --new-file v2.1.9/linux/include/asm-alpha/byteorder.h linux/include/asm-alpha/byteorder.h
--- v2.1.9/linux/include/asm-alpha/byteorder.h	Mon Jul  1 20:06:05 1996
+++ linux/include/asm-alpha/byteorder.h	Thu Nov 14 15:36:13 1996
@@ -7,12 +7,30 @@
 #undef htons
 
 #ifndef __LITTLE_ENDIAN
-#define __LITTLE_ENDIAN
+#define __LITTLE_ENDIAN 1234
 #endif
 
 #ifndef __LITTLE_ENDIAN_BITFIELD
 #define __LITTLE_ENDIAN_BITFIELD
 #endif
+
+#ifdef __KERNEL__
+
+/*
+ * In-kernel byte order macros to handle stuff like
+ * byte-order-dependent filesystems etc.
+ */
+#define cpu_to_le32(x) (x)
+#define le32_to_cpu(x) (x)
+#define cpu_to_le16(x) (x)
+#define le16_to_cpu(x) (x)
+
+#define cpu_to_be32(x) htonl((x))
+#define be32_to_cpu(x) ntohl((x))
+#define cpu_to_be16(x) htons((x))
+#define be16_to_cpu(x) ntohs((x))
+
+#endif /* __KERNEL__ */
 
 extern unsigned long int	ntohl(unsigned long int);
 extern unsigned short int	ntohs(unsigned short int);
diff -u --recursive --new-file v2.1.9/linux/include/asm-alpha/uaccess.h linux/include/asm-alpha/uaccess.h
--- v2.1.9/linux/include/asm-alpha/uaccess.h	Fri Nov  1 17:13:19 1996
+++ linux/include/asm-alpha/uaccess.h	Fri Nov 15 15:43:32 1996
@@ -387,6 +387,16 @@
 	__sfu_ret;							      \
 })
 
+/* Returns: 0 if bad, string length+1 (memory size) of string if ok */
+extern long __strlen_user(const char *);
+
+extern inline long strlen_user(const char *str)
+{
+	long len = __strlen_user(str);
+	if (!access_ok(VERIFY_READ, str, len))
+		len = 0;
+	return len;
+}
 
 /*
  * About the exception table:
diff -u --recursive --new-file v2.1.9/linux/include/asm-i386/bitops.h linux/include/asm-i386/bitops.h
--- v2.1.9/linux/include/asm-i386/bitops.h	Thu Apr 11 13:22:13 1996
+++ linux/include/asm-i386/bitops.h	Thu Nov 14 10:28:29 1996
@@ -134,4 +134,14 @@
 	return word;
 }
 
+#ifdef __KERNEL__
+
+#define ext2_set_bit                 set_bit
+#define ext2_clear_bit               clear_bit
+#define ext2_test_bit                test_bit
+#define ext2_find_first_zero_bit     find_first_zero_bit
+#define ext2_find_next_zero_bit      find_next_zero_bit
+
+#endif /* __KERNEL__ */
+
 #endif /* _I386_BITOPS_H */
diff -u --recursive --new-file v2.1.9/linux/include/asm-i386/byteorder.h linux/include/asm-i386/byteorder.h
--- v2.1.9/linux/include/asm-i386/byteorder.h	Mon Sep 30 11:19:00 1996
+++ linux/include/asm-i386/byteorder.h	Fri Nov 15 15:55:00 1996
@@ -17,6 +17,21 @@
 /* For avoiding bswap on i386 */
 #ifdef __KERNEL__
 #include <linux/config.h>
+
+/*
+ * In-kernel byte order macros to handle stuff like
+ * byte-order-dependent filesystems etc.
+ */
+#define cpu_to_le32(x) (x)
+#define le32_to_cpu(x) (x)
+#define cpu_to_le16(x) (x)
+#define le16_to_cpu(x) (x)
+
+#define cpu_to_be32(x) htonl((x))
+#define be32_to_cpu(x) ntohl((x))
+#define cpu_to_be16(x) htons((x))
+#define be16_to_cpu(x) ntohs((x))
+
 #endif
 
 extern unsigned long int	ntohl(unsigned long int);
diff -u --recursive --new-file v2.1.9/linux/include/asm-i386/uaccess.h linux/include/asm-i386/uaccess.h
--- v2.1.9/linux/include/asm-i386/uaccess.h	Fri Nov  1 17:13:19 1996
+++ linux/include/asm-i386/uaccess.h	Fri Nov 15 15:55:13 1996
@@ -407,5 +407,33 @@
 	return res;
 }
 
+/*
+ * Return the size of a string (including the ending 0)
+ *
+ * Return 0 for error
+ */
+extern inline long strlen_user(const char * s)
+{
+	long res;
+	__asm__ __volatile__(
+		"\n"
+		"0:\trepne ; scasb\n\t"
+		"notl %0\n"
+		"1:\n"
+		".section .fixup,\"ax\"\n"
+		"2:\txorl %0,%0\n\t"
+		"jmp 1b\n"
+		".section __ex_table,\"a\"\n\t"
+		".align 4\n\t"
+		".long 0b,2b\n"
+		".text"
+		:"=c" (res)
+		:"D" (s),"a" (0),"0" (0xffffffff)
+		:"di");
+	if (!access_ok(VERIFY_READ, s, res))
+		res = 0;
+	return res;
+}
+
 
 #endif /* __i386_UACCESS_H */
diff -u --recursive --new-file v2.1.9/linux/include/linux/fs.h linux/include/linux/fs.h
--- v2.1.9/linux/include/linux/fs.h	Tue Oct 29 19:58:47 1996
+++ linux/include/linux/fs.h	Fri Nov 15 15:55:00 1996
@@ -122,6 +122,7 @@
 #ifdef __KERNEL__
 
 #include <asm/semaphore.h>
+#include <asm/byteorder.h>
 #include <asm/bitops.h>
 
 extern void buffer_init(void);
@@ -665,6 +666,7 @@
 
 extern void put_super(kdev_t dev);
 unsigned long generate_cluster(kdev_t dev, int b[], int size);
+unsigned long generate_cluster_swab32(kdev_t dev, int b[], int size);
 extern kdev_t ROOT_DEV;
 
 extern void show_buffers(void);
diff -u --recursive --new-file v2.1.9/linux/include/linux/in.h linux/include/linux/in.h
--- v2.1.9/linux/include/linux/in.h	Tue Nov 12 15:56:14 1996
+++ linux/include/linux/in.h	Fri Nov 15 15:55:00 1996
@@ -118,6 +118,7 @@
 #define INADDR_ALLHOSTS_GROUP 	0xe0000001      /* 224.0.0.1   */
 #define INADDR_MAX_LOCAL_GROUP  0xe00000ff      /* 224.0.0.255 */
 
+
 /* <asm/byteorder.h> contains the htonl type stuff.. */
 #include <asm/byteorder.h> 
 
diff -u --recursive --new-file v2.1.9/linux/include/linux/skbuff.h linux/include/linux/skbuff.h
--- v2.1.9/linux/include/linux/skbuff.h	Sun Nov 10 20:12:15 1996
+++ linux/include/linux/skbuff.h	Fri Nov 15 15:55:11 1996
@@ -465,8 +465,8 @@
 
 extern struct sk_buff *		skb_recv_datagram(struct sock *sk,unsigned flags,int noblock, int *err);
 extern int			datagram_select(struct sock *sk, int sel_type, select_table *wait);
-extern void			skb_copy_datagram(struct sk_buff *from, int offset, char *to,int size);
-extern void			skb_copy_datagram_iovec(struct sk_buff *from, int offset, struct iovec *to,int size);
+extern int			skb_copy_datagram(struct sk_buff *from, int offset, char *to,int size);
+extern int			skb_copy_datagram_iovec(struct sk_buff *from, int offset, struct iovec *to,int size);
 extern void			skb_free_datagram(struct sock * sk, struct sk_buff *skb);
 
 #endif	/* __KERNEL__ */
diff -u --recursive --new-file v2.1.9/linux/include/linux/socket.h linux/include/linux/socket.h
--- v2.1.9/linux/include/linux/socket.h	Tue Nov 12 15:56:14 1996
+++ linux/include/linux/socket.h	Thu Nov 14 18:26:16 1996
@@ -175,8 +175,8 @@
 #define SOPRI_BACKGROUND	2
 
 #ifdef __KERNEL__
-extern void memcpy_fromiovec(unsigned char *kdata, struct iovec *iov, int len);
-extern void memcpy_fromiovecend(unsigned char *kdata, struct iovec *iov, 
+extern int memcpy_fromiovec(unsigned char *kdata, struct iovec *iov, int len);
+extern int memcpy_fromiovecend(unsigned char *kdata, struct iovec *iov, 
 				int offset, int len);
 extern unsigned int csum_partial_copy_fromiovecend(unsigned char *kdata, 
 						   struct iovec *iov, 
@@ -184,7 +184,7 @@
 						   int len, int csum);
 
 extern int verify_iovec(struct msghdr *m, struct iovec *iov, char *address, int mode);
-extern void memcpy_toiovec(struct iovec *v, unsigned char *kdata, int len);
+extern int memcpy_toiovec(struct iovec *v, unsigned char *kdata, int len);
 extern int move_addr_to_user(void *kaddr, int klen, void *uaddr, int *ulen);
 extern int move_addr_to_kernel(void *uaddr, int ulen, void *kaddr);
 #endif
diff -u --recursive --new-file v2.1.9/linux/include/net/ip.h linux/include/net/ip.h
--- v2.1.9/linux/include/net/ip.h	Mon Sep 30 11:24:39 1996
+++ linux/include/net/ip.h	Fri Nov 15 16:00:27 1996
@@ -106,11 +106,11 @@
 				      int free);
 extern void		ip_init(void);
 extern int		ip_build_xmit(struct sock *sk,
-				      void getfrag (const void *,
-						    __u32,
-						    char *,
-						    unsigned int,
-						    unsigned int),
+				      int getfrag (const void *,
+						   __u32,
+						   char *,
+						   unsigned int,
+						   unsigned int),
 				      const void *frag,
 				      unsigned short int length,
 				      __u32 daddr,
diff -u --recursive --new-file v2.1.9/linux/include/net/ipv6.h linux/include/net/ipv6.h
--- v2.1.9/linux/include/net/ipv6.h	Sun Nov 10 20:12:15 1996
+++ linux/include/net/ipv6.h	Fri Nov 15 16:00:29 1996
@@ -133,7 +133,7 @@
  *	Function prototype for build_xmit
  */
 
-typedef void		(*inet_getfrag_t) (const void *data,
+typedef int		(*inet_getfrag_t) (const void *data,
 					   struct in6_addr *addr,
 					   char *,
 					   unsigned int, unsigned int);
diff -u --recursive --new-file v2.1.9/linux/include/net/tcp.h linux/include/net/tcp.h
--- v2.1.9/linux/include/net/tcp.h	Tue Nov 12 15:56:15 1996
+++ linux/include/net/tcp.h	Fri Nov 15 16:00:27 1996
@@ -382,7 +382,7 @@
          * old_window - received_bytes_on_that_win
 	 */
 
-	cur_win = tp->rcv_wup + tp->rcv_wnd - tp->rcv_nxt;
+	cur_win = tp->rcv_wup - (tp->rcv_nxt - tp->rcv_wnd);
 
 
 	/*
@@ -396,82 +396,7 @@
 	return res;
 }
 
-/*
- *      This function returns the amount that we can raise the
- *      usable window based on the following constraints
- *  
- *	1. The window can never be shrunk once it is offered (RFC 793)
- *	2. We limit memory per socket
- */
-
-
-static __inline__ unsigned short tcp_select_window(struct sock *sk)
-{
-	struct tcp_opt *tp = &sk->tp_pinfo.af_tcp;
-	long free_space = sock_rspace(sk);
-	long window;
-	long cur_win;
-	long usable;
-	
-	if (sk->window_clamp)
-		free_space = min(sk->window_clamp, free_space);
-	
-	/*
-	 * compute the actual window i.e.
-	 * old_window - received_bytes_on_that_win
-	 */
-
-	cur_win = tp->rcv_wup + tp->rcv_wnd - tp->rcv_nxt;
-	window  = tp->rcv_wnd;
-	
-	if ( cur_win < 0 )
-	{
-		cur_win = 0;
-		printk(KERN_DEBUG "TSW: win < 0 w=%d 1=%u 2=%u\n",
-		       tp->rcv_wnd, tp->rcv_nxt, tp->rcv_wup);
-	}
-
-	/*
-	 * RFC 1122:
-	 * "the suggested [SWS] avoidance algoritm for the receiver is to keep
-	 *  RECV.NEXT + RCV.WIN fixed until:
-	 *  RCV.BUFF - RCV.USER - RCV.WINDOW >= min(1/2 RCV.BUFF, MSS)"
-	 *
-	 * i.e. don't raise the right edge of the window until you can't raise
-	 * it MSS bytes
-	 */
-
-	/*
-	 * It would be a good idea if it didn't break header prediction.
-	 * and BSD made the header predition standard...
-	 * It expects the same value in the header i.e. th->window to be
-	 * constant
-	 */
-
-	if (tp->rcv_wnd >= free_space)
-	{
-		if (cur_win > (sk->mss << 1))
-			goto out;
-	}
-
-	usable = free_space - cur_win;
-
-#define WROUND(X, Y) ((X + (Y-1)) & (Y-1))
-		
-	window += WROUND(min(usable, sk->mss), 1024);
-
-#undef WROUND
-
-	if (window < cur_win)
-	{
-		window = cur_win;
-	}
-
-  out:	
-	tp->rcv_wnd = window;
-	tp->rcv_wup = tp->rcv_nxt;
-	return window;
-}
+extern unsigned short	tcp_select_window(struct sock *sk);
 
 /*
  * List all states of a TCP socket that can be viewed as a "connected"
diff -u --recursive --new-file v2.1.9/linux/net/appletalk/ddp.c linux/net/appletalk/ddp.c
--- v2.1.9/linux/net/appletalk/ddp.c	Tue Nov 12 15:56:15 1996
+++ linux/net/appletalk/ddp.c	Thu Nov 14 18:26:16 1996
@@ -736,16 +736,15 @@
 	struct device *dev;
 	struct atalk_iface *atif;
 	int ro=(cmd==SIOCSIFADDR);
-	int err=verify_area(ro?VERIFY_READ:VERIFY_WRITE, arg,sizeof(atreq));
+	int err;
 	int ct;
 	int limit;
 	struct rtentry rtdef;
 	
-	if(err)
-		return err;
-	
-	copy_from_user(&atreq,arg,sizeof(atreq));
-	
+	err = copy_from_user(&atreq,arg,sizeof(atreq));
+	if (err)
+		return -EFAULT; 
+
 	if((dev=dev_get(atreq.ifr_name))==NULL)
 		return -ENODEV;
 		
@@ -855,8 +854,13 @@
 			((struct sockaddr_at *)(&atreq.ifr_addr))->sat_addr.s_node=ATADDR_BCAST;
 			break;
 	}
-	copy_to_user(arg,&atreq,sizeof(atreq));
-	return 0;
+	err = copy_to_user(arg,&atreq,sizeof(atreq));
+
+	if (err)
+	{
+		err = -EFAULT;
+	}
+	return err;
 }
 
 /*
@@ -868,11 +872,10 @@
 	int err;
 	struct rtentry rt;
 	
-	err=verify_area(VERIFY_READ, arg, sizeof(rt));
-	if(err)
-		return err;
-	copy_from_user(&rt,arg,sizeof(rt));
-	
+	err = copy_from_user(&rt,arg,sizeof(rt));
+	if (err)
+		return -EFAULT; 
+
 	switch(cmd)
 	{
 		case SIOCDELRT:
@@ -1077,15 +1080,10 @@
 		default:
 			return -EOPNOTSUPP;
 	}
-	err=verify_area(VERIFY_WRITE,optlen,sizeof(int));
-	if(err)
-		return err;
-	put_user(sizeof(int),optlen);
-	err=verify_area(VERIFY_WRITE,optval,sizeof(int));
-	if (err) 
-		return err;
-	put_user(val, (int *)optval);
-	return(0);
+	err = put_user(sizeof(int),optlen);
+	if (!err)
+		err = put_user(val, (int *) optval);
+	return err;
 }
 
 /*
@@ -1736,8 +1734,13 @@
 	if(sk->debug)
 		printk("SK %p: Copy user data (%d bytes).\n", sk, len);
 		
-	memcpy_fromiovec(skb_put(skb,len),msg->msg_iov,len);
-
+	err = memcpy_fromiovec(skb_put(skb,len),msg->msg_iov,len);
+	if (err)
+	{
+		kfree_skb(skb, FREE_WRITE);
+		return err;
+	}
+		
 	if(sk->no_check==1)
 		ddp->deh_sum=0;
 	else
@@ -1816,7 +1819,7 @@
 	struct ddpehdr	*ddp = NULL;
 	int copied = 0;
 	struct sk_buff *skb;
-	int er;
+	int er = 0;
 	
 	if(sk->err)
 		return sock_error(sk);
@@ -1834,14 +1837,18 @@
 		copied=ddp->deh_len;
 		if(copied > size)
 			copied=size;
-		skb_copy_datagram_iovec(skb,0,msg->msg_iov,copied);
+		er = skb_copy_datagram_iovec(skb,0,msg->msg_iov,copied);
+		if (er)
+			goto out;
 	}
 	else
 	{
 		copied=ddp->deh_len - sizeof(*ddp);
 		if (copied > size)
 			copied = size;
-		skb_copy_datagram_iovec(skb,sizeof(*ddp),msg->msg_iov,copied);
+		er = skb_copy_datagram_iovec(skb,sizeof(*ddp),msg->msg_iov,copied);
+		if (er) 
+			goto out; 
 	}
 	if(sat)
 	{
@@ -1850,8 +1857,9 @@
 		sat->sat_addr.s_node=ddp->deh_snode;
 		sat->sat_addr.s_net=ddp->deh_snet;
 	}
+out:
 	skb_free_datagram(sk, skb);
-	return(copied);
+	return er ? er : (copied);
 }		
 
 
@@ -1900,11 +1908,7 @@
 			{
 				if(sk->stamp.tv_sec==0)
 					return -ENOENT;
-				err=verify_area(VERIFY_WRITE,(void *)arg,sizeof(struct timeval));
-				if(err)
-					return err;
-					copy_to_user((void *)arg,&sk->stamp,sizeof(struct timeval));
-				return 0;
+				return copy_to_user((void *)arg,&sk->stamp,sizeof(struct timeval));
 			}
 			return -EINVAL;
 		/*
@@ -1950,11 +1954,7 @@
 		default:
 			return -EINVAL;
 	}
-	err=verify_area(VERIFY_WRITE,(void *)arg,sizeof(int));
-	if(err)
-		return err;
-	put_user(amount, (int *)arg);
-	return(0);
+	return put_user(amount, (int *)arg);
 }
 
 static struct proto_ops atalk_proto_ops = {
diff -u --recursive --new-file v2.1.9/linux/net/bridge/br.c linux/net/bridge/br.c
--- v2.1.9/linux/net/bridge/br.c	Sun Nov 10 20:12:24 1996
+++ linux/net/bridge/br.c	Thu Nov 14 18:26:16 1996
@@ -1442,22 +1442,20 @@
 	switch(cmd)
 	{
 		case SIOCGIFBR:	/* get bridging control blocks */
-			err = verify_area(VERIFY_WRITE, arg, 
-				sizeof(struct br_stat));
-			if(err)
-				return err;
 			memcpy(&br_stats.bridge_data, &bridge_info, sizeof(Bridge_data));
 			memcpy(&br_stats.port_data, &port_info, sizeof(Port_data)*No_of_ports);
-			copy_to_user(arg, &br_stats, sizeof(struct br_stat));
-			return(0);
+			err = copy_to_user(arg, &br_stats, sizeof(struct br_stat));
+			if (err)
+			{
+				err = -EFAULT;
+			}
+			return err;
 		case SIOCSIFBR:
 			if (!suser())
 				return -EPERM;
-			err = verify_area(VERIFY_READ, arg, 
-				sizeof(struct br_cf));
-			if(err)
-				return err;
-			copy_from_user(&bcf, arg, sizeof(struct br_cf));
+			err = copy_from_user(&bcf, arg, sizeof(struct br_cf));
+			if (err)
+				return -EFAULT; 
 			switch (bcf.cmd) {
 				case BRCMD_BRIDGE_ENABLE:
 					if (br_stats.flags & BR_UP)
diff -u --recursive --new-file v2.1.9/linux/net/core/datagram.c linux/net/core/datagram.c
--- v2.1.9/linux/net/core/datagram.c	Fri Nov  1 17:13:19 1996
+++ linux/net/core/datagram.c	Thu Nov 14 18:26:16 1996
@@ -166,9 +166,15 @@
  *	Copy a datagram to a linear buffer.
  */
 
-void skb_copy_datagram(struct sk_buff *skb, int offset, char *to, int size)
+int skb_copy_datagram(struct sk_buff *skb, int offset, char *to, int size)
 {
-	copy_to_user(to,skb->h.raw+offset,size);
+	int err;
+	err = copy_to_user(to, skb->h.raw+offset, size);
+	if (err)
+	{
+		err = -EFAULT;
+	}
+	return err;
 }
 
 
@@ -176,9 +182,16 @@
  *	Copy a datagram to an iovec.
  */
  
-void skb_copy_datagram_iovec(struct sk_buff *skb, int offset, struct iovec *to, int size)
+int skb_copy_datagram_iovec(struct sk_buff *skb, int offset, struct iovec *to,
+			    int size)
 {
-	memcpy_toiovec(to,skb->h.raw+offset,size);
+	int err;
+	err = memcpy_toiovec(to, skb->h.raw+offset, size);
+	if (err)
+	{
+		err = -EFAULT;
+	}
+	return err;
 }
 
 /*
diff -u --recursive --new-file v2.1.9/linux/net/core/dev.c linux/net/core/dev.c
--- v2.1.9/linux/net/core/dev.c	Tue Nov 12 15:56:15 1996
+++ linux/net/core/dev.c	Thu Nov 14 18:26:16 1996
@@ -793,11 +793,10 @@
 	/*
 	 *	Fetch the caller's info block. 
 	 */
-	 
-	err=verify_area(VERIFY_WRITE, arg, sizeof(struct ifconf));
-	if(err)
-	  	return err;
-	copy_from_user(&ifc, arg, sizeof(struct ifconf));
+	
+	err = copy_from_user(&ifc, arg, sizeof(struct ifconf));
+	if (err)
+		return -EFAULT; 
 	len = ifc.ifc_len;
 	pos = ifc.ifc_buf;
 
@@ -805,11 +804,7 @@
 	 *	We now walk the device list filling each active device
 	 *	into the array.
 	 */
-	 
-	err=verify_area(VERIFY_WRITE,pos,len);
-	if(err)
-	  	return err;
-  	
+	
 	/*
 	 *	Loop over the interfaces, and write an info block for each. 
 	 */
@@ -835,7 +830,9 @@
 		 *	Write this block to the caller's space. 
 		 */
 		 
-		copy_to_user(pos, &ifr, sizeof(struct ifreq));
+		err = copy_to_user(pos, &ifr, sizeof(struct ifreq));
+		if (err)
+			return -EFAULT; 
 		pos += sizeof(struct ifreq);
 		len -= sizeof(struct ifreq);		
   	}
@@ -846,8 +843,10 @@
 	 
 	ifc.ifc_len = (pos - ifc.ifc_buf);
 	ifc.ifc_req = (struct ifreq *) ifc.ifc_buf;
-	copy_to_user(arg, &ifc, sizeof(struct ifconf));
-	
+	err = copy_to_user(arg, &ifc, sizeof(struct ifconf));
+	if (err)
+		return -EFAULT; 
+
 	/*
 	 *	Report how much was filled in
 	 */
@@ -956,17 +955,15 @@
 {
 	struct ifreq ifr;
 	struct device *dev;
-	int ret;
+	int ret, err;
 
 	/*
 	 *	Fetch the caller's info block into kernel space
 	 */
-
-	int err=verify_area(VERIFY_WRITE, arg, sizeof(struct ifreq));
-	if(err)
-		return err;
 	
-	copy_from_user(&ifr, arg, sizeof(struct ifreq));
+	err = copy_from_user(&ifr, arg, sizeof(struct ifreq));
+	if (err)
+		return -EFAULT; 
 
 	/*
 	 *	See which interface the caller is talking about. 
@@ -1266,8 +1263,13 @@
 			   (getset <= (SIOCDEVPRIVATE + 15))) {
 				if(dev->do_ioctl==NULL)
 					return -EOPNOTSUPP;
-				ret=dev->do_ioctl(dev, &ifr, getset);
-				copy_to_user(arg,&ifr,sizeof(struct ifreq));
+				ret = dev->do_ioctl(dev, &ifr, getset);
+				if (!ret)
+				{
+					err = copy_to_user(arg,&ifr,sizeof(struct ifreq));
+					if (err)
+						ret = -EFAULT;
+				}
 				break;
 			}
 			
@@ -1278,8 +1280,10 @@
  *	The load of calls that return an ifreq and ok (saves memory).
  */
 rarok:
-	copy_to_user(arg, &ifr, sizeof(struct ifreq));
-	return 0;
+	err = copy_to_user(arg, &ifr, sizeof(struct ifreq));
+	if (err)
+		err = -EFAULT;
+	return err;
 }
 
 
diff -u --recursive --new-file v2.1.9/linux/net/core/iovec.c linux/net/core/iovec.c
--- v2.1.9/linux/net/core/iovec.c	Sun Nov 10 20:12:24 1996
+++ linux/net/core/iovec.c	Thu Nov 14 18:26:16 1996
@@ -11,6 +11,7 @@
  *		Andrew Lunn	:	Errors in iovec copying.
  *		Pedro Roque	:	Added memcpy_fromiovecend and
  *					csum_..._fromiovecend.
+ *      Andi Kleen  :   fixed error handling for 2.1
  */
 
 
@@ -29,6 +30,12 @@
 	return x>y?y:x;
 }
 
+
+/*
+ *	Verify iovec
+ *	verify area does a simple check for completly bogus addresses
+ */
+
 int verify_iovec(struct msghdr *m, struct iovec *iov, char *address, int mode)
 {
 	int err=0;
@@ -37,14 +44,20 @@
 	
 	if(m->msg_name!=NULL)
 	{
-		if(mode==VERIFY_READ) {
+		if(mode==VERIFY_READ)
+		{
 			err=move_addr_to_kernel(m->msg_name, m->msg_namelen, address);
-		} else
+		}
+		else
+		{
 			err=verify_area(mode, m->msg_name, m->msg_namelen);
+		}
+		
 		if(err<0)
 			return err;
 		m->msg_name = address;
 	}
+	
 	if(m->msg_control!=NULL)
 	{
 		err=verify_area(mode, m->msg_control, m->msg_controllen);
@@ -54,11 +67,12 @@
 	
 	for(ct=0;ct<m->msg_iovlen;ct++)
 	{
-		err=verify_area(VERIFY_READ, &m->msg_iov[ct], sizeof(struct iovec));
-		if(err)
+		err = copy_from_user(&iov[ct], &m->msg_iov[ct],
+				     sizeof(struct iovec));
+		if (err)
 			return err;
-		copy_from_user(&iov[ct], &m->msg_iov[ct], sizeof(struct iovec));
-		err=verify_area(mode, iov[ct].iov_base, iov[ct].iov_len);
+		
+		err = verify_area(mode, iov[ct].iov_base, iov[ct].iov_len);
 		if(err)
 			return err;
 		len+=iov[ct].iov_len;
@@ -71,14 +85,18 @@
  *	Copy kernel to iovec.
  */
  
-void memcpy_toiovec(struct iovec *iov, unsigned char *kdata, int len)
+int memcpy_toiovec(struct iovec *iov, unsigned char *kdata, int len)
 {
+	int err; 
 	while(len>0)
 	{
 		if(iov->iov_len)
 		{
 			int copy = min(iov->iov_len,len);
-			copy_to_user(iov->iov_base,kdata,copy);
+			err = copy_to_user(iov->iov_base,kdata,copy);
+			if (err) {
+				return err; 
+			}
 			kdata+=copy;
 			len-=copy;
 			iov->iov_len-=copy;
@@ -86,20 +104,26 @@
 		}
 		iov++;
 	}
+	return 0; 
 }
 
 /*
  *	Copy iovec to kernel.
  */
  
-void memcpy_fromiovec(unsigned char *kdata, struct iovec *iov, int len)
+int memcpy_fromiovec(unsigned char *kdata, struct iovec *iov, int len)
 {
+	int err; 
 	while(len>0)
 	{
 		if(iov->iov_len)
 		{
 			int copy=min(len,iov->iov_len);
-			copy_from_user(kdata, iov->iov_base, copy);
+			err = copy_from_user(kdata, iov->iov_base, copy);
+			if (err)
+			{
+				return err; 
+			}
 			len-=copy;
 			kdata+=copy;
 			iov->iov_base+=copy;
@@ -107,6 +131,7 @@
 		}
 		iov++;
 	}
+	return 0; 
 }
 
 
@@ -114,9 +139,10 @@
  *	For use with ip_build_xmit
  */
 
-void memcpy_fromiovecend(unsigned char *kdata, struct iovec *iov, int offset, 
-			 int len)
+int memcpy_fromiovecend(unsigned char *kdata, struct iovec *iov, int offset,
+			int len)
 {
+	int err; 
 	while(offset>0)
 	{
 		if (offset > iov->iov_len)
@@ -133,21 +159,30 @@
 			copy = min(len, iov->iov_len - offset);
 			offset = 0;
 
-			copy_from_user(kdata, base, copy);
+			err = copy_from_user(kdata, base, copy);
+			if (err)
+			{
+				return err;
+			}
 			len-=copy;
 			kdata+=copy;
 		}
-		iov++;	
+		iov++;
 	}
 
 	while (len>0)
 	{
 		int copy=min(len, iov->iov_len);
-		copy_from_user(kdata, iov->iov_base, copy);
+		err = copy_from_user(kdata, iov->iov_base, copy);
+		if (err)
+		{
+			return err;
+		}
 		len-=copy;
 		kdata+=copy;
 		iov++;
 	}
+	return 0;
 }
 
 /*
@@ -157,6 +192,9 @@
  *
  *	ip_build_xmit must ensure that when fragmenting only the last
  *	call to this function will be unaligned also.
+ *
+ *	FIXME: add an error handling path when a copy/checksum from
+ *	user space failed because of a invalid pointer.
  */
 
 unsigned int csum_partial_copy_fromiovecend(unsigned char *kdata, 
@@ -190,13 +228,18 @@
 					       partial_cnt);
 			}
 
+			/*	
+			 *	FIXME: add exception handling to the
+			 *	csum functions and set *err when an
+			 *	exception occurs.
+			 */
 			csum = csum_partial_copy_fromuser(base, kdata, 
 							  copy, csum);
 
 			len   -= copy + partial_cnt;
 			kdata += copy + partial_cnt;
 		}
-		iov++;			
+		iov++;	
 	}
 
 	while (len>0)
@@ -226,8 +269,7 @@
 			}
 		}
 
-		csum = csum_partial_copy_fromuser(base, kdata, 
-						  copy, csum);
+		csum = csum_partial_copy_fromuser(base, kdata, copy, csum);
 		len   -= copy + partial_cnt;
 		kdata += copy + partial_cnt;
 		iov++;
diff -u --recursive --new-file v2.1.9/linux/net/core/skbuff.c linux/net/core/skbuff.c
--- v2.1.9/linux/net/core/skbuff.c	Sun Nov 10 20:12:24 1996
+++ linux/net/core/skbuff.c	Fri Nov 15 14:04:01 1996
@@ -634,7 +634,7 @@
 struct sk_buff *alloc_skb(unsigned int size,int priority)
 {
 	struct sk_buff *skb;
-	int len=size;
+	int len;
 	unsigned char *bptr;
 
 	if (intr_count && priority!=GFP_ATOMIC) 
@@ -648,6 +648,8 @@
 	}
 
 	size=(size+15)&~15;		/* Allow for alignments. Make a multiple of 16 bytes */
+	len = size;
+	
 	size+=sizeof(struct sk_buff);	/* And stick the control itself on the end */
 	
 	/*
@@ -748,7 +750,7 @@
 	int inbuff = 0;
 	
 	IS_SKB(skb);
-	if (skb_tailroom(skb) >= sizeof(struct sk_buff))
+	if (!skb->inclone && skb_tailroom(skb) >= sizeof(struct sk_buff))
 	{
 		n = ((struct sk_buff *) skb->end) - 1;
 		skb->end -= sizeof(struct sk_buff);
diff -u --recursive --new-file v2.1.9/linux/net/core/sock.c linux/net/core/sock.c
--- v2.1.9/linux/net/core/sock.c	Sun Nov 10 20:12:24 1996
+++ linux/net/core/sock.c	Thu Nov 14 18:26:17 1996
@@ -122,12 +122,13 @@
  */
 
 int sock_setsockopt(struct sock *sk, int level, int optname,
-		char *optval, int optlen)
+		    char *optval, int optlen)
 {
 	int val;
 	int valbool;
 	int err;
 	struct linger ling;
+	int ret = 0;
 
 	/*
 	 *	Options without arguments
@@ -144,33 +145,36 @@
 		
   	if (optval == NULL) 
   		return(-EINVAL);
-
-  	err=verify_area(VERIFY_READ, optval, sizeof(int));
-  	if(err)
-  		return err;
   	
-	get_user(val, (int *)optval);
+	err = get_user(val, (int *)optval);
+	if (err)
+		return err;
+	
   	valbool = val?1:0;
   	
   	switch(optname) 
   	{
 		case SO_DEBUG:	
 			if(val && !suser())
-				return(-EPERM);
-			sk->debug=valbool;
-			return 0;
+			{
+				ret = -EPERM;
+			}
+			else
+				sk->debug=valbool;
+			break;
 		case SO_REUSEADDR:
 			sk->reuse = valbool;
-			return(0);
+			break;
 		case SO_TYPE:
 		case SO_ERROR:
-		  	return(-ENOPROTOOPT);
+			ret = -ENOPROTOOPT;
+		  	break;
 		case SO_DONTROUTE:
 			sk->localroute=valbool;
-			return 0;
+			break;
 		case SO_BROADCAST:
 			sk->broadcast=valbool;
-			return 0;
+			break;
 		case SO_SNDBUF:
 			if(val > SK_WMEM_MAX*2)
 				val = SK_WMEM_MAX*2;
@@ -179,7 +183,7 @@
 			if(val > 65535)
 				val = 65535;
 			sk->sndbuf = val;
-			return 0;
+			break;
 
 		case SO_RCVBUF:
 			if(val > SK_RMEM_MAX*2)
@@ -189,41 +193,45 @@
 			if(val > 65535)
 				val = 65535;
 			sk->rcvbuf = val;
-			return(0);
+			break;
 
 		case SO_KEEPALIVE:
+#ifdef CONFIG_INET
 			if (sk->protocol == IPPROTO_TCP)
 			{
 				tcp_set_keepalive(sk, valbool);
 			}
+#endif
 			sk->keepopen = valbool;
-			return(0);
+			break;
 
 	 	case SO_OOBINLINE:
 			sk->urginline = valbool;
-			return(0);
+			break;
 
 	 	case SO_NO_CHECK:
 			sk->no_check = valbool;
-			return(0);
+			break;
 
 		case SO_PRIORITY:
 			if (val >= 0 && val < DEV_NUMBUFFS) 
 			{
 				sk->priority = val;
 			} 
-			else 
+			else
 			{
 				return(-EINVAL);
 			}
-			return(0);
+			break;
 
 
 		case SO_LINGER:
-			err=verify_area(VERIFY_READ,optval,sizeof(ling));
-			if(err)
-				return err;
-			copy_from_user(&ling,optval,sizeof(ling));
+			err = copy_from_user(&ling,optval,sizeof(ling));
+			if (err)
+			{
+				ret = -EFAULT;
+				break;
+			}
 			if(ling.l_onoff==0)
 				sk->linger=0;
 			else
@@ -231,15 +239,16 @@
 				sk->lingertime=ling.l_linger;
 				sk->linger=1;
 			}
-			return 0;
+			break;
 
 		case SO_BSDCOMPAT:
 			sk->bsdism = valbool;
-			return 0;
+			break;
 			
 		default:
 		  	return(-ENOPROTOOPT);
   	}
+	return ret;
 }
 
 
@@ -303,17 +312,13 @@
 			break;
 		
 		case SO_LINGER:	
-			err=verify_area(VERIFY_WRITE,optval,sizeof(ling));
-			if(err)
-				return err;
-			err=verify_area(VERIFY_WRITE,optlen,sizeof(int));
-			if(err)
-				return err;
-			put_user(sizeof(ling), optlen);
-			ling.l_onoff=sk->linger;
-			ling.l_linger=sk->lingertime;
-			copy_to_user(optval,&ling,sizeof(ling));
-			return 0;
+			err = put_user(sizeof(ling), optlen);
+			if (!err) {
+				ling.l_onoff=sk->linger;
+				ling.l_linger=sk->lingertime;
+				err = copy_to_user(optval,&ling,sizeof(ling));
+			}
+			return err;
 		
 		case SO_BSDCOMPAT:
 			val = sk->bsdism;
@@ -322,17 +327,11 @@
 		default:
 			return(-ENOPROTOOPT);
 	}
-	err=verify_area(VERIFY_WRITE, optlen, sizeof(int));
-	if(err)
-  		return err;
-  	put_user(sizeof(int), optlen);
-
-  	err=verify_area(VERIFY_WRITE, optval, sizeof(int));
-  	if(err)
-  		return err;
-  	put_user(val,(unsigned int *)optval);
+  	err = put_user(sizeof(int), optlen);
+	if (!err)
+		err = put_user(val,(unsigned int *)optval);
 
-  	return(0);
+  	return err;
 }
 
 struct sock *sk_alloc(int priority)
diff -u --recursive --new-file v2.1.9/linux/net/ipv4/af_inet.c linux/net/ipv4/af_inet.c
--- v2.1.9/linux/net/ipv4/af_inet.c	Sun Nov 10 20:12:28 1996
+++ linux/net/ipv4/af_inet.c	Thu Nov 14 18:26:17 1996
@@ -1208,10 +1208,9 @@
 	{
 		case FIOSETOWN:
 		case SIOCSPGRP:
-			err=verify_area(VERIFY_READ,(int *)arg,sizeof(long));
-			if(err)
-				return err;
-			get_user(pid, (int *) arg);
+			err = get_user(pid, (int *) arg);
+			if (err)
+				return err; 
 			/* see inet_fcntl */
 			if (current->pid != pid && current->pgrp != -pid && !suser())
 				return -EPERM;
@@ -1219,19 +1218,16 @@
 			return(0);
 		case FIOGETOWN:
 		case SIOCGPGRP:
-			err=verify_area(VERIFY_WRITE,(void *) arg, sizeof(int));
-			if(err)
-				return err;
-			put_user(sk->proc, (int *)arg);
-			return(0);			
+			return put_user(sk->proc, (int *)arg);
 		case SIOCGSTAMP:
 			if(sk->stamp.tv_sec==0)
 				return -ENOENT;
-			err=verify_area(VERIFY_WRITE,(void *)arg,sizeof(struct timeval));
-			if(err)
-				return err;
-			copy_to_user((void *)arg,&sk->stamp,sizeof(struct timeval));
-			return 0;
+			err = copy_to_user((void *)arg,&sk->stamp,sizeof(struct timeval));
+			if (err)
+			{
+				err = -EFAULT;
+			}
+			return err;
 		case SIOCADDRT:
 		case SIOCDELRT:
 			return(ip_rt_ioctl(cmd,(void *) arg));
diff -u --recursive --new-file v2.1.9/linux/net/ipv4/arp.c linux/net/ipv4/arp.c
--- v2.1.9/linux/net/ipv4/arp.c	Tue Nov 12 15:56:16 1996
+++ linux/net/ipv4/arp.c	Thu Nov 14 18:26:17 1996
@@ -2179,20 +2179,18 @@
 			if (!suser())
 				return -EPERM;
 		case SIOCGARP:
-			err = verify_area(VERIFY_READ, arg, sizeof(struct arpreq));
+			err = copy_from_user(&r, arg, sizeof(struct arpreq));
 			if (err)
-				return err;
-			copy_from_user(&r, arg, sizeof(struct arpreq));
+				return -EFAULT; 
 			break;
 		case OLD_SIOCDARP:
 		case OLD_SIOCSARP:
 			if (!suser())
 				return -EPERM;
 		case OLD_SIOCGARP:
-			err = verify_area(VERIFY_READ, arg, sizeof(struct arpreq_old));
+			err = copy_from_user(&r, arg, sizeof(struct arpreq_old));
 			if (err)
-				return err;
-			copy_from_user(&r, arg, sizeof(struct arpreq_old));
+				return -EFAULT; 
 			memset(&r.arp_dev, 0, sizeof(r.arp_dev));
 			break;
 		default:
@@ -2250,17 +2248,15 @@
 			}
 			return err;
 		case SIOCGARP:
-			err = verify_area(VERIFY_WRITE, arg, sizeof(struct arpreq));
-			if (err)
-				return err;
 			err = arp_req_get(&r, dev);
 			if (!err)
-				copy_to_user(arg, &r, sizeof(r));
+			{
+				err = copy_to_user(arg, &r, sizeof(r));
+				if (err)
+					err = -EFAULT;
+			}
 			return err;
 		case OLD_SIOCGARP:
-			err = verify_area(VERIFY_WRITE, arg, sizeof(struct arpreq_old));
-			if (err)
-				return err;
 			r.arp_flags &= ~ATF_PUBL;
 			err = arp_req_get(&r, dev);
 			if (err < 0)
@@ -2269,7 +2265,11 @@
 				err = arp_req_get(&r, dev);
 			}
 			if (!err)
-				copy_to_user(arg, &r, sizeof(struct arpreq_old));
+			{
+				err = copy_to_user(arg, &r, sizeof(struct arpreq_old));
+				if (err)
+					err = -EFAULT;
+			}
 			return err;
 	}
 	/*NOTREACHED*/
diff -u --recursive --new-file v2.1.9/linux/net/ipv4/icmp.c linux/net/ipv4/icmp.c
--- v2.1.9/linux/net/ipv4/icmp.c	Sun Nov 10 20:12:29 1996
+++ linux/net/ipv4/icmp.c	Thu Nov 14 18:26:17 1996
@@ -474,16 +474,17 @@
  *	Checksum each fragment, and on the first include the headers and final checksum.
  */
  
-static void icmp_glue_bits(const void *p, __u32 saddr, char *to, unsigned int offset, unsigned int fraglen)
+static int icmp_glue_bits(const void *p, __u32 saddr, char *to, unsigned int offset, unsigned int fraglen)
 {
 	struct icmp_bxm *icmp_param = (struct icmp_bxm *)p;
 	struct icmphdr *icmph;
 	unsigned long csum;
 
-	if (offset) {
+	if (offset)
+	{
 		icmp_param->csum=csum_partial_copy(icmp_param->data_ptr+offset-sizeof(struct icmphdr), 
 				to, fraglen,icmp_param->csum);
-		return;
+		return 0;
 	}
 
 	/*
@@ -499,6 +500,8 @@
 		fraglen-sizeof(struct icmphdr), csum);
 	icmph=(struct icmphdr *)to;
 	icmph->checksum = csum_fold(csum);
+
+	return 0; 
 }
  
 /*
diff -u --recursive --new-file v2.1.9/linux/net/ipv4/ip_output.c linux/net/ipv4/ip_output.c
--- v2.1.9/linux/net/ipv4/ip_output.c	Sun Nov 10 20:12:29 1996
+++ linux/net/ipv4/ip_output.c	Thu Nov 14 18:26:17 1996
@@ -504,11 +504,11 @@
  */
 
 int ip_build_xmit(struct sock *sk,
-		   void getfrag (const void *,
-				 __u32,
-				 char *,
-				 unsigned int,	
-				 unsigned int),
+		  int getfrag (const void *,
+			       __u32,
+			       char *,
+			       unsigned int,	
+			       unsigned int),
 		   const void *frag,
 		   unsigned short int length,
 		   __u32 daddr,
@@ -529,6 +529,7 @@
 	struct hh_cache * hh=NULL;
 	int nfrags=0;
 	__u32 true_daddr = daddr;
+	int err; 
 
 	if (opt && opt->srr && !sk->ip_hdrincl)
 	  daddr = opt->faddr;
@@ -648,18 +649,31 @@
 			}
 			iph->check=0;
 			iph->check = ip_fast_csum((unsigned char *)iph, iph->ihl);
-			getfrag(frag,saddr,((char *)iph)+iph->ihl*4,0, length-iph->ihl*4);
+			err = getfrag(frag,saddr,((char *)iph)+iph->ihl*4,0, length-iph->ihl*4);
 		}
 		else
-			getfrag(frag,saddr,(void *)iph,0,length);
+			err = getfrag(frag, saddr, (void *)iph, 0, length);
+		
 		dev_unlock_list();
+		
+		if (err)
+		{
+			err = -EFAULT;
+		}
+
 #ifdef CONFIG_FIREWALL
-		if(call_out_firewall(PF_INET, skb->dev, iph, NULL)< FW_ACCEPT)
+		if(!err && call_out_firewall(PF_INET, skb->dev, iph, NULL)< FW_ACCEPT)
 		{
-			kfree_skb(skb, FREE_WRITE);
-			return -EPERM;
+			err = -EPERM; 
 		}
 #endif
+
+		if (err)
+		{
+			kfree_skb(skb, FREE_WRITE);
+			return err;
+		}
+
 #ifdef CONFIG_IP_ACCT
 		ip_fw_chk(iph,dev,NULL,ip_acct_chain,0,IP_FW_MODE_ACCT_OUT);
 #endif		
@@ -675,7 +689,7 @@
 	if (!sk->ip_hdrincl)
 		length -= sizeof(struct iphdr);
 		
-	if(opt) 
+	if(opt)
 	{
 		length -= opt->optlen;
 		fragheaderlen = dev->hard_header_len + sizeof(struct iphdr) + opt->optlen;
@@ -688,8 +702,8 @@
 			fragheaderlen += 20;
 		
 		/*
-		 *	Fragheaderlen is the size of 'overhead' on each buffer. Now work
-		 *	out the size of the frames to send.
+		 *	Fragheaderlen is the size of 'overhead' on each buffer.
+		 *	Now work out the size of the frames to send.
 		 */
 	 
 		maxfraglen = ((dev->mtu-20) & ~7) + fragheaderlen;
@@ -758,7 +772,7 @@
 		{
 			ip_statistics.IpOutDiscards++;
 			if(nfrags>1)
-				ip_statistics.IpFragCreates++;			
+				ip_statistics.IpFragCreates++;
 			dev_unlock_list();
 			return(error);
 		}
@@ -795,7 +809,7 @@
 				skb->arp = 0;
 #if RT_CACHE_DEBUG >= 2
 				printk("ip_build_xmit: hh miss %08x via %08x\n", rt->rt_dst, rt->rt_gateway);
-#endif				
+#endif
 			}
 		}
 		else if (dev->hard_header)
@@ -856,20 +870,29 @@
 		 *	User data callback
 		 */
 
-		getfrag(frag, saddr, data, offset, fraglen-fragheaderlen);
+		err = getfrag(frag, saddr, data, offset, fraglen-fragheaderlen);
+		if (err)
+		{
+			err = -EFAULT;
+		}
 		
 		/*
 		 *	Account for the fragment.
 		 */
 		 
 #ifdef CONFIG_FIREWALL
-		if(!offset && call_out_firewall(PF_INET, skb->dev, iph, NULL) < FW_ACCEPT)
+		if(!err && !offset && call_out_firewall(PF_INET, skb->dev, iph, NULL) < FW_ACCEPT)
+		{
+			err = -EPERM; 
+		}
+#endif
+		if (err)
 		{
 			kfree_skb(skb, FREE_WRITE);
 			dev_unlock_list();
-			return -EPERM;
+			return err;
 		}
-#endif		
+
 #ifdef CONFIG_IP_ACCT
 		if(!offset)
 			ip_fw_chk(iph, dev, NULL, ip_acct_chain, 0, IP_FW_MODE_ACCT_OUT);
diff -u --recursive --new-file v2.1.9/linux/net/ipv4/ip_sockglue.c linux/net/ipv4/ip_sockglue.c
--- v2.1.9/linux/net/ipv4/ip_sockglue.c	Tue Oct 29 19:58:49 1996
+++ linux/net/ipv4/ip_sockglue.c	Thu Nov 14 18:26:17 1996
@@ -123,11 +123,11 @@
 	}
 	else
 	{
-		err=verify_area(VERIFY_READ, optval, sizeof(int));
-		if(err)
-			return err;
-		get_user(val, (int *) optval);
-		get_user(ucval, (unsigned char *) optval);
+		err = get_user(val, (int *) optval);
+		if (!err)
+			err = get_user(ucval, (unsigned char *) optval);
+		if (err)
+			return err; 
 	}
 	
 	if(level!=SOL_IP)
@@ -147,15 +147,20 @@
 			  struct options * old_opt;
 			  if (optlen > 40 || optlen < 0)
 			  	return -EINVAL;
-			  err = verify_area(VERIFY_READ, optval, optlen);
-			  if (err)
-			  	return err;
 			  opt = kmalloc(sizeof(struct options)+((optlen+3)&~3), GFP_KERNEL);
 			  if (!opt)
 			  	return -ENOMEM;
 			  memset(opt, 0, sizeof(struct options));
 			  if (optlen)
-			  	copy_from_user(opt->__data, optval, optlen);
+			  {
+				  err = copy_from_user(opt->__data, optval, optlen);
+				  if (err)
+				  {
+					  kfree_s(opt, sizeof(struct options) + ((optlen+3)&~3));
+					  return -EFAULT;
+				  }
+			  }
+
 			  while (optlen & 3)
 			  	opt->__data[optlen++] = IPOPT_END;
 			  opt->optlen = optlen;
@@ -228,13 +233,11 @@
 			/*
 			 *	Check the arguments are allowable
 			 */
-
-			err=verify_area(VERIFY_READ, optval, sizeof(addr));
-			if(err)
-				return err;
 				
-			copy_from_user(&addr,optval,sizeof(addr));
-			
+			err = copy_from_user(&addr,optval,sizeof(addr));
+			if (err)
+				return -EFAULT; 
+
 			
 			/*
 			 *	What address has been requested
@@ -278,11 +281,9 @@
 			 *	Check the arguments.
 			 */
 
-			err=verify_area(VERIFY_READ, optval, sizeof(mreq));
-			if(err)
-				return err;
-
-			copy_from_user(&mreq,optval,sizeof(mreq));
+			err = copy_from_user(&mreq,optval,sizeof(mreq));
+			if (err)
+				return -EFAULT; 
 
 			/* 
 			 *	Get device for use later
@@ -333,11 +334,9 @@
 			 *	Check the arguments
 			 */
 			 
-			err=verify_area(VERIFY_READ, optval, sizeof(mreq));
-			if(err)
-				return err;
-
-			copy_from_user(&mreq,optval,sizeof(mreq));
+			err = copy_from_user(&mreq,optval,sizeof(mreq));
+			if (err)
+				return -EFAULT; 
 
 			/*
 			 *	Get device for use later 
@@ -399,10 +398,9 @@
 				return -EPERM;
 			if(optlen>sizeof(tmp_fw) || optlen<1)
 				return -EINVAL;
-			err=verify_area(VERIFY_READ,optval,optlen);
-			if(err)
-				return err;
-			copy_from_user(&tmp_fw,optval,optlen);
+			err = copy_from_user(&tmp_fw,optval,optlen);
+			if (err)
+				return -EFAULT; 
 			err=ip_fw_ctl(optname, &tmp_fw,optlen);
 			return -err;	/* -0 is 0 after all */
 			
@@ -417,10 +415,9 @@
 				return -EPERM;
 			if(optlen>sizeof(tmp_fw) || optlen<1)
 				return -EINVAL;
-			err=verify_area(VERIFY_READ,optval,optlen);
-			if(err)
-				return err;
-			copy_from_user(&tmp_fw, optval,optlen);
+			err = copy_from_user(&tmp_fw, optval,optlen);
+			if (err)
+				return -EFAULT; 
 			err=ip_acct_ctl(optname, &tmp_fw,optlen);
 			return -err;	/* -0 is 0 after all */
 #endif
@@ -458,9 +455,7 @@
 			{
 				unsigned char optbuf[sizeof(struct options)+40];
 				struct options * opt = (struct options*)optbuf;
-				err = verify_area(VERIFY_WRITE, optlen, sizeof(int));
-				if (err)
-					return err;
+
 				cli();
 				opt->optlen = 0;
 				if (sk->opt)
@@ -468,12 +463,8 @@
 				sti();
 				if (opt->optlen == 0) 
 				{
-					put_user(0, optlen);
-					return 0;
+					return put_user(0, optlen);
 				}
-				err = verify_area(VERIFY_WRITE, optval, opt->optlen);
-				if (err)
-					return err;
 /*
  * Now we should undo all the changes done by ip_options_compile().
  */
@@ -503,8 +494,10 @@
 						optptr[2] -= 4;
 					}
 				}
-				put_user(opt->optlen, optlen);
-				copy_to_user(optval, opt->__data, opt->optlen);
+				err = put_user(opt->optlen, optlen);
+				if (!err)
+					err = copy_to_user(optval, opt->__data, opt->optlen);
+				return err; 
 			}
 			return 0;
 		case IP_TOS:
@@ -524,29 +517,17 @@
 			val=sk->ip_mc_loop;
 			break;
 		case IP_MULTICAST_IF:
-			err=verify_area(VERIFY_WRITE, optlen, sizeof(int));
-			if(err)
-  				return err;
   			len=strlen(sk->ip_mc_name);
-  			err=verify_area(VERIFY_WRITE, optval, len);
-		  	if(err)
-  				return err;
-  			put_user(len, optlen);
-			copy_to_user((void *)optval,sk->ip_mc_name, len);
-			return 0;
+  			err = put_user(len, optlen);
+			if (!err)
+				err = copy_to_user((void *)optval,sk->ip_mc_name, len);
+			return err;
 #endif
 		default:
 			return(-ENOPROTOOPT);
 	}
-	err=verify_area(VERIFY_WRITE, optlen, sizeof(int));
-	if(err)
-		return err;
-	put_user(sizeof(int), optlen);
-
-	err=verify_area(VERIFY_WRITE, optval, sizeof(int));
-	if(err)
-		return err;
-	put_user(val,(int *) optval);
-
-	return(0);
+	err = put_user(sizeof(int), optlen);
+	if (err) 
+		return err; 
+	return put_user(val,(int *) optval);
 }
diff -u --recursive --new-file v2.1.9/linux/net/ipv4/ipmr.c linux/net/ipv4/ipmr.c
--- v2.1.9/linux/net/ipv4/ipmr.c	Tue Oct 29 19:58:50 1996
+++ linux/net/ipv4/ipmr.c	Thu Nov 14 18:26:17 1996
@@ -447,11 +447,11 @@
 				return -EOPNOTSUPP;
 			if(optlen!=sizeof(int))
 				return -ENOPROTOOPT;
-			if((err=verify_area(VERIFY_READ,optval,sizeof(int)))<0)
-				return err;
 			{
 				int opt;
-				get_user(opt,(int *)optval);
+				err = get_user(opt,(int *)optval);
+				if (err) 
+					return err; 
 				if (opt != 1)
 					return -ENOPROTOOPT;
 			}
@@ -468,9 +468,9 @@
 		case MRT_DEL_VIF:
 			if(optlen!=sizeof(vif))
 				return -EINVAL;
-			if((err=verify_area(VERIFY_READ, optval, sizeof(vif)))<0)
-				return err;
-			copy_from_user(&vif,optval,sizeof(vif));
+			err = copy_from_user(&vif,optval,sizeof(vif));
+			if (err)
+				return -EFAULT; 
 			if(vif.vifc_vifi > MAXVIFS)
 				return -ENFILE;
 			if(optname==MRT_ADD_VIF)
@@ -545,17 +545,16 @@
 		 */
 		case MRT_ADD_MFC:
 		case MRT_DEL_MFC:
-			err=verify_area(VERIFY_READ, optval, sizeof(mfc));
-			if(err)
-				return err;
-			copy_from_user(&mfc,optval, sizeof(mfc));
-			return ipmr_mfc_modify(optname, &mfc);
+			err = copy_from_user(&mfc,optval, sizeof(mfc));
+			return err ? -EFAULT : ipmr_mfc_modify(optname, &mfc);
 		/*
 		 *	Control PIM assert.
 		 */
 		case MRT_ASSERT:
 			if(optlen!=sizeof(int))
 				return -EINVAL;
+
+			/* BUG BUG this is wrong IMHO -AK. */ 
 			if((err=verify_area(VERIFY_READ, optval,sizeof(int)))<0)
 				return err;
 			mroute_do_pim= (optval)?1:0;
@@ -583,18 +582,19 @@
 	if(optname!=MRT_VERSION && optname!=MRT_ASSERT)
 		return -EOPNOTSUPP;
 	
-	get_user(olr, optlen);
+	err = get_user(olr, optlen);
+	if (err)
+		return err; 
 	if(olr!=sizeof(int))
 		return -EINVAL;
-	err=verify_area(VERIFY_WRITE, optval,sizeof(int));
-	if(err)
-		return err;
-	put_user(sizeof(int),optlen);
+	err = put_user(sizeof(int),optlen);
+	if (err)
+		return err; 
 	if(optname==MRT_VERSION)
-		put_user(0x0305,(int *)optval);
+		err = put_user(0x0305,(int *)optval);
 	else
-		put_user(mroute_do_pim,(int *)optval);
-	return 0;
+		err = put_user(mroute_do_pim,(int *)optval);
+	return err;
 }
 
 /*
@@ -611,10 +611,9 @@
 	switch(cmd)
 	{
 		case SIOCGETVIFCNT:
-			err=verify_area(VERIFY_WRITE, (void *)arg, sizeof(vr));
-			if(err)
-				return err;
-			copy_from_user(&vr,(void *)arg,sizeof(vr));
+			err = copy_from_user(&vr,(void *)arg,sizeof(vr));
+			if (err)
+				return -EFAULT; 
 			if(vr.vifi>=MAXVIFS)
 				return -EINVAL;
 			vif=&vif_table[vr.vifi];
@@ -624,17 +623,19 @@
 				vr.ocount=vif->pkt_out;
 				vr.ibytes=vif->bytes_in;
 				vr.obytes=vif->bytes_out;
-				copy_to_user((void *)arg,&vr,sizeof(vr));
-				return 0;
+				err = copy_to_user((void *)arg,&vr,sizeof(vr));
+				if (err)
+					err = -EFAULT;
+				return err;
 			}
 			return -EADDRNOTAVAIL;
 		case SIOCGETSGCNT:
-			err=verify_area(VERIFY_WRITE, (void *)arg, sizeof(sr));
-			if(err)
-				return err;
-			copy_from_user(&sr,(void *)arg,sizeof(sr));
-			copy_to_user((void *)arg,&sr,sizeof(sr));
-			return 0;
+			err = copy_from_user(&sr,(void *)arg,sizeof(sr));
+			if (!err)
+				err = copy_to_user((void *)arg,&sr,sizeof(sr));
+			if (err)
+				err = -EFAULT;
+			return err;
 		default:
 			return -EINVAL;
 	}
diff -u --recursive --new-file v2.1.9/linux/net/ipv4/packet.c linux/net/ipv4/packet.c
--- v2.1.9/linux/net/ipv4/packet.c	Sun Nov 10 20:12:29 1996
+++ linux/net/ipv4/packet.c	Thu Nov 14 18:26:17 1996
@@ -120,7 +120,8 @@
 	struct device *dev;
 	struct sockaddr_pkt *saddr=(struct sockaddr_pkt *)msg->msg_name;
 	unsigned short proto=0;
-
+	int err;
+	
 	/*
 	 *	Check the flags. 
 	 */
@@ -180,18 +181,33 @@
 	 
 	skb->sk = sk;
 	skb->free = 1;
-	memcpy_fromiovec(skb_put(skb,len), msg->msg_iov, len);
-	skb->arp = 1;		/* No ARP needs doing on this (complete) frame */
+	err = memcpy_fromiovec(skb_put(skb,len), msg->msg_iov, len);
+	skb->arp = 1;	/* No ARP needs doing on this (complete) frame */
 	skb->protocol = proto;
 
 	/*
 	 *	Now send it
 	 */
 
-	if (dev->flags & IFF_UP) 
-		dev_queue_xmit(skb, dev, sk->priority);
+	if (err)
+	{
+		err = -EFAULT;
+	}
 	else
+	{
+		if (!(dev->flags & IFF_UP))
+		{
+			err = -ENODEV;
+		}
+	}
+	
+	if (err) 
+	{
 		kfree_skb(skb, FREE_WRITE);
+		return err;
+	}
+		
+	dev_queue_xmit(skb, dev, sk->priority);
 	return(len);
 }
 
@@ -436,7 +452,13 @@
 	 
 	copied = min(len, skb->len);
 
-	memcpy_toiovec(msg->msg_iov, skb->data, copied);	/* We can't use skb_copy_datagram here */
+	/* We can't use skb_copy_datagram here */
+	err = memcpy_toiovec(msg->msg_iov, skb->data, copied);
+	if (err)
+	{
+		return -EFAULT;
+	}
+
 	sk->stamp=skb->stamp;
 
 	/*
diff -u --recursive --new-file v2.1.9/linux/net/ipv4/rarp.c linux/net/ipv4/rarp.c
--- v2.1.9/linux/net/ipv4/rarp.c	Tue Nov 12 15:56:16 1996
+++ linux/net/ipv4/rarp.c	Thu Nov 14 18:26:17 1996
@@ -289,9 +289,12 @@
 	unsigned long ip;
 	struct rtable *rt;
 	struct device * dev;
+	int err; 
   
-	copy_from_user(&r, req, sizeof(r));
-  
+	err = copy_from_user(&r, req, sizeof(r));
+	if (err)
+		return -EFAULT;
+
 	/*
 	 *	We only understand about IP addresses... 
 	 */
@@ -390,13 +393,16 @@
 	struct rarp_table *entry;
 	struct sockaddr_in *si;
 	unsigned long ip;
-
+	int err; 
+	
 /*
  *	We only understand about IP addresses...
  */
         
-	copy_from_user(&r, req, sizeof(r));
-  
+	err = copy_from_user(&r, req, sizeof(r));
+	if (err)
+		return -EFAULT; 
+
 	if (r.arp_pa.sa_family != AF_INET)
 		return -EPFNOSUPPORT;
   
@@ -430,8 +436,7 @@
  *        Copy the information back
  */
   
-	copy_to_user(req, &r, sizeof(r));
-	return 0;
+	return copy_to_user(req, &r, sizeof(r));
 }
 
 
@@ -450,10 +455,9 @@
 		case SIOCDRARP:
 			if (!suser())
 				return -EPERM;
-			err = verify_area(VERIFY_READ, arg, sizeof(struct arpreq));
-			if(err)
-				return err;
-			copy_from_user(&r, arg, sizeof(r));
+			err = copy_from_user(&r, arg, sizeof(r));
+			if (err)
+				return -EFAULT; 
 			if (r.arp_pa.sa_family != AF_INET)
 				return -EPFNOSUPPORT;
 			si = (struct sockaddr_in *) &r.arp_pa;
@@ -461,16 +465,11 @@
 			return 0;
 
 		case SIOCGRARP:
-			err = verify_area(VERIFY_WRITE, arg, sizeof(struct arpreq));
-			if(err)
-				return err;
+
 			return rarp_req_get((struct arpreq *)arg);
 		case SIOCSRARP:
 			if (!suser())
 				return -EPERM;
-			err = verify_area(VERIFY_READ, arg, sizeof(struct arpreq));
-			if(err)
-				return err;
 			return rarp_req_set((struct arpreq *)arg);
 		default:
 			return -EINVAL;
diff -u --recursive --new-file v2.1.9/linux/net/ipv4/raw.c linux/net/ipv4/raw.c
--- v2.1.9/linux/net/ipv4/raw.c	Sun Nov 10 20:12:29 1996
+++ linux/net/ipv4/raw.c	Thu Nov 14 18:26:17 1996
@@ -161,18 +161,22 @@
  *	Callback support is trivial for SOCK_RAW
  */
   
-static void raw_getfrag(const void *p, __u32 saddr, char *to, unsigned int offset, unsigned int fraglen)
+static int raw_getfrag(const void *p, __u32 saddr, char *to,
+		       unsigned int offset, unsigned int fraglen)
 {
-	copy_from_user(to, (const unsigned char *)p+offset, fraglen);
+	return copy_from_user(to, (const unsigned char *)p+offset, fraglen);
 }
 
 /*
  *	IPPROTO_RAW needs extra work.
  */
  
-static void raw_getrawfrag(const void *p, __u32 saddr, char *to, unsigned int offset, unsigned int fraglen)
+static int raw_getrawfrag(const void *p, __u32 saddr, char *to, unsigned int offset, unsigned int fraglen)
 {
-	copy_from_user(to, (const unsigned char *)p+offset, fraglen);
+	int err; 
+	err = copy_from_user(to, (const unsigned char *)p+offset, fraglen);
+	if (err)
+		return err; 
 	if(offset==0)
 	{
 		struct iphdr *iph=(struct iphdr *)to;
@@ -189,6 +193,7 @@
 			iph->id = htons(ip_id_count++);
 		iph->check=ip_fast_csum((unsigned char *)iph, iph->ihl);
 	}
+	return 0; 
 }
 
 static int raw_sendto(struct sock *sk, const unsigned char *from, 
@@ -283,11 +288,17 @@
 		buf=kmalloc(len, GFP_KERNEL);
 		if(buf==NULL)
 			return -ENOBUFS;
-		memcpy_fromiovec(buf, msg->msg_iov, len);
-		fs=get_fs();
-		set_fs(get_ds());
-		err=raw_sendto(sk,buf,len, noblock, flags, msg->msg_name, msg->msg_namelen);
-		set_fs(fs);
+		err = memcpy_fromiovec(buf, msg->msg_iov, len);
+		if (!err)
+		{
+			fs=get_fs();
+			set_fs(get_ds());
+			err=raw_sendto(sk,buf,len, noblock, flags, msg->msg_name, msg->msg_namelen);
+			set_fs(fs);
+		}
+		else
+			err = -EFAULT;
+		
 		kfree_s(buf,len);
 		return err;
 	}
@@ -341,7 +352,7 @@
 
 	copied = min(len, skb->len);
 	
-	skb_copy_datagram_iovec(skb, 0, msg->msg_iov, copied);
+	err = skb_copy_datagram_iovec(skb, 0, msg->msg_iov, copied);
 	sk->stamp=skb->stamp;
 
 	/* Copy the address. */
@@ -351,7 +362,7 @@
 		sin->sin_addr.s_addr = skb->daddr;
 	}
 	skb_free_datagram(sk, skb);
-	return (copied);
+	return err ? err : (copied);
 }
 
 
diff -u --recursive --new-file v2.1.9/linux/net/ipv4/route.c linux/net/ipv4/route.c
--- v2.1.9/linux/net/ipv4/route.c	Tue Oct 29 19:58:50 1996
+++ linux/net/ipv4/route.c	Thu Nov 14 18:26:17 1996
@@ -1696,10 +1696,9 @@
 		case SIOCDELRT:		/* Delete a route */
 			if (!suser())
 				return -EPERM;
-			err=verify_area(VERIFY_READ, arg, sizeof(struct rtentry));
+			err = copy_from_user(&rt, arg, sizeof(struct rtentry));
 			if (err)
-				return err;
-			copy_from_user(&rt, arg, sizeof(struct rtentry));
+				return -EFAULT; 
 			return (cmd == SIOCDELRT) ? ip_rt_kill(&rt) : ip_rt_new(&rt);
 	}
 
diff -u --recursive --new-file v2.1.9/linux/net/ipv4/tcp.c linux/net/ipv4/tcp.c
--- v2.1.9/linux/net/ipv4/tcp.c	Tue Nov 12 15:56:16 1996
+++ linux/net/ipv4/tcp.c	Fri Nov 15 14:04:01 1996
@@ -658,7 +658,6 @@
 
 int tcp_ioctl(struct sock *sk, int cmd, unsigned long arg)
 {
-	int err;
 	switch(cmd)
 	{
 
@@ -675,21 +674,12 @@
 			lock_sock(sk);
 			amount = tcp_readable(sk);
 			release_sock(sk);
-			err=verify_area(VERIFY_WRITE,(void *)arg, sizeof(int));
-			if(err)
-				return err;
-			put_user(amount, (int *)arg);
-			return(0);
+			return put_user(amount, (int *)arg);
 		}
 		case SIOCATMARK:
 		{
 			int answ = sk->urg_data && sk->urg_seq == sk->copied_seq;
-
-			err = verify_area(VERIFY_WRITE,(void *) arg, sizeof(int));
-			if (err)
-				return err;
-			put_user(answ,(int *) arg);
-			return(0);
+			return put_user(answ,(int *) arg);
 		}
 		case TIOCOUTQ:
 		{
@@ -697,11 +687,7 @@
 
 			if (sk->state == TCP_LISTEN) return(-EINVAL);
 			amount = sock_wspace(sk);
-			err=verify_area(VERIFY_WRITE,(void *)arg, sizeof(int));
-			if(err)
-				return err;
-			put_user(amount, (int *)arg);
-			return(0);
+			return put_user(amount, (int *)arg);
 		}
 		default:
 			return(-EINVAL);
@@ -718,9 +704,9 @@
 	struct tcp_opt *tp=&(sk->tp_pinfo.af_tcp);
 	memcpy(th,(void *) &(sk->dummy_th), sizeof(*th));
 	th->seq = htonl(sk->write_seq);
-#if 0
+
 	th->psh =(push == 0) ? 1 : 0;
-#endif
+
 	sk->bytes_rcv = 0;
 	sk->ack_timed = 0;
 	th->ack_seq = htonl(tp->rcv_nxt);
@@ -986,7 +972,7 @@
 			{
 				tmp += copy;
 			}
-			
+
 			skb = sock_wmalloc(sk, tmp, 0, GFP_KERNEL);
 	
 			/*
@@ -1106,6 +1092,7 @@
 			struct msghdr *msg, int len, int flags, 
 			int *addr_len)
 {
+	int err; 
 	struct tcp_opt *tp = &(sk->tp_pinfo.af_tcp);
 
 	/*
@@ -1138,7 +1125,7 @@
 		char c = sk->urg_data;
 		if (!(flags & MSG_PEEK))
 			sk->urg_data = URG_READ;
-		memcpy_toiovec(msg->msg_iov, &c, 1);
+		err = memcpy_toiovec(msg->msg_iov, &c, 1);
 		if(msg->msg_name)
 		{
 			tp->af_specific->addr2sockaddr(sk, (struct sockaddr *)
@@ -1148,7 +1135,7 @@
 			*addr_len= tp->af_specific->sockaddr_len;
 
 		release_sock(sk);
-		return 1;
+		return err ? -EFAULT : 1;
 	}
 	release_sock(sk);
 
@@ -1226,6 +1213,7 @@
 	u32 peek_seq;
 	volatile u32 *seq;	/* So gcc doesn't overoptimise */
 	unsigned long used;
+	int err = 0; 
 
 	/*
 	 *	This error should be checked.
@@ -1274,6 +1262,8 @@
 			if (copied)
 				break;
 			copied = -ERESTARTSYS;
+			if (nonblock)
+				copied = -EAGAIN;
 			break;
 		}
 
@@ -1398,13 +1388,28 @@
 		*seq += used;
 
 		/*
-		 *	This memcpy_tofs can sleep. If it sleeps and we
+		 *	This memcpy_toiovec can sleep. If it sleeps and we
 		 *	do a second read it relies on the skb->users to avoid
 		 *	a crash when cleanup_rbuf() gets called.
 		 */
 
-		memcpy_toiovec(msg->msg_iov,((unsigned char *)skb->h.th) +
-			skb->h.th->doff*4 + offset, used);
+		/*
+		 *	FIXME: should break out of the loop early when an
+		 *	error occurs
+		 */
+		
+		err = memcpy_toiovec(msg->msg_iov, ((unsigned char *)skb->h.th) + skb->h.th->doff*4 + offset, used);
+		
+		if (err)
+		{
+			/*
+			 *	exception. bailout!
+			 */
+			*seq -= err;
+			skb->users--;
+			return -EFAULT;
+		}
+
 		copied += used;
 		len -= used;
 
@@ -1414,7 +1419,7 @@
 		 *	but you'll just have to fix it neatly ;)
 		 */
 
-		skb->users --;
+		skb->users--;
 
 		if (after(sk->copied_seq,sk->urg_seq))
 			sk->urg_data = 0;
@@ -1824,17 +1829,12 @@
 		default:
 			return(-ENOPROTOOPT);
 	}
-	err=verify_area(VERIFY_WRITE, optlen, sizeof(int));
-	if(err)
-  		return err;
-  	put_user(sizeof(int),(int *) optlen);
-
-  	err=verify_area(VERIFY_WRITE, optval, sizeof(int));
-  	if(err)
-  		return err;
-  	put_user(val,(int *)optval);
 
-  	return(0);
+  	err = put_user(sizeof(int),(int *) optlen);
+	if (!err)
+		err = put_user(val,(int *)optval);
+
+  	return err;
 }
 
 void tcp_set_keepalive(struct sock *sk, int val)
@@ -1847,6 +1847,104 @@
 	{
 		tcp_dec_slow_timer(TCP_SLT_KEEPALIVE);
 	}
+}
+
+
+/*
+ *      This function returns the amount that we can raise the
+ *      usable window based on the following constraints
+ *  
+ *	1. The window can never be shrunk once it is offered (RFC 793)
+ *	2. We limit memory per socket
+ */
+
+
+unsigned short tcp_select_window(struct sock *sk)
+{
+	struct tcp_opt *tp = &sk->tp_pinfo.af_tcp;
+	long free_space = sock_rspace(sk);
+	long window;
+	long cur_win;
+	long usable;
+	int mss = sk->mss;
+	
+	if (sk->window_clamp)
+	{
+		free_space = min(sk->window_clamp, free_space);
+		mss = min(sk->window_clamp, mss);
+	}
+	
+	/*
+	 * compute the actual window i.e.
+	 * old_window - received_bytes_on_that_win
+	 */
+
+	cur_win = tp->rcv_wup - (tp->rcv_nxt - tp->rcv_wnd);
+	window  = tp->rcv_wnd;
+	
+	if ( cur_win < 0 )
+	{
+		cur_win = 0;
+		printk(KERN_DEBUG "TSW: win < 0 w=%d 1=%u 2=%u\n",
+		       tp->rcv_wnd, tp->rcv_nxt, tp->rcv_wup);
+	}
+
+	/*
+	 * RFC 1122:
+	 * "the suggested [SWS] avoidance algoritm for the receiver is to keep
+	 *  RECV.NEXT + RCV.WIN fixed until:
+	 *  RCV.BUFF - RCV.USER - RCV.WINDOW >= min(1/2 RCV.BUFF, MSS)"
+	 *
+	 * i.e. don't raise the right edge of the window until you can't raise
+	 * it MSS bytes
+	 */
+
+	/*
+	 * It would be a good idea if it didn't break header prediction.
+	 * and BSD made the header predition standard...
+	 * It expects the same value in the header i.e. th->window to be
+	 * constant
+	 */
+
+	usable = free_space - cur_win;
+	if (usable < 0)
+	{
+		usable = 0;
+	}
+
+	if ( window <  usable )
+	{
+		/*
+		 *	Window is not blocking the sender
+		 *	and we have enought free space for it
+		 */
+
+		if (cur_win > (sk->mss << 1))
+			goto out;
+	}
+
+       	
+	if (window >= usable)
+	{
+		/*
+		 *	We are offering too much, cut it down... 
+		 *	but don't shrink the window
+		 */
+		
+		window = max(usable, cur_win);
+	}
+	else
+	{	
+		if ((usable - window) >= mss)
+		{
+			window += mss;
+		}
+	}
+
+  out:
+	tp->rcv_wnd = window;
+	tp->rcv_wup = tp->rcv_nxt;
+	return window;
 }
 
 /*
diff -u --recursive --new-file v2.1.9/linux/net/ipv4/tcp_input.c linux/net/ipv4/tcp_input.c
--- v2.1.9/linux/net/ipv4/tcp_input.c	Sun Nov 10 20:12:29 1996
+++ linux/net/ipv4/tcp_input.c	Wed Nov 13 07:59:31 1996
@@ -194,11 +194,18 @@
 	/*
 	 *	We want the right error as BSD sees it (and indeed as we do).
 	 */
-	sk->err = ECONNRESET;
-	if (sk->state == TCP_SYN_SENT)
-		sk->err = ECONNREFUSED;
-	if (sk->state == TCP_CLOSE_WAIT)
-		sk->err = EPIPE;
+	switch (sk->state) {
+		case TCP_TIME_WAIT:
+			break;
+		case TCP_SYN_SENT:
+			sk->err = ECONNREFUSED;
+			break;
+		case TCP_CLOSE_WAIT:
+			sk->err = EPIPE;
+			break;
+		default:
+			sk->err = ECONNRESET;
+	}
 #ifdef CONFIG_TCP_RFC1337
 	/*
 	 *	Time wait assassination protection [RFC1337]
diff -u --recursive --new-file v2.1.9/linux/net/ipv4/udp.c linux/net/ipv4/udp.c
--- v2.1.9/linux/net/ipv4/udp.c	Sun Nov 10 20:12:30 1996
+++ linux/net/ipv4/udp.c	Thu Nov 14 18:26:17 1996
@@ -227,14 +227,14 @@
  *	for direct user->board I/O transfers. That one will be fun.
  */
  
-static void udp_getfrag(const void *p, __u32 saddr, char * to, unsigned int offset, unsigned int fraglen) 
+static int udp_getfrag(const void *p, __u32 saddr, char * to, unsigned int offset, unsigned int fraglen) 
 {
 	struct udpfakehdr *ufh = (struct udpfakehdr *)p;
 	const char *src;
 	char *dst;
 	unsigned int len;
 
-	if (offset) 
+	if (offset)
 	{
 		len = fraglen;
 	 	src = ufh->from+(offset-sizeof(struct udphdr));
@@ -258,6 +258,7 @@
 			ufh->uh.check = -1;
 		memcpy(to, ufh, sizeof(struct udphdr));
 	}
+	return 0;
 }
 
 /*
@@ -267,12 +268,13 @@
  *	this is a valid decision.
  */
  
-static void udp_getfrag_nosum(const void *p, __u32 saddr, char * to, unsigned int offset, unsigned int fraglen) 
+static int udp_getfrag_nosum(const void *p, __u32 saddr, char * to, unsigned int offset, unsigned int fraglen) 
 {
 	struct udpfakehdr *ufh = (struct udpfakehdr *)p;
 	const char *src;
 	char *dst;
 	unsigned int len;
+	int err; 
 
 	if (offset) 
 	{
@@ -286,9 +288,10 @@
  		src = ufh->from;
 		dst = to+sizeof(struct udphdr);
 	}
-	copy_from_user(dst,src,len);
+	err = copy_from_user(dst,src,len);
 	if (offset == 0) 
 		memcpy(to, ufh, sizeof(struct udphdr));
+	return err; 
 }
 
 
@@ -458,11 +461,16 @@
 		buf=kmalloc(len, GFP_KERNEL);
 		if(buf==NULL)
 			return -ENOBUFS;
-		memcpy_fromiovec(buf, msg->msg_iov, len);
-		fs=get_fs();
-		set_fs(get_ds());
-		err=udp_sendto(sk,buf,len, noblock, flags, msg->msg_name, msg->msg_namelen);
-		set_fs(fs);
+		err = memcpy_fromiovec(buf, msg->msg_iov, len);
+		if (err)
+			err = -EFAULT;
+		if (!err)
+		{
+			fs=get_fs();
+			set_fs(get_ds());
+			err=udp_sendto(sk,buf,len, noblock, flags, msg->msg_name, msg->msg_namelen);
+			set_fs(fs);
+		}
 		kfree_s(buf,len);
 		return err;
 	}
@@ -474,7 +482,6 @@
  
 int udp_ioctl(struct sock *sk, int cmd, unsigned long arg)
 {
-	int err;
 	switch(cmd) 
 	{
 		case TIOCOUTQ:
@@ -483,12 +490,7 @@
 
 			if (sk->state == TCP_LISTEN) return(-EINVAL);
 			amount = sock_wspace(sk);
-			err=verify_area(VERIFY_WRITE,(void *)arg,
-					sizeof(unsigned long));
-			if(err)
-				return(err);
-			put_user(amount, (int *)arg);
-			return(0);
+			return put_user(amount, (int *)arg);
 		}
 
 		case TIOCINQ:
@@ -507,12 +509,7 @@
 				 */
 				amount = skb->len-sizeof(struct udphdr);
 			}
-			err=verify_area(VERIFY_WRITE,(void *)arg,
-						sizeof(unsigned long));
-			if(err)
-				return(err);
-			put_user(amount, (int *)arg);
-			return(0);
+			return put_user(amount, (int *)arg);
 		}
 
 		default:
@@ -559,7 +556,9 @@
   	 *	FIXME : should use udp header size info value 
   	 */
   	 
-	skb_copy_datagram_iovec(skb,sizeof(struct udphdr),msg->msg_iov,copied);
+	er = skb_copy_datagram_iovec(skb,sizeof(struct udphdr),msg->msg_iov,copied);
+	if (er)
+		return er; 
 	sk->stamp=skb->stamp;
 
 	/* Copy the address. */
diff -u --recursive --new-file v2.1.9/linux/net/ipv6/Makefile linux/net/ipv6/Makefile
--- v2.1.9/linux/net/ipv6/Makefile	Sun Nov 10 20:12:30 1996
+++ linux/net/ipv6/Makefile	Wed Nov 13 11:07:41 1996
@@ -13,6 +13,7 @@
 	    protocol.o icmp.o mcast.o reassembly.o tcp_ipv6.o \
 	    exthdrs.o sysctl_net_ipv6.o datagram.o
 
+MOD_LIST_NAME := IPV6_MODULES
 M_OBJS   := $(O_TARGET)
 
 include $(TOPDIR)/Rules.make
diff -u --recursive --new-file v2.1.9/linux/net/ipv6/addrconf.c linux/net/ipv6/addrconf.c
--- v2.1.9/linux/net/ipv6/addrconf.c	Tue Nov 12 15:56:16 1996
+++ linux/net/ipv6/addrconf.c	Thu Nov 14 18:26:17 1996
@@ -774,7 +774,7 @@
 
 }
 
-static void addrconf_ifdown(struct device *dev)
+static int addrconf_ifdown(struct device *dev)
 {
 	struct inet6_dev *idev, **bidev;
 	struct inet6_ifaddr *ifa, **bifa;
@@ -796,8 +796,9 @@
 
 	if (idev == NULL)
 	{
-		printk(KERN_DEBUG "addrconf_ifdown: device not found\n"); 
-		return;
+		printk(KERN_DEBUG "addrconf_ifdown: device not found\n");
+		end_bh_atomic();
+		return -ENODEV;
 	}
 	
 	/*
@@ -828,6 +829,7 @@
 
 	kfree(idev);
 	end_bh_atomic();
+	return 0;
 }
 
 /*
@@ -1024,9 +1026,12 @@
 		 *	Remove all addresses from this interface
 		 *	and take the interface out of the list.
 		 */
-		addrconf_ifdown(dev);
-		rt6_ifdown(dev);
-		rt6_sndmsg(RTMSG_NEWDEVICE, NULL, NULL, 0, 0, dev->name, 0);
+		if (addrconf_ifdown(dev) == 0)
+		{
+			rt6_ifdown(dev);
+			rt6_sndmsg(RTMSG_NEWDEVICE, NULL, NULL, 0, 0,
+				   dev->name, 0);
+		}
 
 		break;
 	}
diff -u --recursive --new-file v2.1.9/linux/net/ipv6/af_inet6.c linux/net/ipv6/af_inet6.c
--- v2.1.9/linux/net/ipv6/af_inet6.c	Sun Nov 10 20:12:30 1996
+++ linux/net/ipv6/af_inet6.c	Thu Nov 14 18:26:17 1996
@@ -107,7 +107,7 @@
 	struct proto *prot;
 	int err;
 
-	sk = (struct sock *) kmalloc(sizeof(*sk), GFP_KERNEL);
+	sk = sk_alloc(GFP_KERNEL);
 	if (sk == NULL) 
 		return(-ENOBUFS);
 
diff -u --recursive --new-file v2.1.9/linux/net/ipv6/icmp.c linux/net/ipv6/icmp.c
--- v2.1.9/linux/net/ipv6/icmp.c	Sun Nov 10 20:12:30 1996
+++ linux/net/ipv6/icmp.c	Thu Nov 14 18:26:17 1996
@@ -15,6 +15,12 @@
  *      2 of the License, or (at your option) any later version.
  */
 
+/*
+ *	Changes:
+ *
+ *	Andi Kleen		:	exception handling
+ */
+
 #define __NO_VERSION__
 #include <linux/module.h>
 #include <linux/errno.h>
@@ -95,7 +101,7 @@
  *	not static because it's needed in ndisc.c
  */
 
-static void icmpv6_getfrag(const void *data, struct in6_addr *saddr, 
+static int icmpv6_getfrag(const void *data, struct in6_addr *saddr, 
 			   char *buff, unsigned int offset, unsigned int len)
 {
 	struct icmpv6_msg *msg = (struct icmpv6_msg *) data;
@@ -114,7 +120,7 @@
 					 offset - sizeof(struct icmpv6hdr), 
 					 buff, len, msg->csum);
 		msg->csum = csum;
-		return;
+		return 0;
 	}
 
 	csum = csum_partial_copy((void *) &msg->icmph, buff,
@@ -128,6 +134,7 @@
 
 	icmph->checksum = csum_ipv6_magic(saddr, msg->daddr, msg->len,
 					  IPPROTO_ICMPV6, csum);
+	return 0; 
 }
 
 /*
diff -u --recursive --new-file v2.1.9/linux/net/ipv6/ipv6_output.c linux/net/ipv6/ipv6_output.c
--- v2.1.9/linux/net/ipv6/ipv6_output.c	Tue Nov 12 15:56:16 1996
+++ linux/net/ipv6/ipv6_output.c	Thu Nov 14 18:26:17 1996
@@ -15,6 +15,11 @@
  *      2 of the License, or (at your option) any later version.
  */
 
+/*
+ *	Changes:
+ *
+ *	Andi Kleen		:	exception handling
+ */
 
 #include <linux/errno.h>
 #include <linux/types.h>
@@ -440,7 +445,7 @@
 	int	pktlength;
 	int	pmtu = 0;
 	int	rt_flags = 0;
-	
+	int	error; 
 	
 	if (opt && opt->srcrt)
 	{
@@ -568,8 +573,6 @@
 
 	if (pktlength <= pmtu) 
 	{
-		int error;
-
 		struct sk_buff *skb =
 			sock_alloc_send_skb(sk, pktlength+15+
 					    dev->hard_header_len,
@@ -624,14 +627,22 @@
 		}
 			
 		skb_put(skb, length);
-		getfrag(data, &hdr->saddr,
-			((char *) hdr) + (pktlength - length), 0, length);
+		error = getfrag(data, &hdr->saddr,
+				((char *) hdr) + (pktlength - length),
+				0, length);
 			
-		ipv6_statistics.Ip6OutRequests++;
-		(*output_method)(skb, (struct rt6_info *) dc);
+		if (!error) 
+		{
+			ipv6_statistics.Ip6OutRequests++;
+			(*output_method)(skb, (struct rt6_info *) dc);
+		} else
+		{
+			error = -EFAULT;
+			kfree_skb(skb, FREE_WRITE);			
+		}
 
 		dev_unlock_list();
-		return 0;
+		return error;
 	}
 	else
 	{
@@ -763,31 +774,52 @@
 
 		fhdr_dist = (unsigned char *) fhdr - last_skb->data;
 
-		getfrag(data, &hdr->saddr, last_skb->tail, nfrags * frag_len, 
-			last_len);
+		error = getfrag(data, &hdr->saddr, last_skb->tail,
+				nfrags * frag_len, last_len);
 		
-		while (nfrags--)
-		{
-			struct sk_buff *skb;
-
-			struct frag_hdr *fhdr2;
-
-			printk(KERN_DEBUG "sending frag %d\n", nfrags);
-			skb = skb_copy(last_skb, sk->allocation);
-
-			fhdr2 = (struct frag_hdr *) (skb->data + fhdr_dist);
-			/* more flag on */
-			fhdr2->frag_off = ntohs(nfrags * frag_len + 1);
-
-			/* if (nfrags == 0)
-			   put rest of headers
-			   */
+		if (!error)
+		{	
+			while (nfrags--)
+			{
+				struct sk_buff *skb;
+			
+				struct frag_hdr *fhdr2;
+				
+				printk(KERN_DEBUG "sending frag %d\n", nfrags);
+				skb = skb_copy(last_skb, sk->allocation);
+				
+				fhdr2 = (struct frag_hdr *)
+					(skb->data + fhdr_dist);
+				
+				/* more flag on */
+				fhdr2->frag_off = ntohs(nfrags * frag_len + 1);
+				
+				/*
+				 *	FIXME:
+				 *	if (nfrags == 0)
+				 *	put rest of headers
+				 */
+				
+				error = getfrag(data, &hdr->saddr,
+						skb_put(skb, frag_len), 
+						nfrags * frag_len, frag_len);
+			
+				if (error)
+				{
+					kfree_skb(skb, FREE_WRITE);
+					break;
+				}
 
-			getfrag(data, &hdr->saddr, skb_put(skb, frag_len), 
-				nfrags * frag_len, frag_len);
+				ipv6_statistics.Ip6OutRequests++;
+				(*output_method)(skb, (struct rt6_info *) dc);
+			}
+		}
 
-			ipv6_statistics.Ip6OutRequests++;
-			(*output_method)(skb, (struct rt6_info *) dc);
+		if (error)
+		{
+			kfree_skb(last_skb, FREE_WRITE);
+			dev_unlock_list();
+			return -EFAULT;
 		}
 
 		printk(KERN_DEBUG "sending last frag \n");
diff -u --recursive --new-file v2.1.9/linux/net/ipv6/ipv6_sockglue.c linux/net/ipv6/ipv6_sockglue.c
--- v2.1.9/linux/net/ipv6/ipv6_sockglue.c	Tue Nov 12 15:56:16 1996
+++ linux/net/ipv6/ipv6_sockglue.c	Thu Nov 14 18:26:17 1996
@@ -164,10 +164,6 @@
 	{
 		struct in6_addr addr;
 
-		err=verify_area(VERIFY_READ, optval, sizeof(struct in6_addr));
-		if(err)
-			return err;
-
 		err = copy_from_user(&addr, optval, sizeof(struct in6_addr));
 		if(err)
 			return -EFAULT;
diff -u --recursive --new-file v2.1.9/linux/net/ipv6/raw.c linux/net/ipv6/raw.c
--- v2.1.9/linux/net/ipv6/raw.c	Sun Nov 10 20:12:31 1996
+++ linux/net/ipv6/raw.c	Thu Nov 14 18:26:17 1996
@@ -124,9 +124,12 @@
 	
 	copied = min(len, skb->tail - skb->h.raw);
 	
-	skb_copy_datagram_iovec(skb, 0, msg->msg_iov, copied);
+	err = skb_copy_datagram_iovec(skb, 0, msg->msg_iov, copied);
 	sk->stamp=skb->stamp;
 
+	if (err)
+		return err;
+
 	/* Copy the address. */
 	if (sin6) 
 	{
@@ -166,15 +169,15 @@
 	struct in6_addr *daddr;
 };
 
-static void rawv6_getfrag(const void *data, struct in6_addr *saddr, 
+static int rawv6_getfrag(const void *data, struct in6_addr *saddr, 
 			  char *buff, unsigned int offset, unsigned int len)
 {
 	struct iovec *iov = (struct iovec *) data;
 
-	memcpy_fromiovecend(buff, iov, offset, len);
+	return memcpy_fromiovecend(buff, iov, offset, len);
 }
 
-static void rawv6_frag_cksum(const void *data, struct in6_addr *addr,
+static int rawv6_frag_cksum(const void *data, struct in6_addr *addr,
 			     char *buff, unsigned int offset, 
 			     unsigned int len)
 {
@@ -220,6 +223,7 @@
 			printk(KERN_DEBUG "icmp: cksum offset too big\n");
 		}
 	}	
+	return 0; 
 }
 
 
@@ -354,8 +358,10 @@
 
 	switch (optname) {
 		case ICMPV6_FILTER:
-			copy_from_user(&opt->filter, optval,
+			err = copy_from_user(&opt->filter, optval,
 				       sizeof(struct icmp6_filter));
+			if (err)
+				err = -EFAULT;
 			break;
 		default:
 			err = -ENOPROTOOPT;
diff -u --recursive --new-file v2.1.9/linux/net/ipv6/udp.c linux/net/ipv6/udp.c
--- v2.1.9/linux/net/ipv6/udp.c	Tue Nov 12 15:56:16 1996
+++ linux/net/ipv6/udp.c	Thu Nov 14 18:26:18 1996
@@ -172,7 +172,7 @@
   	int copied = 0;
   	int truesize;
   	struct sk_buff *skb;
-  	int er;
+  	int err;
   	
 
 	/*
@@ -187,9 +187,9 @@
 	 *	the finished NET3, it will do _ALL_ the work!
 	 */
 	 	
-	skb = skb_recv_datagram(sk, flags, noblock, &er);
+	skb = skb_recv_datagram(sk, flags, noblock, &err);
 	if(skb==NULL)
-  		return er;
+  		return err;
   
   	truesize = skb->tail - skb->h.raw - sizeof(struct udphdr);
   	copied = min(len, truesize);
@@ -198,7 +198,11 @@
   	 *	FIXME : should use udp header size info value 
   	 */
   	 
-	skb_copy_datagram_iovec(skb,sizeof(struct udphdr),msg->msg_iov,copied);
+	err = skb_copy_datagram_iovec(skb, sizeof(struct udphdr), 
+				      msg->msg_iov, copied);
+	if (err)
+		return err; 
+	
 	sk->stamp=skb->stamp;
 
 	/* Copy the address. */
@@ -428,8 +432,8 @@
  *	with checksum
  */
 
-static void udpv6_getfrag(const void *data, struct in6_addr *addr,
-			  char *buff, unsigned int offset, unsigned int len)
+static int udpv6_getfrag(const void *data, struct in6_addr *addr,
+			 char *buff, unsigned int offset, unsigned int len)
 {
 	struct udpv6fakehdr *udh = (struct udpv6fakehdr *) data;
 	char *dst;
@@ -479,6 +483,7 @@
 
 		memcpy(buff, udh, sizeof(struct udphdr));
 	}
+	return 0;
 }
 
 static int udpv6_sendmsg(struct sock *sk, struct msghdr *msg, int ulen, 
diff -u --recursive --new-file v2.1.9/linux/net/ipx/af_ipx.c linux/net/ipx/af_ipx.c
--- v2.1.9/linux/net/ipx/af_ipx.c	Tue Oct 29 19:58:50 1996
+++ linux/net/ipx/af_ipx.c	Thu Nov 14 18:26:18 1996
@@ -141,8 +141,7 @@
 	
 	vals.ipxcfg_auto_create_interfaces = ipxcfg_auto_create_interfaces;
 	vals.ipxcfg_auto_select_primary = ipxcfg_auto_select_primary;
-	copy_to_user(arg, &vals, sizeof(vals));
-	return 0;
+	return copy_to_user(arg, &vals, sizeof(vals));
 }
 
 
@@ -1062,7 +1061,8 @@
 			struct sockaddr_ipx *sipx;
 			ipx_interface *ipxif;
 			struct device *dev;
-
+			int err;
+			
 			if (copy_from_user(&ifr,arg,sizeof(ifr)))
 				return -EFAULT;
 			sipx=(struct sockaddr_ipx *)&ifr.ifr_addr;
@@ -1075,9 +1075,10 @@
 			sipx->sipx_family=AF_IPX;
 			sipx->sipx_network=ipxif->if_netnum;
 			memcpy(sipx->sipx_node, ipxif->if_node, sizeof(sipx->sipx_node));
-			if (copy_to_user(arg,&ifr,sizeof(ifr)))
+			err = copy_to_user(arg,&ifr,sizeof(ifr));
+			if (err)
 				return -EFAULT;
-			return 0;
+			return err;
 		}
 		case SIOCAIPXITFCRT: {
 			int err, val;
@@ -1333,7 +1334,12 @@
 	memcpy(ipx->ipx_dest.node,usipx->sipx_node,IPX_NODE_LEN);
 	ipx->ipx_dest.sock=usipx->sipx_port;
 
-	memcpy_fromiovec(skb_put(skb,len),iov,len);
+	err = memcpy_fromiovec(skb_put(skb,len),iov,len);
+	if (err) 
+	{
+		kfree_skb(skb, FREE_WRITE);
+		return -EFAULT; 
+	}	
 
 	/*
 	 *	Apply checksum. Not allowed on 802.3 links.
@@ -1384,13 +1390,11 @@
 	int err;
 	struct rtentry rt;	/* Use these to behave like 'other' stacks */
 	struct sockaddr_ipx *sg,*st;
-
-	err=verify_area(VERIFY_READ,arg,sizeof(rt));
-	if(err)
-		return err;
 		
-	copy_from_user(&rt,arg,sizeof(rt));
-	
+	err = copy_from_user(&rt,arg,sizeof(rt));
+	if (err)
+		return -EFAULT; 
+
 	sg=(struct sockaddr_ipx *)&rt.rt_gateway;
 	st=(struct sockaddr_ipx *)&rt.rt_dst;
 	
@@ -1677,14 +1681,10 @@
 		default:
 			return -EOPNOTSUPP;
 	}
-	err=verify_area(VERIFY_WRITE,optlen,sizeof(int));
-	if(err)
-		return err;
-	put_user(sizeof(int), optlen);
-	err=verify_area(VERIFY_WRITE,optval,sizeof(int));
-	if (err) return err;
-	put_user(val, (int *)optval);
-	return(0);
+	err = put_user(sizeof(int), optlen);
+	if (!err)
+		err = put_user(val, (int *)optval);
+	return err;
 }
 
 static int ipx_listen(struct socket *sock, int backlog)
@@ -2168,8 +2168,11 @@
 	ipx = (ipx_packet *)(skb->h.raw);
 	truesize=ntohs(ipx->ipx_pktsize) - sizeof(ipx_packet);
 	copied = (truesize > size) ? size : truesize;
-	skb_copy_datagram_iovec(skb,sizeof(struct ipx_packet),msg->msg_iov,copied);
+	err = skb_copy_datagram_iovec(skb,sizeof(struct ipx_packet),msg->msg_iov,copied);
 	
+	if (err)
+		return err; 
+
 	if(sipx)
 	{
 		sipx->sipx_family=AF_IPX;
@@ -2203,25 +2206,17 @@
 	switch(cmd)
 	{
 		case TIOCOUTQ:
-			err=verify_area(VERIFY_WRITE,(void *)arg,sizeof(int));
-			if(err)
-				return err;
 			amount=sk->sndbuf-sk->wmem_alloc;
 			if(amount<0)
 				amount=0;
-			put_user(amount, (int *)arg);
-			return 0;
+			return put_user(amount, (int *)arg);
 		case TIOCINQ:
 		{
 			struct sk_buff *skb;
 			/* These two are safe on a single CPU system as only user tasks fiddle here */
 			if((skb=skb_peek(&sk->receive_queue))!=NULL)
 				amount=skb->len-sizeof(struct ipx_packet);
-			err=verify_area(VERIFY_WRITE,(void *)arg,sizeof(int));
-			if(err)
-				return err;
-			put_user(amount, (int *)arg);
-			return 0;
+			return put_user(amount, (int *)arg);
 		}
 		case SIOCADDRT:
 		case SIOCDELRT:
@@ -2237,23 +2232,21 @@
 			return(ipxitf_ioctl(cmd,(void *)arg));
 		case SIOCIPXCFGDATA: 
 		{
-			err=verify_area(VERIFY_WRITE,(void *)arg,
-				sizeof(ipx_config_data));
-			if(err) return err;
 			return(ipxcfg_get_config_data((void *)arg));
 		}
 		case SIOCGSTAMP:
+		{
+			int ret = -EINVAL;
 			if (sk)
 			{
 				if(sk->stamp.tv_sec==0)
 					return -ENOENT;
-				err=verify_area(VERIFY_WRITE,(void *)arg,sizeof(struct timeval));
-				if(err)
-					return err;
-				copy_to_user((void *)arg,&sk->stamp,sizeof(struct timeval));
-				return 0;
+				ret = copy_to_user((void *)arg,&sk->stamp,sizeof(struct timeval));
+				if (ret)
+					ret = -EFAULT;
 			}
-			return -EINVAL;
+			return 0;
+		}
 		case SIOCGIFDSTADDR:
 		case SIOCSIFDSTADDR:
 		case SIOCGIFBRDADDR:
diff -u --recursive --new-file v2.1.9/linux/net/netlink.c linux/net/netlink.c
--- v2.1.9/linux/net/netlink.c	Sun Nov 10 20:12:31 1996
+++ linux/net/netlink.c	Thu Nov 14 18:26:16 1996
@@ -85,12 +85,13 @@
 static long netlink_write(struct inode * inode, struct file * file,
 			  const char * buf, unsigned long count)
 {
+	int err; 
 	unsigned int minor = MINOR(inode->i_rdev);
 	struct sk_buff *skb;
 	skb=alloc_skb(count, GFP_KERNEL);
 	skb->free=1;
-	copy_from_user(skb_put(skb,count),buf, count);
-	return (netlink_handler[minor])(skb);
+	err = copy_from_user(skb_put(skb,count),buf, count);
+	return err ? -EFAULT : (netlink_handler[minor])(skb);
 }
 
 /*
@@ -100,6 +101,7 @@
 static long netlink_read(struct inode * inode, struct file * file, char * buf,
 			 unsigned long count)
 {
+	int err; 
 	unsigned int minor = MINOR(inode->i_rdev);
 	struct sk_buff *skb;
 	cli();
@@ -121,9 +123,9 @@
 	sti();
 	if(skb->len<count)
 		count=skb->len;
-	copy_to_user(buf,skb->data,count);
+	err = copy_to_user(buf,skb->data,count);
 	kfree_skb(skb, FREE_READ);
-	return count;
+	return err ? -EFAULT : count;
 }
 
 static loff_t netlink_lseek(struct inode * inode, struct file * file,
diff -u --recursive --new-file v2.1.9/linux/net/socket.c linux/net/socket.c
--- v2.1.9/linux/net/socket.c	Tue Nov 12 15:56:17 1996
+++ linux/net/socket.c	Thu Nov 14 18:26:16 1996
@@ -159,8 +159,7 @@
 		if(copy_to_user(uaddr,kaddr,len))
 			return -EFAULT;
 	}
- 	put_user(len, ulen);
- 	return 0;
+ 	return put_user(len, ulen);
 }
 
 /*
@@ -649,17 +648,14 @@
 	sock1->state = SS_CONNECTED;
 	sock2->state = SS_CONNECTED;
 
-	er=verify_area(VERIFY_WRITE, usockvec, sizeof(usockvec));
-	if(er)
-	{
+	er = put_user(fd1, &usockvec[0]); 
+	if (!er) 
+		er = put_user(fd2, &usockvec[1]);
+	if (er) {
 		sys_close(fd1);
 		sys_close(fd2);
-	 	return er;
 	}
-	put_user(fd1, &usockvec[0]);
-	put_user(fd2, &usockvec[1]);
-
-	return(0);
+	return er;
 }
 
 
@@ -1133,12 +1129,8 @@
 	if(sock->ops->sendmsg==NULL)
 		return -EOPNOTSUPP;
 
-
-	err=verify_area(VERIFY_READ, msg,sizeof(struct msghdr));
-	if(err)
-		return err;
-
-	copy_from_user(&msg_sys,msg,sizeof(struct msghdr));
+	if ((err = copy_from_user(&msg_sys,msg,sizeof(struct msghdr))))
+		return -EFAULT; 
 
 	/* do not move before msg_sys is valid */
 	if(msg_sys.msg_iovlen>UIO_MAXIOV)
@@ -1200,11 +1192,8 @@
 	if (!(sock = sockfd_lookup(fd, NULL)))
 		return(-ENOTSOCK);
 	
-	err=verify_area(VERIFY_READ, msg,sizeof(struct msghdr));
-	if(err)
-		return err;
-
-	copy_from_user(&msg_sys,msg,sizeof(struct msghdr));
+	if ((err = copy_from_user(&msg_sys,msg,sizeof(struct msghdr))))
+		return -EFAULT; 
 
 	if(msg_sys.msg_iovlen>UIO_MAXIOV)
 		return -EINVAL;
@@ -1240,19 +1229,24 @@
 	if(len<0)
 		return len;
 
-	if (uaddr != NULL) {
+	if (uaddr != NULL)
+	{
 		err = move_addr_to_user(addr, addr_len, uaddr, uaddr_len);
-		if (err)
-			return err;
 	}
 
 	if (msg_sys.msg_control)
 	{
-		copy_to_user(usr_msg_ctl, krn_msg_ctl, msg_sys.msg_controllen);
-		kfree(krn_msg_ctl);
+		if (!err)
+		{
+			int ret;
+			ret = copy_to_user(usr_msg_ctl, krn_msg_ctl,
+					   msg_sys.msg_controllen);
+			err = -EFAULT;
+		}
+		kfree(krn_msg_ctl);		
 	}
 
-	return len;
+	return err ? err : len;
 }
 
 
@@ -1285,7 +1279,6 @@
 
 asmlinkage int sys_socketcall(int call, unsigned long *args)
 {
-	int er;
 	unsigned char nargs[18]={0,3,3,3,2,3,3,3,
 				 4,4,4,6,6,2,5,5,3,3};
 	unsigned long a[6];
@@ -1294,10 +1287,8 @@
 	if(call<1||call>SYS_RECVMSG)
 		return -EINVAL;
 		
-	er=verify_area(VERIFY_READ, args, nargs[call] * sizeof(unsigned long));
-	if(er)
-		return er;
-	copy_from_user(a, args, nargs[call] * sizeof(unsigned long));
+	if ((copy_from_user(a, args, nargs[call] * sizeof(unsigned long))))
+		return -EFAULT;
 		
 	a0=a[0];
 	a1=a[1];
diff -u --recursive --new-file v2.1.9/linux/net/unix/af_unix.c linux/net/unix/af_unix.c
--- v2.1.9/linux/net/unix/af_unix.c	Sun Nov 10 20:12:31 1996
+++ linux/net/unix/af_unix.c	Thu Nov 14 18:26:18 1996
@@ -925,7 +925,15 @@
 			}
 			return err;
 		}
-		size=skb_tailroom(skb);		/* If we dropped back on a limit then our skb is smaller */
+
+		/*
+		 *	If you pass two values to the sock_alloc_send_skb
+		 *	it tries to grab the large buffer with GFP_BUFFER
+		 *	(which can fail easily), and if it fails grab the
+		 *	fallback size buffer which is under a page and will
+		 *	succeed. [Alan]
+		 */
+		size = min(size, skb_tailroom(skb));
 
 		skb->sk=sk;
 		skb->free=1;
@@ -1024,6 +1032,7 @@
 	struct iovec *iov=msg->msg_iov;
 	struct cmsghdr *cm=NULL;
 	int ct=msg->msg_iovlen;
+	int err = 0;
 
 	if(flags&MSG_OOB)
 		return -EOPNOTSUPP;
@@ -1098,8 +1107,13 @@
 			}
 
 			num=min(skb->len,len-done);
-			copy_to_user(sp, skb->data, num);
+			err = copy_to_user(sp, skb->data, num);
 
+			if (err)
+			{
+				goto out;
+			}
+			
 			if (skb->h.filp!=NULL)
 				unix_detach_fds(skb,cm);
 
@@ -1121,7 +1135,7 @@
 out:
 	up(&sk->protinfo.af_unix.readsem);
 
-	return copied;
+	return err ? -EFAULT : copied;
 }
 
 static int unix_shutdown(struct socket *sock, int mode)
@@ -1161,34 +1175,28 @@
 static int unix_ioctl(struct socket *sock, unsigned int cmd, unsigned long arg)
 {
 	unix_socket *sk=sock->data;
-	int err;
 	long amount=0;
 			
 	switch(cmd)
 	{
 	
 		case TIOCOUTQ:
-			err=verify_area(VERIFY_WRITE,(void *)arg,sizeof(int));
-			if(err)
-				return err;
 			amount=sk->sndbuf-sk->wmem_alloc;
 			if(amount<0)
 				amount=0;
-			put_user(amount, (int *)arg);
-			return 0;
+			return put_user(amount, (int *)arg);
 		case TIOCINQ:
 		{
 			struct sk_buff *skb;
 			if(sk->state==TCP_LISTEN)
 				return -EINVAL;
-			/* These two are safe on a single CPU system as only user tasks fiddle here */
+			/*
+			 *	These two are safe on a single CPU system as
+			 *	only user tasks fiddle here
+			 */
 			if((skb=skb_peek(&sk->receive_queue))!=NULL)
 				amount=skb->len;
-			err=verify_area(VERIFY_WRITE,(void *)arg,sizeof(int));
-			if(err)
-				return err;
-			put_user(amount, (int *)arg);
-			return 0;
+			return put_user(amount, (int *)arg);
 		}
 
 		default:
