diff -u --recursive --new-file v2.4.7/linux/Documentation/Configure.help linux/Documentation/Configure.help
--- v2.4.7/linux/Documentation/Configure.help	Wed Jul 25 17:10:16 2001
+++ linux/Documentation/Configure.help	Tue Jul 31 14:43:29 2001
@@ -3245,6 +3245,18 @@
   module will be called atyfb.o. If you want to compile it as a
   module, say M here and read Documentation/modules.txt.
   
+ATI Mach64 GX display support (EXPERIMENTAL)
+CONFIG_FB_ATY_GX
+  This options adds support for the first generation ATI Mach64
+  graphics chips, i.e. the Mach64 GX and CX. Note that this support is
+  limited.
+
+ATI Mach64 CT/VT/GT/LT display support (EXPERIMENTAL)
+CONFIG_FB_ATY_CT
+  This option adss support for ATI Mach64 graphics chips starting
+  with the Mach64 CT family. This includes the Mach64 VT (limited
+  support), GT (3D RAGE family), and LT.
+
 ATI Rage128 display support (EXPERIMENTAL)
 CONFIG_FB_ATY128
   This driver supports graphics boards with the ATI Rage128 chips.
@@ -12471,6 +12483,33 @@
   Say Y here if you would like to use hard disks under Linux which
   were partitioned on a Macintosh.
 
+Windows' Logical Disk Manager (Dynamic Disk) support (EXPERIMENTAL)
+CONFIG_LDM_PARTITION
+  Say Y here if you would like to use hard disks under Linux which
+  were partitioned using Windows 2000's or XP's Logical Disk Manager.
+  They are also known as "Dynamic Disks".
+
+  Windows 2000 introduced the concept of Dynamic Disks to get around
+  the limitations of the PC's partitioning scheme.  The Logical Disk
+  Manager allows the user to repartion a disk and create spanned,
+  mirrored, striped or RAID volumes, all without the need for
+  rebooting.
+
+  Normal partitions are now called Basic Disks under Windows 2000 and XP.
+
+  Technical documentation to accompany this driver is available from:
+  <http://linux-ntfs.sf.net/ldm>
+
+  If unsure, say N.
+
+Windows' LDM extra logging
+CONFIG_LDM_DEBUG
+  Say Y here if you would like LDM to log verbosely.  This could be
+  helpful if the driver doesn't work as expected and you'd like to
+  report a bug.
+
+  If unsure, say N.
+
 PC BIOS (MSDOS partition tables) support
 CONFIG_MSDOS_PARTITION
   Say Y here if you would like to use hard disks under Linux which
@@ -14201,6 +14240,19 @@
 
   If unsure, say N.
 
+Sony Vaio Programmable I/O Control Device support
+CONFIG_SONYPI
+  This driver enables access to the Sony Programmable I/O Control Device
+  which can be found in many (all ?) Sony Vaio laptops.
+
+  If you have one of those laptops, read Documentation/sonypi.txt,
+  and say Y or M here.
+
+  If you want to compile the driver as a module ( = code which can be
+  inserted in and removed from the running kernel whenever you want),
+  say M here and read <file:Documentation/modules.txt>. The module will be
+  called sonypi.o.
+
 Intel Random Number Generator support
 CONFIG_INTEL_RNG
   This driver provides kernel-side support for the Random Number
@@ -17493,6 +17545,19 @@
   module called pms.o ( = code which can be inserted in and removed
   from the running kernel whenever you want). If you want to compile
   it as a module, say M here and read Documentation/modules.txt.
+
+CONFIG_VIDEO_MEYE
+  This is the video4linux driver for the Motion Eye camera found
+  in the Vaio Picturebook laptops. Please read the material in
+  <file:Documentation/video4linux/meye.txt> for more information.
+
+  If you say Y or M here, you need to say Y or M to "Sony Programmable
+  I/O Control Device" in the character device section.
+
+  This driver is available as a module called meye.o ( = code
+  which can be inserted in and removed from the running kernel
+  whenever you want). If you want to compile it as a module, say M
+  here and read <file:Documentation/modules.txt>.
 
 IBM's S/390 architecture
 CONFIG_ARCH_S390
diff -u --recursive --new-file v2.4.7/linux/Documentation/isdn/HiSax.cert linux/Documentation/isdn/HiSax.cert
--- v2.4.7/linux/Documentation/isdn/HiSax.cert	Tue Feb 15 11:40:42 2000
+++ linux/Documentation/isdn/HiSax.cert	Sat Jul 28 12:12:37 2001
@@ -20,6 +20,23 @@
 version and the tested hardware. Any changes to the HiSax source code may
 therefore affect the certification.
 
+Additional ITU approval tests have been carried out for all generic cards
+using Colognechip single chip solutions HFC-S PCI A for PCI cards as well
+as HFC-S USB based USB ISDN ta adapters.
+These tests included all layers 1-3 and as well all functional tests for 
+the layer 1. Because all hardware based on these chips are complete ISDN
+solutions in one chip all cards and USB-TAs using these chips are to be
+regarded as approved for those tests. Some additional electrical tests
+of the layer 1 which are independant of the driver and related to a
+special hardware used will be regarded as approved if at least one 
+solution has been tested including those electrical tests. So if cards 
+or tas have been completely approved for any other os, the approval
+for those electrical tests is valid for linux, too.
+Please send any questions regarding this drivers or approval abouts to 
+werner@isdn-development.de 
+Additional information and the type approval documents will be found
+shortly on the Colognechip website www.colognechip.com 
+
 If you change the main files of the HiSax ISDN stack, the certification will
 become invalid. Because in most countries it is illegal to connect
 unapproved ISDN equipment to the public network, I have to guarantee that
@@ -50,6 +67,7 @@
 drivers/isdn/hisax/cert.c
 drivers/isdn/hisax/elsa.c
 drivers/isdn/hisax/diva.c
+drivers/isdn/hisax/hfc_pci.c
 
 Please send any changes, bugfixes and patches to me rather than implementing
 them directly into the HiSax sources.
diff -u --recursive --new-file v2.4.7/linux/Documentation/pci.txt linux/Documentation/pci.txt
--- v2.4.7/linux/Documentation/pci.txt	Tue Jul  3 17:08:18 2001
+++ linux/Documentation/pci.txt	Sun Aug  5 13:12:40 2001
@@ -80,7 +80,7 @@
 	class_mask	of the class are honored during the comparison.
 	driver_data	Data private to the driver.
 
-When the driver exits, it just calls pci_deregister_driver() and the PCI layer
+When the driver exits, it just calls pci_unregister_driver() and the PCI layer
 automatically calls the remove hook for all devices handled by the driver.
 
 Please mark the initialization and cleanup functions where appropriate
diff -u --recursive --new-file v2.4.7/linux/Documentation/s390/CommonIO linux/Documentation/s390/CommonIO
--- v2.4.7/linux/Documentation/s390/CommonIO	Wed Dec 31 16:00:00 1969
+++ linux/Documentation/s390/CommonIO	Wed Jul 25 14:12:01 2001
@@ -0,0 +1,124 @@
+S/390 common I/O-Layer - command line parameters and /proc entries
+==================================================================
+
+Command line parameters
+-----------------------
+
+* cio_msg = yes | no
+  
+  Determines whether information on found devices and sensed device 
+  characteristics should be shown during startup, i. e. messages of the types 
+  "Detected device 4711 on subchannel 42" and "SenseID: Device 4711 reports: ...".
+
+  Default is off.
+
+
+* cio_notoper_msg = yes | no
+
+  Determines whether messages of the type "Device 4711 became 'not operational'"
+  should be shown during startup; after startup, they will always be shown.
+  
+  Default is on.
+
+
+* cio_ignore = <range of device numbers>, <range of device numbers>, ...
+
+  The given device numbers will be ignored by the common I/O-layer; no detection
+  and device sensing will be done on any of those devices. The subchannel to 
+  which the device in question is attached will be treated as if no device was
+  attached.
+
+  An ignored device can be un-ignored later; see the "/proc entries"-section for
+  details.
+
+  The device numbers must be given hexadecimal.
+
+  For example, 
+	cio_ignore=0x23-0x42,0x4711
+  will ignore all devices with device numbers ranging from 23 to 42 and the 
+  device with device number 4711, if detected.
+
+  By default, no devices are ignored.
+
+
+* cio_proc_devinfo = yes | no
+
+  Determines whether the entries under /proc/deviceinfo/ (see below) should be
+  created. Since there are problems with systems with many devices attached, I
+  made it configurable.
+
+  Until the problems are dealt with, default is off.
+
+
+/proc entries
+-------------
+
+* /proc/subchannels
+
+  Shows for each subchannel
+  - device number
+  - device type/model and if applicable control unit type/model
+  - whether the device is in use
+  - path installed mask, path available mask, path operational mask and last 
+    path used mask
+  - the channel path IDs (chpids)
+
+
+* /proc/deviceinfo/
+
+  Shows in subdirectories for each device some characteristics:
+  - /proc/deviceinfo/<devno>/chpids: 
+	the channel path IDs
+  - /proc/deviceinfo/<devno>/in_use: 
+	whether the device is in use
+  - /proc/deviceinfo/<devno>/sensedata:
+    	the device type/model and if applicable control unit type/model of the
+	device
+
+  NOTE: Since the number of inodes which can be dynamically allocated by procfs
+        is limited, device entries will only be created up to a magic number of
+        devices. The kernel will utter a warning that not all entries can be
+        created. In this case, you shouldn't use "cio_proc_devinfo=yes" (see
+        above).
+
+* /proc/cio_ignore
+
+  Lists the ranges of device numbers which are ignored by common I/O.
+
+  You can un-ignore certain or all devices by piping to /proc/cio_ignore. 
+  "free all" will un-ignore all ignored devices, 
+  "free <devnorange>, <devnorange>, ..." will un-ignore the specified devices.
+
+  For example, if devices 23 to 42 and 4711 are ignored,
+  - echo free 0x30-0x32 > /proc/cio_ignore
+    will un-ignore devices 30 to 32 and will leave devices 23 to 2F, 33 to 42
+    and 4711 ignored;
+  - echo free 0x41 > /proc/cio_ignore will furthermore un-ignore device 41;
+  - echo free all > /proc/cio_ignore will un-ignore all remaining ignored 
+    devices.
+
+  When a device is un-ignored, device recognition and sensing is performed and 
+  the device driver will be notified if possible, so the device will become
+  available to the system.
+
+
+* /proc/s390dbf/cio_*/ (S/390 debug feature)
+
+  Some views generated by the debug feature to hold various debug outputs.
+
+  - /proc/s390dbf/cio_crw/sprintf
+    Messages from the processing of pending channel report words (machine check
+    handling), which will also show when CONFIG_DEBUG_CRW is defined.
+
+  - /proc/s390dbf/cio_msg/sprintf
+    Various debug messages from the common I/O-layer; generally, messages which 
+    will also show when CONFIG_DEBUG_IO is defined.
+
+  - /proc/s390dbf/cio_trace/hex_ascii
+    Logs the calling of functions in the common I/O-layer and, if applicable, 
+    which subchannel they were called for.
+
+  The level of logging can be changed to be more or less verbose by piping to 
+  /proc/s390dbf/cio_*/level a number between 0 and 6; see the documentation on
+  the S/390 debug feature (Documentation/s390/s390dbf.txt) for details.
+
diff -u --recursive --new-file v2.4.7/linux/Documentation/s390/Debugging390.txt linux/Documentation/s390/Debugging390.txt
--- v2.4.7/linux/Documentation/s390/Debugging390.txt	Sun May 20 12:11:38 2001
+++ linux/Documentation/s390/Debugging390.txt	Wed Jul 25 14:12:01 2001
@@ -1,5 +1,5 @@
               
-                          Debugging on Linux for s/390 & zSeries
+                          Debugging on Linux for s/390 & z/Architecture
 			               by
 		Denis Joseph Barrow (djbarrow@de.ibm.com,barrow_dj@yahoo.com)
 		Copyright (C) 2000-2001 IBM Deutschland Entwicklung GmbH, IBM Corporation
@@ -8,7 +8,7 @@
 Overview of Document:
 =====================
 This document is intended to give an good overview of how to debug 
-Linux for s/390 & zSeries it isn't intended as a complete reference & not a
+Linux for s/390 & z/Architecture it isn't intended as a complete reference & not a
 tutorial on the fundamentals of C & assembly, it dosen't go into
 390 IO in any detail. It is intended to compliment the documents in the
 reference section below & any other worthwhile references you get.
@@ -21,46 +21,46 @@
 ========
 Register Set
 Address Spaces on Intel Linux
-Address Spaces on Linux for s/390 & zSeries
-The Linux for s/390 & zSeries Kernel Task Structure
-Register Usage & Stackframes on Linux for s/390 & zSeries
+Address Spaces on Linux for s/390 & z/Architecture
+The Linux for s/390 & z/Architecture Kernel Task Structure
+Register Usage & Stackframes on Linux for s/390 & z/Architecture
 A sample program with comments
-Compiling programs for debugging on Linux for s/390 & zSeries
+Compiling programs for debugging on Linux for s/390 & z/Architecture
 Figuring out gcc compile errors
 Debugging Tools
 objdump
 strace
 Performance Debugging 
 Debugging under VM
-s/390 & zSeries IO Overview
-Debugging IO on s/390 & zSeries under VM
-GDB on s/390 & zSeries
+s/390 & z/Architecture IO Overview
+Debugging IO on s/390 & z/Architecture under VM
+GDB on s/390 & z/Architecture
 Stack chaining in gdb by hand
 Examining core dumps
 ldd
 Debugging modules
 The proc file system
 Starting points for debugging scripting languages etc.
-Tools soon to be available
 SysRq
 References
+Special Thanks
 
 Register Set
 ============
 The current architectures have the following registers.
  
-16  General propose registers, 32 bit on s/390 64 bit on zSeries, r0-r15 or gpr0-gpr15 used for arithmetic & addressing. 
+16  General propose registers, 32 bit on s/390 64 bit on z/Architecture, r0-r15 or gpr0-gpr15 used for arithmetic & addressing. 
 
-16 Control registers, 32 bit on s/390 64 bit on zSeries, ( cr0-cr15 kernel usage only ) used for memory managment,
+16 Control registers, 32 bit on s/390 64 bit on z/Architecture, ( cr0-cr15 kernel usage only ) used for memory managment,
 interrupt control,debugging control etc.
 
-16 Access registers ( ar0-ar15 ) 32 bit on s/390 & zSeries
+16 Access registers ( ar0-ar15 ) 32 bit on s/390 & z/Architecture
 not used by normal programs but potentially could 
 be used as temporary storage. Their main purpose is their 1 to 1
 association with general purpose registers and are used in
 the kernel for copying data between kernel & user address spaces.
-Access register 0 ( & access register 1 on z/Series ( needs 64 bit pointer ) )
-is currently used by the pthread library as a pointer to
+Access register 0 ( & access register 1 on z/Architecture ( needs 64 bit 
+pointer ) ) is currently used by the pthread library as a pointer to
 the current running threads private area.
 
 16 64 bit floating point registers (fp0-fp15 ) IEEE & HFP floating 
@@ -72,7 +72,7 @@
 
 
 The PSW is the most important register on the machine it
-is 64 bit on s/390 & 128 bit on zSeries & serves the roles of 
+is 64 bit on s/390 & 128 bit on z/Architecture & serves the roles of 
 a program counter (pc), condition code register,memory space designator.
 In IBM standard notation I am counting bit 0 as the MSB.
 It has several advantages over a normal program counter
@@ -83,7 +83,7 @@
 currently running at.
 
       Bit           Value
-s/390 zSeries
+s/390 z/Architecture
 0       0     Reserved ( must be 0 ) otherwise specification exception occurs.
 
 1       1     Program Event Recording 1 PER enabled, 
@@ -100,7 +100,7 @@
 
 8-11  8-11    PSW Key used for complex memory protection mechanism not used under linux
 
-12      12    1 on s/390 0 on zSeries
+12      12    1 on s/390 0 on z/Architecture
 
 13      13    Machine Check Mask 1=enable machine check interrupts
 
@@ -175,15 +175,19 @@
                compatible.
  	  
 	  
-Prefix Page
------------	  
+Prefix Page(s)
+--------------	  
 This per cpu memory area is too intimately tied to the processor not to mention.
-It exists between the real addresses 0-4096 on the processor & is exchanged 
-with a page in absolute storage by the set prefix instruction in linux'es startup. 
-This page different on each processor.
-Bytes 0-512 ( 200 hex ) are used by the processor itself for holding such
-information as exception indications & entry points for exceptions.
-Bytes after 0xc00 hex are used by linux for per processor globals.
+It exists between the real addresses 0-4096 on s/390 & 0-8192 z/Architecture & is exchanged 
+with a 1 page on s/390 or 2 pages on z/Architecture in absolute storage by the set 
+prefix instruction in linux'es startup. 
+This page is mapped to a different prefix for each processor in an SMP configuration
+( assuming the os designer is sane of course :-) ).
+Bytes 0-512 ( 200 hex ) on s/390 & 0-512,4096-4544,4604-5119 currently on z/Architecture 
+are used by the processor itself for holding such information as exception indications & 
+entry points for exceptions.
+Bytes after 0xc00 hex are used by linux for per processor globals on s/390 & z/Architecture 
+( there is a gap on z/Architecure too currently between 0xc00 & 1000 which linux uses ).
 The closest thing to this on traditional architectures is the interrupt
 vector table. This is a good thing & does simplify some of the kernel coding
 however it means that we now cannot catch stray NULL pointers in the
@@ -219,9 +223,6 @@
 If using the virtual machine ( VM ) as a debugger it is quite difficult to
 know which user process is running as the address space you are looking at
 could be from any process in the run queue.
-Thankfully you normally get lucky as address spaces don't overlap that &
-you can recognise the code at by cross referencing with a dump made by objdump
-( more about that later ).
 
 The limitation of Intels addressing technique is that the linux
 kernel uses a very simple real address to virtual addressing technique
@@ -240,35 +241,77 @@
 of our 32 bit addresses,however, we use entirely separate address 
 spaces for the user & kernel.
 
-This means we can support 2GB of non Extended RAM, & more
-with the Extended memory managment swap device & 64 Bit
-when it comes along.
+This means we can support 2GB of non Extended RAM on s/390, & more
+with the Extended memory managment swap device & 
+currently 4TB of physical memory currently on z/Architecture.
 
 
-Address Spaces on Linux for S390
-================================
+Address Spaces on Linux for s/390 & z/Architecture
+==================================================
 
 Our addressing scheme is as follows
 
 
-Himem 0x7fffffff 2GB on s/390   *****************          ****************
-2^64 bytes on zSeries           *  User Stack   *          *              *
-				*****************          *              *
-		                *  Shared Libs  *          *              *          
-                                *****************          *              *  
-			        *               *          *    Kernel    *  
-		                *  User Program *          *              *
-		                *   Data BSS    *          *              *
-                                *    Text       *          *              *
-            			*   Sections    *          *              *
-0x00000000                      *****************          ****************
+Himem 0x7fffffff 2GB on s/390    *****************          ****************
+currently 0x3ffffffffff (2^42)-1 *  User Stack   *          *              *
+on z/Architecture.		 *****************          *              *
+		                 *  Shared Libs  *          *              *      
+                                 *****************          *              *  
+			         *               *          *    Kernel    *  
+		                 *  User Program *          *              *
+		                 *   Data BSS    *          *              *
+                                 *    Text       *          *              *
+            			 *   Sections    *          *              *
+0x00000000                       *****************          ****************
 
 This also means that we need to look at the PSW problem state bit
 or the addressing mode to decide whether we are looking at
-user or kernel space. 
+user or kernel space.
+
+Virtual Addresses on s/390 & z/Architecture
+===========================================
+
+A virtual address on s/390 is made up of 3 parts
+The SX ( segment index, roughly corresponding to the PGD & PMD in linux terminology ) 
+being bits 1-11.
+The PX ( page index, corresponding to the page table entry (pte) in linux terminology )
+being bits 12-19. 
+The remaining bits BX (the byte index are the offset in the page )
+i.e. bits 20 to 31.
+
+On z/Architecture in linux we currently make up an address from 4 parts.
+The region index bits (RX) 0-32 we currently use bits 22-32
+The segment index (SX) being bits 33-43
+The page index (PX) being bits  44-51
+The byte index (BX) being bits  52-63
+
+Notes:
+1) s/390 has no PMD so the PMD is really the PGD also.
+A lot of this stuff is defined in pgtable.h.
+
+2) Also seeing as s/390's page indexes are only 1k  in size 
+(bits 12-19 x 4 bytes per pte ) we use 1 ( page 4k )
+to make the best use of memory by updating 4 segment indices 
+entries each time we mess with a PMD & use offsets 
+0,1024,2048 & 3072 in this page as for our segment indexes.
+On z/Architecture our page indexes are now 2k in size
+( bits 12-19 x 8 bytes per pte ) we do a similar trick
+but only mess with 2 segment indices each time we mess with
+a PMD.
+
+3) As z/Architecture supports upto a massive 5-level page table lookup we 
+can only use 3 currently on Linux ( as this is all the generic kernel
+currently supports ) however this may change in future
+this allows us to access ( according to my sums )
+4TB of virtual storage per process i.e.
+4096*512(PTES)*1024(PMDS)*2048(PGD) = 4398046511104 bytes,
+enough for another 2 or 3 of years I think :-).
+to do this we use a region-third-table designation type in
+our address space control registers.
+ 
 
-The Linux for s/390 & zSeries Kernel Task Structure
-===================================================
+The Linux for s/390 & z/Architecture Kernel Task Structure
+==========================================================
 Each process/thread under Linux for S390 has its own kernel task_struct
 defined in linux/include/linux/sched.h
 The S390 on initialisation & resuming of a process on a cpu sets
@@ -287,7 +330,7 @@
             *        ( 4K )        *
 8K aligned  ************************ 
 
-                     zSeries
+                 z/Architecture
             ************************
             *  2 page kernel stack *
 	    *        ( 8K )        *
@@ -298,7 +341,7 @@
 
 What this means is that we don't need to dedicate any register or global variable
 to point to the current running process & can retrieve it with the following
-very simple construct for s/390 & one very similar for zSeries.
+very simple construct for s/390 & one very similar for z/Architecture.
 
 static inline struct task_struct * get_current(void)
 {
@@ -317,8 +360,8 @@
 
 
 
-Register Usage & Stackframes on Linux for s/390 & zSeries
-=========================================================
+Register Usage & Stackframes on Linux for s/390 & z/Architecture
+=================================================================
 Overview:
 ---------
 This is the code that gcc produces at the top & the bottom of
@@ -331,7 +374,7 @@
 limited knowledge of one assembly language.
 
 It should be noted that there are some differences between the
-s/390 & zSeries stack layouts as the zSeries stack layout didn't have
+s/390 & z/Architecture stack layouts as the z/Architecture stack layout didn't have
 to maintain compatibility with older linkage formats.
 
 Glossary:
@@ -367,8 +410,8 @@
 The code generated by the compiler to return to the caller.
 
 frameless-function
-A frameless function in Linux for s390 & zSeries is one which doesn't need 
-more than the register save area ( 96 bytes on s/390, 160 on zSeries )
+A frameless function in Linux for s390 & z/Architecture is one which doesn't 
+need more than the register save area ( 96 bytes on s/390, 160 on z/Architecture )
 given to it by the caller.
 A frameless function never:
 1) Sets up a back chain.
@@ -428,8 +471,8 @@
 }
 
 
-s/390 & zSeries Register usage
-==============================
+s/390 & z/Architecture Register usage
+=====================================
 r0       used by syscalls/assembly                  call-clobbered
 r1	 used by syscalls/assembly                  call-clobbered
 r2       argument 0 / return value 0                call-clobbered
@@ -449,8 +492,8 @@
 
 f0       argument 0 / return value ( float/double ) call-clobbered
 f2       argument 1                                 call-clobbered
-f4       zSeries argument 2                           saved
-f6       zSeries argument 3                           saved
+f4       z/Architecture argument 2                  saved
+f6       z/Architecture argument 3                  saved
 The remaining floating points
 f1,f3,f5 f7-f15 are call-clobbered.
 
@@ -479,12 +522,13 @@
 area if crossing this boundary.
 6) Floating point parameters are mixed with outgoing args
 on the outgoing args area in the order the are passed in as parameters.
-7) Floating point arguments 2 & 3 are saved in the outgoing args area for zSeries
+7) Floating point arguments 2 & 3 are saved in the outgoing args area for 
+z/Architecture
 
 
 Stack Frame Layout
 ------------------
-s/390     zSeries
+s/390     z/Architecture
 0         0             back chain ( a 0 here signifies end of back chain )
 4         8             eos ( end of stack, not used on Linux for S390 used in other linkage formats )
 8         16            glue used in other s/390 linkage formats for saved routine descriptors etc.
@@ -598,8 +642,8 @@
 stack backchain in optimised code as this also causes pipeline stalls, you
 have been warned.
 
-64 bit zSeries code disassembly
--------------------------------
+64 bit z/Architecture code disassembly
+--------------------------------------
 
 If you understand the stuff above you'll understand the stuff
 below too so I'll avoid repeating myself & just say that 
@@ -637,12 +681,14 @@
 
 
 
-Compiling programs for debugging on Linux for s/390 & zSeries
-=============================================================
--gdwarf2 now works & normal -g debugging works much better now
+Compiling programs for debugging on Linux for s/390 & z/Architecture
+====================================================================
+-gdwarf-2 now works it should be considered the default debugging
+format for s/390 & z/Architecture as it is more reliable for debugging
+shared libraries,  normal -g debugging works much better now
 Thanks to the IBM java compiler developers bug reports. 
 
-This is typically done adding/appending the flags -g to the 
+This is typically done adding/appending the flags -g or -gdwarf-2 to the 
 CFLAGS & LDFLAGS variables Makefile of the program concerned.
 
 If using gdb & you would like accurate displays of registers &
@@ -1148,7 +1194,7 @@
 --------------------------------
 D G will display all the gprs
 Adding a extra G to all the commands is neccessary to access the full 64 bit 
-content in VM on zSeries obviously this isn't required for access registers
+content in VM on z/Architecture obviously this isn't required for access registers
 as these are still 32 bit.
 e.g. DGG instead of DG 
 D X will display all the control registers
@@ -1251,7 +1297,7 @@
 tr i pswa <address of main>
 Start the program, if VM drops to CP on what looks like the entry
 point of the main function this is most likely the process you wish to debug.
-Now do a D X13 or D XG13 on zSeries.
+Now do a D X13 or D XG13 on z/Architecture.
 On 31 bit the STD is bits 1-19 ( the STO segment table origin ) 
 & 25-31 ( the STL segment table length ) of CR13.
 now type
@@ -1260,7 +1306,48 @@
 TR I R STD 8F32E1FF 0.7fffffff
 Another very useful variation is
 TR STORE INTO STD <CR13's value> <address range>
+for finding out when a particular variable changes.
 
+An alternative way of finding the STD of a currently running process 
+is to do the following, ( this method is more complex but
+could be quite convient if you aren't updating the kernel much &
+so your kernel structures will stay constant for a reasonable period of
+time ).
+
+grep task /proc/<pid>/status
+from this you should see something like
+task: 0f160000 ksp: 0f161de8 pt_regs: 0f161f68
+This now gives you a pointer to the task structure.
+Now make CC:="s390-gcc -g" kernel/sched.s
+To get the task_struct stabinfo.
+( task_struct is defined in include/linux/sched.h ).
+Now we want to look at
+task->active_mm->pgd
+on my machine the active_mm in the task structure stab is
+active_mm:(4,12),672,32
+its offset is 672/8=84=0x54
+the pgd member in the mm_struct stab is
+pgd:(4,6)=*(29,5),96,32
+so its offset is 96/8=12=0xc
+
+so we'll
+hexdump -s 0xf160054 /dev/mem | more
+i.e. task_struct+active_mm offset
+to look at the active_mm member
+f160054 0fee cc60 0019 e334 0000 0000 0000 0011
+hexdump -s 0x0feecc6c /dev/mem | more
+i.e. active_mm+pgd offset
+feecc6c 0f2c 0000 0000 0001 0000 0001 0000 0010
+we get something like
+now do 
+TR I R STD <pgd|0x7f> 0.7fffffff
+i.e. the 0x7f is added because the pgd only
+gives the page table origin & we need to set the low bits
+to the maximum possible segment table length.
+TR I R STD 0f2c007f 0.7fffffff
+on z/Architecture you'll probably need to do
+TR I R STD <pgd|0x7> 0.ffffffffffffffff
+to set the TableType to 0x1 & the Table length to 3.
 
 
 
@@ -1347,10 +1434,18 @@
 
 Help for displaying ascii textstrings
 -------------------------------------
-As textstrings are cannot be displayed in ASCII under the VM debugger ( I love EBDIC too ) I have 
-written this little program which will convert a command line of hex digits to ascii text
-which can be compiled under linux & you can copy the hex digits from your x3270 terminal to
-your xterm if you are debugging from a linuxbox.
+On the very latest VM Nucleus'es VM can now display ascii
+( thanks Neale for the hint ) by doing
+D TX<lowaddr>.<len>
+e.g.
+D TX0.100
+
+Alternatively
+=============
+Under older VM debuggers ( I love EBDIC too ) you can use this little program I wrote which
+will convert a command line of hex digits to ascii text which can be compiled under linux & 
+you can copy the hex digits from your x3270 terminal to your xterm if you are debugging
+from a linuxbox.
 
 This is quite useful when looking at a parameter passed in as a text string
 under VM ( unless you are good at decoding ASCII in your head ).
@@ -1532,8 +1627,8 @@
 
 
 
-s/390 & zSeries IO Overview
-===========================
+s/390 & z/Architecture IO Overview
+==================================
 
 I am not going to give a course in 390 IO architecture as this would take me quite a
 while & I'm no expert. Instead I'll give a 390 IO architecture summary for Dummies if you have 
@@ -1685,15 +1780,15 @@
 between 2 machines. We use 2 cables under linux to do a bi-directional serial link.
 
 
-Debugging IO on s/390 & zSeries under VM
-=========================================
+Debugging IO on s/390 & z/Architecture under VM
+===============================================
 
 Now we are ready to go on with IO tracing commands under VM
 
 A few self explanatory queries:
 Q OSA
 Q CTC
-Q DISK
+Q DISK ( This command is CMS specific )
 Q DASD
 
 
@@ -1998,9 +2093,14 @@
 This is done using a the same trick described for VM 
 p/x (*($sp+56))&0x7fffffff get the first backchain.
 
-For zSeries do
-p/x *($sp+112) i.e. replace 56 with 112 & ignore the &0x7fffffff
-in the macros below.
+For z/Architecture
+Replace 56 with 112 & ignore the &0x7fffffff
+in the macros below & do nasty casts to longs like the following
+as gdb unfortunately deals with printed arguments as ints which
+messes up everything.
+i.e. here is a 3rd backchain dereference
+p/x *(long *)(***(long ***)$sp+112)
+
 
 this outputs 
 $5 = 0x528f18 
@@ -2265,6 +2365,21 @@
 
 Some driver debugging techniques
 ================================
+debug feature
+-------------
+Some of our drivers now support a "debug feature" in
+/proc/s390dbf see s390dbf.txt in the linux/Documentation directory
+for more info.
+e.g. 
+to switch on the lcs "debug feature"
+echo 5 > /proc/s390dbf/lcs/level
+& then after the error occured.
+cat /proc/s390dbf/lcs/sprintf >/logfile
+the logfile now contains some information which may help
+tech support resolve a problem in the field.
+
+
+
 high level debugging network drivers
 ------------------------------------
 ifconfig is a quite useful command
@@ -2339,65 +2454,10 @@
 & type ? in the debugger for help.
 
 
-Debugging Drivers
-=================
-Some of our drivers now support a debug logging feature in
-/proc/s390dbf see s390dbf.txt in the linux/Documentation directory
-for more info.
-e.g. 
-to switch on lcs debugging
-echo 5 > /proc/s390dbf/lcs/level
-& then after the error occured.
-cat /proc/s390dbf/lcs/sprintf >/logfile
-the logfile now contains some information which may help
-tech support resolve a problem in the field.
-
-If you have VM look at the chapter Debugging IO on S390 under VM.
-
-
-
-
-Tools soon to be available
-==========================
-
-Dumptool & Lcrash
------------------
-Michael Holzheu & others here at IBM have a fairly mature port of 
-SGI's lcrash tool which allows one to look at kernel structures in a
-running kernel.
-
-It also complements a tool called dumptool which dumps all the kernels
-memory pages & registers to either a tape or a disk.
-This can be used by tech support or an ambitous end user do
-post mortem debugging of a machine like gdb core dumps.
-
-Going into how to use this tool in detail will be explained
-in other documentation supplied by IBM & the lcrash homepage
-http://oss.sgi.com/projects/lkcd/.
-
-How they work
--------------
-Lcrash is a perfectly normal application
-however it requires an additional file.
-It is built using a patch to the kernel source base.
-
-
-Debugging a live system it uses /dev/mem
-alternatively for post mortem debugging it uses the data 
-collected by dumptool.
-
-
-Ltrace
-------
-We also have a tool called ltrace in our CVS repository 
-no plans on a delivery date yet.
-ltrace is a superset of strace in that it also allows
-tracing of shared libraries calls as well as system calls,
-man ltrace for more info.
 
 SysRq
 =====
-This is now supported by linux for s/390 & zSeries.
+This is now supported by linux for s/390 & z/Architecture.
 To enable it do compile the kernel with 
 Kernel Hacking -> Magic SysRq Key Enabled
 echo "1" > /proc/sys/kernel/sysrq.
@@ -2426,14 +2486,14 @@
 Various info & man pages.
 CMS Help on tracing commands.
 Linux for s/390 Elf Application Binary Interface
-Linux for zSeries Elf Application Binary Interface ( Both Highly Recommended )
+Linux for z/Series Elf Application Binary Interface ( Both Highly Recommended )
 z/Architecture Principles of Operation SA22-7832-00
 Enterprise Systems Architecture/390 Reference Summary SA22-7209-01 & the
 Enterprise Systems Architecture/390 Principles of Operation SA22-7201-05
 
-
-
-
-
-
+Special Thanks
+==============
+Special thanks to Neale Ferguson who maintains a much
+prettier HTML version of this page at
+http://penguinvm.princeton.edu/notes.html#Debug390
 
diff -u --recursive --new-file v2.4.7/linux/Documentation/s390/TAPE linux/Documentation/s390/TAPE
--- v2.4.7/linux/Documentation/s390/TAPE	Fri Feb 16 15:53:08 2001
+++ linux/Documentation/s390/TAPE	Wed Jul 25 14:12:01 2001
@@ -76,10 +76,9 @@
 - ensure the tape is at the beginning 
      mt -f /dev/ntibm0 rewind 
 
-- set the blocksize of the character driver. The blocksizes 512, 1024
-  and 2048 bytes are supported by ISO9660. 1024 is the default, u
-  which will be used here. 
-     mt -f /dev/ntibm0 setblk 1024 
+- set the blocksize of the character driver. The blocksize 2048 bytes
+  is commonly used on ISO9660 CD-Roms
+     mt -f /dev/ntibm0 setblk 2048 
 
 - write the filesystem to the character device driver 
      mkisofs -o /dev/ntibm0 somedir 
@@ -88,18 +87,16 @@
      mt -f /dev/ntibm0 rewind 
 
 - Now you can mount your new filesystem as a block device: 
-     mount -t iso9660 -o ro,block=1024 /dev/btibm0 /mnt 
+     mount -t iso9660 -o ro,block=2048 /dev/btibm0 /mnt 
 
 TODO List 
 
-- The backend code has to be enhanced to support error-recovery actions. 
-
-- The seeking algorithm of the block device has to be improved to speed 
-  things up 
+   - Driver has to be stabelized still
 
 BUGS 
 
-There are lots of weaknesses still in the code. This is why it is EXPERIMENTAL.
+This driver is considered BETA, which means some weaknesses may still
+be in it.
 If an error occurs which cannot be handled by the code you will get a 
 sense-data dump.In that case please do the following: 
 
diff -u --recursive --new-file v2.4.7/linux/Documentation/s390/chandev.8 linux/Documentation/s390/chandev.8
--- v2.4.7/linux/Documentation/s390/chandev.8	Wed Apr 11 19:02:27 2001
+++ linux/Documentation/s390/chandev.8	Wed Jul 25 14:12:01 2001
@@ -7,29 +7,37 @@
 .SH SYNOPSIS
 The channel device layer is a layer to provide a consistent interface for
 configuration & default machine check (devices appearing & disappearing )
-handling Linux for zSeries channel devices.
+handling on Linux for s/390 & z/Series channel devices.
 
-These include among others
+
+s/390 & z/Series channel devices include among others
 
 .Bl -item
 .It
 lcs ( the most common ethernet/token ring/fddi standard on zSeries )
 .It
-ctc/escon hi speed like serial link standard on zSeries.
+ctc/escon hi speed like serial link standard on s/390 & z/Series.
 .It
 claw used to talk to cisco routers.
 .It
 qeth gigabit ethernet.
-.El
-
+.It
+osad used by osa/sf to configure osa devices, e.g. to share a osa card between 2 or more vm guests. osad is just added to the channel device layer for completeness, there are no plans at the current time to write a driver to exploit this under linux.
+.It
 These devices use two channels one read & one write for configuration &
-or communication.
-The motivation behind producing this layer was that there is a lot of
-duplicate code among the drivers for configuration so the lcs & ctc drivers
-tended to fight over 3088/08's & 3088/1F's which could be either 2216/3172
-lcs compatible devices or escons/ctc's & to resolve this fight
-both device drivers had to be reconfigured rather than doing the
-configuration in a single place.
+or communication ( & a third channel the data channel in the case of gigabit ethernet ).
+The motivation behind developing this layer was that there was a lot of
+duplicate code among the channel device drivers for configuration. 
+Also the lcs & ctc drivers tended to fight over 3088/08's & 3088/1F's which could 
+be either 2216/3172 channel attached lcs compatible devices or escon/ctc pipes 
+between guests & to resolve this fight both device drivers had to be configured 
+separately,  this is now simplified by doing the configuration in a single place
+( the channel device layer ).
+
+This layer isn't invasive & it is quite okay to use channel drivers
+which don't use the channel device layer in conjunction with
+drivers which do.
+.El
 
 .SH DESCRIPTION
 The current setup can be read from /proc/chandev
@@ -37,30 +45,65 @@
 .Bl -enum
 .It
 Piping to /proc/chandev.
+e.g. echo reprobe >/proc/chandev
+will cause uninitialised channel devices to be probed.
 .It
-Entering them into /etc/chandev.conf comments are prefixed #.
+Entering them into /etc/chandev.conf comments are prefixed with #.
 .It
 Or from the boot command line using the 'chandev=' keyword
+e.g. chandev=noauto,0x0,0x480d;noauto,0x4810,0xffff
+will allow only devno's 0x480e & 0x480f to be autodetected.
 .El
 .Bl -item
 .It
-Multiple options can be passed separated by semicolons but no spaces are allowed between parameters. The script /bin/chandev will be called automatically on startup or a machine check of a device as follows.
-/bin/chandev <start starting_devnames> <machine_check (devnames pre_recovery_action_status) (post_recovery_action_status)>.
-The chandev layer doesn't open stdin stdout or stderr so it is advisable that you add the following lines to the start of your script.
+Multiple options can be passed separated by semicolons but no spaces are allowed between parameters. To be consistent with other hotpluggable architectures the script pointed to /proc/sys/kernel/hotplug (normally /sbin/hotplug) will be called automatically on startup or a machine check of a device as follows.
+/sbin/hotplug chandev <start starting_devnames> <machine_check (devname last/pre_recovery_status) (current/post_recovery_status)>.
+The chandev layer doesn't open stdin stdout or stderr so it is advisable that you add the following lines to the start of your script, here is a sample script which starts devices as they become available.
 .It
 #!/bin/bash
 .It
 exec >/dev/console 2>&1 0>&1
+.It
+# Uncomment line below for debugging.
+.It
+# echo $*
+.It
+if [ "$1" = "chandev" ] && [ "$2" = "start" ]
+.It
+then
+.It
+    shift 2
+.It
+    while [ "$1" != "" ]  && [ "$1" != "machine_check" ]
+.It
+    do
+.It
+        isup=`ifconfig $1 2>/dev/null | grep UP`
+.It
+	if [ "$isup" = "" ]
+.It
+	then
+.It
+	     ifup $1
+.It
+	fi
+.It
+	shift
+.It
+    done
+.It
+fi
+.It
+.It
+e.g. if tr0 & ctc0 were starting up & eth0 & eth1 devices disappeared & eth2 got a revalidate machine check ( which is normally fully recoverable ) nearly simultainously the parameters would be.
+.It
+/sbin/hotplug chandev start tr0 ctc0 machine_check eth0 gone gone eth1 gone gone eth2 revalidate good
+.It
+This can be used for example to call /etc/rc.d/init.d/network start when a device appears & make the ipldelay kernel boot parameter obselete on native machines or recover from bad machine checks where the default machine check handling isn't adequete. The machine checks that can be presented as parameters are good not_operational no_path revalidate device_gone. Normally you wouldn't want to do anything like stop networking when a device disappears as this is hopefully temporary, I just added it to be complete. The chandev layer waits a few seconds for machine checks to settle before running /sbin/hotplug because several machine checks usually happen at once & the forked scripts would possibly race against each other to shutdown & start resources at the same time & behave rather stupidly.
 .El
 
-e.g. if tr0 & ctc0 were starting up & eth0 & eth1 didn't recover from a gone machine check at the same instant the  parameters would be.
-
-
-/bin/chandev start tr0 ctc0 machine_check eth0 gone gone eth1 gone gone
 
 
-This can be used for example to call /etc/rc.d/init.d/network start when a device appears & make the ipldelay kernel boot parameter obselete on native machines or recover from bad machine checks where the default machine check handling isn't adequete. The machine checks that can be presented as parameters are good not_operational no_path revalidate device_gone.
-
 valid chandev arguments are <> indicate optional parameters, | indicate a choice.
 
 .B glossary
@@ -77,21 +120,49 @@
 .It
 
 .Bl -item
-
 .It
-.B (ctc|escon|lcs|osad|qeth|claw)<devif_num>, 
-read_devno, write_devno, <port_no/protocol_no>, <checksum_received_ip_pkts>, <use_hw_stats>
+.B (ctc|escon|lcs|osad|qeth)<devif_num>, 
+read_devno,write_devno,<data_devno,memory_usage_in_k,port_no/protocol_no,checksum_received_ip_pkts,use_hw_stats>
+.It
+devif_num of -1 indicates you don't care what device interface number is chosen, omitting it indicates this is a range of devices for which you want to force to be detected as a particular type.
+The data_devno field is only valid for qeth devices when not forcing a range of devices.
+all parameters after & including memory_usage_in_k can be set optionally if not set they
+go to default values. memory_usage_in_k ( 0 the default ) means let the driver choose,checksum_received_ip_pkts & use_hw_stats are set to false
+.It
+e.g. ctc0,0x7c00,0x7c01
 .It
-e.g. ctc0,0x7c00,0x7c01,0,0,0
+Tells the channel layer to force ctc0 if detected to use cuu's 7c00 & 7c01 port,port_no is the relative adapter no on lcs, on ctc/escon this field is the ctc/escon protocol number ( default 0 ), don't do checksumming on received ip packets & as ctc doesn't have hardware stats so it ignores this parameter. This can be used for instance to force a device if it presents bad sense data to the IO layer & thus autodetection fails.
 .It
-Tells the channel layer to force ctc0 if detected to use cuu's 7c00 & 7c01 port,port_no is the relative adapter no on lcs, on ctc/escon this field is the ctc/escon protocol number ( normally 0 ), don't do checksumming on received ip packets & as ctc doesn't have hardware stats so it ignores this parameter.
+qeth,0x7c00,0x7d00,-1,4096
+All devices between 0x7c00 & 7d00 should be detected as gigabit ethernet, let the driver use 4096k for each instance, don't care what port relative adapter number is chosen, don't checksum received ip packets & use hw stats .
+.It
+qeth1,0x7c00,0x7c01,0x7c02
+.It
+devif_num=1,read=0x7c00,write=0x7c01,data=0x7c02, don't checksum received ip packets & use hw stats.
 .El
 .It
-
+.Bl -item
+.B claw devif_num, 
+read_devno,write_devno<,memory_usage_in_k,checksum_received_ip_pkts,use_hw_stats,>
+host_name,adapter_name,api_type
+.It
+CLAW currently is not autodetected as the host_name,adapter_name & api_type
+need to be set up, possibly some convention for setting these automatically
+may be contrived in the future & auto detection may be done but currently there isn't any.
+The names host_name,adapter_name,api_type may be 8 upto characters in length,
+host_name is the name of this host, adapter_name is the name of the adjacent host,
+api_type may be name 1 to 8 chars in length API & TCPIP are common values.
+The remainder of the parameters are the same as the description for other ctc escon etc. 
+.It
+A typical setup may be
+.It
+claw0,0xe00,0xe01,linuxa,rs6k,TCPIP
+.It
+.El
 .Bl -item
 .It
 .B add_parms
-,chan_type,<string>
+,chan_type,<lo_devno,hi_devno,>string
 .It
 chan_type bitfield 
 .It
@@ -99,22 +170,26 @@
 .It
 This is for device driver specific options passed as a string to the driver
 not dealt with by the channel device layer it can't contain spaces.
+low_devno & hi_devno are optional parameters to specify a range.
+The channel device layer doesn't concatenate strings if device ranges overlap,
+before passing to a device driver.
 .El
 .It
 
 .Bl -item
 .It
 .B del_parms
-<,chan_type,exact_match>
+<,chan_type,exact_match,lo_devno>
 .It
 This deletes some or all device driver specific options not specifying chan_type causes it to delete all the strings. exact_match=1 specifies only to remove driver parms where chan_type is exactly equal exact_match=0 specifies to remove parms where any bit matches chan_type.
+lo_devno is an optional parameter the delete to only happen if lo_devno matches a lo_devno in one of the ranges.
 .El
 .It
 
 .Bl -item
 .It
 .B noauto
-,<lo_devno>-<hi_devno>
+<,lo_devno,hi_devno>
 .It
 Don't probe a range of device numbers for channel devices.
 .El
@@ -128,7 +203,6 @@
 .It
 e.g. a token ring read channel 0x7c00 would have an interface called tr0x7c00 this avoids name collisions on devices.
 .El
-.El
 
 
 .B power user options
@@ -168,7 +242,6 @@
 .It
 .B add_model
 ,chan_type, cu_type, cu_model, dev_type, dev_model, max_port_no, automatic_machine_check_handling
-
 .It
 Tells the channel layer to probe for the device described, -1 for any of the parameters other than chan_type & automatic_machine_check_handling is a wildcard.
 Set max_port_no to 0 for non lcs devices.
@@ -180,18 +253,33 @@
 chan_type bitfield
 .It
 ctc=0x1, escon=0x2, lcs=0x4, osad=0x8, qeth=0x10, claw=0x20
-
-.It
+.El
 .Bl -item
 .It
 .B del_model
 ,cu_type,cu_model,dev_type,dev_model
 .It
--1 for any parameter is a wildcard,
+-1 for any parameter is a wildcard.
 .El
+
+.Bl -item
 .It
 .B del_all_models
+.It 
+should be obvious.
+.El
+.Bl -item
+.It
+.B  non_cautious_auto_detect
+.It
+Tells the channel device layer to attempt to auto detect devices even if their type/model pairs don't unambigously identify the device, e.g. 3088/1F's can either be escon CTC's or channel attached 3172 lcs compatible devices. If the wrong device driver attempts to probe these channels there may be big delays on startup or even a kernel lockup, use this option with caution.
+.El
+.Bl -item
+.It
+.B cautious_auto_detect
 .It
+ See non_cautious_auto_detect this is the default.
+.El
 .Bl -item
 .It
 .B auto_msck
@@ -248,6 +336,19 @@
 .It
 .Bl -item
 .It
+.B unregister_probe <probefunc_addr>
+.It
+unregisters a single probe function or all of them.
+.El
+.Bl -item
+.It
+.B unregister_probe_by_chan_type
+.It
+unregisters all probe functions which match the chan_type bitfield exactly,
+useful if you want a configuration to survice a kernel upgrade.
+.El
+.Bl -item
+.It
 .B read_conf
 .It
 Read instructions from /etc/chandev.conf.
@@ -259,6 +360,16 @@
 .It
 Don't automatically read /etc/chandev.conf on boot.
 .El
+.Bl -item
+.It
+.B persist 
+,chan_type
+.It
+Force drivers modules to stay loaded even if no device is found,
+this is useful for debugging & one wishes to examine debug entries in 
+/proc/s390dbf/ to find out why a module failed to load.
+.El
+
 .It
 e.g the following sequence of commands should be roughly equivalent
 to rebooting for channel devices.
@@ -290,8 +401,8 @@
 .B /proc/chandev
 .It
 cat /proc/chandev to see current options chosen.
-.Iy
-echo <command> >proc/chandev to enter a new command
+.It
+echo <command> >/proc/chandev to enter a new command
 .It
 .B /etc/chandev.conf 
 .It
@@ -302,7 +413,7 @@
 .B 'chandev=' 
 keyword.
 .It
-.B /bin/chandev
+.B /sbin/hotplug
 .It 
 A user script/executable which is run when devices come online "appear"
 or go offline "disappear".
diff -u --recursive --new-file v2.4.7/linux/Documentation/sound/btaudio linux/Documentation/sound/btaudio
--- v2.4.7/linux/Documentation/sound/btaudio	Wed Dec 31 16:00:00 1969
+++ linux/Documentation/sound/btaudio	Sun Aug  5 13:15:05 2001
@@ -0,0 +1,81 @@
+
+Intro
+=====
+
+people start bugging me about this with questions, looks like I
+should write up some documentation for this beast.  That way I
+don't have to answer that much mails I hope.  Yes, I'm lazy...
+
+
+You might have noticed that the bt878 grabber cards have actually
+_two_ PCI functions:
+
+$ lspci
+[ ... ]
+00:0a.0 Multimedia video controller: Brooktree Corporation Bt878 (rev 02)
+00:0a.1 Multimedia controller: Brooktree Corporation Bt878 (rev 02)
+[ ... ]
+
+The first does video, it is backward compatible to the bt848.  The second
+does audio.  btaudio is a driver for the second function.  It's a sound
+driver which can be used for recording sound (and _only_ recording, no
+playback).  As most TV cards come with a short cable which can be plugged
+into your sound card's line-in you probably don't need this driver if all
+you want to do is just watching TV...
+
+
+Driver Status
+=============
+
+Still somewhat experimental.  The driver should work stable, i.e. it
+should'nt crash your box.  It might not work as expected, have bugs,
+not being fully OSS API compilant, ...
+
+
+Digital audio mode
+==================
+
+The chip knows different modes.  Right now you have to pick the one you
+want to use at insmod time.  Digital audio mode is the default.  The
+chip gives you 16 bit stereo sound with ~32 kHz sample rate.  According
+to the specs it should be possible to get up to 48 kHz, but I havn't
+figured out yet how this works.  The specs are not very verbose :-(
+
+Lower sample rates are possible too, but the code isn't written yet.
+For now you are limited to the fixed 32 kHz.  Mono works throuth, the
+driver will do that in software for you.
+
+With my Hauppauge I get clear sound, but I got also reports saying that
+digital audio mode does'nt work.  Guess Hauppauge connected the msp34xx
+output to the bt878's I2S digital audio input port.
+
+
+analog mode (A/D)
+=================
+
+You can tell the driver to use this mode with the insmod option "analog=1".
+The chip has three analog inputs.  Consequently you'll get a mixer device
+to control these.
+
+The analog mode supports mono only.  Both 8 + 16 bit.  Both are _signed_
+int, which is uncommon for the 8 bit case.  Sample rate range is 119 kHz
+to 448 kHz.  Yes, the number of digits is correct.  The driver supports
+downsampling by powers of two, so you can ask for more usual sample rates
+like 44 kHz too.
+
+With my Hauppauge I get noisy sound on the second input (mapped to line2
+by the mixer device).  Others get a useable signal on line1.
+
+
+more hints
+==========
+
+/me uses "sox -w -r 32000 -t ossdsp /dev/dsp2 -t ossdsp /dev/dsp"
+to dump audio data from btaudio (dsp2) to es1730 (dsp,dsp1).
+
+Have fun,
+
+  Gerd
+
+-- 
+Gerd Knorr <kraxel@bytesex.org>
diff -u --recursive --new-file v2.4.7/linux/Documentation/video4linux/bttv/CARDLIST linux/Documentation/video4linux/bttv/CARDLIST
--- v2.4.7/linux/Documentation/video4linux/bttv/CARDLIST	Mon Feb 19 14:43:36 2001
+++ linux/Documentation/video4linux/bttv/CARDLIST	Sun Aug  5 13:15:05 2001
@@ -53,11 +53,19 @@
   card=51 - Eagle Wireless Capricorn2 (bt878A)
   card=52 - Pinnacle PCTV Studio Pro
   card=53 - Typhoon TView RDS / FM Stereo
-  card=54 - Livetec 9415 TV
+  card=54 - Lifetec LT 9415 TV
   card=55 - BESTBUY Easy TV
   card=56 - FlyVideo '98/FM
   card=57 - GrandTec 'Grand Video Capture'
   card=58 - Phoebe TV Master Only (No FM)
+  card=59 - TV Capturer
+  card=60 - MM100PCTV
+  card=61 - AG Electronics GMV1
+  card=62 - BESTBUY Easy TV (bt878)
+  card=63 - ATI TV-Wonder
+  card=64 - ATI TV-Wonder VE
+  card=65 - FlyVideo 2000S
+  card=66 - Terratec TValueRadio
 
 tuner.o
   type=0 - Temic PAL (4002 FH5)
@@ -85,3 +93,9 @@
   type=22 - Temic PAL/SECAM multi (4046 FM5)
   type=23 - Philips PAL_DK
   type=24 - Philips PAL/SECAM multi (FQ1216ME)
+  type=25 - LG PAL_I+FM (TAPC-I001D)
+  type=26 - LG PAL_I (TAPC-I701D)
+  type=27 - LG NTSC+FM (TPI8NSR01F)
+  type=28 - LG PAL_BG+FM (TPI8PSB01D)
+  type=29 - LG PAL_BG (TPI8PSB11D)
+  type=30 - Temic PAL* auto + FM (4009 FN5)
diff -u --recursive --new-file v2.4.7/linux/Documentation/video4linux/bttv/Insmod-options linux/Documentation/video4linux/bttv/Insmod-options
--- v2.4.7/linux/Documentation/video4linux/bttv/Insmod-options	Mon Feb 19 14:43:36 2001
+++ linux/Documentation/video4linux/bttv/Insmod-options	Sun Aug  5 13:15:05 2001
@@ -13,6 +13,9 @@
 		triton1=0/1     for Triton1 compatibility
 				Triton1 is automatically recognized
 				but this might also help with other chipsets
+		vsfx=0/1	yet another chipset bug compatibility flag
+				(bt878 docs mentiones via+sis, but no
+				specific chipsets with that problem).
 		bigendian=n	Set the endianness of the gfx framebuffer.
 				Default is native endian.
 		fieldnr=0/1	Count fields.  Some TV descrambling software
diff -u --recursive --new-file v2.4.7/linux/Documentation/video4linux/bttv/README linux/Documentation/video4linux/bttv/README
--- v2.4.7/linux/Documentation/video4linux/bttv/README	Mon Feb 19 14:43:36 2001
+++ linux/Documentation/video4linux/bttv/README	Sun Aug  5 13:15:05 2001
@@ -21,8 +21,7 @@
 CONFIG_I2C_ALGOBIT=m
 CONFIG_VIDEO_DEV=m
 
-The latest bttv version is available here:
-	http://www.strusel007.de/linux/bttv/
+The latest bttv version is available from http://bytesex.org/bttv/
 
 You'll find Ralphs original (mostly outdated) documentation in the
 ralphs-doc subdirectory.
diff -u --recursive --new-file v2.4.7/linux/Documentation/video4linux/bttv/Sound-FAQ linux/Documentation/video4linux/bttv/Sound-FAQ
--- v2.4.7/linux/Documentation/video4linux/bttv/Sound-FAQ	Mon Feb 19 14:43:36 2001
+++ linux/Documentation/video4linux/bttv/Sound-FAQ	Sun Aug  5 13:15:05 2001
@@ -109,6 +109,29 @@
 in  = 	_in_put bits of the data register,
 	i.e. BT848_GPIO_DATA & ~BT848_GPIO_OUT_EN
 
+
+
+Other elements of the tvcards array
+===================================
+
+If you are trying to make a new card work you might find it useful to
+know what the other elements in the tvcards array are good for:
+
+video_inputs    - # of video inputs the card has
+audio_inputs    - historical cruft, not used any more.
+tuner           - which input is the tuner
+svhs            - which input is svhs (all others are labled composite)
+muxsel          - video mux, input->registervalue mapping
+pll             - same as pll= insmod option
+tuner_type      - same as tuner= insmod option
+*_modulename    - hint whenever some card needs this or that audio
+                  module loaded to work properly.
+
+If some config item is specified both from the tvcards array and as
+insmod option, the insmod option takes precedence.
+
+
+
 Good luck,
 
   Gerd
@@ -117,4 +140,4 @@
 PS: If you have a new working entry, mail it to me.
 
 -- 
-Gerd Knorr <kraxel@goldbach.in-berlin.de>
+Gerd Knorr <kraxel@bytesex.org>
diff -u --recursive --new-file v2.4.7/linux/MAINTAINERS linux/MAINTAINERS
--- v2.4.7/linux/MAINTAINERS	Wed Jul 25 17:10:17 2001
+++ linux/MAINTAINERS	Sun Aug  5 13:12:40 2001
@@ -106,6 +106,13 @@
 L:	linux-net@vger.kernel.org
 S:	Maintained
 
+A2232 SERIAL BOARD DRIVER
+P:      Enver Haase
+M:      ehaase@inf.fu-berlin.de
+M:      A2232@gmx.net
+L:      linux-m68k@lists.linux-m68k.org
+S:      Maintained
+
 ACENIC DRIVER
 P:	Jes Sorensen
 M:	jes@trained-monkey.org
@@ -606,6 +613,13 @@
 P:	Nils Faerber
 M:	nils@kernelconcepts.de
 W:	http://www.kernelconcepts.de/
+S:	Maintained
+
+IA64 (Itanium) PLATFORM
+P:	David Mosberger-Tang
+M:	davidm@hpl.hp.com
+L:	linux-ia64@linuxia64.org
+W:	http://www.linuxia64.org/
 S:	Maintained
 
 IBM MCA SCSI SUBSYSTEM DRIVER
diff -u --recursive --new-file v2.4.7/linux/Makefile linux/Makefile
--- v2.4.7/linux/Makefile	Wed Jul 25 17:10:17 2001
+++ linux/Makefile	Fri Aug  3 23:34:34 2001
@@ -1,7 +1,7 @@
 VERSION = 2
 PATCHLEVEL = 4
-SUBLEVEL = 7
-EXTRAVERSION =
+SUBLEVEL = 8
+EXTRAVERSION =-pre5
 
 KERNELRELEASE=$(VERSION).$(PATCHLEVEL).$(SUBLEVEL)$(EXTRAVERSION)
 
diff -u --recursive --new-file v2.4.7/linux/arch/alpha/kernel/entry.S linux/arch/alpha/kernel/entry.S
--- v2.4.7/linux/arch/alpha/kernel/entry.S	Wed Jul 25 17:10:17 2001
+++ linux/arch/alpha/kernel/entry.S	Wed Jul 25 17:11:05 2001
@@ -739,9 +739,12 @@
 	mov	$30,$17
 	br	$1,do_switch_stack
 	mov	$30,$18
+	subq	$30,16,$30
+	stq	$26,0($30)
 	jsr	$26,do_sigsuspend
-	lda	$30,SWITCH_STACK_SIZE($30)
-	br	ret_from_sys_call
+	ldq	$26,0($30)
+	lda	$30,SWITCH_STACK_SIZE+16($30)
+	ret	$31,($26),1
 .end sys_sigsuspend
 
 .align 3
@@ -750,9 +753,12 @@
 	mov	$30,$18
 	br	$1,do_switch_stack
 	mov	$30,$19
+	subq	$30,16,$30
+	stq	$26,0($30)
 	jsr	$26,do_rt_sigsuspend
-	lda	$30,SWITCH_STACK_SIZE($30)
-	br	ret_from_sys_call
+	ldq	$26,0($30)
+	lda	$30,SWITCH_STACK_SIZE+16($30)
+	ret	$31,($26),1
 .end sys_rt_sigsuspend
 
 	.data
diff -u --recursive --new-file v2.4.7/linux/arch/cris/Makefile linux/arch/cris/Makefile
--- v2.4.7/linux/arch/cris/Makefile	Wed Jul 25 17:10:17 2001
+++ linux/arch/cris/Makefile	Thu Jul 26 15:10:06 2001
@@ -1,4 +1,4 @@
-# $Id: Makefile,v 1.19 2001/06/11 12:06:40 bjornw Exp $
+# $Id: Makefile,v 1.20 2001/07/05 10:07:58 jonashg Exp $
 # cris/Makefile
 #
 # This file is included by the global makefile so that you can add your own
@@ -55,7 +55,8 @@
 # each others config options
 SUBDIRS += arch/cris/boot/rescue
 endif
-CORE_FILES += arch/cris/kernel/kernel.o arch/cris/mm/mm.o arch/cris/drivers/drivers.o
+CORE_FILES += arch/cris/kernel/kernel.o arch/cris/mm/mm.o
+DRIVERS += arch/cris/drivers/drivers.o
 LIBGCC = $(shell $(CC) $(CFLAGS) -print-file-name=libgcc.a)
 LIBS := $(TOPDIR)/arch/cris/lib/lib.a $(LIBS) $(TOPDIR)/arch/cris/lib/lib.a $(LIBGCC)
 
diff -u --recursive --new-file v2.4.7/linux/arch/cris/boot/compressed/decompress.ld linux/arch/cris/boot/compressed/decompress.ld
--- v2.4.7/linux/arch/cris/boot/compressed/decompress.ld	Tue Jul  3 17:08:18 2001
+++ linux/arch/cris/boot/compressed/decompress.ld	Thu Jul 26 15:10:06 2001
@@ -13,7 +13,6 @@
 		_stext = . ;
 		*(.text)
 		*(.rodata)
-		*(.rodata.*)
 		_etext = . ;
 	} > dram
 	.data :
diff -u --recursive --new-file v2.4.7/linux/arch/cris/config.in linux/arch/cris/config.in
--- v2.4.7/linux/arch/cris/config.in	Wed Jul 25 17:10:17 2001
+++ linux/arch/cris/config.in	Thu Jul 26 15:10:06 2001
@@ -49,6 +49,10 @@
 int 'DRAM size (dec, in MB)' CONFIG_ETRAX_DRAM_SIZE 8
 
 int 'Buswidth of flash in bytes' CONFIG_ETRAX_FLASH_BUSWIDTH 2
+bool 'Use flash mirroring (for cramfs)' CONFIG_ETRAX_FLASH_MIRRORING_FOR_CRAMFS
+if [ "$CONFIG_ETRAX_FLASH_MIRRORING_FOR_CRAMFS" = "y" ]; then
+	int '  Individual flash chip size (in MB)' CONFIG_ETRAX_FLASH_SIZE 2
+fi
 
 choice 'Product LED port' \
 	"Port-PA-LEDs	CONFIG_ETRAX_PA_LEDS	\
@@ -61,8 +65,8 @@
   int '  First red LED bit' CONFIG_ETRAX_LED1R 3
   int '  Second green LED bit' CONFIG_ETRAX_LED2G 4
   int '  Second red LED bit' CONFIG_ETRAX_LED2R 5
-  int '  Third green LED bit' CONFIG_ETRAX_LED3R 2
-  int '  Third red LED bit' CONFIG_ETRAX_LED3G 2
+  int '  Third green LED bit' CONFIG_ETRAX_LED3G 2
+  int '  Third red LED bit' CONFIG_ETRAX_LED3R 2
 fi
 
 if [ "$CONFIG_ETRAX_CSP0_LEDS" = "y" ]; then
@@ -169,7 +173,7 @@
 
 source drivers/ieee1394/Config.in
 
-source drivers/message/i2o/Config.in
+source drivers/i2o/Config.in
 
 if [ "$CONFIG_NET" = "y" ]; then
   mainmenu_option next_comment
diff -u --recursive --new-file v2.4.7/linux/arch/cris/cris.ld linux/arch/cris/cris.ld
--- v2.4.7/linux/arch/cris/cris.ld	Tue Jul  3 17:08:18 2001
+++ linux/arch/cris/cris.ld	Thu Jul 26 15:10:06 2001
@@ -24,7 +24,7 @@
 		*(.fixup)
 		*(.text.__*)
 		*(.rodata)
-		*(.rodata.*)
+		*(.rodata.__*)
 	}
 
 	. = ALIGN(4);                /* Exception table */
@@ -56,11 +56,18 @@
   	___setup_start = .;
   	.setup.init : { *(.setup.init) }
   	___setup_end = .;
-  	___initcall_start = .;
-  	.initcall.init : { *(.initcall.init) }
-  	___initcall_end = .;
+  	.initcall.init : {
+		___initcall_start = .;
+		*(.initcall.init);
+		___initcall_end = .;
+
+		/* We fill to the next page, so we can discard all init
+		   pages without needing to consider what payload might be
+		   appended to the kernel image.  */
+		FILL (0);
+		. = ALIGN (8192);
+	}
 	__vmlinux_end = .;            /* last address of the physical file */
-  	. = ALIGN(8192);
   	___init_end = .;
 
 	__data_end = . ;              /* Move to _edata ? */
diff -u --recursive --new-file v2.4.7/linux/arch/cris/drivers/eeprom.c linux/arch/cris/drivers/eeprom.c
--- v2.4.7/linux/arch/cris/drivers/eeprom.c	Wed Jul 25 17:10:17 2001
+++ linux/arch/cris/drivers/eeprom.c	Thu Jul 26 15:10:06 2001
@@ -20,6 +20,18 @@
 *!                                  in the spin-lock.
 *!
 *!  $Log: eeprom.c,v $
+*!  Revision 1.8  2001/06/15 13:24:29  jonashg
+*!  * Added verification of pointers from userspace in read and write.
+*!  * Made busy counter volatile.
+*!  * Added define for inital write delay.
+*!  * Removed warnings by using loff_t instead of unsigned long.
+*!
+*!  Revision 1.7  2001/06/14 15:26:54  jonashg
+*!  Removed test because condition is always true.
+*!
+*!  Revision 1.6  2001/06/14 15:18:20  jonashg
+*!  Kb -> kB (makes quite a difference if you don't know if you have 2k or 16k).
+*!
 *!  Revision 1.5  2001/06/14 14:39:51  jonashg
 *!  Forgot to use name when registering the driver.
 *!
@@ -59,6 +71,7 @@
 #include <linux/fs.h>
 #include <linux/init.h>
 #include <linux/delay.h>
+#include <asm/uaccess.h>
 #include "i2c.h"
 
 #define D(x) 
@@ -69,6 +82,10 @@
 #define EEPROM_MAJOR_NR 122  /* use a LOCAL/EXPERIMENTAL major for now */
 #define EEPROM_MINOR_NR 0
 
+/* Empirical sane initial value of the delay, the value will be adapted to
+ * what the chip needs when using EEPROM_ADAPTIVE_TIMING.
+ */
+#define INITIAL_WRITEDELAY_US 4000
 #define MAX_WRITEDELAY_US 10000 /* 10 ms according to spec for 2KB EEPROM */
 
 /* This one defines how many times to try when eeprom fails. */
@@ -98,7 +115,7 @@
   
   /* this one is to keep the read/write operations atomic */
   wait_queue_head_t wait_q;
-  int busy;
+  volatile int busy;
   int retry_cnt_addr; /* Used to keep track of number of retries for
                          adaptive timing adjustments */
   int retry_cnt_read;
@@ -114,9 +131,8 @@
 
 static int  eeprom_address(unsigned long addr);
 static int  read_from_eeprom(char * buf, int count);
-static int eeprom_write_buf(unsigned long addr, const char * buf, int count);
-static int eeprom_read_buf(unsigned long addr,
-                           char * buf, int count);
+static int eeprom_write_buf(loff_t addr, const char * buf, int count);
+static int eeprom_read_buf(loff_t addr, char * buf, int count);
 
 static void eeprom_disable_write_protect(void);
 
@@ -159,7 +175,7 @@
 
   /*
    *  Note: Most of this probing method was taken from the printserver (5470e)
-   *        codebase. It did not contain a way of finding the 16Kb chips
+   *        codebase. It did not contain a way of finding the 16kB chips
    *        (M24128 or variants). The method used here might not work
    *        for all models. If you encounter problems the easiest way
    *        is probably to define your model within #ifdef's, and hard-
@@ -167,7 +183,7 @@
    */
 
   eeprom.size = 0;
-  eeprom.usec_delay_writecycles = 4000;/*MAX_WRITEDELAY_US / EEPROM_RETRIES;*/
+  eeprom.usec_delay_writecycles = INITIAL_WRITEDELAY_US;
   eeprom.usec_delay_step = 128;
   eeprom.adapt_state = 0;
   
@@ -181,7 +197,7 @@
     unsigned char buf_2k_start[16];
     
     /* Im not sure this will work... :) */
-    /* assume 2Kb, if failure go for 16Kb */
+    /* assume 2kB, if failure go for 16kB */
     /* Test with 16kB settings.. */
     /* If it's a 2kB EEPROM and we address it outside it's range
      * it will mirror the address space:
@@ -373,17 +389,17 @@
   switch(eeprom.size)
   {
    case (EEPROM_2KB):
-     printk("%s: " EETEXT " i2c compatible 2Kb eeprom.\n", eeprom_name);
+     printk("%s: " EETEXT " i2c compatible 2kB eeprom.\n", eeprom_name);
      eeprom.sequential_write_pagesize = 16;
      eeprom.select_cmd = 0xA0;
      break;
    case (EEPROM_8KB):
-     printk("%s: " EETEXT " i2c compatible 8Kb eeprom.\n", eeprom_name);
+     printk("%s: " EETEXT " i2c compatible 8kB eeprom.\n", eeprom_name);
      eeprom.sequential_write_pagesize = 16;
      eeprom.select_cmd = 0x80;
      break;
    case (EEPROM_16KB):
-     printk("%s: " EETEXT " i2c compatible 16Kb eeprom.\n", eeprom_name);
+     printk("%s: " EETEXT " i2c compatible 16kB eeprom.\n", eeprom_name);
      eeprom.sequential_write_pagesize = 64;
      eeprom.select_cmd = 0xA0;     
      break;
@@ -463,8 +479,7 @@
 
 /* Reads data from eeprom. */
 
-static int eeprom_read_buf(unsigned long addr,
-                           char * buf, int count)
+static int eeprom_read_buf(loff_t addr, char * buf, int count)
 {
   struct file f;
 
@@ -543,7 +558,7 @@
 
 /* Writes data to eeprom. */
 
-static int eeprom_write_buf(unsigned long addr, const char * buf, int count)
+static int eeprom_write_buf(loff_t addr, const char * buf, int count)
 {
   struct file f;
 
@@ -561,6 +576,11 @@
   int i, written, restart=1;
   unsigned long p;
 
+  if (verify_area(VERIFY_READ, buf, count))
+  {
+    return -EFAULT;
+  }
+
   while(eeprom.busy)
   {
     interruptible_sleep_on(&eeprom.wait_q);
@@ -641,11 +661,8 @@
           /* To High before */
           if (eeprom.usec_delay_step > 1)
           {
-            if (eeprom.usec_delay_step > 0)
-            {
-              eeprom.usec_delay_step *= 2;
-              eeprom.usec_delay_step--;
-            }
+            eeprom.usec_delay_step *= 2;
+            eeprom.usec_delay_step--;
             
             if (eeprom.usec_delay_writecycles > eeprom.usec_delay_step)
             {
@@ -807,7 +824,12 @@
 
   while( (read < count))
   {    
-    buf[read++] = i2c_inbyte();      
+    if (put_user(i2c_inbyte(), &buf[read++]))
+    {
+      i2c_stop();
+
+      return -EFAULT;
+    }
 
     /*
      *  make sure we don't ack last byte or you will get very strange
diff -u --recursive --new-file v2.4.7/linux/arch/cris/drivers/lpslave/e100lpslave.S linux/arch/cris/drivers/lpslave/e100lpslave.S
--- v2.4.7/linux/arch/cris/drivers/lpslave/e100lpslave.S	Wed Jul 25 17:10:17 2001
+++ linux/arch/cris/drivers/lpslave/e100lpslave.S	Thu Jul 26 15:10:06 2001
@@ -1,4 +1,4 @@
-	;; $Id: e100lpslave.S,v 1.2 2001/06/11 12:50:01 olof Exp $
+	;; $Id: e100lpslave.S,v 1.3 2001/06/21 16:55:26 olof Exp $
 	;;
 	;; Etrax100 slave network<->parport forwarder
 	;;
@@ -98,7 +98,7 @@
 
 	move.d	r0, [R_PAR1_CONFIG]
 
-	moveq	IO_FIELD(R_PAR1_DELAY, setup, 1), r0    ; setup time of value * 160 + 20
+	moveq	IO_FIELD(R_PAR1_DELAY, setup, 0), r0    ; setup time of value * 160 + 20 == 20 ns
 	move.d	r0, [R_PAR1_DELAY]
 
 	;; we got four descriptors, that can be active at the same time:
diff -u --recursive --new-file v2.4.7/linux/arch/cris/drivers/lpslave/e100lpslavenet.c linux/arch/cris/drivers/lpslave/e100lpslavenet.c
--- v2.4.7/linux/arch/cris/drivers/lpslave/e100lpslavenet.c	Wed Jul 25 17:10:17 2001
+++ linux/arch/cris/drivers/lpslave/e100lpslavenet.c	Thu Jul 26 15:10:06 2001
@@ -1,4 +1,4 @@
-/* $Id: e100lpslavenet.c,v 1.2 2001/06/11 15:39:52 olof Exp $
+/* $Id: e100lpslavenet.c,v 1.4 2001/06/21 16:55:26 olof Exp $
  *
  * e100lpslavenet.c: A network driver for the ETRAX 100LX slave controller.
  *
@@ -7,6 +7,12 @@
  * The outline of this driver comes from skeleton.c.
  *
  * $Log: e100lpslavenet.c,v $
+ * Revision 1.4  2001/06/21 16:55:26  olof
+ * Minimized par port setup time to gain bandwidth
+ *
+ * Revision 1.3  2001/06/21 15:49:02  olof
+ * Removed setting of default MAC address
+ *
  * Revision 1.2  2001/06/11 15:39:52  olof
  * Clean up and sync with ethernet.c rev 1.16. Increased reset time of slave.
  *
@@ -198,10 +204,6 @@
 	dev->get_stats          = e100_get_stats;
 	dev->set_multicast_list = set_multicast_list;
 	dev->set_mac_address    = e100_set_mac_address;
-        
-        /* set the default MAC address */
-
-	e100_set_mac_address(dev, &default_mac);
 
 	/* Initialise the list of Etrax DMA-descriptors */
 
@@ -385,8 +387,8 @@
           /* We want ECP forward mode since PAR1 is TX */
 	 	IO_STATE(R_PAR1_CONFIG, mode, ecp_fwd);        
 
-        /* Setup time of value * 160 + 20 ns == 180 ns below */
-        *R_PAR1_DELAY = IO_FIELD(R_PAR1_DELAY, setup, 1);  
+        /* Setup time of value * 160 + 20 ns == 20 ns below */
+        *R_PAR1_DELAY = IO_FIELD(R_PAR1_DELAY, setup, 0);  
 
         *R_PAR1_CTRL = 0;
 
@@ -944,7 +946,6 @@
 	TxDescList[1].ctrl = d_eol | d_int; 
                                                       
 	TxDescList[1].buf = virt_to_phys(code);
-        /*TxDescList[1].buf = code;*/
 	TxDescList[1].next = 0;
         
         /* setup the dma channel and start it */
diff -u --recursive --new-file v2.4.7/linux/arch/cris/drivers/parport.c linux/arch/cris/drivers/parport.c
--- v2.4.7/linux/arch/cris/drivers/parport.c	Wed Jul 25 17:10:17 2001
+++ linux/arch/cris/drivers/parport.c	Thu Jul 26 15:10:06 2001
@@ -1,4 +1,4 @@
-/* $Id: parport.c,v 1.5 2001/05/09 12:38:42 johana Exp $
+/* $Id: parport.c,v 1.7 2001/06/25 16:17:30 jonashg Exp $
  * 
  * Elinux parallel port driver
  * NOTE!
@@ -49,7 +49,7 @@
  * Par0 in  : DMA3
  * Par1 out : DMA4
  * Par1 in  : DMA5
- * NOTE! par0 is hared with ser2 and par1 is shared with ser3 regarding
+ * NOTE! par0 is shared with ser2 and par1 is shared with ser3 regarding
  *       DMA and DMA irq
  */
 
@@ -80,8 +80,6 @@
 	volatile char *iclrintradr; /* adr to R_DMA_CHx_CLR_INTR, input */
 	volatile u32 *ifirstadr;   /* adr to R_DMA_CHx_FIRST, input */
 	volatile char *icmdadr;     /* adr to R_DMA_CHx_CMD, input */
-	const volatile u8 *istatusadr;  /* adr to R_DMA_CHx_STATUS, input */
-	volatile u32 *ihwswadr;    /* adr to R_DMA_CHx_HWSW, input */
 
 	/* Non DMA interrupt stuff */
 	unsigned long int_irq; /* R_VECT_MASK_RD */
@@ -97,15 +95,6 @@
   
 	/* ----- end of fields initialised in port_table[] below ----- */
 
-	//  struct etrax_dma_descr tr_descr;
-	//  unsigned char tr_buf[LP_BUFFER_SIZE];
-	//  const unsigned char *tr_buf_curr; /* current char sent */
-	//  const unsigned char *tr_buf_last; /* last char in buf */
-  
-	//  int fifo_magic; /* fifo amount - bytes left in dma buffer */
-	//  unsigned char         fifo_didmagic; /* a fifo eop has been forced */
-	//  volatile int          tr_running; /* 1 if output is running */
-	
 	struct parport *port;
   
 	/* Shadow registers */
@@ -132,8 +121,6 @@
 		R_DMA_CH3_CLR_INTR,
 		R_DMA_CH3_FIRST,
 		R_DMA_CH3_CMD,
-		R_DMA_CH3_STATUS,
-		R_DMA_CH3_HWSW,
 		/* Non DMA interrupt stuff */
 		IO_BITNR(R_VECT_MASK_RD, par0),
 		R_IRQ_MASK0_RD,
@@ -161,8 +148,6 @@
 		R_DMA_CH5_CLR_INTR,
 		R_DMA_CH5_FIRST,
 		R_DMA_CH5_CMD,
-		R_DMA_CH5_STATUS,
-		R_DMA_CH5_HWSW,
 		/* Non DMA interrupt stuff */
 		IO_BITNR(R_VECT_MASK_RD, par1),
 		R_IRQ_MASK1_RD,
@@ -418,7 +403,7 @@
 
 /* ----------- Initialisation code --------------------------------- */
 
-static void 
+static void __init
 parport_etrax_show_parallel_version(void)
 {
 	printk("ETRAX 100LX parallel port driver v1.0, (c) 2001 Axis Communications AB\n");
@@ -436,15 +421,11 @@
 #define PAR1_USE_DMA 0
 #endif
 
-static void 
+static void __init
 parport_etrax_init_registers(void)
 {
 	struct etrax100par_struct *info;
 	int i;
-
-	/* The different times below will be (value*160 + 20) ns,    */
-	/* i.e. 20ns-4.98us. E.g. if setup is set to 00110 (0x6),    */
-	/* the setup time will be (6*160+20) = 980ns.                */
 
 	for (i = 0, info = port_table; i < 2; i++, info++) {
 #ifndef CONFIG_ETRAX_PARALLEL_PORT0
diff -u --recursive --new-file v2.4.7/linux/arch/cris/kernel/Makefile linux/arch/cris/kernel/Makefile
--- v2.4.7/linux/arch/cris/kernel/Makefile	Wed Jul 25 17:10:17 2001
+++ linux/arch/cris/kernel/Makefile	Thu Jul 26 15:10:06 2001
@@ -1,4 +1,4 @@
-# $Id: Makefile,v 1.5 2001/05/15 05:10:00 hp Exp $
+# $Id: Makefile,v 1.7 2001/07/05 01:11:48 hp Exp $
 #
 # Makefile for the linux kernel.
 #
@@ -8,8 +8,10 @@
 #
 # Note 2! The CFLAGS definitions are now in the main makefile...
 
+# These assembly files can't be assembld with -traditional, so we
+# need another build rule than the one in the toplevel Makefile.
 .S.o:
-	$(CC) $(AFLAGS) -traditional -c $< -o $*.o
+	$(CC) $(AFLAGS) -c $< -o $*.o
 
 all: kernel.o head.o
 
@@ -20,6 +22,7 @@
 
 obj-$(CONFIG_ETRAX_KGDB) += kgdb.o
 
+# This dependency isn't caught by mkdep.  See entry.S.
 entry.o: entryoffsets.s
 
 entryoffsets.s: entryoffsets.c
diff -u --recursive --new-file v2.4.7/linux/arch/cris/kernel/entry.S linux/arch/cris/kernel/entry.S
--- v2.4.7/linux/arch/cris/kernel/entry.S	Wed Jul 25 17:10:17 2001
+++ linux/arch/cris/kernel/entry.S	Thu Jul 26 15:10:06 2001
@@ -1,4 +1,4 @@
-/* $Id: entry.S,v 1.27 2001/05/29 11:25:27 markusl Exp $
+/* $Id: entry.S,v 1.31 2001/07/25 16:07:42 bjornw Exp $
  *
  *  linux/arch/cris/entry.S
  *
@@ -7,6 +7,36 @@
  *  Authors:	Bjorn Wesen (bjornw@axis.com)
  *
  *  $Log: entry.S,v $
+ *  Revision 1.31  2001/07/25 16:07:42  bjornw
+ *  softirq_active/mask -> softirq_pending only
+ *
+ *  Revision 1.30  2001/07/05 01:03:32  hp
+ *  - include asm/errno.h to get ENOSYS.
+ *  - Use ENOSYS, not local constant LENOSYS; tweak comments.
+ *  - Explain why .include, not #include is used.
+ *  - Make oops-register-dump if watchdog bits and it's not expected.
+ *  - Don't jsr, use jump _hard_reset_now, and skip spurious nop.
+ *  - Use correct section attribute for section .rodata.
+ *  - Adjust sys_ni_syscall fill number.
+ *
+ *  Revision 1.29  2001/06/25 14:07:00  hp
+ *  	Fix review comment.
+ *  	* head.S: Use IO_STATE, IO_FIELD and IO_MASK constructs instead of
+ *  	magic numbers.  Add comment that -traditional must not be used.
+ *  	* entry.S (SYMBOL_NAME): Change redefinition to use ## concatenation.
+ *  	Correct and update comment.
+ *  	* Makefile (.S.o): Don't use -traditional.  Add comment why the
+ *  	toplevel rule can't be used (now that there's a reason).
+ *
+ *  Revision 1.28  2001/06/21 02:00:40  hp
+ *  	* entry.S: Include asm/unistd.h.
+ *  	(_sys_call_table): Use section .rodata, not .data.
+ *  	(_kernel_thread): Move from...
+ *  	* process.c: ... here.
+ *  	* entryoffsets.c (VAL): Break out from...
+ *  	(OF): Use VAL.
+ *  	(LCLONE_VM): New asmified value from CLONE_VM.
+ *
  *  Revision 1.27  2001/05/29 11:25:27  markusl
  *  In case of "spurious_interrupt", do hard_reset instead of hanging system in a loop...
  *
@@ -130,7 +160,9 @@
 #include <linux/config.h>
 #include <linux/linkage.h>
 #include <linux/sys.h>
+#include <asm/unistd.h>
 #include <asm/sv_addr_ag.h>
+#include <asm/errno.h>
 	
 	;; functions exported from this file
 	
@@ -151,11 +183,9 @@
 			
 	.globl _sys_call_table
 	
-	;; syscall error codes
-	
-LENOSYS = 38
-
-	;; Get offsets into various structs.
+	;; Get values and offsets into various structs.  The file isn't
+	;; suitable for consumption by the preprocessor, so don't use
+	;; #include.
 	.include "entryoffsets.s"
 
 	;; process bits for ptrace.  FIXME: Should be in a header file.
@@ -227,7 +257,7 @@
 	push	r10		; push orig_r10
 	clear.d [sp=sp-4]	; frametype == 0, normal stackframe
 	
-	movs.w	-LENOSYS,r0
+	movs.w	-ENOSYS,r0
 	move.d	r0,[sp+LR10]	; put the default return value in r10 in the frame
 
 	;; check if this process is syscall-traced
@@ -271,9 +301,7 @@
 		
 	;; check if any bottom halves need service
 	
-	move.d	_irq_stat,r10
-	move.d	[r10+],r0	       ; softirq_active
-	and.d	[r10],r0	       ; softirq_mask
+	test.d	[_irq_stat]	       ; softirq_pending
 	bne	handle_softirq
 	nop
 
@@ -320,8 +348,8 @@
 
 tracesys:
 	;; this first invocation of syscall_trace _requires_ that
-	;; LR10 in the frame contains -LENOSYS (as is set in the beginning
-	;; of system_call
+	;; LR10 in the frame contains -ENOSYS (as is set in the beginning
+	;; of system_call).
 
 	jsr	_syscall_trace
 
@@ -333,7 +361,7 @@
 	;; check for sanity in the requested syscall number
 
 	move.d	[sp+LR9], r9
-	movs.w	-LENOSYS, r10
+	movs.w	-ENOSYS, r10
 	cmpu.w	NR_syscalls,r9	
 	bcc	1f
 	lslq	2,r9		;  multiply by 4, in the delay slot
@@ -344,7 +372,7 @@
 
 	;; restore r10, r11, r12, r13, mof and srp into the needed registers
 
-	move.d	[sp+LORIG_R10], r10  ; LR10 is already filled with -LENOSYS
+	move.d	[sp+LORIG_R10], r10  ; LR10 is already filled with -ENOSYS.
 	move.d	[sp+LR11],      r11
 	move.d	[sp+LR12],      r12
 	move.d	[sp+LR13],      r13
@@ -484,10 +512,72 @@
 #endif
 	
 _IRQ1_interrupt:
-_spurious_interrupt:	
+
+#if defined(CONFIG_ETRAX_WATCHDOG) && !defined(CONFIG_SVINTO_SIM)
+;; If we receive a watchdog interrupt while it is not expected, then set
+;; up a canonical frame and dump register contents before dying.
+
+	;; this prologue MUST match the one in irq.h and the struct in ptregs.h!!!
+	move	brp,[sp=sp-16]	; instruction pointer and room for a fake SBFS frame
+	push	srp
+	push	dccr
+	push	mof
 	di
-	jsr _hard_reset_now
+	subq	14*4,sp
+	movem	r13,[sp]
+	push	r10		; push orig_r10
+	clear.d [sp=sp-4]	; frametype == 0, normal frame
+
+;; We don't check that we actually were bit by the watchdog as opposed to
+;; an external NMI, since there is currently no handler for external NMI.
+
+;; We'll see this in ksymoops dumps.
+Watchdog_bite:
+
+;; We need to extend the 3.3ms after the NMI at watchdog bite, so we have
+;; time for an oops-dump over a 115k2 serial wire.  Another 100ms should do.
+
+;; Change the watchdog key to an arbitrary 3-bit value and restart the
+;; watchdog.
+#define WD_INIT 2
+	moveq	  IO_FIELD (R_WATCHDOG, key, WD_INIT), r10
+	move.d	R_WATCHDOG, r11
+
+	move.d	r10,[r11]
+	moveq	  IO_FIELD (R_WATCHDOG, key,				\
+			    IO_EXTRACT (R_WATCHDOG, key,		\
+					IO_MASK (R_WATCHDOG, key))	\
+			    ^ WD_INIT)					\
+		| IO_STATE (R_WATCHDOG, enable, start),r10
+	move.d	r10,[r11]
+
+;; Note that we don't do "setf m" here (or after two necessary NOPs),
+;; since *not* doing that saves us from re-entrancy checks.  We don't want
+;; to get here again due to possible subsequent NMIs; we want the watchdog
+;; to reset us.
+
+	move.d	watchdogmsg,r10
+	jsr	_printk
+
+	move.d	sp,r10
+	jsr	_show_registers
+
+;; This nop is here so we see the "Watchdog_bite" label in ksymoops dumps
+;; rather than "_spurious_interrupt".
 	nop
+;; At this point we drop down into _spurious_interrupt, which will do a
+;; hard reset.
+
+	.section .rodata,"a"
+watchdogmsg:
+	.ascii	"Oops: bitten by watchdog\n\0"
+	.previous
+
+#endif /* CONFIG_ETRAX_WATCHDOG and not CONFIG_SVINTO_SIM */
+
+_spurious_interrupt:	
+	di
+	jump _hard_reset_now
 
 	;; this handles the case when multiple interrupts arrive at the same time
 	;; we jump to the first set interrupt bit in a priority fashion
@@ -579,14 +669,80 @@
 _hw_bp_trig_ptr:
 	.dword _hw_bp_trigs
 
-/* Because we compile this file with -traditional, we need to redefine
-   token-concatenation to the traditional trick, using an empty comment.
-   Normally (in other files, with ISO C as in gcc default) this is done
-   with the ## preprocessor operator.  */
+/*
+ * This is the mechanism for creating a new kernel thread.
+ *
+ * NOTE! Only a kernel-only process (i.e. the swapper or direct descendants
+ * who haven't done an "execve()") should use this: it will work within
+ * a system call from a "real" process, but the process memory space will
+ * not be free'd until both the parent and the child have exited.
+ *
+ * This *can* be done in C with an single-asm-wrapped-in-a-function, but you
+ * get more or less gross code.  The safer you make the asm-constraints,
+ * the grosser the code, at least with the gcc version in cris-dist-1.13.
+ */
+
+/* int kernel_thread(int (*fn)(void *), void * arg, unsigned long flags) */
+/*                   r10                r11         r12  */
+
+	.text
+	.global _kernel_thread
+_kernel_thread:
+
+	/* Save ARG for later.  */
+	move.d r11,r13
+
+	/* r11 is argument 2 to clone, the flags */
+	move.d r12,r11
+	or.w	LCLONE_VM,r11
+
+	/* Save FN for later.  */
+	move.d	r10,r12
+
+	/* r9 contains syscall number, to sys_clone */
+	movu.w	__NR_clone,r9
+
+	/* r10 is argument 1 to clone */
+	clear.d	r10
+	
+	/* call sys_clone, this will fork */
+	break	13
+
+	/* parent or child? child returns 0 here. */
+	test.d	r10
+
+	/* jump if parent */
+	bne	1f
+	nop              /* delay slot */
+
+	/* set argument to function to call */
+	move.d	r13,r10
+
+	/* call specified function */
+	jsr	r12
+	/* If we ever return from the function, something bad has happened.  */
+
+	/* r9 is sys_exit syscall number */
+	movu.w	__NR_exit,r9
+
+	/* Give a really bad exit-value */
+	moveq	-1,r10
+
+	/* call sys_exit, killing the child */
+	break	13
+1:
+	ret
+	nop              /* delay slot */
+
+
+/* The file include/linux/linkage.h is wrong for compiling the
+   Linux/CRIS kernel.  We currently have C symbols in the kernel (only
+   the kernel) prefixed with _, hence, we need to redefine SYMBOL_NAME.  */
 
 #undef SYMBOL_NAME
-#define SYMBOL_NAME(X) _/**/X
-		
+#define SYMBOL_NAME(X) _##X
+
+	.section .rodata,"a"
 _sys_call_table:	
 	.long SYMBOL_NAME(sys_ni_syscall)	/* 0  -  old "setup()" system call*/
 	.long SYMBOL_NAME(sys_exit)
@@ -819,7 +975,7 @@
          * been shrunk every time we add a new system call.
          */
 
-	.rept NR_syscalls-221
+	.rept NR_syscalls-222
 		.long SYMBOL_NAME(sys_ni_syscall)
 	.endr
 	
diff -u --recursive --new-file v2.4.7/linux/arch/cris/kernel/entryoffsets.c linux/arch/cris/kernel/entryoffsets.c
--- v2.4.7/linux/arch/cris/kernel/entryoffsets.c	Wed Jul 25 17:10:17 2001
+++ linux/arch/cris/kernel/entryoffsets.c	Thu Jul 26 15:10:06 2001
@@ -18,16 +18,20 @@
 #include <asm/processor.h>
 
 /* Exclude everything except the assembly by wrapping it in ".if 0".  */
-#undef OF
-#define OF(NAME, TYPE, MEMBER)			\
+#undef VAL
+#define VAL(NAME, VALUE)			\
 void NAME ## _fun (void)			\
  {						\
   __asm__ (".endif \n"				\
 	   #NAME " = %0 \n"			\
 	   ".if 0\n"				\
-	   : : "i" (offsetof (TYPE, MEMBER)));	\
+	   : : "i" (VALUE));			\
  }
 
+#undef OF
+#define OF(NAME, TYPE, MEMBER)			\
+  VAL (NAME, offsetof (TYPE, MEMBER))
+
 /* task_struct offsets.  */
 OF (LTASK_SIGPENDING, struct task_struct, sigpending)
 OF (LTASK_NEEDRESCHED, struct task_struct, need_resched)
@@ -50,5 +54,8 @@
 OF (LTHREAD_KSP, struct thread_struct, ksp)
 OF (LTHREAD_USP, struct thread_struct, usp)
 OF (LTHREAD_DCCR, struct thread_struct, dccr)
+
+/* linux/sched.h values - doesn't have an #ifdef __ASSEMBLY__ for these.  */
+VAL (LCLONE_VM, CLONE_VM)
 
 __asm__ (".endif");
diff -u --recursive --new-file v2.4.7/linux/arch/cris/kernel/head.S linux/arch/cris/kernel/head.S
--- v2.4.7/linux/arch/cris/kernel/head.S	Wed Jul 25 17:10:17 2001
+++ linux/arch/cris/kernel/head.S	Thu Jul 26 15:10:06 2001
@@ -1,4 +1,4 @@
-/* $Id: head.S,v 1.34 2001/05/15 07:08:14 hp Exp $
+/* $Id: head.S,v 1.36 2001/06/29 12:39:31 pkj Exp $
  * 
  * Head of the kernel - alter with care
  *
@@ -7,6 +7,19 @@
  * Authors:	Bjorn Wesen (bjornw@axis.com)
  * 
  * $Log: head.S,v $
+ * Revision 1.36  2001/06/29 12:39:31  pkj
+ * Added support for mirroring the first flash to just below the
+ * second one, to make them look consecutive to cramfs.
+ *
+ * Revision 1.35  2001/06/25 14:07:00  hp
+ * 	Fix review comment.
+ * 	* head.S: Use IO_STATE, IO_FIELD and IO_MASK constructs instead of
+ * 	magic numbers.  Add comment that -traditional must not be used.
+ * 	* entry.S (SYMBOL_NAME): Change redefinition to use ## concatenation.
+ * 	Correct and update comment.
+ * 	* Makefile (.S.o): Don't use -traditional.  Add comment why the
+ * 	toplevel rule can't be used (now that there's a reason).
+ *
  * Revision 1.34  2001/05/15 07:08:14  hp
  * Tweak "notice" to reflect that both r8 r9 are used
  *
@@ -122,6 +135,8 @@
 	
 #include <linux/config.h>
 #define ASSEMBLER_MACROS_ONLY
+/* The IO_* macros use the ## token concatenation operator, so
+   -traditional must not be used when assembling this file.  */
 #include <asm/sv_addr_ag.h>
 
 #define CRAMFS_MAGIC 0x28cd3d45
@@ -165,22 +180,72 @@
 	;; 1G per process with CONFIG_CRIS_LOW_MAP.
 
 #ifdef CONFIG_CRIS_LOW_MAP
-	move.d	0x0004b098, r0	; kseg mappings, temporary map of 0xc0->0x40
+	; kseg mappings, temporary map of 0xc0->0x40
+ 	move.d	  IO_FIELD (R_MMU_KBASE_HI, base_c, 4)		\
+		| IO_FIELD (R_MMU_KBASE_HI, base_b, 0xb)	\
+		| IO_FIELD (R_MMU_KBASE_HI, base_9, 9)		\
+		| IO_FIELD (R_MMU_KBASE_HI, base_8, 8), r0
 	move.d	r0, [R_MMU_KBASE_HI]
 
-	move.d	0x04040000, r0	; temporary map of 0x40->0x40 and 0x00->0x00 
+	; temporary map of 0x40->0x40 and 0x60->0x40 
+ 	move.d	  IO_FIELD (R_MMU_KBASE_LO, base_6, 4)		\
+		| IO_FIELD (R_MMU_KBASE_LO, base_4, 4), r0
 	move.d	r0, [R_MMU_KBASE_LO]
 
-	move.d	0x80075c71, r0	; mmu enable, segs c,b,9,8,6,5,4,0 segment mapped
+	; mmu enable, segs e,c,b,a,6,5,4,0 segment mapped
+ 	move.d	  IO_STATE (R_MMU_CONFIG, mmu_enable, enable)	\
+		| IO_STATE (R_MMU_CONFIG, inv_excp, enable)	\
+		| IO_STATE (R_MMU_CONFIG, acc_excp, enable)	\
+		| IO_STATE (R_MMU_CONFIG, we_excp, enable)	\
+		| IO_STATE (R_MMU_CONFIG, seg_f, page)		\
+		| IO_STATE (R_MMU_CONFIG, seg_e, seg)		\
+		| IO_STATE (R_MMU_CONFIG, seg_d, page)		\
+		| IO_STATE (R_MMU_CONFIG, seg_c, seg)		\
+		| IO_STATE (R_MMU_CONFIG, seg_b, seg)		\
+		| IO_STATE (R_MMU_CONFIG, seg_a, seg)		\
+		| IO_STATE (R_MMU_CONFIG, seg_9, page)		\
+		| IO_STATE (R_MMU_CONFIG, seg_8, page)		\
+		| IO_STATE (R_MMU_CONFIG, seg_7, page)		\
+		| IO_STATE (R_MMU_CONFIG, seg_6, seg)		\
+		| IO_STATE (R_MMU_CONFIG, seg_5, seg)		\
+		| IO_STATE (R_MMU_CONFIG, seg_4, seg)		\
+		| IO_STATE (R_MMU_CONFIG, seg_3, page)		\
+		| IO_STATE (R_MMU_CONFIG, seg_2, page)		\
+		| IO_STATE (R_MMU_CONFIG, seg_1, page)		\
+		| IO_STATE (R_MMU_CONFIG, seg_0, seg), r0
 	move.d	r0, [R_MMU_CONFIG]
 #else
-	move.d	0x0804b000, r0	; kseg mappings
+	; kseg mappings
+ 	move.d	  IO_FIELD (R_MMU_KBASE_HI, base_e, 8)		\
+		| IO_FIELD (R_MMU_KBASE_HI, base_c, 4)		\
+		| IO_FIELD (R_MMU_KBASE_HI, base_b, 0xb), r0
 	move.d	r0, [R_MMU_KBASE_HI]
 
-	move.d	0x00040000, r0	; temporary map of 0x40->0x40 and 0x00->0x00 
+	; temporary map of 0x40->0x40 and 0x00->0x00 
+	move.d	  IO_FIELD (R_MMU_KBASE_LO, base_4, 4), r0
 	move.d	r0, [R_MMU_KBASE_LO]
 
-	move.d	0x8007d811, r0	; mmu enable, segs f,e,c,b,4,0 segment mapped
+	; mmu enable, segs f,e,c,b,4,0 segment mapped
+ 	move.d	  IO_STATE (R_MMU_CONFIG, mmu_enable, enable)	\
+		| IO_STATE (R_MMU_CONFIG, inv_excp, enable)	\
+		| IO_STATE (R_MMU_CONFIG, acc_excp, enable)	\
+		| IO_STATE (R_MMU_CONFIG, we_excp, enable)	\
+		| IO_STATE (R_MMU_CONFIG, seg_f, seg)		\
+		| IO_STATE (R_MMU_CONFIG, seg_e, seg)		\
+		| IO_STATE (R_MMU_CONFIG, seg_d, page)		\
+		| IO_STATE (R_MMU_CONFIG, seg_c, seg)		\
+		| IO_STATE (R_MMU_CONFIG, seg_b, seg)		\
+		| IO_STATE (R_MMU_CONFIG, seg_a, page)		\
+		| IO_STATE (R_MMU_CONFIG, seg_9, page)		\
+		| IO_STATE (R_MMU_CONFIG, seg_8, page)		\
+		| IO_STATE (R_MMU_CONFIG, seg_7, page)		\
+		| IO_STATE (R_MMU_CONFIG, seg_6, page)		\
+		| IO_STATE (R_MMU_CONFIG, seg_5, page)		\
+		| IO_STATE (R_MMU_CONFIG, seg_4, seg)		\
+		| IO_STATE (R_MMU_CONFIG, seg_3, page)		\
+		| IO_STATE (R_MMU_CONFIG, seg_2, page)		\
+		| IO_STATE (R_MMU_CONFIG, seg_1, page)		\
+		| IO_STATE (R_MMU_CONFIG, seg_0, seg), r0
 	move.d	r0, [R_MMU_CONFIG]
 #endif
 
@@ -309,6 +374,9 @@
 #else
 	add.d   0xf0000000, r9	; add flash start in virtual memory (cached)
 #endif
+#ifdef CONFIG_ETRAX_FLASH_MIRRORING_FOR_CRAMFS
+	add.d   MEM_CSE1_START-CONFIG_ETRAX_FLASH_SIZE*0x100000, r9   ; move flash start to upper mirror
+#endif
 	move.d	r9, [_romfs_start]
 
 	moveq	1, r0
@@ -406,26 +474,34 @@
 	
 	moveq	0,r0
 	move.d	r0,[R_EXT_DMA_0_ADDR]
-	move.d	0x860000,r0	; cnt enable, word size, output, stop, size 0
+	; cnt enable, word size, output, stop, size 0
+	move.d	  IO_STATE (R_EXT_DMA_0_CMD, cnt, enable)	\
+		| IO_STATE (R_EXT_DMA_0_CMD, rqpol, ahigh)	\
+		| IO_STATE (R_EXT_DMA_0_CMD, apol, ahigh)	\
+		| IO_STATE (R_EXT_DMA_0_CMD, rq_ack, burst)	\
+		| IO_STATE (R_EXT_DMA_0_CMD, wid, word)		\
+		| IO_STATE (R_EXT_DMA_0_CMD, dir, output)	\
+		| IO_STATE (R_EXT_DMA_0_CMD, run, stop)		\
+		| IO_FIELD (R_EXT_DMA_0_CMD, trf_count, 0),r0
 	move.d	r0,[R_EXT_DMA_0_CMD]
 
 	;; reset dma4 and wait for completion
 	
-	moveq	4,r0
+	moveq	IO_STATE (R_DMA_CH4_CMD, cmd, reset),r0
 	move.b	r0,[R_DMA_CH4_CMD]
 w4u:	move.b	[R_DMA_CH4_CMD],r0
-	and.b	7,r0
-	cmp.b	4,r0
+	and.b	IO_MASK (R_DMA_CH4_CMD, cmd),r0
+	cmp.b	IO_STATE (R_DMA_CH4_CMD, cmd, reset),r0
 	beq	w4u
 	nop
 
 	;; reset dma5 and wait for completion
 	
-	moveq	4,r0
+	moveq	IO_STATE (R_DMA_CH5_CMD, cmd, reset),r0
 	move.b	r0,[R_DMA_CH5_CMD]
 w5u:	move.b	[R_DMA_CH5_CMD],r0
-	and.b	7,r0
-	cmp.b	4,r0
+	and.b	IO_MASK (R_DMA_CH5_CMD, cmd),r0
+	cmp.b	IO_STATE (R_DMA_CH5_CMD, cmd, reset),r0
 	beq	w5u
 	nop
 #endif	
@@ -434,42 +510,66 @@
 
 	moveq	0,r0
 #if !defined(CONFIG_ETRAX_KGDB) && !defined(CONFIG_DMA_MEMCPY)
-	or.d	0x140000,r0	; DMA channels 6 and 7 to ser0, kgdb doesnt want DMA
+	; DMA channels 6 and 7 to ser0, kgdb doesnt want DMA
+	or.d	  IO_STATE (R_GEN_CONFIG, dma7, serial0)	\
+		| IO_STATE (R_GEN_CONFIG, dma6, serial0),r0
 #endif
 #if !defined(CONFIG_ETRAX_KGDB) || !defined(CONFIG_ETRAX_DEBUG_PORT1)	
-	or.d	0xc00000,r0	; DMA channels 8 and 9 to ser1, kgdb doesnt want DMA
+	or.d	  IO_STATE (R_GEN_CONFIG, dma9, serial1)	\
+		| IO_STATE (R_GEN_CONFIG, dma8, serial1),r0
 #endif	
 #ifdef CONFIG_DMA_MEMCPY
-	or.d	0x003c0000,r0	; 6/7 memory-memory DMA
+	; 6/7 memory-memory DMA
+	or.d	  IO_STATE (R_GEN_CONFIG, dma7, intdma6)	\
+		| IO_STATE (R_GEN_CONFIG, dma6, intdma7),r0
 #endif
 #ifdef CONFIG_ETRAX_SERIAL_PORT2
-	or.d	0x2808,r0	; DMA channels 2 and 3 to serport 2, port 2 enabled
+	; DMA channels 2 and 3 to serport 2, port 2 enabled
+	or.d	  IO_STATE (R_GEN_CONFIG, dma3, serial2)	\
+		| IO_STATE (R_GEN_CONFIG, dma2, serial2)	\
+		| IO_STATE (R_GEN_CONFIG, ser2, select),r0
 #endif
 #if defined(CONFIG_ETRAX_SERIAL_PORT3) || defined(CONFIG_ETRAX_SYNCHRONOUS_SERIAL_PORT1)
-	or.d	0x28100,r0	; DMA channels 4 and 5 to serport 3, port 3 enabled
+	; DMA channels 4 and 5 to serport 3, port 3 enabled
+	or.d	  IO_STATE (R_GEN_CONFIG, dma5, serial3)	\
+		| IO_STATE (R_GEN_CONFIG, dma4, serial3)	\
+		| IO_STATE (R_GEN_CONFIG, ser3, select),r0
 #endif	
 #if defined(CONFIG_ETRAX_PARALLEL_PORT0) || defined(CONFIG_ETRAX_ETHERNET_LPSLAVE)
-	or.w	0x4,r0	; parport 0 enabled using DMA 2/3
+	; parport 0 enabled using DMA 2/3
+	or.w	IO_STATE (R_GEN_CONFIG, par0, select),r0
 #endif
 #if defined(CONFIG_ETRAX_PARALLEL_PORT1) || defined(CONFIG_ETRAX_ETHERNET_LPSLAVE)
-	or.w	0x80,r0	; parport 1 enabled using DMA 4/5
+	; parport 1 enabled using DMA 4/5
+	or.w	IO_STATE (R_GEN_CONFIG, par1, select),r0
 #endif
 #ifdef CONFIG_ETRAX_IDE
-	or.d	0x3c02,r0	; DMA channels 2 and 3 to ATA, ATA enabled
+	; DMA channels 2 and 3 to ATA, ATA enabled
+	or.d	  IO_STATE (R_GEN_CONFIG, dma3, ata)	\
+		| IO_STATE (R_GEN_CONFIG, dma2, ata)	\
+		| IO_STATE (R_GEN_CONFIG, ata, select),r0
 #endif
 	
 #ifdef CONFIG_ETRAX_USB_HOST_PORT1
-	or.d	0x20000000,r0	; Set the USB port 1 enable bit
+	; Set the USB port 1 enable bit
+	or.d	IO_STATE (R_GEN_CONFIG, usb1, select),r0
 #endif
 #ifdef CONFIG_ETRAX_USB_HOST_PORT2
-	or.d	0x40000000,r0	; Set the USB port 2 enable bit
+	; Set the USB port 2 enable bit
+	or.d	IO_STATE (R_GEN_CONFIG, usb2, select),r0
 #endif
 #ifdef CONFIG_ETRAX_USB_HOST
-	and.d	0xff3fffff,r0	; Connect DMA channels 8 and 9 to USB
+	; Connect DMA channels 8 and 9 to USB
+	and.d	(~(IO_MASK (R_GEN_CONFIG, dma9)		\
+		   | IO_MASK (R_GEN_CONFIG, dma8)))	\
+		| IO_STATE (R_GEN_CONFIG, dma9, usb)	\
+		| IO_STATE (R_GEN_CONFIG, dma8, usb),r0
 #endif
 	
 #ifdef CONFIG_JULIETTE
-	or.d	0x3c000,r0	; DMA channels 4 and 5 to EXTDMA0, for Juliette
+	; DMA channels 4 and 5 to EXTDMA0, for Juliette
+	or.d	  IO_STATE (R_GEN_CONFIG, dma5, extdma0)	\
+		| IO_STATE (R_GEN_CONFIG, dma4, extdma0),r0
 #endif
 	move.d	r0,[_genconfig_shadow] ; init a shadow register of R_GEN_CONFIG
 
@@ -492,17 +592,17 @@
 	nop
 #endif
 	
-	moveq	4,r0
+	moveq	IO_STATE (R_DMA_CH8_CMD, cmd, reset),r0
 	move.b	r0,[R_DMA_CH8_CMD]	; reset (ser1 dma out)
 	move.b	r0,[R_DMA_CH9_CMD]	; reset (ser1 dma in)
 w81:	move.b	[R_DMA_CH8_CMD],r0	; wait for reset cycle to finish
-	and.b	7,r0
-	cmp.b	4,r0
+	and.b	IO_MASK (R_DMA_CH8_CMD, cmd),r0
+	cmp.b	IO_STATE (R_DMA_CH8_CMD, cmd, reset),r0
 	beq	w81
 	nop
 w91:	move.b	[R_DMA_CH9_CMD],r0	; wait for reset cycle to finish
-	and.b	7,r0
-	cmp.b	4,r0
+	and.b	IO_MASK (R_DMA_CH9_CMD, cmd),r0
+	cmp.b	IO_STATE (R_DMA_CH9_CMD, cmd, reset),r0
 	beq	w91
 	nop
 
@@ -535,46 +635,106 @@
 	
 	;; setup the serial port 0 at 115200 baud for debug purposes
 	
-	moveq	0,r0
+	moveq	  IO_STATE (R_SERIAL0_XOFF, tx_stop, enable)		\
+		| IO_STATE (R_SERIAL0_XOFF, auto_xoff, disable)		\
+		| IO_FIELD (R_SERIAL0_XOFF, xoff_char, 0),r0
 	move.d	r0,[R_SERIAL0_XOFF] 
 
-	move.b	0x99,r0
-	move.b	r0,[R_SERIAL0_BAUD]	; 115.2kbaud for both transmit and receive
-
-	move.b	0x40,r0			; rec enable
+	; 115.2kbaud for both transmit and receive
+	move.b	  IO_STATE (R_SERIAL0_BAUD, tr_baud, c115k2Hz)		\
+		| IO_STATE (R_SERIAL0_BAUD, rec_baud, c115k2Hz),r0
+	move.b	r0,[R_SERIAL0_BAUD]
+
+	; Set up and enable the serial0 receiver.
+	move.b	  IO_STATE (R_SERIAL0_REC_CTRL, dma_err, stop)		\
+		| IO_STATE (R_SERIAL0_REC_CTRL, rec_enable, enable)	\
+		| IO_STATE (R_SERIAL0_REC_CTRL, rts_, active)		\
+		| IO_STATE (R_SERIAL0_REC_CTRL, sampling, middle)	\
+		| IO_STATE (R_SERIAL0_REC_CTRL, rec_stick_par, normal)	\
+		| IO_STATE (R_SERIAL0_REC_CTRL, rec_par, even)		\
+		| IO_STATE (R_SERIAL0_REC_CTRL, rec_par_en, disable)	\
+		| IO_STATE (R_SERIAL0_REC_CTRL, rec_bitnr, rec_8bit),r0
 	move.b	r0,[R_SERIAL0_REC_CTRL] 
 	
-	move.b	0x40,r0			; tr enable
+	; Set up and enable the serial0 transmitter.
+	move.b	  IO_FIELD (R_SERIAL0_TR_CTRL, txd, 0)			\
+		| IO_STATE (R_SERIAL0_TR_CTRL, tr_enable, enable)	\
+		| IO_STATE (R_SERIAL0_TR_CTRL, auto_cts, disabled)	\
+		| IO_STATE (R_SERIAL0_TR_CTRL, stop_bits, one_bit)	\
+		| IO_STATE (R_SERIAL0_TR_CTRL, tr_stick_par, normal)	\
+		| IO_STATE (R_SERIAL0_TR_CTRL, tr_par, even)		\
+		| IO_STATE (R_SERIAL0_TR_CTRL, tr_par_en, disable)	\
+		| IO_STATE (R_SERIAL0_TR_CTRL, tr_bitnr, tr_8bit),r0
 	move.b	r0,[R_SERIAL0_TR_CTRL]
 
 	;; setup the serial port 1 at 115200 baud for debug purposes
 	
-	moveq	0,r0
+	moveq	  IO_STATE (R_SERIAL1_XOFF, tx_stop, enable)		\
+		| IO_STATE (R_SERIAL1_XOFF, auto_xoff, disable)		\
+		| IO_FIELD (R_SERIAL1_XOFF, xoff_char, 0),r0
 	move.d	r0,[R_SERIAL1_XOFF] 
 
-	move.b	0x99,r0
-	move.b	r0,[R_SERIAL1_BAUD]	; 115.2kbaud for both transmit and receive
-
-	move.b	0x40,r0			; rec enable
+	; 115.2kbaud for both transmit and receive
+	move.b	  IO_STATE (R_SERIAL1_BAUD, tr_baud, c115k2Hz)		\
+		| IO_STATE (R_SERIAL1_BAUD, rec_baud, c115k2Hz),r0
+	move.b	r0,[R_SERIAL1_BAUD]
+
+	; Set up and enable the serial1 receiver.
+	move.b	  IO_STATE (R_SERIAL1_REC_CTRL, dma_err, stop)		\
+		| IO_STATE (R_SERIAL1_REC_CTRL, rec_enable, enable)	\
+		| IO_STATE (R_SERIAL1_REC_CTRL, rts_, active)		\
+		| IO_STATE (R_SERIAL1_REC_CTRL, sampling, middle)	\
+		| IO_STATE (R_SERIAL1_REC_CTRL, rec_stick_par, normal)	\
+		| IO_STATE (R_SERIAL1_REC_CTRL, rec_par, even)		\
+		| IO_STATE (R_SERIAL1_REC_CTRL, rec_par_en, disable)	\
+		| IO_STATE (R_SERIAL1_REC_CTRL, rec_bitnr, rec_8bit),r0
 	move.b	r0,[R_SERIAL1_REC_CTRL] 
 	
-	move.b	0x40,r0			; tr enable
+	; Set up and enable the serial1 transmitter.
+	move.b	  IO_FIELD (R_SERIAL1_TR_CTRL, txd, 0)			\
+		| IO_STATE (R_SERIAL1_TR_CTRL, tr_enable, enable)	\
+		| IO_STATE (R_SERIAL1_TR_CTRL, auto_cts, disabled)	\
+		| IO_STATE (R_SERIAL1_TR_CTRL, stop_bits, one_bit)	\
+		| IO_STATE (R_SERIAL1_TR_CTRL, tr_stick_par, normal)	\
+		| IO_STATE (R_SERIAL1_TR_CTRL, tr_par, even)		\
+		| IO_STATE (R_SERIAL1_TR_CTRL, tr_par_en, disable)	\
+		| IO_STATE (R_SERIAL1_TR_CTRL, tr_bitnr, tr_8bit),r0
 	move.b	r0,[R_SERIAL1_TR_CTRL]
 
 	
 #ifdef CONFIG_ETRAX_SERIAL_PORT3	
 	;; setup the serial port 3 at 115200 baud for debug purposes
 	
-	moveq	0,r0
+	moveq	  IO_STATE (R_SERIAL3_XOFF, tx_stop, enable)		\
+		| IO_STATE (R_SERIAL3_XOFF, auto_xoff, disable)		\
+		| IO_FIELD (R_SERIAL3_XOFF, xoff_char, 0),r0
 	move.d	r0,[R_SERIAL3_XOFF] 
 
-	move.b	0x99,r0
-	move.b	r0,[R_SERIAL3_BAUD]	; 115.2kbaud for both transmit and receive
-
-	move.b	0x40,r0			; rec enable
+	; 115.2kbaud for both transmit and receive
+	move.b	  IO_STATE (R_SERIAL3_BAUD, tr_baud, c115k2Hz)		\
+		| IO_STATE (R_SERIAL3_BAUD, rec_baud, c115k2Hz),r0
+	move.b	r0,[R_SERIAL3_BAUD]
+
+	; Set up and enable the serial3 receiver.
+	move.b	  IO_STATE (R_SERIAL3_REC_CTRL, dma_err, stop)		\
+		| IO_STATE (R_SERIAL3_REC_CTRL, rec_enable, enable)	\
+		| IO_STATE (R_SERIAL3_REC_CTRL, rts_, active)		\
+		| IO_STATE (R_SERIAL3_REC_CTRL, sampling, middle)	\
+		| IO_STATE (R_SERIAL3_REC_CTRL, rec_stick_par, normal)	\
+		| IO_STATE (R_SERIAL3_REC_CTRL, rec_par, even)		\
+		| IO_STATE (R_SERIAL3_REC_CTRL, rec_par_en, disable)	\
+		| IO_STATE (R_SERIAL3_REC_CTRL, rec_bitnr, rec_8bit),r0
 	move.b	r0,[R_SERIAL3_REC_CTRL] 
 	
-	move.b	0x40,r0			; tr enable
+	; Set up and enable the serial3 transmitter.
+	move.b	  IO_FIELD (R_SERIAL3_TR_CTRL, txd, 0)			\
+		| IO_STATE (R_SERIAL3_TR_CTRL, tr_enable, enable)	\
+		| IO_STATE (R_SERIAL3_TR_CTRL, auto_cts, disabled)	\
+		| IO_STATE (R_SERIAL3_TR_CTRL, stop_bits, one_bit)	\
+		| IO_STATE (R_SERIAL3_TR_CTRL, tr_stick_par, normal)	\
+		| IO_STATE (R_SERIAL3_TR_CTRL, tr_par, even)		\
+		| IO_STATE (R_SERIAL3_TR_CTRL, tr_par_en, disable)	\
+		| IO_STATE (R_SERIAL3_TR_CTRL, tr_bitnr, tr_8bit),r0
 	move.b	r0,[R_SERIAL3_TR_CTRL]
 #endif
 	
diff -u --recursive --new-file v2.4.7/linux/arch/cris/kernel/irq.c linux/arch/cris/kernel/irq.c
--- v2.4.7/linux/arch/cris/kernel/irq.c	Wed Jul 25 17:10:17 2001
+++ linux/arch/cris/kernel/irq.c	Thu Jul 26 15:10:06 2001
@@ -1,4 +1,4 @@
-/* $Id: irq.c,v 1.15 2001/06/10 11:18:46 bjornw Exp $
+/* $Id: irq.c,v 1.17 2001/07/25 16:08:01 bjornw Exp $
  *
  *	linux/arch/cris/kernel/irq.c
  *
@@ -32,6 +32,7 @@
 #include <linux/timex.h>
 #include <linux/slab.h>
 #include <linux/random.h>
+#include <linux/init.h>
 
 #include <asm/system.h>
 #include <asm/io.h>
@@ -278,7 +279,7 @@
         }
         irq_exit(cpu);
 
-	if (softirq_active(cpu) & softirq_mask(cpu))
+	if (softirq_pending(cpu))
                 do_softirq();
 
         /* unmasking and bottom half handling is done magically for us. */
@@ -422,7 +423,8 @@
 void do_sigtrap(void); /* from entry.S */
 void gdb_handle_breakpoint(void); /* from entry.S */
 
-void init_IRQ(void)
+void __init
+init_IRQ(void)
 {
 	int i;
 
@@ -488,7 +490,8 @@
 
 #if defined(CONFIG_PROC_FS) && defined(CONFIG_SYSCTL)
 /* Used by other archs to show/control IRQ steering during SMP */
-void init_irq_proc(void)
+void __init
+init_irq_proc(void)
 {
 }
 #endif
diff -u --recursive --new-file v2.4.7/linux/arch/cris/kernel/process.c linux/arch/cris/kernel/process.c
--- v2.4.7/linux/arch/cris/kernel/process.c	Wed Jul 25 17:10:17 2001
+++ linux/arch/cris/kernel/process.c	Thu Jul 26 15:10:06 2001
@@ -1,4 +1,4 @@
-/* $Id: process.c,v 1.14 2001/05/29 11:27:59 markusl Exp $
+/* $Id: process.c,v 1.16 2001/06/21 02:00:40 hp Exp $
  * 
  *  linux/arch/cris/kernel/process.c
  *
@@ -8,6 +8,18 @@
  *  Authors:   Bjorn Wesen (bjornw@axis.com)
  *
  *  $Log: process.c,v $
+ *  Revision 1.16  2001/06/21 02:00:40  hp
+ *  	* entry.S: Include asm/unistd.h.
+ *  	(_sys_call_table): Use section .rodata, not .data.
+ *  	(_kernel_thread): Move from...
+ *  	* process.c: ... here.
+ *  	* entryoffsets.c (VAL): Break out from...
+ *  	(OF): Use VAL.
+ *  	(LCLONE_VM): New asmified value from CLONE_VM.
+ *
+ *  Revision 1.15  2001/06/20 16:31:57  hp
+ *  Add comments to describe empty functions according to review.
+ *
  *  Revision 1.14  2001/05/29 11:27:59  markusl
  *  Fixed so that hard_reset_now will do reset even if watchdog wasn't enabled
  *
@@ -71,6 +83,15 @@
       __attribute__((__section__(".data.init_task"))) =
              { INIT_TASK(init_task_union.task) };
 
+/*
+ * The hlt_counter, disable_hlt and enable_hlt is just here as a hook if
+ * there would ever be a halt sequence (for power save when idle) with
+ * some largish delay when halting or resuming *and* a driver that can't
+ * afford that delay.  The hlt_counter would then be checked before
+ * executing the halt sequence, and the driver marks the unhaltable
+ * region by enable_hlt/disable_hlt.
+ */
+
 static int hlt_counter=0;
 
 void disable_hlt(void)
@@ -116,52 +137,27 @@
 	hard_reset_now();
 }
 
-/* can't do much here... */
+/*
+ * Similar to machine_power_off, but don't shut off power.  Add code
+ * here to freeze the system for e.g. post-mortem debug purpose when
+ * possible.  This halt has nothing to do with the idle halt.
+ */
 
 void machine_halt(void)
 {
 }
 
+/* If or when software power-off is implemented, add code here.  */
+
 void machine_power_off(void)
 {
 }
 
 /*
- * This is the mechanism for creating a new kernel thread.
- *
- * NOTE! Only a kernel-only process(ie the swapper or direct descendants
- * who haven't done an "execve()") should use this: it will work within
- * a system call from a "real" process, but the process memory space will
- * not be free'd until both the parent and the child have exited.
- */
-
-int kernel_thread(int (*fn)(void *), void * arg, unsigned long flags)
-{
-	register long __a __asm__ ("r10");
-	
-	__asm__ __volatile__
-		("movu.w %1,r9\n\t"     /* r9 contains syscall number, to sys_clone */
-		 "clear.d r10\n\t"      /* r10 is argument 1 to clone */
-		 "move.d %2,r11\n\t"    /* r11 is argument 2 to clone, the flags */
-		 "break 13\n\t"         /* call sys_clone, this will fork */
-		 "test.d r10\n\t"       /* parent or child? child returns 0 here. */
-		 "bne 1f\n\t"           /* jump if parent */
-		 "nop\n\t"              /* delay slot */
-		 "move.d %4,r10\n\t"    /* set argument to function to call */
-		 "jsr %5\n\t"           /* call specified function */
-		 "movu.w %3,r9\n\t"     /* r9 is sys_exit syscall number */
-		 "moveq -1,r10\n\t"     /* Give a really bad exit-value */
-		 "break 13\n\t"         /* call sys_exit, killing the child */
-		 "1:\n\t"
-		 : "=r" (__a) 
-		 : "g" (__NR_clone), "r" (flags | CLONE_VM), "g" (__NR_exit),
-		   "r" (arg), "r" (fn) 
-		 : "r10", "r11", "r9");
-	
-	return __a;
-}
-
-
+ * When a process does an "exec", machine state like FPU and debug
+ * registers need to be reset.  This is a hook function for that.
+ * Currently we don't have any such state to reset, so this is empty.
+ */
 
 void flush_thread(void)
 {
diff -u --recursive --new-file v2.4.7/linux/arch/cris/kernel/ptrace.c linux/arch/cris/kernel/ptrace.c
--- v2.4.7/linux/arch/cris/kernel/ptrace.c	Wed Jul 25 17:10:17 2001
+++ linux/arch/cris/kernel/ptrace.c	Thu Jul 26 15:10:06 2001
@@ -8,6 +8,9 @@
  * Authors:   Bjorn Wesen
  *
  * $Log: ptrace.c,v $
+ * Revision 1.6  2001/07/25 16:08:47  bjornw
+ * PTRACE_ATTACH bulk moved into arch-independant code in 2.4.7
+ *
  * Revision 1.5  2001/03/26 14:24:28  orjanf
  * * Changed loop condition.
  * * Added comment documenting non-standard ptrace behaviour.
diff -u --recursive --new-file v2.4.7/linux/arch/cris/kernel/setup.c linux/arch/cris/kernel/setup.c
--- v2.4.7/linux/arch/cris/kernel/setup.c	Wed Jul 25 17:10:17 2001
+++ linux/arch/cris/kernel/setup.c	Thu Jul 26 15:10:06 2001
@@ -1,4 +1,4 @@
-/* $Id: setup.c,v 1.16 2001/05/15 01:23:13 hp Exp $
+/* $Id: setup.c,v 1.18 2001/06/28 04:47:16 hp Exp $
  *
  *  linux/arch/cris/kernel/setup.c
  *
@@ -162,9 +162,9 @@
 
 	paging_init();
 
-	/* we dont use a command line yet, so just let it be an empty string 
-	   to start with */
-        
+	/* We dont use a command line yet, so just re-initialize it without
+	   saving anything that might be there.  */
+
 	*cmdline_p = command_line;
 	strcpy(command_line, "root=/dev/rom"); /* use the appended romdisk as root */
 
@@ -249,7 +249,7 @@
 		       cpu_info[revision].flags & HAS_SCSI ? "yes" : "no",
 		       cpu_info[revision].flags & HAS_ATA ? "yes" : "no",
 		       cpu_info[revision].flags & HAS_USB ? "yes" : "no",
-		       (loops_per_jiffy * HZ + 500) / 100000,
-		       ((loops_per_jiffy * HZ + 500) / 1000) % 100);
+		       (loops_per_jiffy * HZ + 500) / 500000,
+		       ((loops_per_jiffy * HZ + 500) / 5000) % 100);
 }
 #endif /* CONFIG_PROC_FS */
diff -u --recursive --new-file v2.4.7/linux/arch/cris/kernel/sys_cris.c linux/arch/cris/kernel/sys_cris.c
--- v2.4.7/linux/arch/cris/kernel/sys_cris.c	Wed Jul 25 17:10:17 2001
+++ linux/arch/cris/kernel/sys_cris.c	Thu Jul 26 15:10:06 2001
@@ -1,4 +1,4 @@
-/* $Id: sys_cris.c,v 1.9 2001/05/30 06:20:26 markusl Exp $
+/* $Id: sys_cris.c,v 1.10 2001/06/27 21:16:15 hp Exp $
  *
  * linux/arch/cris/kernel/sys_cris.c
  *
@@ -42,34 +42,6 @@
                         error = -EFAULT;
         }
         return error;
-}
-
-/* sys_mmap used to take a ptr to a buffer instead containing the args
- * but we support syscalls with 6 arguments now 
- */
-
-asmlinkage unsigned long sys_mmap(unsigned long addr, size_t len,
-				  unsigned long prot, unsigned long flags,
-                                  unsigned long fd, off_t offset)
-{
-	struct file * file = NULL;
-        int ret = -EBADF;
-	
-        lock_kernel();
-        if (!(flags & MAP_ANONYMOUS)) {
-                if (!(file = fget(fd)))
-                        goto out;
-        }
-        
-        flags &= ~(MAP_EXECUTABLE | MAP_DENYWRITE);
-        down_write(&current->mm->mmap_sem);
-        ret = do_mmap(file, addr, len, prot, flags, offset);
-        up_write(&current->mm->mmap_sem);
-        if (file)
-                fput(file);
- out:
-        unlock_kernel();
-        return ret;
 }
 
 /* common code for old and new mmaps */
diff -u --recursive --new-file v2.4.7/linux/arch/cris/kernel/time.c linux/arch/cris/kernel/time.c
--- v2.4.7/linux/arch/cris/kernel/time.c	Wed Jul 25 17:10:17 2001
+++ linux/arch/cris/kernel/time.c	Thu Jul 26 15:10:06 2001
@@ -1,9 +1,9 @@
-/* $Id: time.c,v 1.6 2001/05/29 11:29:42 markusl Exp $
+/* $Id: time.c,v 1.8 2001/07/18 14:01:03 bjornw Exp $
  *
  *  linux/arch/cris/kernel/time.c
  *
  *  Copyright (C) 1991, 1992, 1995  Linus Torvalds
- *  Copyright (C) 1999, 2000 Axis Communications AB
+ *  Copyright (C) 1999, 2000, 2001 Axis Communications AB
  *
  * 1994-07-02    Alan Modra
  *	fixed set_rtc_mmss, fixed time.year for >= 2000, new mktime
@@ -228,7 +228,7 @@
 
 #define WATCHDOG_MIN_FREE_PAGES 8
 
-static inline void
+void
 reset_watchdog(void)
 {
 #if defined(CONFIG_ETRAX_WATCHDOG) && !defined(CONFIG_SVINTO_SIM)
@@ -242,6 +242,18 @@
 #endif
 }
 
+/* stop the watchdog - we still need the correct key */
+
+void 
+stop_watchdog(void)
+{
+#if defined(CONFIG_ETRAX_WATCHDOG) && !defined(CONFIG_SVINTO_SIM)
+	watchdog_key ^= 0x7; /* invert key, which is 3 bits */
+	*R_WATCHDOG = IO_FIELD(R_WATCHDOG, key, watchdog_key) |
+		IO_STATE(R_WATCHDOG, enable, stop);
+#endif	
+}
+
 /* last time the cmos clock got updated */
 static long last_rtc_update = 0;
 
@@ -443,6 +455,19 @@
 #if defined(CONFIG_ETRAX_WATCHDOG) && !defined(CONFIG_SVINTO_SIM)
 	printk("Enabling watchdog...\n");
 	start_watchdog();
-#endif
 
+	/* If we use the hardware watchdog, we want to trap it as an NMI
+	   and dump registers before it resets us.  For this to happen, we
+	   must set the "m" NMI enable flag (which once set, is unset only
+	   when an NMI is taken).
+
+	   The same goes for the external NMI, but that doesn't have any
+	   driver or infrastructure support yet.  */
+	asm ("setf m");
+
+	*R_IRQ_MASK0_SET =
+		IO_STATE(R_IRQ_MASK0_SET, watchdog_nmi, set);
+	*R_VECT_MASK_SET =
+		IO_STATE(R_VECT_MASK_SET, nmi, set);
+#endif
 }
diff -u --recursive --new-file v2.4.7/linux/arch/cris/kernel/traps.c linux/arch/cris/kernel/traps.c
--- v2.4.7/linux/arch/cris/kernel/traps.c	Wed Jul 25 17:10:17 2001
+++ linux/arch/cris/kernel/traps.c	Thu Jul 26 15:10:06 2001
@@ -1,4 +1,4 @@
-/* $Id: traps.c,v 1.12 2001/05/15 15:46:40 bjornw Exp $
+/* $Id: traps.c,v 1.15 2001/07/18 14:02:37 bjornw Exp $
  *
  *  linux/arch/cris/traps.c
  *
@@ -9,6 +9,7 @@
  *  Copyright (C) 2000,2001 Axis Communications AB
  *
  *  Authors:   Bjorn Wesen
+ *  	       Hans-Peter Nilsson
  *
  */
 
@@ -20,6 +21,7 @@
 #include <linux/ptrace.h>
 #include <linux/timer.h>
 #include <linux/mm.h>
+#include <asm/uaccess.h>
 
 #include <asm/system.h>
 #include <asm/segment.h>
@@ -36,6 +38,13 @@
 
 #define MODULE_RANGE (8*1024*1024)
 
+/*
+ * The output (format, strings and order) is adjusted to be usable with
+ * ksymoops-2.4.1 with some necessary CRIS-specific patches.  Please don't
+ * change it unless you're serious about adjusting ksymoops and syncing
+ * with the ksymoops maintainer.
+ */
+
 void 
 show_stack(unsigned long *sp)
 {
@@ -43,22 +52,31 @@
         int i;
 	extern char _stext, _etext;
 
-        /*
-         * debugging aid: "show_stack(NULL);" prints the
-         * back trace for this cpu.
-         */
+	/*
+	 * debugging aid: "show_stack(NULL);" prints a
+	 * back trace.
+	 */
 
         if(sp == NULL)
                 sp = (unsigned long*)rdsp();
 
         stack = sp;
 
+	printk("\nStack from %08lx:\n       ", stack);
         for(i = 0; i < kstack_depth_to_print; i++) {
                 if (((long) stack & (THREAD_SIZE-1)) == 0)
                         break;
                 if (i && ((i % 8) == 0))
                         printk("\n       ");
-                printk("%08lx ", *stack++);
+		if (__get_user (addr, stack)) {
+			/* This message matches "failing address" marked
+			   s390 in ksymoops, so lines containing it will
+			   not be filtered out by ksymoops.  */
+			printk ("Failing address 0x%lx\n", stack);
+			break;
+		}
+		stack++;
+		printk("%08lx ", addr);
         }
 
         printk("\nCall Trace: ");
@@ -67,7 +85,15 @@
         module_start = VMALLOC_START;
         module_end = VMALLOC_END;
         while (((long) stack & (THREAD_SIZE-1)) != 0) {
-                addr = *stack++;
+		if (__get_user (addr, stack)) {
+			/* This message matches "failing address" marked
+			   s390 in ksymoops, so lines containing it will
+			   not be filtered out by ksymoops.  */
+			printk ("Failing address 0x%lx\n", stack);
+			break;
+		}
+		stack++;
+
                 /*
                  * If the address is either in the text segment of the
                  * kernel, or in the region which contains vmalloc'ed
@@ -105,38 +131,53 @@
 void 
 show_registers(struct pt_regs * regs)
 {
+	/* We either use rdusp() - the USP register, which might not
+	   correspond to the current process for all cases we're called,
+	   or we use the current->thread.usp, which is not up to date for
+	   the current process.  Experience shows we want the USP
+	   register.  */
 	unsigned long usp = rdusp();
 
-	printk("IRP: %08lx SRP: %08lx CCR: %08lx USP: %08lx MOF: %08lx\n",
+	printk("IRP: %08lx SRP: %08lx DCCR: %08lx USP: %08lx MOF: %08lx\n",
 	       regs->irp, regs->srp, regs->dccr, usp, regs->mof );
-	printk(" r0: %08lx  r1: %08lx  r2: %08lx  r3: %08lx\n",
+	printk(" r0: %08lx  r1: %08lx   r2: %08lx  r3: %08lx\n",
 	       regs->r0, regs->r1, regs->r2, regs->r3);
-	printk(" r4: %08lx  r5: %08lx  r6: %08lx  r7: %08lx\n",
+	printk(" r4: %08lx  r5: %08lx   r6: %08lx  r7: %08lx\n",
 	       regs->r4, regs->r5, regs->r6, regs->r7);
-	printk(" r8: %08lx  r9: %08lx r10: %08lx r11: %08lx\n",
+	printk(" r8: %08lx  r9: %08lx  r10: %08lx r11: %08lx\n",
 	       regs->r8, regs->r9, regs->r10, regs->r11);
 	printk("r12: %08lx r13: %08lx oR10: %08lx\n",
 	       regs->r12, regs->r13, regs->orig_r10);
+	printk("R_MMU_CAUSE: %08lx\n", *R_MMU_CAUSE);
 	printk("Process %s (pid: %d, stackpage=%08lx)\n",
 	       current->comm, current->pid, (unsigned long)current);
 
-	/* TODO, fix in_kernel detection */
-
-#if 0
 	/*
          * When in-kernel, we also print out the stack and code at the
          * time of the fault..
          */
-        if (1) {
-		
-                printk("\nStack: ");
+        if (! user_mode(regs)) {
+	  	int i;
+
                 show_stack((unsigned long*)usp);
 
+		/* Dump kernel stack if the previous dump wasn't one.  */
+		if (usp != 0)
+			show_stack (NULL);
+
                 printk("\nCode: ");
                 if(regs->irp < PAGE_OFFSET)
                         goto bad;
 
-                for(i = 0; i < 20; i++)
+		/* Often enough the value at regs->irp does not point to
+		   the interesting instruction, which is most often the
+		   _previous_ instruction.  So we dump at an offset large
+		   enough that instruction decoding should be in sync at
+		   the interesting point, but small enough to fit on a row
+		   (sort of).  We point out the regs->irp location in a
+		   ksymoops-friendly way by wrapping the byte for that
+		   address in parentheses.  */
+                for(i = -12; i < 12; i++)
                 {
                         unsigned char c;
                         if(__get_user(c, &((unsigned char*)regs->irp)[i])) {
@@ -144,11 +185,14 @@
                                 printk(" Bad IP value.");
                                 break;
                         }
-                        printk("%02x ", c);
+
+			if (i == 0)
+			  printk("(%02x) ", c);
+			else
+			  printk("%02x ", c);
                 }
+		printk("\n");
         }
-        printk("\n");
-#endif
 }
 
 void 
@@ -157,10 +201,13 @@
 	if(user_mode(regs))
 		return;
 
+	stop_watchdog();
+
 	printk("%s: %04lx\n", str, err & 0xffff);
 
 	show_registers(regs);
-	show_stack(NULL);  /* print backtrace for kernel stack on this CPU */
+
+	reset_watchdog();
 
 	do_exit(SIGSEGV);
 }
diff -u --recursive --new-file v2.4.7/linux/arch/cris/lib/Makefile linux/arch/cris/lib/Makefile
--- v2.4.7/linux/arch/cris/lib/Makefile	Thu Feb  8 16:32:44 2001
+++ linux/arch/cris/lib/Makefile	Thu Jul 26 15:10:06 2001
@@ -6,6 +6,6 @@
 	$(CC) -D__ASSEMBLY__ $(AFLAGS) -traditional -c $< -o $*.o
 
 L_TARGET = lib.a
-obj-y  = checksum.o checksumcopy.o string.o usercopy.o memset.o
+obj-y  = checksum.o checksumcopy.o string.o usercopy.o memset.o csumcpfruser.o
 
 include $(TOPDIR)/Rules.make
diff -u --recursive --new-file v2.4.7/linux/arch/cris/lib/checksumcopy.S linux/arch/cris/lib/checksumcopy.S
--- v2.4.7/linux/arch/cris/lib/checksumcopy.S	Wed Jul 25 17:10:17 2001
+++ linux/arch/cris/lib/checksumcopy.S	Thu Jul 26 15:10:06 2001
@@ -1,4 +1,4 @@
-/* $Id: checksumcopy.S,v 1.5 2001/05/29 11:40:14 markusl Exp $
+/* $Id: checksumcopy.S,v 1.6 2001/06/28 03:57:16 hp Exp $
  * A fast checksum+copy routine using movem
  * Copyright (c) 1998, 2001 Axis Communications AB
  *
@@ -37,6 +37,7 @@
 	subq	10*4,r12	; update length for the first loop
 	
 mloop:	movem	[r10+],r9	; read 10 longwords
+1:	;; A failing userspace access will have this as PC.
 	movem	r9,[r11+]	; write 10 longwords
 
 	;; perform dword checksumming on the 10 longwords
@@ -105,6 +106,7 @@
 	subq	2,r12
 	
 wloop:	move.w	[r10+],r9
+2:	;; A failing userspace access will have this as PC.
 	addu.w	r9,r13
 	subq	2,r12
 	bge	wloop
@@ -123,9 +125,8 @@
 do_byte:	
 	;; copy and checksum the last byte
 	move.b	[r10],r9
+3:	;; A failing userspace access will have this as PC.
 	addu.b	r9,r13
 	move.b	r9,[r11]
 	ret
 	move.d	r13, r10
-		
-	
diff -u --recursive --new-file v2.4.7/linux/arch/cris/lib/csumcpfruser.S linux/arch/cris/lib/csumcpfruser.S
--- v2.4.7/linux/arch/cris/lib/csumcpfruser.S	Wed Dec 31 16:00:00 1969
+++ linux/arch/cris/lib/csumcpfruser.S	Thu Jul 26 15:10:06 2001
@@ -0,0 +1,64 @@
+/*
+ * Add-on to transform csum_partial_copy_nocheck in checksumcopy.S into
+ * csum_partial_copy_from_user by adding exception records.
+ *
+ * Copyright (C) 2001 Axis Communications AB.
+ *
+ * Author: Hans-Peter Nilsson.
+ */
+
+#include <asm/errno.h>
+
+/* Same function body, but a different name.  If we just added exception
+   records to _csum_partial_copy_nocheck and made it generic, we wouldn't
+   know a user fault from a kernel fault and we would have overhead in
+   each kernel caller for the error-pointer argument.
+
+   unsigned int csum_partial_copy_from_user
+     (const char *src, char *dst, int len, unsigned int sum, int *errptr);
+
+   Note that the errptr argument is only set if we encounter an error.
+   It is conveniently located on the stack, so the normal function body
+   does not have to handle it.  */
+
+#define _csum_partial_copy_nocheck _csum_partial_copy_from_user
+
+/* There are local labels numbered 1, 2 and 3 present to mark the
+   different from-user accesses.  */
+#include "checksumcopy.S"
+
+	.section .fixup,"ax"
+
+;; Here from the movem loop; restore stack.
+4:
+	movem	[sp+],r8
+;; r12 is already decremented.  Add back chunk_size-2.
+	addq	40-2,r12
+
+;; Here from the word loop; r12 is off by 2; add it back.
+5:
+	addq	2,r12
+
+;; Here from a failing single byte.
+6:
+
+;; Signal in *errptr that we had a failing access.
+	moveq	-EFAULT,r9
+	move.d	r9,[[sp]]
+
+;; Clear the rest of the destination area using memset.  Preserve the
+;; checksum for the readable bytes.
+	push	srp
+	push	r13
+	move.d	r11,r10
+	clear.d	r11
+	jsr	_memset
+	pop	r10
+	jump	[sp+]
+
+	.previous
+	.section __ex_table,"a"
+	.dword 1b,4b
+	.dword 2b,5b
+	.dword 3b,6b
+	.previous
diff -u --recursive --new-file v2.4.7/linux/arch/cris/mm/fault.c linux/arch/cris/mm/fault.c
--- v2.4.7/linux/arch/cris/mm/fault.c	Wed Jul 25 17:10:17 2001
+++ linux/arch/cris/mm/fault.c	Thu Jul 26 15:10:06 2001
@@ -6,6 +6,16 @@
  *  Authors:  Bjorn Wesen 
  * 
  *  $Log: fault.c,v $
+ *  Revision 1.18  2001/07/18 22:14:32  bjornw
+ *  Enable interrupts in the bulk of do_page_fault
+ *
+ *  Revision 1.17  2001/07/18 13:07:23  bjornw
+ *  * Detect non-existant PTE's in vmalloc pmd synchronization
+ *  * Remove comment about fast-paths for VMALLOC_START etc, because all that
+ *    was totally bogus anyway it turned out :)
+ *  * Fix detection of vmalloc-area synchronization
+ *  * Add some comments
+ *
  *  Revision 1.16  2001/06/13 00:06:08  bjornw
  *  current_pgd should be volatile
  *
@@ -76,7 +86,9 @@
 
 volatile pgd_t *current_pgd;
 
-/* fast TLB-fill fault handler */
+/* fast TLB-fill fault handler
+ * this is called from entry.S with interrupts disabled
+ */
 
 void
 handle_mmu_bus_fault(struct pt_regs *regs)
@@ -85,10 +97,9 @@
 	int index;
 	int page_id;
 	int miss, we, acc, inv;  
-	struct mm_struct *mm = current->active_mm;
 	pmd_t *pmd;
 	pte_t pte;
-	int errcode = 0;
+	int errcode;
 	unsigned long address;
 
 	cause = *R_MMU_CAUSE;
@@ -103,6 +114,20 @@
 	miss    = IO_EXTRACT(R_MMU_CAUSE,  miss_excp, cause);
 	we      = IO_EXTRACT(R_MMU_CAUSE,  we_excp,   cause);
 	
+	/* Note: the reason we don't set errcode's r/w flag here
+	 * using the 'we' flag, is because the latter is only given
+	 * if there is a write-protection exception, not given as a
+	 * general r/w access mode flag. It is currently not possible
+	 * to get this from the MMU (TODO: check if this is the case
+	 * for LXv2).
+	 * 
+	 * The page-fault code won't care, but there will be two page-
+	 * faults instead of one for the case of a write to a non-tabled
+	 * page (miss, then write-protection).
+	 */
+
+	errcode = 0;
+
 	D(printk("bus_fault from IRP 0x%x: addr 0x%x, miss %d, inv %d, we %d, acc %d, "
 		 "idx %d pid %d\n",
 		 regs->irp, address, miss, inv, we, acc, index, page_id));
@@ -157,14 +182,14 @@
 		 * the write to R_TLB_LO also writes the vpn and page_id fields from
 		 * R_MMU_CAUSE, which we in this case obviously want to keep
 		 */
-		
+
 		*R_TLB_LO = pte_val(pte);
 
 		return;
 	} 
 
-	errcode = 0x01 | (we << 1);
-
+	errcode = 1 | (we << 1);
+	
  dofault:
 	/* leave it to the MM system fault handler below */
 	D(printk("do_page_fault %p errcode %d\n", address, errcode));
@@ -214,25 +239,21 @@
 	 * NOTE2: This is done so that, when updating the vmalloc
 	 * mappings we don't have to walk all processes pgdirs and
 	 * add the high mappings all at once. Instead we do it as they
-	 * are used.
+	 * are used. However vmalloc'ed page entries have the PAGE_GLOBAL
+	 * bit set so sometimes the TLB can use a lingering entry.
 	 *
-	 * TODO: On CRIS, we have a PTE Global bit which should be set in
-	 * all the PTE's related to vmalloc in all processes - that means if
-	 * we switch process and a vmalloc PTE is still in the TLB, it won't
-	 * need to be reloaded. It's an optimization.
-	 *
-	 * Linux/CRIS's kernel is not page-mapped, so the comparision below
-	 * should really be >= VMALLOC_START, however, kernel fixup errors
-	 * will be handled more quickly by going through vmalloc_fault and then
-	 * into bad_area_nosemaphore than falling through the find_vma user-mode
-	 * tests.  As an aside can be mentioned that the difference in
-	 * compiled code is neglibible; the instruction is the same, just a
-	 * comparison with a different address of the same size.
+	 * This verifies that the fault happens in kernel space
+         * and that the fault was not a protection error (error_code & 1).
          */
 
-        if (address >= TASK_SIZE)
+        if (address >= VMALLOC_START &&
+	    !(error_code & 1) &&
+	    !user_mode(regs))
                 goto vmalloc_fault;
 
+	/* we can and should enable interrupts at this point */
+	sti();
+
 	mm = tsk->mm;
 	writeaccess = error_code & 2;
 	info.si_code = SEGV_MAPERR;
@@ -409,29 +430,48 @@
 		 * Use current_pgd instead of tsk->active_mm->pgd
 		 * since the latter might be unavailable if this
 		 * code is executed in a misfortunately run irq
+		 * (like inside schedule() between switch_mm and
+		 *  switch_to...).
                  */
 
                 int offset = pgd_index(address);
                 pgd_t *pgd, *pgd_k;
                 pmd_t *pmd, *pmd_k;
+		pte_t *pte_k;
 
                 pgd = current_pgd + offset;
                 pgd_k = init_mm.pgd + offset;
 
-                if (!pgd_present(*pgd)) {
-                        if (!pgd_present(*pgd_k))
-                                goto bad_area_nosemaphore;
-                        set_pgd(pgd, *pgd_k);
-                        return;
-                }
+		/* Since we're two-level, we don't need to do both
+		 * set_pgd and set_pmd (they do the same thing). If
+		 * we go three-level at some point, do the right thing
+		 * with pgd_present and set_pgd here. 
+		 * 
+		 * Also, since the vmalloc area is global, we don't
+		 * need to copy individual PTE's, it is enough to
+		 * copy the pgd pointer into the pte page of the
+		 * root task. If that is there, we'll find our pte if
+		 * it exists.
+		 */
 
                 pmd = pmd_offset(pgd, address);
                 pmd_k = pmd_offset(pgd_k, address);
 
                 if (!pmd_present(*pmd_k))
                         goto bad_area_nosemaphore;
+
                 set_pmd(pmd, *pmd_k);
+
+		/* Make sure the actual PTE exists as well to
+		 * catch kernel vmalloc-area accesses to non-mapped
+		 * addresses. If we don't do this, this will just
+		 * silently loop forever.
+		 */
+
+                pte_k = pte_offset(pmd_k, address);
+                if (!pte_present(*pte_k))
+                        goto no_context;
+
                 return;
         }
-
 }
diff -u --recursive --new-file v2.4.7/linux/arch/cris/mm/init.c linux/arch/cris/mm/init.c
--- v2.4.7/linux/arch/cris/mm/init.c	Wed Jul 25 17:10:17 2001
+++ linux/arch/cris/mm/init.c	Thu Jul 26 15:10:06 2001
@@ -7,6 +7,18 @@
  *  Authors:  Bjorn Wesen (bjornw@axis.com)
  *
  *  $Log: init.c,v $
+ *  Revision 1.29  2001/07/25 16:09:50  bjornw
+ *  val->sharedram will stay 0
+ *
+ *  Revision 1.28  2001/06/28 16:30:17  bjornw
+ *  Oops. This needs to wait until 2.4.6 is merged
+ *
+ *  Revision 1.27  2001/06/28 14:04:07  bjornw
+ *  Fill in sharedram
+ *
+ *  Revision 1.26  2001/06/18 06:36:02  hp
+ *  Enable free_initmem of __init-type pages
+ *
  *  Revision 1.25  2001/06/13 00:02:23  bjornw
  *  Use a separate variable to store the current pgd to avoid races in schedule
  *
@@ -438,11 +450,6 @@
 void 
 free_initmem(void)
 {
-#if 0
-	/* currently this is a bad idea since the cramfs image is catted onto
-	 * the vmlinux image, and the end of that image is not page-padded so
-	 * part of the cramfs image will be freed here
-	 */
         unsigned long addr;
 
         addr = (unsigned long)(&__init_begin);
@@ -454,7 +461,6 @@
         }
         printk ("Freeing unused kernel memory: %dk freed\n", 
 		(&__init_end - &__init_begin) >> 10);
-#endif
 }
 
 void 
@@ -464,7 +470,7 @@
 
 	i = max_mapnr;
 	val->totalram = 0;
-	val->sharedram = atomic_read(&shmem_nrpages);
+	val->sharedram = 0;
 	val->freeram = nr_free_pages();
 	val->bufferram = atomic_read(&buffermem_pages);
 	while (i-- > 0)  {
diff -u --recursive --new-file v2.4.7/linux/arch/cris/mm/tlb.c linux/arch/cris/mm/tlb.c
--- v2.4.7/linux/arch/cris/mm/tlb.c	Wed Jul 25 17:10:17 2001
+++ linux/arch/cris/mm/tlb.c	Thu Jul 26 15:10:06 2001
@@ -40,6 +40,10 @@
  *
  * The last page_id is never running - it is used as an invalid page_id
  * so we can make TLB entries that will never match.
+ *
+ * Notice that we need to make the flushes atomic, otherwise an interrupt
+ * handler that uses vmalloced memory might cause a TLB load in the middle
+ * of a flush causing.
  */
 
 struct mm_struct *page_id_map[NUM_PAGEID];
@@ -49,17 +53,18 @@
 /* invalidate all TLB entries */
 
 void
-flush_tlb_all()
+flush_tlb_all(void)
 {
 	int i;
+	unsigned long flags;
 
 	/* the vpn of i & 0xf is so we dont write similar TLB entries
 	 * in the same 4-way entry group. details.. 
 	 */
 
+	save_and_cli(flags); /* flush needs to be atomic */
 	for(i = 0; i < NUM_TLB_ENTRIES; i++) {
 		*R_TLB_SELECT = ( IO_FIELD(R_TLB_SELECT, index, i) );
-
 		*R_TLB_HI = ( IO_FIELD(R_TLB_HI, page_id, INVALID_PAGEID ) |
 			      IO_FIELD(R_TLB_HI, vpn,     i & 0xf ) );
 		
@@ -69,6 +74,7 @@
 			      IO_STATE(R_TLB_LO, we,    no       ) |
 			      IO_FIELD(R_TLB_LO, pfn,   0        ) );
 	}
+	restore_flags(flags);
 	D(printk("tlb: flushed all\n"));
 }
 
@@ -79,6 +85,7 @@
 {
 	int i;
 	int page_id = mm->context;
+	unsigned long flags;
 
 	D(printk("tlb: flush mm context %d (%p)\n", page_id, mm));
 
@@ -90,6 +97,7 @@
 	 * global pages. is it worth the extra I/O ? 
 	 */
 
+	save_and_cli(flags);  /* flush needs to be atomic */
 	for(i = 0; i < NUM_TLB_ENTRIES; i++) {
 		*R_TLB_SELECT = IO_FIELD(R_TLB_SELECT, index, i);
 		if (IO_EXTRACT(R_TLB_HI, page_id, *R_TLB_HI) == page_id) {
@@ -103,6 +111,7 @@
 				      IO_FIELD(R_TLB_LO, pfn,   0   ) );
 		}
 	}
+	restore_flags(flags);
 }
 
 /* invalidate a single page */
@@ -114,6 +123,7 @@
 	struct mm_struct *mm = vma->vm_mm;
 	int page_id = mm->context;
 	int i;
+	unsigned long flags;
 
 	D(printk("tlb: flush page %p in context %d (%p)\n", addr, page_id, mm));
 
@@ -126,6 +136,7 @@
 	 * and the virtual address requested 
 	 */
 
+	save_and_cli(flags);  /* flush needs to be atomic */
 	for(i = 0; i < NUM_TLB_ENTRIES; i++) {
 		unsigned long tlb_hi;
 		*R_TLB_SELECT = IO_FIELD(R_TLB_SELECT, index, i);
@@ -142,6 +153,7 @@
 				      IO_FIELD(R_TLB_LO, pfn,   0   ) );
 		}
 	}
+	restore_flags(flags);
 }
 
 /* invalidate a page range */
@@ -153,6 +165,7 @@
 {
 	int page_id = mm->context;
 	int i;
+	unsigned long flags;
 
 	D(printk("tlb: flush range %p<->%p in context %d (%p)\n",
 		 start, end, page_id, mm));
@@ -167,6 +180,7 @@
 	 * and the virtual address range
 	 */
 
+	save_and_cli(flags);  /* flush needs to be atomic */
 	for(i = 0; i < NUM_TLB_ENTRIES; i++) {
 		unsigned long tlb_hi, vpn;
 		*R_TLB_SELECT = IO_FIELD(R_TLB_SELECT, index, i);
@@ -184,8 +198,30 @@
 				      IO_FIELD(R_TLB_LO, pfn,   0   ) );
 		}
 	}
+	restore_flags(flags);
 }
 
+/* dump the entire TLB for debug purposes */
+
+#if 0
+void
+dump_tlb_all(void)
+{
+	int i;
+	unsigned long flags;
+	
+	printk("TLB dump. LO is: pfn | reserved | global | valid | kernel | we  |\n");
+
+	save_and_cli(flags);
+	for(i = 0; i < NUM_TLB_ENTRIES; i++) {
+		*R_TLB_SELECT = ( IO_FIELD(R_TLB_SELECT, index, i) );
+		printk("Entry %d: HI 0x%08lx, LO 0x%08lx\n",
+		       i, *R_TLB_HI, *R_TLB_LO);
+	}
+	restore_flags(flags);
+}
+#endif
+
 /*
  * Initialize the context related info for a new mm_struct
  * instance.
@@ -228,8 +264,7 @@
 	map_replace_ptr++;
 
 	if(map_replace_ptr == INVALID_PAGEID)
-		map_replace_ptr = 0;         /* wrap around */
-	
+		map_replace_ptr = 0;         /* wrap around */	
 }
 
 /* 
diff -u --recursive --new-file v2.4.7/linux/arch/i386/boot/Makefile linux/arch/i386/boot/Makefile
--- v2.4.7/linux/arch/i386/boot/Makefile	Thu Feb 22 00:25:29 2001
+++ linux/arch/i386/boot/Makefile	Sun Aug  5 13:13:19 2001
@@ -67,7 +67,7 @@
 	$(AS) -o $@ $<
 
 setup.s: setup.S video.S Makefile $(BOOT_INCL) $(TOPDIR)/include/linux/version.h $(TOPDIR)/include/linux/compile.h
-	$(CPP) $(CPPFLAGS) -traditional $(SVGA_MODE) $(RAMDISK) $< -o $@
+	$(CPP) $(CPPFLAGS) -D__ASSEMBLY__ -traditional $(SVGA_MODE) $(RAMDISK) $< -o $@
 
 bsetup: bsetup.o
 	$(LD) -Ttext 0x0 -s --oformat binary -e begtext -o $@ $<
@@ -76,7 +76,7 @@
 	$(AS) -o $@ $<
 
 bsetup.s: setup.S video.S Makefile $(BOOT_INCL) $(TOPDIR)/include/linux/version.h $(TOPDIR)/include/linux/compile.h
-	$(CPP) $(CPPFLAGS) -D__BIG_KERNEL__ -traditional $(SVGA_MODE) $(RAMDISK) $< -o $@
+	$(CPP) $(CPPFLAGS) -D__BIG_KERNEL__ -D__ASSEMBLY__ -traditional $(SVGA_MODE) $(RAMDISK) $< -o $@
 
 dep:
 
diff -u --recursive --new-file v2.4.7/linux/arch/i386/boot/setup.S linux/arch/i386/boot/setup.S
--- v2.4.7/linux/arch/i386/boot/setup.S	Tue May  1 16:04:56 2001
+++ linux/arch/i386/boot/setup.S	Sun Aug  5 13:13:19 2001
@@ -44,7 +44,6 @@
  *
  */
 
-#define __ASSEMBLY__
 #include <linux/config.h>
 #include <asm/segment.h>
 #include <linux/version.h>
diff -u --recursive --new-file v2.4.7/linux/arch/i386/kernel/cpuid.c linux/arch/i386/kernel/cpuid.c
--- v2.4.7/linux/arch/i386/kernel/cpuid.c	Sun Dec 31 09:23:51 2000
+++ linux/arch/i386/kernel/cpuid.c	Thu Jul 26 13:37:38 2001
@@ -57,7 +57,7 @@
     cpuid(cmd->reg, &cmd->data[0], &cmd->data[1], &cmd->data[2], &cmd->data[3]);
 }
 
-extern inline void do_cpuid(int cpu, u32 reg, u32 *data)
+static inline void do_cpuid(int cpu, u32 reg, u32 *data)
 {
   struct cpuid_command cmd;
   
@@ -73,7 +73,7 @@
 }
 #else /* ! CONFIG_SMP */
 
-extern inline void do_cpuid(int cpu, u32 reg, u32 *data)
+static inline void do_cpuid(int cpu, u32 reg, u32 *data)
 {
   cpuid(reg, &data[0], &data[1], &data[2], &data[3]);
 }
diff -u --recursive --new-file v2.4.7/linux/arch/i386/kernel/dmi_scan.c linux/arch/i386/kernel/dmi_scan.c
--- v2.4.7/linux/arch/i386/kernel/dmi_scan.c	Wed Jul 25 17:10:17 2001
+++ linux/arch/i386/kernel/dmi_scan.c	Wed Jul 25 14:12:01 2001
@@ -15,12 +15,14 @@
 };
 
 #define dmi_printk(x)
-//#define dmi_printk(x) printk(x)
+//#define dmi_printk(x) printk x
 
 static char * __init dmi_string(struct dmi_header *dm, u8 s)
 {
 	u8 *bp=(u8 *)dm;
 	bp+=dm->length;
+	if(!s)
+		return "";
 	s--;
 	while(s>0)
 	{
diff -u --recursive --new-file v2.4.7/linux/arch/i386/kernel/ldt.c linux/arch/i386/kernel/ldt.c
--- v2.4.7/linux/arch/i386/kernel/ldt.c	Wed Apr 11 19:05:37 2001
+++ linux/arch/i386/kernel/ldt.c	Thu Jul 26 13:29:45 2001
@@ -70,34 +70,19 @@
 	}
 
 	/*
-	 * Horrible dependencies! Try to get rid of this. This is wrong,
-	 * as it only reloads the ldt for the first process with this
-	 * mm. The implications are that you should really make sure that
-	 * you have a ldt before you do the first clone(), otherwise
-	 * you get strange behaviour (the kernel is safe, it's just user
-	 * space strangeness).
-	 *
-	 * we have two choices: either we preallocate the LDT descriptor
-	 * and can do a shared modify_ldt(), or we postallocate it and do
-	 * an smp message pass to update it. Currently we are a bit
-	 * un-nice to user-space and reload the LDT only on the next
-	 * schedule. (only an issue on SMP)
-	 *
 	 * the GDT index of the LDT is allocated dynamically, and is
 	 * limited by MAX_LDT_DESCRIPTORS.
 	 */
 	down_write(&mm->mmap_sem);
 	if (!mm->context.segments) {
+		void * segments = vmalloc(LDT_ENTRIES*LDT_ENTRY_SIZE);
 		error = -ENOMEM;
-		mm->context.segments = vmalloc(LDT_ENTRIES*LDT_ENTRY_SIZE);
-		if (!mm->context.segments)
+		if (!segments)
 			goto out_unlock;
-		memset(mm->context.segments, 0, LDT_ENTRIES*LDT_ENTRY_SIZE);
-		
-		/*
-		 * Possibly do an SMP cross-call to other CPUs to reload
-		 * their LDTs?
-		 */
+		memset(segments, 0, LDT_ENTRIES*LDT_ENTRY_SIZE);
+		wmb();
+		mm->context.segments = segments;
+		mm->context.cpuvalid = 1UL << smp_processor_id();
 		load_LDT(mm);
 	}
 
diff -u --recursive --new-file v2.4.7/linux/arch/i386/kernel/mpparse.c linux/arch/i386/kernel/mpparse.c
--- v2.4.7/linux/arch/i386/kernel/mpparse.c	Tue Jul  3 17:08:18 2001
+++ linux/arch/i386/kernel/mpparse.c	Mon Aug  6 10:29:39 2001
@@ -273,24 +273,26 @@
 	int count=sizeof(*mpc);
 	unsigned char *mpt=((unsigned char *)mpc)+count;
 
-	if (memcmp(mpc->mpc_signature,MPC_SIGNATURE,4))
-	{
+	if (memcmp(mpc->mpc_signature,MPC_SIGNATURE,4)) {
 		panic("SMP mptable: bad signature [%c%c%c%c]!\n",
 			mpc->mpc_signature[0],
 			mpc->mpc_signature[1],
 			mpc->mpc_signature[2],
 			mpc->mpc_signature[3]);
-		return 1;
+		return 0;
 	}
-	if (mpf_checksum((unsigned char *)mpc,mpc->mpc_length))
-	{
+	if (mpf_checksum((unsigned char *)mpc,mpc->mpc_length)) {
 		panic("SMP mptable: checksum error!\n");
-		return 1;
+		return 0;
 	}
-	if (mpc->mpc_spec!=0x01 && mpc->mpc_spec!=0x04)
-	{
-		printk("Bad Config Table version (%d)!!\n",mpc->mpc_spec);
-		return 1;
+	if (mpc->mpc_spec!=0x01 && mpc->mpc_spec!=0x04) {
+		printk(KERN_ERR "SMP mptable: bad table version (%d)!!\n",
+			mpc->mpc_spec);
+		return 0;
+	}
+	if (!mpc->mpc_lapic) {
+		printk(KERN_ERR "SMP mptable: null local APIC address!\n");
+		return 0;
 	}
 	memcpy(str,mpc->mpc_oem,8);
 	str[8]=0;
@@ -358,6 +360,8 @@
 			}
 		}
 	}
+	if (!num_processors)
+		printk(KERN_ERR "SMP mptable: no processors registered!\n");
 	return num_processors;
 }
 
@@ -508,8 +512,12 @@
 		 * Read the physical hardware table.  Anything here will
 		 * override the defaults.
 		 */
-		smp_read_mpc((void *)mpf->mpf_physptr);
-
+		if (!smp_read_mpc((void *)mpf->mpf_physptr)) {
+			smp_found_config = 0;
+			printk(KERN_ERR "BIOS bug, MP table errors detected!...\n");
+			printk(KERN_ERR "... disabling SMP support. (tell your hw vendor)\n");
+			return;
+		}
 		/*
 		 * If there are no explicit MP IRQ entries, then we are
 		 * broken.  We set up most of the low 16 IO-APIC pins to
diff -u --recursive --new-file v2.4.7/linux/arch/i386/kernel/msr.c linux/arch/i386/kernel/msr.c
--- v2.4.7/linux/arch/i386/kernel/msr.c	Sun Dec 31 09:24:08 2000
+++ linux/arch/i386/kernel/msr.c	Thu Jul 26 13:37:38 2001
@@ -43,7 +43,7 @@
 /* Note: "err" is handled in a funny way below.  Otherwise one version
    of gcc or another breaks. */
 
-extern inline int wrmsr_eio(u32 reg, u32 eax, u32 edx)
+static inline int wrmsr_eio(u32 reg, u32 eax, u32 edx)
 {
   int err;
 
@@ -64,7 +64,7 @@
   return err;
 }
 
-extern inline int rdmsr_eio(u32 reg, u32 *eax, u32 *edx)
+static inline int rdmsr_eio(u32 reg, u32 *eax, u32 *edx)
 {
   int err;
 
@@ -110,7 +110,7 @@
     cmd->err = rdmsr_eio(cmd->reg, &cmd->data[0], &cmd->data[1]);
 }
 
-extern inline int do_wrmsr(int cpu, u32 reg, u32 eax, u32 edx)
+static inline int do_wrmsr(int cpu, u32 reg, u32 eax, u32 edx)
 {
   struct msr_command cmd;
 
@@ -127,7 +127,7 @@
   }
 }
 
-extern inline int do_rdmsr(int cpu, u32 reg, u32 *eax, u32 *edx)
+static inline int do_rdmsr(int cpu, u32 reg, u32 *eax, u32 *edx)
 {
   struct msr_command cmd;
 
@@ -148,12 +148,12 @@
 
 #else /* ! CONFIG_SMP */
 
-extern inline int do_wrmsr(int cpu, u32 reg, u32 eax, u32 edx)
+static inline int do_wrmsr(int cpu, u32 reg, u32 eax, u32 edx)
 {
   return wrmsr_eio(reg, eax, edx);
 }
 
-extern inline int do_rdmsr(int cpu, u32 reg, u32 *eax, u32 *edx)
+static inline int do_rdmsr(int cpu, u32 reg, u32 *eax, u32 *edx)
 {
   return rdmsr_eio(reg, eax, edx);
 }
diff -u --recursive --new-file v2.4.7/linux/arch/i386/kernel/process.c linux/arch/i386/kernel/process.c
--- v2.4.7/linux/arch/i386/kernel/process.c	Wed Jul 25 17:10:17 2001
+++ linux/arch/i386/kernel/process.c	Wed Jul 25 18:19:11 2001
@@ -518,6 +518,7 @@
 			memcpy(ldt, old_ldt, LDT_ENTRIES*LDT_ENTRY_SIZE);
 	}
 	new_mm->context.segments = ldt;
+	new_mm->context.cpuvalid = ~0UL;	/* valid on all CPU's - they can't have stale data */
 }
 
 /*
diff -u --recursive --new-file v2.4.7/linux/arch/i386/math-emu/poly.h linux/arch/i386/math-emu/poly.h
--- v2.4.7/linux/arch/i386/math-emu/poly.h	Fri Apr  6 10:42:47 2001
+++ linux/arch/i386/math-emu/poly.h	Thu Jul 26 13:37:38 2001
@@ -60,7 +60,7 @@
 /* Some versions of gcc make it difficult to stop eax from being clobbered.
    Merely specifying that it is used doesn't work...
  */
-extern inline unsigned long mul_32_32(const unsigned long arg1,
+static inline unsigned long mul_32_32(const unsigned long arg1,
 				      const unsigned long arg2)
 {
   int retval;
@@ -73,7 +73,7 @@
 
 
 /* Add the 12 byte Xsig x2 to Xsig dest, with no checks for overflow. */
-extern inline void add_Xsig_Xsig(Xsig *dest, const Xsig *x2)
+static inline void add_Xsig_Xsig(Xsig *dest, const Xsig *x2)
 {
   asm volatile ("movl %1,%%edi; movl %2,%%esi;
                  movl (%%esi),%%eax; addl %%eax,(%%edi);
@@ -88,7 +88,7 @@
 /* Note: the constraints in the asm statement didn't always work properly
    with gcc 2.5.8.  Changing from using edi to using ecx got around the
    problem, but keep fingers crossed! */
-extern inline void add_two_Xsig(Xsig *dest, const Xsig *x2, long int *exp)
+static inline void add_two_Xsig(Xsig *dest, const Xsig *x2, long int *exp)
 {
   asm volatile ("movl %2,%%ecx; movl %3,%%esi;
                  movl (%%esi),%%eax; addl %%eax,(%%ecx);
@@ -108,7 +108,7 @@
 
 /* Negate (subtract from 1.0) the 12 byte Xsig */
 /* This is faster in a loop on my 386 than using the "neg" instruction. */
-extern inline void negate_Xsig(Xsig *x)
+static inline void negate_Xsig(Xsig *x)
 {
   asm volatile("movl %1,%%esi; "
                "xorl %%ecx,%%ecx; "
diff -u --recursive --new-file v2.4.7/linux/arch/ia64/Makefile linux/arch/ia64/Makefile
--- v2.4.7/linux/arch/ia64/Makefile	Thu Apr  5 12:51:46 2001
+++ linux/arch/ia64/Makefile	Tue Jul 31 10:30:08 2001
@@ -14,18 +14,18 @@
 export AWK
 
 LINKFLAGS = -static -T arch/$(ARCH)/vmlinux.lds
-AFLAGS += -Wa,-x
 AFLAGS_KERNEL := -mconstant-gp
 EXTRA	=
 
-CFLAGS := $(CFLAGS) -pipe $(EXTRA) -Wa,-x -ffixed-r13 -mfixed-range=f10-f15,f32-f127 \
-	  -funwind-tables -falign-functions=32
-# -frename-registers (this crashes the Nov 17 compiler...)
+CFLAGS := $(CFLAGS) -pipe $(EXTRA) -ffixed-r13 -mfixed-range=f10-f15,f32-f127 -falign-functions=32
 CFLAGS_KERNEL := -mconstant-gp
 
-ifeq ($(CONFIG_ITANIUM_ASTEP_SPECIFIC),y)
-	CFLAGS += -ma-step
+GCC_VERSION=$(shell $(CROSS_COMPILE)$(HOSTCC) -v 2>&1 | fgrep 'gcc version' | cut -f3 -d' ' | cut -f1 -d'.')
+
+ifneq ($(GCC_VERSION),2)
+	CFLAGS += -frename-registers
 endif
+
 ifeq ($(CONFIG_ITANIUM_BSTEP_SPECIFIC),y)
 	CFLAGS += -mb-step
 endif
diff -u --recursive --new-file v2.4.7/linux/arch/ia64/boot/bootloader.c linux/arch/ia64/boot/bootloader.c
--- v2.4.7/linux/arch/ia64/boot/bootloader.c	Thu Apr  5 12:51:47 2001
+++ linux/arch/ia64/boot/bootloader.c	Tue Jul 31 10:30:08 2001
@@ -87,9 +87,6 @@
 	asm volatile ("movl gp=__gp;;" ::: "memory");
 	asm volatile ("mov sp=%0" :: "r"(stack) : "memory");
 	asm volatile ("bsw.1;;");
-#ifdef CONFIG_ITANIUM_ASTEP_SPECIFIC
-	asm volative ("nop 0;; nop 0;; nop 0;;");
-#endif /* CONFIG_ITANIUM_ASTEP_SPECIFIC */
 
 	ssc(0, 0, 0, 0, SSC_CONSOLE_INIT);
 
diff -u --recursive --new-file v2.4.7/linux/arch/ia64/config.in linux/arch/ia64/config.in
--- v2.4.7/linux/arch/ia64/config.in	Tue Apr 17 17:19:24 2001
+++ linux/arch/ia64/config.in	Tue Jul 31 10:30:08 2001
@@ -26,6 +26,12 @@
 define_bool CONFIG_RWSEM_GENERIC_SPINLOCK y
 define_bool CONFIG_RWSEM_XCHGADD_ALGORITHM n
 
+if [ "$CONFIG_IA64_HP_SIM" = "n" ]; then
+  define_bool CONFIG_ACPI y
+  define_bool CONFIG_ACPI_INTERPRETER y
+  define_bool CONFIG_ACPI_KERNEL_CONFIG y
+fi
+
 choice 'IA-64 processor type' \
 	"Itanium			CONFIG_ITANIUM \
 	 McKinley			CONFIG_MCKINLEY" Itanium
@@ -44,7 +50,6 @@
 
 if [ "$CONFIG_ITANIUM" = "y" ]; then
 	define_bool CONFIG_IA64_BRL_EMU y
-	bool '  Enable Itanium A-step specific code' CONFIG_ITANIUM_ASTEP_SPECIFIC
 	bool '  Enable Itanium B-step specific code' CONFIG_ITANIUM_BSTEP_SPECIFIC
 	if [ "$CONFIG_ITANIUM_BSTEP_SPECIFIC" = "y" ]; then
 	  bool '   Enable Itanium B0-step specific code' CONFIG_ITANIUM_B0_SPECIFIC
@@ -59,7 +64,7 @@
 	if [ "$CONFIG_ITANIUM_CSTEP_SPECIFIC" = "y" ]; then
 	  bool '   Enable Itanium C0-step specific code' CONFIG_ITANIUM_C0_SPECIFIC
 	fi
-	if [ "$CONFIG_ITANIUM_ASTEP_SPECIFIC" = "y" -o "$CONFIG_ITANIUM_B0_SPECIFIC" = "y" \
+	if [ "$CONFIG_ITANIUM_B0_SPECIFIC" = "y" \
 	     -o "$CONFIG_ITANIUM_B1_SPECIFIC" = "y" -o "$CONFIG_ITANIUM_B2_SPECIFIC" = "y" ]; then
 	  define_bool CONFIG_ITANIUM_PTCG n
 	else
@@ -84,13 +89,7 @@
 if [ "$CONFIG_IA64_DIG" = "y" ]; then
 	bool '  Force interrupt redirection' CONFIG_IA64_HAVE_IRQREDIR
 	bool '  Enable IA-64 Machine Check Abort' CONFIG_IA64_MCA
-	bool '  Enable ACPI 2.0 with errata 1.3' CONFIG_ACPI20
-	bool '  ACPI kernel configuration manager (EXPERIMENTAL)' CONFIG_ACPI_KERNEL_CONFIG
-	if [ "$CONFIG_ACPI_KERNEL_CONFIG" = "y" ]; then
-	  define_bool CONFIG_PM y
-	  define_bool CONFIG_ACPI y
-	  define_bool CONFIG_ACPI_INTERPRETER y
-	fi
+	define_bool CONFIG_PM y
 fi
 
 if [ "$CONFIG_IA64_SGI_SN1" = "y" ]; then
@@ -112,7 +111,7 @@
 bool 'SMP support' CONFIG_SMP
 bool 'Performance monitor support' CONFIG_PERFMON
 tristate '/proc/pal support' CONFIG_IA64_PALINFO
-tristate '/proc/efi support' CONFIG_IA64_EFIVARS
+tristate '/proc/efi/vars support' CONFIG_EFI_VARS
 
 bool 'Networking support' CONFIG_NET
 bool 'System V IPC' CONFIG_SYSVIPC
@@ -123,6 +122,8 @@
 
 if [ "$CONFIG_IA64_HP_SIM" = "n" ]; then
 
+source drivers/acpi/Config.in
+
 bool 'PCI support' CONFIG_PCI
 source drivers/pci/Config.in
 
@@ -246,6 +247,10 @@
 endmenu
 
 source drivers/usb/Config.in
+
+if [ "$CONFIG_EXPERIMENTAL" = "y" ]; then
+   source net/bluetooth/Config.in
+fi
 
 fi # !HP_SIM
 
diff -u --recursive --new-file v2.4.7/linux/arch/ia64/hp/hpsim_setup.c linux/arch/ia64/hp/hpsim_setup.c
--- v2.4.7/linux/arch/ia64/hp/hpsim_setup.c	Thu Jan  4 12:50:17 2001
+++ linux/arch/ia64/hp/hpsim_setup.c	Tue Jul 31 10:30:08 2001
@@ -27,28 +27,15 @@
 /*
  * Simulator system call.
  */
-inline long
-ia64_ssc (long arg0, long arg1, long arg2, long arg3, int nr)
-{
-#ifdef __GCC_DOESNT_KNOW_IN_REGS__
-	register long in0 asm ("r32") = arg0;
-	register long in1 asm ("r33") = arg1;
-	register long in2 asm ("r34") = arg2;
-	register long in3 asm ("r35") = arg3;
-#else
-	register long in0 asm ("in0") = arg0;
-	register long in1 asm ("in1") = arg1;
-	register long in2 asm ("in2") = arg2;
-	register long in3 asm ("in3") = arg3;
-#endif
-	register long r8 asm ("r8");
-	register long r15 asm ("r15") = nr;
-
-	asm volatile ("break 0x80001"
-		      : "=r"(r8)
-		      : "r"(r15), "r"(in0), "r"(in1), "r"(in2), "r"(in3));
-	return r8;
-}
+asm (".text\n"
+     ".align 32\n"
+     ".global ia64_ssc\n"
+     ".proc ia64_ssc\n"
+     "ia64_ssc:\n"
+     "mov r15=r36\n"
+     "break 0x80001\n"
+     "br.ret.sptk.many rp\n"
+     ".endp\n");
 
 void
 ia64_ssc_connect_irq (long intr, long irq)
diff -u --recursive --new-file v2.4.7/linux/arch/ia64/ia32/Makefile linux/arch/ia64/ia32/Makefile
--- v2.4.7/linux/arch/ia64/ia32/Makefile	Thu Jan  4 12:50:17 2001
+++ linux/arch/ia64/ia32/Makefile	Tue Jul 31 10:30:08 2001
@@ -11,7 +11,8 @@
 
 O_TARGET := ia32.o
 
-obj-y := ia32_entry.o sys_ia32.o ia32_ioctl.o ia32_signal.o ia32_support.o ia32_traps.o binfmt_elf32.o
+obj-y := ia32_entry.o sys_ia32.o ia32_ioctl.o ia32_signal.o ia32_support.o ia32_traps.o \
+	 binfmt_elf32.o ia32_ldt.o
 
 clean::
 
diff -u --recursive --new-file v2.4.7/linux/arch/ia64/ia32/binfmt_elf32.c linux/arch/ia64/ia32/binfmt_elf32.c
--- v2.4.7/linux/arch/ia64/ia32/binfmt_elf32.c	Thu Apr  5 12:51:47 2001
+++ linux/arch/ia64/ia32/binfmt_elf32.c	Tue Jul 31 10:30:08 2001
@@ -2,8 +2,11 @@
  * IA-32 ELF support.
  *
  * Copyright (C) 1999 Arun Sharma <arun.sharma@intel.com>
+ * Copyright (C) 2001 Hewlett-Packard Co
+ * Copyright (C) 2001 David Mosberger-Tang <davidm@hpl.hp.com>
  *
  * 06/16/00	A. Mallick	initialize csd/ssd/tssd/cflg for ia32_load_state
+ * 04/13/01	D. Mosberger	dropped saving tssd in ar.k1---it's not needed
  */
 #include <linux/config.h>
 
@@ -35,8 +38,8 @@
 #undef CLOCKS_PER_SEC
 #define CLOCKS_PER_SEC	IA32_CLOCKS_PER_SEC
 
-extern void ia64_elf32_init(struct pt_regs *regs);
-extern void put_dirty_page(struct task_struct * tsk, struct page *page, unsigned long address);
+extern void ia64_elf32_init (struct pt_regs *regs);
+extern void put_dirty_page (struct task_struct * tsk, struct page *page, unsigned long address);
 
 #define ELF_PLAT_INIT(_r)		ia64_elf32_init(_r)
 #define setup_arg_pages(bprm)		ia32_setup_arg_pages(bprm)
@@ -49,7 +52,7 @@
 unsigned long *ia32_gdt_table, *ia32_tss;
 
 struct page *
-put_shared_page(struct task_struct * tsk, struct page *page, unsigned long address)
+put_shared_page (struct task_struct * tsk, struct page *page, unsigned long address)
 {
 	pgd_t * pgd;
 	pmd_t * pmd;
@@ -83,85 +86,99 @@
 	return 0;
 }
 
-void ia64_elf32_init(struct pt_regs *regs)
+void
+ia64_elf32_init (struct pt_regs *regs)
 {
+	struct vm_area_struct *vma;
 	int nr;
 
-	put_shared_page(current, virt_to_page(ia32_gdt_table), IA32_PAGE_OFFSET);
+	/*
+	 * Map GDT and TSS below 4GB, where the processor can find them.  We need to map
+	 * it with privilege level 3 because the IVE uses non-privileged accesses to these
+	 * tables.  IA-32 segmentation is used to protect against IA-32 accesses to them.
+	 */
+	put_shared_page(current, virt_to_page(ia32_gdt_table), IA32_GDT_OFFSET);
 	if (PAGE_SHIFT <= IA32_PAGE_SHIFT)
-		put_shared_page(current, virt_to_page(ia32_tss), IA32_PAGE_OFFSET + PAGE_SIZE);
+		put_shared_page(current, virt_to_page(ia32_tss), IA32_TSS_OFFSET);
 
-	nr = smp_processor_id();
+	/*
+	 * Install LDT as anonymous memory.  This gives us all-zero segment descriptors
+	 * until a task modifies them via modify_ldt().
+	 */
+	vma = kmem_cache_alloc(vm_area_cachep, SLAB_KERNEL);
+	if (vma) {
+		vma->vm_mm = current->mm;
+		vma->vm_start = IA32_LDT_OFFSET;
+		vma->vm_end = vma->vm_start + PAGE_ALIGN(IA32_LDT_ENTRIES*IA32_LDT_ENTRY_SIZE);
+		vma->vm_page_prot = PAGE_SHARED;
+		vma->vm_flags = VM_READ|VM_WRITE|VM_MAYREAD|VM_MAYWRITE;
+		vma->vm_ops = NULL;
+		vma->vm_pgoff = 0;
+		vma->vm_file = NULL;
+		vma->vm_private_data = NULL;
+		insert_vm_struct(current->mm, vma);
+	}
 
-	/* Do all the IA-32 setup here */
+	nr = smp_processor_id();
 
-	current->thread.map_base  = 0x40000000;
-	current->thread.task_size = 0xc0000000;		/* use what Linux/x86 uses... */
+	current->thread.map_base  = IA32_PAGE_OFFSET/3;
+	current->thread.task_size = IA32_PAGE_OFFSET;	/* use what Linux/x86 uses... */
 	set_fs(USER_DS);				/* set addr limit for new TASK_SIZE */
 
-	/* setup ia32 state for ia32_load_state */
-
-	current->thread.eflag = IA32_EFLAG;
-	current->thread.csd = IA64_SEG_DESCRIPTOR(0L, 0xFFFFFL, 0xBL, 1L, 3L, 1L, 1L, 1L);
-	current->thread.ssd = IA64_SEG_DESCRIPTOR(0L, 0xFFFFFL, 0x3L, 1L, 3L, 1L, 1L, 1L);
-	current->thread.tssd = IA64_SEG_DESCRIPTOR(IA32_PAGE_OFFSET + PAGE_SIZE, 0x1FFFL, 0xBL,
-						   1L, 3L, 1L, 1L, 1L);
-
-	/* CS descriptor */
-	__asm__("mov ar.csd = %0" : /* no outputs */
-		: "r" IA64_SEG_DESCRIPTOR(0L, 0xFFFFFL, 0xBL, 1L,
-					  3L, 1L, 1L, 1L));
-	/* SS descriptor */
-	__asm__("mov ar.ssd = %0" : /* no outputs */
-		: "r" IA64_SEG_DESCRIPTOR(0L, 0xFFFFFL, 0x3L, 1L,
-					  3L, 1L, 1L, 1L));
-	/* EFLAGS */
-	__asm__("mov ar.eflag = %0" : /* no outputs */ : "r" (IA32_EFLAG));
-
-	/* Control registers */
-	__asm__("mov ar.fsr = %0"
-		: /* no outputs */
-		: "r" ((ulong)IA32_FSR_DEFAULT));
-	__asm__("mov ar.fcr = %0"
-		: /* no outputs */
-		: "r" ((ulong)IA32_FCR_DEFAULT));
-	__asm__("mov ar.fir = r0");
-	__asm__("mov ar.fdr = r0");
-	current->thread.old_iob = ia64_get_kr(IA64_KR_IO_BASE);
-	ia64_set_kr(IA64_KR_IO_BASE, IA32_IOBASE);
-
-	/* Get the segment selectors right */
-	regs->r16 = (__USER_DS << 16) |  (__USER_DS); /* ES == DS, GS, FS are zero */
-	regs->r17 = (_TSS(nr) << 48) | (_LDT(nr) << 32)
-		    | (__USER_DS << 16) | __USER_CS;
-
-	/* Setup other segment descriptors - ESD, DSD, FSD, GSD */
-	regs->r24 = IA64_SEG_DESCRIPTOR(0L, 0xFFFFFL, 0x3L, 1L, 3L, 1L, 1L, 1L);
-	regs->r27 = IA64_SEG_DESCRIPTOR(0L, 0xFFFFFL, 0x3L, 1L, 3L, 1L, 1L, 1L);
-	regs->r28 = IA64_SEG_DESCRIPTOR(0L, 0xFFFFFL, 0x3L, 1L, 3L, 1L, 1L, 1L);
-	regs->r29 = IA64_SEG_DESCRIPTOR(0L, 0xFFFFFL, 0x3L, 1L, 3L, 1L, 1L, 1L);
-
-	/* Setup the LDT and GDT */
-	regs->r30 = ia32_gdt_table[_LDT(nr)];
-	regs->r31 = IA64_SEG_DESCRIPTOR(0xc0000000L, 0x400L, 0x3L, 1L, 3L,
-					1L, 1L, 1L);
+	/* Setup the segment selectors */
+	regs->r16 = (__USER_DS << 16) | __USER_DS; /* ES == DS, GS, FS are zero */
+	regs->r17 = (__USER_DS << 16) | __USER_CS; /* SS, CS; ia32_load_state() sets TSS and LDT */
+
+	/* Setup the segment descriptors */
+	regs->r24 = IA32_SEG_UNSCRAMBLE(ia32_gdt_table[__USER_DS >> 3]);	/* ESD */
+	regs->r27 = IA32_SEG_UNSCRAMBLE(ia32_gdt_table[__USER_DS >> 3]);	/* DSD */
+	regs->r28 = 0;								/* FSD (null) */
+	regs->r29 = 0;								/* GSD (null) */
+	regs->r30 = IA32_SEG_UNSCRAMBLE(ia32_gdt_table[_LDT(nr)]);		/* LDTD */
 
-	/* Clear psr.ac */
-	regs->cr_ipsr &= ~IA64_PSR_AC;
+	/*
+	 * Setup GDTD.  Note: GDTD is the descrambled version of the pseudo-descriptor
+	 * format defined by Figure 3-11 "Pseudo-Descriptor Format" in the IA-32
+	 * architecture manual.
+	 */
+	regs->r31 = IA32_SEG_UNSCRAMBLE(IA32_SEG_DESCRIPTOR(IA32_GDT_OFFSET, IA32_PAGE_SIZE - 1, 0,
+							    0, 0, 0, 0, 0, 0));
 
+	ia64_psr(regs)->ac = 0;		/* turn off alignment checking */
 	regs->loadrs = 0;
-}
+	/*
+	 *  According to the ABI %edx points to an `atexit' handler.  Since we don't have
+	 *  one we'll set it to 0 and initialize all the other registers just to make
+	 *  things more deterministic, ala the i386 implementation.
+	 */
+	regs->r8 = 0;	/* %eax */
+	regs->r11 = 0;	/* %ebx */
+	regs->r9 = 0;	/* %ecx */
+	regs->r10 = 0;	/* %edx */
+	regs->r13 = 0;	/* %ebp */
+	regs->r14 = 0;	/* %esi */
+	regs->r15 = 0;	/* %edi */
 
-#undef STACK_TOP
-#define STACK_TOP ((IA32_PAGE_OFFSET/3) * 2)
+	current->thread.eflag = IA32_EFLAG;
+	current->thread.fsr = IA32_FSR_DEFAULT;
+	current->thread.fcr = IA32_FCR_DEFAULT;
+	current->thread.fir = 0;
+	current->thread.fdr = 0;
+	current->thread.csd = IA32_SEG_UNSCRAMBLE(ia32_gdt_table[__USER_CS >> 3]);
+	current->thread.ssd = IA32_SEG_UNSCRAMBLE(ia32_gdt_table[__USER_DS >> 3]);
+	current->thread.tssd = IA32_SEG_UNSCRAMBLE(ia32_gdt_table[_TSS(nr)]);
+
+	ia32_load_state(current);
+}
 
-int ia32_setup_arg_pages(struct linux_binprm *bprm)
+int
+ia32_setup_arg_pages (struct linux_binprm *bprm)
 {
 	unsigned long stack_base;
 	struct vm_area_struct *mpnt;
 	int i;
 
-	stack_base = STACK_TOP - MAX_ARG_PAGES*PAGE_SIZE;
+	stack_base = IA32_STACK_TOP - MAX_ARG_PAGES*PAGE_SIZE;
 
 	bprm->p += stack_base;
 	if (bprm->loader)
@@ -175,7 +192,7 @@
 	{
 		mpnt->vm_mm = current->mm;
 		mpnt->vm_start = PAGE_MASK & (unsigned long) bprm->p;
-		mpnt->vm_end = STACK_TOP;
+		mpnt->vm_end = IA32_STACK_TOP;
 		mpnt->vm_page_prot = PAGE_COPY;
 		mpnt->vm_flags = VM_STACK_FLAGS;
 		mpnt->vm_ops = NULL;
@@ -197,15 +214,15 @@
 }
 
 static unsigned long
-ia32_mm_addr(unsigned long addr)
+ia32_mm_addr (unsigned long addr)
 {
 	struct vm_area_struct *vma;
 
 	if ((vma = find_vma(current->mm, addr)) == NULL)
-		return(ELF_PAGESTART(addr));
+		return ELF_PAGESTART(addr);
 	if (vma->vm_start > addr)
-		return(ELF_PAGESTART(addr));
-	return(ELF_PAGEALIGN(addr));
+		return ELF_PAGESTART(addr);
+	return ELF_PAGEALIGN(addr);
 }
 
 /*
@@ -232,22 +249,9 @@
 	 */
 	if (addr == 0)
 		addr += PAGE_SIZE;
-#if 1
 	set_brk(ia32_mm_addr(addr), addr + eppnt->p_memsz);
 	memset((char *) addr + eppnt->p_filesz, 0, eppnt->p_memsz - eppnt->p_filesz);
 	kernel_read(filep, eppnt->p_offset, (char *) addr, eppnt->p_filesz);
 	retval = (unsigned long) addr;
-#else
-	/* doesn't work yet... */
-#	define IA32_PAGESTART(_v) ((_v) & ~(unsigned long)(ELF_EXEC_PAGESIZE-1))
-#	define IA32_PAGEOFFSET(_v) ((_v) & (ELF_EXEC_PAGESIZE-1))
-#	define IA32_PAGEALIGN(_v) (((_v) + ELF_EXEC_PAGESIZE - 1) & ~(ELF_EXEC_PAGESIZE - 1))
-
-	down_write(&current->mm->mmap_sem);
-	retval = ia32_do_mmap(filep, IA32_PAGESTART(addr),
-			      eppnt->p_filesz + IA32_PAGEOFFSET(eppnt->p_vaddr), prot, type,
-			      eppnt->p_offset - IA32_PAGEOFFSET(eppnt->p_vaddr));
-	up_write(&current->mm->mmap_sem);
-#endif
 	return retval;
 }
diff -u --recursive --new-file v2.4.7/linux/arch/ia64/ia32/ia32_entry.S linux/arch/ia64/ia32/ia32_entry.S
--- v2.4.7/linux/arch/ia64/ia32/ia32_entry.S	Thu Apr  5 12:51:47 2001
+++ linux/arch/ia64/ia32/ia32_entry.S	Tue Jul 31 10:30:08 2001
@@ -140,7 +140,7 @@
 	data8 sys_lchown
 	data8 sys32_ni_syscall	  /* old break syscall holder */
 	data8 sys32_ni_syscall
-	data8 sys_lseek
+	data8 sys32_lseek
 	data8 sys_getpid	  /* 20 */
 	data8 sys_mount
 	data8 sys_oldumount
@@ -233,7 +233,7 @@
 	data8 sys32_ni_syscall
 	data8 sys_iopl		  /* 110 */
 	data8 sys_vhangup
-	data8 sys32_ni_syscall		// used to be sys_idle
+	data8 sys32_ni_syscall		/* used to be sys_idle */
 	data8 sys32_ni_syscall
 	data8 sys32_wait4
 	data8 sys_swapoff	  /* 115 */
@@ -244,7 +244,7 @@
 	data8 sys_clone		  /* 120 */
 	data8 sys_setdomainname
 	data8 sys32_newuname
-	data8 sys_modify_ldt
+	data8 sys32_modify_ldt
 	data8 sys_adjtimex
 	data8 sys32_mprotect	  /* 125 */
 	data8 sys_sigprocmask
@@ -286,13 +286,13 @@
 	data8 sys32_nanosleep
 	data8 sys_mremap
 	data8 sys_setresuid
-	data8 sys_getresuid	  /* 165 */
+	data8 sys32_getresuid	  /* 165 */
 	data8 sys_vm86
 	data8 sys_query_module
 	data8 sys_poll
 	data8 sys_nfsservctl
 	data8 sys_setresgid	  /* 170 */
-	data8 sys_getresgid
+	data8 sys32_getresgid
 	data8 sys_prctl
 	data8 sys32_rt_sigreturn
 	data8 sys32_rt_sigaction
diff -u --recursive --new-file v2.4.7/linux/arch/ia64/ia32/ia32_ldt.c linux/arch/ia64/ia32/ia32_ldt.c
--- v2.4.7/linux/arch/ia64/ia32/ia32_ldt.c	Wed Dec 31 16:00:00 1969
+++ linux/arch/ia64/ia32/ia32_ldt.c	Tue Jul 31 10:30:08 2001
@@ -0,0 +1,120 @@
+/*
+ * Copyright (C) 2001 Hewlett-Packard Co
+ * Copyright (C) 2001 David Mosberger-Tang <davidm@hpl.hp.com>
+ *
+ * Adapted from arch/i386/kernel/ldt.c
+ */
+
+#include <linux/errno.h>
+#include <linux/sched.h>
+#include <linux/string.h>
+#include <linux/mm.h>
+#include <linux/smp.h>
+#include <linux/smp_lock.h>
+#include <linux/vmalloc.h>
+
+#include <asm/uaccess.h>
+#include <asm/ia32.h>
+
+/*
+ * read_ldt() is not really atomic - this is not a problem since synchronization of reads
+ * and writes done to the LDT has to be assured by user-space anyway. Writes are atomic,
+ * to protect the security checks done on new descriptors.
+ */
+static int
+read_ldt (void *ptr, unsigned long bytecount)
+{
+	char *src, *dst, buf[256];	/* temporary buffer (don't overflow kernel stack!) */
+	unsigned long bytes_left, n;
+
+	if (bytecount > IA32_LDT_ENTRIES*IA32_LDT_ENTRY_SIZE)
+		bytecount = IA32_LDT_ENTRIES*IA32_LDT_ENTRY_SIZE;
+
+	bytes_left = bytecount;
+
+	src = (void *) IA32_LDT_OFFSET;
+	dst = ptr;
+
+	while (bytes_left) {
+		n = sizeof(buf);
+		if (n > bytes_left)
+			n = bytes_left;
+
+		/*
+		 * We know we're reading valid memory, but we still must guard against
+		 * running out of memory.
+		 */
+		if (__copy_from_user(buf, src, n))
+			return -EFAULT;
+
+		if (copy_to_user(dst, buf, n))
+			return -EFAULT;
+
+		src += n;
+		dst += n;
+		bytes_left -= n;
+	}
+	return bytecount;
+}
+
+static int
+write_ldt (void * ptr, unsigned long bytecount, int oldmode)
+{
+	struct ia32_modify_ldt_ldt_s ldt_info;
+	__u64 entry;
+
+	if (bytecount != sizeof(ldt_info))
+		return -EINVAL;
+	if (copy_from_user(&ldt_info, ptr, sizeof(ldt_info)))
+		return -EFAULT;
+
+	if (ldt_info.entry_number >= IA32_LDT_ENTRIES)
+		return -EINVAL;
+	if (ldt_info.contents == 3) {
+		if (oldmode)
+			return -EINVAL;
+		if (ldt_info.seg_not_present == 0)
+			return -EINVAL;
+	}
+
+	if (ldt_info.base_addr == 0 && ldt_info.limit == 0
+	    && (oldmode || (ldt_info.contents == 0 && ldt_info.read_exec_only == 1
+			    && ldt_info.seg_32bit == 0 && ldt_info.limit_in_pages == 0
+			    && ldt_info.seg_not_present == 1 && ldt_info.useable == 0)))
+		/* allow LDTs to be cleared by the user */
+		entry = 0;
+	else
+		/* we must set the "Accessed" bit as IVE doesn't emulate it */
+		entry = IA32_SEG_DESCRIPTOR(ldt_info.base_addr, ldt_info.limit,
+					    (((ldt_info.read_exec_only ^ 1) << 1)
+					     | (ldt_info.contents << 2)) | 1,
+					    1, 3, ldt_info.seg_not_present ^ 1,
+					    (oldmode ? 0 : ldt_info.useable),
+					    ldt_info.seg_32bit,
+					    ldt_info.limit_in_pages);
+	/*
+	 * Install the new entry.  We know we're accessing valid (mapped) user-level
+	 * memory, but we still need to guard against out-of-memory, hence we must use
+	 * put_user().
+	 */
+	return __put_user(entry, (__u64 *) IA32_LDT_OFFSET + ldt_info.entry_number);
+}
+
+asmlinkage int
+sys32_modify_ldt (int func, void *ptr, unsigned int bytecount)
+{
+	int ret = -ENOSYS;
+
+	switch (func) {
+	      case 0:
+		ret = read_ldt(ptr, bytecount);
+		break;
+	      case 1:
+		ret = write_ldt(ptr, bytecount, 1);
+		break;
+	      case 0x11:
+		ret = write_ldt(ptr, bytecount, 0);
+		break;
+	}
+	return ret;
+}
diff -u --recursive --new-file v2.4.7/linux/arch/ia64/ia32/ia32_support.c linux/arch/ia64/ia32/ia32_support.c
--- v2.4.7/linux/arch/ia64/ia32/ia32_support.c	Thu Apr  5 12:51:47 2001
+++ linux/arch/ia64/ia32/ia32_support.c	Tue Jul 31 10:30:08 2001
@@ -1,6 +1,11 @@
 /*
  * IA32 helper functions
  *
+ * Copyright (C) 1999 Arun Sharma <arun.sharma@intel.com>
+ * Copyright (C) 2000 Asit K. Mallick <asit.k.mallick@intel.com>
+ * Copyright (C) 2001 Hewlett-Packard Co
+ * Copyright (C) 2001 David Mosberger-Tang <davidm@hpl.hp.com>
+ *
  * 06/16/00	A. Mallick	added csd/ssd/tssd for ia32 thread context
  * 02/19/01	D. Mosberger	dropped tssd; it's not needed
  */
@@ -21,7 +26,7 @@
 extern void die_if_kernel (char *str, struct pt_regs *regs, long err);
 
 void
-ia32_save_state (struct thread_struct *thread)
+ia32_save_state (struct task_struct *t)
 {
 	unsigned long eflag, fsr, fcr, fir, fdr, csd, ssd;
 
@@ -33,28 +38,30 @@
 	     "mov %5=ar.csd;"
 	     "mov %6=ar.ssd;"
 	     : "=r"(eflag), "=r"(fsr), "=r"(fcr), "=r"(fir), "=r"(fdr), "=r"(csd), "=r"(ssd));
-	thread->eflag = eflag;
-	thread->fsr = fsr;
-	thread->fcr = fcr;
-	thread->fir = fir;
-	thread->fdr = fdr;
-	thread->csd = csd;
-	thread->ssd = ssd;
-	asm ("mov ar.k0=%0 ;;" :: "r"(thread->old_iob));
+	t->thread.eflag = eflag;
+	t->thread.fsr = fsr;
+	t->thread.fcr = fcr;
+	t->thread.fir = fir;
+	t->thread.fdr = fdr;
+	t->thread.csd = csd;
+	t->thread.ssd = ssd;
+	ia64_set_kr(IA64_KR_IO_BASE, t->thread.old_iob);
 }
 
 void
-ia32_load_state (struct thread_struct *thread)
+ia32_load_state (struct task_struct *t)
 {
 	unsigned long eflag, fsr, fcr, fir, fdr, csd, ssd;
+	struct pt_regs *regs = ia64_task_regs(t);
+	int nr;
 
-	eflag = thread->eflag;
-	fsr = thread->fsr;
-	fcr = thread->fcr;
-	fir = thread->fir;
-	fdr = thread->fdr;
-	csd = thread->csd;
-	ssd = thread->ssd;
+	eflag = t->thread.eflag;
+	fsr = t->thread.fsr;
+	fcr = t->thread.fcr;
+	fir = t->thread.fir;
+	fdr = t->thread.fdr;
+	csd = t->thread.csd;
+	ssd = t->thread.ssd;
 
 	asm volatile ("mov ar.eflag=%0;"
 		      "mov ar.fsr=%1;"
@@ -64,17 +71,22 @@
 		      "mov ar.csd=%5;"
 		      "mov ar.ssd=%6;"
 		      :: "r"(eflag), "r"(fsr), "r"(fcr), "r"(fir), "r"(fdr), "r"(csd), "r"(ssd));
-	asm ("mov %0=ar.k0 ;;" : "=r"(thread->old_iob));
-	asm ("mov ar.k0=%0 ;;" :: "r"(IA32_IOBASE));
+	current->thread.old_iob = ia64_get_kr(IA64_KR_IO_BASE);
+	ia64_set_kr(IA64_KR_IO_BASE, IA32_IOBASE);
+
+	/* load TSS and LDT while preserving SS and CS: */
+	nr = smp_processor_id();
+	regs->r17 = (_TSS(nr) << 48) | (_LDT(nr) << 32) | (__u32) regs->r17;
 }
 
 /*
- * Setup IA32 GDT and TSS 
+ * Setup IA32 GDT and TSS
  */
 void
-ia32_gdt_init(void)
+ia32_gdt_init (void)
 {
-	unsigned long gdt_and_tss_page;
+	unsigned long gdt_and_tss_page, ldt_size;
+	int nr;
 
 	/* allocate two IA-32 pages of memory: */
 	gdt_and_tss_page = __get_free_pages(GFP_KERNEL,
@@ -86,17 +98,28 @@
 	/* Zero the gdt and tss */
 	memset((void *) gdt_and_tss_page, 0, 2*IA32_PAGE_SIZE);
 
-	/* CS descriptor in IA-32 format */
-	ia32_gdt_table[4] = IA32_SEG_DESCRIPTOR(0L, 0xBFFFFFFFL, 0xBL, 1L,
-						3L, 1L, 1L, 1L, 1L);
-
-	/* DS descriptor in IA-32 format */
-	ia32_gdt_table[5] = IA32_SEG_DESCRIPTOR(0L, 0xBFFFFFFFL, 0x3L, 1L,
-						3L, 1L, 1L, 1L, 1L);
+	/* CS descriptor in IA-32 (scrambled) format */
+	ia32_gdt_table[__USER_CS >> 3] =
+		IA32_SEG_DESCRIPTOR(0, (IA32_PAGE_OFFSET - 1) >> IA32_PAGE_SHIFT,
+				    0xb, 1, 3, 1, 1, 1, 1);
+
+	/* DS descriptor in IA-32 (scrambled) format */
+	ia32_gdt_table[__USER_DS >> 3] =
+		IA32_SEG_DESCRIPTOR(0, (IA32_PAGE_OFFSET - 1) >> IA32_PAGE_SHIFT,
+				    0x3, 1, 3, 1, 1, 1, 1);
+
+	/* We never change the TSS and LDT descriptors, so we can share them across all CPUs.  */
+	ldt_size = PAGE_ALIGN(IA32_LDT_ENTRIES*IA32_LDT_ENTRY_SIZE);
+	for (nr = 0; nr < NR_CPUS; ++nr) {
+		ia32_gdt_table[_TSS(nr)] = IA32_SEG_DESCRIPTOR(IA32_TSS_OFFSET, 235,
+							       0xb, 0, 3, 1, 1, 1, 0);
+		ia32_gdt_table[_LDT(nr)] = IA32_SEG_DESCRIPTOR(IA32_LDT_OFFSET, ldt_size - 1,
+							       0x2, 0, 3, 1, 1, 1, 0);
+	}
 }
 
 /*
- * Handle bad IA32 interrupt via syscall 
+ * Handle bad IA32 interrupt via syscall
  */
 void
 ia32_bad_interrupt (unsigned long int_num, struct pt_regs *regs)
@@ -106,8 +129,7 @@
 	die_if_kernel("Bad IA-32 interrupt", regs, int_num);
 
 	siginfo.si_signo = SIGTRAP;
-	siginfo.si_errno = int_num;	/* XXX is it legal to abuse si_errno like this? */
+	siginfo.si_errno = int_num;	/* XXX is it OK to abuse si_errno like this? */
 	siginfo.si_code = TRAP_BRKPT;
 	force_sig_info(SIGTRAP, &siginfo, current);
 }
-
diff -u --recursive --new-file v2.4.7/linux/arch/ia64/ia32/sys_ia32.c linux/arch/ia64/ia32/sys_ia32.c
--- v2.4.7/linux/arch/ia64/ia32/sys_ia32.c	Thu Apr  5 12:51:47 2001
+++ linux/arch/ia64/ia32/sys_ia32.c	Tue Jul 31 10:30:08 2001
@@ -232,10 +232,17 @@
 	back = NULL;
 	if ((baddr = (addr & PAGE_MASK)) != addr && get_user(c, (char *)baddr) == 0) {
 		front = kmalloc(addr - baddr, GFP_KERNEL);
+		if (!front)
+			return -ENOMEM;
 		__copy_user(front, (void *)baddr, addr - baddr);
 	}
 	if (addr && ((addr + len) & ~PAGE_MASK) && get_user(c, (char *)(addr + len)) == 0) {
 		back = kmalloc(PAGE_SIZE - ((addr + len) & ~PAGE_MASK), GFP_KERNEL);
+		if (!back) {
+			if (front)
+				kfree(front);
+			return -ENOMEM;
+		}
 		__copy_user(back, (char *)addr + len, PAGE_SIZE - ((addr + len) & ~PAGE_MASK));
 	}
 	down_write(&current->mm->mmap_sem);
@@ -334,9 +341,9 @@
 	down_write(&current->mm->mmap_sem);
 	retval = do_mmap_pgoff(file, a.addr, a.len, a.prot, a.flags, a.offset >> PAGE_SHIFT);
 	up_write(&current->mm->mmap_sem);
-#else	// CONFIG_IA64_PAGE_SIZE_4KB
+#else
 	retval = ia32_do_mmap(file, a.addr, a.len, a.prot, a.flags, a.fd, a.offset);
-#endif	// CONFIG_IA64_PAGE_SIZE_4KB
+#endif
 	if (file)
 		fput(file);
 	return retval;
@@ -660,9 +667,11 @@
 	long ret;
 
 	if (times32) {
-		get_user(tv[0].tv_sec, &times32->atime);
+		if (get_user(tv[0].tv_sec, &times32->atime))
+			return -EFAULT;
 		tv[0].tv_usec = 0;
-		get_user(tv[1].tv_sec, &times32->mtime);
+		if (get_user(tv[1].tv_sec, &times32->mtime))
+			return -EFAULT;
 		tv[1].tv_usec = 0;
 		set_fs (KERNEL_DS);
 		tvp = tv;
@@ -747,15 +756,18 @@
 	buf->error = -EINVAL;	/* only used if we fail.. */
 	if (reclen > buf->count)
 		return -EINVAL;
+	buf->error = -EFAULT;	/* only used if we fail.. */
 	dirent = buf->previous;
 	if (dirent)
-		put_user(offset, &dirent->d_off);
+		if (put_user(offset, &dirent->d_off))
+			return -EFAULT;
 	dirent = buf->current_dir;
 	buf->previous = dirent;
-	put_user(ino, &dirent->d_ino);
-	put_user(reclen, &dirent->d_reclen);
-	copy_to_user(dirent->d_name, name, namlen);
-	put_user(0, dirent->d_name + namlen);
+	if (put_user(ino, &dirent->d_ino)
+	    || put_user(reclen, &dirent->d_reclen)
+	    || copy_to_user(dirent->d_name, name, namlen)
+	    || put_user(0, dirent->d_name + namlen))
+		return -EFAULT;
 	((char *) dirent) += reclen;
 	buf->current_dir = dirent;
 	buf->count -= reclen;
@@ -786,7 +798,9 @@
 	error = buf.error;
 	lastdirent = buf.previous;
 	if (lastdirent) {
-		put_user(file->f_pos, &lastdirent->d_off);
+		error = -EINVAL;
+		if (put_user(file->f_pos, &lastdirent->d_off))
+			goto out_putf;
 		error = count - buf.count;
 	}
 
@@ -807,11 +821,12 @@
 		return -EINVAL;
 	buf->count++;
 	dirent = buf->dirent;
-	put_user(ino, &dirent->d_ino);
-	put_user(offset, &dirent->d_offset);
-	put_user(namlen, &dirent->d_namlen);
-	copy_to_user(dirent->d_name, name, namlen);
-	put_user(0, dirent->d_name + namlen);
+	if (put_user(ino, &dirent->d_ino)
+	    || put_user(offset, &dirent->d_offset)
+	    || put_user(namlen, &dirent->d_namlen)
+	    || copy_to_user(dirent->d_name, name, namlen)
+	    || put_user(0, dirent->d_name + namlen))
+		return -EFAULT;
 	return 0;
 }
 
@@ -862,8 +877,10 @@
 	if (tvp32) {
 		time_t sec, usec;
 
-		get_user(sec, &tvp32->tv_sec);
-		get_user(usec, &tvp32->tv_usec);
+		ret = -EFAULT;
+		if (get_user(sec, &tvp32->tv_sec)
+		    || get_user(usec, &tvp32->tv_usec))
+			goto out_nofds;
 
 		ret = -EINVAL;
 		if (sec < 0 || usec < 0)
@@ -916,8 +933,12 @@
 			usec = timeout % HZ;
 			usec *= (1000000/HZ);
 		}
-		put_user(sec, (int *)&tvp32->tv_sec);
-		put_user(usec, (int *)&tvp32->tv_usec);
+		if (put_user(sec, (int *)&tvp32->tv_sec)
+		    || put_user(usec, (int *)&tvp32->tv_usec))
+		{
+			ret = -EFAULT;
+			goto out;
+		}
 	}
 
 	if (ret < 0)
@@ -1558,16 +1579,15 @@
 {
 	union semun fourth;
 	u32 pad;
-	int err, err2;
+	int err = 0, err2;
 	struct semid64_ds s;
 	struct semid_ds32 *usp;
 	mm_segment_t old_fs;
 
 	if (!uptr)
 		return -EINVAL;
-	err = -EFAULT;
-	if (get_user (pad, (u32 *)uptr))
-		return err;
+	if (get_user(pad, (u32 *)uptr))
+		return -EFAULT;
 	if(third == SETVAL)
 		fourth.val = (int)pad;
 	else
@@ -1749,15 +1769,14 @@
 {
 	unsigned long raddr;
 	u32 *uaddr = (u32 *)A((u32)third);
-	int err = -EINVAL;
+	int err;
 
 	if (version == 1)
-		return err;
+		return -EINVAL;
 	err = sys_shmat (first, uptr, second, &raddr);
 	if (err)
 		return err;
-	err = put_user (raddr, uaddr);
-	return err;
+	return put_user(raddr, uaddr);
 }
 
 static int
@@ -1886,8 +1905,7 @@
 		break;
 
 	case SHMAT:
-		err = do_sys32_shmat (first, second, third,
-				      version, (void *)AA(ptr));
+		err = do_sys32_shmat (first, second, third, version, (void *)AA(ptr));
 		break;
 	case SHMDT:
 		err = sys_shmdt ((char *)AA(ptr));
@@ -2125,7 +2143,7 @@
 	case PT_CS:
 		return((unsigned int)__USER_CS);
 	default:
-		printk("getregs:unknown register %d\n", regno);
+		printk(KERN_ERR "getregs:unknown register %d\n", regno);
 		break;
 
 	}
@@ -2177,14 +2195,16 @@
 	case PT_GS:
 	case PT_SS:
 		if (value != __USER_DS)
-			printk("setregs:try to set invalid segment register %d = %x\n", regno, value);
+			printk(KERN_ERR "setregs:try to set invalid segment register %d = %x\n",
+			       regno, value);
 		break;
 	case PT_CS:
 		if (value != __USER_CS)
-			printk("setregs:try to set invalid segment register %d = %x\n", regno, value);
+			printk(KERN_ERR "setregs:try to set invalid segment register %d = %x\n",
+			       regno, value);
 		break;
 	default:
-		printk("getregs:unknown register %d\n", regno);
+		printk(KERN_ERR "getregs:unknown register %d\n", regno);
 		break;
 
 	}
@@ -2240,7 +2260,6 @@
 
 	}
 	__copy_to_user(reg, f, sizeof(*reg));
-	return;
 }
 
 void
@@ -2334,8 +2353,8 @@
  *    the address of `stack' will not be the address of the `pt_regs'.
  */
 asmlinkage long
-sys32_ptrace (long request, pid_t pid, unsigned long addr, unsigned long data,
-	    long arg4, long arg5, long arg6, long arg7, long stack)
+sys32_ptrace (int request, pid_t pid, unsigned int addr, unsigned int data,
+	      long arg4, long arg5, long arg6, long arg7, long stack)
 {
 	struct pt_regs *regs = (struct pt_regs *) &stack;
 	struct task_struct *child;
@@ -2379,7 +2398,7 @@
 	      case PTRACE_PEEKDATA:	/* read word at location addr */
 		ret = ia32_peek(regs, child, addr, &value);
 		if (ret == 0)
-			ret = put_user(value, (unsigned int *)data);
+			ret = put_user(value, (unsigned int *)A(data));
 		else
 			ret = -EIO;
 		goto out;
@@ -2398,12 +2417,12 @@
 		break;
 
 	      case IA32_PTRACE_GETREGS:
-		if (!access_ok(VERIFY_WRITE, (int *)data, 17*sizeof(int))) {
+		if (!access_ok(VERIFY_WRITE, (int *) A(data), 17*sizeof(int))) {
 			ret = -EIO;
 			break;
 		}
 		for ( i = 0; i < 17*sizeof(int); i += sizeof(int) ) {
-			__put_user(getreg(child, i),(unsigned int *) data);
+			__put_user(getreg(child, i), (unsigned int *) A(data));
 			data += sizeof(int);
 		}
 		ret = 0;
@@ -2412,12 +2431,12 @@
 	      case IA32_PTRACE_SETREGS:
 	      {
 		unsigned int tmp;
-		if (!access_ok(VERIFY_READ, (int *)data, 17*sizeof(int))) {
+		if (!access_ok(VERIFY_READ, (int *) A(data), 17*sizeof(int))) {
 			ret = -EIO;
 			break;
 		}
 		for ( i = 0; i < 17*sizeof(int); i += sizeof(int) ) {
-			__get_user(tmp, (unsigned int *) data);
+			__get_user(tmp, (unsigned int *) A(data));
 			putreg(child, i, tmp);
 			data += sizeof(int);
 		}
@@ -2426,11 +2445,11 @@
 	      }
 
 	      case IA32_PTRACE_GETFPREGS:
-		ret = save_ia32_fpstate(child, (struct _fpstate_ia32 *)data);
+		ret = save_ia32_fpstate(child, (struct _fpstate_ia32 *) A(data));
 		break;
 
 	      case IA32_PTRACE_SETFPREGS:
-		ret = restore_ia32_fpstate(child, (struct _fpstate_ia32 *)data);
+		ret = restore_ia32_fpstate(child, (struct _fpstate_ia32 *) A(data));
 		break;
 
 	      case PTRACE_SYSCALL:	/* continue, stop after next syscall */
@@ -2547,8 +2566,8 @@
 {
 	struct pt_regs *regs = (struct pt_regs *)&stack;
 
-	printk("IA32 syscall #%d issued, maybe we should implement it\n",
-		(int)regs->r1);
+	printk(KERN_WARNING "IA32 syscall #%d issued, maybe we should implement it\n",
+	       (int)regs->r1);
 	return(sys_ni_syscall());
 }
 
@@ -2558,7 +2577,7 @@
 #define IOLEN	((65536 / 4) * 4096)
 
 asmlinkage long
-sys_iopl (int level, long arg1, long arg2, long arg3)
+sys_iopl (int level)
 {
 	extern unsigned long ia64_iobase;
 	int fd;
@@ -2570,7 +2589,7 @@
 	if (level != 3)
 		return(-EINVAL);
 	/* Trying to gain more privileges? */
-	__asm__ __volatile__("mov %0=ar.eflag ;;" : "=r"(old));
+	asm volatile ("mov %0=ar.eflag ;;" : "=r"(old));
 	if (level > ((old >> 12) & 3)) {
 		if (!capable(CAP_SYS_RAWIO))
 			return -EPERM;
@@ -2587,17 +2606,13 @@
 	}
 
 	down_write(&current->mm->mmap_sem);
-	lock_kernel();
-
 	addr = do_mmap_pgoff(file, IA32_IOBASE,
-			IOLEN, PROT_READ|PROT_WRITE, MAP_SHARED,
-			(ia64_iobase & ~PAGE_OFFSET) >> PAGE_SHIFT);
-
-	unlock_kernel();
+			     IOLEN, PROT_READ|PROT_WRITE, MAP_SHARED,
+			     (ia64_iobase & ~PAGE_OFFSET) >> PAGE_SHIFT);
 	up_write(&current->mm->mmap_sem);
 
 	if (addr >= 0) {
-		__asm__ __volatile__("mov ar.k0=%0 ;;" :: "r"(addr));
+		ia64_set_kr(IA64_KR_IO_BASE, addr);
 		old = (old & ~0x3000) | (level << 12);
 		__asm__ __volatile__("mov ar.eflag=%0 ;;" :: "r"(old));
 	}
@@ -2608,7 +2623,7 @@
 }
 
 asmlinkage long
-sys_ioperm (unsigned long from, unsigned long num, int on)
+sys_ioperm (unsigned int from, unsigned int num, int on)
 {
 
 	/*
@@ -2621,7 +2636,7 @@
 	 * XXX proper ioperm() support should be emulated by
 	 *	manipulating the page protections...
 	 */
-	return(sys_iopl(3, 0, 0, 0));
+	return sys_iopl(3);
 }
 
 typedef struct {
@@ -2750,6 +2765,54 @@
 	return ret;
 }
 
+extern asmlinkage long sys_getresuid(uid_t *ruid, uid_t *euid, uid_t *suid);
+
+asmlinkage long
+sys32_getresuid (u16 *ruid, u16 *euid, u16 *suid)
+{
+	uid_t a, b, c;
+	int ret;
+	mm_segment_t old_fs = get_fs();
+
+	set_fs(KERNEL_DS);
+	ret = sys_getresuid(&a, &b, &c);
+	set_fs(old_fs);
+
+	if (put_user(a, ruid) || put_user(b, euid) || put_user(c, suid))
+		return -EFAULT;
+	return ret;
+}
+
+extern asmlinkage long sys_getresgid (gid_t *rgid, gid_t *egid, gid_t *sgid);
+
+asmlinkage long
+sys32_getresgid(u16 *rgid, u16 *egid, u16 *sgid)
+{
+	gid_t a, b, c;
+	int ret;
+	mm_segment_t old_fs = get_fs();
+
+	set_fs(KERNEL_DS);
+	ret = sys_getresgid(&a, &b, &c);
+	set_fs(old_fs);
+
+	if (!ret) {
+		ret  = put_user(a, rgid);
+		ret |= put_user(b, egid);
+		ret |= put_user(c, sgid);
+	}
+	return ret;
+}
+
+int
+sys32_lseek (unsigned int fd, int offset, unsigned int whence)
+{
+	extern off_t sys_lseek (unsigned int fd, off_t offset, unsigned int origin);
+
+	/* Sign-extension of "offset" is important here... */
+	return sys_lseek(fd, offset, whence);
+}
+
 #ifdef	NOTYET  /* UNTESTED FOR IA64 FROM HERE DOWN */
 
 /* In order to reduce some races, while at the same time doing additional
@@ -3235,7 +3298,7 @@
 siginfo_t32 *
 siginfo64to32(siginfo_t32 *d, siginfo_t *s)
 {
-	memset (&d, 0, sizeof(siginfo_t32));
+	memset(d, 0, sizeof(siginfo_t32));
 	d->si_signo = s->si_signo;
 	d->si_errno = s->si_errno;
 	d->si_code = s->si_code;
@@ -3440,27 +3503,6 @@
 	segid = (egid == (__kernel_gid_t32)-1) ? ((gid_t)-1) : ((gid_t)egid);
 	ssgid = (sgid == (__kernel_gid_t32)-1) ? ((gid_t)-1) : ((gid_t)sgid);
 	return sys_setresgid(srgid, segid, ssgid);
-}
-
-extern asmlinkage long sys_getresgid(gid_t *rgid, gid_t *egid, gid_t *sgid);
-
-asmlinkage long
-sys32_getresgid(__kernel_gid_t32 *rgid, __kernel_gid_t32 *egid,
-		__kernel_gid_t32 *sgid)
-{
-	gid_t a, b, c;
-	int ret;
-	mm_segment_t old_fs = get_fs();
-
-	set_fs (KERNEL_DS);
-	ret = sys_getresgid(&a, &b, &c);
-	set_fs (old_fs);
-	if (!ret) {
-		ret = put_user (a, rgid);
-		ret |= put_user (b, egid);
-		ret |= put_user (c, sgid);
-	}
-	return ret;
 }
 
 extern asmlinkage long sys_getgroups(int gidsetsize, gid_t *grouplist);
diff -u --recursive --new-file v2.4.7/linux/arch/ia64/kernel/Makefile linux/arch/ia64/kernel/Makefile
--- v2.4.7/linux/arch/ia64/kernel/Makefile	Thu Apr  5 12:51:47 2001
+++ linux/arch/ia64/kernel/Makefile	Tue Jul 31 10:30:08 2001
@@ -13,13 +13,13 @@
 
 export-objs := ia64_ksyms.o
 
-obj-y := acpi.o entry.o gate.o efi.o efi_stub.o ia64_ksyms.o irq.o irq_ia64.o irq_sapic.o ivt.o \
+obj-y := acpi.o entry.o gate.o efi.o efi_stub.o ia64_ksyms.o irq.o irq_ia64.o irq_lsapic.o ivt.o \
 	 machvec.o pal.o process.o perfmon.o ptrace.o sal.o semaphore.o setup.o	\
 	 signal.o sys_ia64.o traps.o time.o unaligned.o unwind.o
 obj-$(CONFIG_IA64_GENERIC) += machvec.o iosapic.o
 obj-$(CONFIG_IA64_DIG) += iosapic.o
 obj-$(CONFIG_IA64_PALINFO) += palinfo.o
-obj-$(CONFIG_IA64_EFIVARS) += efivars.o
+obj-$(CONFIG_EFI_VARS) += efivars.o
 obj-$(CONFIG_PCI) += pci.o
 obj-$(CONFIG_SMP) += smp.o smpboot.o
 obj-$(CONFIG_IA64_MCA) += mca.o mca_asm.o
diff -u --recursive --new-file v2.4.7/linux/arch/ia64/kernel/acpi.c linux/arch/ia64/kernel/acpi.c
--- v2.4.7/linux/arch/ia64/kernel/acpi.c	Thu Apr  5 12:51:47 2001
+++ linux/arch/ia64/kernel/acpi.c	Tue Jul 31 10:30:08 2001
@@ -25,14 +25,12 @@
 #include <linux/irq.h>
 
 #include <asm/acpi-ext.h>
+#include <asm/acpikcfg.h>
 #include <asm/efi.h>
 #include <asm/io.h>
 #include <asm/iosapic.h>
 #include <asm/machvec.h>
 #include <asm/page.h>
-#ifdef CONFIG_ACPI_KERNEL_CONFIG
-# include <asm/acpikcfg.h>
-#endif
 
 #undef ACPI_DEBUG		/* Guess what this does? */
 
@@ -40,7 +38,8 @@
 int __initdata available_cpus;
 int __initdata total_cpus;
 
-void (*pm_idle)(void);
+void (*pm_idle) (void);
+void (*pm_power_off) (void);
 
 asm (".weak iosapic_register_legacy_irq");
 asm (".weak iosapic_init");
@@ -206,11 +205,21 @@
 		case ACPI20_ENTRY_IO_SAPIC:
 			iosapic = (acpi_entry_iosapic_t *) p;
 			if (iosapic_init)
-				iosapic_init(iosapic->address, iosapic->irq_base);
+				/*
+				 * The PCAT_COMPAT flag indicates that the system has a
+				 * dual-8259 compatible setup.
+				 */
+				iosapic_init(iosapic->address, iosapic->irq_base,
+#ifdef CONFIG_ITANIUM
+					     1 /* fw on some Itanium systems is broken... */
+#else
+					     (madt->flags & MADT_PCAT_COMPAT)
+#endif
+					);
 			break;
 
 		case ACPI20_ENTRY_PLATFORM_INT_SOURCE:
-			printk("ACPI 2.0 MADT: PLATFORM INT SOUCE\n");
+			printk("ACPI 2.0 MADT: PLATFORM INT SOURCE\n");
 			acpi20_platform(p);
 			break;
 
@@ -257,6 +266,7 @@
 int __init
 acpi20_parse (acpi20_rsdp_t *rsdp20)
 {
+# ifdef CONFIG_ACPI
 	acpi_xsdt_t *xsdt;
 	acpi_desc_table_hdr_t *hdrp;
 	int tables, i;
@@ -287,9 +297,7 @@
 		hdrp->oem_revision >> 16,
 		hdrp->oem_revision & 0xffff);
 
-#ifdef CONFIG_ACPI_KERNEL_CONFIG
 	acpi_cf_init((void *)rsdp20);
-#endif
 
 	tables =(hdrp->length -sizeof(acpi_desc_table_hdr_t))>>3;
 
@@ -305,17 +313,16 @@
 		acpi20_parse_madt((acpi_madt_t *) hdrp);
 	}
 
-#ifdef CONFIG_ACPI_KERNEL_CONFIG
 	acpi_cf_terminate();
-#endif
 
-#ifdef CONFIG_SMP
+#  ifdef CONFIG_SMP
 	if (available_cpus == 0) {
 		printk("ACPI: Found 0 CPUS; assuming 1\n");
 		available_cpus = 1; /* We've got at least one of these, no? */
 	}
 	smp_boot_data.cpu_count = total_cpus;
-#endif
+#  endif
+# endif /* CONFIG_ACPI */
 	return 1;
 }
 /*
@@ -395,7 +402,12 @@
 		      case ACPI_ENTRY_IO_SAPIC:
 			iosapic = (acpi_entry_iosapic_t *) p;
 			if (iosapic_init)
-				iosapic_init(iosapic->address, iosapic->irq_base);
+				/*
+				 * The ACPI I/O SAPIC table doesn't have a PCAT_COMPAT
+				 * flag like the MADT table, but we can safely assume that
+				 * ACPI 1.0b systems have a dual-8259 setup.
+				 */
+				iosapic_init(iosapic->address, iosapic->irq_base, 1);
 			break;
 
 		      case ACPI_ENTRY_INT_SRC_OVERRIDE:
@@ -421,6 +433,7 @@
 int __init
 acpi_parse (acpi_rsdp_t *rsdp)
 {
+# ifdef CONFIG_ACPI
 	acpi_rsdt_t *rsdt;
 	acpi_desc_table_hdr_t *hdrp;
 	long tables, i;
@@ -439,9 +452,7 @@
 	printk("ACPI: %.6s %.8s %d.%d\n", rsdt->header.oem_id, rsdt->header.oem_table_id,
 	       rsdt->header.oem_revision >> 16, rsdt->header.oem_revision & 0xffff);
 
-#ifdef CONFIG_ACPI_KERNEL_CONFIG
 	acpi_cf_init(rsdp);
-#endif
 
 	tables = (rsdt->header.length - sizeof(acpi_desc_table_hdr_t)) / 8;
 	for (i = 0; i < tables; i++) {
@@ -454,16 +465,15 @@
 		acpi_parse_msapic((acpi_sapic_t *) hdrp);
 	}
 
-#ifdef CONFIG_ACPI_KERNEL_CONFIG
 	acpi_cf_terminate();
-#endif
 
-#ifdef CONFIG_SMP
+#  ifdef CONFIG_SMP
 	if (available_cpus == 0) {
 		printk("ACPI: Found 0 CPUS; assuming 1\n");
 		available_cpus = 1; /* We've got at least one of these, no? */
 	}
 	smp_boot_data.cpu_count = total_cpus;
-#endif
+#  endif
+# endif /* CONFIG_ACPI */
 	return 1;
 }
diff -u --recursive --new-file v2.4.7/linux/arch/ia64/kernel/efi.c linux/arch/ia64/kernel/efi.c
--- v2.4.7/linux/arch/ia64/kernel/efi.c	Thu Apr 12 12:16:35 2001
+++ linux/arch/ia64/kernel/efi.c	Tue Jul 31 10:30:08 2001
@@ -18,10 +18,12 @@
  * Goutham Rao: <goutham.rao@intel.com>
  *	Skip non-WB memory and ignore empty memory ranges.
  */
+#include <linux/config.h>
 #include <linux/kernel.h>
 #include <linux/init.h>
 #include <linux/types.h>
 #include <linux/time.h>
+#include <linux/proc_fs.h>
 
 #include <asm/efi.h>
 #include <asm/io.h>
@@ -36,6 +38,17 @@
 struct efi efi;
 static efi_runtime_services_t *runtime;
 
+/*
+ * efi_dir is allocated here, but the directory isn't created
+ * here, as proc_mkdir() doesn't work this early in the bootup
+ * process.  Therefore, each module, like efivars, must test for
+ *    if (!efi_dir)  efi_dir = proc_mkdir("efi", NULL);
+ * prior to creating their own entries under /proc/efi.
+ */
+#ifdef CONFIG_PROC_FS
+struct proc_dir_entry *efi_dir = NULL;
+#endif
+
 static unsigned long mem_limit = ~0UL;
 
 static efi_status_t
@@ -220,10 +233,8 @@
 		/*
 		 * The only ITLB entry in region 7 that is used is the one installed by
 		 * __start().  That entry covers a 64MB range.
-		 *
-		 * XXX Fixme: should be dynamic here (for page size)
 		 */
-		mask  = ~((1 << _PAGE_SIZE_64M) - 1);
+		mask  = ~((1 << KERNEL_PG_SHIFT) - 1);
 		vaddr = PAGE_OFFSET + md->phys_addr;
 
 		/*
@@ -246,14 +257,14 @@
 
 		printk("CPU %d: mapping PAL code [0x%lx-0x%lx) into [0x%lx-0x%lx)\n",
 		       smp_processor_id(), md->phys_addr, md->phys_addr + (md->num_pages << 12),
-		       vaddr & mask, (vaddr & mask) + 64*1024*1024);
+		       vaddr & mask, (vaddr & mask) + KERNEL_PG_SIZE);
 
 		/*
 		 * Cannot write to CRx with PSR.ic=1
 		 */
 		ia64_clear_ic(flags);
 		ia64_itr(0x1, IA64_TR_PALCODE, vaddr & mask,
-			 pte_val(mk_pte_phys(md->phys_addr, PAGE_KERNEL)), _PAGE_SIZE_64M);
+			 pte_val(mk_pte_phys(md->phys_addr, PAGE_KERNEL)), KERNEL_PG_SHIFT);
 		local_irq_restore(flags);
 		ia64_srlz_i();
 	}
@@ -440,4 +451,36 @@
 	efi.set_variable = __va(runtime->set_variable);
 	efi.get_next_high_mono_count = __va(runtime->get_next_high_mono_count);
 	efi.reset_system = __va(runtime->reset_system);
+}
+
+/*
+ * Walk the EFI memory map looking for the I/O port range.  There can only be one entry of
+ * this type, other I/O port ranges should be described via ACPI.
+ */
+u64
+efi_get_iobase (void)
+{
+	void *efi_map_start, *efi_map_end, *p;
+	efi_memory_desc_t *md;
+	u64 efi_desc_size;
+
+	efi_map_start = __va(ia64_boot_param->efi_memmap);
+	efi_map_end   = efi_map_start + ia64_boot_param->efi_memmap_size;
+	efi_desc_size = ia64_boot_param->efi_memdesc_size;
+
+	for (p = efi_map_start; p < efi_map_end; p += efi_desc_size) {
+		md = p;
+		if (md->type == EFI_MEMORY_MAPPED_IO_PORT_SPACE) {
+			/* paranoia attribute checking */
+			if (md->attribute == (EFI_MEMORY_UC | EFI_MEMORY_RUNTIME))
+				return md->phys_addr;
+		}
+	}
+	return 0;
+}
+
+static void __exit
+efivars_exit(void)
+{
+ 	remove_proc_entry(efi_dir->name, NULL);
 }
diff -u --recursive --new-file v2.4.7/linux/arch/ia64/kernel/efivars.c linux/arch/ia64/kernel/efivars.c
--- v2.4.7/linux/arch/ia64/kernel/efivars.c	Thu Apr  5 12:51:47 2001
+++ linux/arch/ia64/kernel/efivars.c	Tue Jul 31 10:30:08 2001
@@ -6,8 +6,8 @@
  * This code takes all variables accessible from EFI runtime and
  *  exports them via /proc
  *
- * Reads to /proc/efi/varname return an efi_variable_t structure.
- * Writes to /proc/efi/varname must be an efi_variable_t structure.
+ * Reads to /proc/efi/vars/varname return an efi_variable_t structure.
+ * Writes to /proc/efi/vars/varname must be an efi_variable_t structure.
  * Writes with DataSize = 0 or Attributes = 0 deletes the variable.
  * Writes with a new value in VariableName+VendorGuid creates
  * a new variable.
@@ -29,6 +29,15 @@
  *
  * Changelog:
  *
+ *  20 April 2001 - Matt Domsch <Matt_Domsch@dell.com>
+ *   Moved vars from /proc/efi to /proc/efi/vars, and made
+ *   efi.c own the /proc/efi directory.
+ *   v0.03 release to linux-ia64@linuxia64.org
+ *
+ *  26 March 2001 - Matt Domsch <Matt_Domsch@dell.com>
+ *   At the request of Stephane, moved ownership of /proc/efi
+ *   to efi.c, and now efivars lives under /proc/efi/vars.
+ *
  *  12 March 2001 - Matt Domsch <Matt_Domsch@dell.com>
  *   Feedback received from Stephane Eranian incorporated.
  *   efivar_write() checks copy_from_user() return value.
@@ -57,7 +66,7 @@
 MODULE_AUTHOR("Matt Domsch <Matt_Domsch@Dell.com>");
 MODULE_DESCRIPTION("/proc interface to EFI Variables");
 
-#define EFIVARS_VERSION "0.02 2001-Mar-12"
+#define EFIVARS_VERSION "0.03 2001-Apr-20"
 
 static int
 efivar_read(char *page, char **start, off_t off,
@@ -92,7 +101,7 @@
 
 spinlock_t efivars_lock = SPIN_LOCK_UNLOCKED;
 static LIST_HEAD(efivar_list);
-static struct proc_dir_entry *efi_dir = NULL;
+static struct proc_dir_entry *efi_vars_dir = NULL;
 
 #define efivar_entry(n) list_entry(n, efivar_entry_t, list)
 
@@ -188,7 +197,7 @@
 
 
 	/* Create the entry in proc */
-	new_efivar->entry = create_proc_entry(short_name, 0600, efi_dir);
+	new_efivar->entry = create_proc_entry(short_name, 0600, efi_vars_dir);
 	kfree(short_name); short_name = NULL;
 	if (!new_efivar->entry) return 1;
 
@@ -286,7 +295,7 @@
 	/* Since the data ptr we've currently got is probably for
 	   a different variable find the right variable.
 	   This allows any properly formatted data structure to
-	   be written to any of the files in /proc/efi and it will work.
+	   be written to any of the files in /proc/efi/vars and it will work.
 	*/
 	list_for_each(pos, &efivar_list) {
 		search_efivar = efivar_entry(pos);
@@ -320,7 +329,7 @@
 
 	if (!var_data->DataSize || !var_data->Attributes) {
 		/* We just deleted the NVRAM variable */
-		remove_proc_entry(efivar->entry->name, efi_dir);
+		remove_proc_entry(efivar->entry->name, efi_vars_dir);
 		list_del(&efivar->list);
 		kfree(efivar);
 	}
@@ -354,12 +363,22 @@
 
 	printk(KERN_INFO "EFI Variables Facility v%s\n", EFIVARS_VERSION);
 
+        /* Since efi.c happens before procfs is available,
+           we create the directory here if it doesn't
+           already exist.  There's probably a better way
+           to do this.
+        */
+        if (!efi_dir)
+                efi_dir = proc_mkdir("efi", NULL);
+
+	efi_vars_dir = proc_mkdir("vars", efi_dir);
+
+
+
 	/* Per EFI spec, the maximum storage allocated for both
 	   the variable name and variable data is 1024 bytes.
 	*/
 
-	efi_dir = proc_mkdir("efi", NULL);
-
 	memset(variable_name, 0, 1024);
 
 	do {
@@ -401,11 +420,11 @@
 
 	list_for_each(pos, &efivar_list) {
 		efivar = efivar_entry(pos);
-		remove_proc_entry(efivar->entry->name, efi_dir);
+		remove_proc_entry(efivar->entry->name, efi_vars_dir);
 		list_del(&efivar->list);
 		kfree(efivar);
 	}
-	remove_proc_entry(efi_dir->name, NULL);
+	remove_proc_entry(efi_vars_dir->name, efi_dir);
 	spin_unlock(&efivars_lock);
 
 }
diff -u --recursive --new-file v2.4.7/linux/arch/ia64/kernel/entry.S linux/arch/ia64/kernel/entry.S
--- v2.4.7/linux/arch/ia64/kernel/entry.S	Wed Jul 25 17:10:17 2001
+++ linux/arch/ia64/kernel/entry.S	Tue Jul 31 10:30:08 2001
@@ -140,8 +140,8 @@
 	dep r20=0,in0,61,3		// physical address of "current"
 	;;
 	st8 [r22]=sp			// save kernel stack pointer of old task
-	shr.u r26=r20,_PAGE_SIZE_64M
-	mov r16=1
+	shr.u r26=r20,KERNEL_PG_SHIFT
+	mov r16=KERNEL_PG_NUM
 	;;
 	cmp.ne p6,p7=r26,r16		// check >= 64M && < 128M
 	adds r21=IA64_TASK_THREAD_KSP_OFFSET,in0
@@ -175,7 +175,7 @@
 	;;
 	srlz.d
 	or r23=r25,r20			// construct PA | page properties
-	mov r25=_PAGE_SIZE_64M<<2
+	mov r25=KERNEL_PG_SHIFT<<2
 	;;
 	mov cr.itir=r25
 	mov cr.ifa=in0			// VA of next task...
@@ -212,23 +212,20 @@
 	.save @priunat,r17
 	mov r17=ar.unat		// preserve caller's
 	.body
-#if !(defined(CONFIG_ITANIUM_ASTEP_SPECIFIC) \
-      || defined(CONFIG_ITANIUM_B0_SPECIFIC) || defined(CONFIG_ITANIUM_B1_SPECIFIC))
+#if !(defined(CONFIG_ITANIUM_B0_SPECIFIC) || defined(CONFIG_ITANIUM_B1_SPECIFIC))
 	adds r3=80,sp
 	;;
 	lfetch.fault.excl.nt1 [r3],128
 #endif
 	mov ar.rsc=0		// put RSE in mode: enforced lazy, little endian, pl 0
-#if !(defined(CONFIG_ITANIUM_ASTEP_SPECIFIC) \
-      || defined(CONFIG_ITANIUM_B0_SPECIFIC) || defined(CONFIG_ITANIUM_B1_SPECIFIC))
+#if !(defined(CONFIG_ITANIUM_B0_SPECIFIC) || defined(CONFIG_ITANIUM_B1_SPECIFIC))
 	adds r2=16+128,sp
 	;;
 	lfetch.fault.excl.nt1 [r2],128
 	lfetch.fault.excl.nt1 [r3],128
 #endif
 	adds r14=SW(R4)+16,sp
-#if !(defined(CONFIG_ITANIUM_ASTEP_SPECIFIC) \
-      || defined(CONFIG_ITANIUM_B0_SPECIFIC) || defined(CONFIG_ITANIUM_B1_SPECIFIC))
+#if !(defined(CONFIG_ITANIUM_B0_SPECIFIC) || defined(CONFIG_ITANIUM_B1_SPECIFIC))
 	;;
 	lfetch.fault.excl [r2]
 	lfetch.fault.excl [r3]
@@ -325,8 +322,7 @@
 	.prologue
 	.altrp b7
 	.body
-#if !(defined(CONFIG_ITANIUM_ASTEP_SPECIFIC) \
-      || defined(CONFIG_ITANIUM_B0_SPECIFIC) || defined(CONFIG_ITANIUM_B1_SPECIFIC))
+#if !(defined(CONFIG_ITANIUM_B0_SPECIFIC) || defined(CONFIG_ITANIUM_B1_SPECIFIC))
 
 	lfetch.fault.nt1 [sp]
 #endif
@@ -496,15 +492,13 @@
 
 GLOBAL_ENTRY(ia64_ret_from_clone)
 	PT_REGS_UNWIND_INFO(0)
-#ifdef CONFIG_SMP
 	/*
-	 * In SMP mode, we need to call invoke_schedule_tail to complete the scheduling process.
+	 * We need to call schedule_tail() to complete the scheduling process.
 	 * Called by ia64_switch_to after do_fork()->copy_thread().  r8 contains the
 	 * address of the previously executing task.
 	 */
 	br.call.sptk.few rp=invoke_schedule_tail
 .ret8:
-#endif
 	adds r2=IA64_TASK_PTRACE_OFFSET,r13
 	;;
 	ld8 r2=[r2]
@@ -530,14 +524,9 @@
 	// fall through
 GLOBAL_ENTRY(ia64_leave_kernel)
 	PT_REGS_UNWIND_INFO(0)
-	cmp.eq p16,p0=r0,r0			// set the "first_time" flag
-	movl r15=PERCPU_ADDR+IA64_CPU_SOFTIRQ_ACTIVE_OFFSET  // r15 = &cpu_data.softirq.active
-	;;
-	ld8 r2=[r15]
+	lfetch.fault [sp]
 	movl r14=.restart
 	;;
-	lfetch.fault [sp]
-	shr.u r3=r2,32			// r3 = cpu_data.softirq.mask
 	MOVBR(.ret.sptk,rp,r14,.restart)
 .restart:
 	adds r17=IA64_TASK_NEED_RESCHED_OFFSET,r13
@@ -546,37 +535,28 @@
 	adds r19=IA64_TASK_PFM_NOTIFY_OFFSET,r13
 #endif
 	;;
-	ld8 r17=[r17]				// load current->need_resched
-	ld4 r18=[r18]				// load current->sigpending
-(p16)	and r2=r2,r3				// r2 <- (softirq.active & softirq.mask)
-	;;
 #ifdef CONFIG_PERFMON
 	ld8 r19=[r19]				// load current->task.pfm_notify
 #endif
-(p16)	cmp4.ne.unc p6,p0=r2,r0			// p6 <- (softirq.active & softirq.mask) != 0
-(pUser)	cmp.ne.unc p7,p0=r17,r0			// current->need_resched != 0?
+	ld8 r17=[r17]				// load current->need_resched
+	ld4 r18=[r18]				// load current->sigpending
 	;;
-(pUser)	cmp.ne.unc p8,p0=r18,r0			// current->sigpending != 0?
 #ifdef CONFIG_PERFMON
 	cmp.ne p9,p0=r19,r0			// current->task.pfm_notify != 0?
 #endif
-	cmp.ne p16,p0=r0,r0			// clear the "first_time" flag
+(pUser)	cmp.ne.unc p7,p0=r17,r0			// current->need_resched != 0?
+(pUser)	cmp.ne.unc p8,p0=r18,r0			// current->sigpending != 0?
 	;;
-# if __GNUC__ < 3
-(p6)	br.call.spnt.many b7=invoke_do_softirq
-# else
-(p6)	br.call.spnt.many b7=do_softirq
-# endif
+	adds r2=PT(R8)+16,r12
+	adds r3=PT(R9)+16,r12
 #ifdef CONFIG_PERFMON
 (p9)	br.call.spnt.many b7=pfm_overflow_notify
 #endif
-# if __GNUC__ < 3
+#if __GNUC__ < 3
 (p7)	br.call.spnt.many b7=invoke_schedule
 #else
 (p7)	br.call.spnt.many b7=schedule
 #endif
-	adds r2=PT(R8)+16,r12
-	adds r3=PT(R9)+16,r12
 (p8)	br.call.spnt.many b7=handle_signal_delivery	// check & deliver pending signals
 	;;
 	// start restoring the state saved on the kernel stack (struct pt_regs):
@@ -634,14 +614,6 @@
 	;;
 	bsw.0			// switch back to bank 0
 	;;
-#ifdef CONFIG_ITANIUM_ASTEP_SPECIFIC
-	nop.i 0x0
-	;;
-	nop.i 0x0
-	;;
-	nop.i 0x0
-	;;
-#endif
 	adds r16=16,r12
 	adds r17=24,r12
 	;;
@@ -792,7 +764,6 @@
 	br.cond.sptk.many ia64_leave_kernel
 END(handle_syscall_error)
 
-# ifdef CONFIG_SMP
 	/*
 	 * Invoke schedule_tail(task) while preserving in0-in7, which may be needed
 	 * in case a system call gets restarted.
@@ -809,29 +780,7 @@
 	br.ret.sptk.many rp
 END(invoke_schedule_tail)
 
-# endif /* CONFIG_SMP */
-
 #if __GNUC__ < 3
-	/*
-	 * Invoke do_softirq() while preserving in0-in7, which may be needed
-	 * in case a system call gets restarted.  Note that declaring do_softirq()
-	 * with asmlinkage() is NOT enough because that will only preserve as many
-	 * registers as there are formal arguments.
-	 *
-	 * XXX fix me: with gcc 3.0, we won't need this anymore because syscall_linkage
-	 *	renders all eight input registers (in0-in7) as "untouchable".
-	 */
-ENTRY(invoke_do_softirq)
-	.prologue ASM_UNW_PRLG_RP|ASM_UNW_PRLG_PFS, ASM_UNW_PRLG_GRSAVE(8)
-	alloc loc1=ar.pfs,8,2,0,0
-	mov loc0=rp
-	;;
-	.body
-	br.call.sptk.few rp=do_softirq
-.ret13:	mov ar.pfs=loc1
-	mov rp=loc0
-	br.ret.sptk.many rp
-END(invoke_do_softirq)
 
 	/*
 	 * Invoke schedule() while preserving in0-in7, which may be needed
@@ -1187,7 +1136,7 @@
 	data8 sys_newfstat
 	data8 sys_clone2
 	data8 sys_getdents64
-	data8 ia64_ni_syscall			// 1215
+	data8 sys_getunwind			// 1215
 	data8 ia64_ni_syscall
 	data8 ia64_ni_syscall
 	data8 ia64_ni_syscall
diff -u --recursive --new-file v2.4.7/linux/arch/ia64/kernel/entry.h linux/arch/ia64/kernel/entry.h
--- v2.4.7/linux/arch/ia64/kernel/entry.h	Thu Apr  5 12:51:47 2001
+++ linux/arch/ia64/kernel/entry.h	Tue Jul 31 10:30:08 2001
@@ -1,7 +1,7 @@
 #include <linux/config.h>
 
 /* XXX fixme */
-#if defined(CONFIG_ITANIUM_ASTEP_SPECIFIC) || defined(CONFIG_ITANIUM_B1_SPECIFIC)
+#if defined(CONFIG_ITANIUM_B1_SPECIFIC)
 # define MOVBR(type,br,gr,lbl)	mov br=gr
 #else
 # define MOVBR(type,br,gr,lbl)	mov##type br=gr,lbl
diff -u --recursive --new-file v2.4.7/linux/arch/ia64/kernel/fw-emu.c linux/arch/ia64/kernel/fw-emu.c
--- v2.4.7/linux/arch/ia64/kernel/fw-emu.c	Thu Apr  5 12:51:47 2001
+++ linux/arch/ia64/kernel/fw-emu.c	Tue Jul 31 10:30:08 2001
@@ -20,7 +20,7 @@
 
 #define MB	(1024*1024UL)
 
-#define NUM_MEM_DESCS	2
+#define NUM_MEM_DESCS	3
 
 static char fw_mem[(  sizeof(struct ia64_boot_param)
 		    + sizeof(efi_system_table_t)
@@ -121,68 +121,63 @@
  */
 extern void pal_emulator_static (void);
 
-asm ("
-	.proc pal_emulator_static
-pal_emulator_static:
-	mov r8=-1
-
-	mov r9=256
-	;;
-	cmp.gtu p6,p7=r9,r28		/* r28 <= 255? */
-(p6)	br.cond.sptk.few static
-	;;
-	mov r9=512
-	;;
-	cmp.gtu p6,p7=r9,r28
-(p6)	br.cond.sptk.few stacked
-	;;
-static:	cmp.eq p6,p7=6,r28		/* PAL_PTCE_INFO */
-(p7)	br.cond.sptk.few 1f
-	;;
-	mov r8=0			/* status = 0 */
-	movl r9=0x100000000		/* tc.base */
-	movl r10=0x0000000200000003	/* count[0], count[1] */
-	movl r11=0x1000000000002000	/* stride[0], stride[1] */
-	br.cond.sptk.few rp
-
-1:	cmp.eq p6,p7=14,r28		/* PAL_FREQ_RATIOS */
-(p7)	br.cond.sptk.few 1f
-	mov r8=0			/* status = 0 */
-	movl r9 =0x100000064		/* proc_ratio (1/100) */
-	movl r10=0x100000100		/* bus_ratio<<32 (1/256) */
-	movl r11=0x100000064		/* itc_ratio<<32 (1/100) */
-	;;
-1:	cmp.eq p6,p7=19,r28		/* PAL_RSE_INFO */
-(p7)	br.cond.sptk.few 1f
-	mov r8=0			/* status = 0 */
-	mov r9=96			/* num phys stacked */
-	mov r10=0			/* hints */
-	mov r11=0
-	br.cond.sptk.few rp
-
-1:	cmp.eq p6,p7=1,r28		/* PAL_CACHE_FLUSH */
-(p7)	br.cond.sptk.few 1f
-	mov r9=ar.lc
-	movl r8=524288			/* flush 512k million cache lines (16MB) */
-	;;
-	mov ar.lc=r8
-	movl r8=0xe000000000000000
-	;;
-.loop:	fc r8
-	add r8=32,r8
-	br.cloop.sptk.few .loop
-	sync.i
-	;;
-	srlz.i
-	;;
-	mov ar.lc=r9
-	mov r8=r0
-1:	br.cond.sptk.few rp
-
-stacked:
-	br.ret.sptk.few rp
-
-	.endp pal_emulator_static\n");
+asm (
+"	.proc pal_emulator_static\n"
+"pal_emulator_static:"
+"	mov r8=-1\n"
+"	mov r9=256\n"
+"	;;\n"
+"	cmp.gtu p6,p7=r9,r28		/* r28 <= 255? */\n"
+"(p6)	br.cond.sptk.few static\n"
+"	;;\n"
+"	mov r9=512\n"
+"	;;\n"
+"	cmp.gtu p6,p7=r9,r28\n"
+"(p6)	br.cond.sptk.few stacked\n"
+"	;;\n"
+"static:	cmp.eq p6,p7=6,r28		/* PAL_PTCE_INFO */\n"
+"(p7)	br.cond.sptk.few 1f\n"
+"	;;\n"
+"	mov r8=0			/* status = 0 */\n"
+"	movl r9=0x100000000		/* tc.base */\n"
+"	movl r10=0x0000000200000003	/* count[0], count[1] */\n"
+"	movl r11=0x1000000000002000	/* stride[0], stride[1] */\n"
+"	br.cond.sptk.few rp\n"
+"1:	cmp.eq p6,p7=14,r28		/* PAL_FREQ_RATIOS */\n"
+"(p7)	br.cond.sptk.few 1f\n"
+"	mov r8=0			/* status = 0 */\n"
+"	movl r9 =0x100000064		/* proc_ratio (1/100) */\n"
+"	movl r10=0x100000100		/* bus_ratio<<32 (1/256) */\n"
+"	movl r11=0x100000064		/* itc_ratio<<32 (1/100) */\n"
+"	;;\n"
+"1:	cmp.eq p6,p7=19,r28		/* PAL_RSE_INFO */\n"
+"(p7)	br.cond.sptk.few 1f\n"
+"	mov r8=0			/* status = 0 */\n"
+"	mov r9=96			/* num phys stacked */\n"
+"	mov r10=0			/* hints */\n"
+"	mov r11=0\n"
+"	br.cond.sptk.few rp\n"
+"1:	cmp.eq p6,p7=1,r28		/* PAL_CACHE_FLUSH */\n"
+"(p7)	br.cond.sptk.few 1f\n"
+"	mov r9=ar.lc\n"
+"	movl r8=524288			/* flush 512k million cache lines (16MB) */\n"
+"	;;\n"
+"	mov ar.lc=r8\n"
+"	movl r8=0xe000000000000000\n"
+"	;;\n"
+".loop:	fc r8\n"
+"	add r8=32,r8\n"
+"	br.cloop.sptk.few .loop\n"
+"	sync.i\n"
+"	;;\n"
+"	srlz.i\n"
+"	;;\n"
+"	mov ar.lc=r9\n"
+"	mov r8=r0\n"
+"1:	br.cond.sptk.few rp\n"
+"stacked:\n"
+"	br.ret.sptk.few rp\n"
+"	.endp pal_emulator_static\n");
 
 /* Macro to emulate SAL call using legacy IN and OUT calls to CF8, CFC etc.. */
 
@@ -437,8 +432,17 @@
 
 	sal_systab->checksum = -checksum;
 
-	/* fill in a memory descriptor: */
+	/* simulate free memory at physical address zero */
 	md = &efi_memmap[0];
+	md->type = EFI_BOOT_SERVICES_DATA;
+	md->pad = 0;
+	md->phys_addr = 0*MB;
+	md->virt_addr = 0;
+	md->num_pages = (1*MB) >> 12;	/* 1MB (in 4KB pages) */
+	md->attribute = EFI_MEMORY_WB;
+
+	/* fill in a memory descriptor: */
+	md = &efi_memmap[1];
 	md->type = EFI_CONVENTIONAL_MEMORY;
 	md->pad = 0;
 	md->phys_addr = 2*MB;
@@ -447,7 +451,7 @@
 	md->attribute = EFI_MEMORY_WB;
 
 	/* descriptor for firmware emulator: */
-	md = &efi_memmap[1];
+	md = &efi_memmap[2];
 	md->type = EFI_PAL_CODE;
 	md->pad = 0;
 	md->phys_addr = 1*MB;
@@ -462,7 +466,7 @@
 	 */
 
 	/* descriptor for high memory (>4GB): */
-	md = &efi_memmap[2];
+	md = &efi_memmap[3];
 	md->type = EFI_CONVENTIONAL_MEMORY;
 	md->pad = 0;
 	md->phys_addr = 4096*MB;
diff -u --recursive --new-file v2.4.7/linux/arch/ia64/kernel/gate.S linux/arch/ia64/kernel/gate.S
--- v2.4.7/linux/arch/ia64/kernel/gate.S	Thu Apr  5 12:51:47 2001
+++ linux/arch/ia64/kernel/gate.S	Tue Jul 31 10:30:08 2001
@@ -15,15 +15,23 @@
 
 	.section .text.gate,"ax"
 
-	.align PAGE_SIZE
+#	define ARG0_OFF		(16 + IA64_SIGFRAME_ARG0_OFFSET)
+#	define ARG1_OFF		(16 + IA64_SIGFRAME_ARG1_OFFSET)
+#	define ARG2_OFF		(16 + IA64_SIGFRAME_ARG2_OFFSET)
+#	define RBS_BASE_OFF	(16 + IA64_SIGFRAME_RBS_BASE_OFFSET)
+#	define SIGHANDLER_OFF	(16 + IA64_SIGFRAME_HANDLER_OFFSET)
+#	define SIGCONTEXT_OFF	(16 + IA64_SIGFRAME_SIGCONTEXT_OFFSET)
 
-#	define SIGINFO_OFF	16
-#	define SIGCONTEXT_OFF	(SIGINFO_OFF + ((IA64_SIGINFO_SIZE + 15) & ~15))
 #	define FLAGS_OFF	IA64_SIGCONTEXT_FLAGS_OFFSET
 #	define CFM_OFF		IA64_SIGCONTEXT_CFM_OFFSET
 #	define FR6_OFF		IA64_SIGCONTEXT_FR6_OFFSET
 #	define BSP_OFF		IA64_SIGCONTEXT_AR_BSP_OFFSET
 #	define RNAT_OFF		IA64_SIGCONTEXT_AR_RNAT_OFFSET
+#	define UNAT_OFF		IA64_SIGCONTEXT_AR_UNAT_OFFSET
+#	define FPSR_OFF		IA64_SIGCONTEXT_AR_FPSR_OFFSET
+#	define PR_OFF		IA64_SIGCONTEXT_PR_OFFSET
+#	define RP_OFF		IA64_SIGCONTEXT_B0_OFFSET
+#	define SP_OFF		IA64_SIGCONTEXT_R12_OFFSET
 #	define base0		r2
 #	define base1		r3
 	/*
@@ -31,17 +39,9 @@
 	 *
 	 *   +===============================+
        	 *   |				     |
-       	 *   //	    struct sigcontext        //
+       	 *   //	    struct sigframe          //
        	 *   |				     |
-	 *   +===============================+ <-- sp+SIGCONTEXT_OFF
-       	 *   |				     |
-	 *   //     rest of siginfo    	     //
-       	 *   | 			   	     |
-       	 *   +               +---------------+
-       	 *   | 		     | siginfo.code  |
-	 *   +---------------+---------------+
-	 *   | siginfo.errno | siginfo.signo |
-	 *   +-------------------------------+ <-- sp+SIGINFO_OFF
+	 *   +-------------------------------+ <-- sp+16
 	 *   |      16 byte of scratch       |
 	 *   |            space              |
 	 *   +-------------------------------+ <-- sp
@@ -51,46 +51,60 @@
 	 * incoming general register may be a NaT value (including sp, in which case the
 	 * process ends up dying with a SIGSEGV).
 	 *
-	 * The first need to do is a cover to get the registers onto the backing store.
-	 * Once that is done, we invoke the signal handler which may modify some of the
-	 * machine state.  After returning from the signal handler, we return control to
-	 * the previous context by executing a sigreturn system call.  A signal handler
-	 * may call the rt_sigreturn() function to directly return to a given sigcontext.
-	 * However, the user-level sigreturn() needs to do much more than calling the
-	 * rt_sigreturn() system call as it needs to unwind the stack to restore preserved
-	 * registers that may have been saved on the signal handler's call stack.
-	 *
-	 * On entry:
-	 *	r2	= signal number
-	 *	r3	= plabel of signal handler
-	 *	r15	= new register backing store
-	 *	[sp+16] = sigframe
+	 * The first thing need to do is a cover to get the registers onto the backing
+	 * store.  Once that is done, we invoke the signal handler which may modify some
+	 * of the machine state.  After returning from the signal handler, we return
+	 * control to the previous context by executing a sigreturn system call.  A signal
+	 * handler may call the rt_sigreturn() function to directly return to a given
+	 * sigcontext.  However, the user-level sigreturn() needs to do much more than
+	 * calling the rt_sigreturn() system call as it needs to unwind the stack to
+	 * restore preserved registers that may have been saved on the signal handler's
+	 * call stack.
 	 */
 
 GLOBAL_ENTRY(ia64_sigtramp)
-	ld8 r10=[r3],8				// get signal handler entry point
-	br.call.sptk.many rp=invoke_sighandler
-END(ia64_sigtramp)
-
-ENTRY(invoke_sighandler)
-	ld8 gp=[r3]			// get signal handler's global pointer
-	mov b6=r10
+	// describe the state that is active when we get here:
+	.prologue
+	.unwabi @svr4, 's'		// mark this as a sigtramp handler (saves scratch regs)
+	.savesp ar.unat, UNAT_OFF+SIGCONTEXT_OFF
+	.savesp ar.fpsr, FPSR_OFF+SIGCONTEXT_OFF
+	.savesp pr, PR_OFF+SIGCONTEXT_OFF
+	.savesp rp, RP_OFF+SIGCONTEXT_OFF
+	.vframesp SP_OFF+SIGCONTEXT_OFF
+	.body
+
+	.prologue
+	adds base0=SIGHANDLER_OFF,sp
+	adds base1=RBS_BASE_OFF,sp
+	br.call.sptk.many rp=1f
+1:
+	ld8 r17=[base0],(ARG0_OFF-SIGHANDLER_OFF)	// get pointer to signal handler's plabel
+	ld8 r15=[base1],(ARG1_OFF-RBS_BASE_OFF)		// get address of new RBS base (or NULL)
 	cover				// push args in interrupted frame onto backing store
 	;;
+	.save ar.pfs, r8
 	alloc r8=ar.pfs,0,0,3,0		// get CFM0, EC0, and CPL0 into r8
+	ld8 out0=[base0],16		// load arg0 (signum)
 	;;
-	mov r17=ar.bsp			// fetch ar.bsp
+	ld8 out1=[base1]		// load arg1 (siginfop)
+	ld8 r10=[r17],8			// get signal handler entry point
+	;;
+	ld8 out2=[base0]		// load arg2 (sigcontextp)
+	ld8 gp=[r17]			// get signal handler's global pointer
 	cmp.ne p8,p0=r15,r0		// do we need to switch the rbs?
-	mov out0=r2			// signal number
+
+	mov.m r17=ar.bsp		// fetch ar.bsp
+	.spillsp.p p8, ar.rnat, RNAT_OFF+SIGCONTEXT_OFF
 (p8)	br.cond.spnt.few setup_rbs	// yup -> (clobbers r14 and r16)
 back_from_setup_rbs:
 	adds base0=(BSP_OFF+SIGCONTEXT_OFF),sp
 	;;
+	.spillsp ar.bsp, BSP_OFF+SIGCONTEXT_OFF
 	st8 [base0]=r17,(CFM_OFF-BSP_OFF)	// save sc_ar_bsp
-	dep r8=0,r8,38,26		// clear EC0, CPL0 and reserved bits
+	dep r8=0,r8,38,26			// clear EC0, CPL0 and reserved bits
 	adds base1=(FR6_OFF+16+SIGCONTEXT_OFF),sp
 	;;
-
+	.spillsp ar.pfs, CFM_OFF
 	st8 [base0]=r8				// save CFM0
 	adds base0=(FR6_OFF+SIGCONTEXT_OFF),sp
 	;;
@@ -99,14 +113,13 @@
 	;;
 	stf.spill [base0]=f8,32
 	stf.spill [base1]=f9,32
+	mov b6=r10
 	;;
 	stf.spill [base0]=f10,32
 	stf.spill [base1]=f11,32
-	adds out1=SIGINFO_OFF,sp	// siginfo pointer
 	;;
 	stf.spill [base0]=f12,32
 	stf.spill [base1]=f13,32
-	adds out2=SIGCONTEXT_OFF,sp	// sigcontext pointer
 	;;
 	stf.spill [base0]=f14,32
 	stf.spill [base1]=f15,32
@@ -140,9 +153,8 @@
 	ldf.fill f15=[base1],32
 	mov r15=__NR_rt_sigreturn
 	break __BREAK_SYSCALL
-END(invoke_sighandler)
 
-ENTRY(setup_rbs)
+setup_rbs:
 	flushrs					// must be first in insn
 	mov ar.rsc=0				// put RSE into enforced lazy mode
 	adds r16=(RNAT_OFF+SIGCONTEXT_OFF),sp
@@ -150,13 +162,13 @@
 	mov r14=ar.rnat				// get rnat as updated by flushrs
 	mov ar.bspstore=r15			// set new register backing store area
 	;;
+	.spillsp ar.rnat, RNAT_OFF+SIGCONTEXT_OFF
 	st8 [r16]=r14				// save sc_ar_rnat
 	mov ar.rsc=0xf				// set RSE into eager mode, pl 3
 	invala					// invalidate ALAT
 	br.cond.sptk.many back_from_setup_rbs
-END(setup_rbs)
 
-ENTRY(restore_rbs)
+restore_rbs:
 	flushrs
 	mov ar.rsc=0				// put RSE into enforced lazy mode
 	adds r16=(RNAT_OFF+SIGCONTEXT_OFF),sp
@@ -168,4 +180,4 @@
 	mov ar.rsc=0xf				// (will be restored later on from sc_ar_rsc)
 	// invala not necessary as that will happen when returning to user-mode
 	br.cond.sptk.many back_from_restore_rbs
-END(restore_rbs)
+END(ia64_sigtramp)
diff -u --recursive --new-file v2.4.7/linux/arch/ia64/kernel/head.S linux/arch/ia64/kernel/head.S
--- v2.4.7/linux/arch/ia64/kernel/head.S	Thu Apr  5 12:51:47 2001
+++ linux/arch/ia64/kernel/head.S	Tue Jul 31 10:30:08 2001
@@ -63,17 +63,17 @@
 	 * that maps the kernel's text and data:
 	 */
 	rsm psr.i | psr.ic
-	mov r16=((ia64_rid(IA64_REGION_ID_KERNEL, PAGE_OFFSET) << 8) | (_PAGE_SIZE_64M << 2))
+	mov r16=((ia64_rid(IA64_REGION_ID_KERNEL, PAGE_OFFSET) << 8) | (KERNEL_PG_SHIFT << 2))
 	;;
 	srlz.i
-	mov r18=_PAGE_SIZE_64M<<2
-	movl r17=PAGE_OFFSET + 64*1024*1024
+	mov r18=KERNEL_PG_SHIFT<<2
+	movl r17=PAGE_OFFSET + KERNEL_PG_NUM*KERNEL_PG_SIZE
 	;;
 	mov rr[r17]=r16
 	mov cr.itir=r18
 	mov cr.ifa=r17
 	mov r16=IA64_TR_KERNEL
-	movl r18=(64*1024*1024 | PAGE_KERNEL)
+	movl r18=(KERNEL_PG_NUM*KERNEL_PG_SIZE | PAGE_KERNEL)
 	;;
 	srlz.i
 	;;
@@ -111,7 +111,7 @@
 	;;
 
 #ifdef CONFIG_IA64_EARLY_PRINTK
-	mov r3=(6<<8) | (_PAGE_SIZE_64M<<2)
+	mov r3=(6<<8) | (KERNEL_PG_SHIFT<<2)
 	movl r2=6<<61
 	;;
 	mov rr[r2]=r3
@@ -123,11 +123,12 @@
 #define isAP	p2	// are we an Application Processor?
 #define isBP	p3	// are we the Bootstrap Processor?
 
+#ifdef CONFIG_SMP
 	/*
 	 * Find the init_task for the currently booting CPU.  At poweron, and in
-	 * UP mode, cpu_now_booting is 0.
+	 * UP mode, cpucount is 0.
 	 */
-	movl r3=cpu_now_booting
+	movl r3=cpucount
  	;;
 	ld4 r3=[r3]		// r3 <- smp_processor_id()
 	movl r2=init_tasks
@@ -135,6 +136,11 @@
 	shladd r2=r3,3,r2
 	;;
 	ld8 r2=[r2]
+#else
+	mov r3=0
+	movl r2=init_task_union
+	;;
+#endif
 	cmp4.ne isAP,isBP=r3,r0
 	;;			// RAW on r2
 	extr r3=r2,0,61		// r3 == phys addr of task struct
@@ -182,7 +188,7 @@
 #endif /* CONFIG_IA64_EARLY_PRINTK */
 
 #ifdef CONFIG_SMP
-(isAP)	br.call.sptk.few rp=smp_callin
+(isAP)	br.call.sptk.few rp=start_secondary
 .ret0:
 (isAP)	br.cond.sptk.few self
 #endif
@@ -212,8 +218,7 @@
 	add r19=IA64_NUM_DBG_REGS*8,in0
 	;;
 1:	mov r16=dbr[r18]
-#if defined(CONFIG_ITANIUM_ASTEP_SPECIFIC) || defined(CONFIG_ITANIUM_BSTEP_SPECIFIC) \
-    || defined(CONFIG_ITANIUM_C0_SPECIFIC)
+#if defined(CONFIG_ITANIUM_C0_SPECIFIC)
 	;;
 	srlz.d
 #endif
@@ -230,8 +235,7 @@
 
 GLOBAL_ENTRY(ia64_load_debug_regs)
 	alloc r16=ar.pfs,1,0,0,0
-#if !(defined(CONFIG_ITANIUM_ASTEP_SPECIFIC) \
-   || defined(CONFIG_ITANIUM_B0_SPECIFIC) || defined(CONFIG_ITANIUM_B1_SPECIFIC))
+#if !(defined(CONFIG_ITANIUM_B0_SPECIFIC) || defined(CONFIG_ITANIUM_B1_SPECIFIC))
 	lfetch.nta [in0]
 #endif
 	mov r20=ar.lc			// preserve ar.lc
@@ -244,8 +248,7 @@
 	add r18=1,r18
 	;;
 	mov dbr[r18]=r16
-#if defined(CONFIG_ITANIUM_ASTEP_SPECIFIC) || defined(CONFIG_ITANIUM_BSTEP_SPECIFIC) \
-    || defined(CONFIG_ITANIUM_C0_SPECIFIC)
+#if defined(CONFIG_ITANIUM_BSTEP_SPECIFIC) || defined(CONFIG_ITANIUM_C0_SPECIFIC)
 	;;
 	srlz.d
 #endif
diff -u --recursive --new-file v2.4.7/linux/arch/ia64/kernel/ia64_ksyms.c linux/arch/ia64/kernel/ia64_ksyms.c
--- v2.4.7/linux/arch/ia64/kernel/ia64_ksyms.c	Thu Apr  5 12:51:47 2001
+++ linux/arch/ia64/kernel/ia64_ksyms.c	Tue Jul 31 10:30:08 2001
@@ -7,6 +7,7 @@
 
 #include <linux/string.h>
 EXPORT_SYMBOL_NOVERS(memset);
+EXPORT_SYMBOL(memchr);
 EXPORT_SYMBOL(memcmp);
 EXPORT_SYMBOL_NOVERS(memcpy);
 EXPORT_SYMBOL(memmove);
@@ -30,6 +31,9 @@
 EXPORT_SYMBOL(disable_irq);
 EXPORT_SYMBOL(disable_irq_nosync);
 
+#include <linux/interrupt.h>
+EXPORT_SYMBOL(probe_irq_mask);
+
 #include <linux/in6.h>
 #include <asm/checksum.h>
 /* not coded yet?? EXPORT_SYMBOL(csum_ipv6_magic); */
@@ -48,15 +52,14 @@
 EXPORT_SYMBOL_NOVERS(__down_interruptible);
 EXPORT_SYMBOL_NOVERS(__down_trylock);
 EXPORT_SYMBOL_NOVERS(__up);
-EXPORT_SYMBOL_NOVERS(__down_read_failed);
-EXPORT_SYMBOL_NOVERS(__down_write_failed);
-EXPORT_SYMBOL_NOVERS(__rwsem_wake);
 
 #include <asm/page.h>
 EXPORT_SYMBOL(clear_page);
 
 #include <asm/processor.h>
-EXPORT_SYMBOL(cpu_data);
+# ifndef CONFIG_NUMA
+EXPORT_SYMBOL(_cpu_data);
+# endif
 EXPORT_SYMBOL(kernel_thread);
 
 #include <asm/system.h>
@@ -78,6 +81,7 @@
 EXPORT_SYMBOL(smp_call_function);
 EXPORT_SYMBOL(smp_call_function_single);
 EXPORT_SYMBOL(cpu_online_map);
+EXPORT_SYMBOL(ia64_cpu_to_sapicid);
 
 #include <linux/smp.h>
 EXPORT_SYMBOL(smp_num_cpus);
@@ -137,3 +141,8 @@
 
 extern struct efi efi;
 EXPORT_SYMBOL(efi);
+
+#include <linux/proc_fs.h>
+extern struct proc_dir_entry *efi_dir;
+EXPORT_SYMBOL(efi_dir);
+
diff -u --recursive --new-file v2.4.7/linux/arch/ia64/kernel/iosapic.c linux/arch/ia64/kernel/iosapic.c
--- v2.4.7/linux/arch/ia64/kernel/iosapic.c	Thu Apr  5 12:51:47 2001
+++ linux/arch/ia64/kernel/iosapic.c	Tue Jul 31 10:30:08 2001
@@ -20,7 +20,7 @@
  * Here is what the interrupt logic between a PCI device and the CPU looks like:
  *
  * (1) A PCI device raises one of the four interrupt pins (INTA, INTB, INTC, INTD).  The
- *     device is uniquely identified by its bus-, device-, and slot-number (the function
+ *     device is uniquely identified by its bus--, and slot-number (the function
  *     number does not matter here because all functions share the same interrupt
  *     lines).
  *
@@ -51,6 +51,7 @@
 #include <linux/irq.h>
 
 #include <asm/acpi-ext.h>
+#include <asm/acpikcfg.h>
 #include <asm/delay.h>
 #include <asm/io.h>
 #include <asm/iosapic.h>
@@ -59,9 +60,6 @@
 #include <asm/ptrace.h>
 #include <asm/system.h>
 
-#ifdef	CONFIG_ACPI_KERNEL_CONFIG
-# include <asm/acpikcfg.h>
-#endif
 
 #undef DEBUG_IRQ_ROUTING
 
@@ -207,7 +205,45 @@
 static void
 iosapic_set_affinity (unsigned int irq, unsigned long mask)
 {
-	printk("iosapic_set_affinity: not implemented yet\n");
+#ifdef CONFIG_SMP
+	unsigned long flags;
+	u32 high32, low32;
+	int dest, pin;
+	char *addr;
+
+	mask &= (1UL << smp_num_cpus) - 1;
+
+	if (!mask || irq >= IA64_NUM_VECTORS)
+		return;
+
+	dest = cpu_physical_id(ffz(~mask));
+
+	pin = iosapic_irq[irq].pin;
+	addr = iosapic_irq[irq].addr;
+
+	if (pin < 0)
+		return;			/* not an IOSAPIC interrupt */
+
+	/* dest contains both id and eid */
+	high32 = dest << IOSAPIC_DEST_SHIFT;
+
+	spin_lock_irqsave(&iosapic_lock, flags);
+	{
+		/* get current delivery mode by reading the low32 */
+		writel(IOSAPIC_RTE_LOW(pin), addr + IOSAPIC_REG_SELECT);
+		low32 = readl(addr + IOSAPIC_WINDOW);
+
+		/* change delivery mode to fixed */
+		low32 &= ~(7 << IOSAPIC_DELIVERY_SHIFT);
+		low32 |= (IOSAPIC_FIXED << IOSAPIC_DELIVERY_SHIFT);
+
+		writel(IOSAPIC_RTE_HIGH(pin), addr + IOSAPIC_REG_SELECT);
+		writel(high32, addr + IOSAPIC_WINDOW);
+		writel(IOSAPIC_RTE_LOW(pin), addr + IOSAPIC_REG_SELECT);
+		writel(low32, addr + IOSAPIC_WINDOW);
+	}
+	spin_unlock_irqrestore(&iosapic_lock, flags);
+#endif
 }
 
 /*
@@ -330,7 +366,7 @@
 }
 
 void __init
-iosapic_init (unsigned long phys_addr, unsigned int base_irq)
+iosapic_init (unsigned long phys_addr, unsigned int base_irq, int pcat_compat)
 {
 	struct hw_interrupt_type *irq_type;
 	int i, irq, max_pin, vector;
@@ -348,13 +384,7 @@
 		/*
 		 * Fetch the PCI interrupt routing table:
 		 */
-#ifdef CONFIG_ACPI_KERNEL_CONFIG
 		acpi_cf_get_pci_vectors(&pci_irq.route, &pci_irq.num_routes);
-#else
-		pci_irq.route =
-			(struct pci_vector_struct *) __va(ia64_boot_param->pci_vectors);
-		pci_irq.num_routes = ia64_boot_param->num_pci_vectors;
-#endif
 	}
 
 	addr = ioremap(phys_addr, 0);
@@ -365,7 +395,7 @@
 	printk("IOSAPIC: version %x.%x, address 0x%lx, IRQs 0x%02x-0x%02x\n",
 	       (ver & 0xf0) >> 4, (ver & 0x0f), phys_addr, base_irq, base_irq + max_pin);
 
-	if (base_irq == 0)
+	if ((base_irq == 0) && pcat_compat)
 		/*
 		 * Map the legacy ISA devices into the IOSAPIC data.  Some of these may
 		 * get reprogrammed later on with data from the ACPI Interrupt Source
diff -u --recursive --new-file v2.4.7/linux/arch/ia64/kernel/irq.c linux/arch/ia64/kernel/irq.c
--- v2.4.7/linux/arch/ia64/kernel/irq.c	Thu Apr  5 12:51:47 2001
+++ linux/arch/ia64/kernel/irq.c	Tue Jul 31 10:30:08 2001
@@ -626,6 +626,8 @@
 		desc->handler->end(irq);
 		spin_unlock(&desc->lock);
 	}
+	if (local_softirq_pending())
+		do_softirq();
 	return 1;
 }
 
diff -u --recursive --new-file v2.4.7/linux/arch/ia64/kernel/irq_ia64.c linux/arch/ia64/kernel/irq_ia64.c
--- v2.4.7/linux/arch/ia64/kernel/irq_ia64.c	Thu Apr  5 12:51:47 2001
+++ linux/arch/ia64/kernel/irq_ia64.c	Tue Jul 31 10:30:08 2001
@@ -72,6 +72,11 @@
 ia64_handle_irq (ia64_vector vector, struct pt_regs *regs)
 {
 	unsigned long saved_tpr;
+#ifdef CONFIG_SMP
+#	define IS_RESCHEDULE(vec)	(vec == IA64_IPI_RESCHEDULE)
+#else
+#	define IS_RESCHEDULE(vec)	(0)
+#endif
 
 #if IRQ_DEBUG
 	{
@@ -110,24 +115,25 @@
 	 */
 	saved_tpr = ia64_get_tpr();
 	ia64_srlz_d();
-	do {
-		ia64_set_tpr(vector);
-		ia64_srlz_d();
-
-		do_IRQ(local_vector_to_irq(vector), regs);
-
-		/*
-		 * Disable interrupts and send EOI:
-		 */
-		local_irq_disable();
-		ia64_set_tpr(saved_tpr);
+	while (vector != IA64_SPURIOUS_INT_VECTOR) {
+		if (!IS_RESCHEDULE(vector)) {
+			ia64_set_tpr(vector);
+			ia64_srlz_d();
+
+			do_IRQ(local_vector_to_irq(vector), regs);
+
+			/*
+			 * Disable interrupts and send EOI:
+			 */
+			local_irq_disable();
+			ia64_set_tpr(saved_tpr);
+		}
 		ia64_eoi();
 		vector = ia64_get_ivr();
-	} while (vector != IA64_SPURIOUS_INT_VECTOR);
+	}
 }
 
 #ifdef CONFIG_SMP
-
 extern void handle_IPI (int irq, void *dev_id, struct pt_regs *regs);
 
 static struct irqaction ipi_irqaction = {
@@ -147,7 +153,7 @@
 		if (irq_to_vector(irq) == vec) {
 			desc = irq_desc(irq);
 			desc->status |= IRQ_PER_CPU;
-			desc->handler = &irq_type_ia64_sapic;
+			desc->handler = &irq_type_ia64_lsapic;
 			if (action)
 				setup_irq(irq, action);
 		}
diff -u --recursive --new-file v2.4.7/linux/arch/ia64/kernel/irq_lsapic.c linux/arch/ia64/kernel/irq_lsapic.c
--- v2.4.7/linux/arch/ia64/kernel/irq_lsapic.c	Wed Dec 31 16:00:00 1969
+++ linux/arch/ia64/kernel/irq_lsapic.c	Tue Jul 31 10:30:08 2001
@@ -0,0 +1,38 @@
+/*
+ * LSAPIC Interrupt Controller
+ *
+ * This takes care of interrupts that are generated by the CPU's
+ * internal Streamlined Advanced Programmable Interrupt Controller
+ * (LSAPIC), such as the ITC and IPI interrupts.
+    *
+ * Copyright (C) 1999 VA Linux Systems
+ * Copyright (C) 1999 Walt Drummond <drummond@valinux.com>
+ * Copyright (C) 2000 Hewlett-Packard Co
+ * Copyright (C) 2000 David Mosberger-Tang <davidm@hpl.hp.com>
+ */
+
+#include <linux/sched.h>
+#include <linux/irq.h>
+
+static unsigned int
+lsapic_noop_startup (unsigned int irq)
+{
+	return 0;
+}
+
+static void
+lsapic_noop (unsigned int irq)
+{
+	/* nuthing to do... */
+}
+
+struct hw_interrupt_type irq_type_ia64_lsapic = {
+	typename:	"LSAPIC",
+	startup:	lsapic_noop_startup,
+	shutdown:	lsapic_noop,
+	enable:		lsapic_noop,
+	disable:	lsapic_noop,
+	ack:		lsapic_noop,
+	end:		lsapic_noop,
+	set_affinity:	(void (*)(unsigned int, unsigned long)) lsapic_noop
+};
diff -u --recursive --new-file v2.4.7/linux/arch/ia64/kernel/irq_sapic.c linux/arch/ia64/kernel/irq_sapic.c
--- v2.4.7/linux/arch/ia64/kernel/irq_sapic.c	Fri Apr 21 15:21:24 2000
+++ linux/arch/ia64/kernel/irq_sapic.c	Wed Dec 31 16:00:00 1969
@@ -1,38 +0,0 @@
-/*
- * SAPIC Interrupt Controller
- *
- * This takes care of interrupts that are generated by the CPU's
- * internal Streamlined Advanced Programmable Interrupt Controller
- * (SAPIC), such as the ITC and IPI interrupts.
- *
- * Copyright (C) 1999 VA Linux Systems
- * Copyright (C) 1999 Walt Drummond <drummond@valinux.com>
- * Copyright (C) 2000 Hewlett-Packard Co
- * Copyright (C) 2000 David Mosberger-Tang <davidm@hpl.hp.com>
- */
-
-#include <linux/sched.h>
-#include <linux/irq.h>
-
-static unsigned int
-sapic_noop_startup (unsigned int irq)
-{
-	return 0;
-}
-
-static void
-sapic_noop (unsigned int irq)
-{
-	/* nuthing to do... */
-}
-
-struct hw_interrupt_type irq_type_ia64_sapic = {
-	typename:	"SAPIC",
-	startup:	sapic_noop_startup,
-	shutdown:	sapic_noop,
-	enable:		sapic_noop,
-	disable:	sapic_noop,
-	ack:		sapic_noop,
-	end:		sapic_noop,
-	set_affinity:	(void (*)(unsigned int, unsigned long)) sapic_noop
-};
diff -u --recursive --new-file v2.4.7/linux/arch/ia64/kernel/ivt.S linux/arch/ia64/kernel/ivt.S
--- v2.4.7/linux/arch/ia64/kernel/ivt.S	Thu Apr  5 12:51:47 2001
+++ linux/arch/ia64/kernel/ivt.S	Tue Jul 31 10:30:08 2001
@@ -9,16 +9,14 @@
  * 00/12/20 David Mosberger-Tang <davidm@hpl.hp.com> DTLB/ITLB handler now uses virtual PT.
  */
 /*
- * This file defines the interrupt vector table used by the CPU.
+ * This file defines the interruption vector table used by the CPU.
  * It does not include one entry per possible cause of interruption.
  *
- * External interrupts only use 1 entry. All others are internal interrupts
- *
  * The first 20 entries of the table contain 64 bundles each while the
  * remaining 48 entries contain only 16 bundles each.
  *
  * The 64 bundles are used to allow inlining the whole handler for critical
- * interrupts like TLB misses.
+ * interruptions like TLB misses.
  *
  *  For each entry, the comment is as follows:
  *
@@ -27,7 +25,7 @@
  *  entry number ---------/         /                  /          /
  *  size of the entry -------------/                  /          /
  *  vector name -------------------------------------/          /
- *  related interrupts (what is the real interrupt?) ----------/
+ *  interruptions triggering this vector ----------------------/
  *
  * The table is 32KB in size and must be aligned on 32KB boundary.
  * (The CPU ignores the 15 lower bits of the address)
@@ -363,7 +361,7 @@
 	;;
 	ssm psr.ic | PSR_DEFAULT_BITS
 	;;
-	srlz.i					// guarantee that interrupt collection is enabled
+	srlz.i					// guarantee that interruption collectin is on
 	;;
 (p15)	ssm psr.i				// restore psr.i
 	movl r14=ia64_leave_kernel
@@ -536,8 +534,7 @@
 	;;
 1:	ld8 r18=[r17]
 	;;
-# if defined(CONFIG_IA32_SUPPORT) && \
-    (defined(CONFIG_ITANIUM_ASTEP_SPECIFIC) || defined(CONFIG_ITANIUM_B0_SPECIFIC))
+# if defined(CONFIG_IA32_SUPPORT) && defined(CONFIG_ITANIUM_B0_SPECIFIC)
 	/*
 	 * Erratum 85 (Access bit fault could be reported before page not present fault)
 	 *   If the PTE is indicates the page is not present, then just turn this into a
@@ -567,8 +564,7 @@
 	;;
 1:	ld8 r18=[r17]
 	;;
-# if defined(CONFIG_IA32_SUPPORT) && \
-    (defined(CONFIG_ITANIUM_ASTEP_SPECIFIC) || defined(CONFIG_ITANIUM_B0_SPECIFIC))
+# if defined(CONFIG_IA32_SUPPORT) && defined(CONFIG_ITANIUM_B0_SPECIFIC)
 	/*
 	 * Erratum 85 (Access bit fault could be reported before page not present fault)
 	 *   If the PTE is indicates the page is not present, then just turn this into a
@@ -650,7 +646,7 @@
 
 	ssm psr.ic | PSR_DEFAULT_BITS
 	;;
-	srlz.i					// guarantee that interrupt collection is enabled
+	srlz.i					// guarantee that interruption collection is on
 	cmp.eq pSys,pNonSys=r0,r0		// set pSys=1, pNonSys=0
 	;;
 (p15)	ssm psr.i		// restore psr.i
@@ -702,7 +698,7 @@
 	st8 [r16]=r18				// store new value for cr.isr
 
 (p8)	br.call.sptk.many b6=b6			// ignore this return addr
-	br.call.sptk.many rp=ia64_trace_syscall	// rp will be overwritten (ignored)
+	br.cond.sptk.many ia64_trace_syscall
 	// NOT REACHED
 END(break_fault)
 
@@ -724,11 +720,14 @@
 	tnat.nz p15,p0=in7
 
 (p11)	mov in3=-1
+	tnat.nz p8,p0=r15	// demining r15 is not a must, but it is safer
+
 (p12)	mov in4=-1
 (p13)	mov in5=-1
 	;;
 (p14)	mov in6=-1
 (p15)	mov in7=-1
+(p8)	mov r15=-1
 	br.ret.sptk.many rp
 END(demine_args)
 
@@ -790,7 +789,7 @@
 	SAVE_MIN_WITH_COVER
 	ssm psr.ic | PSR_DEFAULT_BITS
 	;;
-	srlz.i		// guarantee that interrupt collection is enabled
+	srlz.i		// guarantee that interruption collection is on
 	;;
 (p15)	ssm psr.i	// restore psr.i
 	adds r3=8,r2	// set up second base pointer for SAVE_REST
@@ -839,7 +838,7 @@
 	mov r14=cr.isr
 	ssm psr.ic | PSR_DEFAULT_BITS
 	;;
-	srlz.i					// guarantee that interrupt collection is enabled
+	srlz.i					// guarantee that interruption collection is on
 	;;
 (p15)	ssm psr.i
 	adds r3=8,r2            // Base pointer for SAVE_REST
@@ -890,8 +889,7 @@
 	;;
 	mov rp=r15
 (p8)	br.call.sptk.many b6=b6
-	;;
-	br.call.sptk.many rp=ia32_trace_syscall	// rp will be overwritten (ignored)
+	br.cond.sptk.many ia32_trace_syscall
 
 non_ia32_syscall:
 	alloc r15=ar.pfs,0,0,2,0
@@ -928,7 +926,7 @@
 
 	ssm psr.ic | PSR_DEFAULT_BITS
 	;;
-	srlz.i				// guarantee that interrupt collection is enabled
+	srlz.i				// guarantee that interruption collection is on
 	;;
 (p15)	ssm psr.i			// restore psr.i
 	movl r15=ia64_leave_kernel
@@ -961,7 +959,7 @@
 
 	ssm psr.ic | PSR_DEFAULT_BITS
 	;;
-	srlz.i					// guarantee that interrupt collection is enabled
+	srlz.i					// guarantee that interruption collection is on
 	;;
 (p15)	ssm psr.i				// restore psr.i
 	adds r3=8,r2				// set up second base pointer
@@ -1003,7 +1001,7 @@
 	;;
 	ssm psr.ic | PSR_DEFAULT_BITS
 	;;
-	srlz.i					// guarantee that interrupt collection is enabled
+	srlz.i					// guarantee that interruption collection is on
 	;;
 (p15)	ssm psr.i				// restore psr.i
 	adds r3=8,r2				// set up second base pointer for SAVE_REST
diff -u --recursive --new-file v2.4.7/linux/arch/ia64/kernel/mca.c linux/arch/ia64/kernel/mca.c
--- v2.4.7/linux/arch/ia64/kernel/mca.c	Thu Apr 12 12:16:35 2001
+++ linux/arch/ia64/kernel/mca.c	Tue Jul 31 10:30:08 2001
@@ -27,6 +27,7 @@
 #include <asm/mca.h>
 
 #include <asm/irq.h>
+#include <asm/machvec.h>
 
 
 typedef struct ia64_fptr {
diff -u --recursive --new-file v2.4.7/linux/arch/ia64/kernel/mca_asm.S linux/arch/ia64/kernel/mca_asm.S
--- v2.4.7/linux/arch/ia64/kernel/mca_asm.S	Thu Apr  5 12:51:47 2001
+++ linux/arch/ia64/kernel/mca_asm.S	Tue Jul 31 10:30:08 2001
@@ -672,7 +672,7 @@
 	//
 	mov	r17=cr.lid
 	// XXX fix me: this is wrong: hard_smp_processor_id() is a pair of lid/eid
-	movl	r18=__cpu_physical_id
+	movl	r18=ia64_cpu_to_sapicid
 	;;
 	dep	r18=0,r18,61,3		// convert to physical address
 	;;
diff -u --recursive --new-file v2.4.7/linux/arch/ia64/kernel/minstate.h linux/arch/ia64/kernel/minstate.h
--- v2.4.7/linux/arch/ia64/kernel/minstate.h	Thu Apr  5 12:51:47 2001
+++ linux/arch/ia64/kernel/minstate.h	Tue Jul 31 10:30:08 2001
@@ -235,12 +235,6 @@
 	stf.spill [r2]=f8,32;			\
 	stf.spill [r3]=f9,32
 
-#ifdef CONFIG_ITANIUM_ASTEP_SPECIFIC
-# define STOPS	nop.i 0x0;; nop.i 0x0;; nop.i 0x0;;
-#else
-# define STOPS
-#endif
-
-#define SAVE_MIN_WITH_COVER	DO_SAVE_MIN(cover, mov rCRIFS=cr.ifs,) STOPS
-#define SAVE_MIN_WITH_COVER_R19	DO_SAVE_MIN(cover, mov rCRIFS=cr.ifs, mov r15=r19) STOPS
-#define SAVE_MIN		DO_SAVE_MIN(     , mov rCRIFS=r0, ) STOPS
+#define SAVE_MIN_WITH_COVER	DO_SAVE_MIN(cover, mov rCRIFS=cr.ifs,)
+#define SAVE_MIN_WITH_COVER_R19	DO_SAVE_MIN(cover, mov rCRIFS=cr.ifs, mov r15=r19)
+#define SAVE_MIN		DO_SAVE_MIN(     , mov rCRIFS=r0, )
diff -u --recursive --new-file v2.4.7/linux/arch/ia64/kernel/pci.c linux/arch/ia64/kernel/pci.c
--- v2.4.7/linux/arch/ia64/kernel/pci.c	Fri Feb  9 11:29:44 2001
+++ linux/arch/ia64/kernel/pci.c	Tue Jul 31 10:30:08 2001
@@ -1,6 +1,6 @@
 /*
  * pci.c - Low-Level PCI Access in IA-64
- * 
+ *
  * Derived from bios32.c of i386 tree.
  */
 #include <linux/config.h>
@@ -53,7 +53,7 @@
 #define PCI_CONFIG_ADDRESS(dev, where) \
 	(((u64) dev->bus->number << 16) | ((u64) (dev->devfn & 0xff) << 8) | (where & 0xff))
 
-static int 
+static int
 pci_conf_read_config_byte(struct pci_dev *dev, int where, u8 *value)
 {
 	s64 status;
@@ -64,7 +64,7 @@
 	return status;
 }
 
-static int 
+static int
 pci_conf_read_config_word(struct pci_dev *dev, int where, u16 *value)
 {
 	s64 status;
@@ -75,7 +75,7 @@
 	return status;
 }
 
-static int 
+static int
 pci_conf_read_config_dword(struct pci_dev *dev, int where, u32 *value)
 {
 	s64 status;
@@ -86,19 +86,19 @@
 	return status;
 }
 
-static int 
+static int
 pci_conf_write_config_byte (struct pci_dev *dev, int where, u8 value)
 {
 	return ia64_sal_pci_config_write(PCI_CONFIG_ADDRESS(dev, where), 1, value);
 }
 
-static int 
+static int
 pci_conf_write_config_word (struct pci_dev *dev, int where, u16 value)
 {
 	return ia64_sal_pci_config_write(PCI_CONFIG_ADDRESS(dev, where), 2, value);
 }
 
-static int 
+static int
 pci_conf_write_config_dword (struct pci_dev *dev, int where, u32 value)
 {
 	return ia64_sal_pci_config_write(PCI_CONFIG_ADDRESS(dev, where), 4, value);
@@ -116,7 +116,7 @@
 /*
  * Initialization. Uses the SAL interface
  */
-void __init 
+void __init
 pcibios_init (void)
 {
 #	define PCI_BUSES_TO_SCAN 255
@@ -125,7 +125,7 @@
 	platform_pci_fixup(0);	/* phase 0 initialization (before PCI bus has been scanned) */
 
 	printk("PCI: Probing PCI hardware\n");
-	for (i = 0; i < PCI_BUSES_TO_SCAN; i++) 
+	for (i = 0; i < PCI_BUSES_TO_SCAN; i++)
 		pci_scan_bus(i, &pci_conf, NULL);
 
 	platform_pci_fixup(1);	/* phase 1 initialization (after PCI bus has been scanned) */
@@ -146,14 +146,14 @@
 pcibios_update_resource (struct pci_dev *dev, struct resource *root,
 			 struct resource *res, int resource)
 {
-        unsigned long where, size;
-        u32 reg;
+	unsigned long where, size;
+	u32 reg;
 
-        where = PCI_BASE_ADDRESS_0 + (resource * 4);
-        size = res->end - res->start;
-        pci_read_config_dword(dev, where, &reg);
-        reg = (reg & size) | (((u32)(res->start - root->start)) & ~size);
-        pci_write_config_dword(dev, where, reg);
+	where = PCI_BASE_ADDRESS_0 + (resource * 4);
+	size = res->end - res->start;
+	pci_read_config_dword(dev, where, &reg);
+	reg = (reg & size) | (((u32)(res->start - root->start)) & ~size);
+	pci_write_config_dword(dev, where, reg);
 
 	/* ??? FIXME -- record old value for shutdown.  */
 }
@@ -190,7 +190,7 @@
 /*
  * PCI BIOS setup, always defaults to SAL interface
  */
-char * __init 
+char * __init
 pcibios_setup (char *str)
 {
 	return NULL;
diff -u --recursive --new-file v2.4.7/linux/arch/ia64/kernel/perfmon.c linux/arch/ia64/kernel/perfmon.c
--- v2.4.7/linux/arch/ia64/kernel/perfmon.c	Fri Apr 13 15:29:37 2001
+++ linux/arch/ia64/kernel/perfmon.c	Tue Jul 31 10:30:08 2001
@@ -32,6 +32,7 @@
 #include <asm/processor.h>
 #include <asm/signal.h>
 #include <asm/system.h>
+#include <asm/system.h>
 #include <asm/uaccess.h>
 #include <asm/delay.h> /* for ia64_get_itc() */
 
@@ -467,7 +468,7 @@
 	if (size > current->rlim[RLIMIT_MEMLOCK].rlim_cur) return -EAGAIN;
 
 	/* find some free area in address space */
-	addr = get_unmapped_area(NULL, 0, size, 0, 0);
+	addr = get_unmapped_area(NULL, 0, size, 0, MAP_PRIVATE);
 	if (!addr) goto no_addr;
 
 	DBprintk((" entries=%ld aligned size=%ld, unmapped @0x%lx\n", entries, size, addr));
@@ -573,12 +574,8 @@
 	/* cannot send to process 1, 0 means do not notify */
 	if (pfx->notify_pid < 0 || pfx->notify_pid == 1) return 0;
 
-	/* asked for sampling, but nothing to record ! */
-	if (pfx->smpl_entries > 0 && pfm_smpl_entry_size(&pfx->smpl_regs, 1) == 0) return 0;
-
 	/* probably more to add here */
 
-
 	return 1;
 }
 
@@ -786,26 +783,22 @@
 	/* XXX: ctx locking may be required here */
 
 	for (i = 0; i < count; i++, req++) {
-		int k;
-
 		if (copy_from_user(&tmp, req, sizeof(tmp))) return -EFAULT;
 
 		if (!PMD_IS_IMPL(tmp.pfr_reg.reg_num)) return -EINVAL;
 
-		k = tmp.pfr_reg.reg_num - PMU_FIRST_COUNTER;
-
 		if (PMD_IS_COUNTER(tmp.pfr_reg.reg_num)) {
 			if (ta == current){
 				val = ia64_get_pmd(tmp.pfr_reg.reg_num);
 			} else {
-				val = th->pmd[k];
+				val = th->pmd[tmp.pfr_reg.reg_num];
 			}
 			val &= pmu_conf.perf_ovfl_val;
 			/*
 			 * lower part of .val may not be zero, so we must be an addition because of
 			 * residual count (see update_counters).
 			 */
-			val += ctx->ctx_pmds[k].val;
+			val += ctx->ctx_pmds[tmp.pfr_reg.reg_num - PMU_FIRST_COUNTER].val;
 		} else {
 			/* for now */
 			if (ta != current) return -EINVAL;
@@ -1646,7 +1639,7 @@
 
 	pmu_conf.pfm_is_disabled = 1;
 
-	printk("perfmon: version %s\n", PFM_VERSION);
+	printk("perfmon: version %s (sampling format v%d)\n", PFM_VERSION, PFM_SMPL_HDR_VERSION);
 	printk("perfmon: Interrupt vectored to %u\n", IA64_PERFMON_VECTOR);
 
 	if ((status=ia64_pal_perf_mon_info(pmu_conf.impl_regs, &pm_info)) != 0) {
@@ -1658,11 +1651,8 @@
 	pmu_conf.num_pmds      = find_num_pm_regs(pmu_conf.impl_regs);
 	pmu_conf.num_pmcs      = find_num_pm_regs(&pmu_conf.impl_regs[4]);
 
-	printk("perfmon: Counters are %d bits\n", pm_info.pal_perf_mon_info_s.width);
-	printk("perfmon: Maximum counter value 0x%lx\n", pmu_conf.perf_ovfl_val);
-	printk("perfmon: %ld PMC/PMD pairs\n", pmu_conf.max_counters);
-	printk("perfmon: %ld PMCs, %ld PMDs\n", pmu_conf.num_pmcs, pmu_conf.num_pmds);
-	printk("perfmon: Sampling format v%d\n", PFM_SMPL_HDR_VERSION);
+	printk("perfmon: %d bits counters (max value 0x%lx)\n", pm_info.pal_perf_mon_info_s.width, pmu_conf.perf_ovfl_val);
+	printk("perfmon: %ld PMC/PMD pairs, %ld PMCs, %ld PMDs\n", pmu_conf.max_counters, pmu_conf.num_pmcs, pmu_conf.num_pmds);
 
 	/* sanity check */
 	if (pmu_conf.num_pmds >= IA64_NUM_PMD_REGS || pmu_conf.num_pmcs >= IA64_NUM_PMC_REGS) {
diff -u --recursive --new-file v2.4.7/linux/arch/ia64/kernel/process.c linux/arch/ia64/kernel/process.c
--- v2.4.7/linux/arch/ia64/kernel/process.c	Thu Apr  5 12:51:47 2001
+++ linux/arch/ia64/kernel/process.c	Tue Jul 31 10:30:08 2001
@@ -143,7 +143,7 @@
 		pfm_save_regs(task);
 #endif
 	if (IS_IA32_PROCESS(ia64_task_regs(task)))
-		ia32_save_state(&task->thread);
+		ia32_save_state(task);
 }
 
 void
@@ -156,7 +156,7 @@
 		pfm_load_regs(task);
 #endif
 	if (IS_IA32_PROCESS(ia64_task_regs(task)))
-		ia32_load_state(&task->thread);
+		ia32_load_state(task);
 }
 
 /*
@@ -282,10 +282,11 @@
 	 * state from the current task to the new task
 	 */
 	if (IS_IA32_PROCESS(ia64_task_regs(current)))
-		ia32_save_state(&p->thread);
+		ia32_save_state(p);
 #endif
 #ifdef CONFIG_PERFMON
-	if (current->thread.pfm_context)
+	p->thread.pfm_pend_notify = 0;
+	if (p->thread.pfm_context)
 		retval = pfm_inherit(p);
 #endif
 	return retval;
@@ -294,11 +295,10 @@
 void
 do_copy_regs (struct unw_frame_info *info, void *arg)
 {
-	unsigned long ar_bsp, addr, mask, sp, nat_bits = 0, ip, ar_rnat;
+	unsigned long mask, sp, nat_bits = 0, ip, ar_rnat, urbs_end, cfm;
 	elf_greg_t *dst = arg;
 	struct pt_regs *pt;
 	char nat;
-	long val;
 	int i;
 
 	memset(dst, 0, sizeof(elf_gregset_t));	/* don't leak any kernel bits to user-level */
@@ -309,17 +309,13 @@
 	unw_get_sp(info, &sp);
 	pt = (struct pt_regs *) (sp + 16);
 
-	ar_bsp = ia64_get_user_bsp(current, pt);
+	urbs_end = ia64_get_user_rbs_end(current, pt, &cfm);
 
-	/*
-	 * Write portion of RSE backing store living on the kernel stack to the VM of the
-	 * process.
-	 */
-	for (addr = pt->ar_bspstore; addr < ar_bsp; addr += 8)
-		if (ia64_peek(current, ar_bsp, addr, &val) == 0)
-			access_process_vm(current, addr, &val, sizeof(val), 1);
+	if (ia64_sync_user_rbs(current, info->sw, pt->ar_bspstore, urbs_end) < 0)
+		return;
 
-	ia64_peek(current, ar_bsp, (long) ia64_rse_rnat_addr((long *) addr - 1), &ar_rnat);
+	ia64_peek(current, info->sw, urbs_end, (long) ia64_rse_rnat_addr((long *) urbs_end),
+		  &ar_rnat);
 
 	/*
 	 * coredump format:
@@ -347,7 +343,7 @@
 
 	unw_get_rp(info, &ip);
 	dst[42] = ip + ia64_psr(pt)->ri;
-	dst[43] = pt->cr_ifs & 0x3fffffffff;
+	dst[43] = cfm;
 	dst[44] = pt->cr_ipsr & IA64_PSR_UM;
 
 	unw_get_ar(info, UNW_AR_RSC, &dst[45]);
@@ -355,7 +351,7 @@
 	 * For bsp and bspstore, unw_get_ar() would return the kernel
 	 * addresses, but we need the user-level addresses instead:
 	 */
-	dst[46] = ar_bsp;
+	dst[46] = urbs_end;	/* note: by convention PT_AR_BSP points to the end of the urbs! */
 	dst[47] = pt->ar_bspstore;
 	dst[48] = ar_rnat;
 	unw_get_ar(info, UNW_AR_CCV, &dst[49]);
@@ -528,13 +524,11 @@
 void
 machine_halt (void)
 {
-	printk("machine_halt: need PAL or ACPI version here!!\n");
-	machine_restart(0);
 }
 
 void
 machine_power_off (void)
 {
-	printk("machine_power_off: unimplemented (need ACPI version here)\n");
-	machine_halt ();
+	if (pm_power_off)
+		pm_power_off();
 }
diff -u --recursive --new-file v2.4.7/linux/arch/ia64/kernel/ptrace.c linux/arch/ia64/kernel/ptrace.c
--- v2.4.7/linux/arch/ia64/kernel/ptrace.c	Wed Jul 25 17:10:17 2001
+++ linux/arch/ia64/kernel/ptrace.c	Tue Jul 31 10:30:08 2001
@@ -144,12 +144,10 @@
 }
 
 /*
- * This routine is used to read an rnat bits that are stored on the
- * kernel backing store.  Since, in general, the alignment of the user
- * and kernel are different, this is not completely trivial.  In
- * essence, we need to construct the user RNAT based on up to two
- * kernel RNAT values and/or the RNAT value saved in the child's
- * pt_regs.
+ * This routine is used to read an rnat bits that are stored on the kernel backing store.
+ * Since, in general, the alignment of the user and kernel are different, this is not
+ * completely trivial.  In essence, we need to construct the user RNAT based on up to two
+ * kernel RNAT values and/or the RNAT value saved in the child's pt_regs.
  *
  * user rbs
  *
@@ -182,20 +180,18 @@
  *					+--------+
  *						  <--- child_stack->ar_bspstore
  *
- * The way to think of this code is as follows: bit 0 in the user rnat
- * corresponds to some bit N (0 <= N <= 62) in one of the kernel rnat
- * value.  The kernel rnat value holding this bit is stored in
- * variable rnat0.  rnat1 is loaded with the kernel rnat value that
+ * The way to think of this code is as follows: bit 0 in the user rnat corresponds to some
+ * bit N (0 <= N <= 62) in one of the kernel rnat value.  The kernel rnat value holding
+ * this bit is stored in variable rnat0.  rnat1 is loaded with the kernel rnat value that
  * form the upper bits of the user rnat value.
  *
  * Boundary cases:
  *
- * o when reading the rnat "below" the first rnat slot on the kernel
- *   backing store, rnat0/rnat1 are set to 0 and the low order bits
- *   are merged in from pt->ar_rnat.
+ * o when reading the rnat "below" the first rnat slot on the kernel backing store,
+ *   rnat0/rnat1 are set to 0 and the low order bits are merged in from pt->ar_rnat.
  *
- * o when reading the rnat "above" the last rnat slot on the kernel
- *   backing store, rnat0/rnat1 gets its value from sw->ar_rnat.
+ * o when reading the rnat "above" the last rnat slot on the kernel backing store,
+ *   rnat0/rnat1 gets its value from sw->ar_rnat.
  */
 static unsigned long
 get_rnat (struct pt_regs *pt, struct switch_stack *sw,
@@ -289,57 +285,82 @@
 	}
 }
 
+/*
+ * Read a word from the user-level backing store of task CHILD.  ADDR is the user-level
+ * address to read the word from, VAL a pointer to the return value, and USER_BSP gives
+ * the end of the user-level backing store (i.e., it's the address that would be in ar.bsp
+ * after the user executed a "cover" instruction).
+ *
+ * This routine takes care of accessing the kernel register backing store for those
+ * registers that got spilled there.  It also takes care of calculating the appropriate
+ * RNaT collection words.
+ */
 long
-ia64_peek (struct task_struct *child, unsigned long user_bsp, unsigned long addr, long *val)
+ia64_peek (struct task_struct *child, struct switch_stack *child_stack, unsigned long user_rbs_end,
+	   unsigned long addr, long *val)
 {
-	unsigned long *bspstore, *krbs, regnum, *laddr, *ubsp = (long *) user_bsp;
-	struct switch_stack *child_stack;
+	unsigned long *bspstore, *krbs, regnum, *laddr, *urbs_end, *rnat_addr;
 	struct pt_regs *child_regs;
 	size_t copied;
 	long ret;
 
+	urbs_end = (long *) user_rbs_end;
 	laddr = (unsigned long *) addr;
 	child_regs = ia64_task_regs(child);
-	child_stack = (struct switch_stack *) (child->thread.ksp + 16);
 	bspstore = (unsigned long *) child_regs->ar_bspstore;
 	krbs = (unsigned long *) child + IA64_RBS_OFFSET/8;
-	if (laddr >= bspstore && laddr <= ia64_rse_rnat_addr(ubsp)) {
+	if (laddr >= bspstore && laddr <= ia64_rse_rnat_addr(urbs_end)) {
 		/*
 		 * Attempt to read the RBS in an area that's actually on the kernel RBS =>
 		 * read the corresponding bits in the kernel RBS.
 		 */
-		if (ia64_rse_is_rnat_slot(laddr))
-			ret = get_rnat(child_regs, child_stack, krbs, laddr);
-		else {
-			if (laddr >= ubsp)
-				ret = 0;
-			else {
-				regnum = ia64_rse_num_regs(bspstore, laddr);
-				ret = *ia64_rse_skip_regs(krbs, regnum);
-			}
+		rnat_addr = ia64_rse_rnat_addr(laddr);
+		ret = get_rnat(child_regs, child_stack, krbs, rnat_addr);
+
+		if (laddr == rnat_addr) {
+			/* return NaT collection word itself */
+			*val = ret;
+			return 0;
+		}
+
+		if (((1UL << ia64_rse_slot_num(laddr)) & ret) != 0) {
+			/*
+			 * It is implementation dependent whether the data portion of a
+			 * NaT value gets saved on a st8.spill or RSE spill (e.g., see
+			 * EAS 2.6, 4.4.4.6 Register Spill and Fill).  To get consistent
+			 * behavior across all possible IA-64 implementations, we return
+			 * zero in this case.
+			 */
+			*val = 0;
+			return 0;
+		}
+
+		if (laddr < urbs_end) {
+			/* the desired word is on the kernel RBS and is not a NaT */
+			regnum = ia64_rse_num_regs(bspstore, laddr);
+			*val = *ia64_rse_skip_regs(krbs, regnum);
+			return 0;
 		}
-	} else {
-		copied = access_process_vm(child, addr, &ret, sizeof(ret), 0);
-		if (copied != sizeof(ret))
-			return -EIO;
 	}
+	copied = access_process_vm(child, addr, &ret, sizeof(ret), 0);
+	if (copied != sizeof(ret))
+		return -EIO;
 	*val = ret;
 	return 0;
 }
 
 long
-ia64_poke (struct task_struct *child, unsigned long user_bsp, unsigned long addr, long val)
+ia64_poke (struct task_struct *child, struct switch_stack *child_stack, unsigned long user_rbs_end,
+	   unsigned long addr, long val)
 {
-	unsigned long *bspstore, *krbs, regnum, *laddr, *ubsp = (long *) user_bsp;
-	struct switch_stack *child_stack;
+	unsigned long *bspstore, *krbs, regnum, *laddr, *urbs_end = (long *) user_rbs_end;
 	struct pt_regs *child_regs;
 
 	laddr = (unsigned long *) addr;
 	child_regs = ia64_task_regs(child);
-	child_stack = (struct switch_stack *) (child->thread.ksp + 16);
 	bspstore = (unsigned long *) child_regs->ar_bspstore;
 	krbs = (unsigned long *) child + IA64_RBS_OFFSET/8;
-	if (laddr >= bspstore && laddr <= ia64_rse_rnat_addr(ubsp)) {
+	if (laddr >= bspstore && laddr <= ia64_rse_rnat_addr(urbs_end)) {
 		/*
 		 * Attempt to write the RBS in an area that's actually on the kernel RBS
 		 * => write the corresponding bits in the kernel RBS.
@@ -347,7 +368,7 @@
 		if (ia64_rse_is_rnat_slot(laddr))
 			put_rnat(child_regs, child_stack, krbs, laddr, val);
 		else {
-			if (laddr < ubsp) {
+			if (laddr < urbs_end) {
 				regnum = ia64_rse_num_regs(bspstore, laddr);
 				*ia64_rse_skip_regs(krbs, regnum) = val;
 			}
@@ -359,11 +380,13 @@
 }
 
 /*
- * Calculate the user-level address that would have been in ar.bsp had the user executed a
- * "cover" instruction right before entering the kernel.
+ * Calculate the address of the end of the user-level register backing store.  This is the
+ * address that would have been stored in ar.bsp if the user had executed a "cover"
+ * instruction right before entering the kernel.  If CFMP is not NULL, it is used to
+ * return the "current frame mask" that was active at the time the kernel was entered.
  */
 unsigned long
-ia64_get_user_bsp (struct task_struct *child, struct pt_regs *pt)
+ia64_get_user_rbs_end (struct task_struct *child, struct pt_regs *pt, unsigned long *cfmp)
 {
 	unsigned long *krbs, *bspstore, cfm;
 	struct unw_frame_info info;
@@ -372,6 +395,7 @@
 	krbs = (unsigned long *) child + IA64_RBS_OFFSET/8;
 	bspstore = (unsigned long *) pt->ar_bspstore;
 	ndirty = ia64_rse_num_regs(krbs, krbs + (pt->loadrs >> 19));
+	cfm = pt->cr_ifs & ~(1UL << 63);
 
 	if ((long) pt->cr_ifs >= 0) {
 		/*
@@ -385,81 +409,102 @@
 			ndirty += (cfm & 0x7f);
 		}
 	}
+	if (cfmp)
+		*cfmp = cfm;
 	return (unsigned long) ia64_rse_skip_regs(bspstore, ndirty);
 }
 
 /*
  * Synchronize (i.e, write) the RSE backing store living in kernel space to the VM of the
- * indicated child process.
- *
- * If new_bsp is non-zero, the bsp will (effectively) be updated to the new value upon
- * resumption of the child process.  This is accomplished by setting the loadrs value to
- * zero and the bspstore value to the new bsp value.
- *
- * When new_bsp and flush_user_rbs are both 0, the register backing store in kernel space
- * is written to user space and the loadrs and bspstore values are left alone.
- *
- * When new_bsp is zero and flush_user_rbs is 1 (non-zero), loadrs is set to 0, and the
- * bspstore value is set to the old bsp value.  This will cause the stacked registers (r32
- * and up) to be obtained entirely from the child's memory space rather than from the
- * kernel.  (This makes it easier to write code for modifying the stacked registers in
- * multi-threaded programs.)
- *
- * Note: I had originally written this function without the flush_user_rbs parameter; it
- * was written so that loadrs would always be set to zero.  But I had problems with
- * certain system calls apparently causing a portion of the RBS to be zeroed.  (I still
- * don't understand why this was happening.) Anyway, it'd definitely less intrusive to
- * leave loadrs and bspstore alone if possible.
+ * CHILD task.  SW and PT are the pointers to the switch_stack and pt_regs structures,
+ * respectively.  USER_RBS_END is the user-level address at which the backing store ends.
  */
-static long
-sync_kernel_register_backing_store (struct task_struct *child, long user_bsp, long new_bsp,
-				    int flush_user_rbs)
+long
+ia64_sync_user_rbs (struct task_struct *child, struct switch_stack *sw,
+		    unsigned long user_rbs_start, unsigned long user_rbs_end)
 {
-	struct pt_regs *child_regs = ia64_task_regs(child);
 	unsigned long addr, val;
 	long ret;
 
-	/*
-	 * Return early if nothing to do.  Note that new_bsp will be zero if the caller
-	 * wants to force synchronization without changing bsp.
-	 */
-	if (user_bsp == new_bsp)
-		return 0;
-
-	/* Write portion of backing store living on kernel stack to the child's VM. */
-	for (addr = child_regs->ar_bspstore; addr < user_bsp; addr += 8) {
-		ret = ia64_peek(child, user_bsp, addr, &val);
-		if (ret != 0)
+	/* now copy word for word from kernel rbs to user rbs: */
+	for (addr = user_rbs_start; addr < user_rbs_end; addr += 8) {
+		ret = ia64_peek(child, sw, user_rbs_end, addr, &val);
+		if (ret < 0)
 			return ret;
 		if (access_process_vm(child, addr, &val, sizeof(val), 1) != sizeof(val))
 			return -EIO;
 	}
+	return 0;
+}
 
-	if (new_bsp != 0) {
-		flush_user_rbs = 1;
-		user_bsp = new_bsp;
-	}
+/*
+ * Simulate user-level "flushrs".  Note: we can't just add pt->loadrs>>16 to
+ * pt->ar_bspstore because the kernel backing store and the user-level backing store may
+ * have different alignments (and therefore a different number of intervening rnat slots).
+ */
+static void
+user_flushrs (struct task_struct *task, struct pt_regs *pt)
+{
+	unsigned long *krbs;
+	long ndirty;
 
-	if (flush_user_rbs) {
-		child_regs->loadrs = 0;
-		child_regs->ar_bspstore = user_bsp;
-	}
-	return 0;
+	krbs = (unsigned long *) task + IA64_RBS_OFFSET/8;
+	ndirty = ia64_rse_num_regs(krbs, krbs + (pt->loadrs >> 19));
+
+	pt->ar_bspstore = (unsigned long) ia64_rse_skip_regs((unsigned long *) pt->ar_bspstore,
+							     ndirty);
+	pt->loadrs = 0;
 }
 
+/*
+ * Synchronize the RSE backing store of CHILD and all tasks that share the address space
+ * with it.  CHILD_URBS_END is the address of the end of the register backing store of
+ * CHILD.  If MAKE_WRITABLE is set, a user-level "flushrs" is simulated such that the VM
+ * can be written via ptrace() and the tasks will pick up the newly written values.  It
+ * would be OK to unconditionally simulate a "flushrs", but this would be more intrusive
+ * than strictly necessary (e.g., it would make it impossible to obtain the original value
+ * of ar.bspstore).
+ */
 static void
-sync_thread_rbs (struct task_struct *child, long bsp, struct mm_struct *mm, int make_writable)
+threads_sync_user_rbs (struct task_struct *child, unsigned long child_urbs_end, int make_writable)
 {
+	struct switch_stack *sw;
+	unsigned long urbs_end;
 	struct task_struct *p;
-	read_lock(&tasklist_lock);
+	struct mm_struct *mm;
+	struct pt_regs *pt;
+	long multi_threaded;
+
+	task_lock(child);
 	{
-		for_each_task(p) {
-			if (p->mm == mm && p->state != TASK_RUNNING)
-				sync_kernel_register_backing_store(p, bsp, 0, make_writable);
+		mm = child->mm;
+		multi_threaded = mm && (atomic_read(&mm->mm_users) > 1);
+	}
+	task_unlock(child);
+
+	if (!multi_threaded) {
+		sw = (struct switch_stack *) (child->thread.ksp + 16);
+		pt = ia64_task_regs(child);
+		ia64_sync_user_rbs(child, sw, pt->ar_bspstore, child_urbs_end);
+		if (make_writable)
+			user_flushrs(child, pt);
+	} else {
+		read_lock(&tasklist_lock);
+		{
+			for_each_task(p) {
+				if (p->mm == mm && p->state != TASK_RUNNING) {
+					sw = (struct switch_stack *) (p->thread.ksp + 16);
+					pt = ia64_task_regs(p);
+					urbs_end = ia64_get_user_rbs_end(p, pt, NULL);
+					ia64_sync_user_rbs(p, sw, pt->ar_bspstore, urbs_end);
+					if (make_writable)
+						user_flushrs(p, pt);
+				}
+			}
 		}
+		read_unlock(&tasklist_lock);
 	}
-	read_unlock(&tasklist_lock);
-	child->thread.flags |= IA64_THREAD_KRBS_SYNCED;
+	child->thread.flags |= IA64_THREAD_KRBS_SYNCED;	/* set the flag in the child thread only */
 }
 
 /*
@@ -528,7 +573,7 @@
 static int
 access_uarea (struct task_struct *child, unsigned long addr, unsigned long *data, int write_access)
 {
-	unsigned long *ptr, regnum, bsp, rnat_addr;
+	unsigned long *ptr, regnum, urbs_end, rnat_addr;
 	struct switch_stack *sw;
 	struct unw_frame_info info;
 	struct pt_regs *pt;
@@ -625,13 +670,24 @@
 		/* scratch state */
 		switch (addr) {
 		      case PT_AR_BSP:
-			bsp = ia64_get_user_bsp(child, pt);
-			if (write_access)
-				return sync_kernel_register_backing_store(child, bsp, *data, 1);
-			else {
-				*data = bsp;
-				return 0;
-			}
+			/*
+			 * By convention, we use PT_AR_BSP to refer to the end of the user-level
+			 * backing store.  Use ia64_rse_skip_regs(PT_AR_BSP, -CFM.sof) to get
+			 * the real value of ar.bsp at the time the kernel was entered.
+			 */
+			urbs_end = ia64_get_user_rbs_end(child, pt, NULL);
+			if (write_access) {
+				if (*data != urbs_end) {
+					if (ia64_sync_user_rbs(child, sw,
+							       pt->ar_bspstore, urbs_end) < 0)
+						return -1;
+					/* simulate user-level write of ar.bsp: */
+					pt->loadrs = 0;
+					pt->ar_bspstore = *data;
+				}
+			} else
+				*data = urbs_end;
+			return 0;
 
 		      case PT_CFM:
 			if ((long) pt->cr_ifs < 0) {
@@ -666,12 +722,12 @@
 			return 0;
 
 		      case PT_AR_RNAT:
-			bsp = ia64_get_user_bsp(child, pt);
-			rnat_addr = (long) ia64_rse_rnat_addr((long *) bsp - 1);
+			urbs_end = ia64_get_user_rbs_end(child, pt, NULL);
+			rnat_addr = (long) ia64_rse_rnat_addr((long *) urbs_end);
 			if (write_access)
-				return ia64_poke(child, bsp, rnat_addr, *data);
+				return ia64_poke(child, sw, urbs_end, rnat_addr, *data);
 			else
-				return ia64_peek(child, bsp, rnat_addr, data);
+				return ia64_peek(child, sw, urbs_end, rnat_addr, data);
 
 				   case PT_R1:  case PT_R2:  case PT_R3:
 		      case PT_R8:  case PT_R9:  case PT_R10: case PT_R11:
@@ -738,8 +794,9 @@
 	    long arg4, long arg5, long arg6, long arg7, long stack)
 {
 	struct pt_regs *pt, *regs = (struct pt_regs *) &stack;
+	unsigned long flags, urbs_end;
 	struct task_struct *child;
-	unsigned long flags, bsp;
+	struct switch_stack *sw;
 	long ret;
 
 	lock_kernel();
@@ -784,25 +841,17 @@
 		goto out_tsk;
 
 	pt = ia64_task_regs(child);
+	sw = (struct switch_stack *) (child->thread.ksp + 16);
 
 	switch (request) {
 	      case PTRACE_PEEKTEXT:
 	      case PTRACE_PEEKDATA:		/* read word at location addr */
-		bsp = ia64_get_user_bsp(child, pt);
-		if (!(child->thread.flags & IA64_THREAD_KRBS_SYNCED)) {
-			struct mm_struct *mm;
-			long do_sync;
-
-			task_lock(child);
-			{
-				mm = child->mm;
-				do_sync = mm && (atomic_read(&mm->mm_users) > 1);
-			}
-			task_unlock(child);
-			if (do_sync)
-				sync_thread_rbs(child, bsp, mm, 0);
-		}
-		ret = ia64_peek(child, bsp, addr, &data);
+		urbs_end = ia64_get_user_rbs_end(child, pt, NULL);
+
+		if (!(child->thread.flags & IA64_THREAD_KRBS_SYNCED))
+			threads_sync_user_rbs(child, urbs_end, 0);
+
+		ret = ia64_peek(child, sw, urbs_end, addr, &data);
 		if (ret == 0) {
 			ret = data;
 			regs->r8 = 0;	/* ensure "ret" is not mistaken as an error code */
@@ -811,21 +860,11 @@
 
 	      case PTRACE_POKETEXT:
 	      case PTRACE_POKEDATA:		/* write the word at location addr */
-		bsp = ia64_get_user_bsp(child, pt);
-		if (!(child->thread.flags & IA64_THREAD_KRBS_SYNCED)) {
-			struct mm_struct *mm;
-			long do_sync;
-
-			task_lock(child);
-			{
-				mm = child->mm;
-				do_sync = mm && (atomic_read(&child->mm->mm_users) > 1);
-			}
-			task_unlock(child);
-			if (do_sync)
-				sync_thread_rbs(child, bsp, mm, 1);
-		}
-		ret = ia64_poke(child, bsp, addr, data);
+		urbs_end = ia64_get_user_rbs_end(child, pt, NULL);
+		if (!(child->thread.flags & IA64_THREAD_KRBS_SYNCED))
+			threads_sync_user_rbs(child, urbs_end, 1);
+
+		ret = ia64_poke(child, sw, urbs_end, addr, data);
 		goto out_tsk;
 
 	      case PTRACE_PEEKUSR:		/* read the word at addr in the USER area */
diff -u --recursive --new-file v2.4.7/linux/arch/ia64/kernel/setup.c linux/arch/ia64/kernel/setup.c
--- v2.4.7/linux/arch/ia64/kernel/setup.c	Thu Apr  5 12:51:47 2001
+++ linux/arch/ia64/kernel/setup.c	Tue Jul 31 10:30:08 2001
@@ -3,7 +3,7 @@
  *
  * Copyright (C) 1998-2001 Hewlett-Packard Co
  * Copyright (C) 1998-2001 David Mosberger-Tang <davidm@hpl.hp.com>
- * Copyright (C) 1998, 1999 Stephane Eranian <eranian@hpl.hp.com>
+ * Copyright (C) 1998, 1999, 2001 Stephane Eranian <eranian@hpl.hp.com>
  * Copyright (C) 2000, Rohit Seth <rohit.seth@intel.com>
  * Copyright (C) 1999 VA Linux Systems
  * Copyright (C) 1999 Walt Drummond <drummond@valinux.com>
@@ -46,20 +46,20 @@
 # error "struct cpuinfo_ia64 too big!"
 #endif
 
+#define MIN(a,b)	((a) < (b) ? (a) : (b))
+#define MAX(a,b)	((a) > (b) ? (a) : (b))
+
 extern char _end;
 
-/* cpu_data[0] is data for the bootstrap processor: */
-struct cpuinfo_ia64 cpu_data[NR_CPUS] __attribute__ ((section ("__special_page_section")));
+#ifdef CONFIG_NUMA
+ struct cpuinfo_ia64 *boot_cpu_data;
+#else
+ struct cpuinfo_ia64 _cpu_data[NR_CPUS] __attribute__ ((section ("__special_page_section")));
+#endif
 
 unsigned long ia64_cycles_per_usec;
 struct ia64_boot_param *ia64_boot_param;
 struct screen_info screen_info;
-/* This tells _start which CPU is booting.  */
-int cpu_now_booting;
-
-#ifdef CONFIG_SMP
-volatile unsigned long cpu_online_map;
-#endif
 
 unsigned long ia64_iobase;	/* virtual address for I/O accesses */
 
@@ -67,6 +67,31 @@
 
 char saved_command_line[COMMAND_LINE_SIZE]; /* used in proc filesystem */
 
+/*
+ * Entries defined so far:
+ * 	- boot param structure itself
+ * 	- memory map
+ * 	- initrd (optional)
+ * 	- command line string
+ * 	- kernel code & data
+ *
+ * More could be added if necessary
+ */
+#define IA64_MAX_RSVD_REGIONS 5
+
+struct rsvd_region {
+	unsigned long start;	/* virtual address of beginning of element */
+	unsigned long end;	/* virtual address of end of element + 1 */
+};
+
+/*
+ * We use a special marker for the end of memory and it uses the extra (+1) slot
+ */
+static struct rsvd_region rsvd_region[IA64_MAX_RSVD_REGIONS + 1];
+static int num_rsvd_regions;
+
+static unsigned long bootmap_start; /* physical address where the bootmem map is located */
+
 static int
 find_max_pfn (unsigned long start, unsigned long end, void *arg)
 {
@@ -78,126 +103,191 @@
 	return 0;
 }
 
+#define IGNORE_PFN0	1	/* XXX fix me: ignore pfn 0 until TLB miss handler is updated... */
+
+/*
+ * Free available memory based on the primitive map created from
+ * the boot parameters. This routine does not assume the incoming
+ * segments are sorted.
+ */
 static int
 free_available_memory (unsigned long start, unsigned long end, void *arg)
 {
-#	define KERNEL_END	((unsigned long) &_end)
-#	define MIN(a,b)		((a) < (b) ? (a) : (b))
-#	define MAX(a,b)		((a) > (b) ? (a) : (b))
-	unsigned long range_start, range_end;
-
-	range_start = MIN(start, KERNEL_START);
-	range_end   = MIN(end, KERNEL_START);
+	unsigned long range_start, range_end, prev_start;
+	int i;
 
+#if IGNORE_PFN0
+	if (start == PAGE_OFFSET) {
+		printk("warning: skipping physical page 0\n");
+		start += PAGE_SIZE;
+		if (start >= end) return 0;
+	}
+#endif
 	/*
-	 * XXX This should not be necessary, but the bootmem allocator
-	 * is broken and fails to work correctly when the starting
-	 * address is not properly aligned.
+	 * lowest possible address(walker uses virtual)
 	 */
-	range_start = PAGE_ALIGN(range_start);
+	prev_start = PAGE_OFFSET;
 
-	if (range_start < range_end)
-		free_bootmem(__pa(range_start), range_end - range_start);
+	for (i = 0; i < num_rsvd_regions; ++i) {
+		range_start = MAX(start, prev_start);
+		range_end   = MIN(end, rsvd_region[i].start);
 
-	range_start = MAX(start, KERNEL_END);
-	range_end   = MAX(end, KERNEL_END);
+		if (range_start < range_end)
+			free_bootmem(__pa(range_start), range_end - range_start);
 
-	/*
-	 * XXX This should not be necessary, but the bootmem allocator
-	 * is broken and fails to work correctly when the starting
-	 * address is not properly aligned.
-	 */
-	range_start = PAGE_ALIGN(range_start);
+		/* nothing more available in this segment */
+		if (range_end == end) return 0;
+
+		prev_start = rsvd_region[i].end;
+	}
+	/* end of memory marker allows full processing inside loop body */
+	return 0;
+}
+
+
+static int
+find_bootmap_location (unsigned long start, unsigned long end, void *arg)
+{
+	unsigned long needed = *(unsigned long *)arg;
+	unsigned long range_start, range_end, free_start;
+	int i;
+
+#if IGNORE_PFN0
+	if (start == PAGE_OFFSET) {
+		start += PAGE_SIZE;
+		if (start >= end) return 0;
+	}
+#endif
+
+	free_start = PAGE_OFFSET;
+
+	for (i = 0; i < num_rsvd_regions; i++) {
+		range_start = MAX(start, free_start);
+		range_end   = MIN(end, rsvd_region[i].start);
 
-	if (range_start < range_end)
-		free_bootmem(__pa(range_start), range_end - range_start);
+		if (range_end <= range_start) continue;	/* skip over empty range */
 
+	       	if (range_end - range_start >= needed) {
+			bootmap_start = __pa(range_start);
+			return 1;	/* done */
+		}
+
+		/* nothing more available in this segment */
+		if (range_end == end) return 0;
+
+		free_start = rsvd_region[i].end;
+	}
 	return 0;
 }
 
-void __init
-setup_arch (char **cmdline_p)
+static void
+sort_regions (struct rsvd_region *rsvd_region, int max)
 {
-	extern unsigned long ia64_iobase;
-	unsigned long max_pfn, bootmap_start, bootmap_size;
+	int j;
 
-	unw_init();
+	/* simple bubble sorting */
+	while (max--) {
+		for (j = 0; j < max; ++j) {
+			if (rsvd_region[j].start > rsvd_region[j+1].start) {
+				struct rsvd_region tmp;
+				tmp = rsvd_region[j];
+				rsvd_region[j] = rsvd_region[j + 1];
+				rsvd_region[j + 1] = tmp;
+			}
+		}
+	}
+}
 
-	*cmdline_p = __va(ia64_boot_param->command_line);
-	strncpy(saved_command_line, *cmdline_p, sizeof(saved_command_line));
-	saved_command_line[COMMAND_LINE_SIZE-1] = '\0';		/* for safety */
+static void
+find_memory (void)
+{
+#	define KERNEL_END	((unsigned long) &_end)
+	unsigned long bootmap_size;
+	unsigned long max_pfn;
+	int n = 0;
 
-	efi_init();
+	/*
+	 * none of the entries in this table overlap
+	 */
+	rsvd_region[n].start = (unsigned long) ia64_boot_param;
+	rsvd_region[n].end   = rsvd_region[n].start + sizeof(*ia64_boot_param);
+	n++;
+
+	rsvd_region[n].start = (unsigned long) __va(ia64_boot_param->efi_memmap);
+	rsvd_region[n].end   = rsvd_region[n].start + ia64_boot_param->efi_memmap_size;
+	n++;
+
+	rsvd_region[n].start = (unsigned long) __va(ia64_boot_param->command_line);
+	rsvd_region[n].end   = (rsvd_region[n].start
+				+ strlen(__va(ia64_boot_param->command_line)) + 1);
+	n++;
+
+	rsvd_region[n].start = KERNEL_START;
+	rsvd_region[n].end   = KERNEL_END;
+	n++;
+
+#ifdef CONFIG_BLK_DEV_INITRD
+	if (ia64_boot_param->initrd_start) {
+		rsvd_region[n].start = (unsigned long)__va(ia64_boot_param->initrd_start);
+		rsvd_region[n].end   = rsvd_region[n].start + ia64_boot_param->initrd_size;
+		n++;
+	}
+#endif
+
+	/* end of memory marker */
+	rsvd_region[n].start = ~0UL;
+	rsvd_region[n].end   = ~0UL;
+	n++;
+
+	num_rsvd_regions = n;
+
+	sort_regions(rsvd_region, num_rsvd_regions);
 
+	/* first find highest page frame number */
 	max_pfn = 0;
 	efi_memmap_walk(find_max_pfn, &max_pfn);
 
-	/*
-	 * This is wrong, wrong, wrong.  Darn it, you'd think if they
-	 * change APIs, they'd do things for the better.  Grumble...
-	 */
-	bootmap_start = PAGE_ALIGN(__pa(&_end));
-	if (ia64_boot_param->initrd_size)
-		bootmap_start = PAGE_ALIGN(bootmap_start + ia64_boot_param->initrd_size);
+	/* how many bytes to cover all the pages */
+	bootmap_size = bootmem_bootmap_pages(max_pfn) << PAGE_SHIFT;
+
+	/* look for a location to hold the bootmap */
+	bootmap_start = ~0UL;
+	efi_memmap_walk(find_bootmap_location, &bootmap_size);
+	if (bootmap_start == ~0UL)
+		panic("Cannot find %ld bytes for bootmap\n", bootmap_size);
+
 	bootmap_size = init_bootmem(bootmap_start >> PAGE_SHIFT, max_pfn);
 
+	/* Free all available memory, then mark bootmem-map as being in use.  */
 	efi_memmap_walk(free_available_memory, 0);
-
 	reserve_bootmem(bootmap_start, bootmap_size);
 
 #ifdef CONFIG_BLK_DEV_INITRD
-	initrd_start = ia64_boot_param->initrd_start;
+	if (ia64_boot_param->initrd_start) {
+		initrd_start = (unsigned long)__va(ia64_boot_param->initrd_start);
+		initrd_end   = initrd_start+ia64_boot_param->initrd_size;
 
-	if (initrd_start) {
-		u64 start, size;
-#		define is_same_page(a,b) (((a)&PAGE_MASK) == ((b)&PAGE_MASK))
-
-#if 1
-		/* XXX for now some backwards compatibility... */
-		if (initrd_start >= PAGE_OFFSET)
-			printk("Warning: boot loader passed virtual address "
-			       "for initrd, please upgrade the loader\n");
-		else
-#endif
-			/*
-			 * The loader ONLY passes physical addresses
-			 */
-			initrd_start = (unsigned long)__va(initrd_start);
-		initrd_end = initrd_start+ia64_boot_param->initrd_size;
-		start      = initrd_start;
-		size       = ia64_boot_param->initrd_size;
-
-		printk("Initial ramdisk at: 0x%p (%lu bytes)\n",
-		       (void *) initrd_start, ia64_boot_param->initrd_size);
-
-		/*
-		 * The kernel end and the beginning of initrd can be
-		 * on the same page. This would cause the page to be
-		 * reserved twice.  While not harmful, it does lead to
-		 * a warning message which can cause confusion.  Thus,
-		 * we make sure that in this case we only reserve new
-		 * pages, i.e., initrd only pages. We need to:
-		 *
-		 *	- align up start
-		 *	- adjust size of reserved section accordingly
-		 *
-		 * It should be noted that this operation is only
-		 * valid for the reserve_bootmem() call and does not
-		 * affect the integrety of the initrd itself.
-		 *
-		 * reserve_bootmem() considers partial pages as reserved.
-		 */
-		if (is_same_page(initrd_start, (unsigned long)&_end)) {
-			start  = PAGE_ALIGN(start);
-			size  -= start-initrd_start;
-
-			printk("Initial ramdisk & kernel on the same page: "
-			       "reserving start=%lx size=%ld bytes\n",
-			       start, size);
-		}
-		reserve_bootmem(__pa(start), size);
+		printk("Initial ramdisk at: 0x%lx (%lu bytes)\n",
+		       initrd_start, ia64_boot_param->initrd_size);
 	}
 #endif
+}
+
+void __init
+setup_arch (char **cmdline_p)
+{
+	extern unsigned long ia64_iobase;
+
+	unw_init();
+
+	*cmdline_p = __va(ia64_boot_param->command_line);
+	strncpy(saved_command_line, *cmdline_p, sizeof(saved_command_line));
+	saved_command_line[COMMAND_LINE_SIZE-1] = '\0';		/* for safety */
+
+	efi_init();
+
+	find_memory();
+
 #if 0
 	/* XXX fix me */
 	init_mm.start_code = (unsigned long) &_stext;
@@ -217,27 +307,37 @@
 	/*
 	 *  Set `iobase' to the appropriate address in region 6
 	 *    (uncached access range)
+	 *
+	 *  The EFI memory map is the "prefered" location to get the I/O port
+	 *  space base, rather the relying on AR.KR0. This should become more
+	 *  clear in future SAL specs. We'll fall back to getting it out of
+	 *  AR.KR0 if no appropriate entry is found in the memory map.
 	 */
-	ia64_iobase = ia64_get_kr(IA64_KR_IO_BASE);
+	ia64_iobase = efi_get_iobase();
+	if (ia64_iobase)
+		/* set AR.KR0 since this is all we use it for anyway */
+		ia64_set_kr(IA64_KR_IO_BASE, ia64_iobase);
+	else {
+		ia64_iobase = ia64_get_kr(IA64_KR_IO_BASE);
+		printk("No I/O port range found in EFI memory map, falling back to AR.KR0\n");
+		printk("I/O port base = 0x%lx\n", ia64_iobase);
+	}
 	ia64_iobase = __IA64_UNCACHED_OFFSET | (ia64_iobase & ~PAGE_OFFSET);
 
-	cpu_init();	/* initialize the bootstrap CPU */
-
 #ifdef CONFIG_SMP
 	cpu_physical_id(0) = hard_smp_processor_id();
 #endif
 
+	cpu_init();	/* initialize the bootstrap CPU */
+
 #ifdef CONFIG_IA64_GENERIC
 	machvec_init(acpi_get_sysname());
 #endif
 
-#ifdef	CONFIG_ACPI20
 	if (efi.acpi20) {
 		/* Parse the ACPI 2.0 tables */
 		acpi20_parse(efi.acpi20);
-	} else
-#endif
-	if (efi.acpi) {
+	} else if (efi.acpi) {
 		/* Parse the ACPI tables */
 		acpi_parse(efi.acpi);
 	}
@@ -257,6 +357,8 @@
 
 	platform_setup(cmdline_p);
 	paging_init();
+
+	unw_create_gate_table();
 }
 
 /*
@@ -270,26 +372,18 @@
 #else
 #	define lpj	loops_per_jiffy
 #endif
-	char family[32], model[32], features[128], *cp, *p = buffer;
+	char family[32], features[128], *cp, *p = buffer;
 	struct cpuinfo_ia64 *c;
-	unsigned long mask;
-
-	for (c = cpu_data; c < cpu_data + NR_CPUS; ++c) {
-#ifdef CONFIG_SMP
-		if (!(cpu_online_map & (1UL << (c - cpu_data))))
-			continue;
-#endif
+	unsigned long mask, cpu;
 
+	for (cpu = 0; cpu < smp_num_cpus; ++cpu) {
+		c = cpu_data(cpu);
 		mask = c->features;
 
-		if (c->family == 7)
-			memcpy(family, "IA-64", 6);
-		else
-			sprintf(family, "%u", c->family);
-
-		switch (c->model) {
-		      case 0:	strcpy(model, "Itanium"); break;
-		      default:	sprintf(model, "%u", c->model); break;
+		switch (c->family) {
+		      case 0x07:	memcpy(family, "Itanium", 8); break;
+		      case 0x1f:	memcpy(family, "McKinley", 9); break;
+		      default:		sprintf(family, "%u", c->family); break;
 		}
 
 		/* build the feature string: */
@@ -306,8 +400,9 @@
 		p += sprintf(p,
 			     "processor  : %lu\n"
 			     "vendor     : %s\n"
+			     "arch       : IA-64\n"
 			     "family     : %s\n"
-			     "model      : %s\n"
+			     "model      : %u\n"
 			     "revision   : %u\n"
 			     "archrev    : %u\n"
 			     "features   :%s\n"	/* don't change this---it _is_ right! */
@@ -316,8 +411,7 @@
 			     "cpu MHz    : %lu.%06lu\n"
 			     "itc MHz    : %lu.%06lu\n"
 			     "BogoMIPS   : %lu.%02lu\n\n",
-			     c - cpu_data, c->vendor, family, model, c->revision, c->archrev,
-			     features,
+			     cpu, c->vendor, family, c->model, c->revision, c->archrev, features,
 			     c->ppn, c->number, c->proc_freq / 1000000, c->proc_freq % 1000000,
 			     c->itc_freq / 1000000, c->itc_freq % 1000000,
 			     lpj*HZ/500000, (lpj*HZ/5000) % 100);
@@ -385,18 +479,54 @@
 void
 cpu_init (void)
 {
-	extern void __init ia64_mmu_init (void);
+	extern void __init ia64_mmu_init (void *);
 	unsigned long num_phys_stacked;
 	pal_vm_info_2_u_t vmi;
 	unsigned int max_ctx;
+	struct cpuinfo_ia64 *my_cpu_data;
+#ifdef CONFIG_NUMA
+	int cpu, order;
+
+	/*
+	 * If NUMA is configured, the cpu_data array is not preallocated. The boot cpu
+	 * allocates entries for every possible cpu. As the remaining cpus come online,
+	 * they reallocate a new cpu_data structure on their local node. This extra work
+	 * is required because some boot code references all cpu_data structures
+	 * before the cpus are actually started.
+	 */
+	if (!boot_cpu_data) {
+		my_cpu_data = alloc_bootmem_pages_node(NODE_DATA(numa_node_id()),
+						       sizeof(struct cpuinfo_ia64));
+		boot_cpu_data = my_cpu_data;
+		my_cpu_data->cpu_data[0] = my_cpu_data;
+		for (cpu = 1; cpu < NR_CPUS; ++cpu)
+			my_cpu_data->cpu_data[cpu]
+				= alloc_bootmem_pages_node(NODE_DATA(numa_node_id()),
+							   sizeof(struct cpuinfo_ia64));
+		for (cpu = 1; cpu < NR_CPUS; ++cpu)
+			memcpy(my_cpu_data->cpu_data[cpu]->cpu_data_ptrs,
+			       my_cpu_data->cpu_data, sizeof(my_cpu_data->cpu_data));
+	} else {
+		order = get_order(sizeof(struct cpuinfo_ia64));
+		my_cpu_data = page_address(alloc_pages_node(numa_node_id(), GFP_KERNEL, order));
+		memcpy(my_cpu_data, boot_cpu_data->cpu_data[smp_processor_id()],
+		       sizeof(struct cpuinfo_ia64));
+		__free_pages(virt_to_page(boot_cpu_data->cpu_data[smp_processor_id()]),
+			     order);
+		for (cpu = 0; cpu < NR_CPUS; ++cpu)
+			boot_cpu_data->cpu_data[cpu]->cpu_data[smp_processor_id()] = my_cpu_data;
+	}
+#else
+	my_cpu_data = cpu_data(smp_processor_id());
+#endif
 
 	/*
-	 * We can't pass "local_cpu_data" do identify_cpu() because we haven't called
+	 * We can't pass "local_cpu_data" to identify_cpu() because we haven't called
 	 * ia64_mmu_init() yet.  And we can't call ia64_mmu_init() first because it
 	 * depends on the data returned by identify_cpu().  We break the dependency by
-	 * accessing cpu_data[] the old way, through identity mapped space.
+	 * accessing cpu_data() the old way, through identity mapped space.
 	 */
-	identify_cpu(&cpu_data[smp_processor_id()]);
+	identify_cpu(my_cpu_data);
 
 	/* Clear the stack memory reserved for pt_regs: */
 	memset(ia64_task_regs(current), 0, sizeof(struct pt_regs));
@@ -415,13 +545,11 @@
 	atomic_inc(&init_mm.mm_count);
 	current->active_mm = &init_mm;
 
-	ia64_mmu_init();
+	ia64_mmu_init(my_cpu_data);
 
 #ifdef CONFIG_IA32_SUPPORT
 	/* initialize global ia32 state - CR0 and CR4 */
-	__asm__("mov ar.cflg = %0"
-		: /* no outputs */
-		: "r" (((ulong) IA32_CR4 << 32) | IA32_CR0));
+	asm volatile ("mov ar.cflg = %0" :: "r" (((ulong) IA32_CR4 << 32) | IA32_CR0));
 #endif
 
 	/* disable all local interrupt sources: */
diff -u --recursive --new-file v2.4.7/linux/arch/ia64/kernel/sigframe.h linux/arch/ia64/kernel/sigframe.h
--- v2.4.7/linux/arch/ia64/kernel/sigframe.h	Wed Dec 31 16:00:00 1969
+++ linux/arch/ia64/kernel/sigframe.h	Tue Jul 31 10:30:08 2001
@@ -0,0 +1,16 @@
+struct sigframe {
+	/*
+	 * Place signal handler args where user-level unwinder can find them easily.
+	 * DO NOT MOVE THESE.  They are part of the IA-64 Linux ABI and there is
+	 * user-level code that depends on their presence!
+	 */
+	unsigned long arg0;		/* signum */
+	unsigned long arg1;		/* siginfo pointer */
+	unsigned long arg2;		/* sigcontext pointer */
+
+	unsigned long rbs_base;		/* base of new register backing store (or NULL) */
+	void *handler;			/* pointer to the plabel of the signal handler */
+
+	struct siginfo info;
+	struct sigcontext sc;
+};
diff -u --recursive --new-file v2.4.7/linux/arch/ia64/kernel/signal.c linux/arch/ia64/kernel/signal.c
--- v2.4.7/linux/arch/ia64/kernel/signal.c	Thu Apr  5 12:51:47 2001
+++ linux/arch/ia64/kernel/signal.c	Tue Jul 31 10:30:08 2001
@@ -25,6 +25,8 @@
 #include <asm/rse.h>
 #include <asm/sigcontext.h>
 
+#include "sigframe.h"
+
 #define DEBUG_SIG	0
 #define STACK_ALIGN	16		/* minimal alignment for stack pointer */
 #define _BLOCKABLE	(~(sigmask(SIGKILL) | sigmask(SIGSTOP)))
@@ -43,11 +45,6 @@
 	struct pt_regs pt;
 };
 
-struct sigframe {
-	struct siginfo info;
-	struct sigcontext sc;
-};
-
 extern long ia64_do_signal (sigset_t *, struct sigscratch *, long);	/* forward decl */
 
 long
@@ -380,7 +377,13 @@
 	if (!access_ok(VERIFY_WRITE, frame, sizeof(*frame)))
 		goto give_sigsegv;
 
-	err  = copy_siginfo_to_user(&frame->info, info);
+	err  = __put_user(sig, &frame->arg0);
+	err |= __put_user(&frame->info, &frame->arg1);
+	err |= __put_user(&frame->sc, &frame->arg2);
+	err |= __put_user(new_rbs, &frame->rbs_base);
+	err |= __put_user(ka->sa.sa_handler, &frame->handler);
+
+	err |= copy_siginfo_to_user(&frame->info, info);
 
 	err |= __put_user(current->sas_ss_sp, &frame->sc.sc_stack.ss_sp);
 	err |= __put_user(current->sas_ss_size, &frame->sc.sc_stack.ss_size);
@@ -390,19 +393,16 @@
 	if (err)
 		goto give_sigsegv;
 
-	scr->pt.r12 = (unsigned long) frame - 16;		/* new stack pointer */
-	scr->pt.r2  = sig;					/* signal number */
-	scr->pt.r3  = (unsigned long) ka->sa.sa_handler;	/* addr. of handler's proc desc */
-	scr->pt.r15 = new_rbs;
+	scr->pt.r12 = (unsigned long) frame - 16;	/* new stack pointer */
 	scr->pt.ar_fpsr = FPSR_DEFAULT;			/* reset fpsr for signal handler */
 	scr->pt.cr_iip = tramp_addr;
 	ia64_psr(&scr->pt)->ri = 0;			/* start executing in first slot */
 
 	/*
-	 * Note: this affects only the NaT bits of the scratch regs
-	 * (the ones saved in pt_regs), which is exactly what we want.
+	 * Note: this affects only the NaT bits of the scratch regs (the ones saved in
+	 * pt_regs), which is exactly what we want.
 	 */
-	scr->scratch_unat = 0; /* ensure NaT bits of at least r2, r3, r12, and r15 are clear */
+	scr->scratch_unat = 0; /* ensure NaT bits of r12 is clear */
 
 #if DEBUG_SIG
 	printk("SIG deliver (%s:%d): sig=%d sp=%lx ip=%lx handler=%lx\n",
diff -u --recursive --new-file v2.4.7/linux/arch/ia64/kernel/smp.c linux/arch/ia64/kernel/smp.c
--- v2.4.7/linux/arch/ia64/kernel/smp.c	Thu Apr  5 12:51:47 2001
+++ linux/arch/ia64/kernel/smp.c	Tue Jul 31 10:30:08 2001
@@ -6,12 +6,16 @@
  *
  * Lots of stuff stolen from arch/alpha/kernel/smp.c
  *
- *  00/09/11 David Mosberger <davidm@hpl.hp.com> Do loops_per_jiffy calibration on each CPU.
- *  00/08/23 Asit Mallick <asit.k.mallick@intel.com> fixed logical processor id
- *  00/03/31 Rohit Seth <rohit.seth@intel.com>	Fixes for Bootstrap Processor & cpu_online_map
- *			now gets done here (instead of setup.c)
- *  99/10/05 davidm	Update to bring it in sync with new command-line processing scheme.
- *  10/13/00 Goutham Rao <goutham.rao@intel.com> Updated smp_call_function and
+ * 01/05/16 Rohit Seth <rohit.seth@intel.com>  IA64-SMP functions. Reorganized
+ * the existing code (on the lines of x86 port).
+ * 00/09/11 David Mosberger <davidm@hpl.hp.com> Do loops_per_jiffy
+ * calibration on each CPU.
+ * 00/08/23 Asit Mallick <asit.k.mallick@intel.com> fixed logical processor id
+ * 00/03/31 Rohit Seth <rohit.seth@intel.com>	Fixes for Bootstrap Processor
+ * & cpu_online_map now gets done here (instead of setup.c)
+ * 99/10/05 davidm	Update to bring it in sync with new command-line processing
+ *  scheme.
+ * 10/13/00 Goutham Rao <goutham.rao@intel.com> Updated smp_call_function and
  *		smp_call_function_single to resend IPI on timeouts
  */
 #define __KERNEL_SYSCALLS__
@@ -45,120 +49,47 @@
 #include <asm/system.h>
 #include <asm/unistd.h>
 
-extern void __init calibrate_delay(void);
-extern int cpu_idle(void * unused);
-extern void machine_halt(void);
-extern void start_ap(void);
-
-extern int cpu_now_booting;			/* used by head.S to find idle task */
-extern volatile unsigned long cpu_online_map;	/* bitmap of available cpu's */
-
-struct smp_boot_data smp_boot_data __initdata;
-
+/* The 'big kernel lock' */
 spinlock_t kernel_flag = SPIN_LOCK_UNLOCKED;
 
-char __initdata no_int_routing;
-
-/* don't make this a CPU-local variable: it's used for IPIs, mostly...  */
-int __cpu_physical_id[NR_CPUS];			/* logical ID -> physical CPU ID map */
-
-unsigned char smp_int_redirect;			/* are INT and IPI redirectable by the chipset? */
-int smp_num_cpus = 1;
-volatile int smp_threads_ready;			/* set when the idlers are all forked */
-unsigned long ap_wakeup_vector;			/* external Int to use to wakeup AP's */
-
-static volatile unsigned long cpu_callin_map;
-static volatile int smp_commenced;
-
-static int max_cpus = -1;			/* command line */
+/*
+ * Structure and data for smp_call_function(). This is designed to minimise static memory
+ * requirements. It also looks cleaner.
+ */
+static spinlock_t call_lock = SPIN_LOCK_UNLOCKED;
 
-struct smp_call_struct {
+struct call_data_struct {
 	void (*func) (void *info);
 	void *info;
 	long wait;
-	atomic_t unstarted_count;
-	atomic_t unfinished_count;
+	atomic_t started;
+	atomic_t finished;
 };
-static volatile struct smp_call_struct *smp_call_function_data;
-
-#define IPI_RESCHEDULE	        0
-#define IPI_CALL_FUNC	        1
-#define IPI_CPU_STOP	        2
-#ifndef CONFIG_ITANIUM_PTCG
-# define IPI_FLUSH_TLB		3
-#endif	/*!CONFIG_ITANIUM_PTCG */
-
-/*
- *	Setup routine for controlling SMP activation
- *
- *	Command-line option of "nosmp" or "maxcpus=0" will disable SMP
- *      activation entirely (the MPS table probe still happens, though).
- *
- *	Command-line option of "maxcpus=<NUM>", where <NUM> is an integer
- *	greater than 0, limits the maximum number of CPUs activated in
- *	SMP mode to <NUM>.
- */
-
-static int __init
-nosmp (char *str)
-{
-	max_cpus = 0;
-	return 1;
-}
-
-__setup("nosmp", nosmp);
-
-static int __init
-maxcpus (char *str)
-{
-	get_option(&str, &max_cpus);
-	return 1;
-}
-
-__setup("maxcpus=", maxcpus);
 
-static int __init
-nointroute (char *str)
-{
-	no_int_routing = 1;
-	return 1;
-}
+static volatile struct call_data_struct *call_data;
 
-__setup("nointroute", nointroute);
+#define IPI_CALL_FUNC		0
+#define IPI_CPU_STOP		1
+#ifndef CONFIG_ITANIUM_PTCG
+# define IPI_FLUSH_TLB		2
+#endif  /*!CONFIG_ITANIUM_PTCG */
 
-/*
- * Yoink this CPU from the runnable list...
- */
-void
-halt_processor (void)
+static void
+stop_this_cpu (void)
 {
+	/*
+	 * Remove this CPU:
+	 */
 	clear_bit(smp_processor_id(), &cpu_online_map);
 	max_xtp();
 	__cli();
-	for (;;)
-		;
-}
-
-static inline int
-pointer_lock (void *lock, void *data, int retry)
-{
-	volatile long *ptr = lock;
- again:
-	if (cmpxchg_acq((void **) lock, 0, data) == 0)
-		return 0;
-
-	if (!retry)
-		return -EBUSY;
-
-	while (*ptr)
-		;
-
-	goto again;
+	for (;;);
 }
 
 void
 handle_IPI (int irq, void *dev_id, struct pt_regs *regs)
 {
+	int this_cpu = smp_processor_id();
 	unsigned long *pending_ipis = &local_cpu_data->ipi_operation;
 	unsigned long ops;
 
@@ -175,28 +106,21 @@
 		ops &= ~(1 << which);
 
 		switch (which) {
-		case IPI_RESCHEDULE:
-			/*
-			 * Reschedule callback.  Everything to be done is done by the
-			 * interrupt return path.
-			 */
-			break;
-
 		case IPI_CALL_FUNC:
 			{
-				struct smp_call_struct *data;
+				struct call_data_struct *data;
 				void (*func)(void *info);
 				void *info;
 				int wait;
 
 				/* release the 'pointer lock' */
-				data = (struct smp_call_struct *) smp_call_function_data;
+				data = (struct call_data_struct *) call_data;
 				func = data->func;
 				info = data->info;
 				wait = data->wait;
 
 				mb();
-				atomic_dec(&data->unstarted_count);
+				atomic_inc(&data->started);
 
 				/* At this point the structure may be gone unless wait is true.  */
 				(*func)(info);
@@ -204,12 +128,12 @@
 				/* Notify the sending CPU that the task is done.  */
 				mb();
 				if (wait)
-					atomic_dec(&data->unfinished_count);
+					atomic_inc(&data->finished);
 			}
 			break;
 
 		case IPI_CPU_STOP:
-			halt_processor();
+			stop_this_cpu();
 			break;
 
 #ifndef CONFIG_ITANIUM_PTCG
@@ -224,13 +148,9 @@
 
 			/*
 			 * Current CPU may be running with different RID so we need to
-			 * reload the RID of flushed address.
-			 * Current CPU may be running with different
-			 * RID so we need to reload the RID of flushed
-			 * address.  Purging the translation also
-			 * needs ALAT invalidation; we do not need
-			 * "invala" here since it is done in
-			 * ia64_leave_kernel.
+			 * reload the RID of flushed address.  Purging the translation
+			 * also needs ALAT invalidation; we do not need "invala" here
+			 * since it is done in ia64_leave_kernel.
 			 */
 			ia64_srlz_d();
 			if (saved_rid != flush_rid) {
@@ -260,8 +180,7 @@
 #endif	/* !CONFIG_ITANIUM_PTCG */
 
 		default:
-			printk(KERN_CRIT "Unknown IPI on CPU %d: %lu\n",
-			       smp_processor_id(), which);
+			printk(KERN_CRIT "Unknown IPI on CPU %d: %lu\n", this_cpu, which);
 			break;
 		} /* Switch */
 	  } while (ops);
@@ -273,11 +192,7 @@
 static inline void
 send_IPI_single (int dest_cpu, int op)
 {
-
-	if (dest_cpu == -1)
-		return;
-
-	set_bit(op, &cpu_data[dest_cpu].ipi_operation);
+	set_bit(op, &cpu_data(dest_cpu)->ipi_operation);
 	platform_send_ipi(dest_cpu, IA64_IPI_VECTOR, IA64_IPI_DM_INT, 0);
 }
 
@@ -310,13 +225,7 @@
 void
 smp_send_reschedule (int cpu)
 {
-	send_IPI_single(cpu, IPI_RESCHEDULE);
-}
-
-void
-smp_send_stop (void)
-{
-	send_IPI_allbutself(IPI_CPU_STOP);
+	platform_send_ipi(cpu, IA64_IPI_RESCHEDULE, IA64_IPI_DM_INT, 0);
 }
 
 #ifndef CONFIG_ITANIUM_PTCG
@@ -328,22 +237,33 @@
 }
 
 void
-smp_resend_flush_tlb(void)
+smp_resend_flush_tlb (void)
 {
+	int i;
+
 	/*
 	 * Really need a null IPI but since this rarely should happen & since this code
 	 * will go away, lets not add one.
 	 */
-	send_IPI_allbutself(IPI_RESCHEDULE);
+	for (i = 0; i < smp_num_cpus; ++i)
+		if (i != smp_processor_id())
+			smp_send_reschedule(i);
 }
 
-#endif /* !CONFIG_ITANIUM_PTCG */
+#endif  /* !CONFIG_ITANIUM_PTCG */
+
+void
+smp_flush_tlb_all (void)
+{
+	smp_call_function ((void (*)(void *))__flush_tlb_all,0,1,1);
+	__flush_tlb_all();
+}
 
 /*
  * Run a function on another CPU
  *  <func>	The function to run. This must be fast and non-blocking.
  *  <info>	An arbitrary pointer to pass to the function.
- *  <retry>	If true, keep retrying until ready.
+ *  <nonatomic>	Currently unused.
  *  <wait>	If true, wait until function has completed on other CPUs.
  *  [RETURNS]   0 on success, else a negative status code.
  *
@@ -352,11 +272,15 @@
  */
 
 int
-smp_call_function_single (int cpuid, void (*func) (void *info), void *info, int retry, int wait)
+smp_call_function_single (int cpuid, void (*func) (void *info), void *info, int nonatomic,
+			  int wait)
 {
-	struct smp_call_struct data;
-	unsigned long timeout;
+	struct call_data_struct data;
 	int cpus = 1;
+#if (defined(CONFIG_ITANIUM_B0_SPECIFIC) \
+     || defined(CONFIG_ITANIUM_B1_SPECIFIC) || defined(CONFIG_ITANIUM_B2_SPECIFIC))
+	unsigned long timeout;
+#endif
 
 	if (cpuid == smp_processor_id()) {
 		printk(__FUNCTION__" trying to call self\n");
@@ -365,115 +289,110 @@
 
 	data.func = func;
 	data.info = info;
+	atomic_set(&data.started, 0);
 	data.wait = wait;
-	atomic_set(&data.unstarted_count, cpus);
-	atomic_set(&data.unfinished_count, cpus);
+	if (wait)
+		atomic_set(&data.finished, 0);
 
-	if (pointer_lock(&smp_call_function_data, &data, retry))
-		return -EBUSY;
+	spin_lock_bh(&call_lock);
+	call_data = &data;
 
-resend:
-	/*  Send a message to all other CPUs and wait for them to respond  */
-	send_IPI_single(cpuid, IPI_CALL_FUNC);
+#if (defined(CONFIG_ITANIUM_B0_SPECIFIC) \
+     || defined(CONFIG_ITANIUM_B1_SPECIFIC) || defined(CONFIG_ITANIUM_B2_SPECIFIC))
+  resend:
+  	send_IPI_single(cpuid, IPI_CALL_FUNC);
 
-	/*  Wait for response  */
+	/*  Wait for response */
 	timeout = jiffies + HZ;
-	while ((atomic_read(&data.unstarted_count) > 0) && time_before(jiffies, timeout))
+	while ((atomic_read(&data.started) != cpus) && time_before(jiffies, timeout))
 		barrier();
-	if (atomic_read(&data.unstarted_count) > 0) {
-#if (defined(CONFIG_ITANIUM_ASTEP_SPECIFIC) || defined(CONFIG_ITANIUM_BSTEP_SPECIFIC))
+	if (atomic_read(&data.started) != cpus)
 		goto resend;
 #else
-		smp_call_function_data = NULL;
-		return -ETIMEDOUT;
+  	send_IPI_single(cpuid, IPI_CALL_FUNC);
+
+	/* Wait for response */
+	while (atomic_read(&data.started) != cpus)
+		barrier();
 #endif
-	}
 	if (wait)
-		while (atomic_read(&data.unfinished_count) > 0)
+		while (atomic_read(&data.finished) != cpus)
 			barrier();
-	/* unlock pointer */
-	smp_call_function_data = NULL;
+	call_data = NULL;
+
+	spin_unlock_bh(&call_lock);
 	return 0;
 }
 
 /*
- * Run a function on all other CPUs.
+ * this function sends a 'generic call function' IPI to all other CPUs
+ * in the system.
+ */
+
+/*
+ *  [SUMMARY]	Run a function on all other CPUs.
  *  <func>	The function to run. This must be fast and non-blocking.
  *  <info>	An arbitrary pointer to pass to the function.
- *  <retry>	If true, keep retrying until ready.
- *  <wait>	If true, wait until function has completed on other CPUs.
+ *  <nonatomic>	currently unused.
+ *  <wait>	If true, wait (atomically) until function has completed on other CPUs.
  *  [RETURNS]   0 on success, else a negative status code.
  *
- * Does not return until remote CPUs are nearly ready to execute <func>
- * or are or have executed.
+ * Does not return until remote CPUs are nearly ready to execute <func> or are or have
+ * executed.
+ *
+ * You must not call this function with disabled interrupts or from a hardware interrupt
+ * handler, you may call it from a bottom half handler.
  */
 int
-smp_call_function (void (*func) (void *info), void *info, int retry, int wait)
+smp_call_function (void (*func) (void *info), void *info, int nonatomic, int wait)
 {
-	struct smp_call_struct data;
+	struct call_data_struct data;
+	int cpus = smp_num_cpus-1;
+#if (defined(CONFIG_ITANIUM_B0_SPECIFIC) \
+     || defined(CONFIG_ITANIUM_B1_SPECIFIC) || defined(CONFIG_ITANIUM_B2_SPECIFIC))
 	unsigned long timeout;
-	int cpus = smp_num_cpus - 1;
+#endif
 
-	if (cpus == 0)
+	if (!cpus)
 		return 0;
 
 	data.func = func;
 	data.info = info;
+	atomic_set(&data.started, 0);
 	data.wait = wait;
-	atomic_set(&data.unstarted_count, cpus);
-	atomic_set(&data.unfinished_count, cpus);
+	if (wait)
+		atomic_set(&data.finished, 0);
 
-	if (pointer_lock(&smp_call_function_data, &data, retry))
-		return -EBUSY;
+	spin_lock_bh(&call_lock);
+	call_data = &data;
 
-	/*  Send a message to all other CPUs and wait for them to respond  */
+#if (defined(CONFIG_ITANIUM_B0_SPECIFIC) \
+     || defined(CONFIG_ITANIUM_B1_SPECIFIC) || defined(CONFIG_ITANIUM_B2_SPECIFIC))
+  resend:
+	/*  Send a message to all other CPUs and wait for them to respond */
 	send_IPI_allbutself(IPI_CALL_FUNC);
 
-retry:
-	/*  Wait for response  */
+	/* Wait for response */
 	timeout = jiffies + HZ;
-	while ((atomic_read(&data.unstarted_count) > 0) && time_before(jiffies, timeout))
+	while ((atomic_read(&data.started) != cpus) && time_before(jiffies, timeout))
 		barrier();
-	if (atomic_read(&data.unstarted_count) > 0) {
-#if (defined(CONFIG_ITANIUM_ASTEP_SPECIFIC) || defined(CONFIG_ITANIUM_BSTEP_SPECIFIC))
-		int i;
-		for (i = 0; i < smp_num_cpus; i++) {
-			if (i != smp_processor_id())
-				platform_send_ipi(i, IA64_IPI_VECTOR, IA64_IPI_DM_INT, 0);
-		}
-		goto retry;
+	if (atomic_read(&data.started) != cpus)
+		goto resend;
 #else
-		smp_call_function_data = NULL;
-		return -ETIMEDOUT;
+	send_IPI_allbutself(IPI_CALL_FUNC);
+
+	/* Wait for response */
+	while (atomic_read(&data.started) != cpus)
+		barrier();
 #endif
-	}
+
 	if (wait)
-		while (atomic_read(&data.unfinished_count) > 0)
+		while (atomic_read(&data.finished) != cpus)
 			barrier();
-	/* unlock pointer */
-	smp_call_function_data = NULL;
-	return 0;
-}
-
-/*
- * Flush all other CPU's tlb and then mine.  Do this with smp_call_function() as we
- * want to ensure all TLB's flushed before proceeding.
- */
-void
-smp_flush_tlb_all (void)
-{
-	smp_call_function((void (*)(void *))__flush_tlb_all, NULL, 1, 1);
-	__flush_tlb_all();
-}
+	call_data = NULL;
 
-/*
- * Ideally sets up per-cpu profiling hooks.  Doesn't do much now...
- */
-static inline void __init
-smp_setup_percpu_timer(void)
-{
-	local_cpu_data->prof_counter = 1;
-	local_cpu_data->prof_multiplier = 1;
+	spin_unlock_bh(&call_lock);
+	return 0;
 }
 
 void
@@ -487,232 +406,18 @@
 	}
 }
 
-
-/*
- * AP's start using C here.
- */
-void __init
-smp_callin (void)
-{
-	extern void ia64_rid_init(void);
-	extern void ia64_init_itm(void);
-	extern void ia64_cpu_local_tick(void);
-#ifdef CONFIG_PERFMON
-	extern void perfmon_init_percpu(void);
-#endif
-	int cpu = smp_processor_id();
-
-	if (test_and_set_bit(cpu, &cpu_online_map)) {
-		printk("CPU#%d already initialized!\n", cpu);
-		machine_halt();
-	}
-
-	efi_map_pal_code();
-	cpu_init();
-
-	smp_setup_percpu_timer();
-
-	/* setup the CPU local timer tick */
-	ia64_init_itm();
-
-#ifdef CONFIG_PERFMON
-	perfmon_init_percpu();
-#endif
-	local_irq_enable();		/* Interrupts have been off until now */
-
-	calibrate_delay();
-	local_cpu_data->loops_per_jiffy = loops_per_jiffy;
-
-	/* allow the master to continue */
-	set_bit(cpu, &cpu_callin_map);
-
-	/* finally, wait for the BP to finish initialization: */
-	while (!smp_commenced);
-
-	cpu_idle(NULL);
-}
-
-/*
- * Create the idle task for a new AP.  DO NOT use kernel_thread() because
- * that could end up calling schedule() in the ia64_leave_kernel exit
- * path in which case the new idle task could get scheduled before we
- * had a chance to remove it from the run-queue...
- */
-static int __init
-fork_by_hand (void)
-{
-	/*
-	 * Don't care about the usp and regs settings since we'll never
-	 * reschedule the forked task.
-	 */
-	return do_fork(CLONE_VM|CLONE_PID, 0, 0, 0);
-}
-
-/*
- * Bring one cpu online.  Return 0 if this fails for any reason.
- */
-static int __init
-smp_boot_one_cpu (int cpu)
-{
-	struct task_struct *idle;
-	int cpu_phys_id = cpu_physical_id(cpu);
-	long timeout;
-
-	/*
-	 * Create an idle task for this CPU.  Note that the address we
-	 * give to kernel_thread is irrelevant -- it's going to start
-	 * where OS_BOOT_RENDEVZ vector in SAL says to start.  But
-	 * this gets all the other task-y sort of data structures set
-	 * up like we wish.   We need to pull the just created idle task
-	 * off the run queue and stuff it into the init_tasks[] array.
-	 * Sheesh . . .
-	 */
-	if (fork_by_hand() < 0)
-		panic("failed fork for CPU 0x%x", cpu_phys_id);
-	/*
-	 * We remove it from the pidhash and the runqueue
-	 * once we got the process:
-	 */
-	idle = init_task.prev_task;
-	if (!idle)
-		panic("No idle process for CPU 0x%x", cpu_phys_id);
-	init_tasks[cpu] = idle;
-	del_from_runqueue(idle);
-	unhash_process(idle);
-
-	/* Schedule the first task manually.  */
-	idle->processor = cpu;
-	idle->has_cpu = 1;
-
-	/* Let _start know what logical CPU we're booting (offset into init_tasks[] */
-	cpu_now_booting = cpu;
-
-	/* Kick the AP in the butt */
-	platform_send_ipi(cpu, ap_wakeup_vector, IA64_IPI_DM_INT, 0);
-
-	/* wait up to 10s for the AP to start  */
-	for (timeout = 0; timeout < 100000; timeout++) {
-		if (test_bit(cpu, &cpu_callin_map))
-			return 1;
-		udelay(100);
-	}
-
-	printk(KERN_ERR "SMP: CPU 0x%x is stuck\n", cpu_phys_id);
-	return 0;
-}
-
-
-
-/*
- * Called by smp_init bring all the secondaries online and hold them.
- */
-void __init
-smp_boot_cpus (void)
-{
-	int i, cpu_count = 1;
-	unsigned long bogosum;
-
-	/* on the BP, the kernel already called calibrate_delay_loop() in init/main.c */
-	local_cpu_data->loops_per_jiffy = loops_per_jiffy;
-#if 0
-	smp_tune_scheduling();
-#endif
-	smp_setup_percpu_timer();
-
-	if (test_and_set_bit(0, &cpu_online_map)) {
-		printk("CPU#%d already initialized!\n", smp_processor_id());
-		machine_halt();
-	}
-	init_idle();
-
-	/* Nothing to do when told not to.  */
-	if (max_cpus == 0) {
-		printk(KERN_INFO "SMP mode deactivated.\n");
-		return;
-	}
-
-	if (max_cpus != -1)
-		printk("Limiting CPUs to %d\n", max_cpus);
-
-	if (smp_boot_data.cpu_count > 1) {
-		printk(KERN_INFO "SMP: starting up secondaries.\n");
-
-		for (i = 0; i < smp_boot_data.cpu_count; i++) {
-			/* skip performance restricted and bootstrap cpu: */
-			if (smp_boot_data.cpu_phys_id[i] == -1
-			    || smp_boot_data.cpu_phys_id[i] == hard_smp_processor_id())
-				continue;
-
-			cpu_physical_id(cpu_count) = smp_boot_data.cpu_phys_id[i];
-			if (!smp_boot_one_cpu(cpu_count))
-				continue;	/* failed */
-
-			cpu_count++; /* Count good CPUs only... */
-			/*
-			 * Bail if we've started as many CPUS as we've been told to.
-			 */
-			if (cpu_count == max_cpus)
-				break;
-		}
-	}
-
-	if (cpu_count == 1) {
-		printk(KERN_ERR "SMP: Bootstrap processor only.\n");
-	}
-
-	bogosum = 0;
-	for (i = 0; i < NR_CPUS; i++) {
-		if (cpu_online_map & (1L << i))
-			bogosum += cpu_data[i].loops_per_jiffy;
-	}
-
-	printk(KERN_INFO "SMP: Total of %d processors activated (%lu.%02lu BogoMIPS).\n",
-	       cpu_count, bogosum*HZ/500000, (bogosum*HZ/5000) % 100);
-
-	smp_num_cpus = cpu_count;
-}
-
 /*
- * Called when the BP is just about to fire off init.
+ * this function calls the 'stop' function on all other CPUs in the system.
  */
-void __init
-smp_commence (void)
+void
+smp_send_stop (void)
 {
-	smp_commenced = 1;
+	send_IPI_allbutself(IPI_CPU_STOP);
+	smp_num_cpus = 1;
 }
 
 int __init
 setup_profiling_timer (unsigned int multiplier)
 {
 	return -EINVAL;
-}
-
-/*
- * Assume that CPU's have been discovered by some platform-dependant
- * interface.  For SoftSDV/Lion, that would be ACPI.
- *
- * Setup of the IPI irq handler is done in irq.c:init_IRQ().
- *
- * This also registers the AP OS_MC_REDVEZ address with SAL.
- */
-void __init
-init_smp_config (void)
-{
-	struct fptr {
-		unsigned long fp;
-		unsigned long gp;
-	} *ap_startup;
-	long sal_ret;
-
-	/* Tell SAL where to drop the AP's.  */
-	ap_startup = (struct fptr *) start_ap;
-	sal_ret = ia64_sal_set_vectors(SAL_VECTOR_OS_BOOT_RENDEZ, __pa(ap_startup->fp),
-				       __pa(ap_startup->gp), 0, 0, 0, 0);
-	if (sal_ret < 0) {
-		printk("SMP: Can't set SAL AP Boot Rendezvous: %s\n", ia64_sal_strerror(sal_ret));
-		printk("     Forcing UP mode\n");
-		max_cpus = 0;
-		smp_num_cpus = 1;
-	}
-
 }
diff -u --recursive --new-file v2.4.7/linux/arch/ia64/kernel/smpboot.c linux/arch/ia64/kernel/smpboot.c
--- v2.4.7/linux/arch/ia64/kernel/smpboot.c	Thu Apr  5 12:51:47 2001
+++ linux/arch/ia64/kernel/smpboot.c	Tue Jul 31 10:30:08 2001
@@ -1,4 +1,563 @@
 /*
+ * SMP boot-related support
+ *
+ * Copyright (C) 2001 David Mosberger-Tang <davidm@hpl.hp.com>
+ *
+ * 01/05/16 Rohit Seth <rohit.seth@intel.com>	Moved SMP booting functions from smp.c to here.
+ * 01/04/27 David Mosberger <davidm@hpl.hp.com>	Added ITC synching code.
  */
 
-/* place holder... */
+
+#define __KERNEL_SYSCALLS__
+
+#include <linux/config.h>
+
+#include <linux/bootmem.h>
+#include <linux/delay.h>
+#include <linux/init.h>
+#include <linux/interrupt.h>
+#include <linux/irq.h>
+#include <linux/kernel.h>
+#include <linux/kernel_stat.h>
+#include <linux/mm.h>
+#include <linux/smp.h>
+#include <linux/smp_lock.h>
+#include <linux/spinlock.h>
+
+#include <asm/atomic.h>
+#include <asm/bitops.h>
+#include <asm/cache.h>
+#include <asm/current.h>
+#include <asm/delay.h>
+#include <asm/efi.h>
+#include <asm/io.h>
+#include <asm/irq.h>
+#include <asm/machvec.h>
+#include <asm/page.h>
+#include <asm/pgalloc.h>
+#include <asm/pgtable.h>
+#include <asm/processor.h>
+#include <asm/ptrace.h>
+#include <asm/sal.h>
+#include <asm/system.h>
+#include <asm/unistd.h>
+
+#if SMP_DEBUG
+#define Dprintk(x...)  printk(x)
+#else
+#define Dprintk(x...)
+#endif
+
+
+/*
+ * ITC synchronization related stuff:
+ */
+#define MASTER	0
+#define SLAVE	(SMP_CACHE_BYTES/8)
+
+#define NUM_ROUNDS	64	/* magic value */
+#define NUM_ITERS	5	/* likewise */
+
+static spinlock_t itc_sync_lock = SPIN_LOCK_UNLOCKED;
+static volatile unsigned long go[SLAVE + 1];
+
+#define DEBUG_ITC_SYNC	0
+
+extern void __init calibrate_delay(void);
+extern void start_ap(void);
+
+int cpucount;
+
+/* Setup configured maximum number of CPUs to activate */
+static int max_cpus = -1;
+
+/* Total count of live CPUs */
+int smp_num_cpus = 1;
+
+/* Bitmask of currently online CPUs */
+volatile unsigned long cpu_online_map;
+
+/* which logical CPU number maps to which CPU (physical APIC ID) */
+volatile int ia64_cpu_to_sapicid[NR_CPUS];
+
+static volatile unsigned long cpu_callin_map;
+
+struct smp_boot_data smp_boot_data __initdata;
+
+/* Set when the idlers are all forked */
+volatile int smp_threads_ready;
+
+unsigned long ap_wakeup_vector = -1; /* External Int use to wakeup APs */
+
+char __initdata no_int_routing;
+
+unsigned char smp_int_redirect; /* are INT and IPI redirectable by the chipset? */
+
+/*
+ * Setup routine for controlling SMP activation
+ *
+ * Command-line option of "nosmp" or "maxcpus=0" will disable SMP
+ * activation entirely (the MPS table probe still happens, though).
+ *
+ * Command-line option of "maxcpus=<NUM>", where <NUM> is an integer
+ * greater than 0, limits the maximum number of CPUs activated in
+ * SMP mode to <NUM>.
+ */
+
+static int __init
+nosmp (char *str)
+{
+	max_cpus = 0;
+	return 1;
+}
+
+__setup("nosmp", nosmp);
+
+static int __init
+maxcpus (char *str)
+{
+	get_option(&str, &max_cpus);
+	return 1;
+}
+
+__setup("maxcpus=", maxcpus);
+
+static int __init
+nointroute (char *str)
+{
+	no_int_routing = 1;
+	return 1;
+}
+
+__setup("nointroute", nointroute);
+
+void
+sync_master (void *arg)
+{
+	unsigned long flags, i;
+
+	go[MASTER] = 0;
+
+	local_irq_save(flags);
+	{
+		for (i = 0; i < NUM_ROUNDS*NUM_ITERS; ++i) {
+			while (!go[MASTER]);
+			go[MASTER] = 0;
+			go[SLAVE] = ia64_get_itc();
+		}
+	}
+	local_irq_restore(flags);
+}
+
+/*
+ * Return the number of cycles by which our itc differs from the itc on the master
+ * (time-keeper) CPU.  A positive number indicates our itc is ahead of the master,
+ * negative that it is behind.
+ */
+static inline long
+get_delta (long *rt, long *master)
+{
+	unsigned long best_t0 = 0, best_t1 = ~0UL, best_tm = 0;
+	unsigned long tcenter, t0, t1, tm;
+	long i;
+
+	for (i = 0; i < NUM_ITERS; ++i) {
+		t0 = ia64_get_itc();
+		go[MASTER] = 1;
+		while (!(tm = go[SLAVE]));
+		go[SLAVE] = 0;
+		t1 = ia64_get_itc();
+
+		if (t1 - t0 < best_t1 - best_t0)
+			best_t0 = t0, best_t1 = t1, best_tm = tm;
+	}
+
+	*rt = best_t1 - best_t0;
+	*master = best_tm - best_t0;
+
+	/* average best_t0 and best_t1 without overflow: */
+	tcenter = (best_t0/2 + best_t1/2);
+	if (best_t0 % 2 + best_t1 % 2 == 2)
+		++tcenter;
+	return tcenter - best_tm;
+}
+
+/*
+ * Synchronize ar.itc of the current (slave) CPU with the ar.itc of the MASTER CPU
+ * (normally the time-keeper CPU).  We use a closed loop to eliminate the possibility of
+ * unaccounted-for errors (such as getting a machine check in the middle of a calibration
+ * step).  The basic idea is for the slave to ask the master what itc value it has and to
+ * read its own itc before and after the master responds.  Each iteration gives us three
+ * timestamps:
+ *
+ *	slave		master
+ *
+ *	t0 ---\
+ *             ---\
+ *		   --->
+ *			tm
+ *		   /---
+ *	       /---
+ *	t1 <---
+ *
+ *
+ * The goal is to adjust the slave's ar.itc such that tm falls exactly half-way between t0
+ * and t1.  If we achieve this, the clocks are synchronized provided the interconnect
+ * between the slave and the master is symmetric.  Even if the interconnect were
+ * asymmetric, we would still know that the synchronization error is smaller than the
+ * roundtrip latency (t0 - t1).
+ *
+ * When the interconnect is quiet and symmetric, this lets us synchronize the itc to
+ * within one or two cycles.  However, we can only *guarantee* that the synchronization is
+ * accurate to within a round-trip time, which is typically in the range of several
+ * hundred cycles (e.g., ~500 cycles).  In practice, this means that the itc's are usually
+ * almost perfectly synchronized, but we shouldn't assume that the accuracy is much better
+ * than half a micro second or so.
+ */
+void
+ia64_sync_itc (unsigned int master)
+{
+	long i, delta, adj, adjust_latency = 0, done = 0;
+	unsigned long flags, rt, master_time_stamp, bound;
+#if DEBUG_ITC_SYNC
+	struct {
+		long rt;	/* roundtrip time */
+		long master;	/* master's timestamp */
+		long diff;	/* difference between midpoint and master's timestamp */
+		long lat;	/* estimate of itc adjustment latency */
+	} t[NUM_ROUNDS];
+#endif
+
+	go[MASTER] = 1;
+
+	if (smp_call_function_single(master, sync_master, NULL, 1, 0) < 0) {
+		printk("sync_itc: failed to get attention of CPU %u!\n", master);
+		return;
+	}
+
+	while (go[MASTER]);	/* wait for master to be ready */
+
+	spin_lock_irqsave(&itc_sync_lock, flags);
+	{
+		for (i = 0; i < NUM_ROUNDS; ++i) {
+			delta = get_delta(&rt, &master_time_stamp);
+			if (delta == 0) {
+				done = 1;	/* let's lock on to this... */
+				bound = rt;
+			}
+
+			if (!done) {
+				if (i > 0) {
+					adjust_latency += -delta;
+					adj = -delta + adjust_latency/4;
+				} else
+					adj = -delta;
+
+				ia64_set_itc(ia64_get_itc() + adj);
+			}
+#if DEBUG_ITC_SYNC
+			t[i].rt = rt;
+			t[i].master = master_time_stamp;
+			t[i].diff = delta;
+			t[i].lat = adjust_latency/4;
+#endif
+		}
+	}
+	spin_unlock_irqrestore(&itc_sync_lock, flags);
+
+#if DEBUG_ITC_SYNC
+	for (i = 0; i < NUM_ROUNDS; ++i)
+		printk("rt=%5ld master=%5ld diff=%5ld adjlat=%5ld\n",
+		       t[i].rt, t[i].master, t[i].diff, t[i].lat);
+#endif
+
+	printk("CPU %d: synchronized ITC with CPU %u (last diff %ld cycles, maxerr %lu cycles)\n",
+	       smp_processor_id(), master, delta, rt);
+}
+
+/*
+ * Ideally sets up per-cpu profiling hooks.  Doesn't do much now...
+ */
+static inline void __init
+smp_setup_percpu_timer (void)
+{
+	local_cpu_data->prof_counter = 1;
+	local_cpu_data->prof_multiplier = 1;
+}
+
+/*
+ * Architecture specific routine called by the kernel just before init is
+ * fired off. This allows the BP to have everything in order [we hope].
+ * At the end of this all the APs will hit the system scheduling and off
+ * we go. Each AP will jump through the kernel
+ * init into idle(). At this point the scheduler will one day take over
+ * and give them jobs to do. smp_callin is a standard routine
+ * we use to track CPUs as they power up.
+ */
+
+static volatile atomic_t smp_commenced = ATOMIC_INIT(0);
+
+void __init
+smp_commence (void)
+{
+	/*
+	 * Lets the callins below out of their loop.
+	 */
+	Dprintk("Setting commenced=1, go go go\n");
+
+	wmb();
+	atomic_set(&smp_commenced,1);
+}
+
+
+void __init
+smp_callin (void)
+{
+	int cpuid, phys_id;
+	extern void ia64_init_itm(void);
+
+#ifdef CONFIG_PERFMON
+	extern void perfmon_init_percpu(void);
+#endif
+
+	cpuid = smp_processor_id();
+	phys_id = hard_smp_processor_id();
+
+	if (test_and_set_bit(cpuid, &cpu_online_map)) {
+		printk("huh, phys CPU#0x%x, CPU#0x%x already present??\n", 
+					phys_id, cpuid);
+		BUG();
+	}
+
+	smp_setup_percpu_timer();
+
+	/*
+	 * Synchronize the ITC with the BP
+	 */
+	Dprintk("Going to syncup ITC with BP.\n");
+
+	ia64_sync_itc(0);
+	/*
+	 * Get our bogomips.
+	 */
+	ia64_init_itm();
+#ifdef CONFIG_PERFMON
+	perfmon_init_percpu();
+#endif
+
+	local_irq_enable();
+	calibrate_delay();
+	local_cpu_data->loops_per_jiffy = loops_per_jiffy;
+	/*
+	 * Allow the master to continue.
+	 */
+	set_bit(cpuid, &cpu_callin_map);
+	Dprintk("Stack on CPU %d at about %p\n",cpuid, &cpuid);
+}
+
+
+/*
+ * Activate a secondary processor.  head.S calls this.
+ */
+int __init
+start_secondary (void *unused)
+{
+	extern int cpu_idle (void);
+
+	efi_map_pal_code();
+	cpu_init();
+	smp_callin();
+	Dprintk("CPU %d is set to go. \n", smp_processor_id());
+	while (!atomic_read(&smp_commenced))
+		;
+
+	Dprintk("CPU %d is starting idle. \n", smp_processor_id());
+	return cpu_idle();
+}
+
+static int __init
+fork_by_hand (void)
+{
+	/*
+	 * don't care about the eip and regs settings since
+	 * we'll never reschedule the forked task.
+	 */
+	return do_fork(CLONE_VM|CLONE_PID, 0, 0, 0);
+}
+
+static void __init
+do_boot_cpu (int sapicid)
+{
+	struct task_struct *idle;
+	int timeout, cpu;
+
+	cpu = ++cpucount;
+	/*
+	 * We can't use kernel_thread since we must avoid to
+	 * reschedule the child.
+	 */
+	if (fork_by_hand() < 0)
+		panic("failed fork for CPU %d", cpu);
+
+	/*
+	 * We remove it from the pidhash and the runqueue
+	 * once we got the process:
+	 */
+	idle = init_task.prev_task;
+	if (!idle)
+		panic("No idle process for CPU %d", cpu);
+
+	idle->processor = cpu;
+	ia64_cpu_to_sapicid[cpu] = sapicid;
+	idle->has_cpu = 1; /* we schedule the first task manually */
+
+	del_from_runqueue(idle);
+	unhash_process(idle);
+	init_tasks[cpu] = idle;
+
+	Dprintk("Sending Wakeup Vector to AP 0x%x/0x%x.\n", cpu, sapicid);
+
+	platform_send_ipi(cpu, ap_wakeup_vector, IA64_IPI_DM_INT, 0);
+
+	/*
+	 * Wait 10s total for the AP to start
+	 */
+	Dprintk("Waiting on callin_map ...");
+	for (timeout = 0; timeout < 100000; timeout++) {
+		Dprintk(".");
+		if (test_bit(cpu, &cpu_callin_map))
+			break;  /* It has booted */
+		udelay(100);
+	}
+	Dprintk("\n");
+
+	if (test_bit(cpu, &cpu_callin_map)) {
+		/* number CPUs logically, starting from 1 (BSP is 0) */
+		printk("CPU%d: ", cpu);
+		/*print_cpu_info(&cpu_data[cpu]); */
+		printk("CPU has booted.\n");
+	} else {
+		printk(KERN_ERR "Processor 0x%x/0x%x is stuck.\n", cpu, sapicid);
+		ia64_cpu_to_sapicid[cpu] = -1;
+		cpucount--;
+	}
+}
+
+/*
+ * Cycle through the APs sending Wakeup IPIs to boot each.
+ */
+void __init
+smp_boot_cpus (void)
+{
+	int sapicid, cpu;
+	int boot_cpu_id = hard_smp_processor_id();
+
+	/*
+	 * Initialize the logical to physical CPU number mapping
+	 * and the per-CPU profiling counter/multiplier
+	 */
+
+	for (cpu = 0; cpu < NR_CPUS; cpu++)
+		ia64_cpu_to_sapicid[cpu] = -1;
+	smp_setup_percpu_timer();
+
+	/*
+	* We have the boot CPU online for sure.
+	*/
+	set_bit(0, &cpu_online_map);
+	set_bit(0, &cpu_callin_map);
+
+	local_cpu_data->loops_per_jiffy = loops_per_jiffy;
+	ia64_cpu_to_sapicid[0] = boot_cpu_id;
+
+	printk("Boot processor id 0x%x/0x%x\n", 0, boot_cpu_id);
+
+	global_irq_holder = 0;
+	current->processor = 0;
+	init_idle();
+
+	/*
+	 * If SMP should be disabled, then really disable it!
+	 */
+	if (!max_cpus || (max_cpus < -1)) {
+		printk(KERN_INFO "SMP mode deactivated.\n");
+		cpu_online_map =  1;
+		smp_num_cpus = 1;
+		goto smp_done;
+	}
+	if  (max_cpus != -1)
+		printk (KERN_INFO "Limiting CPUs to %d\n", max_cpus);
+
+	if (smp_boot_data.cpu_count > 1) {
+
+		printk(KERN_INFO "SMP: starting up secondaries.\n");
+
+		for (cpu = 0; cpu < smp_boot_data.cpu_count; cpu++) {
+			/*
+			 * Don't even attempt to start the boot CPU!
+			 */
+			sapicid = smp_boot_data.cpu_phys_id[cpu];
+			if ((sapicid == -1) || (sapicid == hard_smp_processor_id()))
+				continue;
+
+			if ((max_cpus > 0) && (cpucount + 1 >= max_cpus))
+				break;
+
+			do_boot_cpu(sapicid);
+
+			/*
+			 * Make sure we unmap all failed CPUs
+			 */
+			if (ia64_cpu_to_sapicid[cpu] == -1)
+				printk("phys CPU#%d not responding - cannot use it.\n", cpu);
+		}
+
+		smp_num_cpus = cpucount + 1;
+
+		/*
+		 * Allow the user to impress friends.
+		 */
+
+		printk("Before bogomips.\n");
+		if (!cpucount) {
+			printk(KERN_ERR "Error: only one processor found.\n");
+		} else {
+			unsigned long bogosum = 0;
+  			for (cpu = 0; cpu < NR_CPUS; cpu++)
+				if (cpu_online_map & (1<<cpu))
+					bogosum += cpu_data(cpu)->loops_per_jiffy;
+
+			printk(KERN_INFO"Total of %d processors activated (%lu.%02lu BogoMIPS).\n",
+			       cpucount + 1, bogosum/(500000/HZ), (bogosum/(5000/HZ))%100);
+		}
+	}
+  smp_done:
+	;
+}
+
+/*
+ * Assume that CPU's have been discovered by some platform-dependant interface.  For
+ * SoftSDV/Lion, that would be ACPI.
+ *
+ * Setup of the IPI irq handler is done in irq.c:init_IRQ_SMP().
+ */
+void __init
+init_smp_config(void)
+{
+	struct fptr {
+		unsigned long fp;
+		unsigned long gp;
+	} *ap_startup;
+	long sal_ret;
+
+	/* Tell SAL where to drop the AP's.  */
+	ap_startup = (struct fptr *) start_ap;
+	sal_ret = ia64_sal_set_vectors(SAL_VECTOR_OS_BOOT_RENDEZ,
+				       __pa(ap_startup->fp), __pa(ap_startup->gp), 0, 0, 0, 0);
+	if (sal_ret < 0) {
+		printk("SMP: Can't set SAL AP Boot Rendezvous: %s\n     Forcing UP mode\n",
+		       ia64_sal_strerror(sal_ret));
+		max_cpus = 0;
+		smp_num_cpus = 1;
+	}
+}
diff -u --recursive --new-file v2.4.7/linux/arch/ia64/kernel/sys_ia64.c linux/arch/ia64/kernel/sys_ia64.c
--- v2.4.7/linux/arch/ia64/kernel/sys_ia64.c	Fri Apr 13 15:38:51 2001
+++ linux/arch/ia64/kernel/sys_ia64.c	Tue Jul 31 10:30:08 2001
@@ -22,16 +22,18 @@
 #define COLOR_ALIGN(addr)	(((addr) + SHMLBA - 1) & ~(SHMLBA - 1))
 
 unsigned long
-arch_get_unmapped_area (struct file *filp, unsigned long addr, unsigned long len, unsigned long pgoff, unsigned long flags)
+arch_get_unmapped_area (struct file *filp, unsigned long addr, unsigned long len,
+			unsigned long pgoff, unsigned long flags)
 {
 	struct vm_area_struct * vmm;
+	long map_shared = (flags & MAP_SHARED);
 
 	if (len > RGN_MAP_LIMIT)
 		return -ENOMEM;
 	if (!addr)
 		addr = TASK_UNMAPPED_BASE;
 
-	if (flags & MAP_SHARED)
+	if (map_shared)
 		addr = COLOR_ALIGN(addr);
 	else
 		addr = PAGE_ALIGN(addr);
@@ -45,7 +47,7 @@
 		if (!vmm || addr + len <= vmm->vm_start)
 			return addr;
 		addr = vmm->vm_end;
-		if (flags & MAP_SHARED)
+		if (map_shared)
 			addr = COLOR_ALIGN(addr);
 	}
 }
@@ -176,11 +178,22 @@
 	unsigned long roff;
 	struct file *file = 0;
 
+	flags &= ~(MAP_EXECUTABLE | MAP_DENYWRITE);
+	if (!(flags & MAP_ANONYMOUS)) {
+		file = fget(fd);
+		if (!file)
+			return -EBADF;
+
+		if (!file->f_op || !file->f_op->mmap)
+			return -ENODEV;
+	}
+
 	/*
-	 * A zero mmap always succeeds in Linux, independent of
-	 * whether or not the remaining arguments are valid.
+	 * A zero mmap always succeeds in Linux, independent of whether or not the
+	 * remaining arguments are valid.
 	 */
-	if (PAGE_ALIGN(len) == 0)
+	len = PAGE_ALIGN(len);
+	if (len == 0)
 		return addr;
 
 	/* don't permit mappings into unmapped space or the virtual page table of a region: */
@@ -192,13 +205,6 @@
 	if (rgn_index(addr) != rgn_index(addr + len))
 		return -EINVAL;
 
-	flags &= ~(MAP_EXECUTABLE | MAP_DENYWRITE);
-	if (!(flags & MAP_ANONYMOUS)) {
-		file = fget(fd);
-		if (!file)
-			return -EBADF;
-	}
-
 	down_write(&current->mm->mmap_sem);
 	addr = do_mmap_pgoff(file, addr, len, prot, flags, pgoff);
 	up_write(&current->mm->mmap_sem);
@@ -244,13 +250,6 @@
 sys_vm86 (long arg0, long arg1, long arg2, long arg3)
 {
 	printk(KERN_ERR "sys_vm86(%lx, %lx, %lx, %lx)!\n", arg0, arg1, arg2, arg3);
-	return -ENOSYS;
-}
-
-asmlinkage long
-sys_modify_ldt (long arg0, long arg1, long arg2, long arg3)
-{
-	printk(KERN_ERR "sys_modify_ldt(%lx, %lx, %lx, %lx)!\n", arg0, arg1, arg2, arg3);
 	return -ENOSYS;
 }
 
diff -u --recursive --new-file v2.4.7/linux/arch/ia64/kernel/time.c linux/arch/ia64/kernel/time.c
--- v2.4.7/linux/arch/ia64/kernel/time.c	Thu Apr  5 12:51:47 2001
+++ linux/arch/ia64/kernel/time.c	Tue Jul 31 10:30:08 2001
@@ -25,6 +25,7 @@
 
 extern rwlock_t xtime_lock;
 extern unsigned long wall_jiffies;
+extern unsigned long last_time_offset;
 
 #ifdef CONFIG_IA64_DEBUG_IRQ
 
@@ -45,9 +46,8 @@
 		ip -= (unsigned long) &_stext;
 		ip >>= prof_shift;
 		/*
-		 * Don't ignore out-of-bounds IP values silently,
-		 * put them into the last histogram slot, so if
-		 * present, they will show up as a sharp peak.
+		 * Don't ignore out-of-bounds IP values silently, put them into the last
+		 * histogram slot, so if present, they will show up as a sharp peak.
 		 */
 		if (ip > prof_len - 1)
 			ip = prof_len - 1;
@@ -57,34 +57,29 @@
 }
 
 /*
- * Return the number of micro-seconds that elapsed since the last
- * update to jiffy.  The xtime_lock must be at least read-locked when
- * calling this routine.
+ * Return the number of micro-seconds that elapsed since the last update to jiffy.  The
+ * xtime_lock must be at least read-locked when calling this routine.
  */
 static inline unsigned long
 gettimeoffset (void)
 {
-#ifdef CONFIG_SMP
-	/*
-	 * The code below doesn't work for SMP because only CPU 0
-	 * keeps track of the time.
-	 */
-	return 0;
-#else
-	unsigned long now = ia64_get_itc(), last_tick;
 	unsigned long elapsed_cycles, lost = jiffies - wall_jiffies;
+	unsigned long now, last_tick;
+#	define time_keeper_id	0	/* smp_processor_id() of time-keeper */
 
-	last_tick = (local_cpu_data->itm_next - (lost+1)*local_cpu_data->itm_delta);
-# if 1
+	last_tick = (cpu_data(time_keeper_id)->itm_next
+		     - (lost + 1)*cpu_data(time_keeper_id)->itm_delta);
+
+	now = ia64_get_itc();
 	if ((long) (now - last_tick) < 0) {
-		printk("Yikes: now < last_tick (now=0x%lx,last_tick=%lx)!  No can do.\n",
-		       now, last_tick);
-		return 0;
-	}
+# if 1
+		printk("CPU %d: now < last_tick (now=0x%lx,last_tick=0x%lx)!\n",
+		       smp_processor_id(), now, last_tick);
 # endif
+		return last_time_offset;
+	}
 	elapsed_cycles = now - last_tick;
 	return (elapsed_cycles*local_cpu_data->usec_per_cyc) >> IA64_USEC_PER_CYC_SHIFT;
-#endif
 }
 
 void
@@ -93,11 +88,10 @@
 	write_lock_irq(&xtime_lock);
 	{
 		/*
-		 * This is revolting. We need to set "xtime"
-		 * correctly. However, the value in this location is
-		 * the value at the most recent update of wall time.
-		 * Discover what correction gettimeofday would have
-		 * done, and then undo it!
+		 * This is revolting. We need to set "xtime" correctly. However, the value
+		 * in this location is the value at the most recent update of wall time.
+		 * Discover what correction gettimeofday would have done, and then undo
+		 * it!
 		 */
 		tv->tv_usec -= gettimeoffset();
 		tv->tv_usec -= (jiffies - wall_jiffies) * (1000000 / HZ);
@@ -119,12 +113,24 @@
 void
 do_gettimeofday (struct timeval *tv)
 {
-	unsigned long flags, usec, sec;
+	unsigned long flags, usec, sec, old;
 
 	read_lock_irqsave(&xtime_lock, flags);
 	{
 		usec = gettimeoffset();
 
+		/*
+		 * Ensure time never goes backwards, even when ITC on different CPUs are
+		 * not perfectly synchronized.
+		 */
+		do {
+			old = last_time_offset;
+			if (usec <= old) {
+				usec = old;
+				break;
+			}
+		} while (cmpxchg(&last_time_offset, old, usec) != old);
+
 		sec = xtime.tv_sec;
 		usec += xtime.tv_usec;
 	}
@@ -162,6 +168,8 @@
 #ifdef CONFIG_SMP
 		smp_do_timer(regs);
 #endif
+		new_itm += local_cpu_data->itm_delta;
+
 		if (smp_processor_id() == 0) {
 			/*
 			 * Here we are in the timer irq handler. We have irqs locally
@@ -171,11 +179,11 @@
 			 */
 			write_lock(&xtime_lock);
 			do_timer(regs);
+			local_cpu_data->itm_next = new_itm;
 			write_unlock(&xtime_lock);
-		}
+		} else
+			local_cpu_data->itm_next = new_itm;
 
-		new_itm += local_cpu_data->itm_delta;
-		local_cpu_data->itm_next = new_itm;
 		if (time_after(new_itm, ia64_get_itc()))
 			break;
 	}
@@ -228,9 +236,9 @@
 	long status;
 
 	/*
-	 * According to SAL v2.6, we need to use a SAL call to determine the
-	 * platform base frequency and then a PAL call to determine the
-	 * frequency ratio between the ITC and the base frequency.
+	 * According to SAL v2.6, we need to use a SAL call to determine the platform base
+	 * frequency and then a PAL call to determine the frequency ratio between the ITC
+	 * and the base frequency.
 	 */
 	status = ia64_sal_freq_base(SAL_FREQ_BASE_PLATFORM, &platform_base_freq, &drift);
 	if (status != 0) {
@@ -284,6 +292,6 @@
 time_init (void)
 {
 	register_percpu_irq(IA64_TIMER_VECTOR, &timer_irqaction);
-	efi_gettimeofday(&xtime);
+	efi_gettimeofday((struct timeval *) &xtime);
 	ia64_init_itm();
 }
diff -u --recursive --new-file v2.4.7/linux/arch/ia64/kernel/traps.c linux/arch/ia64/kernel/traps.c
--- v2.4.7/linux/arch/ia64/kernel/traps.c	Thu Apr  5 12:51:47 2001
+++ linux/arch/ia64/kernel/traps.c	Tue Jul 31 10:30:08 2001
@@ -215,12 +215,9 @@
 fp_emulate (int fp_fault, void *bundle, long *ipsr, long *fpsr, long *isr, long *pr, long *ifs,
 	    struct pt_regs *regs)
 {
+	struct ia64_fpreg f6_11[6];
 	fp_state_t fp_state;
 	fpswa_ret_t ret;
-#define FPSWA_BUG
-#ifdef FPSWA_BUG
-	struct ia64_fpreg f6_15[10];
-#endif
 
 	if (!fpswa_interface)
 		return -1;
@@ -232,23 +229,12 @@
 	 * kernel, so set those bits in the mask and set the low volatile
 	 * pointer to point to these registers.
 	 */
-#ifndef FPSWA_BUG
-	fp_state.bitmask_low64 = 0x3c0;  /* bit 6..9 */
-	fp_state.fp_state_low_volatile = (fp_state_low_volatile_t *) &regs->f6;
-#else
-	fp_state.bitmask_low64 = 0xffc0;  /* bit6..bit15 */
-	f6_15[0] = regs->f6;
-	f6_15[1] = regs->f7;
-	f6_15[2] = regs->f8;
-	f6_15[3] = regs->f9;
-	__asm__ ("stf.spill %0=f10%P0" : "=m"(f6_15[4]));
-	__asm__ ("stf.spill %0=f11%P0" : "=m"(f6_15[5]));
-	__asm__ ("stf.spill %0=f12%P0" : "=m"(f6_15[6]));
-	__asm__ ("stf.spill %0=f13%P0" : "=m"(f6_15[7]));
-	__asm__ ("stf.spill %0=f14%P0" : "=m"(f6_15[8]));
-	__asm__ ("stf.spill %0=f15%P0" : "=m"(f6_15[9]));
-	fp_state.fp_state_low_volatile = (fp_state_low_volatile_t *) f6_15;
-#endif
+	fp_state.bitmask_low64 = 0xfc0;  /* bit6..bit11 */
+	f6_11[0] = regs->f6; f6_11[1] = regs->f7;
+	f6_11[2] = regs->f8; f6_11[3] = regs->f9;
+	__asm__ ("stf.spill %0=f10%P0" : "=m"(f6_11[4]));
+	__asm__ ("stf.spill %0=f11%P0" : "=m"(f6_11[5]));
+	fp_state.fp_state_low_volatile = (fp_state_low_volatile_t *) f6_11;
 	/*
 	 * unsigned long (*EFI_FPSWA) (
 	 *      unsigned long    trap_type,
@@ -264,18 +250,10 @@
 					(unsigned long *) ipsr, (unsigned long *) fpsr,
 					(unsigned long *) isr, (unsigned long *) pr,
 					(unsigned long *) ifs, &fp_state);
-#ifdef FPSWA_BUG
-	__asm__ ("ldf.fill f10=%0%P0" :: "m"(f6_15[4]));
-	__asm__ ("ldf.fill f11=%0%P0" :: "m"(f6_15[5]));
-	__asm__ ("ldf.fill f12=%0%P0" :: "m"(f6_15[6]));
-	__asm__ ("ldf.fill f13=%0%P0" :: "m"(f6_15[7]));
-	__asm__ ("ldf.fill f14=%0%P0" :: "m"(f6_15[8]));
-	__asm__ ("ldf.fill f15=%0%P0" :: "m"(f6_15[9]));
-	regs->f6 = f6_15[0];
-	regs->f7 = f6_15[1];
-	regs->f8 = f6_15[2];
-	regs->f9 = f6_15[3];
-#endif
+	regs->f6 = f6_11[0]; regs->f7 = f6_11[1];
+	regs->f8 = f6_11[2]; regs->f9 = f6_11[3];
+	__asm__ ("ldf.fill f10=%0%P0" :: "m"(f6_11[4]));
+	__asm__ ("ldf.fill f11=%0%P0" :: "m"(f6_11[5]));
 	return ret.status;
 }
 
@@ -321,7 +299,7 @@
 			}
 			siginfo.si_signo = SIGFPE;
 			siginfo.si_errno = 0;
-			siginfo.si_code = 0;
+			siginfo.si_code = __SI_FAULT;	/* default code */
 			siginfo.si_addr = (void *) (regs->cr_iip + ia64_psr(regs)->ri);
 			if (isr & 0x11) {
 				siginfo.si_code = FPE_FLTINV;
@@ -339,7 +317,7 @@
 			/* raise exception */
 			siginfo.si_signo = SIGFPE;
 			siginfo.si_errno = 0;
-			siginfo.si_code = 0;
+			siginfo.si_code = __SI_FAULT;	/* default code */
 			siginfo.si_addr = (void *) (regs->cr_iip + ia64_psr(regs)->ri);
 			if (isr & 0x880) {
 				siginfo.si_code = FPE_FLTOVF;
@@ -443,14 +421,12 @@
 		sprintf(buf, "General Exception: %s%s", reason[code],
 			(code == 3) ? ((isr & (1UL << 37))
 				       ? " (RSE access)" : " (data access)") : "");
-#ifndef CONFIG_ITANIUM_ASTEP_SPECIFIC
 		if (code == 8) {
 # ifdef CONFIG_IA64_PRINT_HAZARDS
 			printk("%016lx:possible hazard, pr = %016lx\n", regs->cr_iip, regs->pr);
 # endif
 			return;
 		}
-#endif
 		break;
 
 	      case 25: /* Disabled FP-Register */
diff -u --recursive --new-file v2.4.7/linux/arch/ia64/kernel/unaligned.c linux/arch/ia64/kernel/unaligned.c
--- v2.4.7/linux/arch/ia64/kernel/unaligned.c	Thu Apr  5 12:51:47 2001
+++ linux/arch/ia64/kernel/unaligned.c	Tue Jul 31 10:30:08 2001
@@ -325,11 +325,11 @@
 
 	DPRINT("ubs_end=%p bsp=%p addr=%px\n", (void *) ubs_end, (void *) bsp, (void *) addr);
 
-	ia64_poke(current, (unsigned long) ubs_end, (unsigned long) addr, val);
+	ia64_poke(current, sw, (unsigned long) ubs_end, (unsigned long) addr, val);
 
 	rnat_addr = ia64_rse_rnat_addr(addr);
 
-	ia64_peek(current, (unsigned long) ubs_end, (unsigned long) rnat_addr, &rnats);
+	ia64_peek(current, sw, (unsigned long) ubs_end, (unsigned long) rnat_addr, &rnats);
 	DPRINT("rnat @%p = 0x%lx nat=%d old nat=%ld\n",
 	       (void *) rnat_addr, rnats, nat, (rnats >> ia64_rse_slot_num(addr)) & 1);
 
@@ -338,7 +338,7 @@
 		rnats |=  nat_mask;
 	else
 		rnats &= ~nat_mask;
-	ia64_poke(current, (unsigned long) ubs_end, (unsigned long) rnat_addr, rnats);
+	ia64_poke(current, sw, (unsigned long) ubs_end, (unsigned long) rnat_addr, rnats);
 
 	DPRINT("rnat changed to @%p = 0x%lx\n", (void *) rnat_addr, rnats);
 }
@@ -394,7 +394,7 @@
 
 	DPRINT("ubs_end=%p bsp=%p addr=%p\n", (void *) ubs_end, (void *) bsp, (void *) addr);
 
-	ia64_peek(current, (unsigned long) ubs_end, (unsigned long) addr, val);
+	ia64_peek(current, sw, (unsigned long) ubs_end, (unsigned long) addr, val);
 
 	if (nat) {
 		rnat_addr = ia64_rse_rnat_addr(addr);
@@ -402,7 +402,7 @@
 
 		DPRINT("rnat @%p = 0x%lx\n", (void *) rnat_addr, rnats);
 
-		ia64_peek(current, (unsigned long) ubs_end, (unsigned long) rnat_addr, &rnats);
+		ia64_peek(current, sw, (unsigned long) ubs_end, (unsigned long) rnat_addr, &rnats);
 		*nat = (rnats & nat_mask) != 0;
 	}
 }
@@ -1299,7 +1299,12 @@
 			len = sprintf(buf, "%s(%d): unaligned access to 0x%016lx, "
 				      "ip=0x%016lx\n\r", current->comm, current->pid,
 				      ifa, regs->cr_iip + ipsr->ri);
-			tty_write_message(current->tty, buf);
+			/*
+			 * Don't call tty_write_message() if we're in the kernel; we might
+			 * be holding locks...
+			 */
+			if (user_mode(regs))
+				tty_write_message(current->tty, buf);
 			buf[len-1] = '\0';	/* drop '\r' */
 			printk(KERN_WARNING "%s", buf);	/* watch for command names containing %s */
 		}
diff -u --recursive --new-file v2.4.7/linux/arch/ia64/kernel/unwind.c linux/arch/ia64/kernel/unwind.c
--- v2.4.7/linux/arch/ia64/kernel/unwind.c	Thu Apr 12 12:16:35 2001
+++ linux/arch/ia64/kernel/unwind.c	Tue Jul 31 10:30:08 2001
@@ -24,6 +24,7 @@
  *	o if both the unw.lock spinlock and a script's read-write lock must be
  *	  acquired, then the read-write lock must be acquired first.
  */
+#include <linux/bootmem.h>
 #include <linux/kernel.h>
 #include <linux/sched.h>
 #include <linux/slab.h>
@@ -36,6 +37,7 @@
 #include <asm/ptrace_offsets.h>
 #include <asm/rse.h>
 #include <asm/system.h>
+#include <asm/uaccess.h>
 
 #include "entry.h"
 #include "unwind_i.h"
@@ -97,6 +99,10 @@
 	/* unwind table for the kernel: */
 	struct unw_table kernel_table;
 
+	/* unwind table describing the gate page (kernel code that is mapped into user space): */
+	size_t gate_table_size;
+	unsigned long *gate_table;
+
 	/* hash table that maps instruction pointer to script index: */
 	unsigned short hash[UNW_HASH_SIZE];
 
@@ -323,8 +329,13 @@
 		else
 			*nat_addr &= ~nat_mask;
 	} else {
-		*val = *addr;
-		*nat = (*nat_addr & nat_mask) != 0;
+		if ((*nat_addr & nat_mask) == 0) {
+			*val = *addr;
+			*nat = 0;
+		} else {
+			*val = 0;	/* if register is a NaT, *addr may contain kernel data! */
+			*nat = 1;
+		}
 	}
 	return 0;
 }
@@ -1350,10 +1361,10 @@
 	}
 }
 
-static inline struct unw_table_entry *
+static inline const struct unw_table_entry *
 lookup (struct unw_table *table, unsigned long rel_ip)
 {
-	struct unw_table_entry *e = 0;
+	const struct unw_table_entry *e = 0;
 	unsigned long lo, hi, mid;
 
 	/* do a binary search for right entry: */
@@ -1378,7 +1389,7 @@
 build_script (struct unw_frame_info *info)
 {
 	struct unw_reg_state *rs, *next;
-	struct unw_table_entry *e = 0;
+	const struct unw_table_entry *e = 0;
 	struct unw_script *script = 0;
 	unsigned long ip = info->ip;
 	struct unw_state_record sr;
@@ -1836,9 +1847,9 @@
 
 static void
 init_unwind_table (struct unw_table *table, const char *name, unsigned long segment_base,
-		   unsigned long gp, void *table_start, void *table_end)
+		   unsigned long gp, const void *table_start, const void *table_end)
 {
-	struct unw_table_entry *start = table_start, *end = table_end;
+	const struct unw_table_entry *start = table_start, *end = table_end;
 
 	table->name = name;
 	table->segment_base = segment_base;
@@ -1851,9 +1862,9 @@
 
 void *
 unw_add_unwind_table (const char *name, unsigned long segment_base, unsigned long gp,
-		      void *table_start, void *table_end)
+		      const void *table_start, const void *table_end)
 {
-	struct unw_table_entry *start = table_start, *end = table_end;
+	const struct unw_table_entry *start = table_start, *end = table_end;
 	struct unw_table *table;
 	unsigned long flags;
 
@@ -1936,6 +1947,47 @@
 }
 
 void
+unw_create_gate_table (void)
+{
+	extern char __start_gate_section[], __stop_gate_section[];
+	unsigned long *lp, start, end, segbase = unw.kernel_table.segment_base;
+	const struct unw_table_entry *entry, *first;
+	size_t info_size, size;
+	char *info;
+
+	start = (unsigned long) __start_gate_section - segbase;
+	end   = (unsigned long) __stop_gate_section - segbase;
+	size  = 0;
+	first = lookup(&unw.kernel_table, start);
+
+	for (entry = first; entry->start_offset < end; ++entry)
+		size += 3*8 + 8 + 8*UNW_LENGTH(*(u64 *) (segbase + entry->info_offset));
+	size += 8;	/* reserve space for "end of table" marker */
+
+	unw.gate_table = alloc_bootmem(size);
+	if (!unw.gate_table) {
+		unw.gate_table_size = 0;
+		printk("unwind: unable to create unwind data for gate page!\n");
+		return;
+	}
+	unw.gate_table_size = size;
+
+	lp = unw.gate_table;
+	info = (char *) unw.gate_table + size;
+
+	for (entry = first; entry->start_offset < end; ++entry, lp += 3) {
+		info_size = 8 + 8*UNW_LENGTH(*(u64 *) (segbase + entry->info_offset));
+		info -= info_size;
+		memcpy(info, (char *) segbase + entry->info_offset, info_size);
+
+		lp[0] = entry->start_offset - start + GATE_ADDR;	/* start */
+		lp[1] = entry->end_offset - start + GATE_ADDR;		/* end */
+		lp[2] = info - (char *) unw.gate_table;			/* info */
+	}
+	*lp = 0;	/* end-of-table marker */
+}
+
+void
 unw_init (void)
 {
 	extern int ia64_unw_start, ia64_unw_end, __gp;
@@ -1973,4 +2025,35 @@
 
 	init_unwind_table(&unw.kernel_table, "kernel", KERNEL_START, (unsigned long) &__gp,
 			  &ia64_unw_start, &ia64_unw_end);
+}
+
+/*
+ * This system call copies the unwind data into the buffer pointed to by BUF and returns
+ * the size of the unwind data.  If BUF_SIZE is smaller than the size of the unwind data
+ * or if BUF is NULL, nothing is copied, but the system call still returns the size of the
+ * unwind data.
+ *
+ * The first portion of the unwind data contains an unwind table and rest contains the
+ * associated unwind info (in no particular order).  The unwind table consists of a table
+ * of entries of the form:
+ *
+ *	u64 start;	(64-bit address of start of function)
+ *	u64 end;	(64-bit address of start of function)
+ *	u64 info;	(BUF-relative offset to unwind info)
+ *
+ * The end of the unwind table is indicated by an entry with a START address of zero.
+ *
+ * Please see the IA-64 Software Conventions and Runtime Architecture manual for details
+ * on the format of the unwind info.
+ *
+ * ERRORS
+ *	EFAULT	BUF points outside your accessible address space.
+ */
+asmlinkage long
+sys_getunwind (void *buf, size_t buf_size)
+{
+	if (buf && buf_size >= unw.gate_table_size)
+		if (copy_to_user(buf, unw.gate_table, unw.gate_table_size) != 0)
+			return -EFAULT;
+	return unw.gate_table_size;
 }
diff -u --recursive --new-file v2.4.7/linux/arch/ia64/kernel/unwind_i.h linux/arch/ia64/kernel/unwind_i.h
--- v2.4.7/linux/arch/ia64/kernel/unwind_i.h	Mon Oct  9 17:54:56 2000
+++ linux/arch/ia64/kernel/unwind_i.h	Tue Jul 31 10:30:08 2001
@@ -58,7 +58,7 @@
 	unsigned long segment_base;	/* base for offsets in the unwind table entries */
 	unsigned long start;
 	unsigned long end;
-	struct unw_table_entry *array;
+	const struct unw_table_entry *array;
 	unsigned long length;
 };
 
diff -u --recursive --new-file v2.4.7/linux/arch/ia64/lib/Makefile linux/arch/ia64/lib/Makefile
--- v2.4.7/linux/arch/ia64/lib/Makefile	Thu Apr  5 12:51:47 2001
+++ linux/arch/ia64/lib/Makefile	Tue Jul 31 10:30:08 2001
@@ -14,11 +14,7 @@
 	checksum.o clear_page.o csum_partial_copy.o copy_page.o				\
 	copy_user.o clear_user.o strncpy_from_user.o strlen_user.o strnlen_user.o	\
 	flush.o io.o do_csum.o								\
-	swiotlb.o
-
-ifneq ($(CONFIG_ITANIUM_ASTEP_SPECIFIC),y)
-  obj-y += memcpy.o memset.o strlen.o
-endif
+	memcpy.o memset.o strlen.o swiotlb.o
 
 IGNORE_FLAGS_OBJS =	__divsi3.o __udivsi3.o __modsi3.o __umodsi3.o \
 			__divdi3.o __udivdi3.o __moddi3.o __umoddi3.o
diff -u --recursive --new-file v2.4.7/linux/arch/ia64/lib/checksum.c linux/arch/ia64/lib/checksum.c
--- v2.4.7/linux/arch/ia64/lib/checksum.c	Sun Feb  6 18:42:40 2000
+++ linux/arch/ia64/lib/checksum.c	Tue Jul 31 10:30:08 2001
@@ -9,7 +9,7 @@
  * This file contains network checksum routines that are better done
  * in an architecture-specific manner due to speed..
  */
- 
+
 #include <linux/string.h>
 
 #include <asm/byteorder.h>
@@ -55,8 +55,7 @@
 		  ((unsigned long) ntohs(len) << 16) +
 		  ((unsigned long) proto << 8));
 
-	/* Fold down to 32-bits so we don't loose in the typedef-less 
-	   network stack.  */
+	/* Fold down to 32-bits so we don't loose in the typedef-less network stack.  */
 	/* 64 to 33 */
 	result = (result & 0xffffffff) + (result >> 32);
 	/* 33 to 32 */
@@ -64,8 +63,7 @@
 	return result;
 }
 
-extern unsigned long do_csum(const unsigned char *, unsigned int, unsigned int);
-extern unsigned long do_csum_c(const unsigned char *, unsigned int, unsigned int);
+extern unsigned long do_csum (const unsigned char *, long);
 
 /*
  *	This is a version of ip_compute_csum() optimized for IP headers,
@@ -73,7 +71,7 @@
  */
 unsigned short ip_fast_csum(unsigned char * iph, unsigned int ihl)
 {
-	return ~do_csum(iph,ihl*4,0);
+	return ~do_csum(iph, ihl*4);
 }
 
 /*
@@ -90,7 +88,7 @@
  */
 unsigned int csum_partial(const unsigned char * buff, int len, unsigned int sum)
 {
-	unsigned long result = do_csum(buff, len, 0);
+	unsigned long result = do_csum(buff, len);
 
 	/* add in old sum, and carry.. */
 	result += sum;
@@ -106,5 +104,5 @@
  */
 unsigned short ip_compute_csum(unsigned char * buff, int len)
 {
-	return ~do_csum(buff,len, 0);
+	return ~do_csum(buff,len);
 }
diff -u --recursive --new-file v2.4.7/linux/arch/ia64/lib/clear_page.S linux/arch/ia64/lib/clear_page.S
--- v2.4.7/linux/arch/ia64/lib/clear_page.S	Thu Apr  5 12:51:47 2001
+++ linux/arch/ia64/lib/clear_page.S	Tue Jul 31 10:30:08 2001
@@ -1,8 +1,6 @@
 /*
  *
- * Optimized version of the standard clearpage() function
- *
- * Based on comments from ddd. Try not to overflow the write buffer.
+ * Optimized function to clear a page of memory.
  *
  * Inputs:
  *	in0:	address of page
@@ -13,27 +11,41 @@
  * Copyright (C) 1999-2001 Hewlett-Packard Co
  * Copyright (C) 1999 Stephane Eranian <eranian@hpl.hp.com>
  * Copyright (C) 1999-2001 David Mosberger-Tang <davidm@hpl.hp.com>
+ *
+ * 1/06/01 davidm	Tuned for Itanium.
  */
 #include <asm/asmmacro.h>
 #include <asm/page.h>
 
+#define saved_lc	r2
+#define dst0		in0
+#define dst1		r8
+#define dst2		r9
+#define dst3		r10
+#define dst_fetch	r11
+
 GLOBAL_ENTRY(clear_page)
 	.prologue
-	alloc r11=ar.pfs,1,0,0,0
-	.save ar.lc, r16
-	mov r16=ar.lc		// slow
-
-	.body
-
-	mov r17=PAGE_SIZE/32-1	// -1 = repeat/until
+	.regstk 1,0,0,0
+	mov r16 = PAGE_SIZE/64-1	// -1 = repeat/until
 	;;
-	adds r18=16,in0
-	mov ar.lc=r17
+	.save ar.lc, saved_lc
+	mov saved_lc = ar.lc
+	.body
+	mov ar.lc = r16
+	adds dst1 = 16, dst0
+	adds dst2 = 32, dst0
+	adds dst3 = 48, dst0
+	adds dst_fetch = 512, dst0
 	;;
-1:	stf.spill.nta [in0]=f0,32
-	stf.spill.nta [r18]=f0,32
+1:	stf.spill.nta [dst0] = f0, 64
+	stf.spill.nta [dst1] = f0, 64
+	stf.spill.nta [dst2] = f0, 64
+	stf.spill.nta [dst3] = f0, 64
+
+	lfetch [dst_fetch], 64
 	br.cloop.dptk.few 1b
 	;;
-	mov ar.lc=r16		// restore lc
+	mov ar.lc = r2		// restore lc
 	br.ret.sptk.few rp
 END(clear_page)
diff -u --recursive --new-file v2.4.7/linux/arch/ia64/lib/clear_user.S linux/arch/ia64/lib/clear_user.S
--- v2.4.7/linux/arch/ia64/lib/clear_user.S	Thu Apr  5 12:51:47 2001
+++ linux/arch/ia64/lib/clear_user.S	Tue Jul 31 10:30:08 2001
@@ -69,7 +69,7 @@
 (p6)	br.cond.dptk.few long_do_clear
 	;;				// WAR on ar.lc
 	//
-	// worst case 16 cyles, avg 8 cycles
+	// worst case 16 iterations, avg 8 iterations
 	//
 	// We could have played with the predicates to use the extra
 	// M slot for 2 stores/iteration but the cost the initialization
diff -u --recursive --new-file v2.4.7/linux/arch/ia64/lib/copy_page.S linux/arch/ia64/lib/copy_page.S
--- v2.4.7/linux/arch/ia64/lib/copy_page.S	Thu Apr  5 12:51:47 2001
+++ linux/arch/ia64/lib/copy_page.S	Tue Jul 31 10:30:08 2001
@@ -2,8 +2,6 @@
  *
  * Optimized version of the standard copy_page() function
  *
- * Based on comments from ddd. Try not to overflow write buffer.
- *
  * Inputs:
  *	in0:	address of target page
  *	in1:	address of source page
@@ -12,11 +10,14 @@
  *
  * Copyright (C) 1999, 2001 Hewlett-Packard Co
  * Copyright (C) 1999 Stephane Eranian <eranian@hpl.hp.com>
+ * Copyright (C) 2001 David Mosberger <davidm@hpl.hp.com>
+ *
+ * 4/06/01 davidm	Tuned to make it perform well both for cached and uncached copies.
  */
 #include <asm/asmmacro.h>
 #include <asm/page.h>
 
-#define PIPE_DEPTH	6
+#define PIPE_DEPTH	3
 #define EPI		p[PIPE_DEPTH-1]
 
 #define lcount		r16
@@ -27,62 +28,67 @@
 #define src2		r21
 #define tgt1		r22
 #define tgt2		r23
+#define srcf		r24
+#define tgtf		r25
+
+#define Nrot		((8*PIPE_DEPTH+7)&~7)
 
 GLOBAL_ENTRY(copy_page)
 	.prologue
 	.save ar.pfs, saved_pfs
-	alloc saved_pfs=ar.pfs,3,((2*PIPE_DEPTH+7)&~7),0,((2*PIPE_DEPTH+7)&~7)
+	alloc saved_pfs=ar.pfs,3,Nrot-3,0,Nrot
 
-	.rotr t1[PIPE_DEPTH], t2[PIPE_DEPTH]
+	.rotr t1[PIPE_DEPTH], t2[PIPE_DEPTH], t3[PIPE_DEPTH], t4[PIPE_DEPTH], \
+	      t5[PIPE_DEPTH], t6[PIPE_DEPTH], t7[PIPE_DEPTH], t8[PIPE_DEPTH]
 	.rotp p[PIPE_DEPTH]
 
 	.save ar.lc, saved_lc
-	mov saved_lc=ar.lc	// save ar.lc ahead of time
+	mov saved_lc=ar.lc
+	mov ar.ec=PIPE_DEPTH
+
+	mov lcount=PAGE_SIZE/64-1
 	.save pr, saved_pr
-	mov saved_pr=pr		// rotating predicates are preserved
-				// resgisters we must save.
+	mov saved_pr=pr
+	mov pr.rot=1<<16
+
 	.body
 
-	mov src1=in1		// initialize 1st stream source
-	adds src2=8,in1		// initialize 2nd stream source
-	mov lcount=PAGE_SIZE/16-1 // as many 16bytes as there are on a page
-				  // -1 is because br.ctop is repeat/until
-
-	adds tgt2=8,in0		// initialize 2nd stream target
-	mov tgt1=in0		// initialize 1st stream target
-	;;
-	mov pr.rot=1<<16	// pr16=1 & pr[17-63]=0 , 63 not modified
-
-	mov ar.lc=lcount	// set loop counter
-	mov ar.ec=PIPE_DEPTH	// ar.ec must match pipeline depth
-	;;
-
-	// We need to preload the n-1 stages of the pipeline (n=depth).
-	// We do this during the "prolog" of the loop: we execute
-	// n-1 times the "load" bundle. Then both loads & stores are
-	// enabled until we reach the end of the last word of the page
-	// on the load side. Then, we enter the epilog (controlled by ec)
-	// where we just do the stores and no loads n times : drain the pipe
-	// (we exit the loop when ec=1).
-	//
-	// The initialization of the prolog is done via the predicate registers:
-	// the choice of EPI DEPENDS on the depth of the pipeline (n).
-	// When lc > 0 pr63=1 and it is fed back into pr16 and pr16-pr62
-	// are then shifted right at every iteration,
-	// Thus by initializing pr16=1 and the rest to 0 before the loop
-	// we get EPI=1 after n iterations.
-	//
-1:				// engage loop now, let the magic happen...
-(p16)	ld8 t1[0]=[src1],16	// new data on top of pipeline in 1st stream
-(p16)	ld8 t2[0]=[src2],16	// new data on top of pipeline in 2nd stream
-	nop.i 0x0
-(EPI)	st8 [tgt1]=t1[PIPE_DEPTH-1],16	// store top of  1st pipeline
-(EPI)	st8 [tgt2]=t2[PIPE_DEPTH-1],16	// store top of 2nd pipeline
-	br.ctop.dptk.few 1b	// once lc==0, ec-- & p16=0
-				// stores but no loads anymore
+	mov src1=in1
+	adds src2=8,in1
+	;;
+	adds tgt2=8,in0
+	add srcf=512,in1
+	mov ar.lc=lcount
+	mov tgt1=in0
+	add tgtf=512,in0
+	;;
+1:
+(p[0])	ld8 t1[0]=[src1],16
+(EPI)	st8 [tgt1]=t1[PIPE_DEPTH-1],16
+(p[0])	ld8 t2[0]=[src2],16
+(EPI)	st8 [tgt2]=t2[PIPE_DEPTH-1],16
+	;;
+(p[0])	ld8 t3[0]=[src1],16
+(EPI)	st8 [tgt1]=t3[PIPE_DEPTH-1],16
+(p[0])	ld8 t4[0]=[src2],16
+(EPI)	st8 [tgt2]=t4[PIPE_DEPTH-1],16
+	;;
+(p[0])	ld8 t5[0]=[src1],16
+(EPI)	st8 [tgt1]=t5[PIPE_DEPTH-1],16
+(p[0])	ld8 t6[0]=[src2],16
+(EPI)	st8 [tgt2]=t6[PIPE_DEPTH-1],16
+	;;
+(p[0])	ld8 t7[0]=[src1],16
+(EPI)	st8 [tgt1]=t7[PIPE_DEPTH-1],16
+(p[0])	ld8 t8[0]=[src2],16
+(EPI)	st8 [tgt2]=t8[PIPE_DEPTH-1],16
+
+	lfetch [srcf], 64
+	lfetch [tgtf], 64
+	br.ctop.sptk.few 1b
 	;;
 	mov pr=saved_pr,0xffffffffffff0000	// restore predicates
-	mov ar.pfs=saved_pfs	// restore ar.ec
-	mov ar.lc=saved_lc	// restore saved lc
-	br.ret.sptk.few rp	// bye...
+	mov ar.pfs=saved_pfs
+	mov ar.lc=saved_lc
+	br.ret.sptk.few rp
 END(copy_page)
diff -u --recursive --new-file v2.4.7/linux/arch/ia64/lib/copy_user.S linux/arch/ia64/lib/copy_user.S
--- v2.4.7/linux/arch/ia64/lib/copy_user.S	Thu Apr  5 12:51:47 2001
+++ linux/arch/ia64/lib/copy_user.S	Tue Jul 31 10:30:08 2001
@@ -35,9 +35,9 @@
 // Tuneable parameters
 //
 #define COPY_BREAK	16	// we do byte copy below (must be >=16)
-#define PIPE_DEPTH	4	// pipe depth
+#define PIPE_DEPTH	21	// pipe depth
 
-#define EPI		p[PIPE_DEPTH-1] // PASTE(p,16+PIPE_DEPTH-1)
+#define EPI		p[PIPE_DEPTH-1]
 
 //
 // arguments
@@ -148,8 +148,8 @@
 	//
 
 	//
-	// Optimization. If dst1 is 8-byte aligned (not rarely), we don't need
-	// to copy the head to dst1, to start 8-byte copy software pipleline.
+	// Optimization. If dst1 is 8-byte aligned (quite common), we don't need
+	// to copy the head to dst1, to start 8-byte copy software pipeline.
 	// We know src1 is not 8-byte aligned in this case.
 	//
 	cmp.eq p14,p15=r0,dst2
@@ -233,15 +233,23 @@
 #define SWITCH(pred, shift)	cmp.eq pred,p0=shift,rshift
 #define CASE(pred, shift)	\
 	(pred)	br.cond.spnt.few copy_user_bit##shift
-#define BODY(rshift)							\
-copy_user_bit##rshift:							\
-1:									\
-	EX(failure_out,(EPI) st8 [dst1]=tmp,8);				\
-(EPI_1) shrp tmp=val1[PIPE_DEPTH-3],val1[PIPE_DEPTH-2],rshift;		\
-	EX(failure_in2,(p16) ld8 val1[0]=[src1],8);			\
-	br.ctop.dptk.few 1b;						\
-	;;								\
-	br.cond.spnt.few .diff_align_do_tail
+#define BODY(rshift)						\
+copy_user_bit##rshift:						\
+1:								\
+	EX(failure_out,(EPI) st8 [dst1]=tmp,8);			\
+(EPI_1) shrp tmp=val1[PIPE_DEPTH-3],val1[PIPE_DEPTH-2],rshift;	\
+	EX(3f,(p16) ld8 val1[0]=[src1],8);			\
+	br.ctop.dptk.few 1b;					\
+	;;							\
+	br.cond.sptk.few .diff_align_do_tail;			\
+2:								\
+(EPI)	st8 [dst1]=tmp,8;					\
+(EPI_1)	shrp tmp=val1[PIPE_DEPTH-3],val1[PIPE_DEPTH-2],rshift;	\
+3:								\
+(p16)	mov val1[0]=r0;						\
+	br.ctop.dptk.few 2b;					\
+	;;							\
+	br.cond.sptk.few failure_in2
 
 	//
 	// Since the instruction 'shrp' requires a fixed 128-bit value
@@ -581,13 +589,7 @@
 	br.ret.dptk.few rp
 
 failure_in2:
-	sub ret0=endsrc,src1	// number of bytes to zero, i.e. not copied
-	;;
-3:
-(p16)	mov val1[0]=r0
-(EPI)	st8 [dst1]=val1[PIPE_DEPTH-1],8
-	br.ctop.dptk.few 3b
-	;;
+	sub ret0=endsrc,src1
 	cmp.ne p6,p0=dst1,enddst	// Do we need to finish the tail ?
 	sub len=enddst,dst1,1		// precompute len
 (p6)	br.cond.dptk.few failure_in1bis
diff -u --recursive --new-file v2.4.7/linux/arch/ia64/lib/csum_partial_copy.c linux/arch/ia64/lib/csum_partial_copy.c
--- v2.4.7/linux/arch/ia64/lib/csum_partial_copy.c	Thu Apr  5 12:51:47 2001
+++ linux/arch/ia64/lib/csum_partial_copy.c	Tue Jul 31 10:30:08 2001
@@ -101,7 +101,7 @@
  * This is very ugly but temporary. THIS NEEDS SERIOUS ENHANCEMENTS.
  * But it's very tricky to get right even in C.
  */
-extern unsigned long do_csum(const unsigned char *, int);
+extern unsigned long do_csum(const unsigned char *, long);
 
 static unsigned int
 do_csum_partial_copy_from_user (const char *src, char *dst, int len,
diff -u --recursive --new-file v2.4.7/linux/arch/ia64/lib/do_csum.S linux/arch/ia64/lib/do_csum.S
--- v2.4.7/linux/arch/ia64/lib/do_csum.S	Thu Apr  5 12:51:47 2001
+++ linux/arch/ia64/lib/do_csum.S	Tue Jul 31 10:30:08 2001
@@ -11,6 +11,12 @@
  * Copyright (C) 1999, 2001 Hewlett-Packard Co
  * Copyright (C) 1999 Stephane Eranian <eranian@hpl.hp.com>
  *
+ * 01/04/18	Jun Nakajima <jun.nakajima@intel.com>
+ *		Clean up and optimize and the software pipeline, loading two
+ *		back-to-back 8-byte words per loop. Clean up the initialization
+ *		for the loop. Support the cases where load latency = 1 or 2.
+ *		Set CONFIG_IA64_LOAD_LATENCY to 1 or 2 (default).
+ *
  */
 
 #include <asm/asmmacro.h>
@@ -18,51 +24,54 @@
 //
 // Theory of operations:
 //	The goal is to go as quickly as possible to the point where
-//	we can checksum 8 bytes/loop. Before reaching that point we must
+//	we can checksum 16 bytes/loop. Before reaching that point we must
 //	take care of incorrect alignment of first byte.
 //
 //	The code hereafter also takes care of the "tail" part of the buffer
 //	before entering the core loop, if any. The checksum is a sum so it
-//	allows us to commute operations. So we do do the "head" and "tail"
+//	allows us to commute operations. So we do the "head" and "tail"
 //	first to finish at full speed in the body. Once we get the head and
 //	tail values, we feed them into the pipeline, very handy initialization.
 //
 //	Of course we deal with the special case where the whole buffer fits
 //	into one 8 byte word. In this case we have only one entry in the pipeline.
 //
-//	We use a (3+1)-stage pipeline in the loop to account for possible
-//	load latency and also to accomodate for head and tail.
+//	We use a (LOAD_LATENCY+2)-stage pipeline in the loop to account for
+//	possible load latency and also to accomodate for head and tail.
 //
 //	The end of the function deals with folding the checksum from 64bits
 //	down to 16bits taking care of the carry.
 //
 //	This version avoids synchronization in the core loop by also using a
-//	pipeline for the accumulation of the checksum in result[].
+//	pipeline for the accumulation of the checksum in resultx[] (x=1,2).
 //
-//	 p[]
+//	 wordx[] (x=1,2)
 //	|---|
-//     0|   | r32 : new value loaded in pipeline
+//      |   | 0			: new value loaded in pipeline
 //	|---|
-//     1|   | r33 : in transit data
+//      |   | -			: in transit data
 //	|---|
-//     2|   | r34 : current value to add to checksum
+//      |   | LOAD_LATENCY	: current value to add to checksum
 //	|---|
-//     3|   | r35 : previous value added to checksum (previous iteration)
-//      |---|
+//      |   | LOAD_LATENCY+1	: previous value added to checksum
+//      |---|			(previous iteration)
 //
-//	result[]
+//	resultx[] (x=1,2)
 //	|---|
-//     0|   | r36 : new checksum
+//      |   | 0			: initial value
 //	|---|
-//     1|   | r37 : previous value of checksum
+//      |   | LOAD_LATENCY-1	: new checksum
 //	|---|
-//     2|   | r38 : final checksum when out of the loop (after 2 epilogue rots)
+//      |   | LOAD_LATENCY	: previous value of checksum
 //	|---|
+//      |   | LOAD_LATENCY+1	: final checksum when out of the loop
+//      |---|
+//
 //
+//	See RFC1071 "Computing the Internet Checksum" for various techniques for
+//	calculating the Internet checksum.
 //
 // NOT YET DONE:
-//	- Take advantage of the MMI bandwidth to load more than 8byte per loop
-//	  iteration
 //	- use the lfetch instruction to augment the chances of the data being in
 //	  the cache when we need it.
 //	- Maybe another algorithm which would take care of the folding at the
@@ -71,14 +80,12 @@
 //	  to figure out if we could not split the function depending on the
 //	  type of packet or alignment we get. Like the ip_fast_csum() routine
 //	  where we know we have at least 20bytes worth of data to checksum.
-//	- Look at RFCs about checksums to see whether or not we can do better
-//
 //	- Do a better job of handling small packets.
-//
+
 #define saved_pfs	r11
 #define hmask		r16
 #define tmask		r17
-#define first		r18
+#define first1		r18
 #define firstval	r19
 #define firstoff	r20
 #define last		r21
@@ -89,32 +96,47 @@
 #define tmp1		r26
 #define tmp2		r27
 #define tmp3		r28
-#define carry		r29
+#define carry1		r29
+#define carry2		r30
+#define first2		r31
 
 #define buf		in0
 #define len		in1
 
-// unsigned long do_csum(unsigned char *buf,int len)
+#ifndef CONFIG_IA64_LOAD_LATENCY
+#define CONFIG_IA64_LOAD_LATENCY	2
+#endif
+
+#define LOAD_LATENCY	2	// XXX fix me
+
+#if (LOAD_LATENCY != 1) && (LOAD_LATENCY != 2)
+# error "Only 1 or 2 is supported/tested for LOAD_LATENCY."
+#endif
+
+#define PIPE_DEPTH			(LOAD_LATENCY+2)
+#define ELD	p[LOAD_LATENCY]		// end of load
+#define ELD_1	p[LOAD_LATENCY+1]	// and next stage
+
+// unsigned long do_csum(unsigned char *buf,long len)
 
 GLOBAL_ENTRY(do_csum)
 	.prologue
 	.save ar.pfs, saved_pfs
-	alloc saved_pfs=ar.pfs,2,8,0,8
-
-	.rotr p[4], result[3]
+	alloc saved_pfs=ar.pfs,2,16,1,16
+	.rotr word1[4], word2[4],result1[4],result2[4]
+	.rotp p[PIPE_DEPTH]
 	mov ret0=r0		// in case we have zero length
-	cmp4.lt p0,p6=r0,len	// check for zero length or negative (32bit len)
+	cmp.lt p0,p6=r0,len	// check for zero length or negative (32bit len)
 	;;			// avoid WAW on CFM
 	mov tmp3=0x7		// a temporary mask/value
 	add tmp1=buf,len	// last byte's address
 (p6)	br.ret.spnt.few rp	// return if true (hope we can avoid that)
 
-	and firstoff=7,buf	// how many bytes off for first element
-	tbit.nz p10,p0=buf,0	// is buf an odd address ?
+	and firstoff=7,buf	// how many bytes off for first1 element
+	tbit.nz p15,p0=buf,0	// is buf an odd address ?
 	mov hmask=-1		// intialize head mask
 	;;
-
-	andcm first=buf,tmp3	// 8byte aligned down address of first element
+	andcm first1=buf,tmp3	// 8byte aligned down address of first1 element
 	mov tmask=-1		// initialize tail mask
 	adds tmp2=-1,tmp1	// last-1
 	;;
@@ -123,75 +145,125 @@
 	.save pr, saved_pr
 	mov saved_pr=pr		// preserve predicates (rotation)
 	;;
-	sub tmp3=last,first	// tmp3=distance from first to last
-	cmp.eq p8,p9=last,first	// everything fits in one word ?
+	sub tmp3=last,first1	// tmp3=distance from first1 to last
+	cmp.eq p8,p9=last,first1	// everything fits in one word ?
 	sub tmp1=8,lastoff	// complement to lastoff
-
-	ld8 firstval=[first],8	// load,ahead of time, "first" word
+	ld8 firstval=[first1],8	// load,ahead of time, "first1" word
 	shl tmp2=firstoff,3	// number of bits
 	;;
 	and tmp1=7, tmp1	// make sure that if tmp1==8 -> tmp1=0
-
 (p9)	ld8 lastval=[last]	// load,ahead of time, "last" word, if needed
-(p8)	mov lastval=r0		// we don't need lastval if first==last
-	mov result[1]=r0	// initialize result
+(p9)	adds tmp3=-8,tmp3	// effectively loaded
 	;;
-
+(p8)	mov lastval=r0		// we don't need lastval if first1==last
 	shl tmp1=tmp1,3		// number of bits
-	shl hmask=hmask,tmp2	// build head mask, mask off [0,firstoff[
+	shl hmask=hmask,tmp2	// build head mask, mask off [0,first1off[
 	;;
 	shr.u tmask=tmask,tmp1	// build tail mask, mask off ]8,lastoff]
 	.save ar.lc, saved_lc
 	mov saved_lc=ar.lc	// save lc
 	;;
-
 	.body
+#define count tmp3
 
 (p8)	and hmask=hmask,tmask	// apply tail mask to head mask if 1 word only
-(p9)	and p[1]=lastval,tmask	// mask last it as appropriate
-	shr.u tmp3=tmp3,3	// we do 8 bytes per loop
+(p9)	and word2[0]=lastval,tmask	// mask last it as appropriate
+	shr.u count=count,3	// we do 8 bytes per loop (count)
 	;;
-	cmp.lt p6,p7=2,tmp3	// tmp3 > 2 ?
-	and p[2]=firstval,hmask	// and mask it as appropriate
-	add tmp1=-2,tmp3	// -2 = -1 (br.ctop) -1 (last-first)
+	// If count is odd, finish this 8-byte word so that we can
+	// load two back-to-back 8-byte words per loop thereafter.
+	tbit.nz p10,p11=count,0		// if (count is odd)
+	and word1[0]=firstval,hmask	// and mask it as appropriate
+	;;
+(p8)	mov result1[0]=word1[0]
+(p9)	add result1[0]=word1[0],word2[0]
+	;;
+	cmp.ltu p6,p0=result1[0],word1[0]	// check the carry
+	;;
+(p6)	adds result1[0]=1,result1[0]
+(p8)	br.cond.dptk.few do_csum_exit	// if (within an 8-byte word)
+	;;
+(p11)	br.cond.dptk.few do_csum16	// if (count is even)
+	;;
+	// Here count is odd.
+	ld8 word1[1]=[first1],8		// load an 8-byte word
+	cmp.eq p9,p10=1,count		// if (count == 1)
+	adds count=-1,count		// loaded an 8-byte word
+	;;
+	add result1[0]=result1[0],word1[1]
+	;;
+	cmp.ltu p6,p0=result1[0],word1[1]
+	;;
+(p6)	adds result1[0]=1,result1[0]
+	;;
+(p9)	br.cond.sptk.few do_csum_exit	// if (count == 1) exit
+	// Fall through to caluculate the checksum, feeding result1[0] as
+	// the initial value in result1[0].
 	;;
-	// XXX Fixme: not very nice initialization here
-	//
-	// Setup loop control registers:
 	//
-	// tmp3=0 (1 word)   : lc=0, ec=2, p16=F
-	// tmp3=1 (2 words)  : lc=0, ec=3, p16=F
-	// tmp3=2 (3 words)  : lc=0, ec=4, p16=T
-	// tmp3>2 (4 or more): lc=tmp3-2, ec=4, p16=T
+	// Calculate the checksum loading two 8-byte words per loop.
 	//
-	cmp.eq p8,p9=r0,tmp3	// tmp3 == 0 ?
-(p6)	mov ar.lc=tmp1
-(p7)	mov ar.lc=0
-	;;
-	cmp.lt p6,p7=1,tmp3	// tmp3 > 1 ?
-(p8)	mov ar.ec=2		// we need the extra rotation on result[]
-(p9)	mov ar.ec=3		// hard not to set it twice sometimes
-	;;
-	mov carry=r0			// initialize carry
-(p6)	mov ar.ec=4
-(p6)	mov pr.rot=0xffffffffffff0000	// p16=T, p18=T
-
-	cmp.ne p8,p0=r0,r0		// p8 is false
-	mov p[3]=r0			// make sure first compare fails
-(p7)	mov pr.rot=0xfffffffffffe0000	// p16=F, p18=T
+do_csum16:
+	mov saved_lc=ar.lc
+	shr.u count=count,1	// we do 16 bytes per loop
+	;;
+	cmp.eq p9,p10=r0,count	// if (count == 0)
+	brp.loop.imp 1f,2f
+	;;
+	adds count=-1,count
+	mov ar.ec=PIPE_DEPTH
+	;;
+	mov ar.lc=count	// set lc
+	;;
+	// result1[0] must be initialized in advance.
+	mov result2[0]=r0
 	;;
+	mov pr.rot=1<<16
+	;;
+	mov carry1=r0
+	mov carry2=r0
+	;;
+	add first2=8,first1
+	;;
+(p9)	br.cond.sptk.few do_csum_exit
+	;;
+	nop.m	0
+	nop.i	0
+	;;
+	.align 32
 1:
-(p16)	ld8 p[0]=[first],8		// load next
-(p8)	adds carry=1,carry		// add carry on prev_prev_value
-(p18)	add result[0]=result[1],p[2]	// new_res = prev_res + cur_val
-	cmp.ltu p8,p0=result[1],p[3]	// p8= prev_result < prev_val
-	br.ctop.dptk.few 1b		// loop until lc--==0
-	;;				// RAW on carry when loop exits
- (p8)	adds carry=1,carry;;		// correct for carry on prev_value
-	add result[2]=carry,result[2];;	// add carry to final result
-	cmp.ltu p6,p7=result[2], carry	// check for new carry
+(ELD_1)	cmp.ltu p31,p0=result1[LOAD_LATENCY],word1[LOAD_LATENCY+1]
+(p32)	adds carry1=1,carry1
+(ELD_1)	cmp.ltu p47,p0=result2[LOAD_LATENCY],word2[LOAD_LATENCY+1]
+(p48)	adds carry2=1,carry2
+(ELD)	add result1[LOAD_LATENCY-1]=result1[LOAD_LATENCY],word1[LOAD_LATENCY]
+(ELD)	add result2[LOAD_LATENCY-1]=result2[LOAD_LATENCY],word2[LOAD_LATENCY]
+2:
+(p16)	ld8 word1[0]=[first1],16
+(p16)	ld8 word2[0]=[first2],16
+	br.ctop.sptk.few 1b
+	;;
+	// Since len is a 32-bit value, carry cannot be larger than
+	// a 64-bit value.
+(p32)	adds carry1=1,carry1	// since we miss the last one
+(p48)	adds carry2=1,carry2
+	;;
+	add result1[LOAD_LATENCY+1]=result1[LOAD_LATENCY+1],carry1
+	add result2[LOAD_LATENCY+1]=result2[LOAD_LATENCY+1],carry2
+	;;
+	cmp.ltu p6,p0=result1[LOAD_LATENCY+1],carry1
+	cmp.ltu p7,p0=result2[LOAD_LATENCY+1],carry2
+	;;
+(p6)	adds result1[LOAD_LATENCY+1]=1,result1[LOAD_LATENCY+1]
+(p7)	adds result2[LOAD_LATENCY+1]=1,result2[LOAD_LATENCY+1]
 	;;
-(p6)	adds result[2]=1,result[1]	// correct if required
+	add result1[0]=result1[LOAD_LATENCY+1],result2[LOAD_LATENCY+1]
+	;;
+	cmp.ltu p6,p0=result1[0],result2[LOAD_LATENCY+1]
+	;;
+(p6)	adds result1[0]=1,result1[0]
+	;;
+do_csum_exit:
 	movl tmp3=0xffffffff
 	;;
 	// XXX Fixme
@@ -199,33 +271,66 @@
 	// now fold 64 into 16 bits taking care of carry
 	// that's not very good because it has lots of sequentiality
 	//
-	and tmp1=result[2],tmp3
-	shr.u tmp2=result[2],32
+	and tmp1=result1[0],tmp3
+	shr.u tmp2=result1[0],32
 	;;
-	add result[2]=tmp1,tmp2
+	add result1[0]=tmp1,tmp2
 	shr.u tmp3=tmp3,16
 	;;
-	and tmp1=result[2],tmp3
-	shr.u tmp2=result[2],16
+	and tmp1=result1[0],tmp3
+	shr.u tmp2=result1[0],16
 	;;
-	add result[2]=tmp1,tmp2
+	add result1[0]=tmp1,tmp2
 	;;
-	and tmp1=result[2],tmp3
-	shr.u tmp2=result[2],16
+	and tmp1=result1[0],tmp3
+	shr.u tmp2=result1[0],16
 	;;
-	add result[2]=tmp1,tmp2
+	add result1[0]=tmp1,tmp2
 	;;
-	and tmp1=result[2],tmp3
-	shr.u tmp2=result[2],16
+	and tmp1=result1[0],tmp3
+	shr.u tmp2=result1[0],16
 	;;
 	add ret0=tmp1,tmp2
 	mov pr=saved_pr,0xffffffffffff0000
 	;;
 	// if buf was odd then swap bytes
 	mov ar.pfs=saved_pfs		// restore ar.ec
-(p10)	mux1 ret0=ret0,@rev		// reverse word
+(p15)	mux1 ret0=ret0,@rev		// reverse word
 	;;
 	mov ar.lc=saved_lc
-(p10)	shr.u ret0=ret0,64-16	// + shift back to position = swap bytes
+(p15)	shr.u ret0=ret0,64-16	// + shift back to position = swap bytes
 	br.ret.sptk.few rp
+
+//	I (Jun Nakajima) wrote an equivalent code (see below), but it was
+//	not much better than the original. So keep the original there so that
+//	someone else can challenge.
+//
+//	shr.u word1[0]=result1[0],32
+//	zxt4 result1[0]=result1[0]
+//	;;
+//	add result1[0]=result1[0],word1[0]
+//	;;
+//	zxt2 result2[0]=result1[0]
+//	extr.u word1[0]=result1[0],16,16
+//	shr.u carry1=result1[0],32
+//	;;
+//	add result2[0]=result2[0],word1[0]
+//	;;
+//	add result2[0]=result2[0],carry1
+//	;;
+//	extr.u ret0=result2[0],16,16
+//	;;
+//	add ret0=ret0,result2[0]
+//	;;
+//	zxt2 ret0=ret0
+//	mov ar.pfs=saved_pfs		 // restore ar.ec
+//	mov pr=saved_pr,0xffffffffffff0000
+//	;;
+//	// if buf was odd then swap bytes
+//	mov ar.lc=saved_lc
+//(p15)	mux1 ret0=ret0,@rev		// reverse word
+//	;;
+//(p15)	shr.u ret0=ret0,64-16	// + shift back to position = swap bytes
+//	br.ret.sptk.few rp
+
 END(do_csum)
diff -u --recursive --new-file v2.4.7/linux/arch/ia64/lib/swiotlb.c linux/arch/ia64/lib/swiotlb.c
--- v2.4.7/linux/arch/ia64/lib/swiotlb.c	Thu Apr  5 12:51:47 2001
+++ linux/arch/ia64/lib/swiotlb.c	Tue Jul 31 10:30:08 2001
@@ -263,7 +263,7 @@
 
 	memset(ret, 0, size);
 	pci_addr = virt_to_phys(ret);
-	if ((pci_addr & ~hwdev->dma_mask) != 0)
+	if (hwdev && (pci_addr & ~hwdev->dma_mask) != 0)
 		panic("swiotlb_alloc_consistent: allocated memory is out of range for PCI device");
 	*dma_handle = pci_addr;
 	return ret;
diff -u --recursive --new-file v2.4.7/linux/arch/ia64/mm/extable.c linux/arch/ia64/mm/extable.c
--- v2.4.7/linux/arch/ia64/mm/extable.c	Thu Apr  5 12:51:47 2001
+++ linux/arch/ia64/mm/extable.c	Tue Jul 31 10:30:08 2001
@@ -6,8 +6,9 @@
  */
 
 #include <linux/config.h>
-#include <linux/module.h>
+
 #include <asm/uaccess.h>
+#include <asm/module.h>
 
 extern const struct exception_table_entry __start___ex_table[];
 extern const struct exception_table_entry __stop___ex_table[];
@@ -15,35 +16,25 @@
 static inline const struct exception_table_entry *
 search_one_table (const struct exception_table_entry *first,
 		  const struct exception_table_entry *last,
-		  signed long value)
+		  unsigned long ip, unsigned long gp)
 {
-	/* Abort early if the search value is out of range.  */
-	if (value != (signed int)value)
-		return 0;
-
         while (first <= last) {
 		const struct exception_table_entry *mid;
 		long diff;
-		/*
-		 * We know that first and last are both kernel virtual
-		 * pointers (region 7) so first+last will cause an
-		 * overflow.  We fix that by calling __va() on the
-		 * result, which will ensure that the top two bits get
-		 * set again.
-		 */
-		mid = (void *) __va((((__u64) first + (__u64) last)/2/sizeof(*mid))*sizeof(*mid));
-		diff = mid->addr - value;
+
+		mid = &first[(last - first)/2];
+		diff = (mid->addr + gp) - ip;
                 if (diff == 0)
                         return mid;
                 else if (diff < 0)
-                        first = mid+1;
+                        first = mid + 1;
                 else
-                        last = mid-1;
+                        last = mid - 1;
         }
         return 0;
 }
 
-#ifndef CONFIG_MODULE
+#ifndef CONFIG_MODULES
 register unsigned long main_gp __asm__("gp");
 #endif
 
@@ -53,23 +44,25 @@
 	const struct exception_table_entry *entry;
 	struct exception_fixup fix = { 0 };
 
-#ifndef CONFIG_MODULE
+#ifndef CONFIG_MODULES
 	/* There is only the kernel to search.  */
-	entry = search_one_table(__start___ex_table, __stop___ex_table - 1, addr - main_gp);
+	entry = search_one_table(__start___ex_table, __stop___ex_table - 1, addr, main_gp);
 	if (entry)
 		fix.cont = entry->cont + main_gp;
 	return fix;
 #else
-	struct exception_table_entry *ret;
-	/* The kernel is the last "module" -- no need to treat it special. */
+	struct archdata *archdata;
 	struct module *mp;
 
+	/* The kernel is the last "module" -- no need to treat it special. */
 	for (mp = module_list; mp ; mp = mp->next) {
 		if (!mp->ex_table_start)
 			continue;
-		entry = search_one_table(mp->ex_table_start, mp->ex_table_end - 1, addr - mp->gp);
+		archdata = (struct archdata *) mp->archdata_start;
+		entry = search_one_table(mp->ex_table_start, mp->ex_table_end - 1,
+					 addr, (unsigned long) archdata->gp);
 		if (entry) {
-			fix.cont = entry->cont + mp->gp;
+			fix.cont = entry->cont + (unsigned long) archdata->gp;
 			return fix;
 		}
 	}
diff -u --recursive --new-file v2.4.7/linux/arch/ia64/mm/init.c linux/arch/ia64/mm/init.c
--- v2.4.7/linux/arch/ia64/mm/init.c	Thu Apr  5 12:51:47 2001
+++ linux/arch/ia64/mm/init.c	Tue Jul 31 10:30:08 2001
@@ -42,7 +42,7 @@
 	if (pgtable_cache_size > high) {
 		do {
 			if (pgd_quicklist)
-				free_page((unsigned long)pgd_alloc_one_fast()), ++freed;
+				free_page((unsigned long)pgd_alloc_one_fast(0)), ++freed;
 			if (pmd_quicklist)
 				free_page((unsigned long)pmd_alloc_one_fast(0, 0)), ++freed;
 			if (pte_quicklist)
@@ -111,7 +111,7 @@
 	 *
 	 * To avoid freeing/using the wrong page (kernel sized) we:
 	 *	- align up the beginning of initrd
-	 *	- keep the end untouched
+	 *	- align down the end of initrd
 	 *
 	 *  |             |
 	 *  |=============| a000
@@ -135,11 +135,14 @@
 	 * initrd_start and keep initrd_end as is.
 	 */
 	start = PAGE_ALIGN(start);
+	end = end & PAGE_MASK;
 
 	if (start < end)
 		printk ("Freeing initrd memory: %ldkB freed\n", (end - start) >> 10);
 
 	for (; start < end; start += PAGE_SIZE) {
+		if (!VALID_PAGE(virt_to_page(start)))
+			continue;
 		clear_bit(PG_reserved, &virt_to_page(start)->flags);
 		set_page_count(virt_to_page(start), 1);
 		free_page(start);
@@ -225,7 +228,7 @@
 }
 
 void __init
-ia64_mmu_init (void)
+ia64_mmu_init (void *my_cpu_data)
 {
 	unsigned long flags, rid, pta, impl_va_bits;
 	extern void __init tlb_init (void);
@@ -242,7 +245,7 @@
 	ia64_clear_ic(flags);
 
 	rid = ia64_rid(IA64_REGION_ID_KERNEL, __IA64_UNCACHED_OFFSET);
-	ia64_set_rr(__IA64_UNCACHED_OFFSET, (rid << 8) | (_PAGE_SIZE_64M << 2));
+	ia64_set_rr(__IA64_UNCACHED_OFFSET, (rid << 8) | (KERNEL_PG_SHIFT << 2));
 
 	rid = ia64_rid(IA64_REGION_ID_KERNEL, VMALLOC_START);
 	ia64_set_rr(VMALLOC_START, (rid << 8) | (PAGE_SHIFT << 2) | 1);
@@ -251,8 +254,7 @@
 	ia64_srlz_d();
 
 	ia64_itr(0x2, IA64_TR_PERCPU_DATA, PERCPU_ADDR,
-		 pte_val(mk_pte_phys(__pa(&cpu_data[smp_processor_id()]), PAGE_KERNEL)),
-		 PAGE_SHIFT);
+		 pte_val(mk_pte_phys(__pa(my_cpu_data), PAGE_KERNEL)), PAGE_SHIFT);
 
 	__restore_flags(flags);
 	ia64_srlz_i();
@@ -354,6 +356,7 @@
 {
 	extern char __start_gate_section[];
 	long reserved_pages, codesize, datasize, initsize;
+	unsigned long num_pgt_pages;
 
 #ifdef CONFIG_PCI
 	/*
@@ -386,6 +389,19 @@
 	       (unsigned long) nr_free_pages() << (PAGE_SHIFT - 10),
 	       max_mapnr << (PAGE_SHIFT - 10), codesize >> 10, reserved_pages << (PAGE_SHIFT - 10),
 	       datasize >> 10, initsize >> 10);
+
+	/*
+	 * Allow for enough (cached) page table pages so that we can map the entire memory
+	 * at least once.  Each task also needs a couple of page tables pages, so add in a
+	 * fudge factor for that (don't use "threads-max" here; that would be wrong!).
+	 * Don't allow the cache to be more than 10% of total memory, though.
+	 */
+#	define NUM_TASKS	500	/* typical number of tasks */
+	num_pgt_pages = nr_free_pages() / PTRS_PER_PGD + NUM_TASKS;
+	if (num_pgt_pages > nr_free_pages() / 10)
+		num_pgt_pages = nr_free_pages() / 10;
+	if (num_pgt_pages > pgt_cache_water[1])
+		pgt_cache_water[1] = num_pgt_pages;
 
 	/* install the gate page in the global page table: */
 	put_gate_page(virt_to_page(__start_gate_section), GATE_ADDR);
diff -u --recursive --new-file v2.4.7/linux/arch/ia64/mm/tlb.c linux/arch/ia64/mm/tlb.c
--- v2.4.7/linux/arch/ia64/mm/tlb.c	Thu Apr  5 12:51:47 2001
+++ linux/arch/ia64/mm/tlb.c	Tue Jul 31 10:30:08 2001
@@ -97,7 +97,7 @@
 	/*
 	 * Wait for other CPUs to finish purging entries.
 	 */
-#if defined(CONFIG_ITANIUM_ASTEP_SPECIFIC) || defined(CONFIG_ITANIUM_BSTEP_SPECIFIC)
+#if defined(CONFIG_ITANIUM_BSTEP_SPECIFIC)
 	{
 		extern void smp_resend_flush_tlb (void);
 		unsigned long start = ia64_get_itc();
diff -u --recursive --new-file v2.4.7/linux/arch/ia64/sn/fprom/fw-emu.c linux/arch/ia64/sn/fprom/fw-emu.c
--- v2.4.7/linux/arch/ia64/sn/fprom/fw-emu.c	Thu Apr 12 12:16:35 2001
+++ linux/arch/ia64/sn/fprom/fw-emu.c	Tue Jul 31 10:30:09 2001
@@ -8,7 +8,6 @@
  * Copyright (C) 2000 Silicon Graphics, Inc.
  * Copyright (C) 2000 by Jack Steiner (steiner@sgi.com)
  */
-
 #include <asm/efi.h>
 #include <asm/pal.h>
 #include <asm/sal.h>
diff -u --recursive --new-file v2.4.7/linux/arch/ia64/sn/io/ml_SN_intr.c linux/arch/ia64/sn/io/ml_SN_intr.c
--- v2.4.7/linux/arch/ia64/sn/io/ml_SN_intr.c	Thu Apr 12 12:16:35 2001
+++ linux/arch/ia64/sn/io/ml_SN_intr.c	Tue Jul 31 10:30:09 2001
@@ -36,7 +36,6 @@
 #include <asm/sn/pci/pcibr_private.h>
 #include <asm/sn/intr.h>
 
-
 #if DEBUG_INTR_TSTAMP_DEBUG
 #include <sys/debug.h>
 #include <sys/idbg.h>
diff -u --recursive --new-file v2.4.7/linux/arch/ia64/tools/print_offsets.c linux/arch/ia64/tools/print_offsets.c
--- v2.4.7/linux/arch/ia64/tools/print_offsets.c	Thu Apr  5 12:51:47 2001
+++ linux/arch/ia64/tools/print_offsets.c	Tue Jul 31 10:30:09 2001
@@ -21,6 +21,8 @@
 #include <asm-ia64/siginfo.h>
 #include <asm-ia64/sigcontext.h>
 
+#include "../kernel/sigframe.h"
+
 #ifdef offsetof
 # undef offsetof
 #endif
@@ -46,6 +48,7 @@
     { "IA64_SWITCH_STACK_SIZE",		sizeof (struct switch_stack) },
     { "IA64_SIGINFO_SIZE",		sizeof (struct siginfo) },
     { "IA64_CPU_SIZE",			sizeof (struct cpuinfo_ia64) },
+    { "SIGFRAME_SIZE",			sizeof (struct sigframe) },
     { "UNW_FRAME_INFO_SIZE",		sizeof (struct unw_frame_info) },
     { "", 0 },			/* spacer */
     { "IA64_TASK_PTRACE_OFFSET",	offsetof (struct task_struct, ptrace) },
@@ -153,16 +156,25 @@
     { "IA64_SWITCH_STACK_AR_BSPSTORE_OFFSET",	offsetof (struct switch_stack, ar_bspstore) },
     { "IA64_SWITCH_STACK_PR_OFFSET",	offsetof (struct switch_stack, pr) },
     { "IA64_SIGCONTEXT_AR_BSP_OFFSET",	offsetof (struct sigcontext, sc_ar_bsp) },
+    { "IA64_SIGCONTEXT_AR_FPSR_OFFSET", offsetof (struct sigcontext, sc_ar_fpsr) },
     { "IA64_SIGCONTEXT_AR_RNAT_OFFSET",	offsetof (struct sigcontext, sc_ar_rnat) },
-    { "IA64_SIGCONTEXT_FLAGS_OFFSET",	offsetof (struct sigcontext, sc_flags) },
+    { "IA64_SIGCONTEXT_AR_UNAT_OFFSET", offsetof (struct sigcontext, sc_ar_unat) },
+    { "IA64_SIGCONTEXT_B0_OFFSET",	offsetof (struct sigcontext, sc_br[0]) },
     { "IA64_SIGCONTEXT_CFM_OFFSET",	offsetof (struct sigcontext, sc_cfm) },
+    { "IA64_SIGCONTEXT_FLAGS_OFFSET",	offsetof (struct sigcontext, sc_flags) },
     { "IA64_SIGCONTEXT_FR6_OFFSET",	offsetof (struct sigcontext, sc_fr[6]) },
+    { "IA64_SIGCONTEXT_PR_OFFSET",	offsetof (struct sigcontext, sc_pr) },
+    { "IA64_SIGCONTEXT_R12_OFFSET",	offsetof (struct sigcontext, sc_gr[12]) },
+    { "IA64_SIGFRAME_ARG0_OFFSET",		offsetof (struct sigframe, arg0) },
+    { "IA64_SIGFRAME_ARG1_OFFSET",		offsetof (struct sigframe, arg1) },
+    { "IA64_SIGFRAME_ARG2_OFFSET",		offsetof (struct sigframe, arg2) },
+    { "IA64_SIGFRAME_RBS_BASE_OFFSET",		offsetof (struct sigframe, rbs_base) },
+    { "IA64_SIGFRAME_HANDLER_OFFSET",		offsetof (struct sigframe, handler) },
+    { "IA64_SIGFRAME_SIGCONTEXT_OFFSET",	offsetof (struct sigframe, sc) },
     { "IA64_CLONE_VFORK",		CLONE_VFORK },
     { "IA64_CLONE_VM",			CLONE_VM },
     { "IA64_CPU_IRQ_COUNT_OFFSET",	offsetof (struct cpuinfo_ia64, irq_stat.f.irq_count) },
     { "IA64_CPU_BH_COUNT_OFFSET",	offsetof (struct cpuinfo_ia64, irq_stat.f.bh_count) },
-    { "IA64_CPU_SOFTIRQ_ACTIVE_OFFSET",		offsetof (struct cpuinfo_ia64, softirq.active) },
-    { "IA64_CPU_SOFTIRQ_MASK_OFFSET",		offsetof (struct cpuinfo_ia64, softirq.mask) },
     { "IA64_CPU_PHYS_STACKED_SIZE_P8_OFFSET",	offsetof (struct cpuinfo_ia64, phys_stacked_size_p8) },
 };
 
diff -u --recursive --new-file v2.4.7/linux/arch/ia64/vmlinux.lds.S linux/arch/ia64/vmlinux.lds.S
--- v2.4.7/linux/arch/ia64/vmlinux.lds.S	Tue Jul  3 17:08:18 2001
+++ linux/arch/ia64/vmlinux.lds.S	Tue Jul 31 10:30:09 2001
@@ -25,7 +25,7 @@
   .text : AT(ADDR(.text) - PAGE_OFFSET)
     {
 	*(.text.ivt)
-	/* these are not really text pages, but the zero page needs to be in a fixed location: */
+	/* these are not really text pages, but they need to be page aligned: */
 	*(__special_page_section)
 	__start_gate_section = .;
 	*(.text.gate)
@@ -74,9 +74,9 @@
   __stop___kallsyms = .;
 
   /* Unwind info & table: */
+  . = ALIGN(8);
   .IA_64.unwind_info : AT(ADDR(.IA_64.unwind_info) - PAGE_OFFSET)
 	{ *(.IA_64.unwind_info*) }
-  . = ALIGN(8);
   ia64_unw_start = .;
   .IA_64.unwind : AT(ADDR(.IA_64.unwind) - PAGE_OFFSET)
 	{ *(.IA_64.unwind*) }
diff -u --recursive --new-file v2.4.7/linux/arch/ppc/kernel/misc.S linux/arch/ppc/kernel/misc.S
--- v2.4.7/linux/arch/ppc/kernel/misc.S	Wed Jul 25 17:10:18 2001
+++ linux/arch/ppc/kernel/misc.S	Wed Jul 25 14:12:01 2001
@@ -813,7 +813,7 @@
 _GLOBAL(_set_HID0)
 	sync
 	mtspr	HID0, r3
-	SYNC		/* Handle erratas in some cases */
+	SYNC		/* Handle errata in some cases */
 	blr
 
 _GLOBAL(_get_ICTC)
diff -u --recursive --new-file v2.4.7/linux/arch/s390/Makefile linux/arch/s390/Makefile
--- v2.4.7/linux/arch/s390/Makefile	Wed Apr 11 19:02:27 2001
+++ linux/arch/s390/Makefile	Wed Jul 25 14:12:01 2001
@@ -17,7 +17,11 @@
 CPP=$(CC) -E
 OBJCOPY=$(CROSS_COMPILE)objcopy -O binary -R .note -R .comment -S
 LDFLAGS=-e start
+ifeq ($(CONFIG_SHARED_KERNEL),y)
+LINKFLAGS =-T $(TOPDIR)/arch/s390/vmlinux-shared.lds $(LDFLAGS)
+else
 LINKFLAGS =-T $(TOPDIR)/arch/s390/vmlinux.lds $(LDFLAGS)
+endif
 
 CFLAGS_PIPE := -pipe
 CFLAGS_NSR  := -fno-strength-reduce
@@ -27,8 +31,8 @@
 
 SUBDIRS := $(SUBDIRS) arch/s390/mm arch/s390/kernel arch/s390/lib \
            drivers/s390 arch/s390/math-emu
-CORE_FILES := arch/s390/mm/mm.o arch/s390/kernel/kernel.o $(CORE_FILES) \
-           drivers/s390/io.o
+CORE_FILES := arch/s390/mm/mm.o arch/s390/kernel/kernel.o $(CORE_FILES)
+DRIVERS := $(DRIVERS) drivers/s390/io.o
 LIBS := $(TOPDIR)/arch/s390/lib/lib.a $(LIBS) $(TOPDIR)/arch/s390/lib/lib.a
 
 ifeq ($(CONFIG_MATHEMU),y)
diff -u --recursive --new-file v2.4.7/linux/arch/s390/boot/Makefile linux/arch/s390/boot/Makefile
--- v2.4.7/linux/arch/s390/boot/Makefile	Wed Apr 11 19:02:27 2001
+++ linux/arch/s390/boot/Makefile	Wed Jul 25 14:12:01 2001
@@ -1,5 +1,5 @@
 #
-# Makefile for the linux s390-specific parts of the memory manager.
+# arch/s390/boot/Makefile
 #
 # Note! Dependencies are done automagically by 'make dep', which also
 # removes any old dependencies. DON'T put your own dependencies here
diff -u --recursive --new-file v2.4.7/linux/arch/s390/config.in linux/arch/s390/config.in
--- v2.4.7/linux/arch/s390/config.in	Tue Apr 17 17:19:25 2001
+++ linux/arch/s390/config.in	Wed Jul 25 14:12:01 2001
@@ -50,6 +50,8 @@
 tristate 'Kernel support for ELF binaries' CONFIG_BINFMT_ELF
 tristate 'Kernel support for MISC binaries' CONFIG_BINFMT_MISC
 bool 'Show crashed user process info' CONFIG_PROCESS_DEBUG
+bool 'Pseudo page fault support' CONFIG_PFAULT
+bool 'VM shared kernel support' CONFIG_SHARED_KERNEL
 endmenu
 
 source drivers/s390/Config.in
diff -u --recursive --new-file v2.4.7/linux/arch/s390/defconfig linux/arch/s390/defconfig
--- v2.4.7/linux/arch/s390/defconfig	Wed Apr 11 19:02:27 2001
+++ linux/arch/s390/defconfig	Wed Jul 25 14:12:01 2001
@@ -5,6 +5,8 @@
 # CONFIG_EISA is not set
 # CONFIG_MCA is not set
 CONFIG_UID16=y
+CONFIG_RWSEM_GENERIC_SPINLOCK=y
+# CONFIG_RWSEM_XCHGADD_ALGORITHM is not set
 CONFIG_ARCH_S390=y
 
 #
@@ -40,6 +42,8 @@
 CONFIG_BINFMT_ELF=y
 # CONFIG_BINFMT_MISC is not set
 # CONFIG_PROCESS_DEBUG is not set
+CONFIG_PFAULT=y
+# CONFIG_SHARED_KERNEL is not set
 
 #
 # Block device drivers
@@ -79,10 +83,13 @@
 #
 # S/390 character device drivers
 #
-CONFIG_3215=y
-CONFIG_3215_CONSOLE=y
+CONFIG_TN3270=y
+CONFIG_TN3270_CONSOLE=y
+CONFIG_TN3215=y
+CONFIG_TN3215_CONSOLE=y
 CONFIG_HWC=y
 CONFIG_HWC_CONSOLE=y
+CONFIG_HWC_CPI=m
 CONFIG_S390_TAPE=m
 
 #
@@ -102,6 +109,9 @@
 #
 CONFIG_NETDEVICES=y
 # CONFIG_DUMMY is not set
+# CONFIG_BONDING is not set
+# CONFIG_EQUALIZER is not set
+# CONFIG_TUN is not set
 CONFIG_NET_ETHERNET=y
 CONFIG_TR=y
 # CONFIG_FDDI is not set
@@ -109,7 +119,8 @@
 #
 # S/390 network device drivers
 #
-# CONFIG_CHANDEV is not set
+CONFIG_CHANDEV=y
+CONFIG_HOTPLUG=y
 CONFIG_CTC=m
 CONFIG_IUCV=m
 
@@ -133,7 +144,8 @@
 # CONFIG_IP_MROUTE is not set
 # CONFIG_INET_ECN is not set
 # CONFIG_SYN_COOKIES is not set
-# CONFIG_IPV6 is not set
+CONFIG_IPV6=m
+# CONFIG_IPV6_NETLINK is not set
 # CONFIG_KHTTPD is not set
 # CONFIG_ATM is not set
 
@@ -178,16 +190,18 @@
 # CONFIG_EFS_FS is not set
 # CONFIG_JFFS_FS is not set
 # CONFIG_CRAMFS is not set
+# CONFIG_TMPFS is not set
 # CONFIG_RAMFS is not set
 # CONFIG_ISO9660_FS is not set
 # CONFIG_JOLIET is not set
 # CONFIG_MINIX_FS is not set
+# CONFIG_VXFS_FS is not set
 # CONFIG_NTFS_FS is not set
 # CONFIG_NTFS_RW is not set
 # CONFIG_HPFS_FS is not set
 CONFIG_PROC_FS=y
-# CONFIG_DEVFS_FS is not set
-# CONFIG_DEVFS_MOUNT is not set
+CONFIG_DEVFS_FS=y
+CONFIG_DEVFS_MOUNT=y
 # CONFIG_DEVFS_DEBUG is not set
 # CONFIG_DEVPTS_FS is not set
 # CONFIG_QNX4FS_FS is not set
@@ -195,7 +209,6 @@
 # CONFIG_ROMFS_FS is not set
 CONFIG_EXT2_FS=y
 # CONFIG_SYSV_FS is not set
-# CONFIG_SYSV_FS_WRITE is not set
 # CONFIG_UDF_FS is not set
 # CONFIG_UDF_RW is not set
 # CONFIG_UFS_FS is not set
@@ -243,4 +256,4 @@
 #
 # Kernel hacking
 #
-# CONFIG_MAGIC_SYSRQ is not set
+CONFIG_MAGIC_SYSRQ=y
diff -u --recursive --new-file v2.4.7/linux/arch/s390/kernel/debug.c linux/arch/s390/kernel/debug.c
--- v2.4.7/linux/arch/s390/kernel/debug.c	Wed Apr 11 19:02:27 2001
+++ linux/arch/s390/kernel/debug.c	Wed Jul 25 14:12:01 2001
@@ -14,7 +14,7 @@
 #include <linux/stddef.h>
 #include <linux/kernel.h>
 #include <linux/errno.h>
-#include <linux/malloc.h>
+#include <linux/slab.h>
 #include <linux/ctype.h>
 #include <linux/version.h>
 #include <asm/uaccess.h>
diff -u --recursive --new-file v2.4.7/linux/arch/s390/kernel/entry.S linux/arch/s390/kernel/entry.S
--- v2.4.7/linux/arch/s390/kernel/entry.S	Wed Jul 25 17:10:18 2001
+++ linux/arch/s390/kernel/entry.S	Wed Jul 25 14:12:01 2001
@@ -14,6 +14,7 @@
 #include <linux/sys.h>
 #include <linux/linkage.h>
 #include <linux/config.h>
+#include <asm/cache.h>
 #include <asm/lowcore.h>
 #include <asm/errno.h>
 #include <asm/smp.h>
@@ -200,8 +201,10 @@
 #
 # check, if bottom-half has to be done
 #
-        l       %r0,__LC_IRQ_STAT     # get softirq_active
-        n       %r0,__LC_IRQ_STAT+4   # and it with softirq_mask
+	l       %r1,processor(%r9)    # get cpu number from task struture
+	sll     %r1,L1_CACHE_SHIFT
+	al      %r1,BASED(.Lirq_stat) # get address of irq_stat
+	icm     %r0,15,0(%r1)         # test irq_stat[#cpu].__softirq_pending
         bnz     BASED(sysc_handle_bottom_half)
 #
 # check, if reschedule is needed
@@ -657,10 +660,9 @@
         lh      %r7,__LC_PGM_ILC         # load instruction length
 	GET_CURRENT
 pgm_no_sv:
+	la	%r3,0x7f
         lh      %r8,__LC_PGM_INT_CODE  # N.B. saved int code used later KEEP it
-        lr      %r3,%r8
-        la      %r0,0x7f
-        nr      %r3,%r0           # clear per-event-bit
+	nr      %r3,%r8           # reload & clear per-event-bit
         be      BASED(pgm_dn)     # none of Martins exceptions occurred bypass
         l       %r1,BASED(.Ljump_table)
         sll     %r3,2
@@ -676,8 +678,7 @@
         be      BASED(pgm_go)     # if yes then don't reenable interrupts
         stosm   24(%r15),0x03     # reenable interrupts
 pgm_go: basr    %r14,%r1          # branch to interrupt-handler
-pgm_dn: la      %r0,0x80
-        nr      %r8,%r0           # check for per exception
+pgm_dn: n	%r8,BASED(.Lc128) # check for per excepton
         be      BASED(pgm_return)
         la      %r2,SP_PTREGS(15) # address of register-save area
         l       %r1,BASED(.Lhandle_per) # load adr. of per handler
@@ -713,8 +714,10 @@
 #
 # check, if bottom-half has to be done
 #
-        l       %r0,__LC_IRQ_STAT     # get softirq_active
-        n       %r0,__LC_IRQ_STAT+4   # and it with softirq_mask
+	l       %r1,processor(%r9)    # get cpu number from task struture
+	sll     %r1,L1_CACHE_SHIFT
+	al      %r1,BASED(.Lirq_stat) # get address of irq_stat
+	icm     %r0,15,0(%r1)         # test irq_stat[#cpu].__softirq_pending
         bnz     BASED(io_handle_bottom_half)
 io_return_bh:	
 #
@@ -843,6 +846,7 @@
 .Lc0x2401:     .long  0x2401
 .Lc0x4000:     .long  0x4000
 .Lc0xff:       .long  0xff
+.Lc128:        .long  128
 
 /*
  * Symbol constants
@@ -854,6 +858,7 @@
 .Lentry_base:  .long  entry_base
 .Lext_hash:    .long  ext_int_hash
 .Lhandle_per:  .long  handle_per_exception
+.Lirq_stat:    .long  irq_stat
 .Ljump_table:  .long  pgm_check_table
 .Lschedule:    .long  schedule
 .Lclone:       .long  sys_clone
diff -u --recursive --new-file v2.4.7/linux/arch/s390/kernel/head.S linux/arch/s390/kernel/head.S
--- v2.4.7/linux/arch/s390/kernel/head.S	Wed Jul 25 17:10:18 2001
+++ linux/arch/s390/kernel/head.S	Wed Jul 25 14:12:01 2001
@@ -461,7 +461,7 @@
         .org  0x10000
 startup:basr  %r13,0                     # get base
 .LPG1:  lctl  %c0,%c15,.Lctl-.LPG1(%r13) # load control registers
-	l     %r12,.Lparm1-.LPG1(%r13)   # pointer to parameter area
+	la    %r12,parmarea-.LPG1(%r13)  # pointer to parameter area
 					 # move IPL device to lowcore
         mvc   __LC_IPLDEV(4),IPL_DEVICE-PARMAREA(%r12)
 	
@@ -502,9 +502,7 @@
 # find out if we have an IEEE fpu
 #
         mvc    __LC_PGM_NEW_PSW(8),.Lpcfpu-.LPG1(%r13)
-        ld     %f0,.Lflt0-.LPG1(%r13)   # load (float) 0.0
-        ldr    %f2,%f0
-        adbr   %f0,%f2                  # test IEEE add instruction
+	efpc   %r0,0                    # test IEEE extract fpc instruction
         oi     3(%r12),2                # set IEEE fpu flag
 .Lchkfpu:
 
@@ -514,7 +512,7 @@
        mvc    __LC_PGM_NEW_PSW(8),.Lpccsp-.LPG1(%r13)
        la     %r0,0
        lr     %r1,%r0
-       la     %r2,.Lflt0-.LPG1(%r13)
+       la     %r2,4
        csp    %r0,%r2                   # Test CSP instruction
        oi     3(%r12),8                 # set CSP flag
 .Lchkcsp:
@@ -554,12 +552,7 @@
 .Lpcfpu:.long  0x00080000,0x80000000 + .Lchkfpu
 .Lpccsp:.long  0x00080000,0x80000000 + .Lchkcsp
 .Lpcmvpg:.long 0x00080000,0x80000000 + .Lchkmvpg
-.Lflt0: .double 0
-.Lparm1:.long  PARMAREA
 .L4malign:.long 0xffc00000
-.Lbigmem:.long 0x04000000
-.Lrdstart:.long 0x02000000
-.Lmaxchunk:.long  0x00ffffff
 .Lmemsize:.long memory_size
 .Lmflags:.long machine_flags
 
@@ -567,6 +560,7 @@
 # params at 10400 (setup.h)
 #
 	.org   PARMAREA
+parmarea:	
         .long  0,0                      # IPL_DEVICE
         .long  0,RAMDISK_ORIGIN         # INITRD_START
         .long  0,0x800000               # INITRD_SIZE
@@ -578,7 +572,11 @@
 #
 # startup-code, running in virtual mode
 #
+#ifdef CONFIG_SHARED_KERNEL
+	.org   0x100000
+#else
         .org   0x10800
+#endif
         .globl _stext
 _stext:	basr  %r13,0                    # get base
 .LPG2:
@@ -608,8 +606,8 @@
         jo    .-4                       # branch back, if not finish
 # check control registers
         stctl  %c0,%c15,0(%r15)
-        oc     2(1,%r15),.Locbits+5-.LPG2(%r13) # enable sigp external ints.
-        oc     0(1,%r15),.Locbits+4-.LPG2(%r13) # low addresss proctection
+	oi     2(%r15),0x20             # enable sigp external interrupts
+	oi     0(%r15),0x10             # switch on low address protection
         lctl   %c0,%c15,0(%r15)
 
 #
@@ -622,15 +620,12 @@
         basr  %r13,0
 	lpsw  .Ldw-.(%r13)           # load disabled wait psw
 #
-.Lstart:    .long  start_kernel
             .align 8
+.Ldw:	    .long  0x000a0000,0x00000000
 .Lprefix:   .long  init_S390_lowcore	
 .Linittu:   .long  init_task_union
+.Lstart:    .long  start_kernel
 .Lbss_bgn:  .long  __bss_start
 .Lbss_end:  .long  _end
-.Locbits:   .long  0x01020408,0x10204080
-            .align 4
 .Laregs:    .long  0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0
-	    .align 8
-.Ldw:	    .long  0x000a0000,0x00000000
 
diff -u --recursive --new-file v2.4.7/linux/arch/s390/kernel/irq.c linux/arch/s390/kernel/irq.c
--- v2.4.7/linux/arch/s390/kernel/irq.c	Wed Jul 25 17:10:18 2001
+++ linux/arch/s390/kernel/irq.c	Wed Jul 25 14:12:01 2001
@@ -21,7 +21,7 @@
 #include <linux/ioport.h>
 #include <linux/interrupt.h>
 #include <linux/timex.h>
-#include <linux/malloc.h>
+#include <linux/slab.h>
 #include <linux/string.h>
 #include <linux/random.h>
 #include <linux/smp.h>
@@ -119,7 +119,7 @@
  */
 #ifdef CONFIG_SMP
 atomic_t global_irq_holder = ATOMIC_INIT(NO_PROC_ID);
-atomic_t global_irq_lock;
+atomic_t global_irq_lock = ATOMIC_INIT(0);
 atomic_t global_irq_count = ATOMIC_INIT(0);
 atomic_t global_bh_count;
 
@@ -188,7 +188,7 @@
 		}
 
 		/* Duh, we have to loop. Release the lock to avoid deadlocks */
-		clear_bit(0,&global_irq_lock);
+		atomic_set(&global_irq_lock, 0);
 
 		for (;;) {
 			if (!--count) {
@@ -206,10 +206,8 @@
 			if (!local_bh_count(cpu)
 			    && atomic_read(&global_bh_count))
 				continue;
-			/* this works even though global_irq_lock not
-                           a long, but is arch-specific --RR */
-			if (!test_and_set_bit(0,&global_irq_lock))
-				break;
+			if (!atomic_compare_and_swap(0, 1, &global_irq_lock))
+				 break;
 		}
 	}
 }
@@ -246,18 +244,14 @@
 
 static inline void get_irqlock(int cpu)
 {
-	/* this works even though global_irq_lock not a long, but is
-	   arch-specific --RR */
-	if (test_and_set_bit(0,&global_irq_lock)) {
+	if (atomic_compare_and_swap(0, 1, &global_irq_lock) != 0) {
 		/* do we already hold the lock? */
 		if ( cpu == atomic_read(&global_irq_holder))
 			return;
 		/* Uhhuh.. Somebody else got it. Wait.. */
 		do {
-			do {
-				check_smp_invalidate(cpu);
-			} while (test_bit(0,&global_irq_lock));
-		} while (test_and_set_bit(0,&global_irq_lock));
+			check_smp_invalidate(cpu);
+		} while (atomic_compare_and_swap(0, 1, &global_irq_lock) != 0);
 	}
 	/*
 	 * We also to make sure that nobody else is running
@@ -391,6 +385,10 @@
 EXPORT_SYMBOL(__global_sti);
 EXPORT_SYMBOL(__global_save_flags);
 EXPORT_SYMBOL(__global_restore_flags);
+EXPORT_SYMBOL(global_irq_holder);
+EXPORT_SYMBOL(global_irq_lock);
+EXPORT_SYMBOL(global_irq_count);
+EXPORT_SYMBOL(global_bh_count);
 #endif
 
 EXPORT_SYMBOL(global_bh_lock);
diff -u --recursive --new-file v2.4.7/linux/arch/s390/kernel/process.c linux/arch/s390/kernel/process.c
--- v2.4.7/linux/arch/s390/kernel/process.c	Wed Apr 11 19:02:28 2001
+++ linux/arch/s390/kernel/process.c	Wed Jul 25 14:12:01 2001
@@ -63,8 +63,7 @@
 	wait_psw.mask = _WAIT_PSW_MASK;
 	wait_psw.addr = (unsigned long) &&idle_wakeup | 0x80000000L;
 	while(1) {
-                if (softirq_active(smp_processor_id()) &
-		    softirq_mask(smp_processor_id())) {
+                if (softirq_pending(smp_processor_id())) {
                         do_softirq();
                         __sti();
                         if (!current->need_resched)
@@ -307,11 +306,11 @@
 
         frame = (struct stack_frame *) (2*PAGE_SIZE + (unsigned long) p) -1;
         frame = (struct stack_frame *) (((unsigned long) frame)&-8L);
-        p->thread.regs = &frame->childregs;
+        p->thread.regs = (struct pt_regs *)&frame->childregs;
         p->thread.ksp = (unsigned long) frame;
-        frame->childregs = *regs;
+        memcpy(&frame->childregs,regs,sizeof(struct pt_regs));
         frame->childregs.gprs[15] = new_stackp;
-        frame->eos = 0;
+        frame->back_chain = frame->eos = 0;
 
         /* new return point is ret_from_sys_call */
         frame->gprs[8] = ((unsigned long) &ret_from_fork) | 0x80000000;
@@ -466,54 +465,3 @@
 #undef last_sched
 #undef first_sched
 
-/*
- * This should be safe even if called from tq_scheduler
- * A typical mask would be sigmask(SIGKILL)|sigmask(SIGINT)|sigmask(SIGTERM) or 0.
- *
- */
-void s390_daemonize(char *name,unsigned long mask,int use_init_fs)
-{
-	struct fs_struct *fs;
-	extern struct task_struct *child_reaper;
-	struct task_struct *this_process=current;
-	
-	/*
-	 * If we were started as result of loading a module, close all of the
-	 * user space pages.  We don't need them, and if we didn't close them
-	 * they would be locked into memory.
-	 */
-	exit_mm(current);
-
-	this_process->session = 1;
-	this_process->pgrp = 1;
-	if(name)
-	{
-		strncpy(current->comm,name,15);
-		current->comm[15]=0;
-	}
-	else
-		current->comm[0]=0;
-	/* set signal mask to what we want to respond */
-        siginitsetinv(&current->blocked,mask);
-	/* exit_signal isn't set up */
-        /* if we inherit from cpu idle  */
-	this_process->exit_signal=SIGCHLD;
-	/* if priority=0 schedule can go into a tight loop */
-	this_process->policy= SCHED_OTHER;
-	/* nice goes priority=20-nice; */
-	this_process->nice=10;
-	if(use_init_fs)
-	{
-		exit_fs(this_process);	/* current->fs->count--; */
-		fs = init_task.fs;
-		current->fs = fs;
-		atomic_inc(&fs->count);
-		exit_files(current);
-	}
-	write_lock_irq(&tasklist_lock);
-	/* We want init as our parent */
-	REMOVE_LINKS(this_process);
-	this_process->p_opptr=this_process->p_pptr=child_reaper;
-	SET_LINKS(this_process);
-	write_unlock_irq(&tasklist_lock);
-}
diff -u --recursive --new-file v2.4.7/linux/arch/s390/kernel/s390_ext.c linux/arch/s390/kernel/s390_ext.c
--- v2.4.7/linux/arch/s390/kernel/s390_ext.c	Wed Apr 11 19:02:28 2001
+++ linux/arch/s390/kernel/s390_ext.c	Wed Jul 25 14:12:01 2001
@@ -9,7 +9,7 @@
 
 #include <linux/module.h>
 #include <linux/kernel.h>
-#include <linux/malloc.h>
+#include <linux/slab.h>
 #include <asm/lowcore.h>
 #include <asm/s390_ext.h>
 
@@ -17,12 +17,13 @@
  * Simple hash strategy: index = code & 0xff;
  * ext_int_hash[index] is the start of the list for all external interrupts
  * that hash to this index. With the current set of external interrupts 
- * (0x1202 external call, 0x1004 cpu timer, 0x2401 hwc console and 0x4000
- * iucv) this is always the first element. 
+ * (0x1202 external call, 0x1004 cpu timer, 0x2401 hwc console, 0x4000
+ * iucv and 0x2603 pfault) this is always the first element. 
  */
 ext_int_info_t *ext_int_hash[256] = { 0, };
 ext_int_info_t ext_int_info_timer;
 ext_int_info_t ext_int_info_hwc;
+ext_int_info_t ext_int_pfault;
 
 int register_external_interrupt(__u16 code, ext_int_handler_t handler) {
         ext_int_info_t *p;
@@ -39,7 +40,9 @@
                 p = &ext_int_info_timer;
         else if (code == 0x2401) /* hwc_init is done too early too */
                 p = &ext_int_info_hwc;
-        else
+        else if (code == 0x2603) /* pfault_init is done too early too */
+		p = &ext_int_pfault;
+	else
                 p = (ext_int_info_t *)
                           kmalloc(sizeof(ext_int_info_t), GFP_ATOMIC);
         if (p == NULL)
@@ -70,7 +73,7 @@
                 q->next = p->next;
         else
                 ext_int_hash[index] = p->next;
-        if (code != 0x1004 && code != 0x2401)
+        if (code != 0x1004 && code != 0x2401 && code != 0x2603)
                 kfree(p);
         return 0;
 }
diff -u --recursive --new-file v2.4.7/linux/arch/s390/kernel/s390_ksyms.c linux/arch/s390/kernel/s390_ksyms.c
--- v2.4.7/linux/arch/s390/kernel/s390_ksyms.c	Wed Apr 11 19:02:28 2001
+++ linux/arch/s390/kernel/s390_ksyms.c	Wed Jul 25 14:12:01 2001
@@ -43,6 +43,7 @@
 EXPORT_SYMBOL_NOVERS(strncpy);
 EXPORT_SYMBOL_NOVERS(strnlen);
 EXPORT_SYMBOL_NOVERS(strrchr);
+EXPORT_SYMBOL_NOVERS(strstr);
 EXPORT_SYMBOL_NOVERS(strtok);
 EXPORT_SYMBOL_NOVERS(strpbrk);
 
@@ -53,6 +54,8 @@
 EXPORT_SYMBOL(__udelay);
 EXPORT_SYMBOL(kernel_thread);
 EXPORT_SYMBOL(csum_fold);
+EXPORT_SYMBOL(console_mode);
+EXPORT_SYMBOL(console_device);
 
 #if CONFIG_IP_MULTICAST
 /* Required for lcs gigabit ethernet multicast support */
diff -u --recursive --new-file v2.4.7/linux/arch/s390/kernel/setup.c linux/arch/s390/kernel/setup.c
--- v2.4.7/linux/arch/s390/kernel/setup.c	Wed Apr 11 19:02:28 2001
+++ linux/arch/s390/kernel/setup.c	Wed Jul 25 14:12:01 2001
@@ -43,6 +43,8 @@
 /*
  * Machine setup..
  */
+unsigned int console_mode = 0;
+unsigned int console_device = -1;
 unsigned long memory_size = 0;
 unsigned long machine_flags = 0;
 __u16 boot_cpu_addr;
@@ -141,6 +143,93 @@
 __setup("vmpoff=", vmpoff_setup);
 
 /*
+ * condev= and conmode= setup parameter.
+ */
+
+static int __init condev_setup(char *str)
+{
+	int vdev;
+
+	vdev = simple_strtoul(str, &str, 0);
+	if (vdev >= 0 && vdev < 65536)
+		console_device = vdev;
+	return 1;
+}
+
+__setup("condev=", condev_setup);
+
+static int __init conmode_setup(char *str)
+{
+#if defined(CONFIG_HWC_CONSOLE)
+	if (strncmp(str, "hwc", 4) == 0 && !MACHINE_IS_P390)
+                SET_CONSOLE_HWC;
+#endif
+#if defined(CONFIG_TN3215_CONSOLE)
+	if (strncmp(str, "3215", 5) == 0 && (MACHINE_IS_VM || MACHINE_IS_P390))
+		SET_CONSOLE_3215;
+#endif
+#if defined(CONFIG_TN3270_CONSOLE)
+	if (strncmp(str, "3270", 5) == 0 && (MACHINE_IS_VM || MACHINE_IS_P390))
+		SET_CONSOLE_3270;
+#endif
+        return 1;
+}
+
+__setup("conmode=", conmode_setup);
+
+static void __init conmode_default(void)
+{
+	char query_buffer[1024];
+	char *ptr;
+
+        if (MACHINE_IS_VM) {
+		cpcmd("QUERY TERM", query_buffer, 1024);
+		ptr = strstr(query_buffer, "CONMODE");
+		/*
+		 * Set the conmode to 3215 so that the device recognition 
+		 * will set the cu_type of the console to 3215. If the
+		 * conmode is 3270 and we don't set it back then both
+		 * 3215 and the 3270 driver will try to access the console
+		 * device (3215 as console and 3270 as normal tty).
+		 */
+		cpcmd("TERM CONMODE 3215", NULL, 0);
+		if (ptr == NULL) {
+#if defined(CONFIG_HWC_CONSOLE)
+			SET_CONSOLE_HWC;
+#endif
+			return;
+		}
+		if (strncmp(ptr + 8, "3270", 4) == 0) {
+#if defined(CONFIG_TN3270_CONSOLE)
+			SET_CONSOLE_3270;
+#elif defined(CONFIG_TN3215_CONSOLE)
+			SET_CONSOLE_3215;
+#elif defined(CONFIG_HWC_CONSOLE)
+			SET_CONSOLE_HWC;
+#endif
+		} else if (strncmp(ptr + 8, "3215", 4) == 0) {
+#if defined(CONFIG_TN3215_CONSOLE)
+			SET_CONSOLE_3215;
+#elif defined(CONFIG_TN3270_CONSOLE)
+			SET_CONSOLE_3270;
+#elif defined(CONFIG_HWC_CONSOLE)
+			SET_CONSOLE_HWC;
+#endif
+		}
+        } else if (MACHINE_IS_P390) {
+#if defined(CONFIG_TN3215_CONSOLE)
+		SET_CONSOLE_3215;
+#elif defined(CONFIG_TN3270_CONSOLE)
+		SET_CONSOLE_3270;
+#endif
+	} else {
+#if defined(CONFIG_HWC_CONSOLE)
+		SET_CONSOLE_HWC;
+#endif
+	}
+}
+
+/*
  * Reboot, halt and power_off routines for non SMP.
  */
 
@@ -183,8 +272,6 @@
                 return;
         smptrap=1;
 
-        printk("Command line is: %s\n", COMMAND_LINE);
-
         /*
          * Setup lowcore information for boot cpu
          */
@@ -244,7 +331,6 @@
                  * "ipldelay=XXX[sm]" sets ipl delay in seconds or minutes
                  */
                 if (c == ' ' && strncmp(from, "ipldelay=", 9) == 0) {
-			if (to != command_line) to--;
                         delay = simple_strtoul(from+9, &from, 0);
 			if (*from == 's' || *from == 'S') {
 				delay = delay*1000000;
@@ -253,7 +339,7 @@
 				delay = delay*60*1000000;
 				from++;
 			}
-			/* now wait for the requestedn amount of time */
+			/* now wait for the requested amount of time */
 			udelay(delay);
                 }
                 cn = *(from++);
@@ -261,6 +347,8 @@
                         break;
                 if (cn == '\n')
                         cn = ' ';  /* replace newlines with space */
+		if (cn == 0x0d)
+			cn = ' ';  /* replace 0x0d with space */
                 if (cn == ' ' && c == ' ')
                         continue;  /* remove additional spaces */
                 c = cn;
@@ -322,6 +410,9 @@
 	request_resource(&iomem_resource, res);
 	request_resource(res, &code_resource);
 	request_resource(res, &data_resource);
+
+        /* Setup default console */
+	conmode_default();
 }
 
 void print_cpu_info(struct cpuinfo_S390 *cpuinfo)
diff -u --recursive --new-file v2.4.7/linux/arch/s390/kernel/signal.c linux/arch/s390/kernel/signal.c
--- v2.4.7/linux/arch/s390/kernel/signal.c	Wed Apr 11 19:02:28 2001
+++ linux/arch/s390/kernel/signal.c	Wed Jul 25 14:12:01 2001
@@ -332,6 +332,7 @@
 		/* Set up registers for signal handler */
 		regs->gprs[15] = (addr_t)frame;
 		regs->psw.addr = FIX_PSW(ka->sa.sa_handler);
+		regs->psw.mask = _USER_PSW_MASK;
 	}
 	/* Set up to return from userspace.  If provided, use a stub
 	   already in userspace.  */
@@ -358,6 +359,11 @@
 #endif
 	/* Martin wants this for pthreads */
 	regs->gprs[3] = (addr_t)&frame->sc;
+
+	/* We forgot to include these in the sigcontext.
+	   To avoid breaking binary compatibility, they are passed as args. */
+	regs->gprs[4] = current->thread.trap_no;
+	regs->gprs[5] = current->thread.prot_addr;
 	return;
 
 give_sigsegv:
@@ -414,7 +420,7 @@
 	      siginfo_t *info, sigset_t *oldset, struct pt_regs * regs)
 {
 	/* Are we from a system call? */
-	if (regs->orig_gpr2 >= 0) {
+	if (regs->trap == __LC_SVC_OLD_PSW) {
 		/* If so, check system call restarting.. */
 		switch (regs->gprs[2]) {
 			case -ERESTARTNOHAND:
@@ -561,7 +567,6 @@
                                 /* FALLTHRU */
 
 			default:
-				lock_kernel();
 				sigaddset(&current->pending.signal, signr);
 				recalc_sigpending(current);
 				current->flags |= PF_SIGNALED;
diff -u --recursive --new-file v2.4.7/linux/arch/s390/kernel/smp.c linux/arch/s390/kernel/smp.c
--- v2.4.7/linux/arch/s390/kernel/smp.c	Wed Jul 25 17:10:18 2001
+++ linux/arch/s390/kernel/smp.c	Wed Jul 25 14:12:01 2001
@@ -556,6 +556,7 @@
  *      Activate a secondary processor.
  */
 extern void init_100hz_timer(void);
+extern int pfault_token(void);
 
 int __init start_secondary(void *cpuvoid)
 {
@@ -568,6 +569,10 @@
                 /* nothing */ ;
         /* init per CPU 100 hz timer */
         init_100hz_timer();
+#ifdef CONFIG_PFAULT
+	/* Enable pfault pseudo page faults on this cpu. */
+	pfault_init();
+#endif
         /* cpu_idle will call schedule for us */
         return cpu_idle(NULL);
 }
diff -u --recursive --new-file v2.4.7/linux/arch/s390/kernel/time.c linux/arch/s390/kernel/time.c
--- v2.4.7/linux/arch/s390/kernel/time.c	Tue Feb 13 14:13:44 2001
+++ linux/arch/s390/kernel/time.c	Wed Jul 25 14:12:01 2001
@@ -95,9 +95,10 @@
 {
 	unsigned long flags;
 	unsigned long usec, sec;
-	unsigned long lost_ticks = jiffies - wall_jiffies;
+	unsigned long lost_ticks;
 
 	read_lock_irqsave(&xtime_lock, flags);
+	lost_ticks = jiffies - wall_jiffies;
 	usec = do_gettimeoffset();
 	if (lost_ticks)
 		usec +=(USECS_PER_JIFFY*lost_ticks);
diff -u --recursive --new-file v2.4.7/linux/arch/s390/kernel/traps.c linux/arch/s390/kernel/traps.c
--- v2.4.7/linux/arch/s390/kernel/traps.c	Wed Apr 11 19:02:28 2001
+++ linux/arch/s390/kernel/traps.c	Wed Jul 25 14:12:01 2001
@@ -36,6 +36,7 @@
 #include <asm/gdb-stub.h>
 #endif
 #include <asm/cpcmd.h>
+#include <asm/s390_ext.h>
 
 /* Called from entry.S only */
 extern void handle_per_exception(struct pt_regs *regs);
@@ -53,6 +54,11 @@
 
 extern pgm_check_handler_t do_page_fault;
 extern pgm_check_handler_t do_pseudo_page_fault;
+#ifdef CONFIG_PFAULT
+extern int pfault_init(void);
+extern void pfault_fini(void);
+extern void pfault_interrupt(struct pt_regs *regs, __u16 error_code);
+#endif
 
 spinlock_t die_lock;
 
@@ -142,7 +148,7 @@
 DO_ERROR(SIGILL,  "privileged operation", privileged_op)
 DO_ERROR(SIGILL,  "execute exception", execute_exception)
 DO_ERROR(SIGSEGV, "addressing exception", addressing_exception)
-DO_ERROR(SIGILL,  "fixpoint divide exception", divide_exception)
+DO_ERROR(SIGFPE,  "fixpoint divide exception", divide_exception)
 DO_ERROR(SIGILL,  "translation exception", translation_exception)
 DO_ERROR(SIGILL,  "special operand exception", special_op_exception)
 DO_ERROR(SIGILL,  "operand exception", operand_exception)
@@ -154,7 +160,6 @@
 	int signal = 0;
 	int problem_state=(regs->psw.mask & PSW_PROBLEM_STATE);
 
-        lock_kernel();
 	location = (__u16 *)(regs->psw.addr-S390_lowcore.pgm_ilc);
 	if(problem_state)
 		get_user(*((__u16 *) opcode), location);
@@ -197,7 +202,6 @@
         } else if (signal)
 		do_trap(interruption_code, signal,
 			"illegal operation", regs, NULL);
-        unlock_kernel();
 }
 
 
@@ -210,7 +214,6 @@
 	__u16 *location;
 	int signal = 0;
 
-        lock_kernel();
         if (regs->psw.mask & PSW_PROBLEM_STATE) {
 		location = (__u16 *)(regs->psw.addr-S390_lowcore.pgm_ilc);
 		get_user(*((__u16 *) opcode), location);
@@ -250,7 +253,6 @@
         } else if (signal)
                 do_trap(interruption_code, signal,
 			"specification exception", regs, NULL);
-        unlock_kernel();
 }
 #else
 DO_ERROR(SIGILL, "specification exception", specification_exception)
@@ -262,7 +264,6 @@
 	__u16 *location;
 	int signal = 0;
 
-        lock_kernel();
 	location = (__u16 *)(regs->psw.addr-S390_lowcore.pgm_ilc);
 	if (MACHINE_HAS_IEEE)
 		__asm__ volatile ("stfpc %0\n\t" 
@@ -333,7 +334,6 @@
 	} else if (signal) 
                 do_trap(interruption_code, signal,
 			"data exception", regs, NULL);
-        unlock_kernel();
 }
 
 
@@ -361,8 +361,26 @@
  	pgm_check_table[0x14] = &do_pseudo_page_fault;
         pgm_check_table[0x15] = &operand_exception;
         pgm_check_table[0x1C] = &privileged_op;
+#ifdef CONFIG_PFAULT
+	if (MACHINE_IS_VM) {
+		/* request the 0x2603 external interrupt */
+		if (register_external_interrupt(0x2603, pfault_interrupt) != 0)
+			panic("Couldn't request external interrupt 0x2603");
+		/*
+		 * First try to get pfault pseudo page faults going.
+		 * If this isn't available turn on pagex page faults.
+		 */
+		if (pfault_init() != 0) {
+			/* Tough luck, no pfault. */
+			unregister_external_interrupt(0x2603,
+						      pfault_interrupt);
+			cpcmd("SET PAGEX ON", NULL, 0);
+		}
+	}
+#else
 	if (MACHINE_IS_VM)
-	        cpcmd("SET PAGEX ON", NULL, 0);
+		cpcmd("SET PAGEX ON", NULL, 0);
+#endif
 }
 
 
diff -u --recursive --new-file v2.4.7/linux/arch/s390/mm/Makefile linux/arch/s390/mm/Makefile
--- v2.4.7/linux/arch/s390/mm/Makefile	Tue Feb 13 14:13:44 2001
+++ linux/arch/s390/mm/Makefile	Wed Jul 25 14:12:01 2001
@@ -1,5 +1,5 @@
 #
-# Makefile for the linux i386-specific parts of the memory manager.
+# Makefile for the linux s390-specific parts of the memory manager.
 #
 # Note! Dependencies are done automagically by 'make dep', which also
 # removes any old dependencies. DON'T put your own dependencies here
diff -u --recursive --new-file v2.4.7/linux/arch/s390/mm/fault.c linux/arch/s390/mm/fault.c
--- v2.4.7/linux/arch/s390/mm/fault.c	Wed Apr 11 19:02:27 2001
+++ linux/arch/s390/mm/fault.c	Wed Jul 25 14:12:01 2001
@@ -22,6 +22,7 @@
 #include <linux/smp.h>
 #include <linux/smp_lock.h>
 #include <linux/compatmac.h>
+#include <linux/init.h>
 
 #include <asm/system.h>
 #include <asm/uaccess.h>
@@ -52,25 +53,14 @@
         unsigned long address;
         unsigned long fixup;
         int write;
-        unsigned long psw_mask;
-        unsigned long psw_addr;
 	int si_code = SEGV_MAPERR;
 	int kernel_address = 0;
 
-        /*
-         *  get psw mask of Program old psw to find out,
-         *  if user or kernel mode
-         */
-
-        psw_mask = S390_lowcore.program_old_psw.mask;
-        psw_addr = S390_lowcore.program_old_psw.addr;
-
         /* 
          * get the failing address 
          * more specific the segment and page table portion of 
          * the address 
          */
-
         address = S390_lowcore.trans_exc_code&0x7ffff000;
 
         tsk = current;
@@ -185,7 +175,7 @@
         up_read(&mm->mmap_sem);
 
         /* User mode accesses just cause a SIGSEGV */
-        if (psw_mask & PSW_PROBLEM_STATE) {
+        if (regs->psw.mask & PSW_PROBLEM_STATE) {
 		struct siginfo si;
                 tsk->thread.prot_addr = address;
                 tsk->thread.trap_no = error_code;
@@ -243,7 +233,7 @@
 out_of_memory:
 	up_read(&mm->mmap_sem);
 	printk("VM: killing process %s\n", tsk->comm);
-	if (psw_mask & PSW_PROBLEM_STATE)
+	if (regs->psw.mask & PSW_PROBLEM_STATE)
 		do_exit(SIGKILL);
 	goto no_context;
 
@@ -259,7 +249,7 @@
 	force_sig(SIGBUS, tsk);
 
 	/* Kernel mode? Handle exceptions or die */
-	if (!(psw_mask & PSW_PROBLEM_STATE))
+	if (!(regs->psw.mask & PSW_PROBLEM_STATE))
 		goto no_context;
 }
 
@@ -275,25 +265,17 @@
 static spinlock_t pseudo_wait_spinlock; /* spinlock to protect lock queue */
 
 /*
- * This routine handles pseudo page faults.
+ * This routine handles 'pagex' pseudo page faults.
  */
 asmlinkage void
 do_pseudo_page_fault(struct pt_regs *regs, unsigned long error_code)
 {
-        DECLARE_WAITQUEUE(wait, current);
         pseudo_wait_t wait_struct;
         pseudo_wait_t *ptr, *last, *next;
-        unsigned long psw_mask;
         unsigned long address;
         int kernel_address;
 
         /*
-         *  get psw mask of Program old psw to find out,
-         *  if user or kernel mode
-         */
-        psw_mask = S390_lowcore.program_old_psw.mask;
-
-        /*
          * get the failing address
          * more specific the segment and page table portion of
          * the address
@@ -332,7 +314,7 @@
                 spin_unlock(&pseudo_wait_spinlock);
         } else {
                 /* Pseudo page faults in kernel mode is a bad idea */
-                if (!(psw_mask & PSW_PROBLEM_STATE)) {
+                if (!(regs->psw.mask & PSW_PROBLEM_STATE)) {
                         /*
 			 * VM presents pseudo page faults if the interrupted
 			 * state was not disabled for interrupts. So we can
@@ -383,4 +365,127 @@
                 wait_event(wait_struct.queue, wait_struct.resolved);
         }
 }
-    
+
+#ifdef CONFIG_PFAULT 
+/*
+ * 'pfault' pseudo page faults routines.
+ */
+static int pfault_disable = 0;
+
+static int __init nopfault(char *str)
+{
+	pfault_disable = 1;
+	return 1;
+}
+
+__setup("nopfault", nopfault);
+
+typedef struct {
+	__u16 refdiagc;
+	__u16 reffcode;
+	__u16 refdwlen;
+	__u16 refversn;
+	__u64 refgaddr;
+	__u64 refselmk;
+	__u64 refcmpmk;
+	__u64 reserved;
+} __attribute__ ((packed)) pfault_refbk_t;
+
+int pfault_init(void)
+{
+	pfault_refbk_t refbk =
+	{ 0x258, 0, 5, 2, __LC_KERNEL_STACK, 1ULL << 48, 1ULL << 48, 0ULL };
+        int rc;
+
+	if (pfault_disable)
+		return -1;
+        __asm__ __volatile__(
+                "    diag  %1,%0,0x258\n"
+		"0:  j     2f\n"
+		"1:  la    %0,8\n"
+		"2:\n"
+		".section __ex_table,\"a\"\n"
+		"   .align 4\n"
+		"   .long  0b,1b\n"
+		".previous"
+                : "=d" (rc) : "a" (&refbk) : "cc" );
+        __ctl_set_bit(0, 9);
+        return rc;
+}
+
+void pfault_fini(void)
+{
+	pfault_refbk_t refbk =
+	{ 0x258, 1, 5, 2, 0ULL, 0ULL, 0ULL, 0ULL };
+
+	if (pfault_disable)
+		return;
+	__ctl_clear_bit(0,9);
+        __asm__ __volatile__(
+                "    diag  %0,0,0x258\n"
+		"0:\n"
+		".section __ex_table,\"a\"\n"
+		"   .align 4\n"
+		"   .long  0b,0b\n"
+		".previous"
+		: : "a" (&refbk) : "cc" );
+}
+
+asmlinkage void
+pfault_interrupt(struct pt_regs *regs, __u16 error_code)
+{
+        DECLARE_WAITQUEUE(wait, current);
+	struct task_struct *tsk;
+	wait_queue_head_t queue;
+	wait_queue_head_t *qp;
+	__u16 subcode;
+
+	/*
+	 * Get the external interruption subcode & pfault
+	 * initial/completion signal bit. VM stores this 
+	 * in the 'cpu address' field associated with the
+         * external interrupt. 
+	 */
+	subcode = S390_lowcore.cpu_addr;
+	if ((subcode & 0xff00) != 0x06)
+		return;
+
+	/*
+	 * Get the token (= address of kernel stack of affected task).
+	 */
+	tsk = (struct task_struct *)
+		(*((unsigned long *) __LC_PFAULT_INTPARM) - THREAD_SIZE);
+	
+	if (subcode & 0x0080) {
+		/* signal bit is set -> a page has been swapped in by VM */
+		qp = (wait_queue_head_t *)
+			xchg(&tsk->thread.pfault_wait, -1);
+		if (qp != NULL) {
+			/* Initial interrupt was faster than the completion
+			 * interrupt. pfault_wait is valid. Set pfault_wait
+			 * back to zero and wake up the process. This can
+			 * safely be done because the task is still sleeping
+			 * and can't procude new pfaults. */
+			tsk->thread.pfault_wait = 0ULL;
+			wake_up(qp);
+		}
+	} else {
+		/* signal bit not set -> a real page is missing. */
+                init_waitqueue_head (&queue);
+		qp = (wait_queue_head_t *)
+			xchg(&tsk->thread.pfault_wait, (addr_t) &queue);
+		if (qp != NULL) {
+			/* Completion interrupt was faster than the initial
+			 * interrupt (swapped in a -1 for pfault_wait). Set
+			 * pfault_wait back to zero and exit. This can be
+			 * done safely because tsk is running in kernel 
+			 * mode and can't produce new pfaults. */
+			tsk->thread.pfault_wait = 0ULL;
+		}
+
+                /* go to sleep */
+                wait_event(queue, tsk->thread.pfault_wait == 0ULL);
+	}
+}
+#endif
+
diff -u --recursive --new-file v2.4.7/linux/arch/s390/tools/dasdfmt/Makefile linux/arch/s390/tools/dasdfmt/Makefile
--- v2.4.7/linux/arch/s390/tools/dasdfmt/Makefile	Tue Feb 13 14:13:44 2001
+++ linux/arch/s390/tools/dasdfmt/Makefile	Wed Dec 31 16:00:00 1969
@@ -1,9 +0,0 @@
-all: dasdfmt
-
-dasdfmt: dasdfmt.c
-	$(CC) -o $@ $^
-	$(STRIP) $@
-
-clean:
-	rm -f dasdfmt
-
diff -u --recursive --new-file v2.4.7/linux/arch/s390/tools/dasdfmt/dasdfmt.8 linux/arch/s390/tools/dasdfmt/dasdfmt.8
--- v2.4.7/linux/arch/s390/tools/dasdfmt/dasdfmt.8	Fri Mar  2 11:12:06 2001
+++ linux/arch/s390/tools/dasdfmt/dasdfmt.8	Wed Dec 31 16:00:00 1969
@@ -1,68 +0,0 @@
-.TH DASDFMT 8 "Tue Jan 25 2000"
-.UC 4
-.SH NAME
-dasdfmt \- formatting of DSAD (ECKD) disk drives.
-.SH SYNOPSIS
-\fBdasdfmt\fR [-tvyLV] [-b \fIblockSize\fR] [-l \fIdiskLabel\fR] \fIdiskSpec\fR
-.SH DESCRIPTION
-\fBdasdfmt\fR formats a DASD (ECKD) disk drive to prepare it
-for usage with Linux for S/390. \fBWARNING\fR: Incautious usage of
-\fBdasdfmt\fR can result in \fBLOSS OF DATA\fR.
-
-.SH OPTIONS
-.TP
-\fB-t\fR
-Disables any modification of the disk drive. \fBdasdfmt\fR just prints
-out, what it \fBwould\fR do.
-
-.TP
-\fB-v\fR
-Increases verbosity.
-
-.TP
-\fB-y\fR 
-Start formatting without further user-confirmation.
-
-.TP
-\fB-L\fR 
-Omit the writing of a disk label after formatting.
-
-.TP
-\fB-V\fR 
-Print version number and exit.
-
-.TP
-\fB-b\fR \fIblockSize\fR
-Specify blocksize to be used. \fIblocksize\fR must be a positive integer
-and always be a power of two. Due due some limitations in the driver,
-it is \fBstrongly\fR recommended to use a \fIblockSize\fR of \fI4096\fR.
-
-.TP
-\fB-l\fR \fIdiskLabel\fR
-Specify the label to be written to disk after formatting. If no label is
-specified, a sensible default is used. \fIdiskLabel\fR is interpreted as
-ASCII string and is automatically converted to EBCDIC.
-
-.TP
-\fIdiskSpec\fR
-This parameter specified the device to be formatted. It also can be
-given in two variants:
-.sp
-	\fB-f\fR \fB/dev/dasd\fR\fIX\fR
-.br
-or
-.br
-	\fB-n\fR \fIdevnum\fR
-.sp
-The first form uses the commonly used
-.SM UNIX
-device notation where \fIX\fR is a single lowercase letter.
-The second form uses simply the device number.
-
-.SH BUGS
-None so far ;-)
-
-.SH AUTHOR
-.nf
-This man-page was written by Fritz Elfert <felfert@to.com>
-.fi
diff -u --recursive --new-file v2.4.7/linux/arch/s390/tools/dasdfmt/dasdfmt.c linux/arch/s390/tools/dasdfmt/dasdfmt.c
--- v2.4.7/linux/arch/s390/tools/dasdfmt/dasdfmt.c	Wed Apr 11 19:02:27 2001
+++ linux/arch/s390/tools/dasdfmt/dasdfmt.c	Wed Dec 31 16:00:00 1969
@@ -1,839 +0,0 @@
-/*
- *
- * dasdfmt.c
- *
- *  S390 version
- *    Copyright (C) 1999,2000 IBM Corporation
- *    Author(s): Utz Bacher, <utz.bacher@de.ibm.com>
- *
- *  Device-in-use-checks by Fritz Elfert, <felfert@to.com>
- *  Compatible Disk Layout enhancements by Carsten Otte, <cotte@de.ibm.com>
- *
- * Still to do:
- *   detect non-switch parameters ("dasdfmt -n 170 XY") and complain about them 
- */
-
-/* #define _LINUX_BLKDEV_H */
-
-#include <unistd.h>
-#include <stdio.h>
-#include <sys/types.h>
-#include <sys/stat.h>
-#include <fcntl.h>
-#include <sys/ioctl.h>
-#include <errno.h>
-#include <getopt.h>
-#include <limits.h>
-#include <stdlib.h>
-#include <string.h>
-#include <dirent.h>
-#include <mntent.h>
-#define __KERNEL__ /* we want to use kdev_t and not have to define it */
-#include <linux/kdev_t.h>
-#undef __KERNEL__
-
-#include <linux/fs.h>
-#include <asm/dasd.h>
-#include <linux/hdreg.h>
-
-#define EXIT_MISUSE 1
-#define EXIT_BUSY 2
-#define TEMPFILENAME "/tmp/ddfXXXXXX"
-#define TEMPFILENAMECHARS 8  /* 8 characters are fixed in all temp filenames */
-#define SLASHDEV "/dev/"
-#define PROC_DASD_DEVICES "/proc/dasd/devices"
-/* _PATH_MOUNTED is /etc/mtab - /proc/mounts does not show root-fs correctly */
-#define PROC_MOUNTS _PATH_MOUNTED
-#define PROC_SWAPS "/proc/swaps"
-#define DASD_DRIVER_NAME "dasd"
-#define LABEL_LENGTH 10
-#define PROC_LINE_LENGTH 80
-#define ERR_LENGTH 80
-
-#define MAX_FILELEN NAME_MAX+PATH_MAX
-
-#define GIVEN_DEVNO 1
-#define GIVEN_MAJOR 2
-#define GIVEN_MINOR 4
-
-#define CHECK_START 1
-#define CHECK_END 2
-#define CHECK_BLKSIZE 4
-#define CHECK_ALL ~0
-
-#define ERRMSG(x...) {fflush(stdout);fprintf(stderr,x);}
-#define ERRMSG_EXIT(ec,x...) {fflush(stdout);fprintf(stderr,x);exit(ec);}
-
-#define CHECK_SPEC_MAX_ONCE(i,str) \
-	{if (i>1) \
-		ERRMSG_EXIT(EXIT_MISUSE,"%s: " str " " \
-			"can only be specified once\n",prog_name);}
-
-#define PARSE_PARAM_INTO(x,param,base,str) \
-	{x=(int)strtol(param,&endptr,base); \
-	if (*endptr) \
-		ERRMSG_EXIT(EXIT_MISUSE,"%s: " str " " \
-			"is in invalid format\n",prog_name);}
-
-char *prog_name;/*="dasdfmt";*/
-char tempfilename[]=TEMPFILENAME;
-
-__u8 _ascebc[256] =
-{
- /*00 NUL   SOH   STX   ETX   EOT   ENQ   ACK   BEL */
-     0x00, 0x01, 0x02, 0x03, 0x37, 0x2D, 0x2E, 0x2F,
- /*08  BS    HT    LF    VT    FF    CR    SO    SI */
- /*              ->NL                               */
-     0x16, 0x05, 0x15, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F,
- /*10 DLE   DC1   DC2   DC3   DC4   NAK   SYN   ETB */
-     0x10, 0x11, 0x12, 0x13, 0x3C, 0x3D, 0x32, 0x26,
- /*18 CAN    EM   SUB   ESC    FS    GS    RS    US */
- /*                               ->IGS ->IRS ->IUS */
-     0x18, 0x19, 0x3F, 0x27, 0x22, 0x1D, 0x1E, 0x1F,
- /*20  SP     !     "     #     $     %     &     ' */
-     0x40, 0x5A, 0x7F, 0x7B, 0x5B, 0x6C, 0x50, 0x7D,
- /*28   (     )     *     +     ,     -    .      / */
-     0x4D, 0x5D, 0x5C, 0x4E, 0x6B, 0x60, 0x4B, 0x61,
- /*30   0     1     2     3     4     5     6     7 */
-     0xF0, 0xF1, 0xF2, 0xF3, 0xF4, 0xF5, 0xF6, 0xF7,
- /*38   8     9     :     ;     <     =     >     ? */
-     0xF8, 0xF9, 0x7A, 0x5E, 0x4C, 0x7E, 0x6E, 0x6F,
- /*40   @     A     B     C     D     E     F     G */
-     0x7C, 0xC1, 0xC2, 0xC3, 0xC4, 0xC5, 0xC6, 0xC7,
- /*48   H     I     J     K     L     M     N     O */
-     0xC8, 0xC9, 0xD1, 0xD2, 0xD3, 0xD4, 0xD5, 0xD6,
- /*50   P     Q     R     S     T     U     V     W */
-     0xD7, 0xD8, 0xD9, 0xE2, 0xE3, 0xE4, 0xE5, 0xE6,
- /*58   X     Y     Z     [     \     ]     ^     _ */
-     0xE7, 0xE8, 0xE9, 0xBA, 0xE0, 0xBB, 0xB0, 0x6D,
- /*60   `     a     b     c     d     e     f     g */
-     0x79, 0x81, 0x82, 0x83, 0x84, 0x85, 0x86, 0x87,
- /*68   h     i     j     k     l     m     n     o */
-     0x88, 0x89, 0x91, 0x92, 0x93, 0x94, 0x95, 0x96,
- /*70   p     q     r     s     t     u     v     w */
-     0x97, 0x98, 0x99, 0xA2, 0xA3, 0xA4, 0xA5, 0xA6,
- /*78   x     y     z     {     |     }     ~    DL */
-     0xA7, 0xA8, 0xA9, 0xC0, 0x4F, 0xD0, 0xA1, 0x07,
- /*80*/
-     0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F,
- /*88*/
-     0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F,
- /*90*/
-     0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F,
- /*98*/
-     0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F,
- /*A0*/
-     0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F,
- /*A8*/
-     0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F,
- /*B0*/
-     0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F,
- /*B8*/
-     0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F,
- /*C0*/
-     0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F,
- /*C8*/
-     0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F,
- /*D0*/
-     0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F,
- /*D8*/
-     0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F,
- /*E0        sz						*/
-     0x3F, 0x59, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F,
- /*E8*/
-     0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F,
- /*F0*/
-     0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F,
- /*F8*/
-     0x90, 0x3F, 0x3F, 0x3F, 0x3F, 0xEA, 0x3F, 0xFF
-};
-
-void convert_label(char *str)
-{
-	int i;
-	for (i=0;i<LABEL_LENGTH;i++) str[i]=_ascebc[str[i]];
-}
-
-void
-exit_usage(int exitcode)
-{
-#ifdef RANGE_FORMATTING
-	printf("Usage: %s [-htvyCLV] [-l <label>] [-b <blocksize>] [<range>] " \
-		"<diskspec>\n\n",prog_name);
-#else /* RANGE_FORMATTING */
-	printf("Usage: %s [-htvyCLV] [-l <label>] [-b <blocksize>] " \
-		"<diskspec>\n\n",prog_name);
-#endif /* RANGE_FORMATTING */
-	printf("       -t means testmode\n");
-	printf("       -v means verbose mode\n");
-	printf("       -C means format compatible disk layout\n");
-	printf("       -V means print version\n");
-	printf("       -L means don't write disk label\n");
-	printf("       <label> is a label which is converted to EBCDIC and " \
-		"written to disk\n");
-	printf("       <blocksize> has to be power of 2 and at least 512\n");
-#ifdef RANGE_FORMATTING
-	printf("       <range> is either\n");
-	printf("           -s <start_track> -e <end_track>\n");
-	printf("       or\n");
-	printf("           -r <start_track>-<end_track>\n");
-#endif /* RANGE_FORMATTING */
-	printf("       and <diskspec> is either\n");
-	printf("           -f /dev/dasdX\n");
-	printf("       or\n");
-	printf("           -n <s390-devnr>\n");
-	exit(exitcode);
-}
-
-void
-get_xno_from_xno(int *devno,kdev_t *major_no,kdev_t *minor_no,int mode)
-{
-	FILE *file;
-	int d,rc;
-	kdev_t mi,ma;
-	int mi_i,ma_i; /* for scanf :-( */
-	char line[PROC_LINE_LENGTH];
-
-	file=fopen(PROC_DASD_DEVICES,"r");
-	if (file==NULL)
-		ERRMSG_EXIT(EXIT_FAILURE,"%s: failed to open " \
-			PROC_DASD_DEVICES ": %s (do you have the /proc " \
-			"filesystem enabled?)\n",prog_name,strerror(errno));
-
-	/*	fgets(line,sizeof(line),file); omit first line */ 
-	while (fgets(line,sizeof(line),file)!=NULL) {
-                rc=sscanf(line,"%X %*[(A-Z) ] at (%d:%d)",&d,&ma_i,&mi_i);
-		ma=ma_i;
-		mi=mi_i;
-		if ( (rc==3) &&
-			!((d!=*devno)&&(mode&GIVEN_DEVNO)) &&
-			!((ma!=*major_no)&&(mode&GIVEN_MAJOR)) &&
-			!((mi!=*minor_no)&&(mode&GIVEN_MINOR)) ) {
-			*devno=d;
-			*major_no=ma;
-			*minor_no=mi;
-			/* yes, this is a quick exit, but the easiest way */
-			fclose(file);
-			return;
-		}
-	}
-	fclose(file);
-
-	ERRMSG_EXIT(EXIT_FAILURE,"%s: failed to find device in the /proc " \
-		    "filesystem (are you sure to have the right parameter " \
-		    "dasd=xxx?)\n",
-		prog_name);
-}
-
-char *
-get_devname_from_devno(int devno,int verbosity)
-{
-	kdev_t major_no,minor_no;
-	kdev_t file_major,file_minor;
-	struct stat stat_buf;
-	int rc;
-	int found;
-	char *devname;
-	char tmpname[MAX_FILELEN];
-
-	DIR *dp;
-	struct dirent *direntp;
-
-	/**** get minor number ****/
-	get_xno_from_xno(&devno,&major_no,&minor_no,GIVEN_DEVNO);
-
-	/**** get device file ****/
-	if ((dp=opendir(SLASHDEV)) == NULL)
-		ERRMSG_EXIT(EXIT_FAILURE,"%s: unable to read " SLASHDEV \
-			"\n",prog_name);
-	found=0;
-	while ((direntp=readdir(dp)) != NULL) {
-		strcpy(tmpname,SLASHDEV);
-		strcat(tmpname,direntp->d_name);
-		rc=stat(tmpname,&stat_buf);
-		if (!rc) {
-			file_major=MAJOR(stat_buf.st_rdev);
-			file_minor=MINOR(stat_buf.st_rdev);
-			if ((file_major==major_no) && (file_minor==minor_no)) {
-				found=1;
-				break;
-			}
-		}
-	}
-	if (found) {
-		devname=malloc(strlen(direntp->d_name));
-		strcpy(devname,tmpname);
-	}
-	rc=closedir(dp);
-	if (rc<0) ERRMSG("%s: unable to close directory " SLASHDEV \
-		"; continuing\n",prog_name);
-	if (found)
-		return devname;
-
-	if (verbosity>=1)
-		printf("I didn't find device node in " SLASHDEV \
-			"; trying to create a temporary node\n");
-
-	/**** get temp file and create device node *****/
-	rc=mkstemp(tempfilename);
-	if (rc==-1)
-		ERRMSG_EXIT(EXIT_FAILURE,"%s: failed to get temporary " \
-			"filename: %s\n",prog_name,strerror(errno));
-	close(rc);
-	rc=unlink(tempfilename);
-	
-	rc=mknod(tempfilename,S_IFBLK|0600,MKDEV(major_no,minor_no));
-	if (rc)
-		ERRMSG_EXIT(EXIT_FAILURE,"%s: failed to create temporary " \
-			"device node %s: %s\n",prog_name,tempfilename,
-			strerror(errno));
-	return tempfilename;
-}
-
-char *
-check_param(int mode,format_data_t data)
-{
-	char *s;
-
-	if (NULL==(s=malloc(ERR_LENGTH)))
-		ERRMSG_EXIT(EXIT_FAILURE,"%s: not enough memory.\n",prog_name);
-
-	if ((mode&CHECK_START)&&(data.start_unit<0)) {
-		strcpy(s,"start track must be greater than zero");
-		goto exit;
-	}
-	if ((mode&CHECK_END)&&(data.stop_unit<-1)) {
-		strcpy(s,"end track must be -1 or greater than zero");
-		goto exit;
-	}
-	if ((mode&CHECK_END)&&(data.start_unit>data.stop_unit)&&
-		(data.stop_unit!=-1)) {
-		strcpy(s,"end track must be higher than start track");
-		goto exit;
-	}
-
-	if ((mode&CHECK_BLKSIZE)&&(data.blksize<1)) {
-		strcpy(s,"blocksize must be a positive integer");
-		goto exit;
-	}
-	if (mode&CHECK_BLKSIZE) while (data.blksize>0) {
-		if ((data.blksize%2)&&(data.blksize!=1)) {
-			strcpy(s,"blocksize must be a power of 2");
-			goto exit;
-		}
-		data.blksize/=2;
-	}
-
-	free(s);
-	return NULL;
-exit:
-	return s;
-}
-
-#define ASK_PRINTOUT printf("Please enter %s",output)
-#define ASK_GETBUFFER fgets(buffer,sizeof(buffer),stdin)
-#define ASK_SCANFORNUMBER(var) rc=sscanf(buffer,"%d%c",&var,&c)
-#define ASK_COMPLAIN_FORMAT if ((rc==2)&&(c=='\n')) rc=1; \
-	if (rc==-1) rc=1; /* this happens, if enter is pressed */ \
-	if (rc!=1) printf(" -- wrong input, try again.\n")
-#define ASK_CHECK_PARAM(mode) str=check_param(mode,params); \
-		if (str!=NULL) { printf(" -- %s\n",str); rc=0; free(str); }
-
-format_data_t
-ask_user_for_data(format_data_t params)
-{
-	char buffer[20]; /* should be enough for inputing track numbers */
-	char c;
-	int i,rc;
-	char *str;
-	char output[60],o2[12];
-
-#ifdef RANGE_FORMATTING
-	i=params.start_unit;
-	do {
-		params.start_unit=i;
-		sprintf(output,"the start track of the range to format " \
-			"[%d]: ",i);
-		ASK_PRINTOUT;
-		ASK_GETBUFFER;
-		ASK_SCANFORNUMBER(params.start_unit);
-		ASK_COMPLAIN_FORMAT;
-		ASK_CHECK_PARAM(CHECK_START);
-	} while (rc!=1);
-
-	i=params.stop_unit;
-	do {
-		params.stop_unit=i;
-		sprintf(output,"the end track of the range to format [");
-		if (i==-1) sprintf(o2,"END]: "); else
-			sprintf(o2,"%d]: ",i);
-		strcat(output,o2);
-		ASK_PRINTOUT;
-		ASK_GETBUFFER;
-		if ( (!strcasecmp(buffer,"end")) ||
-			(!strcasecmp(buffer,"end\n")) ) {
-			rc=1;
-			params.stop_unit=-1;
-		} else {
-			ASK_SCANFORNUMBER(params.stop_unit);
-			ASK_COMPLAIN_FORMAT;
-			ASK_CHECK_PARAM(CHECK_END);
-		}
-	} while (rc!=1);
-#endif /* RANGE_FORMATTING */
-
-	i=params.blksize;
-	do {
-		params.blksize=i;
-		sprintf(output,"the blocksize of the formatting [%d]: ",i);
-		ASK_PRINTOUT;
-		ASK_GETBUFFER;
-		ASK_SCANFORNUMBER(params.blksize);
-		ASK_COMPLAIN_FORMAT;
-		ASK_CHECK_PARAM(CHECK_BLKSIZE);
-	} while (rc!=1);
-
-	return params;
-}
-
-/* Check if the device we are going to format is mounted.
- * If true, complain and exit.
- */
-void
-check_mounted(int major, int minor)
-{
-	FILE *f;
-	int ishift = 0;
-	struct mntent *ment;
-	struct stat stbuf;
-	char line[128];
-
-	/* If whole disk to be formatted ... */
-	if ((minor % (1U << DASD_PARTN_BITS)) == 0) {
-		/* ... ignore partition-selector */
-		minor >>= DASD_PARTN_BITS;
-		ishift = DASD_PARTN_BITS;
-	}
-	/*
-	 * first, check filesystems
-	 */
-	if (!(f = fopen(PROC_MOUNTS, "r")))
-		ERRMSG_EXIT(EXIT_FAILURE, "%s: %s\n", PROC_MOUNTS,
-			strerror(errno));
-	while ((ment = getmntent(f))) {
-		if (stat(ment->mnt_fsname, &stbuf) == 0)
-			if ((major == MAJOR(stbuf.st_rdev)) &&
-				(minor == (MINOR(stbuf.st_rdev)>>ishift))) {
-				ERRMSG("%s: device is mounted on %s!!\n",
-					prog_name,ment->mnt_dir);
-				ERRMSG_EXIT(EXIT_BUSY, "If you really want to "
-					"format it, please unmount it.\n");
-			}
-	}
-	fclose(f);
-	/*
-	 * second, check active swap spaces
-	 */
-	if (!(f = fopen(PROC_SWAPS, "r")))
-		ERRMSG_EXIT(EXIT_FAILURE, PROC_SWAPS " %s", strerror(errno));
-	/*
-	 * skip header line
-	 */
-	fgets(line, sizeof(line), f);
-	while (fgets(line, sizeof(line), f)) {
-		char *p;
-		for (p = line; *p && (!isspace(*p)); p++) ;
-		*p = '\0';
-		if (stat(line, &stbuf) == 0)
-			if ((major == MAJOR(stbuf.st_rdev)) &&
-				(minor == (MINOR(stbuf.st_rdev)>>ishift))) {
-				ERRMSG("%s: the device is in use for "
-					"swapping!!\n",prog_name);
-				ERRMSG_EXIT(EXIT_BUSY, "If you really want to "
-					"format it, please use swapoff %s.\n",
-					line);
-			}
-	}
-	fclose(f);
-}
-
-void
-do_format_dasd(char *dev_name,format_data_t format_params,int testmode,
-	int verbosity,int writenolabel,int labelspec,
-	char *label,int withoutprompt,int devno)
-{
-	int fd,rc;
-	struct stat stat_buf;
-	kdev_t minor_no,major_no;
-	int new_blksize;
-	unsigned int label_position;
-	struct hd_geometry new_geometry;
-	char inp_buffer[5]; /* to contain yes */
-
-	fd=open(dev_name,O_RDWR);
-	if (fd==-1)
-		ERRMSG_EXIT(EXIT_FAILURE,"%s: error opening device %s: " \
-			"%s\n",prog_name,dev_name,strerror(errno));
-
-	if (verbosity>=1) {
-	}
-
-	rc=stat(dev_name,&stat_buf);
-	if (rc) {
-		ERRMSG_EXIT(EXIT_FAILURE,"%s: error occurred during stat: " \
-			"%s\n",prog_name,strerror(errno));
-	} else {
-		if (!S_ISBLK(stat_buf.st_mode))
-			ERRMSG_EXIT(EXIT_FAILURE,"%s: file is not a " \
-				"blockdevice.\n",prog_name);
-		major_no=MAJOR(stat_buf.st_rdev);
-		minor_no=MINOR(stat_buf.st_rdev);
-	}
-	check_mounted(major_no, minor_no);
-
-	get_xno_from_xno(&devno,&major_no,&minor_no,
-			GIVEN_MAJOR|GIVEN_MINOR);
-	if ((!writenolabel) && (!labelspec)) {
-		sprintf(label,"LNX1 x%04x",devno);
-	}
-	
-	if ( ((withoutprompt)&&(verbosity>=1)) ||
-		(!withoutprompt) ) {
-		printf("\nI am going to format the device %s in the " \
-			"following way:\n",dev_name);
-		printf("   Device number of device : 0x%x\n",devno);
-		printf("   Major number of device  : %u\n",major_no);
-		printf("   Minor number of device  : %u\n",minor_no);
-		printf("   Labelling device        : %s\n",(writenolabel)?
-			"no":"yes");
-		if (!writenolabel)
-			printf("   Disk label              : %s\n",label);
-		if (format_params.intensity != DASD_FORMAT_DEFAULT_INTENSITY)
-			printf("   Compatible Disk Layout  : %s\n",(format_params.intensity&0x08)?
-			       "yes":"no");
-#ifdef RANGE_FORMATTING
-		printf("   Start track             : %d\n" \
-			,format_params.start_unit);
-		printf("   End track               : ");
-		if (format_params.stop_unit==-1)
-			printf("last track of disk\n");
-		else
-			printf("%d\n",format_params.stop_unit);
-#endif /* RANGE_FORMATTING */
-		printf("   Blocksize               : %d\n" \
-			,format_params.blksize);
-		if (testmode) printf("Test mode active, omitting ioctl.\n");
-	}
-
-	while (!testmode) {
-		if (!withoutprompt) {
-			printf("\n--->> ATTENTION! <<---\n");
-			printf("All data in the specified range of that " \
-				"device will be lost.\nType \"yes\" to " \
-				"continue, no will leave the disk untouched: ");
-			fgets(inp_buffer,sizeof(inp_buffer),stdin);
-			if (strcasecmp(inp_buffer,"yes") &&
-				strcasecmp(inp_buffer,"yes\n")) {
-				printf("Omitting ioctl call (disk will " \
-					"NOT be formatted).\n");
-				break;
-			}
-		}
-
-		if ( !(  (withoutprompt)&&(verbosity<1) ))
-			printf("Formatting the device. This may take a " \
-				"while (get yourself a coffee).\n");
-		rc=ioctl(fd,BIODASDFORMAT,format_params);
-		if (rc)
-			ERRMSG_EXIT(EXIT_FAILURE,"%s: the dasd driver " \
-				"returned with the following error " \
-				"message:\n%s\n",prog_name,strerror(errno));
-		printf("Finished formatting the device.\n");
-
-		if (!writenolabel) {
-			if (verbosity>0)
-				printf("Retrieving disk geometry... ");
-
-			rc=ioctl(fd,HDIO_GETGEO,&new_geometry);
-			if (rc) {
-				ERRMSG("%s: the ioctl call to get geometry " \
-					"returned with the following error " \
-					"message:\n%s\n",prog_name,
-					strerror(errno));
-				goto reread;
-			}
-	
-
-			rc=ioctl(fd,BLKSSZGET,&new_blksize);
-			if (rc) {
-				ERRMSG("%s: the ioctl call to get blocksize " \
-					"returned with the following error " \
-					"message:\n%s\n",prog_name,
-					strerror(errno));
-				goto reread;
-			}
-	
-			if (verbosity>0) printf("done\n");
-
-			label_position=new_geometry.start*new_blksize;
-	
-			if (verbosity>0) printf("Writing label... ");
-			convert_label(label);
-			rc=lseek(fd,label_position,SEEK_SET);
-			if (rc!=label_position) {
-				ERRMSG("%s: lseek on the device to %i " \
-					"failed with the following error " \
-					"message:\n%s\n",prog_name,
-					label_position,strerror(errno));
-				goto reread;
-			}
-			rc=write(fd,label,LABEL_LENGTH);
-			if (rc!=LABEL_LENGTH) {
-				ERRMSG("%s: writing the label only wrote %d " \
-					"bytes.\n",prog_name,rc);
-				goto reread;
-			}
-
-			sync();
-			sync();
-
-			if (verbosity>0) printf("done\n");
-		}
- reread:
-		printf("Rereading the partition table... ");
-		rc=ioctl(fd,BLKRRPART,NULL);
-		if (rc) {
-			ERRMSG("%s: error during rereading the partition " \
-			       "table: %s.\n",prog_name,strerror(errno));
-		} else printf("done.\n");
-
-		break;
-	}
-
-	rc=close(fd);
-	if (rc)
-		ERRMSG("%s: error during close: " \
-			"%s; continuing.\n",prog_name,strerror(errno));
-}
-
-
-
-int main(int argc,char *argv[]) {
-	int verbosity;
-	int testmode;
-	int withoutprompt;
-	int writenolabel,labelspec;
-
-	char *dev_name;
-	int devno;
-	char *dev_filename,*devno_param_str,*range_param_str;
-	char *start_param_str,*end_param_str,*blksize_param_str;
-	char label[LABEL_LENGTH+1];
-	
-	format_data_t format_params;
-
-	int rc;
-	int oc;
-	char *endptr;
-
-	char c1,c2,cbuffer[6]; /* should be able to contain -end plus 1 char */
-	int i,i1,i2;
-	char *str;
-
-	int start_specified,end_specified,blksize_specified;
-	int devfile_specified,devno_specified,range_specified;
-
-	/******************* initialization ********************/
-	prog_name=argv[0];
-
-	endptr=NULL;
-
-	/* set default values */
-	format_params.start_unit=DASD_FORMAT_DEFAULT_START_UNIT;
-	format_params.stop_unit=DASD_FORMAT_DEFAULT_STOP_UNIT;
-	format_params.blksize=DASD_FORMAT_DEFAULT_BLOCKSIZE;
-	format_params.intensity=DASD_FORMAT_DEFAULT_INTENSITY;
-	testmode=0;
-	verbosity=0;
-	withoutprompt=0;
-	writenolabel=0;
-	labelspec=0;
-	for (i=0;i<LABEL_LENGTH;i++) label[i]=' ';
-	label[LABEL_LENGTH]=0;
-
-	start_specified=end_specified=blksize_specified=0;
-	devfile_specified=devno_specified=range_specified=0;
-
-	/*************** parse parameters **********************/
-
-	/* avoid error message generated by getopt */
-	opterr=0;
-
-#ifdef RANGE_FORMATTING
-	while ( (oc=getopt(argc,argv,"r:s:e:b:n:l:f:ChLty?vV")) !=EOF) {
-#endif /* RANGE_FORMATTING */
-	while ( (oc=getopt(argc,argv,"b:n:l:f:ChLty?vV")) !=EOF) {
-		switch (oc) {
-		case 'y':
-			withoutprompt=1;
-			break;
-
-		case 't':
-			testmode=1;
-			break;
-
-		case 'v':
-			verbosity++;
-			break;
-
-		case '?': /* fall-through */
-		case ':':
-			exit_usage(EXIT_MISUSE);
-
-		case 'h':
-			exit_usage(0);
-		case 'C':
-                	format_params.intensity&=0x08;
-			break;
-
-		case 'V':
-			printf("%s version 0.99\n",prog_name);
-			exit(0);
-
-		case 'l':
-			strncpy(label,optarg,LABEL_LENGTH);
-			if (strlen(optarg)<LABEL_LENGTH)
-				label[strlen(optarg)]=' ';
-			labelspec++;
-			break;
-
-		case 'L':
-			writenolabel++;
-			break;
-
-#ifdef RANGE_FORMATTING
-		case 's' :
-			start_param_str=optarg;
-			start_specified++;
-			break;
-			
-		case 'e' :
-			end_param_str=optarg;
-			end_specified++;
-			break;
-
-		case 'r' :
-			range_param_str=optarg;
-			range_specified++;
-			break;
-#endif /* RANGE_FORMATTING */
-
-		case 'b' :
-			blksize_param_str=optarg;
-			blksize_specified++;
-			break;
-			
-		case 'n' :
-			devno_param_str=optarg;
-			devno_specified++;
-			break;
-		
-		case 'f' :
-			dev_filename=optarg;
-			devfile_specified++;
-			break;
-		}
-	}
-
-	/******************** checking of parameters **************/
-
-	/* convert range into -s and -e */
-	CHECK_SPEC_MAX_ONCE(range_specified,"formatting range");
-
-	while (range_specified) {
-		start_specified++;
-		end_specified++;
-
-		/* scan for 1 or 2 integers, separated by a dash */
-		rc=sscanf(range_param_str,"%d%c%d%c",&i1,&c1,&i2,&c2);
-		if ((rc==3)&&(c1=='-')) {
-			format_params.start_unit=i1;
-			format_params.stop_unit=i2;
-			break;
-		}
-		if (rc==1) {
-			format_params.start_unit=i1;
-			break;
-		}
-
-		/* scan for integer and -END */
-		rc=sscanf(range_param_str,"%d%s",&i1,cbuffer);
-		if ((rc==2)&&(!strcasecmp(cbuffer,"-END"))) {
-			format_params.start_unit=i1;
-			format_params.stop_unit=-1;
-			break;
-		}
-		ERRMSG_EXIT(EXIT_MISUSE,"%s: specified range " \
-			"is in invalid format\n",prog_name);
-	}
-
-	if ((!devfile_specified)&&(!devno_specified))
-		ERRMSG_EXIT(EXIT_MISUSE,"%s: device to format " \
-			"not specified\n",prog_name);
-
-	if ((devfile_specified+devno_specified)>1)
-		ERRMSG_EXIT(EXIT_MISUSE,"%s: device to format " \
-			"can only be specified once\n",prog_name);
-
-	if ((!start_specified)&&(!end_specified)&&(!range_specified)&&
-		(!blksize_specified)) {
-		format_params=ask_user_for_data(format_params);
-	}
-
-	CHECK_SPEC_MAX_ONCE(start_specified,"start track");
-	CHECK_SPEC_MAX_ONCE(end_specified,"end track");
-	CHECK_SPEC_MAX_ONCE(blksize_specified,"blocksize");
-	CHECK_SPEC_MAX_ONCE(labelspec,"label");
-	CHECK_SPEC_MAX_ONCE(writenolabel,"omit-label-writing flag");
-
-	if (devno_specified)
-		PARSE_PARAM_INTO(devno,devno_param_str,16,"device number");
-	if (start_specified&&!range_specified)
-		PARSE_PARAM_INTO(format_params.start_unit,start_param_str,10,
-			"start track");
-	if (end_specified&&!range_specified)
-		PARSE_PARAM_INTO(format_params.stop_unit,end_param_str,10,
-			"end track");
-	if (blksize_specified)
-		PARSE_PARAM_INTO(format_params.blksize,blksize_param_str,10,
-			"blocksize");
-
-	/***********get dev_name *********************/
-	dev_name=(devno_specified)?
-		get_devname_from_devno(devno,verbosity):
-		dev_filename;
-
-	/*** range checking *********/
-	str=check_param(CHECK_ALL,format_params);
-	if (str!=NULL) ERRMSG_EXIT(EXIT_MISUSE,"%s: %s\n",prog_name,str);
-
-	/******* issue the real command and reread part table *******/
-	do_format_dasd(dev_name,format_params,testmode,verbosity,
-		writenolabel,labelspec,label,withoutprompt,devno);
-
-	/*************** cleanup ********************************/
-	if (strncmp(dev_name,TEMPFILENAME,TEMPFILENAMECHARS)==0) {
-		rc=unlink(dev_name);
-		if ((rc)&&(verbosity>=1))
-			ERRMSG("%s: temporary device node %s could not be " \
-				"removed: %s\n",prog_name,dev_name,
-				strerror(errno));
-	} else {
-		if (devno_specified) {
-			/* so we have allocated space for the filename */
-			free(dev_name);
-		}
-	}
-
-	return 0;
-}
diff -u --recursive --new-file v2.4.7/linux/arch/s390/tools/silo/Makefile linux/arch/s390/tools/silo/Makefile
--- v2.4.7/linux/arch/s390/tools/silo/Makefile	Tue Feb 13 14:13:44 2001
+++ linux/arch/s390/tools/silo/Makefile	Wed Dec 31 16:00:00 1969
@@ -1,15 +0,0 @@
-all: silo
-
-silo.o: silo.c
-	$(CC) -c -o silo.o -O2 silo.c
-
-cfg.o: cfg.c
-	$(CC) -c -o cfg.o -O2 cfg.c
-
-silo: silo.o cfg.o
-	$(CC) -o $@ $^
-	$(STRIP) $@
-
-clean:
-	rm -f *.o silo
-
diff -u --recursive --new-file v2.4.7/linux/arch/s390/tools/silo/cfg.c linux/arch/s390/tools/silo/cfg.c
--- v2.4.7/linux/arch/s390/tools/silo/cfg.c	Fri May 12 11:41:45 2000
+++ linux/arch/s390/tools/silo/cfg.c	Wed Dec 31 16:00:00 1969
@@ -1,373 +0,0 @@
-/* cfg.c  -  Configuration file parser */
-
-/* Copyright 1992-1997 Werner Almesberger. See file COPYING for details. */
-
-
-#include <stdlib.h>
-#include <stdio.h>
-#include <stdarg.h>
-#include <ctype.h>
-#include <string.h>
-
-#include "cfg.h"
-
-#define MAX_TOKEN 200
-#define MAX_VAR_NAME MAX_TOKEN
-
-static FILE *file;
-static char flag_set;
-static char *last_token = NULL,*last_item = NULL,*last_value = NULL;
-static int line_num;
-static char *file_name = NULL;
-static int back = 0; /* can go back by one char */
-
-
-void pdie(char *msg)
-{
-    fflush(stdout);
-    perror(msg);
-    exit(1);
-}
-
-
-void die(char *fmt,...)
-{
-    va_list ap;
-
-    fflush(stdout);
-    va_start(ap,fmt);
-    vfprintf(stderr,fmt,ap);
-    va_end(ap);
-    fputc('\n',stderr);
-    exit(1);
-}
-
-char *pstrdup(const char *str)
-{
-    char *this;
-
-    if ((this = strdup(str)) == NULL) pdie("Out of memory");
-    return this;
-}
-
-int cfg_open(char *name)
-{
-    if (!strcmp(name,"-")) file = stdin;
-    else if (!(file = fopen(file_name = name,"r"))) pdie(name);
-    line_num = 1;
-    return fileno(file);
-}
-
-void cfg_error(char *msg,...)
-{
-    va_list ap;
-
-    fflush(stdout);
-    va_start(ap,msg);
-    vfprintf(stderr,msg,ap);
-    va_end(ap);
-    if (!file_name) fputc('\n',stderr);
-    else fprintf(stderr," near line %d in file %s\n",line_num,file_name);
-    exit(1);
-}
-
-
-static int next_raw(void)
-{
-    int ch;
-
-    if (!back) return getc(file);
-    ch = back;
-    back = 0;
-    return ch;
-}
-
-
-static int next(void)
-{
-    static char *var;
-    char buffer[MAX_VAR_NAME+1];
-    int ch,braced;
-    char *put;
-
-    if (back) {
-	ch = back;
-	back = 0;
-	return ch;
-    }
-    if (var && *var) return *var++;
-    ch = getc(file);
-    if (ch == '\\') {
-	ch = getc(file);
-	if (ch == '$') return ch;
-	ungetc(ch,file);
-	return '\\';
-    }
-    if (ch != '$') return ch;
-    ch = getc(file);
-    braced = ch == '{';
-    put = buffer;
-    if (!braced) *put++ = ch;
-    while (1) {
-	ch = getc(file);
-#if 0
-	if (!braced && ch < ' ') {
-	    ungetc(ch,file);
-	    break;
-	}
-#endif
-	if (ch == EOF) cfg_error("EOF in variable name");
-	if (ch < ' ') cfg_error("control character in variable name");
-	if (braced && ch == '}') break;
-	if (!braced && !isalpha(ch) && !isdigit(ch) && ch != '_') {
-	    ungetc(ch,file);
-	    break;
-	}
-	if (put-buffer == MAX_VAR_NAME) cfg_error("variable name too long");
-	*put++ = ch;
-    }
-    *put = 0;
-    if (!(var = getenv(buffer))) cfg_error("unknown variable \"%s\"",buffer);
-    return next();
-}
-
-
-static void again(int ch)
-{
-    if (back) die("internal error: again invoked twice");
-    back = ch;
-}
-
-
-static char *cfg_get_token(void)
-{
-    char buf[MAX_TOKEN+1];
-    char *here;
-    int ch,escaped;
-
-    if (last_token) {
-	here = last_token;
-	last_token = NULL;
-	return here;
-    }
-    while (1) {
-	while ((ch = next()), ch == ' ' || ch == '\t' || ch == '\n')
-	    if (ch == '\n') line_num++;
-	if (ch == EOF) return NULL;
-	if (ch != '#') break;
-	while ((ch = next_raw()), ch != '\n')
-	    if (ch == EOF) return NULL;
-	line_num++;
-    }
-    if (ch == '=') return pstrdup("=");
-    if (ch == '"') {
-	here = buf;
-	while (here-buf < MAX_TOKEN) {
-	    if ((ch = next()) == EOF) cfg_error("EOF in quoted string");
-	    if (ch == '"') {
-		*here = 0;
-		return pstrdup(buf);
-	    }
-	    if (ch == '\\') {
-		ch = next();
-		if (ch != '"' && ch != '\\' && ch != '\n')
-		    cfg_error("Bad use of \\ in quoted string");
-		if (ch == '\n') {
-		    while ((ch = next()), ch == ' ' || ch == '\t');
-		    if (!ch) continue;
-		    again(ch);
-		    ch = ' ';
-		}
-	    }
-	    if (ch == '\n' || ch == '\t')
-		cfg_error("\\n and \\t are not allowed in quoted strings");
-	    *here++ = ch;
-	}
-	cfg_error("Quoted string is too long");
-	return 0; /* not reached */
-    }
-    here = buf;
-    escaped = 0;
-    while (here-buf < MAX_TOKEN) {
-	if (escaped) {
-	    if (ch == EOF) cfg_error("\\ precedes EOF");
-	    if (ch == '\n') line_num++;
-	    else *here++ = ch == '\t' ? ' ' : ch;
-	    escaped = 0;
-	}
-	else {
-	    if (ch == ' ' || ch == '\t' || ch == '\n' || ch == '#' ||
-	      ch == '=' || ch == EOF) {
-		again(ch);
-		*here = 0;
-		return pstrdup(buf);
-	    }
-	    if (!(escaped = (ch == '\\'))) *here++ = ch;
-	}
-	ch = next();
-    }
-    cfg_error("Token is too long");
-    return 0; /* not reached */
-}
-
-
-static void cfg_return_token(char *token)
-{
-    last_token = token;
-}
-
-
-static int cfg_next(char **item,char **value)
-{
-    char *this;
-
-    if (last_item) {
-	*item = last_item;
-	*value = last_value;
-	last_item = NULL;
-	return 1;
-    }
-    *value = NULL;
-    if (!(*item = cfg_get_token())) return 0;
-    if (!strcmp(*item,"=")) cfg_error("Syntax error");
-    if (!(this = cfg_get_token())) return 1;
-    if (strcmp(this,"=")) {
-	cfg_return_token(this);
-	return 1;
-    }
-    if (!(*value = cfg_get_token())) cfg_error("Value expected at EOF");
-    if (!strcmp(*value,"=")) cfg_error("Syntax error after %s",*item);
-    return 1;
-}
-
-
-static void cfg_return(char *item,char *value)
-{
-    last_item = item;
-    last_value = value;
-}
-
-
-void cfg_init(CONFIG *table)
-{
-    while (table->type != cft_end) {
-	switch (table->type) {
-	    case cft_strg:
-		if (table->data) free(table->data);
-	    case cft_flag:
-		table->data = NULL;
-		break;
-	    case cft_link:
-		table = ((CONFIG *) table->action)-1;
-		break;
-	    default:
-		die("Unknown syntax code %d",table->type);
-	}
-	table++;
-    }
-}
-
-
-static int cfg_do_set(CONFIG *table,char *item,char *value,int copy,
-    void *context)
-{
-    CONFIG *walk;
-
-    for (walk = table; walk->type != cft_end; walk++) {
-	if (walk->name && !strcasecmp(walk->name,item)) {
-	    if (value && walk->type != cft_strg)
-		cfg_error("'%s' doesn't have a value",walk->name);
-	    if (!value && walk->type == cft_strg)
-		cfg_error("Value expected for '%s'",walk->name);
-	    if (walk->data) {
-		if (walk->context == context)
-		    cfg_error("Duplicate entry '%s'",walk->name);
-		else {
-		    fprintf(stderr,"Ignoring entry '%s'\n",walk->name);
-		    if (!copy) free(value);
-		    return 1;
-		}
-	    }
-	    if (walk->type == cft_flag) walk->data = &flag_set;
-	    else if (walk->type == cft_strg) {
-		    if (copy) walk->data = pstrdup(value);
-		    else walk->data = value;
-	    }
-	    walk->context = context;
-	    if (walk->action) ((void (*)(void)) walk->action)();
-	    break;
-	}
-	if (walk->type == cft_link) walk = ((CONFIG *) walk->action)-1;
-    }
-    if (walk->type != cft_end) return 1;
-    cfg_return(item,value);
-    return 0;
-}
-
-
-void cfg_set(CONFIG *table,char *item,char *value,void *context)
-{
-    if (!cfg_do_set(table,item,value,1,context))
-	cfg_error("cfg_set: Can't set %s",item);
-}
-
-
-void cfg_unset(CONFIG *table,char *item)
-{
-    CONFIG *walk;
-
-    for (walk = table; walk->type != cft_end; walk++)
-	if (walk->name && !strcasecmp(walk->name,item)) {
-	    if (!walk->data) die("internal error (cfg_unset %s, unset)",item);
-	    if (walk->type == cft_strg) free(walk->data);
-	    walk->data = NULL;
-	    return;
-	}
-    die("internal error (cfg_unset %s, unknown",item);
-}
-
-
-int cfg_parse(CONFIG *table)
-{
-    char *item,*value;
-
-    while (1) {
-	if (!cfg_next(&item,&value)) return 0;
-	if (!cfg_do_set(table,item,value,0,table)) return 1;
-	free(item);
-    }
-}
-
-
-int cfg_get_flag(CONFIG *table,char *item)
-{
-    CONFIG *walk;
-
-    for (walk = table; walk->type != cft_end; walk++) {
-	if (walk->name && !strcasecmp(walk->name,item)) {
-	    if (walk->type != cft_flag)
-		die("cfg_get_flag: operating on non-flag %s",item);
-	    return !!walk->data;
-	}
-	if (walk->type == cft_link) walk = ((CONFIG *) walk->action)-1;
-    }
-    die("cfg_get_flag: unknown item %s",item);
-    return 0; /* not reached */
-}
-
-
-char *cfg_get_strg(CONFIG *table,char *item)
-{
-    CONFIG *walk;
-
-    for (walk = table; walk->type != cft_end; walk++) {
-	if (walk->name && !strcasecmp(walk->name,item)) {
-	    if (walk->type != cft_strg)
-		die("cfg_get_strg: operating on non-string %s",item);
-	    return walk->data;
-	}
-	if (walk->type == cft_link) walk = ((CONFIG *) walk->action)-1;
-    }
-    die("cfg_get_strg: unknown item %s",item);
-    return 0; /* not reached */
-}
diff -u --recursive --new-file v2.4.7/linux/arch/s390/tools/silo/cfg.h linux/arch/s390/tools/silo/cfg.h
--- v2.4.7/linux/arch/s390/tools/silo/cfg.h	Fri May 12 11:41:45 2000
+++ linux/arch/s390/tools/silo/cfg.h	Wed Dec 31 16:00:00 1969
@@ -1,58 +0,0 @@
-/* cfg.h  -  Configuration file parser */
-
-/* Copyright 1992-1996 Werner Almesberger. See file COPYING for details. */
-
-
-#ifndef CFG_H
-#define CFG_H
-
-typedef enum { cft_strg, cft_flag, cft_link, cft_end } CFG_TYPE;
-
-typedef struct {
-    CFG_TYPE type;
-    char *name;
-    void *action;
-    void *data;
-    void *context;
-} CONFIG;
-
-extern int cfg_open(char *name);
-
-/* Opens the configuration file. Returns the file descriptor of the open
-   file. */
-
-extern void cfg_error(char *msg,...);
-
-/* Signals an error while parsing the configuration file and terminates the
-   program. */
-
-extern void cfg_init(CONFIG *table);
-
-/* Initializes the specified table. */
-
-extern void cfg_set(CONFIG *table,char *item,char *value,void *context);
-
-/* Sets the specified variable in table. If the variable has already been set
-   since the last call to cfg_init, a warning message is issued if the context
-   keys don't match or a fatal error is reported if they do. */
-
-extern void cfg_unset(CONFIG *table,char *item);
-
-/* Unsets the specified variable in table. It is a fatal error if the variable
-   was not set. */
-
-extern int cfg_parse(CONFIG *table);
-
-/* Parses the configuration file for variables contained in table. A non-zero
-   value is returned if a variable not found in table has been met. Zero is
-   returned if EOF has been reached. */
-
-extern int cfg_get_flag(CONFIG *table,char *item);
-
-/* Returns one if the specified variable is set, zero if it isn't. */
-
-extern char *cfg_get_strg(CONFIG *table,char *item);
-
-/* Returns the value of the specified variable if it is set, NULL otherwise. */
-
-#endif
diff -u --recursive --new-file v2.4.7/linux/arch/s390/tools/silo/silo.c linux/arch/s390/tools/silo/silo.c
--- v2.4.7/linux/arch/s390/tools/silo/silo.c	Wed Apr 11 19:02:27 2001
+++ linux/arch/s390/tools/silo/silo.c	Wed Dec 31 16:00:00 1969
@@ -1,586 +0,0 @@
-/*
- *  arch/s390/boot/silo.c
- *
- *  S390 version
- *    Copyright (C) 1999,2000 IBM Deutschland Entwicklung GmbH, IBM Corporation
- *
- *    Report bugs to: <linux390@de.ibm.com>
- *
- *    Author(s): Holger Smolinski <Holger.Smolinski@de.ibm.com>
- *               Fritz Elfert <felfert@to.com> contributed support for
- *                	/etc/silo.conf based on Intel's lilo
- *    Changes  :
- *               01/15/01 Holger Smolinski <Holger.Smolinski@de.ibm.com>
- *                 adapted to deal with devices and bootsects of various sizes
- */
-
-#include <stddef.h>
-#include <stdlib.h>
-#include <stdio.h>
-#include <string.h>
-#include <unistd.h>
-#include <fcntl.h>
-#include <errno.h>
-#include <limits.h>
-#include <dirent.h>
-#include <linux/fs.h>
-#include <sys/types.h>
-#include <sys/stat.h>
-#include <sys/ioctl.h>
-#include <asm/ioctl.h>
-
-#include "cfg.h"
-
-CONFIG cf_options[] = {
-  { cft_strg, "append",		NULL,		NULL,NULL },
-  { cft_strg, "image",		NULL,		NULL,NULL },
-  { cft_strg, "ipldevice",	NULL,		NULL,NULL },
-  { cft_strg, "bootsect",	NULL,		NULL,NULL },
-  { cft_strg, "map",		NULL,		NULL,NULL },
-  { cft_strg, "parmfile",	NULL,		NULL,NULL },
-  { cft_strg, "ramdisk",	NULL,		NULL,NULL },
-  { cft_strg, "root",		NULL,		NULL,NULL },
-  { cft_flag, "readonly",	NULL,		NULL,NULL },
-  { cft_strg, "verbose",	NULL,		NULL,NULL },
-  { cft_strg, "testlevel",	NULL,		NULL,NULL },
-  { cft_end,  NULL,		NULL,		NULL,NULL }
-};
-  
-/* from dasd.h */
-#define DASD_PARTN_BITS 2
-#define BIODASDRWTB _IOWR('D',0,int)
-/* end */
-
-#define SILO_CFG "/etc/silo.conf"
-#define SILO_IMAGE "./image"
-#define SILO_BOOTMAP "./boot.map"
-#define SILO_PARMFILE "./parmfile"
-#define SILO_BOOTSECT "/boot/ipleckd.boot"
-
-#define PRINT_LEVEL(x,y...) if ( silo_options.verbosity >= x ) printf(y)
-#define ERROR_LEVEL(x,y...) if ( silo_options.verbosity >= x ) fprintf(stderr,y)
-#define TOGGLE(x) ((x)=((x)?(0):(1)))
-#define GETARG(x) {int len=strlen(optarg);x=malloc(len);strncpy(x,optarg,len);PRINT_LEVEL(1,"%s set to %s\n",#x,optarg);}
-
-#define ITRY(x) if ( (x) == -1 ) { ERROR_LEVEL(0,"%s (line:%d) '%s' returned %d='%s'\n", __FILE__,__LINE__,#x,errno,strerror(errno)); usage(); exit(1); }
-#define NTRY(x) if ( (x) == 0 ) { ERROR_LEVEL(0,"%s (line:%d) '%s' returned %d='%s'\n", __FILE__,__LINE__,#x,errno,strerror(errno)); usage(); exit(1); }
-
-#define MAX_CLUSTERS 256
-#define PARTN_MASK ((1 << DASD_PARTN_BITS) - 1)
-
-#define SILO_VERSION "1.1"
-
-struct silo_options
-  {
-    short int verbosity;
-    short int testlevel;
-    char *image;
-    char *ipldevice;
-    char *parmfile;
-    char *ramdisk;
-    char *bootsect;
-    char *conffile;
-    char *bootmap;
-  }
-silo_options =
-{
-  1,				/* verbosity */
-  2,				/* testlevel */
-    SILO_IMAGE,			/* image */
-    NULL,			/* ipldevice */
-    SILO_PARMFILE,		/* parmfile */
-    NULL,			/* initrd */
-    SILO_BOOTSECT,		/* bootsector */
-    SILO_CFG,                   /* silo.conf file */
-    SILO_BOOTMAP,               /* boot.map */
-};
-
-struct blockdesc
-  {
-    unsigned long off;
-    unsigned short ct;
-    unsigned long addr;
-  };
-
-struct blocklist
-  {
-    struct blockdesc blk[MAX_CLUSTERS];
-    unsigned short ix;
-  };
-
-void
-usage (void)
-{
-  printf ("Usage:\n");
-  printf ("silo -d ipldevice [additional options]\n");
-  printf ("-d /dev/node : set ipldevice to /dev/node\n");
-  printf ("-f image : set image to image\n");
-  printf ("-F conffile : specify configuration file (/etc/silo.conf)\n");
-  printf ("-p parmfile : set parameter file to parmfile\n");
-  printf ("-b bootsect : set bootsector to bootsect\n");
-  printf ("Additional options\n");
-  printf ("-B bootmap:\n");
-  printf ("-v: increase verbosity level\n");
-  printf ("-v#: set verbosity level to #\n");
-  printf ("-t: decrease testing level\n");
-  printf ("-h: print this message\n");
-  printf ("-?: print this message\n");
-  printf ("-V: print version\n");
-}
-
-int
-read_cfg(struct silo_options *o)
-{
-	char *tmp;
-	if (access(o->conffile, R_OK) && (errno == ENOENT))
-		return 0;
-	/* If errno != ENOENT, let cfg_open report an error */
-	cfg_open(o->conffile);
-	cfg_parse(cf_options);
-	tmp = cfg_get_strg(cf_options, "ipldevice");
-	if ( ! o->ipldevice  && tmp ) 
-		o->ipldevice = tmp;
-	tmp = cfg_get_strg(cf_options, "image");
-	if ( ! strncmp(o-> image,SILO_IMAGE,strlen(SILO_IMAGE)) && tmp ) 
-		o->image = tmp;
-	tmp = cfg_get_strg(cf_options, "parmfile");
-	if ( !strncmp(o->parmfile,SILO_PARMFILE,strlen(SILO_PARMFILE)) && tmp) 
-		o->parmfile = tmp;
-	if ( ! o -> ramdisk ) 
-		o->ramdisk = cfg_get_strg(cf_options, "ramdisk");
-	tmp = cfg_get_strg(cf_options, "bootsect");
-	if ( !strncmp(o -> bootsect,SILO_BOOTSECT,strlen(SILO_BOOTSECT))&&tmp)
-		o->bootsect = tmp;
-	tmp = cfg_get_strg(cf_options, "map") ;
-	if ( !strncmp(o -> bootmap,SILO_BOOTMAP,strlen(SILO_BOOTMAP)) && tmp) 
-		o->bootmap = tmp; 
-	tmp = cfg_get_strg(cf_options, "verbose");
-	if ( tmp ) {
-		unsigned short v;
-		sscanf (tmp, "%hu", &v);
-		o->verbosity = v;
-	}
-	tmp = cfg_get_strg(cf_options, "testlevel");
-	if ( tmp ) {
-		unsigned short t;
-		sscanf (tmp, "%hu", &t);
-		o->testlevel += t;
-	}
-	return 1;
-}
-
-char *
-gen_tmpparm( char *pfile )
-{
-	char *append = cfg_get_strg(cf_options, "append");
-	char *root = cfg_get_strg(cf_options, "root");
-	int ro = cfg_get_flag(cf_options, "readonly");
-	FILE *f,*of;
-	char *fn;
-	char c;
-	char *tmpdir=NULL,*save=NULL;
-
-	if (!append && !root && !ro)
-		return pfile;
-	of = fopen(pfile, "r");
-	if ( of ) {
-		NTRY( fn = tempnam(NULL,"parm."));
-	} else {
-		fn = pfile;
-	}
-	NTRY( f = fopen(fn, "a+"));
-	if ( of ) {
-		while ( ! feof (of) ) {
-		  c=fgetc(of);
-	  	fputc(c,f);
-		}
-	}
-	if (root)
-		fprintf(f, " root=%s", root);
-	if (ro)
-		fprintf(f, " ro");
-	if (append)
-		fprintf(f, " %s", append);
-	fprintf(f, "\n");
-	fclose(f);
-	fclose(of);
-	printf ("tempfile is %s\n",fn);
-	return strdup(fn);
-}
-
-int
-parse_options (struct silo_options *o, int argc, char *argv[])
-{
-  int rc = 0;
-  int oc;
-
-  while ((oc = getopt (argc, argv, "Vf:F:d:p:r:b:B:h?v::t::")) != -1)
-    {
-      switch (oc)
-	{
-	case 'V':
-	  printf("silo version: %s\n",SILO_VERSION);
-	  exit(0);
-	case 'v':
-	  {
-	    unsigned short v;
-	    if (optarg && sscanf (optarg, "%hu", &v))
-	      o->verbosity = v;
-	    else
-	      o->verbosity++;
-	    PRINT_LEVEL (1, "Verbosity value is now %hu\n", o->verbosity);
-	    break;
-	  }
-	case 't':
-	  {
-	    unsigned short t;
-	    if (optarg && sscanf (optarg, "%hu", &t))
-	      o->testlevel -= t;
-	    else
-	      o->testlevel--;
-            PRINT_LEVEL (1, "Testonly flag is now %d\n", o->testlevel);
-	    break;
-	  }
-	case 'h':
-	case '?':
-	  usage ();
-	  exit(0);
-	case 'd':
-	  GETARG (o->ipldevice);
-	  break;
-	case 'f':
-	  GETARG (o->image);
-	  break;
-        case 'F':                         
- 	   GETARG (o->conffile);              
- 	   break;                          
-	case 'p':
-	  GETARG (o->parmfile);
-	  break;
-	case 'r':
-	  GETARG (o->ramdisk);
-	  break;
-	case 'b':
-	  GETARG (o->bootsect);
-	  break;
-	case 'B':
-	  GETARG (o->bootmap);
-	default:
-	  rc = EINVAL;
-	  break;
-	}
-    }
-  read_cfg(o);
-  return rc;
-}
-
-int
-verify_device (char *name)
-{
-  int rc = 0;
-  struct stat dst;
-  struct stat st;
-  ITRY (stat (name, &dst));
-  if (S_ISBLK (dst.st_mode))
-    {
-      if (!(MINOR (dst.st_rdev) & PARTN_MASK))
-	{
-	  rc = dst.st_rdev;
-	}
-      else
-	/* invalid MINOR & PARTN_MASK */
-	{
-	  ERROR_LEVEL (1, "Cannot boot from partition %d %d %d",
-		       (int) PARTN_MASK, (int) MINOR (dst.st_rdev), (int) (PARTN_MASK & MINOR (dst.st_rdev)));
-	  rc = -1;
-	  errno = EINVAL;
-	}
-    }
-  else
-    /* error S_ISBLK */
-    {
-      ERROR_LEVEL (1, "%s is no block device\n", name);
-      rc = -1;
-      errno = EINVAL;
-    }
-  return rc;
-}
-
-int
-verify_file (char *name, int dev)
-{
-  int rc = 0;
-  struct stat dst;
-  struct stat st;
-  int bs = 1024;
-  int l;
-
-  ITRY(stat ( name, &dst ));
-  if (S_ISREG (dst.st_mode))
-    {
-      if ((unsigned) MAJOR (dev) == (unsigned) MAJOR (dst.st_dev) && (unsigned) MINOR (dev) == (unsigned) (MINOR (dst.st_dev) & ~PARTN_MASK))
-	{
-	  /* whatever to do if all is ok... */
-	}
-      else
-	/* devicenumber doesn't match */
-	{
-	  ERROR_LEVEL (1, "%s is not on device (%d/%d) but on (%d/%d)\n", name, (unsigned) MAJOR (dev), (unsigned) MINOR (dev), (unsigned) MAJOR (dst.st_dev), (unsigned) (MINOR (dst.st_dev) & ~PARTN_MASK));
-	  rc = -1;
-	  errno = EINVAL;
-	}
-    }
-  else
-    /* error S_ISREG */
-    {
-      ERROR_LEVEL (1, "%s is neither regular file nor linkto one\n", name);
-      rc = -1;
-      errno = EINVAL;
-    }
-  return rc;
-}
-
-int
-verify_options (struct silo_options *o)
-{
-  int rc = 0;
-  int dev = 0;
-  int crc = 0;
-  if (!o->ipldevice || !o->image || !o->bootsect)
-    {
-     if (!o->ipldevice)
-       fprintf(stderr,"ipldevice\n");
-     if (!o->image)
-       fprintf(stderr,"image\n");
-     if (!o->bootsect)
-       fprintf(stderr,"bootsect\n");
-
-      usage ();
-      exit (1);
-    }
-  PRINT_LEVEL (1, "Testlevel is set to %d\n",o->testlevel);
-
-  PRINT_LEVEL (1, "IPL device is: '%s'", o->ipldevice);
-  ITRY (dev = verify_device (o->ipldevice));
-  PRINT_LEVEL (2, "...ok...(%d/%d)", (unsigned short) MAJOR (dev), (unsigned short) MINOR (dev));
-  PRINT_LEVEL (1, "\n");
-
-  PRINT_LEVEL (0, "bootsector is: '%s'", o->bootsect);
-  ITRY (verify_file (o->bootsect, dev));
-  PRINT_LEVEL (1, "...ok...");
-  PRINT_LEVEL (0, "\n");
-
-  if ( o -> testlevel > 0  && 
-       ! strncmp( o->bootmap, SILO_BOOTMAP,strlen(SILO_BOOTMAP) )) {
-     NTRY( o -> bootmap = tempnam(NULL,"boot."));
-  }
-  PRINT_LEVEL (0, "bootmap is set to: '%s'", o->bootmap);
-  if ( access ( o->bootmap, O_RDWR ) == -1 ) {
-    if ( errno == ENOENT ) {
-      ITRY (creat ( o-> bootmap, O_RDWR ));
-    } else {
-      PRINT_LEVEL(1,"Cannot access bootmap file '%s': %s\n",o->bootmap,
-		  strerror(errno));
-    }
-  }
-  ITRY (verify_file (o->bootmap, dev));
-  PRINT_LEVEL (1, "...ok...");
-  PRINT_LEVEL (0, "\n");
-
-  PRINT_LEVEL (0, "Kernel image is: '%s'", o->image);
-  ITRY (verify_file (o->image, dev));
-  PRINT_LEVEL (1, "...ok...");
-  PRINT_LEVEL (0, "\n");
-
-  PRINT_LEVEL (0, "original parameterfile is: '%s'", o->parmfile);
-  ITRY (verify_file (o->parmfile, dev));
-  PRINT_LEVEL (1, "...ok...");
-  o->parmfile = gen_tmpparm(o->parmfile);
-  PRINT_LEVEL (0, "final parameterfile is: '%s'", o->parmfile);
-  ITRY (verify_file (o->parmfile, dev));
-  PRINT_LEVEL (1, "...ok...");
-  PRINT_LEVEL (0, "\n");
-
-  if (o->ramdisk)
-    {
-      PRINT_LEVEL (0, "initialramdisk is: '%s'", o->ramdisk);
-      ITRY (verify_file (o->ramdisk, dev));
-      PRINT_LEVEL (1, "...ok...");
-      PRINT_LEVEL (0, "\n");
-    }
-
-  return crc;
-}
-
-
-int
-add_file_to_blocklist (char *name, struct blocklist *lst, long addr)
-{
-  int fd;
-  int devfd;
-  struct stat fst;
-  int i;
-  int blk;
-  int bs;
-  int blocks;
-
-  int rc = 0;
-
-  ITRY (fd = open (name, O_RDONLY));
-  ITRY (fstat (fd, &fst));
-  ITRY (mknod ("/tmp/silodev", S_IFBLK | S_IRUSR | S_IWUSR, fst.st_dev));
-  ITRY (devfd = open ("/tmp/silodev", O_RDONLY));
-  ITRY (ioctl (fd, FIGETBSZ, &bs));
-  blocks = (fst.st_size + bs - 1) / bs;
-  for (i = 0; i < blocks; i++)
-    {
-      blk = i;
-      ITRY (ioctl (fd, FIBMAP, &blk));
-      if (blk)
-	{
-	  int oldblk = blk;
-	  ITRY (ioctl (devfd, BIODASDRWTB, &blk));
-	  if (blk <= 0)
-	    {
-	      ERROR_LEVEL (0, "BIODASDRWTB on blk %d returned %d\n", oldblk, blk);
-	      break;
-	    }
-	}
-      else
-	{
-	  PRINT_LEVEL (1, "Filled hole on blk %d\n", i);
-	}
-      if (lst->ix == 0 || i == 0  || 
-	  lst->blk[lst->ix - 1].ct >= 128 ||
-	  (lst->blk[lst->ix - 1].off + lst->blk[lst->ix - 1].ct != blk &&
-	   !(lst->blk[lst->ix - 1].off == 0 && blk == 0)))
-	{
-	  if (lst->ix >= MAX_CLUSTERS)
-	    {
-	      rc = 1;
-	      errno = ENOMEM;
-	      break;
-	    }
-	  lst->blk[lst->ix].off = blk;
-	  lst->blk[lst->ix].ct = 1;
-	  lst->blk[lst->ix].addr = addr + i * bs;
-	  lst->ix++;
-	}
-      else
-	{
-	  lst->blk[lst->ix - 1].ct++;
-	}
-    }
-  ITRY(unlink("/tmp/silodev"));
-  return rc;
-}
-
-int
-write_bootsect (struct silo_options *o, struct blocklist *blklst)
-{
-  int i;
-  int s_fd, d_fd, b_fd, bd_fd;
-  struct stat s_st, d_st, b_st;
-  int rc=0;
-  int bs, boots;
-  char *tmpdev;
-  char buffer[4096]={0,};
-  int blocksize, sectsize;
-  ITRY (d_fd = open (o->ipldevice, O_RDWR | O_SYNC));
-  ITRY (fstat (d_fd, &d_st));
-  ITRY (s_fd = open (o->bootmap, O_RDWR | O_TRUNC | O_CREAT | O_SYNC));
-  ITRY (verify_file (o->bootsect, d_st.st_rdev));
-  for (i = 0; i < blklst->ix; i++)
-    {
-      int offset = blklst->blk[i].off;
-      int addrct = blklst->blk[i].addr | (blklst->blk[i].ct & 0xff);
-      PRINT_LEVEL (1, "ix %i: offset: %06x count: %02x address: 0x%08x\n", i, offset, blklst->blk[i].ct & 0xff, blklst->blk[i].addr);
-	if ( o->testlevel <= 1 ) {
-	      NTRY (write (s_fd, &offset, sizeof (int)));
-	      NTRY (write (s_fd, &addrct, sizeof (int)));
-	}
-    }
-  ITRY (ioctl (s_fd,FIGETBSZ, &bs));
-  ITRY (stat (o->bootmap, &s_st));
-  if (s_st.st_size > bs )
-    {
-      ERROR_LEVEL (0,"%s is larger than one block\n", o->bootmap);
-      rc = -1;
-      errno = EINVAL;
-    }
-  boots=0;
-  NTRY ( tmpdev = tmpnam(NULL) );
-  ITRY (mknod (tmpdev, S_IFBLK | S_IRUSR | S_IWUSR, s_st.st_dev));
-  ITRY (bd_fd = open (tmpdev, O_RDONLY));
-  ITRY (ioctl(bd_fd,BLKSSZGET,&blocksize));
-  ITRY (ioctl(s_fd,FIBMAP,&boots));
-  ITRY (ioctl (bd_fd, BIODASDRWTB, &boots));
-  PRINT_LEVEL (1, "Bootmap is in block no: 0x%08x\n", boots);
-  close (bd_fd);
-  close(s_fd);
-  ITRY (unlink(tmpdev));
-  /* Now patch the bootsector */
-  ITRY (stat (o->bootsect, &b_st));
-  if ((sectsize = b_st.st_size) > blocksize )
-    {
-      ERROR_LEVEL (0,"Bootsector is larger than sectorsize of volume %d vs %d\n", sectsize, blocksize);
-      rc = -1;
-      errno = EINVAL;
-    }
-  ITRY (b_fd = open (o->bootsect, O_RDONLY));
-  ITRY (read (b_fd, buffer, sectsize));
-  memset (buffer + 0xe0, 0, 8);
-  *(int *) (buffer + 0xe0) = boots;
-  if ( o -> testlevel <= 0 ) {
-    ITRY (write (d_fd, buffer, sectsize));
-    ITRY (lseek (d_fd, blocksize, SEEK_SET));
-    ITRY (write (d_fd, buffer, sectsize));
-  }
-  close (b_fd);
-  close (d_fd);
-  return rc;
-}
-
-int
-do_silo (struct silo_options *o)
-{
-  int rc = 0;
-
-  int device_fd;
-  int image_fd;
-  struct blocklist blklist;
-  memset (&blklist, 0, sizeof (struct blocklist));
-  ITRY (add_file_to_blocklist (o->image, &blklist, 0x00000000));
-  if (o->parmfile)
-    {
-      ITRY (add_file_to_blocklist (o->parmfile, &blklist, 0x00008000));
-    }
-  if (o->ramdisk)
-    {
-      ITRY (add_file_to_blocklist (o->ramdisk, &blklist, 0x00800000));
-    }
-  ITRY (write_bootsect (o, &blklist));
-  return rc;
-}
-
-int
-main (int argct, char *argv[])
-{
-  int rc = 0;
-  char *save=NULL;
-  char *tmpdir=getenv("TMPDIR");
-  if (tmpdir) {
-    NTRY( save=(char*)malloc(strlen(tmpdir)));
-    NTRY( strncpy(save,tmpdir,strlen(tmpdir)));
-  }
-  ITRY( setenv("TMPDIR",".",1));
-  ITRY (parse_options (&silo_options, argct, argv));
-  ITRY (verify_options (&silo_options));
-  if ( silo_options.testlevel > 0 ) {
-    printf ("WARNING: silo does not modify your volume. Use -t2 to change IPL records\n");
-  }
-  ITRY (do_silo (&silo_options));
-  if ( save )
-    ITRY( setenv("TMPDIR",save,1)); 
-  return rc;
-}
diff -u --recursive --new-file v2.4.7/linux/arch/s390/tools/silo/silo.conf linux/arch/s390/tools/silo/silo.conf
--- v2.4.7/linux/arch/s390/tools/silo/silo.conf	Fri May 12 11:41:45 2000
+++ linux/arch/s390/tools/silo/silo.conf	Wed Dec 31 16:00:00 1969
@@ -1,7 +0,0 @@
-ipldevice = /dev/dasda 
-image = /boot/image
-bootsect = /boot/ipleckd.boot
-map = /boot/boot.map
-root = /dev/dasd01
-readonly
-append = "dasd=200-20f noinitrd"
diff -u --recursive --new-file v2.4.7/linux/arch/s390x/Makefile linux/arch/s390x/Makefile
--- v2.4.7/linux/arch/s390x/Makefile	Tue Feb 13 14:13:44 2001
+++ linux/arch/s390x/Makefile	Wed Jul 25 14:12:01 2001
@@ -17,7 +17,11 @@
 CPP=$(CC) -E
 OBJCOPY=$(CROSS_COMPILE)objcopy -O binary -R .note -R .comment -S
 LDFLAGS=-e start
+ifeq ($(CONFIG_SHARED_KERNEL),y)
+LINKFLAGS =-T $(TOPDIR)/arch/s390x/vmlinux-shared.lds $(LDFLAGS)
+else
 LINKFLAGS =-T $(TOPDIR)/arch/s390x/vmlinux.lds $(LDFLAGS)
+endif
 MODFLAGS += -fpic
 
 CFLAGS_PIPE := -pipe
@@ -28,8 +32,8 @@
 
 SUBDIRS := $(SUBDIRS) arch/s390x/mm arch/s390x/kernel arch/s390x/lib \
            drivers/s390
-CORE_FILES := arch/s390x/mm/mm.o arch/s390x/kernel/kernel.o $(CORE_FILES) \
-           drivers/s390/io.o
+CORE_FILES := arch/s390x/mm/mm.o arch/s390x/kernel/kernel.o $(CORE_FILES)
+DRIVERS := $(DRIVERS) drivers/s390/io.o
 LIBS := $(TOPDIR)/arch/s390x/lib/lib.a $(LIBS) $(TOPDIR)/arch/s390x/lib/lib.a
 
 all: image listing
diff -u --recursive --new-file v2.4.7/linux/arch/s390x/config.in linux/arch/s390x/config.in
--- v2.4.7/linux/arch/s390x/config.in	Tue Apr 17 17:19:25 2001
+++ linux/arch/s390x/config.in	Wed Jul 25 14:12:01 2001
@@ -53,6 +53,8 @@
 tristate 'Kernel support for ELF binaries' CONFIG_BINFMT_ELF
 tristate 'Kernel support for MISC binaries' CONFIG_BINFMT_MISC
 bool 'Show crashed user process info' CONFIG_PROCESS_DEBUG
+bool 'Pseudo page fault support' CONFIG_PFAULT
+bool 'VM shared kernel support' CONFIG_SHARED_KERNEL
 endmenu
 
 
diff -u --recursive --new-file v2.4.7/linux/arch/s390x/defconfig linux/arch/s390x/defconfig
--- v2.4.7/linux/arch/s390x/defconfig	Wed Apr 11 19:02:29 2001
+++ linux/arch/s390x/defconfig	Wed Jul 25 14:12:01 2001
@@ -4,6 +4,8 @@
 # CONFIG_ISA is not set
 # CONFIG_EISA is not set
 # CONFIG_MCA is not set
+CONFIG_RWSEM_GENERIC_SPINLOCK=y
+# CONFIG_RWSEM_XCHGADD_ALGORITHM is not set
 CONFIG_ARCH_S390=y
 CONFIG_ARCH_S390X=y
 
@@ -41,6 +43,8 @@
 CONFIG_BINFMT_ELF=y
 # CONFIG_BINFMT_MISC is not set
 # CONFIG_PROCESS_DEBUG is not set
+CONFIG_PFAULT=y
+# CONFIG_SHARED_KERNEL is not set
 
 #
 # Block device drivers
@@ -58,7 +62,6 @@
 CONFIG_DASD=y
 CONFIG_DASD_ECKD=y
 CONFIG_DASD_FBA=y
-# CONFIG_DASD_DIAG is not set
 
 #
 # Multi-device support (RAID and LVM)
@@ -80,10 +83,13 @@
 #
 # S/390 character device drivers
 #
-CONFIG_3215=y
-CONFIG_3215_CONSOLE=y
+CONFIG_TN3270=y
+CONFIG_TN3270_CONSOLE=y
+CONFIG_TN3215=y
+CONFIG_TN3215_CONSOLE=y
 CONFIG_HWC=y
 CONFIG_HWC_CONSOLE=y
+CONFIG_HWC_CPI=m
 CONFIG_S390_TAPE=m
 
 #
@@ -103,6 +109,9 @@
 #
 CONFIG_NETDEVICES=y
 # CONFIG_DUMMY is not set
+# CONFIG_BONDING is not set
+# CONFIG_EQUALIZER is not set
+# CONFIG_TUN is not set
 CONFIG_NET_ETHERNET=y
 CONFIG_TR=y
 # CONFIG_FDDI is not set
@@ -110,7 +119,8 @@
 #
 # S/390 network device drivers
 #
-# CONFIG_CHANDEV is not set
+CONFIG_CHANDEV=y
+CONFIG_HOTPLUG=y
 CONFIG_CTC=m
 CONFIG_IUCV=m
 
@@ -134,7 +144,8 @@
 # CONFIG_IP_MROUTE is not set
 # CONFIG_INET_ECN is not set
 # CONFIG_SYN_COOKIES is not set
-# CONFIG_IPV6 is not set
+CONFIG_IPV6=m
+# CONFIG_IPV6_NETLINK is not set
 # CONFIG_KHTTPD is not set
 # CONFIG_ATM is not set
 
@@ -179,16 +190,18 @@
 # CONFIG_EFS_FS is not set
 # CONFIG_JFFS_FS is not set
 # CONFIG_CRAMFS is not set
+# CONFIG_TMPFS is not set
 # CONFIG_RAMFS is not set
 # CONFIG_ISO9660_FS is not set
 # CONFIG_JOLIET is not set
 # CONFIG_MINIX_FS is not set
+# CONFIG_VXFS_FS is not set
 # CONFIG_NTFS_FS is not set
 # CONFIG_NTFS_RW is not set
 # CONFIG_HPFS_FS is not set
 CONFIG_PROC_FS=y
-# CONFIG_DEVFS_FS is not set
-# CONFIG_DEVFS_MOUNT is not set
+CONFIG_DEVFS_FS=y
+CONFIG_DEVFS_MOUNT=y
 # CONFIG_DEVFS_DEBUG is not set
 # CONFIG_DEVPTS_FS is not set
 # CONFIG_QNX4FS_FS is not set
@@ -196,7 +209,6 @@
 # CONFIG_ROMFS_FS is not set
 CONFIG_EXT2_FS=y
 # CONFIG_SYSV_FS is not set
-# CONFIG_SYSV_FS_WRITE is not set
 # CONFIG_UDF_FS is not set
 # CONFIG_UDF_RW is not set
 # CONFIG_UFS_FS is not set
@@ -244,4 +256,4 @@
 #
 # Kernel hacking
 #
-# CONFIG_MAGIC_SYSRQ is not set
+CONFIG_MAGIC_SYSRQ=y
diff -u --recursive --new-file v2.4.7/linux/arch/s390x/kernel/debug.c linux/arch/s390x/kernel/debug.c
--- v2.4.7/linux/arch/s390x/kernel/debug.c	Wed Apr 11 19:02:29 2001
+++ linux/arch/s390x/kernel/debug.c	Wed Jul 25 14:12:01 2001
@@ -14,7 +14,7 @@
 #include <linux/stddef.h>
 #include <linux/kernel.h>
 #include <linux/errno.h>
-#include <linux/malloc.h>
+#include <linux/slab.h>
 #include <linux/ctype.h>
 #include <linux/version.h>
 #include <asm/uaccess.h>
diff -u --recursive --new-file v2.4.7/linux/arch/s390x/kernel/entry.S linux/arch/s390x/kernel/entry.S
--- v2.4.7/linux/arch/s390x/kernel/entry.S	Wed Jul 25 17:10:19 2001
+++ linux/arch/s390x/kernel/entry.S	Wed Jul 25 14:12:01 2001
@@ -14,6 +14,7 @@
 #include <linux/sys.h>
 #include <linux/linkage.h>
 #include <linux/config.h>
+#include <asm/cache.h>
 #include <asm/lowcore.h>
 #include <asm/errno.h>
 #include <asm/smp.h>
@@ -80,7 +81,7 @@
 sigpending   = 16
 need_resched = 32
 tsk_ptrace   = 40
-processor    = 100
+processor    = 92
 
 /*
  * Register usage in interrupt handlers:
@@ -194,8 +195,11 @@
 #
 # check, if bottom-half has to be done
 #
-        l       %r0,__LC_IRQ_STAT     # get softirq_active
-        n       %r0,__LC_IRQ_STAT+4   # and it with softirq_mask
+	lgf     %r1,processor(%r9)    # get cpu number from task struture
+	larl    %r2,irq_stat
+	sll     %r1,L1_CACHE_SHIFT
+	la      %r1,0(%r1,%r2)
+	icm     %r0,15,0(%r1)         # test irq_stat[#cpu].__softirq_pending
         jnz     sysc_handle_bottom_half
 #
 # check, if reschedule is needed
@@ -607,7 +611,7 @@
         .long  SYSCALL(sys_pivot_root,sys32_pivot_root_wrapper)
         .long  SYSCALL(sys_mincore,sys32_mincore_wrapper)
         .long  SYSCALL(sys_madvise,sys32_madvise_wrapper)
-	.long  SYSCALL(sys_ni_syscall,sys32_getdents64_wrapper)/* 220 */
+	.long  SYSCALL(sys_getdents64,sys32_getdents64_wrapper)/* 220 */
 	.long  SYSCALL(sys_ni_syscall,sys32_fcntl64_wrapper)
         .rept  255-221
 	.long  SYSCALL(sys_ni_syscall,sys_ni_syscall)
@@ -700,8 +704,11 @@
 #
 # check, if bottom-half has to be done
 #
-        l       %r0,__LC_IRQ_STAT     # get softirq_active
-        n       %r0,__LC_IRQ_STAT+4   # and it with softirq_mask
+	lgf     %r1,processor(%r9)    # get cpu number from task struture
+	larl    %r2,irq_stat
+	sll     %r1,L1_CACHE_SHIFT
+	la      %r1,0(%r1,%r2)
+	icm     %r0,15,0(%r1)         # test irq_stat[#cpu].__softirq_pending
         jnz     io_handle_bottom_half
 io_return_bh:	
 #
diff -u --recursive --new-file v2.4.7/linux/arch/s390x/kernel/head.S linux/arch/s390x/kernel/head.S
--- v2.4.7/linux/arch/s390x/kernel/head.S	Wed Jul 25 17:10:19 2001
+++ linux/arch/s390x/kernel/head.S	Wed Jul 25 14:12:01 2001
@@ -261,7 +261,7 @@
 	l     %r1,0xb8                         # load ipl subchannel number
         la    %r2,IPL_BS                       # load start address
         bas   %r14,.Lloader                    # load rest of ipl image
-        l     %r12,.Lparm                      # pointer to parameter area
+        larl  %r12,parmarea                    # pointer to parameter area
         st    %r1,IPL_DEVICE+4-PARMAREA(%r12)  # store ipl device number
 
 #
@@ -303,7 +303,6 @@
         slr   %r0,%r0
         b     .Lcntlp
 .Ldelspc:
-        ic    %r0,0(%r3)
         ic    %r0,0(%r2,%r3)
         chi   %r0,0x20                         # is it a space ?
         be    .Lcntlp
@@ -353,7 +352,6 @@
         l     %r1,.Lstartup
         br    %r1
 
-.Lparm:	.long  PARMAREA
 .Lstartup: .long startup
 .Lcvtab:.long  _ebcasc                         # ebcdic to ascii table
 .Lreset:.byte  0xc3,0xc8,0xc1,0xd5,0xc7,0xc5,0x40,0xd9,0xc4,0xd9,0x40
@@ -459,59 +457,81 @@
 #
         .org  0x10000
 startup:basr  %r13,0                     # get base
-.LPG1:  n     %r13,.Lhighoff-.LPG1(%r13) # remove high order bit
+.LPG1:  sll   %r13,1                     # remove high order bit
+        srl   %r13,1
         lhi   %r1,1                      # mode 1 = esame
         slr   %r0,%r0                    # set cpuid to zero
         sigp  %r1,%r0,0x12               # switch to esame mode
 	sam64				 # switch to 64 bit mode
 	lctlg %c0,%c15,.Lctl-.LPG1(%r13) # load control registers
-	lg    %r12,.Lparm1-.LPG1(%r13)   # pointer to parameter area
+	larl  %r12,parmarea              # pointer to parameter area
 					 # move IPL device to lowcore
         mvc   __LC_IPLDEV(4),IPL_DEVICE+4-PARMAREA(%r12)
+					 # set program check new psw mask
+	mvc   __LC_PGM_NEW_PSW(8),.Lpcmsk-.LPG1(%r13)
+
 
 #
 # find out memory size.
 #
-	mvc   0x1d0(16),.Lpcmem-.LPG1(%r13) # setup program check handler
+	la    %r1,1f-.LPG1(%r13)         # set program check address
+	stg   %r1,__LC_PGM_NEW_PSW+8
         lghi  %r2,1
         sllg  %r2,%r2,17                 # test in increments of 128KB
 	lgr   %r1,%r2
 	aghi  %r1,-8                     # test last word in the segment
-.Lloop:	
-	lg    %r0,0(%r1)                 # test 128KB segment
+0:	lg    %r0,0(%r1)                 # test 128KB segment
+        stg   %r0,0(%r1)
+	algr  %r1,%r2                    # add 128KB
+	bc    12,0b-.LPG1(%r13)          # r1 < 2^64 -> loop
+1:	ng    %r1,.L4malign-.LPG1(%r13)  # align to multiples of 4M
+	larl  %r3,memory_size-.
+	stg   %r1,0(%r3)                 # store memory size
+#
+# find out memory size part 2. Running native the HSA is located at
+# 2GB and we will get an addressing exception trying to access it.
+# We have to restart the scan at 2GB to find out if the machine has
+# more than 2GB of storage.
+#
+	la    %r1,1f-.LPG1(%r13)         # set program check address
+	stg   %r1,__LC_PGM_NEW_PSW+8
+	lg    %r1,.Lscan2g-.LPG1(%r13)   # restart scanning @ 2GB + 128K - 8
+0:	lg    %r0,0(%r1)                 # test 128KB segment
 	stg   %r0,0(%r1)
-	agr   %r1,%r2                    # add 128KB
-	bno   .Lloop-.LPG1(%r13)         # r1 < 0x80000000 -> loop
-.Lchkmem:
+	algr  %r1,%r2                    # add 128 KB
+	bc    12,0b-.LPG1(%r13)          # r1 < 2^64 -> loop
+1:	clg   %r1,.Lscan2g-.LPG1(%r13)   # program check @ 2GB + 128K - 8 ?
+	be    2f-.LPG1(%r13)
 	ng    %r1,.L4malign-.LPG1(%r13)  # align to multiples of 4M
-	lg    %r2,.Lmemsize-.LPG1(%r13)  # address of variable memory_size
-	stg   %r1,0(%r2)                 # store memory size
+	larl  %r3,memory_size-.
+	stg   %r1,0(%r3)                 # store memory size
+2:
 
-	lg    %r12,.Lmflags-.LPG1(%r13)  # get address of machine_flags
+	larl  %r12,machine_flags-.
 #
 # find out if we are running under VM
 #
         stidp  __LC_CPUID               # store cpuid
 	tm     __LC_CPUID,0xff          # running under VM ?
-	bno    .Lnovm-.LPG1(%r13)
+	bno    0f-.LPG1(%r13)
         oi     7(%r12),1                # set VM flag
-.Lnovm:
-        lh     %r0,__LC_CPUID+4         # get cpu version
+0:      lh     %r0,__LC_CPUID+4         # get cpu version
         chi    %r0,0x7490               # running on a P/390 ?
-        bne    .Lnop390-.LPG1(%r13)
+        bne    1f-.LPG1(%r13)
         oi     7(%r12),4                # set P/390 flag
-.Lnop390:
+1:
 
 #
 # find out if we have the MVPG instruction
 #
-       mvc    __LC_PGM_NEW_PSW(16),.Lpcmvpg-.LPG1(%r13)
-       sgr    %r0,%r0
-       lghi   %r1,0
-       lghi   %r2,0
-       mvpg   %r1,%r2                   # Test CSP instruction
-       oi     7(%r12),16                # set MVPG flag
-.Lchkmvpg:
+	la     %r1,0f-.LPG1(%r13)       # set program check address
+	stg    %r1,__LC_PGM_NEW_PSW+8
+	sgr    %r0,%r0
+	lghi   %r1,0
+	lghi   %r2,0
+	mvpg   %r1,%r2                  # test MVPG instruction
+	oi     7(%r12),16               # set MVPG flag
+0:
 
         lpswe .Lentry-.LPG1(13)         # jump to _stext in primary-space,
                                         # virtual and never return ...
@@ -533,21 +553,15 @@
         .quad  0                        # cr13: home space segment table
         .quad  0xc0000000               # cr14: machine check handling off
         .quad  0                        # cr15: linkage stack operations
-.Lpcmem:.quad  0x0000000180000000,.Lchkmem
-.Lpcmvpg:.quad 0x0000000180000000,.Lchkmvpg
-.Lflt0: .double 0
-.Lparm1:.quad  PARMAREA
-.Lhighoff:.long 0x7fffffff
+.Lpcmsk:.quad  0x0000000180000000
 .L4malign:.quad 0xffffffffffc00000
-.Lbigmem:.quad 0x04000000
-.Lmaxchunk:.quad  0x00ffffff
-.Lmemsize:.quad memory_size
-.Lmflags:.quad machine_flags
+.Lscan2g:.quad 0x80000000 + 0x20000 - 8 # 2GB + 128K - 8
 
 #
 # params at 10400 (setup.h)
 #
 	.org   PARMAREA
+parmarea:
 	.quad  0                        # IPL_DEVICE
         .quad  RAMDISK_ORIGIN           # INITRD_START
         .quad  RAMDISK_SIZE             # INITRD_SIZE
@@ -559,7 +573,11 @@
 #
 # startup-code, running in virtual mode
 #
+#ifdef CONFIG_SHARED_KERNEL
+	.org   0x100000
+#else
         .org   0x10800
+#endif
         .globl _stext
 _stext:	basr  %r13,0                    # get base
 .LPG2:
@@ -569,7 +587,7 @@
         l     %r1,__LC_IPLDEV           # load ipl device number
         spx   .Lprefix-.LPG2(%r13)      # set prefix to linux lowcore
         st    %r1,__LC_IPLDEV           # store ipl device number
-        lg    %r15,.Linittu-.LPG2(%r13)
+	larl  %r15,init_task_union
         aghi  %r15,16384                # init_task_union + 16384
         stg   %r15,__LC_KERNEL_STACK    # set end of kernel stack
         aghi  %r15,-160
@@ -579,8 +597,8 @@
 #
 # clear bss memory
 #
-        lg    %r2,.Lbss_bgn-.LPG2(%r13) # start of bss
-        lg    %r3,.Lbss_end-.LPG2(%r13) # end of bss
+	larl  %r2,__bss_start           # start of bss segment
+        larl  %r3,_end                  # end of bss segment
         sgr   %r3,%r2                   # length of bss
         sgr   %r4,%r4                   #
         sgr   %r5,%r5                   # set src,length and pad to zero
@@ -588,8 +606,8 @@
         jo    .-4                       # branch back, if not finish
 # check control registers
         stctg  %c0,%c15,0(%r15)
-        oc     6(1,%r15),.Locbits+5-.LPG2(%r13) # enable sigp external ints.
-        oc     4(1,%r15),.Locbits+4-.LPG2(%r13) # low addresss proctection
+	oi     6(%r15),0x20             # enable sigp external interrupts
+	oi     4(%r15),0x10             # switch on low address proctection
         lctlg  %c0,%c15,0(%r15)
 
 #
@@ -601,15 +619,8 @@
         basr  %r13,0
 	lpswe .Ldw-.(%r13)           # load disabled wait psw
 #
-.Lstart:    .quad  start_kernel
             .align 8
+.Ldw:       .quad  0x0002000180000000,0x0000000000000000
 .Lprefix:   .long  init_S390_lowcore	
-.Linittu:   .quad  init_task_union
-.Lbss_bgn:  .quad  __bss_start
-.Lbss_end:  .quad  _end
-.Locbits:   .quad  0x0102040810204080
-            .align 4
 .Laregs:    .long  0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0
-	    .align 8
-.Ldw:      .quad  0x0002000180000000,0x0000000000000000
 
diff -u --recursive --new-file v2.4.7/linux/arch/s390x/kernel/irq.c linux/arch/s390x/kernel/irq.c
--- v2.4.7/linux/arch/s390x/kernel/irq.c	Wed Jul 25 17:10:19 2001
+++ linux/arch/s390x/kernel/irq.c	Wed Jul 25 14:12:01 2001
@@ -21,7 +21,7 @@
 #include <linux/ioport.h>
 #include <linux/interrupt.h>
 #include <linux/timex.h>
-#include <linux/malloc.h>
+#include <linux/slab.h>
 #include <linux/string.h>
 #include <linux/random.h>
 #include <linux/smp.h>
@@ -385,6 +385,10 @@
 EXPORT_SYMBOL(__global_sti);
 EXPORT_SYMBOL(__global_save_flags);
 EXPORT_SYMBOL(__global_restore_flags);
+EXPORT_SYMBOL(global_irq_holder);
+EXPORT_SYMBOL(global_irq_lock);
+EXPORT_SYMBOL(global_irq_count);
+EXPORT_SYMBOL(global_bh_count);
 #endif
 
 EXPORT_SYMBOL(global_bh_lock);
diff -u --recursive --new-file v2.4.7/linux/arch/s390x/kernel/linux32.c linux/arch/s390x/kernel/linux32.c
--- v2.4.7/linux/arch/s390x/kernel/linux32.c	Wed Jul 25 17:10:19 2001
+++ linux/arch/s390x/kernel/linux32.c	Wed Jul 25 14:12:01 2001
@@ -32,7 +32,7 @@
 #include <linux/sem.h>
 #include <linux/msg.h>
 #include <linux/shm.h>
-#include <linux/malloc.h>
+#include <linux/slab.h>
 #include <linux/uio.h>
 #include <linux/nfs_fs.h>
 #include <linux/smb_fs.h>
@@ -4176,8 +4176,8 @@
 	unsigned long prot, unsigned long flags,
 	unsigned long fd, unsigned long pgoff)
 {
-	int error = -EBADF;
 	struct file * file = NULL;
+	unsigned long error = -EBADF;
 
 	flags &= ~(MAP_EXECUTABLE | MAP_DENYWRITE);
 	if (!(flags & MAP_ANONYMOUS)) {
@@ -4188,6 +4188,11 @@
 
 	down_write(&current->mm->mmap_sem);
 	error = do_mmap_pgoff(file, addr, len, prot, flags, pgoff);
+	if (!IS_ERR((void *) error) && error + len >= 0x80000000ULL) {
+		/* Result is out of bounds.  */
+		do_munmap(current->mm, addr, len);
+		error = -ENOMEM;
+	}
 	up_write(&current->mm->mmap_sem);
 
 	if (file)
diff -u --recursive --new-file v2.4.7/linux/arch/s390x/kernel/process.c linux/arch/s390x/kernel/process.c
--- v2.4.7/linux/arch/s390x/kernel/process.c	Wed Apr 11 19:02:29 2001
+++ linux/arch/s390x/kernel/process.c	Wed Jul 25 14:12:01 2001
@@ -63,8 +63,7 @@
 	wait_psw.mask = _WAIT_PSW_MASK;
 	wait_psw.addr = (unsigned long) &&idle_wakeup;
 	while(1) {
-                if (softirq_active(smp_processor_id()) &
-		    softirq_mask(smp_processor_id())) {
+                if (softirq_pending(smp_processor_id())) {
                         do_softirq();
                         __sti();
                         if (!current->need_resched)
@@ -311,7 +310,7 @@
         p->thread.ksp = (unsigned long) frame;
         frame->childregs = *regs;
         frame->childregs.gprs[15] = new_stackp;
-        frame->eos = 0;
+        frame->back_chain = frame->eos = 0;
 
         /* new return point is ret_from_sys_call */
         frame->gprs[8] = (unsigned long) &ret_from_fork;
@@ -460,54 +459,3 @@
 #undef last_sched
 #undef first_sched
 
-/*
- * This should be safe even if called from tq_scheduler
- * A typical mask would be sigmask(SIGKILL)|sigmask(SIGINT)|sigmask(SIGTERM) or 0.
- *
- */
-void s390_daemonize(char *name,unsigned long mask,int use_init_fs)
-{
-	struct fs_struct *fs;
-	extern struct task_struct *child_reaper;
-	struct task_struct *this_process=current;
-	
-	/*
-	 * If we were started as result of loading a module, close all of the
-	 * user space pages.  We don't need them, and if we didn't close them
-	 * they would be locked into memory.
-	 */
-	exit_mm(current);
-
-	this_process->session = 1;
-	this_process->pgrp = 1;
-	if(name)
-	{
-		strncpy(current->comm,name,15);
-		current->comm[15]=0;
-	}
-	else
-		current->comm[0]=0;
-	/* set signal mask to what we want to respond */
-        siginitsetinv(&current->blocked,mask);
-	/* exit_signal isn't set up */
-        /* if we inherit from cpu idle  */
-	this_process->exit_signal=SIGCHLD;
-	/* if priority=0 schedule can go into a tight loop */
-	this_process->policy= SCHED_OTHER;
-	/* nice goes priority=20-nice; */
-	this_process->nice=10;
-	if(use_init_fs)
-	{
-		exit_fs(this_process);	/* current->fs->count--; */
-		fs = init_task.fs;
-		current->fs = fs;
-		atomic_inc(&fs->count);
-		exit_files(current);
-	}
-	write_lock_irq(&tasklist_lock);
-	/* We want init as our parent */
-	REMOVE_LINKS(this_process);
-	this_process->p_opptr=this_process->p_pptr=child_reaper;
-	SET_LINKS(this_process);
-	write_unlock_irq(&tasklist_lock);
-}
diff -u --recursive --new-file v2.4.7/linux/arch/s390x/kernel/s390_ext.c linux/arch/s390x/kernel/s390_ext.c
--- v2.4.7/linux/arch/s390x/kernel/s390_ext.c	Wed Apr 11 19:02:29 2001
+++ linux/arch/s390x/kernel/s390_ext.c	Wed Jul 25 14:12:01 2001
@@ -9,7 +9,7 @@
 
 #include <linux/module.h>
 #include <linux/kernel.h>
-#include <linux/malloc.h>
+#include <linux/slab.h>
 #include <asm/lowcore.h>
 #include <asm/s390_ext.h>
 
@@ -17,12 +17,13 @@
  * Simple hash strategy: index = code & 0xff;
  * ext_int_hash[index] is the start of the list for all external interrupts
  * that hash to this index. With the current set of external interrupts 
- * (0x1202 external call, 0x1004 cpu timer, 0x2401 hwc console and 0x4000
- * iucv) this is always the first element. 
+ * (0x1202 external call, 0x1004 cpu timer, 0x2401 hwc console, 0x4000
+ * iucv and 0x2603 pfault) this is always the first element. 
  */
 ext_int_info_t *ext_int_hash[256] = { 0, };
 ext_int_info_t ext_int_info_timer;
 ext_int_info_t ext_int_info_hwc;
+ext_int_info_t ext_int_pfault;
 
 int register_external_interrupt(__u16 code, ext_int_handler_t handler) {
         ext_int_info_t *p;
@@ -39,6 +40,8 @@
                 p = &ext_int_info_timer;
         else if (code == 0x2401) /* hwc_init is done too early too */
                 p = &ext_int_info_hwc;
+        else if (code == 0x2603) /* pfault_init is done too early too */
+                p = &ext_int_pfault;
         else
                 p = (ext_int_info_t *)
                           kmalloc(sizeof(ext_int_info_t), GFP_ATOMIC);
@@ -70,7 +73,7 @@
                 q->next = p->next;
         else
                 ext_int_hash[index] = p->next;
-        if (code != 0x1004 && code != 0x2401)
+        if (code != 0x1004 && code != 0x2401 && code != 0x2603)
                 kfree(p);
         return 0;
 }
diff -u --recursive --new-file v2.4.7/linux/arch/s390x/kernel/s390_ksyms.c linux/arch/s390x/kernel/s390_ksyms.c
--- v2.4.7/linux/arch/s390x/kernel/s390_ksyms.c	Wed Apr 11 19:02:29 2001
+++ linux/arch/s390x/kernel/s390_ksyms.c	Wed Jul 25 14:12:01 2001
@@ -64,6 +64,8 @@
 EXPORT_SYMBOL(machine_flags);
 EXPORT_SYMBOL(__udelay);
 EXPORT_SYMBOL(kernel_thread);
+EXPORT_SYMBOL(console_mode);
+EXPORT_SYMBOL(console_device);
 
 #if CONFIG_IP_MULTICAST
 /* Required for lcs gigibit ethernet multicast support */
diff -u --recursive --new-file v2.4.7/linux/arch/s390x/kernel/setup.c linux/arch/s390x/kernel/setup.c
--- v2.4.7/linux/arch/s390x/kernel/setup.c	Wed Apr 11 19:02:29 2001
+++ linux/arch/s390x/kernel/setup.c	Wed Jul 25 14:12:01 2001
@@ -43,6 +43,8 @@
 /*
  * Machine setup..
  */
+unsigned int console_mode = 0;
+unsigned int console_device = -1;
 unsigned long memory_size = 0;
 unsigned long machine_flags = 0;
 __u16 boot_cpu_addr;
@@ -141,6 +143,93 @@
 __setup("vmpoff=", vmpoff_setup);
 
 /*
+ * condev= and conmode= setup parameter.
+ */
+
+static int __init condev_setup(char *str)
+{
+	int vdev;
+
+	vdev = simple_strtoul(str, &str, 0);
+	if (vdev >= 0 && vdev < 65536)
+		console_device = vdev;
+	return 1;
+}
+
+__setup("condev=", condev_setup);
+
+static int __init conmode_setup(char *str)
+{
+#if defined(CONFIG_HWC_CONSOLE)
+	if (strncmp(str, "hwc", 4) == 0 && !MACHINE_IS_P390)
+                SET_CONSOLE_HWC;
+#endif
+#if defined(CONFIG_TN3215_CONSOLE)
+	if (strncmp(str, "3215", 5) == 0 && (MACHINE_IS_VM || MACHINE_IS_P390))
+		SET_CONSOLE_3215;
+#endif
+#if defined(CONFIG_TN3270_CONSOLE)
+	if (strncmp(str, "3270", 5) == 0 && (MACHINE_IS_VM || MACHINE_IS_P390))
+		SET_CONSOLE_3270;
+#endif
+        return 1;
+}
+
+__setup("conmode=", conmode_setup);
+
+static void __init conmode_default(void)
+{
+	char query_buffer[1024];
+	char *ptr;
+
+        if (MACHINE_IS_VM) {
+		cpcmd("QUERY TERM", query_buffer, 1024);
+		ptr = strstr(query_buffer, "CONMODE");
+		/*
+		 * Set the conmode to 3215 so that the device recognition 
+		 * will set the cu_type of the console to 3215. If the
+		 * conmode is 3270 and we don't set it back then both
+		 * 3215 and the 3270 driver will try to access the console
+		 * device (3215 as console and 3270 as normal tty).
+		 */
+		cpcmd("TERM CONMODE 3215", NULL, 0);
+		if (ptr == NULL) {
+#if defined(CONFIG_HWC_CONSOLE)
+			SET_CONSOLE_HWC;
+#endif
+			return;
+		}
+		if (strncmp(ptr + 8, "3270", 4) == 0) {
+#if defined(CONFIG_TN3270_CONSOLE)
+			SET_CONSOLE_3270;
+#elif defined(CONFIG_TN3215_CONSOLE)
+			SET_CONSOLE_3215;
+#elif defined(CONFIG_HWC_CONSOLE)
+			SET_CONSOLE_HWC;
+#endif
+		} else if (strncmp(ptr + 8, "3215", 4) == 0) {
+#if defined(CONFIG_TN3215_CONSOLE)
+			SET_CONSOLE_3215;
+#elif defined(CONFIG_TN3270_CONSOLE)
+			SET_CONSOLE_3270;
+#elif defined(CONFIG_HWC_CONSOLE)
+			SET_CONSOLE_HWC;
+#endif
+		}
+        } else if (MACHINE_IS_P390) {
+#if defined(CONFIG_TN3215_CONSOLE)
+		SET_CONSOLE_3215;
+#elif defined(CONFIG_TN3270_CONSOLE)
+		SET_CONSOLE_3270;
+#endif
+	} else {
+#if defined(CONFIG_HWC_CONSOLE)
+		SET_CONSOLE_HWC;
+#endif
+	}
+}
+
+/*
  * Reboot, halt and power_off routines for non SMP.
  */
 #ifndef CONFIG_SMP
@@ -177,14 +266,11 @@
 	unsigned long start_pfn, end_pfn;
         static unsigned int smptrap=0;
         unsigned long delay = 0;
-        int len = 0;
 
         if (smptrap)
                 return;
         smptrap=1;
 
-        printk("Command line is: %s\n", COMMAND_LINE);
-
         /*
          * Setup lowcore information for boot cpu
          */
@@ -221,7 +307,6 @@
                  * "mem=XXX[kKmM]" sets memsize 
                  */
                 if (c == ' ' && strncmp(from, "mem=", 4) == 0) {
-                        if (to != command_line) to--;
                         memory_end = simple_strtoul(from+4, &from, 0);
                         if ( *from == 'K' || *from == 'k' ) {
                                 memory_end = memory_end << 10;
@@ -235,7 +320,6 @@
                  * "ipldelay=XXX[sm]" sets ipl delay in seconds or minutes
                  */
                 if (c == ' ' && strncmp(from, "ipldelay=", 9) == 0) {
-			if (to != command_line) to--;
                         delay = simple_strtoul(from+9, &from, 0);
 			if (*from == 's' || *from == 'S') {
 				delay = delay*1000000;
@@ -244,7 +328,7 @@
 				delay = delay*60*1000000;
 				from++;
 			}
-			/* now wait for the requestion amount of time */
+			/* now wait for the requested amount of time */
 			udelay(delay);
                 }
                 cn = *(from++);
@@ -252,10 +336,12 @@
                         break;
                 if (cn == '\n')
                         cn = ' ';  /* replace newlines with space */
+		if (cn == 0x0d)
+			cn = ' ';  /* replace 0x0d with space */
                 if (cn == ' ' && c == ' ')
                         continue;  /* remove additional spaces */
                 c = cn;
-                if (COMMAND_LINE_SIZE <= ++len)
+                if (to - command_line >= COMMAND_LINE_SIZE)
                         break;
                 *(to++) = c;
         }
@@ -313,6 +399,9 @@
 	request_resource(&iomem_resource, res);
 	request_resource(res, &code_resource);
 	request_resource(res, &data_resource);
+
+        /* Setup default console */
+	conmode_default();
 }
 
 void print_cpu_info(struct cpuinfo_S390 *cpuinfo)
diff -u --recursive --new-file v2.4.7/linux/arch/s390x/kernel/signal.c linux/arch/s390x/kernel/signal.c
--- v2.4.7/linux/arch/s390x/kernel/signal.c	Wed Apr 11 19:02:29 2001
+++ linux/arch/s390x/kernel/signal.c	Wed Jul 25 14:12:01 2001
@@ -333,6 +333,7 @@
 		/* Set up registers for signal handler */
 		regs->gprs[15] = (addr_t)frame;
 		regs->psw.addr = FIX_PSW(ka->sa.sa_handler);
+		regs->psw.mask = _USER_PSW_MASK;
 	}
 	/* Set up to return from userspace.  If provided, use a stub
 	   already in userspace.  */
@@ -359,6 +360,11 @@
 #endif
 	/* Martin wants this for pthreads */
 	regs->gprs[3] = (addr_t)&frame->sc;
+
+	/* We forgot to include these in the sigcontext.
+	   To avoid breaking binary compatibility, they are passed as args. */
+	regs->gprs[4] = current->thread.trap_no;
+	regs->gprs[5] = current->thread.prot_addr;
 	return;
 
 give_sigsegv:
@@ -415,7 +421,7 @@
 	      siginfo_t *info, sigset_t *oldset, struct pt_regs * regs)
 {
 	/* Are we from a system call? */
-	if (regs->orig_gpr2 >= 0) {
+	if (regs->trap == __LC_SVC_OLD_PSW) {
 		/* If so, check system call restarting.. */
 		switch (regs->gprs[2]) {
 			case -ERESTARTNOHAND:
@@ -568,7 +574,6 @@
                                 /* FALLTHRU */
 
 			default:
-				lock_kernel();
 				sigaddset(&current->pending.signal, signr);
 				recalc_sigpending(current);
 				current->flags |= PF_SIGNALED;
diff -u --recursive --new-file v2.4.7/linux/arch/s390x/kernel/smp.c linux/arch/s390x/kernel/smp.c
--- v2.4.7/linux/arch/s390x/kernel/smp.c	Wed Jul 25 17:10:19 2001
+++ linux/arch/s390x/kernel/smp.c	Wed Jul 25 14:12:01 2001
@@ -543,6 +543,7 @@
  *      Activate a secondary processor.
  */
 extern void init_100hz_timer(void);
+extern int pfault_init(void);
 
 int __init start_secondary(void *cpuvoid)
 {
@@ -555,6 +556,10 @@
                 /* nothing */ ;
         /* init per CPU 100 hz timer */
         init_100hz_timer();
+#ifdef CONFIG_PFAULT
+	/* Enable pfault pseudo page faults on this cpu. */
+	pfault_init();
+#endif
         /* cpu_idle will call schedule for us */
         return cpu_idle(NULL);
 }
diff -u --recursive --new-file v2.4.7/linux/arch/s390x/kernel/time.c linux/arch/s390x/kernel/time.c
--- v2.4.7/linux/arch/s390x/kernel/time.c	Tue Feb 13 14:13:44 2001
+++ linux/arch/s390x/kernel/time.c	Wed Jul 25 14:12:01 2001
@@ -101,9 +101,10 @@
 {
 	unsigned long flags;
 	unsigned long usec, sec;
-	unsigned long lost_ticks = jiffies - wall_jiffies;
+	unsigned long lost_ticks;
 
 	read_lock_irqsave(&xtime_lock, flags);
+	lost_ticks = jiffies - wall_jiffies;
 	usec = do_gettimeoffset();
 	if (lost_ticks)
 		usec +=(USECS_PER_JIFFY*lost_ticks);
diff -u --recursive --new-file v2.4.7/linux/arch/s390x/kernel/traps.c linux/arch/s390x/kernel/traps.c
--- v2.4.7/linux/arch/s390x/kernel/traps.c	Tue Feb 13 14:13:44 2001
+++ linux/arch/s390x/kernel/traps.c	Wed Jul 25 14:12:01 2001
@@ -35,6 +35,8 @@
 #if CONFIG_REMOTE_DEBUG
 #include <asm/gdb-stub.h>
 #endif
+#include <asm/cpcmd.h>
+#include <asm/s390_ext.h>
 
 /* Called from entry.S only */
 extern void handle_per_exception(struct pt_regs *regs);
@@ -51,6 +53,11 @@
 #endif
 
 extern pgm_check_handler_t do_page_fault;
+#ifdef CONFIG_PFAULT
+extern int pfault_init(void);
+extern void pfault_fini(void);
+extern void pfault_interrupt(struct pt_regs *regs, __u16 error_code);
+#endif
 
 spinlock_t die_lock;
 
@@ -152,7 +159,6 @@
 	__u16 *location;
 	int do_sig = 0;
 
-        lock_kernel();
 	location = (__u16 *)(regs->psw.addr-S390_lowcore.pgm_ilc);
 	/* WARNING don't change this check back to */
 	/* int problem_state=(regs->psw.mask & PSW_PROBLEM_STATE); */
@@ -171,7 +177,6 @@
 		do_sig = 1;
 	if (do_sig)
 		do_trap(interruption_code, SIGILL, "illegal operation", regs, NULL);
-        unlock_kernel();
 }
 
 asmlinkage void data_exception(struct pt_regs * regs, long interruption_code)
@@ -179,7 +184,6 @@
 	__u16 *location;
 	int do_sig = 0;
 
-        lock_kernel();
 	location = (__u16 *)(regs->psw.addr-S390_lowcore.pgm_ilc);
 	__asm__ volatile ("stfpc %0\n\t" 
 			  : "=m" (current->thread.fp_regs.fpc));
@@ -194,7 +198,6 @@
 		do_sig = 1;
         if (do_sig)
                 do_trap(interruption_code, SIGILL, "data exception", regs, NULL);
-        unlock_kernel();
 }
 
 
@@ -223,6 +226,21 @@
         pgm_check_table[0x1C] = &privileged_op;
         pgm_check_table[0x38] = &addressing_exception;
         pgm_check_table[0x3B] = &do_page_fault;
+#ifdef CONFIG_PFAULT
+	if (MACHINE_IS_VM) {
+		/* request the 0x2603 external interrupt */
+		if (register_external_interrupt(0x2603, pfault_interrupt) != 0)
+			panic("Couldn't request external interrupt 0x2603");
+		/*
+		 * Try to get pfault pseudo page faults going.
+		 */
+		if (pfault_init() != 0) {
+			/* Tough luck, no pfault. */
+			unregister_external_interrupt(0x2603,
+						      pfault_interrupt);
+		}
+	}
+#endif
 }
 
 
diff -u --recursive --new-file v2.4.7/linux/arch/s390x/mm/fault.c linux/arch/s390x/mm/fault.c
--- v2.4.7/linux/arch/s390x/mm/fault.c	Wed Jul 25 17:10:19 2001
+++ linux/arch/s390x/mm/fault.c	Wed Jul 25 14:12:01 2001
@@ -21,6 +21,7 @@
 #include <linux/mm.h>
 #include <linux/smp.h>
 #include <linux/smp_lock.h>
+#include <linux/init.h>
 
 #include <asm/system.h>
 #include <asm/uaccess.h>
@@ -80,19 +81,9 @@
         unsigned long address;
         unsigned long fixup;
         int write;
-        unsigned long psw_mask;
-        unsigned long psw_addr;
 	int si_code = SEGV_MAPERR;
 	int kernel_address = 0;
 
-        /*
-         *  get psw mask of Program old psw to find out,
-         *  if user or kernel mode
-         */
-
-        psw_mask = S390_lowcore.program_old_psw.mask;
-        psw_addr = S390_lowcore.program_old_psw.addr;
-
         /* 
          * get the failing address 
          * more specific the segment and page table portion of 
@@ -215,7 +206,7 @@
         up_read(&mm->mmap_sem);
 
         /* User mode accesses just cause a SIGSEGV */
-        if (psw_mask & PSW_PROBLEM_STATE) {
+        if (regs->psw.mask & PSW_PROBLEM_STATE) {
 		struct siginfo si;
                 tsk->thread.prot_addr = address;
                 tsk->thread.trap_no = error_code;
@@ -273,7 +264,7 @@
 out_of_memory:
 	up_read(&mm->mmap_sem);
 	printk("VM: killing process %s\n", tsk->comm);
-	if (psw_mask & PSW_PROBLEM_STATE)
+	if (regs->psw.mask & PSW_PROBLEM_STATE)
 		do_exit(SIGKILL);
 	goto no_context;
 
@@ -289,6 +280,140 @@
 	force_sig(SIGBUS, tsk);
 
 	/* Kernel mode? Handle exceptions or die */
-	if (!(psw_mask & PSW_PROBLEM_STATE))
+	if (!(regs->psw.mask & PSW_PROBLEM_STATE))
 		goto no_context;
 }
+
+#ifdef CONFIG_PFAULT
+/*
+ * 'pfault' pseudo page faults routines.
+ */
+static int pfault_disable = 0;
+
+static int __init nopfault(char *str)
+{
+	pfault_disable = 1;
+	return 1;
+}
+
+__setup("nopfault", nopfault);
+
+typedef struct {
+	__u16 refdiagc;
+	__u16 reffcode;
+	__u16 refdwlen;
+	__u16 refversn;
+	__u64 refgaddr;
+	__u64 refselmk;
+	__u64 refcmpmk;
+	__u64 reserved;
+} __attribute__ ((packed)) pfault_refbk_t;
+
+typedef struct _pseudo_wait_t {
+       struct _pseudo_wait_t *next;
+       wait_queue_head_t queue;
+       unsigned long address;
+       int resolved;
+} pseudo_wait_t;
+
+static pseudo_wait_t *pseudo_lock_queue = NULL;
+static spinlock_t pseudo_wait_spinlock; /* spinlock to protect lock queue */
+
+int pfault_init(void)
+{
+	pfault_refbk_t refbk =
+	{ 0x258, 0, 5, 2, __LC_KERNEL_STACK, 1ULL << 48, 1ULL << 48, 0ULL };
+        int rc;
+
+	if (pfault_disable)
+		return -1;
+        __asm__ __volatile__(
+                "    diag  %1,%0,0x258\n"
+		"0:  j     2f\n"
+		"1:  la    %0,8\n"
+		"2:\n"
+		".section __ex_table,\"a\"\n"
+		"   .align 4\n"
+		"   .quad  0b,1b\n"
+		".previous"
+                : "=d" (rc) : "a" (&refbk) : "cc" );
+	__ctl_set_bit(0, 9);
+        return rc;
+}
+
+void pfault_fini(void)
+{
+	pfault_refbk_t refbk =
+	{ 0x258, 1, 5, 2, 0ULL, 0ULL, 0ULL, 0ULL };
+
+	if (pfault_disable)
+		return;
+	__ctl_clear_bit(0, 9);
+        __asm__ __volatile__(
+                "    diag  %0,0,0x258\n"
+		"0:\n"
+		".section __ex_table,\"a\"\n"
+		"   .align 4\n"
+		"   .quad  0b,0b\n"
+		".previous"
+		: : "a" (&refbk) : "cc" );
+}
+
+asmlinkage void
+pfault_interrupt(struct pt_regs *regs, __u16 error_code)
+{
+        DECLARE_WAITQUEUE(wait, current);
+	struct task_struct *tsk;
+	wait_queue_head_t queue;
+	wait_queue_head_t *qp;
+	__u16 subcode;
+
+	/*
+	 * Get the external interruption subcode & pfault
+	 * initial/completion signal bit. VM stores this 
+	 * in the 'cpu address' field associated with the
+         * external interrupt. 
+	 */
+	subcode = S390_lowcore.cpu_addr;
+	if ((subcode & 0xff00) != 0x06)
+		return;
+
+	/*
+	 * Get the token (= address of kernel stack of affected task).
+	 */
+	tsk = (struct task_struct *)
+		(*((unsigned long *) __LC_PFAULT_INTPARM) - THREAD_SIZE);
+
+	if (subcode & 0x0080) {
+		/* signal bit is set -> a page has been swapped in by VM */
+		qp = (wait_queue_head_t *)
+			xchg(&tsk->thread.pfault_wait, -1);
+		if (qp != NULL) {
+			/* Initial interrupt was faster than the completion
+			 * interrupt. pfault_wait is valid. Set pfault_wait
+			 * back to zero and wake up the process. This can
+			 * safely be done because the task is still sleeping
+			 * and can't procude new pfaults. */
+			tsk->thread.pfault_wait = 0ULL;
+			wake_up(qp);
+		}
+	} else {
+		/* signal bit not set -> a real page is missing. */
+                init_waitqueue_head (&queue);
+		qp = (wait_queue_head_t *)
+			xchg(&tsk->thread.pfault_wait, (addr_t) &queue);
+		if (qp != NULL) {
+			/* Completion interrupt was faster than the initial
+			 * interrupt (swapped in a -1 for pfault_wait). Set
+			 * pfault_wait back to zero and exit. This can be
+			 * done safely because tsk is running in kernel 
+			 * mode and can't produce new pfaults. */
+			tsk->thread.pfault_wait = 0ULL;
+		}
+
+                /* go to sleep */
+                wait_event(queue, tsk->thread.pfault_wait == 0ULL);
+	}
+}
+#endif
+
diff -u --recursive --new-file v2.4.7/linux/arch/s390x/tools/dasdfmt/Makefile linux/arch/s390x/tools/dasdfmt/Makefile
--- v2.4.7/linux/arch/s390x/tools/dasdfmt/Makefile	Tue Feb 13 14:13:44 2001
+++ linux/arch/s390x/tools/dasdfmt/Makefile	Wed Dec 31 16:00:00 1969
@@ -1,9 +0,0 @@
-all: dasdfmt
-
-dasdfmt: dasdfmt.c
-	$(CC) -o $@ $^
-	$(STRIP) $@
-
-clean:
-	rm -f dasdfmt
-
diff -u --recursive --new-file v2.4.7/linux/arch/s390x/tools/dasdfmt/dasdfmt.8 linux/arch/s390x/tools/dasdfmt/dasdfmt.8
--- v2.4.7/linux/arch/s390x/tools/dasdfmt/dasdfmt.8	Fri Mar  2 11:12:06 2001
+++ linux/arch/s390x/tools/dasdfmt/dasdfmt.8	Wed Dec 31 16:00:00 1969
@@ -1,68 +0,0 @@
-.TH DASDFMT 8 "Tue Jan 25 2000"
-.UC 4
-.SH NAME
-dasdfmt \- formatting of DSAD (ECKD) disk drives.
-.SH SYNOPSIS
-\fBdasdfmt\fR [-tvyLV] [-b \fIblockSize\fR] [-l \fIdiskLabel\fR] \fIdiskSpec\fR
-.SH DESCRIPTION
-\fBdasdfmt\fR formats a DASD (ECKD) disk drive to prepare it
-for usage with Linux for S/390. \fBWARNING\fR: Incautious usage of
-\fBdasdfmt\fR can result in \fBLOSS OF DATA\fR.
-
-.SH OPTIONS
-.TP
-\fB-t\fR
-Disables any modification of the disk drive. \fBdasdfmt\fR just prints
-out, what it \fBwould\fR do.
-
-.TP
-\fB-v\fR
-Increases verbosity.
-
-.TP
-\fB-y\fR 
-Start formatting without further user-confirmation.
-
-.TP
-\fB-L\fR 
-Omit the writing of a disk label after formatting.
-
-.TP
-\fB-V\fR 
-Print version number and exit.
-
-.TP
-\fB-b\fR \fIblockSize\fR
-Specify blocksize to be used. \fIblocksize\fR must be a positive integer
-and always be a power of two. Due due some limitations in the driver,
-it is \fBstrongly\fR recommended to use a \fIblockSize\fR of \fI4096\fR.
-
-.TP
-\fB-l\fR \fIdiskLabel\fR
-Specify the label to be written to disk after formatting. If no label is
-specified, a sensible default is used. \fIdiskLabel\fR is interpreted as
-ASCII string and is automatically converted to EBCDIC.
-
-.TP
-\fIdiskSpec\fR
-This parameter specified the device to be formatted. It also can be
-given in two variants:
-.sp
-	\fB-f\fR \fB/dev/dasd\fR\fIX\fR
-.br
-or
-.br
-	\fB-n\fR \fIdevnum\fR
-.sp
-The first form uses the commonly used
-.SM UNIX
-device notation where \fIX\fR is a single lowercase letter.
-The second form uses simply the device number.
-
-.SH BUGS
-None so far ;-)
-
-.SH AUTHOR
-.nf
-This man-page was written by Fritz Elfert <felfert@to.com>
-.fi
diff -u --recursive --new-file v2.4.7/linux/arch/s390x/tools/dasdfmt/dasdfmt.c linux/arch/s390x/tools/dasdfmt/dasdfmt.c
--- v2.4.7/linux/arch/s390x/tools/dasdfmt/dasdfmt.c	Wed Apr 11 19:02:29 2001
+++ linux/arch/s390x/tools/dasdfmt/dasdfmt.c	Wed Dec 31 16:00:00 1969
@@ -1,839 +0,0 @@
-/*
- *
- * dasdfmt.c
- *
- *  S390 version
- *    Copyright (C) 1999,2000 IBM Corporation
- *    Author(s): Utz Bacher, <utz.bacher@de.ibm.com>
- *
- *  Device-in-use-checks by Fritz Elfert, <felfert@to.com>
- *  Compatible Disk Layout enhancements by Carsten Otte, <cotte@de.ibm.com>
- *
- * Still to do:
- *   detect non-switch parameters ("dasdfmt -n 170 XY") and complain about them 
- */
-
-/* #define _LINUX_BLKDEV_H */
-
-#include <unistd.h>
-#include <stdio.h>
-#include <sys/types.h>
-#include <sys/stat.h>
-#include <fcntl.h>
-#include <sys/ioctl.h>
-#include <errno.h>
-#include <getopt.h>
-#include <limits.h>
-#include <stdlib.h>
-#include <string.h>
-#include <dirent.h>
-#include <mntent.h>
-#define __KERNEL__ /* we want to use kdev_t and not have to define it */
-#include <linux/kdev_t.h>
-#undef __KERNEL__
-
-#include <linux/fs.h>
-#include <asm/dasd.h>
-#include <linux/hdreg.h>
-
-#define EXIT_MISUSE 1
-#define EXIT_BUSY 2
-#define TEMPFILENAME "/tmp/ddfXXXXXX"
-#define TEMPFILENAMECHARS 8  /* 8 characters are fixed in all temp filenames */
-#define SLASHDEV "/dev/"
-#define PROC_DASD_DEVICES "/proc/dasd/devices"
-/* _PATH_MOUNTED is /etc/mtab - /proc/mounts does not show root-fs correctly */
-#define PROC_MOUNTS _PATH_MOUNTED
-#define PROC_SWAPS "/proc/swaps"
-#define DASD_DRIVER_NAME "dasd"
-#define LABEL_LENGTH 10
-#define PROC_LINE_LENGTH 80
-#define ERR_LENGTH 80
-
-#define MAX_FILELEN NAME_MAX+PATH_MAX
-
-#define GIVEN_DEVNO 1
-#define GIVEN_MAJOR 2
-#define GIVEN_MINOR 4
-
-#define CHECK_START 1
-#define CHECK_END 2
-#define CHECK_BLKSIZE 4
-#define CHECK_ALL ~0
-
-#define ERRMSG(x...) {fflush(stdout);fprintf(stderr,x);}
-#define ERRMSG_EXIT(ec,x...) {fflush(stdout);fprintf(stderr,x);exit(ec);}
-
-#define CHECK_SPEC_MAX_ONCE(i,str) \
-	{if (i>1) \
-		ERRMSG_EXIT(EXIT_MISUSE,"%s: " str " " \
-			"can only be specified once\n",prog_name);}
-
-#define PARSE_PARAM_INTO(x,param,base,str) \
-	{x=(int)strtol(param,&endptr,base); \
-	if (*endptr) \
-		ERRMSG_EXIT(EXIT_MISUSE,"%s: " str " " \
-			"is in invalid format\n",prog_name);}
-
-char *prog_name;/*="dasdfmt";*/
-char tempfilename[]=TEMPFILENAME;
-
-__u8 _ascebc[256] =
-{
- /*00 NUL   SOH   STX   ETX   EOT   ENQ   ACK   BEL */
-     0x00, 0x01, 0x02, 0x03, 0x37, 0x2D, 0x2E, 0x2F,
- /*08  BS    HT    LF    VT    FF    CR    SO    SI */
- /*              ->NL                               */
-     0x16, 0x05, 0x15, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F,
- /*10 DLE   DC1   DC2   DC3   DC4   NAK   SYN   ETB */
-     0x10, 0x11, 0x12, 0x13, 0x3C, 0x3D, 0x32, 0x26,
- /*18 CAN    EM   SUB   ESC    FS    GS    RS    US */
- /*                               ->IGS ->IRS ->IUS */
-     0x18, 0x19, 0x3F, 0x27, 0x22, 0x1D, 0x1E, 0x1F,
- /*20  SP     !     "     #     $     %     &     ' */
-     0x40, 0x5A, 0x7F, 0x7B, 0x5B, 0x6C, 0x50, 0x7D,
- /*28   (     )     *     +     ,     -    .      / */
-     0x4D, 0x5D, 0x5C, 0x4E, 0x6B, 0x60, 0x4B, 0x61,
- /*30   0     1     2     3     4     5     6     7 */
-     0xF0, 0xF1, 0xF2, 0xF3, 0xF4, 0xF5, 0xF6, 0xF7,
- /*38   8     9     :     ;     <     =     >     ? */
-     0xF8, 0xF9, 0x7A, 0x5E, 0x4C, 0x7E, 0x6E, 0x6F,
- /*40   @     A     B     C     D     E     F     G */
-     0x7C, 0xC1, 0xC2, 0xC3, 0xC4, 0xC5, 0xC6, 0xC7,
- /*48   H     I     J     K     L     M     N     O */
-     0xC8, 0xC9, 0xD1, 0xD2, 0xD3, 0xD4, 0xD5, 0xD6,
- /*50   P     Q     R     S     T     U     V     W */
-     0xD7, 0xD8, 0xD9, 0xE2, 0xE3, 0xE4, 0xE5, 0xE6,
- /*58   X     Y     Z     [     \     ]     ^     _ */
-     0xE7, 0xE8, 0xE9, 0xBA, 0xE0, 0xBB, 0xB0, 0x6D,
- /*60   `     a     b     c     d     e     f     g */
-     0x79, 0x81, 0x82, 0x83, 0x84, 0x85, 0x86, 0x87,
- /*68   h     i     j     k     l     m     n     o */
-     0x88, 0x89, 0x91, 0x92, 0x93, 0x94, 0x95, 0x96,
- /*70   p     q     r     s     t     u     v     w */
-     0x97, 0x98, 0x99, 0xA2, 0xA3, 0xA4, 0xA5, 0xA6,
- /*78   x     y     z     {     |     }     ~    DL */
-     0xA7, 0xA8, 0xA9, 0xC0, 0x4F, 0xD0, 0xA1, 0x07,
- /*80*/
-     0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F,
- /*88*/
-     0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F,
- /*90*/
-     0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F,
- /*98*/
-     0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F,
- /*A0*/
-     0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F,
- /*A8*/
-     0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F,
- /*B0*/
-     0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F,
- /*B8*/
-     0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F,
- /*C0*/
-     0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F,
- /*C8*/
-     0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F,
- /*D0*/
-     0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F,
- /*D8*/
-     0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F,
- /*E0        sz						*/
-     0x3F, 0x59, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F,
- /*E8*/
-     0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F,
- /*F0*/
-     0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F,
- /*F8*/
-     0x90, 0x3F, 0x3F, 0x3F, 0x3F, 0xEA, 0x3F, 0xFF
-};
-
-void convert_label(char *str)
-{
-	int i;
-	for (i=0;i<LABEL_LENGTH;i++) str[i]=_ascebc[str[i]];
-}
-
-void
-exit_usage(int exitcode)
-{
-#ifdef RANGE_FORMATTING
-	printf("Usage: %s [-htvyCLV] [-l <label>] [-b <blocksize>] [<range>] " \
-		"<diskspec>\n\n",prog_name);
-#else /* RANGE_FORMATTING */
-	printf("Usage: %s [-htvyCLV] [-l <label>] [-b <blocksize>] " \
-		"<diskspec>\n\n",prog_name);
-#endif /* RANGE_FORMATTING */
-	printf("       -t means testmode\n");
-	printf("       -v means verbose mode\n");
-	printf("       -C means format compatible disk layout\n");
-	printf("       -V means print version\n");
-	printf("       -L means don't write disk label\n");
-	printf("       <label> is a label which is converted to EBCDIC and " \
-		"written to disk\n");
-	printf("       <blocksize> has to be power of 2 and at least 512\n");
-#ifdef RANGE_FORMATTING
-	printf("       <range> is either\n");
-	printf("           -s <start_track> -e <end_track>\n");
-	printf("       or\n");
-	printf("           -r <start_track>-<end_track>\n");
-#endif /* RANGE_FORMATTING */
-	printf("       and <diskspec> is either\n");
-	printf("           -f /dev/dasdX\n");
-	printf("       or\n");
-	printf("           -n <s390-devnr>\n");
-	exit(exitcode);
-}
-
-void
-get_xno_from_xno(int *devno,kdev_t *major_no,kdev_t *minor_no,int mode)
-{
-	FILE *file;
-	int d,rc;
-	kdev_t mi,ma;
-	int mi_i,ma_i; /* for scanf :-( */
-	char line[PROC_LINE_LENGTH];
-
-	file=fopen(PROC_DASD_DEVICES,"r");
-	if (file==NULL)
-		ERRMSG_EXIT(EXIT_FAILURE,"%s: failed to open " \
-			PROC_DASD_DEVICES ": %s (do you have the /proc " \
-			"filesystem enabled?)\n",prog_name,strerror(errno));
-
-	/*	fgets(line,sizeof(line),file); omit first line */ 
-	while (fgets(line,sizeof(line),file)!=NULL) {
-                rc=sscanf(line,"%X %*[(A-Z) ] at (%d:%d)",&d,&ma_i,&mi_i);
-		ma=ma_i;
-		mi=mi_i;
-		if ( (rc==3) &&
-			!((d!=*devno)&&(mode&GIVEN_DEVNO)) &&
-			!((ma!=*major_no)&&(mode&GIVEN_MAJOR)) &&
-			!((mi!=*minor_no)&&(mode&GIVEN_MINOR)) ) {
-			*devno=d;
-			*major_no=ma;
-			*minor_no=mi;
-			/* yes, this is a quick exit, but the easiest way */
-			fclose(file);
-			return;
-		}
-	}
-	fclose(file);
-
-	ERRMSG_EXIT(EXIT_FAILURE,"%s: failed to find device in the /proc " \
-		    "filesystem (are you sure to have the right parameter " \
-		    "dasd=xxx?)\n",
-		prog_name);
-}
-
-char *
-get_devname_from_devno(int devno,int verbosity)
-{
-	kdev_t major_no,minor_no;
-	kdev_t file_major,file_minor;
-	struct stat stat_buf;
-	int rc;
-	int found;
-	char *devname;
-	char tmpname[MAX_FILELEN];
-
-	DIR *dp;
-	struct dirent *direntp;
-
-	/**** get minor number ****/
-	get_xno_from_xno(&devno,&major_no,&minor_no,GIVEN_DEVNO);
-
-	/**** get device file ****/
-	if ((dp=opendir(SLASHDEV)) == NULL)
-		ERRMSG_EXIT(EXIT_FAILURE,"%s: unable to read " SLASHDEV \
-			"\n",prog_name);
-	found=0;
-	while ((direntp=readdir(dp)) != NULL) {
-		strcpy(tmpname,SLASHDEV);
-		strcat(tmpname,direntp->d_name);
-		rc=stat(tmpname,&stat_buf);
-		if (!rc) {
-			file_major=MAJOR(stat_buf.st_rdev);
-			file_minor=MINOR(stat_buf.st_rdev);
-			if ((file_major==major_no) && (file_minor==minor_no)) {
-				found=1;
-				break;
-			}
-		}
-	}
-	if (found) {
-		devname=malloc(strlen(direntp->d_name));
-		strcpy(devname,tmpname);
-	}
-	rc=closedir(dp);
-	if (rc<0) ERRMSG("%s: unable to close directory " SLASHDEV \
-		"; continuing\n",prog_name);
-	if (found)
-		return devname;
-
-	if (verbosity>=1)
-		printf("I didn't find device node in " SLASHDEV \
-			"; trying to create a temporary node\n");
-
-	/**** get temp file and create device node *****/
-	rc=mkstemp(tempfilename);
-	if (rc==-1)
-		ERRMSG_EXIT(EXIT_FAILURE,"%s: failed to get temporary " \
-			"filename: %s\n",prog_name,strerror(errno));
-	close(rc);
-	rc=unlink(tempfilename);
-	
-	rc=mknod(tempfilename,S_IFBLK|0600,MKDEV(major_no,minor_no));
-	if (rc)
-		ERRMSG_EXIT(EXIT_FAILURE,"%s: failed to create temporary " \
-			"device node %s: %s\n",prog_name,tempfilename,
-			strerror(errno));
-	return tempfilename;
-}
-
-char *
-check_param(int mode,format_data_t data)
-{
-	char *s;
-
-	if (NULL==(s=malloc(ERR_LENGTH)))
-		ERRMSG_EXIT(EXIT_FAILURE,"%s: not enough memory.\n",prog_name);
-
-	if ((mode&CHECK_START)&&(data.start_unit<0)) {
-		strcpy(s,"start track must be greater than zero");
-		goto exit;
-	}
-	if ((mode&CHECK_END)&&(data.stop_unit<-1)) {
-		strcpy(s,"end track must be -1 or greater than zero");
-		goto exit;
-	}
-	if ((mode&CHECK_END)&&(data.start_unit>data.stop_unit)&&
-		(data.stop_unit!=-1)) {
-		strcpy(s,"end track must be higher than start track");
-		goto exit;
-	}
-
-	if ((mode&CHECK_BLKSIZE)&&(data.blksize<1)) {
-		strcpy(s,"blocksize must be a positive integer");
-		goto exit;
-	}
-	if (mode&CHECK_BLKSIZE) while (data.blksize>0) {
-		if ((data.blksize%2)&&(data.blksize!=1)) {
-			strcpy(s,"blocksize must be a power of 2");
-			goto exit;
-		}
-		data.blksize/=2;
-	}
-
-	free(s);
-	return NULL;
-exit:
-	return s;
-}
-
-#define ASK_PRINTOUT printf("Please enter %s",output)
-#define ASK_GETBUFFER fgets(buffer,sizeof(buffer),stdin)
-#define ASK_SCANFORNUMBER(var) rc=sscanf(buffer,"%d%c",&var,&c)
-#define ASK_COMPLAIN_FORMAT if ((rc==2)&&(c=='\n')) rc=1; \
-	if (rc==-1) rc=1; /* this happens, if enter is pressed */ \
-	if (rc!=1) printf(" -- wrong input, try again.\n")
-#define ASK_CHECK_PARAM(mode) str=check_param(mode,params); \
-		if (str!=NULL) { printf(" -- %s\n",str); rc=0; free(str); }
-
-format_data_t
-ask_user_for_data(format_data_t params)
-{
-	char buffer[20]; /* should be enough for inputing track numbers */
-	char c;
-	int i,rc;
-	char *str;
-	char output[60],o2[12];
-
-#ifdef RANGE_FORMATTING
-	i=params.start_unit;
-	do {
-		params.start_unit=i;
-		sprintf(output,"the start track of the range to format " \
-			"[%d]: ",i);
-		ASK_PRINTOUT;
-		ASK_GETBUFFER;
-		ASK_SCANFORNUMBER(params.start_unit);
-		ASK_COMPLAIN_FORMAT;
-		ASK_CHECK_PARAM(CHECK_START);
-	} while (rc!=1);
-
-	i=params.stop_unit;
-	do {
-		params.stop_unit=i;
-		sprintf(output,"the end track of the range to format [");
-		if (i==-1) sprintf(o2,"END]: "); else
-			sprintf(o2,"%d]: ",i);
-		strcat(output,o2);
-		ASK_PRINTOUT;
-		ASK_GETBUFFER;
-		if ( (!strcasecmp(buffer,"end")) ||
-			(!strcasecmp(buffer,"end\n")) ) {
-			rc=1;
-			params.stop_unit=-1;
-		} else {
-			ASK_SCANFORNUMBER(params.stop_unit);
-			ASK_COMPLAIN_FORMAT;
-			ASK_CHECK_PARAM(CHECK_END);
-		}
-	} while (rc!=1);
-#endif /* RANGE_FORMATTING */
-
-	i=params.blksize;
-	do {
-		params.blksize=i;
-		sprintf(output,"the blocksize of the formatting [%d]: ",i);
-		ASK_PRINTOUT;
-		ASK_GETBUFFER;
-		ASK_SCANFORNUMBER(params.blksize);
-		ASK_COMPLAIN_FORMAT;
-		ASK_CHECK_PARAM(CHECK_BLKSIZE);
-	} while (rc!=1);
-
-	return params;
-}
-
-/* Check if the device we are going to format is mounted.
- * If true, complain and exit.
- */
-void
-check_mounted(int major, int minor)
-{
-	FILE *f;
-	int ishift = 0;
-	struct mntent *ment;
-	struct stat stbuf;
-	char line[128];
-
-	/* If whole disk to be formatted ... */
-	if ((minor % (1U << DASD_PARTN_BITS)) == 0) {
-		/* ... ignore partition-selector */
-		minor >>= DASD_PARTN_BITS;
-		ishift = DASD_PARTN_BITS;
-	}
-	/*
-	 * first, check filesystems
-	 */
-	if (!(f = fopen(PROC_MOUNTS, "r")))
-		ERRMSG_EXIT(EXIT_FAILURE, "%s: %s\n", PROC_MOUNTS,
-			strerror(errno));
-	while ((ment = getmntent(f))) {
-		if (stat(ment->mnt_fsname, &stbuf) == 0)
-			if ((major == MAJOR(stbuf.st_rdev)) &&
-				(minor == (MINOR(stbuf.st_rdev)>>ishift))) {
-				ERRMSG("%s: device is mounted on %s!!\n",
-					prog_name,ment->mnt_dir);
-				ERRMSG_EXIT(EXIT_BUSY, "If you really want to "
-					"format it, please unmount it.\n");
-			}
-	}
-	fclose(f);
-	/*
-	 * second, check active swap spaces
-	 */
-	if (!(f = fopen(PROC_SWAPS, "r")))
-		ERRMSG_EXIT(EXIT_FAILURE, PROC_SWAPS " %s", strerror(errno));
-	/*
-	 * skip header line
-	 */
-	fgets(line, sizeof(line), f);
-	while (fgets(line, sizeof(line), f)) {
-		char *p;
-		for (p = line; *p && (!isspace(*p)); p++) ;
-		*p = '\0';
-		if (stat(line, &stbuf) == 0)
-			if ((major == MAJOR(stbuf.st_rdev)) &&
-				(minor == (MINOR(stbuf.st_rdev)>>ishift))) {
-				ERRMSG("%s: the device is in use for "
-					"swapping!!\n",prog_name);
-				ERRMSG_EXIT(EXIT_BUSY, "If you really want to "
-					"format it, please use swapoff %s.\n",
-					line);
-			}
-	}
-	fclose(f);
-}
-
-void
-do_format_dasd(char *dev_name,format_data_t format_params,int testmode,
-	int verbosity,int writenolabel,int labelspec,
-	char *label,int withoutprompt,int devno)
-{
-	int fd,rc;
-	struct stat stat_buf;
-	kdev_t minor_no,major_no;
-	int new_blksize;
-	unsigned int label_position;
-	struct hd_geometry new_geometry;
-	char inp_buffer[5]; /* to contain yes */
-
-	fd=open(dev_name,O_RDWR);
-	if (fd==-1)
-		ERRMSG_EXIT(EXIT_FAILURE,"%s: error opening device %s: " \
-			"%s\n",prog_name,dev_name,strerror(errno));
-
-	if (verbosity>=1) {
-	}
-
-	rc=stat(dev_name,&stat_buf);
-	if (rc) {
-		ERRMSG_EXIT(EXIT_FAILURE,"%s: error occurred during stat: " \
-			"%s\n",prog_name,strerror(errno));
-	} else {
-		if (!S_ISBLK(stat_buf.st_mode))
-			ERRMSG_EXIT(EXIT_FAILURE,"%s: file is not a " \
-				"blockdevice.\n",prog_name);
-		major_no=MAJOR(stat_buf.st_rdev);
-		minor_no=MINOR(stat_buf.st_rdev);
-	}
-	check_mounted(major_no, minor_no);
-
-	get_xno_from_xno(&devno,&major_no,&minor_no,
-			GIVEN_MAJOR|GIVEN_MINOR);
-	if ((!writenolabel) && (!labelspec)) {
-		sprintf(label,"LNX1 x%04x",devno);
-	}
-	
-	if ( ((withoutprompt)&&(verbosity>=1)) ||
-		(!withoutprompt) ) {
-		printf("\nI am going to format the device %s in the " \
-			"following way:\n",dev_name);
-		printf("   Device number of device : 0x%x\n",devno);
-		printf("   Major number of device  : %u\n",major_no);
-		printf("   Minor number of device  : %u\n",minor_no);
-		printf("   Labelling device        : %s\n",(writenolabel)?
-			"no":"yes");
-		if (!writenolabel)
-			printf("   Disk label              : %s\n",label);
-		if (format_params.intensity != DASD_FORMAT_DEFAULT_INTENSITY)
-			printf("   Compatible Disk Layout  : %s\n",(format_params.intensity&0x08)?
-			       "yes":"no");
-#ifdef RANGE_FORMATTING
-		printf("   Start track             : %d\n" \
-			,format_params.start_unit);
-		printf("   End track               : ");
-		if (format_params.stop_unit==-1)
-			printf("last track of disk\n");
-		else
-			printf("%d\n",format_params.stop_unit);
-#endif /* RANGE_FORMATTING */
-		printf("   Blocksize               : %d\n" \
-			,format_params.blksize);
-		if (testmode) printf("Test mode active, omitting ioctl.\n");
-	}
-
-	while (!testmode) {
-		if (!withoutprompt) {
-			printf("\n--->> ATTENTION! <<---\n");
-			printf("All data in the specified range of that " \
-				"device will be lost.\nType \"yes\" to " \
-				"continue, no will leave the disk untouched: ");
-			fgets(inp_buffer,sizeof(inp_buffer),stdin);
-			if (strcasecmp(inp_buffer,"yes") &&
-				strcasecmp(inp_buffer,"yes\n")) {
-				printf("Omitting ioctl call (disk will " \
-					"NOT be formatted).\n");
-				break;
-			}
-		}
-
-		if ( !(  (withoutprompt)&&(verbosity<1) ))
-			printf("Formatting the device. This may take a " \
-				"while (get yourself a coffee).\n");
-		rc=ioctl(fd,BIODASDFORMAT,format_params);
-		if (rc)
-			ERRMSG_EXIT(EXIT_FAILURE,"%s: the dasd driver " \
-				"returned with the following error " \
-				"message:\n%s\n",prog_name,strerror(errno));
-		printf("Finished formatting the device.\n");
-
-		if (!writenolabel) {
-			if (verbosity>0)
-				printf("Retrieving disk geometry... ");
-
-			rc=ioctl(fd,HDIO_GETGEO,&new_geometry);
-			if (rc) {
-				ERRMSG("%s: the ioctl call to get geometry " \
-					"returned with the following error " \
-					"message:\n%s\n",prog_name,
-					strerror(errno));
-				goto reread;
-			}
-	
-
-			rc=ioctl(fd,BLKSSZGET,&new_blksize);
-			if (rc) {
-				ERRMSG("%s: the ioctl call to get blocksize " \
-					"returned with the following error " \
-					"message:\n%s\n",prog_name,
-					strerror(errno));
-				goto reread;
-			}
-	
-			if (verbosity>0) printf("done\n");
-
-			label_position=new_geometry.start*new_blksize;
-	
-			if (verbosity>0) printf("Writing label... ");
-			convert_label(label);
-			rc=lseek(fd,label_position,SEEK_SET);
-			if (rc!=label_position) {
-				ERRMSG("%s: lseek on the device to %i " \
-					"failed with the following error " \
-					"message:\n%s\n",prog_name,
-					label_position,strerror(errno));
-				goto reread;
-			}
-			rc=write(fd,label,LABEL_LENGTH);
-			if (rc!=LABEL_LENGTH) {
-				ERRMSG("%s: writing the label only wrote %d " \
-					"bytes.\n",prog_name,rc);
-				goto reread;
-			}
-
-			sync();
-			sync();
-
-			if (verbosity>0) printf("done\n");
-		}
- reread:
-		printf("Rereading the partition table... ");
-		rc=ioctl(fd,BLKRRPART,NULL);
-		if (rc) {
-			ERRMSG("%s: error during rereading the partition " \
-			       "table: %s.\n",prog_name,strerror(errno));
-		} else printf("done.\n");
-
-		break;
-	}
-
-	rc=close(fd);
-	if (rc)
-		ERRMSG("%s: error during close: " \
-			"%s; continuing.\n",prog_name,strerror(errno));
-}
-
-
-
-int main(int argc,char *argv[]) {
-	int verbosity;
-	int testmode;
-	int withoutprompt;
-	int writenolabel,labelspec;
-
-	char *dev_name;
-	int devno;
-	char *dev_filename,*devno_param_str,*range_param_str;
-	char *start_param_str,*end_param_str,*blksize_param_str;
-	char label[LABEL_LENGTH+1];
-	
-	format_data_t format_params;
-
-	int rc;
-	int oc;
-	char *endptr;
-
-	char c1,c2,cbuffer[6]; /* should be able to contain -end plus 1 char */
-	int i,i1,i2;
-	char *str;
-
-	int start_specified,end_specified,blksize_specified;
-	int devfile_specified,devno_specified,range_specified;
-
-	/******************* initialization ********************/
-	prog_name=argv[0];
-
-	endptr=NULL;
-
-	/* set default values */
-	format_params.start_unit=DASD_FORMAT_DEFAULT_START_UNIT;
-	format_params.stop_unit=DASD_FORMAT_DEFAULT_STOP_UNIT;
-	format_params.blksize=DASD_FORMAT_DEFAULT_BLOCKSIZE;
-	format_params.intensity=DASD_FORMAT_DEFAULT_INTENSITY;
-	testmode=0;
-	verbosity=0;
-	withoutprompt=0;
-	writenolabel=0;
-	labelspec=0;
-	for (i=0;i<LABEL_LENGTH;i++) label[i]=' ';
-	label[LABEL_LENGTH]=0;
-
-	start_specified=end_specified=blksize_specified=0;
-	devfile_specified=devno_specified=range_specified=0;
-
-	/*************** parse parameters **********************/
-
-	/* avoid error message generated by getopt */
-	opterr=0;
-
-#ifdef RANGE_FORMATTING
-	while ( (oc=getopt(argc,argv,"r:s:e:b:n:l:f:ChLty?vV")) !=EOF) {
-#endif /* RANGE_FORMATTING */
-	while ( (oc=getopt(argc,argv,"b:n:l:f:ChLty?vV")) !=EOF) {
-		switch (oc) {
-		case 'y':
-			withoutprompt=1;
-			break;
-
-		case 't':
-			testmode=1;
-			break;
-
-		case 'v':
-			verbosity++;
-			break;
-
-		case '?': /* fall-through */
-		case ':':
-			exit_usage(EXIT_MISUSE);
-
-		case 'h':
-			exit_usage(0);
-		case 'C':
-                	format_params.intensity&=0x08;
-			break;
-
-		case 'V':
-			printf("%s version 0.99\n",prog_name);
-			exit(0);
-
-		case 'l':
-			strncpy(label,optarg,LABEL_LENGTH);
-			if (strlen(optarg)<LABEL_LENGTH)
-				label[strlen(optarg)]=' ';
-			labelspec++;
-			break;
-
-		case 'L':
-			writenolabel++;
-			break;
-
-#ifdef RANGE_FORMATTING
-		case 's' :
-			start_param_str=optarg;
-			start_specified++;
-			break;
-			
-		case 'e' :
-			end_param_str=optarg;
-			end_specified++;
-			break;
-
-		case 'r' :
-			range_param_str=optarg;
-			range_specified++;
-			break;
-#endif /* RANGE_FORMATTING */
-
-		case 'b' :
-			blksize_param_str=optarg;
-			blksize_specified++;
-			break;
-			
-		case 'n' :
-			devno_param_str=optarg;
-			devno_specified++;
-			break;
-		
-		case 'f' :
-			dev_filename=optarg;
-			devfile_specified++;
-			break;
-		}
-	}
-
-	/******************** checking of parameters **************/
-
-	/* convert range into -s and -e */
-	CHECK_SPEC_MAX_ONCE(range_specified,"formatting range");
-
-	while (range_specified) {
-		start_specified++;
-		end_specified++;
-
-		/* scan for 1 or 2 integers, separated by a dash */
-		rc=sscanf(range_param_str,"%d%c%d%c",&i1,&c1,&i2,&c2);
-		if ((rc==3)&&(c1=='-')) {
-			format_params.start_unit=i1;
-			format_params.stop_unit=i2;
-			break;
-		}
-		if (rc==1) {
-			format_params.start_unit=i1;
-			break;
-		}
-
-		/* scan for integer and -END */
-		rc=sscanf(range_param_str,"%d%s",&i1,cbuffer);
-		if ((rc==2)&&(!strcasecmp(cbuffer,"-END"))) {
-			format_params.start_unit=i1;
-			format_params.stop_unit=-1;
-			break;
-		}
-		ERRMSG_EXIT(EXIT_MISUSE,"%s: specified range " \
-			"is in invalid format\n",prog_name);
-	}
-
-	if ((!devfile_specified)&&(!devno_specified))
-		ERRMSG_EXIT(EXIT_MISUSE,"%s: device to format " \
-			"not specified\n",prog_name);
-
-	if ((devfile_specified+devno_specified)>1)
-		ERRMSG_EXIT(EXIT_MISUSE,"%s: device to format " \
-			"can only be specified once\n",prog_name);
-
-	if ((!start_specified)&&(!end_specified)&&(!range_specified)&&
-		(!blksize_specified)) {
-		format_params=ask_user_for_data(format_params);
-	}
-
-	CHECK_SPEC_MAX_ONCE(start_specified,"start track");
-	CHECK_SPEC_MAX_ONCE(end_specified,"end track");
-	CHECK_SPEC_MAX_ONCE(blksize_specified,"blocksize");
-	CHECK_SPEC_MAX_ONCE(labelspec,"label");
-	CHECK_SPEC_MAX_ONCE(writenolabel,"omit-label-writing flag");
-
-	if (devno_specified)
-		PARSE_PARAM_INTO(devno,devno_param_str,16,"device number");
-	if (start_specified&&!range_specified)
-		PARSE_PARAM_INTO(format_params.start_unit,start_param_str,10,
-			"start track");
-	if (end_specified&&!range_specified)
-		PARSE_PARAM_INTO(format_params.stop_unit,end_param_str,10,
-			"end track");
-	if (blksize_specified)
-		PARSE_PARAM_INTO(format_params.blksize,blksize_param_str,10,
-			"blocksize");
-
-	/***********get dev_name *********************/
-	dev_name=(devno_specified)?
-		get_devname_from_devno(devno,verbosity):
-		dev_filename;
-
-	/*** range checking *********/
-	str=check_param(CHECK_ALL,format_params);
-	if (str!=NULL) ERRMSG_EXIT(EXIT_MISUSE,"%s: %s\n",prog_name,str);
-
-	/******* issue the real command and reread part table *******/
-	do_format_dasd(dev_name,format_params,testmode,verbosity,
-		writenolabel,labelspec,label,withoutprompt,devno);
-
-	/*************** cleanup ********************************/
-	if (strncmp(dev_name,TEMPFILENAME,TEMPFILENAMECHARS)==0) {
-		rc=unlink(dev_name);
-		if ((rc)&&(verbosity>=1))
-			ERRMSG("%s: temporary device node %s could not be " \
-				"removed: %s\n",prog_name,dev_name,
-				strerror(errno));
-	} else {
-		if (devno_specified) {
-			/* so we have allocated space for the filename */
-			free(dev_name);
-		}
-	}
-
-	return 0;
-}
diff -u --recursive --new-file v2.4.7/linux/arch/s390x/tools/silo/Makefile linux/arch/s390x/tools/silo/Makefile
--- v2.4.7/linux/arch/s390x/tools/silo/Makefile	Tue Feb 13 14:13:44 2001
+++ linux/arch/s390x/tools/silo/Makefile	Wed Dec 31 16:00:00 1969
@@ -1,15 +0,0 @@
-all: silo
-
-silo.o: silo.c
-	$(CC) -c -o silo.o -O2 silo.c
-
-cfg.o: cfg.c
-	$(CC) -c -o cfg.o -O2 cfg.c
-
-silo: silo.o cfg.o
-	$(CC) -o $@ $^
-	$(STRIP) $@
-
-clean:
-	rm -f *.o silo
-
diff -u --recursive --new-file v2.4.7/linux/arch/s390x/tools/silo/cfg.c linux/arch/s390x/tools/silo/cfg.c
--- v2.4.7/linux/arch/s390x/tools/silo/cfg.c	Tue Feb 13 14:13:44 2001
+++ linux/arch/s390x/tools/silo/cfg.c	Wed Dec 31 16:00:00 1969
@@ -1,373 +0,0 @@
-/* cfg.c  -  Configuration file parser */
-
-/* Copyright 1992-1997 Werner Almesberger. See file COPYING for details. */
-
-
-#include <stdlib.h>
-#include <stdio.h>
-#include <stdarg.h>
-#include <ctype.h>
-#include <string.h>
-
-#include "cfg.h"
-
-#define MAX_TOKEN 200
-#define MAX_VAR_NAME MAX_TOKEN
-
-static FILE *file;
-static char flag_set;
-static char *last_token = NULL,*last_item = NULL,*last_value = NULL;
-static int line_num;
-static char *file_name = NULL;
-static int back = 0; /* can go back by one char */
-
-
-void pdie(char *msg)
-{
-    fflush(stdout);
-    perror(msg);
-    exit(1);
-}
-
-
-void die(char *fmt,...)
-{
-    va_list ap;
-
-    fflush(stdout);
-    va_start(ap,fmt);
-    vfprintf(stderr,fmt,ap);
-    va_end(ap);
-    fputc('\n',stderr);
-    exit(1);
-}
-
-char *pstrdup(const char *str)
-{
-    char *this;
-
-    if ((this = strdup(str)) == NULL) pdie("Out of memory");
-    return this;
-}
-
-int cfg_open(char *name)
-{
-    if (!strcmp(name,"-")) file = stdin;
-    else if (!(file = fopen(file_name = name,"r"))) pdie(name);
-    line_num = 1;
-    return fileno(file);
-}
-
-void cfg_error(char *msg,...)
-{
-    va_list ap;
-
-    fflush(stdout);
-    va_start(ap,msg);
-    vfprintf(stderr,msg,ap);
-    va_end(ap);
-    if (!file_name) fputc('\n',stderr);
-    else fprintf(stderr," near line %d in file %s\n",line_num,file_name);
-    exit(1);
-}
-
-
-static int next_raw(void)
-{
-    int ch;
-
-    if (!back) return getc(file);
-    ch = back;
-    back = 0;
-    return ch;
-}
-
-
-static int next(void)
-{
-    static char *var;
-    char buffer[MAX_VAR_NAME+1];
-    int ch,braced;
-    char *put;
-
-    if (back) {
-	ch = back;
-	back = 0;
-	return ch;
-    }
-    if (var && *var) return *var++;
-    ch = getc(file);
-    if (ch == '\\') {
-	ch = getc(file);
-	if (ch == '$') return ch;
-	ungetc(ch,file);
-	return '\\';
-    }
-    if (ch != '$') return ch;
-    ch = getc(file);
-    braced = ch == '{';
-    put = buffer;
-    if (!braced) *put++ = ch;
-    while (1) {
-	ch = getc(file);
-#if 0
-	if (!braced && ch < ' ') {
-	    ungetc(ch,file);
-	    break;
-	}
-#endif
-	if (ch == EOF) cfg_error("EOF in variable name");
-	if (ch < ' ') cfg_error("control character in variable name");
-	if (braced && ch == '}') break;
-	if (!braced && !isalpha(ch) && !isdigit(ch) && ch != '_') {
-	    ungetc(ch,file);
-	    break;
-	}
-	if (put-buffer == MAX_VAR_NAME) cfg_error("variable name too long");
-	*put++ = ch;
-    }
-    *put = 0;
-    if (!(var = getenv(buffer))) cfg_error("unknown variable \"%s\"",buffer);
-    return next();
-}
-
-
-static void again(int ch)
-{
-    if (back) die("internal error: again invoked twice");
-    back = ch;
-}
-
-
-static char *cfg_get_token(void)
-{
-    char buf[MAX_TOKEN+1];
-    char *here;
-    int ch,escaped;
-
-    if (last_token) {
-	here = last_token;
-	last_token = NULL;
-	return here;
-    }
-    while (1) {
-	while ((ch = next()), ch == ' ' || ch == '\t' || ch == '\n')
-	    if (ch == '\n') line_num++;
-	if (ch == EOF) return NULL;
-	if (ch != '#') break;
-	while ((ch = next_raw()), ch != '\n')
-	    if (ch == EOF) return NULL;
-	line_num++;
-    }
-    if (ch == '=') return pstrdup("=");
-    if (ch == '"') {
-	here = buf;
-	while (here-buf < MAX_TOKEN) {
-	    if ((ch = next()) == EOF) cfg_error("EOF in quoted string");
-	    if (ch == '"') {
-		*here = 0;
-		return pstrdup(buf);
-	    }
-	    if (ch == '\\') {
-		ch = next();
-		if (ch != '"' && ch != '\\' && ch != '\n')
-		    cfg_error("Bad use of \\ in quoted string");
-		if (ch == '\n') {
-		    while ((ch = next()), ch == ' ' || ch == '\t');
-		    if (!ch) continue;
-		    again(ch);
-		    ch = ' ';
-		}
-	    }
-	    if (ch == '\n' || ch == '\t')
-		cfg_error("\\n and \\t are not allowed in quoted strings");
-	    *here++ = ch;
-	}
-	cfg_error("Quoted string is too long");
-	return 0; /* not reached */
-    }
-    here = buf;
-    escaped = 0;
-    while (here-buf < MAX_TOKEN) {
-	if (escaped) {
-	    if (ch == EOF) cfg_error("\\ precedes EOF");
-	    if (ch == '\n') line_num++;
-	    else *here++ = ch == '\t' ? ' ' : ch;
-	    escaped = 0;
-	}
-	else {
-	    if (ch == ' ' || ch == '\t' || ch == '\n' || ch == '#' ||
-	      ch == '=' || ch == EOF) {
-		again(ch);
-		*here = 0;
-		return pstrdup(buf);
-	    }
-	    if (!(escaped = (ch == '\\'))) *here++ = ch;
-	}
-	ch = next();
-    }
-    cfg_error("Token is too long");
-    return 0; /* not reached */
-}
-
-
-static void cfg_return_token(char *token)
-{
-    last_token = token;
-}
-
-
-static int cfg_next(char **item,char **value)
-{
-    char *this;
-
-    if (last_item) {
-	*item = last_item;
-	*value = last_value;
-	last_item = NULL;
-	return 1;
-    }
-    *value = NULL;
-    if (!(*item = cfg_get_token())) return 0;
-    if (!strcmp(*item,"=")) cfg_error("Syntax error");
-    if (!(this = cfg_get_token())) return 1;
-    if (strcmp(this,"=")) {
-	cfg_return_token(this);
-	return 1;
-    }
-    if (!(*value = cfg_get_token())) cfg_error("Value expected at EOF");
-    if (!strcmp(*value,"=")) cfg_error("Syntax error after %s",*item);
-    return 1;
-}
-
-
-static void cfg_return(char *item,char *value)
-{
-    last_item = item;
-    last_value = value;
-}
-
-
-void cfg_init(CONFIG *table)
-{
-    while (table->type != cft_end) {
-	switch (table->type) {
-	    case cft_strg:
-		if (table->data) free(table->data);
-	    case cft_flag:
-		table->data = NULL;
-		break;
-	    case cft_link:
-		table = ((CONFIG *) table->action)-1;
-		break;
-	    default:
-		die("Unknown syntax code %d",table->type);
-	}
-	table++;
-    }
-}
-
-
-static int cfg_do_set(CONFIG *table,char *item,char *value,int copy,
-    void *context)
-{
-    CONFIG *walk;
-
-    for (walk = table; walk->type != cft_end; walk++) {
-	if (walk->name && !strcasecmp(walk->name,item)) {
-	    if (value && walk->type != cft_strg)
-		cfg_error("'%s' doesn't have a value",walk->name);
-	    if (!value && walk->type == cft_strg)
-		cfg_error("Value expected for '%s'",walk->name);
-	    if (walk->data) {
-		if (walk->context == context)
-		    cfg_error("Duplicate entry '%s'",walk->name);
-		else {
-		    fprintf(stderr,"Ignoring entry '%s'\n",walk->name);
-		    if (!copy) free(value);
-		    return 1;
-		}
-	    }
-	    if (walk->type == cft_flag) walk->data = &flag_set;
-	    else if (walk->type == cft_strg) {
-		    if (copy) walk->data = pstrdup(value);
-		    else walk->data = value;
-	    }
-	    walk->context = context;
-	    if (walk->action) ((void (*)(void)) walk->action)();
-	    break;
-	}
-	if (walk->type == cft_link) walk = ((CONFIG *) walk->action)-1;
-    }
-    if (walk->type != cft_end) return 1;
-    cfg_return(item,value);
-    return 0;
-}
-
-
-void cfg_set(CONFIG *table,char *item,char *value,void *context)
-{
-    if (!cfg_do_set(table,item,value,1,context))
-	cfg_error("cfg_set: Can't set %s",item);
-}
-
-
-void cfg_unset(CONFIG *table,char *item)
-{
-    CONFIG *walk;
-
-    for (walk = table; walk->type != cft_end; walk++)
-	if (walk->name && !strcasecmp(walk->name,item)) {
-	    if (!walk->data) die("internal error (cfg_unset %s, unset)",item);
-	    if (walk->type == cft_strg) free(walk->data);
-	    walk->data = NULL;
-	    return;
-	}
-    die("internal error (cfg_unset %s, unknown",item);
-}
-
-
-int cfg_parse(CONFIG *table)
-{
-    char *item,*value;
-
-    while (1) {
-	if (!cfg_next(&item,&value)) return 0;
-	if (!cfg_do_set(table,item,value,0,table)) return 1;
-	free(item);
-    }
-}
-
-
-int cfg_get_flag(CONFIG *table,char *item)
-{
-    CONFIG *walk;
-
-    for (walk = table; walk->type != cft_end; walk++) {
-	if (walk->name && !strcasecmp(walk->name,item)) {
-	    if (walk->type != cft_flag)
-		die("cfg_get_flag: operating on non-flag %s",item);
-	    return !!walk->data;
-	}
-	if (walk->type == cft_link) walk = ((CONFIG *) walk->action)-1;
-    }
-    die("cfg_get_flag: unknown item %s",item);
-    return 0; /* not reached */
-}
-
-
-char *cfg_get_strg(CONFIG *table,char *item)
-{
-    CONFIG *walk;
-
-    for (walk = table; walk->type != cft_end; walk++) {
-	if (walk->name && !strcasecmp(walk->name,item)) {
-	    if (walk->type != cft_strg)
-		die("cfg_get_strg: operating on non-string %s",item);
-	    return walk->data;
-	}
-	if (walk->type == cft_link) walk = ((CONFIG *) walk->action)-1;
-    }
-    die("cfg_get_strg: unknown item %s",item);
-    return 0; /* not reached */
-}
diff -u --recursive --new-file v2.4.7/linux/arch/s390x/tools/silo/cfg.h linux/arch/s390x/tools/silo/cfg.h
--- v2.4.7/linux/arch/s390x/tools/silo/cfg.h	Tue Feb 13 14:13:44 2001
+++ linux/arch/s390x/tools/silo/cfg.h	Wed Dec 31 16:00:00 1969
@@ -1,58 +0,0 @@
-/* cfg.h  -  Configuration file parser */
-
-/* Copyright 1992-1996 Werner Almesberger. See file COPYING for details. */
-
-
-#ifndef CFG_H
-#define CFG_H
-
-typedef enum { cft_strg, cft_flag, cft_link, cft_end } CFG_TYPE;
-
-typedef struct {
-    CFG_TYPE type;
-    char *name;
-    void *action;
-    void *data;
-    void *context;
-} CONFIG;
-
-extern int cfg_open(char *name);
-
-/* Opens the configuration file. Returns the file descriptor of the open
-   file. */
-
-extern void cfg_error(char *msg,...);
-
-/* Signals an error while parsing the configuration file and terminates the
-   program. */
-
-extern void cfg_init(CONFIG *table);
-
-/* Initializes the specified table. */
-
-extern void cfg_set(CONFIG *table,char *item,char *value,void *context);
-
-/* Sets the specified variable in table. If the variable has already been set
-   since the last call to cfg_init, a warning message is issued if the context
-   keys don't match or a fatal error is reported if they do. */
-
-extern void cfg_unset(CONFIG *table,char *item);
-
-/* Unsets the specified variable in table. It is a fatal error if the variable
-   was not set. */
-
-extern int cfg_parse(CONFIG *table);
-
-/* Parses the configuration file for variables contained in table. A non-zero
-   value is returned if a variable not found in table has been met. Zero is
-   returned if EOF has been reached. */
-
-extern int cfg_get_flag(CONFIG *table,char *item);
-
-/* Returns one if the specified variable is set, zero if it isn't. */
-
-extern char *cfg_get_strg(CONFIG *table,char *item);
-
-/* Returns the value of the specified variable if it is set, NULL otherwise. */
-
-#endif
diff -u --recursive --new-file v2.4.7/linux/arch/s390x/tools/silo/silo.c linux/arch/s390x/tools/silo/silo.c
--- v2.4.7/linux/arch/s390x/tools/silo/silo.c	Wed Apr 11 19:02:29 2001
+++ linux/arch/s390x/tools/silo/silo.c	Wed Dec 31 16:00:00 1969
@@ -1,586 +0,0 @@
-/*
- *  arch/s390/boot/silo.c
- *
- *  S390 version
- *    Copyright (C) 1999,2000 IBM Deutschland Entwicklung GmbH, IBM Corporation
- *
- *    Report bugs to: <linux390@de.ibm.com>
- *
- *    Author(s): Holger Smolinski <Holger.Smolinski@de.ibm.com>
- *               Fritz Elfert <felfert@to.com> contributed support for
- *                	/etc/silo.conf based on Intel's lilo
- *    Changes  :
- *               01/15/01 Holger Smolinski <Holger.Smolinski@de.ibm.com>
- *                 adapted to deal with devices and bootsects of various sizes
- */
-
-#include <stddef.h>
-#include <stdlib.h>
-#include <stdio.h>
-#include <string.h>
-#include <unistd.h>
-#include <fcntl.h>
-#include <errno.h>
-#include <limits.h>
-#include <dirent.h>
-#include <linux/fs.h>
-#include <sys/types.h>
-#include <sys/stat.h>
-#include <sys/ioctl.h>
-#include <asm/ioctl.h>
-
-#include "cfg.h"
-
-CONFIG cf_options[] = {
-  { cft_strg, "append",		NULL,		NULL,NULL },
-  { cft_strg, "image",		NULL,		NULL,NULL },
-  { cft_strg, "ipldevice",	NULL,		NULL,NULL },
-  { cft_strg, "bootsect",	NULL,		NULL,NULL },
-  { cft_strg, "map",		NULL,		NULL,NULL },
-  { cft_strg, "parmfile",	NULL,		NULL,NULL },
-  { cft_strg, "ramdisk",	NULL,		NULL,NULL },
-  { cft_strg, "root",		NULL,		NULL,NULL },
-  { cft_flag, "readonly",	NULL,		NULL,NULL },
-  { cft_strg, "verbose",	NULL,		NULL,NULL },
-  { cft_strg, "testlevel",	NULL,		NULL,NULL },
-  { cft_end,  NULL,		NULL,		NULL,NULL }
-};
-  
-/* from dasd.h */
-#define DASD_PARTN_BITS 2
-#define BIODASDRWTB _IOWR('D',0,int)
-/* end */
-
-#define SILO_CFG "/etc/silo.conf"
-#define SILO_IMAGE "./image"
-#define SILO_BOOTMAP "./boot.map"
-#define SILO_PARMFILE "./parmfile"
-#define SILO_BOOTSECT "/boot/ipleckd.boot"
-
-#define PRINT_LEVEL(x,y...) if ( silo_options.verbosity >= x ) printf(y)
-#define ERROR_LEVEL(x,y...) if ( silo_options.verbosity >= x ) fprintf(stderr,y)
-#define TOGGLE(x) ((x)=((x)?(0):(1)))
-#define GETARG(x) {int len=strlen(optarg);x=malloc(len);strncpy(x,optarg,len);PRINT_LEVEL(1,"%s set to %s\n",#x,optarg);}
-
-#define ITRY(x) if ( (x) == -1 ) { ERROR_LEVEL(0,"%s (line:%d) '%s' returned %d='%s'\n", __FILE__,__LINE__,#x,errno,strerror(errno)); usage(); exit(1); }
-#define NTRY(x) if ( (x) == 0 ) { ERROR_LEVEL(0,"%s (line:%d) '%s' returned %d='%s'\n", __FILE__,__LINE__,#x,errno,strerror(errno)); usage(); exit(1); }
-
-#define MAX_CLUSTERS 256
-#define PARTN_MASK ((1 << DASD_PARTN_BITS) - 1)
-
-#define SILO_VERSION "1.1"
-
-struct silo_options
-  {
-    short int verbosity;
-    short int testlevel;
-    char *image;
-    char *ipldevice;
-    char *parmfile;
-    char *ramdisk;
-    char *bootsect;
-    char *conffile;
-    char *bootmap;
-  }
-silo_options =
-{
-  1,				/* verbosity */
-  2,				/* testlevel */
-    SILO_IMAGE,			/* image */
-    NULL,			/* ipldevice */
-    SILO_PARMFILE,		/* parmfile */
-    NULL,			/* initrd */
-    SILO_BOOTSECT,		/* bootsector */
-    SILO_CFG,                   /* silo.conf file */
-    SILO_BOOTMAP,               /* boot.map */
-};
-
-struct blockdesc
-  {
-    unsigned long off;
-    unsigned short ct;
-    unsigned long addr;
-  };
-
-struct blocklist
-  {
-    struct blockdesc blk[MAX_CLUSTERS];
-    unsigned short ix;
-  };
-
-void
-usage (void)
-{
-  printf ("Usage:\n");
-  printf ("silo -d ipldevice [additional options]\n");
-  printf ("-d /dev/node : set ipldevice to /dev/node\n");
-  printf ("-f image : set image to image\n");
-  printf ("-F conffile : specify configuration file (/etc/silo.conf)\n");
-  printf ("-p parmfile : set parameter file to parmfile\n");
-  printf ("-b bootsect : set bootsector to bootsect\n");
-  printf ("Additional options\n");
-  printf ("-B bootmap:\n");
-  printf ("-v: increase verbosity level\n");
-  printf ("-v#: set verbosity level to #\n");
-  printf ("-t: decrease testing level\n");
-  printf ("-h: print this message\n");
-  printf ("-?: print this message\n");
-  printf ("-V: print version\n");
-}
-
-int
-read_cfg(struct silo_options *o)
-{
-	char *tmp;
-	if (access(o->conffile, R_OK) && (errno == ENOENT))
-		return 0;
-	/* If errno != ENOENT, let cfg_open report an error */
-	cfg_open(o->conffile);
-	cfg_parse(cf_options);
-	tmp = cfg_get_strg(cf_options, "ipldevice");
-	if ( ! o->ipldevice  && tmp ) 
-		o->ipldevice = tmp;
-	tmp = cfg_get_strg(cf_options, "image");
-	if ( ! strncmp(o-> image,SILO_IMAGE,strlen(SILO_IMAGE)) && tmp ) 
-		o->image = tmp;
-	tmp = cfg_get_strg(cf_options, "parmfile");
-	if ( !strncmp(o->parmfile,SILO_PARMFILE,strlen(SILO_PARMFILE)) && tmp) 
-		o->parmfile = tmp;
-	if ( ! o -> ramdisk ) 
-		o->ramdisk = cfg_get_strg(cf_options, "ramdisk");
-	tmp = cfg_get_strg(cf_options, "bootsect");
-	if ( !strncmp(o -> bootsect,SILO_BOOTSECT,strlen(SILO_BOOTSECT))&&tmp)
-		o->bootsect = tmp;
-	tmp = cfg_get_strg(cf_options, "map") ;
-	if ( !strncmp(o -> bootmap,SILO_BOOTMAP,strlen(SILO_BOOTMAP)) && tmp) 
-		o->bootmap = tmp; 
-	tmp = cfg_get_strg(cf_options, "verbose");
-	if ( tmp ) {
-		unsigned short v;
-		sscanf (tmp, "%hu", &v);
-		o->verbosity = v;
-	}
-	tmp = cfg_get_strg(cf_options, "testlevel");
-	if ( tmp ) {
-		unsigned short t;
-		sscanf (tmp, "%hu", &t);
-		o->testlevel += t;
-	}
-	return 1;
-}
-
-char *
-gen_tmpparm( char *pfile )
-{
-	char *append = cfg_get_strg(cf_options, "append");
-	char *root = cfg_get_strg(cf_options, "root");
-	int ro = cfg_get_flag(cf_options, "readonly");
-	FILE *f,*of;
-	char *fn;
-	char c;
-	char *tmpdir=NULL,*save=NULL;
-
-	if (!append && !root && !ro)
-		return pfile;
-	of = fopen(pfile, "r");
-	if ( of ) {
-		NTRY( fn = tempnam(NULL,"parm."));
-	} else {
-		fn = pfile;
-	}
-	NTRY( f = fopen(fn, "a+"));
-	if ( of ) {
-		while ( ! feof (of) ) {
-		  c=fgetc(of);
-	  	fputc(c,f);
-		}
-	}
-	if (root)
-		fprintf(f, " root=%s", root);
-	if (ro)
-		fprintf(f, " ro");
-	if (append)
-		fprintf(f, " %s", append);
-	fprintf(f, "\n");
-	fclose(f);
-	fclose(of);
-	printf ("tempfile is %s\n",fn);
-	return strdup(fn);
-}
-
-int
-parse_options (struct silo_options *o, int argc, char *argv[])
-{
-  int rc = 0;
-  int oc;
-
-  while ((oc = getopt (argc, argv, "Vf:F:d:p:r:b:B:h?v::t::")) != -1)
-    {
-      switch (oc)
-	{
-	case 'V':
-	  printf("silo version: %s\n",SILO_VERSION);
-	  exit(0);
-	case 'v':
-	  {
-	    unsigned short v;
-	    if (optarg && sscanf (optarg, "%hu", &v))
-	      o->verbosity = v;
-	    else
-	      o->verbosity++;
-	    PRINT_LEVEL (1, "Verbosity value is now %hu\n", o->verbosity);
-	    break;
-	  }
-	case 't':
-	  {
-	    unsigned short t;
-	    if (optarg && sscanf (optarg, "%hu", &t))
-	      o->testlevel -= t;
-	    else
-	      o->testlevel--;
-            PRINT_LEVEL (1, "Testonly flag is now %d\n", o->testlevel);
-	    break;
-	  }
-	case 'h':
-	case '?':
-	  usage ();
-	  exit(0);
-	case 'd':
-	  GETARG (o->ipldevice);
-	  break;
-	case 'f':
-	  GETARG (o->image);
-	  break;
-        case 'F':                         
- 	   GETARG (o->conffile);              
- 	   break;                          
-	case 'p':
-	  GETARG (o->parmfile);
-	  break;
-	case 'r':
-	  GETARG (o->ramdisk);
-	  break;
-	case 'b':
-	  GETARG (o->bootsect);
-	  break;
-	case 'B':
-	  GETARG (o->bootmap);
-	default:
-	  rc = EINVAL;
-	  break;
-	}
-    }
-  read_cfg(o);
-  return rc;
-}
-
-int
-verify_device (char *name)
-{
-  int rc = 0;
-  struct stat dst;
-  struct stat st;
-  ITRY (stat (name, &dst));
-  if (S_ISBLK (dst.st_mode))
-    {
-      if (!(MINOR (dst.st_rdev) & PARTN_MASK))
-	{
-	  rc = dst.st_rdev;
-	}
-      else
-	/* invalid MINOR & PARTN_MASK */
-	{
-	  ERROR_LEVEL (1, "Cannot boot from partition %d %d %d",
-		       (int) PARTN_MASK, (int) MINOR (dst.st_rdev), (int) (PARTN_MASK & MINOR (dst.st_rdev)));
-	  rc = -1;
-	  errno = EINVAL;
-	}
-    }
-  else
-    /* error S_ISBLK */
-    {
-      ERROR_LEVEL (1, "%s is no block device\n", name);
-      rc = -1;
-      errno = EINVAL;
-    }
-  return rc;
-}
-
-int
-verify_file (char *name, int dev)
-{
-  int rc = 0;
-  struct stat dst;
-  struct stat st;
-  int bs = 1024;
-  int l;
-
-  ITRY(stat ( name, &dst ));
-  if (S_ISREG (dst.st_mode))
-    {
-      if ((unsigned) MAJOR (dev) == (unsigned) MAJOR (dst.st_dev) && (unsigned) MINOR (dev) == (unsigned) (MINOR (dst.st_dev) & ~PARTN_MASK))
-	{
-	  /* whatever to do if all is ok... */
-	}
-      else
-	/* devicenumber doesn't match */
-	{
-	  ERROR_LEVEL (1, "%s is not on device (%d/%d) but on (%d/%d)\n", name, (unsigned) MAJOR (dev), (unsigned) MINOR (dev), (unsigned) MAJOR (dst.st_dev), (unsigned) (MINOR (dst.st_dev) & ~PARTN_MASK));
-	  rc = -1;
-	  errno = EINVAL;
-	}
-    }
-  else
-    /* error S_ISREG */
-    {
-      ERROR_LEVEL (1, "%s is neither regular file nor linkto one\n", name);
-      rc = -1;
-      errno = EINVAL;
-    }
-  return rc;
-}
-
-int
-verify_options (struct silo_options *o)
-{
-  int rc = 0;
-  int dev = 0;
-  int crc = 0;
-  if (!o->ipldevice || !o->image || !o->bootsect)
-    {
-     if (!o->ipldevice)
-       fprintf(stderr,"ipldevice\n");
-     if (!o->image)
-       fprintf(stderr,"image\n");
-     if (!o->bootsect)
-       fprintf(stderr,"bootsect\n");
-
-      usage ();
-      exit (1);
-    }
-  PRINT_LEVEL (1, "Testlevel is set to %d\n",o->testlevel);
-
-  PRINT_LEVEL (1, "IPL device is: '%s'", o->ipldevice);
-  ITRY (dev = verify_device (o->ipldevice));
-  PRINT_LEVEL (2, "...ok...(%d/%d)", (unsigned short) MAJOR (dev), (unsigned short) MINOR (dev));
-  PRINT_LEVEL (1, "\n");
-
-  PRINT_LEVEL (0, "bootsector is: '%s'", o->bootsect);
-  ITRY (verify_file (o->bootsect, dev));
-  PRINT_LEVEL (1, "...ok...");
-  PRINT_LEVEL (0, "\n");
-
-  if ( o -> testlevel > 0  && 
-       ! strncmp( o->bootmap, SILO_BOOTMAP,strlen(SILO_BOOTMAP) )) {
-     NTRY( o -> bootmap = tempnam(NULL,"boot."));
-  }
-  PRINT_LEVEL (0, "bootmap is set to: '%s'", o->bootmap);
-  if ( access ( o->bootmap, O_RDWR ) == -1 ) {
-    if ( errno == ENOENT ) {
-      ITRY (creat ( o-> bootmap, O_RDWR ));
-    } else {
-      PRINT_LEVEL(1,"Cannot access bootmap file '%s': %s\n",o->bootmap,
-		  strerror(errno));
-    }
-  }
-  ITRY (verify_file (o->bootmap, dev));
-  PRINT_LEVEL (1, "...ok...");
-  PRINT_LEVEL (0, "\n");
-
-  PRINT_LEVEL (0, "Kernel image is: '%s'", o->image);
-  ITRY (verify_file (o->image, dev));
-  PRINT_LEVEL (1, "...ok...");
-  PRINT_LEVEL (0, "\n");
-
-  PRINT_LEVEL (0, "original parameterfile is: '%s'", o->parmfile);
-  ITRY (verify_file (o->parmfile, dev));
-  PRINT_LEVEL (1, "...ok...");
-  o->parmfile = gen_tmpparm(o->parmfile);
-  PRINT_LEVEL (0, "final parameterfile is: '%s'", o->parmfile);
-  ITRY (verify_file (o->parmfile, dev));
-  PRINT_LEVEL (1, "...ok...");
-  PRINT_LEVEL (0, "\n");
-
-  if (o->ramdisk)
-    {
-      PRINT_LEVEL (0, "initialramdisk is: '%s'", o->ramdisk);
-      ITRY (verify_file (o->ramdisk, dev));
-      PRINT_LEVEL (1, "...ok...");
-      PRINT_LEVEL (0, "\n");
-    }
-
-  return crc;
-}
-
-
-int
-add_file_to_blocklist (char *name, struct blocklist *lst, long addr)
-{
-  int fd;
-  int devfd;
-  struct stat fst;
-  int i;
-  int blk;
-  int bs;
-  int blocks;
-
-  int rc = 0;
-
-  ITRY (fd = open (name, O_RDONLY));
-  ITRY (fstat (fd, &fst));
-  ITRY (mknod ("/tmp/silodev", S_IFBLK | S_IRUSR | S_IWUSR, fst.st_dev));
-  ITRY (devfd = open ("/tmp/silodev", O_RDONLY));
-  ITRY (ioctl (fd, FIGETBSZ, &bs));
-  blocks = (fst.st_size + bs - 1) / bs;
-  for (i = 0; i < blocks; i++)
-    {
-      blk = i;
-      ITRY (ioctl (fd, FIBMAP, &blk));
-      if (blk)
-	{
-	  int oldblk = blk;
-	  ITRY (ioctl (devfd, BIODASDRWTB, &blk));
-	  if (blk <= 0)
-	    {
-	      ERROR_LEVEL (0, "BIODASDRWTB on blk %d returned %d\n", oldblk, blk);
-	      break;
-	    }
-	}
-      else
-	{
-	  PRINT_LEVEL (1, "Filled hole on blk %d\n", i);
-	}
-      if (lst->ix == 0 || i == 0  || 
-	  lst->blk[lst->ix - 1].ct >= 128 ||
-	  (lst->blk[lst->ix - 1].off + lst->blk[lst->ix - 1].ct != blk &&
-	   !(lst->blk[lst->ix - 1].off == 0 && blk == 0)))
-	{
-	  if (lst->ix >= MAX_CLUSTERS)
-	    {
-	      rc = 1;
-	      errno = ENOMEM;
-	      break;
-	    }
-	  lst->blk[lst->ix].off = blk;
-	  lst->blk[lst->ix].ct = 1;
-	  lst->blk[lst->ix].addr = addr + i * bs;
-	  lst->ix++;
-	}
-      else
-	{
-	  lst->blk[lst->ix - 1].ct++;
-	}
-    }
-  ITRY(unlink("/tmp/silodev"));
-  return rc;
-}
-
-int
-write_bootsect (struct silo_options *o, struct blocklist *blklst)
-{
-  int i;
-  int s_fd, d_fd, b_fd, bd_fd;
-  struct stat s_st, d_st, b_st;
-  int rc=0;
-  int bs, boots;
-  char *tmpdev;
-  char buffer[4096]={0,};
-  int blocksize, sectsize;
-  ITRY (d_fd = open (o->ipldevice, O_RDWR | O_SYNC));
-  ITRY (fstat (d_fd, &d_st));
-  ITRY (s_fd = open (o->bootmap, O_RDWR | O_TRUNC | O_CREAT | O_SYNC));
-  ITRY (verify_file (o->bootsect, d_st.st_rdev));
-  for (i = 0; i < blklst->ix; i++)
-    {
-      int offset = blklst->blk[i].off;
-      int addrct = blklst->blk[i].addr | (blklst->blk[i].ct & 0xff);
-      PRINT_LEVEL (1, "ix %i: offset: %06x count: %02x address: 0x%08x\n", i, offset, blklst->blk[i].ct & 0xff, blklst->blk[i].addr);
-	if ( o->testlevel <= 1 ) {
-	      NTRY (write (s_fd, &offset, sizeof (int)));
-	      NTRY (write (s_fd, &addrct, sizeof (int)));
-	}
-    }
-  ITRY (ioctl (s_fd,FIGETBSZ, &bs));
-  ITRY (stat (o->bootmap, &s_st));
-  if (s_st.st_size > bs )
-    {
-      ERROR_LEVEL (0,"%s is larger than one block\n", o->bootmap);
-      rc = -1;
-      errno = EINVAL;
-    }
-  boots=0;
-  NTRY ( tmpdev = tmpnam(NULL) );
-  ITRY (mknod (tmpdev, S_IFBLK | S_IRUSR | S_IWUSR, s_st.st_dev));
-  ITRY (bd_fd = open (tmpdev, O_RDONLY));
-  ITRY (ioctl(bd_fd,BLKSSZGET,&blocksize));
-  ITRY (ioctl(s_fd,FIBMAP,&boots));
-  ITRY (ioctl (bd_fd, BIODASDRWTB, &boots));
-  PRINT_LEVEL (1, "Bootmap is in block no: 0x%08x\n", boots);
-  close (bd_fd);
-  close(s_fd);
-  ITRY (unlink(tmpdev));
-  /* Now patch the bootsector */
-  ITRY (stat (o->bootsect, &b_st));
-  if ((sectsize = b_st.st_size) > blocksize )
-    {
-      ERROR_LEVEL (0,"Bootsector is larger than sectorsize of volume %d vs %d\n", sectsize, blocksize);
-      rc = -1;
-      errno = EINVAL;
-    }
-  ITRY (b_fd = open (o->bootsect, O_RDONLY));
-  ITRY (read (b_fd, buffer, sectsize));
-  memset (buffer + 0xe0, 0, 8);
-  *(int *) (buffer + 0xe0) = boots;
-  if ( o -> testlevel <= 0 ) {
-    ITRY (write (d_fd, buffer, sectsize));
-    ITRY (lseek (d_fd, blocksize, SEEK_SET));
-    ITRY (write (d_fd, buffer, sectsize));
-  }
-  close (b_fd);
-  close (d_fd);
-  return rc;
-}
-
-int
-do_silo (struct silo_options *o)
-{
-  int rc = 0;
-
-  int device_fd;
-  int image_fd;
-  struct blocklist blklist;
-  memset (&blklist, 0, sizeof (struct blocklist));
-  ITRY (add_file_to_blocklist (o->image, &blklist, 0x00000000));
-  if (o->parmfile)
-    {
-      ITRY (add_file_to_blocklist (o->parmfile, &blklist, 0x00008000));
-    }
-  if (o->ramdisk)
-    {
-      ITRY (add_file_to_blocklist (o->ramdisk, &blklist, 0x00800000));
-    }
-  ITRY (write_bootsect (o, &blklist));
-  return rc;
-}
-
-int
-main (int argct, char *argv[])
-{
-  int rc = 0;
-  char *save=NULL;
-  char *tmpdir=getenv("TMPDIR");
-  if (tmpdir) {
-    NTRY( save=(char*)malloc(strlen(tmpdir)));
-    NTRY( strncpy(save,tmpdir,strlen(tmpdir)));
-  }
-  ITRY( setenv("TMPDIR",".",1));
-  ITRY (parse_options (&silo_options, argct, argv));
-  ITRY (verify_options (&silo_options));
-  if ( silo_options.testlevel > 0 ) {
-    printf ("WARNING: silo does not modify your volume. Use -t2 to change IPL records\n");
-  }
-  ITRY (do_silo (&silo_options));
-  if ( save )
-    ITRY( setenv("TMPDIR",save,1)); 
-  return rc;
-}
diff -u --recursive --new-file v2.4.7/linux/arch/s390x/tools/silo/silo.conf linux/arch/s390x/tools/silo/silo.conf
--- v2.4.7/linux/arch/s390x/tools/silo/silo.conf	Tue Feb 13 14:13:44 2001
+++ linux/arch/s390x/tools/silo/silo.conf	Wed Dec 31 16:00:00 1969
@@ -1,7 +0,0 @@
-ipldevice = /dev/dasda 
-image = /boot/image
-bootsect = /boot/ipleckd.boot
-map = /boot/boot.map
-root = /dev/dasd01
-readonly
-append = "dasd=200-20f noinitrd"
diff -u --recursive --new-file v2.4.7/linux/arch/sparc/Makefile linux/arch/sparc/Makefile
--- v2.4.7/linux/arch/sparc/Makefile	Fri Dec 29 14:07:20 2000
+++ linux/arch/sparc/Makefile	Sat Jul 28 12:12:37 2001
@@ -1,4 +1,4 @@
-# $Id: Makefile,v 1.48 2000/12/15 00:41:24 davem Exp $
+# $Id: Makefile,v 1.49 2001/07/27 09:42:22 davem Exp $
 # sparc/Makefile
 #
 # Makefile for the architecture dependent flags and dependencies on the
@@ -60,7 +60,7 @@
 
 archdep: check_asm
 
-check_asm:
+check_asm: include/linux/version.h
 	$(MAKE) -C arch/sparc/kernel check_asm
 
 tftpboot.img:
diff -u --recursive --new-file v2.4.7/linux/arch/sparc/kernel/ptrace.c linux/arch/sparc/kernel/ptrace.c
--- v2.4.7/linux/arch/sparc/kernel/ptrace.c	Wed Jul 25 17:10:19 2001
+++ linux/arch/sparc/kernel/ptrace.c	Sat Jul 28 12:12:38 2001
@@ -318,8 +318,6 @@
 
 	if ((current->personality == PER_SUNOS && request == PTRACE_SUNATTACH)
 	    || (current->personality != PER_SUNOS && request == PTRACE_ATTACH)) {
-		unsigned long flags;
-
 		if (ptrace_attach(child)) {
 			pt_error_return(regs, EPERM);
 			goto out_tsk;
diff -u --recursive --new-file v2.4.7/linux/arch/sparc/mm/fault.c linux/arch/sparc/mm/fault.c
--- v2.4.7/linux/arch/sparc/mm/fault.c	Sun Mar 25 18:14:21 2001
+++ linux/arch/sparc/mm/fault.c	Sat Jul 28 12:12:38 2001
@@ -1,4 +1,4 @@
-/* $Id: fault.c,v 1.119 2001/03/24 09:36:10 davem Exp $
+/* $Id: fault.c,v 1.120 2001/07/18 13:40:05 anton Exp $
  * fault.c:  Page fault handlers for the Sparc.
  *
  * Copyright (C) 1995 David S. Miller (davem@caip.rutgers.edu)
@@ -36,8 +36,6 @@
 
 extern struct sparc_phys_banks sp_banks[SPARC_PHYS_BANKS];
 extern int prom_node_root;
-
-struct linux_romvec *romvec;
 
 /* At boot time we determine these two values necessary for setting
  * up the segment maps and page table entries (pte's).
diff -u --recursive --new-file v2.4.7/linux/arch/sparc64/Makefile linux/arch/sparc64/Makefile
--- v2.4.7/linux/arch/sparc64/Makefile	Fri Dec 29 14:07:21 2000
+++ linux/arch/sparc64/Makefile	Sat Jul 28 12:12:38 2001
@@ -1,4 +1,4 @@
-# $Id: Makefile,v 1.46 2000/12/14 22:57:26 davem Exp $
+# $Id: Makefile,v 1.47 2001/07/27 09:42:22 davem Exp $
 # sparc64/Makefile
 #
 # Makefile for the architecture dependent flags and dependencies on the
@@ -98,7 +98,7 @@
 
 archdep: check_asm
 
-check_asm:
+check_asm: include/linux/version.h
 	$(MAKE) -C arch/sparc64/kernel check_asm
 
 tftpboot.img:
diff -u --recursive --new-file v2.4.7/linux/arch/sparc64/kernel/ioctl32.c linux/arch/sparc64/kernel/ioctl32.c
--- v2.4.7/linux/arch/sparc64/kernel/ioctl32.c	Tue Jul  3 17:08:19 2001
+++ linux/arch/sparc64/kernel/ioctl32.c	Sat Jul 28 12:12:38 2001
@@ -1,4 +1,4 @@
-/* $Id: ioctl32.c,v 1.117 2001/06/02 21:39:55 davem Exp $
+/* $Id: ioctl32.c,v 1.119 2001/07/21 00:28:25 davem Exp $
  * ioctl32.c: Conversion between 32bit and 64bit native ioctls.
  *
  * Copyright (C) 1997-2000  Jakub Jelinek  (jakub@redhat.com)
@@ -89,10 +89,14 @@
 #include <linux/atm_tcp.h>
 #include <linux/sonet.h>
 #include <linux/atm_suni.h>
+#include <linux/mtd/mtd.h>
 
 #include <net/bluetooth/bluetooth.h>
 #include <net/bluetooth/hci.h>
 
+#include <linux/usb.h>
+#include <linux/usbdevice_fs.h>
+
 /* Use this to get at 32-bit user passed pointers. 
    See sys_sparc32.c for description about these. */
 #define A(__x) ((unsigned long)(__x))
@@ -3081,6 +3085,453 @@
 	return rw_long(fd, AUTOFS_IOC_SETTIMEOUT, arg);
 }
 
+struct usbdevfs_ctrltransfer32 {
+	__u8 requesttype;
+	__u8 request;
+	__u16 value;
+	__u16 index;
+	__u16 length;
+	__u32 timeout;  /* in milliseconds */
+	__u32 data;
+};
+
+#define USBDEVFS_CONTROL32           _IOWR('U', 0, struct usbdevfs_ctrltransfer32)
+
+static int do_usbdevfs_control(unsigned int fd, unsigned int cmd, unsigned long arg)
+{
+	struct usbdevfs_ctrltransfer kctrl;
+	struct usbdevfs_ctrltransfer32 *uctrl;
+	mm_segment_t old_fs;
+	__u32 udata;
+	void *uptr, *kptr;
+	int err;
+
+	uctrl = (struct usbdevfs_ctrltransfer32 *) arg;
+
+	if (copy_from_user(&kctrl, uctrl,
+			   (sizeof(struct usbdevfs_ctrltransfer) -
+			    sizeof(void *))))
+		return -EFAULT;
+
+	if (get_user(udata, &uctrl->data))
+		return -EFAULT;
+	uptr = (void *) A(udata);
+
+	/* In usbdevice_fs, it limits the control buffer to a page,
+	 * for simplicity so do we.
+	 */
+	if (!uptr || kctrl.length > PAGE_SIZE)
+		return -EINVAL;
+
+	kptr = (void *)__get_free_page(GFP_KERNEL);
+
+	if ((kctrl.requesttype & 0x80) == 0) {
+		err = -EFAULT;
+		if (copy_from_user(kptr, uptr, kctrl.length))
+			goto out;
+	}
+
+	kctrl.data = kptr;
+
+	old_fs = get_fs();
+	set_fs(KERNEL_DS);
+	err = sys_ioctl(fd, USBDEVFS_CONTROL, (unsigned long)&kctrl);
+	set_fs(old_fs);
+
+	if (err >= 0 &&
+	    ((kctrl.requesttype & 0x80) != 0)) {
+		if (copy_to_user(uptr, kptr, kctrl.length))
+			err = -EFAULT;
+	}
+
+out:
+	free_page((unsigned long) kptr);
+	return err;
+}
+
+struct usbdevfs_bulktransfer32 {
+	unsigned int ep;
+	unsigned int len;
+	unsigned int timeout; /* in milliseconds */
+	__u32 data;
+};
+
+#define USBDEVFS_BULK32              _IOWR('U', 2, struct usbdevfs_bulktransfer32)
+
+static int do_usbdevfs_bulk(unsigned int fd, unsigned int cmd, unsigned long arg)
+{
+	struct usbdevfs_bulktransfer kbulk;
+	struct usbdevfs_bulktransfer32 *ubulk;
+	mm_segment_t old_fs;
+	__u32 udata;
+	void *uptr, *kptr;
+	int err;
+
+	ubulk = (struct usbdevfs_bulktransfer32 *) arg;
+
+	if (get_user(kbulk.ep, &ubulk->ep) ||
+	    get_user(kbulk.len, &ubulk->len) ||
+	    get_user(kbulk.timeout, &ubulk->timeout) ||
+	    get_user(udata, &ubulk->data))
+		return -EFAULT;
+
+	uptr = (void *) A(udata);
+
+	/* In usbdevice_fs, it limits the control buffer to a page,
+	 * for simplicity so do we.
+	 */
+	if (!uptr || kbulk.len > PAGE_SIZE)
+		return -EINVAL;
+
+	kptr = (void *) __get_free_page(GFP_KERNEL);
+
+	if ((kbulk.ep & 0x80) == 0) {
+		err = -EFAULT;
+		if (copy_from_user(kptr, uptr, kbulk.len))
+			goto out;
+	}
+
+	kbulk.data = kptr;
+
+	old_fs = get_fs();
+	set_fs(KERNEL_DS);
+	err = sys_ioctl(fd, USBDEVFS_BULK, (unsigned long) &kbulk);
+	set_fs(old_fs);
+
+	if (err >= 0 &&
+	    ((kbulk.ep & 0x80) != 0)) {
+		if (copy_to_user(uptr, kptr, kbulk.len))
+			err = -EFAULT;
+	}
+
+out:
+	free_page((unsigned long) kptr);
+	return err;
+}
+
+/* This needs more work before we can enable it.  Unfortunately
+ * because of the fancy asynchronous way URB status/error is written
+ * back to userspace, we'll need to fiddle with USB devio internals
+ * and/or reimplement entirely the frontend of it ourselves. -DaveM
+ *
+ * The issue is:
+ *
+ *	When an URB is submitted via usbdevicefs it is put onto an
+ *	asynchronous queue.  When the URB completes, it may be reaped
+ *	via another ioctl.  During this reaping the status is written
+ *	back to userspace along with the length of the transfer.
+ *
+ *	We must translate into 64-bit kernel types so we pass in a kernel
+ *	space copy of the usbdevfs_urb structure.  This would mean that we
+ *	must do something to deal with the async entry reaping.  First we
+ *	have to deal somehow with this transitory memory we've allocated.
+ *	This is problematic since there are many call sites from which the
+ *	async entries can be destroyed (and thus when we'd need to free up
+ *	this kernel memory).  One of which is the close() op of usbdevicefs.
+ *	To handle that we'd need to make our own file_operations struct which
+ *	overrides usbdevicefs's release op with our own which runs usbdevicefs's
+ *	real release op then frees up the kernel memory.
+ *
+ *	But how to keep track of these kernel buffers?  We'd need to either
+ *	keep track of them in some table _or_ know about usbdevicefs internals
+ *	(ie. the exact layout of it's file private, which is actually defined
+ *	in linux/usbdevice_fs.h, the layout of the async queues are private to
+ *	devio.c)
+ *
+ * There is one possible other solution I considered, also involving knowledge
+ * of usbdevicefs internals:
+ *
+ *	After an URB is submitted, we "fix up" the address back to the user
+ *	space one.  This would work if the status/length fields written back
+ *	by the async URB completion lines up perfectly in the 32-bit type with
+ *	the 64-bit kernel type.  Unfortunately, it does not because the iso
+ *	frame descriptors, at the end of the struct, can be written back.
+ *
+ * I think we'll just need to simply duplicate the devio URB engine here.
+ */
+#if 0
+struct usbdevfs_urb32 {
+	__u8 type;
+	__u8 endpoint;
+	__s32 status;
+	__u32 flags;
+	__u32 buffer;
+	__s32 buffer_length;
+	__s32 actual_length;
+	__s32 start_frame;
+	__s32 number_of_packets;
+	__s32 error_count;
+	__u32 signr;
+	__u32 usercontext; /* unused */
+	struct usbdevfs_iso_packet_desc iso_frame_desc[0];
+};
+
+#define USBDEVFS_SUBMITURB32       _IOR('U', 10, struct usbdevfs_urb32)
+
+static int get_urb32(struct usbdevfs_urb *kurb,
+		     struct usbdevfs_urb32 *uurb)
+{
+	if (get_user(kurb->type, &uurb->type) ||
+	    __get_user(kurb->endpoint, &uurb->endpoint) ||
+	    __get_user(kurb->status, &uurb->status) ||
+	    __get_user(kurb->flags, &uurb->flags) ||
+	    __get_user(kurb->buffer_length, &uurb->buffer_length) ||
+	    __get_user(kurb->actual_length, &uurb->actual_length) ||
+	    __get_user(kurb->start_frame, &uurb->start_frame) ||
+	    __get_user(kurb->number_of_packets, &uurb->number_of_packets) ||
+	    __get_user(kurb->error_count, &uurb->error_count) ||
+	    __get_user(kurb->signr, &uurb->signr))
+		return -EFAULT;
+
+	kurb->usercontext = 0; /* unused currently */
+
+	return 0;
+}
+
+/* Just put back the values which usbdevfs actually changes. */
+static int put_urb32(struct usbdevfs_urb *kurb,
+		     struct usbdevfs_urb32 *uurb)
+{
+	if (put_user(kurb->status, &uurb->status) ||
+	    __put_user(kurb->actual_length, &uurb->actual_length) ||
+	    __put_user(kurb->error_count, &uurb->error_count))
+		return -EFAULT;
+
+	if (kurb->number_of_packets != 0) {
+		int i;
+
+		for (i = 0; i < kurb->number_of_packets; i++) {
+			if (__put_user(kurb->iso_frame_desc[i].actual_length,
+				       &uurb->iso_frame_desc[i].actual_length) ||
+			    __put_user(kurb->iso_frame_desc[i].status,
+				       &uurb->iso_frame_desc[i].status))
+				return -EFAULT;
+		}
+	}
+
+	return 0;
+}
+
+static int get_urb32_isoframes(struct usbdevfs_urb *kurb,
+			       struct usbdevfs_urb32 *uurb)
+{
+	unsigned int totlen;
+	int i;
+
+	if (kurb->type != USBDEVFS_URB_TYPE_ISO) {
+		kurb->number_of_packets = 0;
+		return 0;
+	}
+
+	if (kurb->number_of_packets < 1 ||
+	    kurb->number_of_packets > 128)
+		return -EINVAL;
+
+	if (copy_from_user(&kurb->iso_frame_desc[0],
+			   &uurb->iso_frame_desc[0],
+			   sizeof(struct usbdevfs_iso_packet_desc) *
+			   kurb->number_of_packets))
+		return -EFAULT;
+
+	totlen = 0;
+	for (i = 0; i < kurb->number_of_packets; i++) {
+		unsigned int this_len;
+
+		this_len = kurb->iso_frame_desc[i].length;
+		if (this_len > 1023)
+			return -EINVAL;
+
+		totlen += this_len;
+	}
+
+	if (totlen > 32768)
+		return -EINVAL;
+
+	kurb->buffer_length = totlen;
+
+	return 0;
+}
+
+static int do_usbdevfs_urb(unsigned int fd, unsigned int cmd, unsigned long arg)
+{
+	struct usbdevfs_urb *kurb;
+	struct usbdevfs_urb32 *uurb;
+	mm_segment_t old_fs;
+	__u32 udata;
+	void *uptr, *kptr;
+	unsigned int buflen;
+	int err;
+
+	uurb = (struct usbdevfs_urb32 *) arg;
+
+	err = -ENOMEM;
+	kurb = kmalloc(sizeof(struct usbdevfs_urb) +
+		       (sizeof(struct usbdevfs_iso_packet_desc) * 128),
+		       GFP_KERNEL);
+	if (!kurb)
+		goto out;
+
+	err = -EFAULT;
+	if (get_urb32(kurb, uurb))
+		goto out;
+
+	err = get_urb32_isoframes(kurb, uurb);
+	if (err)
+		goto out;
+
+	err = -EFAULT;
+	if (__get_user(udata, &uurb->buffer))
+		goto out;
+	uptr = (void *) A(udata);
+
+	err = -ENOMEM;
+	buflen = kurb->buffer_length;
+	kptr = kmalloc(buflen, GFP_KERNEL);
+	if (!kptr)
+		goto out;
+
+	kurb->buffer = kptr;
+
+	err = -EFAULT;
+	if (copy_from_user(kptr, uptr, buflen))
+		goto out_kptr;
+
+	old_fs = get_fs();
+	set_fs(KERNEL_DS);
+	err = sys_ioctl(fd, USBDEVFS_SUBMITURB, (unsigned long) kurb);
+	set_fs(old_fs);
+
+	if (err >= 0) {
+		/* XXX Shit, this doesn't work for async URBs :-( XXX */
+		if (put_urb32(kurb, uurb)) {
+			err = -EFAULT;
+		} else if ((kurb->endpoint & USB_DIR_IN) != 0) {
+			if (copy_to_user(uptr, kptr, buflen))
+				err = -EFAULT;
+		}
+	}
+
+out_kptr:
+	kfree(kptr);
+
+out:
+	kfree(kurb);
+	return err;
+}
+#endif
+
+#define USBDEVFS_REAPURB32         _IOW('U', 12, u32)
+#define USBDEVFS_REAPURBNDELAY32   _IOW('U', 13, u32)
+
+static int do_usbdevfs_reapurb(unsigned int fd, unsigned int cmd, unsigned long arg)
+{
+	mm_segment_t old_fs;
+	void *kptr;
+	int err;
+
+	old_fs = get_fs();
+	set_fs(KERNEL_DS);
+	err = sys_ioctl(fd,
+			(cmd == USBDEVFS_REAPURB32 ?
+			 USBDEVFS_REAPURB :
+			 USBDEVFS_REAPURBNDELAY),
+			(unsigned long) &kptr);
+	set_fs(old_fs);
+
+	if (err >= 0 &&
+	    put_user(((u32)(long)kptr), (u32 *) A(arg)))
+		err = -EFAULT;
+
+	return err;
+}
+
+struct usbdevfs_disconnectsignal32 {
+	unsigned int signr;
+	u32 context;
+};
+
+#define USBDEVFS_DISCSIGNAL32      _IOR('U', 14, struct usbdevfs_disconnectsignal32)
+
+static int do_usbdevfs_discsignal(unsigned int fd, unsigned int cmd, unsigned long arg)
+{
+	struct usbdevfs_disconnectsignal kdis;
+	struct usbdevfs_disconnectsignal32 *udis;
+	mm_segment_t old_fs;
+	u32 uctx;
+	int err;
+
+	udis = (struct usbdevfs_disconnectsignal32 *) arg;
+
+	if (get_user(kdis.signr, &udis->signr) ||
+	    __get_user(uctx, &udis->context))
+		return -EFAULT;
+
+	kdis.context = (void *) (long)uctx;
+
+	old_fs = get_fs();
+	set_fs(KERNEL_DS);
+	err = sys_ioctl(fd, USBDEVFS_DISCSIGNAL, (unsigned long) &kdis);
+	set_fs(old_fs);
+
+	return err;
+}
+
+struct mtd_oob_buf32 {
+	u32 start;
+	u32 length;
+	u32 ptr;	/* unsigned char* */
+};
+
+#define MEMWRITEOOB32 	_IOWR('M',3,struct mtd_oob_buf32)
+#define MEMREADOOB32 	_IOWR('M',4,struct mtd_oob_buf32)
+
+static inline int 
+mtd_rw_oob(unsigned int fd, unsigned int cmd, unsigned long arg)
+{
+	mm_segment_t 			old_fs 	= get_fs();
+	struct mtd_oob_buf32	*uarg 	= (struct mtd_oob_buf32 *)arg;
+	struct mtd_oob_buf		karg;
+	u32 tmp;
+	char *ptr;
+	int ret;
+
+	if (get_user(karg.start, &uarg->start) 		||
+	    get_user(karg.length, &uarg->length)	||
+	    get_user(tmp, &uarg->ptr))
+		return -EFAULT;
+
+	ptr = (char *)A(tmp);
+	if (0 >= karg.length) 
+		return -EINVAL;
+
+	karg.ptr = kmalloc(karg.length, GFP_KERNEL);
+	if (NULL == karg.ptr)
+		return -ENOMEM;
+
+	if (copy_from_user(karg.ptr, ptr, karg.length)) {
+		kfree(karg.ptr);
+		return -EFAULT;
+	}
+
+	set_fs(KERNEL_DS);
+	if (MEMREADOOB32 == cmd) 
+		ret = sys_ioctl(fd, MEMREADOOB, (unsigned long)&karg);
+	else if (MEMWRITEOOB32 == cmd)
+		ret = sys_ioctl(fd, MEMWRITEOOB, (unsigned long)&karg);
+	else
+		ret = -EINVAL;
+	set_fs(old_fs);
+
+	if (0 == ret && cmd == MEMREADOOB32) {
+		ret = copy_to_user(ptr, karg.ptr, karg.length);
+		ret |= put_user(karg.start, &uarg->start);
+		ret |= put_user(karg.length, &uarg->length);
+	}
+
+	kfree(karg.ptr);
+	return ((0 == ret) ? 0 : -EFAULT);
+}	
+
 struct ioctl_trans {
 	unsigned int cmd;
 	unsigned int handler;
@@ -3744,7 +4195,28 @@
 COMPATIBLE_IOCTL(PCIIOC_MMAP_IS_IO)
 COMPATIBLE_IOCTL(PCIIOC_MMAP_IS_MEM)
 COMPATIBLE_IOCTL(PCIIOC_WRITE_COMBINE)
+/* USB */
+COMPATIBLE_IOCTL(USBDEVFS_RESETEP)
+COMPATIBLE_IOCTL(USBDEVFS_SETINTERFACE)
+COMPATIBLE_IOCTL(USBDEVFS_SETCONFIGURATION)
+COMPATIBLE_IOCTL(USBDEVFS_GETDRIVER)
+COMPATIBLE_IOCTL(USBDEVFS_DISCARDURB)
+COMPATIBLE_IOCTL(USBDEVFS_CLAIMINTERFACE)
+COMPATIBLE_IOCTL(USBDEVFS_RELEASEINTERFACE)
+COMPATIBLE_IOCTL(USBDEVFS_CONNECTINFO)
+COMPATIBLE_IOCTL(USBDEVFS_HUB_PORTINFO)
+COMPATIBLE_IOCTL(USBDEVFS_RESET)
+COMPATIBLE_IOCTL(USBDEVFS_CLEAR_HALT)
+/* MTD */
+COMPATIBLE_IOCTL(MEMGETINFO)
+COMPATIBLE_IOCTL(MEMERASE)
+COMPATIBLE_IOCTL(MEMLOCK)
+COMPATIBLE_IOCTL(MEMUNLOCK)
+COMPATIBLE_IOCTL(MEMGETREGIONCOUNT)
+COMPATIBLE_IOCTL(MEMGETREGIONINFO)
 /* And these ioctls need translation */
+HANDLE_IOCTL(MEMREADOOB32, mtd_rw_oob)
+HANDLE_IOCTL(MEMWRITEOOB32, mtd_rw_oob)
 HANDLE_IOCTL(SIOCGIFNAME, dev_ifname32)
 HANDLE_IOCTL(SIOCGIFCONF, dev_ifconf)
 HANDLE_IOCTL(SIOCGIFFLAGS, dev_ifsioc)
@@ -3905,6 +4377,12 @@
 HANDLE_IOCTL(RTC32_EPOCH_READ, do_rtc_ioctl)
 HANDLE_IOCTL(RTC32_EPOCH_SET, do_rtc_ioctl)
 #endif
+HANDLE_IOCTL(USBDEVFS_CONTROL32, do_usbdevfs_control)
+HANDLE_IOCTL(USBDEVFS_BULK32, do_usbdevfs_bulk)
+/*HANDLE_IOCTL(USBDEVFS_SUBMITURB32, do_usbdevfs_urb)*/
+HANDLE_IOCTL(USBDEVFS_REAPURB32, do_usbdevfs_reapurb)
+HANDLE_IOCTL(USBDEVFS_REAPURBNDELAY32, do_usbdevfs_reapurb)
+HANDLE_IOCTL(USBDEVFS_DISCSIGNAL32, do_usbdevfs_discsignal)
 IOCTL_TABLE_END
 
 unsigned int ioctl32_hash_table[1024];
diff -u --recursive --new-file v2.4.7/linux/arch/sparc64/kernel/ptrace.c linux/arch/sparc64/kernel/ptrace.c
--- v2.4.7/linux/arch/sparc64/kernel/ptrace.c	Wed Jul 25 17:10:19 2001
+++ linux/arch/sparc64/kernel/ptrace.c	Sat Jul 28 12:12:38 2001
@@ -168,8 +168,6 @@
 
 	if ((current->personality == PER_SUNOS && request == PTRACE_SUNATTACH)
 	    || (current->personality != PER_SUNOS && request == PTRACE_ATTACH)) {
-		unsigned long flags;
-
 		if (ptrace_attach(child)) {
 			pt_error_return(regs, EPERM);
 			goto out_tsk;
diff -u --recursive --new-file v2.4.7/linux/drivers/block/DAC960.c linux/drivers/block/DAC960.c
--- v2.4.7/linux/drivers/block/DAC960.c	Sat Apr 28 11:27:53 2001
+++ linux/drivers/block/DAC960.c	Mon Aug  6 10:34:38 2001
@@ -20,7 +20,7 @@
 
 
 #define DAC960_DriverVersion			"2.4.10"
-#define DAC960_DriverDate			"1 February 2001"
+#define DAC960_DriverDate			"23 July 2001"
 
 
 #include <linux/version.h>
@@ -28,6 +28,7 @@
 #include <linux/types.h>
 #include <linux/blk.h>
 #include <linux/blkdev.h>
+#include <linux/completion.h>
 #include <linux/delay.h>
 #include <linux/hdreg.h>
 #include <linux/interrupt.h>
@@ -484,14 +485,14 @@
 static void DAC960_ExecuteCommand(DAC960_Command_T *Command)
 {
   DAC960_Controller_T *Controller = Command->Controller;
-  DECLARE_MUTEX_LOCKED(Semaphore);
+  DECLARE_COMPLETION(Completion);
   unsigned long ProcessorFlags;
-  Command->Semaphore = &Semaphore;
+  Command->Completion = &Completion;
   DAC960_AcquireControllerLock(Controller, &ProcessorFlags);
   DAC960_QueueCommand(Command);
   DAC960_ReleaseControllerLock(Controller, &ProcessorFlags);
   if (in_interrupt()) return;
-  down(&Semaphore);
+  wait_for_completion(&Completion);
 }
 
 
@@ -1316,7 +1317,7 @@
 						 *Controller)
 {
   DAC960_V1_DCDB_T DCDBs[DAC960_V1_MaxChannels], *DCDB;
-  Semaphore_T Semaphores[DAC960_V1_MaxChannels], *Semaphore;
+  Completion_T Completions[DAC960_V1_MaxChannels], *Completion;
   unsigned long ProcessorFlags;
   int Channel, TargetID;
   for (TargetID = 0; TargetID < Controller->Targets; TargetID++)
@@ -1327,12 +1328,12 @@
 	  DAC960_SCSI_Inquiry_T *InquiryStandardData =
 	    &Controller->V1.InquiryStandardData[Channel][TargetID];
 	  InquiryStandardData->PeripheralDeviceType = 0x1F;
-	  Semaphore = &Semaphores[Channel];
-	  init_MUTEX_LOCKED(Semaphore);
+	  Completion = &Completions[Channel];
+	  init_completion(Completion);
 	  DCDB = &DCDBs[Channel];
 	  DAC960_V1_ClearCommand(Command);
 	  Command->CommandType = DAC960_ImmediateCommand;
-	  Command->Semaphore = Semaphore;
+	  Command->Completion = Completion;
 	  Command->V1.CommandMailbox.Type3.CommandOpcode = DAC960_V1_DCDB;
 	  Command->V1.CommandMailbox.Type3.BusAddress = Virtual_to_Bus32(DCDB);
 	  DCDB->Channel = Channel;
@@ -1363,11 +1364,11 @@
 	  DAC960_SCSI_Inquiry_UnitSerialNumber_T *InquiryUnitSerialNumber =
 	    &Controller->V1.InquiryUnitSerialNumber[Channel][TargetID];
 	  InquiryUnitSerialNumber->PeripheralDeviceType = 0x1F;
-	  Semaphore = &Semaphores[Channel];
-	  down(Semaphore);
+	  Completion = &Completions[Channel];
+	  wait_for_completion(Completion);
 	  if (Command->V1.CommandStatus != DAC960_V1_NormalCompletion)
 	    continue;
-	  Command->Semaphore = Semaphore;
+	  Command->Completion = Completion;
 	  DCDB = &DCDBs[Channel];
 	  DCDB->TransferLength = sizeof(DAC960_SCSI_Inquiry_UnitSerialNumber_T);
 	  DCDB->BusAddress = Virtual_to_Bus32(InquiryUnitSerialNumber);
@@ -1381,7 +1382,7 @@
 	  DAC960_AcquireControllerLock(Controller, &ProcessorFlags);
 	  DAC960_QueueCommand(Command);
 	  DAC960_ReleaseControllerLock(Controller, &ProcessorFlags);
-	  down(Semaphore);
+	  wait_for_completion(Completion);
 	}
     }
   return true;
@@ -2768,7 +2769,7 @@
   if (Request->cmd == READ)
     Command->CommandType = DAC960_ReadCommand;
   else Command->CommandType = DAC960_WriteCommand;
-  Command->Semaphore = Request->sem;
+  Command->Completion = Request->waiting;
   Command->LogicalDriveNumber = DAC960_LogicalDriveNumber(Request->rq_dev);
   Command->BlockNumber =
     Request->sector
@@ -2921,13 +2922,10 @@
 	      DAC960_ProcessCompletedBuffer(BufferHeader, true);
 	      BufferHeader = NextBufferHeader;
 	    }
-	  /*
-	    Wake up requestor for swap file paging requests.
-	  */
-	  if (Command->Semaphore != NULL)
+	  if (Command->Completion != NULL)
 	    {
-	      up(Command->Semaphore);
-	      Command->Semaphore = NULL;
+	      complete(Command->Completion);
+	      Command->Completion = NULL;
 	    }
 	  add_blkdev_randomness(DAC960_MAJOR + Controller->ControllerNumber);
 	}
@@ -2969,13 +2967,10 @@
 	      DAC960_ProcessCompletedBuffer(BufferHeader, false);
 	      BufferHeader = NextBufferHeader;
 	    }
-	  /*
-	    Wake up requestor for swap file paging requests.
-	  */
-	  if (Command->Semaphore != NULL)
+	  if (Command->Completion != NULL)
 	    {
-	      up(Command->Semaphore);
-	      Command->Semaphore = NULL;
+	      complete(Command->Completion);
+	      Command->Completion = NULL;
 	    }
 	}
     }
@@ -3589,8 +3584,8 @@
     }
   if (CommandType == DAC960_ImmediateCommand)
     {
-      up(Command->Semaphore);
-      Command->Semaphore = NULL;
+      complete(Command->Completion);
+      Command->Completion = NULL;
       return;
     }
   if (CommandType == DAC960_QueuedCommand)
@@ -3931,13 +3926,10 @@
 	      DAC960_ProcessCompletedBuffer(BufferHeader, true);
 	      BufferHeader = NextBufferHeader;
 	    }
-	  /*
-	    Wake up requestor for swap file paging requests.
-	  */
-	  if (Command->Semaphore != NULL)
+	  if (Command->Completion != NULL)
 	    {
-	      up(Command->Semaphore);
-	      Command->Semaphore = NULL;
+	      complete(Command->Completion);
+	      Command->Completion = NULL;
 	    }
 	  add_blkdev_randomness(DAC960_MAJOR + Controller->ControllerNumber);
 	}
@@ -3979,13 +3971,10 @@
 	      DAC960_ProcessCompletedBuffer(BufferHeader, false);
 	      BufferHeader = NextBufferHeader;
 	    }
-	  /*
-	    Wake up requestor for swap file paging requests.
-	  */
-	  if (Command->Semaphore != NULL)
+	  if (Command->Completion != NULL)
 	    {
-	      up(Command->Semaphore);
-	      Command->Semaphore = NULL;
+	      complete(Command->Completion);
+	      Command->Completion = NULL;
 	    }
 	}
     }
@@ -4539,8 +4528,8 @@
     }
   if (CommandType == DAC960_ImmediateCommand)
     {
-      up(Command->Semaphore);
-      Command->Semaphore = NULL;
+      complete(Command->Completion);
+      Command->Completion = NULL;
       return;
     }
   if (CommandType == DAC960_QueuedCommand)
diff -u --recursive --new-file v2.4.7/linux/drivers/block/DAC960.h linux/drivers/block/DAC960.h
--- v2.4.7/linux/drivers/block/DAC960.h	Tue Feb 20 21:26:22 2001
+++ linux/drivers/block/DAC960.h	Mon Aug  6 10:34:38 2001
@@ -2139,6 +2139,7 @@
 typedef struct buffer_head BufferHeader_T;
 typedef struct file File_T;
 typedef struct block_device_operations BlockDeviceOperations_T;
+typedef struct completion Completion_T;
 typedef struct gendisk GenericDiskInfo_T;
 typedef struct hd_geometry DiskGeometry_T;
 typedef struct hd_struct DiskPartition_T;
@@ -2153,7 +2154,6 @@
 typedef struct pt_regs Registers_T;
 typedef struct request IO_Request_T;
 typedef request_queue_t RequestQueue_T;
-typedef struct semaphore Semaphore_T;
 typedef struct super_block SuperBlock_T;
 typedef struct timer_list Timer_T;
 typedef wait_queue_head_t WaitQueue_T;
@@ -2220,7 +2220,7 @@
   DAC960_CommandType_T CommandType;
   struct DAC960_Controller *Controller;
   struct DAC960_Command *Next;
-  Semaphore_T *Semaphore;
+  Completion_T *Completion;
   unsigned int LogicalDriveNumber;
   unsigned int BlockNumber;
   unsigned int BlockCount;
diff -u --recursive --new-file v2.4.7/linux/drivers/block/cpqarray.c linux/drivers/block/cpqarray.c
--- v2.4.7/linux/drivers/block/cpqarray.c	Tue May 22 10:23:16 2001
+++ linux/drivers/block/cpqarray.c	Wed Jul 25 14:12:01 2001
@@ -18,9 +18,6 @@
  *
  *    Questions/Comments/Bugfixes to arrays@compaq.com
  *
- *    If you want to make changes, improve or add functionality to this
- *    driver, you'll probably need the Compaq Array Controller Interface
- *    Specificiation (Document number ECG086/1198)
  */
 #include <linux/config.h>	/* CONFIG_PROC_FS */
 #include <linux/module.h>
@@ -44,8 +41,8 @@
 
 #define SMART2_DRIVER_VERSION(maj,min,submin) ((maj<<16)|(min<<8)|(submin))
 
-#define DRIVER_NAME "Compaq SMART2 Driver (v 2.4.4)"
-#define DRIVER_VERSION SMART2_DRIVER_VERSION(2,4,4)
+#define DRIVER_NAME "Compaq SMART2 Driver (v 2.4.5)"
+#define DRIVER_VERSION SMART2_DRIVER_VERSION(2,4,5)
 
 /* Embedded module documentation macros - see modules.h */
 /* Original author Chris Frantz - Compaq Computer Corporation */
@@ -206,7 +203,7 @@
 static void __init ida_procinit(int i)
 {
 	if (proc_array == NULL) {
-		proc_array = proc_mkdir("array", proc_root_driver);
+		proc_array = proc_mkdir("cpqarray", proc_root_driver);
 		if (!proc_array) return;
 	}
 
@@ -315,11 +312,18 @@
 {
 	int i;
 	struct gendisk *g;
-
-	remove_proc_entry("array", proc_root_driver);
+	char buff[4]; 
 
 	for(i=0; i<nr_ctlr; i++) {
-		hba[i]->access.set_intr_mask(hba[i], 0);
+
+		/* sendcmd will turn off interrupt, and send the flush... 
+		 * To write all data in the battery backed cache to disks    
+		 * no data returned, but don't want to send NULL to sendcmd */	
+		if( sendcmd(FLUSH_CACHE, i, buff, 4, 0, 0, 0))
+		{
+			printk(KERN_WARNING "Unable to flush cache on "
+				"controller %d\n", i);	
+		}
 		free_irq(hba[i]->intr, hba[i]);
 		iounmap(hba[i]->vaddr);
 		unregister_blkdev(MAJOR_NR+i, hba[i]->devname);
@@ -342,7 +346,7 @@
 			}
 		}
 	}
-
+	remove_proc_entry("cpqarray", proc_root_driver);
 	kfree(ida);
 	kfree(ida_sizes);
 	kfree(ida_hardsizes);
@@ -1079,7 +1083,7 @@
 
 	if (cmd->req.hdr.rcode & RCODE_NONFATAL &&
 	   (hba[cmd->ctlr]->misc_tflags & MISC_NONFATAL_WARN) == 0) {
-		printk(KERN_WARNING "Non Fatal error on ida/c%dd%d\n",
+		printk(KERN_NOTICE "Non Fatal error on ida/c%dd%d\n",
 				cmd->ctlr, cmd->hdr.unit);
 		hba[cmd->ctlr]->misc_tflags |= MISC_NONFATAL_WARN;
 	}
@@ -1148,6 +1152,15 @@
 			 */
 			if (c->busaddr == a) {
 				removeQ(&h->cmpQ, c);
+				/*  Check for invalid command.
+                                 *  Controller returns command error,
+                                 *  But rcode = 0.
+                                 */
+
+				if((a1 & 0x03) && (c->req.hdr.rcode == 0))
+                                {
+                                	c->req.hdr.rcode = RCODE_INVREQ;
+                                }
 				if (c->type == CMD_RWREQ) {
 					complete_command(c, 0);
 					cmd_free(h, c, 1);
@@ -1315,6 +1328,8 @@
 		c->req.hdr.sg_cnt = 1;
 		break;
 	case IDA_READ:
+	case READ_FLASH_ROM:
+	case SENSE_CONTROLLER_PERFORMANCE:
 		p = kmalloc(io->sg[0].size, GFP_KERNEL);
 		if (!p) 
 		{ 
@@ -1331,6 +1346,8 @@
 	case IDA_WRITE:
 	case IDA_WRITE_MEDIA:
 	case DIAG_PASS_THRU:
+	case COLLECT_BUFFER:
+	case WRITE_FLASH_ROM:
 		p = kmalloc(io->sg[0].size, GFP_KERNEL);
 		if (!p) 
  		{ 
@@ -1373,10 +1390,14 @@
                                 PCI_DMA_BIDIRECTIONAL);
 	case IDA_READ:
 	case DIAG_PASS_THRU:
+	case SENSE_CONTROLLER_PERFORMANCE:
+	case READ_FLASH_ROM:
 		copy_to_user((void*)io->sg[0].addr, p, io->sg[0].size);
 		/* fall through and free p */
 	case IDA_WRITE:
 	case IDA_WRITE_MEDIA:
+	case COLLECT_BUFFER:
+	case WRITE_FLASH_ROM:
 		kfree(p);
 		break;
 	default:;
diff -u --recursive --new-file v2.4.7/linux/drivers/block/floppy.c linux/drivers/block/floppy.c
--- v2.4.7/linux/drivers/block/floppy.c	Fri Feb  9 11:30:22 2001
+++ linux/drivers/block/floppy.c	Sun Aug  5 13:12:40 2001
@@ -1034,7 +1034,7 @@
 }
 
 /* waits for a delay (spinup or select) to pass */
-static int wait_for_completion(unsigned long delay, timeout_fn function)
+static int fd_wait_for_completion(unsigned long delay, timeout_fn function)
 {
 	if (FDCS->reset){
 		reset_fdc(); /* do the reset during sleep to win time
@@ -1392,7 +1392,7 @@
 	 * Pause 5 msec to avoid trouble. (Needs to be 2 jiffies)
 	 */
 	FDCS->dtr = raw_cmd->rate & 3;
-	return(wait_for_completion(jiffies+2UL*HZ/100,
+	return(fd_wait_for_completion(jiffies+2UL*HZ/100,
 				   (timeout_fn) floppy_ready));
 } /* fdc_dtr */
 
@@ -1509,7 +1509,7 @@
 			function = (timeout_fn) setup_rw_floppy;
 
 		/* wait until the floppy is spinning fast enough */
-		if (wait_for_completion(ready_date,function))
+		if (fd_wait_for_completion(ready_date,function))
 			return;
 	}
 	dflags = DRS->flags;
@@ -1939,7 +1939,7 @@
 	set_dor(fdc, mask, data);
 
 	/* wait_for_completion also schedules reset if needed. */
-	return(wait_for_completion(DRS->select_date+DP->select_delay,
+	return(fd_wait_for_completion(DRS->select_date+DP->select_delay,
 				   (timeout_fn) function));
 }
 
diff -u --recursive --new-file v2.4.7/linux/drivers/block/ida_cmd.h linux/drivers/block/ida_cmd.h
--- v2.4.7/linux/drivers/block/ida_cmd.h	Mon Dec 11 12:50:39 2000
+++ linux/drivers/block/ida_cmd.h	Wed Jul 25 14:12:01 2001
@@ -18,9 +18,6 @@
  *
  *    Questions/Comments/Bugfixes to arrays@compaq.com
  *
- *    If you want to make changes, improve or add functionality to this
- *    driver, you'll probably need the Compaq Array Controller Interface
- *    Specificiation (Document number ECG086/1198)
  */
 #ifndef ARRAYCMD_H
 #define ARRAYCMD_H
@@ -342,6 +339,11 @@
 } scsi_param_t;
 
 #define RESUME_BACKGROUND_ACTIVITY	0x99
+#define SENSE_CONTROLLER_PERFORMANCE	0xa8
+#define FLUSH_CACHE			0xc2
+#define COLLECT_BUFFER			0xd2
+#define READ_FLASH_ROM			0xf6
+#define WRITE_FLASH_ROM			0xf7
 #pragma pack()	
 
 #endif /* ARRAYCMD_H */
diff -u --recursive --new-file v2.4.7/linux/drivers/block/ida_ioctl.h linux/drivers/block/ida_ioctl.h
--- v2.4.7/linux/drivers/block/ida_ioctl.h	Mon Dec 11 12:50:39 2000
+++ linux/drivers/block/ida_ioctl.h	Wed Jul 25 14:12:01 2001
@@ -18,9 +18,6 @@
  *
  *    Questions/Comments/Bugfixes to arrays@compaq.com
  *
- *    If you want to make changes, improve or add functionality to this
- *    driver, you'll probably need the Compaq Array Controller Interface
- *    Specificiation (Document number ECG086/1198)
  */
 #ifndef IDA_IOCTL_H
 #define IDA_IOCTL_H
diff -u --recursive --new-file v2.4.7/linux/drivers/block/ll_rw_blk.c linux/drivers/block/ll_rw_blk.c
--- v2.4.7/linux/drivers/block/ll_rw_blk.c	Wed Jul 25 17:10:19 2001
+++ linux/drivers/block/ll_rw_blk.c	Fri Aug  3 22:37:09 2001
@@ -119,17 +119,10 @@
 int * max_sectors[MAX_BLKDEV];
 
 /*
- * queued sectors for all devices, used to make sure we don't fill all
- * of memory with locked buffers
+ * How many reqeusts do we allocate per queue,
+ * and how many do we "batch" on freeing them?
  */
-atomic_t queued_sectors;
-
-/*
- * high and low watermark for above
- */
-static int high_queued_sectors, low_queued_sectors;
-static int batch_requests, queue_nr_requests;
-static DECLARE_WAIT_QUEUE_HEAD(blk_buffers_wait);
+static int queue_nr_requests, batch_requests;
 
 static inline int get_max_sectors(kdev_t dev)
 {
@@ -592,13 +585,6 @@
 	 */
 	if (q) {
 		/*
-		 * we've released enough buffers to start I/O again
-		 */
-		if (waitqueue_active(&blk_buffers_wait)
-		    && atomic_read(&queued_sectors) < low_queued_sectors)
-			wake_up(&blk_buffers_wait);
-
-		/*
 		 * Add to pending free list and batch wakeups
 		 */
 		list_add(&req->table, &q->pending_freelist[rw]);
@@ -1032,16 +1018,6 @@
 	for (i = 0; i < nr; i++) {
 		struct buffer_head *bh = bhs[i];
 
-		/*
-		 * don't lock any more buffers if we are above the high
-		 * water mark. instead start I/O on the queued stuff.
-		 */
-		if (atomic_read(&queued_sectors) >= high_queued_sectors) {
-			run_task_queue(&tq_disk);
-			wait_event(blk_buffers_wait,
-			 atomic_read(&queued_sectors) < low_queued_sectors);
-		}
-
 		/* Only one thread can actually submit the I/O. */
 		if (test_and_set_bit(BH_Lock, &bh->b_state))
 			continue;
@@ -1168,42 +1144,21 @@
 	memset(max_readahead, 0, sizeof(max_readahead));
 	memset(max_sectors, 0, sizeof(max_sectors));
 
-	atomic_set(&queued_sectors, 0);
 	total_ram = nr_free_pages() << (PAGE_SHIFT - 10);
 
 	/*
-	 * Try to keep 128MB max hysteris. If not possible,
-	 * use half of RAM
-	 */
-	high_queued_sectors = (total_ram * 2) / 3;
-	low_queued_sectors = high_queued_sectors / 3;
-	if (high_queued_sectors - low_queued_sectors > MB(128))
-		low_queued_sectors = high_queued_sectors - MB(128);
-
-
-	/*
-	 * make it sectors (512b)
+	 * Free request slots per queue.
+	 * (Half for reads, half for writes)
 	 */
-	high_queued_sectors <<= 1;
-	low_queued_sectors <<= 1;
+	queue_nr_requests = 64;
+	if (total_ram > MB(32))
+		queue_nr_requests = 128;
 
 	/*
-	 * Scale free request slots per queue too
+	 * Batch frees according to queue length
 	 */
-	total_ram = (total_ram + MB(32) - 1) & ~(MB(32) - 1);
-	if ((queue_nr_requests = total_ram >> 9) > QUEUE_NR_REQUESTS)
-		queue_nr_requests = QUEUE_NR_REQUESTS;
-
-	/*
-	 * adjust batch frees according to queue length, with upper limit
-	 */
-	if ((batch_requests = queue_nr_requests >> 3) > 32)
-		batch_requests = 32;
-
-	printk("block: queued sectors max/low %dkB/%dkB, %d slots per queue\n",
-						high_queued_sectors / 2,
-						low_queued_sectors / 2,
-						queue_nr_requests);
+	batch_requests = queue_nr_requests >> 3;
+	printk("block: %d slots per queue, batch=%d\n", queue_nr_requests, batch_requests);
 
 #ifdef CONFIG_AMIGA_Z2RAM
 	z2_init();
@@ -1324,4 +1279,3 @@
 EXPORT_SYMBOL(generic_make_request);
 EXPORT_SYMBOL(blkdev_release_request);
 EXPORT_SYMBOL(generic_unplug_device);
-EXPORT_SYMBOL(queued_sectors);
diff -u --recursive --new-file v2.4.7/linux/drivers/char/drm/agpsupport.c linux/drivers/char/drm/agpsupport.c
--- v2.4.7/linux/drivers/char/drm/agpsupport.c	Tue Jul  3 17:08:19 2001
+++ linux/drivers/char/drm/agpsupport.c	Sun Aug  5 13:12:40 2001
@@ -292,8 +292,8 @@
 		case ALI_M1651: 	head->chipset = "ALi M1651";	 break;
 		case SVWRKS_GENERIC:	head->chipset = "Serverworks Generic";
 			break;
-		case SVWRKS_HE: 	head->chipset = "Serverworks HE";
-		case SVWRKS_LE: 	head->chipset = "Serverworks LE";
+		case SVWRKS_HE: 	head->chipset = "Serverworks HE"; break;
+		case SVWRKS_LE: 	head->chipset = "Serverworks LE"; break;
 
 		default:		head->chipset = "Unknown";       break;
 		}
diff -u --recursive --new-file v2.4.7/linux/drivers/char/mem.c linux/drivers/char/mem.c
--- v2.4.7/linux/drivers/char/mem.c	Wed Jul 25 17:10:19 2001
+++ linux/drivers/char/mem.c	Sat Jul 28 12:37:23 2001
@@ -260,7 +260,9 @@
 			if (len > PAGE_SIZE)
 				len = PAGE_SIZE;
 			len = vread(kbuf, (char *)p, len);
-			if (len && copy_to_user(buf, kbuf, len)) {
+			if (!len)
+				break;
+			if (copy_to_user(buf, kbuf, len)) {
 				free_page((unsigned long)kbuf);
 				return -EFAULT;
 			}
diff -u --recursive --new-file v2.4.7/linux/drivers/char/moxa.c linux/drivers/char/moxa.c
--- v2.4.7/linux/drivers/char/moxa.c	Wed Jul 25 17:10:19 2001
+++ linux/drivers/char/moxa.c	Wed Jul 25 14:12:02 2001
@@ -573,6 +573,8 @@
 			up(&moxaBuffSem);
 			return (-ENOMEM);
 		}
+		/* This test is guarded by the BuffSem so no longer needed
+		   delete me in 2.5 */
 		if (moxaXmitBuff)
 			free_page(page);
 		else
diff -u --recursive --new-file v2.4.7/linux/drivers/char/mxser.c linux/drivers/char/mxser.c
--- v2.4.7/linux/drivers/char/mxser.c	Wed May 16 10:31:27 2001
+++ linux/drivers/char/mxser.c	Mon Aug  6 10:33:27 2001
@@ -884,8 +884,6 @@
 	if (!tty || !info->xmit_buf || !mxvar_tmp_buf)
 		return (0);
 
-	if (from_user)
-		down(&mxvar_tmp_buf_sem);
 	save_flags(flags);
 	if (from_user) {
 		down(&mxvar_tmp_buf_sem);
diff -u --recursive --new-file v2.4.7/linux/drivers/char/nvram.c linux/drivers/char/nvram.c
--- v2.4.7/linux/drivers/char/nvram.c	Tue Jul  3 17:08:19 2001
+++ linux/drivers/char/nvram.c	Sun Aug  5 13:12:40 2001
@@ -113,7 +113,7 @@
 #define	NVRAM_EXCL		2		/* opened with O_EXCL */
 
 #define	RTC_FIRST_BYTE		14	/* RTC register number of first NVRAM byte */
-#define	NVRAM_BYTES			128	/* number of NVRAM bytes */
+#define	NVRAM_BYTES			128-RTC_FIRST_BYTE	/* number of NVRAM bytes */
 
 
 static int mach_check_checksum( void );
diff -u --recursive --new-file v2.4.7/linux/drivers/char/riscom8.c linux/drivers/char/riscom8.c
--- v2.4.7/linux/drivers/char/riscom8.c	Wed May 16 10:31:27 2001
+++ linux/drivers/char/riscom8.c	Mon Aug  6 16:24:33 2001
@@ -24,7 +24,11 @@
  *      along with this program; if not, write to the Free Software
  *      Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
  *
- *	Revision 1.0 
+ *	Revision 1.1
+ *
+ *	ChangeLog:
+ *	Arnaldo Carvalho de Melo <acme@conectiva.com.br> - 27-Jun-2001
+ *	- get rid of check_region and several cleanups
  */
 
 #include <linux/module.h>
@@ -97,10 +101,18 @@
 };
 
 static struct riscom_board rc_board[RC_NBOARD] =  {
-	{ 0, RC_IOBASE1, 0, },
-	{ 0, RC_IOBASE2, 0, },
-	{ 0, RC_IOBASE3, 0, },
-	{ 0, RC_IOBASE4, 0, },
+	{
+		base:	RC_IOBASE1,
+	},
+	{
+		base:	RC_IOBASE2,
+	},
+	{
+		base:	RC_IOBASE3,
+	},
+	{
+		base:	RC_IOBASE4,
+	},
 };
 
 static struct riscom_port rc_port[RC_NBOARD * RC_NPORT];
@@ -122,9 +134,9 @@
 				    kdev_t device, const char *routine)
 {
 #ifdef RISCOM_PARANOIA_CHECK
-	static const char *badmagic =
+	static const char badmagic[] = KERN_INFO
 		"rc: Warning: bad riscom port magic number for device %s in %s\n";
-	static const char *badinfo =
+	static const char badinfo[] = KERN_INFO
 		"rc: Warning: null riscom port for device %s in %s\n";
 
 	if (!port) {
@@ -186,32 +198,29 @@
 		if (!rc_in(bp, CD180_CCR))
 			return;
 	
-	printk("rc%d: Timeout waiting for CCR.\n", board_No(bp));
+	printk(KERN_INFO "rc%d: Timeout waiting for CCR.\n", board_No(bp));
 }
 
 /*
  *  RISCom/8 probe functions.
  */
 
-static inline int rc_check_io_range(struct riscom_board * const bp)
+static inline int rc_request_io_range(struct riscom_board * const bp)
 {
 	int i;
 	
 	for (i = 0; i < RC_NIOPORT; i++)  
-		if (check_region(RC_TO_ISA(rc_ioport[i]) + bp->base, 1))  {
-			printk("rc%d: Skipping probe at 0x%03x. I/O address in use.\n",
-			       board_No(bp), bp->base);
-			return 1;
+		if (!request_region(RC_TO_ISA(rc_ioport[i]) + bp->base, 1,
+				   "RISCom/8"))  {
+			goto out_release;
 		}
 	return 0;
-}
-
-static inline void rc_request_io_range(struct riscom_board * const bp)
-{
-	int i;
-	
-	for (i = 0; i < RC_NIOPORT; i++) 
-		request_region(RC_TO_ISA(rc_ioport[i]) + bp->base, 1, "RISCom/8" );
+out_release:
+	printk(KERN_INFO "rc%d: Skipping probe at 0x%03x. IO address in use.\n",
+			 board_No(bp), bp->base);
+	while(--i >= 0)
+		release_region(RC_TO_ISA(rc_ioport[i]) + bp->base, 1);
+	return 1;
 }
 
 static inline void rc_release_io_range(struct riscom_board * const bp)
@@ -221,7 +230,6 @@
 	for (i = 0; i < RC_NIOPORT; i++)  
 		release_region(RC_TO_ISA(rc_ioport[i]) + bp->base, 1);
 }
-
 	
 /* Must be called with enabled interrupts */
 static inline void rc_long_delay(unsigned long delay)
@@ -265,7 +273,7 @@
 	
 	bp->irq = 0;
 
-	if (rc_check_io_range(bp))
+	if (rc_request_io_range(bp))
 		return 1;
 	
 	/* Are the I/O ports here ? */
@@ -277,9 +285,9 @@
 	val2 = rc_in(bp, CD180_PPRL);
 	
 	if ((val1 != 0x5a) || (val2 != 0xa5))  {
-		printk("rc%d: RISCom/8 Board at 0x%03x not found.\n",
+		printk(KERN_ERR "rc%d: RISCom/8 Board at 0x%03x not found.\n",
 		       board_No(bp), bp->base);
-		return 1;
+		goto out_release;
 	}
 	
 	/* It's time to find IRQ for this board */
@@ -297,27 +305,30 @@
 		rc_init_CD180(bp);	       		/* Reset CD180 again      */
 	
 		if ((val1 & RC_BSR_TINT) || (val2 != (RC_ID | GIVR_IT_TX)))  {
-			printk("rc%d: RISCom/8 Board at 0x%03x not found.\n",
-			       board_No(bp), bp->base);
-			return 1;
+			printk(KERN_ERR "rc%d: RISCom/8 Board at 0x%03x not "
+					"found.\n", board_No(bp), bp->base);
+			goto out_release;
 		}
 	}
 	
 	if (irqs <= 0)  {
-		printk("rc%d: Can't find IRQ for RISCom/8 board at 0x%03x.\n",
-		       board_No(bp), bp->base);
-		return 1;
+		printk(KERN_ERR "rc%d: Can't find IRQ for RISCom/8 board "
+				"at 0x%03x.\n", board_No(bp), bp->base);
+		goto out_release;
 	}
-	rc_request_io_range(bp);
 	bp->irq = irqs;
 	bp->flags |= RC_BOARD_PRESENT;
 	
-	printk("rc%d: RISCom/8 Rev. %c board detected at 0x%03x, IRQ %d.\n",
+	printk(KERN_INFO "rc%d: RISCom/8 Rev. %c board detected at "
+			 "0x%03x, IRQ %d.\n",
 	       board_No(bp),
 	       (rc_in(bp, CD180_GFRCR) & 0x0f) + 'A',   /* Board revision */
 	       bp->base, bp->irq);
 	
 	return 0;
+out_release:
+	rc_release_io_range(bp);
+	return 1;
 }
 
 /* 
@@ -354,7 +365,7 @@
 			return port;
 		}
 	}
-	printk("rc%d: %s interrupt from invalid port %d\n", 
+	printk(KERN_ERR "rc%d: %s interrupt from invalid port %d\n", 
 	       board_No(bp), what, channel);
 	return NULL;
 }
@@ -371,7 +382,8 @@
 
 	tty = port->tty;
 	if (tty->flip.count >= TTY_FLIPBUF_SIZE)  {
-		printk("rc%d: port %d: Working around flip buffer overflow.\n",
+		printk(KERN_WARNING "rc%d: port %d: Working around flip "
+				    "buffer overflow.\n",
 		       board_No(bp), port_No(port));
 		return;
 	}
@@ -381,7 +393,7 @@
 	if (status & RCSR_OE)  {
 		port->overrun++;
 #if 0		
-		printk("rc%d: port %d: Overrun. Total %ld overruns.\n", 
+		printk(KERN_ERR "rc%d: port %d: Overrun. Total %ld overruns\n", 
 		       board_No(bp), port_No(port), port->overrun);
 #endif		
 	}
@@ -394,12 +406,13 @@
 		return;
 	}
 	if (status & RCSR_TOUT)  {
-		printk("rc%d: port %d: Receiver timeout. Hardware problems ?\n", 
+		printk(KERN_WARNING "rc%d: port %d: Receiver timeout. "
+				    "Hardware problems ?\n", 
 		       board_No(bp), port_No(port));
 		return;
 		
 	} else if (status & RCSR_BREAK)  {
-		printk("rc%d: port %d: Handling break...\n",
+		printk(KERN_INFO "rc%d: port %d: Handling break...\n",
 		       board_No(bp), port_No(port));
 		*tty->flip.flag_buf_ptr++ = TTY_BREAK;
 		if (port->flags & ASYNC_SAK)
@@ -441,7 +454,8 @@
 	
 	while (count--)  {
 		if (tty->flip.count >= TTY_FLIPBUF_SIZE)  {
-			printk("rc%d: port %d: Working around flip buffer overflow.\n",
+			printk(KERN_WARNING "rc%d: port %d: Working around "
+					    "flip buffer overflow.\n",
 			       board_No(bp), port_No(port));
 			break;
 		}
@@ -594,7 +608,8 @@
 				  RC_BSR_MINT | RC_BSR_RINT))) {
 	
 		if (status & RC_BSR_TOUT) 
-			printk("rc%d: Got timeout. Hardware error ?\n", board_No(bp));
+			printk(KERN_WARNING "rc%d: Got timeout. Hardware "
+					    "error?\n", board_No(bp));
 		
 		else if (status & RC_BSR_RINT) {
 			ack = rc_in(bp, RC_ACK_RINT);
@@ -604,7 +619,8 @@
 			else if (ack == (RC_ID | GIVR_IT_REXC))
 				rc_receive_exc(bp);
 			else
-				printk("rc%d: Bad receive ack 0x%02x.\n",
+				printk(KERN_WARNING "rc%d: Bad receive ack "
+						    "0x%02x.\n",
 				       board_No(bp), ack);
 		
 		} else if (status & RC_BSR_TINT) {
@@ -613,7 +629,8 @@
 			if (ack == (RC_ID | GIVR_IT_TX))
 				rc_transmit(bp);
 			else
-				printk("rc%d: Bad transmit ack 0x%02x.\n",
+				printk(KERN_WARNING "rc%d: Bad transmit ack "
+						    "0x%02x.\n",
 				       board_No(bp), ack);
 		
 		} else /* if (status & RC_BSR_MINT) */ {
@@ -622,7 +639,8 @@
 			if (ack == (RC_ID | GIVR_IT_MODEM)) 
 				rc_check_modem(bp);
 			else
-				printk("rc%d: Bad modem ack 0x%02x.\n",
+				printk(KERN_WARNING "rc%d: Bad modem ack "
+						    "0x%02x.\n",
 				       board_No(bp), ack);
 		
 		} 
@@ -644,7 +662,8 @@
 	if (bp->flags & RC_BOARD_ACTIVE) 
 		return 0;
 	
-	error = request_irq(bp->irq, rc_interrupt, SA_INTERRUPT, "RISCom/8", NULL);
+	error = request_irq(bp->irq, rc_interrupt, SA_INTERRUPT,
+			    "RISCom/8", NULL);
 	if (error) 
 		return error;
 	
@@ -892,14 +911,14 @@
 		return;
 	
 #ifdef RC_REPORT_OVERRUN
-	printk("rc%d: port %d: Total %ld overruns were detected.\n",
+	printk(KERN_INFO "rc%d: port %d: Total %ld overruns were detected.\n",
 	       board_No(bp), port_No(port), port->overrun);
 #endif	
 #ifdef RC_REPORT_FIFO
 	{
 		int i;
 		
-		printk("rc%d: port %d: FIFO hits [ ",
+		printk(KERN_INFO "rc%d: port %d: FIFO hits [ ",
 		       board_No(bp), port_No(port));
 		for (i = 0; i < 10; i++)  {
 			printk("%ld ", port->hits[i]);
@@ -932,7 +951,8 @@
 	port->flags &= ~ASYNC_INITIALIZED;
 	
 	if (--bp->count < 0)  {
-		printk("rc%d: rc_shutdown_port: bad board count: %d\n",
+		printk(KERN_INFO "rc%d: rc_shutdown_port: "
+				 "bad board count: %d\n",
 		       board_No(bp), bp->count);
 		bp->count = 0;
 	}
@@ -1118,27 +1138,24 @@
 		return;
 	
 	save_flags(flags); cli();
-	if (tty_hung_up_p(filp))  {
-		restore_flags(flags);
-		return;
-	}
+	if (tty_hung_up_p(filp))
+		goto out;
 	
 	bp = port_Board(port);
 	if ((tty->count == 1) && (port->count != 1))  {
-		printk("rc%d: rc_close: bad port count;"
+		printk(KERN_INFO "rc%d: rc_close: bad port count;"
 		       " tty->count is 1, port count is %d\n",
 		       board_No(bp), port->count);
 		port->count = 1;
 	}
 	if (--port->count < 0)  {
-		printk("rc%d: rc_close: bad port count for tty%d: %d\n",
+		printk(KERN_INFO "rc%d: rc_close: bad port count "
+				 "for tty%d: %d\n",
 		       board_No(bp), port_No(port), port->count);
 		port->count = 0;
 	}
-	if (port->count)  {
-		restore_flags(flags);
-		return;
-	}
+	if (port->count)
+		goto out;
 	port->flags |= ASYNC_CLOSING;
 	/*
 	 * Save the termios structure, since this port may have
@@ -1198,7 +1215,7 @@
 	port->flags &= ~(ASYNC_NORMAL_ACTIVE|ASYNC_CALLOUT_ACTIVE|
 			 ASYNC_CLOSING);
 	wake_up_interruptible(&port->close_wait);
-	restore_flags(flags);
+out:	restore_flags(flags);
 }
 
 static int rc_write(struct tty_struct * tty, int from_user, 
@@ -1293,15 +1310,13 @@
 
 	save_flags(flags); cli();
 	
-	if (port->xmit_cnt >= SERIAL_XMIT_SIZE - 1) {
-		restore_flags(flags);
-		return;
-	}
+	if (port->xmit_cnt >= SERIAL_XMIT_SIZE - 1)
+		goto out;
 
 	port->xmit_buf[port->xmit_head++] = ch;
 	port->xmit_head &= SERIAL_XMIT_SIZE - 1;
 	port->xmit_cnt++;
-	restore_flags(flags);
+out:	restore_flags(flags);
 }
 
 static void rc_flush_chars(struct tty_struct * tty)
@@ -1383,21 +1398,18 @@
 		| ((status & MSVR_CD)  ? TIOCM_CAR : 0)
 		| ((status & MSVR_DSR) ? TIOCM_DSR : 0)
 		| ((status & MSVR_CTS) ? TIOCM_CTS : 0);
-	put_user(result, value);
-	return 0;
+	return put_user(result, value);
 }
 
 static int rc_set_modem_info(struct riscom_port * port, unsigned int cmd,
 			     unsigned int *value)
 {
-	int error;
 	unsigned int arg;
 	unsigned long flags;
 	struct riscom_board *bp = port_Board(port);
 
-	error = get_user(arg, value);
-	if (error) 
-		return error;
+	if (get_user(arg, value))
+		return -EFAULT;
 	switch (cmd) {
 	 case TIOCMBIS: 
 		if (arg & TIOCM_RTS) 
@@ -1453,12 +1465,9 @@
 	struct riscom_board *bp = port_Board(port);
 	int change_speed;
 	unsigned long flags;
-	int error;
 	
-	error = verify_area(VERIFY_READ, (void *) newinfo, sizeof(tmp));
-	if (error)
-		return error;
-	copy_from_user(&tmp, newinfo, sizeof(tmp));
+	if (copy_from_user(&tmp, newinfo, sizeof(tmp)))
+		return -EFAULT;
 	
 #if 0	
 	if ((tmp.irq != bp->irq) ||
@@ -1501,11 +1510,6 @@
 {
 	struct serial_struct tmp;
 	struct riscom_board *bp = port_Board(port);
-	int error;
-	
-	error = verify_area(VERIFY_WRITE, (void *) retinfo, sizeof(tmp));
-	if (error)
-		return error;
 	
 	memset(&tmp, 0, sizeof(tmp));
 	tmp.type = PORT_CIRRUS;
@@ -1517,8 +1521,7 @@
 	tmp.close_delay = port->close_delay * HZ/100;
 	tmp.closing_wait = port->closing_wait * HZ/100;
 	tmp.xmit_fifo_size = CD180_NFIFO;
-	copy_to_user(retinfo, &tmp, sizeof(tmp));
-	return 0;
+	return copy_to_user(retinfo, &tmp, sizeof(tmp)) ? -EFAULT : 0;
 }
 
 static int rc_ioctl(struct tty_struct * tty, struct file * filp, 
@@ -1526,7 +1529,6 @@
 		    
 {
 	struct riscom_port *port = (struct riscom_port *)tty->driver_data;
-	int error;
 	int retval;
 				
 	if (rc_paranoia_check(port, tty->device, "rc_ioctl"))
@@ -1540,29 +1542,24 @@
 		tty_wait_until_sent(tty, 0);
 		if (!arg)
 			rc_send_break(port, HZ/4);	/* 1/4 second */
-		return 0;
+		break;
 	 case TCSBRKP:	/* support for POSIX tcsendbreak() */
 		retval = tty_check_change(tty);
 		if (retval)
 			return retval;
 		tty_wait_until_sent(tty, 0);
 		rc_send_break(port, arg ? arg*(HZ/10) : HZ/4);
-		return 0;
+		break;
 	 case TIOCGSOFTCAR:
 		return put_user(C_CLOCAL(tty) ? 1 : 0, (unsigned int *) arg);
 	 case TIOCSSOFTCAR:
-		retval = get_user(arg,(unsigned int *) arg);
-		if (retval)
-			return retval;
+		if (get_user(arg,(unsigned int *) arg))
+			return -EFAULT;
 		tty->termios->c_cflag =
 			((tty->termios->c_cflag & ~CLOCAL) |
 			(arg ? CLOCAL : 0));
-		return 0;
+		break;
 	 case TIOCMGET:
-		error = verify_area(VERIFY_WRITE, (void *) arg,
-				    sizeof(unsigned int));
-		if (error)
-			return error;
 		return rc_get_modem_info(port, (unsigned int *) arg);
 	 case TIOCMBIS:
 	 case TIOCMBIC:
@@ -1751,7 +1748,7 @@
 
 	
 	if (!(tmp_buf = (unsigned char *) get_free_page(GFP_KERNEL))) {
-		printk("rc: Couldn't get free page.\n");
+		printk(KERN_ERR "rc: Couldn't get free page.\n");
 		return 1;
 	}
 	init_bh(RISCOM8_BH, do_riscom_bh);
@@ -1795,14 +1792,16 @@
 	
 	if ((error = tty_register_driver(&riscom_driver)))  {
 		free_page((unsigned long)tmp_buf);
-		printk("rc: Couldn't register RISCom/8 driver, error = %d\n",
+		printk(KERN_ERR "rc: Couldn't register RISCom/8 driver, "
+				"error = %d\n",
 		       error);
 		return 1;
 	}
 	if ((error = tty_register_driver(&riscom_callout_driver)))  {
 		free_page((unsigned long)tmp_buf);
 		tty_unregister_driver(&riscom_driver);
-		printk("rc: Couldn't register RISCom/8 callout driver, error = %d\n",
+		printk(KERN_ERR "rc: Couldn't register RISCom/8 callout "
+				"driver, error = %d\n",
 		       error);
 		return 1;
 	}
@@ -1867,6 +1866,12 @@
 __setup("riscom8=", riscom8_setup);
 #endif
 
+static char banner[] __initdata =
+	KERN_INFO "rc: SDL RISCom/8 card driver v1.1, (c) D.Gorodchanin "
+		  "1994-1996.\n";
+static char no_boards_msg[] __initdata =
+	KERN_INFO "rc: No RISCom/8 boards detected.\n";
+
 /* 
  * This routine must be called by kernel at boot time 
  */
@@ -1875,7 +1880,7 @@
 	int i;
 	int found = 0;
 
-	printk("rc: SDL RISCom/8 card driver v1.0, (c) D.Gorodchanin 1994-1996.\n");
+	printk(banner);
 
 	if (rc_init_drivers()) 
 		return -EIO;
@@ -1886,7 +1891,7 @@
 	
 	if (!found)  {
 		rc_release_drivers();
-		printk("rc: No RISCom/8 boards detected.\n");
+		printk(no_boards_msg);
 		return -EIO;
 	}
 	return 0;
diff -u --recursive --new-file v2.4.7/linux/drivers/char/sbc60xxwdt.c linux/drivers/char/sbc60xxwdt.c
--- v2.4.7/linux/drivers/char/sbc60xxwdt.c	Tue Jul  3 17:08:19 2001
+++ linux/drivers/char/sbc60xxwdt.c	Sun Aug  5 13:12:40 2001
@@ -178,7 +178,7 @@
 			char c;
 			if(get_user(c, buf+ofs))
 				return -EFAULT;
-			if(buf[ofs] == 'V')
+			if(c == 'V')
 				wdt_expect_close = 1;
 		}
 		/* Well, anyhow someone wrote to us, we should return that favour */
diff -u --recursive --new-file v2.4.7/linux/drivers/char/serial.c linux/drivers/char/serial.c
--- v2.4.7/linux/drivers/char/serial.c	Wed Jul 25 17:10:20 2001
+++ linux/drivers/char/serial.c	Sun Aug  5 13:12:41 2001
@@ -3157,6 +3157,9 @@
 	info->tty->low_latency = (info->flags & ASYNC_LOW_LATENCY) ? 1 : 0;
 #endif
 
+	/*
+	 *	This relies on lock_kernel() stuff so wants tidying for 2.5
+	 */
 	if (!tmp_buf) {
 		page = get_zeroed_page(GFP_KERNEL);
 		if (!page) {
@@ -5429,6 +5432,10 @@
 			state->io_type = SERIAL_IO_HUB6;
 		if (state->port && check_region(state->port,8))
 			continue;
+#ifdef CONFIG_MCA			
+		if ((state->flags & ASYNC_BOOT_ONLYMCA) && !MCA_bus)
+			continue;
+#endif			
 		if (state->flags & ASYNC_BOOT_AUTOCONF)
 			autoconfig(state);
 	}
diff -u --recursive --new-file v2.4.7/linux/drivers/char/synclink.c linux/drivers/char/synclink.c
--- v2.4.7/linux/drivers/char/synclink.c	Tue May  1 16:05:00 2001
+++ linux/drivers/char/synclink.c	Wed Jul 25 14:12:02 2001
@@ -1,7 +1,7 @@
 /*
  * linux/drivers/char/synclink.c
  *
- * $Id: synclink.c,v 3.8 2001/03/30 17:30:38 ez Exp $
+ * $Id: synclink.c,v 3.12 2001/07/18 19:14:21 paulkf Exp $
  *
  * Device driver for Microgate SyncLink ISA and PCI
  * high speed multiprotocol serial adapters.
@@ -879,35 +879,35 @@
 /*
  * Global linked list of SyncLink devices
  */
-struct mgsl_struct *mgsl_device_list = NULL;
-int mgsl_device_count = 0;
+struct mgsl_struct *mgsl_device_list;
+int mgsl_device_count;
 
 /*
  * Set this param to non-zero to load eax with the
  * .text section address and breakpoint on module load.
  * This is useful for use with gdb and add-symbol-file command.
  */
-int break_on_load=0;
+int break_on_load;
 
 /*
  * Driver major number, defaults to zero to get auto
  * assigned major number. May be forced as module parameter.
  */
-int ttymajor=0;
+int ttymajor;
 
-int cuamajor=0;
+int cuamajor;
 
 /*
  * Array of user specified options for ISA adapters.
  */
-static int io[MAX_ISA_DEVICES] = {0,};
-static int irq[MAX_ISA_DEVICES] = {0,};
-static int dma[MAX_ISA_DEVICES] = {0,};
-static int debug_level = 0;
-static int maxframe[MAX_TOTAL_DEVICES] = {0,};
-static int dosyncppp[MAX_TOTAL_DEVICES] = {0,};
-static int txdmabufs[MAX_TOTAL_DEVICES] = {0,};
-static int txholdbufs[MAX_TOTAL_DEVICES] = {0,};
+static int io[MAX_ISA_DEVICES];
+static int irq[MAX_ISA_DEVICES];
+static int dma[MAX_ISA_DEVICES];
+static int debug_level;
+static int maxframe[MAX_TOTAL_DEVICES];
+static int dosyncppp[MAX_TOTAL_DEVICES];
+static int txdmabufs[MAX_TOTAL_DEVICES];
+static int txholdbufs[MAX_TOTAL_DEVICES];
 	
 MODULE_PARM(break_on_load,"i");
 MODULE_PARM(ttymajor,"i");
@@ -922,7 +922,7 @@
 MODULE_PARM(txholdbufs,"1-" __MODULE_STRING(MAX_TOTAL_DEVICES) "i");
 
 static char *driver_name = "SyncLink serial driver";
-static char *driver_version = "3.8";
+static char *driver_version = "$Revision: 3.12 $";
 
 static int __init synclink_init_one (struct pci_dev *dev,
 				     const struct pci_device_id *ent);
@@ -4356,9 +4356,9 @@
 			goto errout;
 		}
 		info->shared_mem_requested = 1;
-		if (request_mem_region(info->phys_lcr_base,128,"synclink") == NULL) {
+		if (request_mem_region(info->phys_lcr_base + info->lcr_offset,128,"synclink") == NULL) {
 			printk( "%s(%d):lcr mem addr conflict device %s Addr=%08X\n",
-				__FILE__,__LINE__,info->device_name, info->phys_lcr_base);
+				__FILE__,__LINE__,info->device_name, info->phys_lcr_base + info->lcr_offset);
 			goto errout;
 		}
 		info->lcr_mem_requested = 1;
@@ -4440,7 +4440,7 @@
 		info->shared_mem_requested = 0;
 	}
 	if ( info->lcr_mem_requested ) {
-		release_mem_region(info->phys_lcr_base,128);
+		release_mem_region(info->phys_lcr_base + info->lcr_offset,128);
 		info->lcr_mem_requested = 0;
 	}
 	if (info->memory_base){
@@ -4520,7 +4520,9 @@
 	}
 
 #ifdef CONFIG_SYNCLINK_SYNCPPP
+#ifdef MODULE
 	if (info->dosyncppp)
+#endif
 		mgsl_sppp_init(info);
 #endif
 }	/* end of mgsl_add_device() */
@@ -4637,7 +4639,7 @@
 		printk("%s(%d):Couldn't register callout driver\n",
 			__FILE__,__LINE__);
 
- 	printk("%s version %s, tty major#%d callout major#%d\n",
+ 	printk("%s %s, tty major#%d callout major#%d\n",
 		driver_name, driver_version,
 		serial_driver.major, callout_driver.major);
 		
@@ -4703,7 +4705,7 @@
 
 	EXPORT_NO_SYMBOLS;
 	
- 	printk("%s version %s\n", driver_name, driver_version);
+ 	printk("%s %s\n", driver_name, driver_version);
 	
 	mgsl_enum_isa_devices();
 	pci_register_driver(&synclink_pci_driver);
@@ -4739,7 +4741,7 @@
 	struct mgsl_struct *info;
 	struct mgsl_struct *tmp;
 
-	printk("Unloading %s: version %s\n", driver_name, driver_version);
+	printk("Unloading %s: %s\n", driver_name, driver_version);
 	save_flags(flags);
 	cli();
 	if ((rc = tty_unregister_driver(&serial_driver)))
@@ -7985,6 +7987,10 @@
 	d->get_stats = mgsl_net_stats;
 	d->tx_timeout = mgsl_sppp_tx_timeout;
 	d->watchdog_timeo = 10*HZ;
+
+#if LINUX_VERSION_CODE < VERSION(2,4,4) 
+	dev_init_buffers(d);
+#endif
 
 	if (register_netdev(d) == -1) {
 		printk(KERN_WARNING "%s: register_netdev failed.\n", d->name);
diff -u --recursive --new-file v2.4.7/linux/drivers/char/sysrq.c linux/drivers/char/sysrq.c
--- v2.4.7/linux/drivers/char/sysrq.c	Fri Feb  9 11:30:22 2001
+++ linux/drivers/char/sysrq.c	Tue Aug  7 00:18:21 2001
@@ -26,7 +26,6 @@
 
 #include <asm/ptrace.h>
 
-extern void wakeup_bdflush(int);
 extern void reset_vc(unsigned int);
 extern struct list_head super_blocks;
 
@@ -99,12 +98,12 @@
 	case 's':					    /* S -- emergency sync */
 		printk("Emergency Sync\n");
 		emergency_sync_scheduled = EMERG_SYNC;
-		wakeup_bdflush(0);
+		wakeup_bdflush();
 		break;
 	case 'u':					    /* U -- emergency remount R/O */
 		printk("Emergency Remount R/O\n");
 		emergency_sync_scheduled = EMERG_REMOUNT;
-		wakeup_bdflush(0);
+		wakeup_bdflush();
 		break;
 	case 'p':					    /* P -- show PC */
 		printk("Show Regs\n");
diff -u --recursive --new-file v2.4.7/linux/drivers/ide/sis5513.c linux/drivers/ide/sis5513.c
--- v2.4.7/linux/drivers/ide/sis5513.c	Sat May 19 17:43:06 2001
+++ linux/drivers/ide/sis5513.c	Mon Aug  6 10:11:58 2001
@@ -48,7 +48,15 @@
 	{ "SiS540",	PCI_DEVICE_ID_SI_540,	SIS5513_FLAG_ATA_66, },
 	{ "SiS620",	PCI_DEVICE_ID_SI_620,	SIS5513_FLAG_ATA_66|SIS5513_FLAG_LATENCY, },
 	{ "SiS630",	PCI_DEVICE_ID_SI_630,	SIS5513_FLAG_ATA_66|SIS5513_FLAG_LATENCY, },
+	{ "SiS635",	PCI_DEVICE_ID_SI_635,	SIS5513_FLAG_ATA_66|SIS5513_FLAG_LATENCY, },
+	{ "SiS640",	PCI_DEVICE_ID_SI_640,	SIS5513_FLAG_ATA_66|SIS5513_FLAG_LATENCY, },
+	{ "SiS645",	PCI_DEVICE_ID_SI_645,	SIS5513_FLAG_ATA_66|SIS5513_FLAG_LATENCY, },
+	{ "SiS650",	PCI_DEVICE_ID_SI_650,	SIS5513_FLAG_ATA_66|SIS5513_FLAG_LATENCY, },
 	{ "SiS730",	PCI_DEVICE_ID_SI_730,	SIS5513_FLAG_ATA_66|SIS5513_FLAG_LATENCY, },
+	{ "SiS735",	PCI_DEVICE_ID_SI_735,	SIS5513_FLAG_ATA_66|SIS5513_FLAG_LATENCY, },
+	{ "SiS740",	PCI_DEVICE_ID_SI_740,	SIS5513_FLAG_ATA_66|SIS5513_FLAG_LATENCY, },
+	{ "SiS745",	PCI_DEVICE_ID_SI_745,	SIS5513_FLAG_ATA_66|SIS5513_FLAG_LATENCY, },
+	{ "SiS750",	PCI_DEVICE_ID_SI_750,	SIS5513_FLAG_ATA_66|SIS5513_FLAG_LATENCY, },
 	{ "SiS5591",	PCI_DEVICE_ID_SI_5591,	SIS5513_FLAG_ATA_33, },
 	{ "SiS5597",	PCI_DEVICE_ID_SI_5597,	SIS5513_FLAG_ATA_33, },
 	{ "SiS5600",	PCI_DEVICE_ID_SI_5600,	SIS5513_FLAG_ATA_33, },
@@ -338,7 +346,15 @@
 			case PCI_DEVICE_ID_SI_540:
 			case PCI_DEVICE_ID_SI_620:
 			case PCI_DEVICE_ID_SI_630:
+			case PCI_DEVICE_ID_SI_635:
+			case PCI_DEVICE_ID_SI_640:
+			case PCI_DEVICE_ID_SI_645:
+			case PCI_DEVICE_ID_SI_650:
 			case PCI_DEVICE_ID_SI_730:
+			case PCI_DEVICE_ID_SI_735:
+			case PCI_DEVICE_ID_SI_740:
+			case PCI_DEVICE_ID_SI_745:
+			case PCI_DEVICE_ID_SI_750:
 				unmask   = 0xF0;
 				four_two = 0x01;
 				break;
@@ -423,7 +439,15 @@
 
 	if (host_dev) {
 		switch(host_dev->device) {
+			case PCI_DEVICE_ID_SI_635:
+			case PCI_DEVICE_ID_SI_640:
+			case PCI_DEVICE_ID_SI_645:
+			case PCI_DEVICE_ID_SI_650:
 			case PCI_DEVICE_ID_SI_730:
+			case PCI_DEVICE_ID_SI_735:
+			case PCI_DEVICE_ID_SI_740:
+			case PCI_DEVICE_ID_SI_745:
+			case PCI_DEVICE_ID_SI_750:
 				ultra_100 = 1;
 			case PCI_DEVICE_ID_SI_530:
 			case PCI_DEVICE_ID_SI_540:
@@ -598,7 +622,15 @@
 			case PCI_DEVICE_ID_SI_540:
 			case PCI_DEVICE_ID_SI_620:
 			case PCI_DEVICE_ID_SI_630:
+			case PCI_DEVICE_ID_SI_635:
+			case PCI_DEVICE_ID_SI_640:
+			case PCI_DEVICE_ID_SI_645:
+			case PCI_DEVICE_ID_SI_650:
 			case PCI_DEVICE_ID_SI_730:
+			case PCI_DEVICE_ID_SI_735:
+			case PCI_DEVICE_ID_SI_740:
+			case PCI_DEVICE_ID_SI_745:
+			case PCI_DEVICE_ID_SI_750:
 				ata66 = (reg48h & mask) ? 0 : 1;
 			default:
 				break;
@@ -625,7 +657,15 @@
 			case PCI_DEVICE_ID_SI_540:
 			case PCI_DEVICE_ID_SI_620:
 			case PCI_DEVICE_ID_SI_630:
+			case PCI_DEVICE_ID_SI_635:
+			case PCI_DEVICE_ID_SI_640:
+			case PCI_DEVICE_ID_SI_645:
+			case PCI_DEVICE_ID_SI_650:
 			case PCI_DEVICE_ID_SI_730:
+			case PCI_DEVICE_ID_SI_735:
+			case PCI_DEVICE_ID_SI_740:
+			case PCI_DEVICE_ID_SI_745:
+			case PCI_DEVICE_ID_SI_750:
 			case PCI_DEVICE_ID_SI_5600:
 			case PCI_DEVICE_ID_SI_5597:
 			case PCI_DEVICE_ID_SI_5591:
diff -u --recursive --new-file v2.4.7/linux/drivers/ieee1394/hosts.c linux/drivers/ieee1394/hosts.c
--- v2.4.7/linux/drivers/ieee1394/hosts.c	Wed Jul 25 17:10:20 2001
+++ linux/drivers/ieee1394/hosts.c	Sun Jul 29 10:48:33 2001
@@ -147,10 +147,6 @@
         int count;
         struct hpsb_host *host;
 
-	/* PCI cards should register one host at a time */
-	if (tmpl->detect_hosts == NULL)
-		return;
-
         count = tmpl->detect_hosts(tmpl);
 
         for (host = tmpl->hosts; host != NULL; host = host->next) {
@@ -254,8 +250,13 @@
 int hpsb_register_lowlevel(struct hpsb_host_template *tmpl)
 {
         add_template(tmpl);
-        HPSB_DEBUG("Registered %s driver, initializing now", tmpl->name);
-        init_hosts(tmpl);
+
+	/* PCI cards should be smart and use the PCI detection layer, and
+	 * not this one shot deal. detect_hosts() will be obsoleted soon. */
+	if (tmpl->detect_hosts != NULL) {
+		HPSB_DEBUG("Registered %s driver, initializing now", tmpl->name);
+		init_hosts(tmpl);
+	}
 
         return 0;
 }
diff -u --recursive --new-file v2.4.7/linux/drivers/ieee1394/ieee1394_core.c linux/drivers/ieee1394/ieee1394_core.c
--- v2.4.7/linux/drivers/ieee1394/ieee1394_core.c	Wed Jul 25 17:10:20 2001
+++ linux/drivers/ieee1394/ieee1394_core.c	Sun Aug  5 13:12:40 2001
@@ -293,12 +293,13 @@
 void hpsb_selfid_received(struct hpsb_host *host, quadlet_t sid)
 {
         if (host->in_bus_reset) {
-                HPSB_DEBUG("Including SelfID 0x%x", sid);
+#ifdef CONFIG_IEEE1394_VERBOSEDEBUG
+                HPSB_INFO("Including SelfID 0x%x", sid);
+#endif
                 host->topology_map[host->selfid_count++] = sid;
         } else {
-                /* FIXME - info on which host */
-                HPSB_NOTICE("Spurious SelfID packet (0x%08x) received from %s",
-			    sid, host->template->name);
+                HPSB_NOTICE("Spurious SelfID packet (0x%08x) received from bus %d",
+			    sid, (host->node_id & BUS_MASK) >> 6);
         }
 }
 
@@ -352,7 +353,7 @@
         }
 
         if (ackcode != ACK_PENDING || !packet->expect_response) {
-                packet->state = complete;
+                packet->state = completed;
                 up(&packet->state_change);
                 up(&packet->state_change);
                 run_task_queue(&packet->complete_tq);
@@ -505,7 +506,7 @@
                 break;
         }
 
-        packet->state = complete;
+        packet->state = completed;
         up(&packet->state_change);
         run_task_queue(&packet->complete_tq);
 }
@@ -725,7 +726,7 @@
         while (lh != &llist) {
                 packet = list_entry(lh, struct hpsb_packet, list);
                 lh = lh->next;
-                packet->state = complete;
+                packet->state = completed;
                 packet->ack_code = ACKX_ABORTED;
                 up(&packet->state_change);
                 run_task_queue(&packet->complete_tq);
@@ -770,7 +771,7 @@
         while (lh != &expiredlist) {
                 packet = list_entry(lh, struct hpsb_packet, list);
                 lh = lh->next;
-                packet->state = complete;
+                packet->state = completed;
                 packet->ack_code = ACKX_TIMEOUT;
                 up(&packet->state_change);
                 run_task_queue(&packet->complete_tq);
diff -u --recursive --new-file v2.4.7/linux/drivers/ieee1394/ieee1394_core.h linux/drivers/ieee1394/ieee1394_core.h
--- v2.4.7/linux/drivers/ieee1394/ieee1394_core.h	Wed Jul 25 17:10:20 2001
+++ linux/drivers/ieee1394/ieee1394_core.h	Sun Aug  5 13:12:40 2001
@@ -24,11 +24,11 @@
         /* Okay, this is core internal and a no care for hosts.
          * queued   = queued for sending
          * pending  = sent, waiting for response
-         * complete = processing completed, successful or not
+         * completed = processing completed, successful or not
          * incoming = incoming packet
          */
         enum { 
-                unused, queued, pending, complete, incoming 
+                unused, queued, pending, completed, incoming 
         } __attribute__((packed)) state;
 
         /* These are core internal. */
diff -u --recursive --new-file v2.4.7/linux/drivers/ieee1394/ieee1394_syms.c linux/drivers/ieee1394/ieee1394_syms.c
--- v2.4.7/linux/drivers/ieee1394/ieee1394_syms.c	Wed Jul 25 17:10:20 2001
+++ linux/drivers/ieee1394/ieee1394_syms.c	Sun Jul 29 10:48:33 2001
@@ -76,5 +76,5 @@
 EXPORT_SYMBOL(highlevel_host_reset);
 EXPORT_SYMBOL(highlevel_add_one_host);
 EXPORT_SYMBOL(hpsb_guid_get_handle);
-EXPORT_SYMBOL(hpsb_get_host_by_ge);
+EXPORT_SYMBOL(hpsb_get_host_by_ne);
 EXPORT_SYMBOL(hpsb_guid_fill_packet);
diff -u --recursive --new-file v2.4.7/linux/drivers/ieee1394/nodemgr.c linux/drivers/ieee1394/nodemgr.c
--- v2.4.7/linux/drivers/ieee1394/nodemgr.c	Wed Jul 25 17:10:20 2001
+++ linux/drivers/ieee1394/nodemgr.c	Sun Jul 29 10:48:33 2001
@@ -39,18 +39,31 @@
  * XXX: Most of this isn't done yet :)  */
 
 
-static atomic_t outstanding_requests;
-
 static LIST_HEAD(node_list);
 rwlock_t node_lock = RW_LOCK_UNLOCKED;
 
 static LIST_HEAD(host_info_list);
 spinlock_t host_info_lock = SPIN_LOCK_UNLOCKED;
 
+struct bus_options {
+	u8	irmc;		/* Iso Resource Manager Capable */
+	u8	cmc;		/* Cycle Master Capable */
+	u8	isc;		/* Iso Capable */
+	u8	bmc;		/* Bus Master Capable */
+	u8	pmc;		/* Power Manager Capable (PNP spec) */
+	u8	cyc_clk_acc;	/* Cycle clock accuracy */
+	u8	generation;	/* Incremented when configrom changes */
+	u8	lnkspd;		/* Link speed */
+	u16	max_rec;	/* Maximum packet size node can receive */
+	atomic_t changed;	/* We set this to 1 if generation has changed */
+};
+
 struct host_info {
 	struct hpsb_host *host;
-	int pid;
-	wait_queue_head_t reset_wait;
+	pid_t pid;			/* PID of the nodemgr thread */
+	pid_t ppid;			/* Parent PID for the thread */
+	struct tq_struct task;		/* Used to kickstart the thread */
+	wait_queue_head_t reset_wait;	/* Wait queue awoken on bus reset */
 	struct list_head list;
 };
 
@@ -62,70 +75,126 @@
 
         struct hpsb_host *host;
         nodeid_t node_id;
-        
+
+	struct bus_options busopt;
+
         atomic_t generation;
 };
 
 static struct node_entry *create_node_entry(void)
 {
-        struct node_entry *ge;
+        struct node_entry *ne;
         unsigned long flags;
 
-        ge = kmalloc(sizeof(struct node_entry), SLAB_ATOMIC);
-        if (!ge) return NULL;
+        ne = kmalloc(sizeof(struct node_entry), SLAB_ATOMIC);
+        if (!ne) return NULL;
 
-        INIT_LIST_HEAD(&ge->list);
-        atomic_set(&ge->refcount, 0);
-        ge->guid = (u64) -1;
-        ge->host = NULL;
-        ge->node_id = 0;
-        atomic_set(&ge->generation, -1);
+        INIT_LIST_HEAD(&ne->list);
+        atomic_set(&ne->refcount, 0);
+        ne->guid = (u64) -1;
+        ne->host = NULL;
+        ne->node_id = 0;
+        atomic_set(&ne->generation, -1);
+	atomic_set(&ne->busopt.changed, 0);
 
         write_lock_irqsave(&node_lock, flags);
-        list_add_tail(&ge->list, &node_list);
+        list_add_tail(&ne->list, &node_list);
         write_unlock_irqrestore(&node_lock, flags);
 
-        return ge;
+        return ne;
 }
 
 static struct node_entry *find_entry(u64 guid)
 {
         struct list_head *lh;
-        struct node_entry *ge;
+        struct node_entry *ne;
         
         lh = node_list.next;
         while (lh != &node_list) {
-                ge = list_entry(lh, struct node_entry, list);
-                if (ge->guid == guid) return ge;
+                ne = list_entry(lh, struct node_entry, list);
+                if (ne->guid == guid) return ne;
                 lh = lh->next;
         }
 
         return NULL;
 }
 
-static void associate_guid(struct hpsb_host *host, nodeid_t nodeid, u64 guid)
+static int register_guid(struct hpsb_host *host, nodeid_t nodeid, u64 guid,
+			  quadlet_t busoptions)
 {
-        struct node_entry *ge;
-        unsigned long flags;
-
-        HPSB_DEBUG("Node %d on %s host: GUID %02x:%02x:%02x:%02x:%02x:%02x:%02x:%02x",
-                   nodeid & NODE_MASK, host->template->name, ((u8 *)&guid)[0],
-		   ((u8 *)&guid)[1], ((u8 *)&guid)[2], ((u8 *)&guid)[3],
-		   ((u8 *)&guid)[4], ((u8 *)&guid)[5], ((u8 *)&guid)[6],
-		   ((u8 *)&guid)[7]);
+        struct node_entry *ne;
+        unsigned long flags, new = 0;
 
         read_lock_irqsave(&node_lock, flags);
-        ge = find_entry(guid);
+        ne = find_entry(guid);
         read_unlock_irqrestore(&node_lock, flags);
 
-        if (!ge) ge = create_node_entry();
-        if (!ge) return;
+	/* New entry */
+	if (!ne) {
+		if ((ne = create_node_entry()) == NULL)
+			return -1;
+
+		HPSB_DEBUG("%s added: node %d, bus %d: GUID %02x:%02x:%02x:%02x:%02x:%02x:%02x:%02x",
+			   (host->node_id == nodeid) ? "Local host" : "Device",
+			   nodeid & NODE_MASK, (nodeid & BUS_MASK) >> 6, ((u8 *)&guid)[0],
+			   ((u8 *)&guid)[1], ((u8 *)&guid)[2], ((u8 *)&guid)[3],
+			   ((u8 *)&guid)[4], ((u8 *)&guid)[5], ((u8 *)&guid)[6],
+			   ((u8 *)&guid)[7]);
+
+		ne->guid = guid;
+		new = 1;
+	}
+
+	if (!new && ne->node_id != nodeid)
+		HPSB_DEBUG("Node %d changed to %d on bus %d",
+			   ne->node_id & NODE_MASK, nodeid & NODE_MASK, (nodeid & BUS_MASK) >> 6);
+
+	ne->host = host;
+        ne->node_id = nodeid;
+
+        atomic_set(&ne->generation, get_hpsb_generation());
+
+	/* Now set the bus options. Only do all this crap if this is a new
+	 * node, or if the generation number has changed.  */
+	if (new || ne->busopt.generation != ((busoptions >> 6) & 0x3)) {
+		ne->busopt.irmc		= (busoptions >> 31) & 1;
+		ne->busopt.cmc		= (busoptions >> 30) & 1;
+		ne->busopt.isc		= (busoptions >> 29) & 1;
+		ne->busopt.bmc		= (busoptions >> 28) & 1;
+		ne->busopt.pmc		= (busoptions >> 27) & 1;
+		ne->busopt.cyc_clk_acc	= (busoptions >> 16) & 0xff;
+		ne->busopt.max_rec	= 1 << (((busoptions >> 12) & 0xf) + 1);
+		ne->busopt.generation	= (busoptions >> 6) & 0x3;
+		ne->busopt.lnkspd	= busoptions & 0x7;
+
+		new = 1; /* To make sure we probe the rest of the ConfigROM too */
+	}
 
-        ge->host = host;
-        ge->node_id = nodeid;
-        ge->guid = guid;
+#ifdef CONFIG_IEEE1394_VERBOSEDEBUG
+	HPSB_DEBUG("raw=0x%08x irmc=%d cmc=%d isc=%d bmc=%d pmc=%d cyc_clk_acc=%d "
+		   "max_rec=%d gen=%d lspd=%d\n", busoptions,
+		   ne->busopt.irmc, ne->busopt.cmc, ne->busopt.isc, ne->busopt.bmc,
+		   ne->busopt.pmc, ne->busopt.cyc_clk_acc, ne->busopt.max_rec,
+		   ne->busopt.generation, ne->busopt.lnkspd);
+#endif
+
+	return new;
+}
+
+static void nodemgr_remove_node(struct node_entry *ne)
+{
+	HPSB_DEBUG("Device removed: node %d, bus %d: GUID "
+		   "%02x:%02x:%02x:%02x:%02x:%02x:%02x:%02x",
+		   ne->node_id & NODE_MASK, (ne->node_id & BUS_MASK) >> 6,
+		   ((u8 *)&ne->guid)[0], ((u8 *)&ne->guid)[1],
+		   ((u8 *)&ne->guid)[2], ((u8 *)&ne->guid)[3],
+		   ((u8 *)&ne->guid)[4], ((u8 *)&ne->guid)[5],
+		   ((u8 *)&ne->guid)[6], ((u8 *)&ne->guid)[7]);
 
-        atomic_set(&ge->generation, get_hpsb_generation());
+	list_del(&ne->list);
+	kfree(ne);
+
+	return;
 }
 
 /* This is where we probe the nodes for their information and provided
@@ -133,94 +202,150 @@
 static void nodemgr_node_probe(struct hpsb_host *host)
 {
         struct selfid *sid = (struct selfid *)host->topology_map;
+	struct list_head *lh;
+	struct node_entry *ne;
         int nodecount = host->node_count;
         nodeid_t nodeid = LOCAL_BUS;
 	quadlet_t buffer[5], quad;
 	octlet_t base = CSR_REGISTER_BASE + CSR_CONFIG_ROM;
-	int retval;
+	int flags;
 
 	/* We need to detect when the ConfigROM's generation has changed,
 	 * so we only update the node's info when it needs to be.  */
         for (; nodecount; nodecount--, nodeid++, sid++) {
-		int header_count = 0;
-		unsigned header_size = 0;
+		int retries = 3;
+		int header_count;
+		unsigned header_size;
+		octlet_t guid;
+
+		/* Skip extended, and non-active node's */
                 while (sid->extended)
 			sid++;
                 if (!sid->link_active)
 			continue;
-		if (nodeid == host->node_id)
+
+		/* Just use our local ROM */
+		if (nodeid == host->node_id) {
+			int i;
+			for (i = 0; i < 5; i++)
+				buffer[i] = be32_to_cpu(host->csr.rom[i]);
+			goto set_options;
+		}
+
+retry_configrom:
+		
+		if (!retries--) {
+			HPSB_ERR("Giving up on node %d for ConfigROM probe, too many errors",
+				 nodeid & NODE_MASK);
 			continue;
+		}
 
-		HPSB_DEBUG("Initiating ConfigROM request for node %d", nodeid & NODE_MASK);
+		header_count = 0;
+		header_size = 0;
 
-		retval = hpsb_read(host, nodeid, base, &quad, 4);
-		buffer[header_count++] = be32_to_cpu(quad);
+#ifdef CONFIG_IEEE1394_VERBOSEDEBUG
+		HPSB_INFO("Initiating ConfigROM request for node %d", nodeid & NODE_MASK);
+#endif
+
+		/* Now, P1212 says that devices should support 64byte block
+		 * reads, aligned on 64byte boundaries. That doesn't seem
+		 * to work though, and we are forced to doing quadlet
+		 * sized reads.  */
 
-		if (retval) {
-			HPSB_ERR("ConfigROM quadlet transaction error for %d",
+		if (hpsb_read(host, nodeid, base, &quad, 4)) {
+			HPSB_ERR("ConfigROM quadlet transaction error for node %d",
 				 nodeid & NODE_MASK);
-			continue;
+			goto retry_configrom;
 		}
+		buffer[header_count++] = be32_to_cpu(quad);
 
 		header_size = buffer[0] >> 24;
 
 		if (header_size < 4) {
-			HPSB_INFO("Node %d on %s host has non-standard ROM format (%d quads), "
-				  "cannot parse", nodeid & NODE_MASK, host->template->name,
+			HPSB_INFO("Node %d on bus %d has non-standard ROM format (%d quads), "
+				  "cannot parse", nodeid & NODE_MASK, (nodeid & BUS_MASK) >> 6,
 				  header_size);
 			continue;
 		}
 
 		while (header_count <= header_size && (header_count<<2) < sizeof(buffer)) {
-			retval = hpsb_read(host, nodeid, base + (header_count<<2), &quad, 4);
-			buffer[header_count++] = be32_to_cpu(quad);
-
-			if (retval) {
+			if (hpsb_read(host, nodeid, base + (header_count<<2), &quad, 4)) {
 				HPSB_ERR("ConfigROM quadlet transaction error for %d",
 					 nodeid & NODE_MASK);
-				goto failed_read;
+				goto retry_configrom;
 			}
-
+			buffer[header_count++] = be32_to_cpu(quad);
+		}
+set_options:
+		guid = be64_to_cpu(((u64)buffer[3] << 32) | buffer[4]);
+		switch (register_guid(host, nodeid, guid, buffer[2])) {
+			case -1:
+				HPSB_ERR("Failed to register node in ConfigROM probe");
+				continue;
+			case 1:
+				/* Need to probe the rest of the ConfigROM
+				 * here.  */
+				break;
+			default:
+				/* Nothing to do, this is an old unchanged
+				 * node.  */
+				break;
 		}
-
-		associate_guid(host, nodeid, be64_to_cpu(((u64)buffer[3] << 32) | buffer[4]));
-failed_read:
-		continue;
         }
 
-	/* Need to detect when nodes are no longer associated with
-	 * anything. I believe we can do this using the generation of the
-	 * entries after a reset, compared the the hosts generation.  */
+	/* Now check to see if we have any nodes that aren't referenced
+	 * any longer.  */
+        write_lock_irqsave(&node_lock, flags);
+	lh = node_list.next;
+	while (lh != &node_list) {
+		ne = list_entry(lh, struct node_entry, list);
+
+		/* Only checking this host */
+		if (ne->host != host)
+			continue;
+
+		/* If the generation didn't get updated, then either the
+		 * node was removed, or it failed the above probe. Either
+		 * way, we remove references to it, since they are
+		 * invalid.  */
+		if (atomic_read(&ne->generation) != get_hpsb_generation())
+			nodemgr_remove_node(ne);
+
+		lh = lh->next;
+	}
+	write_unlock_irqrestore(&node_lock, flags);
+
+	return;
 }
 
 
 struct node_entry *hpsb_guid_get_handle(u64 guid)
 {
         unsigned long flags;
-        struct node_entry *ge;
+        struct node_entry *ne;
 
         read_lock_irqsave(&node_lock, flags);
-        ge = find_entry(guid);
-        if (ge) atomic_inc(&ge->refcount);
+        ne = find_entry(guid);
+        if (ne) atomic_inc(&ne->refcount);
         read_unlock_irqrestore(&node_lock, flags);
 
-        return ge;
+        return ne;
 }
 
-struct hpsb_host *hpsb_get_host_by_ge(struct node_entry *ge)
+struct hpsb_host *hpsb_get_host_by_ne(struct node_entry *ne)
 {
-        if (atomic_read(&ge->generation) != get_hpsb_generation()) return NULL;
-        if (ge->node_id == ge->host->node_id) return ge->host;
+        if (atomic_read(&ne->generation) != get_hpsb_generation()) return NULL;
+        if (ne->node_id == ne->host->node_id) return ne->host;
         return NULL;
 }
 
-int hpsb_guid_fill_packet(struct node_entry *ge, struct hpsb_packet *pkt)
+int hpsb_guid_fill_packet(struct node_entry *ne, struct hpsb_packet *pkt)
 {
-        if (atomic_read(&ge->generation) != get_hpsb_generation()) return 0;
+        if (atomic_read(&ne->generation) != get_hpsb_generation()) return 0;
 
-        pkt->host = ge->host;
-        pkt->node_id = ge->node_id;
-        pkt->generation = atomic_read(&ge->generation);
+        pkt->host = ne->host;
+        pkt->node_id = ne->node_id;
+        pkt->generation = atomic_read(&ne->generation);
         return 1;
 }
 
@@ -229,33 +354,38 @@
 	struct host_info *hi = (struct host_info *)__hi;
 	struct hpsb_host *host = hi->host;
 
-	/* Standard thread setup */
+
 	lock_kernel();
-	daemonize();
-	strcpy(current->comm, "NodeMngr");
-	unlock_kernel();
 
-	for (;;) {
-		if (signal_pending(current))
-			break;
+	siginitsetinv(&current->blocked, sigmask(SIGKILL)|sigmask(SIGINT)|sigmask(SIGTERM));
 
-		/* Let's take a short pause to make sure all the devices
-		 * have time to settle.  */
+	strcpy(current->comm, "NodeMngr");
 
+	unlock_kernel();
+
+	do {
 		current->state = TASK_INTERRUPTIBLE;
 		schedule_timeout(HZ/50);
 
-		if (hi && host)
+		if (hi && host) {
 			nodemgr_node_probe(host);
-
-		/* Wait for the next bus reset */
-		if (hi && host)
 			interruptible_sleep_on(&hi->reset_wait);
-	}
+		} else
+			break;
+
+	} while (!signal_pending(current) && hi);
 
 	return(0);
 }
 
+static void nodemgr_schedule_thread (void *__hi)
+{
+	struct host_info *hi = (struct host_info *)__hi;
+
+	hi->ppid = current->pid;
+	hi->pid = kernel_thread(nodemgr_reset_handler, hi, 0);
+}
+
 static void nodemgr_add_host(struct hpsb_host *host)
 {
 	struct host_info *hi = kmalloc (sizeof (struct host_info), GFP_KERNEL);
@@ -266,10 +396,14 @@
 		return;
 	}
 
+	/* We simply initialize the struct here. We don't start the thread
+	 * until the first bus reset.  */
 	hi->host = host;
 	INIT_LIST_HEAD(&hi->list);
 	hi->pid = -1;
+	hi->ppid = -1;
 	init_waitqueue_head(&hi->reset_wait);
+	INIT_TQUEUE(&hi->task, nodemgr_schedule_thread, hi);
 
 	spin_lock_irqsave (&host_info_lock, flags);
 	list_add_tail (&hi->list, &host_info_list);
@@ -278,14 +412,6 @@
 	return;
 }
 
-static void nodemgr_schedule_thread (void *__hi)
-{
-	struct host_info *hi = (struct host_info *)__hi;
-
-	hi->pid = kernel_thread(nodemgr_reset_handler, hi,
-				CLONE_FS|CLONE_FILES|CLONE_SIGHAND);
-}
-
 static void nodemgr_host_reset(struct hpsb_host *host)
 {
 	struct list_head *lh;
@@ -311,18 +437,7 @@
 	if (hi->pid >= 0) {
 		wake_up(&hi->reset_wait);
 	} else {
-		if (in_interrupt()) {
-			static struct tq_struct task;
-			memset(&task, 0, sizeof(struct tq_struct));
-
-			task.routine = nodemgr_schedule_thread;
-			task.data = (void*)hi;
-
-			if (schedule_task(&task) < 0)
-				HPSB_ERR ("Failed to schedule Node Manager thread!\n");
-		} else {
-			nodemgr_schedule_thread(hi);
-		}
+		schedule_task(&hi->task);
 	}
 
 done_reset_host:
@@ -335,8 +450,24 @@
 {
 	struct list_head *lh;
 	struct host_info *hi = NULL;
+	struct node_entry *ne;
 	int flags;
 
+	/* First remove all node entries for this host */
+	write_lock_irqsave(&node_lock, flags);
+	lh = node_list.next;
+	while (lh != &node_list) {
+		ne = list_entry(lh, struct node_entry, list);
+
+		/* Only checking this host */
+		if (ne->host != host)
+			continue;
+
+		nodemgr_remove_node(ne);
+		lh = lh->next;
+	}
+	write_unlock_irqrestore(&node_lock, flags);
+
 	spin_lock_irqsave (&host_info_lock, flags);
 	lh = host_info_list.next;
 	while (lh != &host_info_list) {
@@ -349,15 +480,24 @@
 	}
 
 	if (hi == NULL) {
-		HPSB_ERR ("Could not remove non-exitent host in Node Manager");
+		HPSB_ERR ("Could not remove non-existent host in Node Manager");
 		goto done_remove_host;
 	}
 
-	if (hi->pid >= 0)
-		kill_proc(hi->pid, SIGINT, 1);
+	mb();
 
-	current->state = TASK_INTERRUPTIBLE;
-	schedule_timeout(HZ*2);   /* 2 second delay */
+	if (hi->pid >= 0) {
+		/* Kill the proc */
+		kill_proc(hi->pid, SIGKILL, 1);
+
+		/* XXX: We need a better way... */
+		current->state = TASK_INTERRUPTIBLE;
+		schedule_timeout(HZ/20);
+
+		/* Now tell the parent to sluff off the zombied body */
+		mb();
+		kill_proc(hi->ppid, SIGCHLD, 1);
+	}
 
 	kfree (hi);
 
@@ -377,8 +517,6 @@
 
 void init_ieee1394_nodemgr(void)
 {
-        atomic_set(&outstanding_requests, 0);
-
         hl = hpsb_register_highlevel("Node manager", &guid_ops);
         if (!hl) {
                 HPSB_ERR("Out of memory during ieee1394 initialization");
diff -u --recursive --new-file v2.4.7/linux/drivers/ieee1394/nodemgr.h linux/drivers/ieee1394/nodemgr.h
--- v2.4.7/linux/drivers/ieee1394/nodemgr.h	Wed Jul 25 17:10:20 2001
+++ linux/drivers/ieee1394/nodemgr.h	Sun Jul 29 10:48:33 2001
@@ -50,7 +50,7 @@
  * Note that the local GUID currently isn't collected, so this will always
  * return NULL.
  */
-struct hpsb_host *hpsb_get_host_by_ge(hpsb_guid_t handle);
+struct hpsb_host *hpsb_get_host_by_ne(hpsb_guid_t handle);
 
 /*
  * This will fill in the given, pre-initialised hpsb_packet with the current
diff -u --recursive --new-file v2.4.7/linux/drivers/ieee1394/ohci1394.c linux/drivers/ieee1394/ohci1394.c
--- v2.4.7/linux/drivers/ieee1394/ohci1394.c	Wed Jul 25 17:10:20 2001
+++ linux/drivers/ieee1394/ohci1394.c	Sun Jul 29 10:48:33 2001
@@ -36,14 +36,8 @@
  * . Async Stream Packets
  * . DMA error recovery
  *
- * Things to be fixed:
- * . Latency problems on UltraSPARC
- *
  * Known bugs:
- * . SelfID are sometimes not received properly 
- *   if card is initialized with no other nodes 
- *   on the bus
- * . Apple PowerBook detected but not working yet
+ * . Apple PowerBook detected but not working yet (still true?)
  */
 
 /* 
@@ -277,10 +271,7 @@
 	size_t size;
 	quadlet_t q0, q1;
 
-	/* SelfID handling seems much easier than for the aic5800 chip.
-	   All the self-id packets, including this devices own self-id,
-	   should be correctly arranged in the selfid buffer at this
-	   stage */
+	mdelay(10);
 
 	/* Check status of self-id reception */
 
@@ -320,7 +311,7 @@
 		}
 		
 		if (q0 == ~q1) {
-			PRINT(KERN_DEBUG, ohci->id, "SelfID packet 0x%x received", q0);
+			DBGMSG (ohci->id, "SelfID packet 0x%x received", q0);
 			hpsb_selfid_received(host, cpu_to_be32(q0));
 			if (((q0 & 0x3f000000) >> 24) == phyid)
 				DBGMSG (ohci->id, "SelfID for this node is 0x%08x", q0);
@@ -332,7 +323,7 @@
 		size -= 2;
 	}
 
-	PRINT(KERN_DEBUG, ohci->id, "SelfID complete");
+	DBGMSG(ohci->id, "SelfID complete");
 
 	hpsb_selfid_complete(host, phyid, isroot);
 	return 0;
@@ -346,10 +337,10 @@
 	for (i = 0; i < OHCI_LOOP_COUNT; i++) {
 		if (reg_read(ohci, OHCI1394_HCControlSet) & 0x00010000)
 			break;
-		mdelay(10);
+		mdelay(1);
 	}
 
-	PRINT(KERN_DEBUG, ohci->id, "Soft reset finished");
+	DBGMSG (ohci->id, "Soft reset finished");
 
 	return 0;
 }
@@ -458,41 +449,32 @@
 	return ctx;
 }
 
+static void ohci_init_config_rom(struct ti_ohci *ohci);
+
 /* Global initialization */
 static int ohci_initialize(struct hpsb_host *host)
 {
 	struct ti_ohci *ohci=host->hostdata;
 	int retval, i;
+	quadlet_t buf;
 
 	spin_lock_init(&ohci->phy_reg_lock);
 	spin_lock_init(&ohci->event_lock);
   
-	/*
-	 * Tip by James Goodwin <jamesg@Filanet.com>:
-	 * We need to add delays after the soft reset, setting LPS, and
-	 * enabling our link. This might fixes the self-id reception 
-	 * problem at initialization.
-	 */ 
-
 	/* Soft reset */
 	if ((retval = ohci_soft_reset(ohci)) < 0)
 		return retval;
 
-	/* 
-	 * Delay after soft reset to make sure everything has settled
-	 * down (sanity)
-	 */
-	mdelay(10);    
-  
+	/* Put some defaults to these undefined bus options */
+	buf = reg_read(ohci, OHCI1394_BusOptions);
+	buf |=  0x60000000; /* Enable CMC and ISC */
+	buf &= ~0x00ff0000; /* XXX: Set cyc_clk_acc to zero for now */
+	buf &= ~0x98000000; /* Disable PMC, IRMC and BMC */
+	reg_write(ohci, OHCI1394_BusOptions, buf);
+
 	/* Set Link Power Status (LPS) */
 	reg_write(ohci, OHCI1394_HCControlSet, 0x00080000);
 
-	/*
-	 * Delay after setting LPS in order to make sure link/phy
-	 * communication is established
-	 */
-	mdelay(10);   
-
 	/* Set the bus number */
 	reg_write(ohci, OHCI1394_NodeID, 0x0000ffc0);
 
@@ -515,13 +497,15 @@
 	/* enable self-id dma */
 	reg_write(ohci, OHCI1394_LinkControlSet, 0x00000200);
 
-	/* Set the configuration ROM mapping register */
+	/* Set the Config ROM mapping register */
 	reg_write(ohci, OHCI1394_ConfigROMmap, ohci->csr_config_rom_bus);
 
+	/* Initialize the Config ROM */
+	ohci_init_config_rom(ohci);
+
+	/* Now get our max packet size */
 	ohci->max_packet_size = 
 		1<<(((reg_read(ohci, OHCI1394_BusOptions)>>12)&0xf)+1);
-	PRINT(KERN_DEBUG, ohci->id, "Max packet size = %d bytes",
-	       ohci->max_packet_size);
 
 	/* Don't accept phy packets into AR request context */ 
 	reg_write(ohci, OHCI1394_LinkControlClear, 0x00000400);
@@ -622,6 +606,14 @@
 	/* Enable link */
 	reg_write(ohci, OHCI1394_HCControlSet, 0x00020000);
 
+	buf = reg_read(ohci, OHCI1394_Version);
+	PRINT(KERN_INFO, ohci->id, "OHCI-1394 %d.%d (PCI): IRQ=[%d]  MMIO=[%lx-%lx]"
+	      "  Max Packet=[%d]", ((((buf) >> 16) & 0xf) + (((buf) >> 20) & 0xf) * 10),
+	      ((((buf) >> 4) & 0xf) + ((buf) & 0xf) * 10), ohci->dev->irq,
+	      pci_resource_start(ohci->dev, 0),
+	      pci_resource_start(ohci->dev, 0) + pci_resource_len(ohci->dev, 0),
+	      ohci->max_packet_size);
+
 	return 1;
 }
 
@@ -884,7 +876,7 @@
 
 	switch (cmd) {
 	case RESET_BUS:
-		PRINT (KERN_DEBUG, ohci->id, "Resetting bus on request%s",
+		DBGMSG(ohci->id, "Bus reset requested%s",
 		       ((host->attempt_root || attempt_root) ? 
 		       " and attempting to become root" : ""));
 		set_phy_reg_mask (ohci, 1, 0x40 | ((host->attempt_root || attempt_root) ?
@@ -1076,10 +1068,13 @@
 	struct hpsb_host *host = ohci->host;
 	int phyid = -1, isroot = 0, flags;
 
-	/* Read the interrupt event register */
+	/* Read the interrupt event register. We don't clear the bus reset
+	 * here. We wait till we get a selfid complete interrupt and clear
+	 * it then, and _only_ then.  */
 	spin_lock_irqsave(&ohci->event_lock, flags);
 	event = reg_read(ohci, OHCI1394_IntEventClear);
-	reg_write(ohci, OHCI1394_IntEventClear, event);
+	reg_write(ohci, OHCI1394_IntEventClear,
+		  event & ~(OHCI1394_selfIDComplete|OHCI1394_busReset));
 	spin_unlock_irqrestore(&ohci->event_lock, flags);
 
 	if (!event) return;
@@ -1093,15 +1088,12 @@
 		return;
 	}
 
-	/* Someone wants a bus reset. Better watch what you wish for...
-	 *
-	 * XXX: Read 6.1.1 of the OHCI1394 spec. We need to take special
-	 * care with the BusReset Interrupt, before and until the SelfID
-	 * phase is over. This is why the SelfID phase sometimes fails for
-	 * this driver.  */
+	/* Someone wants a bus reset. Better watch what you wish for... */
 	if (event & OHCI1394_busReset) {
 		if (!host->in_bus_reset) {
-			PRINT(KERN_DEBUG, ohci->id, "Bus reset requested");
+			DBGMSG(ohci->id, "Bus reset requested%s",
+			      ((host->attempt_root || attempt_root) ?
+			      " and attempting to become root" : ""));
 			
 			/* Wait for the AT fifo to be flushed */
 			dma_trm_reset(ohci->at_req_context);
@@ -1112,7 +1104,8 @@
 			
 			ohci->NumBusResets++;
 		}
-		event &= ~OHCI1394_busReset;
+		/* Mask out everything except selfid */
+		event &= OHCI1394_selfIDComplete;
 	}
 
 	/* XXX: We need a way to also queue the OHCI1394_reqTxComplete,
@@ -1219,7 +1212,7 @@
 				phyid =  node_id & 0x0000003f;
 				isroot = (node_id & 0x40000000) != 0;
 
-				PRINT(KERN_DEBUG, ohci->id,
+				DBGMSG(ohci->id,
 				      "SelfID interrupt received "
 				      "(phyid %d, %s)", phyid, 
 				      (isroot ? "root" : "not root"));
@@ -1249,6 +1242,12 @@
 		} else
 			PRINT(KERN_ERR, ohci->id, 
 			      "SelfID received outside of bus reset sequence");
+
+		/* Clear everything, it's a new day */
+		spin_lock_irqsave(&ohci->event_lock, flags);
+		reg_write(ohci, OHCI1394_IntEventClear, 0xffffffff);
+		spin_unlock_irqrestore(&ohci->event_lock, flags);
+
 		event &= ~OHCI1394_selfIDComplete;
 	}
 	if (event & OHCI1394_phyRegRcvd) {
@@ -1260,6 +1259,9 @@
 			      "Physical register received outside of bus reset sequence");
 		event &= ~OHCI1394_phyRegRcvd;
 	}
+
+	/* Make sure we handle everything, just in case we accidentally
+	 * enabled an interrupt that we didn't write a handler for.  */
 	if (event)
 		PRINT(KERN_ERR, ohci->id, "Unhandled interrupt(s) 0x%08x\n",
 		      event);
@@ -1374,7 +1376,7 @@
 				spin_unlock_irqrestore(&d->lock, flags);
 				return;
 			}
-#if 0
+
 			if (le32_to_cpu(d->prg_cpu[(idx+1)%d->num_desc]->status)
 			    == d->buf_size) {
 				/* Other part of packet not written yet.
@@ -1387,7 +1389,7 @@
 				spin_unlock_irqrestore(&d->lock, flags);
 				return;
 			}
-#endif
+
 			split_left = length;
 			split_ptr = (char *)d->spb;
 			memcpy(split_ptr,buf_ptr,d->buf_size-offset);
@@ -1448,7 +1450,7 @@
 			hpsb_packet_received(ohci->host, d->spb, 
 					     length-4, ack);
 		}
-#if OHCI1394_DEBUG
+#ifdef OHCI1394_DEBUG
 		else
 			PRINT (KERN_DEBUG, ohci->id, "Got phy packet ctx=%d ... discarded",
 			       d->ctx);
@@ -1837,41 +1839,47 @@
 
 #define cf_put_keyval(cr, key, val) (((cr)->data++)[0] = cpu_to_be32((key) << 24) | (val))
 
-#define cf_put_crc16(cr, unit) \
-	(*(cr)->unitdir[unit].start = cpu_to_be32(((cr)->unitdir[unit].length << 16) | \
-	 ohci_crc16((cr)->unitdir[unit].start + 1, (cr)->unitdir[unit].length)))
-
-#define cf_unit_begin(cr, unit)					\
-do {								\
-	if ((cr)->unitdir[unit].refer != NULL) {		\
-		*(cr)->unitdir[unit].refer |=			\
-			(cr)->data - (cr)->unitdir[unit].refer;	\
-		cf_put_crc16(cr, (cr)->unitdir[unit].refunit);	\
-        }							\
-        (cr)->unitnum = (unit);					\
-        (cr)->unitdir[unit].start = (cr)->data++;		\
-} while (0)
+static inline void cf_put_crc16(struct config_rom_ptr *cr, int unit)
+{
+	*cr->unitdir[unit].start =
+		cpu_to_be32((cr->unitdir[unit].length << 16) |
+			    ohci_crc16(cr->unitdir[unit].start + 1,
+				       cr->unitdir[unit].length));
+}
 
-#define cf_put_refer(cr, key, unit)			\
-do {							\
-	(cr)->unitdir[unit].refer = (cr)->data;		\
-	(cr)->unitdir[unit].refunit = (cr)->unitnum;	\
-	((cr)->data++)[0] = cpu_to_be32((key) << 24);		\
-} while(0)
+static inline void cf_unit_begin(struct config_rom_ptr *cr, int unit)
+{
+	if (cr->unitdir[unit].refer != NULL) {
+		*cr->unitdir[unit].refer |=
+			cr->data - cr->unitdir[unit].refer;
+		cf_put_crc16(cr, cr->unitdir[unit].refunit);
+	}
+	cr->unitnum = unit;
+	cr->unitdir[unit].start = cr->data++;
+}
 
-#define cf_unit_end(cr)						\
-do {								\
-	(cr)->unitdir[(cr)->unitnum].length = (cr)->data -	\
-		((cr)->unitdir[(cr)->unitnum].start + 1);	\
-	cf_put_crc16((cr), (cr)->unitnum);			\
-} while(0)
+static inline void cf_put_refer(struct config_rom_ptr *cr, char key, int unit)
+{
+	cr->unitdir[unit].refer = cr->data;
+	cr->unitdir[unit].refunit = cr->unitnum;
+	(cr->data++)[0] = cpu_to_be32(key << 24);
+}
+
+static inline void cf_unit_end(struct config_rom_ptr *cr)
+{
+	cr->unitdir[cr->unitnum].length = cr->data -
+		(cr->unitdir[cr->unitnum].start + 1);
+	cf_put_crc16(cr, cr->unitnum);
+}
+
+/* End of NetBSD derived code.  */
 
 static void ohci_init_config_rom(struct ti_ohci *ohci)
 {
 	struct config_rom_ptr cr;
 
 	memset(&cr, 0, sizeof(cr));
-	memset (ohci->csr_config_rom_cpu, 0, sizeof (ohci->csr_config_rom_cpu));
+	memset(ohci->csr_config_rom_cpu, 0, sizeof (ohci->csr_config_rom_cpu));
 
 	cr.data = ohci->csr_config_rom_cpu;
 
@@ -1887,7 +1895,7 @@
 		reg_read(ohci, OHCI1394_GUIDLo));
 
 	/* IEEE P1212 suggests the initial ROM header CRC should only
-	 * cover the header itself (and not the entire ROM). Since we use
+	 * cover the header itself (and not the entire ROM). Since we do
 	 * this, then we can make our bus_info_len the same as the CRC
 	 * length.  */
 	ohci->csr_config_rom_cpu[0] |= cpu_to_be32(
@@ -1981,7 +1989,7 @@
 		if (reg_read(ohci, OHCI1394_CSRControl) & 0x80000000)
 			break;
 
-		mdelay(10);
+		mdelay(1);
 	}
 
 	*data = reg_read(ohci, OHCI1394_CSRData);
@@ -1998,29 +2006,15 @@
 	return data;
 }
 
-struct hpsb_host_template *get_ohci_template(void)
-{
-	static struct hpsb_host_template tmpl;
-	static int initialized = 0;
-
-	if (!initialized) {
-		memset (&tmpl, 0, sizeof (struct hpsb_host_template));
-
-		/* Initialize by field names so that a template structure
-		 * reorganization does not influence this code. */
-		tmpl.name = "ohci1394";
-
-		tmpl.initialize_host = ohci_initialize;
-		tmpl.release_host = ohci_remove;
-		tmpl.get_rom = get_ohci_rom;
-		tmpl.transmit_packet = ohci_transmit;
-		tmpl.devctl = ohci_devctl;
-		tmpl.hw_csr_reg = ohci_hw_csr_reg;
-		initialized = 1;
-	}
-
-	return &tmpl;
-}
+static struct hpsb_host_template ohci_template = {
+	name:			OHCI1394_DRIVER_NAME,
+	initialize_host:	ohci_initialize,
+	release_host:		ohci_remove,
+	get_rom:		get_ohci_rom,
+	transmit_packet:	ohci_transmit,
+	devctl:			ohci_devctl,
+	hw_csr_reg:		ohci_hw_csr_reg,
+};
 
 static int __devinit ohci1394_add_one(struct pci_dev *dev, const struct pci_device_id *ent)
 {
@@ -2040,7 +2034,7 @@
         }
         pci_set_master(dev);
 
-	host = hpsb_get_host(get_ohci_template(), sizeof (struct ti_ohci));
+	host = hpsb_get_host(&ohci_template, sizeof (struct ti_ohci));
 	if (!host) {
 		PRINT_G(KERN_ERR, "Out of memory trying to allocate host structure");
 		return -ENOMEM;
@@ -2054,8 +2048,6 @@
 	ohci->host = host;
 	pci_set_drvdata(dev, ohci);
 
-	PRINT(KERN_INFO, ohci->id, "OHCI (PCI) IEEE-1394 Controller");
-
 	/* We don't want hardware swapping */
 	pci_write_config_dword(dev, OHCI1394_PCI_HCI_Control, 0);
 
@@ -2173,14 +2165,10 @@
 	ohci->ISO_channel_usage = 0;
         spin_lock_init(&ohci->IR_channel_lock);
 
-	if (!request_irq(dev->irq, ohci_irq_handler, SA_SHIRQ,
+	if (request_irq(dev->irq, ohci_irq_handler, SA_SHIRQ,
 			 OHCI1394_DRIVER_NAME, ohci))
-		PRINT(KERN_DEBUG, ohci->id, "Allocated interrupt %d", dev->irq);
-	else
 		FAIL("Failed to allocate shared interrupt %d", dev->irq);
 
-	ohci_init_config_rom(ohci);
-
 	/* Tell the highlevel this host is ready */
 	highlevel_add_one_host (host);
 
@@ -2190,7 +2178,9 @@
 
 static void remove_card(struct ti_ohci *ohci)
 {
-	/* Reset the board properly before leaving */
+	quadlet_t buf;
+
+	/* Soft reset before we start */
 	ohci_soft_reset(ohci);
 
 	/* Free AR dma */
@@ -2207,6 +2197,10 @@
         /* Free IT dma */
         free_dma_trm_ctx(&ohci->it_context);
 
+	/* Disable all interrupts */
+	reg_write(ohci, OHCI1394_IntMaskClear, 0x80000000);
+	free_irq(ohci->dev->irq, ohci);
+
 	/* Free self-id buffer */
 	if (ohci->selfid_buf_cpu) {
 		pci_free_consistent(ohci->dev, OHCI1394_SI_DMA_BUF_SIZE, 
@@ -2222,9 +2216,15 @@
 				    ohci->csr_config_rom_bus);
 		OHCI_DMA_FREE("consistent csr_config_rom");
 	}
-	
-	/* Free the IRQ */
-	free_irq(ohci->dev->irq, ohci);
+
+	/* Disable our bus options */
+	buf = reg_read(ohci, OHCI1394_BusOptions);
+	buf &= ~0xf8000000;
+	buf |=  0x00ff0000;
+	reg_write(ohci, OHCI1394_BusOptions, buf);
+
+	/* Clear LinkEnable and LPS */
+	reg_write(ohci, OHCI1394_HCControlClear, 0x000a0000);
 
 	if (ohci->registers)
 		iounmap(ohci->registers);
@@ -2398,7 +2398,7 @@
 }
 
 static struct pci_driver ohci1394_driver = {
-	name:		"ohci1394",
+	name:		OHCI1394_DRIVER_NAME,
 	id_table:	ohci1394_pci_tbl,
 	probe:		ohci1394_add_one,
 	remove:		ohci1394_remove_one,
@@ -2406,20 +2406,20 @@
 
 static void __exit ohci1394_cleanup (void)
 {
-	hpsb_unregister_lowlevel(get_ohci_template());
+	hpsb_unregister_lowlevel(&ohci_template);
 	pci_unregister_driver(&ohci1394_driver);
 }
 
 static int __init ohci1394_init(void)
 {
 	int ret;
-	if (hpsb_register_lowlevel(get_ohci_template())) {
+	if (hpsb_register_lowlevel(&ohci_template)) {
 		PRINT_G(KERN_ERR, "Registering failed");
 		return -ENXIO;
 	}
 	if ((ret = pci_module_init(&ohci1394_driver))) {
 		PRINT_G(KERN_ERR, "PCI module init failed\n");
-		hpsb_unregister_lowlevel(get_ohci_template());
+		hpsb_unregister_lowlevel(&ohci_template);
 		return ret;
 	}
 	return ret;
diff -u --recursive --new-file v2.4.7/linux/drivers/ieee1394/pcilynx.c linux/drivers/ieee1394/pcilynx.c
--- v2.4.7/linux/drivers/ieee1394/pcilynx.c	Wed Jul 25 17:10:20 2001
+++ linux/drivers/ieee1394/pcilynx.c	Sun Jul 29 10:48:33 2001
@@ -58,6 +58,17 @@
 #define PRINTD(level, card, fmt, args...) do {} while (0)
 #endif
 
+static struct pci_device_id pcilynx_pci_tbl[] __devinitdata = {
+	{
+	  vendor: PCI_VENDOR_ID_TI,
+	  device: PCI_DEVICE_ID_TI_PCILYNX,
+	  subvendor: PCI_ANY_ID,
+	  subdevice: PCI_ANY_ID,
+	},
+	{ }			/* Terminating entry */
+};
+MODULE_DEVICE_TABLE(pci, pcilynx_pci_tbl);
+
 static struct ti_lynx cards[MAX_PCILYNX_CARDS];
 static int num_of_cards = 0;
 
diff -u --recursive --new-file v2.4.7/linux/drivers/ieee1394/video1394.c linux/drivers/ieee1394/video1394.c
--- v2.4.7/linux/drivers/ieee1394/video1394.c	Wed Jul 25 17:10:20 2001
+++ linux/drivers/ieee1394/video1394.c	Sun Jul 29 10:48:33 2001
@@ -807,7 +807,7 @@
 			   unsigned int cmd, unsigned long arg)
 {
 	struct video_card *video = NULL;
-	struct ti_ohci *ohci= video->ohci;
+	struct ti_ohci *ohci;
 	unsigned long flags;
 	struct list_head *lh;
 
@@ -818,6 +818,7 @@
 			p = list_entry(lh, struct video_card, list);
 			if (p->id == MINOR(inode->i_rdev)) {
 				video = p;
+				ohci = video->ohci;
 				break;
 			}
 		}
@@ -1602,7 +1603,7 @@
 
 MODULE_AUTHOR("Sebastien Rougeaux <sebastien.rougeaux@anu.edu.au>");
 MODULE_DESCRIPTION("driver for digital video on OHCI board");
-MODULE_SUPPORTED_DEVICE("video1394");
+MODULE_SUPPORTED_DEVICE(VIDEO1394_DRIVER_NAME);
 
 static void __exit video1394_exit_module (void)
 {
diff -u --recursive --new-file v2.4.7/linux/drivers/isdn/hisax/Makefile linux/drivers/isdn/hisax/Makefile
--- v2.4.7/linux/drivers/isdn/hisax/Makefile	Wed Apr 11 19:02:36 2001
+++ linux/drivers/isdn/hisax/Makefile	Sat Jul 28 12:12:37 2001
@@ -58,9 +58,6 @@
 obj-$(CONFIG_HISAX_SEDLBAUER_CS)	+= sedlbauer_cs.o
 obj-$(CONFIG_HISAX_ELSA_CS)	+= elsa_cs.o
 
-MD5FILES 	:= isac.c isdnl1.c isdnl2.c isdnl3.c \
-		   tei.c callc.c cert.c l3dss1.c l3_1tr6.c \
-		   elsa.c diva.c sedlbauer.c
 CERT := $(shell md5sum -c md5sums.asc >> /dev/null;echo $$?)
 CFLAGS_cert.o := -DCERTIFICATION=$(CERT)
 
diff -u --recursive --new-file v2.4.7/linux/drivers/isdn/hisax/cert.c linux/drivers/isdn/hisax/cert.c
--- v2.4.7/linux/drivers/isdn/hisax/cert.c	Fri Mar  2 11:12:08 2001
+++ linux/drivers/isdn/hisax/cert.c	Sat Jul 28 12:12:37 2001
@@ -1,4 +1,4 @@
-/* $Id: cert.c,v 2.3.6.1 2001/02/16 16:43:25 kai Exp $
+/* $Id: cert.c,v 2.3.6.2 2001/07/27 09:08:27 kai Exp $
  *
  * Author       Karsten Keil (keil@isdn4linux.de)
  *
@@ -20,6 +20,7 @@
 		printk(KERN_INFO "HiSax: Approved with ELSA Microlink PCI cards\n");
 		printk(KERN_INFO "HiSax: Approved with Eicon Technology Diva 2.01 PCI cards\n");
 		printk(KERN_INFO "HiSax: Approved with Sedlbauer Speedfax + cards\n");
+		printk(KERN_INFO "HiSax: Approved with HFC-S PCI A based cards\n");
 	}
 	return(0);
 #endif
diff -u --recursive --new-file v2.4.7/linux/drivers/isdn/hisax/hfc_pci.c linux/drivers/isdn/hisax/hfc_pci.c
--- v2.4.7/linux/drivers/isdn/hisax/hfc_pci.c	Tue Jul  3 17:08:19 2001
+++ linux/drivers/isdn/hisax/hfc_pci.c	Sat Jul 28 12:12:37 2001
@@ -1,11 +1,12 @@
-/* $Id: hfc_pci.c,v 1.34.6.6 2001/06/09 15:14:17 kai Exp $
+/* $Id: hfc_pci.c,v 1.34.6.7 2001/07/27 09:08:27 kai Exp $
 
  * hfc_pci.c     low level driver for CCD´s hfc-pci based cards
  *
  * Author     Werner Cornelius (werner@isdn4linux.de)
  *            based on existing driver for CCD hfc ISA cards
+ *            type approval valid for HFC-S PCI A based card 
  *
- * Copyright 1999  by Werner Cornelius (werner@isdn4linux.de)
+ * Copyright 1999  by Werner Cornelius (werner@isdn-development.de)
  * Copyright 1999  by Karsten Keil (keil@isdn4linux.de)
  *
  * This program is free software; you can redistribute it and/or modify
@@ -35,7 +36,7 @@
 
 extern const char *CardType[];
 
-static const char *hfcpci_revision = "$Revision: 1.34.6.6 $";
+static const char *hfcpci_revision = "$Revision: 1.34.6.7 $";
 
 /* table entry in the PCI devices list */
 typedef struct {
@@ -1232,7 +1233,7 @@
 			l1_msg(cs, HW_POWERUP | CONFIRM, NULL);
 			break;
 		case (HW_ENABLE | REQUEST):
-			Write_hfc(cs, HFCPCI_STATES, HFCPCI_ACTIVATE | HFCPCI_DO_ACTION);
+			Write_hfc(cs, HFCPCI_STATES, HFCPCI_DO_ACTION);
 			break;
 		case (HW_DEACTIVATE | REQUEST):
 			cs->hw.hfcpci.mst_m &= ~HFCPCI_MASTER;
diff -u --recursive --new-file v2.4.7/linux/drivers/isdn/hisax/md5sums.asc linux/drivers/isdn/hisax/md5sums.asc
--- v2.4.7/linux/drivers/isdn/hisax/md5sums.asc	Tue Jul  3 17:08:19 2001
+++ linux/drivers/isdn/hisax/md5sums.asc	Sat Jul 28 12:12:37 2001
@@ -1,10 +1,9 @@
------BEGIN PGP SIGNED MESSAGE-----
-
 # This are valid md5sums for certificated HiSax driver.
 # The certification is valid only if the md5sums of all files match.
 # The certification is valid only for ELSA Microlink PCI,
-# Eicon Technology Diva 2.01 PCI and Sedlbauer SpeedFax+
-# cards in the moment.
+# Eicon Technology Diva 2.01 PCI, Sedlbauer SpeedFax+, 
+# HFC-S PCI A based cards and HFC-S USB based isdn tas 
+# in the moment.
 # Read ../../../Documentation/isdn/HiSax.cert for more informations.
 # 
 6f9433a8b696076562562d090e3c420f  isac.c
@@ -13,11 +12,11 @@
 7076deb94a363945c21ea27aca4a720a  isdnl3.c
 51c603829b6cc4f8421f744ad657ceff  tei.c
 669050ab5079f02887ed0239d86e5474  callc.c
-e592db58630c1f1029cc064110108156  cert.c
+ecacd146b8f8881ef9349935dab3df4a  cert.c
 fadeb3b85bb23bc1ac48470c0848d6fa  l3dss1.c
 cf7dec9fac6283716904d26b99188476  l3_1tr6.c
-65d9e5471bc129624f858ebcf0743525  elsa.c
+2f75c8765e1be13d114d5f4433cf364b  elsa.c
 b4cf8a4dceed9ea6dcba65a85b4eecc7  diva.c
-99e67bea8f6945fa0d4e0aded5bf0fa0  sedlbauer.c
+dee3f8f40c6fe78a4b57729804b7e6cd  sedlbauer.c
+0d79fe6dfc5bfaa4826970c41a6d273d  hfc_pci.c
 # end of md5sums
-
diff -u --recursive --new-file v2.4.7/linux/drivers/isdn/hisax/sedlbauer_cs.c linux/drivers/isdn/hisax/sedlbauer_cs.c
--- v2.4.7/linux/drivers/isdn/hisax/sedlbauer_cs.c	Sun Mar 25 18:24:31 2001
+++ linux/drivers/isdn/hisax/sedlbauer_cs.c	Sat Jul 28 12:12:37 2001
@@ -42,7 +42,7 @@
 #include <linux/init.h>
 #include <linux/sched.h>
 #include <linux/ptrace.h>
-#include <linux/malloc.h>
+#include <linux/slab.h>
 #include <linux/string.h>
 #include <linux/timer.h>
 #include <linux/ioport.h>
diff -u --recursive --new-file v2.4.7/linux/drivers/isdn/isdn_net.c linux/drivers/isdn/isdn_net.c
--- v2.4.7/linux/drivers/isdn/isdn_net.c	Tue Jul  3 17:08:19 2001
+++ linux/drivers/isdn/isdn_net.c	Sat Jul 28 12:12:37 2001
@@ -1,4 +1,4 @@
-/* $Id: isdn_net.c,v 1.140.6.6 2001/06/11 22:08:37 kai Exp $
+/* $Id: isdn_net.c,v 1.140.6.7 2001/07/27 11:15:53 kai Exp $
 
  * Linux ISDN subsystem, network interfaces and related functions (linklevel).
  *
@@ -190,7 +190,7 @@
 static void isdn_net_ciscohdlck_connected(isdn_net_local *lp);
 static void isdn_net_ciscohdlck_disconnected(isdn_net_local *lp);
 
-char *isdn_net_revision = "$Revision: 1.140.6.6 $";
+char *isdn_net_revision = "$Revision: 1.140.6.7 $";
 
  /*
   * Code for raw-networking over ISDN
@@ -2028,17 +2028,8 @@
 {
 	ushort max_hlhdr_len = 0;
 	isdn_net_local *lp = (isdn_net_local *) ndev->priv;
-	int drvidx,
-	 i;
+	int drvidx, i;
 
-	if (ndev == NULL) {
-		printk(KERN_WARNING "isdn_net_init: dev = NULL!\n");
-		return -ENODEV;
-	}
-	if (ndev->priv == NULL) {
-		printk(KERN_WARNING "isdn_net_init: dev->priv = NULL!\n");
-		return -ENODEV;
-	}
 	ether_setup(ndev);
 	lp->org_hhc = ndev->hard_header_cache;
 	lp->org_hcu = ndev->header_cache_update;
diff -u --recursive --new-file v2.4.7/linux/drivers/isdn/isdn_ppp.c linux/drivers/isdn/isdn_ppp.c
--- v2.4.7/linux/drivers/isdn/isdn_ppp.c	Tue Jul  3 17:08:19 2001
+++ linux/drivers/isdn/isdn_ppp.c	Sat Jul 28 12:12:37 2001
@@ -1,4 +1,4 @@
-/* $Id: isdn_ppp.c,v 1.85.6.5 2001/05/26 15:19:56 kai Exp $
+/* $Id: isdn_ppp.c,v 1.85.6.6 2001/07/27 09:08:27 kai Exp $
  *
  * Linux ISDN subsystem, functions for synchronous PPP (linklevel).
  *
@@ -83,7 +83,7 @@
 static int isdn_ppp_bundle(struct ippp_struct *, int unit);
 #endif	/* CONFIG_ISDN_MPP */
   
-char *isdn_ppp_revision = "$Revision: 1.85.6.5 $";
+char *isdn_ppp_revision = "$Revision: 1.85.6.6 $";
 
 static struct ippp_struct *ippp_table[ISDN_MAX_CHANNELS];
 
@@ -1913,8 +1913,15 @@
 	sdev = lp->slave;
 	while (sdev) {
 		isdn_net_local *mlp = (isdn_net_local *) sdev->priv;
-		if ((mlp->flags & ISDN_NET_CONNECTED))
+
+		if (mlp->slave) { /* find last connected link in chain */
+			isdn_net_local *nlp = (isdn_net_local *) mlp->slave->priv;
+
+			if (!(nlp->flags & ISDN_NET_CONNECTED))
+				break;
+		} else if (mlp->flags & ISDN_NET_CONNECTED)
 			break;
+		
 		sdev = mlp->slave;
 	}
 	if (!sdev)
diff -u --recursive --new-file v2.4.7/linux/drivers/isdn/isdn_tty.c linux/drivers/isdn/isdn_tty.c
--- v2.4.7/linux/drivers/isdn/isdn_tty.c	Wed Jul 25 17:10:20 2001
+++ linux/drivers/isdn/isdn_tty.c	Sat Jul 28 12:12:37 2001
@@ -1,4 +1,4 @@
-/* $Id: isdn_tty.c,v 1.94.6.3 2001/07/03 14:48:25 kai Exp $
+/* $Id: isdn_tty.c,v 1.94.6.4 2001/07/27 11:15:53 kai Exp $
 
  * Linux ISDN subsystem, tty functions and AT-command emulator (linklevel).
  *
@@ -66,7 +66,7 @@
 static int si2bit[8] =
 {4, 1, 4, 4, 4, 4, 4, 4};
 
-char *isdn_tty_revision = "$Revision: 1.94.6.3 $";
+char *isdn_tty_revision = "$Revision: 1.94.6.4 $";
 
 
 /* isdn_tty_try_read() is called from within isdn_tty_rcv_skb()
@@ -1181,8 +1181,6 @@
 	atemu *m = &info->emu;
 
 	if (isdn_tty_paranoia_check(info, tty->device, "isdn_tty_write"))
-		return 0;
-	if (!tty)
 		return 0;
 	if (from_user)
 		down(&info->write_sem);
diff -u --recursive --new-file v2.4.7/linux/drivers/media/radio/Config.in linux/drivers/media/radio/Config.in
--- v2.4.7/linux/drivers/media/radio/Config.in	Tue Jul  3 17:08:20 2001
+++ linux/drivers/media/radio/Config.in	Sun Aug  5 13:15:05 2001
@@ -21,6 +21,7 @@
 if [ "$CONFIG_RADIO_GEMTEK" = "y" ]; then
    hex '    GemTek i/o port (0x20c, 0x30c, 0x24c or 0x34c)' CONFIG_RADIO_GEMTEK_PORT 34c
 fi
+dep_tristate '  GemTek PCI Radio Card support' CONFIG_RADIO_GEMTEK_PCI $CONFIG_VIDEO_DEV
 dep_tristate '  Guillemot MAXI Radio FM 2000 radio' CONFIG_RADIO_MAXIRADIO $CONFIG_VIDEO_DEV
 dep_tristate '  Maestro on board radio' CONFIG_RADIO_MAESTRO $CONFIG_VIDEO_DEV
 dep_tristate '  miroSOUND PCM20 radio' CONFIG_RADIO_MIROPCM20 $CONFIG_VIDEO_DEV $CONFIG_SOUND_ACI_MIXER
diff -u --recursive --new-file v2.4.7/linux/drivers/media/radio/Makefile linux/drivers/media/radio/Makefile
--- v2.4.7/linux/drivers/media/radio/Makefile	Tue Jul  3 17:08:20 2001
+++ linux/drivers/media/radio/Makefile	Sun Aug  5 13:15:05 2001
@@ -39,6 +39,7 @@
 obj-$(CONFIG_RADIO_MIROPCM20) += miropcm20.o
 obj-$(CONFIG_RADIO_MIROPCM20_RDS) += miropcm20-rds.o
 obj-$(CONFIG_RADIO_GEMTEK) += radio-gemtek.o
+obj-$(CONFIG_RADIO_GEMTEK_PCI) += radio-gemtek-pci.o
 obj-$(CONFIG_RADIO_TRUST) += radio-trust.o
 obj-$(CONFIG_RADIO_MAESTRO) += radio-maestro.o
 
diff -u --recursive --new-file v2.4.7/linux/drivers/media/radio/radio-gemtek-pci.c linux/drivers/media/radio/radio-gemtek-pci.c
--- v2.4.7/linux/drivers/media/radio/radio-gemtek-pci.c	Wed Dec 31 16:00:00 1969
+++ linux/drivers/media/radio/radio-gemtek-pci.c	Sun Aug  5 13:15:05 2001
@@ -0,0 +1,451 @@
+/*
+ ***************************************************************************
+ *     
+ *     radio-gemtek-pci.c - Gemtek PCI Radio driver
+ *     (C) 2001 Vladimir Shebordaev <vshebordaev@mail.ru>
+ *
+ ***************************************************************************
+ *
+ *     This program is free software; you can redistribute it and/or
+ *     modify it under the terms of the GNU General Public License as
+ *     published by the Free Software Foundation; either version 2 of
+ *     the License, or (at your option) any later version.
+ *
+ *     This program is distributed in the hope that it will be useful,
+ *     but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *     GNU General Public License for more details.
+ *
+ *     You should have received a copy of the GNU General Public
+ *     License along with this program; if not, write to the Free
+ *     Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139,
+ *     USA.
+ *
+ ***************************************************************************
+ *
+ *     Gemtek Corp still silently refuses to release any specifications
+ *     of their multimedia devices, so the protocol still has to be
+ *     reverse engineered.
+ *
+ *     The v4l code was inspired by Jonas Munsin's  Gemtek serial line
+ *     radio device driver.
+ *
+ *     Please, let me know if this piece of code was useful :)
+ * 
+ *     TODO: multiple device support and portability were not tested
+ *
+ ***************************************************************************
+ */
+
+#include <linux/version.h>
+#include <linux/config.h>
+#include <linux/types.h>
+#include <linux/list.h>
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/pci.h>
+#include <linux/videodev.h>
+#include <linux/errno.h>
+
+#include <asm/io.h>
+#include <asm/uaccess.h>
+
+#ifndef PCI_VENDOR_ID_GEMTEK
+#define PCI_VENDOR_ID_GEMTEK 0x5046
+#endif
+
+#ifndef PCI_DEVICE_ID_GEMTEK_PR103
+#define PCI_DEVICE_ID_GEMTEK_PR103 0x1001
+#endif
+
+#ifndef GEMTEK_PCI_RANGE_LOW
+#define GEMTEK_PCI_RANGE_LOW (87*16000)
+#endif
+
+#ifndef GEMTEK_PCI_RANGE_HIGH
+#define GEMTEK_PCI_RANGE_HIGH (108*16000)
+#endif
+
+#ifndef TRUE
+#define TRUE (1)
+#endif
+
+#ifndef FALSE 
+#define FALSE (0)
+#endif
+
+struct gemtek_pci_card {
+	struct video_device *videodev;
+	
+	u32 iobase;
+	u32 length;
+	u8  chiprev;
+	u16 model;
+	
+	u32 current_frequency;
+	u8  mute;
+};
+
+static const char rcsid[] = "$Id: radio-gemtek-pci.c,v 1.1 2001/07/23 08:08:16 ted Exp ted $";
+
+static int nr_radio = -1;
+
+static int gemtek_pci_open( struct video_device *dev, int flags)
+{
+	struct gemtek_pci_card *card =  dev->priv;
+
+/* Paranoid check */
+	if ( !card )
+		return -ENODEV;
+
+	return 0;
+}
+
+static void gemtek_pci_close( struct video_device *dev )
+{
+/*
+ *  The module usage is managed by 'videodev'
+ */
+}
+
+static inline u8 gemtek_pci_out( u16 value, u32 port )
+{
+	outw( value, port );
+
+	return (u8)value;
+}
+
+#define _b0( v ) *((u8 *)&v)  
+static void __gemtek_pci_cmd( u16 value, u32 port, u8 *last_byte, int keep )
+{
+	register u8 byte = *last_byte;
+
+	if ( !value ) {
+		if ( !keep )
+			value = (u16)port;
+		byte &= 0xfd;	
+	} else
+		byte |= 2;
+
+	_b0( value ) = byte;
+	outw( value, port );
+	byte |= 1;
+	_b0( value ) = byte;
+	outw( value, port );
+	byte &= 0xfe;
+	_b0( value ) = byte;
+	outw( value, port );
+	
+	*last_byte = byte;
+}
+
+static inline void gemtek_pci_nil( u32 port, u8 *last_byte )
+{
+	__gemtek_pci_cmd( 0x00, port, last_byte, FALSE );
+}
+
+static inline void gemtek_pci_cmd( u16 cmd, u32 port, u8 *last_byte )
+{
+	__gemtek_pci_cmd( cmd, port, last_byte, TRUE );
+}
+
+static void gemtek_pci_setfrequency( struct gemtek_pci_card *card, unsigned long frequency )
+{
+	register int i;
+	register u32 value = frequency / 200 + 856;
+	register u16 mask = 0x8000;
+	u8 last_byte;
+	u32 port = card->iobase;
+
+	last_byte = gemtek_pci_out( 0x06, port );
+
+	i = 0;
+	do {
+		gemtek_pci_nil( port, &last_byte );
+		i++;
+	} while ( i < 9 );
+
+	i = 0;
+	do {
+		gemtek_pci_cmd( value & mask, port, &last_byte );
+		mask >>= 1;
+		i++;
+	} while ( i < 16 );
+
+	outw( 0x10, port );
+}
+
+
+static inline void gemtek_pci_mute( struct gemtek_pci_card *card )
+{
+	outb( 0x1f, card->iobase );
+	card->mute = TRUE;
+}
+
+static inline void gemtek_pci_unmute( struct gemtek_pci_card *card )
+{
+	if ( card->mute ) {
+		gemtek_pci_setfrequency( card, card->current_frequency );
+		card->mute = FALSE;
+	}
+}
+
+static inline unsigned int gemtek_pci_getsignal( struct gemtek_pci_card *card )
+{
+	return ( inb( card->iobase ) & 0x08 ) ? 0 : 1;
+}
+
+static int gemtek_pci_ioctl( struct video_device *dev, unsigned int cmd, void *arg)
+{
+	struct gemtek_pci_card *card = dev->priv;
+
+	switch ( cmd ) {
+		case VIDIOCGCAP:
+		{
+			struct video_capability c;
+
+			c.type = VID_TYPE_TUNER;
+			c.channels = 1;
+			c.audios = 1;
+			c.maxwidth = 0;
+			c.maxheight = 0;
+			c.minwidth = 0;
+			c.minheight = 0;
+			strcpy( c.name, "Gemtek PCI Radio" );
+			if ( copy_to_user( arg, &c, sizeof( c ) ) )
+				return -EFAULT;
+
+			return 0;
+		} 
+
+		case VIDIOCGTUNER:
+		{
+			struct video_tuner t;
+
+			if ( copy_from_user( &t, arg, sizeof( struct video_tuner ) ) )
+				return -EFAULT;
+
+			if ( t.tuner ) 
+				return -EINVAL;
+
+			t.rangelow = GEMTEK_PCI_RANGE_LOW;
+			t.rangehigh = GEMTEK_PCI_RANGE_HIGH;
+			t.flags = VIDEO_TUNER_LOW;
+			t.mode = VIDEO_MODE_AUTO;
+			t.signal = 0xFFFF * gemtek_pci_getsignal( card );
+			strcpy( t.name, "FM" );
+
+			if ( copy_to_user( arg, &t, sizeof( struct video_tuner ) ) )
+				return -EFAULT;
+
+			return 0;
+		}
+
+		case VIDIOCSTUNER:
+		{
+			struct video_tuner t;
+
+			if ( copy_from_user( &t, arg, sizeof( struct video_tuner ) ) )
+				return -EFAULT;
+
+			if ( t.tuner )
+				return -EINVAL;
+
+			return 0;
+		}
+
+		case VIDIOCGFREQ:
+			return put_user( card->current_frequency, (u32 *)arg );
+
+		case VIDIOCSFREQ:
+		{
+			u32 frequency;
+	 
+			if ( get_user( frequency, (u32 *)arg ) )
+				return -EFAULT;
+
+			if ( (frequency < GEMTEK_PCI_RANGE_LOW) || (frequency > GEMTEK_PCI_RANGE_HIGH) )
+				return -EINVAL;
+
+			gemtek_pci_setfrequency( card, frequency );
+			card->current_frequency = frequency;
+			card->mute = FALSE;
+
+			return 0;
+		}
+  
+		case VIDIOCGAUDIO:
+		{	
+			struct video_audio a;
+
+			memset( &a, 0, sizeof( a ) );
+			a.flags |= VIDEO_AUDIO_MUTABLE;
+			a.volume = 1;
+			a.step = 65535;
+			strcpy( a.name, "Radio" );
+
+			if ( copy_to_user( arg, &a, sizeof( struct video_audio ) ) )
+				return -EFAULT;
+
+			return 0;			
+		}
+
+		case VIDIOCSAUDIO:
+		{
+			struct video_audio a;
+
+			if ( copy_from_user( &a, arg, sizeof( struct video_audio ) ) ) 
+				return -EFAULT;	
+
+			if ( a.audio ) 
+				return -EINVAL;
+
+			if ( a.flags & VIDEO_AUDIO_MUTE ) 
+				gemtek_pci_mute( card );
+
+			else
+				gemtek_pci_unmute( card );
+
+			return 0;
+		}
+
+		default:
+			return -ENOIOCTLCMD;
+	}
+}
+
+enum {
+	GEMTEK_PR103
+};
+
+static char *card_names[] __devinitdata = {
+	"GEMTEK_PR103"
+};
+
+static struct pci_device_id gemtek_pci_id[] =
+{
+	{ PCI_VENDOR_ID_GEMTEK, PCI_DEVICE_ID_GEMTEK_PR103,
+	  PCI_ANY_ID, PCI_ANY_ID, 0, 0, GEMTEK_PR103 },
+	{ 0 }
+};
+
+MODULE_DEVICE_TABLE( pci, gemtek_pci_id );
+
+static u8 mx = 1;
+
+static char gemtek_pci_videodev_name[] = "Gemtek PCI Radio";
+
+static inline void gemtek_pci_init_struct( struct video_device *dev )
+{
+	memset( dev, 0, sizeof( struct video_device ) );
+	dev->owner = THIS_MODULE;
+	strcpy( dev->name , gemtek_pci_videodev_name );
+	dev->type = VID_TYPE_TUNER;
+	dev->hardware = VID_HARDWARE_GEMTEK;
+	dev->open = gemtek_pci_open;
+	dev->close = gemtek_pci_close;
+	dev->ioctl = gemtek_pci_ioctl;
+}
+
+static int __devinit gemtek_pci_probe( struct pci_dev *pci_dev, const struct pci_device_id *pci_id )
+{
+	struct gemtek_pci_card *card;
+	struct video_device *devradio;
+
+	if ( (card = kmalloc( sizeof( struct gemtek_pci_card ), GFP_KERNEL )) == NULL ) {
+		printk( KERN_ERR "gemtek_pci: out of memory\n" );
+		return -ENOMEM;
+	}
+	memset( card, 0, sizeof( struct gemtek_pci_card ) );
+
+	if ( pci_enable_device( pci_dev ) ) 
+		goto err_pci;
+	
+	card->iobase = pci_resource_start( pci_dev, 0 );
+	card->length = pci_resource_len( pci_dev, 0 );
+
+	if ( request_region( card->iobase, card->length, card_names[pci_id->driver_data] ) == NULL ) {
+		printk( KERN_ERR "gemtek_pci: i/o port already in use\n" );
+		goto err_pci;
+	}
+
+	pci_read_config_byte( pci_dev, PCI_REVISION_ID, &card->chiprev );
+	pci_read_config_word( pci_dev, PCI_SUBSYSTEM_ID, &card->model );
+
+	pci_set_drvdata( pci_dev, card );
+ 
+	if ( (devradio = kmalloc( sizeof( struct video_device ), GFP_KERNEL )) == NULL ) {
+		printk( KERN_ERR "gemtek_pci: out of memory\n" );
+		goto err_video;
+	}
+	gemtek_pci_init_struct( devradio );
+
+	if ( video_register_device( devradio, VFL_TYPE_RADIO , nr_radio) == -1 ) {
+		kfree( devradio );
+		goto err_video;
+	}
+
+	card->videodev = devradio;
+	devradio->priv = card;
+	gemtek_pci_mute( card );
+
+	printk( KERN_INFO "Gemtek PCI Radio (rev. %d) found at 0x%04x-0x%04x.\n", 
+		card->chiprev, card->iobase, card->iobase + card->length - 1 );
+
+	return 0;
+
+err_video:
+	release_region( card->iobase, card->length );
+
+err_pci:
+	kfree( card );
+	return -ENODEV;        
+}
+
+static void __devexit gemtek_pci_remove( struct pci_dev *pci_dev )
+{
+	struct gemtek_pci_card *card = pci_get_drvdata( pci_dev );
+
+	video_unregister_device( card->videodev );
+	kfree( card->videodev );
+
+	release_region( card->iobase, card->length );
+	
+	if ( mx )
+		gemtek_pci_mute( card );
+
+	kfree( card );
+	
+	pci_set_drvdata( pci_dev, NULL );
+}
+
+static struct pci_driver gemtek_pci_driver =
+{
+    name:	"gemtek_pci",
+id_table:	gemtek_pci_id,
+   probe:	gemtek_pci_probe,
+  remove:	gemtek_pci_remove
+};
+
+static int __init gemtek_pci_init_module( void )
+{
+	return pci_module_init( &gemtek_pci_driver );
+}
+
+static void __exit gemtek_pci_cleanup_module( void )
+{
+	return pci_unregister_driver( &gemtek_pci_driver );
+}
+
+MODULE_AUTHOR( "Vladimir Shebordaev <vshebordaev@mail.ru>" );
+MODULE_DESCRIPTION( "The video4linux driver for the Gemtek PCI Radio Card" );
+MODULE_PARM( mx, "b" );
+MODULE_PARM_DESC( mx, "single digit: 1 - turn off the turner upon module exit (default), 0 - do not" );
+MODULE_PARM( nr_radio, "i");
+MODULE_PARM_DESC( nr_radio, "video4linux device number to use");
+
+EXPORT_NO_SYMBOLS;
+
+module_init( gemtek_pci_init_module );
+module_exit( gemtek_pci_cleanup_module );
+
diff -u --recursive --new-file v2.4.7/linux/drivers/media/video/adv7175.c linux/drivers/media/video/adv7175.c
--- v2.4.7/linux/drivers/media/video/adv7175.c	Sat May 19 17:43:06 2001
+++ linux/drivers/media/video/adv7175.c	Sun Aug  5 13:15:05 2001
@@ -30,7 +30,7 @@
 #include <linux/fs.h>
 #include <linux/kernel.h>
 #include <linux/major.h>
-#include <linux/malloc.h>
+#include <linux/slab.h>
 #include <linux/mm.h>
 #include <linux/pci.h>
 #include <linux/signal.h>
diff -u --recursive --new-file v2.4.7/linux/drivers/media/video/bt819.c linux/drivers/media/video/bt819.c
--- v2.4.7/linux/drivers/media/video/bt819.c	Sat May 19 17:43:06 2001
+++ linux/drivers/media/video/bt819.c	Sun Aug  5 13:15:05 2001
@@ -31,7 +31,7 @@
 #include <linux/errno.h>
 #include <linux/fs.h>
 #include <linux/kernel.h>
-#include <linux/malloc.h>
+#include <linux/slab.h>
 #include <linux/mm.h>
 #include <linux/pci.h>
 #include <linux/signal.h>
diff -u --recursive --new-file v2.4.7/linux/drivers/media/video/bt848.h linux/drivers/media/video/bt848.h
--- v2.4.7/linux/drivers/media/video/bt848.h	Tue Jul 18 22:35:33 2000
+++ linux/drivers/media/video/bt848.h	Sun Aug  5 13:15:05 2001
@@ -351,5 +351,6 @@
 
 #define BT878_DEVCTRL 0x40
 #define BT878_EN_TBFX 0x02
+#define BT878_EN_VSFX 0x04
 
 #endif
diff -u --recursive --new-file v2.4.7/linux/drivers/media/video/bt856.c linux/drivers/media/video/bt856.c
--- v2.4.7/linux/drivers/media/video/bt856.c	Sat May 19 17:43:06 2001
+++ linux/drivers/media/video/bt856.c	Sun Aug  5 13:15:05 2001
@@ -32,7 +32,7 @@
 #include <linux/fs.h>
 #include <linux/kernel.h>
 #include <linux/major.h>
-#include <linux/malloc.h>
+#include <linux/slab.h>
 #include <linux/mm.h>
 #include <linux/pci.h>
 #include <linux/signal.h>
diff -u --recursive --new-file v2.4.7/linux/drivers/media/video/bttv-cards.c linux/drivers/media/video/bttv-cards.c
--- v2.4.7/linux/drivers/media/video/bttv-cards.c	Wed Apr 11 19:02:36 2001
+++ linux/drivers/media/video/bttv-cards.c	Sun Aug  5 13:15:05 2001
@@ -46,13 +46,16 @@
 #endif
 
 static void winview_audio(struct bttv *btv, struct video_audio *v, int set);
+static void lt9415_audio(struct bttv *btv, struct video_audio *v, int set);
 static void avermedia_tvphone_audio(struct bttv *btv, struct video_audio *v,
 				    int set);
 static void terratv_audio(struct bttv *btv, struct video_audio *v, int set);
 static void gvbctv3pci_audio(struct bttv *btv, struct video_audio *v, int set);
+static void winfast2000_audio(struct bttv *btv, struct video_audio *v, int set);
 
 /* config variables */
 static int triton1=0;
+static int vsfx=0;
 int no_overlay=-1;
 static unsigned int card[4]  = { -1, -1, -1, -1 };
 static unsigned int pll[4]   = { -1, -1, -1, -1 };
@@ -111,38 +114,55 @@
 	int cardnr;
 	char *name;
 } cards[] __devinitdata = {
-	{ 0x00011002, BTTV_HAUPPAUGE878,  "ATI TV Wonder" },
-	{ 0x00011461, BTTV_AVPHONE98,     "AVerMedia TVPhone98" },
-	{ 0x00021461, BTTV_AVERMEDIA98,   "Avermedia TVCapture 98" },
-	{ 0x00031002, BTTV_HAUPPAUGE878,  "ATI TV Wonder/VE" },
-	{ 0x00031461, BTTV_AVPHONE98,     "AVerMedia TVPhone98" },
-	{ 0x00041461, BTTV_AVERMEDIA98,   "AVerMedia TVCapture 98" },
-	{ 0x010114c7, 16 /* FIXME */,     "Modular Technology PCTV" },
-	{ 0x10b42636, BTTV_HAUPPAUGE878,  "STB ???" },
-	{ 0x1118153b, BTTV_TERRATVALUE,   "Terratec TV Value" },
-	{ 0x1123153b, BTTV_TERRATVRADIO,  "Terratec TV/Radio+" },
-	{ 0x1200bd11, BTTV_PINNACLE,      "Pinnacle PCTV" },
 	{ 0x13eb0070, BTTV_HAUPPAUGE878,  "Hauppauge WinTV" },
-	{ 0x18501851, BTTV_CHRONOS_VS2,   "Chronos Video Shuttle II" },
-	{ 0x18521852, BTTV_TYPHOON_TVIEW, "Typhoon TView TV/FM Tuner" },
-	{ 0x217d6606, BTTV_WINFAST2000,   "Leadtek WinFast TV 2000" },
+	{ 0x39000070, BTTV_HAUPPAUGE878,  "Hauppauge WinTV-D" },
+	{ 0x45000070, BTTV_HAUPPAUGE878,  "Hauppauge WinTV/PVR" },
+	{ 0xff000070, BTTV_HAUPPAUGE878,  "Osprey-100" },
+	{ 0xff010070, BTTV_HAUPPAUGE878,  "Osprey-200" },
+
+	{ 0x00011002, BTTV_ATI_TVWONDER,  "ATI TV Wonder" },
+	{ 0x00031002, BTTV_ATI_TVWONDERVE,"ATI TV Wonder/VE" },
+
+	{ 0x6606107d, BTTV_WINFAST2000,   "Leadtek WinFast TV 2000" },
 	{ 0x263610b4, BTTV_STB2,          "STB TV PCI FM, P/N 6000704" },
+ 	{ 0x402010fc, BTTV_GVBCTV3PCI,    "I-O Data Co. GV-BCV3/PCI" },
+	{ 0x405010fc, BTTV_GVBCTV3PCI,    "I-O Data Co. GV-BCV4/PCI" },
+	{ 0x001211bd, BTTV_PINNACLE,      "Pinnacle PCTV" },
 	{ 0x3000121a, 0/* no entry yet */,"VoodooTV 200" },
+
 	{ 0x3000144f, BTTV_MAGICTVIEW063, "TView 99 (CPH063)" },
-	{ 0x300014ff, BTTV_MAGICTVIEW061, "TView 99 (CPH061)" },
 	{ 0x3002144f, BTTV_MAGICTVIEW061, "Askey Magic TView" },
+
+	{ 0x00011461, BTTV_AVPHONE98,     "AVerMedia TVPhone98" },
+	{ 0x00021461, BTTV_AVERMEDIA98,   "AVermedia TVCapture 98" },
+	{ 0x00031461, BTTV_AVPHONE98,     "AVerMedia TVPhone98" },
+	{ 0x00041461, BTTV_AVERMEDIA98,   "AVerMedia TVCapture 98" },
+
+	{ 0x300014ff, BTTV_MAGICTVIEW061, "TView 99 (CPH061)" },
 	{ 0x300214ff, BTTV_PHOEBE_TVMAS,  "Phoebe TV Master" },
-	{ 0x39000070, BTTV_HAUPPAUGE878,  "Hauppauge WinTV-D" },
+
+	{ 0x1117153b, BTTV_TERRATVALUE,   "Terratec TValue" },
+	{ 0x1118153b, BTTV_TERRATVALUE,   "Terratec TValue" },
+	{ 0x1119153b, BTTV_TERRATVALUE,   "Terratec TValue" },
+	{ 0x111a153b, BTTV_TERRATVALUE,   "Terratec TValue" },
+	{ 0x1123153b, BTTV_TERRATVRADIO,  "Terratec TV Radio+" },
+	{ 0x1127153b, BTTV_TERRATV,       "Terratec TV+"    },
+	{ 0x1134153b, BTTV_TERRATVALUE,   "Terratec TValue" },
+	{ 0x1135153b, BTTV_TERRATVALUER,  "Terratec TValue Radio" },
+
 	{ 0x400a15b0, BTTV_ZOLTRIX_GENIE, "Zoltrix Genie TV" },
 	{ 0x400d15b0, BTTV_ZOLTRIX_GENIE, "Zoltrix Genie TV / Radio" },
 	{ 0x401015b0, BTTV_ZOLTRIX_GENIE, "Zoltrix Genie TV / Radio" },
- 	{ 0x402010fc, BTTV_GVBCTV3PCI,    "I-O Data Co. GV-BCV3/PCI" },
-	{ 0xff000070, BTTV_HAUPPAUGE878,  "Osprey-100" },
-	{ 0xff010070, BTTV_HAUPPAUGE878,  "Osprey-200" },
-#if 0 /* probably wrong */
-	{ 0x14610002, BTTV_AVERMEDIA98,   "Avermedia TVCapture 98" },
-	{ 0x6606217d, BTTV_WINFAST2000,   "Leadtek WinFast TV 2000" },
-#endif
+
+    	{ 0x010115cb, BTTV_GMV1,          "AG GMV1" },
+	{ 0x010114c7, 16 /* FIXME */,     "Modular Technology PCTV" },
+	{ 0x18501851, BTTV_CHRONOS_VS2,   "Chronos Video Shuttle II" },
+	{ 0x18511851, 0 /* FIXME */,      "CyberMail AV" },
+	{ 0x18521852, BTTV_TYPHOON_TVIEW, "Typhoon TView TV/FM Tuner" },
+	{ 0x10b42636, BTTV_HAUPPAUGE878,  "STB ???" },
+	{ 0x217d6606, BTTV_WINFAST2000,   "Leadtek WinFast TV 2000" },
+	{ 0x1200bd11, BTTV_PINNACLE,      "Pinnacle PCTV" },
+
 	{ 0, -1, NULL }
 };
 
@@ -223,13 +243,10 @@
 	audio_inputs:	1,
 	tuner:		0,
 	svhs:		3,
-	/* old 
-	gpiomask:	15,
-	audiomux:	{12, 4,11,11, 0},
-	*/
 	muxsel:		{ 2, 3, 1, 1},
 	gpiomask:	0x0f,
-	audiomux:	{ 0x04, 0x04, 0x08, 0x04, 0},
+	audiomux:	{ 0x0c, 0x04, 0x08, 0x04, 0},
+	/*                0x04 for some cards ?? */
 	needs_tvaudio:	1,
 	tuner_type:	-1,
 	audio_hook:	avermedia_tvphone_audio,
@@ -286,9 +303,9 @@
 	audio_inputs:	1,
 	tuner:		0,
 	svhs:		2,
-	gpiomask:	0x3000f,
+	gpiomask:	0x3014f,
 	muxsel:		{ 2, 3, 1, 1},
-	audiomux:	{ 1,0x10001, 0, 0,10},
+	audiomux:	{ 0x20001,0x10001, 0, 0,10},
 	needs_tvaudio:	1,
 	tuner_type:	-1,
 },{
@@ -490,7 +507,7 @@
 	muxsel:		{ 2, 3, 1, 1},
 	audiomux:	{ 0x20000, 0x30000, 0x10000, 0x00000, 0x40000},
 	needs_tvaudio:	1,
-	tuner_type:	-1,
+	tuner_type:	TUNER_PHILIPS_PAL,
 	audio_hook:	terratv_audio,
 },{
 	/* Jannik Fritsch <jannik@techfak.uni-bielefeld.de> */
@@ -556,12 +573,13 @@
 	audio_inputs:	1,
 	tuner:		0,
 	svhs:		2,
-	gpiomask:	0xfff000,
+	gpiomask:	0xc33000,
 	muxsel:		{ 2, 3, 1, 1,0},
-	audiomux:	{ 0x621000,0x6ddf07,0x621100,0x620000,0xE210000,0x620000},
-	needs_tvaudio:	1,
+	audiomux:	{ 0x422000,0x001000,0x621100,0x620000,0x800000,0x620000},
+	needs_tvaudio:	0,
 	pll:		PLL_28,
 	tuner_type:	-1,
+	audio_hook:	winfast2000_audio,
 },{
 	name:		"Chronos Video Shuttle II",
 	video_inputs:	3,
@@ -808,7 +826,7 @@
 		options bttv card=0 pll=1 radio=1 gpiomask=0x18e0
 		audiomux=0x44c71f,0x44d71f,0,0x44d71f,0x44dfff
 		options tuner type=5 */
-	name:		"Livetec 9415 TV",
+	name:		"Lifetec LT 9415 TV",
 	video_inputs:	4,
 	audio_inputs:	1,
 	tuner:		0,
@@ -816,10 +834,15 @@
 	gpiomask:	0x18e0,
 	muxsel:		{ 2, 3, 1, 1},
 	audiomux:	{ 0x0000,0x0800,0x1000,0x1000,0x18e0 },
+		       /* 0x0000: Tuner normal stereo
+			  0x0080: Tuner A2 SAP (second audio program = Zweikanalton)
+			  0x0880: Tuner A2 stereo */
 	pll:		PLL_28,
 	tuner_type:	TUNER_PHILIPS_PAL,
+	audio_hook:	lt9415_audio,
 },{
-	/* Miguel Angel Alvarez <maacruz@navegalia.com> */
+	/* Miguel Angel Alvarez <maacruz@navegalia.com>
+	   old Easy TV BT848 version (model CPH031) */
 	name:           "BESTBUY Easy TV",
 	video_inputs:	4,
 	audio_inputs:   1,
@@ -830,22 +853,22 @@
 	audiomux:       { 2, 0, 0, 0, 10},
 	needs_tvaudio:  0,
 	pll:		PLL_28,
-	tuner_type:	TUNER_TEMIC_PAL_I,
+	tuner_type:	TUNER_TEMIC_PAL,
 },{
 
 /* ---- card 0x38 ---------------------------------- */
-	/* Gordon Heydon <gjheydon@bigfoot.com */
+	/* Gordon Heydon <gjheydon@bigfoot.com ('98) */
 	name:           "FlyVideo '98/FM",
 	video_inputs:   3,
 	audio_inputs:   3,
 	tuner:          0,
 	svhs:           2,
 	gpiomask:       0x1800,
-	muxsel:         { 2, 3, 1, 1},
+	muxsel:         { 2, 3, 0, 1},
 	audiomux:       { 0, 0x800, 0, 0, 0x1800, 0 },
 	needs_tvaudio:  1,
 	pll:            PLL_28,
-	tuner_type:     -1,
+	tuner_type:     5,
 },{
 	/* This is the ultimate cheapo capture card 
 	 * just a BT848A on a small PCB!
@@ -875,6 +898,112 @@
         needs_tvaudio:  1,
         pll:            PLL_NONE,
         tuner_type:     TUNER_TEMIC_4036FY5_NTSC,
+},{
+	/* Matti Mottus <mottus@physic.ut.ee> */
+	name:		"TV Capturer",
+	video_inputs:	4,
+	audio_inputs:	1,
+	tuner:		0,
+	svhs:		2,
+        gpiomask:       0x03000F,
+	muxsel:		{ 2, 3, 1, 0},
+        audiomux:       { 2,0,0,0,1 },
+	pll:            PLL_28,
+	tuner_type:	0,
+},{
+
+/* ---- card 0x3c ---------------------------------- */
+	/* Philip Blundell <philb@gnu.org> */
+	name:           "MM100PCTV",
+	video_inputs:   2,
+	audio_inputs:   2,
+	gpiomask:       11,
+	muxsel:         { 2, 3, 1, 1},
+	audiomux:       { 2, 0, 0, 1, 8},
+	pll:            PLL_NONE,
+	tuner_type:     TUNER_TEMIC_PAL,
+
+},{
+	/* Adrian Cox <adrian@humboldt.co.uk */
+	name:	        "AG Electronics GMV1",
+	video_inputs:   2,
+	audio_inputs:   0,
+	tuner:	        -1,
+	svhs:	        1,
+	gpiomask:       0xF,
+	muxsel:	        { 2, 2},
+	audiomux:       { },
+	no_msp34xx:     1,
+	needs_tvaudio:  0,
+	pll:	        PLL_28,
+	tuner_type:     -1,
+},{
+	/* Miguel Angel Alvarez <maacruz@navegalia.com>
+	   new Easy TV BT878 version (model CPH061) 
+	   special thanks to Informatica Mieres for providing the card */
+	name:           "BESTBUY Easy TV (bt878)",
+	video_inputs:	3,
+	audio_inputs:   2,
+	tuner:          0,
+	svhs:           2,
+	gpiomask:       0xFF,
+	muxsel:         { 2, 3, 1, 0},
+	audiomux:       { 1, 0, 4, 4, 9},
+	needs_tvaudio:  0,
+	pll:		PLL_28,
+	tuner_type:	TUNER_PHILIPS_PAL,
+},{
+	/* Lukas Gebauer <geby@volny.cz> */
+	name:		"ATI TV-Wonder",
+	video_inputs:	3,
+	audio_inputs:	1,
+	tuner:		0,
+	svhs:		2,
+	gpiomask:	0xf03f,
+	muxsel:		{ 2, 3, 0, 1},
+	audiomux:	{ 0xbffe, 0, 0xbfff, 0, 0xbffe},
+	pll:		PLL_28,
+	tuner_type:	TUNER_TEMIC_4006FN5_MULTI_PAL,
+},{
+
+/* ---- card 0x40 ---------------------------------- */
+	/* Lukas Gebauer <geby@volny.cz> */
+	name:		"ATI TV-Wonder VE",
+	video_inputs:	2,
+	audio_inputs:	1,
+	tuner:		0,
+	svhs:		-1,
+	gpiomask:	1,
+	muxsel:		{ 2, 3, 0, 1},
+	audiomux:	{ 0, 0, 1, 0, 0},
+	no_msp34xx:	1,
+	pll:		PLL_28,
+	tuner_type:	TUNER_TEMIC_4006FN5_MULTI_PAL,
+},{
+	/* DeeJay <deejay@westel900.net (2000S) */
+	name:           "FlyVideo 2000S",
+	video_inputs:   3,
+	audio_inputs:   3,
+	tuner:          0,
+	svhs:           2,
+	gpiomask:	0x18e0,
+	muxsel:		{ 2, 3, 0, 1},
+	audiomux:	{ 0,0x18e0,0x1000,0x1000,0x1080, 0x1080 },
+	needs_tvaudio:  1,
+	pll:            PLL_28,
+	tuner_type:     5,
+},{
+	name:		"Terratec TValueRadio",
+	video_inputs:	3,
+	audio_inputs:	1,
+	tuner:		0,
+	svhs:		2,
+	gpiomask:	0xffff00,
+	muxsel:		{ 2, 3, 1, 1},
+	audiomux:	{ 0x500, 0x500, 0x300, 0x900, 0x900},
+	needs_tvaudio:	1,
+	pll:		PLL_28,
+	tuner_type:	TUNER_PHILIPS_PAL,
 }};
 
 const int bttv_num_tvcards = (sizeof(bttv_tvcards)/sizeof(struct tvcard));
@@ -1031,6 +1160,14 @@
 		btv->mbox_mask    = 0x38;
 	}
 
+	if (btv->type == BTTV_LIFETEC_9415) {
+		if (btread(BT848_GPIO_DATA) & 0x4000)
+			printk("bttv%d: lifetec: tv mono/fm stereo card\n", btv->nr);
+		else
+			printk("bttv%d: lifetec: stereo(TDA9821) card\n",btv->nr);
+		btv->has_radio=1;
+	}
+
 	/* pll configuration */
         if (!(btv->id==848 && btv->revision==0x11)) {
 		/* defaults from card list */
@@ -1149,19 +1286,19 @@
         { TUNER_TEMIC_4066FY5_PAL_I, "Temic 4066FY5" },
         { TUNER_ABSENT,        "Philips TD1536" },
         { TUNER_ABSENT,        "Philips TD1536D" },
-        { TUNER_ABSENT,        "Philips FMR1236" },
+	{ TUNER_PHILIPS_NTSC,  "Philips FMR1236" }, /* mono radio */
         { TUNER_ABSENT,        "Philips FI1256MP" },
         { TUNER_ABSENT,        "Samsung TCPQ9091P" },
         { TUNER_TEMIC_4006FN5_MULTI_PAL, "Temic 4006FN5" },
         { TUNER_TEMIC_4009FR5_PAL, "Temic 4009FR5" },
         { TUNER_TEMIC_4046FM5,     "Temic 4046FM5" },
-	{ TUNER_ABSENT,        "Temic 4009FN5" },
+	{ TUNER_TEMIC_4009FN5_MULTI_PAL_FM, "Temic 4009FN5" },
 	{ TUNER_ABSENT,        "Philips TD1536D_FH_44"},
-	{ TUNER_ABSENT,	       "LG TP18NSR01F"},
-	{ TUNER_ABSENT,        "LG TP18PSB01D"},
-	{ TUNER_ABSENT,        "LG TP18PSB11D"},	
-	{ TUNER_ABSENT,        "LG TAPC_l001D"},
-	{ TUNER_ABSENT,        "LG TAPC_l701D"}
+	{ TUNER_LG_NTSC_FM,    "LG TP18NSR01F"},
+	{ TUNER_LG_PAL_FM,     "LG TP18PSB01D"},
+	{ TUNER_LG_PAL,        "LG TP18PSB11D"},	
+	{ TUNER_LG_PAL_I_FM,   "LG TAPC-I001D"},
+	{ TUNER_LG_PAL_I,      "LG TAPC-I701D"}
 };
 
 static void __devinit hauppauge_eeprom(struct bttv *btv)
@@ -1394,7 +1531,8 @@
 	int bits_out, loops, vol, data;
 
 	if (!set) {
-		v->mode |= VIDEO_AUDIO_VOLUME;
+		/* Fixed by Leandro Lucarella <luca@linuxmendoza.org.ar (07/31/01) */
+		v->flags |= VIDEO_AUDIO_VOLUME;
 		return;
 	}
 	
@@ -1490,6 +1628,37 @@
 	}
 }
 
+/* Lifetec 9415 handling */
+static void
+lt9415_audio(struct bttv *btv, struct video_audio *v, int set)
+{
+        int val = 0;
+
+        if (btread(BT848_GPIO_DATA) & 0x4000) {
+		v->mode = VIDEO_SOUND_MONO;
+		return;
+	}
+
+        if (set) {
+                if (v->mode & VIDEO_SOUND_LANG2)  /* A2 SAP */
+                        val = 0x0080;
+		if (v->mode & VIDEO_SOUND_STEREO) /* A2 stereo */
+                        val = 0x0880;
+                if ((v->mode & VIDEO_SOUND_LANG1) ||
+		    (v->mode & VIDEO_SOUND_MONO))
+			val = 0;
+                btaor(val, ~0x0880, BT848_GPIO_DATA);
+                if (bttv_gpio)
+                        bttv_gpio_tracking(btv,"lt9415");
+        } else {
+		/* autodetect doesn't work with this card :-( */
+                v->mode = VIDEO_SOUND_MONO | VIDEO_SOUND_STEREO |
+			VIDEO_SOUND_LANG1 | VIDEO_SOUND_LANG2;
+                return;
+        }
+}
+
+
 static void
 terratv_audio(struct bttv *btv, struct video_audio *v, int set)
 {
@@ -1510,6 +1679,31 @@
 	}
 }
 
+static void
+winfast2000_audio(struct bttv *btv, struct video_audio *v, int set)
+{
+	unsigned long val = 0;
+
+	if (set) {
+		/*btor (0xc32000, BT848_GPIO_OUT_EN);*/
+		if (v->mode & VIDEO_SOUND_MONO)		/* Mono */
+			val = 0x420000;
+		if (v->mode & VIDEO_SOUND_LANG1)	/* Mono */
+			val = 0x420000;
+		if (v->mode & VIDEO_SOUND_LANG2)	/* SAP */
+			val = 0x410000;
+		if (v->mode & VIDEO_SOUND_STEREO)	/* Stereo */
+			val = 0x020000;
+		if (val) {
+			btaor(val, ~0x430000, BT848_GPIO_DATA);
+			if (bttv_gpio)
+				bttv_gpio_tracking(btv,"winfast2000");
+		}
+	} else {
+		v->mode = VIDEO_SOUND_MONO | VIDEO_SOUND_STEREO |
+			  VIDEO_SOUND_LANG1 | VIDEO_SOUND_LANG2;
+	}
+}
 
 /* ----------------------------------------------------------------------- */
 /* motherboard chipset specific stuff                                      */
@@ -1525,10 +1719,14 @@
 
 	if (pci_pci_problems & (PCIPCI_TRITON|PCIPCI_NATOMA|PCIPCI_VIAETBF))
 		triton1 = 1;
+	while ((dev = pci_find_device(PCI_VENDOR_ID_VIA, PCI_DEVICE_ID_VIA_82C576, dev)))
+		vsfx = 1;
 
 	/* print warnings about quirks found */
 	if (triton1)
 		printk(KERN_INFO "bttv: Host bridge needs ETBF enabled.\n");
+	if (vsfx)
+		printk(KERN_INFO "bttv: Host bridge needs VSFX enabled.\n");
 
 	if (pcipci_fail) {
 		printk(KERN_WARNING "bttv: BT848 and your chipset may not work together.\n");
@@ -1553,25 +1751,28 @@
 {
  	unsigned char command;
 
-	if (!triton1)
+	if (!triton1 && !vsfx)
 		return 0;
 
-	if (bttv_verbose)
-		printk("bttv%d: enabling 430FX/VP3 compatibilty\n",btv->nr);
+	if (bttv_verbose) {
+		if (triton1)
+			printk("bttv%d: enabling ETBF (430FX/VP3 compatibilty)\n",btv->nr);
+		if (vsfx && btv->id >= 878)
+			printk("bttv%d: enabling VSFX\n",btv->nr);
+	}
 
 	if (btv->id < 878) {
-		/* bt848 (mis)uses a bit in the irq mask */
-		btv->triton1 = BT848_INT_ETBF;
+		/* bt848 (mis)uses a bit in the irq mask for etbf */
+		if (triton1)
+			btv->triton1 = BT848_INT_ETBF;
 	} else {
 		/* bt878 has a bit in the pci config space for it */
                 pci_read_config_byte(btv->dev, BT878_DEVCTRL, &command);
-                command |= BT878_EN_TBFX;
+		if (triton1)
+			command |= BT878_EN_TBFX;
+		if (vsfx)
+			command |= BT878_EN_VSFX;
                 pci_write_config_byte(btv->dev, BT878_DEVCTRL, command);
-                pci_read_config_byte(btv->dev, BT878_DEVCTRL, &command);
-                if (!(command&BT878_EN_TBFX)) {
-                        printk("bttv: 430FX compatibility could not be enabled\n");
-			return -1;
-                }
         }
 	return 0;
 }
diff -u --recursive --new-file v2.4.7/linux/drivers/media/video/bttv-driver.c linux/drivers/media/video/bttv-driver.c
--- v2.4.7/linux/drivers/media/video/bttv-driver.c	Wed Jul 25 17:10:20 2001
+++ linux/drivers/media/video/bttv-driver.c	Sun Aug  5 13:15:05 2001
@@ -69,6 +69,7 @@
 static unsigned int gbuffers = 2;
 static unsigned int gbufsize = BTTV_MAX_FBUF;
 static unsigned int combfilter = 0;
+static unsigned int lumafilter = 0;
 static int video_nr = -1;
 static int radio_nr = -1;
 static int vbi_nr = -1;
@@ -96,6 +97,7 @@
 MODULE_PARM(gbufsize,"i");
 MODULE_PARM_DESC(gbufsize,"size of the capture buffers, default is 0x208000");
 MODULE_PARM(combfilter,"i");
+MODULE_PARM(lumafilter,"i");
 
 MODULE_PARM(video_nr,"i");
 MODULE_PARM(radio_nr,"i");
@@ -699,7 +701,7 @@
 		 vadr+=bl;
 		 if((rcmd&(15<<28))==BT848_RISC_WRITE123)
 		 {
-		 	*((*rp)++)=(kvirt_to_bus(cbadr));
+		 	*((*rp)++)=cpu_to_le32(kvirt_to_bus(cbadr));
 		 	cbadr+=blcb;
 		 	*((*rp)++)=cpu_to_le32(kvirt_to_bus(cradr));
 		 	cradr+=blcr;
@@ -1175,7 +1177,7 @@
 	if(btv->gbuf[mp->frame].stat != GBUFFER_UNUSED)
 		return -EBUSY;
 		
-	if(mp->height < 32 || mp->width < 32)
+	if(mp->height < 32 || mp->width < 48)
 		return -EINVAL;
 	if (mp->format >= PALETTEFMT_MAX)
 		return -EINVAL;
@@ -1391,10 +1393,16 @@
 {
 	struct bttv *btv=(struct bttv *)dev;
  	unsigned long irq_flags;
+	int need_wait;
 
 	down(&btv->lock);
 	btv->user--;
 	spin_lock_irqsave(&btv->s_lock, irq_flags);
+	need_wait = (-1 != btv->gq_grab);
+	btv->gq_start = 0;
+	btv->gq_in = 0;
+	btv->gq_out = 0;
+	btv->gq_grab = -1;
 	btv->scr_on = 0;
 	btv->risc_cap_odd = 0;
 	btv->risc_cap_even = 0;
@@ -1410,7 +1418,7 @@
 
 	btread(BT848_I2C); 	/* This fixes the PCI posting delay */
 	
-	if (-1 != btv->gq_grab) {
+	if (need_wait) {
 		/*
 		 *	This is sucky but right now I can't find a good way to
 		 *	be sure its safe to free the buffer. We wait 5-6 fields
@@ -1504,7 +1512,7 @@
 		b.audios = bttv_tvcards[btv->type].audio_inputs;
 		b.maxwidth = tvnorms[btv->win.norm].swidth;
 		b.maxheight = tvnorms[btv->win.norm].sheight;
-		b.minwidth = 32;
+		b.minwidth = 48;
 		b.minheight = 32;
 		if(copy_to_user(arg,&b,sizeof(b)))
 			return -EFAULT;
@@ -1717,13 +1725,11 @@
 	case VIDIOCGWIN:
 	{
 		struct video_window vw;
-		/* Oh for a COBOL move corresponding .. */
+		memset(&vw,0,sizeof(vw));
 		vw.x=btv->win.x;
 		vw.y=btv->win.y;
 		vw.width=btv->win.width;
 		vw.height=btv->win.height;
-		vw.chromakey=0;
-		vw.flags=0;
 		if(btv->win.interlace)
 			vw.flags|=VIDEO_WINDOW_INTERLACE;
 		if(copy_to_user(arg,&vw,sizeof(vw)))
@@ -2196,6 +2202,10 @@
 	}
 	case VIDIOCGFREQ:
 	case VIDIOCSFREQ:
+	case VIDIOCGTUNER:
+	case VIDIOCSTUNER:
+	case VIDIOCGCHAN:
+	case VIDIOCSCHAN:
 	case BTTV_VERSION:
 		return bttv_ioctl(dev-2,cmd,arg);
 	case BTTV_VBISIZE:
@@ -2290,8 +2300,11 @@
 		if(v.tuner||btv->channel)	/* Only tuner 0 */
 			return -EINVAL;
 		strcpy(v.name, "Radio");
-		v.rangelow=(int)(76*16);	/* jp: 76.0MHz - 89.9MHz  */
-		v.rangehigh=(int)(108*16);	/* eu: 87.5MHz - 108.0MHz */
+		/* japan:          76.0 MHz -  89.9 MHz
+		   western europe: 87.5 MHz - 108.0 MHz
+		   russia:         65.0 MHz - 108.0 MHz */
+		v.rangelow=(int)(65*16);
+		v.rangehigh=(int)(108*16);
 		v.flags= 0; /* XXX */
 		v.mode = 0; /* XXX */
 		bttv_call_i2c_clients(btv,cmd,&v);
@@ -2441,20 +2454,22 @@
 		bt848_dma(btv, 0);
 }
 
+# define do_video_register(dev,type,nr) video_register_device(dev,type,nr)
+
 static int __devinit init_video_dev(struct bttv *btv)
 {
 	audio(btv, AUDIO_MUTE, 1);
         
-	if(video_register_device(&btv->video_dev,VFL_TYPE_GRABBER,video_nr)<0)
+	if(do_video_register(&btv->video_dev,VFL_TYPE_GRABBER,video_nr)<0)
 		return -1;
-	if(video_register_device(&btv->vbi_dev,VFL_TYPE_VBI,vbi_nr)<0) 
+	if(do_video_register(&btv->vbi_dev,VFL_TYPE_VBI,vbi_nr)<0) 
         {
 	        video_unregister_device(&btv->video_dev);
 		return -1;
 	}
 	if (btv->has_radio)
 	{
-		if(video_register_device(&btv->radio_dev, VFL_TYPE_RADIO, radio_nr)<0) 
+		if(do_video_register(&btv->radio_dev, VFL_TYPE_RADIO, radio_nr)<0) 
                 {
 		        video_unregister_device(&btv->vbi_dev);
 		        video_unregister_device(&btv->video_dev);
@@ -2491,8 +2506,8 @@
 	btv->win.interlace=1;
 	btv->win.x=0;
 	btv->win.y=0;
-	btv->win.width=768; /* 640 */
-	btv->win.height=576; /* 480 */
+	btv->win.width=320;
+	btv->win.height=240;
 	btv->win.bpp=2;
 	btv->win.depth=16;
 	btv->win.color_fmt=BT848_COLOR_FMT_RGB16;
@@ -2542,9 +2557,6 @@
 
 	btv->fbuffer=NULL;
 
-	bt848_muxsel(btv, 1);
-	bt848_set_winsize(btv);
-
 /*	btwrite(0, BT848_TDEC); */
         btwrite(0x10, BT848_COLOR_CTL);
 	btwrite(0x00, BT848_CAP_CTL);
@@ -2574,8 +2586,13 @@
 	btwrite(/*BT848_ADC_SYNC_T|*/
 		BT848_ADC_RESERVED|BT848_ADC_CRUSH, BT848_ADC);
 
-	btwrite(BT848_CONTROL_LDEC, BT848_E_CONTROL);
-	btwrite(BT848_CONTROL_LDEC, BT848_O_CONTROL);
+	if (lumafilter) {
+		btwrite(0, BT848_E_CONTROL);
+		btwrite(0, BT848_O_CONTROL);
+	} else {
+		btwrite(BT848_CONTROL_LDEC, BT848_E_CONTROL);
+		btwrite(BT848_CONTROL_LDEC, BT848_O_CONTROL);
+	}
 
 	btv->picture.colour=254<<7;
 	btv->picture.brightness=128<<8;
@@ -2599,6 +2616,8 @@
 		BT848_INT_FMTCHG|BT848_INT_HLOCK,
 		BT848_INT_MASK);
 
+	bt848_muxsel(btv, 1);
+	bt848_set_winsize(btv);
 	make_vbitab(btv);
 	spin_lock_irqsave(&btv->s_lock, irq_flags);
 	bt848_set_risc_jmps(btv,-1);
@@ -2749,7 +2768,7 @@
 				wake_up_interruptible(&btv->capq);
 				break;
 			}
-			if (stat&(8<<28)) 
+			if (stat&(8<<28) && btv->gq_start) 
 			{
 				spin_lock(&btv->s_lock);
 				btv->gq_start = 0;
diff -u --recursive --new-file v2.4.7/linux/drivers/media/video/bttv.h linux/drivers/media/video/bttv.h
--- v2.4.7/linux/drivers/media/video/bttv.h	Wed Apr 11 19:02:36 2001
+++ linux/drivers/media/video/bttv.h	Sun Aug  5 13:15:05 2001
@@ -72,9 +72,15 @@
 #define BTTV_EAGLE         0x33
 #define BTTV_PINNACLEPRO   0x34
 #define BTTV_TVIEW_RDS_FM  0x35
-#define BTTV_LIVETEC_9415  0x36
+#define BTTV_LIFETEC_9415  0x36
 #define BTTV_BESTBUY_EASYTV 0x37
 #define BTTV_FLYVIDEO_98FM 0x38
+#define BTTV_GMV1          0x3d
+#define BTTV_BESTBUY_EASYTV2 0x3e
+#define BTTV_ATI_TVWONDER  0x3f
+#define BTTV_ATI_TVWONDERVE 0x40
+#define BTTV_FLYVIDEO2000   0x41
+#define BTTV_TERRATVALUER   0x42
 
 /* i2c address list */
 #define I2C_TSA5522        0xc2
@@ -190,15 +196,12 @@
 
 /* i2c */
 #define I2C_CLIENTS_MAX 8
-extern struct i2c_algo_bit_data bttv_i2c_algo_template;
-extern struct i2c_adapter bttv_i2c_adap_template;
-extern struct i2c_client bttv_i2c_client_template;
 extern void bttv_bit_setscl(void *data, int state);
 extern void bttv_bit_setsda(void *data, int state);
 extern void bttv_call_i2c_clients(struct bttv *btv, unsigned int cmd, void *arg);
 extern int bttv_I2CRead(struct bttv *btv, unsigned char addr, char *probe_for);
 extern int bttv_I2CWrite(struct bttv *btv, unsigned char addr, unsigned char b1,
-	     unsigned char b2, int both);
+			 unsigned char b2, int both);
 extern void bttv_readee(struct bttv *btv, unsigned char *eedata, int addr);
 
 #endif /* _BTTV_H_ */
diff -u --recursive --new-file v2.4.7/linux/drivers/media/video/bttvp.h linux/drivers/media/video/bttvp.h
--- v2.4.7/linux/drivers/media/video/bttvp.h	Mon Feb 19 14:43:36 2001
+++ linux/drivers/media/video/bttvp.h	Sun Aug  5 13:15:05 2001
@@ -25,7 +25,7 @@
 #ifndef _BTTVP_H_
 #define _BTTVP_H_
 
-#define BTTV_VERSION_CODE KERNEL_VERSION(0,7,57)
+#define BTTV_VERSION_CODE KERNEL_VERSION(0,7,72)
 
 
 #include <linux/types.h>
@@ -195,20 +195,8 @@
 };
 #endif
 
-#if defined(__powerpc__) /* big-endian */
-extern __inline__ void io_st_le32(volatile unsigned *addr, unsigned val)
-{
-        __asm__ __volatile__ ("stwbrx %1,0,%2" : \
-                            "=m" (*addr) : "r" (val), "r" (addr));
-      __asm__ __volatile__ ("eieio" : : : "memory");
-}
-
-#define btwrite(dat,adr)  io_st_le32((unsigned *)(btv->bt848_mem+(adr)),(dat))
-#define btread(adr)       ld_le32((unsigned *)(btv->bt848_mem+(adr)))
-#else
 #define btwrite(dat,adr)    writel((dat), (char *) (btv->bt848_mem+(adr)))
 #define btread(adr)         readl(btv->bt848_mem+(adr))
-#endif
 
 #define btand(dat,adr)      btwrite((dat) & btread(adr), adr)
 #define btor(dat,adr)       btwrite((dat) | btread(adr), adr)
diff -u --recursive --new-file v2.4.7/linux/drivers/media/video/meye.c linux/drivers/media/video/meye.c
--- v2.4.7/linux/drivers/media/video/meye.c	Wed Jul 25 17:10:20 2001
+++ linux/drivers/media/video/meye.c	Sat Jul 28 12:35:55 2001
@@ -209,28 +209,23 @@
 
 /* return a page table pointing to N pages of locked memory */
 static void *ptable_alloc(int npages, u32 *pt_addr) {
-	int i = 0;
+	int i;
 	void *vmem;
-	u32 ptable[npages+1];
-	signed long size;
+	u32 *ptable;
 	unsigned long adr;
 
-	size = (npages + 1) * PAGE_SIZE;
-	vmem = rvmalloc(size);
+	vmem = rvmalloc((npages + 1) * PAGE_SIZE);
 	if (!vmem)
 		return NULL;
 
-	memset(ptable, 0, sizeof(ptable));
         adr = (unsigned long)vmem;
-	while (size > 0) {
-		ptable[i++] = virt_to_bus(__va(kvirt_to_pa(adr)));
+	ptable = (u32 *)(vmem + npages * PAGE_SIZE);
+	for (i = 0; i < npages; i++) {
+		ptable[i] = (u32) kvirt_to_bus(adr);
 		adr += PAGE_SIZE;
-		size -= PAGE_SIZE;
 	}
 
-	memcpy(vmem + npages * PAGE_SIZE, ptable, PAGE_SIZE);
-	*pt_addr = ptable[npages];
-
+	*pt_addr = (u32) kvirt_to_bus(adr);
 	return vmem;
 }
 
diff -u --recursive --new-file v2.4.7/linux/drivers/media/video/meye.h linux/drivers/media/video/meye.h
--- v2.4.7/linux/drivers/media/video/meye.h	Wed Jul 25 17:10:20 2001
+++ linux/drivers/media/video/meye.h	Sat Jul 28 12:35:55 2001
@@ -29,7 +29,7 @@
 #define _MEYE_PRIV_H_
 
 #define MEYE_DRIVER_MAJORVERSION	1
-#define MEYE_DRIVER_MINORVERSION	0
+#define MEYE_DRIVER_MINORVERSION	1
 
 /****************************************************************************/
 /* Motion JPEG chip registers                                               */
diff -u --recursive --new-file v2.4.7/linux/drivers/media/video/msp3400.c linux/drivers/media/video/msp3400.c
--- v2.4.7/linux/drivers/media/video/msp3400.c	Tue Mar  6 19:44:35 2001
+++ linux/drivers/media/video/msp3400.c	Sun Aug  5 13:15:05 2001
@@ -57,6 +57,7 @@
 #include <linux/unistd.h>
 
 #include "audiochip.h"
+#include "msp3400.h"
 
 /* Addresses to scan */
 static unsigned short normal_i2c[] = {I2C_CLIENT_END};
@@ -81,6 +82,12 @@
 static int simple  = -1;   /* use short programming (>= msp3410 only) */
 static int dolby   = 0;
 
+#define DFP_COUNT 0x41
+static const int bl_dfp[] = {
+	0x00, 0x01, 0x02, 0x03,  0x06, 0x08, 0x09, 0x0a,
+	0x0b, 0x0d, 0x0e, 0x10
+};
+
 struct msp3400c {
 	int simple;
 	int nicam;
@@ -90,12 +97,15 @@
 	int nicam_on;
 	int acb;
 	int main, second;	/* sound carrier */
-	int scart;              /* input is scart */
+	int scart;              /* input is scart (extern) */
 
 	int muted;
 	int left, right;	/* volume */
 	int bass, treble;
 
+	/* shadow register set */
+	int dfp_regs[DFP_COUNT];
+
 	/* thread */
 	struct task_struct  *thread;
 	wait_queue_head_t    wq;
@@ -525,6 +535,8 @@
 		src = 0x0010 | nicam;
 		break;
 	}
+	if (msp->scart)
+		src |= 0x0200;
 	if (dolby) {
 		msp3400c_write(client,I2C_MSP3400C_DFP, 0x0008,0x0520);
 		msp3400c_write(client,I2C_MSP3400C_DFP, 0x0009,0x0620);
@@ -534,6 +546,7 @@
 		msp3400c_write(client,I2C_MSP3400C_DFP, 0x0008,src);
 		msp3400c_write(client,I2C_MSP3400C_DFP, 0x0009,src);
 		msp3400c_write(client,I2C_MSP3400C_DFP, 0x000a,src);
+		msp3400c_write(client,I2C_MSP3400C_DFP, 0x000b,src);
 	}
 }
 
@@ -561,6 +574,19 @@
 	}
 }
 
+static void
+msp3400c_restore_dfp(struct i2c_client *client)
+{
+	struct msp3400c *msp = client->data;
+	int i;
+
+	for (i = 0; i < DFP_COUNT; i++) {
+		if (-1 == msp->dfp_regs[i])
+			continue;
+		msp3400c_write(client,I2C_MSP3400C_DFP, i, msp->dfp_regs[i]);
+	}
+}
+
 /* ----------------------------------------------------------------------- */
 
 struct REGISTER_DUMP {
@@ -901,8 +927,9 @@
 			break;
 		}
 
-		/* unmute */
+		/* unmute + restore dfp registers */
 		msp3400c_setvolume(client, msp->muted, msp->left, msp->right);
+		msp3400c_restore_dfp(client);
 
 		if (msp->watch_stereo)
 			mod_timer(&msp->wake_stereo, jiffies+5*HZ);
@@ -1139,10 +1166,11 @@
 			break;
 		}
 		
-		/* unmute */
+		/* unmute + restore dfp registers */
 		msp3400c_setbass(client, msp->bass);
 		msp3400c_settreble(client, msp->treble);
 		msp3400c_setvolume(client, msp->muted, msp->left, msp->right);
+		msp3400c_restore_dfp(client);
 
 		if (msp->watch_stereo)
 			mod_timer(&msp->wake_stereo, jiffies+HZ);
@@ -1189,7 +1217,7 @@
 	DECLARE_MUTEX_LOCKED(sem);
 	struct msp3400c *msp;
         struct i2c_client *c;
-	int              rev1,rev2=0,i;
+	int              rev1,rev2,i;
 
         client_template.adapter = adap;
         client_template.addr = addr;
@@ -1212,6 +1240,9 @@
 	msp->right  = 65535;
 	msp->bass   = 32768;
 	msp->treble = 32768;
+	for (i = 0; i < DFP_COUNT; i++)
+		msp->dfp_regs[i] = -1;
+
 	c->data = msp;
 	init_waitqueue_head(&msp->wq);
 
@@ -1331,18 +1362,25 @@
 	switch (cmd) {
 
 	case AUDC_SET_INPUT:
-#if 1
+		/* scart switching
+		     - IN1 is often used for external input
+		     - Hauppauge uses IN2 for the radio */
 		dprintk(KERN_DEBUG "msp34xx: AUDC_SET_INPUT(%d)\n",*sarg);
-		/* hauppauge 44xxx scart switching */
 		msp->scart = 0;
 		switch (*sarg) {
 		case AUDIO_RADIO:
 			msp3400c_set_scart(client,SCART_IN2,0);
+			msp3400c_write(client,I2C_MSP3400C_DFP,0x000d,0x1900);
+			msp3400c_setstereo(client,msp->stereo);
 			break;
 		case AUDIO_EXTERN:
-			msp->scart   = 1;
+			msp->scart = 1;
 			msp3400c_set_scart(client,SCART_IN1,0);
-			msp3400c_write(client,I2C_MSP3400C_DFP,0x0008,0x0220);
+			msp3400c_write(client,I2C_MSP3400C_DFP,0x000d,0x1900);
+			msp3400c_setstereo(client,msp->stereo);
+			break;
+		case AUDIO_TUNER:
+			msp3400c_setstereo(client,msp->stereo);
 			break;
 		default:
 			if (*sarg & AUDIO_MUTE)
@@ -1351,7 +1389,6 @@
 		}
 		if (msp->active)
 			msp->restart = 1;
-#endif
 		break;
 
 	case AUDC_SET_RADIO:
@@ -1373,6 +1410,33 @@
 			msp->restart = 1;
 		break;
 
+#if 1
+	/* work-in-progress:  hook to control the DFP registers */
+	case MSP_SET_DFPREG:
+	{
+		struct msp_dfpreg *r = arg;
+		int i;
+
+		if (r->reg < 0 || r->reg >= DFP_COUNT)
+			return -EINVAL;
+		for (i = 0; i < sizeof(bl_dfp)/sizeof(int); i++)
+			if (r->reg == bl_dfp[i])
+				return -EINVAL;
+		msp->dfp_regs[r->reg] = r->value;
+		msp3400c_write(client,I2C_MSP3400C_DFP,r->reg,r->value);
+		return 0;
+	}
+	case MSP_GET_DFPREG:
+	{
+		struct msp_dfpreg *r = arg;
+
+		if (r->reg < 0 || r->reg >= DFP_COUNT)
+			return -EINVAL;
+		r->value = msp3400c_read(client,I2C_MSP3400C_DFP,r->reg);
+		return 0;
+	}
+#endif
+
 	/* --- v4l ioctls --- */
 	/* take care: bttv does userspace copying, we'll get a
 	   kernel pointer here... */
@@ -1443,82 +1507,9 @@
 		break;
 	}
 
-	/* --- v4l2 ioctls --- */
-	/* NOT YET */
-
-#if 0
-	/* --- old, obsolete interface --- */
-	case AUDC_SET_TVNORM:
-		msp->norm = *iarg;
-		break;
-	case AUDC_SWITCH_MUTE:
-		/* channels switching step one -- mute */
-		msp->watch_stereo=0;
-		del_timer(&msp->wake_stereo);
-		msp3400c_setvolume(client,0,0);
-		break;
-	case AUDC_NEWCHANNEL:
-		/* channels switching step two -- trigger sound carrier scan */
-		msp->watch_stereo=0;
-		del_timer(&msp->wake_stereo);
-		if (msp->active)
-			msp->restart = 1;
-		wake_up_interruptible(&msp->wq);
-		break;
-
-	case AUDC_GET_VOLUME_LEFT:
-		*sarg = msp->left;
-		break;
-	case AUDC_GET_VOLUME_RIGHT:
-		*sarg = msp->right;
-		break;
-	case AUDC_SET_VOLUME_LEFT:
-		msp->left = *sarg;
-		msp3400c_setvolume(client,msp->left, msp->right);
-		break;
-	case AUDC_SET_VOLUME_RIGHT:
-		msp->right = *sarg;
-		msp3400c_setvolume(client,msp->left, msp->right);
-		break;
-
-	case AUDC_GET_BASS:
-		*sarg = msp->bass;
-		break;
-	case AUDC_SET_BASS:
-		msp->bass = *sarg;
-		msp3400c_setbass(client,msp->bass);
-		break;
-
-	case AUDC_GET_TREBLE:
-		*sarg = msp->treble;
-		break;
-	case AUDC_SET_TREBLE:
-		msp->treble = *sarg;
-		msp3400c_settreble(client,msp->treble);
-		break;
-
-	case AUDC_GET_STEREO:	
-	        autodetect_stereo(client);
-	        *sarg = msp->stereo;		
-		break;
-	case AUDC_SET_STEREO:
-		if (*sarg) {
-			msp->watch_stereo=0;
-			del_timer(&msp->wake_stereo);
-			msp->stereo = *sarg;
-			msp3400c_setstereo(client,*sarg);
-		}
-		break;
-
-	case AUDC_GET_DC:
-		if (msp->simple)
-			break; /* fixme */
-		*sarg = ((int)msp3400c_read(client, I2C_MSP3400C_DFP, 0x1b) +
-			 (int)msp3400c_read(client, I2C_MSP3400C_DFP, 0x1c));
-		break;
-#endif
-	default:;
+	default:
 		/* nothing */
+		break;
 	}
 	return 0;
 }
diff -u --recursive --new-file v2.4.7/linux/drivers/media/video/msp3400.h linux/drivers/media/video/msp3400.h
--- v2.4.7/linux/drivers/media/video/msp3400.h	Wed Dec 31 16:00:00 1969
+++ linux/drivers/media/video/msp3400.h	Sun Aug  5 13:15:05 2001
@@ -0,0 +1,14 @@
+#ifndef MSP3400_H
+#define MSP3400_H
+
+/* ---------------------------------------------------------------------- */
+
+struct msp_dfpreg {
+    int reg;
+    int value;
+};
+
+#define MSP_SET_DFPREG     _IOW('m',15,struct msp_dfpreg)
+#define MSP_GET_DFPREG     _IOW('m',16,struct msp_dfpreg)
+
+#endif /* MSP3400_H */
diff -u --recursive --new-file v2.4.7/linux/drivers/media/video/tda7432.c linux/drivers/media/video/tda7432.c
--- v2.4.7/linux/drivers/media/video/tda7432.c	Fri Feb  9 11:30:23 2001
+++ linux/drivers/media/video/tda7432.c	Sun Aug  5 13:15:05 2001
@@ -5,6 +5,8 @@
  * This driver will not complain if used with any 
  * other i2c device with the same address.
  *
+ * Muting and tone control by Jonathan Isom <jisom@ematic.com>
+ *
  * Copyright (c) 2000 Eric Sandeen <eric_sandeen@bigfoot.com>
  * This code is placed under the terms of the GNU General Public License
  * Based on tda9855.c by Steve VanDeBogart (vandebo@uclink.berkeley.edu)
@@ -16,18 +18,21 @@
  *
  * loudness - set between 0 and 15 for varying degrees of loudness effect
  *
- * TODO:
- *  Implement tone controls
  *
+ *
+ *  Revision: 0.6 - added tone controls
+ *  Revision: 0.5 - Fixed odd balance problem
+ *  Revision: 0.4 - added muting
  *  Revision: 0.3 - Fixed silly reversed volume controls.  :)
  *  Revision: 0.2 - Cleaned up #defines
  *			fixed volume control
- *                  Added I2C_DRIVERID_TDA7432
+ *          Added I2C_DRIVERID_TDA7432
  *			added loudness insmod control
  *  Revision: 0.1 - initial version
  */
 
 #include <linux/module.h>
+#include <linux/init.h>
 #include <linux/kernel.h>
 #include <linux/sched.h>
 #include <linux/string.h>
@@ -75,7 +80,7 @@
 	int addr;
 	int input;
 	int volume;
-	int tone;
+	int bass, treble;
 	int lf, lr, rf, rr;
 	int loud;
 	struct i2c_client c;
@@ -121,7 +126,7 @@
 /* Bits 0,1,2 control input:
  * 0x00 - Stereo input
  * 0x02 - Mono input
- * 0x03 - Mute
+ * 0x03 - Mute  (Using Attenuators Plays better with modules)
  * Mono probably isn't used - I'm guessing only the stereo
  * input is connected on most cards, so we'll set it to stereo.
  * 
@@ -133,7 +138,6 @@
  
 #define TDA7432_STEREO_IN	0
 #define TDA7432_MONO_IN		2	/* Probably won't be used */
-#define TDA7432_MUTE		3	/* Probably won't be used */
 #define TDA7432_BASS_SYM	1 << 3
 #define TDA7432_BASS_NORM	1 << 4
 
@@ -178,7 +182,7 @@
 #define TDA7432_TREBLE_0DB		0xf 
 #define TDA7432_TREBLE			7
 #define TDA7432_TREBLE_GAIN		1 << 3
-#define TDA7432_BASS_0DB		0xf << 4
+#define TDA7432_BASS_0DB		0xf
 #define TDA7432_BASS			7 << 4
 #define TDA7432_BASS_GAIN		1 << 7
 
@@ -200,6 +204,7 @@
  */
 
 #define TDA7432_ATTEN_0DB	0x00
+#define TDA7432_MUTE        0x1 << 5
 
 
 /* Subaddress 0x07 - Loudness Control */
@@ -257,18 +262,19 @@
 	d2printk("tda7432: In tda7432_set\n");
 	
 	dprintk(KERN_INFO 
-		"tda7432: 7432_set(0x%02x,0x%02x,0x%02x,0x%02x,0x%02x,0x%02x,0x%02x,0x%02x)\n",
-		t->input,t->volume,t->tone,t->lf,t->lr,t->rf,t->rr,t->loud);
+		"tda7432: 7432_set(0x%02x,0x%02x,0x%02x,0x%02x,0x%02x,0x%02x,0x%02x,0x%02x,0x%02x)\n",
+		t->input,t->volume,t->bass,t->treble,t->lf,t->lr,t->rf,t->rr,t->loud);
 	buf[0]  = TDA7432_IN;
 	buf[1]  = t->input;
 	buf[2]  = t->volume;
-	buf[3]  = t->tone;
-	buf[4]  = t->lf;
-	buf[5]  = t->lr;
-	buf[6]  = t->rf;
-	buf[7]  = t->rr;
-	buf[8]  = t->loud;
-	if (9 != i2c_master_send(client,buf,9)) {
+	buf[3]  = t->bass;
+	buf[4]	= t->treble;
+	buf[5]  = t->lf;
+	buf[6]  = t->lr;
+	buf[7]  = t->rf;
+	buf[8]  = t->rr;
+	buf[9]  = t->loud;
+	if (10 != i2c_master_send(client,buf,10)) {
 		printk(KERN_WARNING "tda7432: I/O error, trying tda7432_set\n");
 		return -1;
 	}
@@ -287,8 +293,8 @@
 	t->volume = TDA7432_VOL_0DB;	 /* 0dB Volume            */
 	if (loudness)			 /* Turn loudness on?     */
 		t->volume |= TDA7432_LD_ON;	
-	t->tone   = TDA7432_TREBLE_0DB | /* 0dB Treble            */
-		    TDA7432_BASS_0DB; 	 /* 0dB Bass              */
+	t->treble   = TDA7432_TREBLE_0DB; /* 0dB Treble            */
+	t->bass		= TDA7432_BASS_0DB; 	 /* 0dB Bass              */
 	t->lf     = TDA7432_ATTEN_0DB;	 /* 0dB attenuation       */
 	t->lr     = TDA7432_ATTEN_0DB;	 /* 0dB attenuation       */
 	t->rf     = TDA7432_ATTEN_0DB;	 /* 0dB attenuation       */
@@ -353,9 +359,6 @@
 {
 	struct tda7432 *t = client->data;
 	d2printk("tda7432: In tda7432_command\n");
-#if 0
-	__u16 *sarg = arg;
-#endif
 
 	switch (cmd) {
 	/* --- v4l ioctls --- */
@@ -371,7 +374,7 @@
 		va->flags |= VIDEO_AUDIO_VOLUME |
 			VIDEO_AUDIO_BASS |
 			VIDEO_AUDIO_TREBLE;
-
+		va->mode |= VIDEO_SOUND_STEREO;
 		/* Master volume control
 		 * V4L volume is min 0, max 65535
 		 * TDA7432 Volume: 
@@ -389,18 +392,24 @@
 		 * attenuation exists for lf, lr, rf, rr
 		 * we use only lf and rf (front channels)
 		 */
-		 
+		
 		if ( (t->lf) < (t->rf) )
 			/* right is attenuated, balance shifted left */
 			va->balance = (32768 - 1057*(t->rf));
 		else
 			/* left is attenuated, balance shifted right */
 			va->balance = (32768 + 1057*(t->lf));
-
-		/* Bass/treble */
-		va->bass = 32768;   /* brain hurts... set to middle for now */
-		va->treble = 32768; /* brain hurts... set to middle for now */
 		
+		/* Bass/treble */	
+		va->bass=t->bass;
+		if(va->bass >= 0x8)
+				va->bass = ~(va->bass - 0x8) & 0xf;
+		va->bass = va->bass << 12;
+		va->treble=t->treble;
+		if(va->treble >= 0x8)
+				va->treble = ~(va->treble - 0x8) & 0xf;
+		va->treble = va->treble << 12;
+								
 		break; /* VIDIOCGAUDIO case */
 	}
 
@@ -415,26 +424,65 @@
 		if (loudness)		/* Turn on the loudness bit */
 			t->volume |= TDA7432_LD_ON;
 		
-		if (va->balance < 32768) {
+		if(va->flags & VIDEO_AUDIO_BASS)
+		{
+			t->bass = va->bass >> 12;
+			if(t->bass>= 0x8)
+					t->bass = (~t->bass & 0xf) + 0x8 ;
+			t->bass = t->bass | 0x10;
+		}
+		if(va->flags & VIDEO_AUDIO_TREBLE)
+		{
+			t->treble= va->treble >> 12;
+			if(t->treble>= 0x8)
+					t->treble = (~t->treble & 0xf) + 0x8 ;
+						
+		}
+		
+		if (va->balance < 32768) 
+		{
 			/* shifted to left, attenuate right */
 			t->rr = (32768 - va->balance)/1057;
 			t->rf = t->rr;
+			t->lr = TDA7432_ATTEN_0DB;
+			t->lf = TDA7432_ATTEN_0DB;	
 		}
-		else {
+		else if(va->balance > 32769)
+		{
 			/* shifted to right, attenuate left */
 			t->lf = (va->balance - 32768)/1057;
 			t->lr = t->lf;
+			t->rr = TDA7432_ATTEN_0DB;
+			t->rf = TDA7432_ATTEN_0DB;		
 		}
-		
-		/* t->tone = 0xff; */ /* Brain hurts - no tone control for now... */
-
+		else 
+		{
+			/* centered */		
+			t->rr = TDA7432_ATTEN_0DB;
+			t->rf = TDA7432_ATTEN_0DB;
+			t->lf = TDA7432_ATTEN_0DB;
+			t->lr = TDA7432_ATTEN_0DB;
+		}
+					
+		tda7432_write(client,TDA7432_TN, (t->bass << 4)| t->treble );		
 		tda7432_write(client,TDA7432_VL, t->volume);
-		/* tda7432_write(client,TDA7432_TN, t->tone); */
-		tda7432_write(client,TDA7432_LF, t->lf);
-		tda7432_write(client,TDA7432_LR, t->lr);
-		tda7432_write(client,TDA7432_RF, t->rf);
-		tda7432_write(client,TDA7432_RR, t->rr);
-
+		
+		if (va->flags & VIDEO_AUDIO_MUTE)
+		{
+			/* Mute & update balance*/	
+			tda7432_write(client,TDA7432_LF, t->lf | TDA7432_MUTE);
+			tda7432_write(client,TDA7432_LR, t->lr | TDA7432_MUTE);
+			tda7432_write(client,TDA7432_RF, t->rf | TDA7432_MUTE);
+			tda7432_write(client,TDA7432_RR, t->rr | TDA7432_MUTE);
+		}
+		else
+		{	
+			tda7432_write(client,TDA7432_LF, t->lf);
+			tda7432_write(client,TDA7432_LR, t->lr);
+			tda7432_write(client,TDA7432_RF, t->rf);
+			tda7432_write(client,TDA7432_RR, t->rr);
+		}
+							
 		break;
 
 	} /* end of VIDEOCSAUDIO case */
@@ -469,11 +517,7 @@
         &driver
 };
 
-#ifdef MODULE
-int init_module(void)
-#else
 int tda7432_init(void)
-#endif
 {
 
 	if ( (loudness < 0) || (loudness > 15) )
@@ -482,17 +526,17 @@
 		return -EINVAL;
 	}
 
-
 	i2c_add_driver(&driver);
 	return 0;
 }
 
-#ifdef MODULE
-void cleanup_module(void)
+void tda7432_fini(void)
 {
 	i2c_del_driver(&driver);
 }
-#endif
+
+module_init(tda7432_init);
+module_exit(tda7432_fini);
 
 /*
  * Local variables:
diff -u --recursive --new-file v2.4.7/linux/drivers/media/video/tuner.c linux/drivers/media/video/tuner.c
--- v2.4.7/linux/drivers/media/video/tuner.c	Tue Jul  3 17:08:20 2001
+++ linux/drivers/media/video/tuner.c	Sun Aug  5 13:15:05 2001
@@ -36,12 +36,16 @@
 static int addr  =  0;
 static char *pal =  "b";
 static int this_adap;
+static int tv_range[2]    = { 44, 958 };
+static int radio_range[2] = { 65, 108 };
 
 #define dprintk     if (debug) printk
 
 MODULE_PARM(debug,"i");
 MODULE_PARM(type,"i");
 MODULE_PARM(addr,"i");
+MODULE_PARM(tv_range,"2i");
+MODULE_PARM(radio_range,"2i");
 MODULE_PARM(pal,"s");
 
 struct tuner
@@ -173,7 +177,20 @@
 	  16*170.00,16*450.00,0xa0,0x90,0x30,0x8e,623},
 
 	{ "Philips PAL/SECAM multi (FQ1216ME)", Philips, PAL,
-	  16*170.00,16*450.00,0xa0,0x90,0x30,0x8e,623}
+	  16*170.00,16*450.00,0xa0,0x90,0x30,0x8e,623},
+	{ "LG PAL_I+FM (TAPC-I001D)", LGINNOTEK, PAL_I,
+	  16*170.00,16*450.00,0xa0,0x90,0x30,0x8e,623},
+	{ "LG PAL_I (TAPC-I701D)", LGINNOTEK, PAL_I,
+	  16*170.00,16*450.00,0xa0,0x90,0x30,0x8e,623},
+	{ "LG NTSC+FM (TPI8NSR01F)", LGINNOTEK, NTSC,
+	  16*210.00,16*497.00,0xa0,0x90,0x30,0x8e,732},
+
+	{ "LG PAL_BG+FM (TPI8PSB01D)", LGINNOTEK, PAL,
+	  16*170.00,16*450.00,0xa0,0x90,0x30,0x8e,623},
+	{ "LG PAL_BG (TPI8PSB11D)", LGINNOTEK, PAL,
+	  16*170.00,16*450.00,0xa0,0x90,0x30,0x8e,623},
+	{ "Temic PAL* auto + FM (4009 FN5)", TEMIC, PAL,
+	  16*141.00, 16*464.00, 0xa0,0x90,0x30,0x8e,623}
 };
 #define TUNERS (sizeof(tuners)/sizeof(struct tunertype))
 
@@ -234,13 +251,13 @@
         unsigned char buffer[4];
 	int rc;
 
-	if (freq < 45*16 || freq > 890*16) {
+	if (freq < tv_range[0]*16 || freq > tv_range[1]*16) {
 		/* FIXME: better do that chip-specific, but
 		   right now we don't have that in the config
 		   struct and this way is still better than no
 		   check at all */
-		printk("tuner: TV freq out of range\n");
-		return;
+		printk("tuner: TV freq (%d.%02d) out of range (%d-%d)\n",
+		       freq/16,freq%16*100/16,tv_range[0],tv_range[1]);
 	}
 
 	if (t->type == -1) {
@@ -357,8 +374,10 @@
         unsigned char buffer[4];
 	int rc;
 
-	if (freq < 76*16 || freq > 108*16) {
-		printk("tuner: radio freq out of range\n");
+	if (freq < radio_range[0]*16 || freq > radio_range[1]*16) {
+		printk("tuner: radio freq (%d.%02d) out of range (%d-%d)\n",
+		       freq/16,freq%16*100/16,
+		       radio_range[0],radio_range[1]);
 		return;
 	}
 	if (t->type == -1) {
@@ -410,7 +429,7 @@
         client_template.adapter = adap;
         client_template.addr = addr;
 
-        printk("tuner: chip found @ 0x%x\n",addr);
+        printk("tuner: chip found @ 0x%x\n", addr<<1);
 
         if (NULL == (client = kmalloc(sizeof(struct i2c_client), GFP_KERNEL)))
                 return -ENOMEM;
diff -u --recursive --new-file v2.4.7/linux/drivers/media/video/tuner.h linux/drivers/media/video/tuner.h
--- v2.4.7/linux/drivers/media/video/tuner.h	Mon Feb 19 14:43:36 2001
+++ linux/drivers/media/video/tuner.h	Sun Aug  5 13:15:05 2001
@@ -47,10 +47,16 @@
 #define TUNER_TEMIC_4046FM5             22  /* you must actively select B/G, D/K, I, L, L` !  */
 #define TUNER_PHILIPS_PAL_DK		23
 #define TUNER_PHILIPS_FQ1216ME		24  /* you must actively select B/G/D/K, I, L, L` */
+#define TUNER_LG_PAL_I_FM	25
+#define TUNER_LG_PAL_I		26
+#define TUNER_LG_NTSC_FM	27
+#define TUNER_LG_PAL_FM		28
+#define TUNER_LG_PAL		29
+#define TUNER_TEMIC_4009FN5_MULTI_PAL_FM	30  /* B/G, I and D/K autodetected */
 
 
 #define NOTUNER 0
-#define PAL     1
+#define PAL     1	/* PAL_BG */
 #define PAL_I   2
 #define NTSC    3
 #define SECAM   4
@@ -60,6 +66,7 @@
 #define TEMIC   2
 #define Sony    3
 #define Alps    4
+#define LGINNOTEK 5
 
 #define TUNER_SET_TYPE               _IOW('t',1,int)    /* set tuner type */
 #define TUNER_SET_TVFREQ             _IOW('t',2,int)    /* set tv freq */
diff -u --recursive --new-file v2.4.7/linux/drivers/media/video/tvaudio.c linux/drivers/media/video/tvaudio.c
--- v2.4.7/linux/drivers/media/video/tvaudio.c	Tue May  1 16:05:00 2001
+++ linux/drivers/media/video/tvaudio.c	Sun Aug  5 13:15:05 2001
@@ -98,6 +98,7 @@
 	int  inputreg;
 	int  inputmap[8];
 	int  inputmute;
+	int  inputmask;
 };
 static struct CHIPDESC chiplist[];
 
@@ -113,7 +114,7 @@
 
 	/* current settings */
 	__u16 left,right,treble,bass,mode;
-
+	int prevmode;
 	/* thread */
 	struct task_struct  *thread;
 	struct semaphore    *notify;
@@ -124,7 +125,7 @@
 
 
 /* ---------------------------------------------------------------------- */
-/* i2c addresses                                                           */
+/* i2c addresses                                                          */
 
 static unsigned short normal_i2c[] = {
 	I2C_TDA8425   >> 1,
@@ -182,6 +183,18 @@
 	return 0;
 }
 
+static int chip_write_masked(struct CHIPSTATE *chip, int subaddr, int val, int mask)
+{
+	if (mask != 0) {
+		if (-1 == subaddr) {
+			val = (chip->shadow.bytes[1] & ~mask) | (val & mask);
+		} else {
+			val = (chip->shadow.bytes[subaddr+1] & ~mask) | (val & mask);
+		}
+	}
+	return chip_write(chip, subaddr, val);
+}
+
 static int chip_read(struct CHIPSTATE *chip)
 {
 	unsigned char buffer;
@@ -283,7 +296,6 @@
 			continue;
 		
 		/* have a look what's going on */
-		dprintk("%s: thread checkmode\n", chip->c.name);
 		desc->checkmode(chip);
 		
 		/* schedule next check */
@@ -303,10 +315,16 @@
 	struct CHIPDESC  *desc = chiplist + chip->type;
 	int mode = desc->getmode(chip);
 
-	if (mode & VIDEO_SOUND_STEREO)
-		desc->setmode(chip,VIDEO_SOUND_STEREO);
-	else if (mode & VIDEO_SOUND_LANG1)
+	if (mode == chip->prevmode)
+	    return;
+
+	dprintk("%s: thread checkmode\n", chip->c.name);
+	chip->prevmode = mode;
+
+	if (mode & VIDEO_SOUND_LANG1)
 		desc->setmode(chip,VIDEO_SOUND_LANG1);
+	else if (mode & VIDEO_SOUND_STEREO)
+		desc->setmode(chip,VIDEO_SOUND_STEREO);
 	else
 		desc->setmode(chip,VIDEO_SOUND_MONO);
 }
@@ -331,6 +349,9 @@
 #define TDA9840_ST_STEREO  0x40 /* Stereo sound identified        */
 #define TDA9840_PONRES     0x80 /* Power-on reset detected if = 1 */
 
+#define TDA9840_TEST_INT1SN 0x1 /* Integration time 0.5s when set */
+#define TDA9840_TEST_INTFU 0x02 /* Disables integrator function */
+
 int  tda9840_getmode(struct CHIPSTATE *chip)
 {
 	int val, mode;
@@ -528,6 +549,7 @@
  *  1,  0  external stereo
  *  0,  1  external mono
  */
+#define TDA9873_INP_MASK    3
 #define TDA9873_INTERNAL    0
 #define TDA9873_EXT_STEREO  2
 #define TDA9873_EXT_MONO    1
@@ -543,6 +565,7 @@
  *  0, 1, 1   Dual BA
  */
 
+#define TDA9873_TR_MASK     (7 << 2)
 #define TDA9873_TR_MONO     4
 #define TDA9873_TR_STEREO   1 << 4
 #define TDA9873_TR_REVERSE  (1 << 3) & (1 << 2)
@@ -643,10 +666,10 @@
 
 void tda9873_setmode(struct CHIPSTATE *chip, int mode)
 {
-	int sw_data  = chip->shadow.bytes[TDA9873_SW+1] & 0xe3;
+	int sw_data  = chip->shadow.bytes[TDA9873_SW+1] & ~ TDA9873_TR_MASK;
 	/*	int adj_data = chip->shadow.bytes[TDA9873_AD+1] ; */
 
-	if (sw_data & 3) {
+	if ((sw_data & TDA9873_INP_MASK) != TDA9873_INTERNAL) {
 		dprintk("tda9873_setmode(): external input\n");
 		return;
 	}
@@ -667,9 +690,13 @@
 	case VIDEO_SOUND_LANG2:
 		sw_data |= TDA9873_TR_DUALB;
 		break;
+	default:
+		chip->mode = 0;
+		return;
 	}
-	dprintk("tda9873_setmode(): req. mode %d; chip_write: %d\n", mode, sw_data);
-	chip_write(chip,TDA9873_SW,sw_data);
+
+	dprintk("tda9873_setmode(): req. mode %d; chip_write: %d\n",
+		mode, sw_data);
 }
 
 int tda9873_checkit(struct CHIPSTATE *chip)
@@ -777,7 +804,8 @@
 		setmode:    tda9840_setmode,
 		checkmode:  generic_checkmode,
 
-		init:       { 2, { TDA9840_SW, 0x2a } }
+	        init:       { 2, { TDA9840_TEST, TDA9840_TEST_INT1SN
+				/* ,TDA9840_SW, TDA9840_MONO */} }
 	},
 	{
 		name:       "tda9873h",
@@ -795,8 +823,9 @@
 
 		init:       { 4, { TDA9873_SW, 0xa4, 0x06, 0x03 } },
 		inputreg:   TDA9873_SW,
-		inputmute:  0xc0,
-		inputmap:   {0xa4, 0xa2, 0xa4, 0xa4, 0xc0}
+		inputmute:  TDA9873_MUTE | TDA9873_AUTOMUTE,
+		inputmap:   {0xa0, 0xa2, 0xa0, 0xa0, 0xc0},
+		inputmask:  TDA9873_INP_MASK | TDA9873_MUTE | TDA9873_AUTOMUTE
 		
 	},
 	{
@@ -932,7 +961,7 @@
 	chip->c.data = chip;
 
 	/* find description for the chip */
-	dprintk("tvaudio: chip @ addr=0x%x\n",addr<<1);
+	dprintk("tvaudio: chip @ addr=0x%x\n", addr<<1);
 	for (desc = chiplist; desc->name != NULL; desc++) {
 		if (0 == *(desc->insmodopt))
 			continue;
@@ -956,7 +985,7 @@
 	strcpy(chip->c.name,desc->name);
 	chip->type = desc-chiplist;
 	chip->shadow.count = desc->registers+1;
-
+        chip->prevmode = -1;
 	/* register */
 	MOD_INC_USE_COUNT;
 	i2c_attach_client(&chip->c);
@@ -1002,6 +1031,7 @@
 {
 	struct CHIPSTATE *chip = client->data;
 
+	del_timer(&chip->wt);
 	if (NULL != chip->thread) {
 		/* shutdown async thread */
 		DECLARE_MUTEX_LOCKED(sem);
@@ -1034,9 +1064,9 @@
 	case AUDC_SET_INPUT:
 		if (desc->flags & CHIP_HAS_INPUTSEL) {
 			if (*sarg & 0x80)
-				chip_write(chip,desc->inputreg,desc->inputmute);
+				chip_write_masked(chip,desc->inputreg,desc->inputmute,desc->inputmask);
 			else
-				chip_write(chip,desc->inputreg,desc->inputmap[*sarg]);
+				chip_write_masked(chip,desc->inputreg,desc->inputmap[*sarg],desc->inputmask);
 		}
 		break;
 	/* --- v4l ioctls --- */
@@ -1090,9 +1120,11 @@
 	}
 	case VIDIOCSFREQ:
 	{
-		chip->mode = 0; /* automatic */
+	    	chip->mode = 0; /* automatic */
 		if (desc->checkmode) {
 			desc->setmode(chip,VIDEO_SOUND_MONO);
+		    	if (chip->prevmode != VIDEO_SOUND_MONO)
+		    		chip->prevmode = -1; /* reset previous mode */
 			mod_timer(&chip->wt, jiffies+2*HZ);
 			/* the thread will call checkmode() later */
 		}
diff -u --recursive --new-file v2.4.7/linux/drivers/media/video/zr36067.c linux/drivers/media/video/zr36067.c
--- v2.4.7/linux/drivers/media/video/zr36067.c	Wed Jul 25 17:10:20 2001
+++ linux/drivers/media/video/zr36067.c	Wed Jul 25 14:12:02 2001
@@ -50,7 +50,7 @@
 #include <linux/fs.h>
 #include <linux/kernel.h>
 #include <linux/major.h>
-#include <linux/malloc.h>
+#include <linux/slab.h>
 #include <linux/mm.h>
 #include <linux/pci.h>
 #include <linux/signal.h>
@@ -3752,6 +3752,9 @@
 			/*
 			 *   Write the overlay mask if clips are wanted.
 			 */
+			 
+			if (vw.clipcount > 2048)
+				return -EINVAL;
 			if (vw.clipcount) {
 				vcp =
 				    vmalloc(sizeof(struct video_clip) *
diff -u --recursive --new-file v2.4.7/linux/drivers/net/arlan.c linux/drivers/net/arlan.c
--- v2.4.7/linux/drivers/net/arlan.c	Wed Jul 25 17:10:21 2001
+++ linux/drivers/net/arlan.c	Sun Aug  5 13:12:40 2001
@@ -1435,7 +1435,7 @@
 	ARLAN_DEBUG_EXIT("arlan_queue_retransmit");
 };
 
-extern inline void RetryOrFail(struct net_device *dev)
+static inline void RetryOrFail(struct net_device *dev)
 {
 	struct arlan_private *priv = ((struct arlan_private *) dev->priv);
 
diff -u --recursive --new-file v2.4.7/linux/drivers/net/hamradio/scc.c linux/drivers/net/hamradio/scc.c
--- v2.4.7/linux/drivers/net/hamradio/scc.c	Tue Jul  3 17:08:20 2001
+++ linux/drivers/net/hamradio/scc.c	Sun Aug  5 13:12:40 2001
@@ -1775,8 +1775,8 @@
 					Ivec[hwcfg.irq].used = 1;
 			}
 
-			if (hwcfg.vector_latch) {
-				if (!request_region(Vector_Latch, 1, "scc vector latch"))
+			if (hwcfg.vector_latch && !Vector_Latch) {
+				if (!request_region(hwcfg.vector_latch, 1, "scc vector latch"))
 					printk(KERN_WARNING "z8530drv: warning, cannot reserve vector latch port 0x%lx\n, disabled.", hwcfg.vector_latch);
 				else
 					Vector_Latch = hwcfg.vector_latch;
diff -u --recursive --new-file v2.4.7/linux/drivers/net/irda/ali-ircc.c linux/drivers/net/irda/ali-ircc.c
--- v2.4.7/linux/drivers/net/irda/ali-ircc.c	Wed Jul 25 17:10:21 2001
+++ linux/drivers/net/irda/ali-ircc.c	Sun Aug  5 13:12:40 2001
@@ -27,7 +27,7 @@
 #include <linux/netdevice.h>
 #include <linux/ioport.h>
 #include <linux/delay.h>
-#include <linux/malloc.h>
+#include <linux/slab.h>
 #include <linux/init.h>
 #include <linux/rtnetlink.h>
 #include <linux/serial_reg.h>
@@ -331,8 +331,8 @@
 	self->tx_buff.head = (__u8 *) kmalloc(self->tx_buff.truesize, 
 					      GFP_KERNEL|GFP_DMA); 
 	if (self->tx_buff.head == NULL) {
-		kfree(self);
 		kfree(self->rx_buff.head);
+		kfree(self);
 		return -ENOMEM;
 	}
 	memset(self->tx_buff.head, 0, self->tx_buff.truesize);
diff -u --recursive --new-file v2.4.7/linux/drivers/net/irda/irda-usb.c linux/drivers/net/irda/irda-usb.c
--- v2.4.7/linux/drivers/net/irda/irda-usb.c	Tue May  1 16:05:00 2001
+++ linux/drivers/net/irda/irda-usb.c	Sun Aug  5 13:12:40 2001
@@ -33,7 +33,7 @@
 #include <linux/init.h>
 #include <linux/skbuff.h>
 #include <linux/netdevice.h>
-#include <linux/malloc.h>
+#include <linux/slab.h>
 #include <linux/rtnetlink.h>
 #include <linux/usb.h>
 
diff -u --recursive --new-file v2.4.7/linux/drivers/net/ne2.c linux/drivers/net/ne2.c
--- v2.4.7/linux/drivers/net/ne2.c	Tue Jul  3 17:08:20 2001
+++ linux/drivers/net/ne2.c	Sun Aug  5 13:12:40 2001
@@ -118,9 +118,9 @@
 static int irqs[4] __initdata = {3, 4, 5, 9};
 
 /* From the D-Link ADF file: */
-static unsigned int dlink_addresses[4]=
+static unsigned int dlink_addresses[4] __initdata =
                 {0x300, 0x320, 0x340, 0x360};
-static int dlink_irqs[8] = {3, 4, 5, 9, 10, 11, 14, 15};
+static int dlink_irqs[8] __initdata = {3, 4, 5, 9, 10, 11, 14, 15};
 
 struct ne2_adapters_t {
 	unsigned int	id;
@@ -165,7 +165,7 @@
  *
  */
 
-static void dlink_put_eeprom(unsigned char value, unsigned int addr)
+static void __init dlink_put_eeprom(unsigned char value, unsigned int addr)
 {
 	int z;
 	unsigned char v1, v2;
@@ -186,7 +186,7 @@
 	}
 }
 
-static void dlink_send_eeprom_bit(unsigned int bit, unsigned int addr)
+static void __init dlink_send_eeprom_bit(unsigned int bit, unsigned int addr)
 {
 	/* shift data bit into correct position */
 
@@ -200,7 +200,7 @@
 	dlink_put_eeprom(0x09 | bit, addr);
 }
 
-static void dlink_send_eeprom_word(unsigned int value, unsigned int len, unsigned int addr)
+static void __init dlink_send_eeprom_word(unsigned int value, unsigned int len, unsigned int addr)
 {
 	int z;
 
@@ -216,7 +216,7 @@
 	}
 }
 
-static unsigned int dlink_get_eeprom(unsigned int eeaddr, unsigned int addr)
+static unsigned int __init dlink_get_eeprom(unsigned int eeaddr, unsigned int addr)
 {
 	int z;
 	unsigned int value = 0;
diff -u --recursive --new-file v2.4.7/linux/drivers/net/pcmcia/3c574_cs.c linux/drivers/net/pcmcia/3c574_cs.c
--- v2.4.7/linux/drivers/net/pcmcia/3c574_cs.c	Wed Jul 25 17:10:21 2001
+++ linux/drivers/net/pcmcia/3c574_cs.c	Sun Aug  5 13:12:40 2001
@@ -233,7 +233,7 @@
 static int mdio_read(ioaddr_t ioaddr, int phy_id, int location);
 static void mdio_write(ioaddr_t ioaddr, int phy_id, int location, int value);
 static u_short read_eeprom(ioaddr_t ioaddr, int index);
-static void wait_for_completion(struct net_device *dev, int cmd);
+static void tc574_wait_for_completion(struct net_device *dev, int cmd);
 
 static void tc574_reset(struct net_device *dev);
 static void media_check(u_long arg);
@@ -515,8 +515,8 @@
 		outw(0x8040, ioaddr + Wn3_Options);
 		mdelay(1);
 		outw(0xc040, ioaddr + Wn3_Options);
-		wait_for_completion(dev, TxReset);
-		wait_for_completion(dev, RxReset);
+		tc574_wait_for_completion(dev, TxReset);
+		tc574_wait_for_completion(dev, RxReset);
 		mdelay(1);
 		outw(0x8040, ioaddr + Wn3_Options);
 		
@@ -656,7 +656,7 @@
 /*
   Use this for commands that may take time to finish
 */
-static void wait_for_completion(struct net_device *dev, int cmd)
+static void tc574_wait_for_completion(struct net_device *dev, int cmd)
 {
     int i = 1500;
     outw(cmd, dev->base_addr + EL3_CMD);
@@ -764,7 +764,7 @@
 	struct el3_private *lp = (struct el3_private *)dev->priv;
 	int i, ioaddr = dev->base_addr;
 
-	wait_for_completion(dev, TotalReset|0x10);
+	tc574_wait_for_completion(dev, TotalReset|0x10);
 
 	/* Clear any transactions in progress. */
 	outw(0, ioaddr + RunnerWrCtrl);
@@ -787,8 +787,8 @@
 	outw(0x8040, ioaddr + Wn3_Options);
 	mdelay(1);
 	outw(0xc040, ioaddr + Wn3_Options);
-	wait_for_completion(dev, TxReset);
-	wait_for_completion(dev, RxReset);
+	tc574_wait_for_completion(dev, TxReset);
+	tc574_wait_for_completion(dev, RxReset);
 	mdelay(1);
 	outw(0x8040, ioaddr + Wn3_Options);
 
@@ -859,7 +859,7 @@
 	lp->stats.tx_errors++;
 	dev->trans_start = jiffies;
 	/* Issue TX_RESET and TX_START commands. */
-	wait_for_completion(dev, TxReset);
+	tc574_wait_for_completion(dev, TxReset);
 	outw(TxEnable, ioaddr + EL3_CMD);
 	netif_wake_queue(dev);
 }
@@ -876,7 +876,7 @@
 		if (!(tx_status & 0x84)) break;
 		/* reset transmitter on jabber error or underrun */
 		if (tx_status & 0x30)
-			wait_for_completion(dev, TxReset);
+			tc574_wait_for_completion(dev, TxReset);
 		if (tx_status & 0x38) {
 			DEBUG(1, "%s: transmit error: status 0x%02x\n",
 				  dev->name, tx_status);
@@ -968,12 +968,12 @@
 					   " register %04x.\n", dev->name, fifo_diag);
 				if (fifo_diag & 0x0400) {
 					/* Tx overrun */
-					wait_for_completion(dev, TxReset);
+					tc574_wait_for_completion(dev, TxReset);
 					outw(TxEnable, ioaddr + EL3_CMD);
 				}
 				if (fifo_diag & 0x2000) {
 					/* Rx underrun */
-					wait_for_completion(dev, RxReset);
+					tc574_wait_for_completion(dev, RxReset);
 					set_rx_mode(dev);
 					outw(RxEnable, ioaddr + EL3_CMD);
 				}
@@ -1175,7 +1175,7 @@
 				lp->stats.rx_dropped++;
 			}
 		}
-		wait_for_completion(dev, RxDiscard);
+		tc574_wait_for_completion(dev, RxDiscard);
 	}
 
 	return worklimit;
diff -u --recursive --new-file v2.4.7/linux/drivers/net/pcmcia/3c589_cs.c linux/drivers/net/pcmcia/3c589_cs.c
--- v2.4.7/linux/drivers/net/pcmcia/3c589_cs.c	Wed Jul 25 17:10:21 2001
+++ linux/drivers/net/pcmcia/3c589_cs.c	Sun Aug  5 13:12:40 2001
@@ -528,7 +528,7 @@
 /*
   Use this for commands that may take time to finish
 */
-static void wait_for_completion(struct net_device *dev, int cmd)
+static void tc589_wait_for_completion(struct net_device *dev, int cmd)
 {
     int i = 100;
     outw(cmd, dev->base_addr + EL3_CMD);
@@ -686,7 +686,7 @@
     lp->stats.tx_errors++;
     dev->trans_start = jiffies;
     /* Issue TX_RESET and TX_START commands. */
-    wait_for_completion(dev, TxReset);
+    tc589_wait_for_completion(dev, TxReset);
     outw(TxEnable, ioaddr + EL3_CMD);
     netif_wake_queue(dev);
 }
@@ -703,7 +703,7 @@
 	if (!(tx_status & 0x84)) break;
 	/* reset transmitter on jabber error or underrun */
 	if (tx_status & 0x30)
-	    wait_for_completion(dev, TxReset);
+	    tc589_wait_for_completion(dev, TxReset);
 	if (tx_status & 0x38) {
 	    DEBUG(1, "%s: transmit error: status 0x%02x\n",
 		  dev->name, tx_status);
@@ -796,12 +796,12 @@
 		       " register %04x.\n", dev->name, fifo_diag);
 		if (fifo_diag & 0x0400) {
 		    /* Tx overrun */
-		    wait_for_completion(dev, TxReset);
+		    tc589_wait_for_completion(dev, TxReset);
 		    outw(TxEnable, ioaddr + EL3_CMD);
 		}
 		if (fifo_diag & 0x2000) {
 		    /* Rx underrun */
-		    wait_for_completion(dev, RxReset);
+		    tc589_wait_for_completion(dev, RxReset);
 		    set_multicast_list(dev);
 		    outw(RxEnable, ioaddr + EL3_CMD);
 		}
@@ -1003,7 +1003,7 @@
 	    }
 	}
 	/* Pop the top of the Rx FIFO */
-	wait_for_completion(dev, RxDiscard);
+	tc589_wait_for_completion(dev, RxDiscard);
     }
     if (worklimit == 0)
 	printk(KERN_NOTICE "%s: too much work in el3_rx!\n", dev->name);
diff -u --recursive --new-file v2.4.7/linux/drivers/net/pcmcia/ibmtr_cs.c linux/drivers/net/pcmcia/ibmtr_cs.c
--- v2.4.7/linux/drivers/net/pcmcia/ibmtr_cs.c	Wed Jul 25 17:10:21 2001
+++ linux/drivers/net/pcmcia/ibmtr_cs.c	Sun Aug  5 13:12:41 2001
@@ -49,7 +49,7 @@
 #include <linux/init.h>
 #include <linux/sched.h>
 #include <linux/ptrace.h>
-#include <linux/malloc.h>
+#include <linux/slab.h>
 #include <linux/string.h>
 #include <linux/timer.h>
 #include <linux/module.h>
@@ -361,7 +361,7 @@
     mem.CardOffset = mmiobase;
     mem.Page = 0;
     CS_CHECK(MapMemPage, link->win, &mem);
-    ti->mmio = (u_long)ioremap(req.Base, req.Size);
+    ti->mmio = ioremap(req.Base, req.Size);
 
     /* Allocate the SRAM memory window */
     req.Attributes = WIN_DATA_WIDTH_16|WIN_MEMORY_TYPE_CM|WIN_ENABLE;
diff -u --recursive --new-file v2.4.7/linux/drivers/net/sk98lin/skge.c linux/drivers/net/sk98lin/skge.c
--- v2.4.7/linux/drivers/net/sk98lin/skge.c	Wed Jul 25 17:10:21 2001
+++ linux/drivers/net/sk98lin/skge.c	Wed Jul 25 14:12:02 2001
@@ -1473,7 +1473,7 @@
 {
 DEV_NET			*pNet;
 SK_AC			*pAC;
-unsigned int	Flags;		/* for spin lock */
+unsigned long	Flags;		/* for spin lock */
 int		i;
 SK_EVPARA		EvPara;		/* an event parameter union */
 
@@ -1580,7 +1580,7 @@
 DEV_NET		*pNet;
 SK_AC		*pAC;
 
-unsigned int	Flags;		/* for spin lock */
+unsigned long	Flags;		/* for spin lock */
 int				i;
 int				PortIdx;
 SK_EVPARA		EvPara;
@@ -1732,7 +1732,7 @@
 struct sk_buff	*pMessage)	/* pointer to send-message */
 {
 TXD		*pTxd;		/* the rxd to fill */
-unsigned int	Flags;
+unsigned long	Flags;
 SK_U64		PhysAddr;
 int		BytesSend;
 
@@ -1898,7 +1898,7 @@
 RX_PORT		*pRxPort)	/* ptr to port struct for which the ring
 				   should be filled */
 {
-unsigned int	Flags;
+unsigned long	Flags;
 
 	spin_lock_irqsave(&pRxPort->RxDesRingLock, Flags);
 	while (pRxPort->RxdRingFree > pRxPort->RxFillLimit) {
@@ -2329,7 +2329,7 @@
 RX_PORT	*pRxPort)	/* pointer to rx port struct */
 {
 RXD		*pRxd;	/* pointer to the current descriptor */
-unsigned int	Flags;
+unsigned long	Flags;
  SK_U64		PhysAddr;
 
 	if (pRxPort->RxdRingFree == pAC->RxDescrPerRing) {
@@ -2376,7 +2376,7 @@
 {
 TXD		*pTxd;		/* pointer to the current descriptor */
 int		i;
-unsigned int	Flags;
+unsigned long	Flags;
 
 	spin_lock_irqsave(&pTxPort->TxDesRingLock, Flags);
 	pTxd = pTxPort->pTxdRingHead;
@@ -2500,8 +2500,8 @@
 SK_AC	*pAC = pNet->pAC;
 
 struct sockaddr	*addr = p;
-unsigned int	Flags;
-	
+unsigned long	Flags;
+
 	SK_DBG_MSG(NULL, SK_DBGMOD_DRV, SK_DBGCAT_DRV_ENTRY,
 		("SkGeSetMacAddr starts now...\n"));
 	if(netif_running(dev)) {
@@ -2548,7 +2548,7 @@
 struct dev_mc_list	*pMcList;
 int			i;
 int			PortIdx;
-unsigned int		Flags;
+unsigned long		Flags;
 
 	SK_DBG_MSG(NULL, SK_DBGMOD_DRV, SK_DBGCAT_DRV_ENTRY,
 		("SkGeSetRxMode starts now... "));
@@ -2619,7 +2619,7 @@
 DEV_NET		*pNet;
 DEV_NET		*pOtherNet;
 SK_AC		*pAC;
-unsigned int	Flags;
+unsigned long	Flags;
 int		i;
 SK_EVPARA 	EvPara;
 
@@ -2842,7 +2842,7 @@
 SK_PNMI_STRUCT_DATA *pPnmiStruct;       /* structure for all Pnmi-Data */
 SK_PNMI_STAT    *pPnmiStat;             /* pointer to virtual XMAC stat. data */SK_PNMI_CONF    *pPnmiConf;             /* pointer to virtual link config. */
 unsigned int    Size;                   /* size of pnmi struct */
-unsigned int	Flags;			/* for spin lock */
+unsigned long	Flags;			/* for spin lock */
 
 	SK_DBG_MSG(NULL, SK_DBGMOD_DRV, SK_DBGCAT_DRV_ENTRY,
 		("SkGeStats starts now...\n"));
@@ -2966,7 +2966,7 @@
 unsigned int	Size,	/* length of ioctl data */
 int		mode)	/* flag for set/preset */
 {
-unsigned int	Flags;	/* for spin lock */
+unsigned long	Flags;	/* for spin lock */
 SK_AC		*pAC;
 
 	SK_DBG_MSG(NULL, SK_DBGMOD_DRV, SK_DBGCAT_DRV_ENTRY,
@@ -3370,7 +3370,7 @@
 int	StrLen = 80;		/* length of the string, defined in SK_AC */
 char	Keyword[] = VPD_NAME;	/* vpd productname identifier */
 int	ReturnCode;		/* return code from vpd_read */
-unsigned int Flags;
+unsigned long Flags;
 
 	spin_lock_irqsave(&pAC->SlowPathLock, Flags);
 	ReturnCode = VpdRead(pAC, pAC->IoBase, Keyword, pAC->DeviceStr,
@@ -3639,7 +3639,7 @@
 int		ToPort;		/* the port we switch to */
 SK_EVPARA	NewPara;	/* parameter for further events */
 int		Stat;
-unsigned int	Flags;
+unsigned long	Flags;
 
 	switch (Event) {
 	case SK_DRV_ADAP_FAIL:
diff -u --recursive --new-file v2.4.7/linux/drivers/net/sk98lin/skproc.c linux/drivers/net/sk98lin/skproc.c
--- v2.4.7/linux/drivers/net/sk98lin/skproc.c	Wed Jul 25 17:10:21 2001
+++ linux/drivers/net/sk98lin/skproc.c	Wed Jul 25 14:12:02 2001
@@ -103,7 +103,7 @@
 	DEV_NET				*pNet;
 	SK_AC				*pAC;
 	char 				test_buf[100];
-	unsigned int			Flags;		
+	unsigned long			Flags;		
 	unsigned int			Size;
 	struct net_device 		*next;
 	struct net_device 		*SkgeProcDev = root_dev;
diff -u --recursive --new-file v2.4.7/linux/drivers/net/starfire.c linux/drivers/net/starfire.c
--- v2.4.7/linux/drivers/net/starfire.c	Wed Jul 25 17:10:22 2001
+++ linux/drivers/net/starfire.c	Sun Jul 29 21:12:59 2001
@@ -87,8 +87,7 @@
 
 	LK1.3.3 (Ion Badulescu)
 	- Initialize the TxMode register properly
-	- Set the MII registers _after_ resetting it
-	- Don't dereference dev->priv after unregister_netdev() has freed it
+	- Don't dereference dev->priv after freeing it
 
 TODO:
 	- implement tx_timeout() properly
@@ -988,12 +987,12 @@
 	struct netdev_private *np = dev->priv;
 	u16 reg0;
 
+	mdio_write(dev, np->phys[0], MII_ADVERTISE, np->advertising);
 	mdio_write(dev, np->phys[0], MII_BMCR, BMCR_RESET);
 	udelay(500);
 	while (mdio_read(dev, np->phys[0], MII_BMCR) & BMCR_RESET);
 
 	reg0 = mdio_read(dev, np->phys[0], MII_BMCR);
-	mdio_write(dev, np->phys[0], MII_ADVERTISE, np->advertising);
 
 	if (np->autoneg) {
 		reg0 |= BMCR_ANENABLE | BMCR_ANRESTART;
@@ -1940,12 +1939,12 @@
 		pci_free_consistent(pdev, PAGE_SIZE,
 				    np->rx_ring, np->rx_ring_dma);
 
-	unregister_netdev(dev);			/* Will also free np!! */
+	unregister_netdev(dev);
 	iounmap((char *)dev->base_addr);
 	pci_release_regions(pdev);
 
 	pci_set_drvdata(pdev, NULL);
-	kfree(dev);
+	kfree(dev);			/* Will also free np!! */
 }
 
 
diff -u --recursive --new-file v2.4.7/linux/drivers/net/sunhme.c linux/drivers/net/sunhme.c
--- v2.4.7/linux/drivers/net/sunhme.c	Tue Jul  3 17:08:20 2001
+++ linux/drivers/net/sunhme.c	Sat Jul 28 12:12:37 2001
@@ -1,4 +1,4 @@
-/* $Id: sunhme.c,v 1.120 2001/06/14 17:37:23 jgarzik Exp $
+/* $Id: sunhme.c,v 1.121 2001/07/27 10:22:57 davem Exp $
  * sunhme.c: Sparc HME/BigMac 10/100baseT half/full duplex auto switching,
  *           auto carrier detecting ethernet driver.  Also known as the
  *           "Happy Meal Ethernet" found on SunSwift SBUS cards.
@@ -32,6 +32,7 @@
 #include <linux/delay.h>
 #include <linux/init.h>
 #include <linux/ethtool.h>
+#include <linux/mii.h>
 #include <asm/system.h>
 #include <asm/bitops.h>
 #include <asm/io.h>
@@ -569,21 +570,21 @@
  */
 static int try_next_permutation(struct happy_meal *hp, unsigned long tregs)
 {
-	hp->sw_bmcr = happy_meal_tcvr_read(hp, tregs, DP83840_BMCR);
+	hp->sw_bmcr = happy_meal_tcvr_read(hp, tregs, MII_BMCR);
 
 	/* Downgrade from full to half duplex.  Only possible
 	 * via ethtool.
 	 */
 	if (hp->sw_bmcr & BMCR_FULLDPLX) {
 		hp->sw_bmcr &= ~(BMCR_FULLDPLX);
-		happy_meal_tcvr_write(hp, tregs, DP83840_BMCR, hp->sw_bmcr);
+		happy_meal_tcvr_write(hp, tregs, MII_BMCR, hp->sw_bmcr);
 		return 0;
 	}
 
 	/* Downgrade from 100 to 10. */
 	if (hp->sw_bmcr & BMCR_SPEED100) {
 		hp->sw_bmcr &= ~(BMCR_SPEED100);
-		happy_meal_tcvr_write(hp, tregs, DP83840_BMCR, hp->sw_bmcr);
+		happy_meal_tcvr_write(hp, tregs, MII_BMCR, hp->sw_bmcr);
 		return 0;
 	}
 
@@ -599,7 +600,7 @@
 	else
 		printk("internal ");
 	printk("transceiver at ");
-	hp->sw_lpa = happy_meal_tcvr_read(hp, tregs, DP83840_LPA);
+	hp->sw_lpa = happy_meal_tcvr_read(hp, tregs, MII_LPA);
 	if (hp->sw_lpa & (LPA_100HALF | LPA_100FULL)) {
 		if (hp->sw_lpa & LPA_100FULL)
 			printk("100Mb/s, Full Duplex.\n");
@@ -621,7 +622,7 @@
 	else
 		printk("internal ");
 	printk("transceiver at ");
-	hp->sw_bmcr = happy_meal_tcvr_read(hp, tregs, DP83840_BMCR);
+	hp->sw_bmcr = happy_meal_tcvr_read(hp, tregs, MII_BMCR);
 	if (hp->sw_bmcr & BMCR_SPEED100)
 		printk("100Mb/s, ");
 	else
@@ -640,7 +641,7 @@
 	 * proper duplex setting.
 	 */
 	if (hp->timer_state == arbwait) {
-		hp->sw_lpa = happy_meal_tcvr_read(hp, tregs, DP83840_LPA);
+		hp->sw_lpa = happy_meal_tcvr_read(hp, tregs, MII_LPA);
 		if (!(hp->sw_lpa & (LPA_10HALF | LPA_10FULL | LPA_100HALF | LPA_100FULL)))
 			goto no_response;
 		if (hp->sw_lpa & LPA_100FULL)
@@ -653,7 +654,7 @@
 			full = 0;
 	} else {
 		/* Forcing a link mode. */
-		hp->sw_bmcr = happy_meal_tcvr_read(hp, tregs, DP83840_BMCR);
+		hp->sw_bmcr = happy_meal_tcvr_read(hp, tregs, MII_BMCR);
 		if (hp->sw_bmcr & BMCR_FULLDPLX)
 			full = 1;
 		else
@@ -728,11 +729,11 @@
 		if (hp->timer_ticks >= 10) {
 			/* Enter force mode. */
 	do_force_mode:
-			hp->sw_bmcr = happy_meal_tcvr_read(hp, tregs, DP83840_BMCR);
+			hp->sw_bmcr = happy_meal_tcvr_read(hp, tregs, MII_BMCR);
 			printk(KERN_NOTICE "%s: Auto-Negotiation unsuccessful, trying force link mode\n",
 			       hp->dev->name);
 			hp->sw_bmcr = BMCR_SPEED100;
-			happy_meal_tcvr_write(hp, tregs, DP83840_BMCR, hp->sw_bmcr);
+			happy_meal_tcvr_write(hp, tregs, MII_BMCR, hp->sw_bmcr);
 
 			if (!is_lucent_phy(hp)) {
 				/* OK, seems we need do disable the transceiver for the first
@@ -748,7 +749,7 @@
 			restart_timer = 1;
 		} else {
 			/* Anything interesting happen? */
-			hp->sw_bmsr = happy_meal_tcvr_read(hp, tregs, DP83840_BMSR);
+			hp->sw_bmsr = happy_meal_tcvr_read(hp, tregs, MII_BMSR);
 			if (hp->sw_bmsr & BMSR_ANEGCOMPLETE) {
 				int ret;
 
@@ -779,7 +780,7 @@
 		 * forever until some sort of error is signalled, reporting
 		 * a message to the user at 10 second intervals.
 		 */
-		hp->sw_bmsr = happy_meal_tcvr_read(hp, tregs, DP83840_BMSR);
+		hp->sw_bmsr = happy_meal_tcvr_read(hp, tregs, MII_BMSR);
 		if (hp->sw_bmsr & BMSR_LSTATUS) {
 			/* Wheee, it's up, display the link mode in use and put
 			 * the timer to sleep.
@@ -805,7 +806,7 @@
 		 * permutations, but then again this is essentially
 		 * error recovery code for the most part.
 		 */
-		hp->sw_bmsr = happy_meal_tcvr_read(hp, tregs, DP83840_BMSR);
+		hp->sw_bmsr = happy_meal_tcvr_read(hp, tregs, MII_BMSR);
 		hp->sw_csconfig = happy_meal_tcvr_read(hp, tregs, DP83840_CSCONFIG);
 		if (hp->timer_ticks == 1) {
 			if (!is_lucent_phy(hp)) {
@@ -1066,9 +1067,9 @@
 		hp->tcvr_type = internal;
 		hp->paddr = TCV_PADDR_ITX;
 		ASD(("ISOLATE,"));
-		happy_meal_tcvr_write(hp, tregs, DP83840_BMCR,
+		happy_meal_tcvr_write(hp, tregs, MII_BMCR,
 				      (BMCR_LOOPBACK|BMCR_PDOWN|BMCR_ISOLATE));
-		result = happy_meal_tcvr_read(hp, tregs, DP83840_BMCR);
+		result = happy_meal_tcvr_read(hp, tregs, MII_BMCR);
 		if (result == TCVR_FAILURE) {
 			ASD(("phyread_fail>\n"));
 			return -1;
@@ -1082,9 +1083,9 @@
 			ASD(("internal<PSELECT,"));
 			hme_write32(hp, tregs + TCVR_CFG, (tconfig | TCV_CFG_PSELECT));
 			ASD(("ISOLATE,"));
-			happy_meal_tcvr_write(hp, tregs, DP83840_BMCR,
+			happy_meal_tcvr_write(hp, tregs, MII_BMCR,
 					      (BMCR_LOOPBACK|BMCR_PDOWN|BMCR_ISOLATE));
-			result = happy_meal_tcvr_read(hp, tregs, DP83840_BMCR);
+			result = happy_meal_tcvr_read(hp, tregs, MII_BMCR);
 			if (result == TCVR_FAILURE) {
 				ASD(("phyread_fail>\n"));
 				return -1;
@@ -1097,10 +1098,10 @@
 	}
 
 	ASD(("BMCR_RESET "));
-	happy_meal_tcvr_write(hp, tregs, DP83840_BMCR, BMCR_RESET);
+	happy_meal_tcvr_write(hp, tregs, MII_BMCR, BMCR_RESET);
 
 	while (--tries) {
-		result = happy_meal_tcvr_read(hp, tregs, DP83840_BMCR);
+		result = happy_meal_tcvr_read(hp, tregs, MII_BMCR);
 		if (result == TCVR_FAILURE)
 			return -1;
 		hp->sw_bmcr = result;
@@ -1115,18 +1116,18 @@
 	ASD(("RESET_OK\n"));
 
 	/* Get fresh copies of the PHY registers. */
-	hp->sw_bmsr      = happy_meal_tcvr_read(hp, tregs, DP83840_BMSR);
-	hp->sw_physid1   = happy_meal_tcvr_read(hp, tregs, DP83840_PHYSID1);
-	hp->sw_physid2   = happy_meal_tcvr_read(hp, tregs, DP83840_PHYSID2);
-	hp->sw_advertise = happy_meal_tcvr_read(hp, tregs, DP83840_ADVERTISE);
+	hp->sw_bmsr      = happy_meal_tcvr_read(hp, tregs, MII_BMSR);
+	hp->sw_physid1   = happy_meal_tcvr_read(hp, tregs, MII_PHYSID1);
+	hp->sw_physid2   = happy_meal_tcvr_read(hp, tregs, MII_PHYSID2);
+	hp->sw_advertise = happy_meal_tcvr_read(hp, tregs, MII_ADVERTISE);
 
 	ASD(("UNISOLATE"));
 	hp->sw_bmcr &= ~(BMCR_ISOLATE);
-	happy_meal_tcvr_write(hp, tregs, DP83840_BMCR, hp->sw_bmcr);
+	happy_meal_tcvr_write(hp, tregs, MII_BMCR, hp->sw_bmcr);
 
 	tries = TCVR_UNISOLATE_TRIES;
 	while (--tries) {
-		result = happy_meal_tcvr_read(hp, tregs, DP83840_BMCR);
+		result = happy_meal_tcvr_read(hp, tregs, MII_BMCR);
 		if (result == TCVR_FAILURE)
 			return -1;
 		if (!(result & BMCR_ISOLATE))
@@ -1350,14 +1351,14 @@
 	int timeout;
 
 	/* Read all of the registers we are interested in now. */
-	hp->sw_bmsr      = happy_meal_tcvr_read(hp, tregs, DP83840_BMSR);
-	hp->sw_bmcr      = happy_meal_tcvr_read(hp, tregs, DP83840_BMCR);
-	hp->sw_physid1   = happy_meal_tcvr_read(hp, tregs, DP83840_PHYSID1);
-	hp->sw_physid2   = happy_meal_tcvr_read(hp, tregs, DP83840_PHYSID2);
+	hp->sw_bmsr      = happy_meal_tcvr_read(hp, tregs, MII_BMSR);
+	hp->sw_bmcr      = happy_meal_tcvr_read(hp, tregs, MII_BMCR);
+	hp->sw_physid1   = happy_meal_tcvr_read(hp, tregs, MII_PHYSID1);
+	hp->sw_physid2   = happy_meal_tcvr_read(hp, tregs, MII_PHYSID2);
 
 	/* XXX Check BMSR_ANEGCAPABLE, should not be necessary though. */
 
-	hp->sw_advertise = happy_meal_tcvr_read(hp, tregs, DP83840_ADVERTISE);
+	hp->sw_advertise = happy_meal_tcvr_read(hp, tregs, MII_ADVERTISE);
 	if (ep == NULL || ep->autoneg == AUTONEG_ENABLE) {
 		/* Advertise everything we can support. */
 		if (hp->sw_bmsr & BMSR_10HALF)
@@ -1377,7 +1378,7 @@
 			hp->sw_advertise |= (ADVERTISE_100FULL);
 		else
 			hp->sw_advertise &= ~(ADVERTISE_100FULL);
-		happy_meal_tcvr_write(hp, tregs, DP83840_ADVERTISE, hp->sw_advertise);
+		happy_meal_tcvr_write(hp, tregs, MII_ADVERTISE, hp->sw_advertise);
 
 		/* XXX Currently no Happy Meal cards I know off support 100BaseT4,
 		 * XXX and this is because the DP83840 does not support it, changes
@@ -1399,17 +1400,17 @@
 
 		/* Enable Auto-Negotiation, this is usually on already... */
 		hp->sw_bmcr |= BMCR_ANENABLE;
-		happy_meal_tcvr_write(hp, tregs, DP83840_BMCR, hp->sw_bmcr);
+		happy_meal_tcvr_write(hp, tregs, MII_BMCR, hp->sw_bmcr);
 
 		/* Restart it to make sure it is going. */
 		hp->sw_bmcr |= BMCR_ANRESTART;
-		happy_meal_tcvr_write(hp, tregs, DP83840_BMCR, hp->sw_bmcr);
+		happy_meal_tcvr_write(hp, tregs, MII_BMCR, hp->sw_bmcr);
 
 		/* BMCR_ANRESTART self clears when the process has begun. */
 
 		timeout = 64;  /* More than enough. */
 		while (--timeout) {
-			hp->sw_bmcr = happy_meal_tcvr_read(hp, tregs, DP83840_BMCR);
+			hp->sw_bmcr = happy_meal_tcvr_read(hp, tregs, MII_BMCR);
 			if (!(hp->sw_bmcr & BMCR_ANRESTART))
 				break; /* got it. */
 			udelay(10);
@@ -1443,7 +1444,7 @@
 			if (ep->duplex == DUPLEX_FULL)
 				hp->sw_bmcr |= BMCR_FULLDPLX;
 		}
-		happy_meal_tcvr_write(hp, tregs, DP83840_BMCR, hp->sw_bmcr);
+		happy_meal_tcvr_write(hp, tregs, MII_BMCR, hp->sw_bmcr);
 
 		if (!is_lucent_phy(hp)) {
 			/* OK, seems we need do disable the transceiver for the first
@@ -1782,8 +1783,8 @@
 		return;
 
 	/* Latch PHY registers as of now. */
-	hp->sw_bmsr      = happy_meal_tcvr_read(hp, tregs, DP83840_BMSR);
-	hp->sw_advertise = happy_meal_tcvr_read(hp, tregs, DP83840_ADVERTISE);
+	hp->sw_bmsr      = happy_meal_tcvr_read(hp, tregs, MII_BMSR);
+	hp->sw_advertise = happy_meal_tcvr_read(hp, tregs, MII_ADVERTISE);
 
 	/* Advertise everything we can support. */
 	if (hp->sw_bmsr & BMSR_10HALF)
@@ -1805,7 +1806,7 @@
 		hp->sw_advertise &= ~(ADVERTISE_100FULL);
 
 	/* Update the PHY advertisement register. */
-	happy_meal_tcvr_write(hp, tregs, DP83840_ADVERTISE, hp->sw_advertise);
+	happy_meal_tcvr_write(hp, tregs, MII_ADVERTISE, hp->sw_advertise);
 }
 
 /* Once status is latched (by happy_meal_interrupt) it is cleared by
@@ -1929,8 +1930,8 @@
 	unsigned long tregs = hp->tcvregs;
 
 	printk(KERN_INFO "%s: Link status change.\n", hp->dev->name);
-	hp->sw_bmcr = happy_meal_tcvr_read(hp, tregs, DP83840_BMCR);
-	hp->sw_lpa = happy_meal_tcvr_read(hp, tregs, DP83840_LPA);
+	hp->sw_bmcr = happy_meal_tcvr_read(hp, tregs, MII_BMCR);
+	hp->sw_lpa = happy_meal_tcvr_read(hp, tregs, MII_LPA);
 
 	/* Use the fastest transmission protocol possible. */
 	if (hp->sw_lpa & LPA_100FULL) {
@@ -1945,7 +1946,7 @@
 	} else {
 		printk(KERN_INFO "%s: Using 10Mbps at half duplex.", hp->dev->name);
 	}
-	happy_meal_tcvr_write(hp, tregs, DP83840_BMCR, hp->sw_bmcr);
+	happy_meal_tcvr_write(hp, tregs, MII_BMCR, hp->sw_bmcr);
 
 	/* Finally stop polling and shut up the MIF. */
 	happy_meal_poll_stop(hp, tregs);
@@ -2458,8 +2459,8 @@
 		ecmd.phy_address = 0; /* XXX fixed PHYAD */
 
 		/* Record PHY settings. */
-		hp->sw_bmcr = happy_meal_tcvr_read(hp, hp->tcvregs, DP83840_BMCR);
-		hp->sw_lpa = happy_meal_tcvr_read(hp, hp->tcvregs, DP83840_LPA);
+		hp->sw_bmcr = happy_meal_tcvr_read(hp, hp->tcvregs, MII_BMCR);
+		hp->sw_lpa = happy_meal_tcvr_read(hp, hp->tcvregs, MII_LPA);
 		if (hp->sw_bmcr & BMCR_ANENABLE) {
 			ecmd.autoneg = AUTONEG_ENABLE;
 			ecmd.speed =
diff -u --recursive --new-file v2.4.7/linux/drivers/net/tokenring/ibmtr.c linux/drivers/net/tokenring/ibmtr.c
--- v2.4.7/linux/drivers/net/tokenring/ibmtr.c	Wed Jul 25 17:10:22 2001
+++ linux/drivers/net/tokenring/ibmtr.c	Sun Aug  5 13:12:41 2001
@@ -228,7 +228,7 @@
 	printk("\n");
 }
 
-static void __devinit HWPrtChanID(__u32 pcid, short stride)
+static void __devinit HWPrtChanID(void * pcid, short stride)
 {
 	short i, j;
 	for (i = 0, j = 0; i < 24; i++, j += stride)
@@ -330,7 +330,6 @@
 	for (i = 0; ibmtr_portlist[i]; i++) {
 		int ioaddr = ibmtr_portlist[i];
 
-		if (check_region(ioaddr, IBMTR_IO_EXTENT)) continue;
 		if (!ibmtr_probe1(dev, ioaddr)) return 0;
 	}
 	return -ENODEV;
@@ -342,9 +341,9 @@
 {
 
 	unsigned char segment, intr=0, irq=0, i, j, cardpresent=NOTOK, temp=0;
-	__u32 t_mmio = 0;
+	void * t_mmio = 0;
 	struct tok_info *ti = 0;
-	__u32 cd_chanid;
+	void *cd_chanid;
 	unsigned char *tchanid, ctemp;
 #ifndef PCMCIA
 	unsigned char t_irq=0;
@@ -355,6 +354,8 @@
 #ifndef MODULE
 #ifndef PCMCIA
 	dev = init_trdev(dev, 0);
+	if (!dev)
+		return -ENOMEM;
 #endif
 #endif
 
@@ -377,14 +378,14 @@
 	 *    Compute the linear base address of the MMIO area
 	 *    as LINUX doesn't care about segments
 	 */
-	t_mmio = (u32)ioremap(((__u32) (segment & 0xfc) << 11) + 0x80000,2048);
+	t_mmio = ioremap(((__u32) (segment & 0xfc) << 11) + 0x80000,2048);
 	if (!t_mmio) { 
 		DPRINTK("Cannot remap mmiobase memory area") ; 
 		return -ENODEV ; 
 	} 
 	intr = segment & 0x03;	/* low bits is coded interrupt # */
 	if (ibmtr_debug_trace & TRC_INIT)
-		DPRINTK("PIOaddr: %4hx seg/intr: %2x mmio base: %08X intr: %d\n"
+		DPRINTK("PIOaddr: %4hx seg/intr: %2x mmio base: %p intr: %d\n"
 				, PIOaddr, (int) segment, t_mmio, (int) intr);
 
 	/*
@@ -392,8 +393,9 @@
 	 *    what we is there to learn of ISA/MCA or not TR card
 	 */
 #ifdef PCMCIA
+	iounmap(t_mmio);
 	ti = dev->priv;		/*BMS moved up here */
-	t_mmio = ti->mmio;	/*BMS to get virtual address */
+	t_mmio = (void *)ti->mmio;	/*BMS to get virtual address */
 	irq = ti->irq;		/*BMS to display the irq!   */
 #endif
 	cd_chanid = (CHANNEL_ID + t_mmio);	/* for efficiency */
@@ -424,7 +426,12 @@
 	if (cardpresent == TR_ISA && (readb(AIPFID + t_mmio) == 0x0e))
 		cardpresent = TR_ISAPNP;
 	if (cardpresent == NOTOK) {	/* "channel_id" did not match, report */
-		if (!(ibmtr_debug_trace & TRC_INIT)) return -ENODEV;
+		if (!(ibmtr_debug_trace & TRC_INIT)) {
+#ifndef PCMCIA
+			iounmap(t_mmio);
+#endif
+			return -ENODEV;
+		}
 		DPRINTK( "Channel ID string not found for PIOaddr: %4hx\n",
 								PIOaddr);
 		DPRINTK("Expected for ISA: ");
@@ -442,7 +449,10 @@
 	   waste the memory, just use the existing structure */
 #ifndef PCMCIA
 	ti = (struct tok_info *) kmalloc(sizeof(struct tok_info), GFP_KERNEL);
-	if (ti == NULL) return -ENOMEM;
+	if (ti == NULL) {
+		iounmap(t_mmio);
+		return -ENOMEM;
+	}
 	memset(ti, 0, sizeof(struct tok_info));
 	ti->mmio = t_mmio;
 	dev->priv = ti;		/* this seems like the logical use of the
@@ -459,7 +469,7 @@
 		ti->turbo=1;
 		t_irq=turbo_irq[i];
         }
-#endif
+#endif /* !PCMCIA */
 	ti->readlog_pending = 0;
 	init_waitqueue_head(&ti->wait_for_reset);
 
@@ -496,6 +506,7 @@
 		while (!readb(ti->mmio + ACA_OFFSET + ACA_RW + RRR_EVEN)){
 			if (!time_after(jiffies, timeout)) continue;
 			DPRINTK( "Hardware timeout during initialization.\n");
+			iounmap(t_mmio);
 			kfree(ti);
 			return -ENODEV;
 		}
@@ -510,7 +521,7 @@
 		DPRINTK("irq=%d", irq);
 		printk(", sram_virt=0x%x", ti->sram_virt);
 		if(ibmtr_debug_trace&TRC_INITV){ /* full chat in verbose only */
-			DPRINTK(", ti->mmio=%08X", ti->mmio);
+			DPRINTK(", ti->mmio=%p", ti->mmio);
 			printk(", segment=%02X", segment);
 		}
 		printk(".\n");
@@ -609,6 +620,7 @@
 		default:
 			DPRINTK("Unknown shared ram paging info %01X\n",
 							ti->shared_ram_paging);
+			iounmap(t_mmio); 
 			kfree(ti);
 			return -ENODEV;
 			break;
@@ -638,6 +650,7 @@
 			DPRINTK("Shared RAM for this adapter (%05x) exceeds "
 			"driver limit (%05x), adapter not started.\n",
 			chk_base, ibmtr_mem_base + IBMTR_SHARED_RAM_SIZE);
+			iounmap(t_mmio);
 			kfree(ti);
 			return -ENODEV;
 		} else { /* seems cool, record what we have figured out */
@@ -652,16 +665,24 @@
 	if (request_irq(dev->irq = irq, &tok_interrupt, 0, "ibmtr", dev) != 0) {
 		DPRINTK("Could not grab irq %d.  Halting Token Ring driver.\n",
 					irq);
+		iounmap(t_mmio);
 		kfree(ti);
 		return -ENODEV;
 	}
 	/*?? Now, allocate some of the PIO PORTs for this driver.. */
 	/* record PIOaddr range as busy */
-	request_region(PIOaddr, IBMTR_IO_EXTENT, "ibmtr");
+	if (!request_region(PIOaddr, IBMTR_IO_EXTENT, "ibmtr")) {
+		DPRINTK("Could not grab PIO range. Halting driver.\n");
+		free_irq(dev->irq, dev);
+		iounmap(t_mmio);
+		kfree(ti);
+		return -EBUSY;
+	}
+
 	if (!version_printed++) {
 		printk(version);
 	}
-#endif
+#endif /* !PCMCIA */
 	DPRINTK("%s %s found\n",
 		channel_def[cardpresent - 1], adapter_def(ti->adapter_type));
 	DPRINTK("using irq %d, PIOaddr %hx, %dK shared RAM.\n",
diff -u --recursive --new-file v2.4.7/linux/drivers/net/wan/sbni.c linux/drivers/net/wan/sbni.c
--- v2.4.7/linux/drivers/net/wan/sbni.c	Wed Jul 25 17:10:22 2001
+++ linux/drivers/net/wan/sbni.c	Wed Jul 25 14:12:02 2001
@@ -1,64 +1,42 @@
-/*
- * Driver for Granch SBNI-12 leased line network adapters.
- * 
- * Copyright 1997 - 1999, Granch ltd.
- * Written 1999 by Yaroslav Polyakov (xenon@granch.ru).
+/* sbni.c:  Granch SBNI12 leased line adapters driver for linux
+ *
+ *	Written 2001 by Denis I.Timofeev (timofeev@granch.ru)
+ *
+ *	Previous versions were written by Yaroslav Polyakov,
+ *	Alexey Zverev and Max Khon.
+ *
+ *	Driver supports SBNI12-02,-04,-05,-10,-11 cards, single and
+ *	double-channel, PCI and ISA modifications.
+ *	More info and useful utilities to work with SBNI12 cards you can find
+ *	at http://www.granch.com (English) or http://www.granch.ru (Russian)
+ *
+ *	This software may be used and distributed according to the terms
+ *	of the GNU Public License.
  *
- * This software may be used and distributed according to the terms
- * of the GNU General Public License, incorporated herein by reference.
- * 
- *   // Whole developers team:
- *   //   Yaroslav Polyakov (xenon@granch.ru)
- *   //      - main developer of this version
- *   //   Alexey Zverev (zverev@granch.ru)
- *   //      - previous SBNI driver for linux
- *   //   Alexey Chirkov (chirkov@granch.ru)
- *   //      - all the hardware work and consulting
- *   //   Max Khon (max@iclub.nsu.ru)
- *   //      - first SBNI driver for linux
- *   // --------------------------------------------
- *   // also I thank: 
- *   //   Max Krasnyansky (max@uznet.net)
- *   //      - for bug hunting and many ideas
- *   //   Alan Cox (Alan.Cox@linux.org)
- *   //	     - for consulting in some hardcore questions
- *   //   Donald Becker (becker@scyld.com)
- *   //      - for pretty nice skeleton 
- * 
- *   More info and useful utilities to work w/ SBNI you can find at 
- *   http://www.granch.ru.
  *
- *  3.0.0 = Initial Revision, Yaroslav Polyakov (24 Feb 1999)
+ *  5.0.1	Jun 22 2001
+ *	  - Fixed bug in probe
+ *  5.0.0	Jun 06 2001
+ *	  - Driver was completely redesigned by Denis I.Timofeev,
+ *	  - now PCI/Dual, ISA/Dual (with single interrupt line) models are
+ *	  - supported
+ *  3.3.0	Thu Feb 24 21:30:28 NOVT 2000 
+ *        - PCI cards support
+ *  3.2.0	Mon Dec 13 22:26:53 NOVT 1999
+ * 	  - Completely rebuilt all the packet storage system
+ * 	  -    to work in Ethernet-like style.
+ *  3.1.1	just fixed some bugs (5 aug 1999)
+ *  3.1.0	added balancing feature	(26 apr 1999)
+ *  3.0.1	just fixed some bugs (14 apr 1999).
+ *  3.0.0	Initial Revision, Yaroslav Polyakov (24 Feb 1999)
  *        - added pre-calculation for CRC, fixed bug with "len-2" frames, 
  *        - removed outbound fragmentation (MTU=1000), written CRC-calculation 
  *        - on asm, added work with hard_headers and now we have our own cache 
  *        - for them, optionally supported word-interchange on some chipsets,
- *        - something else I cant remember ;) 
  * 
- *  3.0.1 = just fixed some bugs (14 apr 1999).
- * 	  - fixed statistical tx bug 
- *        - fixed wrong creation dates (1998 -> 1999) in driver source code ;)
- * 	  - fixed source address bug.
- *        - fixed permanent nirvana bug 
- * 
- *  3.1.0 = (Katyusha) (26 apr 1999)
- *        - Added balancing feature
- * 
- *  3.1.1 = (Medea) (5 aug 1999)
- *        - Fixed mac.raw bug
- *	  - Thanks to tolix@olviko.ru and 
- *        - to Barnaul Brewery, producers of my favorite beer "Medea".
- *
- *
+ *	Known problem: this driver wasn't tested on multiprocessor machine.
  */
 
-
-#undef GOODBUS16
-#define CRCASM
-#define KATYUSHA
-
-#include <linux/version.h>
-
 #include <linux/module.h>
 #include <linux/kernel.h>
 #include <linux/sched.h>
@@ -66,1450 +44,1666 @@
 #include <linux/fcntl.h>
 #include <linux/ioport.h>
 #include <linux/interrupt.h>
-#include <linux/slab.h>
+#include <linux/malloc.h>
 #include <linux/string.h>
 #include <linux/errno.h>
-#include <linux/spinlock.h>
 
 #include <asm/io.h>
 #include <asm/types.h>
 #include <asm/byteorder.h>
+#include <asm/irq.h>
+#include <asm/uaccess.h>
 
 
 #include <linux/netdevice.h>
 #include <linux/etherdevice.h>
 #include <linux/skbuff.h>
 #include <linux/timer.h>
-#include <linux/config.h>	/* for CONFIG_INET. do we need this?*/
+#include <linux/init.h>
 
 #include <net/arp.h>
+#include <linux/pci.h>
 
-#include <asm/uaccess.h>
-#include <linux/init.h>
 
+#ifndef MODULE
+#include <linux/string.h>
+#endif
+
+#include <linux/config.h>
 #include "sbni.h"
 
 
-static const char *version = 
-"sbni.c: ver. 3.1.1 Medea 5 Aug 1999 Yaroslav Polyakov (xenon@granch.ru)\n";
+/* device private data */
 
-int sbni_probe(struct net_device *dev);
-static int  sbni_probe1(struct net_device *dev, int ioaddr);
-static int  sbni_open(struct net_device *dev);
-static int  sbni_start_xmit(struct sk_buff *skb, struct net_device *dev);
-static void sbni_interrupt(int irq, void *dev_id, struct pt_regs *regs);
-static int  sbni_close(struct net_device *dev);
-static void sbni_drop_tx_queue(struct net_device *dev);
-static struct net_device_stats *sbni_get_stats(struct net_device *dev);
-static void card_start(struct net_device *dev);
-static inline unsigned short sbni_recv(struct net_device *dev);
-void change_level(struct net_device *dev);
-static inline void sbni_xmit(struct net_device *dev);
-static inline void sbni_get_packet(struct net_device* dev);
-static void sbni_watchdog(unsigned long arg);
-static void set_multicast_list(struct net_device *dev);
-static int sbni_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd);
-static int sbni_set_mac_address(struct net_device *dev, void *addr);
-unsigned long calc_crc(char *mem, int len, unsigned initial);
-void sbni_nirvana(struct net_device *dev);
-static int sbni_header(struct sk_buff *skb, struct net_device *dev, unsigned short type,
-		void *daddr, void *saddr, unsigned len);
+struct net_local {
+	struct net_device_stats	stats;
+	struct timer_list	watchdog;
+
+	spinlock_t	lock;
+	struct sk_buff  *rx_buf_p;		/* receive buffer ptr */
+	struct sk_buff  *tx_buf_p;		/* transmit buffer ptr */
+	
+	unsigned int	framelen;		/* current frame length */
+	unsigned int	maxframe;		/* maximum valid frame length */
+	unsigned int	state;
+	unsigned int	inppos, outpos;		/* positions in rx/tx buffers */
 
-static int sbni_rebuild_header(struct sk_buff *skb);
-static int sbni_header_cache(struct neighbour *neigh, struct hh_cache *hh);
+	/* transmitting frame number - from frames qty to 1 */
+	unsigned int	tx_frameno;
 
-static inline void sbni_outs(int port, void *data, int len);
-static inline void sbni_ins(int port, void *data, int len);
+	/* expected number of next receiving frame */
+	unsigned int	wait_frameno;
 
+	/* count of failed attempts to frame send - 32 attempts do before
+	   error - while receiver tunes on opposite side of wire */
+	unsigned int	trans_errors;
 
+	/* idle time; send pong when limit exceeded */
+	unsigned int	timer_ticks;
 
-#define SIZE_OF_TIMEOUT_RXL_TAB 4
-static u_char timeout_rxl_tab[] = {
-  0x03, 0x05, 0x08, 0x0b
-};
+	/* fields used for receive level autoselection */
+	int	delta_rxl;
+	unsigned int	cur_rxl_index, timeout_rxl;
+	unsigned long	cur_rxl_rcvd, prev_rxl_rcvd;
 
-static u_char rxl_tab[] = {
-  0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x08, 
-  0x0a, 0x0c, 0x0f, 0x16, 0x18, 0x1a, 0x1c, 0x1f
-};
+	struct sbni_csr1	csr1;		/* current value of CSR1 */
+	struct sbni_in_stats	in_stats; 	/* internal statistics */ 
 
-/* A zero-terminated list of I/O addresses to be probed */
-static unsigned int netcard_portlist[] =  { 
-	0x210, 0x2c0, 0x2d0, 0x2f0, 0x220, 0x230, 0x240, 0x250, 
-	0x260, 0x290, 0x2a0, 0x2b0, 0x224, 0x234, 0x244, 0x254, 
-	0x264, 0x294, 0x2a4, 0x2b4, 0};
+	struct net_device		*second;	/* for ISA/dual cards */
 
-static unsigned char magic_reply[] = {
-	0x5a,0x06,0x30,0x00,0x00,0x50,0x65,0x44,0x20
+#ifdef CONFIG_SBNI_MULTILINE
+	struct net_device		*master;
+	struct net_device		*link;
+#endif
 };
 
-static int def_baud = DEF_RATE;
-static int def_rxl = DEF_RXL_DELTA;
-static long def_mac = 0;
+
+static int  sbni_card_probe( unsigned long );
+static int  sbni_pci_probe( struct net_device  * );
+static struct net_device  *sbni_probe1(struct net_device *, unsigned long, int);
+static int  sbni_open( struct net_device * );
+static int  sbni_close( struct net_device * );
+static int  sbni_start_xmit( struct sk_buff *, struct net_device * );
+static int  sbni_ioctl( struct net_device *, struct ifreq *, int );
+static struct net_device_stats  *sbni_get_stats( struct net_device * );
+static void  set_multicast_list( struct net_device * );
+
+static void  sbni_interrupt( int, void *, struct pt_regs * );
+static void  handle_channel( struct net_device * );
+static int   recv_frame( struct net_device * );
+static void  send_frame( struct net_device * );
+static int   upload_data( struct net_device *,
+			  unsigned, unsigned, unsigned, u32 );
+static void  download_data( struct net_device *, u32 * );
+static void  sbni_watchdog( unsigned long );
+static void  interpret_ack( struct net_device *, unsigned );
+static int   append_frame_to_pkt( struct net_device *, unsigned, u32 );
+static void  indicate_pkt( struct net_device * );
+static void  card_start( struct net_device * );
+static void  prepare_to_send( struct sk_buff *, struct net_device * );
+static void  drop_xmit_queue( struct net_device * );
+static void  send_frame_header( struct net_device *, u32 * );
+static int   skip_tail( unsigned int, unsigned int, u32 );
+static int   check_fhdr( u32, u32 *, u32 *, u32 *, u32 *, u32 * );
+static void  change_level( struct net_device * );
+static void  timeout_change_level( struct net_device * );
+static u32   calc_crc32( u32, u8 *, u32 );
+static struct sk_buff *  get_rx_buf( struct net_device * );
+
+#ifdef CONFIG_SBNI_MULTILINE
+static int  enslave( struct net_device *, struct net_device * );
+static int  emancipate( struct net_device * );
+#endif
+
+#define ASM_CRC 1
+
+static const char  version[] =
+	"Granch SBNI12 driver ver 5.0.1  Jun 22 2001  Denis I.Timofeev.\n";
+
+static int  skip_pci_probe	__initdata = 0;
+static int  scandone	__initdata = 0;
+static int  num		__initdata = 0;
+
+static unsigned char  rxl_tab[];
+static u32  crc32tab[];
+
+/* A list of all installed devices, for removing the driver module. */
+static struct net_device  *sbni_cards[ SBNI_MAX_NUM_CARDS ];
+
+/* Lists of device's parameters */
+static u32	io[   SBNI_MAX_NUM_CARDS ] __initdata =
+	{ [0 ... SBNI_MAX_NUM_CARDS-1] = -1 };
+static u32	irq[  SBNI_MAX_NUM_CARDS ] __initdata;
+static u32	baud[ SBNI_MAX_NUM_CARDS ] __initdata;
+static u32	rxl[  SBNI_MAX_NUM_CARDS ] __initdata =
+	{ [0 ... SBNI_MAX_NUM_CARDS-1] = -1 };
+static u32	mac[  SBNI_MAX_NUM_CARDS ] __initdata;
+
+#ifndef MODULE
+typedef u32  iarr[];
+static iarr  *dest[5] = { &io, &irq, &baud, &rxl, &mac };
+#endif
+
+/* A zero-terminated list of I/O addresses to be probed on ISA bus */
+static unsigned int  netcard_portlist[ ] __initdata = { 
+	0x210, 0x214, 0x220, 0x224, 0x230, 0x234, 0x240, 0x244, 0x250, 0x254,
+	0x260, 0x264, 0x270, 0x274, 0x280, 0x284, 0x290, 0x294, 0x2a0, 0x2a4,
+	0x2b0, 0x2b4, 0x2c0, 0x2c4, 0x2d0, 0x2d4, 0x2e0, 0x2e4, 0x2f0, 0x2f4,
+	0 };
 
 
 /*
- * CRC-32 stuff
+ * Look for SBNI card which addr stored in dev->base_addr, if nonzero.
+ * Otherwise, look through PCI bus. If none PCI-card was found, scan ISA.
  */
 
-#define CRC32(c,crc) (crc32tab[((size_t)(crc) ^ (c)) & 0xff] ^ (((crc) >> 8) & 0x00FFFFFF))
-/* CRC generator 0xEDB88320 */
-/* CRC remainder 0x2144DF1C */
-/* CRC initial value 0x00000000 */
-#define CRC32_REMAINDER 0x2144DF1C
-#define CRC32_INITIAL 0x00000000
+static inline int __init
+sbni_isa_probe( struct net_device  *dev )
+{
+	if( dev->base_addr > 0x1ff
+	    &&  !check_region( dev->base_addr, SBNI_IO_EXTENT )
+	    &&  sbni_probe1( dev, dev->base_addr, dev->irq ) )
+
+		return  0;
+	else {
+		printk( KERN_ERR "sbni: base address 0x%lx is busy, or adapter "
+			"is malfunctional!\n", dev->base_addr );
+		return  -ENODEV;
+	}
+}
 
-static unsigned long crc32tab[] = {
-	0xD202EF8D,  0xA505DF1B,  0x3C0C8EA1,  0x4B0BBE37,
-	0xD56F2B94,  0xA2681B02,  0x3B614AB8,  0x4C667A2E,
-	0xDCD967BF,  0xABDE5729,  0x32D70693,  0x45D03605,
-	0xDBB4A3A6,  0xACB39330,  0x35BAC28A,  0x42BDF21C,
-	0xCFB5FFE9,  0xB8B2CF7F,  0x21BB9EC5,  0x56BCAE53,
-	0xC8D83BF0,  0xBFDF0B66,  0x26D65ADC,  0x51D16A4A,
-	0xC16E77DB,  0xB669474D,  0x2F6016F7,  0x58672661,
-	0xC603B3C2,  0xB1048354,  0x280DD2EE,  0x5F0AE278,
-	0xE96CCF45,  0x9E6BFFD3,  0x0762AE69,  0x70659EFF,
-	0xEE010B5C,  0x99063BCA,  0x000F6A70,  0x77085AE6,
-	0xE7B74777,  0x90B077E1,  0x09B9265B,  0x7EBE16CD,
-	0xE0DA836E,  0x97DDB3F8,  0x0ED4E242,  0x79D3D2D4,
-	0xF4DBDF21,  0x83DCEFB7,  0x1AD5BE0D,  0x6DD28E9B,
-	0xF3B61B38,  0x84B12BAE,  0x1DB87A14,  0x6ABF4A82,
-	0xFA005713,  0x8D076785,  0x140E363F,  0x630906A9,
-	0xFD6D930A,  0x8A6AA39C,  0x1363F226,  0x6464C2B0,
-	0xA4DEAE1D,  0xD3D99E8B,  0x4AD0CF31,  0x3DD7FFA7,
-	0xA3B36A04,  0xD4B45A92,  0x4DBD0B28,  0x3ABA3BBE,
-	0xAA05262F,  0xDD0216B9,  0x440B4703,  0x330C7795,
-	0xAD68E236,  0xDA6FD2A0,  0x4366831A,  0x3461B38C,
-	0xB969BE79,  0xCE6E8EEF,  0x5767DF55,  0x2060EFC3,
-	0xBE047A60,  0xC9034AF6,  0x500A1B4C,  0x270D2BDA,
-	0xB7B2364B,  0xC0B506DD,  0x59BC5767,  0x2EBB67F1,
-	0xB0DFF252,  0xC7D8C2C4,  0x5ED1937E,  0x29D6A3E8,
-	0x9FB08ED5,  0xE8B7BE43,  0x71BEEFF9,  0x06B9DF6F,
-	0x98DD4ACC,  0xEFDA7A5A,  0x76D32BE0,  0x01D41B76,
-	0x916B06E7,  0xE66C3671,  0x7F6567CB,  0x0862575D,
-	0x9606C2FE,  0xE101F268,  0x7808A3D2,  0x0F0F9344,
-	0x82079EB1,  0xF500AE27,  0x6C09FF9D,  0x1B0ECF0B,
-	0x856A5AA8,  0xF26D6A3E,  0x6B643B84,  0x1C630B12,	
-	0x8CDC1683,  0xFBDB2615,  0x62D277AF,  0x15D54739,
-	0x8BB1D29A,  0xFCB6E20C,  0x65BFB3B6,  0x12B88320,
-	0x3FBA6CAD,  0x48BD5C3B,  0xD1B40D81,  0xA6B33D17,
-	0x38D7A8B4,  0x4FD09822,  0xD6D9C998,  0xA1DEF90E,
-	0x3161E49F,  0x4666D409,  0xDF6F85B3,  0xA868B525,
-	0x360C2086,  0x410B1010,  0xD80241AA,  0xAF05713C,
-	0x220D7CC9,  0x550A4C5F,  0xCC031DE5,  0xBB042D73,
-	0x2560B8D0,  0x52678846,  0xCB6ED9FC,  0xBC69E96A,
-	0x2CD6F4FB,  0x5BD1C46D,  0xC2D895D7,  0xB5DFA541,
-	0x2BBB30E2,  0x5CBC0074,  0xC5B551CE,  0xB2B26158,
-	0x04D44C65,  0x73D37CF3,  0xEADA2D49,  0x9DDD1DDF,
-	0x03B9887C,  0x74BEB8EA,  0xEDB7E950,  0x9AB0D9C6,
-	0x0A0FC457,  0x7D08F4C1,  0xE401A57B,  0x930695ED,
-	0x0D62004E,  0x7A6530D8,  0xE36C6162,  0x946B51F4,
-	0x19635C01,  0x6E646C97,  0xF76D3D2D,  0x806A0DBB,
-	0x1E0E9818,  0x6909A88E,  0xF000F934,  0x8707C9A2,
-	0x17B8D433,  0x60BFE4A5,  0xF9B6B51F,  0x8EB18589,
-	0x10D5102A,  0x67D220BC,  0xFEDB7106,  0x89DC4190,
-	0x49662D3D,  0x3E611DAB,  0xA7684C11,  0xD06F7C87,
-	0x4E0BE924,  0x390CD9B2,  0xA0058808,  0xD702B89E,
-	0x47BDA50F,  0x30BA9599,  0xA9B3C423,  0xDEB4F4B5,
-	0x40D06116,  0x37D75180,  0xAEDE003A,  0xD9D930AC,
-	0x54D13D59,  0x23D60DCF,  0xBADF5C75,  0xCDD86CE3,
-	0x53BCF940,  0x24BBC9D6,  0xBDB2986C,  0xCAB5A8FA,
-	0x5A0AB56B,  0x2D0D85FD,  0xB404D447,  0xC303E4D1,
-	0x5D677172,  0x2A6041E4,  0xB369105E,  0xC46E20C8,
-	0x72080DF5,  0x050F3D63,  0x9C066CD9,  0xEB015C4F,
-	0x7565C9EC,  0x0262F97A,  0x9B6BA8C0,  0xEC6C9856,
-	0x7CD385C7,  0x0BD4B551,  0x92DDE4EB,  0xE5DAD47D,
-	0x7BBE41DE,  0x0CB97148,  0x95B020F2,  0xE2B71064,
-	0x6FBF1D91,  0x18B82D07,  0x81B17CBD,  0xF6B64C2B,
-	0x68D2D988,  0x1FD5E91E,  0x86DCB8A4,  0xF1DB8832,
-	0x616495A3,  0x1663A535,  0x8F6AF48F,  0xF86DC419,
-	0x660951BA,  0x110E612C,  0x88073096,  0xFF000000
-};
 
-static inline void sbni_outs(int port, void *data, int len)
+int __init
+sbni_probe( struct net_device  *dev )
 {
-#ifdef GOODBUS16
-	outsw(port,data,len/2);
-	if(len & 1)
-		outb(((char*)data)[len - 1],port);
-#else
-	outsb(port,data,len);
-#endif
+	int  i;
+
+	static unsigned  version_printed __initdata = 0;
+	if( version_printed++ == 0 )
+		printk( KERN_INFO "%s", version );
+
+	if( !dev ) {	/* simple sanity check */
+		printk( KERN_ERR "sbni: NULL device!\n" );
+		return  -ENODEV;
+	}
+
+	SET_MODULE_OWNER( dev );
+
+	if( dev->base_addr )
+		return  sbni_isa_probe( dev );
+	/* otherwise we have to perform search our adapter */
+
+	if( io[ num ] != -1 )
+		dev->base_addr	= io[ num ],
+		dev->irq	= irq[ num ];
+	else if( scandone  ||  io[ 0 ] != -1 )
+		return  -ENODEV;
+
+	/* if io[ num ] contains non-zero address, then that is on ISA bus */
+	if( dev->base_addr )
+		return  sbni_isa_probe( dev );
+
+	/* ...otherwise - scan PCI first */
+	if( !skip_pci_probe  &&  !sbni_pci_probe( dev ) )
+		return  0;
+
+	if( io[ num ] == -1 ) {
+		/* Auto-scan will be stopped when first ISA card were found */
+		scandone = 1;
+		if( num > 0 )
+			return  -ENODEV;
+	}
+
+	for( i = 0;  netcard_portlist[ i ];  ++i ) {
+		int  ioaddr = netcard_portlist[ i ];
+		if( !check_region( ioaddr, SBNI_IO_EXTENT )
+		    &&  sbni_probe1( dev, ioaddr, 0 ))
+			return 0;
+	}
+
+	return  -ENODEV;
 }
 
-static inline void sbni_ins(int port, void *data, int len)
+
+int __init
+sbni_pci_probe( struct net_device  *dev )
 {
-#ifdef GOODBUS16
-	insw(port,data,len/2);
-	if(len & 1)
-		((char*)data)[len - 1] = inb(port);
-#else
-	insb(port,data,len);
-#endif
+	struct pci_dev  *pdev = NULL;
+
+	if( !pci_present( ) )
+		return  -ENODEV;
+
+	while( (pdev = pci_find_class( PCI_CLASS_NETWORK_OTHER << 8, pdev ))
+	       != NULL ) {
+		int  pci_irq_line;
+		unsigned long  pci_ioaddr;
+		u16  subsys;
+
+		if( pdev->vendor != SBNI_PCI_VENDOR
+		    &&  pdev->device != SBNI_PCI_DEVICE )
+				continue;
+
+		pci_ioaddr = pci_resource_start( pdev, 0 );
+		pci_irq_line = pdev->irq;
+
+		/* Avoid already found cards from previous calls */
+		if( check_region( pci_ioaddr, SBNI_IO_EXTENT ) ) {
+			pci_read_config_word( pdev, PCI_SUBSYSTEM_ID, &subsys );
+			if( subsys != 2  ||	/* Dual adapter is present */
+			    check_region( pci_ioaddr += 4, SBNI_IO_EXTENT ) )
+				continue;
+		}
+
+		if( pci_irq_line <= 0  ||  pci_irq_line >= NR_IRQS )
+			printk( KERN_WARNING "  WARNING: The PCI BIOS assigned "
+				"this PCI card to IRQ %d, which is unlikely "
+				"to work!.\n"
+				KERN_WARNING " You should use the PCI BIOS "
+				"setup to assign a valid IRQ line.\n",
+				pci_irq_line );
+
+		/* avoiding re-enable dual adapters */
+		if( (pci_ioaddr & 7) == 0  &&  pci_enable_device( pdev ) )
+			return  -EIO;
+		if( sbni_probe1( dev, pci_ioaddr, pci_irq_line ) )
+			return  0;
+	}
+	return  -ENODEV;
 }
 
 
-static int sbni_header(struct sk_buff *skb, struct net_device *dev, unsigned short type,
-	   void *daddr, void *saddr, unsigned len)
+static struct net_device * __init
+sbni_probe1( struct net_device  *dev,  unsigned long  ioaddr,  int  irq )
 {
-	struct sbni_hard_header *hh = (struct sbni_hard_header *) 
-			skb_push(skb, sizeof(struct sbni_hard_header));
-  
-  
-	if(type!=ETH_P_802_3) 
-		hh->h_proto = htons(type);
+	struct net_local  *nl;
+
+	if( !request_region( ioaddr, SBNI_IO_EXTENT, dev->name ) )
+		return  0;
+
+	if( sbni_card_probe( ioaddr ) ) {
+		release_region( ioaddr, SBNI_IO_EXTENT );
+		return  0;
+	}
+
+	outb( 0, ioaddr + CSR0 );
+
+	if( irq < 2 ) {
+		autoirq_setup( 5 );
+		outb( EN_INT | TR_REQ, ioaddr + CSR0 );
+		outb( PR_RES, ioaddr + CSR1 );
+		irq = autoirq_report( 5 );
+		outb( 0, ioaddr + CSR0 );
+
+		if( !irq ) {
+			printk( KERN_ERR "%s: can't detect device irq!\n",
+				dev->name );
+			release_region( ioaddr, SBNI_IO_EXTENT );
+			return  0;
+		}
+	} else if( irq == 2 )
+		irq = 9;
+
+	dev->irq = irq;
+	dev->base_addr = ioaddr;
+
+	/* Allocate dev->priv and fill in sbni-specific dev fields. */
+	nl = (struct net_local *) kmalloc(sizeof(struct net_local), GFP_KERNEL);
+	if( !nl ) {
+		printk( KERN_ERR "%s: unable to get memory!\n", dev->name );
+		release_region( ioaddr, SBNI_IO_EXTENT );
+		return  0;
+	}
+
+	dev->priv = nl;
+	memset( nl, 0, sizeof(struct net_local) );
+	spin_lock_init( &nl->lock );
+
+	/* store MAC address (generate if that isn't known) */
+	*(u16 *)dev->dev_addr = htons( 0x00ff );
+	*(u32 *)(dev->dev_addr + 2) = htonl( 0x01000000 |
+		( (mac[num]  ?  mac[num]  :  (u32)dev->priv) & 0x00ffffff) );
+
+	/* store link settings (speed, receive level ) */
+	nl->maxframe  = DEFAULT_FRAME_LEN;
+	nl->csr1.rate = baud[ num ];
+
+	if( (nl->cur_rxl_index = rxl[ num ]) == -1 )
+		/* autotune rxl */
+		nl->cur_rxl_index = DEF_RXL,
+		nl->delta_rxl = DEF_RXL_DELTA;
 	else
-		hh->h_proto = htons(len);
-  
-	if(saddr)
-		memcpy(hh->h_source,saddr,dev->addr_len);
+		nl->delta_rxl = 0;
+	nl->csr1.rxl  = rxl_tab[ nl->cur_rxl_index ];
+	if( inb( ioaddr + CSR0 ) & 0x01 )
+		nl->state |= FL_SLOW_MODE;
+
+	printk( KERN_NOTICE "%s: ioaddr %#lx, irq %d, "
+		"MAC: 00:ff:01:%02x:%02x:%02x\n", 
+		dev->name, dev->base_addr, dev->irq,
+		((u8 *) dev->dev_addr) [3],
+		((u8 *) dev->dev_addr) [4],
+		((u8 *) dev->dev_addr) [5] );
+
+	printk( KERN_NOTICE "%s: speed %d, receive level ", dev->name,
+		( (nl->state & FL_SLOW_MODE)  ?  500000 : 2000000)
+		/ (1 << nl->csr1.rate) );
+
+	if( nl->delta_rxl == 0 )
+		printk( "0x%x (fixed)\n", nl->cur_rxl_index ); 
 	else
-		memcpy(hh->h_source,dev->dev_addr,dev->addr_len);
+		printk( "(auto)\n");
 
-	if(daddr)
-	{
-		memcpy(hh->h_dest,daddr,dev->addr_len);
-		return dev->hard_header_len;
-	} 
-	return -dev->hard_header_len;
+#ifdef CONFIG_SBNI_MULTILINE
+	nl->master = dev;
+	nl->link   = NULL;
+#endif
+   
+	dev->open		= &sbni_open;
+	dev->stop		= &sbni_close;
+	dev->hard_start_xmit	= &sbni_start_xmit;
+	dev->get_stats		= &sbni_get_stats;
+	dev->set_multicast_list	= &set_multicast_list;
+	dev->do_ioctl		= &sbni_ioctl;
+	ether_setup( dev );
+
+	sbni_cards[ num++ ] = dev;
+	return  dev;
 }
 
+/* -------------------------------------------------------------------------- */
+
+#ifdef CONFIG_SBNI_MULTILINE
 
-int sbni_header_cache(struct neighbour *neigh, struct hh_cache *hh)
+static int
+sbni_start_xmit( struct sk_buff  *skb,  struct net_device  *dev )
 {
-	unsigned short type = hh->hh_type;
-	struct sbni_hard_header *sbni = (struct sbni_hard_header*)
-						(((u8*)hh->hh_data) - 8);
-	struct net_device *dev = neigh->dev;
-  
-  
-	if (type == htons(ETH_P_802_3))
-		return -1;
-  
-	sbni->h_proto = type;
-	memcpy(sbni->h_source, dev->dev_addr, dev->addr_len);
-	memcpy(sbni->h_dest, neigh->ha, dev->addr_len);
-	return 0;
+	struct net_device  *p;
+
+	netif_stop_queue( dev );
+
+	/* Looking for idle device in the list */
+	for( p = dev;  p; ) {
+		struct net_local  *nl = (struct net_local *) p->priv;
+		spin_lock( &nl->lock );
+		if( nl->tx_buf_p  ||  (nl->state & FL_LINE_DOWN) ) {
+			p = nl->link;
+			spin_unlock( &nl->lock );
+		} else {
+			/* Idle dev is found */
+			prepare_to_send( skb, p );
+			spin_unlock( &nl->lock );
+			netif_start_queue( dev );
+			return  0;
+		}
+	}
+
+	return  1;
 }
 
-static int sbni_rebuild_header(struct sk_buff *skb)
+#else	/* CONFIG_SBNI_MULTILINE */
+
+static int
+sbni_start_xmit( struct sk_buff  *skb,  struct net_device  *dev )
 {
-	struct sbni_hard_header *hh = (struct sbni_hard_header *)skb;
-	/*
-	 *	Only ARP/IP is currently supported
-	 */
+	struct net_local  *nl  = (struct net_local *) dev->priv;
 
-	/*
-	 *	Try to get ARP to resolve the header.
-	 */
-  
-#ifdef CONFIG_INET
-  	return arp_find((unsigned char*)hh->h_dest, skb)? 1 : 0;  
-#else
-	return 0;	
-#endif	
+	netif_stop_queue( dev );
+	spin_lock( &nl->lock );
+
+	prepare_to_send( skb, dev );
+
+	spin_unlock( &nl->lock );
+	return  0;
 }
 
-static void sbni_header_cache_update(struct hh_cache *hh, struct net_device *dev, unsigned char * haddr)
-{
-	memcpy(((u8*)hh->hh_data) + 2, haddr, dev->addr_len);
+#endif	/* CONFIG_SBNI_MULTILINE */
+
+/* -------------------------------------------------------------------------- */
+
+/* interrupt handler */
+
+/*
+ * 	SBNI12D-10, -11/ISA boards within "common interrupt" mode could not
+ * be looked as two independent single-channel devices. Every channel seems
+ * as Ethernet interface but interrupt handler must be common. Really, first
+ * channel ("master") driver only registers the handler. In its struct net_local
+ * it has got pointer to "slave" channel's struct net_local and handles that's
+ * interrupts too.
+ *	dev of successfully attached ISA SBNI boards is linked to list.
+ * While next board driver is initialized, it scans this list. If one
+ * has found dev with same irq and ioaddr different by 4 then it assumes
+ * this board to be "master".
+ */ 
+
+static void
+sbni_interrupt( int  irq,  void  *dev_id,  struct pt_regs  *regs )
+{
+	struct net_device	  *dev = (struct net_device *) dev_id;
+	struct net_local  *nl  = (struct net_local *) dev->priv;
+	int	repeat;
+
+	spin_lock( &nl->lock );
+	if( nl->second )
+		spin_lock( &((struct net_local *) nl->second->priv)->lock );
+
+	do {
+		repeat = 0;
+		if( inb( dev->base_addr + CSR0 ) & (RC_RDY | TR_RDY) )
+			handle_channel( dev ),
+			repeat = 1;
+		if( nl->second  && 	/* second channel present */
+		    (inb( nl->second->base_addr+CSR0 ) & (RC_RDY | TR_RDY)) )
+			handle_channel( nl->second ),
+			repeat = 1;
+	} while( repeat );
+
+	if( nl->second )
+		spin_unlock( &((struct net_local *)nl->second->priv)->lock );
+	spin_unlock( &nl->lock );
 }
 
 
+static void
+handle_channel( struct net_device  *dev )
+{
+	struct net_local	*nl    = (struct net_local *) dev->priv;
+	unsigned long		ioaddr = dev->base_addr;
+
+	int  req_ans;
+	unsigned char  csr0;
+
+#ifdef CONFIG_SBNI_MULTILINE
+	/* Lock the master device because we going to change its local data */
+	if( nl->state & FL_SLAVE )
+		spin_lock( &((struct net_local *) nl->master->priv)->lock );
+#endif
 
-#ifdef HAVE_DEVLIST
-struct netdev_entry sbni_drv = {
-	"sbni", sbni_probe1, SBNI_IO_EXTENT, netcard_portlist 
-};
+	outb( (inb( ioaddr + CSR0 ) & ~EN_INT) | TR_REQ, ioaddr + CSR0 );
 
-#else
+	nl->timer_ticks = CHANGE_LEVEL_START_TICKS;
+	for(;;) {
+		csr0 = inb( ioaddr + CSR0 );
+		if( ( csr0 & (RC_RDY | TR_RDY) ) == 0 )
+			break;
 
-int __init sbni_probe(struct net_device *dev)
-{
-	int i;
-	int base_addr = dev ? dev->base_addr : 0;
-	
-	DP( printk("%s: sbni_probe\n", dev->name); )
+		req_ans = !(nl->state & FL_PREV_OK);
 
-	if(base_addr > 0x1ff)	/* Check a single specified location. */
-		return sbni_probe1(dev, base_addr);
-	else if(base_addr != 0)	/* Don't probe at all. */
-		return -ENXIO;
-	for(i = 0; (base_addr = netcard_portlist[i]); i++)
-	{ 
-		if(!check_region(base_addr, SBNI_IO_EXTENT) && base_addr != 1)
-		{
-			/* Lock this address, or later we'll try it again */
-			netcard_portlist[i] = 1;
-			if(sbni_probe1(dev, base_addr) == 0)
-				return 0;
-		}
+		if( csr0 & RC_RDY )
+			req_ans = recv_frame( dev );
+
+		/*
+		 * TR_RDY always equals 1 here because we have owned the marker,
+		 * and we set TR_REQ when disabled interrupts
+		 */
+		csr0 = inb( ioaddr + CSR0 );
+		if( !(csr0 & TR_RDY)  ||  (csr0 & RC_RDY) )
+			printk( KERN_ERR "%s: internal error!\n", dev->name );
+
+		/* if state & FL_NEED_RESEND != 0 then tx_frameno != 0 */
+		if( req_ans  ||  nl->tx_frameno != 0 )
+			send_frame( dev );
+		else
+			/* send marker without any data */
+			outb( inb( ioaddr + CSR0 ) & ~TR_REQ, ioaddr + CSR0 );
 	}
-	return -ENODEV;
+
+	outb( inb( ioaddr + CSR0 ) | EN_INT, ioaddr + CSR0 );
+
+#ifdef CONFIG_SBNI_MULTILINE
+	if( nl->state & FL_SLAVE )
+		spin_unlock( &((struct net_local *) nl->master->priv)->lock );
+#endif
 }
 
-#endif /* have devlist*/
 
 /*
- *	The actual probe. 
+ * Routine returns 1 if it need to acknoweledge received frame.
+ * Empty frame received without errors won't be acknoweledged.
  */
 
-/*
-	Valid combinations in CSR0 (for probing):
-
-	VALID_DECODER	0000,0011,1011,1010
+static int
+recv_frame( struct net_device  *dev )
+{
+	struct net_local  *nl   = (struct net_local *) dev->priv;
+	unsigned long  ioaddr	= dev->base_addr;
 
-				    	; 0   ; -
-				TR_REQ	; 1   ; +
-			TR_RDY	    	; 2   ; -
-			TR_RDY	TR_REQ	; 3   ; +
-		BU_EMP		    	; 4   ; +
-		BU_EMP	     	TR_REQ	; 5   ; +
-		BU_EMP	TR_RDY	    	; 6   ; -
-		BU_EMP	TR_RDY	TR_REQ	; 7   ; +
-	RC_RDY 		     		; 8   ; +
-	RC_RDY			TR_REQ	; 9   ; +
-	RC_RDY		TR_RDY		; 10  ; -
-	RC_RDY		TR_RDY	TR_REQ	; 11  ; -
-	RC_RDY	BU_EMP			; 12  ; -
-	RC_RDY	BU_EMP		TR_REQ	; 13  ; -
-	RC_RDY	BU_EMP	TR_RDY		; 14  ; -
-	RC_RDY	BU_EMP	TR_RDY	TR_REQ	; 15  ; -
-*/
-#define VALID_DECODER (2 + 8 + 0x10 + 0x20 + 0x80 + 0x100 + 0x200)
+	u32  crc = CRC32_INITIAL;
 
-static int __init sbni_probe1(struct net_device *dev, int ioaddr)
+	unsigned  framelen, frameno, ack;
+	unsigned  is_first, frame_ok;
+
+	if( check_fhdr( ioaddr, &framelen, &frameno, &ack, &is_first, &crc ) ) {
+		frame_ok = framelen > 4
+			?  upload_data( dev, framelen, frameno, is_first, crc )
+			:  skip_tail( ioaddr, framelen, crc );
+		if( frame_ok )
+			interpret_ack( dev, ack );
+	} else
+		frame_ok = 0;
+
+	outb( inb( ioaddr + CSR0 ) ^ CT_ZER, ioaddr + CSR0 );
+	if( frame_ok ) {
+		nl->state |= FL_PREV_OK;
+		if( framelen > 4 )
+			nl->in_stats.all_rx_number++;
+	} else
+		nl->state &= ~FL_PREV_OK,
+		change_level( dev ),
+		nl->in_stats.all_rx_number++,
+		nl->in_stats.bad_rx_number++;
+
+	return  !frame_ok  ||  framelen > 4;
+}
 
-{
-	int autoirq = 0;
-	int bad_card = 0;
-	unsigned char csr0;
-	struct net_local* lp;
-	static int version_printed = 0;
-
-	DP( printk("%s: sbni_probe1 ioaddr=%d\n", dev->name, ioaddr); )
-       
-	if(check_region(ioaddr, SBNI_IO_EXTENT) < 0)
-		return -ENODEV;
-	if(version_printed++ == 0)
-		printk(version);
-     
-	/* check for valid combination in CSR0 */
-	csr0 = inb(ioaddr + CSR0);
-	if(csr0 == 0xff || csr0 == 0)
-		bad_card = 1;
-	else 
-	{
-		csr0 &= ~EN_INT;
-		if(csr0 & BU_EMP)
-			csr0 |= EN_INT;
-		if((VALID_DECODER & (1 << (csr0 >> 4))) == 0)
-			bad_card = 1;
-	}
 
-	if(bad_card)
-		return -ENODEV;
-	else
-		outb(0, ioaddr + CSR0); 
-	if(dev->irq < 2)
-	{
-		DP( printk("%s: autoprobing\n", dev->name); );
-		autoirq_setup(5);
-		outb(EN_INT | TR_REQ, ioaddr + CSR0);
-		outb(PR_RES, ioaddr + CSR1);
-		autoirq = autoirq_report(5);
-
-		if(autoirq == 0)
-		{
-			printk("sbni probe at %#x failed to detect IRQ line\n", ioaddr);
-			return -EAGAIN;
+static void
+send_frame( struct net_device  *dev )
+{
+	struct net_local  *nl    = (struct net_local *) dev->priv;
+
+	u32  crc = CRC32_INITIAL;
+
+	if( nl->state & FL_NEED_RESEND ) {
+
+		/* if frame was sended but not ACK'ed - resend it */
+		if( nl->trans_errors ) {
+			--nl->trans_errors;
+			if( nl->framelen != 0 )
+				nl->in_stats.resend_tx_number++;
+		} else {
+			/* cannot xmit with many attempts */
+#ifdef CONFIG_SBNI_MULTILINE
+			if( (nl->state & FL_SLAVE)  ||  nl->link )
+#endif
+			nl->state |= FL_LINE_DOWN;
+			drop_xmit_queue( dev );
+			goto  do_send;
 		}
-	}
-	/* clear FIFO buffer */
-	outb(0, ioaddr + CSR0);
-   
-	if(autoirq)
-		dev->irq = autoirq;
+	} else
+		nl->trans_errors = TR_ERROR_COUNT;
 
-	{
-   		int irqval=request_irq(dev->irq, sbni_interrupt, 0, dev->name, dev);
-		if (irqval) 
-		{
-			printk (" unable to get IRQ %d (irqval=%d).\n", dev->irq, irqval);
-			return -EAGAIN;
-		}
-	}
-     
-	/* 
-	 *	Initialize the device structure. 
+	send_frame_header( dev, &crc );
+	nl->state |= FL_NEED_RESEND;
+	/*
+	 * FL_NEED_RESEND will be cleared after ACK, but if empty
+	 * frame sended then in prepare_to_send next frame
 	 */
 
-	dev->priv = kmalloc(sizeof(struct net_local), GFP_KERNEL);
-	if(dev->priv == NULL)
-	{
-		DP( printk("%s: cannot allocate memory\n", dev->name); )
-		free_irq(dev->irq, dev);
-		return -ENOMEM;
-	}
-   
-	memset(dev->priv, 0, sizeof(struct net_local));
-	dev->base_addr = ioaddr;
-	request_region(ioaddr, SBNI_IO_EXTENT, "sbni");
-
-	/* 
-	 * generate Ethernet address (0x00ff01xxxxxx)
-	 */
 
-	*(u16*)dev->dev_addr = htons(0x00ff);
-	*(u32*)(dev->dev_addr+2) = htonl(((def_mac ? def_mac : (u32) dev->priv) & 0x00ffffff) | 0x01000000);
-   
-	lp = dev->priv;
-	if(def_rxl < 0)
-	{
-		/* autodetect receive level */
-		lp->rxl_curr = 0xf;
-		lp->rxl_delta = -1;
-	} else {
-		/* fixed receive level */
-		lp->rxl_curr = def_rxl & 0xf;
-		lp->rxl_delta = 0;
+	if( nl->framelen ) {
+		download_data( dev, &crc );
+		nl->in_stats.all_tx_number++;
+		nl->state |= FL_WAIT_ACK;
 	}
-	lp->csr1.rxl = rxl_tab[lp->rxl_curr];
-	lp->csr1.rate = def_baud & 3;
-	lp->frame_len = DEF_FRAME_LEN;
-	printk("%s: sbni adapter at %#lx, using %sIRQ %d, MAC: 00:ff:01:%x:%x:%x\n", 
-		dev->name, dev->base_addr, autoirq ? "auto":"assigned ", dev->irq,
-	       *(unsigned char*)(dev->dev_addr+3),
-	       *(unsigned char*)(dev->dev_addr+4),
-	       *(unsigned char*)(dev->dev_addr+5)
-	);
 
-	printk("%s: receive level: ", dev->name);
-	if(lp->rxl_delta == 0)
-		printk ("%#1x (fixed)", lp->rxl_curr); 
-	else
-		printk ("autodetect");
-	printk(", baud rate: %u\n", (unsigned)lp->csr1.rate);
-   
-	/*
-	 *	The SBNI-specific entries in the device structure. 
-	 */
-	dev->open = &sbni_open;
-	dev->hard_start_xmit = &sbni_start_xmit;
-	dev->stop = &sbni_close;
-	dev->get_stats = &sbni_get_stats;
-	dev->set_multicast_list = &set_multicast_list;
-	dev->set_mac_address = &sbni_set_mac_address;
-	dev->do_ioctl = &sbni_ioctl;
-   
-	/*
-	 *	Setup the generic properties 
-	 */
+	outsb( dev->base_addr + DAT, (u8 *)&crc, sizeof crc );
 
-	ether_setup(dev);
-   
-	dev->hard_header = sbni_header;
-	dev->hard_header_len = sizeof(struct sbni_hard_header);
-	dev->rebuild_header=sbni_rebuild_header;
-	dev->mtu = DEF_FRAME_LEN;
+do_send:
+	outb( inb( dev->base_addr + CSR0 ) & ~TR_REQ, dev->base_addr + CSR0 );
 
-	dev->hard_header_cache = sbni_header_cache;
-	dev->header_cache_update = sbni_header_cache_update;
-  
-  	spin_lock_init(&lp->lock);
-	lp->m=dev;
-	lp->me=dev;
-	lp->next_lp=NULL;
-  
-	return 0;
+	if( nl->tx_frameno )
+		/* next frame exists - we request card to send it */
+		outb( inb( dev->base_addr + CSR0 ) | TR_REQ,
+		      dev->base_addr + CSR0 );
 }
 
+
 /*
- *	Open/initialize the board. 
+ * Write the frame data into adapter's buffer memory, and calculate CRC.
+ * Do padding if necessary.
  */
 
-static int sbni_open(struct net_device *dev)
+static void
+download_data( struct net_device  *dev,  u32  *crc_p )
 {
-	struct net_local* lp = (struct net_local*)dev->priv;
-	struct timer_list* watchdog = &lp->watchdog;
-	unsigned long flags;   
-      
-	DP( printk("%s: sbni_open\n", dev->name); )
-     
-     	save_flags(flags);
-	cli();
-	lp->currframe = NULL;
-   
-	card_start(dev);
-	/* set timer  watchdog */
-	init_timer(watchdog);
-	watchdog->expires = jiffies + SBNI_TIMEOUT;
-	watchdog->data = (unsigned long)dev;
-	watchdog->function = sbni_watchdog;
-	add_timer(watchdog);
-	DP( printk("%s: sbni timer watchdog initialized\n", dev->name); );
-   
-	restore_flags(flags);
-	   
-	netif_start_queue(dev);
-	MOD_INC_USE_COUNT;
-	return 0;
+	struct net_local  *nl    = (struct net_local *) dev->priv;
+	struct sk_buff    *skb	 = nl->tx_buf_p;
+
+	unsigned  len = min( skb->len - nl->outpos, nl->framelen );
+
+	outsb( dev->base_addr + DAT, skb->data + nl->outpos, len );
+	*crc_p = calc_crc32( *crc_p, skb->data + nl->outpos, len );
+
+	/* if packet too short we should write some more bytes to pad */
+	for( len = nl->framelen - len;  len--; )
+		outb( 0, dev->base_addr + DAT ),
+		*crc_p = CRC32( 0, *crc_p );
 }
 
-static int sbni_close(struct net_device *dev)
+
+static int
+upload_data( struct net_device  *dev,  unsigned  framelen,  unsigned  frameno,
+	     unsigned  is_first,  u32  crc )
 {
-	int ioaddr = dev->base_addr;
-	struct net_local* lp = (struct net_local*) dev->priv;
-	struct timer_list* watchdog = &lp->watchdog;
-	unsigned long flags;
-	
-	DP( printk("%s: sbni_close\n", dev->name); )
+	struct net_local  *nl = (struct net_local *) dev->priv;
 
-	netif_stop_queue(dev);
+	int  frame_ok;
 
-	save_flags(flags);
-	cli();
-	sbni_drop_tx_queue(dev);	
-	del_timer(watchdog);
-	outb(0, ioaddr + CSR0);
-	restore_flags(flags);
+	if( is_first )
+		nl->wait_frameno = frameno,
+		nl->inppos = 0;
 
-	MOD_DEC_USE_COUNT;
-	return 0;
+	if( nl->wait_frameno == frameno ) {
+
+		if( nl->inppos + framelen  <=  ETHER_MAX_LEN )
+			frame_ok = append_frame_to_pkt( dev, framelen, crc );
+
+		/*
+		 * if CRC is right but framelen incorrect then transmitter
+		 * error was occured... drop entire packet
+		 */
+		else if( (frame_ok = skip_tail( dev->base_addr, framelen, crc ))
+			 != 0 )
+			nl->wait_frameno = 0,
+			nl->inppos = 0,
+#ifdef CONFIG_SBNI_MULTILINE
+			((struct net_local *) nl->master->priv)
+				->stats.rx_errors++,
+			((struct net_local *) nl->master->priv)
+				->stats.rx_missed_errors++;
+#else
+			nl->stats.rx_errors++,
+			nl->stats.rx_missed_errors++;
+#endif
+			/* now skip all frames until is_first != 0 */
+	} else
+		frame_ok = skip_tail( dev->base_addr, framelen, crc );
+
+	if( is_first  &&  !frame_ok )
+		/*
+		 * Frame has been broken, but we had already stored
+		 * is_first... Drop entire packet.
+		 */
+		nl->wait_frameno = 0,
+#ifdef CONFIG_SBNI_MULTILINE
+		((struct net_local *) nl->master->priv)->stats.rx_errors++,
+		((struct net_local *) nl->master->priv)->stats.rx_crc_errors++;
+#else
+		nl->stats.rx_errors++,
+		nl->stats.rx_crc_errors++;
+#endif
+
+	return  frame_ok;
 }
 
-static int sbni_start_xmit(struct sk_buff *skb, struct net_device *dev)
+
+static __inline void
+send_complete( struct net_local  *nl )
 {
-	struct net_local *lp = (struct net_local*)dev->priv;
-	struct sbni_hard_header *hh=(struct sbni_hard_header *)skb->data;
-	unsigned long flags;
-  
-#ifdef KATYUSHA   
-	struct net_local *nl;
-	int stop;
-#endif
-  
-	DP( printk("%s: sbni_start_xmit In \n", dev->name); );
-  
-  
-	if(lp->me != dev)
-		panic("sbni: lp->me != dev !!!\nMail to developer (xenon@granch.ru) if you noticed this error\n");
-  
-	hh->number = 1;
-	hh->reserv = 0;
-  
-	hh->packetlen =  (skb->len - sizeof (unsigned short) - 
-			(sizeof(struct sbni_hard_header) - SBNI_HH_SZ)) 
-			| PACKET_SEND_OK | PACKET_FIRST_FRAME;
-  
-	/* we should use hairy method to calculate crc because of extra bytes are 
-	  livin between hard header and data*/
-	hh->crc = calc_crc((void*)&hh->packetlen, SBNI_HH_SZ - sizeof(unsigned), CRC32_INITIAL);
-	hh->crc = calc_crc(skb->data + sizeof(struct sbni_hard_header),
-		       skb->len - sizeof(struct sbni_hard_header),
-		       hh->crc);
-  
-  	spin_lock_irqsave(&lp->lock, flags);
-#ifdef KATYUSHA
-	/* looking for first idle device */
-	for (stop=0,nl=lp; nl && !stop; nl=nl->next_lp)
-	{
-		if((!nl->currframe) && (nl->carrier)) /* if idle */
-		{
-			skb->dev = lp->me;
-			nl->currframe = skb;
-			/* set request for transmit */
-			outb(inb(nl->me->base_addr + CSR0) | TR_REQ, 
-				nl->me->base_addr + CSR0);
-			stop=1;
-		}
-	}
-  
-	if(!stop) /* we havent found any idle.*/
-	{
-		skb_queue_tail(&lp->queue,skb);
-		outb(inb(dev->base_addr + CSR0) | TR_REQ, dev->base_addr + CSR0);
-      
-	}		
-#else 
-	if (lp->currframe || 1)
-	{
-		skb_queue_tail(&lp->queue,skb);
-		  
-	}
-	else
-	{
-		lp->currframe = skb;
-	}
-	/* set request for transmit */
-	outb(inb(dev->base_addr + CSR0) | TR_REQ, dev->base_addr + CSR0);
+#ifdef CONFIG_SBNI_MULTILINE
+	((struct net_local *) nl->master->priv)->stats.tx_packets++;
+	((struct net_local *) nl->master->priv)->stats.tx_bytes
+		+= nl->tx_buf_p->len;
+#else
+	nl->stats.tx_packets++;
+	nl->stats.tx_bytes += nl->tx_buf_p->len;
 #endif
-	spin_unlock_irqrestore(&lp->lock, flags);
-	return 0;
+	dev_kfree_skb_irq( nl->tx_buf_p );
+
+	nl->tx_buf_p = NULL;
+
+	nl->outpos = 0;
+	nl->state &= ~(FL_WAIT_ACK | FL_NEED_RESEND);
+	nl->framelen   = 0;
 }
 
-static void card_start(struct net_device *dev)
+
+static void
+interpret_ack( struct net_device  *dev,  unsigned  ack )
 {
-	struct net_local *lp = (struct net_local*)dev->priv;
-   
-	DP( printk("%s: card_start\n",dev->name); )
-	lp->wait_frame_number = 0;
-	lp->inppos = lp->outpos = 0;
-	lp->eth_trans_buffer_len = 0;
-	lp->tr_err = TR_ERROR_COUNT;
-	lp->last_receive_OK = FALSE;
-	lp->tr_resend = FALSE;
-	lp->timer_ticks = CHANGE_LEVEL_START_TICKS;
-	lp->timeout_rxl = 0;
-
-	lp->waitack=0;
-	skb_queue_head_init(&lp->queue);
-	sbni_drop_tx_queue(dev);
-	/* Reset the card and set start parameters */
-	outb(PR_RES | *(char*)&lp->csr1, dev->base_addr + CSR1);
-	outb(EN_INT, dev->base_addr + CSR0);
-}
-
-void sbni_nirvana(struct net_device *dev)
-{
-	sbni_outs(dev->base_addr+DAT,magic_reply,9);
-}
-
-static inline unsigned short sbni_recv(struct net_device *dev)
-{
-	struct net_local *lp = (struct net_local*)dev->priv;
-	unsigned long crc;
-	unsigned short packetlen = 0;
-	unsigned short packetinf, packetfirst, receiveframeresend;
-	unsigned char current_frame;
-	unsigned int i, j;
-	unsigned char delme,rcv_res=RCV_WR;
-  
-	lp->in_stats.all_rx_number++;
-  
-	if((delme=inb(dev->base_addr + DAT)) == SBNI_SIG)
-	{
-		crc = CRC32_INITIAL;
-		*(((unsigned char *)&packetlen) + 0) = inb(dev->base_addr + DAT);
-		crc = CRC32(*(((unsigned char *)&packetlen) + 0), crc);
-		*(((unsigned char *)&packetlen) + 1) = inb(dev->base_addr + DAT);
-		crc = CRC32(*(((unsigned char *)&packetlen) + 1), crc);
-		packetinf = packetlen & PACKET_INF_MASK;
-		packetfirst = packetlen & PACKET_FIRST_FRAME;
-		receiveframeresend = packetlen & RECEIVE_FRAME_RESEND;
-		packetlen = packetlen & PACKET_LEN_MASK;
-    
-    
-		if((packetlen <= SB_MAX_BUFFER_ARRAY - 3) && (packetlen >= 6))
-		{
-			/* read frame number */
-			current_frame = inb(dev->base_addr + DAT);
-			crc = CRC32(current_frame, crc);
-			/* read HandShake counter */
-			lp->HSCounter = inb(dev->base_addr + DAT);
-			crc = CRC32(lp->HSCounter, crc);
-			packetlen -= 2;
-      
-			sbni_ins(dev->base_addr + DAT, lp->eth_rcv_buffer + lp->inppos, packetlen);
-      
-			for(i = lp->inppos; i < (packetlen + lp->inppos); i++)
-			{
-				crc = CRC32(lp->eth_rcv_buffer[i], crc);
-			}
-      
-			if(crc == CRC32_REMAINDER)
-			{
-				if(packetlen > 4) 
-					rcv_res=RCV_OK;
-				else if(packetlen == 4) 
-					rcv_res=RCV_NO;
-      		
-				if(lp->waitack && packetinf == PACKET_RESEND)
-					lp->in_stats.resend_tx_number++;
-	
-	
-				switch(packetinf)
-				{
-				case PACKET_SEND_OK:
-				{
-					lp->tr_err = TR_ERROR_COUNT;
-					lp->tr_resend = FALSE;
-					/* if(lp->trans_frame_number){ */
-					lp->outpos += lp->realframelen;
-	      
-					/* SendComplete
-					 * not supported
-					 */
-					DP( printk("%s: sbni_recv SendComplete\n",dev->name); );
-					/*
-					 *	We successfully sent current packet
-					 */
-	      
-					if(lp->waitack)
-					{
-						dev_kfree_skb(lp->currframe);
-						lp->stats.tx_packets++;
-#ifdef KATYUSHA
-						lp->currframe=skb_dequeue(&(((struct net_local*) (lp->m->priv))->queue));
+	struct net_local  *nl = (struct net_local *) dev->priv;
+
+	if( ack == FRAME_SENT_OK ) {
+		nl->state &= ~FL_NEED_RESEND;
+
+		if( nl->state & FL_WAIT_ACK ) {
+			nl->outpos += nl->framelen;
+
+			if( --nl->tx_frameno )
+				nl->framelen = min( nl->maxframe,
+					nl->tx_buf_p->len - nl->outpos );
+			else
+				send_complete( nl ),
+#ifdef CONFIG_SBNI_MULTILINE
+				netif_wake_queue( nl->master );
 #else
-						lp->currframe=skb_dequeue(&lp->queue);
-#endif		       
-						lp->in_stats.all_tx_number++;
-						lp->waitack=0;
-					}
-	      
-					/*
-	      				 * reset output active flags
-					 */
-					netif_wake_queue(dev);
-					/*} if */
-				}
-				case PACKET_RESEND:
-				{
-					if(lp->tr_err) /**/
-						lp->tr_err--;
-					if(lp->ok_curr < 0xffffffff)
-						lp->ok_curr++;
-					if(packetlen > 4 && !(lp->last_receive_OK && receiveframeresend))
-					{
-						if(packetfirst)
-						{
-							if(lp->wait_frame_number)
-							{
-								for(i = lp->inppos, j = 0; 
-									i < (lp->inppos + packetlen - 4); 
-									i++, j++)
-								lp->eth_rcv_buffer[j] = lp->eth_rcv_buffer[i];
-							}
-							lp->wait_frame_number = current_frame;
-							lp->inppos = 0;
-						}
-						if(current_frame == lp->wait_frame_number)
-						{
-							lp->inppos += (packetlen - 4);
-							if(lp->wait_frame_number == 1)
-		  					{
-								sbni_get_packet(dev);
-								lp->inppos = 0;
-							}
-							lp->wait_frame_number--;
-						}
-					}
-					lp->last_receive_OK = TRUE;
-					break;
-				}
-				default:
-					break;
-				}
-			}
-			else 
-			{
-				DP(printk("%s: bad CRC32\n",dev->name));
-				change_level(dev);
-			}
-		}
-		else 
-		{
-			DP(printk("%s: bad len\n ",dev->name));
-			change_level(dev);
-			lp->stats.rx_over_errors++;
+				netif_wake_queue( dev );
+#endif
 		}
 	}
-	else 
-	{
-		DP(printk("%s: bad sig\n",dev->name));
-		change_level(dev);
-	}
-	outb(inb(dev->base_addr + CSR0) ^ CT_ZER, dev->base_addr + CSR0);
-	return (rcv_res);
+
+	nl->state &= ~FL_WAIT_ACK;
 }
 
-void change_level(struct net_device *dev)
+
+/*
+ * Glue received frame with previous fragments of packet.
+ * Indicate packet when last frame would be accepted.
+ */
+
+static int
+append_frame_to_pkt( struct net_device  *dev,  unsigned  framelen,  u32  crc )
 {
-	struct net_local *lp = (struct net_local*)dev->priv;
+	struct net_local  *nl = (struct net_local *) dev->priv;
 
-	lp->in_stats.bad_rx_number++;
-	lp->stats.tx_errors++;
-	if(lp->rxl_delta == 0)
-		return;
-	/* 
-	 * set new rxl_delta value
-	 */
-	if(lp->rxl_curr == 0)
-		lp->rxl_delta = 1;
-	else if(lp->rxl_curr == 0xf)
-		lp->rxl_delta = -1;
-	else if(lp->ok_curr < lp->ok_prev)
-		lp->rxl_delta = -lp->rxl_delta;
-	/*
-	 * set new rxl_curr value
-	 */
-	lp->csr1.rxl = rxl_tab[lp->rxl_curr += lp->rxl_delta];
-	outb(*(char*)&lp->csr1, dev->base_addr + CSR1);
-  
-  
-	/*
-	 * update ok_prev/ok_curr counters
-	 */
-	lp->ok_prev = lp->ok_curr;
-	lp->ok_curr = 0;
+	u8  *p;
+
+	if( nl->inppos + framelen  >  ETHER_MAX_LEN )
+		return  0;
+
+	if( !nl->rx_buf_p  &&  !(nl->rx_buf_p = get_rx_buf( dev )) )
+		return  0;
 
-	DP( printk("%s: receive error, rxl_curr = %d, rxl_delta = %d\n",\
-		   dev->name,lp->rxl_curr, lp->rxl_delta); )
-     
+	p = nl->rx_buf_p->data + nl->inppos;
+	insb( dev->base_addr + DAT, p, framelen );
+	if( calc_crc32( crc, p, framelen ) != CRC32_REMAINDER )
+		return  0;
+
+	nl->inppos += framelen - 4;
+	if( --nl->wait_frameno == 0 )		/* last frame received */
+		indicate_pkt( dev );
+
+	return  1;
 }
 
-static inline void sbni_xmit(struct net_device *dev)
+
+/*
+ * Prepare to start output on adapter.
+ * Transmitter will be actually activated when marker is accepted.
+ */
+
+static void
+prepare_to_send( struct sk_buff  *skb,  struct net_device  *dev )
 {
-	struct net_local* lp = (struct net_local *)dev->priv;
-	struct sk_buff *skb;
- 
-	skb=lp->currframe;
-  
-	DP( printk("%s: sbni_xmit CSR0=%02x\n",dev->name, (unsigned char)inb(dev->base_addr + CSR0)); );
-	  
-	/* push signature*/  
-	outb(SBNI_SIG, dev->base_addr + DAT);
-	
-	/* push frame w/o crc [HAiRY]*/
-	sbni_outs(dev->base_addr + DAT,
-	      &((struct sbni_hard_header *)(skb->data))->packetlen,
-	      SBNI_HH_SZ - sizeof(unsigned)); 
-	
-	sbni_outs(dev->base_addr + DAT,
-	      skb->data + sizeof(struct sbni_hard_header),
-	      skb->len - sizeof(struct sbni_hard_header)); /* ÕÓÐÅÅÍ ÅÝÅ */
+	struct net_local  *nl = (struct net_local *) dev->priv;
 
-	/* push crc */
-	sbni_outs(dev->base_addr + DAT, skb->data, sizeof(unsigned));
-	
-	lp->waitack=1;
+	unsigned int  len;
+
+	/* nl->tx_buf_p == NULL here! */
+	if( nl->tx_buf_p )
+		printk( KERN_ERR "%s: memory leak!\n", dev->name );
+
+	nl->outpos = 0;
+	nl->state &= ~(FL_WAIT_ACK | FL_NEED_RESEND);
+
+	len = skb->len;
+	if( len < SBNI_MIN_LEN )
+		len = SBNI_MIN_LEN;
+
+	nl->tx_buf_p	= skb;
+	nl->tx_frameno	= (len + nl->maxframe - 1) / nl->maxframe;
+	nl->framelen	= len < nl->maxframe  ?  len  :  nl->maxframe;
+
+	outb( inb( dev->base_addr + CSR0 ) | TR_REQ,  dev->base_addr + CSR0 );
+#ifdef CONFIG_SBNI_MULTILINE
+	nl->master->trans_start = jiffies;
+#else
+	dev->trans_start = jiffies;
+#endif
+}
+
+
+static void
+drop_xmit_queue( struct net_device  *dev )
+{
+	struct net_local  *nl = (struct net_local *) dev->priv;
+
+	if( nl->tx_buf_p )
+		dev_kfree_skb_any( nl->tx_buf_p ),
+		nl->tx_buf_p = NULL,
+#ifdef CONFIG_SBNI_MULTILINE
+		((struct net_local *) nl->master->priv)
+			->stats.tx_errors++,
+		((struct net_local *) nl->master->priv)
+			->stats.tx_carrier_errors++;
+#else
+		nl->stats.tx_errors++,
+		nl->stats.tx_carrier_errors++;
+#endif
+
+	nl->tx_frameno	= 0;
+	nl->framelen	= 0;
+	nl->outpos	= 0;
+	nl->state &= ~(FL_WAIT_ACK | FL_NEED_RESEND);
+#ifdef CONFIG_SBNI_MULTILINE
+	netif_start_queue( nl->master );
+	nl->master->trans_start = jiffies;
+#else
+	netif_start_queue( dev );
+	dev->trans_start = jiffies;
+#endif
 }
 
+
+static void
+send_frame_header( struct net_device  *dev,  u32  *crc_p )
+{
+	struct net_local  *nl  = (struct net_local *) dev->priv;
+
+	u32  crc = *crc_p;
+	u32  len_field = nl->framelen + 6;	/* CRC + frameno + reserved */
+	u8   value;
+
+	if( nl->state & FL_NEED_RESEND )
+		len_field |= FRAME_RETRY;	/* non-first attempt... */
+
+	if( nl->outpos == 0 )
+		len_field |= FRAME_FIRST;
+
+	len_field |= (nl->state & FL_PREV_OK) ? FRAME_SENT_OK : FRAME_SENT_BAD;
+	outb( SBNI_SIG, dev->base_addr + DAT );
+
+	value = (u8) len_field;
+	outb( value, dev->base_addr + DAT );
+	crc = CRC32( value, crc );
+	value = (u8) (len_field >> 8);
+	outb( value, dev->base_addr + DAT );
+	crc = CRC32( value, crc );
+
+	outb( nl->tx_frameno, dev->base_addr + DAT );
+	crc = CRC32( nl->tx_frameno, crc );
+	outb( 0, dev->base_addr + DAT );
+	crc = CRC32( 0, crc );
+	*crc_p = crc;
+}
+
+
 /*
- *	The typical workload of the driver:
- *	Handle the ether interface interrupts. 
+ * if frame tail not needed (incorrect number or received twice),
+ * it won't store, but CRC will be calculated
  */
-static void sbni_interrupt(int irq, void *dev_id, struct pt_regs *regs)
+
+static int
+skip_tail( unsigned int  ioaddr,  unsigned int  tail_len,  u32 crc )
 {
-	struct net_device *dev = dev_id;
-	struct net_local* lp;
-	u_char csr0;
-	unsigned short rcv_res = RCV_NO;
-  
-  
-	if(dev == NULL || dev->irq != irq)
-	{
-		printk("sbni: irq %d for unknown device\n", irq);
-		return;
-	}
-   
-	csr0 = inb(dev->base_addr + CSR0);
-	DP( printk("%s: entering interrupt handler, CSR0 = %02x\n", dev->name, csr0); )
-     
-	lp=dev->priv;
+	while( tail_len-- )
+		crc = CRC32( inb( ioaddr + DAT ), crc );
 
-   	spin_lock(&lp->lock);
-  
-	if(!lp->carrier)
-		lp->carrier=1;
-  
-	/*
-	 * Disable adapter interrupts
-	 */
-	outb((csr0 & ~EN_INT) | TR_REQ, dev->base_addr + CSR0);
-	lp->timer_ticks = CHANGE_LEVEL_START_TICKS;
-	csr0 = inb(dev->base_addr + CSR0);
-   
-	if(csr0 & (TR_RDY | RC_RDY))
-	{
-		if(csr0 & RC_RDY)
-			rcv_res = sbni_recv(dev);
-	   
-		if((lp->currframe) && (rcv_res != RCV_WR))
-			sbni_xmit(dev);
-		else if (rcv_res == RCV_OK)
-			sbni_nirvana(dev);
-       
-		csr0 = inb(dev->base_addr + CSR0);
-		DP( printk("%s: CSR0 = %02x\n",dev->name, (u_int)csr0); );
-	}
-   
-  
-	DP( printk("%s: leaving interrupt handler, CSR0 = %02x\n",dev->name, csr0 | EN_INT); );
-     
-	/* here we should send pong */
-	outb(inb(dev->base_addr+CSR0) & ~TR_REQ, dev->base_addr + CSR0);
-	if(lp->currframe)
-		outb(inb(dev->base_addr+CSR0) | TR_REQ, dev->base_addr + CSR0);
-	else
-		csr0 = inb(dev->base_addr + CSR0);
-  
-	/*
-	 * Enable adapter interrupts
-	 */
-  
-	outb(csr0 | EN_INT, dev->base_addr + CSR0);
-	spin_unlock(&lp->lock);
+	return  crc == CRC32_REMAINDER;
+}
+
+
+/*
+ * Preliminary checks if frame header is correct, calculates its CRC
+ * and split it to simple fields
+ */
+
+static int
+check_fhdr( u32  ioaddr,  u32  *framelen,  u32  *frameno,  u32  *ack,
+	    u32  *is_first,  u32  *crc_p )
+{
+	u32  crc = *crc_p;
+	u8   value;
+
+	if( inb( ioaddr + DAT ) != SBNI_SIG )
+		return  0;
+
+	value = inb( ioaddr + DAT );
+	*framelen = (u32)value;
+	crc = CRC32( value, crc );
+	value = inb( ioaddr + DAT );
+	*framelen |= ((u32)value) << 8;
+	crc = CRC32( value, crc );
+
+	*ack = *framelen & FRAME_ACK_MASK;
+	*is_first = (*framelen & FRAME_FIRST) != 0;
+
+	if( (*framelen &= FRAME_LEN_MASK) < 6
+	    ||  *framelen > SBNI_MAX_FRAME - 3 )
+		return  0;
+
+	value = inb( ioaddr + DAT );
+	*frameno = (u32)value;
+	crc = CRC32( value, crc );
+
+	crc = CRC32( inb( ioaddr + DAT ), crc );	/* reserved byte */
+	*framelen -= 2;
+
+	*crc_p = crc;
+	return  1;
 }
 
-static struct net_device_stats *sbni_get_stats(struct net_device *dev)
+
+static struct sk_buff *
+get_rx_buf( struct net_device  *dev )
 {
-	struct net_local *lp = (struct net_local *)dev->priv;
-	return &lp->stats;
+	/* +2 is to compensate for the alignment fixup below */
+	struct sk_buff  *skb = dev_alloc_skb( ETHER_MAX_LEN + 2 );
+	if( !skb )
+		return  NULL;
+
+#ifdef CONFIG_SBNI_MULTILINE
+	skb->dev = ((struct net_local *) dev->priv)->master;
+#else
+	skb->dev = dev;
+#endif
+	skb_reserve( skb, 2 );		/* Align IP on longword boundaries */
+	return  skb;
 }
 
-static inline void sbni_get_packet(struct net_device* dev)
+
+static void
+indicate_pkt( struct net_device  *dev )
 {
-	struct net_local* lp = (struct net_local*)dev->priv;
-	struct sk_buff* skb;
-	unsigned char *rawp;
-    
-   
-     
-	skb = dev_alloc_skb(lp->inppos - ETH_HLEN + sizeof(struct sbni_hard_header));
-   
-	if(skb == NULL)
-	{
-		DP( printk("%s: Memory squeeze, dropping packet.\n", dev->name); )
-		lp->stats.rx_dropped++;
-		return;
-	} else {
-#ifdef KATYUSHA
-		skb->dev = lp->m;
+	struct net_local  *nl  = (struct net_local *) dev->priv;
+	struct sk_buff    *skb = nl->rx_buf_p;
+
+	skb_put( skb, nl->inppos );
+
+#ifdef CONFIG_SBNI_MULTILINE
+	skb->protocol = eth_type_trans( skb, nl->master );
+	netif_rx( skb );
+	dev->last_rx = jiffies;
+	++((struct net_local *) nl->master->priv)->stats.rx_packets;
+	((struct net_local *) nl->master->priv)->stats.rx_bytes += nl->inppos;
 #else
-		skb->dev = dev;
-#endif      
-		memcpy((unsigned char*)skb_put(skb, lp->inppos + 8)+8,
-			lp->eth_rcv_buffer,
-			lp->inppos);
-      
-      
-		skb->mac.raw = skb->data + 8;
-    
-		if((*(char*)lp->eth_rcv_buffer) & 1)
-		{
-			if(memcmp(lp->eth_rcv_buffer,dev->broadcast, ETH_ALEN)==0)
-				skb->pkt_type=PACKET_BROADCAST;
-			else
-				skb->pkt_type=PACKET_MULTICAST;
-		}
-		else if(dev->flags&(IFF_PROMISC|IFF_ALLMULTI))
-		{
-			if(memcmp(lp->eth_rcv_buffer,dev->dev_addr, ETH_ALEN))
-				skb->pkt_type=PACKET_OTHERHOST;
-		}
-      
-		if( htons(*((unsigned short*)(&lp->eth_rcv_buffer[2*ETH_ALEN]))) >= 1536)
-			skb->protocol =  *((unsigned short*)(&lp->eth_rcv_buffer[2*ETH_ALEN]));
-		else
-		{
-			rawp = (unsigned char*)(&lp->eth_rcv_buffer[2*ETH_ALEN]);
-			if (*(unsigned short *)rawp == 0xFFFF)
-				skb->protocol=htons(ETH_P_802_3);
-			else
-				skb->protocol=htons(ETH_P_802_2);
+	skb->protocol = eth_type_trans( skb, dev );
+	netif_rx( skb );
+	dev->last_rx = jiffies;
+	++nl->stats.rx_packets;
+	nl->stats.rx_bytes += nl->inppos;
+#endif
+	nl->rx_buf_p = NULL;	/* protocol driver will clear this sk_buff */
+}
+
+
+/* -------------------------------------------------------------------------- */
+
+/*
+ * Routine checks periodically wire activity and regenerates marker if
+ * connect was inactive for a long time.
+ */
+
+static void
+sbni_watchdog( unsigned long  arg )
+{
+	struct net_device  *dev = (struct net_device *) arg;
+	struct net_local   *nl  = (struct net_local *) dev->priv;
+	struct timer_list  *w   = &nl->watchdog; 
+	unsigned long	   flags;
+	unsigned char	   csr0;
+
+	spin_lock_irqsave( &nl->lock, flags );
+
+	csr0 = inb( dev->base_addr + CSR0 );
+	if( csr0 & RC_CHK ) {
+
+		if( nl->timer_ticks ) {
+			if( csr0 & (RC_RDY | BU_EMP) )
+				/* receiving not active */
+				nl->timer_ticks--;
+		} else {
+			nl->in_stats.timeout_number++;
+			if( nl->delta_rxl )
+				timeout_change_level( dev );
+
+			outb( *(u_char *)&nl->csr1 | PR_RES,
+			      dev->base_addr + CSR1 );
+			csr0 = inb( dev->base_addr + CSR0 );
 		}
-            
+	} else
+		nl->state &= ~FL_LINE_DOWN;
 
-		skb_pull(skb,SBNI_HH_SZ);
-   
-		skb->dev->last_rx = jiffies;
-		lp->stats.rx_bytes += skb->len;
-		netif_rx(skb);
-		lp->stats.rx_packets++;
-	}
-	return;
+	outb( csr0 | RC_CHK, dev->base_addr + CSR0 ); 
+
+	init_timer( w );
+	w->expires	= jiffies + SBNI_TIMEOUT;
+	w->data		= arg;
+	w->function	= sbni_watchdog;
+	add_timer( w );
+
+	spin_unlock_irqrestore( &nl->lock, flags );
 }
 
-static void sbni_watchdog(unsigned long arg)
+
+static unsigned char  rxl_tab[] = {
+	0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x08,
+	0x0a, 0x0c, 0x0f, 0x16, 0x18, 0x1a, 0x1c, 0x1f
+};
+
+#define SIZE_OF_TIMEOUT_RXL_TAB 4
+static unsigned char  timeout_rxl_tab[] = {
+	0x03, 0x05, 0x08, 0x0b
+};
+
+/* -------------------------------------------------------------------------- */
+
+static void
+card_start( struct net_device  *dev )
 {
-	struct net_device* dev = (struct net_device*)arg;
-	struct net_local* lp = (struct net_local *)dev->priv;
-	u_char csr0;
+	struct net_local  *nl = (struct net_local *) dev->priv;
 
+	nl->timer_ticks = CHANGE_LEVEL_START_TICKS;
+	nl->state &= ~(FL_WAIT_ACK | FL_NEED_RESEND);
+	nl->state |= FL_PREV_OK;
+
+	nl->inppos = nl->outpos = 0;
+	nl->wait_frameno = 0;
+	nl->tx_frameno	 = 0;
+	nl->framelen	 = 0;
+
+	outb( *(u_char *)&nl->csr1 | PR_RES, dev->base_addr + CSR1 );
+	outb( EN_INT, dev->base_addr + CSR0 );
+}
+
+/* -------------------------------------------------------------------------- */
+
+/* Receive level auto-selection */
+
+static void
+change_level( struct net_device  *dev )
+{
+	struct net_local  *nl = (struct net_local *) dev->priv;
+
+	if( nl->delta_rxl == 0 )	/* do not auto-negotiate RxL */
+		return;
+
+	if( nl->cur_rxl_index == 0 )
+		nl->delta_rxl = 1;
+	else if( nl->cur_rxl_index == 15 )
+		nl->delta_rxl = -1;
+	else if( nl->cur_rxl_rcvd < nl->prev_rxl_rcvd )
+		nl->delta_rxl = -nl->delta_rxl;
+
+	nl->csr1.rxl = rxl_tab[ nl->cur_rxl_index += nl->delta_rxl ];
+	inb( dev->base_addr + CSR0 );	/* needs for PCI cards */
+	outb( *(u8 *)&nl->csr1, dev->base_addr + CSR1 );
+
+	nl->prev_rxl_rcvd = nl->cur_rxl_rcvd;
+	nl->cur_rxl_rcvd  = 0;
+}
+
+
+static void
+timeout_change_level( struct net_device  *dev )
+{
+	struct net_local  *nl = (struct net_local *) dev->priv;
+
+	nl->cur_rxl_index = timeout_rxl_tab[ nl->timeout_rxl ];
+	if( ++nl->timeout_rxl >= 4 )
+		nl->timeout_rxl = 0;
+
+	nl->csr1.rxl = rxl_tab[ nl->cur_rxl_index ];
+	inb( dev->base_addr + CSR0 );
+	outb( *(unsigned char *)&nl->csr1, dev->base_addr + CSR1 );
+
+	nl->prev_rxl_rcvd = nl->cur_rxl_rcvd;
+	nl->cur_rxl_rcvd  = 0;
+}
+
+/* -------------------------------------------------------------------------- */
+
+/*
+ *	Open/initialize the board. 
+ */
+
+static int
+sbni_open( struct net_device  *dev )
+{
+	struct net_local	*nl = (struct net_local *) dev->priv;
+	struct timer_list	*w  = &nl->watchdog;
 
-  
-	DP( printk("%s: watchdog start\n",dev->name); )	
 	/*
-	 * if no pong received and transmission is not in progress
-	 * then assume error
+	 * For double ISA adapters within "common irq" mode, we have to
+	 * determine whether primary or secondary channel is initialized,
+	 * and set the irq handler only in first case.
 	 */
-	cli();
-	csr0 = inb(dev->base_addr + CSR0);
-	if(csr0 & (RC_CHK | TR_REQ))
-	{
-		if(lp->timer_ticks)
-		{
-			if(csr0 & (RC_RDY | BU_EMP))
-			{
-				lp->timer_ticks--;
-			}
-		}
-		else 
-		{
-			if(lp->rxl_delta)
-			{
-				lp->ok_prev = lp->ok_curr;
-				lp->ok_curr = 0;
-				lp->rxl_curr = timeout_rxl_tab[lp->timeout_rxl];
-				lp->timeout_rxl++;
-				if(lp->timeout_rxl > SIZE_OF_TIMEOUT_RXL_TAB - 1)
-					lp->timeout_rxl = 0; 
-				lp->csr1.rxl = rxl_tab[lp->rxl_curr];
-				/*
-				 * update ok_prev/ok_curr counters
-				 */
-				lp->ok_prev = lp->ok_curr;
-				lp->ok_curr = 0;
+	if( dev->base_addr < 0x400 ) {		/* ISA only */
+		struct net_device  **p = sbni_cards;
+		for( ;  *p  &&  p < sbni_cards + SBNI_MAX_NUM_CARDS;  ++p )
+			if( (*p)->irq == dev->irq
+			    &&  ((*p)->base_addr == dev->base_addr + 4
+				 ||  (*p)->base_addr == dev->base_addr - 4)
+			    &&  (*p)->flags & IFF_UP ) {
+
+				((struct net_local *) ((*p)->priv))
+					->second = dev;
+				printk( KERN_NOTICE "%s: using shared irq "
+					"with %s\n", dev->name, (*p)->name );
+				nl->state |= FL_SECONDARY;
+				goto  handler_attached;
 			}
-			if(lp->tr_err)
-				lp->tr_err--;
-			else 
-			{
-				/* Drop the queue of tx packets */
-				sbni_drop_tx_queue(dev);
-				lp->carrier=0;
-			}
-	     
-			/*
-			 * send pong
-			 */
-
-			csr0 = inb(dev->base_addr + CSR0);
-			outb(csr0 & ~TR_REQ, dev->base_addr + CSR0);
-			outb(*(char*)(&lp->csr1) | PR_RES, dev->base_addr + CSR1);
-			lp->in_stats.timeout_number++;
-		}
 	}
-	sti();
-	outb(csr0 | RC_CHK, dev->base_addr + CSR0);
-	if(netif_running(dev))
-	{
-		struct timer_list* watchdog = &lp->watchdog; 
-		init_timer(watchdog);
-		watchdog->expires = jiffies + SBNI_TIMEOUT;
-		watchdog->data = arg;
-		watchdog->function = sbni_watchdog;
-		add_timer(watchdog);
+
+	if( request_irq(dev->irq, sbni_interrupt, SA_SHIRQ, dev->name, dev) ) {
+		printk( KERN_ERR "%s: unable to get IRQ %d.\n",
+			dev->name, dev->irq );
+		return  -EAGAIN;
 	}
-}
 
-static void sbni_drop_tx_queue(struct net_device *dev)
-{
-	struct net_local* lp = (struct net_local *)dev->priv,*nl;
-	struct sk_buff *tmp;
+handler_attached:
+
+	spin_lock( &nl->lock );
+	memset( &nl->stats, 0, sizeof(struct net_device_stats) );
+	memset( &nl->in_stats, 0, sizeof(struct sbni_in_stats) );
+
+	card_start( dev );
+
+	netif_start_queue( dev );
+
+	/* set timer watchdog */
+	init_timer( w );
+	w->expires	= jiffies + SBNI_TIMEOUT;
+	w->data		= (unsigned long) dev;
+	w->function	= sbni_watchdog;
+	add_timer( w );
    
-	/* first of all, we should try to gift our packets to another interface */
-  
-	nl=(struct net_local *)lp->m->priv;
-	if(nl==lp)
-		nl=lp->next_lp;
-  
-	if(nl)
-	{
-		/* we found device*/
-		if(lp->currframe)
-		{
-			if(!nl->currframe)
-			{
-				nl->currframe=lp->currframe;
-			}
-			else
-			{
-				skb_queue_head(&((struct net_local*)(lp->m->priv))->queue,lp->currframe);
-			}
-		}
-		lp->currframe=NULL;
+	spin_unlock( &nl->lock );
+	return 0;
+}
+
 
-		if(!nl->currframe)
-			nl->currframe=skb_dequeue(&(((struct net_local*)(lp->m->priv))->queue));
+static int
+sbni_close( struct net_device  *dev )
+{
+	struct net_local  *nl = (struct net_local *) dev->priv;
 
-		/* set request for transmit */
-		outb(inb(nl->me->base_addr + CSR0) | TR_REQ,  nl->me->base_addr + CSR0);
-    
+	if( nl->second  &&  nl->second->flags & IFF_UP ) {
+		printk( KERN_NOTICE "Secondary channel (%s) is active!\n",
+			nl->second->name );
+		return  -EBUSY;
 	}
+
+#ifdef CONFIG_SBNI_MULTILINE
+	if( nl->state & FL_SLAVE )
+		emancipate( dev );
 	else
-	{
-		/* *sigh*, we should forget this packets */
-		nl=lp->m->priv;
-    
-		while((tmp = skb_dequeue(&nl->queue)) != NULL)
-		{
-			dev_kfree_skb(tmp);
-			lp->stats.tx_packets++;
-		}
-    
-		if (lp->currframe)
-		{
-			dev_kfree_skb(lp->currframe);
-			lp->currframe = NULL;
-			lp->stats.tx_packets++;
-		}
-	}
-	lp->waitack=0;
-	netif_wake_queue(dev);
-	
-	DP( printk("%s: queue dropping stopped\n",dev->name); );	
+		while( nl->link )	/* it's master device! */
+			emancipate( nl->link );
+#endif
+
+	spin_lock( &nl->lock );
+
+	nl->second = NULL;
+	drop_xmit_queue( dev );	
+	netif_stop_queue( dev );
+   
+	del_timer( &nl->watchdog );
+
+	outb( 0, dev->base_addr + CSR0 );
+
+	if( !(nl->state & FL_SECONDARY) )
+		free_irq( dev->irq, dev );
+	nl->state &= FL_SECONDARY;
+
+	spin_unlock( &nl->lock );
+	return 0;
 }
 
+
 /*
- * Set or clear the multicast filter for this adaptor.
- * num_addrs == -1	Promiscuous mode, receive all packets
- * num_addrs == 0	Normal mode, clear multicast list
- * num_addrs > 0	Multicast mode, receive normal and MC packets,
- *			and do best-effort filtering.
- */
- 
-static void set_multicast_list(struct net_device *dev)
+	Valid combinations in CSR0 (for probing):
+
+	VALID_DECODER	0000,0011,1011,1010
+
+				    	; 0   ; -
+				TR_REQ	; 1   ; +
+			TR_RDY	    	; 2   ; -
+			TR_RDY	TR_REQ	; 3   ; +
+		BU_EMP		    	; 4   ; +
+		BU_EMP	     	TR_REQ	; 5   ; +
+		BU_EMP	TR_RDY	    	; 6   ; -
+		BU_EMP	TR_RDY	TR_REQ	; 7   ; +
+	RC_RDY 		     		; 8   ; +
+	RC_RDY			TR_REQ	; 9   ; +
+	RC_RDY		TR_RDY		; 10  ; -
+	RC_RDY		TR_RDY	TR_REQ	; 11  ; -
+	RC_RDY	BU_EMP			; 12  ; -
+	RC_RDY	BU_EMP		TR_REQ	; 13  ; -
+	RC_RDY	BU_EMP	TR_RDY		; 14  ; -
+	RC_RDY	BU_EMP	TR_RDY	TR_REQ	; 15  ; -
+*/
+
+#define VALID_DECODER (2 + 8 + 0x10 + 0x20 + 0x80 + 0x100 + 0x200)
+
+
+static int
+sbni_card_probe( unsigned long  ioaddr )
 {
-	/*
-	 * always enabled promiscuous mode.
-	*/
-	return;
-}
+	unsigned char  csr0;
 
-static int sbni_set_mac_address(struct net_device *dev, void *addr)
-{	
-	/* struct net_local *lp = (struct net_local *)dev->priv; */
-	struct sockaddr *saddr = addr;
-	
-	if(netif_running(dev))
-	{
-		/* Only possible while card isn't started */
-		return -EBUSY;
+	csr0 = inb( ioaddr + CSR0 );
+	if( csr0 != 0xff  &&  csr0 != 0x00 ) {
+		csr0 &= ~EN_INT;
+		if( csr0 & BU_EMP )
+			csr0 |= EN_INT;
+      
+		if( VALID_DECODER & (1 << (csr0 >> 4)) )
+			return  0;
 	}
-	memcpy(dev->dev_addr, saddr->sa_data, dev->addr_len);
-	return (0);
+   
+	return  -ENODEV;
 }
 
-static int sbni_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd)
+/* -------------------------------------------------------------------------- */
+
+static int
+sbni_ioctl( struct net_device  *dev,  struct ifreq  *ifr,  int  cmd )
 {
-	struct net_local* lp = (struct net_local *)dev->priv,*tlp; 
-	struct net_device *slave;
-	int error = 0;
-	char tmpstr[6];
-  
+	struct net_local  *nl = (struct net_local *) dev->priv; 
+	struct sbni_flags  flags;
+	int  error = 0;
+
+#ifdef CONFIG_SBNI_MULTILINE
+	struct net_device  *slave_dev;
+	char  slave_name[ 8 ];
+#endif
   
-	switch(cmd)
-	{
-		case SIOCDEVGETINSTATS:
-		{
-			struct sbni_in_stats *in_stats = (struct sbni_in_stats *)ifr->ifr_data;
-			DP( printk("%s: SIOCDEVGETINSTATS %08x\n",dev->name,(unsigned)in_stats);)
-			if(copy_to_user((void *)in_stats, (void *)(&(lp->in_stats)), sizeof(struct sbni_in_stats)))
-				return -EFAULT;
-			break;
-		}
-		case SIOCDEVRESINSTATS:
-		{
-			if(!capable(CAP_NET_ADMIN))
-				return -EPERM;
-			DP( printk("%s: SIOCDEVRESINSTATS\n",dev->name); )
-			lp->in_stats.all_rx_number = 0;
-			lp->in_stats.bad_rx_number = 0;
-			lp->in_stats.timeout_number = 0;
-			lp->in_stats.all_tx_number = 0;
-			lp->in_stats.resend_tx_number = 0;
-			break;
-		}
-		case SIOCDEVGHWSTATE:
-		{
-			struct sbni_flags flags;
-			flags.rxl = lp->rxl_curr;
-			flags.rate = lp->csr1.rate;
-			flags.fixed_rxl = (lp->rxl_delta == 0);
-			flags.fixed_rate = 1;
-			ifr->ifr_data = *(caddr_t*)&flags;
-			DP( printk("%s: get flags (0x%02x)\n",dev->name, (unsigned char)ifr->ifr_data); )
-			break;
-		}
-		case SIOCDEVSHWSTATE:
-		{
-			struct sbni_flags flags;
-			DP( printk("%s: SIOCDEVSHWSTATE flags=0x%02x\n",dev->name, (unsigned char)ifr->ifr_data); )
-			/* root only */
-			if(!capable(CAP_NET_ADMIN))
-				return -EPERM;
-			flags = *(struct sbni_flags*)&ifr->ifr_data;
-			if(flags.fixed_rxl)
-			{
-				lp->rxl_delta = 0;
-				lp->rxl_curr = flags.rxl;
-			}
-			else
-			{
-				lp->rxl_delta = DEF_RXL_DELTA;
-				lp->rxl_curr = DEF_RXL;
-			}
-			lp->csr1.rxl = rxl_tab[lp->rxl_curr];
-			if(flags.fixed_rate)
-				lp->csr1.rate = flags.rate;
-			else
-				lp->csr1.rate = DEF_RATE;
-			/*
-			 * Don't be afraid...
-			 */
-			outb(*(char*)(&lp->csr1) | PR_RES, dev->base_addr + CSR1);
+	switch( cmd ) {
+	case  SIOCDEVGETINSTATS :
+		error = verify_area( VERIFY_WRITE, ifr->ifr_data,
+				     sizeof(struct sbni_in_stats) );
+		if( !error )
+			copy_to_user( ifr->ifr_data, &nl->in_stats,
+				      sizeof(struct sbni_in_stats) );
+		break;
+
+	case  SIOCDEVRESINSTATS :
+		if( current->euid != 0 )	/* root only */
+			return  -EPERM;
+		memset( &nl->in_stats, 0, sizeof(struct sbni_in_stats) );
+		break;
+
+	case  SIOCDEVGHWSTATE :
+		flags.mac_addr	= *(u32 *)(dev->dev_addr + 3);
+		flags.rate	= nl->csr1.rate;
+		flags.slow_mode	= (nl->state & FL_SLOW_MODE) != 0;
+		flags.rxl	= nl->cur_rxl_index;
+		flags.fixed_rxl	= nl->delta_rxl == 0;
+
+		error = verify_area( VERIFY_WRITE, ifr->ifr_data,
+				     sizeof flags );
+		if( !error )
+			copy_to_user( ifr->ifr_data, &flags, sizeof flags );
+		break;
+
+	case  SIOCDEVSHWSTATE :
+		if( current->euid != 0 )	/* root only */
+			return  -EPERM;
+
+		spin_lock( &nl->lock );
+		flags = *(struct sbni_flags*) &ifr->ifr_data;
+		if( flags.fixed_rxl )
+			nl->delta_rxl = 0,
+			nl->cur_rxl_index = flags.rxl;
+		else
+			nl->delta_rxl = DEF_RXL_DELTA,
+			nl->cur_rxl_index = DEF_RXL;
 
-			DP( printk("%s: set flags (0x%02x)\n receive level: %u, baud rate: %u\n",\
-				dev->name, (unsigned char)ifr->ifr_data, (unsigned)lp->rxl_curr, (unsigned)lp->csr1.rate); )
-			break;
+		nl->csr1.rxl = rxl_tab[ nl->cur_rxl_index ];
+		nl->csr1.rate = flags.rate;
+		outb( *(u8 *)&nl->csr1 | PR_RES, dev->base_addr + CSR1 );
+		spin_unlock( &nl->lock );
+		break;
+
+#ifdef CONFIG_SBNI_MULTILINE
+
+	case  SIOCDEVENSLAVE :
+		if( current->euid != 0 )	/* root only */
+			return  -EPERM;
+
+		if( (error = verify_area( VERIFY_READ, ifr->ifr_data,
+					  sizeof slave_name )) != 0 )
+			return  error;
+
+		copy_from_user( slave_name, ifr->ifr_data, sizeof slave_name );
+		slave_dev = dev_get_by_name( slave_name );
+		if( !slave_dev  ||  !(slave_dev->flags & IFF_UP) ) {
+			printk( KERN_ERR "%s: trying to enslave non-active "
+				"device %s\n", dev->name, slave_name );
+			return  -EPERM;
 		}
 
-		case SIOCDEVENSLAVE:
-			if(!capable(CAP_NET_ADMIN))
-				return -EPERM;
-			if(copy_from_user( tmpstr, ifr->ifr_data, 6))
-				return -EFAULT;
-			slave = dev_get_by_name(tmpstr);
-			if(!(slave && slave->flags & IFF_UP && dev->flags & IFF_UP))
-			{
-				printk("%s: Both devices should be UP to enslave!\n",dev->name);
-				if (slave)
-					dev_put(slave);
-				return -EINVAL;
-			}
-		
-			if(slave)
-			{
-				if(!((dev->flags & IFF_SLAVE) || (slave->flags & IFF_SLAVE)))
-				{
-					/* drop queue*/
-					sbni_drop_tx_queue(slave);
-					slave->flags |= IFF_SLAVE;
-					((struct net_local *)(slave->priv))->m=dev;
-					while(lp->next_lp)	//tail it after last slave
-						lp=lp->next_lp;
-					lp->next_lp=slave->priv;
-					lp=(struct net_local *)dev->priv;
-					dev->flags |= IFF_MASTER;
-					}
-				else
-				{
-					printk("%s: one of devices is already slave!\n",dev->name);
-					error = -EBUSY;
-				}
-				dev_put(slave);
-			}
-			else
-			{
-				printk("%s: can't find device %s to enslave\n",dev->name,ifr->ifr_data);
-				return -ENOENT;
-			}
-			break;    
+		return  enslave( dev, slave_dev );
 
-		case SIOCDEVEMANSIPATE:
-			if(!capable(CAP_NET_ADMIN))
-				return -EPERM;
-
-			if(dev->flags & IFF_SLAVE)
-			{
-				dev->flags &= ~IFF_SLAVE;
-				/* exclude us from masters slavelist*/
-				for(tlp=lp->m->priv;tlp->next_lp!=lp && tlp->next_lp;tlp=tlp->next_lp);
-				if(tlp->next_lp)
-				{
-					tlp->next_lp = lp->next_lp;
-					if(!((struct net_local *)lp->m->priv)->next_lp)
-					{
-						lp->m->flags &= ~IFF_MASTER;	
-					}
-					lp->next_lp=NULL;
-					lp->m=dev;     	
-				}
-				else
-				{
-					printk("%s: Ooops. drivers structure is mangled!\n",dev->name);
-					return -EIO;
-				}      
-			}
-			else
-			{
-				printk("%s: isn't slave device!\n",dev->name);
-				return -EINVAL;
-			}
-			break;    
+	case  SIOCDEVEMANSIPATE :
+		if( current->euid != 0 )	/* root only */
+			return  -EPERM;
+
+		return  emancipate( dev );
 
-		default:
-			DP( printk("%s: invalid ioctl: 0x%x\n",dev->name, cmd); )
-			error = -EINVAL;
+#endif	/* CONFIG_SBNI_MULTILINE */
+
+	default :
+		return  -EOPNOTSUPP;
 	}
-	return (error);
-}
 
+	return  error;
+}
 
 
-#ifdef CRCASM
+#ifdef CONFIG_SBNI_MULTILINE
 
-unsigned long calc_crc(char *mem, int len, unsigned initial)
+static int
+enslave( struct net_device  *dev,  struct net_device  *slave_dev )
 {
-	unsigned crc, dummy_len;
-	__asm__ (
-		"xorl %%eax,%%eax\n\t"
-		"1:\n\t"
-		"lodsb\n\t"
-		"xorb %%dl,%%al\n\t"
-		"shrl $8,%%edx\n\t"
-		"xorl (%%edi,%%eax,4),%%edx\n\t"
-		"loop 1b"
-		: "=d" (crc), "=c" (dummy_len)
-		: "S" (mem), "D" (&crc32tab[0]), "1" (len), "0" (initial)
-		: "eax"
-	);
-	return crc;
+	struct net_local  *nl  = (struct net_local *) dev->priv;
+	struct net_local  *snl = (struct net_local *) slave_dev->priv;
+
+	if( nl->state & FL_SLAVE )	/* This isn't master or free device */
+		return  -EBUSY;
+
+	if( snl->state & FL_SLAVE )	/* That was already enslaved */
+		return  -EBUSY;
+
+	spin_lock( &nl->lock );
+	spin_lock( &snl->lock );
+
+	/* append to list */
+	snl->link = nl->link;
+	nl->link  = slave_dev;
+	snl->master = dev;
+	snl->state |= FL_SLAVE;
+
+	/* Summary statistics of MultiLine operation will be stored
+	   in master's counters */
+	memset( &snl->stats, 0, sizeof(struct net_device_stats) );
+	netif_stop_queue( slave_dev );
+	netif_wake_queue( dev );	/* Now we are able to transmit */
+
+	spin_unlock( &snl->lock );
+	spin_unlock( &nl->lock );
+	printk( KERN_NOTICE "%s: slave device (%s) attached.\n",
+		dev->name, slave_dev->name );
+	return  0;
 }
 
-#else
 
-unsigned long calc_crc(char *mem, int len, unsigned initial)
+static int
+emancipate( struct net_device  *dev )
 {
-	unsigned crc;
-	crc = initial;
-   
-	for(;len;mem++,len--)
-	{
-		crc = CRC32(*mem, crc);
+	struct net_local   *snl = (struct net_local *) dev->priv;
+	struct net_device  *p   = snl->master;
+	struct net_local   *nl  = (struct net_local *) p->priv;
+
+	if( !(snl->state & FL_SLAVE) )
+		return  -EINVAL;
+
+	spin_lock( &nl->lock );
+	spin_lock( &snl->lock );
+	drop_xmit_queue( dev );
+
+	/* exclude from list */
+	for(;;) {	/* must be in list */
+		struct net_local  *t = (struct net_local *) p->priv;
+		if( t->link == dev ) {
+			t->link = snl->link;
+			break;
+		}
+		p = t->link;
 	}
-	return(crc);
+
+	snl->link = NULL;
+	snl->master = dev;
+	snl->state &= ~FL_SLAVE;
+
+	netif_start_queue( dev );
+
+	spin_unlock( &snl->lock );
+	spin_unlock( &nl->lock );
+
+	dev_put( dev );
+	return  0;
+}
+
+#endif
+
+
+static struct net_device_stats *
+sbni_get_stats( struct net_device  *dev )
+{
+	return  &((struct net_local *) dev->priv)->stats;
 }
-#endif /* CRCASM */
+
+
+static void
+set_multicast_list( struct net_device  *dev )
+{
+	return;		/* sbni always operate in promiscuos mode */
+}
+
+
 #ifdef MODULE
 
-static int io[SBNI_MAX_NUM_CARDS] = { 0 };
-static int irq[SBNI_MAX_NUM_CARDS] = { 0 };
-static int rxl[SBNI_MAX_NUM_CARDS] = { -1, -1, -1, -1, -1, -1, -1, -1 };
-static int baud[SBNI_MAX_NUM_CARDS] = { 0 };
-static long mac[SBNI_MAX_NUM_CARDS] = { 0 };
-
-MODULE_PARM(io, "1-" __MODULE_STRING(SBNI_MAX_NUM_CARDS) "i");
-MODULE_PARM(irq, "1-" __MODULE_STRING(SBNI_MAX_NUM_CARDS) "i");
-MODULE_PARM(rxl, "1-" __MODULE_STRING(SBNI_MAX_NUM_CARDS) "i");
-MODULE_PARM(baud, "1-" __MODULE_STRING(SBNI_MAX_NUM_CARDS) "i");
-MODULE_PARM(mac, "1-" __MODULE_STRING(SBNI_MAX_NUM_CARDS) "i");
-
-
-static int sbniautodetect = -1;
-
-static struct net_device dev_sbni[SBNI_MAX_NUM_CARDS] = {
-	{
-		"sbni0",
-		0, 0, 0, 0,		/* memory */
-		0, 0,			/* base, irq */
-		0, 0, 0, NULL, sbni_probe 
-	},
-	{
-		"sbni1",
-		0, 0, 0, 0,		/* memory */
-		0, 0,			/* base, irq */
-		0, 0, 0, NULL, sbni_probe 
-	},
-	{
-		"sbni2",
-		0, 0, 0, 0,		/* memory */
-		0, 0,			/* base, irq */
-		0, 0, 0, NULL, sbni_probe 
-	},
-	{
-		"sbni3",
-		0, 0, 0, 0,		/* memory */
-		0, 0,			/* base, irq */
-		0, 0, 0, NULL, sbni_probe 
-	},
-	{
-		"sbni4",
-		0, 0, 0, 0,		/* memory */
-		0, 0,			/* base, irq */
-		0, 0, 0, NULL, sbni_probe 
-	},
-	{
-		"sbni5",
-		0, 0, 0, 0,		/* memory */
-		0, 0,			/* base, irq */
-		0, 0, 0, NULL, sbni_probe 
-	},
-	{
-		"sbni6",
-		0, 0, 0, 0,		/* memory */
-		0, 0,			/* base, irq */
-		0, 0, 0, NULL, sbni_probe 
-	},
-	{
-		"sbni7",
-		0, 0, 0, 0,		/* memory */
-		0, 0,			/* base, irq */
-		0, 0, 0, NULL, sbni_probe 
-	}
-};
+MODULE_PARM(	io,	"1-" __MODULE_STRING( SBNI_MAX_NUM_CARDS ) "i" );
+MODULE_PARM(	irq,	"1-" __MODULE_STRING( SBNI_MAX_NUM_CARDS ) "i" );
+MODULE_PARM(	baud,	"1-" __MODULE_STRING( SBNI_MAX_NUM_CARDS ) "i" );
+MODULE_PARM(	rxl,	"1-" __MODULE_STRING( SBNI_MAX_NUM_CARDS ) "i" );
+MODULE_PARM(	mac,	"1-" __MODULE_STRING( SBNI_MAX_NUM_CARDS ) "i" );
 
-int init_module(void)
+MODULE_PARM(	skip_pci_probe,	"i" );
+
+
+int
+init_module( void )
 {
-	int devices = 0;
-	int installed = 0;
-	int i;
+	struct net_device  *dev;
 
-	/* My simple plug for this huge init_module. "XenON */
-      
-	if(sbniautodetect != -1)
-	{
-		/* Autodetect mode */
-		printk("sbni: Autodetect mode (not recommended!) ...\n");
-		if(!sbniautodetect)
-			sbniautodetect=SBNI_MAX_NUM_CARDS;
-		printk("Trying to find %d SBNI cards...\n", sbniautodetect);
-		if(sbniautodetect > SBNI_MAX_NUM_CARDS)
-		{
-			sbniautodetect = SBNI_MAX_NUM_CARDS;
-			printk("sbni: You want to detect too many cards. Truncated to %d\n", SBNI_MAX_NUM_CARDS);
+	while( num < SBNI_MAX_NUM_CARDS ) {
+		if( !(dev = kmalloc(sizeof(struct net_device), GFP_KERNEL)) ){
+			printk( KERN_ERR "sbni: unable to allocate device!\n" );
+			return  -ENOMEM;
 		}
-		for(i = 0; i < sbniautodetect; i++)
-		{
-			if(!register_netdev(&dev_sbni[i]))
-				installed++;
+
+		memset( dev, 0, sizeof(struct net_device) );
+		sprintf( dev->name, "sbni%d", num );
+
+		dev->init = sbni_probe;
+		if( register_netdev( dev ) ) {
+			kfree( dev );
+			break;
 		}
-		if(installed)
-			return 0;
-		else
-		    return -EIO;
-	}
-	
-	/* Manual mode */
-	for(i = 0; i < SBNI_MAX_NUM_CARDS; i++)
-	{
-		if((io[i] != 0) || (irq[i] != 0))
-			devices++;
 	}
-	for(i = 0; i < devices; i++)
-	{
-		dev_sbni[i].irq = irq[i];
-		dev_sbni[i].base_addr = io[i];
-		def_rxl = rxl[i];
-		def_baud = baud[i];
-		def_mac = mac[i];
-		if(register_netdev(&dev_sbni[i]))
-			printk("sbni: card not found!\n");
-		else
-			installed++;
-	}
-	if(installed)
-		return 0;
-	else
-		return -EIO;
+
+	return  *sbni_cards  ?  0  :  -ENODEV;
 }
 
-void cleanup_module(void)
+void
+cleanup_module( void )
 {
-	int i;
-	for(i = 0; i < 4; i++)
-	{
-		if(dev_sbni[i].priv)
-		{
-			free_irq(dev_sbni[i].irq, &dev_sbni[i]);
-			release_region(dev_sbni[i].base_addr, SBNI_IO_EXTENT);
-			unregister_netdev(&dev_sbni[i]);
-			kfree(dev_sbni[i].priv);
-			dev_sbni[i].priv = NULL;
+	struct net_device  *dev;
+	int  num;
+
+	/* No need to check MOD_IN_USE, as sys_delete_module( ) checks. */
+	for( num = 0;  num < SBNI_MAX_NUM_CARDS;  ++num )
+		if( (dev = sbni_cards[ num ]) != NULL ) {
+			unregister_netdev( dev );
+			release_region( dev->base_addr, SBNI_IO_EXTENT );
+			kfree( dev->priv );
+			kfree( dev );
 		}
+}
+
+#else	/* MODULE */
+
+void __init
+sbni_setup( char  *p )
+{
+	int  n, parm;
+
+	if( *p++ != '(' )
+		goto  bad_param;
+
+	for( n = 0, parm = 0;  *p  &&  n < 8; ) {
+		(*dest[ parm ])[ n ] = simple_strtol( p, &p, 0 );
+		if( !*p  ||  *p == ')' )
+			return;
+		if( *p == ';' )
+			++p, ++n, parm = 0;
+		else if( *p++ != ',' )
+			break;
+		else
+			if( ++parm >= 5 )
+				break;
 	}
+bad_param:
+	printk( KERN_ERR "Error in sbni kernel parameter!\n" );
 }
-#endif /* MODULE */
+
+__setup( "sbni=", sbni_setup );
+
+#endif	/* MODULE */
+
+/* -------------------------------------------------------------------------- */
+
+#ifdef ASM_CRC
+
+static u32
+calc_crc32( u32  crc,  u8  *p,  u32  len )
+{
+	register u32  _crc __asm ( "ax" );
+	_crc = crc;
+	
+	__asm __volatile (
+		"xorl	%%ebx, %%ebx\n"
+		"movl	%1, %%esi\n" 
+		"movl	%2, %%ecx\n" 
+		"movl	$crc32tab, %%edi\n"
+		"shrl	$2, %%ecx\n"
+		"jz	1f\n"
+
+		".align 4\n"
+	"0:\n"
+		"movb	%%al, %%bl\n"
+		"movl	(%%esi), %%edx\n"
+		"shrl	$8, %%eax\n"
+		"xorb	%%dl, %%bl\n"
+		"shrl	$8, %%edx\n"
+		"xorl	(%%edi,%%ebx,4), %%eax\n"
+
+		"movb	%%al, %%bl\n"
+		"shrl	$8, %%eax\n"
+		"xorb	%%dl, %%bl\n"
+		"shrl	$8, %%edx\n"
+		"xorl	(%%edi,%%ebx,4), %%eax\n"
+
+		"movb	%%al, %%bl\n"
+		"shrl	$8, %%eax\n"
+		"xorb	%%dl, %%bl\n"
+		"movb	%%dh, %%dl\n" 
+		"xorl	(%%edi,%%ebx,4), %%eax\n"
+
+		"movb	%%al, %%bl\n"
+		"shrl	$8, %%eax\n"
+		"xorb	%%dl, %%bl\n"
+		"addl	$4, %%esi\n"
+		"xorl	(%%edi,%%ebx,4), %%eax\n"
+
+		"decl	%%ecx\n"
+		"jnz	0b\n"
+
+	"1:\n"
+		"movl	%2, %%ecx\n"
+		"andl	$3, %%ecx\n"
+		"jz	2f\n"
+
+		"movb	%%al, %%bl\n"
+		"shrl	$8, %%eax\n"
+		"xorb	(%%esi), %%bl\n"
+		"xorl	(%%edi,%%ebx,4), %%eax\n"
+
+		"decl	%%ecx\n"
+		"jz	2f\n"
+
+		"movb	%%al, %%bl\n"
+		"shrl	$8, %%eax\n"
+		"xorb	1(%%esi), %%bl\n"
+		"xorl	(%%edi,%%ebx,4), %%eax\n"
+
+		"decl	%%ecx\n"
+		"jz	2f\n"
+
+		"movb	%%al, %%bl\n"
+		"shrl	$8, %%eax\n"
+		"xorb	2(%%esi), %%bl\n"
+		"xorl	(%%edi,%%ebx,4), %%eax\n"
+	"2:\n"
+		:
+		: "a" (_crc), "g" (p), "g" (len)
+		: "ax", "bx", "cx", "dx", "si", "di"
+	);
+
+	return  _crc;
+}
+
+#else	/* ASM_CRC */
+
+static u32
+calc_crc32( u32  crc,  u8  *p,  u32  len )
+{
+	while( len-- )
+		crc = CRC32( *p++, crc );
+
+	return  crc;
+}
+
+#endif	/* ASM_CRC */
+
+
+static u32  crc32tab[] __attribute__ ((aligned(8))) = {
+	0xD202EF8D,  0xA505DF1B,  0x3C0C8EA1,  0x4B0BBE37,
+	0xD56F2B94,  0xA2681B02,  0x3B614AB8,  0x4C667A2E,
+	0xDCD967BF,  0xABDE5729,  0x32D70693,  0x45D03605,
+	0xDBB4A3A6,  0xACB39330,  0x35BAC28A,  0x42BDF21C,
+	0xCFB5FFE9,  0xB8B2CF7F,  0x21BB9EC5,  0x56BCAE53,
+	0xC8D83BF0,  0xBFDF0B66,  0x26D65ADC,  0x51D16A4A,
+	0xC16E77DB,  0xB669474D,  0x2F6016F7,  0x58672661,
+	0xC603B3C2,  0xB1048354,  0x280DD2EE,  0x5F0AE278,
+	0xE96CCF45,  0x9E6BFFD3,  0x0762AE69,  0x70659EFF,
+	0xEE010B5C,  0x99063BCA,  0x000F6A70,  0x77085AE6,
+	0xE7B74777,  0x90B077E1,  0x09B9265B,  0x7EBE16CD,
+	0xE0DA836E,  0x97DDB3F8,  0x0ED4E242,  0x79D3D2D4,
+	0xF4DBDF21,  0x83DCEFB7,  0x1AD5BE0D,  0x6DD28E9B,
+	0xF3B61B38,  0x84B12BAE,  0x1DB87A14,  0x6ABF4A82,
+	0xFA005713,  0x8D076785,  0x140E363F,  0x630906A9,
+	0xFD6D930A,  0x8A6AA39C,  0x1363F226,  0x6464C2B0,
+	0xA4DEAE1D,  0xD3D99E8B,  0x4AD0CF31,  0x3DD7FFA7,
+	0xA3B36A04,  0xD4B45A92,  0x4DBD0B28,  0x3ABA3BBE,
+	0xAA05262F,  0xDD0216B9,  0x440B4703,  0x330C7795,
+	0xAD68E236,  0xDA6FD2A0,  0x4366831A,  0x3461B38C,
+	0xB969BE79,  0xCE6E8EEF,  0x5767DF55,  0x2060EFC3,
+	0xBE047A60,  0xC9034AF6,  0x500A1B4C,  0x270D2BDA,
+	0xB7B2364B,  0xC0B506DD,  0x59BC5767,  0x2EBB67F1,
+	0xB0DFF252,  0xC7D8C2C4,  0x5ED1937E,  0x29D6A3E8,
+	0x9FB08ED5,  0xE8B7BE43,  0x71BEEFF9,  0x06B9DF6F,
+	0x98DD4ACC,  0xEFDA7A5A,  0x76D32BE0,  0x01D41B76,
+	0x916B06E7,  0xE66C3671,  0x7F6567CB,  0x0862575D,
+	0x9606C2FE,  0xE101F268,  0x7808A3D2,  0x0F0F9344,
+	0x82079EB1,  0xF500AE27,  0x6C09FF9D,  0x1B0ECF0B,
+	0x856A5AA8,  0xF26D6A3E,  0x6B643B84,  0x1C630B12,
+	0x8CDC1683,  0xFBDB2615,  0x62D277AF,  0x15D54739,
+	0x8BB1D29A,  0xFCB6E20C,  0x65BFB3B6,  0x12B88320,
+	0x3FBA6CAD,  0x48BD5C3B,  0xD1B40D81,  0xA6B33D17,
+	0x38D7A8B4,  0x4FD09822,  0xD6D9C998,  0xA1DEF90E,
+	0x3161E49F,  0x4666D409,  0xDF6F85B3,  0xA868B525,
+	0x360C2086,  0x410B1010,  0xD80241AA,  0xAF05713C,
+	0x220D7CC9,  0x550A4C5F,  0xCC031DE5,  0xBB042D73,
+	0x2560B8D0,  0x52678846,  0xCB6ED9FC,  0xBC69E96A,
+	0x2CD6F4FB,  0x5BD1C46D,  0xC2D895D7,  0xB5DFA541,
+	0x2BBB30E2,  0x5CBC0074,  0xC5B551CE,  0xB2B26158,
+	0x04D44C65,  0x73D37CF3,  0xEADA2D49,  0x9DDD1DDF,
+	0x03B9887C,  0x74BEB8EA,  0xEDB7E950,  0x9AB0D9C6,
+	0x0A0FC457,  0x7D08F4C1,  0xE401A57B,  0x930695ED,
+	0x0D62004E,  0x7A6530D8,  0xE36C6162,  0x946B51F4,
+	0x19635C01,  0x6E646C97,  0xF76D3D2D,  0x806A0DBB,
+	0x1E0E9818,  0x6909A88E,  0xF000F934,  0x8707C9A2,
+	0x17B8D433,  0x60BFE4A5,  0xF9B6B51F,  0x8EB18589,
+	0x10D5102A,  0x67D220BC,  0xFEDB7106,  0x89DC4190,
+	0x49662D3D,  0x3E611DAB,  0xA7684C11,  0xD06F7C87,
+	0x4E0BE924,  0x390CD9B2,  0xA0058808,  0xD702B89E,
+	0x47BDA50F,  0x30BA9599,  0xA9B3C423,  0xDEB4F4B5,
+	0x40D06116,  0x37D75180,  0xAEDE003A,  0xD9D930AC,
+	0x54D13D59,  0x23D60DCF,  0xBADF5C75,  0xCDD86CE3,
+	0x53BCF940,  0x24BBC9D6,  0xBDB2986C,  0xCAB5A8FA,
+	0x5A0AB56B,  0x2D0D85FD,  0xB404D447,  0xC303E4D1,
+	0x5D677172,  0x2A6041E4,  0xB369105E,  0xC46E20C8,
+	0x72080DF5,  0x050F3D63,  0x9C066CD9,  0xEB015C4F,
+	0x7565C9EC,  0x0262F97A,  0x9B6BA8C0,  0xEC6C9856,
+	0x7CD385C7,  0x0BD4B551,  0x92DDE4EB,  0xE5DAD47D,
+	0x7BBE41DE,  0x0CB97148,  0x95B020F2,  0xE2B71064,
+	0x6FBF1D91,  0x18B82D07,  0x81B17CBD,  0xF6B64C2B,
+	0x68D2D988,  0x1FD5E91E,  0x86DCB8A4,  0xF1DB8832,
+	0x616495A3,  0x1663A535,  0x8F6AF48F,  0xF86DC419,
+	0x660951BA,  0x110E612C,  0x88073096,  0xFF000000
+};
+
diff -u --recursive --new-file v2.4.7/linux/drivers/net/wan/sbni.h linux/drivers/net/wan/sbni.h
--- v2.4.7/linux/drivers/net/wan/sbni.h	Tue Jul 11 11:12:24 2000
+++ linux/drivers/net/wan/sbni.h	Wed Jul 25 14:12:02 2001
@@ -1,25 +1,10 @@
-/*
- * sbni.h - header file for sbni linux device driver
- *
- * Copyright (C) 1999 Granch ltd., Yaroslav Polyakov (xenon@granch.ru).
- *
- */
-
-/*
- * SBNI12 definitions
- *
- * Revision 2.0.0  1997/08/27
- * Initial revision
- *
- * Revision 2.1.0  1999/04/26
- * dev_priv structure changed to support balancing and some other features.
- *
+/* sbni.h:  definitions for a Granch SBNI12 driver, version 5.0.0
+ * Written 2001 Denis I.Timofeev (timofeev@granch.ru)
+ * This file is distributed under the GNU GPL
  */
 
-#ifndef __SBNI_H
-#define __SBNI_H
-
-#define SBNI_DEBUG 0
+#ifndef SBNI_H
+#define SBNI_H
 
 #if SBNI_DEBUG
 #define DP( A ) A
@@ -27,168 +12,132 @@
 #define DP( A )
 #endif
 
-typedef unsigned char BOOLEAN;
-
-#define TRUE 1
-#define FALSE 0
 
-#define	SBNI_IO_EXTENT	0x4
-#define SB_MAX_BUFFER_ARRAY 1023
-
-#define CSR0	0
-#define CSR1	1
-
-#define	DAT	2
+/* We don't have official vendor id yet... */
+#define SBNI_PCI_VENDOR 	0x55 
+#define SBNI_PCI_DEVICE 	0x9f
+
+#define ISA_MODE 0x00
+#define PCI_MODE 0x01
+
+#define	SBNI_IO_EXTENT	4
+
+enum sbni_reg {
+	CSR0 = 0,
+	CSR1 = 1,
+	DAT  = 2
+};
 
 /* CSR0 mapping */
-#define BU_EMP	(1 << 1)	/* r z    */
-#define	RC_CHK	(1 << 2)	/* rw     */
-#define	CT_ZER	(1 << 3)	/*  w     */
-#define	TR_REQ	(1 << 4)	/* rwz*   */
-
-#define TR_RDY	(1 << 5)	/* r z    */
-#define EN_INT	(1 << 6)	/* rwz* */
-#define RC_RDY	(1 << 7)	/* r z    */
+enum {
+	BU_EMP = 0x02,
+	RC_CHK = 0x04,
+	CT_ZER = 0x08,
+	TR_REQ = 0x10,
+	TR_RDY = 0x20,
+	EN_INT = 0x40,
+	RC_RDY = 0x80
+};
+
 
 /* CSR1 mapping */
-#define PR_RES	(1 << 7)	/*  w     */
+#define PR_RES 0x80
 
 struct sbni_csr1 {
-	unsigned rxl:5;
-	unsigned rate:2;
-	unsigned:1;
+	unsigned rxl	: 5;
+	unsigned rate	: 2;
+	unsigned 	: 1;
 };
 
-#define DEF_RXL_DELTA	-1
-#define DEF_RXL		0xf
-#define DEF_RATE	0
-#define DEF_FRAME_LEN	(1023 - 14 - 9)
-
-#ifdef MODULE
+/* fields in frame header */
+#define FRAME_ACK_MASK  (unsigned short)0x7000
+#define FRAME_LEN_MASK  (unsigned short)0x03FF
+#define FRAME_FIRST     (unsigned short)0x8000
+#define FRAME_RETRY     (unsigned short)0x0800
+
+#define FRAME_SENT_BAD  (unsigned short)0x4000
+#define FRAME_SENT_OK   (unsigned short)0x3000
+
+
+/* state flags */
+enum {
+	FL_WAIT_ACK    = 0x01,
+	FL_NEED_RESEND = 0x02,
+	FL_PREV_OK     = 0x04,
+	FL_SLOW_MODE   = 0x08,
+	FL_SECONDARY   = 0x10,
+#ifdef CONFIG_SBNI_MULTILINE
+	FL_SLAVE       = 0x20,
+#endif
+	FL_LINE_DOWN   = 0x40
+};
 
-#define SBNI_MAX_NUM_CARDS 8
-#define SBNI_MAX_SLAVES 8
 
+enum {
+	DEFAULT_IOBASEADDR = 0x210,
+	DEFAULT_INTERRUPTNUMBER = 5,
+	DEFAULT_RATE = 0,
+	DEFAULT_FRAME_LEN = 1012
+};
 
-#endif				/* MODULE */
+#define DEF_RXL_DELTA	-1
+#define DEF_RXL		0xf
 
 #define SBNI_SIG 0x5a
 
-#define	SB_ETHER_MIN_LEN 60
+#define	SBNI_MIN_LEN	60	/* Shortest Ethernet frame without FCS */
+#define SBNI_MAX_FRAME	1023
+#define ETHER_MAX_LEN	1518
 
-#define SB_FILLING_CHAR (unsigned char)0x00
-#define TR_ERROR_COUNT 32
-#define CHANGE_LEVEL_START_TICKS 4
-#define SBNI_INTERNAL_QUEUE_SIZE 10	/* 100 ? */
+#define SBNI_TIMEOUT	(HZ/10)
 
-#define PACKET_FIRST_FRAME (unsigned short)0x8000
-#define RECEIVE_FRAME_RESEND (unsigned short)0x0800
-#define PACKET_RESEND 0x4000
-#define PACKET_SEND_OK 0x3000
-#define PACKET_LEN_MASK (unsigned short)0x03ff
-#define PACKET_INF_MASK (unsigned short)0x7000
-
-#define ETHER_ADDR_LEN 6
+#define TR_ERROR_COUNT	32
+#define CHANGE_LEVEL_START_TICKS 4
 
-#define SBNI_TIMEOUT HZ/10	/* ticks to wait for pong or packet */
-		/* sbni watchdog called SBNI_HZ times per sec. */
+#define SBNI_MAX_NUM_CARDS	16
 
+/* internal SBNI-specific statistics */
 struct sbni_in_stats {
-	unsigned int all_rx_number;
-	unsigned int bad_rx_number;
-	unsigned int timeout_number;
-	unsigned int all_tx_number;
-	unsigned int resend_tx_number;
+	u32	all_rx_number;
+	u32	bad_rx_number;
+	u32	timeout_number;
+	u32	all_tx_number;
+	u32	resend_tx_number;
 };
 
+/* SBNI ioctl params */
+#define SIOCDEVGETINSTATS 	SIOCDEVPRIVATE
+#define SIOCDEVRESINSTATS 	SIOCDEVPRIVATE+1
+#define SIOCDEVGHWSTATE   	SIOCDEVPRIVATE+2
+#define SIOCDEVSHWSTATE   	SIOCDEVPRIVATE+3
+#define SIOCDEVENSLAVE  	SIOCDEVPRIVATE+4
+#define SIOCDEVEMANSIPATE  	SIOCDEVPRIVATE+5
 
-/*
- *    Board-specific info in dev->priv. 
- */
-struct net_local {
-	struct net_device_stats stats;
-
-	struct timer_list watchdog;
-	unsigned int realframelen;	/* the current size of the SB-frame */
-	unsigned int eth_trans_buffer_len;	/* tx buffer length */
-	unsigned int outpos;
-	unsigned int inppos;
-	unsigned int frame_len;	/* The set SB-frame size */
-	unsigned int tr_err;
-	unsigned int timer_ticks;
-	BOOLEAN last_receive_OK;
-	BOOLEAN tr_resend;
-
-	unsigned char wait_frame_number;
-	unsigned char eth_trans_buffer[1520];	/* tx buffer */
-	unsigned char HSCounter;	/* Reserved field */
-	unsigned char eth_rcv_buffer[2600];	/* rx buffer */
-	struct sbni_csr1 csr1;
-	/* Internal Statistics */
-	struct sbni_in_stats in_stats;
-
-	int rxl_curr;		/* current receive level value [0..0xf] */
-	int rxl_delta;		/* receive level delta (+1, -1)
-				   rxl_delta == 0 - receive level
-				   autodetection
-				   disabled            */
-	unsigned int ok_curr;	/* current ok frames received           */
-	unsigned int ok_prev;	/* previous ok frames received          */
-	unsigned int timeout_rxl;
-
-	struct sk_buff_head queue;
-	struct sk_buff *currframe;
-	BOOLEAN waitack;
-
-	struct net_device *m;	/* master */
-	struct net_device *me;	/* me */
-	struct net_local *next_lp;	/* next lp */
-
-	int carrier;
-
-	spinlock_t lock;
-};
-
-
-struct sbni_hard_header {
-
-	/* internal sbni stuff */
-	unsigned int crc;	/* 4 */
-	unsigned short packetlen;	/* 2 */
-	unsigned char number;	/* 1 */
-	unsigned char reserv;	/* 1 */
-
-	/* 8 */
-
-	/* ethernet stuff */
-	unsigned char h_dest[ETH_ALEN];		/* destination eth addr */
-	unsigned char h_source[ETH_ALEN];	/* source ether addr    */
-	unsigned short h_proto;	/* packet type ID field */
-	/* +14 */
-	/* 22 */
-
-};
-
-#define SBNI_HH_SZ 22
 
+/* data packet for SIOCDEVGHWSTATE/SIOCDEVSHWSTATE ioctl requests */
 struct sbni_flags {
-	unsigned rxl:4;
-	unsigned rate:2;
-	unsigned fixed_rxl:1;
-	unsigned fixed_rate:1;
+	u32	rxl		: 4;
+	u32	rate		: 2;
+	u32	fixed_rxl	: 1;
+	u32	slow_mode	: 1;
+	u32	mac_addr	: 24;
 };
 
-#define RCV_NO 0
-#define RCV_OK 1
-#define RCV_WR 2
+/*
+ * CRC-32 stuff
+ */
+#define CRC32(c,crc) (crc32tab[((size_t)(crc) ^ (c)) & 0xff] ^ (((crc) >> 8) & 0x00FFFFFF))
+      /* CRC generator 0xEDB88320 */
+      /* CRC remainder 0x2144DF1C */
+      /* CRC initial value 0x00000000 */
+#define CRC32_REMAINDER 0x2144DF1C
+#define CRC32_INITIAL 0x00000000
 
+#ifndef __initdata
+#define __initdata
+#endif
 
-#define SIOCDEVGETINSTATS 	SIOCDEVPRIVATE
-#define SIOCDEVRESINSTATS 	SIOCDEVPRIVATE+1
-#define SIOCDEVGHWSTATE   	SIOCDEVPRIVATE+2
-#define SIOCDEVSHWSTATE   	SIOCDEVPRIVATE+3
-#define SIOCDEVENSLAVE  	SIOCDEVPRIVATE+4
-#define SIOCDEVEMANSIPATE  	SIOCDEVPRIVATE+5
+#define min( x, y )	( (x) < (y)  ?  (x)  :  (y) )
 
+#endif
 
-#endif				/* __SBNI_H */
diff -u --recursive --new-file v2.4.7/linux/drivers/pci/quirks.c linux/drivers/pci/quirks.c
--- v2.4.7/linux/drivers/pci/quirks.c	Tue Jul  3 17:08:20 2001
+++ linux/drivers/pci/quirks.c	Sun Aug  5 13:12:40 2001
@@ -92,42 +92,58 @@
  *	see PCI Latency Adjust on http://www.viahardware.com/download/viatweak.shtm
  *      Also see http://home.tiscalinet.de/au-ja/review-kt133a-1-en.html for
  *      the info on which Mr Breese based his work.
+ *
+ *	Updated based on further information from the site and also on
+ *	information provided by VIA 
  */
 static void __init quirk_vialatency(struct pci_dev *dev)
 {
-	u8 r70;
+	struct pci_dev *p;
 	u8 rev;
-	struct pci_dev *vt82c686;
-   
-   
-	/* we want to look for a VT82C686 south bridge, and then apply the via latency
-	 * patch if we find that it's a 686B (by revision) <cpbotha@ieee.org>
+	u8 busarb;
+	/* Ok we have a potential problem chipset here. Now see if we have
+	   a buggy southbridge */
+	   
+	p=pci_find_device(PCI_VENDOR_ID_VIA, PCI_DEVICE_ID_VIA_82C686, NULL);
+	if(p!=NULL)
+	{
+		pci_read_config_byte(p, PCI_CLASS_REVISION, &rev);
+		/* 0x40 - 0x4f == 686B, 0x10 - 0x2f == 686A; thanks Dan Hollis */
+		/* Check for buggy part revisions */
+		if (rev < 0x40 || rev > 0x42) 
+			return;
+	}
+	else
+	{
+		p = pci_find_device(PCI_VENDOR_ID_VIA, PCI_DEVICE_ID_VIA_8231, NULL);
+		if(p==NULL)	/* No problem parts */
+			return;
+		pci_read_config_byte(p, PCI_CLASS_REVISION, &rev);
+		/* Check for buggy part revisions */
+		if (rev < 0x10 || rev > 0x12) 
+			return;
+	}
+	
+	/*
+	 *	Ok we have the problem. Now set the PCI master grant to 
+	 *	occur every master grant. The apparent bug is that under high
+	 *	PCI load (quite common in Linux of course) you can get data
+	 *	loss when the CPU is held off the bus for 3 bus master requests
+	 *	This happens to include the IDE controllers....
+	 *
+	 *	VIA only apply this fix when an SB Live! is present but under
+	 *	both Linux and Windows this isnt enough, and we have seen
+	 *	corruption without SB Live! but with things like 3 UDMA IDE
+	 *	controllers. So we ignore that bit of the VIA recommendation..
 	 */
-	vt82c686 = pci_find_device(PCI_VENDOR_ID_VIA, PCI_DEVICE_ID_VIA_82C686, NULL);
-	if (vt82c686)   
-     	{
-		pci_read_config_byte(vt82c686, PCI_CLASS_REVISION, &rev);
-        	/* 0x40 - 0x4f == 686B, 0x10 - 0x2f == 686A; thanks Dan Hollis */
-		if (rev >= 0x40 && rev <= 0x4f)
-		{
-        		printk(KERN_INFO "Applying VIA PCI latency patch (found VT82C686B).\n");
-			/*
-	 		 *    In register 0x70, mask off bit 2 (PCI Master read caching)
-	 		 *    and 1 (Delay Transaction)
-	 		 */
-			pci_read_config_byte(dev, 0x70, &r70);
-			r70 &= 0xf9;
-			pci_write_config_byte(dev, 0x70, r70);
-			/*
-	 	 	 *    Turn off PCI Latency timeout (set to 0 clocks)
-	 	 	 */
-			pci_write_config_byte(dev, 0x75, 0x80);
-		}
-		else
-		{
-			printk(KERN_INFO "Found VT82C686A, not applying VIA latency patch.\n");
-		}
-	} /* if (vt82c686) ... */
+
+	pci_read_config_byte(dev, 0x76, &busarb);
+	/* Set bit 4 and bi 5 of byte 76 to 0x01 
+	   "Master priority rotation on every PCI master grant */
+	busarb &= ~(1<<5);
+	busarb |= (1<<4);
+	pci_write_config_byte(dev, 0x76, busarb);
+	printk(KERN_INFO "Applying VIA southbridge workaround.\n");
 }
 
 /*
@@ -416,6 +432,8 @@
 	{ PCI_FIXUP_FINAL,	PCI_VENDOR_ID_SI,	PCI_DEVICE_ID_SI_5597,		quirk_nopcipci },
 	{ PCI_FIXUP_FINAL,	PCI_VENDOR_ID_SI,	PCI_DEVICE_ID_SI_496,		quirk_nopcipci },
 	{ PCI_FIXUP_FINAL,	PCI_VENDOR_ID_VIA,	PCI_DEVICE_ID_VIA_8363_0,	quirk_vialatency },
+	{ PCI_FIXUP_FINAL,	PCI_VENDOR_ID_VIA,	PCI_DEVICE_ID_VIA_8371_1,	quirk_vialatency },
+	{ PCI_FIXUP_FINAL,	PCI_VENDOR_ID_VIA,	0x3112	/* Not out yet ? */,	quirk_vialatency },
 	{ PCI_FIXUP_FINAL,	PCI_VENDOR_ID_VIA,	PCI_DEVICE_ID_VIA_82C597_0,	quirk_viaetbf },
 	{ PCI_FIXUP_HEADER,	PCI_VENDOR_ID_VIA,	PCI_DEVICE_ID_VIA_82C597_0,	quirk_vt82c598_id },
 	{ PCI_FIXUP_HEADER,	PCI_VENDOR_ID_VIA,	PCI_DEVICE_ID_VIA_82C586_3,	quirk_vt82c586_acpi },
diff -u --recursive --new-file v2.4.7/linux/drivers/pcmcia/i82365.c linux/drivers/pcmcia/i82365.c
--- v2.4.7/linux/drivers/pcmcia/i82365.c	Tue May  1 16:05:00 2001
+++ linux/drivers/pcmcia/i82365.c	Wed Jul 25 14:12:02 2001
@@ -57,6 +57,8 @@
 #include <pcmcia/ss.h>
 #include <pcmcia/cs.h>
 
+#include <linux/isapnp.h>
+
 /* ISA-bus controllers */
 #include "i82365.h"
 #include "cirrus.h"
@@ -816,10 +818,56 @@
 
 #ifdef CONFIG_ISA
 
+#if defined(CONFIG_ISAPNP) || (defined(CONFIG_ISAPNP_MODULE) && defined(MODULE))
+#define I82365_ISAPNP
+#endif
+
+#ifdef I82365_ISAPNP
+static struct isapnp_device_id id_table[] __initdata = {
+	{ 	ISAPNP_ANY_ID, ISAPNP_ANY_ID, ISAPNP_VENDOR('P', 'N', 'P'),
+		ISAPNP_FUNCTION(0x0e00), (unsigned long) "Intel 82365-Compatible" },
+	{ 	ISAPNP_ANY_ID, ISAPNP_ANY_ID, ISAPNP_VENDOR('P', 'N', 'P'),
+		ISAPNP_FUNCTION(0x0e01), (unsigned long) "Cirrus Logic CL-PD6720" },
+	{ 	ISAPNP_ANY_ID, ISAPNP_ANY_ID, ISAPNP_VENDOR('P', 'N', 'P'),
+		ISAPNP_FUNCTION(0x0e02), (unsigned long) "VLSI VL82C146" },
+	{	0 }
+};
+MODULE_DEVICE_TABLE(isapnp, id_table);
+
+static struct pci_dev *i82365_pnpdev;
+#endif
+
 static void __init isa_probe(void)
 {
     int i, j, sock, k, ns, id;
     ioaddr_t port;
+#ifdef I82365_ISAPNP
+    struct isapnp_device_id *devid;
+    struct pci_dev *dev;
+
+    for (devid = id_table; devid->vendor; devid++) {
+	if ((dev = isapnp_find_dev(NULL, devid->vendor, devid->function, NULL))) {
+	    printk("ISAPNP ");
+
+	    if (dev->prepare && dev->prepare(dev) < 0) {
+		printk("prepare failed\n");
+		break;
+	    }
+
+	    if (dev->activate && dev->activate(dev) < 0) {
+		printk("activate failed\n");
+		break;
+	    }
+
+	    if ((i365_base = pci_resource_start(dev, 0))) {
+		printk("no resources ?\n");
+		break;
+	    }
+	    i82365_pnpdev = dev;
+	    break;
+	}
+    }
+#endif
 
     if (check_region(i365_base, 2) != 0) {
 	if (sockets == 0)
@@ -1604,6 +1652,10 @@
 	i365_set(i, I365_CSCINT, 0);
 	release_region(socket[i].ioaddr, 2);
     }
+#if defined(CONFIG_ISA) && defined(I82365_ISAPNP)
+    if (i82365_pnpdev && i82365_pnpdev->deactivate)
+		i82365_pnpdev->deactivate(i82365_pnpdev);
+#endif
 } /* exit_i82365 */
 
 module_init(init_i82365);
diff -u --recursive --new-file v2.4.7/linux/drivers/pnp/Config.in linux/drivers/pnp/Config.in
--- v2.4.7/linux/drivers/pnp/Config.in	Mon Oct 11 10:13:24 1999
+++ linux/drivers/pnp/Config.in	Wed Jul 25 14:12:02 2001
@@ -8,4 +8,8 @@
 
 dep_tristate '  ISA Plug and Play support' CONFIG_ISAPNP $CONFIG_PNP
 
+if [ "$CONFIG_EXPERIMENTAL" = "y" ]; then
+   dep_bool '  PNPBIOS support (EXPERIMENTAL)' CONFIG_PNPBIOS $CONFIG_PNP
+fi
+
 endmenu
diff -u --recursive --new-file v2.4.7/linux/drivers/s390/Config.in linux/drivers/s390/Config.in
--- v2.4.7/linux/drivers/s390/Config.in	Wed Apr 11 19:02:29 2001
+++ linux/drivers/s390/Config.in	Sun Aug  5 13:12:41 2001
@@ -14,12 +14,21 @@
 
 tristate 'Support for DASD devices' CONFIG_DASD
 if [ "$CONFIG_DASD" != "n"  ]; then
-  bool '   Support for ECKD Disks' CONFIG_DASD_ECKD
-  bool '   Support for FBA  Disks' CONFIG_DASD_FBA
-#  bool '   Support for CKD  Disks' CONFIG_DASD_CKD
-  if [ "$CONFIG_ARCH_S390" = "y" ]; then
-    bool '   Support for DIAG access to CMS reserved Disks' CONFIG_DASD_DIAG
+  dep_tristate '   Support for ECKD Disks' CONFIG_DASD_ECKD $CONFIG_DASD
+  if [ "$CONFIG_DASD_ECKD" = "m" ]; then
+    bool     '   Automatic activation of ECKD module' CONFIG_DASD_AUTO_ECKD
   fi;
+  dep_tristate '   Support for FBA  Disks' CONFIG_DASD_FBA $CONFIG_DASD
+  if [ "$CONFIG_DASD_FBA" = "m" ]; then
+    bool     '   Automatic activation of FBA  module' CONFIG_DASD_AUTO_FBA
+  fi;
+#  dep_tristate '   Support for CKD  Disks' CONFIG_DASD_CKD $CONFIG_DASD
+  if [ "$CONFIG_ARCH_S390X" != "y" ]; then
+    dep_tristate '   Support for DIAG access to CMS reserved Disks' CONFIG_DASD_DIAG $CONFIG_DASD
+    if [ "$CONFIG_DASD_DIAG" = "m" ]; then
+      bool     '   Automatic activation of DIAG module' CONFIG_DASD_AUTO_DIAG
+    fi;
+  fi; 
 fi
 
 endmenu
@@ -35,19 +44,18 @@
 
 comment 'S/390 character device drivers'
 
-tristate 'Support for locally attached 3270 tubes' CONFIG_3270
-if [ "$CONFIG_3270" = "y" ]; then
-  bool 'Support for console on 3270 line mode terminal' CONFIG_3270_CONSOLE
-fi
-if [ "$CONFIG_3270_CONSOLE" != "y" ]; then
-  bool 'Support for 3215 line mode terminal' CONFIG_3215
-  if [ "$CONFIG_3215" = "y" ]; then
-    bool 'Support for console on 3215 line mode terminal' CONFIG_3215_CONSOLE
-  fi
+tristate 'Support for locally attached 3270 tubes' CONFIG_TN3270
+if [ "$CONFIG_TN3270" = "y" ]; then
+  bool 'Support for console on 3270 line mode terminal' CONFIG_TN3270_CONSOLE
+fi
+bool 'Support for 3215 line mode terminal' CONFIG_TN3215
+if [ "$CONFIG_TN3215" = "y" ]; then
+  bool 'Support for console on 3215 line mode terminal' CONFIG_TN3215_CONSOLE
 fi
 bool 'Support for HWC line mode terminal' CONFIG_HWC
 if [ "$CONFIG_HWC" = "y" ]; then
-  bool 'console on HWC line mode terminal' CONFIG_HWC_CONSOLE
+  bool '   console on HWC line mode terminal' CONFIG_HWC_CONSOLE
+  tristate '   Control-Program Identification' CONFIG_HWC_CPI
 fi
 tristate 'S/390 tape device support' CONFIG_S390_TAPE
 if [ "$CONFIG_S390_TAPE" != "n" ]; then
@@ -67,11 +75,18 @@
 
   if [ "$CONFIG_NETDEVICES" = "y" ]; then
     tristate 'Dummy net driver support' CONFIG_DUMMY
+    tristate 'Bonding driver support' CONFIG_BONDING
+    tristate 'EQL (serial line load balancing) support' CONFIG_EQUALIZER
+    tristate 'Universal TUN/TAP device driver support' CONFIG_TUN
     bool 'Ethernet (10 or 100Mbit)' CONFIG_NET_ETHERNET
     bool 'Token Ring driver support' CONFIG_TR
     bool 'FDDI driver support' CONFIG_FDDI
     comment 'S/390 network device drivers'
-    bool 'Channel Device Configuration (Temporary Option)' CONFIG_CHANDEV
+    bool 'Channel Device Configuration' CONFIG_CHANDEV
+    if [ "$CONFIG_CHANDEV" = "y" ]; then
+	define_bool CONFIG_HOTPLUG y
+    fi
+
     tristate 'CTC device support' CONFIG_CTC
     tristate 'IUCV device support (VM only)' CONFIG_IUCV
   fi
diff -u --recursive --new-file v2.4.7/linux/drivers/s390/Makefile linux/drivers/s390/Makefile
--- v2.4.7/linux/drivers/s390/Makefile	Wed Apr 11 19:02:29 2001
+++ linux/drivers/s390/Makefile	Wed Jul 25 14:12:02 2001
@@ -6,9 +6,10 @@
 
 subdir-y := block char misc net
 subdir-m := $(subdir-y)
-obj-y := $(foreach dir,$(subdir-y),$(dir)/s390-$(dir).o)
 
-obj-y += s390io.o s390mach.o s390dyn.o idals.o ccwcache.o
+obj-y := s390io.o s390mach.o s390dyn.o idals.o ccwcache.o
 export-objs += ccwcache.o idals.o s390dyn.o s390io.o
+
+obj-y += $(foreach dir,$(subdir-y),$(dir)/s390-$(dir).o)
 
 include $(TOPDIR)/Rules.make
diff -u --recursive --new-file v2.4.7/linux/drivers/s390/block/Makefile linux/drivers/s390/block/Makefile
--- v2.4.7/linux/drivers/s390/block/Makefile	Wed Apr 11 19:02:28 2001
+++ linux/drivers/s390/block/Makefile	Sun Aug  5 13:12:41 2001
@@ -4,19 +4,31 @@
 
 O_TARGET := s390-block.o
 
-list-multi := dasd_mod.o
+list-multi := dasd_mod.o dasd_eckd_mod.o dasd_fba_mod.o dasd_diag_mod.o
 export-objs := dasd.o
 
-dasd_mod-$(CONFIG_DASD_ECKD) += dasd_eckd.o dasd_3990_erp.o dasd_9343_erp.o
-dasd_mod-$(CONFIG_DASD_FBA) += dasd_fba.o dasd_3370_erp.o dasd_9336_erp.o
-dasd_mod-$(CONFIG_DASD_DIAG) += dasd_diag.o
-dasd_mod-objs := dasd.o $(dasd_mod-y)
+dasd_eckd_mod-objs := dasd_eckd.o dasd_3990_erp.o dasd_9343_erp.o
+dasd_fba_mod-objs  := dasd_fba.o dasd_3370_erp.o dasd_9336_erp.o
+dasd_diag_mod-objs := dasd_diag.o
+dasd_mod-objs      := dasd.o
 
 obj-$(CONFIG_DASD) += dasd_mod.o
+obj-$(CONFIG_DASD_ECKD) += dasd_eckd_mod.o
+obj-$(CONFIG_DASD_FBA)  += dasd_fba_mod.o
+obj-$(CONFIG_DASD_DIAG) += dasd_diag_mod.o
 obj-$(CONFIG_BLK_DEV_XPRAM) += xpram.o
 
 include $(TOPDIR)/Rules.make
 
 dasd_mod.o: $(dasd_mod-objs)
 	$(LD) -r -o $@ $(dasd_mod-objs)
+
+dasd_eckd_mod.o: $(dasd_eckd_mod-objs)
+	$(LD) -r -o $@ $(dasd_eckd_mod-objs)
+
+dasd_fba_mod.o: $(dasd_fba_mod-objs)
+	$(LD) -r -o $@ $(dasd_fba_mod-objs)
+
+dasd_diag_mod.o: $(dasd_diag_mod-objs)
+	$(LD) -r -o $@ $(dasd_diag_mod-objs)
 
diff -u --recursive --new-file v2.4.7/linux/drivers/s390/block/dasd.c linux/drivers/s390/block/dasd.c
--- v2.4.7/linux/drivers/s390/block/dasd.c	Tue May 15 01:29:34 2001
+++ linux/drivers/s390/block/dasd.c	Sun Aug  5 13:12:41 2001
@@ -1,14 +1,13 @@
-/* 
+/*
  * File...........: linux/drivers/s390/block/dasd.c
  * Author(s)......: Holger Smolinski <Holger.Smolinski@de.ibm.com>
- *                  Horst Hummel <Horst.Hummel@de.ibm.com>  
+ *                  Horst Hummel <Horst.Hummel@de.ibm.com> 
  *                  Carsten Otte <Cotte@de.ibm.com>
  * Bugreports.to..: <Linux390@de.ibm.com>
- * (C) IBM Corporation, IBM Deutschland Entwicklung GmbH, 1999,2000
+ * (C) IBM Corporation, IBM Deutschland Entwicklung GmbH, 1999-2001
  *
  * History of changes (starts July 2000)
  * 11/09/00 complete redesign after code review
- * 02/01/01 removed some warnings
  * 02/01/01 added dynamic registration of ioctls
  *          fixed bug in registration of new majors
  *          fixed handling of request during dasd_end_request
@@ -18,20 +17,34 @@
  *          fixed some race conditions related to modules
  *          added devfs suupport
  * 03/06/01 refined dynamic attach/detach for leaving devices which are online.
- * 06/09/01 refined dynamic modifiaction of devices
- *          renewed debug feature exploitation
+ * 03/09/01 refined dynamic modifiaction of devices
+ * 03/12/01 moved policy in dasd_format to dasdfmt (renamed BIODASDFORMAT)
+ * 03/19/01 added BIODASDINFO-ioctl
+ *          removed 2.2 compatibility
+ * 04/27/01 fixed PL030119COT (dasd_disciplines does not work)
+ * 04/30/01 fixed PL030146HSM (module locking with dynamic ioctls)
+ *          fixed PL030130SBA (handling of invalid ranges)
+ * 05/02/01 fixed PL030145SBA (killing dasdmt)
+ *          fixed PL030149SBA (status of 'accepted' devices)
+ *          fixed PL030146SBA (BUG in ibm.c after adding device)
+ *          added BIODASDPRRD ioctl interface
+ * 05/11/01 fixed  PL030164MVE (trap in probeonly mode)
+ * 05/15/01 fixed devfs support for unformatted devices
+ * 06/26/01 hopefully fixed PL030172SBA,PL030234SBA
+ * 07/09/01 fixed PL030324MSH (wrong statistics output)
+ * 07/16/01 merged in new fixes for handling low-mem situations
  */
 
-#include <linux/module.h>
 #include <linux/config.h>
 #include <linux/version.h>
+#include <linux/kmod.h>
 #include <linux/init.h>
 #include <linux/blkdev.h>
 #include <linux/stddef.h>
 #include <linux/kernel.h>
 #include <linux/tqueue.h>
 #include <linux/timer.h>
-#include <linux/malloc.h>
+#include <linux/slab.h>
 #include <linux/genhd.h>
 #include <linux/hdreg.h>
 #include <linux/interrupt.h>
@@ -42,9 +55,9 @@
 #include <linux/spinlock.h>
 #include <linux/devfs_fs_kernel.h>
 #include <linux/blkpg.h>
+#include <linux/wait.h>
 
 #include <asm/ccwcache.h>
-#include <asm/dasd.h>
 #include <asm/debug.h>
 
 #include <asm/atomic.h>
@@ -57,6 +70,9 @@
 #include <asm/s390_ext.h>
 #include <asm/s390dyn.h>
 #include <asm/idals.h>
+#include <asm/dasd.h>
+
+#include "dasd_int.h"
 
 #ifdef CONFIG_DASD_ECKD
 #include "dasd_eckd.h"
@@ -68,25 +84,40 @@
 #include "dasd_diag.h"
 #endif				/*  CONFIG_DASD_DIAG */
 
+/* SECTION: exported variables of dasd.c */
+
+debug_info_t *dasd_debug_area;
+
 MODULE_AUTHOR ("Holger Smolinski <Holger.Smolinski@de.ibm.com>");
 MODULE_DESCRIPTION ("Linux on S/390 DASD device driver,"
 		    " Copyright 2000 IBM Corporation");
 MODULE_SUPPORTED_DEVICE ("dasd");
 MODULE_PARM (dasd, "1-" __MODULE_STRING (256) "s");
-EXPORT_SYMBOL (dasd_discipline_enq);
-EXPORT_SYMBOL (dasd_discipline_deq);
+MODULE_PARM (dasd_disciplines, "1-" __MODULE_STRING (8) "s");
+EXPORT_SYMBOL (dasd_chanq_enq_head);
+EXPORT_SYMBOL (dasd_debug_area);
+EXPORT_SYMBOL (dasd_chanq_enq);
+EXPORT_SYMBOL (dasd_chanq_deq);
+EXPORT_SYMBOL (dasd_discipline_add);
+EXPORT_SYMBOL (dasd_discipline_del);
 EXPORT_SYMBOL (dasd_start_IO);
+EXPORT_SYMBOL (dasd_term_IO);
+EXPORT_SYMBOL (dasd_schedule_bh);
 EXPORT_SYMBOL (dasd_int_handler);
+EXPORT_SYMBOL (dasd_oper_handler);
 EXPORT_SYMBOL (dasd_alloc_request);
 EXPORT_SYMBOL (dasd_free_request);
-EXPORT_SYMBOL(dasd_ioctl_no_register);  
-EXPORT_SYMBOL(dasd_ioctl_no_unregister);
+EXPORT_SYMBOL (dasd_ioctl_no_register);
+EXPORT_SYMBOL (dasd_ioctl_no_unregister);
+EXPORT_SYMBOL (dasd_default_erp_action);
+EXPORT_SYMBOL (dasd_default_erp_postaction);
+EXPORT_SYMBOL (dasd_sleep_on_req);
+EXPORT_SYMBOL (dasd_set_normalized_cda);
 
 /* SECTION: Constant definitions to be used within this file */
 
-#define PRINTK_HEADER DASD_NAME": "
+#define PRINTK_HEADER DASD_NAME":"
 
-#define DASD_EMERGENCY_REQUESTS 16
 #define DASD_MIN_SIZE_FOR_QUEUE 32
 #undef CONFIG_DYNAMIC_QUEUE_MIN_SIZE
 #define DASD_CHANQ_MAX_SIZE 6
@@ -94,27 +125,36 @@
 /* SECTION: prototypes for static functions of dasd.c */
 
 static request_fn_proc do_dasd_request;
-static int dasd_set_device_level (unsigned int, int, dasd_discipline_t *, int);
+static int dasd_set_device_level (unsigned int, dasd_discipline_t *, int);
 static request_queue_t *dasd_get_queue (kdev_t kdev);
 static void cleanup_dasd (void);
-int dasd_fillgeo(int kdev,struct hd_geometry *geo);
-
+static void dasd_plug_device (dasd_device_t * device);
+static int dasd_fillgeo (int kdev, struct hd_geometry *geo);
+static void dasd_enable_ranges (dasd_range_t *, dasd_discipline_t *, int); 
+static void dasd_disable_ranges (dasd_range_t *, dasd_discipline_t *, int, int); 
+static void dasd_enable_single_device ( unsigned long);
+static inline int dasd_state_init_to_ready(dasd_device_t*);
+static inline void dasd_setup_partitions ( dasd_device_t *);
+static inline int dasd_setup_blkdev(dasd_device_t*);
+static inline int dasd_disable_blkdev(dasd_device_t*);
+static void dasd_flush_chanq ( dasd_device_t * device, int destroy ); 
+static void dasd_flush_request_queues ( dasd_device_t * device, int destroy );
 static struct block_device_operations dasd_device_operations;
-
+static inline dasd_device_t ** dasd_device_from_devno (int);
+static void dasd_process_queues (dasd_device_t * device);
 /* SECTION: static variables of dasd.c */
 
 static devfs_handle_t dasd_devfs_handle;
-
-/* SECTION: exported variables of dasd.c */
-
-debug_info_t *dasd_debug_area;
+static wait_queue_head_t dasd_init_waitq;
+static atomic_t dasd_init_pending = ATOMIC_INIT (0);
 
 #ifdef CONFIG_DASD_DYNAMIC
+
 /* SECTION: managing dynamic configuration of dasd_driver */
 
-static struct list_head dasd_devreg_head = LIST_HEAD_INIT(dasd_devreg_head);
+static struct list_head dasd_devreg_head = LIST_HEAD_INIT (dasd_devreg_head);
 
-/* 
+/*
  * function: dasd_create_devreg
  * creates a dasd_devreg_t related to a devno
  */
@@ -131,7 +171,7 @@
 	return r;
 }
 
-/* 
+/*
  * function: dasd_destroy_devreg
  * destroys the dasd_devreg_t given as argument
  */
@@ -149,44 +189,44 @@
 static int dasd_probeonly = 1;	/* is true, when probeonly mode is active */
 static int dasd_autodetect = 1;	/* is true, when autodetection is active */
 
-/* dasd_range_t are used for ordering the DASD devices */
-typedef struct dasd_range_t {
-	unsigned int from;	/* first DASD in range */
-	unsigned int to;	/* last DASD in range */
-	char discipline[4];	/* placeholder to force discipline */
-	struct dasd_range_t *next;	/* next one in linked list */
-} dasd_range_t;
-
-static dasd_range_t *dasd_range_head = NULL;	/* anchor for list of ranges */
+static dasd_range_t dasd_range_head =
+    { list:LIST_HEAD_INIT (dasd_range_head.list) };
 static spinlock_t range_lock = SPIN_LOCK_UNLOCKED;
-static spinlock_t dasd_open_count_lock;
 
-/* 
+/*
  * function: dasd_create_range
- * creates a dasd_range_t according to the arguments 
+ * creates a dasd_range_t according to the arguments
  * FIXME: no check is performed for reoccurrence of a devno
  */
 static inline dasd_range_t *
-dasd_create_range (int from, int to)
+dasd_create_range (int from, int to, int features)
 {
 	dasd_range_t *range = NULL;
+        int i;
+
+	if ( from > to ) {
+                printk (KERN_WARNING PRINTK_HEADER "Adding device range %04X-%04X: range invalid, ignoring.\n",from,to);
+		return NULL;
+	}
+	for (i=from;i<=to;i++) {
+                if (dasd_device_from_devno(i)) {
+                        printk (KERN_WARNING PRINTK_HEADER "device range %04X-%04X: device %04X is already in a range.\n",from,to,i);
+                }
+        }
 	range = (dasd_range_t *) kmalloc (sizeof (dasd_range_t), GFP_KERNEL);
 	if (range == NULL)
 		return NULL;
 	memset (range, 0, sizeof (dasd_range_t));
 	range->from = from;
-	if (to == 0) {		/* single devno ? */
-		range->to = from;
-	} else {
-		range->to = to;
-	}
+        range->to = to;
+        range->features = features;
 	return range;
 }
 
-/* 
+/*
  * function dasd_destroy_range
  * destroy a range allocated wit dasd_crate_range
- * CAUTION: must not be callen in arunning sysztem, because it destroys 
+ * CAUTION: must not be callen in arunning sysztem, because it destroys
  * the mapping of DASDs
  */
 static inline void
@@ -195,68 +235,50 @@
 	kfree (range);
 }
 
-/* 
+/*
  * function: dasd_append_range
- * appends the range given as argument to the list anchored at dasd_range_head. 
+ * appends the range given as argument to the list anchored at dasd_range_head.
  */
 static inline void
 dasd_append_range (dasd_range_t * range)
 {
-	dasd_range_t *temp;
 	long flags;
 
 	spin_lock_irqsave (&range_lock, flags);
-	if (dasd_range_head == NULL) {
-		dasd_range_head = range;
-	} else {
-		for (temp = dasd_range_head;
-		     temp && temp->next;
-		     temp = temp->next) ;
-		temp->next = range;
-	}
+	list_add_tail (&range->list, &dasd_range_head.list);
 	spin_unlock_irqrestore (&range_lock, flags);
 }
 
 /*
  * function dasd_dechain_range
  * removes a range from the chain of ranges
- * CAUTION: must not be called in a running system because it destroys 
+ * CAUTION: must not be called in a running system because it destroys
  * the mapping of devices
  */
 static inline void
 dasd_dechain_range (dasd_range_t * range)
 {
-	dasd_range_t *temp, *prev = NULL;
 	unsigned long flags;
 
 	spin_lock_irqsave (&range_lock, flags);
-	for (temp = dasd_range_head; temp != NULL; temp = temp->next) {
-		if (temp == range)
-			break;
-		prev = temp;
-	}
-	if (!temp)
-		BUG ();
-	if (prev) {
-		prev->next = temp->next;
-	} else {
-		dasd_range_head = temp->next;
-	}
+	list_del (&range->list);
 	spin_unlock_irqrestore (&range_lock, flags);
 }
 
-/* 
+/*
  * function: dasd_add_range
  * creates a dasd_range_t according to the arguments and
  * appends it to the list of ranges
- * additionally a devreg_t is created and added to the list of devregs 
+ * additionally a devreg_t is created and added to the list of devregs
  */
-static inline dasd_range_t*
-dasd_add_range (int from, int to)
+static inline dasd_range_t *
+dasd_add_range (int from, int to, int features)
 {
 	dasd_range_t *range;
-	range = dasd_create_range (from, to);
-	if (!range) return NULL;
+
+	range = dasd_create_range (from, to, features);
+	if (!range)
+		return NULL;
 
 	dasd_append_range (range);
 #ifdef CONFIG_DASD_DYNAMIC
@@ -266,14 +288,14 @@
 		for (i = range->from; i <= range->to; i++) {
 			dasd_devreg_t *reg = dasd_create_devreg (i);
 			s390_device_register (&reg->devreg);
-                        list_add(&reg->list,&dasd_devreg_head);
+			list_add (&reg->list, &dasd_devreg_head);
 		}
 	}
 #endif				/* CONFIG_DASD_DYNAMIC */
 	return range;
 }
 
-/* 
+/*
  * function: dasd_remove_range
  * removes a range and the corresponding devregs from all of the chains
  * CAUTION: must not be called in a running system because it destroys
@@ -287,10 +309,10 @@
 	{
 		int i;
 		for (i = range->from; i <= range->to; i++) {
-                        struct list_head *l;
-                        dasd_devreg_t *reg = NULL;
+			struct list_head *l;
+			dasd_devreg_t *reg = NULL;
 			list_for_each (l, &dasd_devreg_head) {
-                                reg = list_entry(l,dasd_devreg_t,list);
+				reg = list_entry (l, dasd_devreg_t, list);
 				if (reg->devreg.flag == DEVREG_TYPE_DEVNO &&
 				    reg->devreg.ci.devno == i &&
 				    reg->devreg.oper_func == dasd_oper_handler)
@@ -319,9 +341,11 @@
 	dasd_range_t *temp;
 	int devindex = 0;
 	unsigned long flags;
+	struct list_head *l;
 
 	spin_lock_irqsave (&range_lock, flags);
-	for (temp = dasd_range_head; temp; temp = temp->next) {
+	list_for_each (l, &dasd_range_head.list) {
+		temp = list_entry (l, dasd_range_t, list);
 		if (devno >= temp->from && devno <= temp->to) {
 			spin_unlock_irqrestore (&range_lock, flags);
 			return devindex + devno - temp->from;
@@ -332,19 +356,43 @@
 	return -ENODEV;
 }
 
+/*
+ * function: dasd_devno_from_devindex
+ */
+static int
+dasd_devno_from_devindex (int devindex)
+{
+	dasd_range_t *temp;
+	unsigned long flags;
+	struct list_head *l;
+
+	spin_lock_irqsave (&range_lock, flags);
+	list_for_each (l, &dasd_range_head.list) {
+		temp = list_entry (l, dasd_range_t, list);
+                if ( devindex < temp->to - temp->from + 1) {
+			spin_unlock_irqrestore (&range_lock, flags);
+			return temp->from + devindex;
+		}
+		devindex -= temp->to - temp->from + 1;
+	}
+	spin_unlock_irqrestore (&range_lock, flags);
+	return -ENODEV;
+}
+
 /* SECTION: parsing the dasd= parameter of the parmline/insmod cmdline */
 
-/* 
+/*
  * char *dasd[] is intended to hold the ranges supplied by the dasd= statement
  * it is named 'dasd' to directly be filled by insmod with the comma separated
  * strings when running as a module.
  * a maximum of 256 ranges can be supplied, as the parmline is limited to
  * <1024 Byte anyway.
  */
-char *dasd[256] = {NULL,};
+char *dasd[256];
+char *dasd_disciplines[8];
 
 #ifndef MODULE
-/* 
+/*
  * function: dasd_split_parm_string
  * splits the parmline given to the kernel into comma separated strings
  * which are filled into the 'dasd[]' array, to be parsed later on
@@ -354,7 +402,7 @@
 {
 	char *tmp = str;
 	int count = 0;
-	do {
+	while (tmp != NULL && *tmp != '\0') {
 		char *end;
 		int len;
 		end = strchr (tmp, ',');
@@ -366,27 +414,28 @@
 			end++;
 		}
 		dasd[count] = kmalloc (len * sizeof (char), GFP_ATOMIC);
-		if (dasd == NULL) {
+		if (dasd[count] == NULL) {
 			printk (KERN_WARNING PRINTK_HEADER
-			    "can't store dasd= parameter no %d\n", count + 1);
+				"can't store dasd= parameter no %d\n",
+				count + 1);
 			break;
 		}
 		memset (dasd[count], 0, len * sizeof (char));
 		memcpy (dasd[count], tmp, len * sizeof (char));
 		count++;
 		tmp = end;
-	} while (tmp != NULL && *tmp != '\0');
+	};
 }
 
-/* 
+/*
  * dasd_parm_string holds a concatenated version of all 'dasd=' parameters
- * supplied in the parmline, which is later to be split by 
+ * supplied in the parmline, which is later to be split by
  * dasd_split_parm_string
  * FIXME: why first concatenate then split ?
  */
-static char dasd_parm_string[1024] __initdata = {0,};
+static char dasd_parm_string[1024] __initdata = { 0, };
 
-/* 
+/*
  * function: dasd_setup
  * is invoked for any single 'dasd=' parameter supplied in the parmline
  * it merges all the arguments into dasd_parm_string
@@ -400,44 +449,90 @@
 	}
 	strcat (dasd_parm_string, str);
 }
-/* 
- * function: dasd_call_setup 
+
+/*
+ * function: dasd_call_setup
  * is the 2.4 version of dasd_setup and
  * is invoked for any single 'dasd=' parameter supplied in the parmline
  */
 int __init
 dasd_call_setup (char *str)
 {
-        int dummy;
-        dasd_setup(str,&dummy);
+	int dummy;
+	dasd_setup (str, &dummy);
+	return 1;
+}
+
+int __init
+dasd_disciplines_setup (char *str)
+{
 	return 1;
 }
 
 __setup ("dasd=", dasd_call_setup);
+__setup ("dasd_disciplines=", dasd_disciplines_setup);
 
-#endif /* MODULE */
+#endif				/* MODULE */
 
-/* 
+/*
  * function: dasd_strtoul
  * provides a wrapper to simple_strtoul to strip leading '0x' and
  * interpret any argument to dasd=[range,...] as hexadecimal
  */
 static inline int
-dasd_strtoul (char *str, char **stra)
+dasd_strtoul (char *str, char **stra, int* features)
 {
-	char *temp = str;
-	int val;
-	if (*temp == '0') {
-		temp++;		/* strip leading zero */
-		if (*temp == 'x')
-			temp++;	/* strip leading x */
-	}
-	val = simple_strtoul (temp, &temp, 16);		/* interpret anything as hex */
-	*stra = temp;
-	return val;
+        char *temp=str;
+        char *buffer;
+        int val,i,start;
+
+        buffer=(char*)kmalloc((strlen(str)+1)*sizeof(char),GFP_ATOMIC);
+        if (buffer==NULL) {
+            printk (KERN_WARNING PRINTK_HEADER
+                    "can't parse dasd= parameter %s due to low memory\n",
+                    str);
+        }
+
+        /* remove leading '0x' */
+        if (*temp == '0') {
+                temp++;         /* strip leading zero */
+                if (*temp == 'x')
+                        temp++; /* strip leading x */
+        }
+
+        /* copy device no to buffer and convert to decimal */
+        for (i=0;isxdigit(temp[i]);i++)
+                buffer[i]=temp[i];
+        buffer[i]='\0';
+
+        val = simple_strtoul (buffer, &buffer, 16);
+
+        /* check for features - e.g. (ro) ; the '\0', ')' and '-' stops check */
+        if (temp[i]=='(') {
+
+                while (temp[i]!='\0' && temp[i]!=')'&&temp[i]!='-') { 
+                        start=++i;      
+        
+                        /* move next feature to buffer */
+                        for (;temp[i]!='\0'&&temp[i]!=':'&&temp[i]!=')'&&temp[i]!='-';i++)
+                                buffer[i-start]=temp[i];
+                        buffer[i-start]='\0';
+
+                        if (strlen(buffer)) { 
+                                if (!strcmp(buffer,"ro")) { /* handle 'ro' feature */
+                                        (*features) |= DASD_FEATURE_READONLY;
+                                        break;
+                                }
+                                printk (KERN_WARNING PRINTK_HEADER 
+                                        "unsupported feature: %s, ignoring setting",buffer);
+                        }
+                }
+        }
+        *stra = temp+i;
+        return val;
 }
 
-/* 
+/*
  * function: dasd_parse
  * examines the strings given in the string array str and
  * creates and adds the ranges to the apropriate lists
@@ -447,6 +542,7 @@
 {
 	char *temp;
 	int from, to;
+        int features = 0;
 
 	if (*str) {
 		/* turn off probeonly mode, if any dasd parameter is present */
@@ -468,12 +564,13 @@
 		} else {
 			/* turn off autodetect mode, if any range is present */
 			dasd_autodetect = 0;
-			from = dasd_strtoul (temp, &temp);
+			from = dasd_strtoul (temp, &temp, &features);
+                        to = from;
 			if (*temp == '-') {
 				temp++;
-				to = dasd_strtoul (temp, &temp);
+				to = dasd_strtoul (temp, &temp, &features);
 			}
-			dasd_add_range (from, to);
+			dasd_add_range (from, to ,features);
 		}
 		str++;
 	}
@@ -483,18 +580,16 @@
 
 static spinlock_t dasd_major_lock = SPIN_LOCK_UNLOCKED;
 
-static major_info_t dasd_major_info[] =
-{
+static major_info_t dasd_major_info[] = {
 	{
-		list: LIST_HEAD_INIT(dasd_major_info[1].list )
-	},
+	      list:LIST_HEAD_INIT (dasd_major_info[1].list)
+	 },
 	{
-		list: LIST_HEAD_INIT(dasd_major_info[0].list ),
-		gendisk: {
-                        INIT_GENDISK(94,DASD_NAME,DASD_PARTN_BITS,DASD_PER_MAJOR)
-		},
-		flags : DASD_MAJOR_INFO_IS_STATIC
-	}
+	      list:LIST_HEAD_INIT (dasd_major_info[0].list),
+	      gendisk:{
+	  INIT_GENDISK (94, DASD_NAME, DASD_PARTN_BITS, DASD_PER_MAJOR)
+	  },
+      flags:DASD_MAJOR_INFO_IS_STATIC}
 };
 
 static major_info_t *
@@ -504,17 +599,21 @@
 
 	major_info = kmalloc (sizeof (major_info_t), GFP_KERNEL);
 	if (major_info) {
-		static major_info_t temp_major_info =
-		{
-			gendisk: {
-				INIT_GENDISK(0,DASD_NAME,DASD_PARTN_BITS,DASD_PER_MAJOR)
-			}
+		static major_info_t temp_major_info = {
+			gendisk:{
+				 INIT_GENDISK (0, DASD_NAME, DASD_PARTN_BITS,
+					       DASD_PER_MAJOR)}
 		};
 		memcpy (major_info, &temp_major_info, sizeof (major_info_t));
 	}
 	return major_info;
 }
 
+/*
+ * register major number
+ * is called with the 'static' major_info during init of the driver or 'NULL' to
+ * allocate an additional dynamic major.
+ */
 static int
 dasd_register_major (major_info_t * major_info)
 {
@@ -522,67 +621,86 @@
 	int major;
 	unsigned long flags;
 
+        /* allocate dynamic major */
 	if (major_info == NULL) {
 		major_info = get_new_major_info ();
 		if (!major_info) {
 			printk (KERN_WARNING PRINTK_HEADER
 				"Cannot get memory to allocate another major number\n");
 			return -ENOMEM;
-		} else {
-			printk (KERN_INFO PRINTK_HEADER
-				"Created another major number\n");
 		}
 	}
+
 	major = major_info->gendisk.major;
-	major_info->gendisk.de_arr = (devfs_handle_t*)
-		kmalloc(DASD_PER_MAJOR * sizeof(devfs_handle_t), GFP_KERNEL);
-	memset(major_info->gendisk.de_arr,0,DASD_PER_MAJOR * sizeof(devfs_handle_t));
-	major_info->gendisk.flags = (char*)
-		kmalloc(DASD_PER_MAJOR * sizeof(char), GFP_KERNEL);
-	memset(major_info->gendisk.flags,0,DASD_PER_MAJOR * sizeof(char));
 
+        /* init devfs array */
+	major_info->gendisk.de_arr = (devfs_handle_t *)
+	    kmalloc (DASD_PER_MAJOR * sizeof (devfs_handle_t), GFP_KERNEL);
+	memset (major_info->gendisk.de_arr, 0,
+		DASD_PER_MAJOR * sizeof (devfs_handle_t));
+
+        /* init flags */
+	major_info->gendisk.flags = (char *)
+	    kmalloc (DASD_PER_MAJOR * sizeof (char), GFP_KERNEL);
+	memset (major_info->gendisk.flags, 0, DASD_PER_MAJOR * sizeof (char));
+
+        /* register blockdevice */
 	rc = devfs_register_blkdev (major, DASD_NAME, &dasd_device_operations);
 	if (rc < 0) {
 		printk (KERN_WARNING PRINTK_HEADER
-		      "Cannot register to major no %d, rc = %d\n", major, rc);
-		return rc;
+			"Cannot register to major no %d, rc = %d\n", major, rc);
+		goto out_reg_blkdev; 
 	} else {
 		major_info->flags |= DASD_MAJOR_INFO_REGISTERED;
 	}
-        /* Insert the new major info into dasd_major_info if needed */
-        if (!(major_info->flags & DASD_MAJOR_INFO_IS_STATIC) ){
-                spin_lock_irqsave (&dasd_major_lock, flags);
-		list_add_tail(&major_info->list,&dasd_major_info[0].list);
+
+	/* Insert the new major info into dasd_major_info if needed (dynamic major) */
+	if (!(major_info->flags & DASD_MAJOR_INFO_IS_STATIC)) {
+		spin_lock_irqsave (&dasd_major_lock, flags);
+		list_add_tail (&major_info->list, &dasd_major_info[0].list);
 		spin_unlock_irqrestore (&dasd_major_lock, flags);
-        }
+	}
+
 	if (major == 0) {
 		major = rc;
 		rc = 0;
 	}
-	major_info->dasd_device = (dasd_device_t **) kmalloc (DASD_PER_MAJOR * sizeof (dasd_device_t *),
-							      GFP_ATOMIC);
+
+        /* init array of devices */
+	major_info->dasd_device =
+	    (dasd_device_t **) kmalloc (DASD_PER_MAJOR *
+					sizeof (dasd_device_t *), GFP_ATOMIC);
 	if (!major_info->dasd_device)
-		goto out_devfs;
-	memset (major_info->dasd_device, 0, DASD_PER_MAJOR * sizeof (dasd_device_t *));
+		goto out_devices;
+	memset (major_info->dasd_device, 0,
+		DASD_PER_MAJOR * sizeof (dasd_device_t *));
+
+        /* init blk_size */
 	blk_size[major] =
 	    (int *) kmalloc ((1 << MINORBITS) * sizeof (int), GFP_ATOMIC);
 	if (!blk_size[major])
-		goto out_dasd_device;
+		goto out_blk_size;
 	memset (blk_size[major], 0, (1 << MINORBITS) * sizeof (int));
+
+        /* init blksize_size */
 	blksize_size[major] =
 	    (int *) kmalloc ((1 << MINORBITS) * sizeof (int), GFP_ATOMIC);
 	if (!blksize_size[major])
-		goto out_blk_size;
+		goto out_blksize_size;
 	memset (blksize_size[major], 0, (1 << MINORBITS) * sizeof (int));
+
+        /* init_hardsect_size */
 	hardsect_size[major] =
 	    (int *) kmalloc ((1 << MINORBITS) * sizeof (int), GFP_ATOMIC);
 	if (!hardsect_size[major])
-		goto out_blksize_size;
+		goto out_hardsect_size;
 	memset (hardsect_size[major], 0, (1 << MINORBITS) * sizeof (int));
+
+        /* init max_sectors */
 	max_sectors[major] =
 	    (int *) kmalloc ((1 << MINORBITS) * sizeof (int), GFP_ATOMIC);
 	if (!max_sectors[major])
-		goto out_hardsect_size;
+		goto out_max_sectors;
 	memset (max_sectors[major], 0, (1 << MINORBITS) * sizeof (int));
 
 	/* finally do the gendisk stuff */
@@ -590,29 +708,65 @@
 					    sizeof (struct hd_struct),
 					    GFP_ATOMIC);
 	if (!major_info->gendisk.part)
-		goto out_max_sectors;
+		goto out_gendisk;
 	memset (major_info->gendisk.part, 0, (1 << MINORBITS) *
 		sizeof (struct hd_struct));
 
-	INIT_BLK_DEV(major,do_dasd_request,dasd_get_queue,NULL);
+	INIT_BLK_DEV (major, do_dasd_request, dasd_get_queue, NULL);
 
 	major_info->gendisk.major = major;
 	major_info->gendisk.next = gendisk_head;
 	major_info->gendisk.sizes = blk_size[major];
 	gendisk_head = &major_info->gendisk;
 	return major;
-out_max_sectors:
-	kfree(max_sectors[major]);
-out_hardsect_size:
-	kfree(hardsect_size[major]);
-out_blksize_size:
-	kfree(blksize_size[major]);
-out_blk_size:
-	kfree(blk_size[major]);
-out_dasd_device:
-	kfree(major_info->dasd_device);
-out_devfs:
-	devfs_unregister_blkdev(major, DASD_NAME);
+
+        /* error handling - free the prior allocated memory */  
+      out_gendisk:
+	kfree (max_sectors[major]);
+	max_sectors[major] = NULL;
+
+      out_max_sectors:
+	kfree (hardsect_size[major]);
+	hardsect_size[major] = NULL;
+
+      out_hardsect_size:
+	kfree (blksize_size[major]);
+	blksize_size[major] = NULL;
+
+      out_blksize_size:
+	kfree (blk_size[major]);
+	blk_size[major] = NULL;
+
+      out_blk_size:
+	kfree (major_info->dasd_device);
+
+      out_devices:
+	/* Delete the new major info from dasd_major_info list if needed (dynamic) +*/
+	if (!(major_info->flags & DASD_MAJOR_INFO_IS_STATIC)) {
+		spin_lock_irqsave (&dasd_major_lock, flags);
+		list_del (&major_info->list);
+		spin_unlock_irqrestore (&dasd_major_lock, flags);
+	}
+
+        /* unregister blockdevice */
+	rc = devfs_unregister_blkdev (major, DASD_NAME);
+	if (rc < 0) {
+		printk (KERN_WARNING PRINTK_HEADER
+			"Unable to unregister from major no %d, rc = %d\n", major,
+			rc);
+	} else {
+		major_info->flags &= ~DASD_MAJOR_INFO_REGISTERED;
+	}
+
+      out_reg_blkdev:
+        kfree (major_info->gendisk.flags);
+        kfree (major_info->gendisk.de_arr);
+
+	/* Delete the new major info from dasd_major_info if needed */
+	if (!(major_info->flags & DASD_MAJOR_INFO_IS_STATIC)) {
+		kfree (major_info);
+	}
+
 	return -ENOMEM;
 }
 
@@ -628,11 +782,7 @@
 		return -EINVAL;
 	}
 	major = major_info->gendisk.major;
-        INIT_BLK_DEV(major,NULL,NULL,NULL);
-	blk_size[major] = NULL;
-	blksize_size[major] = NULL;
-	hardsect_size[major] = NULL;
-	max_sectors[major] = NULL;
+	INIT_BLK_DEV (major, NULL, NULL, NULL);
 
 	/* do the gendisk stuff */
 	for (dd = gendisk_head; dd; dd = dd->next) {
@@ -648,34 +798,43 @@
 	if (dd == NULL) {
 		return -ENOENT;
 	}
-	kfree (major_info->gendisk.de_arr);
-	kfree (major_info->gendisk.flags);
 	kfree (major_info->dasd_device);
+	kfree (major_info->gendisk.part);
+
 	kfree (blk_size[major]);
 	kfree (blksize_size[major]);
 	kfree (hardsect_size[major]);
 	kfree (max_sectors[major]);
-	kfree (major_info->gendisk.part);
+
+	blk_size[major]      = NULL;
+	blksize_size[major]  = NULL;
+	hardsect_size[major] = NULL;
+	max_sectors[major]   = NULL;
 
 	rc = devfs_unregister_blkdev (major, DASD_NAME);
 	if (rc < 0) {
 		printk (KERN_WARNING PRINTK_HEADER
-		  "Cannot unregister from major no %d, rc = %d\n", major, rc);
+			"Cannot unregister from major no %d, rc = %d\n", major,
+			rc);
 		return rc;
 	} else {
 		major_info->flags &= ~DASD_MAJOR_INFO_REGISTERED;
 	}
-        /* Delete the new major info from dasd_major_info if needed */
-        if (!(major_info->flags & DASD_MAJOR_INFO_IS_STATIC)) {
-                spin_lock_irqsave (&dasd_major_lock, flags);
-		list_del(&major_info->list);
+
+	kfree (major_info->gendisk.flags);
+	kfree (major_info->gendisk.de_arr);
+
+	/* Delete the new major info from dasd_major_info if needed */
+	if (!(major_info->flags & DASD_MAJOR_INFO_IS_STATIC)) {
+		spin_lock_irqsave (&dasd_major_lock, flags);
+		list_del (&major_info->list);
 		spin_unlock_irqrestore (&dasd_major_lock, flags);
 		kfree (major_info);
-        }
+	}
 	return rc;
 }
 
-/* 
+/*
  * function: dasd_device_from_kdev
  * finds the device structure corresponding to the kdev supplied as argument
  * in the major_info structures and returns it or NULL when not found
@@ -688,9 +847,9 @@
 	unsigned long flags;
 
 	spin_lock_irqsave (&dasd_major_lock, flags);
-	list_for_each(l,&dasd_major_info[0].list) {
-		major_info = list_entry(l,major_info_t,list);
-		if ( major_info->gendisk.major == MAJOR(kdev) )
+	list_for_each (l, &dasd_major_info[0].list) {
+		major_info = list_entry (l, major_info_t, list);
+		if (major_info->gendisk.major == MAJOR (kdev))
 			break;
 	}
 	spin_unlock_irqrestore (&dasd_major_lock, flags);
@@ -699,10 +858,10 @@
 	return NULL;
 }
 
-/* 
+/*
  * function: dasd_device_from_devno
- * finds the address of the device structure corresponding to the devno 
- * supplied as argument in the major_info structures and returns 
+ * finds the address of the device structure corresponding to the devno
+ * supplied as argument in the major_info structures and returns
  * it or NULL when not found
  */
 static inline dasd_device_t **
@@ -714,8 +873,8 @@
 	unsigned long flags;
 
 	spin_lock_irqsave (&dasd_major_lock, flags);
-	list_for_each(l,&dasd_major_info[0].list) {
-		major_info = list_entry(l,major_info_t,list);
+	list_for_each (l, &dasd_major_info[0].list) {
+		major_info = list_entry (l, major_info_t, list);
 		if (devindex < DASD_PER_MAJOR) {
 			spin_unlock_irqrestore (&dasd_major_lock, flags);
 			return &major_info->dasd_device[devindex];
@@ -726,70 +885,105 @@
 	return NULL;
 }
 
+/*
+ * function: dasd_features_from_devno
+ * finds the device range corresponding to the devno
+ * supplied as argument in the major_info structures and returns
+ * the features set for it
+ */
+
+static int
+dasd_features_from_devno (int devno)
+{
+	dasd_range_t *temp;
+	int devindex = 0;
+	unsigned long flags;
+	struct list_head *l;
+
+	spin_lock_irqsave (&range_lock, flags);
+	list_for_each (l, &dasd_range_head.list) {
+		temp = list_entry (l, dasd_range_t, list);
+		if (devno >= temp->from && devno <= temp->to) {
+			spin_unlock_irqrestore (&range_lock, flags);
+			return temp->features;
+		}
+		devindex += temp->to - temp->from + 1;
+	}
+	spin_unlock_irqrestore (&range_lock, flags);
+	return -ENODEV;
+}
+
+
+
 /* SECTION: managing dasd disciplines */
 
 /* anchor and spinlock for list of disciplines */
-static dasd_discipline_t *dasd_disciplines;
+static struct list_head dasd_disc_head = LIST_HEAD_INIT(dasd_disc_head);
 static spinlock_t discipline_lock = SPIN_LOCK_UNLOCKED;
 
-/* 
- * function dasd_discipline_enq 
+/*
+ * function dasd_discipline_enq
  * chains the discpline given as argument to the head of disiplines
  * head chaining policy is required to allow module disciplines to
  * be preferred against those, who are statically linked
  */
-void
+static inline void
 dasd_discipline_enq (dasd_discipline_t * d)
 {
-	spin_lock (&discipline_lock);
-	d->next = dasd_disciplines;
-	dasd_disciplines = d;
-	spin_unlock (&discipline_lock);
+    list_add(&d->list, &dasd_disc_head);
 }
 
-/* 
- * function dasd_discipline_deq 
+/*
+ * function dasd_discipline_deq
  * removes the discipline given as argument from the list of disciplines
  */
-int
+static inline void
 dasd_discipline_deq (dasd_discipline_t * d)
 {
-	int rc = 0;
-	spin_lock (&discipline_lock);
-	if (dasd_disciplines == d) {
-		dasd_disciplines = dasd_disciplines->next;
-	} else {
-		dasd_discipline_t *b;
-		b = dasd_disciplines;
-		while (b && b->next != d)
-			b = b->next;
-		if (b != NULL) {
-			b->next = b->next->next;
-		} else {
-			rc = -ENOENT;
-		}
-	}
-	spin_unlock (&discipline_lock);
-	return rc;
+        list_del(&d->list);
+}
+
+void
+dasd_discipline_add (dasd_discipline_t * d)
+{
+        unsigned long flags;
+        MOD_INC_USE_COUNT;
+	spin_lock_irqsave (&discipline_lock,flags);
+        dasd_discipline_enq (d);
+	spin_unlock_irqrestore (&discipline_lock,flags);
+        dasd_enable_ranges (&dasd_range_head, d, DASD_STATE_ONLINE);
+}
+
+void dasd_discipline_del (dasd_discipline_t * d)
+{
+        unsigned long flags;
+	spin_lock_irqsave (&discipline_lock,flags);
+        dasd_disable_ranges(&dasd_range_head, d, DASD_STATE_DEL, 1);
+        dasd_discipline_deq (d);
+	spin_unlock_irqrestore (&discipline_lock,flags);
+        MOD_DEC_USE_COUNT;
 }
 
 static inline dasd_discipline_t *
-dasd_find_discipline (dasd_device_t * device)
+dasd_find_disc (dasd_device_t * device, dasd_discipline_t *d)
 {
-	dasd_discipline_t *temp;
-	for (temp = dasd_disciplines; temp != NULL; temp = temp->next) {
-		if (temp->id_check)
-			if (temp->id_check (&device->devinfo)) {
-				continue;
-                        }
-		if (temp->check_characteristics) {
-			if (temp->check_characteristics (device)) {
-				continue;
-                        }
-		}
-		break;
-	}
-	return temp;
+        dasd_discipline_t *t;
+        struct list_head *l = d ? &d->list : dasd_disc_head.next;
+        do {
+                t = list_entry(l,dasd_discipline_t,list);
+                if ( ( t->id_check == NULL ||
+                       t->id_check (&device->devinfo) == 0 ) &&
+                     ( t->check_characteristics == NULL ||
+                       t->check_characteristics (device) == 0 ) )
+                        break;
+                l = l->next;
+                if ( d || 
+                     l == &dasd_disc_head ) {
+                        t = NULL;
+                        break;
+                }
+         } while ( 1 );
+	return t;
 }
 
 /* SECTION: profiling stuff */
@@ -813,9 +1007,9 @@
 }
 
 /*
- * function dasd_profile_add 
+ * function dasd_profile_add
  * adds the profiling information from the cqr given as argument to the
- * global and device specific profiling information 
+ * global and device specific profiling information
  */
 void
 dasd_profile_add (ccw_req_t * cqr)
@@ -840,8 +1034,10 @@
 		memset (&device->profile, 0, sizeof (dasd_profile_info_t));
 	};
 
-        dasd_global_profile.dasd_io_reqs++;
-        device->profile.dasd_io_reqs++;
+	dasd_global_profile.dasd_io_reqs++;
+	device->profile.dasd_io_reqs++;
+	dasd_global_profile.dasd_io_sects+=sectors;
+	device->profile.dasd_io_sects+=sectors;
 	dasd_profile_add_counter (sectors, dasd_io_secs, device);
 	dasd_profile_add_counter (tottime, dasd_io_times, device);
 	dasd_profile_add_counter (tottimeps, dasd_io_timps, device);
@@ -851,54 +1047,168 @@
 	dasd_profile_add_counter (endtime, dasd_io_time3, device);
 }
 
-/* SECTION: (de)queueing of requests to channel program queues */
 
-/* 
- * function dasd_chanq_enq 
- * appends the cqr given as argument to the queue
- * has to be called with the queue lock (namely the s390_irq_lock) acquired
+/* SECTION: All the gendisk stuff */
+
+
+/* SECTION: Managing wrappers for ccwcache */
+
+/*
+ * function dasd_alloc_request
+ * tries to return space for a channel program of length cplength with
+ * additional data of size datasize.
+ * If the ccwcache cannot fulfill the request it tries the emergeny requests
+ * before giving up finally
+ * FIXME: initialization of ccw_req_t should be done by function of ccwcache
  */
-static inline void
-dasd_chanq_enq (dasd_chanq_t * q, ccw_req_t * cqr)
+ccw_req_t *
+dasd_alloc_request (char *magic, int cplength, int datasize, dasd_device_t* device)
 {
-	if (q->head != NULL) {
-		q->tail->next = cqr;
-	} else
+	ccw_req_t *rv = NULL;
+	int i;
+	unsigned long flags;
+
+	if ((rv = ccw_alloc_request (magic, cplength, datasize)) != NULL) {
+		return rv;
+	}
+	if ((((sizeof (ccw_req_t) + 7) & -8) +
+	     cplength * sizeof (ccw1_t) + datasize) > PAGE_SIZE) {
+		BUG ();
+		}
+        if (device->lowmem_cqr==NULL) {
+                DASD_MESSAGE (KERN_WARNING, device, "Low memory! Using emergency request %p",device->lowmem_ccws);
+                device->lowmem_cqr=device->lowmem_ccws;
+                rv = device->lowmem_ccws;
+		memset (rv, 0, PAGE_SIZE);
+		strncpy ((char *) (&rv->magic), magic, 4);
+		ASCEBC ((char *) (&rv->magic), 4);
+		rv->cplength = cplength;
+		rv->datasize = datasize;
+		rv->data = (void *) ((long) rv + PAGE_SIZE - datasize);
+		rv->cpaddr = (ccw1_t *) ((long) rv + sizeof (ccw_req_t));
+        } else {
+                DASD_MESSAGE (KERN_WARNING, device,"Refusing emergency mem for request NULL, already in use at %p.",device->lowmem_ccws);
+	}
+	return rv;
+}
+
+/*
+ * function dasd_free_request
+ * returns a ccw_req_t to the appropriate cache or emergeny request line
+ */
+void
+dasd_free_request (ccw_req_t * request, dasd_device_t* device)
+{
+#ifdef CONFIG_ARCH_S390X
+    ccw1_t* ccw;
+    /* clear any idals used for chain */
+    ccw=request->cpaddr-1;
+    do {
+            ccw++;
+            if ((ccw->cda < (unsigned long) device->lowmem_idals) || (ccw->cda >= (unsigned long) device->lowmem_idals+PAGE_SIZE))
+                    clear_normalized_cda (ccw);
+            else {
+                    if (device->lowmem_idal_ptr != device->lowmem_idals)
+                            DASD_MESSAGE (KERN_WARNING, device, "Freeing emergency idals from request at %p.",request);
+                    device->lowmem_idal_ptr = device->lowmem_idals;
+                    device->lowmem_cqr=NULL;
+            }
+    } while ((ccw->flags & CCW_FLAG_CC) || (ccw->flags & CCW_FLAG_DC));
+#endif
+    if (request != device->lowmem_ccws) { /* compare to lowmem_ccws to protect usage of lowmem_cqr for IDAL only ! */
+		ccw_free_request (request);
+    } else {
+            DASD_MESSAGE (KERN_WARNING, device,  "Freeing emergency request at %p",request);
+            device->lowmem_cqr=NULL;
+	}
+}
+
+int
+dasd_set_normalized_cda ( ccw1_t * cp, unsigned long address, ccw_req_t* request, dasd_device_t* device )
+{
+#ifdef CONFIG_ARCH_S390X
+	int nridaws;
+        int count = cp->count;
+        
+        if (set_normalized_cda (cp, address)!=-ENOMEM) {
+            return 0;
+        }
+
+        if ((device->lowmem_cqr!=NULL) && (device->lowmem_cqr!=request)) {
+            DASD_MESSAGE (KERN_WARNING, device, "Refusing emergency idals for request %p, memory is already in use for request %p",request,device->lowmem_cqr);
+            return -ENOMEM;
+        }
+        device->lowmem_cqr=request;
+        if (device->lowmem_idal_ptr == device->lowmem_idals) {
+            DASD_MESSAGE (KERN_WARNING,device, "Low memory! Using emergency IDALs for request %p.\n",request);
+        }
+        nridaws = ((address & (IDA_BLOCK_SIZE-1)) + count + 
+		   (IDA_BLOCK_SIZE-1)) >> IDA_SIZE_LOG;
+	if ( device->lowmem_idal_ptr>=device->lowmem_idals + PAGE_SIZE ) {
+		/* Ouch! No Idals left for emergency request */
+		BUG();
+	}
+	cp->flags |= CCW_FLAG_IDA;
+	cp->cda = (__u32)(unsigned long)device->lowmem_idal_ptr;
+        do {
+		*((long*)device->lowmem_idal_ptr) = address;
+		address = (address & -(IDA_BLOCK_SIZE)) + (IDA_BLOCK_SIZE);
+		nridaws --;
+                device->lowmem_idal_ptr += sizeof(unsigned long);
+        } while ( nridaws > 0 );
+#else 
+        cp -> cda = address;
+#endif
+	return 0;
+}
+
+
+/* SECTION: (de)queueing of requests to channel program queues */
+
+/*
+ * function dasd_chanq_enq
+ * appends the cqr given as argument to the queue
+ * has to be called with the queue lock (namely the s390_irq_lock) acquired
+ */
+inline void
+dasd_chanq_enq (dasd_chanq_t * q, ccw_req_t * cqr)
+{
+	if (q->head != NULL) {
+		q->tail->next = cqr;
+	} else
 		q->head = cqr;
 	cqr->next = NULL;
 	q->tail = cqr;
 	check_then_set (&cqr->status, CQR_STATUS_FILLED, CQR_STATUS_QUEUED);
 }
 
-/* 
+/*
  * function dasd_chanq_enq_head
  * chains the cqr given as argument to the queue head
  * has to be called with the queue lock (namely the s390_irq_lock) acquired
  */
-static inline void
+inline void
 dasd_chanq_enq_head (dasd_chanq_t * q, ccw_req_t * cqr)
 {
 	cqr->next = q->head;
 	q->head = cqr;
 	if (q->tail == NULL)
 		q->tail = cqr;
-	check_then_set (&cqr->status,
-		       CQR_STATUS_FILLED,
-		       CQR_STATUS_QUEUED);
+	check_then_set (&cqr->status, CQR_STATUS_FILLED, CQR_STATUS_QUEUED);
 }
 
-/* 
+/*
  * function dasd_chanq_deq
  * dechains the cqr given as argument from the queue
  * has to be called with the queue lock (namely the s390_irq_lock) acquired
  */
-int
+inline void
 dasd_chanq_deq (dasd_chanq_t * q, ccw_req_t * cqr)
 {
 	ccw_req_t *prev;
 
 	if (cqr == NULL)
-                BUG ();
+		BUG ();
 
 	if (cqr == q->head) {
 		q->head = cqr->next;
@@ -910,138 +1220,82 @@
 		while (prev && prev->next != cqr)
 			prev = prev->next;
 		if (prev == NULL)
-			return -ENOENT;
+			return;
 		prev->next = cqr->next;
 		if (prev->next == NULL)
 			q->tail = prev;
 	}
 	cqr->next = NULL;
-	return 0;
 }
 
-/* SECTION: All the gendisk stuff */
+/* SECTION: Managing the device queues etc. */
 
-/* 
- * function dasd_partn_detect
- * calls the function in genhd, which is appropriate to setup a partitioned disk
+/*
+ * function dasd_start_IO
+ * attempts to start the IO and returns an appropriate return code
  */
-static void
-dasd_partn_detect (dasd_device_t * dev)
+int
+dasd_term_IO (ccw_req_t * cqr)
 {
-	major_info_t *major_info = dev->major_info;
-	struct gendisk *dd = &major_info->gendisk;
-	int minor = MINOR (dev->kdev);
-
-	register_disk (dd,
-		       MKDEV (dd->major, minor),
-		       1 << DASD_PARTN_BITS,
-		       &dasd_device_operations,
-		       (dev->sizes.blocks << dev->sizes.s2b_shift));
-}
-
-/* SECTION: Managing wrappers for ccwcache */
-
-/* array and spinlock of emergency requests */
-static ccw_req_t *dasd_emergency_req[DASD_EMERGENCY_REQUESTS];
-static spinlock_t dasd_emergency_req_lock = SPIN_LOCK_UNLOCKED;
+	int rc = 0;
+	dasd_device_t *device = cqr->device;
+	int irq;
+        int retries = 0;
 
-/* 
- * function dasd_init_emergeny_req
- * allocates emergeny requests
- */
-static inline void __init
-dasd_init_emergency_req (void)
-{
-	int i;
-	for (i = 0; i < DASD_EMERGENCY_REQUESTS; i++) {
-		dasd_emergency_req[i] = (ccw_req_t *) get_free_page (GFP_KERNEL);
-		memset (dasd_emergency_req[i], 0, PAGE_SIZE);
+	if (!cqr) {
+		BUG ();
 	}
-}
-
-/* 
- * function dasd_cleanup_emergeny_req
- * tries to free emergeny requests skipping those, which are currently in use
- */
-static inline void
-dasd_cleanup_emergency_req (void)
-{
-	int i;
-	for (i = 0; i < DASD_EMERGENCY_REQUESTS; i++) {
-		if (dasd_emergency_req[i])
-			free_page ((long) (dasd_emergency_req[i]));
-		else
-			printk (KERN_WARNING PRINTK_HEADER
-				"losing page for emergency request in use\n");
+	irq = device->devinfo.irq;
+	if (strncmp ((char *) &cqr->magic, device->discipline->ebcname, 4)) {
+		DASD_MESSAGE (KERN_WARNING, device,
+			      " ccw_req_t 0x%08X magic doesn't match"
+			      " discipline 0x%08X\n",
+			      cqr->magic,
+			      *(unsigned int *) device->discipline->name);
+		return -EINVAL;
 	}
-}
-
-/* 
- * function dasd_alloc_request
- * tries to return space for a channel program of length cplength with
- * additional data of size datasize. 
- * If the ccwcache cannot fulfill the request it tries the emergeny requests
- * before giving up finally
- * FIXME: initialization of ccw_req_t should be done by function of ccwcache
- */
-ccw_req_t *
-dasd_alloc_request (char *magic, int cplength, int datasize)
-{
-	ccw_req_t *rv = NULL;
-	int i;
-	unsigned long flags;
 
-	if ((rv = ccw_alloc_request (magic, cplength, datasize)) != NULL) {
-		return rv;
-	}
-	if ((((sizeof (ccw_req_t) + 7) & -8) + 
-             cplength*sizeof(ccw1_t) + datasize) > PAGE_SIZE) {
-            BUG();
+        while ( retries < 5 ) {
+            if ( retries < 2 )
+                rc = halt_IO(irq, (long)cqr, 
+                             cqr->options | DOIO_WAIT_FOR_INTERRUPT);
+            else
+                rc = clear_IO(irq, (long)cqr, 
+                              cqr->options | DOIO_WAIT_FOR_INTERRUPT);
+            switch (rc) {
+            case 0:
+		break;
+            case -ENODEV:
+		DASD_MESSAGE (KERN_WARNING, device, "%s",
+			      "device gone, retry\n");
+		break;
+            case -EIO:
+		DASD_MESSAGE (KERN_WARNING, device, "%s",
+			      "I/O error, retry\n");
+		break;
+            case -EBUSY:
+		DASD_MESSAGE (KERN_WARNING, device, "%s",
+			      "device busy, retry later\n");
+		break;
+            default:
+		DASD_MESSAGE (KERN_ERR, device,
+			      "line %d unknown RC=%d, please report"
+			      " to linux390@de.ibm.com\n", __LINE__, rc);
+		BUG ();
+		break;
+            }
+            if (rc == 0) {
+		check_then_set (&cqr->status,
+				CQR_STATUS_IN_IO, CQR_STATUS_FAILED);
+                asm volatile ("STCK %0":"=m" (cqr->stopclk));
+                break;
+            }
+            retries ++;
         }
-	spin_lock_irqsave (&dasd_emergency_req_lock, flags);
-	for (i = 0; i < DASD_EMERGENCY_REQUESTS; i++) {
-		if (dasd_emergency_req[i] != NULL) {
-			rv = dasd_emergency_req[i];
-			dasd_emergency_req[i] = NULL;
-			break;
-		}
-	}
-	spin_unlock_irqrestore (&dasd_emergency_req_lock, flags);
-	if (rv) {
-		memset (rv, 0, PAGE_SIZE);
-		rv->cache = (kmem_cache_t *) (dasd_emergency_req + i);
-		strncpy ((char *) (&rv->magic), magic, 4);
-		ASCEBC ((char *) (&rv->magic), 4);
-		rv->cplength = cplength;
-		rv->datasize = datasize;
-		rv->data = (void *) ((long) rv + PAGE_SIZE - datasize);
-		rv->cpaddr = (ccw1_t *) ((long) rv + sizeof (ccw_req_t));
-	} else {
-		panic ("No way to fulfill request for I/O request\n");
-	}
-	return rv;
+	return rc;
 }
 
-/* 
- * function dasd_free_request
- * returns a ccw_req_t to the appropriate cache or emergeny request line
- */
-void
-dasd_free_request (ccw_req_t * request)
-{
-	if ((request->cache >= (kmem_cache_t *) dasd_emergency_req) &&
-	    (request->cache < (kmem_cache_t *) (dasd_emergency_req +
-						DASD_EMERGENCY_REQUESTS))) {
-		*((ccw_req_t **) (request->cache)) = request;
-	} else {
-		ccw_free_request (request);
-	}
-}			
-
-/* SECTION: Managing the device queues etc. */
-
-
-/* 
+/*
  * function dasd_start_IO
  * attempts to start the IO and returns an appropriate return code
  */
@@ -1051,7 +1305,7 @@
 	int rc = 0;
 	dasd_device_t *device = cqr->device;
 	int irq;
-        unsigned long long now;
+	unsigned long long now;
 
 	if (!cqr) {
 		BUG ();
@@ -1066,75 +1320,80 @@
 		return -EINVAL;
 	}
 
-        asm volatile ("STCK %0":"=m" (now));
-        rc = do_IO (irq, cqr->cpaddr, (long) cqr, cqr->lpm, cqr->options);
-        switch (rc) {
-        case 0:
-            break;
-        case -ENODEV:
-                check_then_set (&cqr->status, 
-                               CQR_STATUS_QUEUED, CQR_STATUS_FAILED);
-            break;
-        case -EIO:
-                check_then_set (&cqr->status, 
-                               CQR_STATUS_QUEUED, CQR_STATUS_FAILED);
-            break;
-        case -EBUSY:
-                DASD_MESSAGE (KERN_WARNING, device,"%s",
-                              "device busy, retry later\n");
-                break;
-        default:
-                DASD_MESSAGE (KERN_ERR, device,
-                              "line %d unknown RC=%d, please report"
-                              " to linux390@de.ibm.com\n",
-                              __LINE__, rc);
-                BUG();
-            break;
-        }
+	asm volatile ("STCK %0":"=m" (now));
+	rc = do_IO (irq, cqr->cpaddr, (long) cqr, cqr->lpm, cqr->options);
+	switch (rc) {
+	case 0:
+		break;
+	case -ENODEV:
+		check_then_set (&cqr->status,
+				CQR_STATUS_QUEUED, CQR_STATUS_FAILED);
+		break;
+	case -EIO:
+		check_then_set (&cqr->status,
+				CQR_STATUS_QUEUED, CQR_STATUS_FAILED);
+		break;
+	case -EBUSY:
+		DASD_MESSAGE (KERN_WARNING, device, "%s",
+			      "device busy, retry later\n");
+		break;
+	default:
+		DASD_MESSAGE (KERN_ERR, device,
+			      "line %d unknown RC=%d, please report"
+			      " to linux390@de.ibm.com\n", __LINE__, rc);
+		BUG ();
+		break;
+	}
 	if (rc == 0) {
-                check_then_set (&cqr->status, 
-                               CQR_STATUS_QUEUED, CQR_STATUS_IN_IO);
-                cqr->startclk = now;
+		check_then_set (&cqr->status,
+				CQR_STATUS_QUEUED, CQR_STATUS_IN_IO);
+		cqr->startclk = now;
 	}
 	return rc;
 }
 
-/* 
- * function sleep_on_req
+/*
+ * function dasd_sleep_on_req
  * attempts to start the IO and waits for completion
  * FIXME: replace handmade sleeping by wait_event
  */
-static int
-sleep_on_req (ccw_req_t * req)
+int
+dasd_sleep_on_req (ccw_req_t * req)
 {
 	unsigned long flags;
 	int cs;
 	int rc = 0;
 	dasd_device_t *device = (dasd_device_t *) req->device;
 
+        if ( signal_pending(current) ) {
+                return -ERESTARTSYS;
+        }
 	s390irq_spin_lock_irqsave (device->devinfo.irq, flags);
 	dasd_chanq_enq (&device->queue, req);
-        /* let the bh start the request to keep them in order */
-	dasd_schedule_bh (device); 
-        
+	/* let the bh start the request to keep them in order */
+	dasd_schedule_bh (device);
 	do {
 		s390irq_spin_unlock_irqrestore (device->devinfo.irq, flags);
-                wait_event (device->wait_q,
-                            (((cs=req->status)==CQR_STATUS_DONE)||
-                            (cs==CQR_STATUS_FAILED)));
+		wait_event ( device->wait_q,
+			     (((cs = req->status) == CQR_STATUS_DONE) ||
+			     (cs == CQR_STATUS_FAILED) ||
+                             signal_pending(current)));
 		s390irq_spin_lock_irqsave (device->devinfo.irq, flags);
-		cs = req->status;
+                if ( signal_pending(current) ) {
+                        rc = -ERESTARTSYS;
+		     	if (req->status == CQR_STATUS_IN_IO ) 
+                        	device->discipline->term_IO(req);
+                        break;
+                } else if ( req->status == CQR_STATUS_FAILED) {
+                        rc = -EIO;
+                        break;
+                }
 	} while (cs != CQR_STATUS_DONE && cs != CQR_STATUS_FAILED);
-
 	s390irq_spin_unlock_irqrestore (device->devinfo.irq, flags);
-	if (cs == CQR_STATUS_FAILED) {
-		rc = -EIO;
-	}
 	return rc;
+}				/* end dasd_sleep_on_req */
 
-}				/* end sleep_on_req */
-
-/* 
+/*
  * function dasd_end_request
  * posts the buffer_cache about a finalized request
  * FIXME: for requests splitted to serveral cqrs
@@ -1142,7 +1401,8 @@
 static inline void
 dasd_end_request (struct request *req, int uptodate)
 {
-	while (end_that_request_first (req, uptodate, DASD_NAME)) {}
+	while (end_that_request_first (req, uptodate, DASD_NAME)) {
+	}
 #ifndef DEVICE_NO_RANDOM
 	add_blkdev_randomness (MAJOR (req->rq_dev));
 #endif
@@ -1150,7 +1410,7 @@
 	return;
 }
 
-/* 
+/*
  * function dasd_get_queue
  * returns the queue corresponding to a device behind a kdev
  */
@@ -1158,10 +1418,10 @@
 dasd_get_queue (kdev_t kdev)
 {
 	dasd_device_t *device = dasd_device_from_kdev (kdev);
-	return &device->request_queue;
+	return device->request_queue;
 }
 
-/* 
+/*
  * function dasd_check_expire_time
  * check the request given as argument for expiration
  * and returns 0 if not yet expired, nonzero else
@@ -1173,18 +1433,17 @@
 	int rc = 0;
 
 	asm volatile ("STCK %0":"=m" (now));
-	if ( cqr->expires && 
-             cqr->expires + cqr->startclk <  now) {
-		DASD_MESSAGE (KERN_ERR, ((dasd_device_t*)cqr->device),
+	if (cqr->expires && cqr->expires + cqr->startclk < now) {
+		DASD_MESSAGE (KERN_ERR, ((dasd_device_t *) cqr->device),
 			      "IO timeout 0x%08lx%08lx usecs in req %p\n",
-			      (long) (cqr->expires >> 44), 
-                              (long) (cqr->expires >> 12), cqr);
-		cqr->expires <<=1;
+			      (long) (cqr->expires >> 44),
+			      (long) (cqr->expires >> 12), cqr);
+		cqr->expires <<= 1;
 	}
 	return rc;
 }
 
-/* 
+/*
  * function dasd_finalize_request
  * implemets the actions to perform, when a request is finally finished
  * namely in status CQR_STATUS_DONE || CQR_STATUS_FAILED
@@ -1192,190 +1451,226 @@
 static inline void
 dasd_finalize_request (ccw_req_t * cqr)
 {
-        dasd_device_t *device = cqr->device;
-        
+	dasd_device_t *device = cqr->device;
+
 	asm volatile ("STCK %0":"=m" (cqr->endclk));
 	if (cqr->req) {
-                dasd_end_request (cqr->req, (cqr->status == CQR_STATUS_DONE));
-                dasd_profile_add (cqr);
+		dasd_profile_add (cqr);
+		dasd_end_request (cqr->req, (cqr->status == CQR_STATUS_DONE));
 		/* free request if nobody is waiting on it */
-		dasd_free_request (cqr);
+		dasd_free_request (cqr, cqr->device);
 	} else {
-		/* during format we don't have the request structure */
+                if ( cqr == device->init_cqr && /* bring late devices online */
+                     device->level <= DASD_STATE_ONLINE ) { 
+                        device->timer.function = dasd_enable_single_device; 
+                        device->timer.data     = (unsigned long) device;
+                        device->timer.expires  = jiffies;
+                        add_timer(&device->timer);
+                }
 		/* notify sleeping task about finished postprocessing */
 		wake_up (&device->wait_q);
+                
 	}
 	return;
 }
 
-/* 
+/*
  * function dasd_process_queues
  * transfers the requests on the queue given as argument to the chanq
  * if possible, the request ist started on a fastpath
  */
 static void
-dasd_process_queues (dasd_device_t *device)
+dasd_process_queues (dasd_device_t * device)
 {
-        unsigned long flags;
-        struct request *req;
-        request_queue_t * queue = &device->request_queue;
+	unsigned long flags;
+	struct request *req;
+	request_queue_t *queue = device->request_queue;
 	dasd_chanq_t *qp = &device->queue;
-        int irq = device -> devinfo.irq;
-        ccw_req_t *final_requests= NULL;
-        static int chanq_min_size = DASD_MIN_SIZE_FOR_QUEUE;
-        int chanq_max_size = DASD_CHANQ_MAX_SIZE;
-        ccw_req_t * cqr=NULL,*temp;
-        dasd_erp_postaction_fn_t erp_postaction;
-
-        s390irq_spin_lock_irqsave (irq, flags);
-        /* First we dechain the requests, processed with completed status */
-        while ( qp -> head && 
-                ((qp -> head -> status == CQR_STATUS_DONE) || 
-                 (qp -> head -> status == CQR_STATUS_FAILED) ||
-		 (qp -> head -> status == CQR_STATUS_ERROR) ) ) {
+	int irq = device->devinfo.irq;
+	ccw_req_t *final_requests = NULL;
+	static int chanq_min_size = DASD_MIN_SIZE_FOR_QUEUE;
+	int chanq_max_size = DASD_CHANQ_MAX_SIZE;
+	ccw_req_t *cqr = NULL, *temp;
+	dasd_erp_postaction_fn_t erp_postaction;
+
+
+	s390irq_spin_lock_irqsave (irq, flags);
+
+	/* First we dechain the requests, processed with completed status */
+	while (qp->head &&
+	       ((qp->head->status == CQR_STATUS_DONE  ) ||
+		(qp->head->status == CQR_STATUS_FAILED) ||
+		(qp->head->status == CQR_STATUS_ERROR )   )) {
+
 		dasd_erp_action_fn_t erp_action;
-		ccw_req_t *erp_cqr = NULL;
+		ccw_req_t            *erp_cqr = NULL;
+
 		/*  preprocess requests with CQR_STATUS_ERROR */
-		if (qp -> head -> status == CQR_STATUS_ERROR) {
-			if ((qp -> head -> dstat -> flag & DEVSTAT_HALT_FUNCTION) ||
-			    (qp->head->retries-- == 0 ) ||
-			    (device->discipline->erp_action==NULL) ||
-			    ((erp_action=device->discipline->erp_action(qp->head))==NULL)||
-			    ((erp_cqr = erp_action(qp->head))== NULL)) {
-				check_then_set (&qp->head->status,
+		if (qp->head->status == CQR_STATUS_ERROR) {
+
+                        qp->head->retries--; 
+
+			if (qp->head->dstat->flag & DEVSTAT_HALT_FUNCTION) {
+
+                                check_then_set (&qp->head->status,
                                                 CQR_STATUS_ERROR,
                                                 CQR_STATUS_FAILED);
-                                continue;
+
+                        } else if ((device->discipline->erp_action == NULL                          ) ||
+                                   ((erp_action = device->discipline->erp_action (qp->head)) == NULL)   ) {
+                                
+				erp_cqr = dasd_default_erp_action (qp->head);
+
+			} else { /* call discipline ERP action */
+
+                                erp_cqr = erp_action (qp->head);
+                        }
+                        continue;
+
+		} else if (qp->head->refers) {	/* we deal with a finished ERP */
+
+			if (qp->head->status == CQR_STATUS_DONE) {
+
+                                DASD_MESSAGE (KERN_DEBUG, device, "%s",
+                                              "ERP successful");
 			} else {
-                                if (erp_cqr != qp->head){
-                                        dasd_chanq_enq_head (qp, erp_cqr);
-                                }
-				/* chain of completed requests is now broken */
-				continue; 
+
+                                DASD_MESSAGE (KERN_ERR, device, "%s",
+                                              "ERP unsuccessful");
 			}
-		} else if ( qp -> head -> refers ) { /* we deal with an ERP */
-                        char *uptodatestr;
-                        if ( qp -> head -> status == CQR_STATUS_DONE) {
-                                uptodatestr = "ERP successful";
-                        } else {
-                                uptodatestr = "ERP unsuccessful";
-                        }
-                        
-                        if (device->discipline->erp_postaction == NULL ||
-                            ((erp_postaction = device->discipline->erp_postaction (qp->head)) == NULL)) {
-                                /* 
-                                                         * maybe we shoud set it to FAILED, 
-                                                         * because we are very paranoid ;) 
-                                                         */
-                                erp_postaction = default_erp_postaction;
+
+			if ((device->discipline->erp_postaction == NULL                              )||
+			    ((erp_postaction = device->discipline->erp_postaction (qp->head)) == NULL)  ) {
+
+                                dasd_default_erp_postaction (qp->head);
+
+			} else {  /* call ERP postaction of discipline */
+
+                                erp_postaction (qp->head);
                         }
-                        DASD_MESSAGE (KERN_INFO, device,
-                                      "%s: postaction [<%p>]\n",
-                                      uptodatestr, erp_postaction);
-                        erp_postaction (qp->head);
-                        continue;
-                }
-                
+
+			continue;
+		}
+
 		/* dechain request now */
-                if ( final_requests == NULL )
-                        final_requests = qp -> head;
-                cqr = qp -> head;
-                qp -> head = qp -> head -> next;
+		if (final_requests == NULL)
+			final_requests = qp->head;
+
+		cqr      = qp->head;
+		qp->head = qp->head->next;
+
 		if (qp->head == NULL)
 			qp->tail = NULL;
-        }
-        if ( cqr )
-            cqr -> next = NULL;
-        /* Now we try to fetch requests from the request queue */
-        for (temp = cqr; temp != NULL ;temp=temp-> next )
-                if ( temp ->status == CQR_STATUS_QUEUED)
-                        chanq_max_size --;
-	while ( (! queue->plugged) &&
-		(! list_empty(&queue->queue_head)) && 
-                (req=dasd_next_request(queue)) != NULL) {
-                /* queue empty or certain critera fulfilled -> transfer */
-                if ( qp -> head == NULL ||
-                     chanq_max_size > 0 ||
-                     (req->nr_sectors >= chanq_min_size)) {
-                        ccw_req_t *cqr;
-                        /* relocate request according to partition table */
-                        req->sector += device->major_info->gendisk.part[MINOR (req->rq_dev)].start_sect;
-                        cqr = device->discipline->build_cp_from_req (device, req);
-                        if (cqr == NULL) {
-                                DASD_MESSAGE (KERN_WARNING, device,
-                                              "CCW creation failed on request %p\n", req);
-				/* revert relocation of request */
-                                req->sector -= device->major_info->gendisk.part[MINOR (req->rq_dev)].start_sect;
-                                break; /* terminate request queue loop */
-                                
-                        } 
+
+	} /* end while over completed requests */
+
+	if (cqr)
+		cqr->next = NULL;
+	/* Now clean the requests with final status */
+	while (final_requests) { 
+		temp = final_requests;
+		final_requests = temp->next;
+		dasd_finalize_request (temp);
+	}
+	/* Now we try to fetch requests from the request queue */
+	for (temp = cqr; temp != NULL; temp = temp->next)
+		if (temp->status == CQR_STATUS_QUEUED)
+			chanq_max_size--;
+	while ((atomic_read(&device->plugged) == 0) &&
+               (!queue->plugged) &&
+	       (!list_empty (&queue->queue_head)) &&
+	       (req = dasd_next_request (queue)) != NULL) {
+		/* queue empty or certain critera fulfilled -> transfer */
+		if (qp->head == NULL ||
+		    chanq_max_size > 0 || (req->nr_sectors >= chanq_min_size)) {
+			ccw_req_t *cqr = NULL;
+                        if (is_read_only(device->kdev) && req->cmd == WRITE) {
+                            DASD_MESSAGE (KERN_WARNING, device,
+                                          "rejecting write request %p\n",
+                                          req);
+                                dasd_end_request (req, 0);
+                                dasd_dequeue_request (queue,req);
+                        } else {
+                            /* relocate request according to partition table */
+                            req->sector +=
+                                device->major_info->gendisk.
+                                part[MINOR (req->rq_dev)].start_sect;
+                            cqr = device->discipline->build_cp_from_req (device, req);
+                            if (cqr == NULL) {
+				    DASD_MESSAGE (KERN_WARNING, device,
+                                                  "CCW creation failed on request %p\n",
+                                                  req);
+                                    /* revert relocation of request */
+                                    req->sector -=
+                                        device->major_info->gendisk.
+                                        part[MINOR (req->rq_dev)].start_sect;
+                                    break;	/* terminate request queue loop */
+                                    
+                            }
 #ifdef CONFIG_DYNAMIC_QUEUE_MIN_SIZE
-                        chanq_min_size = (chanq_min_size + req->nr_sectors)>>1; 
-#endif /* CONFIG_DYNAMIC_QUEUE_MIN_SIZE */
-                        dasd_dequeue_request(queue,req);
-			dasd_chanq_enq (qp, cqr);
-                } else { /* queue not empty OR criteria not met */
-                        break; /* terminate request queue loop */
-                }
-        }
-        /* we process the requests with non-final status */
-        if ( qp -> head ) {
-                switch ( qp->head->status ) {
-                case CQR_STATUS_QUEUED:
-                        /* try to start the first I/O that can be started */
-                        if ( device->discipline->start_IO (qp->head) != 0) 
-                                BUG();
-                        break;
-                case CQR_STATUS_IN_IO:
-                        /* Check, if to invoke the missing interrupt handler */
-                        if ( dasd_check_expire_time (qp->head) ) {
-                                /* to be filled with MIH */
+                            chanq_min_size =
+                                (chanq_min_size + req->nr_sectors) >> 1;
+#endif				/* CONFIG_DYNAMIC_QUEUE_MIN_SIZE */
+                            dasd_dequeue_request (queue, req);
+                            dasd_chanq_enq (qp, cqr);
                         }
-                        break;
+		} else {	/* queue not empty OR criteria not met */
+			break;	/* terminate request queue loop */
+		}
+	}
+	/* we process the requests with non-final status */
+	if (qp->head) {
+		switch (qp->head->status) {
+		case CQR_STATUS_QUEUED:
+			/* try to start the first I/O that can be started */
+			if (device->discipline->start_IO == NULL)
+				BUG ();
+                        device->discipline->start_IO(qp->head);
+			break;
+		case CQR_STATUS_IN_IO:
+			/* Check, if to invoke the missing interrupt handler */
+			if (dasd_check_expire_time (qp->head)) {
+				/* to be filled with MIH */
+			}
+			break;
 
-                case CQR_STATUS_PENDING:
-                        /* just wait */
-                        break;
-                default: 
-                        BUG();
-                }
-        }
-        /* Now clean the requests with final status */
-        while ( final_requests ) {
-                cqr = final_requests;
-                final_requests = cqr-> next;
-                dasd_finalize_request( cqr );
-        }
-        s390irq_spin_unlock_irqrestore (irq, flags);
+		case CQR_STATUS_PENDING:
+			/* just wait */
+			break;
+		default:
+			BUG ();
+		}
+	}
+	s390irq_spin_unlock_irqrestore (irq, flags);
 }
 
-/* 
+/*
  * function dasd_run_bh
  * acquires the locks needed and then runs the bh
  */
 static void
-dasd_run_bh (dasd_device_t *device)
+dasd_run_bh (dasd_device_t * device)
 {
 	long flags;
 	spin_lock_irqsave (&io_request_lock, flags);
-	atomic_set(&device->bh_scheduled,0);
+	atomic_set (&device->bh_scheduled, 0);
 	dasd_process_queues (device);
 	spin_unlock_irqrestore (&io_request_lock, flags);
 }
 
-/* 
+/*
  * function dasd_schedule_bh
  * schedules the request_fn to run with next run_bh cycle
  */
 void
-dasd_schedule_bh (dasd_device_t *device)
+dasd_schedule_bh (dasd_device_t * device)
 {
 	/* Protect against rescheduling, when already running */
-        if (atomic_compare_and_swap(0,1,&device->bh_scheduled)) {
-                return;
-        }
+	if (atomic_compare_and_swap (0, 1, &device->bh_scheduled)) {
+		return;
+	}
 
-	INIT_LIST_HEAD(&device->bh_tq.list);
+	INIT_LIST_HEAD (&device->bh_tq.list);
 	device->bh_tq.sync = 0;
 	device->bh_tq.routine = (void *) (void *) dasd_run_bh;
 	device->bh_tq.data = device;
@@ -1385,46 +1680,24 @@
 	return;
 }
 
-/* 
+/*
  * function do_dasd_request
- * is called from ll_rw_blk.c and provides the caller of 
+ * is called from ll_rw_blk.c and provides the caller of
  * dasd_process_queues
  */
-#if (LINUX_VERSION_CODE > KERNEL_VERSION(2,3,98))
 static void
 do_dasd_request (request_queue_t * queue)
 {
-        dasd_device_t *device = (dasd_device_t *)
-                ((long)queue-(long)offsetof (dasd_device_t, request_queue));
+        dasd_device_t *device = (dasd_device_t *)queue->queuedata;
 	dasd_process_queues (device);
 }
-#else
-static void
-do_dasd_request (void)
-{
-	major_info_t *major_info;
-	dasd_device_t *device;
-	int i;
-
-	for (major_info = dasd_major_info;
-	     major_info != NULL;
-	     major_info = major_info->next) {
-		for (i = 0; i < DASD_PER_MAJOR; i++) {
-			device = major_info->dasd_device[i];
-			if (!device)
-				continue;	/* remove indentation level */
-			dasd_process_queues (device);
-		}
-	}
-}
-#endif				/* LINUX_IS_24 */
 
 /*
- * DASD_HANDLE_STATE_CHANGE_PENDING 
+ * DASD_HANDLE_STATE_CHANGE_PENDING
  *
  * DESCRIPTION
  *   Handles the state change pending interrupt.
- *   Search for the device related request queue and check if the first 
+ *   Search for the device related request queue and check if the first
  *   cqr in queue in in status 'CQR_STATUE_PENDING'.
  *   If so the status is set to 'CQR_STATUS_QUEUED' to reactivate
  *   the device.
@@ -1432,43 +1705,42 @@
  *  PARAMETER
  *   stat               device status of state change pending interrupt.
  */
-void 
-dasd_handle_state_change_pending (devstat_t *stat)
+void
+dasd_handle_state_change_pending (devstat_t * stat)
 {
-        dasd_device_t **device_addr;
-        ccw_req_t     *cqr;
+	dasd_device_t **device_addr;
+	ccw_req_t *cqr;
 
 	device_addr = dasd_device_from_devno (stat->devno);
 
-        if (device_addr == NULL) {
-		printk (KERN_INFO PRINTK_HEADER
-                        "unable to find device for state change pending "
-                        "interrupt: devno%04X\n",
-                        stat->devno);
-        } else {
-                /* re-activate first request in queue */
-                cqr = (*device_addr)->queue.head;
+	if (device_addr == NULL) {
 
-                if (cqr->status == CQR_STATUS_PENDING) {
+		printk (KERN_DEBUG PRINTK_HEADER
+			"unable to find device for state change pending "
+			"interrupt: devno%04X\n", stat->devno);
+	} else {
+		/* re-activate first request in queue */
+		cqr = (*device_addr)->queue.head;
 
-                        DASD_MESSAGE (KERN_INFO, (*device_addr),
-                                      "%s",
-                                      "device request queue restarted by "
-                                      "state change pending interrupt\n");
+		if (cqr->status == CQR_STATUS_PENDING) {
 
-                        del_timer(&(*device_addr)->timer);
+			DASD_MESSAGE (KERN_DEBUG, (*device_addr),
+				      "%s",
+				      "device request queue restarted by "
+				      "state change pending interrupt\n");
 
-                        check_then_set(&cqr->status, 
-                                       CQR_STATUS_PENDING, 
-                                       CQR_STATUS_QUEUED);
+			del_timer (&(*device_addr)->timer);
 
-                        dasd_schedule_bh(*device_addr);
+			check_then_set (&cqr->status,
+					CQR_STATUS_PENDING, CQR_STATUS_QUEUED);
 
-                }
-        }
-} /* end dasd_handle_state_change_pending */
+			dasd_schedule_bh (*device_addr);
 
-/* 
+		}
+	}
+}				/* end dasd_handle_state_change_pending */
+
+/*
  * function dasd_int_handler
  * is the DASD driver's default interrupt handler for SSCH-IO
  */
@@ -1476,16 +1748,14 @@
 dasd_int_handler (int irq, void *ds, struct pt_regs *regs)
 {
 	int ip;
-        int devno;
 	ccw_req_t *cqr;
 	dasd_device_t *device;
         unsigned long long now;
-#ifdef ERP_DEBUG
-	static int counter = 0;
-#endif
 	dasd_era_t era = dasd_era_none; /* default is everything is okay */
 	devstat_t *stat = (devstat_t *)ds;
 
+        DASD_DRIVER_DEBUG_EVENT (4, dasd_int_handler,
+                                 "Interrupt: IRQ 0x%x",irq);
         asm volatile ("STCK %0":"=m" (now));
         if (stat == NULL) {
                 BUG();
@@ -1495,145 +1765,148 @@
         if (stat->dstat & (DEV_STAT_ATTENTION | 
                            DEV_STAT_DEV_END   |
                            DEV_STAT_UNIT_EXCEP )) {
-
+                DASD_DRIVER_DEBUG_EVENT (2, dasd_int_handler,
+                                         "State change Interrupt: %04X",
+                                         stat->devno);
                 dasd_handle_state_change_pending (stat);
                 //return; /* TBD */
         }
 
 	ip = stat->intparm;
 	if (!ip) {		/* no intparm: unsolicited interrupt */
-		printk (KERN_INFO PRINTK_HEADER
+                DASD_DRIVER_DEBUG_EVENT (2, dasd_int_handler,
+                                         "Unsolicited Interrupt: %04X",
+                                         stat->devno);
+		printk (KERN_DEBUG PRINTK_HEADER
                         "unsolicited interrupt: irq0x%x devno%04X\n",
                         irq,stat->devno);
 		return;
 	}
 	if (ip & 0x80000001) {
-		printk (KERN_INFO PRINTK_HEADER
+                DASD_DRIVER_DEBUG_EVENT (2, dasd_int_handler,
+                                         "spurious Interrupt: %04X",
+                                         stat->devno);
+		printk (KERN_DEBUG PRINTK_HEADER
                         "spurious interrupt: irq0x%x devno%04X, parm %08x\n",
                         irq,stat->devno,ip);
 		return;
 	}
 	cqr = (ccw_req_t *)(long)ip;
 	device = (dasd_device_t *) cqr->device;
-	if (device == NULL || device != ds-offsetof(dasd_device_t,dev_status)) {
+	if (device == NULL || 
+            device != ds-offsetof(dasd_device_t,dev_status)) {
                 BUG();
 	}
-	devno = device->devinfo.devno;
 	if (device->devinfo.irq != irq) {
                 BUG();
 	}
 	if (strncmp (device->discipline->ebcname, (char *) &cqr->magic, 4)) {
                 BUG();
 	}
-#ifdef ERP_DEBUG
-                if ((++counter % 937 >= 0) &&
-                    (  counter % 937 <= 10) &&
-                    (  counter < 5000    ) &&
-                    (  counter > 2000    )   ){
-                        static int fake_count = 0;
-                        printk ( KERN_INFO PRINTK_HEADER "***********************************************\n");
-                        printk ( KERN_INFO PRINTK_HEADER "Faking I/O error to recover from; cntr=%i / %02X\n",counter,++fake_count);
-                        printk ( KERN_INFO PRINTK_HEADER "***********************************************\n");
+#ifdef ERP_FAKE
+        {
+                static int counter    = 0;
+                static int fake_count = 0;
+
+                if ((++counter % 937 >=   0) &&
+                    (  counter % 937 <=  10) && 
+                    (  counter       < 5000) && 
+                    (  counter       > 2000)   ) {
+
+                        char *sense = stat->ii.sense.data;
+                        
+                        printk (KERN_INFO PRINTK_HEADER
+                                "***********************************************\n");
+                        printk (KERN_INFO PRINTK_HEADER
+                                "Faking I/O error to recover from; cntr=%i / %02X\n",
+                                counter, ++fake_count);
+                        printk (KERN_INFO PRINTK_HEADER
+                                "***********************************************\n");
+
                         era = dasd_era_recover;
-                        stat->flag |= DEVSTAT_FLAG_SENSE_AVAIL;
+                        stat->flag  |= DEVSTAT_FLAG_SENSE_AVAIL;
                         stat->dstat |= 0x02;
-// sense 32
-                        {
-                                char *sense = stat->ii.sense.data;
-                                sense [25] = 0x1D;
-                                sense [27] = 0x00;
-                                //sense [25] = (fake_count % 256); //0x1B;
-                                //sense [27] = 0x00;
-                        }
-// sense 24
-//                        {
-//                                char *sense = stat->ii.sense.data;
-//                                sense [0] = (counter % 0xFF); //0x1B;
-//                                sense [1] = ((counter * 7) % 0xFF); //0x1B;
-//                                sense [2] = (fake_count % 0xFF); //0x1B;
-//                                sense [27] = 0x80;
-//                        }
-
-/*
-                memset(stat->ii.sense.data,0,32);
-                stat->ii.sense.data[2] = 0x06;
-                stat->ii.sense.data[4] = 0x04;
-                stat->ii.sense.data[5] = 0x60;
-                stat->ii.sense.data[6] = 0x41;
-                stat->ii.sense.data[8] = 0xff;
-                stat->ii.sense.data[9] = 0xff;
-                stat->ii.sense.data[15] = 0x05;
-                stat->ii.sense.data[16] = 0x21;
-                stat->ii.sense.data[18] = 0x60;
-                stat->ii.sense.data[19] = 0x3b;
-                stat->ii.sense.data[20] = 0x24;
-                stat->ii.sense.data[21] = 0x61;
-                stat->ii.sense.data[22] = 0x65;
-                stat->ii.sense.data[23] = 0x03;
-                stat->ii.sense.data[24] = 0x04;
-                stat->ii.sense.data[25] = 0x10;
-                stat->ii.sense.data[26] = 0x4e;
-*/
-        }
-#endif
-        /* first of all lets try to find out the appropriate era_action */
-        if ( stat->flag & DEVSTAT_FLAG_SENSE_AVAIL ||
-             stat->dstat & ~(DEV_STAT_CHN_END | DEV_STAT_DEV_END) ) {
-                /* anything abnormal ? */
-                if ( device->discipline->examine_error == NULL ||
-                     stat->flag & DEVSTAT_HALT_FUNCTION ) {
-                        era = dasd_era_fatal;
-                } else {
-                        era = device->discipline->examine_error (cqr, stat);
+                        memset(sense,0,32);
+
+                        /* 32 byte sense (byte 27 bit 1 = 0)*/
+                        sense[25] = 0x1D;
+//                        sense [25] = (fake_count % 256); //0x1B;
+
+                        /* 24 byte sense (byte 27 bit 1 = 1)*/
+//                        sense [0] = (counter % 0xFF); //0x1B;
+//                        sense [1] = ((counter * 7) % 0xFF); //0x1B;
+//                        sense [2] = (fake_count % 0xFF); //0x1B;
+//                        sense [27] = 0x80;
                 }
         }
+#endif /* ERP_FAKE */
+        /* first of all lets try to find out the appropriate era_action */
+        DASD_DEVICE_DEBUG_EVENT (4, device," Int: CS/DS 0x%04X",
+                                 ((stat->cstat<<8)|stat->dstat));
+	/* first of all lets try to find out the appropriate era_action */
+	if (stat->flag & DEVSTAT_FLAG_SENSE_AVAIL ||
+	    stat->dstat & ~(DEV_STAT_CHN_END | DEV_STAT_DEV_END)) {
+		/* anything abnormal ? */
+		if (device->discipline->examine_error == NULL ||
+		    stat->flag & DEVSTAT_HALT_FUNCTION) {
+			era = dasd_era_fatal;
+		} else {
+			era = device->discipline->examine_error (cqr, stat);
+		}
+                DASD_DRIVER_DEBUG_EVENT (1, dasd_int_handler," era_code %d",
+                                         era);
+	}
         if ( era == dasd_era_none ) {
-		if (device->level == DASD_DEVICE_LEVEL_ANALYSIS_PENDING)
-			device->level = DASD_DEVICE_LEVEL_ANALYSIS_PREPARED;
                 check_then_set(&cqr->status, 
                                CQR_STATUS_IN_IO, CQR_STATUS_DONE);
                 cqr->stopclk=now;
-                cqr=cqr->next;
 		/* start the next queued request if possible -> fast_io */
-                if (cqr->status == CQR_STATUS_QUEUED) {
-                        if (device->discipline->start_IO (cqr) != 0) {
+                if (cqr->next &&
+                    cqr->next->status == CQR_STATUS_QUEUED) {
+                        if (device->discipline->start_IO (cqr->next) != 0) {
                                 printk (KERN_WARNING PRINTK_HEADER
                                         "Interrupt fastpath failed!\n");
                         } 
                 }
         } else { /* error */
-                if (cqr->dstat == NULL)
-                        cqr->dstat = kmalloc (sizeof (devstat_t), GFP_ATOMIC);
-                if (cqr->dstat) {
-                        memcpy (cqr->dstat, stat, sizeof (devstat_t));
-                } else {
-                        PRINT_ERR ("no memory for dstat...ignoring\n");
-                }
-                /* dump sense data */
-                if (device->discipline &&
-                    device->discipline->dump_sense) {
-                        char *errmsg = device->discipline->dump_sense (device, cqr);
-                        if (errmsg != NULL) {
-                                printk ("Sense data:\n%s", errmsg);
-                                free_page ((unsigned long) errmsg);
-                        } else {
-                                printk (KERN_WARNING PRINTK_HEADER
-                                        "No memory to dump error message\n");
-                        }
-                }
-                switch(era) {
-                case dasd_era_fatal:
-                        check_then_set (&cqr->status,CQR_STATUS_IN_IO,
-                                        CQR_STATUS_FAILED);
-                        break;
-                case dasd_era_recover:
-                        check_then_set (&cqr->status,CQR_STATUS_IN_IO,
-                                        CQR_STATUS_ERROR);
-                        break;
-                default:
-                        BUG();
-                }
-        }                
+		if (cqr->dstat == NULL)
+			cqr->dstat = kmalloc (sizeof (devstat_t), GFP_ATOMIC);
+		if (cqr->dstat) {
+			memcpy (cqr->dstat, stat, sizeof (devstat_t));
+		} else {
+			PRINT_ERR ("no memory for dstat...ignoring\n");
+		}
+
+#ifdef ERP_DEBUG
+		/* dump sense data */
+		if (device->discipline            && 
+                    device->discipline->dump_sense  ) {
+
+                        device->discipline->dump_sense (device, 
+                                                        cqr);
+		}
+#endif
+
+		switch (era) {
+		case dasd_era_fatal:
+			check_then_set (&cqr->status, CQR_STATUS_IN_IO,
+					CQR_STATUS_FAILED);
+			break;
+		case dasd_era_recover:
+			check_then_set (&cqr->status, CQR_STATUS_IN_IO,
+					CQR_STATUS_ERROR);
+			break;
+		default:
+			BUG ();
+		}
+	}
+        if ( cqr == device->init_cqr &&
+             ( cqr->status == CQR_STATUS_DONE ||
+               cqr->status == CQR_STATUS_FAILED )){
+                dasd_state_init_to_ready(device);
+                if ( atomic_read(&dasd_init_pending) == 0)
+                        wake_up (&dasd_init_waitq);
+        }
 	dasd_schedule_bh (device);
 }
 
@@ -1653,26 +1926,39 @@
  *   erp                CQR performing the ERP
  */
 ccw_req_t *
-default_erp_action (ccw_req_t * cqr)
+dasd_default_erp_action (ccw_req_t * cqr)
 {
-	ccw_req_t *erp = dasd_alloc_request ((char *) &cqr->magic, 1, 0);
 
-	printk (KERN_WARNING PRINTK_HEADER
-		"Default ERP called... \n");
+        dasd_device_t *device = cqr->device;
+	ccw_req_t     *erp    = dasd_alloc_request ((char *) &cqr->magic, 1, 0, cqr->device);
+
+	printk (KERN_DEBUG PRINTK_HEADER "Default ERP called... \n");
+
+	if (!erp) {
+
+                DASD_MESSAGE (KERN_ERR, device, "%s",
+                              "Unable to allocate ERP request");
+                
+                check_then_set (&cqr->status,
+                                CQR_STATUS_ERROR,
+                                CQR_STATUS_FAILED);
 
-        if (erp == NULL)
-               return NULL;
+                return cqr;
+	}
 
 	erp->cpaddr->cmd_code = CCW_CMD_TIC;
-	erp->cpaddr->cda = (__u32)(void *)cqr->cpaddr;
-	erp->function = default_erp_action;
-	erp->refers = cqr;
+	erp->cpaddr->cda = (__u32) (void *) cqr->cpaddr;
+	erp->function = dasd_default_erp_action;
+	erp->refers = (unsigned int) (unsigned long) cqr;
 	erp->device = cqr->device;
 	erp->magic = cqr->magic;
 	erp->retries = 16;
 
 	erp->status = CQR_STATUS_FILLED;
 
+        dasd_chanq_enq_head (&device->queue,
+                             erp);
+
 	return erp;
 }
 
@@ -1683,6 +1969,8 @@
  *   Frees all ERPs of the current ERP Chain and set the status
  *   of the original CQR either to CQR_STATUS_DONE if ERP was successful
  *   or to CQR_STATUS_FAILED if ERP was NOT successful.
+ *   NOTE: This function is only called if no discipline postaction
+ *         is available
  *
  * PARAMETER
  *   erp                current erp_head
@@ -1691,96 +1979,63 @@
  *   cqr                pointer to the original CQR
  */
 ccw_req_t *
-default_erp_postaction (ccw_req_t * erp)
+dasd_default_erp_postaction (ccw_req_t *erp)
 {
-	ccw_req_t *cqr = NULL, *free_erp = NULL;
-	dasd_device_t *device = NULL;
-        int success;
-        
-	device = (dasd_device_t *) (erp->device);
+
+	ccw_req_t     *cqr      = NULL, 
+                      *free_erp = NULL;
+	dasd_device_t *device   = erp->device;
+	int           success;
+
+	if (erp->refers   == NULL || 
+            erp->function == NULL   ) {
+
+		BUG ();
+	}
 
 	if (erp->status == CQR_STATUS_DONE)
 		success = 1;
 	else
 		success = 0;
 
-#ifdef ERP_DEBUG
-
-	/* print current erp_chain */
-        printk (KERN_WARNING PRINTK_HEADER
-                "default ERP postaction called for erp chain:\n");
-        {
-                ccw_req_t *temp_erp = NULL;
-                for (temp_erp = erp; temp_erp != NULL; temp_erp = temp_erp->refers){
-                        printk(KERN_WARNING PRINTK_HEADER 
-                               "       erp %p refers to %p with erp function %p\n",
-                               temp_erp,
-                               temp_erp->refers,
-                               temp_erp->function );
-                }
-        }
-
-#endif /* ERP_DEBUG*/
-
-	if (erp->refers == NULL || erp->function == NULL) {
-                BUG();
-	}
-	if (erp->function != default_erp_action) {
-                printk (KERN_WARNING PRINTK_HEADER
-                        "default ERP postaction called ERP action [<%p>]\n",
-                        erp->function);
-	}
 	/* free all ERPs - but NOT the original cqr */
-        
 	while (erp->refers != NULL) {
-                free_erp = erp;
-		erp = erp->refers;
+
+		free_erp = erp;
+		erp      = erp->refers;
+
 		/* remove the request from the device queue */
-		dasd_chanq_deq (&device->queue,	free_erp);
+		dasd_chanq_deq (&device->queue,
+                                free_erp);
+
 		/* free the finished erp request */
-		dasd_free_request (free_erp);
+		dasd_free_request (free_erp, free_erp->device);
 	}
-        
+
 	/* save ptr to original cqr */
 	cqr = erp;
 
-#ifdef ERP_DEBUG
-	printk (KERN_INFO PRINTK_HEADER
-		"default_erp_postaction - left original request = %p \n",cqr);
-#endif /* ERP_DEBUG */
-
 	/* set corresponding status to original cqr */
 	if (success) {
+
 		check_then_set (&cqr->status, 
-                                CQR_STATUS_ERROR, 
-                                CQR_STATUS_DONE);
+                                CQR_STATUS_ERROR,
+				CQR_STATUS_DONE);
 	} else {
+
 		check_then_set (&cqr->status,
-                                CQR_STATUS_ERROR,
+				CQR_STATUS_ERROR, 
                                 CQR_STATUS_FAILED);
 	}
 
-#ifdef ERP_DEBUG
-	/* print current erp_chain */
-	printk (KERN_WARNING PRINTK_HEADER
-		"default ERP postaction finished with remaining chain:\n");
-	{
-		ccw_req_t *temp_erp = NULL;
-		for (temp_erp = cqr; temp_erp != NULL; temp_erp = temp_erp->refers) {
-			printk (KERN_WARNING PRINTK_HEADER
-				" erp %p refers to %p \n",
-				temp_erp, temp_erp->refers);
-		}
-	}
-#endif /* ERP_DEBUG */
-
 	return cqr;
-}				/* end default_erp_postaction */
+
+} /* end default_erp_postaction */
 
 /* SECTION: The helpers of the struct file_operations */
 
-/* 
- * function dasd_format 
+/*
+ * function dasd_format
  * performs formatting of _device_ according to _fdata_
  * Note: The discipline's format_function is assumed to deliver formatting
  * commands to format a single unit of the device. In terms of the ECKD
@@ -1791,196 +2046,114 @@
 dasd_format (dasd_device_t * device, format_data_t * fdata)
 {
 	int rc = 0;
-        int format_done = 0;
-	ccw_req_t *req = NULL;
-	format_data_t temp =
-	{
-		fdata->start_unit,
-		fdata->stop_unit,
-		fdata->blksize,
-		fdata->intensity
-	};
-        
-        spin_lock (&dasd_open_count_lock);
-	if (device->open_count != 1) {
-		DASD_MESSAGE (KERN_INFO, device,
-			      "device is already open %d times",
-			      device->open_count);
-                spin_unlock(&dasd_open_count_lock);
-		return -EINVAL;
-	}
-	if (!device->discipline->format_device) {
-                spin_unlock(&dasd_open_count_lock);
-		return -EINVAL;
-	}
-        device->open_count = -1;
-        spin_unlock (&dasd_open_count_lock);
-	/* downgrade state of the device */
-	dasd_set_device_level (device->devinfo.irq,
-			       DASD_DEVICE_LEVEL_RECOGNIZED,
-			       device->discipline,
-			       0);
-	DASD_MESSAGE (KERN_INFO, device, 
-                      "Starting format from %d to %d (%d B blocks flags %d",
-                      fdata->start_unit,
-                      fdata->stop_unit,
-                      fdata->blksize,
-                      fdata->intensity);
-	/* Invalidate first track */
-	if (fdata->start_unit == DASD_FORMAT_DEFAULT_START_UNIT &&
-	    fdata->stop_unit  == DASD_FORMAT_DEFAULT_STOP_UNIT  &&
-	    fdata->intensity  == DASD_FORMAT_DEFAULT_INTENSITY    ) {
-		format_data_t temp2 =
-		{0, 0, fdata->blksize, 0x04};
-		DASD_MESSAGE (KERN_INFO, device, 
-                              "%s", 
-                              "Invalidating first track...");
-		req = device->discipline->format_device (device, &temp2);
-		if (req) {
-			rc = sleep_on_req (req);
-			dasd_free_request (req);	/* request is no longer used */
-		} else {
-			rc = -EINVAL;
-		}
-		if (rc) {
-                        DASD_MESSAGE (KERN_WARNING, device, 
-                                      "%s",
-                                      "Can't invalidate Track 0\n");
-		} else {
-                        DASD_MESSAGE (KERN_INFO, device, 
-                                      "%s", 
-                                      "...Invalidation complete");
-                }
-		temp.start_unit++;
-	}
-	/* format remainnig tracks of device */
-	while (!rc                                                                 &&
-	       ((req = device->discipline->format_device (device, &temp)) != NULL)   ) {
-                                format_done=1;
-		if ((rc = sleep_on_req (req)) != 0) {
+	int openct = atomic_read (&device->open_count);
 
-
-			DASD_MESSAGE (KERN_WARNING, device,
-				      " Formatting failed with rc = %d\n",
-				      rc);
+	if (openct > 1) {
+		DASD_MESSAGE (KERN_WARNING, device, "%s",
+			      "dasd_format: device is open! expect errors.");
+	}
+	DASD_MESSAGE (KERN_INFO, device,
+		      "formatting units %d to %d (%d B blocks) flags %d",
+		      fdata->start_unit, fdata->stop_unit,
+		      fdata->blksize, fdata->intensity);
+	while ((!rc) && (fdata->start_unit <= fdata->stop_unit)) {
+                ccw_req_t *req;
+                dasd_format_fn_t ffn = device->discipline->format_device;
+		ffn = device->discipline->format_device;
+		if (ffn == NULL)
+			break;
+		req = ffn (device, fdata);
+		if (req == NULL) {
+			rc = -ENOMEM;
 			break;
 		}
-                
-		dasd_free_request (req);	/* request is no longer used */
-		temp.start_unit++;
+		if ((rc = dasd_sleep_on_req (req)) != 0) {
+			DASD_MESSAGE (KERN_WARNING, device,
+				      " Formatting of unit %d failed with rc = %d\n",
+				      fdata->start_unit, rc);
+			break;
+		} 
+		dasd_free_request (req, device);	/* request is no longer used */
+	        if ( signal_pending(current) )
+			break;		
+		fdata->start_unit++;
 	}
-
-	if (!rc         &&
-	    req == NULL   ) {
-		if (fdata->start_unit == DASD_FORMAT_DEFAULT_START_UNIT &&
-		    fdata->stop_unit  == DASD_FORMAT_DEFAULT_STOP_UNIT  &&
-	    	    fdata->intensity  == DASD_FORMAT_DEFAULT_INTENSITY    ) {
-			format_data_t temp2 =
-			{0, 0, fdata->blksize, fdata->intensity};
-			DASD_MESSAGE (KERN_INFO, device, 
-                                      "%s", 
-                                      "Revalidating first track...");
-			req = device->discipline->format_device (device, &temp2);
-			if (req) {
-				rc = sleep_on_req (req);
-				dasd_free_request (req);	/* request is no longer used */
-			} else {
-				rc = -EINVAL;
-			}
-			if (rc) {
-				DASD_MESSAGE (KERN_WARNING, device,
-                                              "%s",
-                                              "Can't revalidate Track 0\n");
-			} else {
-                                DASD_MESSAGE (KERN_INFO, device, 
-                                              "%s", 
-                                              "...Revalidation complete");
-                        }
-		}
-	}			/* end if no more requests */
-
-        /* check if at least one format cp was build in discipline */
-        if (!format_done) {
-                rc = -EINVAL;
-        }
-
-	if (rc)
-		DASD_MESSAGE (KERN_WARNING, device,
-			      "%s", " Formatting finished unsuccessfully");
-	else
-		DASD_MESSAGE (KERN_INFO, device,
-			      "%s", " Formatting finished successfully");
-
-        /* 
-         * re-analyse device
-         */
-        dasd_set_device_level (device->devinfo.irq,
-                               DASD_DEVICE_LEVEL_ONLINE,
-                               device->discipline,
-                               0);
-        udelay (1500000);
-                
-        dasd_set_device_level (device->devinfo.irq,
-                               DASD_DEVICE_LEVEL_ONLINE,
-                               device->discipline,
-                               0);
-
-        spin_lock (&dasd_open_count_lock);
-        device->open_count=1;
-        spin_unlock (&dasd_open_count_lock);
 	return rc;
 }				/* end dasd_format */
 
-static struct list_head dasd_ioctls = LIST_HEAD_INIT(dasd_ioctls);
+static struct list_head dasd_ioctls = LIST_HEAD_INIT (dasd_ioctls);
 
 static dasd_ioctl_list_t *
-dasd_find_ioctl( int no )
+dasd_find_ioctl (int no)
 {
 	struct list_head *curr;
-	list_for_each(curr,&dasd_ioctls){
-		if (list_entry(curr,dasd_ioctl_list_t,list)->no == no ){
-			return list_entry(curr,dasd_ioctl_list_t,list);
+	list_for_each (curr, &dasd_ioctls) {
+		if (list_entry (curr, dasd_ioctl_list_t, list)->no == no) {
+			return list_entry (curr, dasd_ioctl_list_t, list);
 		}
 	}
 	return NULL;
 }
 
 int
-dasd_ioctl_no_register ( int no, dasd_ioctl_fn_t handler )
+dasd_ioctl_no_register (struct module *owner, int no, dasd_ioctl_fn_t handler)
 {
 	dasd_ioctl_list_t *new;
-	if (dasd_find_ioctl(no))
+	if (dasd_find_ioctl (no))
 		return -EBUSY;
-	new = kmalloc(sizeof(dasd_ioctl_list_t),GFP_KERNEL);
- 	if ( new ==  NULL )
+	new = kmalloc (sizeof (dasd_ioctl_list_t), GFP_KERNEL);
+	if (new == NULL)
 		return -ENOMEM;
-	new -> no = no;
-	new -> handler = handler;
-	list_add(&new->list,&dasd_ioctls);
-#ifdef MODULE
-        MOD_INC_USE_COUNT;
-#endif
+	new->owner = owner;
+	new->no = no;
+	new->handler = handler;
+	list_add (&new->list, &dasd_ioctls);
+	MOD_INC_USE_COUNT;
 	return 0;
 }
 
 int
-dasd_ioctl_no_unregister ( int no, dasd_ioctl_fn_t handler )
-{	
-	dasd_ioctl_list_t *old = dasd_find_ioctl(no);
-	if ( old == NULL )
+dasd_ioctl_no_unregister (struct module *owner, int no, dasd_ioctl_fn_t handler)
+{
+	dasd_ioctl_list_t *old = dasd_find_ioctl (no);
+	if (old == NULL)
 		return -ENOENT;
-	if ( old->no != no ||
-	     old->handler != handler )
+	if (old->no != no || old->handler != handler || owner != old->owner )
 		return -EINVAL;
-	list_del(&old->list);
-	kfree(old);
-#ifdef MODULE
-        MOD_DEC_USE_COUNT;
-#endif
+	list_del (&old->list);
+	kfree (old);
+	MOD_DEC_USE_COUNT;
 	return 0;
 }
 
 static int
+dasd_revalidate (dasd_device_t * device)
+{
+        int rc = 0;
+	int i;
+	kdev_t kdev = device->kdev;
+	int openct = atomic_read (&device->open_count);
+	int start = MINOR (kdev);
+	if (openct != 1) {
+		DASD_MESSAGE (KERN_WARNING, device, "%s",
+			      "BLKRRPART: device is open! expect errors.");
+	}
+	for (i = (1 << DASD_PARTN_BITS) - 1; i >= 0; i--) {
+                int major = device->major_info->gendisk.major;
+		int minor = start + i;
+		kdev_t devi = MKDEV (major, minor);
+		struct super_block *sb = get_super (devi);
+		sync_dev (devi);
+		if (sb)
+			invalidate_inodes (sb);
+		invalidate_buffers (devi);
+	}
+        dasd_destroy_partitions(device);
+        dasd_setup_partitions(device);
+        return rc;
+
+}
+static int
 do_dasd_ioctl (struct inode *inp, /* unsigned */ int no, unsigned long data)
 {
 	int rc = 0;
@@ -2009,31 +2182,37 @@
 		_IOC_DIR (no) == (_IOC_READ | _IOC_WRITE) ? "rw" : "u",
 		_IOC_TYPE (no), _IOC_NR (no), _IOC_SIZE (no),
 		device->name, MAJOR (inp->i_rdev), MINOR (inp->i_rdev),
-		device->devinfo.devno, device->devinfo.irq,
-		data);
+		device->devinfo.devno, device->devinfo.irq, data);
 #endif
 	switch (no) {
+        case DASDAPIVER: {
+                       int ver = DASD_API_VERSION;
+                       rc = copy_to_user ((int *) data, &ver, sizeof (int));
+                       if (rc)
+                               rc = -EFAULT;
+                       break;
+        }
 	case BLKGETSIZE:{	/* Return device size */
-			long blocks = blk_size[MAJOR (inp->i_rdev)][MINOR (inp->i_rdev)] << 1;
-			rc = copy_to_user ((long *) data, &blocks, sizeof (long));
+			long blocks = major_info->gendisk.sizes 
+                                      [MINOR (inp->i_rdev)] << 1;
+			rc =
+			    copy_to_user ((long *) data, &blocks,
+					  sizeof (long));
 			if (rc)
 				rc = -EFAULT;
 			break;
 		}
 	case BLKRRPART:{
-                        if (!capable(CAP_SYS_ADMIN)) {
-                            rc = -EACCES;
-                            break;
-                        }
-			fsync_dev(inp->i_rdev);
-			dasd_partn_detect (device);
-			invalidate_buffers(inp->i_rdev);
-			rc = 0;
+			if (!capable (CAP_SYS_ADMIN)) {
+				rc = -EACCES;
+				break;
+			}
+			rc = dasd_revalidate (device);
 			break;
 		}
 	case HDIO_GETGEO:{
-			struct hd_geometry geo = {0,};
-			rc = dasd_fillgeo(inp->i_rdev, &geo);
+			struct hd_geometry geo = { 0, };
+			rc = dasd_fillgeo (inp->i_rdev, &geo);
 			if (rc)
 				break;
 
@@ -2043,148 +2222,208 @@
 				rc = -EFAULT;
 			break;
 		}
-#if (LINUX_VERSION_CODE > KERNEL_VERSION(2,3,98))
-        case BLKSSZGET:
-        case BLKROSET:
-        case BLKROGET:
-        case BLKRASET:
-        case BLKRAGET:
-        case BLKFLSBUF:
-        case BLKPG: 
-        case BLKELVGET:
-        case BLKELVSET:
-                return blk_ioctl(inp->i_rdev, no, data);
-                break;
-#else
-        case BLKRASET:
-                if(!capable(CAP_SYS_ADMIN))
-                        return -EACCES;
-                if(!dev || arg > 0xff)
-                        return -EINVAL;
-                read_ahead[MAJOR(dev)] = arg;
-                rc = 0;
-                break;
-        case BLKRAGET:
-                if (!arg)
-                        return -EINVAL;
-                rc = put_user(read_ahead[MAJOR(dev)], (long *) arg);
-                break;
-        case BLKSSZGET: {
-            /* Block size of media */
-            rc = copy_to_user((int *)data,
-                              &blksize_size[MAJOR(device->kdev)]
-                              [MINOR(device->kdev)],
-                              sizeof(int)) ? -EFAULT : 0;
-        }
-        RO_IOCTLS (inp->i_rdev, data);
-	case BLKFLSBUF:{
-                if (!capable(CAP_SYS_ADMIN)) 
-                        return -EACCES;
-                fsync_dev(inp->i_rdev);
-                invalidate_buffers(inp->i_rdev);
-                rc = 0;
-                break;
+	case BIODASDDISABLE:{
+			if (!capable (CAP_SYS_ADMIN)) {
+				rc = -EACCES;
+				break;
+			}
+                        if ( device->level > DASD_STATE_ACCEPT) {
+                                if ( device->request_queue)
+                                        dasd_flush_request_queues(device,0);
+                                dasd_flush_chanq(device,0);
+                                dasd_disable_blkdev(device);
+                                dasd_set_device_level (device->devinfo.devno, 
+                                                       device->discipline, 
+                                                       DASD_STATE_ACCEPT);
+                        }
+                        break;
         }
-#endif				/* LINUX_IS_24 */
-	case BIODASDRSID:{
-			rc = copy_to_user ((void *) data,
-					   &(device->devinfo.sid_data),
-					   sizeof (senseid_t)) ? -EFAULT : 0;
-			break;
-		}
-	case BIODASDRWTB:{
-			int offset = 0;
-			int xlt;
-			rc = copy_from_user (&xlt, (void *) data,
-					     sizeof (int)) ? -EFAULT : 0;
-			if (rc)
+	case BIODASDENABLE:{
+                        dasd_range_t range = { 
+                                from: device->devinfo.devno,
+                                to: device->devinfo.devno 
+                        };
+			if (!capable (CAP_SYS_ADMIN)) {
+				rc = -EACCES;
+				break;
+			}
+                        dasd_enable_ranges (&range, device->discipline, 0);
+                        break;
+        }
+	case BIODASDFMT:{
+			/* fdata == NULL is no longer a valid arg to dasd_format ! */
+			int partn = MINOR (inp->i_rdev) &
+			    ((1 << major_info->gendisk.minor_shift) - 1);
+			format_data_t fdata;
+
+			if (!capable (CAP_SYS_ADMIN)) {
+				rc = -EACCES;
 				break;
-			offset = major_info->gendisk.part[MINOR (inp->i_rdev)].start_sect >>
-			    device->sizes.s2b_shift;
-			xlt += offset;
-			rc = copy_to_user ((void *) data, &xlt,
-					   sizeof (int)) ? -EFAULT : 0;
-			break;
-		}
-	case BIODASDFORMAT:{
-			/* fdata == NULL is a valid arg to dasd_format ! */
-			int partn;
-			format_data_t fdata =
-			{
-				DASD_FORMAT_DEFAULT_START_UNIT,
-				DASD_FORMAT_DEFAULT_STOP_UNIT,
-				DASD_FORMAT_DEFAULT_BLOCKSIZE,
-				DASD_FORMAT_DEFAULT_INTENSITY};
-
-                        if (!capable(CAP_SYS_ADMIN)) {
-                            rc = -EACCES;
-                            break;
+			}
+                        if (dasd_features_from_devno(device->devinfo.devno)&DASD_FEATURE_READONLY) {
+                                rc = -EROFS;
+                                break;
                         }
-			if (data) {
-				rc = copy_from_user (&fdata, (void *) data,
-						     sizeof (format_data_t));
-				if (rc) {
-					rc = -EFAULT;
-					break;
-				}
+			if (!data) {
+				rc = -EINVAL;
+				break;
+			}
+			rc = copy_from_user (&fdata, (void *) data,
+					     sizeof (format_data_t));
+			if (rc) {
+				rc = -EFAULT;
+				break;
 			}
-			partn = MINOR (inp->i_rdev) & ((1 << major_info->gendisk.minor_shift) - 1);
 			if (partn != 0) {
-				printk (KERN_WARNING PRINTK_HEADER
-					" devno 0x%04X on subchannel %d = /dev/%s (%d:%d)"
-				     " Cannot low-level format a partition\n",
-					device->devinfo.devno, device->devinfo.irq, device->name,
-				    MAJOR (inp->i_rdev), MINOR (inp->i_rdev));
+				DASD_MESSAGE (KERN_WARNING, device, "%s",
+					      "Cannot low-level format a partition");
 				return -EINVAL;
 			}
 			rc = dasd_format (device, &fdata);
 			break;
 		}
+	case BIODASDPRRST:{
+			if (!capable (CAP_SYS_ADMIN)) {
+				rc = -EACCES;
+				break;
+			}
+			memset (&device->profile, 0,
+				sizeof (dasd_profile_info_t));
+			break;
+		}
+	case BIODASDPRRD:{
+			rc = copy_to_user((long *)data,
+					  (long *)&device->profile,
+					  sizeof(dasd_profile_info_t));
+			if (rc)
+				rc = -EFAULT;
+			break;
+		}
 	case BIODASDRSRV:{
-            ccw_req_t *req;
-            if (!capable(CAP_SYS_ADMIN)) {
-                rc = -EACCES;
-                break;
-            }
-            req = device->discipline->reserve (device);
-            rc = sleep_on_req (req);
-            dasd_free_request (req);
-            break;
-        }
+			ccw_req_t *req;
+			if (!capable (CAP_SYS_ADMIN)) {
+				rc = -EACCES;
+				break;
+			}
+			req = device->discipline->reserve (device);
+			rc = dasd_sleep_on_req (req);
+			dasd_free_request (req, device);
+			break;
+		}
 	case BIODASDRLSE:{
-            ccw_req_t *req;
-            if (!capable(CAP_SYS_ADMIN)) {
-                rc = -EACCES;
-                break;
-            }
-            req = device->discipline->release (device);
-            rc = sleep_on_req (req);
-            dasd_free_request (req);
-            break;
-        }
+			ccw_req_t *req;
+			if (!capable (CAP_SYS_ADMIN)) {
+				rc = -EACCES;
+				break;
+			}
+			req = device->discipline->release (device);
+			rc = dasd_sleep_on_req (req);
+			dasd_free_request (req, device);
+			break;
+		}
 	case BIODASDSLCK:{
 			printk (KERN_WARNING PRINTK_HEADER
 				"Unsupported ioctl BIODASDSLCK\n");
 			break;
 		}
+	case BIODASDINFO:{
+			dasd_information_t dasd_info;
+			unsigned long flags;
+			rc = device->discipline->fill_info (device, &dasd_info);
+                        dasd_info.label_block = device->sizes.pt_block;
+			dasd_info.devno = device->devinfo.devno;
+			dasd_info.schid = device->devinfo.irq;
+			dasd_info.cu_type = device->devinfo.sid_data.cu_type;
+			dasd_info.cu_model = device->devinfo.sid_data.cu_model;
+			dasd_info.dev_type = device->devinfo.sid_data.dev_type;
+			dasd_info.dev_model = device->devinfo.sid_data.dev_model;
+			dasd_info.open_count =
+			    atomic_read (&device->open_count);
+			dasd_info.status = device->level;
+			if (device->discipline) {
+				memcpy (dasd_info.type,
+					device->discipline->name, 4);
+			} else {
+				memcpy (dasd_info.type, "none", 4);
+			}
+			dasd_info.req_queue_len = 0;
+			dasd_info.chanq_len = 0;
+			if (device->request_queue->request_fn) {
+				struct list_head *l;
+				ccw_req_t *cqr = device->queue.head;
+				spin_lock_irqsave (&io_request_lock, flags);
+				list_for_each (l,
+					       &device->request_queue->
+					       queue_head) {
+					dasd_info.req_queue_len++;
+				}
+				spin_unlock_irqrestore (&io_request_lock,
+							flags);
+				s390irq_spin_lock_irqsave (device->devinfo.irq,
+							   flags);
+				while (cqr) {
+					cqr = cqr->next;
+					dasd_info.chanq_len++;
+				}
+				s390irq_spin_unlock_irqrestore (device->devinfo.
+								irq, flags);
+			}
+			rc =
+			    copy_to_user ((long *) data, (long *) &dasd_info,
+					  sizeof (dasd_information_t));
+			if (rc)
+				rc = -EFAULT;
+			break;
+		}
+#if 0 /* needed for XFS */
+	case BLKBSZSET:{
+		int bsz;
+		rc = copy_from_user ((long *)&bsz,(long *)data,sizeof(int));
+		if ( rc ) {
+			rc = -EFAULT;
+		} else {
+			if ( bsz >= device->sizes.bp_block )
+				rc = blk_ioctl (inp->i_rdev, no, data);
+			else
+				rc = -EINVAL; 
+		}
+		break;
+		}
+#endif /* 0 */
+	case BLKSSZGET:
+	case BLKROSET:
+	case BLKROGET:
+	case BLKRASET:
+	case BLKRAGET:
+	case BLKFLSBUF:
+	case BLKPG:
+	case BLKELVGET:
+	case BLKELVSET:
+		return blk_ioctl (inp->i_rdev, no, data);
+		break;
 	default:{
 
-			dasd_ioctl_list_t *old = dasd_find_ioctl(no);
-			if ( old ) {
-				rc = old->handler(inp,no,data);
+			dasd_ioctl_list_t *old = dasd_find_ioctl (no);
+			if (old) {
+				if ( old->owner )
+					__MOD_INC_USE_COUNT(old->owner);
+				rc = old->handler (inp, no, data);
+				if ( old->owner )
+					__MOD_DEC_USE_COUNT(old->owner);
 			} else {
 				DASD_MESSAGE (KERN_INFO, device,
-					    "ioctl 0x%08x=%s'0x%x'%d(%d) data %8lx\n",
+					      "ioctl 0x%08x=%s'0x%x'%d(%d) data %8lx\n",
 					      no,
 					      _IOC_DIR (no) == _IOC_NONE ? "0" :
 					      _IOC_DIR (no) == _IOC_READ ? "r" :
-					      _IOC_DIR (no) == _IOC_WRITE ? "w" :
-					   _IOC_DIR (no) == (_IOC_READ | _IOC_WRITE) ?
-					      "rw" : "u",
-					 _IOC_TYPE (no), _IOC_NR (no), _IOC_SIZE (no),
+					      _IOC_DIR (no) ==
+					      _IOC_WRITE ? "w" : _IOC_DIR (no)
+					      == (_IOC_READ | _IOC_WRITE) ? "rw"
+					      : "u", _IOC_TYPE (no),
+					      _IOC_NR (no), _IOC_SIZE (no),
 					      data);
-				rc = -EINVAL;
-			}	
+				rc = -ENOTTY;
+			}
 			break;
 		}
 	}
@@ -2209,37 +2448,46 @@
 dasd_open (struct inode *inp, struct file *filp)
 {
 	int rc = 0;
+        unsigned long flags;
 	dasd_device_t *device;
 
+        MOD_INC_USE_COUNT;
 	if ((!inp) || !(inp->i_rdev)) {
-		return -EINVAL;
+		rc = -EINVAL;
+                goto fail;
 	}
 	if (dasd_probeonly) {
-		printk ("\n" KERN_INFO PRINTK_HEADER "No access to device (%d:%d) due to probeonly mode\n", MAJOR (inp->i_rdev), MINOR (inp->i_rdev));
-		return -EPERM;
+		printk ("\n" KERN_INFO PRINTK_HEADER
+			"No access to device (%d:%d) due to probeonly mode\n",
+			MAJOR (inp->i_rdev), MINOR (inp->i_rdev));
+		rc = -EPERM;
+                goto fail;
 	}
+        spin_lock_irqsave(&discipline_lock,flags);
 	device = dasd_device_from_kdev (inp->i_rdev);
-	if (device == NULL) {
+	if (device == NULL ) {
 		printk (KERN_WARNING PRINTK_HEADER
-			"No device registered as (%d:%d)\n", MAJOR (inp->i_rdev), MINOR (inp->i_rdev));
-		return -ENODEV;
+			"No device registered as (%d:%d)\n",
+			MAJOR (inp->i_rdev), MINOR (inp->i_rdev));
+		rc = -ENODEV;
+                goto unlock;
 	}
-	if (device->level < DASD_DEVICE_LEVEL_RECOGNIZED ||
-	    device->discipline == NULL) {
+	if (device->level < DASD_STATE_ACCEPT ) {
 		DASD_MESSAGE (KERN_WARNING, device,
 			      " %s", " Cannot open unrecognized device\n");
-		return -EINVAL;
+		rc = -ENODEV;
+                goto unlock;
 	}
-        spin_lock(&dasd_open_count_lock);
-        if (device->open_count == -1) {
-            spin_unlock (&dasd_open_count_lock);
-            return -EBUSY;
+	if (atomic_inc_return (&device->open_count) == 1 ) {
+                if ( device->discipline->owner )
+                        __MOD_INC_USE_COUNT(device->discipline->owner);
+        } else {
+                MOD_DEC_USE_COUNT;
         }
-#ifdef MODULE
-	MOD_INC_USE_COUNT;
-#endif				/* MODULE */
-	device->open_count++;
-        spin_unlock (&dasd_open_count_lock);
+ unlock:
+        spin_unlock_irqrestore(&discipline_lock,flags);
+ fail:
+        if (rc) MOD_DEC_USE_COUNT;
 	return rc;
 }
 
@@ -2247,28 +2495,41 @@
 dasd_release (struct inode *inp, struct file *filp)
 {
 	int rc = 0;
+        int count;
 	dasd_device_t *device;
 
 	if ((!inp) || !(inp->i_rdev)) {
-		return -EINVAL;
+		rc = -EINVAL;
+                goto out;
 	}
 	device = dasd_device_from_kdev (inp->i_rdev);
 	if (device == NULL) {
 		printk (KERN_WARNING PRINTK_HEADER
 			"No device registered as %d:%d\n",
 			MAJOR (inp->i_rdev), MINOR (inp->i_rdev));
-		return -EINVAL;
+		rc = -EINVAL;
+                goto out;
 	}
-        spin_lock(&dasd_open_count_lock);
-	if (device->open_count--) {
-#ifdef MODULE
-		MOD_DEC_USE_COUNT;
-#endif				/* MODULE */
-	} 
-	fsync_dev(inp->i_rdev); /* sync the device */
-	if (device->open_count == 0) /* finally invalidate buffers */
-		invalidate_buffers(inp->i_rdev);
-        spin_unlock(&dasd_open_count_lock);
+
+	if (device->level < DASD_STATE_ACCEPT ) {
+		DASD_MESSAGE (KERN_WARNING, device,
+			      " %s", " Cannot release unrecognized device\n");
+		rc = -ENODEV;
+                goto out;
+	}
+	fsync_dev (inp->i_rdev);	/* sync the device */
+        count = atomic_dec_return (&device->open_count);
+        if ( count == 0) {
+                invalidate_buffers (inp->i_rdev);
+                if ( device->discipline->owner )
+                        __MOD_DEC_USE_COUNT(device->discipline->owner);
+                MOD_DEC_USE_COUNT;
+	} else if ( count == -1 ) { /* paranoia only */
+                atomic_set (&device->open_count,0);
+                printk (KERN_WARNING PRINTK_HEADER
+                        "release called with open count==0\n");
+        }
+ out:
 	return rc;
 }
 
@@ -2278,11 +2539,6 @@
 	open:dasd_open,
 	release:dasd_release,
 	ioctl:dasd_ioctl,
-#if ! (LINUX_VERSION_CODE > KERNEL_VERSION(2,3,98))
-	read:block_read,
-	write:block_write,
-	fsync:block_fsync,
-#endif				/* LINUX_IS_24 */
 };
 
 /* SECTION: Management of device list */
@@ -2294,16 +2550,9 @@
 		return -EINVAL;
 
 	device->discipline->fill_geometry (device, geo);
-	geo->start = device->major_info->
-			gendisk.part[MINOR(kdev)].start_sect;
-
-	/* This is a hack.  dasdfmt and ibm.c expect geo.start 
-	   to contain the block number of the label block when
-	   it calls HDIO_GETGEO on the first partition. */
-	if (geo->start == 0)
-                geo->start = device->sizes.pt_block;
-
-	return 0;
+	geo->start = device->major_info->gendisk.part[MINOR(kdev)].start_sect 
+		     >> device->sizes.s2b_shift;;
+        return 0;
 } 
 
 
@@ -2315,11 +2564,11 @@
 	char first, second, third;
 
 	if (hd) {
-		major_info_t *major_info=NULL;
+		major_info_t *major_info = NULL;
 		struct list_head *l;
 
-		list_for_each(l,&dasd_major_info[0].list) {
-			major_info = list_entry(l,major_info_t,list); 
+		list_for_each (l, &dasd_major_info[0].list) {
+			major_info = list_entry (l, major_info_t, list);
 			if (&major_info->gendisk == hd) {
 				break;
 			}
@@ -2330,14 +2579,14 @@
 		}
 	}
 	third = index % 26;
-	second = ((index-26) / 26) % 26;
-	first = (((index-702) / 26) / 26) % 26;
+	second = ((index - 26) / 26) % 26;
+	first = (((index - 702) / 26) / 26) % 26;
 
 	len = sprintf (str, "dasd");
-	if (index>701) {
+	if (index > 701) {
 		len += sprintf (str + len, "%c", first + 'a');
 	}
-	if (index>25) {
+	if (index > 25) {
 		len += sprintf (str + len, "%c", second + 'a');
 	}
 	len += sprintf (str + len, "%c", third + 'a');
@@ -2352,19 +2601,214 @@
 	return 0;
 }
 
-#ifdef CONFIG_DASD_DYNAMIC
 static void
-dasd_plug_device (dasd_device_t *device)
+dasd_plug_device (dasd_device_t * device)
 {
-        device->request_queue.plugged = 1; /* inhibit further calls of request_fn */
+	atomic_set(&device->plugged,1);	
+}
+
+static void
+dasd_unplug_device (dasd_device_t * device)
+{
+	atomic_set(&device->plugged,0);	
+        dasd_schedule_bh(device);
+}
+
+static void
+dasd_flush_chanq ( dasd_device_t * device, int destroy ) 
+{
+        ccw_req_t *cqr;
+        unsigned long flags;
+        if ( destroy ) {
+                s390irq_spin_lock_irqsave (device->devinfo.irq, flags);
+                cqr = device->queue.head;
+                while ( cqr != NULL ) {
+                        if ( cqr -> status == CQR_STATUS_IN_IO )
+                                device->discipline->term_IO (cqr);
+                        if ( cqr->status != CQR_STATUS_DONE ||
+                             cqr->status != CQR_STATUS_FAILED ) {
+                                cqr->status = CQR_STATUS_FAILED;
+                        }
+                        dasd_schedule_bh(device);
+                        cqr = cqr->next;
+                }
+                s390irq_spin_unlock_irqrestore (device->devinfo.irq, flags);
+        }
+        wait_event( device->wait_q, device->queue.head == NULL );
+}
+
+static void
+dasd_flush_request_queues ( dasd_device_t * device, int destroy )
+{
+        int i;
+        int major = MAJOR(device->kdev);
+        int minor = MINOR(device->kdev);
+        for ( i = 0; i < (1 << DASD_PARTN_BITS); i ++) {
+                if ( destroy )
+                        destroy_buffers(MKDEV(major,minor+i)); 
+                else
+                        invalidate_buffers(MKDEV(major,minor+i)); 
+        } 
+}
+
+static int
+dasd_disable_volume ( dasd_device_t * device, int force ) 
+{
+        int rc = 0;
+        int target  = DASD_STATE_KNOWN;
+        int count = atomic_read (&device->open_count);
+        int part;
+        
+	if ( count ) {
+		DASD_MESSAGE (KERN_EMERG, device, "%s",
+			      "device has vanished although it was open!");
+        }
+        if ( force ) {
+                dasd_flush_chanq(device,force);
+                dasd_flush_request_queues(device,force);
+                dasd_disable_blkdev(device);
+                target = DASD_STATE_DEL;
+        }
+
+#if 0
+        /* unregister devfs entries */
+        for (part = 0; part < (1 << DASD_PARTN_BITS); part++) {
+                devfs_unregister(device->major_info->gendisk.part[MINOR(device->kdev)+part].de);
+                device->major_info->gendisk.part[MINOR(device->kdev)+part].de = NULL;
+        }                        
+#endif
+        
+        DASD_MESSAGE (KERN_WARNING, device, 
+                      "disabling device, target state:%d",target);
+        dasd_set_device_level (device->devinfo.devno, 
+                               device->discipline, 
+                               target);
+        return rc;
+}
+
+static void
+dasd_disable_ranges (dasd_range_t *range, 
+                     dasd_discipline_t *d,
+                     int all, int force ) 
+{
+        dasd_range_t *rrange;
+        int j;
+
+        if (range == &dasd_range_head) {
+                rrange = list_entry (range->list.next, 
+                                     dasd_range_t, list);
+        } else {
+                rrange = range;
+        }
+        do {
+                for (j = rrange->from; j <= rrange->to; j++) {
+                        dasd_device_t **dptr;
+                        dasd_device_t *device;
+                        dptr = dasd_device_from_devno(j);
+                        if ( dptr == NULL ) {
+                            continue;
+                        }
+                        device = *dptr;
+                        if (device == NULL ||
+                            (d != NULL &&
+                             device -> discipline != d))
+                                continue;
+                        
+                        dasd_disable_volume(device, force);
+                }
+                rrange = list_entry (rrange->list.next, dasd_range_t, list);
+        } while ( all && rrange && rrange != range );
+}
+
+static void 
+dasd_enable_single_device ( unsigned long arg ) {
+        dasd_device_t * device =(dasd_device_t *) arg;
+        int devno = device->devinfo.devno;
+        dasd_range_t range = { from: devno, to:devno };
+        dasd_enable_ranges (&range,NULL,0);
 }
 
 static void
-dasd_unplug_device (dasd_device_t *device)
+dasd_enable_ranges (dasd_range_t *range, dasd_discipline_t *d, int all ) 
 {
-        generic_unplug_device(&device->request_queue);
+        int retries = 0;
+	int j;
+        kdev_t tempdev;
+	dasd_range_t *rrange;
+
+	if (range == NULL)
+		return;
+        
+        do {
+                if (range == &dasd_range_head) {
+                        rrange = list_entry (range->list.next, 
+                                             dasd_range_t, list);
+                } else {
+                        rrange = range;
+                }
+                do {
+                        for (j = rrange->from; j <= rrange->to; j++) {
+                                if ( dasd_devindex_from_devno(j) < 0 )
+                                        continue;
+                                dasd_set_device_level (j, d, DASD_STATE_ONLINE);
+                        }
+                        rrange = list_entry (rrange->list.next, dasd_range_t, list);
+                } while ( all && rrange && rrange != range );
+
+                if (atomic_read (&dasd_init_pending) == 0) /* we are done, exit loop */
+                        break;
+
+                if ( retries == 0 ) {
+                        printk (KERN_INFO PRINTK_HEADER
+                                "waiting for responses...\n");
+                } else if ( retries < 5 ) {
+                        printk (KERN_INFO PRINTK_HEADER
+                                "waiting a little bit longer...\n");
+                } else {
+                        printk (KERN_INFO PRINTK_HEADER
+                                "giving up, enable late devices manually!\n");
+                        break;
+                }
+                interruptible_sleep_on_timeout (&dasd_init_waitq, (1 * HZ));
+                retries ++;
+        } while (1);
+        /* now setup block devices */
+
+        /* Now do block device and partition setup */
+        if (range == &dasd_range_head) {
+                rrange = list_entry (range->list.next, 
+                                     dasd_range_t, list);
+        } else {
+                rrange = range;
+        }
+        do {
+                for (j = rrange->from; j <= rrange->to; j++) {
+                        dasd_device_t **dptr;
+                        dasd_device_t *device;
+                        if ( dasd_devindex_from_devno(j) < 0 )
+                                continue;
+                        dptr = dasd_device_from_devno(j);
+                        device = *dptr;
+                        if (device == NULL )
+                                continue;
+                        if ( ((d == NULL && device->discipline != NULL) ||
+                              (device->discipline == d )) &&
+                             device->level >= DASD_STATE_READY &&
+                             device->request_queue == NULL ) {
+                                if (dasd_features_from_devno(j)&DASD_FEATURE_READONLY) {
+                                    for (tempdev=device->kdev;tempdev<(device->kdev +(1 << DASD_PARTN_BITS));tempdev++)
+                                        set_device_ro (tempdev, 1);
+                                     printk (KERN_WARNING PRINTK_HEADER "setting read-only mode for device /dev/%s\n",device->name);
+                                }
+                                dasd_setup_blkdev(device);
+                                dasd_setup_partitions(device);
+                        }
+                }
+                rrange = list_entry (rrange->list.next, dasd_range_t, list);
+        } while ( all && rrange && rrange != range );
 }
 
+#ifdef CONFIG_DASD_DYNAMIC
 static void
 dasd_not_oper_handler (int irq, int status)
 {
@@ -2373,13 +2817,12 @@
 	struct list_head *l;
 	int i, devno = -ENODEV;
 
-        /* find out devno of leaving device: CIO has already deleted this information ! */
-	list_for_each(l,&dasd_major_info[0].list) {
-		major_info=list_entry(l, major_info_t,list);	
+	/* find out devno of leaving device: CIO has already deleted this information ! */
+	list_for_each (l, &dasd_major_info[0].list) {
+		major_info = list_entry (l, major_info_t, list);
 		for (i = 0; i < DASD_PER_MAJOR; i++) {
 			device = major_info->dasd_device[i];
-			if (device &&
-			    device->devinfo.irq == irq) {
+			if (device && device->devinfo.irq == irq) {
 				devno = device->devinfo.devno;
 				break;
 			}
@@ -2392,360 +2835,561 @@
 			"not_oper_handler called on irq %d no devno!\n", irq);
 		return;
 	}
-
-	if (device->open_count != 0) {
-                DASD_MESSAGE(KERN_ALERT,device,"%s",
-                             "open device has gone. please repair!");
-                dasd_set_device_level (irq, DASD_DEVICE_LEVEL_ANALYSED, 
-                                       NULL, 0);
-	} else {
-                DASD_MESSAGE(KERN_INFO,device,"%s","device has gone");
-                dasd_set_device_level (irq, DASD_DEVICE_LEVEL_UNKNOWN, 
-                                       NULL, 0);
-        }
+        dasd_disable_volume(device, 0);
 }
 
-static int
-dasd_enable_single_volume (int irq)
+int
+dasd_oper_handler (int irq, devreg_t * devreg)
 {
+	int devno;
 	int rc = 0;
-	dasd_set_device_level (irq, DASD_DEVICE_LEVEL_ONLINE,
-			       NULL, 0);
-	printk (KERN_INFO PRINTK_HEADER "waiting for response...\n");
-	{
-		static wait_queue_head_t wait_queue;
-		init_waitqueue_head (&wait_queue);
-		interruptible_sleep_on_timeout (&wait_queue, (5 * HZ) >> 1);
+	major_info_t *major_info = NULL;
+        dasd_range_t *rptr,range;
+        dasd_device_t *device = NULL;
+	struct list_head *l;
+        int i;
+
+	devno = get_devno_by_irq (irq);
+	if (devno == -ENODEV) {
+		rc = -ENODEV;
+                goto out;
 	}
-	dasd_set_device_level (irq, DASD_DEVICE_LEVEL_ONLINE, NULL, 0);
+	/* find out devno of leaving device: CIO has already deleted this information ! */
+	list_for_each (l, &dasd_major_info[0].list) {
+		major_info = list_entry (l, major_info_t, list);
+		for (i = 0; i < DASD_PER_MAJOR; i++) {
+			device = major_info->dasd_device[i];
+			if (device && device->devinfo.irq == irq) {
+				devno = device->devinfo.devno;
+				break;
+			}
+		}
+		if (devno != -ENODEV)
+			break;
+	}
+	if (devno < 0) {
+                BUG();
+	}
+        if ( device &&
+             device->level == DASD_STATE_READY ) {
+            dasd_set_device_level (device->devinfo.devno, 
+                                   device->discipline, DASD_STATE_ONLINE);
+
+        } else {
+            if (dasd_autodetect) {
+		rptr = dasd_add_range (devno, devno, DASD_DEFAULT_FEATURES);
+                if ( rptr == NULL ) {
+                    rc = -ENOMEM;
+                    goto out;
+                }
+            } else {
+                range.from = devno;
+                range.to = devno;
+                rptr = &range;
+            }
+            dasd_enable_ranges (rptr, NULL, 0);
+        }
+ out:
 	return rc;
 }
+#endif				/* CONFIG_DASD_DYNAMIC */
+
+static inline dasd_device_t **
+dasd_find_device_addr ( int devno ) 
+{
+        dasd_device_t **device_addr;
+
+	DASD_DRIVER_DEBUG_EVENT (1, dasd_find_device_addr, 
+                                 "devno %04X", devno);
+	if ( dasd_devindex_from_devno (devno) < 0 ) {
+                DASD_DRIVER_DEBUG_EXCEPTION (1, dasd_find_device_addr, 
+                                             "no dasd: devno %04X",
+                                             devno);
+		return NULL;
+	}
+        /* allocate major numbers on demand  for new devices */
+	while ((device_addr = dasd_device_from_devno (devno)) == NULL) {
+                int rc;
+
+		if ((rc = dasd_register_major (NULL)) <= 0) {
+
+                        DASD_DRIVER_DEBUG_EXCEPTION (1, dasd_find_device_addr, 
+                                                     "%s",
+                                                     "out of major numbers!");
+                        break;
+		}
+	}
+        return device_addr;
+}
+
+static inline int
+dasd_state_del_to_new (dasd_device_t **addr ) 
+{
+        dasd_device_t* device;
+        int rc = 0;
+	if (*addr == NULL) { /* allocate device descriptor on demand for new device */
+                device = kmalloc (sizeof (dasd_device_t), GFP_ATOMIC);
+		if (device == NULL ) {
+			rc = -ENOMEM;
+                        goto out;
+		}
+		memset (device, 0, sizeof (dasd_device_t));
+                *addr = device;
+                device->lowmem_ccws = (void*)get_free_page (GFP_ATOMIC|GFP_DMA);
+                if (device->lowmem_ccws == NULL) {
+                        rc = -ENOMEM;
+                        goto noccw;
+	}
+#ifdef CONFIG_ARCH_S390X
+                device->lowmem_idals =
+                    device->lowmem_idal_ptr = (void*) get_free_page (GFP_ATOMIC|GFP_DMA);
+                if (device->lowmem_idals == NULL) {
+                        rc = -ENOMEM;
+                        goto noidal;
+                }                
+#endif
+}
+        goto out;
+ noidal:
+        free_page ((long) device->lowmem_ccws);
+ noccw:
+        kfree(device);
+ out:
+        return rc;
+}
+
+static inline int
+dasd_state_new_to_del (dasd_device_t **addr )
+{
+        dasd_device_t *device = *addr;
+        if (device && device->private) {
+                kfree(device->private);
+                device->private = NULL;
+        }
+#ifdef CONFIG_ARCH_S390X
+        free_page ((long)(device->lowmem_idals));
+#endif
+        free_page((long)(device->lowmem_ccws));
+        kfree(device);
+        *addr = NULL; 
+        return 0;
+}
+
+static inline int
+dasd_state_new_to_known (dasd_device_t **dptr, int devno, dasd_discipline_t *disc) 
+{
+        int rc = 0;
+	umode_t devfs_perm  = S_IFBLK | S_IRUSR | S_IWUSR;
+        struct list_head *l;
+        major_info_t *major_info = NULL;
+        int i;
+        dasd_device_t *device = *dptr;
+        devfs_handle_t dir;
+        char buffer[5];
+        
+
+	list_for_each (l, &dasd_major_info[0].list) {
+                major_info = list_entry (l, major_info_t, list);
+		for (i = 0; i < DASD_PER_MAJOR; i++) {
+			if (major_info->dasd_device[i] == device) {
+				device->kdev = MKDEV (major_info->gendisk.major,
+                                                      i << DASD_PARTN_BITS);
+				break;
+			}
+		}
+		if (i < DASD_PER_MAJOR) /* we found one */
+			break;
+	}
+        if ( major_info == NULL || major_info == &dasd_major_info[0] ) 
+                BUG();
+
+        device->major_info = major_info;
+        dasd_device_name (device->name,
+                          (((long)dptr -
+                            (long)device->major_info->dasd_device) /
+                           sizeof (dasd_device_t *)),
+                          0, &device->major_info->gendisk);
+        init_waitqueue_head (&device->wait_q);
+        
+        rc = get_dev_info_by_devno (devno, &device->devinfo);
+        if ( rc ) {
+                goto out;
+        }
+        if ( devno != device->devinfo.devno )
+                BUG();
+        device->discipline = dasd_find_disc (device, disc);
+        if ( device->discipline == NULL ) {
+                rc = -ENODEV;
+                goto out;
+        }
+        sprintf (buffer, "%04x", device->devinfo.devno);
+        dir = devfs_mk_dir (dasd_devfs_handle, buffer, device);
+        device->major_info->gendisk.de_arr[MINOR(device->kdev)
+                                          >> DASD_PARTN_BITS] = dir;
+	if (dasd_features_from_devno(device->devinfo.devno)&DASD_FEATURE_READONLY) {
+	        devfs_perm &= ~(S_IWUSR);
+	}
+        device->devfs_entry = devfs_register (dir,"device",DEVFS_FL_DEFAULT,
+                                              MAJOR(device->kdev),
+                                              MINOR(device->kdev),
+                                              devfs_perm,
+                                              &dasd_device_operations,NULL);
+        device->level = DASD_STATE_KNOWN;
+ out:
+        return rc;
+}
+
+static inline int
+dasd_state_known_to_new (dasd_device_t *device ) 
+{
+        int rc = 0;
+        /* don't reset to zeros because of persistent data durich detach/attach! */
+        devfs_unregister(device->devfs_entry);
+        devfs_unregister(device->major_info->gendisk.de_arr[MINOR(device->kdev) >> DASD_PARTN_BITS]);
+
+        return rc;
+}
+
+static inline int
+dasd_state_known_to_accept (dasd_device_t *device) 
+{
+        int rc = 0;
+        device->debug_area = debug_register (device->name, 0, 2, 
+                                             3 * sizeof (long));
+        debug_register_view (device->debug_area, &debug_sprintf_view);
+        debug_register_view (device->debug_area, &debug_hex_ascii_view);
+        DASD_DEVICE_DEBUG_EVENT (0, device,"%p debug area created",device);
+        
+        if (device->discipline->int_handler) {
+                rc = s390_request_irq_special (device->devinfo.irq,
+                                               device->discipline->int_handler,
+                                               dasd_not_oper_handler,
+                                               0, DASD_NAME,
+                                               &device->dev_status);
+                if ( rc ) {
+                        printk("No request IRQ\n");
+                        goto out;
+                }
+        }
+        device->level = DASD_STATE_ACCEPT;
+ out:
+        return rc;
+}
+
+static inline int
+dasd_state_accept_to_known (dasd_device_t *device ) 
+{
+        if ( device->discipline == NULL )
+                goto out;
+        if (device->discipline->int_handler) {
+                free_irq (device->devinfo.irq, &device->dev_status);
+        }
+        DASD_DEVICE_DEBUG_EVENT (0, device,"%p debug area deleted",device);
+        if ( device->debug_area != NULL )
+                debug_unregister (device->debug_area);
+        device->discipline = NULL;
+        device->level = DASD_STATE_KNOWN;
+ out:
+        return 0;
+}
+
+static inline int
+dasd_state_accept_to_init (dasd_device_t *device) 
+{
+        int rc = 0;
+        unsigned long flags;
+
+        if ( device->discipline->init_analysis ) {
+                device->init_cqr=device->discipline->init_analysis (device);
+                if ( device->init_cqr != NULL ) {
+                        if ( device->discipline->start_IO == NULL )
+                                BUG();
+                        atomic_inc (&dasd_init_pending);
+                        s390irq_spin_lock_irqsave (device->devinfo.irq, 
+                                                   flags);
+                        rc = device->discipline->start_IO (device->init_cqr);
+                        s390irq_spin_unlock_irqrestore(device->devinfo.irq, 
+                                                       flags);
+                        if ( rc )
+                                goto out;
+                        device->level = DASD_STATE_INIT;
+                } else {
+                        rc = -ENOMEM;
+                }
+        } else {
+                rc = dasd_state_init_to_ready ( device ); 
+        }
+ out:
+        return rc;
+}
+
+static inline int
+dasd_state_init_to_ready (dasd_device_t *device ) 
+{
+        int rc = 0;    
+        if (device->discipline->do_analysis != NULL)
+                if ( device->discipline->do_analysis (device) == 0 ) 
+                        switch (device->sizes.bp_block) {
+                        case 512:
+                        case 1024:
+                        case 2048:
+                        case 4096:
+                                break;
+                        default:
+                                rc = -EMEDIUMTYPE;
+                        }
+        if ( device->init_cqr ) {
+                atomic_dec(&dasd_init_pending);
+                device->init_cqr = NULL; /* This one is no longer needed */
+        }
+        device->level = DASD_STATE_READY;
+        return rc;
+}
+
+static inline int
+dasd_state_ready_to_accept (dasd_device_t *device ) 
+{
+        int rc = 0;
+        unsigned long flags;
+
+        if ( device->init_cqr != NULL ) {
+                if ( device->discipline->term_IO == NULL )
+                        BUG();
+                s390irq_spin_lock_irqsave (device->devinfo.irq, flags);
+                device->discipline->term_IO (device->init_cqr);
+                s390irq_spin_unlock_irqrestore(device->devinfo.irq, flags);
+                atomic_dec (&dasd_init_pending);
+                dasd_free_request (device->init_cqr, device);
+                device->init_cqr = NULL;
+        }
+        memset(&device->sizes,0,sizeof(dasd_sizes_t));
+        device->level = DASD_STATE_ACCEPT;
+        return rc;
+}
+
+static inline int
+dasd_state_ready_to_online (dasd_device_t *device ) 
+{
+        int rc = 0;
+        dasd_unplug_device (device);
+        device->level = DASD_STATE_ONLINE;
+        return rc;
+}
+
+static inline int
+dasd_state_online_to_ready (dasd_device_t *device ) 
+{
+        int rc = 0;
+        dasd_plug_device (device);
+        device->level = DASD_STATE_READY;
+        return rc;
+}
+
+static inline int
+dasd_setup_blkdev (dasd_device_t *device ) 
+{
+        int rc = 0;
+        int i;
+        int major = MAJOR(device->kdev);
+        int minor = MINOR(device->kdev);
+
+        for (i = 0; i < (1 << DASD_PARTN_BITS); i++) {
+                if (i == 0)
+                        device->major_info->gendisk.sizes[minor] =
+                                (device->sizes.blocks << device->
+                                 sizes.s2b_shift) >> 1;
+                else
+                        device->major_info->gendisk.sizes[minor + i] = 0;
+                hardsect_size[major][minor + i] = device->sizes.bp_block;
+                blksize_size[major][minor + i] = device->sizes.bp_block;
+                max_sectors[major][minor + i] =
+                        device->discipline->max_blocks << 
+                        device->sizes.s2b_shift;
+		device->major_info->gendisk.part[minor+i].start_sect = 0;
+		device->major_info->gendisk.part[minor+i].nr_sects = 0;
+        }
+        device->request_queue = kmalloc(sizeof(request_queue_t),GFP_KERNEL);
+        device->request_queue->queuedata = device;
+        blk_init_queue (device->request_queue, do_dasd_request);
+        blk_queue_headactive (device->request_queue, 0);
+        elevator_init (&(device->request_queue->elevator),ELEVATOR_NOOP);
+        return rc;
+}
+
+static inline int
+dasd_disable_blkdev (dasd_device_t *device ) 
+{
+        int i;
+        int major = MAJOR(device->kdev);
+        int minor = MINOR(device->kdev);
+
+        for (i = 0; i < (1 << DASD_PARTN_BITS); i++) {
+                destroy_buffers(MKDEV(major,minor+i));
+                device->major_info->gendisk.sizes[minor + i] = 0;
+                hardsect_size[major][minor + i] = 0;
+                blksize_size[major][minor + i] = 0;
+                max_sectors[major][minor + i] = 0;
+        }
+        if (device->request_queue) {
+            blk_cleanup_queue (device->request_queue);
+            kfree(device->request_queue);
+            device->request_queue = NULL;
+        }
+        return 0;
+}
+
+
+/*
+ * function dasd_setup_partitions
+ * calls the function in genhd, which is appropriate to setup a partitioned disk
+ */
+static inline void
+dasd_setup_partitions ( dasd_device_t * device ) 
+{
+	register_disk (&device->major_info->gendisk,
+                       device->kdev,
+		       1 << DASD_PARTN_BITS,
+		       &dasd_device_operations,
+		       (device->sizes.blocks << device->sizes.s2b_shift));
+}
 
-int
-dasd_oper_handler (int irq, devreg_t * devreg)
+static inline void
+dasd_destroy_partitions ( dasd_device_t * device ) 
 {
-	int devno;
-	int rc;
-	devno = get_devno_by_irq (irq);
-        printk (KERN_WARNING PRINTK_HEADER "Oper handler called\n");
-	if (devno == -ENODEV) {
-          printk (KERN_WARNING PRINTK_HEADER "NODEV\n");
-		return -ENODEV;
+        int i;
+        int major = MAJOR(device->kdev);
+        int minor = MINOR(device->kdev);
+        
+        for (i = 0; i < (1 << DASD_PARTN_BITS); i++) {
+                device->major_info->gendisk.part[minor+i].start_sect = 0;
+                device->major_info->gendisk.part[minor+i].nr_sects   = 0;
         }
-	if (dasd_autodetect) {
-		dasd_add_range (devno, 0);
-	}
-	rc = dasd_enable_single_volume (irq);
-	return rc;
+        devfs_register_partitions(&device->major_info->gendisk,
+                                  MINOR(device->kdev),1);
 }
-#endif	/* CONFIG_DASD_DYNAMIC */
 
-/* 
- * function dasd_set_device_level 
+static inline void
+dasd_resetup_partitions ( dasd_device_t * device ) 
+{
+    BUG();
+    dasd_destroy_partitions ( device ) ;
+    dasd_setup_partitions ( device ) ;
+}
+
+/*
+ * function dasd_set_device_level
  */
 static int
-dasd_set_device_level (unsigned int irq, int desired_level,
-		       dasd_discipline_t * discipline, int flags)
+dasd_set_device_level (unsigned int devno, 
+                       dasd_discipline_t * discipline,
+                       int to_state)
 {
 	int rc = 0;
-	int devno;
-	dasd_device_t **device_addr, *device;
-	int current_level;
-	major_info_t *major_info = NULL;
-	struct list_head *l;
-	int i, minor, major;
-	ccw_req_t *cqr = NULL;
-	struct gendisk *dd;
+        dasd_device_t **device_addr;
+        dasd_device_t *device;
+        int from_state;
 
-	devno = get_devno_by_irq (irq);
-	if (devno < 0) { /* e.g. when device has been detached before */
-		/* search in device list */
-		list_for_each(l,&dasd_major_info[0].list) {
-			major_info = list_entry(l,major_info_t,list);	
-			for (i = 0; i < DASD_PER_MAJOR; i++) {
-				device = major_info->dasd_device[i];
-				if (device && device->devinfo.irq == irq) {
-					devno = device->devinfo.devno;
-					break;
-				}
-			}
-			if (devno == -ENODEV)
-				return -ENODEV;
-		}
-	}
-	if (dasd_devindex_from_devno (devno) < 0) {
-		return -ENODEV;
-	}
-	while ((device_addr = dasd_device_from_devno (devno)) == NULL) {
-		if ((rc = dasd_register_major (NULL)) > 0) {
-			printk (KERN_INFO PRINTK_HEADER
-				"Registered to major number: %u\n", rc);
-		} else {
-			printk (KERN_WARNING PRINTK_HEADER
-				"Couldn't register to another major no\n");
-			return -ERANGE;
-		}
-	}
-	device = *device_addr;
-	if (!device) {		/* allocate device descriptor */
-		device = kmalloc (sizeof (dasd_device_t), GFP_ATOMIC);
-		if (!device) {
-			printk (KERN_WARNING PRINTK_HEADER " No memory for device descriptor\n");
-			goto nomem;
-		}
-		memset (device, 0, sizeof (dasd_device_t));
-		*device_addr = device;
-	}
-	list_for_each(l,&dasd_major_info[0].list) {
-		int i;
-		major_info = list_entry(l,major_info_t,list);	
-		for (i = 0; i < DASD_PER_MAJOR; i++) {
-			if (major_info->dasd_device[i] == device) {
-				device->kdev = MKDEV (major_info->gendisk.major, i << DASD_PARTN_BITS);
-				break;
-			}
-		}
-		if (i < DASD_PER_MAJOR)
-			break;
-	}
-	if (major_info == &dasd_major_info[0]) {
-		return -ENODEV;
-	}
-	minor = MINOR (device->kdev);
-	major = MAJOR (device->kdev);
-	current_level = device->level;
-	if (desired_level > current_level) {
-		switch (current_level) {
-		case DASD_DEVICE_LEVEL_UNKNOWN:	/* Find a discipline */
-                        device->major_info = major_info;
-                        dasd_device_name (device->name,
-                                          ((long) device_addr -
-                                           (long) device->major_info->dasd_device) /
-                                          sizeof (dasd_device_t *),
-                                          0, &major_info->gendisk);
-			rc = get_dev_info_by_irq (irq, &device->devinfo);
-			if (rc < 0) {
-				break;
-			}
-			discipline = dasd_find_discipline (device);
-			if (discipline && !rc) {
-                                DASD_MESSAGE (KERN_INFO, device,
-                                              "%s", " ");
-			} else {
-                                break;
-			}
-			device->discipline = discipline;
-                        device->debug_area = debug_register(device->name,0,2,3*sizeof(long));
-                        debug_register_view(device->debug_area,&debug_sprintf_view);
-                        debug_register_view(device->debug_area,&debug_hex_ascii_view);
-			if (device->discipline->int_handler) {
-#ifdef CONFIG_DASD_DYNAMIC
-				s390_request_irq_special (irq,
-                                                          device->discipline->int_handler,
-                                                          dasd_not_oper_handler,
-							  0,
-							  DASD_NAME,
-							  &device->dev_status);
-#else				/* !defined(CONFIG_DASD_DYNAMIC) */
-				request_irq (irq,
-					     device->discipline->int_handler,
-					     0,
-					     DASD_NAME,
-					     &device->dev_status);
-#endif				/* CONFIG_DASD_DYNAMIC */
-			}
-			device->proc_dir = (struct proc_dir_entry *)
-			    kmalloc (sizeof (struct proc_dir_entry), GFP_KERNEL);
-			if (device->proc_dir) {
-				memset (device->proc_dir, 0, sizeof (struct proc_dir_entry));
-				device->proc_info = (struct proc_dir_entry *)
-				    kmalloc (sizeof (struct proc_dir_entry), GFP_KERNEL);
-				if (device->proc_info) {
-					memset (device->proc_info, 0,
-					      sizeof (struct proc_dir_entry));
-				}
-				device->proc_stats = (struct proc_dir_entry *)
-				    kmalloc (sizeof (struct proc_dir_entry), GFP_KERNEL);
-				if (device->proc_stats) {
-					memset (device->proc_stats, 0,
-					      sizeof (struct proc_dir_entry));
-				}
-			}
-			init_waitqueue_head (&device->wait_q);
-			check_then_set (&device->level,
-				       DASD_DEVICE_LEVEL_UNKNOWN,
-				       DASD_DEVICE_LEVEL_RECOGNIZED);
-			if (desired_level == DASD_DEVICE_LEVEL_RECOGNIZED)
-				break;
-		case DASD_DEVICE_LEVEL_RECOGNIZED:	/* Fallthrough ?? */
-			if (device->discipline->init_analysis) {
-				cqr = device->discipline->init_analysis (device);
-				if (cqr != NULL) {
-					dasd_chanq_enq (&device->queue, cqr);
-					if (device->discipline->start_IO) {
-						long flags;
-						s390irq_spin_lock_irqsave (irq, flags);
-						device->discipline->start_IO (cqr);
-						check_then_set (&device->level,
-                                                                DASD_DEVICE_LEVEL_RECOGNIZED,
-                                                                DASD_DEVICE_LEVEL_ANALYSIS_PENDING);
-						s390irq_spin_unlock_irqrestore (irq, flags);
-					}
-				}
-			} else {
-				check_then_set (&device->level, DASD_DEVICE_LEVEL_RECOGNIZED,
-                                                DASD_DEVICE_LEVEL_ANALYSIS_PREPARED);
-			}
-			if (desired_level >= DASD_DEVICE_LEVEL_ANALYSIS_PENDING)
-				break;
-		case DASD_DEVICE_LEVEL_ANALYSIS_PENDING:	/* Fallthrough ?? */
-			return -EAGAIN;
-		case DASD_DEVICE_LEVEL_ANALYSIS_PREPARED:	/* Re-entering here ! */
-			if (device->discipline->do_analysis)
-                                if (device->discipline->do_analysis (device))
-                                        return -ENODEV;
-			switch (device->sizes.bp_block) {
-			case 512:
-			case 1024:
-			case 2048:
-			case 4096:
-				break;
-			default:
-				{
-					printk (KERN_INFO PRINTK_HEADER
-						"/dev/%s (devno 0x%04X): Detected invalid blocksize of %d bytes"
-						" Did you format the drive?\n",
-						device->name, devno, device->sizes.bp_block);
-					return -EMEDIUMTYPE;
-				}
-			}
-			blk_init_queue (&device->request_queue, do_dasd_request);
-			blk_queue_headactive (&device->request_queue, 0);
-			elevator_init(&device->request_queue.elevator, ELEVATOR_NOOP);
-			for (i = 0; i < (1 << DASD_PARTN_BITS); i++) {
-                                if (i == 0)
-                                        blk_size[major][minor] = (device->sizes.blocks << device->sizes.s2b_shift) >> 1;
-				else
-					blk_size[major][minor + i] = 0;
-				hardsect_size[major][minor + i] = device->sizes.bp_block;
-				blksize_size[major][minor + i] = device->sizes.bp_block;
-				if (blksize_size[major][minor + i] < 1024)
-					blksize_size[major][minor + i] = 1024;
-
-				max_sectors[major][minor + i] =
-                                        device->discipline->max_blocks << device->sizes.s2b_shift;
-			}
-			check_then_set (&device->level,
-				       DASD_DEVICE_LEVEL_ANALYSIS_PREPARED,
-				       DASD_DEVICE_LEVEL_ANALYSED);
-			dd = &major_info->gendisk;
-			dd->sizes[minor] = (device->sizes.blocks <<
-					    device->sizes.s2b_shift) >> 1;
-                        dd->part[minor].start_sect = 0;
-			{
-				char buffer[5];
-				sprintf(buffer,"%04X",device->devinfo.devno);
-				dd->de_arr[minor>>DASD_PARTN_BITS] = devfs_mk_dir(dasd_devfs_handle,buffer,NULL);
-			}
-#if !(LINUX_VERSION_CODE > KERNEL_VERSION(2,3,98))
-#ifndef MODULE
-			if (flags & 0x80)
+        device_addr = dasd_find_device_addr ( devno );
+        if ( device_addr == NULL ) {
+                rc = -ENODEV;
+                goto out;
+        }
+        device = *device_addr;
+
+        if ( device == NULL ) {
+                from_state = DASD_STATE_DEL;
+                if ( to_state == DASD_STATE_DEL )
+                        goto out;
+        } else {
+                from_state = device->level;
+        }
+
+        if ( from_state == to_state )
+                goto out;
+
+        if ( to_state < from_state )
+                goto shutdown;
+
+        /* First check for bringup */
+        if ( from_state <= DASD_STATE_DEL &&
+             to_state >= DASD_STATE_NEW ) { 
+                rc = dasd_state_del_to_new(device_addr);
+                if ( rc ) {
+                        goto bringup_fail;
+                }
+                device = *device_addr;
+        }
+        if ( from_state <= DASD_STATE_NEW &&
+             to_state >= DASD_STATE_KNOWN ) { 
+                rc = dasd_state_new_to_known( device_addr, devno, discipline );
+                if ( rc ) {
+                        goto bringup_fail;
+                }
+        }
+        if ( from_state <= DASD_STATE_KNOWN &&
+             to_state >= DASD_STATE_ACCEPT ) { 
+                rc = dasd_state_known_to_accept(device);
+                if ( rc ) {
+                        goto bringup_fail;
+                }
+        }
+        if ( dasd_probeonly ) {
+            goto out;
+        }
+        if ( from_state <= DASD_STATE_ACCEPT &&
+             to_state >= DASD_STATE_INIT ) { 
+                rc = dasd_state_accept_to_init(device);
+                if ( rc ) {
+                        goto bringup_fail;
+                }
+        }
+        if ( from_state <= DASD_STATE_INIT &&
+             to_state >= DASD_STATE_READY ) { 
+                rc = -EAGAIN;
+                goto out;
+        }
+        if ( from_state <= DASD_STATE_READY &&
+             to_state >= DASD_STATE_ONLINE ) { 
+                rc = dasd_state_ready_to_online(device);
+                if ( rc ) {
+                        goto bringup_fail;
+                }
+        }
+        goto out;
+ bringup_fail:   /* revert changes */
+#if 0
+        printk (KERN_DEBUG PRINTK_HEADER
+                "failed to set device from state %d to %d at level %d rc %d. Reverting...\n",
+                from_state,to_state,device->level,rc);
 #endif
-#endif				/* KERNEL_VERSION */
-				dasd_partn_detect (device);
-			if (desired_level == DASD_DEVICE_LEVEL_ANALYSED)
-				break;
-		case DASD_DEVICE_LEVEL_ANALYSED:	/* Fallthrough ?? */
-                        dasd_unplug_device(device);
-			check_then_set (&device->level,
-                                        DASD_DEVICE_LEVEL_ANALYSED,
-                                        DASD_DEVICE_LEVEL_ONLINE);
-                        
-			if (desired_level == DASD_DEVICE_LEVEL_ONLINE)
-                                break;
-		case DASD_DEVICE_LEVEL_ONLINE:	
-                        break;
-		default:
-			printk (KERN_WARNING PRINTK_HEADER
-				"Internal error in " __FILE__ " on line %d."
-				" validate_dasd called from %p with "
-				" desired_level = %d, current_level =%d"
-				" Pls send this message and your System.map to"
-				" linux390@de.ibm.com\n",
-				__LINE__, __builtin_return_address (0),
-				desired_level, current_level);
-			break;
-		}
-	} else if (desired_level < current_level) {	/* donwgrade device status */
-		switch (current_level) {
-		case DASD_DEVICE_LEVEL_ONLINE:	/* Fallthrough ?? */
-                        dasd_plug_device(device); 
-			check_then_set (&device->level,
-                                        DASD_DEVICE_LEVEL_ONLINE,
-                                        DASD_DEVICE_LEVEL_ANALYSED);
-			if (desired_level == DASD_DEVICE_LEVEL_ANALYSED)
-                                break;
-                case DASD_DEVICE_LEVEL_ANALYSED:	/* Fallthrough ?? */
-			for (i = 0; i < (1 << DASD_PARTN_BITS); i++) {
-                                __invalidate_buffers(MKDEV(major,minor),1);
-                                blk_size[major][minor] = 0;
-				hardsect_size[major][minor + i] = 0;
-				blksize_size[major][minor + i] = 0;
-				max_sectors[major][minor + i] = 0;
-			}
-			memset (&device->sizes, 0, sizeof (dasd_sizes_t));
-			blk_cleanup_queue (&device->request_queue);
-                        check_then_set (&device->level,
-                                        DASD_DEVICE_LEVEL_ANALYSED,
-                                        DASD_DEVICE_LEVEL_ANALYSIS_PREPARED);
-                        if (desired_level == DASD_DEVICE_LEVEL_ANALYSIS_PREPARED)
-                                break;
-		case DASD_DEVICE_LEVEL_ANALYSIS_PREPARED:
-			check_then_set (&device->level,
-				       DASD_DEVICE_LEVEL_ANALYSIS_PREPARED,
-				       DASD_DEVICE_LEVEL_ANALYSIS_PENDING);
-			if (desired_level == DASD_DEVICE_LEVEL_ANALYSIS_PENDING)
-				break;
-		case DASD_DEVICE_LEVEL_ANALYSIS_PENDING:	/* Fallthrough ?? */
-			check_then_set (&device->level,
-				       DASD_DEVICE_LEVEL_ANALYSIS_PENDING,
-				       DASD_DEVICE_LEVEL_RECOGNIZED);
-			if (desired_level == DASD_DEVICE_LEVEL_RECOGNIZED)
-				break;
-		case DASD_DEVICE_LEVEL_RECOGNIZED:	/* Fallthrough ?? */
-			if (device->discipline->int_handler) {
-				free_irq (irq, &device->dev_status);
-			}
-			device->discipline = NULL;
-                        debug_unregister(device->debug_area);
-			check_then_set (&device->level,
-				       DASD_DEVICE_LEVEL_RECOGNIZED,
-				       DASD_DEVICE_LEVEL_UNKNOWN);
-                        *device_addr = NULL;
-                        kfree(device);
-			if (desired_level == DASD_DEVICE_LEVEL_UNKNOWN)
-				break;
-		case DASD_DEVICE_LEVEL_UNKNOWN:
-			break;
-		default:
-			printk (KERN_WARNING PRINTK_HEADER
-				"Internal error in " __FILE__ " on line %d."
-				" validate_dasd called from %p with "
-				" desired_level = %d, current_level =%d"
-				" Pls send this message and your System.map to"
-				" linux390@de.ibm.com\n",
-				__LINE__, __builtin_return_address (0),
-				desired_level, current_level);
-			break;
-		}
-	}
-	if (rc) {
-		goto exit;
-	}
-      nomem:
-	rc = -ENOMEM;
-      exit:
-	return 0;
+        to_state = from_state;
+        from_state = device->level;
+        
+        /* now do a shutdown */
+ shutdown: 
+        if ( from_state >= DASD_STATE_ONLINE &&
+             to_state <= DASD_STATE_READY ) 
+                if (dasd_state_online_to_ready(device))
+                        BUG();
+        if ( from_state >= DASD_STATE_READY &&
+                      to_state <= DASD_STATE_ACCEPT ) 
+                if ( dasd_state_ready_to_accept(device))
+                        BUG();
+        if ( from_state >= DASD_STATE_ACCEPT &&
+             to_state <= DASD_STATE_KNOWN ) 
+                if ( dasd_state_accept_to_known(device))
+                        BUG();
+        if ( from_state >= DASD_STATE_KNOWN &&
+             to_state <= DASD_STATE_NEW ) 
+                if ( dasd_state_known_to_new(device))
+                        BUG();
+        if ( from_state >= DASD_STATE_NEW &&
+             to_state <= DASD_STATE_DEL) 
+                if (dasd_state_new_to_del(device_addr))
+                        BUG();
+        goto out;
+ out:
+        return rc;
 }
 
 /* SECTION: Procfs stuff */
@@ -2754,29 +3398,16 @@
 	int len;
 } tempinfo_t;
 
-void dasd_fill_inode (struct inode* inode, int fill) {
-    if (fill)
-        MOD_INC_USE_COUNT;
-    else
-        MOD_DEC_USE_COUNT;
+void
+dasd_fill_inode (struct inode *inode, int fill)
+{
+	if (fill)
+		MOD_INC_USE_COUNT;
+	else
+		MOD_DEC_USE_COUNT;
 }
 
-#if (LINUX_VERSION_CODE > KERNEL_VERSION(2,3,98))
 static struct proc_dir_entry *dasd_proc_root_entry = NULL;
-#else
-static struct proc_dir_entry dasd_proc_root_entry =
-{
-	low_ino:0,
-	namelen:4,
-	name:"dasd",
-	mode:S_IFDIR | S_IRUGO | S_IXUGO | S_IWUSR | S_IWGRP,
-	nlink:1,
-	uid:0,
-	gid:0,
-	size:0,
-        fill_inode:dasd_fill_inode
-};
-#endif				/* KERNEL_VERSION */
 static struct proc_dir_entry *dasd_devices_entry;
 static struct proc_dir_entry *dasd_statistics_entry;
 
@@ -2786,94 +3417,138 @@
 	int rc = 0;
 	int size = 1;
 	int len = 0;
-	major_info_t *temp = dasd_major_info;
+	major_info_t *temp = NULL;
 	struct list_head *l;
 	tempinfo_t *info;
 	int i;
+        unsigned long flags;
+        int index = 0;
 
+        MOD_INC_USE_COUNT;
+        spin_lock_irqsave(&discipline_lock,flags);
 	info = (tempinfo_t *) vmalloc (sizeof (tempinfo_t));
 	if (info == NULL) {
-		printk (KERN_WARNING "No memory available for data\n");
-		return -ENOMEM;
+                printk (KERN_WARNING "No memory available for data\n");
+                MOD_DEC_USE_COUNT;
+                return -ENOMEM;
 	} else {
 		file->private_data = (void *) info;
 	}
-	list_for_each(l,&dasd_major_info[0].list) {
-		temp = list_entry(l,major_info_t,list);	
-		for (i = 0; i < 1 << (MINORBITS - DASD_PARTN_BITS); i++) {
-			dasd_device_t *device = temp->dasd_device[i];
-			if (device) {
-				size += 128;
-			}
-		}
+	list_for_each (l, &dasd_major_info[0].list) {
+                size += 128 * 1 << (MINORBITS - DASD_PARTN_BITS);
 	}
-	temp = dasd_major_info;
-	info->data = (char *) vmalloc (size);	/* FIXME! determine space needed in a better way */
+	info->data = (char *) vmalloc (size);	
+	DASD_DRIVER_DEBUG_EVENT (1, dasd_devices_open, "area: %p, size 0x%x",
+				 info->data, size);
 	if (size && info->data == NULL) {
 		printk (KERN_WARNING "No memory available for data\n");
 		vfree (info);
+                MOD_DEC_USE_COUNT;
 		return -ENOMEM;
 	}
-	list_for_each(l,&dasd_major_info[0].list) {
-		temp = list_entry(l,major_info_t,list);	
+	list_for_each (l, &dasd_major_info[0].list) {
+		temp = list_entry (l, major_info_t, list);
 		for (i = 0; i < 1 << (MINORBITS - DASD_PARTN_BITS); i++) {
-			dasd_device_t *device = temp->dasd_device[i];
+			dasd_device_t *device;
+                        int devno = dasd_devno_from_devindex(index+i);
+                        if ( devno == -ENODEV )
+                                continue;
+                        device = temp->dasd_device[i];
 			if (device) {
 				len += sprintf (info->data + len,
-						"%04X(%s) at (%d:%d) is %7s:",
+						"%04X(%s) at (%3d:%3d) is %7s:",
 						device->devinfo.devno,
-						device->discipline ? device->discipline->name : "none",
-				    temp->gendisk.major, i << DASD_PARTN_BITS,
+						device->discipline ?
+						device->
+						discipline->name : "none",
+						temp->gendisk.major,
+						i << DASD_PARTN_BITS,
 						device->name);
 				switch (device->level) {
-				case DASD_DEVICE_LEVEL_UNKNOWN:
-					len += sprintf (info->data + len, "unknown\n");
-					break;
-				case DASD_DEVICE_LEVEL_RECOGNIZED:
-					len += sprintf (info->data + len, "passive");
-					len += sprintf (info->data + len, " at blocksize: %d, %ld blocks, %ld MB\n",
-							device->sizes.bp_block,
-							device->sizes.blocks,
-							((device->sizes.bp_block >> 9) * device->sizes.blocks) >> 11);
+				case DASD_STATE_NEW:
+                                        len +=
+					    sprintf (info->data + len,
+						     "new");
+                                        break;
+				case DASD_STATE_KNOWN:
+					len +=
+					    sprintf (info->data + len,
+						     "detected");
 					break;
-				case DASD_DEVICE_LEVEL_ANALYSIS_PENDING:
-					len += sprintf (info->data + len, "busy   \n");
+				case DASD_STATE_ACCEPT:
+                                        len += sprintf (info->data + len,"accepted");
 					break;
-				case DASD_DEVICE_LEVEL_ANALYSIS_PREPARED:
-					len += sprintf (info->data + len, "n/f    \n");
+				case DASD_STATE_INIT:
+					len +=
+					    sprintf (info->data + len,
+						     "busy   ");
 					break;
-				case DASD_DEVICE_LEVEL_ANALYSED:
-					len += sprintf (info->data + len, "active ");
-					len += sprintf (info->data + len, " at blocksize: %d, %ld blocks, %ld MB\n",
-							device->sizes.bp_block,
-							device->sizes.blocks,
-							((device->sizes.bp_block >> 9) * device->sizes.blocks) >> 11);
-					break;
-				case DASD_DEVICE_LEVEL_ONLINE:
-					len += sprintf (info->data + len, "active ");
-					len += sprintf (info->data + len, " at blocksize: %d, %ld blocks, %ld MB\n",
-							device->sizes.bp_block,
-							device->sizes.blocks,
-							((device->sizes.bp_block >> 9) * device->sizes.blocks) >> 11);
+				case DASD_STATE_READY:
+				case DASD_STATE_ONLINE:
+                                    if ( atomic_read(&device->plugged) )
+                                        len +=
+                                            sprintf (info->data + len,
+                                                     "fenced ");
+                                    else
+                                        len +=
+                                            sprintf (info->data + len,
+                                                     "active ");
+                                    if ( device->sizes.bp_block == 512 ||
+                                         device->sizes.bp_block == 1024 ||
+                                         device->sizes.bp_block == 2048 ||
+                                         device->sizes.bp_block == 4096 )
+					len +=
+					    sprintf (info->data + len,
+						     "at blocksize: %d, %ld blocks, %ld MB",
+						     device->sizes.bp_block,
+						     device->sizes.blocks,
+						     ((device->
+						       sizes.bp_block >> 9) *
+						      device->sizes.
+						      blocks) >> 11);
+                                    else
+                                        len +=
+                                            sprintf (info->data + len,
+                                                     "n/f    ");
 					break;
 				default:
-					len += sprintf (info->data + len, "no stat\n");
+					len +=
+					    sprintf (info->data + len,
+						     "no stat");
 					break;
 				}
-			}
+			} else {
+                                char buffer[7];
+                                dasd_device_name (buffer, i, 0, &temp->gendisk);
+                                if ( devno < 0  ) {
+                                        len += sprintf (info->data + len,
+                                                        "none");
+                                } else {
+                                        len += sprintf (info->data + len,
+                                                        "%04X",devno);
+                                }
+                                len += sprintf (info->data + len,
+                                                "(none) at (%3d:%3d) is %7s: unknown",
+						temp->gendisk.major,
+						i << DASD_PARTN_BITS,
+						buffer);
+                        }
+                        if ( dasd_probeonly )
+                            len += sprintf(info->data + len,"(probeonly)");
+                        len += sprintf(info->data + len,"\n");
 		}
+                index += 1 << (MINORBITS - DASD_PARTN_BITS);
 	}
 	info->len = len;
-#ifdef MODULE
-        MOD_INC_USE_COUNT;
-#endif
+        spin_unlock_irqrestore(&discipline_lock,flags);
 	return rc;
 }
 
 #define MIN(a,b) ((a)<(b)?(a):(b))
 
 static ssize_t
-dasd_devices_read (struct file *file, char *user_buf, size_t user_len, loff_t * offset)
+dasd_generic_read (struct file *file, char *user_buf, size_t user_len,
+		   loff_t * offset)
 {
 	loff_t len;
 	tempinfo_t *p_info = (tempinfo_t *) file->private_data;
@@ -2890,85 +3565,68 @@
 }
 
 static ssize_t
-dasd_devices_write (struct file *file, const char *user_buf, size_t user_len, loff_t * offset)
+dasd_devices_write (struct file *file, const char *user_buf,
+		    size_t user_len, loff_t * offset)
 {
 	char *buffer = vmalloc (user_len+1);
 	int off = 0;
 	char *temp;
-        int irq;
-        int j,target;
-        dasd_range_t *rptr, range;
+	dasd_range_t range;
+        int features = 0;
 
 	if (buffer == NULL)
 		return -ENOMEM;
 	if (copy_from_user (buffer, user_buf, user_len)) {
-		vfree(buffer);
+		vfree (buffer);
 		return -EFAULT;
 	}
 	buffer[user_len] = 0;
-	printk (KERN_INFO PRINTK_HEADER "Now executing %s\n", buffer);
-        if (strncmp ( buffer, "set ",4) &&
-            strncmp ( buffer, "add ",4)){
-                printk (KERN_WARNING PRINTK_HEADER 
-                        "/proc/dasd/devices: only 'set' and 'add' are supported verbs");
-                return -EINVAL;
-        }
-        off += 4;
-        while (!isalnum(buffer[off])) off++;
+	printk (KERN_INFO PRINTK_HEADER "/proc/dasd/devices: '%s'\n", buffer);
+	if (strncmp (buffer, "set ", 4) && strncmp (buffer, "add ", 4)) {
+		printk (KERN_WARNING PRINTK_HEADER
+			"/proc/dasd/devices: only 'set' and 'add' are supported verbs\n");
+		return -EINVAL;
+	}
+	off += 4;
+	while (buffer[off] && !isalnum (buffer[off]))
+		off++;
 	if (!strncmp (buffer + off, "device", strlen ("device"))) {
-		off += strlen("device");
-		while (!isalnum(buffer[off])) off++;
-        }
+		off += strlen ("device");
+		while (buffer[off] && !isalnum (buffer[off]))
+			off++;
+	}
 	if (!strncmp (buffer + off, "range=", strlen ("range="))) {
-		off += strlen("range=");
-		while (!isalnum(buffer[off])) off++;
-        }
-        temp = buffer+off;
-        range.from = dasd_strtoul (temp, &temp);
-        range.to = range.from;
-        if (*temp == '-') {
-                temp++;
-                range.to = dasd_strtoul (temp, &temp);
-        }
-        off = (long)temp - (long)buffer;
-        if ( !strncmp ( buffer, "add",strlen("add"))) {
-                rptr = dasd_add_range (range.from, range.to);
-        } else {
-                rptr = &range;
-        }
-        while (!isalnum(buffer[off])) off++;
-        printk (KERN_INFO PRINTK_HEADER 
-                "varying device range %04X-%04X\n", rptr->from, rptr->to);
-        if ( !strncmp ( buffer, "add",strlen("add")) ||
-             !strncmp ( buffer+off, "on",strlen("on")) ) {
-                target = DASD_DEVICE_LEVEL_ONLINE;
-                for (j = rptr->from; j <= rptr->to; j++) {
-			irq = get_irq_by_devno (j);
-			if (irq >= 0) {
-				dasd_set_device_level (irq, DASD_DEVICE_LEVEL_ONLINE, NULL, 0);
-			}
-		}
-		printk (KERN_INFO PRINTK_HEADER "waiting for responses...\n");
-		{
-			static wait_queue_head_t wait_queue;
-			init_waitqueue_head (&wait_queue);
-			interruptible_sleep_on_timeout (&wait_queue, (5 * HZ) );
+		off += strlen ("range=");
+		while (buffer[off] && !isalnum (buffer[off]))
+			off++;
+	}
+	
+	temp = buffer + off;
+	range.from = dasd_strtoul (temp, &temp, &features);
+	range.to = range.from;
+
+	if (*temp == '-') {
+		temp++;
+		range.to = dasd_strtoul (temp, &temp, &features);
+	}
+
+	off = (long) temp - (long) buffer;
+	if (!strncmp (buffer, "add", strlen ("add"))) {
+		dasd_add_range (range.from, range.to, features);
+                dasd_enable_ranges (&range, NULL, 0);
+	} else { 
+		while (buffer[off] && !isalnum (buffer[off]))
+			off++;
+		if (!strncmp (buffer + off, "on", strlen ("on"))) {
+        	        dasd_enable_ranges (&range, NULL, 0);
+		} else if (!strncmp (buffer + off, "off", strlen ("off"))) {
+        	        dasd_disable_ranges (&range, NULL, 0, 1);
+		} else {
+			printk (KERN_WARNING PRINTK_HEADER
+			"/proc/dasd/devices: parse error in '%s'", buffer);
 		}
-        } else if ( !strncmp ( buffer+off, "off",strlen("off"))) {
-                target = DASD_DEVICE_LEVEL_UNKNOWN;
-        } else {
-                printk (KERN_WARNING PRINTK_HEADER 
-                        "/proc/dasd/devices: parse error in '%s'", buffer);
-                vfree (buffer);
-                return -EINVAL;
-                
-        }
-        for (j = rptr->from; j <= rptr->to; j++) {
-                irq = get_irq_by_devno (j);
-                if (irq >= 0) {
-                        dasd_set_device_level (irq, target, NULL, 0);
-                }
-        }
+	}
+	vfree (buffer);
 	return user_len;
 }
 
@@ -2982,25 +3640,18 @@
 			vfree (p_info->data);
 		vfree (p_info);
 	}
-#ifdef MODULE
-        MOD_DEC_USE_COUNT;
-#endif
+	MOD_DEC_USE_COUNT;
 	return rc;
 }
 
-static struct file_operations dasd_devices_file_ops =
-{
-	read:dasd_devices_read,	/* read */
+static struct file_operations dasd_devices_file_ops = {
+	read:dasd_generic_read,	/* read */
 	write:dasd_devices_write,	/* write */
 	open:dasd_devices_open,	/* open */
 	release:dasd_devices_close,	/* close */
 };
 
-static struct inode_operations dasd_devices_inode_ops =
-{
-#if !(LINUX_VERSION_CODE > KERNEL_VERSION(2,3,98))
-	default_file_ops:&dasd_devices_file_ops		/* file ops */
-#endif				/* LINUX_IS_24 */
+static struct inode_operations dasd_devices_inode_ops = {
 };
 
 static int
@@ -3011,9 +3662,11 @@
 	tempinfo_t *info;
 	int shift, i, help = 0;
 
+        MOD_INC_USE_COUNT;
 	info = (tempinfo_t *) vmalloc (sizeof (tempinfo_t));
 	if (info == NULL) {
 		printk (KERN_WARNING "No memory available for data\n");
+                MOD_DEC_USE_COUNT;
 		return -ENOMEM;
 	} else {
 		file->private_data = (void *) info;
@@ -3023,99 +3676,154 @@
 		printk (KERN_WARNING "No memory available for data\n");
 		vfree (info);
 		file->private_data = NULL;
+                MOD_DEC_USE_COUNT;
 		return -ENOMEM;
 	}
 	for (shift = 0, help = dasd_global_profile.dasd_io_reqs;
-	     help > 8192;
-	     help = help >> 1, shift++) ;
-	len = sprintf (info->data, "%ld dasd I/O requests\n", dasd_global_profile.dasd_io_reqs);
-	len += sprintf (info->data + len, "__<4 ___8 __16 __32 __64 _128 _256 _512 __1k __2k __4k __8k _16k _32k _64k 128k\n");
-	len += sprintf (info->data + len, "_256 _512 __1M __2M __4M __8M _16M _32M _64M 128M 256M 512M __1G __2G __4G _>4G\n");
+	     help > 8192; help = help >> 1, shift++) ;
+	len =
+	    sprintf (info->data, "%d dasd I/O requests\n",
+		     dasd_global_profile.dasd_io_reqs);
+	len +=
+	    sprintf (info->data + len, "with %d sectors(512B each)\n",
+		     dasd_global_profile.dasd_io_sects);
+	len +=
+	    sprintf (info->data + len,
+		     "__<4 ___8 __16 __32 __64 _128 _256 _512 __1k __2k __4k __8k _16k _32k _64k 128k\n");
+	len +=
+	    sprintf (info->data + len,
+		     "_256 _512 __1M __2M __4M __8M _16M _32M _64M 128M 256M 512M __1G __2G __4G _>4G\n");
 	len += sprintf (info->data + len, "Histogram of sizes (512B secs)\n");
 	for (i = 0; i < 16; i++) {
-		len += sprintf (info->data + len, "%4ld ", dasd_global_profile.dasd_io_secs[i] >> shift);
+		len +=
+		    sprintf (info->data + len, "%4d ",
+			     dasd_global_profile.dasd_io_secs[i] >> shift);
 	}
 	len += sprintf (info->data + len, "\n");
 	len += sprintf (info->data + len, "Histogram of I/O times\n");
 	for (i = 0; i < 16; i++) {
-		len += sprintf (info->data + len, "%4ld ", dasd_global_profile.dasd_io_times[i] >> shift);
+		len +=
+		    sprintf (info->data + len, "%4d ",
+			     dasd_global_profile.dasd_io_times[i] >> shift);
 	}
 	len += sprintf (info->data + len, "\n");
 	for (; i < 32; i++) {
-		len += sprintf (info->data + len, "%4ld ", dasd_global_profile.dasd_io_times[i] >> shift);
+		len +=
+		    sprintf (info->data + len, "%4d ",
+			     dasd_global_profile.dasd_io_times[i] >> shift);
 	}
 	len += sprintf (info->data + len, "\n");
-	len += sprintf (info->data + len, "Histogram of I/O times per sector\n");
+	len +=
+	    sprintf (info->data + len, "Histogram of I/O times per sector\n");
 	for (i = 0; i < 16; i++) {
-		len += sprintf (info->data + len, "%4ld ", dasd_global_profile.dasd_io_timps[i] >> shift);
+		len +=
+		    sprintf (info->data + len, "%4d ",
+			     dasd_global_profile.dasd_io_timps[i] >> shift);
 	}
 	len += sprintf (info->data + len, "\n");
 	for (; i < 32; i++) {
-		len += sprintf (info->data + len, "%4ld ", dasd_global_profile.dasd_io_timps[i] >> shift);
+		len +=
+		    sprintf (info->data + len, "%4d ",
+			     dasd_global_profile.dasd_io_timps[i] >> shift);
 	}
 	len += sprintf (info->data + len, "\n");
 	len += sprintf (info->data + len, "Histogram of I/O time till ssch\n");
 	for (i = 0; i < 16; i++) {
-		len += sprintf (info->data + len, "%4ld ", dasd_global_profile.dasd_io_time1[i] >> shift);
+		len +=
+		    sprintf (info->data + len, "%4d ",
+			     dasd_global_profile.dasd_io_time1[i] >> shift);
 	}
 	len += sprintf (info->data + len, "\n");
 	for (; i < 32; i++) {
-		len += sprintf (info->data + len, "%4ld ", dasd_global_profile.dasd_io_time1[i] >> shift);
+		len +=
+		    sprintf (info->data + len, "%4d ",
+			     dasd_global_profile.dasd_io_time1[i] >> shift);
 	}
 	len += sprintf (info->data + len, "\n");
-	len += sprintf (info->data + len, "Histogram of I/O time between ssch and irq\n");
+	len +=
+	    sprintf (info->data + len,
+		     "Histogram of I/O time between ssch and irq\n");
 	for (i = 0; i < 16; i++) {
-		len += sprintf (info->data + len, "%4ld ", dasd_global_profile.dasd_io_time2[i] >> shift);
+		len +=
+		    sprintf (info->data + len, "%4d ",
+			     dasd_global_profile.dasd_io_time2[i] >> shift);
 	}
 	len += sprintf (info->data + len, "\n");
 	for (; i < 32; i++) {
-		len += sprintf (info->data + len, "%4ld ", dasd_global_profile.dasd_io_time2[i] >> shift);
+		len +=
+		    sprintf (info->data + len, "%4d ",
+			     dasd_global_profile.dasd_io_time2[i] >> shift);
 	}
 	len += sprintf (info->data + len, "\n");
-	len += sprintf (info->data + len, "Histogram of I/O time between ssch and irq per sector\n");
+	len +=
+	    sprintf (info->data + len,
+		     "Histogram of I/O time between ssch and irq per sector\n");
 	for (i = 0; i < 16; i++) {
-		len += sprintf (info->data + len, "%4ld ", dasd_global_profile.dasd_io_time2ps[i] >> shift);
+		len +=
+		    sprintf (info->data + len, "%4d ",
+			     dasd_global_profile.dasd_io_time2ps[i] >> shift);
 	}
 	len += sprintf (info->data + len, "\n");
 	for (; i < 32; i++) {
-		len += sprintf (info->data + len, "%4ld ", dasd_global_profile.dasd_io_time2ps[i] >> shift);
+		len +=
+		    sprintf (info->data + len, "%4d ",
+			     dasd_global_profile.dasd_io_time2ps[i] >> shift);
 	}
 	len += sprintf (info->data + len, "\n");
-	len += sprintf (info->data + len, "Histogram of I/O time between irq and end\n");
+	len +=
+	    sprintf (info->data + len,
+		     "Histogram of I/O time between irq and end\n");
 	for (i = 0; i < 16; i++) {
-		len += sprintf (info->data + len, "%4ld ", dasd_global_profile.dasd_io_time3[i] >> shift);
+		len +=
+		    sprintf (info->data + len, "%4d ",
+			     dasd_global_profile.dasd_io_time3[i] >> shift);
 	}
 	len += sprintf (info->data + len, "\n");
 	for (; i < 32; i++) {
-		len += sprintf (info->data + len, "%4ld ", dasd_global_profile.dasd_io_time3[i] >> shift);
+		len +=
+		    sprintf (info->data + len, "%4d ",
+			     dasd_global_profile.dasd_io_time3[i] >> shift);
 	}
 	len += sprintf (info->data + len, "\n");
 	info->len = len;
-#ifdef MODULE
-        MOD_INC_USE_COUNT;
-#endif
 	return rc;
 }
 
-static struct file_operations dasd_statistics_file_ops =
+static ssize_t
+dasd_statistics_write (struct file *file, const char *user_buf,
+		       size_t user_len, loff_t * offset)
 {
-	read:dasd_devices_read,	/* read */
+	char *buffer = vmalloc (user_len);
+
+	if (buffer == NULL)
+		return -ENOMEM;
+	if (copy_from_user (buffer, user_buf, user_len)) {
+		vfree (buffer);
+		return -EFAULT;
+	}
+	buffer[user_len] = 0;
+	printk (KERN_INFO PRINTK_HEADER "/proc/dasd/statictics: '%s'\n",
+		buffer);
+	if (strncmp (buffer, "reset", 4)) {
+		memset (&dasd_global_profile, 0, sizeof (dasd_profile_info_t));
+	}
+	return user_len;
+}
+
+static struct file_operations dasd_statistics_file_ops = {
+	read:dasd_generic_read,	/* read */
 	open:dasd_statistics_open,	/* open */
+	write:dasd_statistics_write,	/* write */
 	release:dasd_devices_close,	/* close */
 };
 
-static struct inode_operations dasd_statistics_inode_ops =
-{
-#if !(LINUX_VERSION_CODE > KERNEL_VERSION(2,3,98))
-	default_file_ops:&dasd_statistics_file_ops	/* file ops */
-#endif				/* LINUX_IS_24 */
+static struct inode_operations dasd_statistics_inode_ops = {
 };
 
 int
 dasd_proc_init (void)
 {
 	int rc = 0;
-#if (LINUX_VERSION_CODE > KERNEL_VERSION(2,3,98))
 	dasd_proc_root_entry = proc_mkdir ("dasd", &proc_root);
 	dasd_devices_entry = create_proc_entry ("devices",
 						S_IFREG | S_IRUGO | S_IWUSR,
@@ -3127,204 +3835,175 @@
 						   dasd_proc_root_entry);
 	dasd_statistics_entry->proc_fops = &dasd_statistics_file_ops;
 	dasd_statistics_entry->proc_iops = &dasd_statistics_inode_ops;
-#else
-	proc_register (&proc_root, &dasd_proc_root_entry);
-	dasd_devices_entry = (struct proc_dir_entry *) kmalloc (sizeof (struct proc_dir_entry), GFP_ATOMIC);
-	if (dasd_devices_entry) {
-		memset (dasd_devices_entry, 0, sizeof (struct proc_dir_entry));
-		dasd_devices_entry->name = "devices";
-		dasd_devices_entry->namelen = strlen ("devices");
-		dasd_devices_entry->low_ino = 0;
-		dasd_devices_entry->mode = (S_IFREG | S_IRUGO | S_IWUSR);
-		dasd_devices_entry->nlink = 1;
-		dasd_devices_entry->uid = 0;
-		dasd_devices_entry->gid = 0;
-		dasd_devices_entry->size = 0;
-		dasd_devices_entry->get_info = NULL;
-		dasd_devices_entry->ops = &dasd_devices_inode_ops;
-		proc_register (&dasd_proc_root_entry, dasd_devices_entry);
-	}
-	dasd_statistics_entry = (struct proc_dir_entry *) kmalloc (sizeof (struct proc_dir_entry), GFP_ATOMIC);
-	if (dasd_statistics_entry) {
-		memset (dasd_statistics_entry, 0, sizeof (struct proc_dir_entry));
-		dasd_statistics_entry->name = "statistics";
-		dasd_statistics_entry->namelen = strlen ("statistics");
-		dasd_statistics_entry->low_ino = 0;
-		dasd_statistics_entry->mode = (S_IFREG | S_IRUGO | S_IWUSR);
-		dasd_statistics_entry->nlink = 1;
-		dasd_statistics_entry->uid = 0;
-		dasd_statistics_entry->gid = 0;
-		dasd_statistics_entry->size = 0;
-		dasd_statistics_entry->get_info = NULL;
-		dasd_statistics_entry->ops = &dasd_statistics_inode_ops;
-		proc_register (&dasd_proc_root_entry, dasd_statistics_entry);
-	}
-#endif				/* LINUX_IS_24 */
 	return rc;
 }
 
 void
 dasd_proc_cleanup (void)
 {
-#if (LINUX_VERSION_CODE > KERNEL_VERSION(2,3,98))
 	remove_proc_entry ("devices", dasd_proc_root_entry);
 	remove_proc_entry ("statistics", dasd_proc_root_entry);
 	remove_proc_entry ("dasd", &proc_root);
-#else
-	proc_unregister (&dasd_proc_root_entry, dasd_statistics_entry->low_ino);
-	kfree (dasd_statistics_entry);
-	proc_unregister (&dasd_proc_root_entry, dasd_devices_entry->low_ino);
-	kfree (dasd_devices_entry);
-	proc_unregister (&proc_root, dasd_proc_root_entry.low_ino);
-#endif				/* LINUX_IS_24 */
 }
 
+int
+dasd_request_module ( void *name ) {
+	int rc = -ERESTARTSYS;
+    	strcpy(current->comm, name);
+   	daemonize();
+   	while ( current->fs->root == NULL ) { /* wait for root-FS */
+        	DECLARE_WAIT_QUEUE_HEAD(wait);
+        	sleep_on_timeout(&wait,HZ); /* wait in steps of one second */
+	} 
+	while ( (rc=request_module(name)) != 0 ) {
+        	DECLARE_WAIT_QUEUE_HEAD(wait);
+		printk ( KERN_INFO "request_module returned %d for %s\n",rc,(char*)name);
+        	sleep_on_timeout(&wait,5* HZ); /* wait in steps of 5 seconds */
+    	}
+    	return rc;
+}
+
+
 /* SECTION: Initializing the driver */
 int __init
 dasd_init (void)
 {
 	int rc = 0;
 	int irq;
-	int j;
-	major_info_t *major_info=NULL;
+	major_info_t *major_info = NULL;
 	struct list_head *l;
-	dasd_range_t *range;
 
 	printk (KERN_INFO PRINTK_HEADER "initializing...\n");
-        dasd_debug_area = debug_register(DASD_NAME,0,2,3*sizeof(long));
-        debug_register_view(dasd_debug_area,&debug_sprintf_view);
-        debug_register_view(dasd_debug_area,&debug_hex_ascii_view);
-        
-        if ( dasd_debug_area == NULL ) {
-                goto failed;
-        }
-        DASD_DRIVER_DEBUG_EVENT(0,dasd_init,"%s","ENTRY");
-	dasd_devfs_handle = devfs_mk_dir(NULL,DASD_NAME,NULL);
-        if ( dasd_devfs_handle < 0 ) {
-                DASD_DRIVER_DEBUG_EVENT(1,dasd_init,"%s","no devfs");
-                goto failed;
-        }
-	list_for_each(l,&dasd_major_info[0].list) {
-		major_info=list_entry(l,major_info_t,list);
-                if ((rc = dasd_register_major (major_info)) > 0) {
-                        DASD_DRIVER_DEBUG_EVENT(1,dasd_init,
-                                                "major %d: success",major_info->gendisk.major);
-                        printk (KERN_INFO PRINTK_HEADER
-                                "Registered successfully to major no %u\n", major_info->gendisk.major);
+	dasd_debug_area = debug_register (DASD_NAME, 0, 2, 4 * sizeof (long));
+	debug_register_view (dasd_debug_area, &debug_sprintf_view);
+	debug_register_view (dasd_debug_area, &debug_hex_ascii_view);
+
+	init_waitqueue_head (&dasd_init_waitq);
+
+	if (dasd_debug_area == NULL) {
+		goto failed;
+	}
+	DASD_DRIVER_DEBUG_EVENT (0, dasd_init, "%s", "ENTRY");
+	dasd_devfs_handle = devfs_mk_dir (NULL, DASD_NAME, NULL);
+	if (dasd_devfs_handle < 0) {
+		DASD_DRIVER_DEBUG_EVENT (1, dasd_init, "%s", "no devfs");
+		goto failed;
+	}
+	list_for_each (l, &dasd_major_info[0].list) {
+		major_info = list_entry (l, major_info_t, list);
+		if ((rc = dasd_register_major (major_info)) > 0) {
+			DASD_DRIVER_DEBUG_EVENT (1, dasd_init,
+						 "major %d: success",
+						 major_info->gendisk.major);
+			printk (KERN_INFO PRINTK_HEADER
+				"Registered successfully to major no %u\n",
+				major_info->gendisk.major);
 		} else {
-                        DASD_DRIVER_DEBUG_EVENT(1,dasd_init,
-                                                "major %d: failed",major_info->gendisk.major);
+			DASD_DRIVER_DEBUG_EVENT (1, dasd_init,
+						 "major %d: failed",
+						 major_info->gendisk.major);
 			printk (KERN_WARNING PRINTK_HEADER
-				"Couldn't register successfully to major no %d\n", major_info->gendisk.major);
+				"Couldn't register successfully to major no %d\n",
+				major_info->gendisk.major);
 			/* revert registration of major infos */
-                        goto failed;
+			goto failed;
 		}
 	}
 #ifndef MODULE
 	dasd_split_parm_string (dasd_parm_string);
 #endif				/* ! MODULE */
 	dasd_parse (dasd);
-	dasd_init_emergency_req ();
 
 	rc = dasd_proc_init ();
 	if (rc) {
-                DASD_DRIVER_DEBUG_EVENT(1,dasd_init,
-                                        "%s","no proc-FS");
-                goto failed;
+		DASD_DRIVER_DEBUG_EVENT (1, dasd_init, "%s", "no proc-FS");
+		goto failed;
 	}
 	genhd_dasd_name = dasd_device_name;
-	genhd_dasd_fillgeo = dasd_fillgeo;
 
+	if (dasd_autodetect) {	/* update device range to all devices */
+		for (irq = get_irq_first (); irq != -ENODEV;
+		     irq = get_irq_next (irq)) {
+			int devno = get_devno_by_irq (irq);
+			int index = dasd_devindex_from_devno (devno);
+			if (index == -ENODEV) {	/* not included in ranges */
+				DASD_DRIVER_DEBUG_EVENT (2, dasd_init,
+							 "add %04X to range",
+							 devno);
+				dasd_add_range (devno, devno, DASD_DEFAULT_FEATURES);
+			}
+		}
+	}
+
+	if (MACHINE_IS_VM) {
+#ifdef CONFIG_DASD_DIAG
+		rc = dasd_diag_init ();
+		if (rc == 0) {
+			DASD_DRIVER_DEBUG_EVENT (1, dasd_init,
+						 "DIAG discipline %s",
+						 "success");
+			printk (KERN_INFO PRINTK_HEADER
+				"Registered DIAG discipline successfully\n");
+		} else {
+			DASD_DRIVER_DEBUG_EVENT (1, dasd_init,
+						 "DIAG discipline %s",
+						 "failed");
+			goto failed;
+		}
+#endif /* CONFIG_DASD_DIAG */
+#if defined(CONFIG_DASD_DIAG_MODULE) && defined(CONFIG_DASD_AUTO_DIAG)
+                kernel_thread(dasd_request_module,"dasd_diag_mod",SIGCHLD);
+#endif /* CONFIG_DASD_AUTO_DIAG */
+	}
 #ifdef CONFIG_DASD_ECKD
 	rc = dasd_eckd_init ();
 	if (rc == 0) {
-                DASD_DRIVER_DEBUG_EVENT(1,dasd_init,
-                                        "ECKD discipline %s","success");
+		DASD_DRIVER_DEBUG_EVENT (1, dasd_init,
+					 "ECKD discipline %s", "success");
 		printk (KERN_INFO PRINTK_HEADER
 			"Registered ECKD discipline successfully\n");
 	} else {
-                DASD_DRIVER_DEBUG_EVENT(1,dasd_init,
-                                        "ECKD discipline %s","failed");
-                goto failed;
-	}
-#endif				/* CONFIG_DASD_ECKD */
+		DASD_DRIVER_DEBUG_EVENT (1, dasd_init,
+					 "ECKD discipline %s", "failed");
+		goto failed;
+	}
+#endif /* CONFIG_DASD_ECKD */
+#if defined(CONFIG_DASD_ECKD_MODULE) && defined(CONFIG_DASD_AUTO_ECKD)
+        kernel_thread(dasd_request_module,"dasd_eckd_mod",SIGCHLD);
+#endif /* CONFIG_DASD_AUTO_ECKD */
 #ifdef CONFIG_DASD_FBA
 	rc = dasd_fba_init ();
 	if (rc == 0) {
-                DASD_DRIVER_DEBUG_EVENT(1,dasd_init,
-                                        "FBA discipline %s","success");
+		DASD_DRIVER_DEBUG_EVENT (1, dasd_init,
+					 "FBA discipline %s", "success");
 
 		printk (KERN_INFO PRINTK_HEADER
 			"Registered FBA discipline successfully\n");
 	} else {
-                DASD_DRIVER_DEBUG_EVENT(1,dasd_init,
-                                        "FBA discipline %s","failed");
-                goto failed;
-	}
-#endif				/* CONFIG_DASD_FBA */
-#ifdef CONFIG_DASD_DIAG
-	if (MACHINE_IS_VM) {
-		rc = dasd_diag_init ();
-		if (rc == 0) {
-                        DASD_DRIVER_DEBUG_EVENT(1,dasd_init,
-                                                "DIAG discipline %s","success");
-			printk (KERN_INFO PRINTK_HEADER
-				"Registered DIAG discipline successfully\n");
-		} else {
-                        DASD_DRIVER_DEBUG_EVENT(1,dasd_init,
-                                                "DIAG discipline %s","failed");
-                        goto failed;
-		}
-	}
-#endif				/* CONFIG_DASD_DIAG */
-	rc = 0;
-	if (dasd_autodetect) { /* update device range to all devices */
-		for (irq = get_irq_first (); irq != -ENODEV; 
-                     irq = get_irq_next (irq)) {
-			int devno = get_devno_by_irq (irq);
-			int index = dasd_devindex_from_devno (devno);
-			if (index == -ENODEV) {		/* not included in ranges */
-                                DASD_DRIVER_DEBUG_EVENT(2,dasd_init,
-                                                        "add %04X to range",
-                                                        devno);
-				dasd_add_range (devno, 0);
-                        }
+		DASD_DRIVER_DEBUG_EVENT (1, dasd_init,
+					 "FBA discipline %s", "failed");
+		goto failed;
+	}
+#endif /* CONFIG_DASD_FBA */
+#if defined(CONFIG_DASD_FBA_MODULE) && defined(CONFIG_DASD_AUTO_FBA)
+        kernel_thread(dasd_request_module,"dasd_fba_mod",SIGCHLD);
+#endif /* CONFIG_DASD_AUTO_FBA */
+        {
+                char **disc=dasd_disciplines;
+                while (*disc) {
+                        kernel_thread(dasd_request_module,*disc,SIGCHLD);
+                        disc++;
                 }
         }
-	for (range = dasd_range_head; range; range = range->next) {
-		for (j = range->from; j <= range->to; j++) {
-			irq = get_irq_by_devno (j);
-                        if (irq >= 0)
-                                DASD_DRIVER_DEBUG_EVENT(2,dasd_init,
-                                                        "1st step in initialization irq 0x%x",irq);
-                        dasd_set_device_level (irq, DASD_DEVICE_LEVEL_ONLINE,
-                                               NULL, 0);
-		}
-	}
-	printk (KERN_INFO PRINTK_HEADER "waiting for responses...\n");
-	{
-		static wait_queue_head_t wait_queue;
-		init_waitqueue_head (&wait_queue);
-		interruptible_sleep_on_timeout (&wait_queue,
-						(5 * HZ) );
-	}
-	for (range = dasd_range_head; range; range = range->next) {
-		for (j = range->from; j <= range->to; j++) {
-			irq = get_irq_by_devno (j);
-			if (irq >= 0) {
-                                DASD_DRIVER_DEBUG_EVENT(2,dasd_init,
-                                                        "2nd step in initialization irq 0x%x",irq);
-				dasd_set_device_level (irq, DASD_DEVICE_LEVEL_ONLINE,
-						       NULL, 0);
-			}
-		}
-	}
-        goto out;
- failed:
-	printk (KERN_INFO PRINTK_HEADER "initialization not performed due to errors\n");
-        cleanup_dasd();
- out:
-        DASD_DRIVER_DEBUG_EVENT(0,dasd_init,"%s","LEAVE");
+
+	rc = 0;
+	goto out;
+      failed:
+	printk (KERN_INFO PRINTK_HEADER
+		"initialization not performed due to errors\n");
+	cleanup_dasd ();
+      out:
+	DASD_DRIVER_DEBUG_EVENT (0, dasd_init, "%s", "LEAVE");
 	printk (KERN_INFO PRINTK_HEADER "initialization finished\n");
 	return rc;
 }
@@ -3332,95 +4011,78 @@
 static void
 cleanup_dasd (void)
 {
-	int i,j,rc;
-	int irq;
-	major_info_t *major_info=NULL;
-	struct list_head *l;
-	dasd_range_t *range, *next;
+	int i,rc=0;
+	major_info_t *major_info = NULL;
+	struct list_head *l,*n;
+	dasd_range_t *range;
 
 	printk (KERN_INFO PRINTK_HEADER "shutting down\n");
         DASD_DRIVER_DEBUG_EVENT(0,"cleanup_dasd","%s","ENTRY");
-	for (range = dasd_range_head; range; range = range->next) {
-		for (j = range->from; j <= range->to; j++) {
-			irq = get_irq_by_devno (j);
-			if (irq >= 0) {
-                                DASD_DRIVER_DEBUG_EVENT(2,"cleanup_dasd",
-                                                        "shutdown irq 0x%x",irq);
-				dasd_set_device_level (irq, DASD_DEVICE_LEVEL_UNKNOWN,
-						       NULL, 0);
-			}
-		}
-	}
+	dasd_disable_ranges (&dasd_range_head, NULL, 1, 1);
+        if (MACHINE_IS_VM) {
 #ifdef CONFIG_DASD_DIAG
-	if (MACHINE_IS_VM) {
-		dasd_diag_cleanup ();
-                DASD_DRIVER_DEBUG_EVENT(1,"cleanup_dasd",
-                                        "DIAG discipline %s","success");
+                dasd_diag_cleanup ();
+                DASD_DRIVER_DEBUG_EVENT (1, "cleanup_dasd",
+                                         "DIAG discipline %s", "success");
                 printk (KERN_INFO PRINTK_HEADER
-                        "De-Registered DIAG discipline successfully\n");
+			"De-Registered DIAG discipline successfully\n");
+#endif /* CONFIG_DASD_ECKD_BUILTIN */
 	}
-#endif				/* CONFIG_DASD_DIAG */
 #ifdef CONFIG_DASD_FBA
 	dasd_fba_cleanup ();
-        DASD_DRIVER_DEBUG_EVENT(1,"cleanup_dasd",
-                                "FBA discipline %s","success");
-        printk (KERN_INFO PRINTK_HEADER
-                "De-Registered FBA discipline successfully\n");
-#endif				/* CONFIG_DASD_FBA */
+	DASD_DRIVER_DEBUG_EVENT (1, "cleanup_dasd",
+				 "FBA discipline %s", "success");
+	printk (KERN_INFO PRINTK_HEADER
+		"De-Registered FBA discipline successfully\n");
+#endif /* CONFIG_DASD_ECKD_BUILTIN */
 #ifdef CONFIG_DASD_ECKD
 	dasd_eckd_cleanup ();
-        DASD_DRIVER_DEBUG_EVENT(1,"cleanup_dasd",
-                                "ECKD discipline %s","success");
-        printk (KERN_INFO PRINTK_HEADER
-                "De-Registered ECKD discipline successfully\n");
-#endif				/* CONFIG_DASD_ECKD */
+	DASD_DRIVER_DEBUG_EVENT (1, "cleanup_dasd",
+				 "ECKD discipline %s", "success");
+	printk (KERN_INFO PRINTK_HEADER
+		"De-Registered ECKD discipline successfully\n");
+#endif /* CONFIG_DASD_ECKD_BUILTIN */
         
 	dasd_proc_cleanup ();
-	dasd_cleanup_emergency_req ();
-
-	list_for_each(l,&dasd_major_info[0].list) {
-		major_info=list_entry(l,major_info_t,list);	
+        
+	list_for_each_safe (l, n, &dasd_major_info[0].list) {
+		major_info = list_entry (l, major_info_t, list);
 		for (i = 0; i < DASD_PER_MAJOR; i++) {
 			kfree (major_info->dasd_device[i]);
 		}
-		if ((major_info -> flags & DASD_MAJOR_INFO_REGISTERED) &&
+		if ((major_info->flags & DASD_MAJOR_INFO_REGISTERED) &&
 		    (rc = dasd_unregister_major (major_info)) == 0) {
-                        DASD_DRIVER_DEBUG_EVENT(1,"cleanup_dasd",
-                                                "major %d: success",major_info->gendisk.major);
+			DASD_DRIVER_DEBUG_EVENT (1, "cleanup_dasd",
+						 "major %d: success",
+						 major_info->gendisk.major);
 			printk (KERN_INFO PRINTK_HEADER
-				"Unregistered successfully from major no %u\n", major_info->gendisk.major);
+				"Unregistered successfully from major no %u\n",
+				major_info->gendisk.major);
 		} else {
-                        DASD_DRIVER_DEBUG_EVENT(1,"cleanup_dasd",
-                                                "major %d: failed",major_info->gendisk.major);
+			DASD_DRIVER_DEBUG_EVENT (1, "cleanup_dasd",
+						 "major %d: failed",
+						 major_info->gendisk.major);
 			printk (KERN_WARNING PRINTK_HEADER
-				"Couldn't unregister successfully from major no %d rc = %d\n", major_info->gendisk.major, rc);
-		}
-	}
-
+				"Couldn't unregister successfully from major no %d rc = %d\n",
+				major_info->gendisk.major, rc);
+  		}
+  	}
+	list_for_each_safe (l, n, &dasd_range_head.list) {
+		range = list_entry (l, dasd_range_t, list);
+                dasd_remove_range(range);
+        }
 
-	range = dasd_range_head;
-	while (range) {
-		next = range->next;
-                dasd_remove_range (range);
-		if (next == NULL)
-			break;
-		else
-			range = next;
-	}
-	dasd_range_head = NULL;
-        
 #ifndef MODULE
-        for( j = 0; j < 256; j++ )
-                if ( dasd[j] ) {
-                        kfree(dasd[j]);
-                        dasd[j] = NULL;
+        for( i = 0; i < 256; i++ )
+                if ( dasd[i] ) {
+                        kfree(dasd[i]);
+                        dasd[i] = NULL;
                 }
 #endif /* MODULE */
         if (dasd_devfs_handle) 
                 devfs_unregister(dasd_devfs_handle);
         if (dasd_debug_area != NULL )
                 debug_unregister(dasd_debug_area);
-
 	printk (KERN_INFO PRINTK_HEADER "shutdown completed\n");
         DASD_DRIVER_DEBUG_EVENT(0,"cleanup_dasd","%s","LEAVE");
 }
@@ -3430,7 +4092,7 @@
 init_module (void)
 {
 	int rc = 0;
-	return dasd_init ();
+	rc = dasd_init ();
 	return rc;
 }
 
@@ -3449,7 +4111,7 @@
  * of the file.
  * ---------------------------------------------------------------------------
  * Local variables:
- * c-indent-level: 4 
+ * c-indent-level: 4
  * c-brace-imaginary-offset: 0
  * c-brace-offset: -4
  * c-argdecl-indent: 4
diff -u --recursive --new-file v2.4.7/linux/drivers/s390/block/dasd_3370_erp.c linux/drivers/s390/block/dasd_3370_erp.c
--- v2.4.7/linux/drivers/s390/block/dasd_3370_erp.c	Tue Feb 13 14:13:44 2001
+++ linux/drivers/s390/block/dasd_3370_erp.c	Sun Aug  5 13:12:41 2001
@@ -6,8 +6,9 @@
  */
 
 #include <asm/ccwcache.h>
-#include <asm/dasd.h>
 
+#include "dasd_int.h"
+#include "dasd_3370_erp.h"
 #ifdef PRINTK_HEADER
 #undef PRINTK_HEADER
 #define PRINTK_HEADER "dasd_erp(3370)"
@@ -29,7 +30,7 @@
  *   dasd_era_fatal     for all fatal (unrecoverable errors)
  *   dasd_era_recover   for all others.
  */
-dasd_era_t
+dasd_era_t 
 dasd_3370_erp_examine (ccw_req_t * cqr, devstat_t * stat)
 {
 	char *sense = stat->ii.sense.data;
@@ -37,7 +38,7 @@
 	/* check for successful execution first */
 	if (stat->cstat == 0x00 &&
 	    stat->dstat == (DEV_STAT_CHN_END | DEV_STAT_DEV_END))
-		return dasd_era_none;
+		    return dasd_era_none;
 	if (sense[0] & 0x80) {	/* CMD reject */
 		return dasd_era_fatal;
 	}
diff -u --recursive --new-file v2.4.7/linux/drivers/s390/block/dasd_3370_erp.h linux/drivers/s390/block/dasd_3370_erp.h
--- v2.4.7/linux/drivers/s390/block/dasd_3370_erp.h	Wed Dec 31 16:00:00 1969
+++ linux/drivers/s390/block/dasd_3370_erp.h	Sun Aug  5 13:12:41 2001
@@ -0,0 +1,15 @@
+/* 
+ * File...........: linux/drivers/s390/block/dasd_3370_erp.h
+ * Author(s)......: Horst Hummel <Horst Hummel@de.ibm.com>
+ * Bugreports.to..: <Linux390@de.ibm.com>
+ * (C) IBM Corporation, IBM Deutschland Entwicklung GmbH, 2000
+ *
+ * History of changes (starts July 2000)
+ */
+
+#ifndef DASD_3370_ERP_H
+#define DASD_3370_ERP_H
+
+dasd_era_t dasd_3370_erp_examine (ccw_req_t *, devstat_t *);
+
+#endif				/* DASD_3990_ERP_H */
diff -u --recursive --new-file v2.4.7/linux/drivers/s390/block/dasd_3990_erp.c linux/drivers/s390/block/dasd_3990_erp.c
--- v2.4.7/linux/drivers/s390/block/dasd_3990_erp.c	Wed Apr 11 19:02:28 2001
+++ linux/drivers/s390/block/dasd_3990_erp.c	Sun Aug  5 13:12:41 2001
@@ -4,13 +4,17 @@
  *                  Holger Smolinski <Holger.Smolinski@de.ibm.com>
  * Bugreports.to..: <Linux390@de.ibm.com>
  * (C) IBM Corporation, IBM Deutschland Entwicklung GmbH, 2000, 2001
+ *
+ * History of changes:
+ * 05/14/01 fixed PL030160GTO (BUG() in erp_action_5)
  */
 
 #include <asm/ccwcache.h>
 #include <asm/idals.h>
-#include <asm/dasd.h>
 #include <asm/s390io.h>
 #include <linux/timer.h>
+
+#include "dasd_int.h"
 #include "dasd_eckd.h"
 #include "dasd_3990_erp.h"
 
@@ -24,7 +28,6 @@
  * SECTION DEBUG ROUTINES
  ***************************************************************************** 
  */
-#ifdef ERP_DEBUG
 void
 log_erp_chain (ccw_req_t *cqr,
                int       caller,
@@ -34,104 +37,100 @@
         ccw_req_t     *loop_cqr = cqr;
 	dasd_device_t *device   = cqr->device;
 
-        char    *page = (char *)get_free_page(GFP_ATOMIC);
-        int     len = 0;
         int     i;
         char    *nl, 
                 *end_cqr,
                 *begin, 
                 *end;
+        
+        /* dump sense data */
+        if (device->discipline            && 
+            device->discipline->dump_sense  ) {
 
-        if ( page == NULL ) {
-                printk (KERN_WARNING PRINTK_HEADER
-                        "No memory to dump ERP chain\n");
-                return;
-        }        
-                        
+                device->discipline->dump_sense (device, 
+                                                cqr);
+        }
+
+        /* log the channel program */
         while (loop_cqr != NULL) {
                 
-                memset (page, 0, 4096);
-                len = 0;
-
-                len += sprintf ( page + len, KERN_WARNING PRINTK_HEADER 
-                                 "device %04X on irq %d: (%s) ERP chain report for req: %p\n",
-                                 device->devinfo.devno,
-                                 device->devinfo.irq,
-                                 caller == 0 ? "EXAMINE" : "ACTION",
-                                 loop_cqr);
+                DASD_MESSAGE (KERN_ERR, device, 
+                              "(%s) ERP chain report for req: %p\n",
+                              caller == 0 ? "EXAMINE" : "ACTION",
+                              loop_cqr);
                 
                 nl      = (char *) loop_cqr;
                 end_cqr = nl + sizeof (ccw_req_t); 
-
+                
                 while (nl < end_cqr) {
-
-                        len += sprintf ( page + len, KERN_WARNING PRINTK_HEADER 
-                                         "%p: %02x%02x%02x%02x %02x%02x%02x%02x "
-                                         "%02x%02x%02x%02x %02x%02x%02x%02x\n",
-                                         nl,
-                                         nl[0], nl[1], nl[2], nl[3],
-                                         nl[4], nl[5], nl[6], nl[7],
-                                         nl[8], nl[9], nl[10], nl[11],
-                                         nl[12], nl[13], nl[14], nl[15]);
+                        
+                        DASD_MESSAGE (KERN_ERR, device, 
+                                      "%p: %02x%02x%02x%02x %02x%02x%02x%02x "
+                                      "%02x%02x%02x%02x %02x%02x%02x%02x\n",
+                                      nl,
+                                      nl[0], nl[1], nl[2], nl[3],
+                                      nl[4], nl[5], nl[6], nl[7],
+                                      nl[8], nl[9], nl[10], nl[11],
+                                      nl[12], nl[13], nl[14], nl[15]);
                         nl +=16;
                 }        
                 
                 nl  = (char *) loop_cqr->cpaddr;
+                
+                if (loop_cqr->cplength > 40) { /* log only parts of the CP */
 
-                if (loop_cqr->cplength > 40 ) { /* log only parts of the CP */
-
-                        len += sprintf ( page + len, KERN_WARNING PRINTK_HEADER 
-                                         "Start of channel program:\n");
-
+                        DASD_MESSAGE (KERN_ERR, device, "%s",
+                                      "Start of channel program:\n");
+                        
                         for (i = 0; i < 20; i += 2) { 
-
-                                len += sprintf ( page + len, KERN_WARNING PRINTK_HEADER 
-                                                 "%p: %02x%02x%02x%02x %02x%02x%02x%02x "
-                                                 "%02x%02x%02x%02x %02x%02x%02x%02x\n",
-                                                 nl,
-                                                 nl[0], nl[1], nl[2], nl[3],
-                                                 nl[4], nl[5], nl[6], nl[7],
-                                                 nl[8], nl[9], nl[10], nl[11],
-                                                 nl[12], nl[13], nl[14], nl[15]);
+                                
+                                DASD_MESSAGE (KERN_ERR, device, 
+                                              "%p: %02x%02x%02x%02x %02x%02x%02x%02x "
+                                              "%02x%02x%02x%02x %02x%02x%02x%02x\n",
+                                              nl,
+                                              nl[0], nl[1], nl[2], nl[3],
+                                              nl[4], nl[5], nl[6], nl[7],
+                                              nl[8], nl[9], nl[10], nl[11],
+                                              nl[12], nl[13], nl[14], nl[15]);
                                 
                                 nl += 16;
                         }
                         
-                        len += sprintf ( page + len, KERN_WARNING PRINTK_HEADER 
-                                         "End of channel program:\n");
+                        DASD_MESSAGE (KERN_ERR, device, "%s",
+                                      "End of channel program:\n");
                         
                         nl  = (char *) loop_cqr->cpaddr;
                         nl  += ((loop_cqr->cplength - 10) * 8);
                         
                         for (i = 0; i < 20; i += 2) { 
                                 
-                                len += sprintf ( page + len, KERN_WARNING PRINTK_HEADER 
-                                                 "%p: %02x%02x%02x%02x %02x%02x%02x%02x "
-                                                 "%02x%02x%02x%02x %02x%02x%02x%02x\n",
-                                                 nl,
-                                                 nl[0], nl[1], nl[2], nl[3],
-                                                 nl[4], nl[5], nl[6], nl[7],
-                                                 nl[8], nl[9], nl[10], nl[11],
-                                                 nl[12], nl[13], nl[14], nl[15]);
+                                DASD_MESSAGE (KERN_ERR, device, 
+                                              "%p: %02x%02x%02x%02x %02x%02x%02x%02x "
+                                              "%02x%02x%02x%02x %02x%02x%02x%02x\n",
+                                              nl,
+                                              nl[0], nl[1], nl[2], nl[3],
+                                              nl[4], nl[5], nl[6], nl[7],
+                                              nl[8], nl[9], nl[10], nl[11],
+                                              nl[12], nl[13], nl[14], nl[15]);
                                 
                                 nl += 16;
                         }
                         
                 } else { /* log the whole CP */
                         
-                        len += sprintf ( page + len, KERN_WARNING PRINTK_HEADER 
-                                         "Channel program (complete):\n");
+                        DASD_MESSAGE (KERN_ERR, device, "%s",
+                                      "Channel program (complete):\n");
                         
                         for (i = 0; i < (loop_cqr->cplength + 4); i += 2) { 
                                 
-                                len += sprintf ( page + len, KERN_WARNING PRINTK_HEADER 
-                                                 "%p: %02x%02x%02x%02x %02x%02x%02x%02x "
-                                                 "%02x%02x%02x%02x %02x%02x%02x%02x\n",
-                                                 nl,
-                                                 nl[0], nl[1], nl[2], nl[3],
-                                                 nl[4], nl[5], nl[6], nl[7],
-                                                 nl[8], nl[9], nl[10], nl[11],
-                                                 nl[12], nl[13], nl[14], nl[15]);
+                                DASD_MESSAGE (KERN_ERR, device, 
+                                              "%p: %02x%02x%02x%02x %02x%02x%02x%02x "
+                                              "%02x%02x%02x%02x %02x%02x%02x%02x\n",
+                                              nl,
+                                              nl[0], nl[1], nl[2], nl[3],
+                                              nl[4], nl[5], nl[6], nl[7],
+                                              nl[8], nl[9], nl[10], nl[11],
+                                              nl[12], nl[13], nl[14], nl[15]);
                                 
                                 nl += 16;
                         }
@@ -140,51 +139,47 @@
                 /* log bytes arround failed CCW if not already done */ 
                 begin = (char *) loop_cqr->cpaddr;
                 end   = begin + ((loop_cqr->cplength+4) * 8);
-                nl = (void *)cpa;
+                nl = (void *)(long)cpa;
 
                 if (loop_cqr == cqr) {  /* log only once */
  
-                        if ((loop_cqr->cplength > 40) ||     /* not whole CP was logged or */
-                            ((nl < begin ) &&                /* CCW is outside logged CP   */
-                             (nl > end   )          )   ) {
+                        /* if not whole CP logged OR CCW outside logged CP */
+                        if ((loop_cqr->cplength > 40) ||   
+                            ((nl < begin        ) &&
+                             (nl > end          )   )   ) {
                         
-                                nl -= 10*8;     /* start some bytes before */          
+                                nl -= 10*8;     /* start some bytes before */
                                 
-                                len += sprintf ( page + len, KERN_WARNING PRINTK_HEADER 
-                                                 "Failed CCW (%p) (area):\n",
-                                                 (void *)cpa);
+                                DASD_MESSAGE (KERN_ERR, device, 
+                                                "Failed CCW (%p) (area):\n",
+                                                (void *)(long)cpa);
                                 
                                 for (i = 0; i < 20; i += 2) { 
                                         
-                                        len += sprintf ( page + len, KERN_WARNING PRINTK_HEADER 
-                                                         "%p: %02x%02x%02x%02x %02x%02x%02x%02x "
-                                                         "%02x%02x%02x%02x %02x%02x%02x%02x\n",
-                                                         nl,
-                                                         nl[0], nl[1], nl[2], nl[3],
-                                                         nl[4], nl[5], nl[6], nl[7],
-                                                         nl[8], nl[9], nl[10], nl[11],
-                                                         nl[12], nl[13], nl[14], nl[15]);
+                                        DASD_MESSAGE (KERN_ERR, device, 
+                                                      "%p: %02x%02x%02x%02x %02x%02x%02x%02x "
+                                                      "%02x%02x%02x%02x %02x%02x%02x%02x\n",
+                                                      nl,
+                                                      nl[0], nl[1], nl[2], nl[3],
+                                                      nl[4], nl[5], nl[6], nl[7],
+                                                      nl[8], nl[9], nl[10], nl[11],
+                                                      nl[12], nl[13], nl[14], nl[15]);
                                         
                                         nl += 16;
                                 }
                                 
                         } else {
                                 
-                                len += sprintf ( page + len, KERN_WARNING PRINTK_HEADER 
-                                                 "Failed CCW (%p) already logged\n",
-                                                 (void *)cpa);
+                                DASD_MESSAGE (KERN_ERR, device, 
+                                              "Failed CCW (%p) already logged\n",
+                                              (void *)(long)cpa);
                         }
                 }
-
-                printk ("%s", page);
+                
                 loop_cqr = loop_cqr->refers;
         }
         
-        free_page ((unsigned long) page);
-
 } /* end log_erp_chain */
-#endif /* ERP_DEBUG */
-
 
 /*
  ***************************************************************************** 
@@ -211,32 +206,46 @@
  *   dasd_era_recover   for all others.
  */
 dasd_era_t
-dasd_3990_erp_examine_24 (char *sense)
+dasd_3990_erp_examine_24 (ccw_req_t *cqr,
+                          char      *sense)
 {
 
-	/* check for 'Command Recejct' which is always a fatal error  */
-	if (sense[0] & SNS0_CMD_REJECT) {
-		if (sense[2] & SNS2_ENV_DATA_PRESENT) {
-			return dasd_era_recover;
-		} else {
-			return dasd_era_fatal;
-		}
+        dasd_device_t *device = cqr->device;
+        
+	/* check for 'Command Reject' */
+	if ((  sense[0] & SNS0_CMD_REJECT       ) &&
+	    (!(sense[2] & SNS2_ENV_DATA_PRESENT))   ) {
+
+                DASD_MESSAGE (KERN_ERR, device, "%s",
+                              "EXAMINE 24: Command Reject detected - "
+                              "fatal error");
+
+                return dasd_era_fatal;
 	}
-	/* check for 'Invalid Track Format'                           */
-	if (sense[1] & SNS1_INV_TRACK_FORMAT) {
-		if (sense[2] & SNS2_ENV_DATA_PRESENT) {
-			return dasd_era_recover;
-		} else {
-			return dasd_era_fatal;
-		}
+
+	/* check for 'Invalid Track Format' */
+	if ((  sense[1] & SNS1_INV_TRACK_FORMAT ) &&
+            (!(sense[2] & SNS2_ENV_DATA_PRESENT))   ) {
+
+                DASD_MESSAGE (KERN_ERR, device, "%s",
+                              "EXAMINE 24: Invalid Track Format detected "
+                              "- fatal error");
+
+                return dasd_era_fatal;
 	}
-	/* check for 'No Record Found'                                */
+
+	/* check for 'No Record Found' */
 	if (sense[1] & SNS1_NO_REC_FOUND) {
-            return dasd_era_fatal;
+                
+                DASD_MESSAGE (KERN_ERR, device, "%s",
+                              "EXAMINE 24: No Record Found detected "
+                              "- fatal error");
+
+                return dasd_era_fatal;
 	}
-	/* return recoverable for all others                          */
-	return dasd_era_recover;
 
+	/* return recoverable for all others */
+  	return dasd_era_recover;
 } /* END dasd_3990_erp_examine_24 */
 
 /*
@@ -253,19 +262,27 @@
  *   dasd_era_recover   for recoverable others.
  */
 dasd_era_t
-dasd_3990_erp_examine_32 (char *sense)
+dasd_3990_erp_examine_32 (ccw_req_t *cqr,
+                          char      *sense)
 {
 
+        dasd_device_t *device = cqr->device;
+
 	switch (sense[25]) {
 	case 0x00:
 		return dasd_era_none;
+
 	case 0x01:
+                DASD_MESSAGE (KERN_ERR, device, "%s",
+                              "EXAMINE 32: fatal error");
 		return dasd_era_fatal;
+
 	default:
+
 		return dasd_era_recover;
 	}
 
-}				/* end dasd_3990_erp_examine_32 */
+} /* end dasd_3990_erp_examine_32 */
 
 /*
  * DASD_3990_ERP_EXAMINE 
@@ -292,31 +309,30 @@
         dasd_era_t era    = dasd_era_recover;
 
 	/* check for successful execution first */
-	if (stat->cstat == 0x00 &&
-	    stat->dstat == (DEV_STAT_CHN_END | DEV_STAT_DEV_END))
+	if (stat->cstat == 0x00                                 &&
+	    stat->dstat == (DEV_STAT_CHN_END | DEV_STAT_DEV_END)  )
 		return dasd_era_none;
 
 	/* distinguish between 24 and 32 byte sense data */
 	if (sense[27] & DASD_SENSE_BIT_0) {
 
-		/* examine the 24 byte sense data */
-		era = dasd_3990_erp_examine_24 (sense);
+		era = dasd_3990_erp_examine_24 (cqr,
+                                                sense);
 
 	} else {
 
-		/* examine the 32 byte sense data */
-		era = dasd_3990_erp_examine_32 (sense);
+		era = dasd_3990_erp_examine_32 (cqr,
+                                                sense);
 
-	} /* end distinguish between 24 and 32 byte sense data */
+	} 
 
-#ifdef ERP_DEBUG
+        /* log the erp chain if fatal error occurred */
         if (era == dasd_era_fatal) {
 
                 log_erp_chain (cqr, 
                                0, 
                                stat->cpa);
         }
-#endif /* ERP_DEBUG */
         
         return era;
 
@@ -334,6 +350,37 @@
  */
 
 /*
+ * DASD_3990_ERP_CLEANUP 
+ *
+ * DESCRIPTION
+ *   Removes the already build but not neccessary ERP request and sets
+ *   the status of the original cqr / erp to the given (final) status
+ *
+ *  PARAMETER
+ *   erp                request to be blocked
+ *   final_status       either CQR_STATUS_DONE or CQR_STATUS_FAILED 
+ *
+ * RETURN VALUES
+ *   cqr                original cqr               
+ */
+ccw_req_t *
+dasd_3990_erp_cleanup (ccw_req_t *erp,
+                       char      final_status)
+{
+
+        ccw_req_t *cqr = erp->refers;
+        
+        dasd_free_request (erp, erp->device);
+
+        check_then_set (&cqr->status,
+                        CQR_STATUS_ERROR,
+                        final_status);
+
+        return cqr;
+
+} /* end dasd_3990_erp_cleanup */ 
+
+/*
  * DASD_3990_ERP_BLOCK_QUEUE 
  *
  * DESCRIPTION
@@ -365,8 +412,9 @@
 
         /* restart queue after some time */
         device->timer.function = dasd_3990_erp_restart_queue; 
-        device->timer.data = (unsigned long) erp;
-        device->timer.expires = jiffies + (expires * HZ);
+        device->timer.data     = (unsigned long) erp;
+        device->timer.expires  = jiffies + (expires * HZ);
+
         add_timer(&device->timer); 
 
 } /* end dasd_3990_erp_block_queue */ 
@@ -390,6 +438,7 @@
 void
 dasd_3990_erp_restart_queue (unsigned long erp)
 {
+
         ccw_req_t     *cqr    = (void *) erp;
 	dasd_device_t *device = cqr->device;
 	unsigned long flags;
@@ -399,10 +448,9 @@
                                    flags);
 
         /* 'restart' the device queue */
-        if (cqr->status == CQR_STATUS_PENDING){
+        if (cqr->status == CQR_STATUS_PENDING) {
                 
-                DASD_MESSAGE (KERN_INFO, device,
-                              "%s",
+                DASD_MESSAGE (KERN_INFO, device, "%s",
                               "request queue restarted by MIH");
 
                 check_then_set (&cqr->status,
@@ -414,11 +462,10 @@
         s390irq_spin_unlock_irqrestore (device->devinfo.irq, 
                                         flags);
 
-        dasd_schedule_bh(device);
+        dasd_schedule_bh (device);
 
 } /* end dasd_3990_erp_restart_queue */
 
-#ifdef ERP_FULL_ERP
 /*
  * DASD_3990_ERP_INT_REQ 
  *
@@ -434,27 +481,31 @@
 ccw_req_t *
 dasd_3990_erp_int_req (ccw_req_t *erp)
 {
+
 	dasd_device_t *device = erp->device;
 
         /* first time set initial retry counter and erp_function */
+        /* and retry once without blocking queue                 */
+        /* (this enables easier enqueing of the cqr)             */
         if (erp->function != dasd_3990_erp_int_req) {
+
                 erp->retries  = 256;
                 erp->function = dasd_3990_erp_int_req;
-        }
 
-        /* issue a message and wait for 'device ready' interrupt */
-        DASD_MESSAGE (KERN_WARNING, device,
-                      "%s",
-                      "is offline or not installed - "
-                      "INTERVENTION REQUIRED!!\n");
+        } else {
 
-        dasd_3990_erp_block_queue (erp,
-                                   60);
+                /* issue a message and wait for 'device ready' interrupt */
+                DASD_MESSAGE (KERN_ERR, device, "%s",
+                              "is offline or not installed - "
+                              "INTERVENTION REQUIRED!!");
+                
+                dasd_3990_erp_block_queue (erp,
+                                           60);
+        }
 
 	return erp;
 
 } /* end dasd_3990_erp_int_req */
-#endif /* ERP_FULL_ERP */
 
 /*
  * DASD_3990_ERP_ALTERNATE_PATH 
@@ -478,22 +529,17 @@
 	dasd_device_t *device = erp->device;
         int irq = device->devinfo.irq;
 
-	/* dissable current channel path - this causes the use of an other 
-	   channel path if there is one.. */
-
-	DASD_MESSAGE (KERN_WARNING, device,
-                      "disable lpu %x",
-                      erp->dstat->lpum);
-
         /* try alternate valid path */
         erp->lpm     &= ~(erp->dstat->lpum);
         erp->options |= DOIO_VALID_LPM;		/* use LPM for DO_IO */
 
 	if ((erp->lpm & ioinfo[irq]->opm) != 0x00) {
 
-		DASD_MESSAGE (KERN_WARNING, device,
-                              "try alternate lpm %x",
-                              erp->lpm);
+		DASD_MESSAGE (KERN_DEBUG, device,
+                              "try alternate lpm=%x (lpum=%x / opm=%x)",
+                              erp->lpm,
+                              erp->dstat->lpum,
+                              ioinfo[irq]->opm);
 
 		/* reset status to queued to handle the request again... */
 		check_then_set (&erp->status,
@@ -504,10 +550,11 @@
                 
 	} else {
          
-                DASD_MESSAGE (KERN_WARNING, device,
-                              "%s",      
-                              "No alternate channel path left -> "
-                              "permanent error");
+                DASD_MESSAGE (KERN_ERR, device,
+                              "No alternate channel path left (lpum=%x / "
+                              "opm=%x) -> permanent error",
+                              erp->dstat->lpum,
+                              ioinfo[irq]->opm);
                 
                 /* post request with permanent error */
                 check_then_set (&erp->status,
@@ -518,7 +565,6 @@
         
 } /* end dasd_3990_erp_alternate_path */
 
-#ifdef ERP_FULL_ERP
 /*
  * DASD_3990_ERP_DCTL
  *
@@ -527,7 +573,7 @@
  *   Inhibit Write subcommand (0x20) and the given modifier.
  *
  *  PARAMETER
- *   erp                pointer to the current ERP
+ *   erp                pointer to the current (failed) ERP
  *   modifier           subcommand modifier
  *   
  * RETURN VALUES
@@ -538,14 +584,25 @@
 dasd_3990_erp_DCTL (ccw_req_t *erp,
                     char      modifier)
 {
-	DCTL_data_t *DCTL_data;
-        ccw1_t      *ccw;
-        ccw_req_t   *dctl_cqr = dasd_alloc_request ((char *) &erp->magic,
-                                                    1,
-                                                    sizeof(DCTL_data_t));
+
+	dasd_device_t *device = erp->device;
+	DCTL_data_t   *DCTL_data;
+        ccw1_t        *ccw;
+        ccw_req_t     *dctl_cqr = dasd_alloc_request ((char *) &erp->magic,
+                                                      1,
+                                                      sizeof(DCTL_data_t),
+                                                      erp->device);
         
-	if (dctl_cqr == NULL) {
-		BUG();
+	if (!dctl_cqr) {
+
+                DASD_MESSAGE (KERN_ERR, device, "%s",
+                              "Unable to allocate DCTL-CQR");
+                
+                check_then_set (&erp->status,
+                                CQR_STATUS_ERROR,
+                                CQR_STATUS_FAILED);
+
+		return erp;
         }
 
 	DCTL_data = dctl_cqr->data;
@@ -557,15 +614,24 @@
 	memset (ccw, 0, sizeof (ccw1_t));
         ccw->cmd_code = CCW_CMD_DCTL;
         ccw->count    = 4;
-        set_normalized_cda(ccw, __pa (DCTL_data));
+        if (dasd_set_normalized_cda(ccw, 
+                                    __pa (DCTL_data), dctl_cqr, erp->device)) {
+                dasd_free_request (dctl_cqr, erp->device);
+                DASD_MESSAGE (KERN_ERR, device, "%s",
+                              "Unable to allocate DCTL-CQR");
 
+                check_then_set (&erp->status,
+                                CQR_STATUS_ERROR,
+                                CQR_STATUS_FAILED);
+		return erp;
+        }
         dctl_cqr->function = dasd_3990_erp_DCTL;
-        dctl_cqr->refers = erp;
-        dctl_cqr->device = erp->device;
-        dctl_cqr->magic = erp->magic;
-        dctl_cqr->lpm = LPM_ANYPATH;
-        dctl_cqr->expires = 5 * TOD_MIN;
-        dctl_cqr->retries = 2;
+        dctl_cqr->refers   = erp;
+        dctl_cqr->device   = erp->device;
+        dctl_cqr->magic    = erp->magic;
+        dctl_cqr->lpm      = LPM_ANYPATH;
+        dctl_cqr->expires  = 5 * TOD_MIN;
+        dctl_cqr->retries  = 2;
 	asm volatile ("STCK %0":"=m" (dctl_cqr->buildclk));
 
         dctl_cqr->status = CQR_STATUS_FILLED;
@@ -573,7 +639,6 @@
 	return dctl_cqr;
 
 } /* end dasd_3990_erp_DCTL */
-#endif /* ERP_FULL_ERP */  
 
 /*
  * DASD_3990_ERP_ACTION_1 
@@ -595,6 +660,7 @@
 ccw_req_t *
 dasd_3990_erp_action_1 (ccw_req_t *erp)
 {
+
         erp->function = dasd_3990_erp_action_1;
 
         dasd_3990_erp_alternate_path (erp);
@@ -624,21 +690,22 @@
 dasd_3990_erp_action_4 (ccw_req_t *erp,
 			char      *sense)
 {
+
 	dasd_device_t *device = erp->device;
 
         /* first time set initial retry counter and erp_function    */
         /* and retry once without waiting for state change pending  */
         /* interrupt (this enables easier enqueing of the cqr)      */
         if (erp->function != dasd_3990_erp_action_4) {
-                erp->retries  = 255; 
+
+                erp->retries  = 256; 
                 erp->function = dasd_3990_erp_action_4;
 
         } else {
 
                 if (sense[25] & 0x1D) {	/* state change pending */
                         
-                        DASD_MESSAGE (KERN_WARNING, device,
-                                      "%s",
+                        DASD_MESSAGE (KERN_INFO, device, "%s",
                                       "waiting for state change pending "
                                       "int");
                         
@@ -646,11 +713,8 @@
                                                    30);
                         
                 } else {
+
                         /* no state change pending - retry */
-                        DASD_MESSAGE (KERN_WARNING, device,
-                                      "%s",
-                                      "no state change pending - retry");
-                        
                         check_then_set (&erp->status,
                                         CQR_STATUS_ERROR,
                                         CQR_STATUS_QUEUED);
@@ -667,12 +731,12 @@
  ***************************************************************************** 
  */
 
-#ifdef ERP_FULL_ERP
 /*
  * DASD_3990_ERP_ACTION_5 
  *
  * DESCRIPTION
  *   Setup ERP to do the ERP action 5 (see Reference manual).
+ *   NOTE: Further handling is done in xxx_further_erp after the retries.
  *
  *  PARAMETER
  *   erp                pointer to the current ERP
@@ -684,16 +748,11 @@
 ccw_req_t *
 dasd_3990_erp_action_5 (ccw_req_t *erp)
 {
+
         /* first of all retry */
         erp->retries = 10;
         erp->function = dasd_3990_erp_action_5;
 
-        check_then_set (&erp->status,
-                        CQR_STATUS_ERROR,
-                        CQR_STATUS_QUEUED);
-
-        /* further handling is done in xxx_further_erp after the retries */
-
         return erp;
 
 } /* end dasd_3990_erp_action_5 */
@@ -713,15 +772,17 @@
  *   void
  */
 void
-dasd_3990_handle_env_data (char *sense)
+dasd_3990_handle_env_data (ccw_req_t *erp,
+                           char      *sense)
 {
-	/* check bytes 7-23 for further information */
 
-	char msg_format = (sense[7] & 0xF0);
-	char msg_no = (sense[7] & 0x0F);
+        dasd_device_t *device = erp->device;
+	char msg_format       = (sense[7] & 0xF0);
+	char msg_no           = (sense[7] & 0x0F);
+        
 
 	switch (msg_format) {
-	case 0x00:		/* Format 0 - Program or System Checks */
+	case 0x00:	/* Format 0 - Program or System Checks */
 
 		if (sense[1] & 0x10) {	/* check message to operator bit */
 
@@ -729,579 +790,595 @@
 			case 0x00:	/* No Message */
 				break;
 			case 0x01:
-				printk (KERN_WARNING PRINTK_HEADER
-					"FORMAT 0 - Invalid Command\n");
+                                DASD_MESSAGE (KERN_WARNING, device, "%s",
+                                              "FORMAT 0 - Invalid Command");
 				break;
 			case 0x02:
-				printk (KERN_WARNING PRINTK_HEADER
-				     "FORMAT 0 - Invalid Command Sequence\n");
+                                DASD_MESSAGE (KERN_WARNING, device, "%s",
+                                              "FORMAT 0 - Invalid Command "
+                                              "Sequence");
 				break;
 			case 0x03:
-				printk (KERN_WARNING PRINTK_HEADER
-					"FORMAT 0 - CCW Count less than "
-					"required\n");
+                                DASD_MESSAGE (KERN_WARNING, device, "%s",
+                                              "FORMAT 0 - CCW Count less than "
+                                              "required");
 				break;
 			case 0x04:
-				printk (KERN_WARNING PRINTK_HEADER
-					"FORMAT 0 - Invalid Parameter\n");
+                                DASD_MESSAGE (KERN_WARNING, device, "%s",
+                                              "FORMAT 0 - Invalid Parameter");
 				break;
 			case 0x05:
-				printk (KERN_WARNING PRINTK_HEADER
-					"FORMAT 0 - Diagnostic of Sepecial "
-					"Command Violates File Mask\n");
+                                DASD_MESSAGE (KERN_WARNING, device, "%s",
+                                              "FORMAT 0 - Diagnostic of Sepecial"
+                                              " Command Violates File Mask");
 				break;
 			case 0x07:
-				printk (KERN_WARNING PRINTK_HEADER
-					"FORMAT 0 - Channel Returned with "
-					"Incorrect retry CCW\n");
+                                DASD_MESSAGE (KERN_WARNING, device, "%s",
+                                              "FORMAT 0 - Channel Returned with "
+                                              "Incorrect retry CCW");
 				break;
 			case 0x08:
-				printk (KERN_WARNING PRINTK_HEADER
-					"FORMAT 0 - Reset Notification\n");
+                                DASD_MESSAGE (KERN_WARNING, device, "%s",
+                                              "FORMAT 0 - Reset Notification");
 				break;
 			case 0x09:
-				printk (KERN_WARNING PRINTK_HEADER
-					"FORMAT 0 - Storage Path Restart\n");
+                                DASD_MESSAGE (KERN_WARNING, device, "%s",
+                                              "FORMAT 0 - Storage Path Restart");
 				break;
 			case 0x0A:
-				printk (KERN_WARNING PRINTK_HEADER
-				    "FORMAT 0 - Channel requested ... %02x\n",
-					sense[8]);
+                                DASD_MESSAGE (KERN_WARNING, device,
+                                              "FORMAT 0 - Channel requested "
+                                              "... %02x",
+                                              sense[8]);
 				break;
 			case 0x0B:
-				printk (KERN_WARNING PRINTK_HEADER
-				     "FORMAT 0 - Invalid Defective/Alternate "
-					"Track Pointer\n");
+                                DASD_MESSAGE (KERN_WARNING, device, "%s",
+                                              "FORMAT 0 - Invalid Defective/"
+                                              "Alternate Track Pointer");
 				break;
 			case 0x0C:
-				printk (KERN_WARNING PRINTK_HEADER
-					"FORMAT 0 - DPS Installation Check\n");
+                                DASD_MESSAGE (KERN_WARNING, device, "%s",
+                                              "FORMAT 0 - DPS Installation "
+                                              "Check");
 				break;
 			case 0x0E:
-				printk (KERN_WARNING PRINTK_HEADER
-				    "FORMAT 0 - Command Invalid on Secondary "
-					"Address\n");
+                                DASD_MESSAGE (KERN_WARNING, device, "%s",
+                                              "FORMAT 0 - Command Invalid on "
+                                              "Secondary Address");
 				break;
 			case 0x0F:
-				printk (KERN_WARNING PRINTK_HEADER
-					"FORMAT 0 - Status Not As Required: "
-					"reason %02x\n",
-					sense[8]);
+                                DASD_MESSAGE (KERN_WARNING, device,
+                                              "FORMAT 0 - Status Not As "
+                                              "Required: reason %02x",
+                                              sense[8]);
 				break;
 			default:
-				printk (KERN_WARNING PRINTK_HEADER
-					"FORMAT 0 - Reseved\n");
+                                DASD_MESSAGE (KERN_WARNING, device, "%s",
+                                              "FORMAT 0 - Reseved");
 			}
 		} else {
 			switch (msg_no) {
 			case 0x00:	/* No Message */
 				break;
 			case 0x01:
-				printk (KERN_WARNING PRINTK_HEADER
-					"FORMAT 0 - Device Error Source\n");
+                                DASD_MESSAGE (KERN_WARNING, device, "%s",
+                                              "FORMAT 0 - Device Error Source");
 				break;
 			case 0x02:
-				printk (KERN_WARNING PRINTK_HEADER
-					"FORMAT 0 - Reserved\n");
+                                DASD_MESSAGE (KERN_WARNING, device, "%s",
+                                              "FORMAT 0 - Reserved");
 				break;
 			case 0x03:
-				printk (KERN_WARNING PRINTK_HEADER
-					"FORMAT 0 - Device Fenced - device = "
-					"%02x\n",
-					sense[4]);
+                                DASD_MESSAGE (KERN_WARNING, device,
+                                              "FORMAT 0 - Device Fenced - "
+                                              "device = %02x",
+                                              sense[4]);
 				break;
 			case 0x04:
-				printk (KERN_WARNING PRINTK_HEADER
-					"FORMAT 0 - Data Pinned for Device\n");
+                                DASD_MESSAGE (KERN_WARNING, device, "%s",
+                                              "FORMAT 0 - Data Pinned for "
+                                              "Device");
 				break;
 			default:
-				printk (KERN_WARNING PRINTK_HEADER
-					"FORMAT 0 - Reserved\n");
+                                DASD_MESSAGE (KERN_WARNING, device, "%s",
+                                              "FORMAT 0 - Reserved");
 			}
                 }
                 break;
 		
-	case 0x10:		/* Format 1 - Device Equipment Checks */
+	case 0x10:	/* Format 1 - Device Equipment Checks */
 		switch (msg_no) {
 		case 0x00:	/* No Message */
 			break;
 		case 0x01:
-			printk (KERN_WARNING PRINTK_HEADER
-				"FORMAT 1 - Device Status 1 not as "
-				"expected\n");
+                        DASD_MESSAGE (KERN_WARNING, device, "%s",
+                                      "FORMAT 1 - Device Status 1 not as "
+                                      "expected");
 			break;
 		case 0x03:
-			printk (KERN_WARNING PRINTK_HEADER
-				"FORMAT 1 - Index missing\n");
+                        DASD_MESSAGE (KERN_WARNING, device, "%s",
+                                      "FORMAT 1 - Index missing");
 			break;
 		case 0x04:
-			printk (KERN_WARNING PRINTK_HEADER
-				"FORMAT 1 - Interruption cannot be reset\n");
+                        DASD_MESSAGE (KERN_WARNING, device, "%s",
+                                      "FORMAT 1 - Interruption cannot be reset");
 			break;
 		case 0x05:
-			printk (KERN_WARNING PRINTK_HEADER
-				"FORMAT 1 - Device did not respond to "
-				"selection\n");
+                        DASD_MESSAGE (KERN_WARNING, device, "%s",
+                                      "FORMAT 1 - Device did not respond to "
+                                      "selection");
 			break;
 		case 0x06:
-			printk (KERN_WARNING PRINTK_HEADER
-				"FORMAT 1 - Device check-2 error or Set "
-				"Sector is not complete\n");
+                        DASD_MESSAGE (KERN_WARNING, device, "%s",
+                                      "FORMAT 1 - Device check-2 error or Set "
+                                      "Sector is not complete");
 			break;
 		case 0x07:
-			printk (KERN_WARNING PRINTK_HEADER
-				"FORMAT 1 - Head address does not compare\n");
+                        DASD_MESSAGE (KERN_WARNING, device, "%s",
+                                      "FORMAT 1 - Head address does not "
+                                      "compare");
 			break;
 		case 0x08:
-			printk (KERN_WARNING PRINTK_HEADER
-				"FORMAT 1 - Device status 1 not valid\n");
+                        DASD_MESSAGE (KERN_WARNING, device, "%s",
+                                      "FORMAT 1 - Device status 1 not valid");
 			break;
 		case 0x09:
-			printk (KERN_WARNING PRINTK_HEADER
-				"FORMAT 1 - Device not ready\n");
+                        DASD_MESSAGE (KERN_WARNING, device, "%s",
+                                      "FORMAT 1 - Device not ready");
 			break;
 		case 0x0A:
-			printk (KERN_WARNING PRINTK_HEADER
-				"FORMAT 1 - Track physical address did "
-				"not compare\n");
+                        DASD_MESSAGE (KERN_WARNING, device, "%s",
+                                      "FORMAT 1 - Track physical address did "
+                                      "not compare");
 			break;
 		case 0x0B:
-			printk (KERN_WARNING PRINTK_HEADER
-				"FORMAT 1 - Missing device address bit\n");
+                        DASD_MESSAGE (KERN_WARNING, device, "%s",
+                                      "FORMAT 1 - Missing device address bit");
 			break;
 		case 0x0C:
-			printk (KERN_WARNING PRINTK_HEADER
-				"FORMAT 1 - Drive motor switch is off\n");
+                        DASD_MESSAGE (KERN_WARNING, device, "%s",
+                                      "FORMAT 1 - Drive motor switch is off");
 			break;
 		case 0x0D:
-			printk (KERN_WARNING PRINTK_HEADER
-				"FORMAT 1 - Seek incomplete\n");
+                        DASD_MESSAGE (KERN_WARNING, device, "%s",
+                                      "FORMAT 1 - Seek incomplete");
 			break;
 		case 0x0E:
-			printk (KERN_WARNING PRINTK_HEADER
-				"FORMAT 1 - Cylinder address did not "
-				"compare\n");
+                        DASD_MESSAGE (KERN_WARNING, device, "%s",
+                                      "FORMAT 1 - Cylinder address did not "
+                                      "compare");
 			break;
 		case 0x0F:
-			printk (KERN_WARNING PRINTK_HEADER
-				"FORMAT 1 - Offset active cannot be reset\n");
+                        DASD_MESSAGE (KERN_WARNING, device, "%s",
+                                      "FORMAT 1 - Offset active cannot be "
+                                      "reset");
 			break;
 		default:
-			printk (KERN_WARNING PRINTK_HEADER
-				"FORMAT 1 - Reserved\n");
+                        DASD_MESSAGE (KERN_WARNING, device, "%s",
+                                      "FORMAT 1 - Reserved");
 		}
                 break;		
                         
-	case 0x20:		/* Format 2 - 3990 Equipment Checks */
+	case 0x20:	/* Format 2 - 3990 Equipment Checks */
 		switch (msg_no) {
 		case 0x08:
-			printk (KERN_WARNING PRINTK_HEADER
-				"FORMAT 2 - 3990 check-2 error\n");
+                        DASD_MESSAGE (KERN_WARNING, device, "%s",
+                                      "FORMAT 2 - 3990 check-2 error");
 			break;
 		case 0x0E:
-			printk (KERN_WARNING PRINTK_HEADER
-				"FORMAT 2 - Support facility errors\n");
+                        DASD_MESSAGE (KERN_WARNING, device, "%s",
+                                      "FORMAT 2 - Support facility errors");
 			break;
 		case 0x0F:
-			printk (KERN_WARNING PRINTK_HEADER
-				"FORMAT 2 - Microcode detected error %02x\n",
-				sense[8]);
+                        DASD_MESSAGE (KERN_WARNING, device,
+                                      "FORMAT 2 - Microcode detected error %02x",
+                                      sense[8]);
 			break;
 		default:
-			printk (KERN_WARNING PRINTK_HEADER
-				"FORMAT 2 - Reserved\n");
+                        DASD_MESSAGE (KERN_WARNING, device, "%s",
+                                      "FORMAT 2 - Reserved");
 		}
                 break;		
 
-	case 0x30:		/* Format 3 - 3990 Control Checks */
+	case 0x30:	/* Format 3 - 3990 Control Checks */
 		switch (msg_no) {
 		case 0x0F:
-			printk (KERN_WARNING PRINTK_HEADER
-				"FORMAT 3 - Allegiance terminated\n");
+                        DASD_MESSAGE (KERN_WARNING, device, "%s",
+                                      "FORMAT 3 - Allegiance terminated");
 			break;
 		default:
-			printk (KERN_WARNING PRINTK_HEADER
-				"FORMAT 3 - Reserved\n");
+                        DASD_MESSAGE (KERN_WARNING, device, "%s",
+                                      "FORMAT 3 - Reserved");
 		}
                 break;		
 
-	case 0x40:		/* Format 4 - Data Checks */
+	case 0x40:	/* Format 4 - Data Checks */
 		switch (msg_no) {
 		case 0x00:
-			printk (KERN_WARNING PRINTK_HEADER
-				"FORMAT 4 - Home address area error\n");
+                        DASD_MESSAGE (KERN_WARNING, device, "%s",
+                                      "FORMAT 4 - Home address area error");
 			break;
 		case 0x01:
-			printk (KERN_WARNING PRINTK_HEADER
-				"FORMAT 4 - Count area error\n");
+                        DASD_MESSAGE (KERN_WARNING, device, "%s",
+                                      "FORMAT 4 - Count area error");
 			break;
 		case 0x02:
-			printk (KERN_WARNING PRINTK_HEADER
-				"FORMAT 4 - Key area error\n");
+                        DASD_MESSAGE (KERN_WARNING, device, "%s",
+                                      "FORMAT 4 - Key area error");
 			break;
 		case 0x03:
-			printk (KERN_WARNING PRINTK_HEADER
-				"FORMAT 4 - Data area error\n");
+                        DASD_MESSAGE (KERN_WARNING, device, "%s",
+                                      "FORMAT 4 - Data area error");
 			break;
 		case 0x04:
-			printk (KERN_WARNING PRINTK_HEADER
-			    "FORMAT 4 - No sync byte in home address area\n");
+                        DASD_MESSAGE (KERN_WARNING, device, "%s",
+                                      "FORMAT 4 - No sync byte in home address "
+                                      "area");
 			break;
 		case 0x05:
-			printk (KERN_WARNING PRINTK_HEADER
-			    "FORMAT 4 - No syn byte in count address area\n");
+                        DASD_MESSAGE (KERN_WARNING, device, "%s",
+                                      "FORMAT 4 - No sync byte in count address "
+                                      "area");
 			break;
 		case 0x06:
-			printk (KERN_WARNING PRINTK_HEADER
-				"FORMAT 4 - No sync byte in key area\n");
+                        DASD_MESSAGE (KERN_WARNING, device, "%s",
+                                      "FORMAT 4 - No sync byte in key area");
 			break;
 		case 0x07:
-			printk (KERN_WARNING PRINTK_HEADER
-				"FORMAT 4 - No syn byte in data area\n");
+                        DASD_MESSAGE (KERN_WARNING, device, "%s",
+                                      "FORMAT 4 - No sync byte in data area");
 			break;
 		case 0x08:
-			printk (KERN_WARNING PRINTK_HEADER
-				"FORMAT 4 - Home address area error; "
-				"offset active\n");
+                        DASD_MESSAGE (KERN_WARNING, device, "%s",
+                                      "FORMAT 4 - Home address area error; "
+                                      "offset active");
 			break;
 		case 0x09:
-			printk (KERN_WARNING PRINTK_HEADER
-			      "FORMAT 4 - Count area error; offset active\n");
+                        DASD_MESSAGE (KERN_WARNING, device, "%s",
+                                      "FORMAT 4 - Count area error; offset "
+                                      "active");
 			break;
 		case 0x0A:
-			printk (KERN_WARNING PRINTK_HEADER
-				"FORMAT 4 - Key area error; offset active\n");
+                        DASD_MESSAGE (KERN_WARNING, device, "%s",
+                                      "FORMAT 4 - Key area error; offset "
+                                      "active");
 			break;
 		case 0x0B:
-			printk (KERN_WARNING PRINTK_HEADER
-				"FORMAT 4 - Data area error; offset active\n");
+                        DASD_MESSAGE (KERN_WARNING, device, "%s",
+                                      "FORMAT 4 - Data area error; "
+                                      "offset active");
 			break;
 		case 0x0C:
-			printk (KERN_WARNING PRINTK_HEADER
-			      "FORMAT 4 - No sync byte in home address area; "
-				"offset active\n");
+                        DASD_MESSAGE (KERN_WARNING, device, "%s",
+                                      "FORMAT 4 - No sync byte in home "
+                                      "address area; offset active");
 			break;
 		case 0x0D:
-			printk (KERN_WARNING PRINTK_HEADER
-			      "FORMAT 4 - No syn byte in count address area; "
-				"offset active\n");
+                        DASD_MESSAGE (KERN_WARNING, device, "%s",
+                                      "FORMAT 4 - No syn byte in count "
+                                      "address area; offset active");
 			break;
 		case 0x0E:
-			printk (KERN_WARNING PRINTK_HEADER
-				"FORMAT 4 - No sync byte in key area; "
-				"offset active\n");
+                        DASD_MESSAGE (KERN_WARNING, device, "%s",
+                                      "FORMAT 4 - No sync byte in key area; "
+                                      "offset active");
 			break;
 		case 0x0F:
-			printk (KERN_WARNING PRINTK_HEADER
-				"FORMAT 4 - No syn byte in data area; "
-				"offset active\n");
+                        DASD_MESSAGE (KERN_WARNING, device, "%s",
+                                      "FORMAT 4 - No syn byte in data area; "
+                                      "offset active");
 			break;
 		default:
-			printk (KERN_WARNING PRINTK_HEADER
-				"FORMAT 4 - Reserved\n");
+                        DASD_MESSAGE (KERN_WARNING, device, "%s",
+                                      "FORMAT 4 - Reserved");
 		}
                 break;		
 
-	case 0x50:		/* Format 5 - Data Check with displacement information */
+	case 0x50:	/* Format 5 - Data Check with displacement information */
 		switch (msg_no) {
 		case 0x00:
-			printk (KERN_WARNING PRINTK_HEADER
-			  "FORMAT 5 - Data Check in the home address area\n");
+                        DASD_MESSAGE (KERN_WARNING, device, "%s",
+                                      "FORMAT 5 - Data Check in the "
+                                      "home address area");
 			break;
 		case 0x01:
-			printk (KERN_WARNING PRINTK_HEADER
-				"FORMAT 5 - Data Check in the count area\n");
+                        DASD_MESSAGE (KERN_WARNING, device, "%s",
+                                      "FORMAT 5 - Data Check in the count area");
 			break;
 		case 0x02:
-			printk (KERN_WARNING PRINTK_HEADER
-				"FORMAT 5 - Data Check in the key area\n");
+                        DASD_MESSAGE (KERN_WARNING, device, "%s",
+                                      "FORMAT 5 - Data Check in the key area");
 			break;
 		case 0x03:
-			printk (KERN_WARNING PRINTK_HEADER
-				"FORMAT 5 - Data Check in the data area\n");
+                        DASD_MESSAGE (KERN_WARNING, device, "%s",
+                                      "FORMAT 5 - Data Check in the data area");
 			break;
 		case 0x08:
-			printk (KERN_WARNING PRINTK_HEADER
-			    "FORMAT 5 - Data Check in the home address area; "
-				"offset active\n");
+                        DASD_MESSAGE (KERN_WARNING, device, "%s",
+                                      "FORMAT 5 - Data Check in the "
+                                      "home address area; offset active");
 			break;
 		case 0x09:
-			printk (KERN_WARNING PRINTK_HEADER
-				"FORMAT 5 - Data Check in the count area; "
-				"offset active\n");
+                        DASD_MESSAGE (KERN_WARNING, device, "%s",
+                                      "FORMAT 5 - Data Check in the count area; "
+                                      "offset active");
 			break;
 		case 0x0A:
-			printk (KERN_WARNING PRINTK_HEADER
-				"FORMAT 5 - Data Check in the key area; "
-				"offset active\n");
+                        DASD_MESSAGE (KERN_WARNING, device, "%s",
+                                      "FORMAT 5 - Data Check in the key area; "
+                                      "offset active");
 			break;
 		case 0x0B:
-			printk (KERN_WARNING PRINTK_HEADER
-				"FORMAT 5 - Data Check in the data area; "
-				"offset active\n");
+                        DASD_MESSAGE (KERN_WARNING, device, "%s",
+                                      "FORMAT 5 - Data Check in the data area; "
+                                      "offset active");
 			break;
 		default:
-			printk (KERN_WARNING PRINTK_HEADER
-				"FORMAT 5 - Reserved\n");
+                        DASD_MESSAGE (KERN_WARNING, device, "%s",
+                                      "FORMAT 5 - Reserved");
 		}
                 break;		
 
-	case 0x60:		/* Format 6 - Usage Statistics/Overrun Errors */
+	case 0x60:	/* Format 6 - Usage Statistics/Overrun Errors */
 		switch (msg_no) {
 		case 0x00:
-			printk (KERN_WARNING PRINTK_HEADER
-				"FORMAT 6 - Overrun on channel A\n");
+                        DASD_MESSAGE (KERN_WARNING, device, "%s",
+                                      "FORMAT 6 - Overrun on channel A");
 			break;
 		case 0x01:
-			printk (KERN_WARNING PRINTK_HEADER
-				"FORMAT 6 - Overrun on channel B\n");
+                        DASD_MESSAGE (KERN_WARNING, device, "%s",
+                                      "FORMAT 6 - Overrun on channel B");
 			break;
 		case 0x02:
-			printk (KERN_WARNING PRINTK_HEADER
-				"FORMAT 6 - Overrun on channel C\n");
+                        DASD_MESSAGE (KERN_WARNING, device, "%s",
+                                      "FORMAT 6 - Overrun on channel C");
 			break;
 		case 0x03:
-			printk (KERN_WARNING PRINTK_HEADER
-				"FORMAT 6 - Overrun on channel D\n");
+                        DASD_MESSAGE (KERN_WARNING, device, "%s",
+                                      "FORMAT 6 - Overrun on channel D");
 			break;
 		case 0x04:
-			printk (KERN_WARNING PRINTK_HEADER
-				"FORMAT 6 - Overrun on channel E\n");
+                        DASD_MESSAGE (KERN_WARNING, device, "%s",
+                                      "FORMAT 6 - Overrun on channel E");
 			break;
 		case 0x05:
-			printk (KERN_WARNING PRINTK_HEADER
-				"FORMAT 6 - Overrun on channel F\n");
+                        DASD_MESSAGE (KERN_WARNING, device, "%s",
+                                      "FORMAT 6 - Overrun on channel F");
 			break;
 		case 0x06:
-			printk (KERN_WARNING PRINTK_HEADER
-				"FORMAT 6 - Overrun on channel G\n");
+                        DASD_MESSAGE (KERN_WARNING, device, "%s",
+                                      "FORMAT 6 - Overrun on channel G");
 			break;
 		case 0x07:
-			printk (KERN_WARNING PRINTK_HEADER
-				"FORMAT 6 - Overrun on channel H\n");
+                        DASD_MESSAGE (KERN_WARNING, device, "%s",
+                                      "FORMAT 6 - Overrun on channel H");
 			break;
 		default:
-			printk (KERN_WARNING PRINTK_HEADER
-				"FORMAT 6 - Reserved\n");
+                        DASD_MESSAGE (KERN_WARNING, device, "%s",
+                                      "FORMAT 6 - Reserved");
 		}
                 break;		
 
-	case 0x70:		/* Format 7 - Device Connection Control Checks */
+	case 0x70:	/* Format 7 - Device Connection Control Checks */
 		switch (msg_no) {
 		case 0x00:
-			printk (KERN_WARNING PRINTK_HEADER
-				"FORMAT 7 - RCC initiated by a connection "
-				"check alert\n");
+                        DASD_MESSAGE (KERN_WARNING, device, "%s",
+                                      "FORMAT 7 - RCC initiated by a connection "
+                                      "check alert");
 			break;
 		case 0x01:
-			printk (KERN_WARNING PRINTK_HEADER
-				"FORMAT 7 - RCC 1 sequence not successful\n");
+                        DASD_MESSAGE (KERN_WARNING, device, "%s",
+                                      "FORMAT 7 - RCC 1 sequence not "
+                                      "successful");
 			break;
 		case 0x02:
-			printk (KERN_WARNING PRINTK_HEADER
-				"FORMAT 7 - RCC 1 and RCC 2 sequences not "
-				"successful\n");
+                        DASD_MESSAGE (KERN_WARNING, device, "%s",
+                                      "FORMAT 7 - RCC 1 and RCC 2 sequences not "
+                                      "successful");
 			break;
 		case 0x03:
-			printk (KERN_WARNING PRINTK_HEADER
-				"FORMAT 7 - Invalid tag-in during selection "
-				"sequence\n");
+                        DASD_MESSAGE (KERN_WARNING, device, "%s",
+                                      "FORMAT 7 - Invalid tag-in during "
+                                      "selection sequence");
 			break;
 		case 0x04:
-			printk (KERN_WARNING PRINTK_HEADER
-				"FORMAT 7 - extra RCC required\n");
+                        DASD_MESSAGE (KERN_WARNING, device, "%s",
+                                      "FORMAT 7 - extra RCC required");
 			break;
 		case 0x05:
-			printk (KERN_WARNING PRINTK_HEADER
-				"FORMAT 7 - Invalid DCC selection response "
-				"or timeout\n");
+                        DASD_MESSAGE (KERN_WARNING, device, "%s",
+                                      "FORMAT 7 - Invalid DCC selection "
+                                      "response or timeout");
 			break;
 		case 0x06:
-			printk (KERN_WARNING PRINTK_HEADER
-				"FORMAT 7 - Missing end operation; device "
-				"transfer complete\n");
+                        DASD_MESSAGE (KERN_WARNING, device, "%s",
+                                      "FORMAT 7 - Missing end operation; device "
+                                      "transfer complete");
 			break;
 		case 0x07:
-			printk (KERN_WARNING PRINTK_HEADER
-				"FORMAT 7 - Missing end operation; device "
-				"transfer incomplete\n");
+                        DASD_MESSAGE (KERN_WARNING, device, "%s",
+                                      "FORMAT 7 - Missing end operation; device "
+                                      "transfer incomplete");
 			break;
 		case 0x08:
-			printk (KERN_WARNING PRINTK_HEADER
-				"FORMAT 7 - Invalid tag-in for an immediate "
-				"command sequence\n");
+                        DASD_MESSAGE (KERN_WARNING, device, "%s",
+                                      "FORMAT 7 - Invalid tag-in for an "
+                                      "immediate command sequence");
 			break;
 		case 0x09:
-			printk (KERN_WARNING PRINTK_HEADER
-				"FORMAT 7 - Invalid tag-in for an extended "
-				"command sequence\n");
+                        DASD_MESSAGE (KERN_WARNING, device, "%s",
+                                      "FORMAT 7 - Invalid tag-in for an "
+                                      "extended command sequence");
 			break;
 		case 0x0A:
-			printk (KERN_WARNING PRINTK_HEADER
-				"FORMAT 7 - 3990 microcode time out when "
-				"stopping selection\n");
+                        DASD_MESSAGE (KERN_WARNING, device, "%s",
+                                      "FORMAT 7 - 3990 microcode time out when "
+                                      "stopping selection");
 			break;
 		case 0x0B:
-			printk (KERN_WARNING PRINTK_HEADER
-				"FORMAT 7 - No response to selection after "
-				"a poll interruption\n");
+                        DASD_MESSAGE (KERN_WARNING, device, "%s",
+                                      "FORMAT 7 - No response to selection "
+                                      "after a poll interruption");
 			break;
 		case 0x0C:
-			printk (KERN_WARNING PRINTK_HEADER
-				"FORMAT 7 - Permanent path error (DASD "
-				"controller not available)\n");
+                        DASD_MESSAGE (KERN_WARNING, device, "%s",
+                                      "FORMAT 7 - Permanent path error (DASD "
+                                      "controller not available)");
 			break;
 		case 0x0D:
-			printk (KERN_WARNING PRINTK_HEADER
-				"FORMAT 7 - DASD controller not available on "
-				"disconnected command chain\n");
+                        DASD_MESSAGE (KERN_WARNING, device, "%s",
+                                      "FORMAT 7 - DASD controller not available"
+                                      " on disconnected command chain");
 			break;
 		default:
-			printk (KERN_WARNING PRINTK_HEADER
-				"FORMAT 7 - Reserved\n");
+                        DASD_MESSAGE (KERN_WARNING, device, "%s",
+                                      "FORMAT 7 - Reserved");
 		}
                 break;		
 
-	case 0x80:		/* Format 8 - Additional Device Equipment Checks */
+	case 0x80:	/* Format 8 - Additional Device Equipment Checks */
 		switch (msg_no) {
 		case 0x00:	/* No Message */
 		case 0x01:
-			printk (KERN_WARNING PRINTK_HEADER
-				"FORMAT 8 - Error correction code hardware "
-				"fault\n");
+                        DASD_MESSAGE (KERN_WARNING, device, "%s",
+                                      "FORMAT 8 - Error correction code "
+                                      "hardware fault");
 			break;
 		case 0x03:
-			printk (KERN_WARNING PRINTK_HEADER
-				"FORMAT 8 - Unexpected end operation response "
-				"code\n");
+                        DASD_MESSAGE (KERN_WARNING, device, "%s",
+                                      "FORMAT 8 - Unexpected end operation "
+                                      "response code");
 			break;
 		case 0x04:
-			printk (KERN_WARNING PRINTK_HEADER
-				"FORMAT 8 - End operation with transfer count "
-				"not zero\n");
+                        DASD_MESSAGE (KERN_WARNING, device, "%s",
+                                      "FORMAT 8 - End operation with transfer "
+                                      "count not zero");
 			break;
 		case 0x05:
-			printk (KERN_WARNING PRINTK_HEADER
-				"FORMAT 8 - End operation with transfer "
-				"count zero\n");
+                        DASD_MESSAGE (KERN_WARNING, device, "%s",
+                                      "FORMAT 8 - End operation with transfer "
+                                      "count zero");
 			break;
 		case 0x06:
-			printk (KERN_WARNING PRINTK_HEADER
-			      "FORMAT 8 - DPS checks after a system reset or "
-				"selective reset\n");
+                        DASD_MESSAGE (KERN_WARNING, device, "%s",
+                                      "FORMAT 8 - DPS checks after a system "
+                                      "reset or selective reset");
 			break;
 		case 0x07:
-			printk (KERN_WARNING PRINTK_HEADER
-				"FORMAT 8 - DPS cannot be filled\n");
+                        DASD_MESSAGE (KERN_WARNING, device, "%s",
+                                      "FORMAT 8 - DPS cannot be filled");
 			break;
 		case 0x08:
-			printk (KERN_WARNING PRINTK_HEADER
-				"FORMAT 8 - Short busy time-out during device "
-				"selection\n");
+                        DASD_MESSAGE (KERN_WARNING, device, "%s",
+                                      "FORMAT 8 - Short busy time-out during "
+                                      "device selection");
 			break;
 		case 0x09:
-			printk (KERN_WARNING PRINTK_HEADER
-				"FORMAT 8 - DASD controller failed to set or "
-				"reset the long busy latch\n");
+                        DASD_MESSAGE (KERN_WARNING, device, "%s",
+                                      "FORMAT 8 - DASD controller failed to "
+                                      "set or reset the long busy latch");
 			break;
 		case 0x0A:
-			printk (KERN_WARNING PRINTK_HEADER
-			      "FORMAT 8 - No interruption from device during "
-				"a command chain\n");
+                        DASD_MESSAGE (KERN_WARNING, device, "%s",
+                                      "FORMAT 8 - No interruption from device "
+                                      "during a command chain");
 			break;
 		default:
-			printk (KERN_WARNING PRINTK_HEADER
-				"FORMAT 8 - Reserved\n");
+                        DASD_MESSAGE (KERN_WARNING, device, "%s",
+                                      "FORMAT 8 - Reserved");
 		}
                 break;		
 
-	case 0x90:		/* Format 9 - Device Read, Write, and Seek Checks */
+	case 0x90:	/* Format 9 - Device Read, Write, and Seek Checks */
 		switch (msg_no) {
 		case 0x00:
 			break;	/* No Message */
 		case 0x06:
-			printk (KERN_WARNING PRINTK_HEADER
-				"FORMAT 9 - Device check-2 error\n");
+                        DASD_MESSAGE (KERN_WARNING, device, "%s",
+                                      "FORMAT 9 - Device check-2 error");
 			break;
 		case 0x07:
-			printk (KERN_WARNING PRINTK_HEADER
-				"FORMAT 9 - Head address did not compare\n");
+                        DASD_MESSAGE (KERN_WARNING, device, "%s",
+                                      "FORMAT 9 - Head address did not compare");
 			break;
 		case 0x0A:
-			printk (KERN_WARNING PRINTK_HEADER
-				"FORMAT 9 - Track physical address did not "
-				"compare while oriented\n");
+                        DASD_MESSAGE (KERN_WARNING, device, "%s",
+                                      "FORMAT 9 - Track physical address did "
+                                      "not compare while oriented");
 			break;
 		case 0x0E:
-			printk (KERN_WARNING PRINTK_HEADER
-			     "FORMAT 9 - Cylinder address did not compare\n");
+                        DASD_MESSAGE (KERN_WARNING, device, "%s",
+                                      "FORMAT 9 - Cylinder address did not "
+                                      "compare");
 			break;
 		default:
-			printk (KERN_WARNING PRINTK_HEADER
-				"FORMAT 9 - Reserved\n");
+                        DASD_MESSAGE (KERN_WARNING, device, "%s",
+                                      "FORMAT 9 - Reserved");
 		}
                 break;		
 
 	case 0xF0:		/* Format F - Cache Storage Checks */
 		switch (msg_no) {
 		case 0x00:
-			printk (KERN_WARNING PRINTK_HEADER
-				"FORMAT F - Operation Terminated\n");
+                        DASD_MESSAGE (KERN_WARNING, device, "%s",
+                                      "FORMAT F - Operation Terminated");
 			break;
 		case 0x01:
-			printk (KERN_WARNING PRINTK_HEADER
-				"FORMAT F - Subsystem Processing Error\n");
+                        DASD_MESSAGE (KERN_WARNING, device, "%s",
+                                      "FORMAT F - Subsystem Processing Error");
 			break;
 		case 0x02:
-			printk (KERN_WARNING PRINTK_HEADER
-				"FORMAT F - Cache or nonvolatile storage "
-				"equipment failure\n");
+                        DASD_MESSAGE (KERN_WARNING, device, "%s",
+                                      "FORMAT F - Cache or nonvolatile storage "
+                                      "equipment failure");
 			break;
 		case 0x04:
-			printk (KERN_WARNING PRINTK_HEADER
-				"FORMAT F - Caching terminated\n");
+                        DASD_MESSAGE (KERN_WARNING, device, "%s",
+                                      "FORMAT F - Caching terminated");
 			break;
 		case 0x06:
-			printk (KERN_WARNING PRINTK_HEADER
-				"FORMAT F - Cache fast write access not "
-				"authorized\n");
+                        DASD_MESSAGE (KERN_WARNING, device, "%s",
+                                      "FORMAT F - Cache fast write access not "
+                                      "authorized");
 			break;
 		case 0x07:
-			printk (KERN_WARNING PRINTK_HEADER
-				"FORMAT F - Track format incorrect\n");
+                        DASD_MESSAGE (KERN_WARNING, device, "%s",
+                                      "FORMAT F - Track format incorrect");
 			break;
 		case 0x09:
-			printk (KERN_WARNING PRINTK_HEADER
-				"FORMAT F - Caching reinitiated\n");
+                        DASD_MESSAGE (KERN_WARNING, device, "%s",
+                                      "FORMAT F - Caching reinitiated");
 			break;
 		case 0x0A:
-			printk (KERN_WARNING PRINTK_HEADER
-				"FORMAT F - Nonvolatile storage terminated\n");
+                        DASD_MESSAGE (KERN_WARNING, device, "%s",
+                                      "FORMAT F - Nonvolatile storage "
+                                      "terminated");
 			break;
 		case 0x0B:
-			printk (KERN_WARNING PRINTK_HEADER
-				"FORMAT F - Volume is suspended duplex\n");
+                        DASD_MESSAGE (KERN_WARNING, device, "%s",
+                                      "FORMAT F - Volume is suspended duplex");
 			break;
 		case 0x0C:
-			printk (KERN_WARNING PRINTK_HEADER
-				"FORMAT F - Subsystem status connot be "
-				"determined\n");
+                        DASD_MESSAGE (KERN_WARNING, device, "%s",
+                                      "FORMAT F - Subsystem status connot be "
+                                      "determined");
 			break;
 		case 0x0D:
-			printk (KERN_WARNING PRINTK_HEADER
-			      "FORMAT F - Caching status reset to default\n");
+                        DASD_MESSAGE (KERN_WARNING, device, "%s",
+                                      "FORMAT F - Caching status reset to "
+                                      "default");
 			break;
 		case 0x0E:
-			printk (KERN_WARNING PRINTK_HEADER
-				"FORMAT F - DASD Fast Write inhibited\n");
+                        DASD_MESSAGE (KERN_WARNING, device, "%s",
+                                      "FORMAT F - DASD Fast Write inhibited");
 			break;
 		default:
-			printk (KERN_WARNING PRINTK_HEADER
-				"FORMAT D - Reserved\n");
+                        DASD_MESSAGE (KERN_WARNING, device, "%s",
+                                      "FORMAT D - Reserved");
 		}
                 break;		
 
-	default:		/* unknown message format - should not happen */
+	default:	/* unknown message format - should not happen */
 
 	} /* end switch message format */
 
@@ -1324,38 +1401,29 @@
 dasd_3990_erp_com_rej (ccw_req_t *erp,
 		       char      *sense)
 {
+
 	dasd_device_t *device = erp->device;
-        ccw_req_t     *cqr    = NULL;
 
         erp->function = dasd_3990_erp_com_rej;
 
 	/* env data present (ACTION 10 - retry should work) */
 	if (sense[2] & SNS2_ENV_DATA_PRESENT) {
 
-                DASD_MESSAGE (KERN_WARNING, device,
-                              "%s",
-                              "Command Reject - environmental data present\n");
+                DASD_MESSAGE (KERN_DEBUG, device, "%s",
+                              "Command Reject - environmental data present");
 
-		dasd_3990_handle_env_data (sense);
+		dasd_3990_handle_env_data (erp,
+                                           sense);
 
 		erp->retries = 5;
 
 	} else {
 		/* fatal error -  set status to FAILED */
-                DASD_MESSAGE (KERN_WARNING, device,
-                              "%s",
-                              "Command Reject - Fatal error\n");
-
-                cqr = erp->refers;
-
-                dasd_free_request (erp);
-
-                erp = cqr;
-
- 		check_then_set (&erp->status,
-                                CQR_STATUS_ERROR,
-                                CQR_STATUS_FAILED);
+                DASD_MESSAGE (KERN_ERR, device, "%s",
+                              "Command Reject - Fatal error");
 
+                erp = dasd_3990_erp_cleanup (erp,
+                                             CQR_STATUS_FAILED);
 	}
 
 	return erp;
@@ -1376,27 +1444,31 @@
 ccw_req_t *
 dasd_3990_erp_bus_out (ccw_req_t *erp)
 {
+
 	dasd_device_t *device = erp->device;
 
         /* first time set initial retry counter and erp_function */
+        /* and retry once without blocking queue                 */
+        /* (this enables easier enqueing of the cqr)             */
         if (erp->function != dasd_3990_erp_bus_out) {
                 erp->retries  = 256;
                 erp->function = dasd_3990_erp_bus_out;
-        }
-
-        /* issue a message and wait for 'device ready' interrupt */
 
-	DASD_MESSAGE (KERN_WARNING, device,
-                      "%s",
-                      "bus out parity error or BOPC requested by channel\n");
+        } else {
 
-        dasd_3990_erp_block_queue (erp,
-                                   60);
+                /* issue a message and wait for 'device ready' interrupt */
+                DASD_MESSAGE (KERN_DEBUG, device, "%s",
+                              "bus out parity error or BOPC requested by "
+                              "channel");
+                
+                dasd_3990_erp_block_queue (erp,
+                                           60);
+                
+        }
 
 	return erp;
 
 } /* end dasd_3990_erp_bus_out */
-#endif /* ERP_FULL_ERP */
 
 /*
  * DASD_3990_ERP_EQUIP_CHECK
@@ -1413,60 +1485,51 @@
 dasd_3990_erp_equip_check (ccw_req_t *erp,
 			   char      *sense)
 {
+
 	dasd_device_t *device = erp->device;
 
 	erp->function = dasd_3990_erp_equip_check;
 
-#ifdef ERP_FULL_ERP
 	if (sense[1] & SNS1_WRITE_INHIBITED) {
 
-		DASD_MESSAGE (KERN_WARNING, device,
-                              "%s",
+		DASD_MESSAGE (KERN_DEBUG, device, "%s",
                               "Write inhibited path encountered");
 
 		/* vary path offline */
-		DASD_MESSAGE (KERN_WARNING, device,
-                              "%s",
+		DASD_MESSAGE (KERN_ERR, device, "%s",
                               "Path should be varied off-line. "
-                              "This is not implemented yet \n - please report to "
-                              "linux390@de.ibm.com");
+                              "This is not implemented yet \n - please report "
+                              "to linux390@de.ibm.com");
 
 		erp = dasd_3990_erp_action_1 (erp);
 
-	} else 
-#endif /* ERP_FULL_ERP */
-                if (sense[2] & SNS2_ENV_DATA_PRESENT) {
-                        
-                        DASD_MESSAGE (KERN_WARNING, device,
-                                      "%s",
-                                      "Equipment Check - "
-                                      "environmental data present");
-#ifdef ERP_FULL_ERP
-                        dasd_3990_handle_env_data (sense);
-#endif /* ERP_FULL_ERP */
-                        
-                        erp = dasd_3990_erp_action_4 (erp,
-                                                      sense);
-
-#ifdef ERP_FULL_ERP
-                } else if (sense[1] & SNS1_PERM_ERR) {
-                        DASD_MESSAGE (KERN_WARNING, device,
-                                      "%s",
-                                      "Equipment Check - retry exhausted or "
-                                      "undesirable\n");
-                        
-                        erp = dasd_3990_erp_action_1 (erp);
-                        
-                } else {
-                        /* all other equipment checks - Action 5 */
-                        /* rest is done when retries == 0 */
-                        DASD_MESSAGE (KERN_WARNING, device,
-                                      "%s",
-                                      "Equipment check or processing error\n");
-                        
-                        erp = dasd_3990_erp_action_5 (erp);
-#endif /* ERP_FULL_ERP */
-                }
+	} else if (sense[2] & SNS2_ENV_DATA_PRESENT) {
+                
+                DASD_MESSAGE (KERN_DEBUG, device, "%s",
+                              "Equipment Check - "
+                              "environmental data present");
+                
+                dasd_3990_handle_env_data (erp,
+                                           sense);
+                
+                erp = dasd_3990_erp_action_4 (erp,
+                                              sense);
+                
+        } else if (sense[1] & SNS1_PERM_ERR) {
+                DASD_MESSAGE (KERN_DEBUG, device, "%s",
+                              "Equipment Check - retry exhausted or "
+                              "undesirable");
+                
+                erp = dasd_3990_erp_action_1 (erp);
+                
+        } else {
+                /* all other equipment checks - Action 5 */
+                /* rest is done when retries == 0 */
+                DASD_MESSAGE (KERN_DEBUG, device, "%s",
+                              "Equipment check or processing error");
+                
+                erp = dasd_3990_erp_action_5 (erp);
+        }
         
         return erp;
         
@@ -1487,18 +1550,17 @@
 dasd_3990_erp_data_check (ccw_req_t *erp,
 			  char      *sense)
 {
+
 	dasd_device_t *device = erp->device;
 
 	erp->function = dasd_3990_erp_data_check;
 
-#ifdef ERP_FULL_ERP
 	if (sense[2] & SNS2_CORRECTABLE) {	/* correctable data check */
 
 		/* issue message that the data has been corrected */
-		DASD_MESSAGE (KERN_WARNING, device,
-                              "%s",
+		DASD_MESSAGE (KERN_EMERG, device, "%s",
                               "Data recovered during retry with PCI "
-                              "fetch mode active\n");
+                              "fetch mode active");
 
                 /* not possible to handle this situation in Linux */    
                 panic("No way to inform appliction about the possibly "
@@ -1506,8 +1568,7 @@
 
 	} else if (sense[2] & SNS2_ENV_DATA_PRESENT) {
 
-		DASD_MESSAGE (KERN_WARNING, device,
-                              "%s",
+		DASD_MESSAGE (KERN_DEBUG, device, "%s",
                               "Uncorrectable data check recovered secondary "
                               "addr of duplex pair");
 
@@ -1516,41 +1577,25 @@
 
 	} else if (sense[1] & SNS1_PERM_ERR) {
 
-		DASD_MESSAGE (KERN_WARNING, device,
-                              "%s",
+		DASD_MESSAGE (KERN_DEBUG, device, "%s",
                               "Uncorrectable data check with internal "
-                              "retry exhausted\n");
+                              "retry exhausted");
 
 		erp = dasd_3990_erp_action_1 (erp);
 
 	} else {
 		/* all other data checks */
-		DASD_MESSAGE (KERN_WARNING, device,
-                              "%s",
+		DASD_MESSAGE (KERN_DEBUG, device, "%s",
                               "Uncorrectable data check with retry count "
-                              "exhausted...\n");
+                              "exhausted...");
 
 		erp = dasd_3990_erp_action_5 (erp);
 	}
 
-#else
-	if (sense[2] & SNS2_ENV_DATA_PRESENT) {
-                
-		DASD_MESSAGE (KERN_WARNING, device,
-                              "%s",
-                              "Uncorrectable data check recovered secondary "
-                              "addr of duplex pair");
-
-		erp = dasd_3990_erp_action_4 (erp,
-					      sense);
-	}
-#endif /* ERP_FULL_ERP */
-
 	return erp;
 
 } /* end dasd_3990_erp_data_check */
 
-#ifdef ERP_FULL_ERP
 /*
  * DASD_3990_ERP_OVERRUN
  *
@@ -1566,21 +1611,20 @@
 dasd_3990_erp_overrun (ccw_req_t *erp,
 		       char      *sense)
 {
+
 	dasd_device_t *device = erp->device;
 
 	erp->function = dasd_3990_erp_overrun;
 
-        DASD_MESSAGE (KERN_WARNING, device,
-                      "%s",
+        DASD_MESSAGE (KERN_DEBUG, device, "%s",
                       "Overrun - service overrun or overrun"
-                      " error requested by channel\n");
+                      " error requested by channel");
 
         erp = dasd_3990_erp_action_5 (erp);
 
 	return erp;
 
 } /* end dasd_3990_erp_overrun */
-#endif /* ERP_FULL_ERP */
 
 /*
  * DASD_3990_ERP_INV_FORMAT
@@ -1597,44 +1641,36 @@
 dasd_3990_erp_inv_format (ccw_req_t *erp,
 			  char      *sense)
 {
+
 	dasd_device_t *device = erp->device;
 
 	erp->function = dasd_3990_erp_inv_format;
 
 	if (sense[2] & SNS2_ENV_DATA_PRESENT) {
 
-		DASD_MESSAGE (KERN_WARNING, device,
-                              "%s",
+		DASD_MESSAGE (KERN_DEBUG, device, "%s",
                               "Track format error when destaging or "
                               "staging data");
 
-#ifdef ERP_FULL_ERP
-		dasd_3990_handle_env_data (sense);
+		dasd_3990_handle_env_data (erp,
+                                           sense);
 
 		erp = dasd_3990_erp_action_4 (erp,
 					      sense);
 
 	} else {
-		DASD_MESSAGE (KERN_WARNING, device,
-                              "%s",
+		DASD_MESSAGE (KERN_ERR, device, "%s",
                               "Invalid Track Format - Fatal error should have "
-                              "been handled within the interrupt handler\n");
+                              "been handled within the interrupt handler");
 
-		check_then_set (&erp->status,
-                                CQR_STATUS_ERROR,
-                                CQR_STATUS_FAILED);
+                erp= dasd_3990_erp_cleanup (erp,
+                                            CQR_STATUS_FAILED);
         }
-#else
-		erp = dasd_3990_erp_action_4 (erp,
-					      sense);
-	}
-#endif /* ERP_FULL_ERP */
 
 	return erp;
 
 } /* end dasd_3990_erp_inv_format */
 
-#ifdef ERP_FULL_ERP
 /*
  * DASD_3990_ERP_EOC
  *
@@ -1642,30 +1678,25 @@
  *   Handles 24 byte 'End-of-Cylinder' error.
  *
  * PARAMETER
- *   erp                current erp_head
+ *   erp                already added default erp
  * RETURN VALUES
- *   erp                new erp_head - pointer to new ERP
+ *   erp                pointer to original (failed) cqr.
  */
 ccw_req_t *
-dasd_3990_erp_EOC (ccw_req_t *erp,
+dasd_3990_erp_EOC (ccw_req_t *default_erp,
 		   char      *sense)
 {
 
-	dasd_device_t *device = erp->device;
-
-	erp->function = dasd_3990_erp_EOC;
+	dasd_device_t *device = default_erp->device;
 
-        DASD_MESSAGE (KERN_WARNING, device,
-                      "%s",
-                      "End-of-Cylinder - must never happen\n");
+        DASD_MESSAGE (KERN_ERR, device, "%s",
+                      "End-of-Cylinder - must never happen");
 
-        /* implement action 7 */
-        BUG();
-
-	return erp;
+        /* implement action 7 - BUG */
+        return dasd_3990_erp_cleanup (default_erp,
+                                      CQR_STATUS_FAILED);
 
 } /* end dasd_3990_erp_EOC */
-#endif /* ERP_FULL_ERP */  
 
 /*
  * DASD_3990_ERP_ENV_DATA
@@ -1682,16 +1713,16 @@
 dasd_3990_erp_env_data (ccw_req_t *erp,
 			char      *sense)
 {
+
 	dasd_device_t *device = erp->device;
 
 	erp->function = dasd_3990_erp_env_data;
 
-        DASD_MESSAGE (KERN_WARNING, device,
-                      "%s",
+        DASD_MESSAGE (KERN_DEBUG, device, "%s",
                       "Environmental data present");
-#ifdef ERP_FULL_ERP
-        dasd_3990_handle_env_data (sense);
-#endif /* ERP_FULL_ERP */  
+
+        dasd_3990_handle_env_data (erp,
+                                   sense);
 
 	erp = dasd_3990_erp_action_4 (erp,
 				      sense);
@@ -1700,7 +1731,6 @@
 
 } /* end dasd_3990_erp_env_data */
 
-#ifdef ERP_FULL_ERP
 /*
  * DASD_3990_ERP_NO_REC
  *
@@ -1708,28 +1738,24 @@
  *   Handles 24 byte 'No Record Found' error.
  *
  * PARAMETER
- *   erp                current erp_head
+ *   erp                already added default ERP
+ *              
  * RETURN VALUES
  *   erp                new erp_head - pointer to new ERP
  */
 ccw_req_t *
-dasd_3990_erp_no_rec (ccw_req_t *erp,
+dasd_3990_erp_no_rec (ccw_req_t *default_erp,
 		      char      *sense)
 {
-	dasd_device_t *device = erp->device;
 
-	erp->function = dasd_3990_erp_no_rec;
-        
-        DASD_MESSAGE (KERN_WARNING, device,
-                      "%s",
+	dasd_device_t *device = default_erp->device;
+
+        DASD_MESSAGE (KERN_ERR, device, "%s",
                       "No Record Found - Fatal error should "
-                      "have been handled within the interrupt handler\n");
-        
-        check_then_set (&erp->status,
-                        CQR_STATUS_ERROR,
-                        CQR_STATUS_FAILED);
+                      "have been handled within the interrupt handler");
 
-	return erp;
+        return dasd_3990_erp_cleanup (default_erp,
+                                      CQR_STATUS_FAILED);
 
 } /* end dasd_3990_erp_no_rec */
 
@@ -1749,22 +1775,16 @@
 ccw_req_t *
 dasd_3990_erp_file_prot (ccw_req_t *erp)
 {
-	dasd_device_t *device = erp->device;
 
-	erp->function = dasd_3990_erp_file_prot;
+	dasd_device_t *device = erp->device;
 
-        DASD_MESSAGE (KERN_WARNING, device,
-                      "%s",
-                      "File Protected\n");
+        DASD_MESSAGE (KERN_ERR, device, "%s",
+                      "File Protected");
 
-        check_then_set (&erp->status,
-                        CQR_STATUS_ERROR,
-                        CQR_STATUS_FAILED);
-
-	return erp;
+        return dasd_3990_erp_cleanup (erp,
+                                      CQR_STATUS_FAILED);
 
 } /* end dasd_3990_erp_file_prot */
-#endif /* ERP_FULL_ERP */  
 
 /*
  * DASD_3990_ERP_INSPECT_24 
@@ -1781,14 +1801,13 @@
  *   erp                pointer to the (addtitional) ERP
  */
 ccw_req_t *
-dasd_3990_erp_inspect_24 ( ccw_req_t *erp,
-                           char      *sense)
+dasd_3990_erp_inspect_24 (ccw_req_t *erp,
+                          char      *sense)
 {
+
 	ccw_req_t *erp_filled = NULL;
-	dasd_device_t *device = erp->device;
 
 	/* Check sense for ....    */
-#ifdef ERP_FULL_ERP
 	/* 'Command Reject'        */
 	if ((erp_filled == NULL) &&
 	    (sense[0] & SNS0_CMD_REJECT)) {
@@ -1805,7 +1824,6 @@
 	    (sense[0] & SNS0_BUS_OUT_CHECK)) {
 		erp_filled = dasd_3990_erp_bus_out (erp);
 	}
-#endif /* ERP_FULL_ERP */  
 	/* 'Equipment Check'       */
 	if ((erp_filled == NULL) &&
 	    (sense[0] & SNS0_EQUIPMENT_CHECK)) {
@@ -1818,35 +1836,30 @@
 		erp_filled = dasd_3990_erp_data_check (erp,
 						       sense);
 	}
-#ifdef ERP_FULL_ERP
 	/* 'Overrun'               */
 	if ((erp_filled == NULL) &&
 	    (sense[0] & SNS0_OVERRUN)) {
 		erp_filled = dasd_3990_erp_overrun (erp,
 						    sense);
 	}
-#endif /* ERP_FULL_ERP */  
 	/* 'Invalid Track Format'  */
 	if ((erp_filled == NULL) &&
 	    (sense[1] & SNS1_INV_TRACK_FORMAT)) {
 		erp_filled = dasd_3990_erp_inv_format (erp,
 						       sense);
 	}
-#ifdef ERP_FULL_ERP
 	/* 'End-of-Cylinder'       */
 	if ((erp_filled == NULL) &&
 	    (sense[1] & SNS1_EOC)) {
 		erp_filled = dasd_3990_erp_EOC (erp,
 						sense);
 	}
-#endif /* ERP_FULL_ERP */  
 	/* 'Environmental Data'    */
 	if ((erp_filled == NULL) &&
 	    (sense[2] & SNS2_ENV_DATA_PRESENT)) {
 		erp_filled = dasd_3990_erp_env_data (erp,
 						     sense);
 	}
-#ifdef ERP_FULL_ERP
 	/* 'No Record Found'       */
 	if ((erp_filled == NULL) &&
 	    (sense[1] & SNS1_NO_REC_FOUND)) {
@@ -1858,15 +1871,9 @@
 	    (sense[1] & SNS1_FILE_PROTECTED)) {
 		erp_filled = dasd_3990_erp_file_prot (erp);
 	}
-#endif /* ERP_FULL_ERP */  
-
-	/* other (unknown) error - do default ERP                     */
+	/* other (unknown) error - do default ERP */
 	if (erp_filled == NULL) {
 
-                DASD_MESSAGE (KERN_WARNING, device,
-                              "%s",
-                              "default ERP taken");
-
 		erp_filled = erp;	
 	}
 
@@ -1880,7 +1887,6 @@
  ***************************************************************************** 
  */
 
-#ifdef ERP_FULL_ERP
 /*
  * DASD_3990_ERPACTION_10_32 
  *
@@ -1898,19 +1904,18 @@
 dasd_3990_erp_action_10_32 (ccw_req_t *erp,
                             char      *sense)
 {
+
 	dasd_device_t *device = erp->device;
 
         erp->retries  = 256;
         erp->function = dasd_3990_erp_action_10_32;
 
-	DASD_MESSAGE (KERN_WARNING, device,
-                      "%s",
-                      "Perform logging requested\n");
+	DASD_MESSAGE (KERN_DEBUG, device, "%s",
+                      "Perform logging requested");
 
 	return erp;
 
 } /* end dasd_3990_erp_action_10_32 */
-#endif /* ERP_FULL_ERP */  
 
 /*
  * DASD_3990_ERP_ACTION_1B_32
@@ -1924,8 +1929,9 @@
  *   action because it contains no DE/LO data space.
  *
  * PARAMETER
- *   default_erp        already created default erp.
+ *   default_erp        already added default erp.
  *   sense              current sense data 
+ *
  * RETURN VALUES
  *   erp                new erp or 
  *                      default_erp in case of imprecise ending or error
@@ -1934,6 +1940,7 @@
 dasd_3990_erp_action_1B_32 (ccw_req_t *default_erp,
                             char      *sense)
 {
+
 	dasd_device_t  *device = default_erp->device;
         __u32          cpa     = 0;
         ccw_req_t      *cqr;
@@ -1942,14 +1949,14 @@
 	char           *LO_data;   /* LO_eckd_data_t */
         ccw1_t         *ccw;
 
-	DASD_MESSAGE (KERN_WARNING, device,
-                      "%s",
-                      "Write not finsihed because of unexpected condition");
+	DASD_MESSAGE (KERN_DEBUG, device, "%s",
+                      "Write not finished because of unexpected condition");
         
         default_erp->function = dasd_3990_erp_action_1B_32;
 
         /* determine the original cqr */
         cqr = default_erp; 
+
         while (cqr->refers != NULL){
                 cqr = cqr->refers;
         }
@@ -1957,8 +1964,7 @@
         /* for imprecise ending just do default erp */
         if (sense[1] & 0x01) {
 
-                DASD_MESSAGE (KERN_WARNING, device,
-                              "%s",
+                DASD_MESSAGE (KERN_DEBUG, device, "%s",
                               "Imprecise ending is set - just retry");
 
                 return default_erp;
@@ -1970,34 +1976,28 @@
         
         if (cpa == 0) {
                 
-                DASD_MESSAGE (KERN_WARNING, device,
-                              "%s",
+                DASD_MESSAGE (KERN_DEBUG, device, "%s",
                               "Unable to determine address of the CCW "
                               "to be restarted");
                 
-                check_then_set (&default_erp->status,
-                                CQR_STATUS_FILLED,
-                                CQR_STATUS_FAILED);
-                
-                return default_erp;
+                return dasd_3990_erp_cleanup (default_erp,
+                                              CQR_STATUS_FAILED);
         }
         
 	/* Build new ERP request including DE/LO */
 	erp = dasd_alloc_request ((char *) &cqr->magic,
                                   2 + 1,                    /* DE/LO + TIC */
                                   sizeof (DE_eckd_data_t) +
-                                  sizeof (LO_eckd_data_t));
+                                  sizeof (LO_eckd_data_t),
+                                  device);
+
+	if (!erp) {
 
-	if ( !erp ) {
-                DASD_MESSAGE (KERN_WARNING, device,
-                              "%s",
+                DASD_MESSAGE (KERN_ERR, device, "%s",
                               "Unable to allocate ERP");
                 
-                check_then_set (&default_erp->status,
-                                               CQR_STATUS_FILLED,
-                                               CQR_STATUS_FAILED);
-                
-                return default_erp;
+                return dasd_3990_erp_cleanup (default_erp,
+                                              CQR_STATUS_FAILED);
 	}
         
         /* use original DE */
@@ -2012,10 +2012,11 @@
         if ((sense[3]  == 0x01) &&
             (LO_data[1] & 0x01)   ){
 
-                DASD_MESSAGE (KERN_WARNING, device,
-                              "%s",
+                DASD_MESSAGE (KERN_ERR, device, "%s",
                               "BUG - this should not happen");
-                //BUG();    /* check for read count suffixing n.a. */
+
+                return dasd_3990_erp_cleanup (default_erp,
+                                              CQR_STATUS_FAILED);
         }
 
         if ((sense[7] & 0x3F) == 0x01) {
@@ -2043,22 +2044,38 @@
         ccw = erp->cpaddr;
 	memset (ccw, 0, sizeof (ccw1_t));
 	ccw->cmd_code = DASD_ECKD_CCW_DEFINE_EXTENT;
-	ccw->flags = CCW_FLAG_CC;
-	ccw->count = 16;
-	set_normalized_cda (ccw, __pa (DE_data));
+	ccw->flags    = CCW_FLAG_CC;
+	ccw->count    = 16;
+	if (dasd_set_normalized_cda (ccw,
+                                     __pa (DE_data), erp, device)) {
+                dasd_free_request (erp, device);
+                DASD_MESSAGE (KERN_ERR, device, "%s",
+                              "Unable to allocate ERP");
+
+                return dasd_3990_erp_cleanup (default_erp,
+                                              CQR_STATUS_FAILED);
+        }
 
         /* create LO ccw */    
         ccw++;
 	memset (ccw, 0, sizeof (ccw1_t));
 	ccw->cmd_code = DASD_ECKD_CCW_LOCATE_RECORD;
-	ccw->flags = CCW_FLAG_CC;
-	ccw->count = 16;
-	set_normalized_cda (ccw, __pa (LO_data));
+	ccw->flags    = CCW_FLAG_CC;
+	ccw->count    = 16;
+	if (dasd_set_normalized_cda (ccw, 
+                                     __pa (LO_data), erp, device)){
+                dasd_free_request (erp, device);
+                DASD_MESSAGE (KERN_ERR, device, "%s",
+                              "Unable to allocate ERP");
+                
+                return dasd_3990_erp_cleanup (default_erp,
+                                              CQR_STATUS_FAILED);
+        }
         
         /* TIC to the failed ccw */
         ccw++;
 	ccw->cmd_code = CCW_CMD_TIC;
-	ccw->cda = cpa;
+	ccw->cda      = cpa;
 
         /* fill erp related fields */
         erp->function = dasd_3990_erp_action_1B_32;
@@ -2067,11 +2084,11 @@
 	erp->magic    = default_erp->magic;
 	erp->lpm      = 0xFF;
 	erp->expires  = 0;
-	erp->retries  = 255;
+	erp->retries  = 256;
 	erp->status   = CQR_STATUS_FILLED;
         
         /* remove the default erp */
-        dasd_free_request (default_erp);
+        dasd_free_request (default_erp, device);
         
 	return erp;
         
@@ -2096,6 +2113,7 @@
 dasd_3990_update_1B (ccw_req_t *previous_erp,
                      char      *sense)
 {
+
 	dasd_device_t  *device = previous_erp->device;
         __u32          cpa     = 0;
         ccw_req_t      *cqr;
@@ -2103,13 +2121,13 @@
 	char           *LO_data;   /* LO_eckd_data_t */
         ccw1_t         *ccw;
 
-	DASD_MESSAGE (KERN_WARNING, device,
-                      "%s",
-                      "Write not finsihed because of unexpected condition"
+	DASD_MESSAGE (KERN_DEBUG, device, "%s",
+                      "Write not finished because of unexpected condition"
                       " - follow on");
         
         /* determine the original cqr */
-        cqr = previous_erp; 
+        cqr = previous_erp;
+
         while (cqr->refers != NULL){
                 cqr = cqr->refers;
         }
@@ -2117,13 +2135,12 @@
         /* for imprecise ending just do default erp */
         if (sense[1] & 0x01) {
 
-                DASD_MESSAGE (KERN_WARNING, device,
-                              "%s",
+                DASD_MESSAGE (KERN_DEBUG, device, "%s",
                               "Imprecise ending is set - just retry");
 
                 check_then_set (&previous_erp->status,
-                                               CQR_STATUS_ERROR,
-                                               CQR_STATUS_QUEUED);
+                                CQR_STATUS_ERROR,
+                                CQR_STATUS_QUEUED);
 
                 return previous_erp;
         } 
@@ -2133,16 +2150,8 @@
         cpa = previous_erp->dstat->cpa;    
         
         if (cpa == 0) {
-                ccw = cqr->cpaddr;   /* addr of first data transfer */
-                ccw++;               /* command in domain           */
-                ccw++;
-                cpa = (__u32) ccw; 
-        }
-        
-        if (cpa == 0) {
                 
-                DASD_MESSAGE (KERN_WARNING, device,
-                              "%s",
+                DASD_MESSAGE (KERN_DEBUG, device, "%s",
                               "Unable to determine address of the CCW "
                               "to be restarted");
                 
@@ -2161,10 +2170,14 @@
         if ((sense[3]  == 0x01) &&
             (LO_data[1] & 0x01)   ){
 
-                DASD_MESSAGE (KERN_WARNING, device,
-                              "%s",
+                DASD_MESSAGE (KERN_ERR, device, "%s",
                               "BUG - this should not happen");
-                //BUG();    /* check for read count suffixing n.a. */
+
+                check_then_set (&previous_erp->status,
+                                CQR_STATUS_ERROR,
+                                CQR_STATUS_FAILED);
+                
+                return previous_erp;
         }
 
         if ((sense[7] & 0x3F) == 0x01) {
@@ -2202,12 +2215,14 @@
         
 } /* end dasd_3990_update_1B */
 
-#ifdef ERP_FULL_ERP
 /*
  * DASD_3990_ERP_COMPOUND_RETRY 
  *
  * DESCRIPTION
  *   Handles the compound ERP action retry code.
+ *   NOTE: At least one retry is done even if zero is specified
+ *         by the sense data. This makes enqueueing of the request
+ *         easier.
  *
  * PARAMETER
  *   sense              sense data of the actual error
@@ -2221,41 +2236,30 @@
 dasd_3990_erp_compound_retry (ccw_req_t *erp,
                               char      *sense)
 {
+
         switch (sense[25] & 0x03) { 
         case 0x00:	/* no not retry */
-                erp->retries = 0;
-                break;
+                erp->retries = 1; 
+                break;            
                 
         case 0x01:	/* retry 2 times */
                 erp->retries = 2;
-
-                check_then_set (&erp->status,
-                                CQR_STATUS_ERROR,
-                                CQR_STATUS_QUEUED);
                 break;
                 
         case 0x02:	/* retry 10 times */
                 erp->retries = 10;
-
-                check_then_set (&erp->status,
-                                CQR_STATUS_ERROR,
-                                CQR_STATUS_QUEUED);
                 break;
                 
-        case 0x03:	/* retry 255 times */
-                erp->retries = 255;
-
-                check_then_set (&erp->status,
-                                CQR_STATUS_ERROR,
-                                CQR_STATUS_QUEUED);
+        case 0x03:	/* retry 256 times */
+                erp->retries = 256;
                 break;
                 
         default:
                 BUG();
         }
-
+        
         erp->function = dasd_3990_erp_compound_retry;
-
+        
 } /* end dasd_3990_erp_compound_retry */
 
 /*
@@ -2277,14 +2281,14 @@
 dasd_3990_erp_compound_path (ccw_req_t *erp,
                              char      *sense)
 {
-
+        
         if (sense[25] & DASD_SENSE_BIT_3) {
                 dasd_3990_erp_alternate_path (erp);
                 
                 if (erp->status == CQR_STATUS_FAILED) {
                         /* reset the lpm and the status to be able to 
                          * try further actions. */
-        
+                        
                         erp->lpm = LPM_ANYPATH;
                         
                         check_then_set (&erp->status,
@@ -2316,7 +2320,6 @@
 dasd_3990_erp_compound_code (ccw_req_t *erp,
                              char      *sense)
 {
-
         
         if (sense[25] & DASD_SENSE_BIT_2) {
 
@@ -2337,7 +2340,8 @@
                         break;
                         
                 default:
-                        BUG();
+                        /* should not happen - continue */
+
                 }
         }
 
@@ -2367,16 +2371,17 @@
 dasd_3990_erp_compound_config (ccw_req_t *erp,
                                char      *sense)
 {
+
         if ((sense[25] & DASD_SENSE_BIT_1) && 
             (sense[26] & DASD_SENSE_BIT_2)   ) {	
 
                 /* set to suspended duplex state then restart */
                 dasd_device_t *device  = erp->device;
 
-                DASD_MESSAGE (KERN_WARNING, device,
-                              "%s",      
-                              "Set device to suspended duplex state should be done!\n"
-                              "This is not implemented yet (for compound ERP)\n"
+                DASD_MESSAGE (KERN_ERR, device, "%s",      
+                              "Set device to suspended duplex state should be "
+                              "done!\n"
+                              "This is not implemented yet (for compound ERP)"
                               " - please report to linux390@de.ibm.com");
                 
         }
@@ -2389,12 +2394,12 @@
  * DASD_3990_ERP_COMPOUND 
  *
  * DESCRIPTION
- *   Does a detailed inspection of the 32 byte sense data
- *   and sets up a related error recovery action.  
+ *   Does the further compound program action if 
+ *   compound retry was not successful.
  *
  * PARAMETER
  *   sense              sense data of the actual error
- *   erp                pointer to the currently created ERP
+ *   erp                pointer to the current (failed) ERP
  *
  * RETURN VALUES
  *   erp                (additional) ERP pointer
@@ -2404,33 +2409,23 @@
 dasd_3990_erp_compound (ccw_req_t *erp,
                         char      *sense)
 {
-        if ((erp->function != dasd_3990_erp_compound_retry ) &&
-            (erp->function != dasd_3990_erp_compound_path  ) &&
-            (erp->function != dasd_3990_erp_compound_code  ) &&
-            (erp->function != dasd_3990_erp_compound_config)   ) {
 
-                /* called first time */
-                dasd_3990_erp_compound_retry (erp,
-                                              sense);
-        }
-        
-        /* do further action if no retry is specified / left */
         if ((erp->function == dasd_3990_erp_compound_retry) &&
-            (erp->status   == CQR_STATUS_ERROR            )   ){
+            (erp->status   == CQR_STATUS_ERROR            )   ) {
                 
                 dasd_3990_erp_compound_path (erp,
                                              sense);
         }
 
         if ((erp->function == dasd_3990_erp_compound_path) &&
-            (erp->status   == CQR_STATUS_ERROR           )   ){
+            (erp->status   == CQR_STATUS_ERROR           )    ){
 
                 erp = dasd_3990_erp_compound_code (erp,
                                                    sense);
         }
 
         if ((erp->function == dasd_3990_erp_compound_code) && 
-            (erp->status   == CQR_STATUS_ERROR           )   ){
+            (erp->status   == CQR_STATUS_ERROR           )   ) {
                 
                 dasd_3990_erp_compound_config (erp,
                                                sense);
@@ -2447,7 +2442,6 @@
         return erp;
         
 } /* end dasd_3990_erp_compound */
-#endif /* ERP_FULL_ERP */  
 
 /*
  * DASD_3990_ERP_INSPECT_32 
@@ -2468,6 +2462,7 @@
 dasd_3990_erp_inspect_32 ( ccw_req_t *erp,
                            char      *sense )
 {
+
 	dasd_device_t *device = erp->device;
 
 	erp->function = dasd_3990_erp_inspect_32;
@@ -2475,40 +2470,32 @@
 	if (sense[25] & DASD_SENSE_BIT_0) {
 
 		/* compound program action codes (byte25 bit 0 == '1') */
-#ifdef ERP_FULL_ERP
-                erp = dasd_3990_erp_compound (erp,
+                dasd_3990_erp_compound_retry (erp,
                                               sense);
-#else
-                DASD_MESSAGE (KERN_WARNING, device,
-                              "%s",
-                              "default ERP taken");
-#endif /* ERP_FULL_ERP */  
 
 	} else {
 
 		/* single program action codes (byte25 bit 0 == '0') */
 		switch (sense[25]) {
-#ifdef ERP_FULL_ERP
+
 		case 0x00:	/* success */
-                        DASD_MESSAGE (KERN_WARNING, device,
+                        DASD_MESSAGE (KERN_DEBUG, device,
                                       "ERP called for successful request %p"
                                       " - NO ERP necessary",
                                       erp);
+                        
+                        erp = dasd_3990_erp_cleanup (erp,
+                                                     CQR_STATUS_DONE);
 
-                        check_then_set (&erp->status,
-                                        CQR_STATUS_ERROR,
-                                        CQR_STATUS_DONE);
                         break;
                         
 		case 0x01:	/* fatal error */
-                        DASD_MESSAGE (KERN_WARNING, device,
-                                      "%s",
-                                      "Fatal error should "
-                                      "have been handled within the interrupt handler\n");
+                        DASD_MESSAGE (KERN_ERR, device, "%s",
+                                      "Fatal error should have been "
+                                      "handled within the interrupt handler");
 
-                        check_then_set (&erp->status,
-                                        CQR_STATUS_ERROR,
-                                        CQR_STATUS_FAILED);
+                        erp = dasd_3990_erp_cleanup (erp,
+                                                     CQR_STATUS_FAILED);
                         break;
 
 		case 0x02:	/* intervention required */
@@ -2517,15 +2504,15 @@
                         break;
 
 		case 0x0F:	/* length mismatch during update write command */
-                        DASD_MESSAGE (KERN_WARNING, device,
-                                      "%s",
-                                      "update write command error - should not happen; "
-                                      "Please send this message together with the above "
-                                      "sense data to linux390@de.ibm.com\n");
+                        DASD_MESSAGE (KERN_ERR, device, "%s",
+                                      "update write command error - should not "
+                                      "happen;\n"
+                                      "Please send this message together with "
+                                      "the above sense data to linux390@de."
+                                      "ibm.com");
 
-                        check_then_set (&erp->status,
-                                        CQR_STATUS_ERROR,
-                                        CQR_STATUS_FAILED);
+                        erp = dasd_3990_erp_cleanup (erp,
+                                                     CQR_STATUS_FAILED);
                         break;
 
 		case 0x10:	/* logging required for other channel program */
@@ -2534,17 +2521,16 @@
                         break;
 
 		case 0x15:	/* next track outside defined extend */
-                        DASD_MESSAGE (KERN_WARNING, device,
-                                      "%s",
-                                      "next track outside defined extend - should not happen; "
-                                      "Please send this message together with the above "
-                                      "sense data to linux390@de.ibm.com\n");
+                        DASD_MESSAGE (KERN_ERR, device, "%s",
+                                      "next track outside defined extend - "
+                                      "should not happen;\n"
+                                      "Please send this message together with "
+                                      "the above sense data to linux390@de."
+                                      "ibm.com");
 
-                        check_then_set (&erp->status,
-                                        CQR_STATUS_ERROR,
-                                        CQR_STATUS_FAILED);
+                        erp= dasd_3990_erp_cleanup (erp,
+                                                    CQR_STATUS_FAILED);
                         break;
-#endif /* ERP_FULL_ERP */  
 
 		case 0x1B:	/* unexpected condition during write */
 
@@ -2552,22 +2538,18 @@
                                                           sense);
                         break;
 
-#ifdef ERP_FULL_ERP
 		case 0x1C:	/* invalid data */
-                        DASD_MESSAGE (KERN_WARNING, device,
-                                      "%s",
+                        DASD_MESSAGE (KERN_EMERG, device, "%s",
                                       "Data recovered during retry with PCI "
-                                      "fetch mode active\n");
+                                      "fetch mode active");
                         
                         /* not possible to handle this situation in Linux */    
-                        panic("No way to inform appliction about the possibly "
-                              "incorret data");
+                        panic("Invalid data - No way to inform appliction about "
+                              "the possibly incorret data");
 			break;
-#endif /* ERP_FULL_ERP */  
 
 		case 0x1D:	/* state-change pending */
-                        DASD_MESSAGE (KERN_WARNING, device, 
-                                      "%s",
+                        DASD_MESSAGE (KERN_DEBUG, device, "%s",
                                       "A State change pending condition exists "
                                       "for the subsystem or device");
 
@@ -2575,10 +2557,8 @@
                                                       sense);
 			break;
 
-		default:	/* all others errors */
-                        DASD_MESSAGE (KERN_WARNING, device,
-                                      "%s",
-                                      "default ERP taken");
+		default:	/* all others errors - default erp  */
+                        
 		}
 	}
 
@@ -2607,6 +2587,7 @@
 ccw_req_t *
 dasd_3990_erp_inspect (ccw_req_t *erp)
 {
+
 	ccw_req_t *erp_new = NULL;
 	/* sense data are located in the refers record of the */
 	/* already set up new ERP !                           */
@@ -2648,24 +2629,34 @@
 ccw_req_t *
 dasd_3990_erp_add_erp (ccw_req_t *cqr)
 {
+
+	dasd_device_t *device = cqr->device;
+
 	/* allocate additional request block */
-	ccw_req_t *erp = dasd_alloc_request ((char *) &cqr->magic, 1, 0);
-	if ( !erp ) {
-		printk( KERN_WARNING PRINTK_HEADER
-			"unable to allocate ERP request\n" );
-                return NULL;
+	ccw_req_t *erp = dasd_alloc_request ((char *) &cqr->magic, 1, 0, cqr->device);
+
+	if (!erp) {
+
+                DASD_MESSAGE (KERN_ERR, device, "%s",
+                              "Unable to allocate ERP request");
+                
+                check_then_set (&cqr->status,
+                                CQR_STATUS_ERROR,
+                                CQR_STATUS_FAILED);
+
+                return cqr;
 	}
 
 	/* initialize request with default TIC to current ERP/CQR */
 	erp->cpaddr->cmd_code = CCW_CMD_TIC;
-	erp->cpaddr->cda      = ((__u32) cqr->cpaddr);
+	erp->cpaddr->cda      = (long)(cqr->cpaddr);
 	erp->function = dasd_3990_erp_add_erp;
 	erp->refers   = cqr;
 	erp->device   = cqr->device;
 	erp->magic    = cqr->magic;
 	erp->lpm      = 0xFF;
 	erp->expires  = 0;
-	erp->retries  = 255;
+	erp->retries  = 256;
 
 	erp->status = CQR_STATUS_FILLED;
 
@@ -2697,7 +2688,8 @@
 	erp = dasd_3990_erp_add_erp (cqr);
 
 	/* inspect sense, determine specific ERP if possible */
-        if (erp != NULL) {
+        if (erp != cqr) {
+
                 erp = dasd_3990_erp_inspect (erp);
         }
 
@@ -2727,13 +2719,13 @@
 dasd_3990_erp_error_match (ccw_req_t *cqr1,
 			   ccw_req_t *cqr2)
 {
+
 	/* check failed CCW */
 	if (cqr1->dstat->cpa !=
 	    cqr2->dstat->cpa) {
 	//	return 0;	/* CCW doesn't match */
-                printk(KERN_WARNING PRINTK_HEADER 
-                       "_error_match: CCW doesn't match -> ignore\n");
 	}
+
 	/* check sense data; byte 0-2,25,27 */
 	if (!((strncmp (cqr1->dstat->ii.sense.data,
 			cqr2->dstat->ii.sense.data,
@@ -2745,9 +2737,10 @@
 
 		return 0;	/* sense doesn't match */
 	}
+
 	return 1;		/* match */
 
-}				/* end dasd_3990_erp_error_match */
+} /* end dasd_3990_erp_error_match */
 
 /*
  * DASD_3990_ERP_IN_ERP
@@ -2760,35 +2753,38 @@
  *   cqr                failed cqr (either original cqr or already an erp)
  *
  * RETURN VALUES
- *   erp                erp-pointer to the already defined error recovery procedure OR
+ *   erp                erp-pointer to the already defined error 
+ *                      recovery procedure OR
  *                      NULL if a 'new' error occurred.
  */
 ccw_req_t *
 dasd_3990_erp_in_erp (ccw_req_t *cqr)
 {
-	ccw_req_t *erp_head = cqr,	/* save erp chain head */
-	         *erp_match = NULL;	/* save erp chain head */
+
+	ccw_req_t *erp_head  = cqr,	/* save erp chain head */
+                  *erp_match = NULL;	/* save erp chain head */
 	int match = 0;		/* 'boolean' for matching error found */
 
 	if (cqr->refers == NULL) {	/* return if not in erp */
 		return NULL;
 	}
+
 	/* check the erp/cqr chain for current error */
 	do {
 		match = dasd_3990_erp_error_match (erp_head,
 						   cqr->refers);
-		erp_match = cqr;	/* save possible matching erp  */
-		cqr = cqr->refers;	/* check next erp/cqr in queue */
+		erp_match = cqr;	 /* save possible matching erp  */
+		cqr       = cqr->refers; /* check next erp/cqr in queue */
+
 	} while ((cqr->refers != NULL) &&
-		 (match == 0));
+		 (!match             )   );
 
-	if (match) {
-		return erp_match;	/* return address of matching erp */
-	} else {
-		return NULL;	/* return NULL to indicate that no match
-				   was found */
+	if (!match) {
+		return NULL; 	/* no match was found */
 	}
 
+        return erp_match;	/* return address of matching erp */
+
 } /* END dasd_3990_erp_in_erp */
 
 /*
@@ -2810,9 +2806,10 @@
 ccw_req_t *
 dasd_3990_erp_further_erp (ccw_req_t *erp)
 {
-        dasd_device_t     *device = erp->device;
+
+        dasd_device_t *device = erp->device;
+        char          *sense  = erp->dstat->ii.sense.data;
         
-#ifdef ERP_FULL_ERP
         /* check for 24 byte sense ERP */
 	if ((erp->function == dasd_3990_erp_bus_out ) ||
             (erp->function == dasd_3990_erp_action_1) ||
@@ -2823,8 +2820,6 @@
 	} else if (erp->function == dasd_3990_erp_action_5) {
                 
                 /* retries have not been successful */
-                char *sense = erp->dstat->ii.sense.data;
-                
                 /* prepare erp for retry on different channel path */
                 erp = dasd_3990_erp_action_1 (erp);
                 
@@ -2853,26 +2848,25 @@
                                 break;
                         }
                         default:
-                                DASD_MESSAGE (KERN_WARNING, device,
-                                              "invalid subcommand modifier 0x%x for "
-                                              "Diagnostic Control Command",
+                                DASD_MESSAGE (KERN_DEBUG, device,
+                                              "invalid subcommand modifier 0x%x "
+                                              "for Diagnostic Control Command",
                                               sense[25]);
                         }
                 } 
 
-//        /* check for 32 byte sense ERP */
-//	} else if ((erp->function == dasd_3990_erp_xxx){
-#else
-        /* check for 24 byte sense ERP */
-	if ((erp->function == dasd_3990_erp_action_1) ||
-            (erp->function == dasd_3990_erp_action_4)   ){
-                
-                erp = dasd_3990_erp_action_1 (erp);
-#endif /* ERP_FULL_ERP */  
+        /* check for 32 byte sense ERP */
+	} else if ((erp->function == dasd_3990_erp_compound_retry ) ||
+                   (erp->function == dasd_3990_erp_compound_path  ) ||
+                   (erp->function == dasd_3990_erp_compound_code  ) ||
+                   (erp->function == dasd_3990_erp_compound_config)   ) {
                 
+                erp = dasd_3990_erp_compound (erp,
+                                              sense);
+
 	} else {
                 /* no retry left and no additional special handling necessary */
-                DASD_MESSAGE (KERN_WARNING, device,
+                DASD_MESSAGE (KERN_ERR, device,
                               "no retries left for erp %p - "
                               "set status to FAILED",
                               erp);
@@ -2892,102 +2886,87 @@
  * DESCRIPTION
  *   An error occurred again and an ERP has been detected which is already
  *   used to handle this error (e.g. retries). 
- *   All prior ERP's are set to status DONE and the retry counter is
- *   decremented.
- *   If retry counter is already 0, it has to checked if further action
- *   is needed (besides retry) or if the ERP has failed.
+ *   All prior ERP's are asumed to be successful and therefore removed
+ *   from queue.
+ *   If retry counter of matching erp is already 0, it is checked if further 
+ *   action is needed (besides retry) or if the ERP has failed.
  *
  * PARAMETER
  *   erp_head           first ERP in ERP-chain
- *   erp_match          ERP that handles the actual error.
+ *   erp                ERP that handles the actual error.
+ *                      (matching erp)
  *
  * RETURN VALUES
- *   none                
+ *   erp                modified/additional ERP
  */
-void
+ccw_req_t *
 dasd_3990_erp_handle_match_erp (ccw_req_t *erp_head,
-				ccw_req_t *erp_match)
+				ccw_req_t *erp)
 {
 
 	dasd_device_t *device   = erp_head->device;
-	ccw_req_t     *erp_done = erp_head;
+	ccw_req_t     *erp_done = erp_head;  /* finished req */
         ccw_req_t     *erp_free = NULL;      /* req to be freed */    
-
+        
 	/* loop over successful ERPs and remove them from chanq */
-	while ((erp_done != erp_match) &&
-	       (erp_done != NULL)) {
-
-#ifdef ERP_DEBUG
-                DASD_MESSAGE (KERN_WARNING, device,
-                              "successful ERP - dequeue and free request %p",
-                              (void *) erp_done);
-#endif /* ERP_DEBUG */
+	while (erp_done != erp) {
 
-		check_then_set (&erp_done->status,
-                                CQR_STATUS_ERROR,
-                                CQR_STATUS_DONE);
+                if (erp_done == NULL) 	/* end of chain reached */
+                        panic (PRINTK_HEADER "Programming error in ERP! The "
+                               "original request was lost\n");
 
 		/* remove the request from the device queue */
 		dasd_chanq_deq (&device->queue,
 				erp_done);
-
+                
                 erp_free = erp_done;
 		erp_done = erp_done->refers;
                 
 		/* free the finished erp request */
-		dasd_free_request (erp_free);
+		dasd_free_request (erp_free, erp_free->device);
 
-	}
+	} /* end while */
 
-	if (erp_done == NULL) 	/* erp_done should never be NULL! */
-		panic (PRINTK_HEADER "Programming error in ERP! The original "
-                       "request was lost\n");
-
-#ifdef ERP_DEBUG
-	/* handle matching ERP */
-        DASD_MESSAGE (KERN_WARNING, device,
-                      "handle matching erp %p",
-                      (void *) erp_done);
-#endif
-        
-        if (erp_done->retries > 0) {
+        if (erp->retries > 0) {
+                
+                char *sense = erp->dstat->ii.sense.data;
                 
                 /* check for special retries */
-                if (erp_done->function == dasd_3990_erp_action_4) {
-                        char *sense = erp_done->dstat->ii.sense.data;
-                        erp_done = dasd_3990_erp_action_4 (erp_done,
-                                                           sense);
-                        
-                } else if (erp_done->function == dasd_3990_erp_action_1B_32) {
-                        char *sense = erp_done->dstat->ii.sense.data;
-                        erp_done = dasd_3990_update_1B (erp_done,
-                                                        sense);
-
-#ifdef ERP_FULL_ERP
-                } else if (erp_done->function == dasd_3990_erp_int_req) {
-                        erp_done = dasd_3990_erp_int_req (erp_done);
-#endif /* ERP_FULL_ERP */  
+                if (erp->function == dasd_3990_erp_action_4) {
+                        
+                        erp = dasd_3990_erp_action_4 (erp,
+                                                      sense);
+                        
+                } else if (erp->function == dasd_3990_erp_action_1B_32) {
+                        
+                        erp = dasd_3990_update_1B (erp,
+                                                   sense);
+
+                } else if (erp->function == dasd_3990_erp_int_req) {
+
+                        erp = dasd_3990_erp_int_req (erp);
                         
                 } else {
                         /* simple retry   */
-                        DASD_MESSAGE (KERN_WARNING, device,
+                        DASD_MESSAGE (KERN_DEBUG, device,
                                       "%i retries left for erp %p",
-                                      erp_done->retries,
-                                      (void *) erp_done);
+                                      erp->retries,
+                                      erp);
                         
                         /* handle the request again... */
-                        check_then_set (&erp_done->status,
+                        check_then_set (&erp->status,
                                         CQR_STATUS_ERROR,
                                         CQR_STATUS_QUEUED);
                 }
+                
         } else {
                 /* no retry left - check for further necessary action    */
                 /* if no further actions, handle rest as permanent error */
-                erp_done = dasd_3990_erp_further_erp (erp_done);
+                erp = dasd_3990_erp_further_erp (erp);
 	}
 
-        erp_head = erp_done;
-
+        return erp;
+        
 } /* end dasd_3990_erp_handle_match_erp */
 
 /*
@@ -3004,30 +2983,27 @@
  *   erp                erp-pointer to the head of the ERP action chain.
  *                      This means:
  *                       - either a ptr to an additional ERP cqr or
- *                       - the original given cqr (which's status might be modified)
+ *                       - the original given cqr (which's status might 
+ *                         be modified)
  */
 ccw_req_t *
 dasd_3990_erp_action (ccw_req_t *cqr)
 {
+
 	ccw_req_t     *erp    = NULL;
 	dasd_device_t *device = cqr->device;
+        __u32         cpa     = cqr->dstat->cpa;    
 
 #ifdef ERP_DEBUG 
-        __u32 cpa = cqr->dstat->cpa;    
-#endif /* ERP_DEBUG */
-
-#ifdef ERP_DEBUG 
-
-	printk (KERN_WARNING PRINTK_HEADER
-		"entering 3990 ERP for "
-		"0x%04X on sch %d = /dev/%s \n",
-		device->devinfo.devno,
-		device->devinfo.irq,
-		device->name);
+        DASD_MESSAGE (KERN_DEBUG, device,
+                      "entering 3990 ERP for "
+                      "0x%04X on sch %d = /dev/%s ",
+                      device->devinfo.devno,
+                      device->devinfo.irq,
+                      device->name);
 
 	/* print current erp_chain */
-        DASD_MESSAGE (KERN_WARNING, device,
-                      "%s",
+        DASD_MESSAGE (KERN_DEBUG, device, "%s",
                       "ERP chain at BEGINNING of ERP-ACTION");
         {
                 ccw_req_t *temp_erp = NULL;
@@ -3035,23 +3011,24 @@
                      temp_erp != NULL; 
                      temp_erp = temp_erp->refers){
 
-                        DASD_MESSAGE (KERN_WARNING, device,
-                                      "      erp %p refers to %p \n",
+                        DASD_MESSAGE (KERN_DEBUG, device,
+                                      "      erp %p refers to %p",
                                       temp_erp,
                                       temp_erp->refers);
                 }
         } 
-#endif
+#endif /* ERP_DEBUG */
 
 	/* double-check if current erp/cqr was successfull */
-	if ((cqr->dstat->cstat == 0x00) &&
-	    (cqr->dstat->dstat == (DEV_STAT_CHN_END | DEV_STAT_DEV_END))) {
-                DASD_MESSAGE (KERN_WARNING, device,
+	if ((cqr->dstat->cstat == 0x00                                 ) &&
+	    (cqr->dstat->dstat == (DEV_STAT_CHN_END | DEV_STAT_DEV_END))   ) {
+
+                DASD_MESSAGE (KERN_DEBUG, device,
                               "ERP called for successful request %p"
                               " - NO ERP necessary",
                               cqr);
                 
-                check_then_set (&erp->status,
+                check_then_set (&cqr->status,
                                 CQR_STATUS_ERROR,
                                 CQR_STATUS_DONE);
 
@@ -3059,12 +3036,12 @@
 	}
 	/* check if sense data are available */
 	if (!cqr->dstat->ii.sense.data) {
-		DASD_MESSAGE (KERN_WARNING, device,
+		DASD_MESSAGE (KERN_DEBUG, device,
 			"ERP called witout sense data avail ..."
 			"request %p - NO ERP possible",
 			cqr);
 
-                check_then_set (&erp->status,
+                check_then_set (&cqr->status,
                                 CQR_STATUS_ERROR,
                                 CQR_STATUS_FAILED);
 
@@ -3080,38 +3057,178 @@
 		erp = dasd_3990_erp_additional_erp (cqr);
 	} else {
 		/* matching erp found - set all leading erp's to DONE */
-		dasd_3990_erp_handle_match_erp (cqr, erp);
-		erp = cqr;
+		erp = dasd_3990_erp_handle_match_erp (cqr, 
+                                                      erp);
 	}
 
 #ifdef ERP_DEBUG
 	/* print current erp_chain */
-        DASD_MESSAGE (KERN_WARNING, device,
-                      "%s",
+        DASD_MESSAGE (KERN_DEBUG, device, "%s",
                       "ERP chain at END of ERP-ACTION");
         {
                 ccw_req_t *temp_erp = NULL;
                 for (temp_erp = erp; 
                      temp_erp != NULL; 
-                     temp_erp = temp_erp->refers){
+                     temp_erp = temp_erp->refers) {
 
-                        DASD_MESSAGE (KERN_WARNING, device,
-                                      "      erp %p refers to %p \n",
+                        DASD_MESSAGE (KERN_DEBUG, device,
+                                      "      erp %p refers to %p",
                                       temp_erp,
                                       temp_erp->refers);
                 }
         }
 #endif /* ERP_DEBUG */
 
-#ifdef ERP_DEBUG
         if (erp->status == CQR_STATUS_FAILED) {
-                log_erp_chain (erp, 1, cpa);
+
+                log_erp_chain (erp,
+                               1,
+                               cpa);
+        }
+
+        /* enqueue added ERP request */
+        if ((erp != cqr                      ) &&
+            (erp->status == CQR_STATUS_FILLED)   ){
+
+                dasd_chanq_enq_head (&device->queue,
+                                     erp);
+        } else {
+                if ((erp->status == CQR_STATUS_FILLED )||
+                    (erp != cqr                       )  ){
+                        /* something strange happened - log the error and throw a BUG() */
+                        DASD_MESSAGE (KERN_ERR, device, "%s",
+                                      "Problems with ERP chain!!! BUG");
+
+                        /* print current erp_chain */
+                        DASD_MESSAGE (KERN_DEBUG, device, "%s",
+                                      "ERP chain at END of ERP-ACTION");
+                        {
+                                ccw_req_t *temp_erp = NULL;
+                                for (temp_erp = erp; 
+                                     temp_erp != NULL; 
+                                     temp_erp = temp_erp->refers) {
+
+                                        DASD_MESSAGE (KERN_DEBUG, device,
+                                                      "      erp %p (function %p) refers to %p",
+                                                      temp_erp,
+                                                      temp_erp->function,
+                                                      temp_erp->refers);
+                                }
+                        }
+                        BUG();
+                }
+
         }
-#endif /* ERP_DEBUG */
 
 	return erp;
 
 } /* end dasd_3990_erp_action */
+
+/*
+ * DASD_3990_ERP_POSTACTION
+ *
+ * DESCRIPTION
+ *   Frees all ERPs of the current ERP Chain and set the status
+ *   of the original CQR either to CQR_STATUS_DONE if ERP was successful
+ *   or to CQR_STATUS_FAILED if ERP was NOT successful.
+ *
+ * PARAMETER
+ *   erp                current erp_head
+ *
+ * RETURN VALUES
+ *   cqr                pointer to the original CQR
+ */
+ccw_req_t *
+dasd_3990_erp_postaction (ccw_req_t *erp)
+{
+
+	ccw_req_t     *cqr      = NULL, 
+                      *free_erp = NULL;
+	dasd_device_t *device   = erp->device;
+	int           success;
+
+	if (erp->refers   == NULL || 
+            erp->function == NULL   ) {
+
+		BUG ();
+	}
+
+	if (erp->status == CQR_STATUS_DONE)
+		success = 1;
+	else
+		success = 0;
+
+#ifdef ERP_DEBUG
+
+	/* print current erp_chain */
+	printk (KERN_DEBUG PRINTK_HEADER
+		"3990 ERP postaction called for erp chain:\n");
+	{
+		ccw_req_t *temp_erp = NULL;
+
+		for (temp_erp = erp; 
+                     temp_erp != NULL;
+		     temp_erp = temp_erp->refers) {
+
+			printk (KERN_DEBUG PRINTK_HEADER
+				"       erp %p refers to %p with erp function %p\n",
+				temp_erp, temp_erp->refers, temp_erp->function);
+		}
+	}
+
+#endif /* ERP_DEBUG */
+
+	/* free all ERPs - but NOT the original cqr */
+	while (erp->refers != NULL) {
+
+		free_erp = erp;
+		erp      = erp->refers;
+
+		/* remove the request from the device queue */
+		dasd_chanq_deq (&device->queue,
+                                free_erp);
+
+		/* free the finished erp request */
+		dasd_free_request (free_erp, free_erp->device);
+	}
+
+	/* save ptr to original cqr */
+	cqr = erp;
+
+	/* set corresponding status to original cqr */
+	if (success) {
+
+		check_then_set (&cqr->status, 
+                                CQR_STATUS_ERROR,
+				CQR_STATUS_DONE);
+	} else {
+
+		check_then_set (&cqr->status,
+				CQR_STATUS_ERROR, 
+                                CQR_STATUS_FAILED);
+	}
+
+#ifdef ERP_DEBUG
+	/* print current erp_chain */
+	printk (KERN_DEBUG PRINTK_HEADER
+		"3990 ERP postaction finished with remaining chain:\n");
+	{
+		ccw_req_t *temp_erp = NULL;
+
+		for (temp_erp = cqr; 
+                     temp_erp != NULL;
+		     temp_erp = temp_erp->refers) {
+
+			printk (KERN_DEBUG PRINTK_HEADER
+				" erp %p refers to %p \n", temp_erp,
+				temp_erp->refers);
+		}
+	}
+#endif /* ERP_DEBUG */
+
+	return cqr;
+
+} /* end dasd_3990_erp_postaction */
 
 /*
  * Overrides for Emacs so that we follow Linus's tabbing style.
diff -u --recursive --new-file v2.4.7/linux/drivers/s390/block/dasd_3990_erp.h linux/drivers/s390/block/dasd_3990_erp.h
--- v2.4.7/linux/drivers/s390/block/dasd_3990_erp.h	Wed Apr 11 19:02:28 2001
+++ linux/drivers/s390/block/dasd_3990_erp.h	Sun Aug  5 13:12:41 2001
@@ -10,7 +10,6 @@
 #ifndef DASD_3990_ERP_H
 #define DASD_3990_ERP_H
 
-
 dasd_era_t dasd_3990_erp_examine (ccw_req_t *, devstat_t *);
 
 ccw_req_t *dasd_3990_erp_action (ccw_req_t *);
@@ -19,10 +18,9 @@
 void dasd_3990_erp_restart_queue (unsigned long);
 
 typedef struct DCTL_data_t {
-	unsigned char  subcommand;  /* e.g Inhibit Write, Enable Write,... */
-	unsigned char  modifier;    /* Subcommand modifier                 */
-	unsigned short res;	    /* reserved */
+	unsigned char subcommand;	/* e.g Inhibit Write, Enable Write,... */
+	unsigned char modifier;	/* Subcommand modifier                 */
+	unsigned short res;	/* reserved */
 } __attribute__ ((packed)) DCTL_data_t;
 
-
-#endif /* DASD_3990_ERP_H */
+#endif				/* DASD_3990_ERP_H */
diff -u --recursive --new-file v2.4.7/linux/drivers/s390/block/dasd_9336_erp.c linux/drivers/s390/block/dasd_9336_erp.c
--- v2.4.7/linux/drivers/s390/block/dasd_9336_erp.c	Tue Feb 13 14:13:44 2001
+++ linux/drivers/s390/block/dasd_9336_erp.c	Sun Aug  5 13:12:41 2001
@@ -6,7 +6,8 @@
  */
 
 #include <asm/ccwcache.h>
-#include <asm/dasd.h>
+#include "dasd_int.h"
+#include "dasd_9336_erp.h"
 
 #ifdef PRINTK_HEADER
 #undef PRINTK_HEADER
@@ -29,15 +30,12 @@
  *   dasd_era_fatal     for all fatal (unrecoverable errors)
  *   dasd_era_recover   for all others.
  */
-dasd_era_t
-dasd_9336_erp_examine (ccw_req_t * cqr, devstat_t * stat)
+dasd_era_t dasd_9336_erp_examine (ccw_req_t * cqr, devstat_t * stat)
 {
-	char *sense = stat->ii.sense.data;
-
 	/* check for successful execution first */
 	if (stat->cstat == 0x00 &&
 	    stat->dstat == (DEV_STAT_CHN_END | DEV_STAT_DEV_END))
-		return dasd_era_none;
+		    return dasd_era_none;
 
 	/* examine the 24 byte sense data */
 	return dasd_era_recover;
diff -u --recursive --new-file v2.4.7/linux/drivers/s390/block/dasd_9336_erp.h linux/drivers/s390/block/dasd_9336_erp.h
--- v2.4.7/linux/drivers/s390/block/dasd_9336_erp.h	Wed Dec 31 16:00:00 1969
+++ linux/drivers/s390/block/dasd_9336_erp.h	Sun Aug  5 13:12:41 2001
@@ -0,0 +1,15 @@
+/* 
+ * File...........: linux/drivers/s390/block/dasd_9336_erp.h
+ * Author(s)......: Horst Hummel <Horst Hummel@de.ibm.com>
+ * Bugreports.to..: <Linux390@de.ibm.com>
+ * (C) IBM Corporation, IBM Deutschland Entwicklung GmbH, 2000
+ *
+ * History of changes (starts July 2000)
+ */
+
+#ifndef DASD_9336_ERP_H
+#define DASD_9336_ERP_H
+
+dasd_era_t dasd_9336_erp_examine (ccw_req_t *, devstat_t *);
+
+#endif				/* DASD_3990_ERP_H */
diff -u --recursive --new-file v2.4.7/linux/drivers/s390/block/dasd_9343_erp.c linux/drivers/s390/block/dasd_9343_erp.c
--- v2.4.7/linux/drivers/s390/block/dasd_9343_erp.c	Tue Feb 13 14:13:44 2001
+++ linux/drivers/s390/block/dasd_9343_erp.c	Sun Aug  5 13:12:41 2001
@@ -6,18 +6,17 @@
  */
 
 #include <asm/ccwcache.h>
-#include <asm/dasd.h>
+#include "dasd_int.h"
 
 #ifdef PRINTK_HEADER
 #undef PRINTK_HEADER
 #define PRINTK_HEADER "dasd_erp(9343)"
 #endif				/* PRINTK_HEADER */
 
-dasd_era_t
-dasd_9343_erp_examine (ccw_req_t * cqr, devstat_t * stat)
+dasd_era_t dasd_9343_erp_examine (ccw_req_t * cqr, devstat_t * stat)
 {
 	if (stat->cstat == 0x00 &&
 	    stat->dstat == (DEV_STAT_CHN_END | DEV_STAT_DEV_END))
-		return dasd_era_none;
+		    return dasd_era_none;
 	return dasd_era_recover;
 }
diff -u --recursive --new-file v2.4.7/linux/drivers/s390/block/dasd_9343_erp.h linux/drivers/s390/block/dasd_9343_erp.h
--- v2.4.7/linux/drivers/s390/block/dasd_9343_erp.h	Wed Apr 11 19:02:28 2001
+++ linux/drivers/s390/block/dasd_9343_erp.h	Sun Aug  5 13:12:41 2001
@@ -10,9 +10,8 @@
 #ifndef DASD_9343_ERP_H
 #define DASD_9343_ERP_H
 
-
 dasd_era_t dasd_9343_erp_examine (ccw_req_t *, devstat_t *);
 
 ccw_req_t *dasd_9343_erp_action (ccw_req_t *);
 
-#endif /* DASD_9343_ERP_H */
+#endif				/* DASD_9343_ERP_H */
diff -u --recursive --new-file v2.4.7/linux/drivers/s390/block/dasd_diag.c linux/drivers/s390/block/dasd_diag.c
--- v2.4.7/linux/drivers/s390/block/dasd_diag.c	Wed Apr 11 19:02:28 2001
+++ linux/drivers/s390/block/dasd_diag.c	Sun Aug  5 13:12:41 2001
@@ -14,11 +14,12 @@
  *          fixed partition handling and HDIO_GETGEO
  */
 
+#include <linux/config.h>
 #include <linux/stddef.h>
 #include <linux/kernel.h>
 #include <asm/debug.h>
 
-#include <linux/malloc.h>
+#include <linux/slab.h>
 #include <linux/hdreg.h>	/* HDIO_GETGEO                      */
 #include <linux/blk.h>
 #include <asm/ccwcache.h>
@@ -29,6 +30,7 @@
 #include <asm/irq.h>
 #include <asm/s390dyn.h>
 
+#include "dasd_int.h"
 #include "dasd_diag.h"
 
 #ifdef PRINTK_HEADER
@@ -39,7 +41,7 @@
 dasd_discipline_t dasd_diag_discipline;
 
 typedef struct
-dasd_diag_private_t {
+    dasd_diag_private_t {
 	dasd_diag_characteristics_t rdc_data;
 	diag_rw_io_t iob;
 	diag_init_io_t iib;
@@ -64,10 +66,8 @@
 			      ".previous\n"
 			      ".section __ex_table,\"a\"\n"
 			      "    .align 4\n"
-			      "    .long 0b,2b\n"
-			      ".previous\n"
-			      :"=d"   (rc)
-			      :"d"    ((void *) __pa (devchar))
+			      "    .long 0b,2b\n" ".previous\n":"=d" (rc)
+			      :"d" ((void *) __pa (devchar))
 			      :"1");
 	return rc;
 }
@@ -75,11 +75,11 @@
 static __inline__ int
 dia250 (void *iob, int cmd)
 {
- 	__asm__ __volatile__ ("    lr    0,%1\n"
-                              "    diag  0,%0,0x250\n"
-                              "0:  ipm   %0\n"
-                              "    srl   %0,28\n"
- 			      "    or    %0,1\n"
+	__asm__ __volatile__ ("    lr    0,%1\n"
+			      "    diag  0,%0,0x250\n"
+			      "0:  ipm   %0\n"
+			      "    srl   %0,28\n"
+			      "    or    %0,1\n"
 			      "1:\n"
 			      ".section .fixup,\"ax\"\n"
 			      "2:  lhi   %0,3\n"
@@ -90,12 +90,10 @@
 			      ".previous\n"
 			      ".section __ex_table,\"a\"\n"
 			      "    .align 4\n"
-                              "    .long 0b,2b\n"
-                              ".previous\n"
-                              : "+d" (cmd)
-                              : "d" ((void *) __pa (iob))
-                              : "0", "1", "cc" );
- 	return cmd;
+			      "    .long 0b,2b\n" ".previous\n":"+d" (cmd)
+			      :"d" ((void *) __pa (iob))
+			      :"0", "1", "cc");
+	return cmd;
 }
 
 static __inline__ int
@@ -115,7 +113,7 @@
 
 	rc = dia250 (iib, INIT_BIO);
 
-	return rc&3;
+	return rc & 3;
 }
 
 static __inline__ int
@@ -128,7 +126,7 @@
 	memset (iib, 0, sizeof (diag_init_io_t));
 	iib->dev_nr = device->devinfo.devno;
 	rc = dia250 (iib, TERM_BIO);
-	return rc&3;
+	return rc & 3;
 }
 
 int
@@ -154,20 +152,17 @@
 	if (rc > 8) {
 		PRINT_WARN ("dia250 returned CC %d\n", rc);
 		check_then_set (&cqr->status,
-					       CQR_STATUS_QUEUED,
-					       CQR_STATUS_ERROR);
-        } else if (rc == 0 ) {                                     
-               check_then_set(&cqr->status,        
-                                             CQR_STATUS_QUEUED,   
-                                             CQR_STATUS_DONE);    
-               dasd_schedule_bh(device);                                
-	 } else {
+				CQR_STATUS_QUEUED, CQR_STATUS_ERROR);
+	} else if (rc == 0) {
+		check_then_set (&cqr->status,
+				CQR_STATUS_QUEUED, CQR_STATUS_DONE);
+		dasd_schedule_bh (device);
+	} else {
 		if (cqr->expires) {
 			cqr->expires += cqr->startclk;
 		}
 		check_then_set (&cqr->status,
-					       CQR_STATUS_QUEUED,
-					       CQR_STATUS_IN_IO);
+				CQR_STATUS_QUEUED, CQR_STATUS_IN_IO);
 		rc = 0;
 	}
 	return rc;
@@ -176,22 +171,26 @@
 void
 dasd_ext_handler (struct pt_regs *regs, __u16 code)
 {
+    	int cpu = smp_processor_id();
 	ccw_req_t *cqr;
 	int ip = S390_lowcore.ext_params;
-	char status = *((char *) S390_lowcore.ext_params + 5);
+	char status = *((char *) &S390_lowcore.ext_params + 5);
 	dasd_device_t *device;
 	int done_fast_io = 0;
 	int devno;
 
+	irq_enter(cpu, -1);
+
 	if (!ip) {		/* no intparm: unsolicited interrupt */
 		printk (KERN_WARNING PRINTK_HEADER
 			"caught unsolicited interrupt\n");
+		irq_exit(cpu, -1);
 		return;
 	}
 	if (ip & 0x80000001) {
 		printk (KERN_WARNING PRINTK_HEADER
-			"caught spurious interrupt with parm %08x\n",
-			ip);
+			"caught spurious interrupt with parm %08x\n", ip);
+		irq_exit(cpu, -1);
 		return;
 	}
 	cqr = (ccw_req_t *) ip;
@@ -201,7 +200,8 @@
 		printk (KERN_WARNING PRINTK_HEADER
 			" INT on devno 0x%04X  = /dev/%s (%d:%d)"
 			" belongs to NULL device\n",
-			devno, device->name, MAJOR (device->kdev), MINOR (device->kdev));
+			devno, device->name, MAJOR (device->kdev),
+			MINOR (device->kdev));
 	}
 	if (strncmp (device->discipline->ebcname, (char *) &cqr->magic, 4)) {
 		printk (KERN_WARNING PRINTK_HEADER
@@ -211,18 +211,15 @@
 			devno, device->name,
 			MAJOR (device->kdev), MINOR (device->kdev),
 			cqr->magic, *(int *) (&device->discipline->name));
+		irq_exit(cpu, -1);
 		return;
 	}
 	asm volatile ("STCK %0":"=m" (cqr->stopclk));
 	switch (status) {
 	case 0x00:
 		check_then_set (&cqr->status,
-					       CQR_STATUS_IN_IO,
-					       CQR_STATUS_DONE);
-		if ( device->level == DASD_DEVICE_LEVEL_ANALYSIS_PENDING)
-					device->level = DASD_DEVICE_LEVEL_ANALYSIS_PREPARED;
-		if (cqr->next &&
-		    (cqr->next->status == CQR_STATUS_QUEUED)) {
+				CQR_STATUS_IN_IO, CQR_STATUS_DONE);
+		if (cqr->next && (cqr->next->status == CQR_STATUS_QUEUED)) {
 			if (dasd_start_diag (cqr->next) == 0) {
 				done_fast_io = 1;
 			}
@@ -233,12 +230,12 @@
 	case 0x03:
 	default:
 		check_then_set (&cqr->status,
-					       CQR_STATUS_IN_IO,
-					       CQR_STATUS_FAILED);
+				CQR_STATUS_IN_IO, CQR_STATUS_FAILED);
 		break;
 	}
 	wake_up (&device->wait_q);
 	dasd_schedule_bh (device);
+	irq_exit(cpu, -1);
 }
 
 static int
@@ -255,47 +252,46 @@
 
 	if (device == NULL) {
 		printk (KERN_WARNING PRINTK_HEADER
-		   "Null device pointer passed to characteristics checker\n");
+			"Null device pointer passed to characteristics checker\n");
 		return -ENODEV;
 	}
-	if (device->private != NULL) {
-                kfree (device->private);
-        } 
-        device->private = kmalloc (sizeof (dasd_diag_private_t), GFP_KERNEL);
-        if (device->private == NULL) {
-                printk (KERN_WARNING PRINTK_HEADER
-                        "memory allocation failed for private data\n");
-                return -ENOMEM;
+	device->private = kmalloc (sizeof (dasd_diag_private_t), GFP_KERNEL);
+	if (device->private == NULL) {
+		printk (KERN_WARNING PRINTK_HEADER
+			"memory allocation failed for private data\n");
+		rc = -ENOMEM;
+                goto fail;
 	}
 	private = (dasd_diag_private_t *) device->private;
 	rdc_data = (void *) &(private->rdc_data);
-        
+
 	rdc_data->dev_nr = device->devinfo.devno;
 	rdc_data->rdc_len = sizeof (dasd_diag_characteristics_t);
-        
-	if (dia210 (rdc_data) != 0) {
-                goto nodiag;
+
+        rc = dia210 (rdc_data);
+	if ( rc != 0) {
+		goto fail;
 	}
 	if (rdc_data->vdev_class != DEV_CLASS_FBA &&
 	    rdc_data->vdev_class != DEV_CLASS_ECKD &&
 	    rdc_data->vdev_class != DEV_CLASS_CKD) {
-                goto nodiag;
+                rc = -ENOTSUPP;
+		goto fail;
 	}
 #if 0
 	printk (KERN_INFO PRINTK_HEADER
 		"%04X: %04X on real %04X/%02X\n",
 		rdc_data->dev_nr,
-		rdc_data->vdev_type,
-		rdc_data->rdev_type, rdc_data->rdev_model);
+		rdc_data->vdev_type, rdc_data->rdev_type, rdc_data->rdev_model);
 #endif
 	/* Figure out position of label block */
 	if (private->rdc_data.vdev_class == DEV_CLASS_FBA) {
-		label_block = 1;
+		device->sizes.pt_block = 1;
 	} else if (private->rdc_data.vdev_class == DEV_CLASS_ECKD ||
 		   private->rdc_data.vdev_class == DEV_CLASS_CKD) {
-		label_block = 2;
+		device->sizes.pt_block = 2;
 	} else {
-                goto nodiag;
+                BUG();
 	}
 	private->label = (long *) get_free_page (GFP_KERNEL);
 	label = private->label;
@@ -304,86 +300,69 @@
 	for (bsize = 512; bsize <= PAGE_SIZE; bsize <<= 1) {
 		diag_bio_t *bio;
 		diag_rw_io_t *iob = &private->iob;
-                
+
 		rc = mdsk_init_io (device, bsize, 0, 64);
 		if (rc > 4) {
 			continue;
 		}
-		cqr = ccw_alloc_request (dasd_diag_discipline.name, sizeof(diag_bio_t)/sizeof(ccw1_t), 0);
+		cqr = dasd_alloc_request (dasd_diag_discipline.name,
+                                         sizeof (diag_bio_t) / sizeof (ccw1_t),
+                                         0, device);
 		if (cqr == NULL) {
 			printk (KERN_WARNING PRINTK_HEADER
-                                "No memory to allocate initialization request\n");
-                        free_page((long)private->label);
-                        kfree(private);
-                        device->private = NULL;
-                        return -ENOMEM;
+				"No memory to allocate initialization request\n");
+			free_page ((long) private->label);
+                        rc = -ENOMEM;
+                        goto fail;
 		}
 		bio = (diag_bio_t *) (cqr->cpaddr);
 		memset (bio, 0, sizeof (diag_bio_t));
 		bio->type = MDSK_READ_REQ;
-		bio->block_number = label_block + 1;
+		bio->block_number = device->sizes.pt_block + 1;
 		bio->buffer = __pa (private->label);
 		cqr->device = device;
-		cqr->status= CQR_STATUS_FILLED;
+		cqr->status = CQR_STATUS_FILLED;
 		memset (iob, 0, sizeof (diag_rw_io_t));
 		iob->dev_nr = rdc_data->dev_nr;
 		iob->block_count = 1;
-		iob->interrupt_params = (u32)cqr;
+		iob->interrupt_params = (u32) cqr;
 		iob->bio_list = __pa (bio);
 		rc = dia250 (iob, RW_BIO);
 		if (rc == 0) {
-			if (label[3] != bsize) {
-                                goto nodiag;
-			}
-			if (label[0] != 0xc3d4e2f1) {	/* != CMS1 */
-                                goto nodiag;
-			}
-			if (label[13] == 0) {
-                                goto nodiag;
+			if (label[3] != bsize ||
+                            label[0] != 0xc3d4e2f1 ||	/* != CMS1 */
+                            label[13] == 0 ){
+                                rc = -EMEDIUMTYPE;
+				goto fail;
 			}
 			break;
 		}
 		mdsk_term_io (device);
 	}
-        if ( bsize > PAGE_SIZE )
-                goto nodiag;
+        if (bsize > PAGE_SIZE) {
+                rc = -EMEDIUMTYPE;
+		goto fail;
+        }
+	device->sizes.blocks = label[7];
 	device->sizes.bp_block = bsize;
 	device->sizes.s2b_shift = 0;	/* bits to shift 512 to get a block */
 	for (sb = 512; sb < bsize; sb = sb << 1)
 		device->sizes.s2b_shift++;
-        goto good;
- nodiag:
-        kfree(private);
-        device -> private = NULL;
-        rc = -ENODEV;
- good:
-	return rc;
-}
-
-static int
-dasd_diag_do_analysis (struct dasd_device_t *device)
-{
-	dasd_diag_private_t *private = (dasd_diag_private_t *) device->private;
-
-	long *label = private->label;
-
-	/* real size of the volume */
-	device->sizes.blocks = label[7];
-        if (private->rdc_data.vdev_class == DEV_CLASS_FBA) {
-		device->sizes.pt_block = 1;
-	} else if (private->rdc_data.vdev_class == DEV_CLASS_ECKD ||
-		   private->rdc_data.vdev_class == DEV_CLASS_CKD) {
-		device->sizes.pt_block = 2;
-	} else {
-		return -EINVAL;
-        }
 	printk (KERN_INFO PRINTK_HEADER
 		"/dev/%s (%04X): capacity (%dkB blks): %ldkB\n",
 		device->name, device->devinfo.devno,
 		(device->sizes.bp_block >> 10),
 		(device->sizes.blocks << device->sizes.s2b_shift) >> 1);
-        free_page((long)private->label);
-	return 0;
+	free_page ((long) private->label);
+        rc = 0;
+	goto out;
+ fail:
+        if ( rc ) {
+                kfree (device->private);
+                device->private = NULL;
+        }
+ out:
+	return rc;
 }
 
 static int
@@ -418,23 +397,6 @@
 	return dasd_era_fatal;
 }
 
-static dasd_erp_action_fn_t
-dasd_diag_erp_action (ccw_req_t * cqr)
-{
-	return default_erp_action;
-}
-
-static dasd_erp_postaction_fn_t
-dasd_diag_erp_postaction (ccw_req_t * cqr)
-{
-	if (cqr->function == default_erp_action)
-		return default_erp_postaction;
-	printk (KERN_WARNING PRINTK_HEADER
-		"unknown ERP action %p\n",
-		cqr->function);
-	return NULL;
-}
-
 static ccw_req_t *
 dasd_diag_build_cp_from_req (dasd_device_t * device, struct request *req)
 {
@@ -459,14 +421,12 @@
 	}
 	bhct = 0;
 	for (bh = req->bh; bh; bh = bh->b_reqnext) {
-		if (bh->b_size > byt_per_blk)
-			for (size = 0; size < bh->b_size; size += byt_per_blk)
-				bhct++;
-		else
-			bhct++;
+		if (bh->b_size < byt_per_blk)
+                        BUG();
+                bhct += bh->b_size >> (device->sizes.s2b_shift+9);
 	}
 	/* Build the request */
-	rw_cp = dasd_alloc_request (dasd_diag_discipline.name, bhct << 1, 0);
+	rw_cp = dasd_alloc_request (dasd_diag_discipline.name, bhct << 1, 0, device);
 	if (!rw_cp) {
 		return NULL;
 	}
@@ -474,28 +434,36 @@
 
 	block = req->sector >> device->sizes.s2b_shift;
 	for (bh = req->bh; bh; bh = bh->b_reqnext) {
-		if (bh->b_size >= byt_per_blk) {
-			memset (bio, 0, sizeof (diag_bio_t));
-			for (size = 0; size < bh->b_size; size += byt_per_blk) {
-				bio->type = rw_cmd;
-				bio->block_number = block + 1;
-				bio->buffer = __pa (bh->b_data + size);
-				bio++;
-				block++;
-			}
-		} else {
-			PRINT_WARN ("Cannot fulfill request smaller than block\n");
-			ccw_free_request (rw_cp);
-			return NULL;
-		}
+                memset (bio, 0, sizeof (diag_bio_t));
+                for (size = 0; size < bh->b_size; size += byt_per_blk) {
+                        bio->type = rw_cmd;
+                        bio->block_number = block + 1;
+                        bio->buffer = __pa (bh->b_data + size);
+                        bio++;
+                        block++;
+                }
 	}
+	asm volatile ("STCK %0":"=m" (rw_cp->buildclk));
 	rw_cp->device = device;
-	rw_cp->expires = 50 * TOD_SEC;		/* 50 seconds */
+	rw_cp->expires = 50 * TOD_SEC;	/* 50 seconds */
 	rw_cp->req = req;
 	check_then_set (&rw_cp->status, CQR_STATUS_EMPTY, CQR_STATUS_FILLED);
 	return rw_cp;
 }
 
+static int
+dasd_diag_fill_info (dasd_device_t * device, dasd_information_t * info)
+{
+	int rc = 0;
+	info->FBA_layout = 1;
+	info->characteristics_size = sizeof (dasd_diag_characteristics_t);
+	memcpy (info->characteristics,
+		&((dasd_diag_private_t *) device->private)->rdc_data,
+		sizeof (dasd_diag_characteristics_t));
+	info->confdata_size = 0;
+	return rc;
+}
+
 static char *
 dasd_diag_dump_sense (struct dasd_device_t *device, ccw_req_t * req)
 {
@@ -511,21 +479,19 @@
 	return page;
 }
 
-dasd_discipline_t dasd_diag_discipline =
-{
+dasd_discipline_t dasd_diag_discipline = {
+        owner: THIS_MODULE,
 	name:"DIAG",
 	ebcname:"DIAG",
-	max_blocks:PAGE_SIZE/sizeof(diag_bio_t),
+	max_blocks:PAGE_SIZE / sizeof (diag_bio_t),
 	check_characteristics:dasd_diag_check_characteristics,
-	do_analysis:dasd_diag_do_analysis,
 	fill_geometry:dasd_diag_fill_geometry,
 	start_IO:dasd_start_diag,
 	examine_error:dasd_diag_examine_error,
-	erp_action:dasd_diag_erp_action,
-	erp_postaction:dasd_diag_erp_postaction,
 	build_cp_from_req:dasd_diag_build_cp_from_req,
 	dump_sense:dasd_diag_dump_sense,
-	int_handler:dasd_ext_handler
+	int_handler:dasd_ext_handler,
+	fill_info:dasd_diag_fill_info,
 };
 
 int
@@ -534,32 +500,55 @@
 	int rc = 0;
 	if (MACHINE_IS_VM) {
 		printk (KERN_INFO PRINTK_HEADER
-		   "%s discipline initializing\n", dasd_diag_discipline.name);
+			"%s discipline initializing\n",
+			dasd_diag_discipline.name);
 		ASCEBC (dasd_diag_discipline.ebcname, 4);
 		ctl_set_bit (0, 9);
 		register_external_interrupt (0x2603, dasd_ext_handler);
-		dasd_discipline_enq (&dasd_diag_discipline);
+		dasd_discipline_add (&dasd_diag_discipline);
 	} else {
 		printk (KERN_INFO PRINTK_HEADER
-			"Machine is not VM: %s discipline not initializing\n", dasd_diag_discipline.name);
+			"Machine is not VM: %s discipline not initializing\n",
+			dasd_diag_discipline.name);
 		rc = -EINVAL;
 	}
 	return rc;
 }
 
 void
-dasd_diag_cleanup( void ) {
-        if ( MACHINE_IS_VM ) {
-          printk ( KERN_INFO PRINTK_HEADER
-                   "%s discipline cleaning up\n", dasd_diag_discipline.name);
-          dasd_discipline_deq(&dasd_diag_discipline);
-          unregister_external_interrupt (0x2603, dasd_ext_handler);
-          ctl_clear_bit (0, 9);
-        } else {
-          printk ( KERN_INFO PRINTK_HEADER
-                   "Machine is not VM: %s discipline not initializing\n", dasd_diag_discipline.name);
-        }
+dasd_diag_cleanup (void)
+{
+	if (MACHINE_IS_VM) {
+		printk (KERN_INFO PRINTK_HEADER
+			"%s discipline cleaning up\n",
+			dasd_diag_discipline.name);
+		dasd_discipline_del (&dasd_diag_discipline);
+		unregister_external_interrupt (0x2603, dasd_ext_handler);
+		ctl_clear_bit (0, 9);
+	} else {
+		printk (KERN_INFO PRINTK_HEADER
+			"Machine is not VM: %s discipline not initializing\n",
+			dasd_diag_discipline.name);
+	}
 }
+
+#ifdef MODULE
+int
+init_module (void)
+{
+	int rc = 0;
+	rc = dasd_diag_init ();
+	return rc;
+}
+
+void
+cleanup_module (void)
+{
+	dasd_diag_cleanup ();
+	return;
+}
+#endif
+
 /*
  * Overrides for Emacs so that we follow Linus's tabbing style.
  * Emacs will notice this stuff at the end of the file and automatically
diff -u --recursive --new-file v2.4.7/linux/drivers/s390/block/dasd_diag.h linux/drivers/s390/block/dasd_diag.h
--- v2.4.7/linux/drivers/s390/block/dasd_diag.h	Tue Feb 13 14:13:44 2001
+++ linux/drivers/s390/block/dasd_diag.h	Sun Aug  5 13:12:41 2001
@@ -29,9 +29,9 @@
 	u8 rdev_type;
 	u8 rdev_model;
 	u8 rdev_features;
-} __attribute__             ((packed, aligned (4))) 
+} __attribute__ ((packed, aligned (4)))
 
-dasd_diag_characteristics_t;
+    dasd_diag_characteristics_t;
 
 typedef struct diag_bio_t {
 	u8 type;
@@ -40,9 +40,9 @@
 	u32 block_number;
 	u32 alet;
 	u32 buffer;
-} __attribute__ ((packed, aligned (8))) 
+} __attribute__ ((packed, aligned (8)))
 
-diag_bio_t;
+    diag_bio_t;
 
 typedef struct diag_init_io_t {
 	u16 dev_nr;
@@ -52,9 +52,9 @@
 	u32 start_block;
 	u32 end_block;
 	u32 spare2[6];
-} __attribute__ ((packed, aligned (8))) 
+} __attribute__ ((packed, aligned (8)))
 
-diag_init_io_t;
+    diag_init_io_t;
 
 typedef struct diag_rw_io_t {
 	u16 dev_nr;
@@ -67,9 +67,9 @@
 	u32 bio_list;
 	u32 interrupt_params;
 	u32 spare3[5];
-} __attribute__ ((packed, aligned (8))) 
+} __attribute__ ((packed, aligned (8)))
 
-diag_rw_io_t;
+    diag_rw_io_t;
 
 int dasd_diag_init (void);
-void dasd_diag_cleanup(void);
+void dasd_diag_cleanup (void);
diff -u --recursive --new-file v2.4.7/linux/drivers/s390/block/dasd_eckd.c linux/drivers/s390/block/dasd_eckd.c
--- v2.4.7/linux/drivers/s390/block/dasd_eckd.c	Wed Apr 11 19:02:28 2001
+++ linux/drivers/s390/block/dasd_eckd.c	Sun Aug  5 13:12:41 2001
@@ -1,6 +1,7 @@
 /* 
  * File...........: linux/drivers/s390/block/dasd_eckd.c
  * Author(s)......: Holger Smolinski <Holger.Smolinski@de.ibm.com>
+                    Carsten Otte <Cotte@de.ibm.com>
  * Bugreports.to..: <Linux390@de.ibm.com>
  * (C) IBM Corporation, IBM Deutschland Entwicklung GmbH, 1999,2000
 
@@ -22,27 +23,25 @@
 #include <linux/config.h>
 #include <linux/stddef.h>
 #include <linux/kernel.h>
-#include <asm/debug.h>
-
-#include <linux/malloc.h>
+#include <linux/slab.h>
 #include <linux/hdreg.h>	/* HDIO_GETGEO                      */
 #include <linux/blk.h>
+
+#include <asm/debug.h>
 #include <asm/ccwcache.h>
 #include <asm/idals.h>
-#include <asm/dasd.h>
-
 #include <asm/ebcdic.h>
 #include <asm/io.h>
 #include <asm/irq.h>
 #include <asm/s390dyn.h>
 
+#include "dasd_int.h"
 #include "dasd_eckd.h"
 
 #ifdef PRINTK_HEADER
 #undef PRINTK_HEADER
 #endif				/* PRINTK_HEADER */
-#define PRINTK_HEADER DASD_NAME"(eckd): "
-#undef DASD_CDL // Support compatible disk layout
+#define PRINTK_HEADER DASD_NAME"(eckd):"
 #undef CDL_PRINTK
 
 #define ECKD_C0(i) (i->home_bytes)
@@ -62,55 +61,39 @@
 dasd_eckd_private_t {
 	dasd_eckd_characteristics_t rdc_data;
 	dasd_eckd_confdata_t conf_data;
-#ifdef DASD_CDL
-        eckd_count_t count_area[5];
-#else
-	eckd_count_t count_area;
-#endif
-	ccw_req_t *init_cqr;
-#ifdef DASD_CDL
-        int uses_cdl; 
-#endif
+	eckd_count_t count_area[5];
+	int uses_cdl;
 } dasd_eckd_private_t;
 
 #ifdef CONFIG_DASD_DYNAMIC
 static
-devreg_t dasd_eckd_known_devices[] =
-{
-	{
-		ci:
-		{hc:
-		 {ctype:0x3990}},
-		flag: (DEVREG_MATCH_CU_TYPE |
-                       DEVREG_NO_DEV_INFO| 
-                       DEVREG_TYPE_DEVCHARS),
-		oper_func:dasd_oper_handler
-	},
+devreg_t dasd_eckd_known_devices[] = {
+        {
+                ci: { hc: {ctype:0x3880, dtype: 3390}},
+                flag:(DEVREG_MATCH_CU_TYPE | DEVREG_MATCH_DEV_TYPE | 
+                      DEVREG_TYPE_DEVCHARS),
+                oper_func:dasd_oper_handler
+        },
+        {
+                ci: { hc: {ctype:0x3990}},
+                flag:(DEVREG_MATCH_CU_TYPE | DEVREG_TYPE_DEVCHARS),
+                oper_func:dasd_oper_handler
+        },
 	{
-		ci:
-		{hc:
-		 {ctype:0x2105}},
-		flag:(DEVREG_MATCH_CU_TYPE |
-                       DEVREG_NO_DEV_INFO| 
-                       DEVREG_TYPE_DEVCHARS),
-		oper_func:dasd_oper_handler
-	},
+                ci: { hc: {ctype:0x2105}},
+                flag:(DEVREG_MATCH_CU_TYPE | DEVREG_TYPE_DEVCHARS),
+                oper_func:dasd_oper_handler
+        },
 	{
-		ci:
-		{hc:
-		 {ctype:0x9343}},
-		flag:(DEVREG_MATCH_CU_TYPE |
-                       DEVREG_NO_DEV_INFO| 
-                       DEVREG_TYPE_DEVCHARS),
-		oper_func:dasd_oper_handler
-	}
+                ci: { hc: {ctype:0x9343}},
+                flag:(DEVREG_MATCH_CU_TYPE | DEVREG_TYPE_DEVCHARS),
+                oper_func:dasd_oper_handler
+        }
 };
 #endif
 
-#ifdef DASD_CDL
-int sizes_trk0[]={28,148,84};
+int sizes_trk0[] = { 28, 148, 84 };
 #define LABEL_SIZE 140
-#endif
 
 static inline unsigned int
 round_up_multiple (unsigned int no, unsigned int mult)
@@ -126,8 +109,7 @@
 }
 
 static inline int
-bytes_per_record (dasd_eckd_characteristics_t * rdc,
-		  int kl,	/* key length */
+bytes_per_record (dasd_eckd_characteristics_t * rdc, int kl,	/* key length */
 		  int dl /* data length */ )
 {
 	int bpr = 0;
@@ -194,8 +176,7 @@
 				       9 + ceil_quot (kl + 6 * kn, 34) +
 				       9 + ceil_quot (dl + 6 * dn, 34));
 		} else
-			return 1729 / (10 +
-				       9 + ceil_quot (dl + 6 * dn, 34));
+			return 1729 / (10 + 9 + ceil_quot (dl + 6 * dn, 34));
 	case 0x9345:
 		dn = ceil_quot (dl + 6, 232) + 1;
 		if (kl) {
@@ -204,21 +185,17 @@
 				       7 + ceil_quot (kl + 6 * kn, 34) +
 				       ceil_quot (dl + 6 * dn, 34));
 		} else
-			return 1420 / (18 +
-				       7 + ceil_quot (dl + 6 * dn, 34));
+			return 1420 / (18 + 7 + ceil_quot (dl + 6 * dn, 34));
 	}
 	return rpt;
 }
 
-
-static inline void
+static inline int
 define_extent (ccw1_t * de_ccw,
 	       DE_eckd_data_t * data,
-	       int trk,
-	       int totrk,
-	       int cmd,
-	       dasd_device_t * device)
+	       int trk, int totrk, int cmd, dasd_device_t * device, ccw_req_t* cqr)
 {
+        int rc=0;
 	ch_t geo, beg, end;
 	dasd_eckd_private_t *private = (dasd_eckd_private_t *) device->private;
 
@@ -232,7 +209,8 @@
 	memset (de_ccw, 0, sizeof (ccw1_t));
 	de_ccw->cmd_code = DASD_ECKD_CCW_DEFINE_EXTENT;
 	de_ccw->count = 16;
-	set_normalized_cda (de_ccw, __pa (data));
+	if (rc=dasd_set_normalized_cda (de_ccw, __pa (data), cqr, device)) 
+                return rc;
 
 	memset (data, 0, sizeof (DE_eckd_data_t));
 	switch (cmd) {
@@ -259,6 +237,7 @@
 	case DASD_ECKD_CCW_WRITE_CKD_MT:
 		data->attributes.operation = 0x1;	/* format through cache */
 		break;
+	case DASD_ECKD_CCW_ERASE:
 	case DASD_ECKD_CCW_WRITE_HOME_ADDRESS:
 	case DASD_ECKD_CCW_WRITE_RECORD_ZERO:
 		data->mask.perm = 0x3;
@@ -270,46 +249,66 @@
 		break;
 	}
 	data->attributes.mode = 0x3;
-	if (private->rdc_data.cu_type == 0x2105 
-#ifdef DASD_CDL
-            && !(private->uses_cdl && trk < 2)
-#endif
-            ) {
+	if (private->rdc_data.cu_type == 0x2105
+	    && !(private->uses_cdl && trk < 2)
+	    ) {
 		data->reserved |= 0x40;
 	}
 	data->beg_ext.cyl = beg.cyl;
 	data->beg_ext.head = beg.head;
 	data->end_ext.cyl = end.cyl;
 	data->end_ext.head = end.head;
+        return rc;
 }
 
-static inline void
+static inline int
 locate_record (ccw1_t * lo_ccw,
 	       LO_eckd_data_t * data,
 	       int trk,
 	       int rec_on_trk,
-	       int no_rec,
-	       int cmd,
-	       dasd_device_t * device,
-	       int reclen)
+	       int no_rec, int cmd, dasd_device_t * device, int reclen, ccw_req_t* cqr)
 {
+        int rc=0;
 	dasd_eckd_private_t *private = (dasd_eckd_private_t *) device->private;
-	ch_t geo =
-	{private->rdc_data.no_cyl,
-	 private->rdc_data.trk_per_cyl};
-	ch_t seek =
-	{trk / (geo.head), trk % (geo.head)};
-	int sector;
+	ch_t geo = { private->rdc_data.no_cyl,
+		private->rdc_data.trk_per_cyl
+	};
+	ch_t seek = { trk / (geo.head), trk % (geo.head) };
+	int sector = 0;
 
 #ifdef CDL_PRINTK
-        printk ("Locate: trk %d, rec %d, no_rec %d, cmd %d, reclen %d\n",trk,rec_on_trk,no_rec,cmd,reclen);
+	printk ("Locate: trk %d, rec %d, no_rec %d, cmd %d, reclen %d\n", trk,
+		rec_on_trk, no_rec, cmd, reclen);
 #endif
 	memset (lo_ccw, 0, sizeof (ccw1_t));
 	lo_ccw->cmd_code = DASD_ECKD_CCW_LOCATE_RECORD;
 	lo_ccw->count = 16;
-	set_normalized_cda (lo_ccw, __pa (data));
+	if (rc=dasd_set_normalized_cda (lo_ccw, __pa (data), cqr, device))
+                return rc;
 
 	memset (data, 0, sizeof (LO_eckd_data_t));
+        if (rec_on_trk) {
+                switch (private->rdc_data.dev_type) {
+                case 0x3390:{
+                        int dn, d;
+                        dn = ceil_quot (reclen + 6, 232);
+                        d = 9 + ceil_quot (reclen + 6 * (dn + 1), 34);
+                        sector = (49 + (rec_on_trk - 1) * (10 + d)) / 8;
+                        break;
+                }
+                case 0x3380:{
+                        int d;
+                        d = 7 + ceil_quot (reclen + 12, 32);
+                        sector = (39 + (rec_on_trk - 1) * (8 + d)) / 7;
+                        break;
+                }
+                case 0x9345:
+                default:
+                        sector = 0;
+                }
+        }
+        data->sector = sector;
+	data->count = no_rec;
 	switch (cmd) {
 	case DASD_ECKD_CCW_WRITE_HOME_ADDRESS:
 		data->operation.orientation = 0x3;
@@ -360,32 +359,18 @@
 	case DASD_ECKD_CCW_READ_COUNT:
 		data->operation.operation = 0x06;
 		break;
+	case DASD_ECKD_CCW_ERASE:
+                data->length = reclen;
+                data->auxiliary.last_bytes_used = 0x1;
+		data->operation.operation = 0x0b;
+		break;
 	default:
 		INTERNAL_ERROR ("unknown opcode 0x%x\n", cmd);
 	}
-	switch (private->rdc_data.dev_type) {
-	case 0x3390:{
-			int dn, d;
-			dn = ceil_quot (reclen + 6, 232);
-			d = 9 + ceil_quot (reclen + 6 * (dn + 1), 34);
-			sector = (49 + (rec_on_trk - 1) * (10 + d)) / 8;
-			break;
-		}
-	case 0x3380:{
-			int d;
-			d = 7 + ceil_quot (reclen + 12, 32);
-			sector = (39 + (rec_on_trk - 1) * (8 + d)) / 7;
-			break;
-		}
-	case 0x9345:
-	default:
-		sector = 0;
-	}
-	data->sector = sector;
 	memcpy (&(data->seek_addr), &seek, sizeof (ch_t));
 	memcpy (&(data->search_arg), &seek, sizeof (ch_t));
 	data->search_arg.record = rec_on_trk;
-	data->count += no_rec;
+        return rc;
 }
 
 static int
@@ -393,12 +378,10 @@
 {
 	if (info->sid_data.cu_type == 0x3990 ||
 	    info->sid_data.cu_type == 0x2105)
-		if (info->sid_data.dev_type == 0x3390)
-			return 0;
+		    if (info->sid_data.dev_type == 0x3390) return 0;
 	if (info->sid_data.cu_type == 0x3990 ||
 	    info->sid_data.cu_type == 0x2105)
-		if (info->sid_data.dev_type == 0x3380)
-			return 0;
+		    if (info->sid_data.dev_type == 0x3380) return 0;
 	if (info->sid_data.cu_type == 0x9343)
 		if (info->sid_data.dev_type == 0x9345)
 			return 0;
@@ -408,7 +391,7 @@
 static int
 dasd_eckd_check_characteristics (struct dasd_device_t *device)
 {
-	int rc = -ENODEV;
+	int rc = 0;
 	void *conf_data;
 	void *rdc_data;
 	int conf_len;
@@ -416,82 +399,89 @@
 
 	if (device == NULL) {
 		printk (KERN_WARNING PRINTK_HEADER
-		   "Null device pointer passed to characteristics checker\n");
-		return -ENODEV;
+			"Null device pointer passed to characteristics checker\n");
+                return -ENODEV;
+	}
+	device->private = kmalloc (sizeof (dasd_eckd_private_t), GFP_KERNEL);
+	if (device->private == NULL) {
+		printk (KERN_WARNING PRINTK_HEADER
+			"memory allocation failed for private data\n");
+		rc = -ENOMEM;
+                goto fail;
 	}
-        if (device->private != NULL) {
-                kfree(device->private);
-        }
-        device->private = kmalloc (sizeof (dasd_eckd_private_t), GFP_KERNEL);
-        if (device->private == NULL) {
-                printk (KERN_WARNING PRINTK_HEADER
-                        "memory allocation failed for private data\n");
-                return -ENOMEM;
-        }
 	private = (dasd_eckd_private_t *) device->private;
 	rdc_data = (void *) &(private->rdc_data);
 	rc = read_dev_chars (device->devinfo.irq, &rdc_data, 64);
 	if (rc) {
 		printk (KERN_WARNING PRINTK_HEADER
 			"Read device characteristics returned error %d\n", rc);
-		return rc;
-	}
+                goto fail;
+        }
 	printk (KERN_INFO PRINTK_HEADER
-	    "%04X on sch %d: %04X/%02X(CU:%04X/%02X) Cyl:%d Head:%d Sec:%d\n",
+		"%04X on sch %d: %04X/%02X(CU:%04X/%02X) "
+                "Cyl:%d Head:%d Sec:%d\n",
 		device->devinfo.devno, device->devinfo.irq,
 		private->rdc_data.dev_type, private->rdc_data.dev_model,
 		private->rdc_data.cu_type, private->rdc_data.cu_model.model,
 		private->rdc_data.no_cyl, private->rdc_data.trk_per_cyl,
 		private->rdc_data.sec_per_trk);
-	rc = 0 ? 0 : read_conf_data (device->devinfo.irq, &conf_data, &conf_len, LPM_ANYPATH);
+	rc = read_conf_data (device->devinfo.irq, &conf_data, &conf_len,
+                             LPM_ANYPATH);
+
+        if (rc == -EOPNOTSUPP) {
+                rc = 0; /* this one is ok */
+        }
 	if (rc) {
-		if (rc == -EOPNOTSUPP)
-			return 0;
 		printk (KERN_WARNING PRINTK_HEADER
 			"Read configuration data returned error %d\n", rc);
-		return rc;
-	}
-	if (conf_len != sizeof (dasd_eckd_confdata_t)) {
-		printk (KERN_WARNING PRINTK_HEADER
-			"sizes of configuration data mismatch %d (read) vs %ld (expected)\n",
-			conf_len, sizeof (dasd_eckd_confdata_t));
-		return rc;
+                goto fail;
 	}
-	if (conf_data == NULL) {
+        if (conf_data == NULL) {
 		printk (KERN_WARNING PRINTK_HEADER
 			"No configuration data retrieved\n");
-		return -ENOMEM;
-	}
-	memcpy (&private->conf_data, conf_data, sizeof (dasd_eckd_confdata_t));
-	printk (KERN_INFO PRINTK_HEADER
-                "%04X on sch %d: %04X/%02X(CU:%04X/%02X): Configuration data read\n",
-		device->devinfo.devno, device->devinfo.irq,
-		private->rdc_data.dev_type, private->rdc_data.dev_model,
-		private->rdc_data.cu_type, private->rdc_data.cu_model.model);
-	device->sizes.bp_block = 4096;
-	device->sizes.s2b_shift = 3;
-	device->sizes.blocks = (private->rdc_data.no_cyl *
-				private->rdc_data.trk_per_cyl *
-				recs_per_track (&private->rdc_data,
-						0, device->sizes.bp_block));
-	return 0;
+                goto out; /* no errror */
+	} 
+        if (conf_len != sizeof (dasd_eckd_confdata_t)) {
+		printk (KERN_WARNING PRINTK_HEADER
+			"sizes of configuration data mismatch"
+                        "%d (read) vs %ld (expected)\n",
+			conf_len, sizeof (dasd_eckd_confdata_t));
+                goto out; /* no errror */
+	} 
+        memcpy (&private->conf_data, conf_data, 
+                sizeof (dasd_eckd_confdata_t));
+        printk (KERN_INFO PRINTK_HEADER
+                "%04X on sch %d: %04X/%02X(CU:%04X/%02X): "
+                "Configuration data read\n",
+                device->devinfo.devno, device->devinfo.irq,
+                private->rdc_data.dev_type, 
+                private->rdc_data.dev_model,
+                private->rdc_data.cu_type, 
+                private->rdc_data.cu_model.model);
+        goto out;
+ fail:
+        if ( rc ) {
+                kfree (device->private);
+                device->private = NULL;
+        }
+ out:
+	return rc;
 }
 
-#ifdef DASD_CDL
 static inline int
-dasd_eckd_cdl_reclen (dasd_device_t* device,int recid) {
-        dasd_eckd_private_t *private = (dasd_eckd_private_t *) device->private;
-        int byt_per_blk = device->sizes.bp_block;
-        int blk_per_trk = recs_per_track (&(private->rdc_data), 0, byt_per_blk);
-        if (recid < 3) 
-                return sizes_trk0[recid];
-        if (recid < blk_per_trk)
-                return byt_per_blk;
-        if (recid < 2*blk_per_trk )
-                return LABEL_SIZE;
-        return byt_per_blk;
+dasd_eckd_cdl_reclen (dasd_device_t * device, int recid)
+{
+	dasd_eckd_private_t *private = (dasd_eckd_private_t *) device->private;
+	int byt_per_blk = device->sizes.bp_block;
+	int blk_per_trk = recs_per_track (&(private->rdc_data), 0, byt_per_blk);
+	if (recid < 3)
+		return sizes_trk0[recid];
+	if (recid < blk_per_trk)
+		return byt_per_blk;
+	if (recid < 2 * blk_per_trk)
+		return LABEL_SIZE;
+	return byt_per_blk;
 }
-#endif
 
 static ccw_req_t *
 dasd_eckd_init_analysis (struct dasd_device_t *device)
@@ -500,76 +490,82 @@
 	ccw1_t *ccw;
 	DE_eckd_data_t *DE_data;
 	LO_eckd_data_t *LO_data;
-	dasd_eckd_private_t *private = (dasd_eckd_private_t *) device->private;
-#ifdef DASD_CDL
-        eckd_count_t *count_data = private->count_area;
-#else
-	eckd_count_t *count_data = &(private->count_area);
-#endif
-#ifdef DASD_CDL
-        cqr = ccw_alloc_request (dasd_eckd_discipline.name, 8 + 1, 
-                                 sizeof (DE_eckd_data_t) + 
-                                 2*sizeof (LO_eckd_data_t));
-#else
-	cqr = ccw_alloc_request (dasd_eckd_discipline.name, 3 + 1, 
-                                 sizeof (DE_eckd_data_t) + 
-                                 sizeof (LO_eckd_data_t));
-#endif
+	dasd_eckd_private_t *private = (dasd_eckd_private_t *)device->private;
+	eckd_count_t *count_data = private->count_area;
+
+	cqr = dasd_alloc_request (dasd_eckd_discipline.name, 8 + 1,
+				 sizeof (DE_eckd_data_t) +
+				 2 * sizeof (LO_eckd_data_t),
+                                 device);
 	if (cqr == NULL) {
-		printk (KERN_WARNING PRINTK_HEADER
-			"No memory to allocate initialization request\n");
-		return NULL;
-	} else {
-		private->init_cqr = cqr;
+                printk (KERN_WARNING PRINTK_HEADER
+                        "No memory to allocate initialization request\n");
+                goto out;
 	}
 	DE_data = cqr->data;
 	LO_data = cqr->data + sizeof (DE_eckd_data_t);
 	ccw = cqr->cpaddr;
-#ifdef DASD_CDL
-        define_extent (ccw, DE_data, 0, 2, DASD_ECKD_CCW_READ_COUNT, device);
-#else
-	define_extent (ccw, DE_data, 0, 0, DASD_ECKD_CCW_READ_COUNT, device);
-#endif
+	if (define_extent (ccw, DE_data, 0, 2, DASD_ECKD_CCW_READ_COUNT, device, cqr)) {
+                goto clear_cqr;
+        }        
 	ccw->flags |= CCW_FLAG_CC;
 	ccw++;
-#ifdef DASD_CDL
-        locate_record (ccw, LO_data++, 0, 0, 4, DASD_ECKD_CCW_READ_COUNT, device, 0);
-#else
-	locate_record (ccw, LO_data, 0, 0, 1, DASD_ECKD_CCW_READ_COUNT, device, 0);
-#endif
-#ifdef DASD_CDL
+	if (locate_record (ccw, LO_data++, 0, 0, 4, DASD_ECKD_CCW_READ_COUNT,
+                           device, 0, cqr)) {
+                goto clear_cqr;
+        }       
 	ccw->flags |= CCW_FLAG_CC;
 	ccw++;
 	ccw->cmd_code = DASD_ECKD_CCW_READ_COUNT;
 	ccw->count = 8;
-        set_normalized_cda (ccw, __pa (count_data++));
-        ccw->flags |= CCW_FLAG_CC;
-        ccw++;
-        ccw->cmd_code = DASD_ECKD_CCW_READ_COUNT;
-        ccw->count = 8;
-        set_normalized_cda (ccw, __pa (count_data++));
-        ccw->flags |= CCW_FLAG_CC;
-        ccw++;
-        ccw->cmd_code = DASD_ECKD_CCW_READ_COUNT;
-        ccw->count = 8;
-        set_normalized_cda (ccw, __pa (count_data++));
-        ccw->flags |= CCW_FLAG_CC;
-        ccw++;
-        ccw->cmd_code = DASD_ECKD_CCW_READ_COUNT;
-        ccw->count = 8;
-        set_normalized_cda (ccw, __pa (count_data++));
-        ccw->flags |= CCW_FLAG_CC;
-        ccw++;
-        locate_record (ccw, LO_data++, 2, 0, 1, DASD_ECKD_CCW_READ_COUNT, device, 0);
-#endif
-        ccw->flags |= CCW_FLAG_CC;
-        ccw++;
-        ccw->cmd_code = DASD_ECKD_CCW_READ_COUNT;
-        ccw->count = 8;
-        set_normalized_cda (ccw, __pa (count_data));
+	if (dasd_set_normalized_cda (ccw, __pa (count_data++), cqr, device)) {
+                goto clear_cqr;
+        }
+	ccw->flags |= CCW_FLAG_CC;
+	ccw++;
+	ccw->cmd_code = DASD_ECKD_CCW_READ_COUNT;
+	ccw->count = 8;
+	if (dasd_set_normalized_cda (ccw, __pa (count_data++), cqr, device)) {
+                goto clear_cqr;
+        }
+	ccw->flags |= CCW_FLAG_CC;
+	ccw++;
+	ccw->cmd_code = DASD_ECKD_CCW_READ_COUNT;
+	ccw->count = 8;
+	if (dasd_set_normalized_cda (ccw, __pa (count_data++), cqr, device)) {
+                goto clear_cqr;
+        }
+	ccw->flags |= CCW_FLAG_CC;
+	ccw++;
+	ccw->cmd_code = DASD_ECKD_CCW_READ_COUNT;
+	ccw->count = 8;
+	if (dasd_set_normalized_cda (ccw, __pa (count_data++), cqr, device)) {
+                goto clear_cqr;
+        }
+	ccw->flags |= CCW_FLAG_CC;
+	ccw++;
+	if (locate_record (ccw, LO_data++, 2, 0, 1, DASD_ECKD_CCW_READ_COUNT,
+                           device, 0, cqr)) {
+                goto clear_cqr;
+        }       
+	ccw->flags |= CCW_FLAG_CC;
+	ccw++;
+	ccw->cmd_code = DASD_ECKD_CCW_READ_COUNT;
+	ccw->count = 8;
+	if (dasd_set_normalized_cda (ccw, __pa (count_data), cqr, device)) {
+                goto clear_cqr;
+        }
 	cqr->device = device;
 	cqr->retries = 0;
 	cqr->status = CQR_STATUS_FILLED;
+        dasd_chanq_enq (&device->queue, cqr);
+        goto out;
+ clear_cqr:
+        dasd_free_request (cqr,device);
+        printk (KERN_WARNING PRINTK_HEADER
+                "No memory to allocate initialization request\n");
+        cqr=NULL;
+ out:
 	return cqr;
 }
 
@@ -578,105 +574,91 @@
 {
 	int sb, rpt;
 	dasd_eckd_private_t *private = (dasd_eckd_private_t *) device->private;
-        eckd_count_t *count_area = NULL;
-        char *cdl_msg;
-#ifdef DASD_CDL /* BAD HACK SO FIX ME UP */
-        int i;
-        private -> uses_cdl = 1;
-
-        /* Free the cqr and cleanup device->sizes */
-        dasd_chanq_deq (&device->queue, private->init_cqr);
-        ccw_free_request (private->init_cqr);
-        private->init_cqr = NULL;
-        memset (&(device->sizes), 0, sizeof (dasd_sizes_t));
-        /* Check Track 0 for Compatible Disk Layout */
-        for (i = 0; i < 3; i++) { 
-                if ((i < 3) &&
-                    ((private->count_area[i].kl != 4) ||
-                     (private->count_area[i].dl != 
-                      dasd_eckd_cdl_reclen (device,i) - 4))) {
-                        private -> uses_cdl = 0;
-                        break;
-                } 
-        }
-        if ( i == 3 ) {
-                count_area = &private->count_area[4];
-        }
-        if (private->uses_cdl == 0) { 
-                for (i = 0; i < 5; i++) {
-                        if ((private->count_area[i].kl != 0) ||
-                            (private->count_area[i].dl != 
-                             private->count_area[0].dl)) {
-                                break;
-                        }
-                }
-                if ( i == 5 ) {
-                        count_area = &private->count_area[0];
-                }
-        } else {
-                if (private->count_area[3].record == 1) {
-                        DASD_MESSAGE(KERN_WARNING,device,"%s",
-                                     "Trk 0: no records after VTOC!");
-                }
+	eckd_count_t *count_area = NULL;
+	char *cdl_msg;
+        int status;
+	int i;
+	private->uses_cdl = 1;
+        status = device->init_cqr->status;
+	dasd_chanq_deq (&device->queue, device->init_cqr);
+	dasd_free_request (device->init_cqr, device);
+	/* Free the cqr and cleanup device->sizes */
+        if ( status != CQR_STATUS_DONE ) {
+                DASD_MESSAGE (KERN_WARNING,device,"%s",
+                              "volume analysis returned fatal error");
+                return -EMEDIUMTYPE;
         }
-        if (count_area != NULL && /* we found notthing violating our disk layout */
-            count_area ->kl == 0) { 
+	/* Check Track 0 for Compatible Disk Layout */
+	for (i = 0; i < 3; i++) {
+		if ((i < 3) &&
+		    ((private->count_area[i].kl != 4) ||
+		     (private->count_area[i].dl !=
+		      dasd_eckd_cdl_reclen (device, i) - 4))) {
+			private->uses_cdl = 0;
+			break;
+		}
+	}
+	if (i == 3) {
+		count_area = &private->count_area[4];
+	}
+	if (private->uses_cdl == 0) {
+		for (i = 0; i < 5; i++) {
+			if ((private->count_area[i].kl != 0) ||
+			    (private->count_area[i].dl !=
+			     private->count_area[0].dl)) {
+				break;
+			}
+		}
+		if (i == 5) {
+			count_area = &private->count_area[0];
+		}
+	} else {
+		if (private->count_area[3].record == 1) {
+			DASD_MESSAGE (KERN_WARNING, device, "%s",
+				      "Trk 0: no records after VTOC!");
+		}
+	}
+	if (count_area != NULL &&	/* we found notthing violating our disk layout */
+	    count_area->kl == 0) {
                 /* find out blocksize */
                 switch (count_area->dl) {
                 case 512:
-                case 1024:
-                case 2048:
-                case 4096:
-                        device->sizes.bp_block = count_area->dl;
-                        break;
-                }
-        }
-#else
-	dasd_chanq_deq (&device->queue, private->init_cqr);
-	ccw_free_request (private->init_cqr);
-	private->init_cqr = NULL;
-	memset (&(device->sizes), 0, sizeof (dasd_sizes_t));
-	switch (private->count_area.dl) {
-	case 512:
-	case 1024:
-	case 2048:
-	case 4096:
-		device->sizes.bp_block = private->count_area.dl;
-		break;
+		case 1024:
+		case 2048:
+		case 4096:
+			device->sizes.bp_block = count_area->dl;
+			break;
+		}
+	}
+	if (device->sizes.bp_block == 0) {
+		DASD_MESSAGE (KERN_WARNING, device, "%s\n",
+			      "Volume has incompatible disk layout");
+		return -EMEDIUMTYPE;
 	}
-#endif
-        if ( device->sizes.bp_block == 0 ) {
-                DASD_MESSAGE(KERN_WARNING, device,"%s\n",
-                             "Volume has incompatible disk layout");
-                return -EMEDIUMTYPE;
-        }
 	device->sizes.s2b_shift = 0;	/* bits to shift 512 to get a block */
-        device->sizes.pt_block = 2;
+	device->sizes.pt_block = 2;
 	for (sb = 512; sb < device->sizes.bp_block; sb = sb << 1)
 		device->sizes.s2b_shift++;
 
 	rpt = recs_per_track (&private->rdc_data, 0, device->sizes.bp_block);
-	device->sizes.blocks = (private->rdc_data.no_cyl * 
-                                private->rdc_data.trk_per_cyl *
-                                recs_per_track (&private->rdc_data, 0, 
-                                                device->sizes.bp_block));
-#ifdef DASD_CDL
-        cdl_msg = private->uses_cdl?"compatible disk layout":"classic disk layout";
-#else
-        cdl_msg = "classic disk layout";
-#endif           
-                  
-        DASD_MESSAGE(KERN_INFO,device,"(%dkB blks): %dkB at %dkB/trk %s",
-                     (device->sizes.bp_block >> 10),
-                     (private->rdc_data.no_cyl * 
-                      private->rdc_data.trk_per_cyl *
-                      recs_per_track (&private->rdc_data, 0, 
-                                      device->sizes.bp_block) *
-                      (device->sizes.bp_block >> 9)) >> 1,
-                     (recs_per_track (&private->rdc_data, 0, 
-                                      device->sizes.bp_block) * 
-                      device->sizes.bp_block) >> 10,
-                     cdl_msg);
+	device->sizes.blocks = (private->rdc_data.no_cyl *
+				private->rdc_data.trk_per_cyl *
+				recs_per_track (&private->rdc_data, 0,
+						device->sizes.bp_block));
+	cdl_msg =
+	    private->
+	    uses_cdl ? "compatible disk layout" : "classic disk layout";
+
+	DASD_MESSAGE (KERN_INFO, device, "(%dkB blks): %dkB at %dkB/trk %s",
+		      (device->sizes.bp_block >> 10),
+		      (private->rdc_data.no_cyl *
+		       private->rdc_data.trk_per_cyl *
+		       recs_per_track (&private->rdc_data, 0,
+				       device->sizes.bp_block) *
+		       (device->sizes.bp_block >> 9)) >> 1,
+		      (recs_per_track (&private->rdc_data, 0,
+				       device->sizes.bp_block) *
+		       device->sizes.bp_block) >> 10, cdl_msg);
 	return 0;
 }
 
@@ -690,13 +672,14 @@
 	case 1024:
 	case 2048:
 	case 4096:
-		break;
+            geo->sectors = recs_per_track (&(private->rdc_data), 
+                                           0, device->sizes.bp_block);
+            break;
 	default:
-		return -EINVAL;
+            break;
 	}
 	geo->cylinders = private->rdc_data.no_cyl;
 	geo->heads = private->rdc_data.trk_per_cyl;
-	geo->sectors = recs_per_track (&(private->rdc_data), 0, device->sizes.bp_block);
 	return rc;
 }
 
@@ -713,95 +696,89 @@
 	ccw1_t *last_ccw = NULL;
 	void *last_data = NULL;
 	dasd_eckd_private_t *private = (dasd_eckd_private_t *) device->private;
-	int trk = fdata->start_unit;
-	int bs = fdata->blksize == DASD_FORMAT_DEFAULT_BLOCKSIZE ? 4096 : fdata->blksize;
-	int flags = fdata->intensity == DASD_FORMAT_DEFAULT_INTENSITY ? 0 : fdata->intensity;
-
-	int rpt = recs_per_track (&(private->rdc_data), 0, bs);
-	int cyl = trk / private->rdc_data.trk_per_cyl;
-	int head = trk % private->rdc_data.trk_per_cyl;
+
+	int rpt = recs_per_track (&(private->rdc_data), 0, fdata->blksize);
+	int cyl = fdata->start_unit / private->rdc_data.trk_per_cyl;
+	int head = fdata->start_unit % private->rdc_data.trk_per_cyl;
 	int wrccws = rpt;
 	int datasize = sizeof (DE_eckd_data_t) + sizeof (LO_eckd_data_t);
-#ifdef DASD_CDL
-        int formatCDL=0;
-#endif
-
-	if (((fdata->stop_unit == DASD_FORMAT_DEFAULT_STOP_UNIT) &&
-	 trk >= (private->rdc_data.no_cyl * private->rdc_data.trk_per_cyl)) ||
-	    ((fdata->stop_unit != DASD_FORMAT_DEFAULT_STOP_UNIT) &&
-	     trk > fdata->stop_unit)) {
-		DASD_MESSAGE(KERN_INFO, device,"Track %d reached! ending.", trk);
+        
+	if (fdata->start_unit >= (private->rdc_data.no_cyl * private->rdc_data.trk_per_cyl)){
+                DASD_MESSAGE (KERN_INFO, device, "Track no %d too big!", fdata->start_unit);
+                return NULL;
+        }
+        if ( fdata->start_unit > fdata->stop_unit) {
+                DASD_MESSAGE (KERN_INFO, device, "Track %d reached! ending.",
+                              fdata->start_unit);
 		return NULL;
 	}
-	switch (bs) {
+	switch (fdata->blksize) {
 	case 512:
 	case 1024:
 	case 2048:
 	case 4096:
 		break;
 	default:
-		printk (KERN_WARNING PRINTK_HEADER "Invalid blocksize %d...terminating!\n", bs);
+		printk (KERN_WARNING PRINTK_HEADER
+			"Invalid blocksize %d...terminating!\n", fdata->blksize);
 		return NULL;
 	}
-	switch (flags) {
+	switch (fdata->intensity) {
 	case 0x00:
 	case 0x01:
 	case 0x03:
 	case 0x04:		/* make track invalid */
-                break;
-#ifdef DASD_CDL /* Format compatible disk Layout */
-        case 0x08:
-        case 0x09:
-        case 0x0b:
-        case 0x0c:
-                formatCDL=1;
+	case 0x08:
+	case 0x09:
+	case 0x0b:
+	case 0x0c:
 		break;
-#endif
 	default:
-		printk (KERN_WARNING PRINTK_HEADER "Invalid flags 0x%x...terminating!\n", flags);
+		printk (KERN_WARNING PRINTK_HEADER
+			"Invalid flags 0x%x...terminating!\n", fdata->intensity);
 		return NULL;
 	}
 
 	/* print status line */
 	if ((private->rdc_data.no_cyl < 20) ?
-	    (trk % private->rdc_data.no_cyl == 0) :
-	    (trk % private->rdc_data.no_cyl == 0 &&
-	     (trk / private->rdc_data.no_cyl) %
+	    (fdata->start_unit % private->rdc_data.no_cyl == 0) :
+	    (fdata->start_unit % private->rdc_data.no_cyl == 0 &&
+	     (fdata->start_unit / private->rdc_data.no_cyl) %
 	     (private->rdc_data.no_cyl / 20))) {
-		DASD_MESSAGE(KERN_INFO, device, "Format Cylinder: %d Flags: %d\n",
-			trk / private->rdc_data.trk_per_cyl,
-			flags);
+		DASD_MESSAGE (KERN_INFO, device,
+			      "Format Cylinder: %d Flags: %d\n",
+			      fdata->start_unit / private->rdc_data.trk_per_cyl, fdata->intensity);
 	}
-	if (flags & 0x04) {
-                rpt = 1;
+	if ((fdata->intensity & ~0x8) & 0x04) {
 		wrccws = 1;
-                bs = 8;
+		rpt = 1;
 	} else {
-		if (flags & 0x1) {
+		if (fdata->intensity & 0x1) {
 			wrccws++;
 			datasize += sizeof (eckd_count_t);
 		}
-		if (flags & 0x2) {
+		if (fdata->intensity & 0x2) {
 			wrccws++;
 			datasize += sizeof (eckd_home_t);
 		}
 	}
-	fcp = ccw_alloc_request (dasd_eckd_discipline.name,
+	fcp = dasd_alloc_request (dasd_eckd_discipline.name,
 				 wrccws + 2 + 1,
-				 datasize + rpt * sizeof (eckd_count_t));
+				 datasize + rpt * sizeof (eckd_count_t),
+                                 device );
 	if (fcp != NULL) {
 		fcp->device = device;
-                fcp->retries = 2;       /* set retry counter to enable ERP */
+		fcp->retries = 2;	/* set retry counter to enable ERP */
 		last_data = fcp->data;
 		DE_data = (DE_eckd_data_t *) last_data;
 		last_data = (void *) (DE_data + 1);
 		LO_data = (LO_eckd_data_t *) last_data;
 		last_data = (void *) (LO_data + 1);
-		if (flags & 0x2) {
+		if (fdata->intensity & 0x2) {
 			ha_data = (eckd_home_t *) last_data;
 			last_data = (void *) (ha_data + 1);
 		}
-		if (flags & 0x1) {
+		if (fdata->intensity & 0x1) {
 			r0_data = (eckd_count_t *) last_data;
 			last_data = (void *) (r0_data + 1);
 		}
@@ -809,63 +786,65 @@
 
 		last_ccw = fcp->cpaddr;
 
-		switch (flags) {
+		switch (fdata->intensity & ~0x08) {
 		case 0x03:
-                case 0x0b:
-			define_extent (last_ccw, DE_data, trk, trk,
-				    DASD_ECKD_CCW_WRITE_HOME_ADDRESS, device);
+			if (define_extent (last_ccw, DE_data, fdata->start_unit, fdata->start_unit,
+				       DASD_ECKD_CCW_WRITE_HOME_ADDRESS,
+                                           device, fcp)) {
+                                goto clear_fcp;
+                        }
 			last_ccw->flags |= CCW_FLAG_CC;
 			last_ccw++;
-			locate_record (last_ccw, LO_data, trk, 0, wrccws,
-				       DASD_ECKD_CCW_WRITE_HOME_ADDRESS, device, device->sizes.bp_block);
+			if (locate_record (last_ccw, LO_data, fdata->start_unit, 0, wrccws,
+				       DASD_ECKD_CCW_WRITE_HOME_ADDRESS, device,
+                                           device->sizes.bp_block, fcp)) {
+                                goto clear_fcp;
+                        }
 			last_ccw->flags |= CCW_FLAG_CC;
 			last_ccw++;
 			break;
 		case 0x01:
-                case 0x09:
-			define_extent (last_ccw, DE_data, trk, trk,
-				     DASD_ECKD_CCW_WRITE_RECORD_ZERO, device);
+			if (define_extent (last_ccw, DE_data, fdata->start_unit, fdata->start_unit,
+                                           DASD_ECKD_CCW_WRITE_RECORD_ZERO, device, fcp)) {
+                                goto clear_fcp;
+                        }
 			last_ccw->flags |= CCW_FLAG_CC;
 			last_ccw++;
-			locate_record (last_ccw, LO_data, trk, 0, wrccws,
-				       DASD_ECKD_CCW_WRITE_RECORD_ZERO, device, device->sizes.bp_block);
+			if (locate_record (last_ccw, LO_data, fdata->start_unit, 0, wrccws,
+				       DASD_ECKD_CCW_WRITE_RECORD_ZERO, device,
+                                           device->sizes.bp_block, fcp)) {
+                                goto clear_fcp;
+                        }
 			last_ccw->flags |= CCW_FLAG_CC;
 			last_ccw++;
 			memset (r0_data, 0, sizeof (eckd_count_t));
 			break;
-		case 0x00:
-                case 0x08:
-			define_extent (last_ccw, DE_data, trk, trk,
-				       DASD_ECKD_CCW_WRITE_CKD, device);
-			last_ccw->flags |= CCW_FLAG_CC;
-			last_ccw++;
-			locate_record (last_ccw, LO_data, trk, 0, wrccws,
-				       DASD_ECKD_CCW_WRITE_CKD, device, device->sizes.bp_block);
-			LO_data->length = bs;
-			last_ccw->flags |= CCW_FLAG_CC;
-			last_ccw++;
-			break;
 		case 0x04:
-                case 0x0c:
-			define_extent (last_ccw, DE_data, trk, trk,
-				       DASD_ECKD_CCW_WRITE_CKD, device);
+                        fdata->blksize = 8;
+		case 0x00:
+			if (define_extent (last_ccw, DE_data, fdata->start_unit, fdata->start_unit,
+                                           DASD_ECKD_CCW_WRITE_CKD, device, fcp)) {
+                                dasd_free_request (fcp, device);
+                                return NULL;
+                        }
 			last_ccw->flags |= CCW_FLAG_CC;
 			last_ccw++;
-			locate_record (last_ccw, LO_data, trk, 0, wrccws,
-				       DASD_ECKD_CCW_WRITE_CKD, device, 0);
-			LO_data->length = bs;
+			if (locate_record (last_ccw, LO_data, fdata->start_unit, 0, wrccws,
+                                           DASD_ECKD_CCW_WRITE_CKD, device, fdata->blksize, fcp)) {
+                                goto clear_fcp;
+                        }
 			last_ccw->flags |= CCW_FLAG_CC;
 			last_ccw++;
 			break;
 		default:
-			PRINT_WARN ("Unknown format flags...%d\n", flags);
+			PRINT_WARN ("Unknown format flags...%d\n", fdata->intensity);
 			return NULL;
 		}
-		if (flags & 0x02) {
-			PRINT_WARN ("Unsupported format flag...%d\n", flags);
+		if (fdata->intensity & 0x02) {
+			PRINT_WARN ("Unsupported format flag...%d\n", fdata->intensity);
 			return NULL;
 		}
-		if (flags & 0x01) {	/* write record zero */
+		if (fdata->intensity & 0x01) {	/* write record zero */
 			r0_data->cyl = cyl;
 			r0_data->head = head;
 			r0_data->record = 0;
@@ -874,49 +853,73 @@
 			last_ccw->cmd_code = DASD_ECKD_CCW_WRITE_RECORD_ZERO;
 			last_ccw->count = 8;
 			last_ccw->flags |= CCW_FLAG_CC | CCW_FLAG_SLI;
-			set_normalized_cda (last_ccw, __pa (r0_data));
+			if (dasd_set_normalized_cda (last_ccw, __pa (r0_data), fcp, device)) {
+                                goto clear_fcp;
+                        }
 			last_ccw++;
 		}
-		/* write remaining records */
-		for (i = 0; i < rpt; i++) {
-			memset (ct_data + i, 0, sizeof (eckd_count_t));
-			(ct_data + i)->cyl = cyl;
-			(ct_data + i)->head = head;
-			(ct_data + i)->record = i + 1;
-			(ct_data + i)->kl = 0;
-#ifdef DASD_CDL
-                        if (formatCDL) { 
-                            // special handling when formatting CDL
-                            switch (trk) {
-                            case 0:
-                                if (i<3) {
-                                    (ct_data + i)->kl = 4;
-                                    (ct_data + i)->dl = sizes_trk0[i]-4;
-                                } else 
-                                    (ct_data + i)->dl = bs;
-                                break;
-                            case 1:
-                                (ct_data + i)->kl = 44;
-                                (ct_data + i)->dl = LABEL_SIZE-44;
-                                break;
-                            default:
-                                (ct_data + i)->dl = bs;
-                                break;
-                            }
-                        }
-                        else
-#endif                            
-                        (ct_data + i)->dl = bs;
+		if ((fdata->intensity & ~0x08) & 0x04) {	/* erase track */
+			memset (ct_data, 0, sizeof (eckd_count_t));
+			ct_data->cyl = cyl;
+			ct_data->head = head;
+			ct_data->record = 1;
+			ct_data->kl = 0;
+			ct_data->dl = 0;
 			last_ccw->cmd_code = DASD_ECKD_CCW_WRITE_CKD;
-			last_ccw->flags |= CCW_FLAG_CC | CCW_FLAG_SLI;
 			last_ccw->count = 8;
-			set_normalized_cda (last_ccw, __pa (ct_data + i));
+			last_ccw->flags |= CCW_FLAG_CC | CCW_FLAG_SLI;
+			if (dasd_set_normalized_cda (last_ccw, __pa (ct_data), fcp, device)) {
+                                goto clear_fcp;
+                        }
 			last_ccw++;
+		} else {	/* write remaining records */
+			for (i = 0; i < rpt; i++) {
+				memset (ct_data + i, 0, sizeof (eckd_count_t));
+				(ct_data + i)->cyl = cyl;
+				(ct_data + i)->head = head;
+				(ct_data + i)->record = i + 1;
+				(ct_data + i)->kl = 0;
+				if (fdata->intensity & 0x08) {
+					// special handling when formatting CDL
+					switch (fdata->start_unit) {
+					case 0:
+						if (i < 3) {
+							(ct_data + i)->kl = 4;
+							
+							    (ct_data + i)->dl =
+							    sizes_trk0[i] - 4;
+						} else
+							(ct_data + i)->dl = fdata->blksize;
+						break;
+					case 1:
+						(ct_data + i)->kl = 44;
+						(ct_data + i)->dl = LABEL_SIZE - 44;
+						break;
+					default:
+						(ct_data + i)->dl = fdata->blksize;
+						break;
+					}
+				} else
+					(ct_data + i)->dl = fdata->blksize;
+				last_ccw->cmd_code = DASD_ECKD_CCW_WRITE_CKD;
+				last_ccw->flags |= CCW_FLAG_CC | CCW_FLAG_SLI;
+				last_ccw->count = 8;
+				if (dasd_set_normalized_cda (last_ccw,
+                                                             __pa (ct_data + i), fcp, device)) {
+                                goto clear_fcp;
+                                }
+				last_ccw++;
+			}
 		}
 		(last_ccw - 1)->flags &= ~(CCW_FLAG_CC | CCW_FLAG_DC);
 		fcp->device = device;
 		fcp->status = CQR_STATUS_FILLED;
 	}
+        goto out;
+ clear_fcp:
+        dasd_free_request (fcp, device);
+        fcp=NULL;
+ out:
 	return fcp;
 }
 
@@ -927,7 +930,7 @@
 
 	if (stat->cstat == 0x00 &&
 	    stat->dstat == (DEV_STAT_CHN_END | DEV_STAT_DEV_END))
-		return dasd_era_none;
+		    return dasd_era_none;
 
 	switch (device->devinfo.sid_data.cu_type) {
 	case 0x3990:
@@ -946,56 +949,56 @@
 dasd_eckd_erp_action (ccw_req_t * cqr)
 {
 	dasd_device_t *device = (dasd_device_t *) cqr->device;
-        
+
 	switch (device->devinfo.sid_data.cu_type) {
 	case 0x3990:
 	case 0x2105:
 		return dasd_3990_erp_action;
 	case 0x9343:
-                /* Return dasd_9343_erp_action; */
+		/* Return dasd_9343_erp_action; */
 	default:
-		return default_erp_action;
+		return dasd_default_erp_action;
 	}
 }
 
 static dasd_erp_postaction_fn_t
 dasd_eckd_erp_postaction (ccw_req_t * cqr)
 {
-	return default_erp_postaction;
+	return dasd_default_erp_postaction;
 }
 
 
-#ifdef DASD_CDL
 inline unsigned char
-dasd_eckd_cdl_cmd(dasd_device_t *device,int recid,int cmd) {
-    dasd_eckd_private_t *private = (dasd_eckd_private_t *) device->private;
-    int byt_per_blk = device->sizes.bp_block;
-    int blk_per_trk = recs_per_track (&(private->rdc_data), 0, byt_per_blk);
-    switch (cmd) {
-    case READ:
-        if (recid < 3) 
-            return DASD_ECKD_CCW_READ_KD_MT;
-        if (recid < blk_per_trk)
-            return DASD_ECKD_CCW_READ_MT;
-        if (recid < 2*blk_per_trk)
-            return DASD_ECKD_CCW_READ_KD_MT;
-        return DASD_ECKD_CCW_READ_MT;
-        break;
-    case WRITE:
-        if (recid < 3)
-            return DASD_ECKD_CCW_WRITE_KD_MT;
-        if (recid < blk_per_trk)
-            return DASD_ECKD_CCW_WRITE_MT;
-        if (recid < 2*blk_per_trk)
-            return DASD_ECKD_CCW_WRITE_KD_MT;
-        return DASD_ECKD_CCW_WRITE_MT;
-        break;
-    default:
-        BUG();
-    }
-    return 0; // never executed
+dasd_eckd_cdl_cmd (dasd_device_t * device, int recid, int cmd)
+{
+	dasd_eckd_private_t *private = (dasd_eckd_private_t *) device->private;
+	int byt_per_blk = device->sizes.bp_block;
+	int blk_per_trk = recs_per_track (&(private->rdc_data), 0, byt_per_blk);
+	switch (cmd) {
+	case READ:
+		if (recid < 3)
+			return DASD_ECKD_CCW_READ_KD_MT;
+		if (recid < blk_per_trk)
+			return DASD_ECKD_CCW_READ_MT;
+		if (recid < 2 * blk_per_trk)
+			return DASD_ECKD_CCW_READ_KD_MT;
+		return DASD_ECKD_CCW_READ_MT;
+		break;
+	case WRITE:
+		if (recid < 3)
+			return DASD_ECKD_CCW_WRITE_KD_MT;
+		if (recid < blk_per_trk)
+			return DASD_ECKD_CCW_WRITE_MT;
+		if (recid < 2 * blk_per_trk)
+			return DASD_ECKD_CCW_WRITE_KD_MT;
+		return DASD_ECKD_CCW_WRITE_MT;
+		break;
+	default:
+		BUG ();
+	}
+	return 0;		// never executed
 }
-#endif
+
 
 static ccw_req_t *
 dasd_eckd_build_cp_from_req (dasd_device_t * device, struct request *req)
@@ -1014,11 +1017,9 @@
 	int blk_per_trk = recs_per_track (&(private->rdc_data), 0, byt_per_blk);
 	int btrk = (req->sector >> shift) / blk_per_trk;
 	int etrk = ((req->sector + req->nr_sectors - 1) >> shift) / blk_per_trk;
-#ifdef DASD_CDL
-        int recid = req->sector >> shift;
-        int locate4k_set=0;
-        int nlocs=0;
-#endif
+	int recid = req->sector >> shift;
+	int locate4k_set = 0;
+	int nlocs = 0;
 
 	if (req->cmd == READ) {
 		rw_cmd = DASD_ECKD_CCW_READ_MT;
@@ -1032,142 +1033,78 @@
 	/* count bhs to prevent errors, when bh smaller than block */
 	bhct = 0;
 	for (bh = req->bh; bh; bh = bh->b_reqnext) {
-		if (bh->b_size > byt_per_blk)
-			for (size = 0; size < bh->b_size; size += byt_per_blk)
-				bhct++;
-		else
-			bhct++;
+		if (bh->b_size < byt_per_blk)
+                        BUG();
+                bhct+= bh->b_size >> (device->sizes.s2b_shift+9);
+	}
+	if (btrk < 2 && private->uses_cdl) {
+		if (etrk < 2)
+                        nlocs = bhct;
+                else
+                        nlocs = 2 * blk_per_trk - recid;
 	}
-#ifndef DASD_CDL
-	rw_cp = dasd_alloc_request (dasd_eckd_discipline.name,
-				    2 + bhct + 1,
-				    sizeof (DE_eckd_data_t) +
-				    sizeof (LO_eckd_data_t));
-#else
-        if (btrk<2 && private->uses_cdl) {
-            nlocs+= 2*blk_per_trk-recid;
-            if (etrk<2)
-                nlocs-=2*blk_per_trk-((req->sector + req->nr_sectors - 1) >> shift);
-        }
-        rw_cp = dasd_alloc_request (dasd_eckd_discipline.name,
+	rw_cp = dasd_alloc_request (dasd_eckd_discipline.name, 
                                     2 + nlocs + bhct + 1,
-                                    sizeof (DE_eckd_data_t) +
-                                    (1+nlocs)*sizeof (LO_eckd_data_t));
-#endif
+                                    sizeof (DE_eckd_data_t) + (1 +
+                                                               nlocs) *
+                                    sizeof (LO_eckd_data_t),
+                                    device);
 	if (!rw_cp) {
 		return NULL;
 	}
 	DE_data = rw_cp->data;
 	LO_data = rw_cp->data + sizeof (DE_eckd_data_t);
 	ccw = rw_cp->cpaddr;
-	define_extent (ccw, DE_data, btrk, etrk, rw_cmd, device);
-	ccw->flags |= CCW_FLAG_CC;
-#ifndef DASD_CDL
-	ccw++;
-        locate_record (ccw, LO_data, btrk, (req->sector >> shift) % blk_per_trk + 1,
-                       req->nr_sectors >> shift, rw_cmd, device, device->sizes.bp_block);
+	if (define_extent (ccw, DE_data, btrk, etrk, rw_cmd, device, rw_cp)) {
+                goto clear_rw_cp;
+        }
 	ccw->flags |= CCW_FLAG_CC;
-#endif
 	for (bh = req->bh; bh != NULL;) {
-		if (bh->b_size > byt_per_blk) {
-			for (size = 0; size < bh->b_size; size += byt_per_blk) {
-#ifdef DASD_CDL
-                                if (!locate4k_set) {
-                                    // we need to chain a locate record before our rw-ccw
-                                    ccw++;
-                                    if ((recid/blk_per_trk)<2 && private->uses_cdl) {
+                for (size = 0; size < bh->b_size; size += byt_per_blk) {
+                        if (!locate4k_set) {
+                                // we need to chain a locate record before our rw-ccw
+                                ccw++;
+                                if ((recid / blk_per_trk) < 2
+                                    && private->uses_cdl) {
                                         /* Do a locate record for our special blocks */
-                                        locate_record (ccw, LO_data++, recid/blk_per_trk, 
-                                                       recid % blk_per_trk + 1, 1, 
-                                                       dasd_eckd_cdl_cmd(device,recid,req->cmd), 
-                                                       device, 
-                                                       dasd_eckd_cdl_reclen(device,recid));
-                                    } else {
-                                        // Do a locate record for standard blocks */
-                                        locate_record (ccw, LO_data++, recid/blk_per_trk,
+                                        int cmd = dasd_eckd_cdl_cmd (device,recid, req->cmd);
+                                        if (locate_record (ccw, 
+                                                       LO_data++,
+                                                       recid / blk_per_trk, 
                                                        recid % blk_per_trk + 1, 
-                                                       (((req->sector + req->nr_sectors) >> shift)-recid),
-                                                       rw_cmd,device, device->sizes.bp_block);
-                                        locate4k_set=1;
-                                    }                                        
-                                    ccw->flags |= CCW_FLAG_CC;
-                                }
-#endif
-				ccw++;
-#ifndef DASD_CDL
-				ccw->flags |= CCW_FLAG_CC;
-				ccw->cmd_code= rw_cmd;
-				ccw->count = bh->b_size;
-#else
-                                ccw->flags |= CCW_FLAG_CC;
-                                ccw->cmd_code=locate4k_set?rw_cmd:
-                                    dasd_eckd_cdl_cmd(device,recid,req->cmd);
-                                ccw->count =locate4k_set?bh->b_size:
-                                    dasd_eckd_cdl_reclen(device,recid);
-#endif
-				set_normalized_cda (ccw, __pa (bh->b_data));
-				size += bh->b_size;
-				bh = bh->b_reqnext;
-#ifdef DASD_CDL
-                                recid++;
-#endif
-			}
-			bh = bh->b_reqnext;
-		} else {	/* group N bhs to fit into byt_per_blk */
-			for (size = 0; bh != NULL && size < byt_per_blk;) {
-#ifdef DASD_CDL
-                                if (!locate4k_set) {
-                                    // we need to chain a locate record before our rw-ccw
-                                    ccw++;
-                                    if ((recid/blk_per_trk)<2 && private->uses_cdl) {
-                                        /* Do a locate record for our special blocks */
-                                        locate_record (ccw, LO_data++, recid/blk_per_trk, 
-                                                       recid % blk_per_trk + 1, 1, 
-                                                       dasd_eckd_cdl_cmd(device,recid,req->cmd), 
-                                                       device, 
-                                                       dasd_eckd_cdl_reclen(device,recid));
-                                    } else {
+                                                       1, cmd, device,
+                                                           dasd_eckd_cdl_reclen(device, recid), rw_cp)) {
+                                                goto clear_rw_cp;
+                                        }
+                                } else {
                                         // Do a locate record for standard blocks */
-                                        locate_record (ccw, LO_data++, recid/blk_per_trk,
-                                                       recid % blk_per_trk + 1, 
-                                                       (((req->sector + req->nr_sectors) >> shift)-recid),
-                                                       rw_cmd,device, device->sizes.bp_block);
-                                        locate4k_set=1;
-                                    }                                        
-                                    ccw->flags |= CCW_FLAG_CC;
+                                        if (locate_record (ccw, 
+                                                       LO_data++,
+                                                       recid /blk_per_trk,
+                                                       recid %blk_per_trk + 1,
+                                                       (((req->sector +
+                                                          req->nr_sectors) >>
+                                                         shift) - recid), 
+                                                       rw_cmd, device,
+                                                           device->sizes.bp_block, rw_cp)) {
+                                                goto clear_rw_cp;
+                                        }
+                                        locate4k_set = 1;
                                 }
-#endif
-				ccw++;
-#ifndef DASD_CDL
-				ccw->flags |= CCW_FLAG_DC;
-				ccw->cmd_code= rw_cmd;
-				ccw->count = bh->b_size;
-#else
-                                ccw->flags |= locate4k_set?CCW_FLAG_DC:CCW_FLAG_CC;
-                                ccw->cmd_code=locate4k_set?rw_cmd:
-                                    dasd_eckd_cdl_cmd(device,recid,req->cmd);
-                                ccw->count =locate4k_set?bh->b_size:
-                                    dasd_eckd_cdl_reclen(device,recid);
-#endif
-				set_normalized_cda (ccw, __pa (bh->b_data));
-				size += bh->b_size;
-				bh = bh->b_reqnext;
-#ifdef DASD_CDL
-                                recid++;
-#endif
-			}
-			if (size != byt_per_blk) {
-				PRINT_WARN ("Cannot fulfill small request %ld vs. %d (%ld sects)\n",
-					    size,
-					    byt_per_blk,
-					    req->nr_sectors);
-
-				ccw_free_request (rw_cp);
-				return NULL;
-			}
-			ccw->flags &= ~CCW_FLAG_DC;
-			ccw->flags |= CCW_FLAG_CC;
-		}
+                                ccw->flags |= CCW_FLAG_CC;
+                        }
+                        ccw++;
+                        ccw->flags |= CCW_FLAG_CC;
+                        ccw->cmd_code = locate4k_set ? rw_cmd :
+                                dasd_eckd_cdl_cmd (device, recid, req->cmd);
+                        ccw->count = locate4k_set ? byt_per_blk :
+                                dasd_eckd_cdl_reclen (device, recid);
+                        if (dasd_set_normalized_cda (ccw, __pa (bh->b_data+size), rw_cp, device)) {
+                                goto clear_rw_cp;
+                        }
+                        recid++;
+                }
+                bh = bh->b_reqnext;
 	}
 	ccw->flags &= ~(CCW_FLAG_DC | CCW_FLAG_CC);
 	rw_cp->device = device;
@@ -1176,11 +1113,15 @@
 	rw_cp->lpm = LPM_ANYPATH;
 	rw_cp->retries = 2;
 	asm volatile ("STCK %0":"=m" (rw_cp->buildclk));
-	check_then_set (&rw_cp->status,
-				       CQR_STATUS_EMPTY,
-				       CQR_STATUS_FILLED);
+	check_then_set (&rw_cp->status, CQR_STATUS_EMPTY, CQR_STATUS_FILLED);
+        goto out;
+ clear_rw_cp:
+        dasd_free_request (rw_cp, device);
+        rw_cp=NULL;
+ out:
 	return rw_cp;
 }
+
 #if 0
 int
 dasd_eckd_cleanup_request (ccw_req_t * cqr)
@@ -1197,7 +1138,8 @@
 				ccw->flags |= CCW_FLAG_CC;
 				ccw->cmd_code = rw_cmd;
 				ccw->count = byt_per_blk;
-				set_normalized_cda (ccw, __pa (bh->b_data + size));
+				set_normalized_cda (ccw,
+						    __pa (bh->b_data + size));
 			}
 			bh = bh->b_reqnext;
 		} else {	/* group N bhs to fit into byt_per_blk */
@@ -1218,7 +1160,8 @@
 ccw_req_t *
 dasd_eckd_reserve (struct dasd_device_t * device)
 {
-	ccw_req_t *cqr = ccw_alloc_request (dasd_eckd_discipline.name, 1 + 1, 0);
+	ccw_req_t *cqr =
+	    dasd_alloc_request (dasd_eckd_discipline.name, 1 + 1, 0, device);
 	if (cqr == NULL) {
 		printk (KERN_WARNING PRINTK_HEADER
 			"No memory to allocate initialization request\n");
@@ -1234,7 +1177,8 @@
 ccw_req_t *
 dasd_eckd_release (struct dasd_device_t * device)
 {
-	ccw_req_t *cqr = ccw_alloc_request (dasd_eckd_discipline.name, 1 + 1, 0);
+	ccw_req_t *cqr =
+	    dasd_alloc_request (dasd_eckd_discipline.name, 1 + 1, 0, device);
 	if (cqr == NULL) {
 		printk (KERN_WARNING PRINTK_HEADER
 			"No memory to allocate initialization request\n");
@@ -1254,67 +1198,91 @@
 	ccw1_t *cp;
 
 	cp = cqr->cpaddr;
-        do {
+	do {
 		if (cp->cmd_code == cmd)
 			return cp;
 		if (cp->cmd_code == CCW_CMD_TIC) {
-			cp = (ccw1_t *)cp->cda;
-                        continue;
-		} 
-                if ( cp->flags & (CCW_FLAG_DC | CCW_FLAG_CC) ) {
-                        cp ++;
-                        continue;
-		}
-                break;
-	} while ( 1 );
-        return NULL;
+			cp = (ccw1_t *) (long) cp->cda;
+			continue;
+		}
+		if (cp->flags & (CCW_FLAG_DC | CCW_FLAG_CC)) {
+			cp++;
+			continue;
+		}
+		break;
+	} while (1);
+	return NULL;
 }
 
-ccw_req_t *
-dasd_eckd_merge_cp ( dasd_device_t *device )
+static ccw_req_t *
+dasd_eckd_merge_cp (dasd_device_t * device)
 {
-        return NULL;
+	return NULL;
 }
 
-static char *
-dasd_eckd_dump_sense (struct dasd_device_t *device, ccw_req_t * req)
+static int
+dasd_eckd_fill_info (dasd_device_t * device, dasd_information_t * info)
 {
+	int rc = 0;
+	info->label_block = 2;
+	if (((dasd_eckd_private_t *) device->private)->uses_cdl)
+		info->FBA_layout = 0;
+	else
+		info->FBA_layout = 1;
+	info->characteristics_size = sizeof (dasd_eckd_characteristics_t);
+	memcpy (info->characteristics,
+		&((dasd_eckd_private_t *) device->private)->rdc_data,
+		sizeof (dasd_eckd_characteristics_t));
+	info->confdata_size = sizeof (dasd_eckd_confdata_t);
+	memcpy (info->configuration_data,
+		&((dasd_eckd_private_t *) device->private)->conf_data,
+		sizeof (dasd_eckd_confdata_t));
+	return rc;
+}
+
+static char*
+dasd_eckd_dump_sense (struct dasd_device_t *device, 
+                      ccw_req_t            *req)
+{
+
 	char *page = (char *) get_free_page (GFP_ATOMIC);
 	devstat_t *stat = &device->dev_status;
 	char *sense = stat->ii.sense.data;
 	int len, sl, sct;
 
 	if (page == NULL) {
+                printk (KERN_ERR PRINTK_HEADER
+                        "No memory to dump sense data\n");
 		return NULL;
 	}
-	len = sprintf (page, KERN_WARNING PRINTK_HEADER
+
+	len = sprintf (page, KERN_ERR PRINTK_HEADER
 		       "device %04X on irq %d: I/O status report:\n",
 		       device->devinfo.devno, device->devinfo.irq);
-	len += sprintf (page + len, KERN_WARNING PRINTK_HEADER
+	len += sprintf (page + len, KERN_ERR PRINTK_HEADER
 			"in req: %p CS: 0x%02X DS: 0x%02X\n",
 			req, stat->cstat, stat->dstat);
-	len += sprintf (page + len, KERN_WARNING PRINTK_HEADER
-			"Failing CCW: %p\n", (void *) stat->cpa);
-        {
-            ccw1_t *act = req -> cpaddr;
-            int i = req -> cplength;
-            do {
-#ifdef ERP_DEBUB
-                printk ( KERN_INFO "CCW %p: %08X %08X\n", 
-                         act,((int*)act)[0],((int*)act)[1]);
-                printk ( KERN_INFO "DAT: %08X %08X %08X %08X\n", 
-                         ((int*)act->cda)[0],((int*)act->cda)[1],
-                         ((int*)act->cda)[2],((int*)act->cda)[3]);
-#endif /* ERP_DEBUG */
-                act ++;
-            } while ( --i );
-        }
+	len += sprintf (page + len, KERN_ERR PRINTK_HEADER
+			"Failing CCW: %p\n", (void *) (long) stat->cpa);
+	{
+		ccw1_t *act = req->cpaddr;
+		int i = req->cplength;
+		do {
+#ifdef ERP_DEBUG
+			printk (KERN_ERR "CCW %p: %08X %08X\n",
+				act, ((int *) act)[0], ((int *) act)[1]);
+			printk (KERN_ERR "DAT: %08X %08X %08X %08X\n",
+				((int *) act->cda)[0], ((int *) act->cda)[1],
+				((int *) act->cda)[2], ((int *) act->cda)[3]);
+#endif				/* ERP_DEBUG */
+			act++;
+		} while (--i);
+	}
 	if (stat->flag & DEVSTAT_FLAG_SENSE_AVAIL) {
 		for (sl = 0; sl < 4; sl++) {
-			len += sprintf (page + len, KERN_WARNING PRINTK_HEADER
+			len += sprintf (page + len, KERN_ERR PRINTK_HEADER
 					"Sense(hex) %2d-%2d:",
-					(8 * sl),
-					((8 * sl) + 7));
+					(8 * sl), ((8 * sl) + 7));
 
 			for (sct = 0; sct < 8; sct++) {
 				len += sprintf (page + len, " %02x",
@@ -1325,22 +1293,29 @@
 
 		if (sense[27] & DASD_SENSE_BIT_0) {
 			/* 24 Byte Sense Data */
-			len += sprintf (page + len, KERN_WARNING PRINTK_HEADER
-				     "24 Byte: %x MSG %x, %s MSGb to SYSOP\n",
+			len += sprintf (page + len, KERN_ERR PRINTK_HEADER
+					"24 Byte: %x MSG %x, %s MSGb to SYSOP\n",
 					sense[7] >> 4, sense[7] & 0x0f,
 					sense[1] & 0x10 ? "" : "no");
 		} else {
 			/* 32 Byte Sense Data */
-			len += sprintf (page + len, KERN_WARNING PRINTK_HEADER
-				   "32 Byte: Format: %x Exception class %x\n",
+			len += sprintf (page + len, KERN_ERR PRINTK_HEADER
+					"32 Byte: Format: %x Exception class %x\n",
 					sense[6] & 0x0f, sense[22] >> 4);
 		}
 	}
-	return page;
+
+        printk ("Sense data:\n%s", 
+                page);
+
+        free_page ((unsigned long) page);
+        
+	return NULL;
 }
 
-dasd_discipline_t dasd_eckd_discipline =
-{
+
+dasd_discipline_t dasd_eckd_discipline = {
+        owner: THIS_MODULE,
 	name:"ECKD",
 	ebcname:"ECKD",
 	max_blocks:255,
@@ -1350,6 +1325,7 @@
 	do_analysis:dasd_eckd_do_analysis,
 	fill_geometry:dasd_eckd_fill_geometry,
 	start_IO:dasd_start_IO,
+	term_IO:dasd_term_IO,
 	format_device:dasd_eckd_format_device,
 	examine_error:dasd_eckd_examine_error,
 	erp_action:dasd_eckd_erp_action,
@@ -1359,7 +1335,8 @@
 	int_handler:dasd_int_handler,
 	reserve:dasd_eckd_reserve,
 	release:dasd_eckd_release,
-	merge_cp:dasd_eckd_merge_cp
+	merge_cp:dasd_eckd_merge_cp,
+	fill_info:dasd_eckd_fill_info,
 };
 
 int
@@ -1369,40 +1346,62 @@
 	printk (KERN_INFO PRINTK_HEADER
 		"%s discipline initializing\n", dasd_eckd_discipline.name);
 	ASCEBC (dasd_eckd_discipline.ebcname, 4);
-	dasd_discipline_enq (&dasd_eckd_discipline);
+	dasd_discipline_add (&dasd_eckd_discipline);
 #ifdef CONFIG_DASD_DYNAMIC
-        {
-	int i;
-	for (i = 0; i < sizeof (dasd_eckd_known_devices) / sizeof (devreg_t); i++) {
-                printk (KERN_INFO PRINTK_HEADER
-                        "We are interested in: CU %04X/%02x\n",
-			dasd_eckd_known_devices[i].ci.hc.ctype,
-			dasd_eckd_known_devices[i].ci.hc.cmode);
-		s390_device_register (&dasd_eckd_known_devices[i]);
-        }
-        }
+	{
+		int i;
+		for (i = 0;
+		     i < sizeof (dasd_eckd_known_devices) / sizeof (devreg_t);
+		     i++) {
+			printk (KERN_INFO PRINTK_HEADER
+				"We are interested in: CU %04X/%02x\n",
+				dasd_eckd_known_devices[i].ci.hc.ctype,
+				dasd_eckd_known_devices[i].ci.hc.cmode);
+			s390_device_register (&dasd_eckd_known_devices[i]);
+		}
+	}
 #endif				/* CONFIG_DASD_DYNAMIC */
 	return rc;
 }
 
 void
-dasd_eckd_cleanup( void ) {
-        printk ( KERN_INFO PRINTK_HEADER
-                 "%s discipline cleaning up\n", dasd_eckd_discipline.name);
+dasd_eckd_cleanup (void)
+{
+	printk (KERN_INFO PRINTK_HEADER
+		"%s discipline cleaning up\n", dasd_eckd_discipline.name);
 #ifdef CONFIG_DASD_DYNAMIC
-        {
-	int i;
-        for ( i=0; i<sizeof(dasd_eckd_known_devices)/sizeof(devreg_t); i++) {
-		printk (KERN_INFO PRINTK_HEADER
-			"We were interested in: CU %04X/%02x\n",
-			dasd_eckd_known_devices[i].ci.hc.ctype,
-			dasd_eckd_known_devices[i].ci.hc.cmode);
-		s390_device_unregister(&dasd_eckd_known_devices[i]);
-	}
-        } 
-#endif /* CONFIG_DASD_DYNAMIC */
-        dasd_discipline_deq(&dasd_eckd_discipline);
+	{
+		int i;
+		for (i = 0;
+		     i < sizeof (dasd_eckd_known_devices) / sizeof (devreg_t);
+		     i++) {
+			printk (KERN_INFO PRINTK_HEADER
+				"We were interested in: CU %04X/%02x\n",
+				dasd_eckd_known_devices[i].ci.hc.ctype,
+				dasd_eckd_known_devices[i].ci.hc.cmode);
+			s390_device_unregister (&dasd_eckd_known_devices[i]);
+		}
+	}
+#endif				/* CONFIG_DASD_DYNAMIC */
+	dasd_discipline_del (&dasd_eckd_discipline);
 }
+
+#ifdef MODULE
+int
+init_module (void)
+{
+	int rc = 0;
+	rc = dasd_eckd_init ();
+	return rc;
+}
+
+void
+cleanup_module (void)
+{
+	dasd_eckd_cleanup ();
+	return;
+}
+#endif
 
 /*
  * Overrides for Emacs so that we follow Linus's tabbing style.
diff -u --recursive --new-file v2.4.7/linux/drivers/s390/block/dasd_eckd.h linux/drivers/s390/block/dasd_eckd.h
--- v2.4.7/linux/drivers/s390/block/dasd_eckd.h	Wed Apr 11 19:02:28 2001
+++ linux/drivers/s390/block/dasd_eckd.h	Sun Aug  5 13:12:41 2001
@@ -10,6 +10,7 @@
 #define DASD_ECKD_CCW_READ_HOME_ADDRESS 0x0a
 #define DASD_ECKD_CCW_WRITE_KD 0x0d
 #define DASD_ECKD_CCW_READ_KD 0x0e
+#define DASD_ECKD_CCW_ERASE 0x11
 #define DASD_ECKD_CCW_READ_COUNT 0x12
 #define DASD_ECKD_CCW_WRITE_RECORD_ZERO 0x15
 #define DASD_ECKD_CCW_READ_RECORD_ZERO 0x16
@@ -26,52 +27,51 @@
 #define DASD_ECKD_CCW_WRITE_CKD_MT 0x9d
 #define DASD_ECKD_CCW_RESERVE 0xB4
 
-
-typedef 
-struct eckd_count_t {
+typedef
+    struct eckd_count_t {
 	__u16 cyl;
 	__u16 head;
 	__u8 record;
 	__u8 kl;
 	__u16 dl;
-} __attribute__ ((packed)) 
+} __attribute__ ((packed))
 
-eckd_count_t;
+    eckd_count_t;
 
 typedef
-struct ch_t {
+    struct ch_t {
 	__u16 cyl;
 	__u16 head;
-} __attribute__ ((packed)) 
+} __attribute__ ((packed))
 
-ch_t;
+    ch_t;
 
 typedef
-struct chs_t {
+    struct chs_t {
 	__u16 cyl;
 	__u16 head;
 	__u32 sector;
-} __attribute__ ((packed)) 
+} __attribute__ ((packed))
 
-chs_t;
+    chs_t;
 
 typedef
-struct chr_t {
+    struct chr_t {
 	__u16 cyl;
 	__u16 head;
 	__u8 record;
-} __attribute__ ((packed)) 
+} __attribute__ ((packed))
 
-chr_t;
+    chr_t;
 
 typedef
-struct geom_t {
+    struct geom_t {
 	__u16 cyl;
 	__u16 head;
 	__u32 sector;
-} __attribute__ ((packed)) 
+} __attribute__ ((packed))
 
-geom_t;
+    geom_t;
 
 typedef struct eckd_home_t {
 	__u8 skip_control[14];
@@ -82,12 +82,12 @@
 	__u8 reserved;
 	__u8 key_length;
 	__u8 reserved2[2];
-} __attribute__ ((packed)) 
+} __attribute__ ((packed))
 
-eckd_home_t;
+    eckd_home_t;
 
 typedef
-struct DE_eckd_data_t {
+    struct DE_eckd_data_t {
 	struct {
 		unsigned char perm:2;	/* Permissions on this extent */
 		unsigned char reserved:1;
@@ -108,12 +108,12 @@
 	__u8 reserved;
 	ch_t beg_ext;
 	ch_t end_ext;
-} __attribute__ ((packed)) 
+} __attribute__ ((packed))
 
-DE_eckd_data_t;
+    DE_eckd_data_t;
 
 typedef
-struct LO_eckd_data_t {
+    struct LO_eckd_data_t {
 	struct {
 		unsigned char orientation:2;
 		unsigned char operation:6;
@@ -129,12 +129,12 @@
 	chr_t search_arg;
 	__u8 sector;
 	__u16 length;
-} __attribute__ ((packed)) 
+} __attribute__ ((packed))
 
-LO_eckd_data_t;
+    LO_eckd_data_t;
 
 typedef
-struct dasd_eckd_characteristics_t {
+    struct dasd_eckd_characteristics_t {
 	__u16 cu_type;
 	struct {
 		unsigned char support:2;
@@ -204,9 +204,9 @@
 	__u8 factor8;
 	__u8 reserved2[3];
 	__u8 reserved3[10];
-} __attribute__             ((packed)) 
+} __attribute__ ((packed))
 
-dasd_eckd_characteristics_t;
+    dasd_eckd_characteristics_t;
 
 typedef struct dasd_eckd_confdata_t {
 	struct {
@@ -323,10 +323,10 @@
 		__u8 log_dev_address;
 		unsigned char reserved2[12];
 	} __attribute__ ((packed)) neq;
-} __attribute__      ((packed)) 
+} __attribute__ ((packed))
 
-dasd_eckd_confdata_t;
+    dasd_eckd_confdata_t;
 
 int dasd_eckd_init (void);
-void dasd_eckd_cleanup(void);
+void dasd_eckd_cleanup (void);
 #endif				/* DASD_ECKD_H */
diff -u --recursive --new-file v2.4.7/linux/drivers/s390/block/dasd_fba.c linux/drivers/s390/block/dasd_fba.c
--- v2.4.7/linux/drivers/s390/block/dasd_fba.c	Wed Apr 11 19:02:28 2001
+++ linux/drivers/s390/block/dasd_fba.c	Sun Aug  5 13:12:41 2001
@@ -12,19 +12,21 @@
 #include <linux/kernel.h>
 #include <asm/debug.h>
 
-#include <linux/malloc.h>
+#include <linux/slab.h>
 #include <linux/hdreg.h>	/* HDIO_GETGEO                      */
 #include <linux/blk.h>
+
 #include <asm/ccwcache.h>
 #include <asm/idals.h>
-#include <asm/dasd.h>
-
 #include <asm/ebcdic.h>
 #include <asm/io.h>
 #include <asm/irq.h>
 #include <asm/s390dyn.h>
 
+#include "dasd_int.h"
 #include "dasd_fba.h"
+#include "dasd_3370_erp.h"
+#include "dasd_9336_erp.h"
 
 #ifdef PRINTK_HEADER
 #undef PRINTK_HEADER
@@ -39,44 +41,38 @@
 dasd_discipline_t dasd_fba_discipline;
 
 typedef struct
-dasd_fba_private_t {
+    dasd_fba_private_t {
 	dasd_fba_characteristics_t rdc_data;
 } dasd_fba_private_t;
 
 #ifdef CONFIG_DASD_DYNAMIC
 static
-devreg_t dasd_fba_known_devices[] =
-{
+devreg_t dasd_fba_known_devices[] = {
 	{
-		ci:
-		{hc:
-		 {ctype:0x6310,
-                  dtype:0x9336}},
-		flag:(DEVREG_MATCH_CU_TYPE |
-                      DEVREG_MATCH_DEV_TYPE| 
-                      DEVREG_TYPE_DEVCHARS),
-		oper_func:dasd_oper_handler
-	},
+	      ci: { hc: {ctype:0x6310, dtype:0x9336}},
+	      flag:(DEVREG_MATCH_CU_TYPE |
+                    DEVREG_MATCH_DEV_TYPE | DEVREG_TYPE_DEVCHARS),
+              oper_func:dasd_oper_handler
+        },
 	{
-		ci:
-		{hc:
-		 {ctype:0x3880,
-                  dtype:0x3370}},
-		flag:(DEVREG_MATCH_CU_TYPE |
-                      DEVREG_MATCH_DEV_TYPE| 
-                      DEVREG_TYPE_DEVCHARS),
-		oper_func:dasd_oper_handler
-	}
+                ci: { hc: {ctype:0x3880, dtype:0x3370}},
+                flag:(DEVREG_MATCH_CU_TYPE |
+                      DEVREG_MATCH_DEV_TYPE | DEVREG_TYPE_DEVCHARS),
+                oper_func:dasd_oper_handler
+        }
 };
 #endif
-static inline void
+static inline int
 define_extent (ccw1_t * ccw, DE_fba_data_t * DE_data, int rw,
-	       int blksize, int beg, int nr)
+	       int blksize, int beg, int nr, ccw_req_t* cqr,
+               dasd_device_t* device)
 {
+        int rc=0;
 	memset (DE_data, 0, sizeof (DE_fba_data_t));
 	ccw->cmd_code = DASD_FBA_CCW_DEFINE_EXTENT;
 	ccw->count = 16;
-	set_normalized_cda (ccw, __pa (DE_data));
+	if (rc=dasd_set_normalized_cda (ccw, __pa (DE_data), cqr, device))
+                return rc;
 	if (rw == WRITE)
 		(DE_data->mask).perm = 0x0;
 	else if (rw == READ)
@@ -86,16 +82,17 @@
 	DE_data->blk_size = blksize;
 	DE_data->ext_loc = beg;
 	DE_data->ext_end = nr - 1;
+        return rc;
 }
 
 static inline void
 locate_record (ccw1_t * ccw, LO_fba_data_t * LO_data, int rw, int block_nr,
-	       int block_ct)
+	       int block_ct, ccw_req_t* cqr, dasd_device_t* device)
 {
 	memset (LO_data, 0, sizeof (LO_fba_data_t));
 	ccw->cmd_code = DASD_FBA_CCW_LOCATE;
 	ccw->count = 8;
-	set_normalized_cda (ccw, __pa (LO_data));
+	dasd_set_normalized_cda (ccw, __pa (LO_data), cqr, device);
 	if (rw == WRITE)
 		LO_data->operation.cmd = 0x5;
 	else if (rw == READ)
@@ -109,9 +106,9 @@
 static int
 dasd_fba_id_check (s390_dev_info_t * info)
 {
-        if (info->sid_data.cu_type == 0x3880)
-                if (info->sid_data.dev_type == 0x3370)
-                        return 0;
+	if (info->sid_data.cu_type == 0x3880)
+		if (info->sid_data.dev_type == 0x3370)
+			return 0;
 	if (info->sid_data.cu_type == 0x6310)
 		if (info->sid_data.dev_type == 0x9336)
 			return 0;
@@ -127,37 +124,43 @@
 
 	if (device == NULL) {
 		printk (KERN_WARNING PRINTK_HEADER
-		   "Null device pointer passed to characteristics checker\n");
-		return -ENODEV;
+			"Null device pointer passed to characteristics checker\n");
+                return -ENODEV;
 	}
-        if ( device->private != NULL ) {
-                kfree(device->private);
-        }
-        device->private = kmalloc (sizeof (dasd_fba_private_t), GFP_KERNEL);
+	device->private = kmalloc (sizeof (dasd_fba_private_t), GFP_KERNEL);
 	if (device->private == NULL) {
-                printk (KERN_WARNING PRINTK_HEADER
-                        "memory allocation failed for private data\n");
-                return -ENOMEM;
+		printk (KERN_WARNING PRINTK_HEADER
+			"memory allocation failed for private data\n");
+                rc = -ENOMEM;
+                goto fail;
 	}
 	private = (dasd_fba_private_t *) device->private;
 	rdc_data = (void *) &(private->rdc_data);
 	rc = read_dev_chars (device->devinfo.irq, &rdc_data, 32);
 	if (rc) {
-            printk (KERN_WARNING PRINTK_HEADER
-                    "Read device characteristics returned error %d\n", rc);
-            kfree(private);
-            device->private=NULL;
-            return rc;
+		printk (KERN_WARNING PRINTK_HEADER
+			"Read device characteristics returned error %d\n", rc);
+                goto fail;
 	}
 	printk (KERN_INFO PRINTK_HEADER
 		"%04X on sch %d: %04X/%02X(CU:%04X/%02X) %dMB at(%d B/blk)\n",
 		device->devinfo.devno, device->devinfo.irq,
-                device->devinfo.sid_data.dev_type, device->devinfo.sid_data.dev_model,
-                device->devinfo.sid_data.cu_type, device->devinfo.sid_data.cu_model,
+		device->devinfo.sid_data.dev_type,
+		device->devinfo.sid_data.dev_model,
+		device->devinfo.sid_data.cu_type,
+		device->devinfo.sid_data.cu_model,
 		(private->rdc_data.blk_bdsa *
 		 (private->rdc_data.blk_size >> 9)) >> 11,
 		private->rdc_data.blk_size);
-	return 0;
+        goto out;
+ fail:
+        if ( rc ) {
+                kfree(device->private);
+                device->private = NULL;
+        }
+        
+ out:
+	return rc;
 }
 
 static int
@@ -187,7 +190,7 @@
 		device->sizes.s2b_shift++;
 
 	device->sizes.blocks = (private->rdc_data.blk_bdsa);
-        device->sizes.pt_block = 1;
+	device->sizes.pt_block = 1;
 
 	return rc;
 }
@@ -221,7 +224,7 @@
 	dasd_device_t *device = (dasd_device_t *) cqr->device;
 	if (stat->cstat == 0x00 &&
 	    stat->dstat == (DEV_STAT_CHN_END | DEV_STAT_DEV_END))
-		return dasd_era_none;
+		    return dasd_era_none;
 
 	switch (device->devinfo.sid_data.dev_model) {
 	case 0x3370:
@@ -236,17 +239,16 @@
 static dasd_erp_action_fn_t
 dasd_fba_erp_action (ccw_req_t * cqr)
 {
-	return default_erp_action;
+	return dasd_default_erp_action;
 }
 
 static dasd_erp_postaction_fn_t
 dasd_fba_erp_postaction (ccw_req_t * cqr)
 {
-	if (cqr->function == default_erp_action)
-		return default_erp_postaction;
+	if (cqr->function == dasd_default_erp_action)
+		return dasd_default_erp_postaction;
 	printk (KERN_WARNING PRINTK_HEADER
-		"unknown ERP action %p\n",
-		cqr->function);
+		"unknown ERP action %p\n", cqr->function);
 	return NULL;
 }
 
@@ -255,7 +257,7 @@
 {
 	ccw_req_t *rw_cp = NULL;
 	int rw_cmd;
-	int bhct, i;
+	int bhct, i = 0;
 	long size;
 	ccw1_t *ccw;
 	DE_fba_data_t *DE_data;
@@ -263,7 +265,7 @@
 	struct buffer_head *bh;
 	dasd_fba_private_t *private = (dasd_fba_private_t *) device->private;
 	int byt_per_blk = device->sizes.bp_block;
-
+        
 	if (req->cmd == READ) {
 		rw_cmd = DASD_FBA_CCW_READ;
 	} else if (req->cmd == WRITE) {
@@ -273,20 +275,30 @@
 		return NULL;
 	}
 	/* Build the request */
-	/* count bhs to prevent errors, when bh smaller than block */
+	/* count hs to prevent errors, when bh smaller than block */
+        bh = req -> bh;
 	bhct = 0;
-	for (bh = req->bh; bh; bh = bh->b_reqnext) {
-		if (bh->b_size > byt_per_blk)
-			for (size = 0; size < bh->b_size; size += byt_per_blk)
-				bhct++;
-		else
-			bhct++;
-	}
-
-	rw_cp = dasd_alloc_request (dasd_fba_discipline.name,
-				    1 + 2*bhct,
-				    sizeof (DE_fba_data_t) +
-				    bhct*sizeof (LO_fba_data_t));
+        while ( bh != NULL ) {
+                if (bh->b_size < byt_per_blk) {
+                        BUG();
+                }
+                bhct += bh->b_size >> (device->sizes.s2b_shift+9);
+                bh = bh->b_reqnext;
+        }
+        
+        if (private->rdc_data.mode.bits.data_chain) {
+                rw_cp = dasd_alloc_request (dasd_fba_discipline.name,
+                                            2 + bhct,
+                                            sizeof (DE_fba_data_t) +
+                                            sizeof (LO_fba_data_t),
+                                            device);
+        } else {
+                rw_cp = dasd_alloc_request (dasd_fba_discipline.name,
+                                            1 + 2 * bhct,
+                                            sizeof (DE_fba_data_t) +
+                                            bhct * sizeof (LO_fba_data_t),
+                                            device);
+        }
 	if (!rw_cp) {
 		return NULL;
 	}
@@ -294,64 +306,77 @@
 	LO_data = rw_cp->data + sizeof (DE_fba_data_t);
 	ccw = rw_cp->cpaddr;
 
-	define_extent (ccw, DE_data, req->cmd, byt_per_blk,
-		       req->sector, req->nr_sectors);
+	if (define_extent (ccw, DE_data, req->cmd, byt_per_blk,
+                           req->sector, req->nr_sectors, rw_cp, device)) {
+                goto clear_rw_cp;
+        }
 	ccw->flags |= CCW_FLAG_CC;
-
-	for (i = 0, bh = req->bh; bh;) {
-		if (bh->b_size > byt_per_blk) {
-			for (size = 0; size < bh->b_size; size += byt_per_blk) {
-                                ccw++;
-                                locate_record (ccw, LO_data, req->cmd, i, 1);
-                                ccw->flags |= CCW_FLAG_CC;
-				ccw++;
-                                ccw->flags |= CCW_FLAG_CC|CCW_FLAG_SLI;
-				ccw->cmd_code = rw_cmd;
-				ccw->count = byt_per_blk;
-				set_normalized_cda (ccw, __pa (bh->b_data + size));
-                                i++;
-                                LO_data++;
-			}
-			bh = bh->b_reqnext;
-		} else {	/* group N bhs to fit into byt_per_blk */
-			for (size = 0; bh != NULL && size < byt_per_blk;) {
-                                ccw++;
-                                locate_record (ccw, LO_data, req->cmd, i, 1);
+        ccw ++;
+        locate_record (ccw, LO_data, req->cmd, 0, 
+                       private->rdc_data.mode.bits.data_chain ? bhct : 1, rw_cp, device);
+        if (ccw->cda == 0) {
+                goto clear_rw_cp;
+        }
+        ccw->flags |= CCW_FLAG_CC;
+        
+        bh = req -> bh;
+        i = 0;
+        while ( bh != NULL ) {
+                for (size = 0; size < bh->b_size; size += byt_per_blk) {
+                        ccw ++;
+                        ccw->cmd_code = rw_cmd;
+                        ccw->count = byt_per_blk;
+                        if (dasd_set_normalized_cda (ccw,__pa (bh->b_data + size), rw_cp, device)) {
+                                goto clear_rw_cp;
+                        }
+                        if (private->rdc_data.mode.bits.data_chain) {
+                                ccw->flags |= CCW_FLAG_DC;
+                        } else {
                                 ccw->flags |= CCW_FLAG_CC;
-				ccw++;
-				if (private->rdc_data.mode.bits.data_chain) {
-					ccw->flags |= CCW_FLAG_DC|CCW_FLAG_SLI;
-				} else {
-					PRINT_WARN ("Cannot chain chunks smaller than one block\n");
-					ccw_free_request (rw_cp);
-					return NULL;
-				}
-				ccw->cmd_code = rw_cmd;
-				ccw->count = bh->b_size;
-				set_normalized_cda (ccw, __pa (bh->b_data));
-				size += bh->b_size;
-				bh = bh->b_reqnext;
-                                i++;
-                                LO_data++;
-			}
-			ccw->flags &= ~CCW_FLAG_DC;
-			ccw->flags |= CCW_FLAG_CC|CCW_FLAG_SLI;
-			if (size != byt_per_blk) {
-				PRINT_WARN ("Cannot fulfill request smaller than block\n");
-				ccw_free_request (rw_cp);
-				return NULL;
-			}
-		}
-	}
+                        }
+                }
+                bh = bh->b_reqnext;
+                if ( bh != NULL &&
+                     !(private->rdc_data.mode.bits.data_chain)) {
+                        ccw++;
+                        i++;
+                        LO_data++;
+                        locate_record (ccw, LO_data, req->cmd, i, 1, rw_cp, device);
+                        if (ccw->cda == 0) {
+                                goto clear_rw_cp;
+                        }
+                        ccw->flags |= CCW_FLAG_CC;
+                }
+        }
 	ccw->flags &= ~(CCW_FLAG_DC | CCW_FLAG_CC);
 
 	rw_cp->device = device;
 	rw_cp->expires = 5 * TOD_MIN;		/* 5 minutes */
 	rw_cp->req = req;
 	check_then_set (&rw_cp->status, CQR_STATUS_EMPTY, CQR_STATUS_FILLED);
+        goto out;
+ clear_rw_cp:
+        dasd_free_request (rw_cp, device);
+        rw_cp = NULL;
+ out:
 	return rw_cp;
 }
 
+static int
+dasd_fba_fill_info (dasd_device_t * device, dasd_information_t * info)
+{
+	int rc = 0;
+	info->label_block = 1;
+	info->FBA_layout = 1;
+	info->characteristics_size = sizeof (dasd_fba_characteristics_t);
+	memcpy (info->characteristics,
+		&((dasd_fba_private_t *) device->private)->rdc_data,
+		sizeof (dasd_fba_characteristics_t));
+	info->confdata_size = 0;
+	return rc;
+}
+
+
 static char *
 dasd_fba_dump_sense (struct dasd_device_t *device, ccw_req_t * req)
 {
@@ -367,25 +392,26 @@
 	return page;
 }
 
-dasd_discipline_t dasd_fba_discipline =
-{
+dasd_discipline_t dasd_fba_discipline = {
+        owner: THIS_MODULE,
 	name:"FBA ",
 	ebcname:"FBA ",
-	max_blocks:((PAGE_SIZE >> 1)/sizeof(ccw1_t)-1),
+	max_blocks:((PAGE_SIZE >> 1) / sizeof (ccw1_t) - 1),
 	id_check:dasd_fba_id_check,
 	check_characteristics:dasd_fba_check_characteristics,
 	do_analysis:dasd_fba_do_analysis,
 	fill_geometry:dasd_fba_fill_geometry,
 	start_IO:dasd_start_IO,
+	term_IO:dasd_term_IO,
 	examine_error:dasd_fba_examine_error,
 	erp_action:dasd_fba_erp_action,
 	erp_postaction:dasd_fba_erp_postaction,
 	build_cp_from_req:dasd_fba_build_cp_from_req,
 	dump_sense:dasd_fba_dump_sense,
-	int_handler:dasd_int_handler
+	int_handler:dasd_int_handler,
+	fill_info:dasd_fba_fill_info,
 };
 
-
 int
 dasd_fba_init (void)
 {
@@ -393,18 +419,22 @@
 	printk (KERN_INFO PRINTK_HEADER
 		"%s discipline initializing\n", dasd_fba_discipline.name);
 	ASCEBC (dasd_fba_discipline.ebcname, 4);
-	dasd_discipline_enq (&dasd_fba_discipline);
-#ifdef CONFIG_DASD_DYNAMIC 
-        {
-            int i;
-            for (i = 0; i < sizeof (dasd_fba_known_devices) / sizeof (devreg_t); i++) {
-		printk (KERN_INFO PRINTK_HEADER
-			"We are interested in: CU %04X/%02x\n",
-			dasd_fba_known_devices[i].ci.hc.ctype,
-			dasd_fba_known_devices[i].ci.hc.cmode);
-		s390_device_register (&dasd_fba_known_devices[i]);
-            }
-        }
+	dasd_discipline_add (&dasd_fba_discipline);
+#ifdef CONFIG_DASD_DYNAMIC
+	{
+		int i;
+		for (i = 0;
+		     i < sizeof (dasd_fba_known_devices) / sizeof (devreg_t);
+		     i++) {
+			printk (KERN_INFO PRINTK_HEADER
+				"We are interested in: Dev %04X/%02X @ CU %04X/%02x\n",
+				dasd_fba_known_devices[i].ci.hc.dtype,
+				dasd_fba_known_devices[i].ci.hc.dmode,
+				dasd_fba_known_devices[i].ci.hc.ctype,
+				dasd_fba_known_devices[i].ci.hc.cmode);
+			s390_device_register (&dasd_fba_known_devices[i]);
+		}
+	}
 #endif				/* CONFIG_DASD_DYNAMIC */
         return rc;
 }
@@ -417,16 +447,31 @@
         {
 	int i;
         for ( i=0; i<sizeof(dasd_fba_known_devices)/sizeof(devreg_t); i++) {
-                printk (KERN_INFO PRINTK_HEADER
-                        "We were interested in: CU %04X/%02x\n",
-                        dasd_fba_known_devices[i].ci.hc.ctype,
-                        dasd_fba_known_devices[i].ci.hc.cmode);
                 s390_device_unregister(&dasd_fba_known_devices[i]);
         }
         }
 #endif /* CONFIG_DASD_DYNAMIC */
-        dasd_discipline_deq(&dasd_fba_discipline);
+        dasd_discipline_del(&dasd_fba_discipline);
+}
+
+#ifdef MODULE
+int
+init_module (void)
+{
+	int rc = 0;
+	rc = dasd_fba_init ();
+	return rc;
 }
+
+void
+cleanup_module (void)
+{
+	dasd_fba_cleanup ();
+	return;
+}
+#endif
+
+
 /*
  * Overrides for Emacs so that we follow Linus's tabbing style.
  * Emacs will notice this stuff at the end of the file and automatically
diff -u --recursive --new-file v2.4.7/linux/drivers/s390/block/dasd_fba.h linux/drivers/s390/block/dasd_fba.h
--- v2.4.7/linux/drivers/s390/block/dasd_fba.h	Tue Feb 13 14:13:44 2001
+++ linux/drivers/s390/block/dasd_fba.h	Sun Aug  5 13:12:41 2001
@@ -3,7 +3,7 @@
 #define DASD_FBA_H
 
 typedef
-struct DE_fba_data_t {
+    struct DE_fba_data_t {
 	struct {
 		unsigned char perm:2;	/* Permissions on this extent */
 		unsigned char zero:2;	/* Must be zero */
@@ -16,12 +16,12 @@
 	__u32 ext_loc;		/* Extent locator */
 	__u32 ext_beg;		/* logical number of block 0 in extent */
 	__u32 ext_end;		/* logocal number of last block in extent */
-} __attribute__ ((packed)) 
+} __attribute__ ((packed))
 
-DE_fba_data_t;
+    DE_fba_data_t;
 
 typedef
-struct LO_fba_data_t {
+    struct LO_fba_data_t {
 	struct {
 		unsigned char zero:4;
 		unsigned char cmd:4;
@@ -29,12 +29,12 @@
 	__u8 auxiliary;
 	__u16 blk_ct;
 	__u32 blk_nr;
-} __attribute__ ((packed)) 
+} __attribute__ ((packed))
 
-LO_fba_data_t;
+    LO_fba_data_t;
 
 typedef
-struct dasd_fba_characteristics_t {
+    struct dasd_fba_characteristics_t {
 	union {
 		__u8 c;
 		struct {
@@ -67,10 +67,10 @@
 	__u16 blk_ce;
 	__u32 reserved2;
 	__u16 reserved3;
-} __attribute__            ((packed)) 
+} __attribute__ ((packed))
 
-dasd_fba_characteristics_t;
+    dasd_fba_characteristics_t;
 
 int dasd_fba_init (void);
-void dasd_fba_cleanup(void);
+void dasd_fba_cleanup (void);
 #endif				/* DASD_FBA_H */
diff -u --recursive --new-file v2.4.7/linux/drivers/s390/block/dasd_int.h linux/drivers/s390/block/dasd_int.h
--- v2.4.7/linux/drivers/s390/block/dasd_int.h	Wed Dec 31 16:00:00 1969
+++ linux/drivers/s390/block/dasd_int.h	Sun Aug  5 13:12:41 2001
@@ -0,0 +1,390 @@
+/* 
+ * File...........: linux/drivers/s390/block/dasd.c
+ * Author(s)......: Holger Smolinski <Holger.Smolinski@de.ibm.com>
+ * Bugreports.to..: <Linux390@de.ibm.com>
+ * (C) IBM Corporation, IBM Deutschland Entwicklung GmbH, 1999,2000
+ *
+ * History of changes (starts July 2000)
+ * 02/01/01 added dynamic registration of ioctls
+ */
+
+#ifndef DASD_INT_H
+#define DASD_INT_H
+
+#define DASD_API_VERSION 0
+
+#include <asm/dasd.h>
+
+#define CONFIG_DASD_DYNAMIC
+
+typedef int(*dasd_ioctl_fn_t) (void *inp, int no, long args);
+int dasd_ioctl_no_register(struct module *, int no, dasd_ioctl_fn_t handler);
+int dasd_ioctl_no_unregister(struct module *, int no, dasd_ioctl_fn_t handler);
+
+#define DASD_NAME "dasd"
+#define DASD_PER_MAJOR ( 1U<<(MINORBITS-DASD_PARTN_BITS))
+
+
+#define DASD_FORMAT_INTENS_WRITE_RECZERO 0x01
+#define DASD_FORMAT_INTENS_WRITE_HOMEADR 0x02
+
+#define DASD_STATE_DEL   -1
+#define DASD_STATE_NEW    0
+#define DASD_STATE_KNOWN  1
+#define DASD_STATE_ACCEPT 2
+#define DASD_STATE_INIT   3
+#define DASD_STATE_READY  4
+#define DASD_STATE_ONLINE 5
+
+
+#define DASD_FORMAT_INTENS_WRITE_RECZERO 0x01
+#define DASD_FORMAT_INTENS_WRITE_HOMEADR 0x02
+#define DASD_FORMAT_INTENS_INVALIDATE    0x04
+#define DASD_FORMAT_INTENS_CDL 0x08
+#ifdef __KERNEL__
+#include <linux/module.h>
+#include <linux/version.h>
+#include <linux/major.h>
+#include <linux/wait.h>
+#include <linux/blk.h> 
+#if (LINUX_VERSION_CODE > KERNEL_VERSION(2,3,98))
+#include <linux/blkdev.h> 
+#include <linux/devfs_fs_kernel.h>
+#endif
+#include <linux/genhd.h>
+#include <linux/hdreg.h>
+#include <linux/compatmac.h>
+
+#include <asm/ccwcache.h>
+#include <asm/irq.h>
+#include <asm/s390dyn.h>
+#include <asm/todclk.h>
+#include <asm/debug.h>
+
+/* Kernel Version Compatibility section */
+#if (LINUX_VERSION_CODE < KERNEL_VERSION(2,3,98))
+typedef struct request *request_queue_t;
+#define block_device_operations file_operations
+#define __setup(x,y) struct dasd_device_t
+#define devfs_register_blkdev(major,name,ops) register_blkdev(major,name,ops)
+#define register_disk(dd,dev,partn,ops,size) \
+do { \
+	dd->sizes[MINOR(dev)] = size >> 1; \
+	resetup_one_dev(dd,MINOR(dev)>>DASD_PARTN_BITS); \
+} while(0)
+#define init_waitqueue_head(x) do { *x = NULL; } while(0)
+#define blk_cleanup_queue(x) do {} while(0)
+#define blk_init_queue(x...) do {} while(0)
+#define blk_queue_headactive(x...) do {} while(0)
+#define blk_queue_make_request(x) do {} while(0)
+#define list_empty(x) (0)
+#define INIT_BLK_DEV(d_major,d_request_fn,d_queue_fn,d_current) \
+do { \
+        blk_dev[d_major].request_fn = d_request_fn; \
+        blk_dev[d_major].queue = d_queue_fn; \
+        blk_dev[d_major].current_request = d_current; \
+} while(0)
+#define INIT_GENDISK(D_MAJOR,D_NAME,D_PARTN_BITS,D_PER_MAJOR) \
+	major:D_MAJOR, \
+	major_name:D_NAME, \
+	minor_shift:D_PARTN_BITS, \
+	max_p:1 << D_PARTN_BITS, \
+	max_nr:D_PER_MAJOR, \
+	nr_real:D_PER_MAJOR,
+static inline struct request * 
+dasd_next_request( request_queue_t *queue ) 
+{
+    return *queue;
+}
+static inline void 
+dasd_dequeue_request( request_queue_t * q, struct request *req )
+{
+        *q = req->next;
+        req->next = NULL;
+}
+#else
+#define INIT_BLK_DEV(d_major,d_request_fn,d_queue_fn,d_current) \
+do { \
+        blk_dev[d_major].queue = d_queue_fn; \
+} while(0)
+#define INIT_GENDISK(D_MAJOR,D_NAME,D_PARTN_BITS,D_PER_MAJOR) \
+	major:D_MAJOR, \
+	major_name:D_NAME, \
+	minor_shift:D_PARTN_BITS, \
+	max_p:1 << D_PARTN_BITS, \
+	nr_real:D_PER_MAJOR, \
+        fops:&dasd_device_operations, 
+static inline struct request * 
+dasd_next_request( request_queue_t *queue ) 
+{
+        return blkdev_entry_next_request(&queue->queue_head);
+}
+static inline void 
+dasd_dequeue_request( request_queue_t * q, struct request *req )
+{
+        blkdev_dequeue_request (req);
+}
+#endif
+
+/* dasd_range_t are used for dynamic device att-/detachment */
+typedef struct dasd_devreg_t {
+        devreg_t devreg; /* the devreg itself */
+        /* build a linked list of devregs, needed for cleanup */
+        struct list_head list;
+} dasd_devreg_t;
+
+typedef struct {
+	struct list_head list;
+	struct module *owner;
+	int no;
+	dasd_ioctl_fn_t handler;
+} dasd_ioctl_list_t;
+
+typedef enum {
+	dasd_era_fatal = -1,	/* no chance to recover              */
+	dasd_era_none = 0,	/* don't recover, everything alright */
+	dasd_era_msg = 1,	/* don't recover, just report...     */
+	dasd_era_recover = 2	/* recovery action recommended       */
+} dasd_era_t;
+
+/* BIT DEFINITIONS FOR SENSE DATA */
+#define DASD_SENSE_BIT_0 0x80
+#define DASD_SENSE_BIT_1 0x40
+#define DASD_SENSE_BIT_2 0x20
+#define DASD_SENSE_BIT_3 0x10
+
+#define check_then_set(where,from,to) \
+do { \
+        if ((*(where)) != (from) ) { \
+                printk (KERN_ERR PRINTK_HEADER "was %d\n", *(where)); \
+                BUG(); \
+        } \
+        (*(where)) = (to); \
+} while (0)
+
+#define DASD_MESSAGE(d_loglevel,d_device,d_string,d_args...)\
+do { \
+        int d_devno = d_device->devinfo.devno; \
+        int d_irq = d_device->devinfo.irq; \
+        char *d_name = d_device->name; \
+        int d_major = MAJOR(d_device->kdev); \
+        int d_minor = MINOR(d_device->kdev); \
+        printk(d_loglevel PRINTK_HEADER \
+               "/dev/%s(%d:%d),%04x@0x%x:" \
+               d_string "\n",d_name,d_major,d_minor,d_devno,d_irq,d_args ); \
+} while(0)
+
+/* 
+ * struct dasd_sizes_t
+ * represents all data needed to access dasd with properly set up sectors
+ */
+typedef
+struct dasd_sizes_t {
+	unsigned long blocks; /* size of volume in blocks */
+	unsigned int bp_block; /* bytes per block */
+	unsigned int s2b_shift; /* log2 (bp_block/512) */
+        unsigned int pt_block; /* from which block to read the partn table */
+} dasd_sizes_t;
+
+/* 
+ * struct dasd_chanq_t 
+ * represents a queue of channel programs related to a single device
+ */
+typedef
+struct dasd_chanq_t {
+	ccw_req_t *head;
+	ccw_req_t *tail;
+} dasd_chanq_t;
+
+#define DASD_DEVICE_FORMAT_STRING "Device: %p"
+#define DASD_DEVICE_DEBUG_EVENT(d_level, d_device, d_str, d_data...)\
+do {\
+        if ( d_device->debug_area != NULL )\
+        debug_sprintf_event(d_device->debug_area,d_level,\
+                    DASD_DEVICE_FORMAT_STRING d_str "\n",\
+                    d_device, d_data);\
+} while(0);
+#define DASD_DEVICE_DEBUG_EXCEPTION(d_level, d_device, d_str, d_data...)\
+do {\
+        if ( d_device->debug_area != NULL )\
+        debug_sprintf_exception(d_device->debug_area,d_level,\
+                        DASD_DEVICE_FORMAT_STRING d_str "\n",\
+                        d_device, d_data);\
+} while(0);
+
+#define DASD_DRIVER_FORMAT_STRING "Driver: <[%p]>"
+#define DASD_DRIVER_DEBUG_EVENT(d_level, d_fn, d_str, d_data...)\
+do {\
+        if ( dasd_debug_area != NULL )\
+        debug_sprintf_event(dasd_debug_area, d_level,\
+                    DASD_DRIVER_FORMAT_STRING #d_fn ":" d_str "\n",\
+                    d_fn, d_data);\
+} while(0);
+#define DASD_DRIVER_DEBUG_EXCEPTION(d_level, d_fn, d_str, d_data...)\
+do {\
+        if ( dasd_debug_area != NULL )\
+        debug_sprintf_exception(dasd_debug_area, d_level,\
+                        DASD_DRIVER_FORMAT_STRING #d_fn ":" d_str "\n",\
+                        d_fn, d_data);\
+} while(0);
+
+struct dasd_device_t;
+struct request;
+
+/* 
+ * signatures for the functions of dasd_discipline_t 
+ * make typecasts much easier
+ */
+typedef ccw_req_t *(*dasd_erp_action_fn_t) (ccw_req_t * cqr);
+typedef ccw_req_t *(*dasd_erp_postaction_fn_t) (ccw_req_t * cqr);
+
+typedef int (*dasd_ck_id_fn_t) (s390_dev_info_t *);
+typedef int (*dasd_ck_characteristics_fn_t) (struct dasd_device_t *);
+typedef int (*dasd_fill_geometry_fn_t) (struct dasd_device_t *, struct hd_geometry *);
+typedef ccw_req_t *(*dasd_format_fn_t) (struct dasd_device_t *, struct format_data_t *);
+typedef ccw_req_t *(*dasd_init_analysis_fn_t) (struct dasd_device_t *);
+typedef int (*dasd_do_analysis_fn_t) (struct dasd_device_t *);
+typedef int (*dasd_io_starter_fn_t) (ccw_req_t *);
+typedef int (*dasd_io_stopper_fn_t) (ccw_req_t *);
+typedef void (*dasd_int_handler_fn_t)(int irq, void *, struct pt_regs *);
+typedef dasd_era_t (*dasd_error_examine_fn_t) (ccw_req_t *, devstat_t * stat);
+typedef dasd_erp_action_fn_t (*dasd_error_analyse_fn_t) (ccw_req_t *);
+typedef dasd_erp_postaction_fn_t (*dasd_erp_analyse_fn_t) (ccw_req_t *);
+typedef ccw_req_t *(*dasd_cp_builder_fn_t)(struct dasd_device_t *,struct request *);
+typedef char *(*dasd_dump_sense_fn_t)(struct dasd_device_t *,ccw_req_t *);
+typedef ccw_req_t *(*dasd_reserve_fn_t)(struct dasd_device_t *);
+typedef ccw_req_t *(*dasd_release_fn_t)(struct dasd_device_t *);
+typedef ccw_req_t *(*dasd_merge_cp_fn_t)(struct dasd_device_t *);
+typedef int (*dasd_info_fn_t) (struct dasd_device_t *, dasd_information_t *);
+typedef int (*dasd_use_count_fn_t) (int);
+
+
+/*
+ * the dasd_discipline_t is
+ * sth like a table of virtual functions, if you think of dasd_eckd
+ * inheriting dasd...
+ * no, currently we are not planning to reimplement the driver in C++
+ */
+typedef struct dasd_discipline_t {
+        struct module *owner;
+	char ebcname[8]; /* a name used for tagging and printks */
+        char name[8];		/* a name used for tagging and printks */
+	int max_blocks;	/* maximum number of blocks to be chained */
+	dasd_ck_id_fn_t id_check;	/* to check sense data */
+	dasd_ck_characteristics_fn_t check_characteristics;	/* to check the characteristics */
+	dasd_init_analysis_fn_t init_analysis;	/* to start the analysis of the volume */
+	dasd_do_analysis_fn_t do_analysis;	/* to complete the analysis of the volume */
+	dasd_fill_geometry_fn_t fill_geometry;	/* to set up hd_geometry */
+	dasd_io_starter_fn_t start_IO;
+	dasd_io_stopper_fn_t term_IO;
+        dasd_format_fn_t format_device;		/* to format the device */
+	dasd_error_examine_fn_t examine_error;
+	dasd_error_analyse_fn_t erp_action;
+	dasd_erp_analyse_fn_t erp_postaction;
+        dasd_cp_builder_fn_t build_cp_from_req;
+        dasd_dump_sense_fn_t dump_sense;
+        dasd_int_handler_fn_t int_handler;
+        dasd_reserve_fn_t reserve;
+        dasd_release_fn_t release;
+        dasd_merge_cp_fn_t merge_cp;
+        dasd_info_fn_t fill_info;
+	struct list_head list;	/* used for list of disciplines */
+} dasd_discipline_t;
+
+#define DASD_DEFAULT_FEATURES 0
+#define DASD_FEATURE_READONLY 1
+
+/* dasd_range_t are used for ordering the DASD devices */
+typedef struct dasd_range_t {
+	unsigned int from;	/* first DASD in range */
+	unsigned int to;	/* last DASD in range */
+	char discipline[4];	/* placeholder to force discipline */
+        int features;
+	struct list_head list;	/* next one in linked list */
+} dasd_range_t;
+
+
+
+#define DASD_MAJOR_INFO_REGISTERED 1
+#define DASD_MAJOR_INFO_IS_STATIC 2
+
+typedef struct major_info_t {
+	struct list_head list;
+	struct dasd_device_t **dasd_device;
+	int flags;
+	struct gendisk gendisk; /* actually contains the major number */
+} __attribute__ ((packed)) major_info_t;
+
+typedef struct dasd_device_t {
+	s390_dev_info_t devinfo;
+	dasd_discipline_t *discipline;
+	int level;
+        atomic_t open_count;
+        kdev_t kdev;
+        major_info_t *major_info;
+	struct dasd_chanq_t queue;
+        wait_queue_head_t wait_q;
+        request_queue_t *request_queue;
+        struct timer_list timer;      
+	devstat_t dev_status; /* needed ONLY!! for request_irq */
+        dasd_sizes_t sizes;
+        char name[16]; /* The name of the device in /dev */
+	char *private;	/* to be used by the discipline internally */
+#if (LINUX_VERSION_CODE > KERNEL_VERSION(2,3,98))
+        devfs_handle_t devfs_entry;
+#endif /* LINUX_IS_24 */
+	struct tq_struct bh_tq;
+        atomic_t bh_scheduled;
+        debug_info_t *debug_area;
+        dasd_profile_info_t profile;
+        ccw_req_t *init_cqr;
+        atomic_t plugged;
+        void* lowmem_cqr;
+        void* lowmem_ccws;
+        void* lowmem_idals;
+        void* lowmem_idal_ptr;
+}  dasd_device_t;
+
+int dasd_init (void);
+void dasd_discipline_add(dasd_discipline_t *);
+void dasd_discipline_del(dasd_discipline_t *);
+int dasd_start_IO (ccw_req_t *);
+int dasd_term_IO (ccw_req_t *);
+void dasd_int_handler (int , void *, struct pt_regs *);
+ccw_req_t *dasd_default_erp_action (ccw_req_t *);
+ccw_req_t *dasd_default_erp_postaction (ccw_req_t *);
+inline void dasd_chanq_deq (dasd_chanq_t *, ccw_req_t *);
+inline void dasd_chanq_enq (dasd_chanq_t *, ccw_req_t *);
+inline void dasd_chanq_enq_head (dasd_chanq_t *, ccw_req_t *);
+ccw_req_t *dasd_alloc_request (char *, int, int, dasd_device_t *);
+void dasd_free_request (ccw_req_t *, dasd_device_t *);
+int dasd_oper_handler (int irq, devreg_t * devreg);
+void dasd_schedule_bh (dasd_device_t *);
+int dasd_sleep_on_req(ccw_req_t*);
+int  dasd_set_normalized_cda ( ccw1_t * cp, unsigned long address, ccw_req_t* request, dasd_device_t* device );
+
+extern debug_info_t *dasd_debug_area;
+extern int (*genhd_dasd_name) (char *, int, int, struct gendisk *);
+
+#endif /* __KERNEL__ */
+
+#endif				/* DASD_H */
+
+/*
+ * Overrides for Emacs so that we follow Linus's tabbing style.
+ * Emacs will notice this stuff at the end of the file and automatically
+ * adjust the settings for this buffer only.  This must remain at the end
+ * of the file.
+ * ---------------------------------------------------------------------------
+ * Local variables:
+ * c-indent-level: 4 
+ * c-brace-imaginary-offset: 0
+ * c-brace-offset: -4
+ * c-argdecl-indent: 4
+ * c-label-offset: -4
+ * c-continued-statement-offset: 4
+ * c-continued-brace-offset: 0
+ * indent-tabs-mode: nil
+ * tab-width: 8
+ * End:
+ */
diff -u --recursive --new-file v2.4.7/linux/drivers/s390/block/xpram.c linux/drivers/s390/block/xpram.c
--- v2.4.7/linux/drivers/s390/block/xpram.c	Wed Apr 11 19:02:28 2001
+++ linux/drivers/s390/block/xpram.c	Wed Jul 25 14:12:02 2001
@@ -74,7 +74,7 @@
 #endif /* V24 */
 #include <linux/sched.h>
 #include <linux/kernel.h> /* printk() */
-#include <linux/malloc.h> /* kmalloc() */
+#include <linux/slab.h> /* kmalloc() */
 #if (XPRAM_VERSION == 24)
 #  include <linux/devfs_fs_kernel.h>
 #endif /* V24 */
@@ -92,6 +92,7 @@
 #if (XPRAM_VERSION == 24)
 #define MAJOR_NR xpram_major /* force definitions on in blk.h */
 int xpram_major;   /* must be declared before including blk.h */
+devfs_handle_t xpram_devfs_handle;
 
 #define DEVICE_NR(device) MINOR(device)   /* xpram has no partition bits */
 #define DEVICE_NAME "xpram"               /* name for messaging */
@@ -999,12 +1000,18 @@
 #elif (XPRAM_VERSION == 24)
 	result = devfs_register_blkdev(xpram_major, "xpram", &xpram_devops);
 #endif /* V22/V24 */
-	
 	if (result < 0) {
 		PRINT_ERR("Can't get major %d\n",xpram_major);
                 PRINT_ERR("Giving up xpram\n");
 		return result;
 	}
+#if (XPRAM_VERSION == 24)
+	xpram_devfs_handle = devfs_mk_dir (NULL, "slram", NULL);
+	devfs_register_series (xpram_devfs_handle, "%u", XPRAM_MAX_DEVS,
+			       DEVFS_FL_DEFAULT, XPRAM_MAJOR, 0,
+			       S_IFBLK | S_IRUSR | S_IWUSR,
+			       &xpram_devops, NULL);
+#endif /* V22/V24 */
 	if (xpram_major == 0) xpram_major = result; /* dynamic */
 	major = xpram_major; /* Use `major' later on to save typing */
 
@@ -1226,6 +1233,12 @@
 	kfree(xpram_offsets);
 
 				/* finally, the usual cleanup */
+#if (XPRAM_VERSION == 22)
 	unregister_blkdev(major, "xpram");
+#elif (XPRAM_VERSION == 24)
+	devfs_unregister(xpram_devfs_handle);
+	if (devfs_unregister_blkdev(MAJOR_NR, "xpram"))
+		printk(KERN_WARNING "xpram: cannot unregister blkdev\n");
+#endif /* V22/V24 */
 	kfree(xpram_devices);
 }
diff -u --recursive --new-file v2.4.7/linux/drivers/s390/ccwcache.c linux/drivers/s390/ccwcache.c
--- v2.4.7/linux/drivers/s390/ccwcache.c	Wed Apr 11 19:02:28 2001
+++ linux/drivers/s390/ccwcache.c	Wed Jul 25 14:12:02 2001
@@ -10,7 +10,7 @@
  */
 
 #include <linux/module.h>
-#include <linux/malloc.h>
+#include <linux/slab.h>
 #include <linux/version.h>
 
 #if (LINUX_VERSION_CODE > KERNEL_VERSION(2,3,98))
diff -u --recursive --new-file v2.4.7/linux/drivers/s390/char/Makefile linux/drivers/s390/char/Makefile
--- v2.4.7/linux/drivers/s390/char/Makefile	Wed Apr 11 19:02:29 2001
+++ linux/drivers/s390/char/Makefile	Wed Jul 25 14:12:02 2001
@@ -1,42 +1,33 @@
-# Makefile for the S/390 supported character devices
 #
-# 4 January 2001 Richard Hitt
-# Modeled after similar files of Michael Elizabeth Chastain
-# Rewritten to use lists instead of if-statements.
+# S/390 character devices
+#
 
-O_TARGET	:= s390-char.o
+O_TARGET := s390-char.o
 
-export-objs     :=
 list-multi	:= tub3270.o tape390.o
 
-obj-y		:=
-obj-m		:=
-obj-n		:=
-obj-		:=
-
-tub3270-objs			:= tuball.o tubfs.o tubtty.o \
-					tubttyaid.o tubttybld.o tubttyrcl.o \
-					tubttyscl.o tubttysiz.o
+tub3270-objs := tuball.o tubfs.o tubtty.o \
+                     tubttyaid.o tubttybld.o tubttyscl.o \
+                     tubttyrcl.o tubttysiz.o
+
+tape390-$(CONFIG_S390_TAPE_CHAR) += tapechar.o
+tape390-$(CONFIG_S390_TAPE_BLOCK) += tapeblock.o
+tape390-$(CONFIG_S390_TAPE_3480) += tape3480.o tape34xx.o
+tape390-$(CONFIG_S390_TAPE_3490) += tape3490.o tape34xx.o
+tape390-objs := tape.o $(sort $(tape390-y))
 
 obj-y += ctrlchar.o
-obj-$(CONFIG_3215_CONSOLE)	+= con3215.o
-obj-$(CONFIG_HWC)		+= hwc_con.o hwc_rw.o hwc_tty.o
-obj-$(CONFIG_3270)		+= tub3270.o
-
-tape-y				:= tape.o
-tape-$(CONFIG_S390_TAPE_CHAR)	+= tapechar.o
-tape-$(CONFIG_S390_TAPE_BLOCK)	+= tapeblock.o
-tape-$(CONFIG_S390_TAPE_3480)	+= tape3480.o tape34xx.o
-tape-$(CONFIG_S390_TAPE_3490)	+= tape3490.o tape34xx.o
-tape390-objs			:= $(sort $(tape-y))
-obj-$(CONFIG_S390_TAPE)		+= tape390.o
-
-# Hand off to Rules.make.
+obj-$(CONFIG_TN3215) += con3215.o
+obj-$(CONFIG_HWC) += hwc_con.o hwc_rw.o hwc_tty.o
+obj-$(CONFIG_HWC_CPI) += hwc_cpi.o
+obj-$(CONFIG_TN3270) += tub3270.o
+obj-$(CONFIG_S390_TAPE) += tape390.o
 
 include $(TOPDIR)/Rules.make
 
-tub3270.o:	$(tub3270-objs)
+tub3270.o: $(tub3270-objs)
 	$(LD) -r -o $@ $(tub3270-objs)
 
-tape390.o:	$(tape390-objs)
+tape390.o: $(tape390-objs)
 	$(LD) -r -o $@ $(tape390-objs)
+
diff -u --recursive --new-file v2.4.7/linux/drivers/s390/char/con3215.c linux/drivers/s390/char/con3215.c
--- v2.4.7/linux/drivers/s390/char/con3215.c	Wed Apr 11 19:02:29 2001
+++ linux/drivers/s390/char/con3215.c	Wed Jul 25 14:12:02 2001
@@ -30,6 +30,7 @@
 #include <asm/delay.h>
 #include <asm/cpcmd.h>
 #include <asm/irq.h>
+#include <asm/setup.h>
 
 #include "ctrlchar.h"
 
@@ -115,18 +116,6 @@
 #define MIN(a,b)	((a) < (b) ? (a) : (b))
 #endif
 
-static int __init con3215_setup(char *str)
-{
-        int vdev;
-
-        vdev = simple_strtoul(str,&str,0);
-        if (vdev >= 0 && vdev < 65536)
-                raw3215_condevice = vdev;
-        return 1;
-}
-
-__setup("condev=", con3215_setup);
-
 /*
  * Get a request structure from the free list
  */
@@ -765,7 +754,7 @@
         while (count <= number && irq != -ENODEV) {
                 if (get_dev_info(irq, &dinfo) == -ENODEV)
                         break;
-                if (dinfo.devno == raw3215_condevice ||
+                if (dinfo.devno == console_device ||
                     dinfo.sid_data.cu_type == 0x3215) {
                         count++;
                     if (count > number)
@@ -776,7 +765,7 @@
         return -1;            /* console not found */
 }
 
-#ifdef CONFIG_3215_CONSOLE
+#ifdef CONFIG_TN3215_CONSOLE
 
 /*
  * Write a string to the 3215 console
@@ -1070,14 +1059,19 @@
 {
 	raw3215_info *raw;
 	raw3215_req *req;
+	int irq;
 	int i;
 
-	if (!MACHINE_IS_VM && !MACHINE_IS_P390)
-                return;
-        if (MACHINE_IS_VM) {
-	        cpcmd("TERM CONMODE 3215", NULL, 0);
-	        cpcmd("TERM AUTOCR OFF", NULL, 0);
-        }
+	/* Check if 3215 is to be the console */
+	if (!CONSOLE_IS_3215)
+		return;
+	irq = raw3215_find_dev(0);
+
+	/* Set the console mode for VM */
+	if (MACHINE_IS_VM) {
+		cpcmd("TERM CONMODE 3215", NULL, 0);
+		cpcmd("TERM AUTOCR OFF", NULL, 0);
+	}
 
 	/* allocate 3215 request structures */
 	raw3215_freelist = NULL;
@@ -1090,7 +1084,7 @@
 
 	ctrlchar_init();
 
-#ifdef CONFIG_3215_CONSOLE
+#ifdef CONFIG_TN3215_CONSOLE
         raw3215[0] = raw = (raw3215_info *)
                 alloc_bootmem_low(sizeof(raw3215_info));
 	memset(raw, 0, sizeof(raw3215_info));
@@ -1126,8 +1120,6 @@
  */
 void __init tty3215_init(void)
 {
-	if (!MACHINE_IS_VM && !MACHINE_IS_P390)
-                return;
 	/*
 	 * Initialize the tty_driver structure
 	 * Entries in tty3215_driver that are NOT initialized:
diff -u --recursive --new-file v2.4.7/linux/drivers/s390/char/ctrlchar.c linux/drivers/s390/char/ctrlchar.c
--- v2.4.7/linux/drivers/s390/char/ctrlchar.c	Wed Apr 11 19:02:29 2001
+++ linux/drivers/s390/char/ctrlchar.c	Wed Jul 25 14:12:02 2001
@@ -1,5 +1,5 @@
 /*
- *  drivers/s390/char/controlchar.c
+ *  drivers/s390/char/ctrlchar.c
  *  Unified handling of special chars.
  *
  *    Copyright (C) 2001 IBM Deutschland Entwicklung GmbH, IBM Corporation
diff -u --recursive --new-file v2.4.7/linux/drivers/s390/char/ctrlchar.h linux/drivers/s390/char/ctrlchar.h
--- v2.4.7/linux/drivers/s390/char/ctrlchar.h	Thu Apr 12 12:16:35 2001
+++ linux/drivers/s390/char/ctrlchar.h	Wed Jul 25 14:12:02 2001
@@ -1,5 +1,5 @@
 /*
- *  drivers/s390/char/controlchar.c
+ *  drivers/s390/char/ctrlchar.c
  *  Unified handling of special chars.
  *
  *    Copyright (C) 2001 IBM Deutschland Entwicklung GmbH, IBM Corporation
@@ -7,6 +7,7 @@
  *
  */
 
+#include <linux/config.h>
 #include <linux/types.h>
 #include <linux/tty.h>
 
diff -u --recursive --new-file v2.4.7/linux/drivers/s390/char/hwc.h linux/drivers/s390/char/hwc.h
--- v2.4.7/linux/drivers/s390/char/hwc.h	Wed Apr 11 19:02:29 2001
+++ linux/drivers/s390/char/hwc.h	Wed Jul 25 14:12:02 2001
@@ -4,7 +4,7 @@
  *
  *  S390 version
  *    Copyright (C) 1999 IBM Deutschland Entwicklung GmbH, IBM Corporation
- *    Author(s): Martin Peschke <peschke@fh-brandenburg.de>
+ *    Author(s): Martin Peschke <mpeschke@de.ibm.com>
  *
  * 
  * 
@@ -13,17 +13,22 @@
 #ifndef __HWC_H__
 #define __HWC_H__
 
+#define HWC_EXT_INT_PARAM_ADDR	0xFFFFFFF8
+#define HWC_EXT_INT_PARAM_PEND 0x00000001
+
 #define ET_OpCmd		0x01
 #define ET_Msg		0x02
 #define ET_StateChange	0x08
 #define ET_PMsgCmd		0x09
 #define ET_CntlProgOpCmd	0x20
+#define ET_CntlProgIdent	0x0B
 
 #define ET_OpCmd_Mask	0x80000000
 #define ET_Msg_Mask		0x40000000
 #define ET_StateChange_Mask	0x01000000
 #define ET_PMsgCmd_Mask	0x00800000
 #define ET_CtlProgOpCmd_Mask	0x00000001
+#define ET_CtlProgIdent_Mask	0x00200000
 
 #define GMF_DOM		0x8000
 #define GMF_SndAlrm	0x4000
@@ -210,7 +215,7 @@
 	0x0000,
 	sizeof (_hwcb_mask_t),
 	ET_OpCmd_Mask | ET_PMsgCmd_Mask | ET_StateChange_Mask,
-	ET_Msg_Mask | ET_PMsgCmd_Mask
+	ET_Msg_Mask | ET_PMsgCmd_Mask | ET_CtlProgIdent_Mask
 };
 
 typedef struct {
diff -u --recursive --new-file v2.4.7/linux/drivers/s390/char/hwc_con.c linux/drivers/s390/char/hwc_con.c
--- v2.4.7/linux/drivers/s390/char/hwc_con.c	Wed Apr 11 19:02:29 2001
+++ linux/drivers/s390/char/hwc_con.c	Wed Jul 25 14:12:02 2001
@@ -4,7 +4,7 @@
  *
  *  S390 version
  *    Copyright (C) 1999 IBM Deutschland Entwicklung GmbH, IBM Corporation
- *    Author(s): Martin Peschke <peschke@fh-brandenburg.de>
+ *    Author(s): Martin Peschke <mpeschke@de.ibm.com>
  */
 
 #include <linux/config.h>
@@ -17,7 +17,6 @@
 #include <linux/fs.h>
 #include <linux/init.h>
 
-#include "ctrlchar.h"
 #include "hwc_rw.h"
 
 #ifdef CONFIG_HWC_CONSOLE
@@ -82,20 +81,14 @@
 void __init 
 hwc_console_init (void)
 {
-
-#if defined(CONFIG_3215_CONSOLE) || defined(CONFIG_3270_CONSOLE)
-	if (MACHINE_IS_VM)
-		return;
-#endif
-	if (MACHINE_IS_P390)
+	if (!MACHINE_HAS_HWC)
 		return;
 
-	ctrlchar_init ();
-  
 	if (hwc_init () == 0) {
 #ifdef CONFIG_HWC_CONSOLE
 
-		register_console (&hwc_console);
+		if (CONSOLE_IS_HWC)
+			register_console (&hwc_console);
 #endif
 	} else
 		panic (HWC_CON_PRINT_HEADER "hwc initialisation failed !");
diff -u --recursive --new-file v2.4.7/linux/drivers/s390/char/hwc_cpi.c linux/drivers/s390/char/hwc_cpi.c
--- v2.4.7/linux/drivers/s390/char/hwc_cpi.c	Wed Dec 31 16:00:00 1969
+++ linux/drivers/s390/char/hwc_cpi.c	Wed Jul 25 14:12:02 2001
@@ -0,0 +1,199 @@
+
+/*
+ * Author: Martin Peschke <mpeschke@de.ibm.com>
+ * Copyright (C) 2001 IBM Entwicklung GmbH, IBM Corporation
+ */
+
+#include <linux/string.h>
+#include <linux/ctype.h>
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/errno.h>
+#include <linux/malloc.h>
+#include <linux/version.h>
+#include <asm/semaphore.h>
+#include <asm/ebcdic.h>
+#include "hwc_rw.h"
+#include "hwc.h"
+
+#define CPI_LENGTH_SYSTEM_TYPE	8
+#define CPI_LENGTH_SYSTEM_NAME	8
+#define CPI_LENGTH_SYSPLEX_NAME	8
+
+typedef struct {
+	_EBUF_HEADER
+	u8 id_format;
+	u8 reserved0;
+	u8 system_type[CPI_LENGTH_SYSTEM_TYPE];
+	u64 reserved1;
+	u8 system_name[CPI_LENGTH_SYSTEM_NAME];
+	u64 reserved2;
+	u64 system_level;
+	u64 reserved3;
+	u8 sysplex_name[CPI_LENGTH_SYSPLEX_NAME];
+	u8 reserved4[16];
+} __attribute__ ((packed)) 
+
+cpi_evbuf_t;
+
+typedef struct _cpi_hwcb_t {
+	_HWCB_HEADER
+	cpi_evbuf_t cpi_evbuf;
+} __attribute__ ((packed)) 
+
+cpi_hwcb_t;
+
+cpi_hwcb_t *cpi_hwcb;
+
+static int __init cpi_module_init (void);
+static void __exit cpi_module_exit (void);
+
+module_init (cpi_module_init);
+module_exit (cpi_module_exit);
+
+MODULE_AUTHOR (
+		      "Martin Peschke, IBM Deutschland Entwicklung GmbH "
+		      "<mpeschke@de.ibm.com>");
+
+MODULE_DESCRIPTION (
+  "identify this operating system instance to the S/390 or zSeries hardware");
+
+static char *system_name = NULL;
+MODULE_PARM (system_name, "s");
+MODULE_PARM_DESC (system_name, "e.g. hostname - max. 8 characters");
+
+static char *sysplex_name = NULL;
+#ifdef ALLOW_SYSPLEX_NAME
+MODULE_PARM (sysplex_name, "s");
+MODULE_PARM_DESC (sysplex_name, "if applicable - max. 8 characters");
+#endif
+
+static char *system_type = "LINUX";
+
+hwc_request_t cpi_request =
+{};
+
+hwc_callback_t cpi_callback;
+
+static DECLARE_MUTEX_LOCKED (sem);
+
+static int __init 
+cpi_module_init (void)
+{
+	int retval;
+	int system_type_length;
+	int system_name_length;
+	int sysplex_name_length = 0;
+
+	if (!MACHINE_HAS_HWC) {
+		printk ("cpi: bug: hardware console not present\n");
+		retval = -EINVAL;
+		goto out;
+	}
+	if (!system_type) {
+		printk ("cpi: bug: no system type specified\n");
+		retval = -EINVAL;
+		goto out;
+	}
+	system_type_length = strlen (system_type);
+	if (system_type_length > CPI_LENGTH_SYSTEM_NAME) {
+		printk ("cpi: bug: system type has length of %i characters - "
+			"only %i characters supported\n",
+			system_type_length,
+			CPI_LENGTH_SYSTEM_TYPE);
+		retval = -EINVAL;
+		goto out;
+	}
+	if (!system_name) {
+		printk ("cpi: no system name specified\n");
+		retval = -EINVAL;
+		goto out;
+	}
+	system_name_length = strlen (system_name);
+	if (system_name_length > CPI_LENGTH_SYSTEM_NAME) {
+		printk ("cpi: system name has length of %i characters - "
+			"only %i characters supported\n",
+			system_name_length,
+			CPI_LENGTH_SYSTEM_NAME);
+		retval = -EINVAL;
+		goto out;
+	}
+	if (sysplex_name) {
+		sysplex_name_length = strlen (sysplex_name);
+		if (sysplex_name_length > CPI_LENGTH_SYSPLEX_NAME) {
+			printk ("cpi: sysplex name has length of %i characters - "
+				"only %i characters supported\n",
+				sysplex_name_length,
+				CPI_LENGTH_SYSPLEX_NAME);
+			retval = -EINVAL;
+			goto out;
+		}
+	}
+	cpi_hwcb = kmalloc (sizeof (cpi_hwcb_t), GFP_KERNEL);
+	if (!cpi_hwcb) {
+		printk ("cpi: no storage to fulfill request\n");
+		retval = -ENOMEM;
+		goto out;
+	}
+	memset (cpi_hwcb, 0, sizeof (cpi_hwcb_t));
+
+	cpi_hwcb->length = sizeof (cpi_hwcb_t);
+	cpi_hwcb->cpi_evbuf.length = sizeof (cpi_evbuf_t);
+	cpi_hwcb->cpi_evbuf.type = 0x0B;
+
+	memset (cpi_hwcb->cpi_evbuf.system_type, ' ', CPI_LENGTH_SYSTEM_TYPE);
+	memcpy (cpi_hwcb->cpi_evbuf.system_type, system_type, system_type_length);
+	HWC_ASCEBC_STR (cpi_hwcb->cpi_evbuf.system_type, CPI_LENGTH_SYSTEM_TYPE);
+	EBC_TOUPPER (cpi_hwcb->cpi_evbuf.system_type, CPI_LENGTH_SYSTEM_TYPE);
+
+	memset (cpi_hwcb->cpi_evbuf.system_name, ' ', CPI_LENGTH_SYSTEM_NAME);
+	memcpy (cpi_hwcb->cpi_evbuf.system_name, system_name, system_name_length);
+	HWC_ASCEBC_STR (cpi_hwcb->cpi_evbuf.system_name, CPI_LENGTH_SYSTEM_NAME);
+	EBC_TOUPPER (cpi_hwcb->cpi_evbuf.system_name, CPI_LENGTH_SYSTEM_NAME);
+
+	cpi_hwcb->cpi_evbuf.system_level = LINUX_VERSION_CODE;
+
+	if (sysplex_name) {
+		memset (cpi_hwcb->cpi_evbuf.sysplex_name, ' ', CPI_LENGTH_SYSPLEX_NAME);
+		memcpy (cpi_hwcb->cpi_evbuf.sysplex_name, sysplex_name, sysplex_name_length);
+		HWC_ASCEBC_STR (cpi_hwcb->cpi_evbuf.sysplex_name, CPI_LENGTH_SYSPLEX_NAME);
+		EBC_TOUPPER (cpi_hwcb->cpi_evbuf.sysplex_name, CPI_LENGTH_SYSPLEX_NAME);
+	}
+	cpi_request.block = cpi_hwcb;
+	cpi_request.word = HWC_CMDW_WRITEDATA;
+	cpi_request.callback = cpi_callback;
+
+	retval = hwc_send (&cpi_request);
+	if (retval) {
+		printk ("cpi: failed (%i)\n", retval);
+		goto free;
+	}
+	down (&sem);
+
+	switch (cpi_hwcb->response_code) {
+	case 0x0020:
+		printk ("cpi: succeeded\n");
+		break;
+	default:
+		printk ("cpi: failed with response code 0x%x\n",
+			cpi_hwcb->response_code);
+	}
+
+      free:
+	kfree (cpi_hwcb);
+
+      out:
+	return retval;
+}
+
+static void __exit 
+cpi_module_exit (void)
+{
+	printk ("cpi: exit\n");
+}
+
+void 
+cpi_callback (hwc_request_t * req)
+{
+	up (&sem);
+}
diff -u --recursive --new-file v2.4.7/linux/drivers/s390/char/hwc_rw.c linux/drivers/s390/char/hwc_rw.c
--- v2.4.7/linux/drivers/s390/char/hwc_rw.c	Wed Apr 11 19:02:29 2001
+++ linux/drivers/s390/char/hwc_rw.c	Wed Jul 25 14:12:02 2001
@@ -4,7 +4,7 @@
  *
  *  S390 version
  *    Copyright (C) 1999 IBM Deutschland Entwicklung GmbH, IBM Corporation
- *    Author(s): Martin Peschke <peschke@fh-brandenburg.de>
+ *    Author(s): Martin Peschke <mpeschke@de.ibm.com>
  *
  * 
  *
@@ -20,6 +20,7 @@
 #include <linux/mm.h>
 #include <linux/timer.h>
 #include <linux/bootmem.h>
+#include <linux/module.h>
 
 #include <asm/ebcdic.h>
 #include <asm/uaccess.h>
@@ -28,28 +29,25 @@
 #include <asm/setup.h>
 #include <asm/page.h>
 #include <asm/s390_ext.h>
+#include <asm/irq.h>
 
 #ifndef MIN
 #define MIN(a,b) (((a<b) ? a : b))
 #endif
 
-#define HWC_ASCEBC(x) ((MACHINE_IS_VM ? _ascebc[x] : _ascebc_500[x]))
-
-#define HWC_EBCASC_STR(s,c) ((MACHINE_IS_VM ? EBCASC(s,c) : EBCASC_500(s,c)))
-
 #define HWC_RW_PRINT_HEADER "hwc low level driver: "
 
 #define  USE_VM_DETECTION
 
 #define  DEFAULT_CASE_DELIMITER '%'
 
-#define DUMP_HWC_INIT_ERROR
+#undef DUMP_HWC_INIT_ERROR
 
-#define DUMP_HWC_WRITE_ERROR
+#undef DUMP_HWC_WRITE_ERROR
 
-#define DUMP_HWC_WRITE_LIST_ERROR
+#undef DUMP_HWC_WRITE_LIST_ERROR
 
-#define DUMP_HWC_READ_ERROR
+#undef DUMP_HWC_READ_ERROR
 
 #undef DUMP_HWCB_INPUT
 
@@ -179,6 +177,8 @@
 
 	hwc_high_level_calls_t *calls;
 
+	hwc_request_t *request;
+
 	spinlock_t lock;
 
 	struct timer_list write_timer;
@@ -222,6 +222,7 @@
 	    0,
 	    0,
 	    0,
+	    NULL,
 	    NULL
 
 };
@@ -327,15 +328,15 @@
 	return condition_code;
 }
 
-static inline unsigned char *
-ext_int_param (void)
+static inline unsigned long 
+hwc_ext_int_param (void)
 {
 	u32 param;
 
 	__asm__ __volatile__ ("L %0,128\n\t"
 			      :"=r" (param));
 
-	return ((unsigned char *) param);
+	return (unsigned long) param;
 }
 
 static int 
@@ -417,11 +418,11 @@
 		internal_print (
 				       DELAYED_WRITE,
 				       HWC_RW_PRINT_HEADER
-			"found invalid HWCB at address 0x%x. List corrupted. "
+		       "found invalid HWCB at address 0x%lx. List corrupted. "
 			   "Lost %i HWCBs with %i characters within up to %i "
 			   "messages. Saved %i HWCB with last %i characters i"
 				       "within up to %i messages.\n",
-				       (unsigned int) bad_addr,
+				       (unsigned long) bad_addr,
 				       lost_hwcb, lost_char, lost_msg,
 				       hwc_data.hwcb_count,
 				       ALL_HWCB_CHAR, ALL_HWCB_MTO);
@@ -747,24 +748,22 @@
 }
 
 static int 
-write_event_data_2 (void)
+write_event_data_2 (u32 ext_int_param)
 {
 	write_hwcb_t *hwcb;
 	int retval = 0;
 
 #ifdef DUMP_HWC_WRITE_ERROR
-	unsigned char *param;
-
-	param = ext_int_param ();
-	if (param != hwc_data.current_hwcb) {
+	if ((ext_int_param & HWC_EXT_INT_PARAM_ADDR)
+	    != (unsigned long) hwc_data.current_hwcb) {
 		internal_print (
 				       DELAYED_WRITE,
 				       HWC_RW_PRINT_HEADER
-				       "write_event_mask_2 : "
+				       "write_event_data_2 : "
 				       "HWCB address does not fit "
-				       "(expected: 0x%x, got: 0x%x).\n",
-				       hwc_data.current_hwcb,
-				       param);
+				       "(expected: 0x%lx, got: 0x%lx).\n",
+				       (unsigned long) hwc_data.current_hwcb,
+				       ext_int_param);
 		return -EINVAL;
 	}
 #endif
@@ -1707,7 +1706,7 @@
 }
 
 static int 
-unconditional_read_2 (void)
+unconditional_read_2 (u32 ext_int_param)
 {
 	read_hwcb_t *hwcb = (read_hwcb_t *) hwc_data.page;
 
@@ -1844,7 +1843,7 @@
 }
 
 static int 
-write_event_mask_2 (void)
+write_event_mask_2 (u32 ext_int_param)
 {
 	init_hwcb_t *hwcb = (init_hwcb_t *) hwc_data.page;
 	int retval = 0;
@@ -1991,7 +1990,7 @@
 	return retval;
 }
 
-void do_hwc_interrupt (struct pt_regs *regs, __u16 code);
+void hwc_interrupt_handler (struct pt_regs *regs, __u16 code);
 
 int 
 hwc_init (void)
@@ -2005,7 +2004,7 @@
 
 #endif
 
-	if (register_external_interrupt (0x2401, do_hwc_interrupt) != 0)
+	if (register_external_interrupt (0x2401, hwc_interrupt_handler) != 0)
 		panic ("Couldn't request external interrupts 0x2401");
 
 	spin_lock_init (&hwc_data.lock);
@@ -2083,60 +2082,161 @@
 	return 0;
 }
 
+int 
+hwc_send (hwc_request_t * req)
+{
+	unsigned long flags;
+	int retval;
+	int cc;
+
+	spin_lock_irqsave (&hwc_data.lock, flags);
+	if (!req || !req->callback || !req->block) {
+		retval = -EINVAL;
+		goto unlock;
+	}
+	if (hwc_data.request) {
+		retval = -ENOTSUPP;
+		goto unlock;
+	}
+	hwc_data.request = req;
+	cc = service_call (req->word, req->block);
+	switch (cc) {
+	case 0:
+		hwc_data.current_servc = req->word;
+		hwc_data.current_hwcb = req->block;
+		retval = 0;
+		break;
+	case 2:
+		retval = -EBUSY;
+		break;
+	default:
+		retval = -ENOSYS;
+
+	}
+      unlock:
+	spin_unlock_irqrestore (&hwc_data.lock, flags);
+	return retval;
+}
+
+EXPORT_SYMBOL (hwc_send);
+
 void 
-do_hwc_interrupt (struct pt_regs *regs, __u16 code)
+do_hwc_callback (u32 ext_int_param)
 {
+	if (!hwc_data.request || !hwc_data.request->callback)
+		return;
+	if ((ext_int_param & HWC_EXT_INT_PARAM_ADDR)
+	    != (unsigned long) hwc_data.request->block)
+		return;
+	hwc_data.request->callback (hwc_data.request);
+	hwc_data.request = NULL;
+	hwc_data.current_hwcb = NULL;
+	hwc_data.current_servc = 0;
+}
 
-	if (hwc_data.flags & HWC_INIT) {
+void 
+hwc_do_interrupt (u32 ext_int_param)
+{
+	u32 finished_hwcb = ext_int_param & HWC_EXT_INT_PARAM_ADDR;
+	u32 evbuf_pending = ext_int_param & HWC_EXT_INT_PARAM_PEND;
 
-		hwc_data.flags |= HWC_INTERRUPT;
-	} else if (hwc_data.flags & HWC_BROKEN) {
+	if (hwc_data.flags & HWC_PTIMER_RUNS) {
+		del_timer (&hwc_data.poll_timer);
+		hwc_data.flags &= ~HWC_PTIMER_RUNS;
+	}
+	if (finished_hwcb) {
 
-		if (!do_hwc_init ()) {
-			hwc_data.flags &= ~HWC_BROKEN;
-			internal_print (DELAYED_WRITE,
-					HWC_RW_PRINT_HEADER
-					"delayed HWC setup after"
-					" temporary breakdown\n");
+		if ((unsigned long) hwc_data.current_hwcb != finished_hwcb) {
+			internal_print (
+					       DELAYED_WRITE,
+					       HWC_RW_PRINT_HEADER
+					       "interrupt: mismatch: "
+					       "ext. int param. (0x%x) vs. "
+					       "current HWCB (0x%x)\n",
+					       ext_int_param,
+					       hwc_data.current_hwcb);
+		} else {
+			if (hwc_data.request) {
+
+				do_hwc_callback (ext_int_param);
+			} else {
+
+				switch (hwc_data.current_servc) {
+
+				case HWC_CMDW_WRITEMASK:
+
+					write_event_mask_2 (ext_int_param);
+					break;
+
+				case HWC_CMDW_WRITEDATA:
+
+					write_event_data_2 (ext_int_param);
+					break;
+
+				case HWC_CMDW_READDATA:
+
+					unconditional_read_2 (ext_int_param);
+					break;
+				default:
+				}
+			}
 		}
 	} else {
-		spin_lock (&hwc_data.lock);
 
-		if (hwc_data.flags & HWC_PTIMER_RUNS) {
-			del_timer (&hwc_data.poll_timer);
-			hwc_data.flags &= ~HWC_PTIMER_RUNS;
+		if (hwc_data.current_hwcb) {
+			internal_print (
+					       DELAYED_WRITE,
+					       HWC_RW_PRINT_HEADER
+					       "interrupt: mismatch: "
+					       "ext. int. param. (0x%x) vs. "
+					       "current HWCB (0x%x)\n",
+					       ext_int_param,
+					       hwc_data.current_hwcb);
 		}
-		if (!hwc_data.current_servc) {
+	}
 
-			unconditional_read_1 ();
+	if (evbuf_pending) {
 
-		} else {
+		unconditional_read_1 ();
+	} else {
 
-			switch (hwc_data.current_servc) {
+		write_event_data_1 ();
+	}
 
-			case HWC_CMDW_WRITEMASK:
+	if (!hwc_data.calls || !hwc_data.calls->wake_up)
+		return;
+	(hwc_data.calls->wake_up) ();
+}
 
-				write_event_mask_2 ();
-				break;
+void 
+hwc_interrupt_handler (struct pt_regs *regs, __u16 code)
+{
+	int cpu = smp_processor_id ();
 
-			case HWC_CMDW_WRITEDATA:
+	u32 ext_int_param = hwc_ext_int_param ();
 
-				write_event_data_2 ();
-				break;
+	irq_enter (cpu, 0x2401);
 
-			case HWC_CMDW_READDATA:
+	if (hwc_data.flags & HWC_INIT) {
 
-				unconditional_read_2 ();
-				break;
-			}
+		hwc_data.flags |= HWC_INTERRUPT;
+	} else if (hwc_data.flags & HWC_BROKEN) {
 
-			write_event_data_1 ();
+		if (!do_hwc_init ()) {
+			hwc_data.flags &= ~HWC_BROKEN;
+			internal_print (DELAYED_WRITE,
+					HWC_RW_PRINT_HEADER
+					"delayed HWC setup after"
+					" temporary breakdown"
+					" (ext. int. parameter=0x%x)\n",
+					ext_int_param);
 		}
-		if (hwc_data.calls != NULL)
-			if (hwc_data.calls->wake_up != NULL)
-				(hwc_data.calls->wake_up) ();
+	} else {
+		spin_lock (&hwc_data.lock);
+		hwc_do_interrupt (ext_int_param);
 		spin_unlock (&hwc_data.lock);
 	}
+	irq_exit (cpu, 0x2401);
 }
 
 void 
diff -u --recursive --new-file v2.4.7/linux/drivers/s390/char/hwc_rw.h linux/drivers/s390/char/hwc_rw.h
--- v2.4.7/linux/drivers/s390/char/hwc_rw.h	Tue Feb 13 14:13:44 2001
+++ linux/drivers/s390/char/hwc_rw.h	Wed Jul 25 14:12:02 2001
@@ -4,7 +4,7 @@
  *
  *  S390 version
  *    Copyright (C) 1999 IBM Deutschland Entwicklung GmbH, IBM Corporation
- *    Author(s): Martin Peschke <peschke@fh-brandenburg.de>
+ *    Author(s): Martin Peschke <mpeschke@de.ibm.com>
  */
 
 #ifndef __HWC_RW_H__
@@ -19,6 +19,25 @@
 	void (*wake_up) (void);
 } hwc_high_level_calls_t;
 
+struct _hwc_request;
+
+typedef void hwc_callback_t (struct _hwc_request *);
+
+typedef struct _hwc_request {
+	void *block;
+	u32 word;
+	hwc_callback_t *callback;
+	void *data;
+} __attribute__ ((packed)) 
+
+hwc_request_t;
+
+#define HWC_ASCEBC(x) ((MACHINE_IS_VM ? _ascebc[x] : _ascebc_500[x]))
+
+#define HWC_EBCASC_STR(s,c) ((MACHINE_IS_VM ? EBCASC(s,c) : EBCASC_500(s,c)))
+
+#define HWC_ASCEBC_STR(s,c) ((MACHINE_IS_VM ? ASCEBC(s,c) : ASCEBC_500(s,c)))
+
 #define IN_HWCB      1
 #define IN_WRITE_BUF 2
 #define IN_BUFS_TOTAL        (IN_HWCB | IN_WRITE_BUF)
@@ -105,6 +124,8 @@
 extern signed int hwc_register_calls (hwc_high_level_calls_t *);
 
 extern signed int hwc_unregister_calls (hwc_high_level_calls_t *);
+
+extern int hwc_send (hwc_request_t *);
 
 #endif
 
diff -u --recursive --new-file v2.4.7/linux/drivers/s390/char/hwc_tty.c linux/drivers/s390/char/hwc_tty.c
--- v2.4.7/linux/drivers/s390/char/hwc_tty.c	Tue May 22 10:23:16 2001
+++ linux/drivers/s390/char/hwc_tty.c	Wed Jul 25 14:12:02 2001
@@ -4,7 +4,7 @@
  *
  *  S390 version
  *    Copyright (C) 1999 IBM Deutschland Entwicklung GmbH, IBM Corporation
- *    Author(s): Martin Peschke <peschke@fh-brandenburg.de>
+ *    Author(s): Martin Peschke <mpeschke@de.ibm.com>
  *
  *  Thanks to Martin Schwidefsky.
  */
@@ -22,6 +22,7 @@
 #include <asm/uaccess.h>
 
 #include "hwc_rw.h"
+#include "ctrlchar.h"
 
 #define HWC_TTY_PRINT_HEADER "hwc tty driver: "
 
@@ -217,12 +218,10 @@
 void 
 hwc_tty_init (void)
 {
-#if defined(CONFIG_3215_CONSOLE) || defined(CONFIG_3270_CONSOLE)
-	if (MACHINE_IS_VM)
-		return;
-#endif
-	if (MACHINE_IS_P390)
+	if (!CONSOLE_IS_HWC)
 		return;
+
+	ctrlchar_init ();
 
 	memset (&hwc_tty_driver, 0, sizeof (struct tty_driver));
 	memset (&hwc_tty_data, 0, sizeof (hwc_tty_data_struct));
diff -u --recursive --new-file v2.4.7/linux/drivers/s390/char/tape.c linux/drivers/s390/char/tape.c
--- v2.4.7/linux/drivers/s390/char/tape.c	Wed Apr 11 19:02:28 2001
+++ linux/drivers/s390/char/tape.c	Wed Jul 25 14:12:02 2001
@@ -18,6 +18,7 @@
 #include <linux/kernel.h>
 #include <linux/version.h>
 #include <linux/proc_fs.h>
+#include <linux/init.h>
 #include <asm/types.h>
 #include <asm/ccwcache.h>
 #include <asm/idals.h>
@@ -26,9 +27,7 @@
 #ifdef MODULE
 #include <linux/module.h>
 #endif   
-#ifdef TAPE_DEBUG
 #include <asm/debug.h>
-#endif
 #ifdef CONFIG_S390_TAPE_DYNAMIC
 #include <asm/s390dyn.h>
 #endif
@@ -50,15 +49,19 @@
 #endif
 #define PRINTK_HEADER "T390:"
 
+
 /* state handling routines */
-inline void tapestate_set (tape_info_t * tape, int newstate);
-inline int tapestate_get (tape_info_t * tape);
-void tapestate_event (tape_info_t * tape, int event);
+inline void tapestate_set (tape_info_t * ti, int newstate);
+inline int tapestate_get (tape_info_t * ti);
+void tapestate_event (tape_info_t * ti, int event);
 
 /* our globals */
 tape_info_t *first_tape_info = NULL;
 tape_discipline_t *first_discipline = NULL;
 tape_frontend_t *first_frontend = NULL;
+devreg_t* tape_devreg[128];
+int devregct=0;
+
 #ifdef TAPE_DEBUG
 debug_info_t *tape_debug_area = NULL;
 #endif
@@ -107,17 +110,17 @@
 devfs_handle_t tape_devfs_root_entry;
 
 inline void
-tape_mkdevfsroots (tape_info_t* tape) 
+tape_mkdevfsroots (tape_info_t* ti) 
 {
     char devno [5];
-    sprintf (devno,"%04X",tape->devinfo.devno);
-    tape->devfs_dir=devfs_mk_dir (tape_devfs_root_entry, devno, tape);
+    sprintf (devno,"%04x",ti->devinfo.devno);
+    ti->devfs_dir=devfs_mk_dir (tape_devfs_root_entry, devno, ti);
 }
 
 inline void
-tape_rmdevfsroots (tape_info_t* tape)
+tape_rmdevfsroots (tape_info_t* ti)
 {
-    devfs_unregister (tape->devfs_dir);
+    devfs_unregister (ti->devfs_dir);
 }
 #endif
 
@@ -135,14 +138,14 @@
 tape_devices_open (struct inode *inode, struct file *file)
 {
     int size=80;
-    tape_info_t* tape;
+    tape_info_t* ti;
     tempinfo_t* tempinfo;
     char* data;
     int pos=0;
     tempinfo = kmalloc (sizeof(tempinfo_t),GFP_KERNEL);
     if (!tempinfo)
         return -ENOMEM;
-    for (tape=first_tape_info;tape!=NULL;tape=tape->next)
+    for (ti=first_tape_info;ti!=NULL;ti=ti->next)
         size+=80; // FIXME: Guess better!
     data=vmalloc(size);
     if (!data) {
@@ -150,13 +153,13 @@
         return -ENOMEM;
     }
     pos+=sprintf(data+pos,"TapeNo\tDevNo\tCuType\tCuModel\tDevType\tDevModel\tState\n");
-    for (tape=first_tape_info;tape!=NULL;tape=tape->next) {
-        pos+=sprintf(data+pos,"%d\t%04X\t%04X\t%02X\t%04X\t%02X\t\t%s\n",tape->rew_minor/2,
-                     tape->devinfo.devno,tape->devinfo.sid_data.cu_type,
-                     tape->devinfo.sid_data.cu_model,tape->devinfo.sid_data.dev_type,
-                     tape->devinfo.sid_data.dev_model,((tapestate_get(tape) >= 0) &&
-                                                       (tapestate_get(tape) < TS_SIZE)) ?
-                     state_verbose[tapestate_get (tape)] : "TS UNKNOWN");
+    for (ti=first_tape_info;ti!=NULL;ti=ti->next) {
+        pos+=sprintf(data+pos,"%d\t%04X\t%04X\t%02X\t%04X\t%02X\t\t%s\n",ti->rew_minor/2,
+                     ti->devinfo.devno,ti->devinfo.sid_data.cu_type,
+                     ti->devinfo.sid_data.cu_model,ti->devinfo.sid_data.dev_type,
+                     ti->devinfo.sid_data.dev_model,((tapestate_get(ti) >= 0) &&
+                                                       (tapestate_get(ti) < TS_SIZE)) ?
+                     state_verbose[tapestate_get (ti)] : "TS UNKNOWN");
     }
     tempinfo->len=pos;
     tempinfo->data=data;
@@ -215,6 +218,183 @@
 };
 #endif /* CONFIG_PROC_FS */
 
+/* SECTION: Parameters for tape */
+char *tape[256] = { NULL, };
+
+#ifndef MODULE
+static char tape_parm_string[1024] __initdata = { 0, };
+static void
+tape_split_parm_string (char *str)
+{
+	char *tmp = str;
+	int count = 0;
+	while (tmp != NULL && *tmp != '\0') {
+		char *end;
+		int len;
+		end = strchr (tmp, ',');
+		if (end == NULL) {
+			len = strlen (tmp) + 1;
+		} else {
+			len = (long) end - (long) tmp + 1;
+			*end = '\0';
+			end++;
+		}
+		tape[count] = kmalloc (len * sizeof (char), GFP_ATOMIC);
+		if (tape[count] == NULL) {
+			printk (KERN_WARNING PRINTK_HEADER
+				"can't store tape= parameter no %d\n",
+				count + 1);
+			break;
+		}
+		memset (tape[count], 0, len * sizeof (char));
+		memcpy (tape[count], tmp, len * sizeof (char));
+		count++;
+		tmp = end;
+	};
+}
+
+void __init
+tape_parm_setup (char *str, int *ints)
+{
+	int len = strlen (tape_parm_string);
+	if (len != 0) {
+		strcat (tape_parm_string, ",");
+	}
+	strcat (tape_parm_string, str);
+}
+
+int __init
+tape_parm_call_setup (char *str)
+{
+	int dummy;
+	tape_parm_setup (str, &dummy);
+	return 1;
+}
+
+#if (LINUX_VERSION_CODE > KERNEL_VERSION(2,2,16))
+__setup("tape=", tape_parm_call_setup);
+#endif   /* kernel <2.2.19 */
+#endif   /* not defined MODULE */
+
+static inline int
+tape_parm_strtoul (char *str, char **stra)
+{
+	char *temp = str;
+	int val;
+	if (*temp == '0') {
+		temp++;		/* strip leading zero */
+		if (*temp == 'x')
+			temp++;	/* strip leading x */
+	}
+	val = simple_strtoul (temp, &temp, 16);	/* interpret anything as hex */
+	*stra = temp;
+	return val;
+}
+
+static inline devreg_t *
+tape_create_devreg (int devno)
+{
+	devreg_t *devreg = kmalloc (sizeof (devreg_t), GFP_KERNEL);
+	if (devreg != NULL) {
+		memset (devreg, 0, sizeof (devreg_t));
+		devreg->ci.devno = devno;
+		devreg->flag = DEVREG_TYPE_DEVNO;
+		devreg->oper_func = tape_oper_handler;
+	}
+	return devreg;
+}
+
+static inline void
+tape_parm_parse (char **str)
+{
+	char *temp;
+	int from, to,i,irq=0,rc,retries=0,tape_num=0;
+        s390_dev_info_t dinfo;
+        tape_info_t* ti,*tempti;
+        tape_discipline_t* disc;
+        long lockflags;
+	if (*str==NULL) {
+            /* no params present -> leave */
+            return;
+	}
+	while (*str) {
+		temp = *str;
+		from = 0;
+		to = 0;
+
+                /* turn off autodetect mode, if any range is present */
+                from = tape_parm_strtoul (temp, &temp);
+                to = from;
+                if (*temp == '-') {
+                    temp++;
+                    to = tape_parm_strtoul (temp, &temp);
+                }
+                for (i=from;i<=to;i++) {
+                    retries=0;
+                    // register for attch/detach of a devno
+                    tape_devreg[devregct]=tape_create_devreg(i);
+                    if (tape_devreg[devregct]==NULL) {
+                        PRINT_WARN ("Could not create devreg for devno %04x, dyn. attach for this devno deactivated.\n",i);
+                    } else {
+                        s390_device_register (tape_devreg[devregct++]);
+                    }
+                    // we are activating a device if it is present
+                    for (irq = get_irq_first(); irq!=-ENODEV; irq=get_irq_next(irq)) {
+                        rc = get_dev_info_by_irq (irq, &dinfo);
+                     
+                        disc = first_discipline;
+                        while ((dinfo.devno == i) && (disc != NULL) && (disc->cu_type != dinfo.sid_data.cu_type))
+                            disc = (tape_discipline_t *) (disc->next);
+                        if ((disc == NULL) || (rc == -ENODEV) || (i!=dinfo.devno)) {
+                            continue;
+                        }
+#ifdef TAPE_DEBUG
+                        debug_text_event (tape_debug_area,3,"det irq:  ");
+                        debug_int_event (tape_debug_area,3,irq);
+                        debug_text_event (tape_debug_area,3,"cu:       ");
+                        debug_int_event (tape_debug_area,3,disc->cu_type);
+#endif /* TAPE_DEBUG */
+                        PRINT_INFO ("using devno %04x with discipline %04x on irq %d as tape device %d\n",dinfo.devno,dinfo.sid_data.cu_type,irq,tape_num/2);
+                        /* Allocate tape structure  */
+                        ti = kmalloc (sizeof (tape_info_t), GFP_ATOMIC);
+                        if (ti == NULL) {
+#ifdef TAPE_DEBUG
+                            debug_text_exception (tape_debug_area,3,"ti:no mem ");
+#endif /* TAPE_DEBUG */
+                            PRINT_INFO ("tape: can't allocate memory for "
+                                        "tape info structure\n");
+                            continue;
+                        }
+                        memset(ti,0,sizeof(tape_info_t));
+                        ti->discipline = disc;
+                        disc->tape = ti;
+                        rc = tape_setup (ti, irq, tape_num);
+                        if (rc) {
+#ifdef TAPE_DEBUG
+                            debug_text_event (tape_debug_area,3,"tsetup err");
+                            debug_int_exception (tape_debug_area,3,rc);
+#endif /* TAPE_DEBUG */
+                            kfree (ti);
+                        } else {
+                            s390irq_spin_lock_irqsave (irq, lockflags);
+                            if (first_tape_info == NULL) {
+                                first_tape_info = ti;
+                            } else {
+                                tempti = first_tape_info;
+                                while (tempti->next != NULL)
+                                    tempti = tempti->next;
+                                tempti->next = ti;
+                            }
+                            s390irq_spin_unlock_irqrestore (irq, lockflags);
+                        }
+                    }
+                    tape_num+=2;
+                }
+                str++;
+        }
+}
+
+
 /* SECTION: Managing wrappers for ccwcache */
 
 #define TAPE_EMERGENCY_REQUESTS 16
@@ -286,7 +466,6 @@
 		*((ccw_req_t **) (request->cache)) = request;
 	} else {
 		clear_normalized_cda ((ccw1_t *) (request->cpaddr));	// avoid memory leak caused by modeset_byte
-
 		ccw_free_request (request);
 	}
 }
@@ -296,12 +475,12 @@
  */
 inline
  ccw_req_t *
-tape_alloc_ccw_req (tape_info_t * tape, int cplength, int datasize)
+tape_alloc_ccw_req (tape_info_t * ti, int cplength, int datasize)
 {
 	char tape_magic_id[] = "tape";
 	ccw_req_t *cqr = NULL;
 
-	if (!tape)
+	if (!ti)
 		return NULL;
 	cqr = tape_alloc_request (tape_magic_id, cplength, datasize);
 
@@ -311,7 +490,7 @@
 #endif
 	}
 	cqr->magic = TAPE_MAGIC;	/* sets an identifier for tape driver   */
-	cqr->device = tape;	/* save pointer to tape info    */
+	cqr->device = ti;	/* save pointer to tape info    */
 	return cqr;
 }
 
@@ -321,15 +500,15 @@
 static inline tape_info_t *
 tapedev_find_info (int irq)
 {
-	tape_info_t *tape;
+	tape_info_t *ti;
 
-	tape = first_tape_info;
-	if (tape != NULL)
+	ti = first_tape_info;
+	if (ti != NULL)
 		do {
-			if (tape->devinfo.irq == irq)
+			if (ti->devinfo.irq == irq)
 				break;
-		} while ((tape = (tape_info_t *) tape->next) != NULL);
-	return tape;
+		} while ((ti = (tape_info_t *) ti->next) != NULL);
+	return ti;
 }
 
 #define QUEUE_THRESHOLD 5
@@ -340,32 +519,31 @@
 void
 tape_irq (int irq, void *int_parm, struct pt_regs *regs)
 {
-	tape_info_t *tape = tapedev_find_info (irq);
+	tape_info_t *ti = tapedev_find_info (irq);
 
 	/* analyse devstat and fire event */
-	if (tape->devstat.dstat & DEV_STAT_UNIT_CHECK) {
-		tapestate_event (tape, TE_ERROR);
-	} else if (tape->devstat.dstat & (DEV_STAT_DEV_END)) {
-		tapestate_event (tape, TE_DONE);
+	if (ti->devstat.dstat & DEV_STAT_UNIT_CHECK) {
+		tapestate_event (ti, TE_ERROR);
+	} else if (ti->devstat.dstat & (DEV_STAT_DEV_END)) {
+		tapestate_event (ti, TE_DONE);
 	} else
-		tapestate_event (tape, TE_OTHER);
+		tapestate_event (ti, TE_OTHER);
 }
 
 int 
 tape_oper_handler ( int irq, struct _devreg *dreg) {
-    tape_info_t* tape=first_tape_info;
+    tape_info_t* ti=first_tape_info;
     tape_info_t* newtape;
-    int rc,tape_num,retries=0;
+    int rc,tape_num,retries=0,i;
     s390_dev_info_t dinfo;
     tape_discipline_t* disc;
 #ifdef CONFIG_DEVFS_FS
     tape_frontend_t* frontend;
 #endif
     long lockflags;
-    PRINT_WARN ("oper handler was called\n");
-    while ((tape!=NULL) && (tape->devinfo.irq!=irq)) 
-        tape=tape->next;
-    if (tape!=NULL) {
+    while ((ti!=NULL) && (ti->devinfo.irq!=irq)) 
+        ti=ti->next;
+    if (ti!=NULL) {
         // irq is (still) used by tape. tell ingo to try again later
         PRINT_WARN ("Oper handler for irq %d called while irq still (internaly?) used.\n",irq);
         return -EAGAIN;
@@ -384,51 +562,61 @@
     while ((disc != NULL) && (disc->cu_type != dinfo.sid_data.cu_type))
         disc = (tape_discipline_t *) (disc->next);
     if (disc == NULL)
-        PRINT_WARN ("No matching discipline for cu_type %x found\n",dinfo.sid_data.cu_type);
+        PRINT_WARN ("No matching discipline for cu_type %x found, ignoring device %04x.\n",dinfo.sid_data.cu_type,dinfo.devno);
     if (rc == -ENODEV) 
         PRINT_WARN ("No device information for new dev. could be retrieved.\n");
     if ((disc == NULL) || (rc == -ENODEV))
         return -ENODEV;
     
     /* Allocate tape structure  */
-    tape = kmalloc (sizeof (tape_info_t), GFP_ATOMIC);
-    if (tape == NULL) {
-        PRINT_INFO (KERN_ERR "tape: can't allocate memory for "
+    ti = kmalloc (sizeof (tape_info_t), GFP_ATOMIC);
+    if (ti == NULL) {
+        PRINT_INFO ( "tape: can't allocate memory for "
                     "tape info structure\n");
         return -ENOBUFS;
     }
-    memset(tape,0,sizeof(tape_info_t));
-    tape->discipline = disc;
-    disc->tape = tape;
+    memset(ti,0,sizeof(tape_info_t));
+    ti->discipline = disc;
+    disc->tape = ti;
     tape_num=0;
-    newtape=first_tape_info;
-    while (newtape!=NULL) {
-        if (newtape->rew_minor==tape_num) {
-            // tape num in use. try next one
-            tape_num+=2;
-            newtape=first_tape_info;
-        } else {
-            // tape num not used by newtape. look at next tape info
-            newtape=newtape->next;
+    if (*tape) {
+        // we have static device ranges, so fingure out the tape_num of the attached tape
+        for (i=0;i<devregct;i++)
+            if (tape_devreg[i]->ci.devno==dinfo.devno) {
+                tape_num=2*i;
+                break;
+            }
+    } else {
+        // we are running in autoprobe mode, find a free tape_num
+        newtape=first_tape_info;
+        while (newtape!=NULL) {
+            if (newtape->rew_minor==tape_num) {
+                // tape num in use. try next one
+                tape_num+=2;
+                newtape=first_tape_info;
+            } else {
+                // tape num not used by newtape. look at next tape info
+                newtape=newtape->next;
+            }
         }
     }
-    rc = tape_setup (tape, irq, tape_num);
+    rc = tape_setup (ti, irq, tape_num);
     if (rc) {
-        kfree (tape);
+        kfree (ti);
         return -ENOBUFS;
     }
 #ifdef CONFIG_DEVFS_FS
     for (frontend=first_frontend;frontend!=NULL;frontend=frontend->next) 
-        frontend->mkdevfstree(tape);
+        frontend->mkdevfstree(ti);
 #endif
     s390irq_spin_lock_irqsave (irq,lockflags);
     if (first_tape_info == NULL) {
-        first_tape_info = tape;
+        first_tape_info = ti;
     } else {
         newtape = first_tape_info;
         while (newtape->next != NULL)
             newtape = newtape->next;
-        newtape->next = tape;
+        newtape->next = ti;
     }
     s390irq_spin_unlock_irqrestore (irq, lockflags);
     return 0;
@@ -492,8 +680,11 @@
 void
 tape_dump_sense (devstat_t * stat)
 {
-	int sl;
+#ifdef TAPE_DEBUG
+        int sl;
+#endif
 #if 0
+
 	PRINT_WARN ("------------I/O resulted in unit check:-----------\n");
 	for (sl = 0; sl < 4; sl++) {
 		PRINT_WARN ("Sense:");
@@ -542,6 +733,10 @@
 	long lockflags;
 	int rc = 0;
 
+        if (minor>254) {
+            PRINT_WARN ("Device id %d on irq %d will not be accessible since this driver is restricted to 128 devices.\n",minor/2,irq);
+            return -EINVAL;
+        }
 	rc = get_dev_info_by_irq (irq, &(ti->devinfo));
 	if (rc == -ENODEV) {	/* end of device list */
 		return rc;
@@ -560,10 +755,8 @@
 #endif
 	s390irq_spin_lock_irqsave (irq, lockflags);
 	ti->next = NULL;
-	if (rc) {
-		PRINT_WARN ("Cannot register irq %d, rc=%d\n", irq, rc);
-	} else
-		PRINT_WARN ("Register irq %d for using with discipline %x dev #%d\n", irq, ti->discipline->cu_type,ti->blk_minor/2);
+	if (rc)
+            PRINT_WARN ("Cannot register irq %d, rc=%d\n", irq, rc);
 	init_waitqueue_head (&ti->wq);
 	ti->kernbuf = ti->userbuf = ti->discdata = NULL;
 	tapestate_set (ti, TS_UNUSED);
@@ -599,7 +792,7 @@
 #endif /* TAPE_DEBUG */
 
         /* print banner */        
-        PRINT_WARN ("IBM S/390 Tape Device Driver (BETA).\n");
+        PRINT_WARN ("IBM S/390 Tape Device Driver (v1.01).\n");
         PRINT_WARN ("(C) IBM Deutschland Entwicklung GmbH, 2000\n");
         opt_char=opt_block=opt_3480=opt_3490="not present";
 #ifdef CONFIG_S390_TAPE_CHAR
@@ -620,18 +813,33 @@
         PRINT_WARN ("support for 3480 compatible : %s\n",opt_3480);
         PRINT_WARN ("support for 3490 compatible : %s\n",opt_3490);
         
-
+#ifndef MODULE
+        tape_split_parm_string(tape_parm_string);
+#endif
+        if (*tape) 
+            PRINT_INFO ("Using ranges supplied in parameters, disabling autoprobe mode.\n");
+        else
+            PRINT_INFO ("No parameters supplied, enabling autoprobe mode for all supported devices.\n");
 #ifdef CONFIG_S390_TAPE_3490
-	first_discipline = tape3490_init ();
+        if (*tape)
+            first_discipline = tape3490_init (0); // no autoprobe for devices
+        else
+            first_discipline = tape3490_init (1); // do autoprobe since no parm specified
 	first_discipline->next = NULL;
 #endif
 
 #ifdef CONFIG_S390_TAPE_3480
         if (first_discipline == NULL) {
-            first_discipline = tape3480_init ();
+            if (*tape)
+                first_discipline = tape3480_init (0); // no autoprobe for devices
+            else 
+                first_discipline = tape3480_init (1); // do autoprobe since no parm specified
             first_discipline->next = NULL;
         } else {
-            first_discipline->next = tape3480_init ();
+            if (*tape)
+                first_discipline->next = tape3480_init (0); // no autoprobe for devices
+            else
+                first_discipline->next = tape3480_init (1); // do autoprobe since no parm specified
             ((tape_discipline_t*) (first_discipline->next))->next=NULL;
         }
 #endif
@@ -643,33 +851,32 @@
         debug_text_event (tape_debug_area,3,"dev detect");
 #endif /* TAPE_DEBUG */
 	/* Allocate the tape structures */
-	for (irq = 0; irq < NR_IRQS; irq++) {
+        if (*tape!=NULL) {
+            // we have parameters, continue with parsing the parameters and set the devices online
+            tape_parm_parse (tape);
+        } else {
+            // we are running in autodetect mode, search all devices for compatibles
+            for (irq = get_irq_first(); irq!=-ENODEV; irq=get_irq_next(irq)) {
 		rc = get_dev_info_by_irq (irq, &dinfo);
-
-		if (rc == -ENODEV) {
-			retries++;
-			if (retries > 5)
-				irq = NR_IRQS;
-		}
 		disc = first_discipline;
 		while ((disc != NULL) && (disc->cu_type != dinfo.sid_data.cu_type))
-			disc = (tape_discipline_t *) (disc->next);
-
+                    disc = (tape_discipline_t *) (disc->next);
 		if ((disc == NULL) || (rc == -ENODEV))
-			continue;
+                    continue;
 #ifdef TAPE_DEBUG
                 debug_text_event (tape_debug_area,3,"det irq:  ");
                 debug_int_event (tape_debug_area,3,irq);
                 debug_text_event (tape_debug_area,3,"cu:       ");
                 debug_int_event (tape_debug_area,3,disc->cu_type);
 #endif /* TAPE_DEBUG */
+                PRINT_INFO ("using devno %04x with discipline %04x on irq %d as tape device %d\n",dinfo.devno,dinfo.sid_data.cu_type,irq,tape_num/2);
 		/* Allocate tape structure  */
 		ti = kmalloc (sizeof (tape_info_t), GFP_ATOMIC);
 		if (ti == NULL) {
 #ifdef TAPE_DEBUG
                     debug_text_exception (tape_debug_area,3,"ti:no mem ");
 #endif /* TAPE_DEBUG */
-                    PRINT_INFO (KERN_ERR "tape: can't allocate memory for "
+                    PRINT_INFO ("tape: can't allocate memory for "
 				    "tape info structure\n");
                     continue;
 		}
@@ -679,25 +886,26 @@
 		rc = tape_setup (ti, irq, tape_num);
 		if (rc) {
 #ifdef TAPE_DEBUG
-                        debug_text_event (tape_debug_area,3,"tsetup err");
-                        debug_int_exception (tape_debug_area,3,rc);
+                    debug_text_event (tape_debug_area,3,"tsetup err");
+                    debug_int_exception (tape_debug_area,3,rc);
 #endif /* TAPE_DEBUG */
-			kfree (ti);
+                    kfree (ti);
 		} else {
-			s390irq_spin_lock_irqsave (irq, lockflags);
-			if (first_tape_info == NULL) {
-				first_tape_info = ti;
-			} else {
-				tempti = first_tape_info;
-				while (tempti->next != NULL)
-					tempti = tempti->next;
-				tempti->next = ti;
-			}
-			tape_num += 2;
-			s390irq_spin_unlock_irqrestore (irq, lockflags);
+                    s390irq_spin_lock_irqsave (irq, lockflags);
+                    if (first_tape_info == NULL) {
+                        first_tape_info = ti;
+                    } else {
+                        tempti = first_tape_info;
+                        while (tempti->next != NULL)
+                            tempti = tempti->next;
+                        tempti->next = ti;
+                    }
+                    tape_num += 2;
+                    s390irq_spin_unlock_irqrestore (irq, lockflags);
 		}
-	}
-
+            }
+        }
+            
 	/* Allocate local buffer for the ccwcache       */
 	tape_init_emergency_req ();
 #ifdef CONFIG_PROC_FS
@@ -733,6 +941,7 @@
 #ifdef MODULE
 MODULE_AUTHOR("(C) 2001 IBM Deutschland Entwicklung GmbH by Carsten Otte (cotte@de.ibm.com)");
 MODULE_DESCRIPTION("Linux for S/390 channel attached tape device driver");
+MODULE_PARM (tape, "1-" __MODULE_STRING (256) "s");
 
 int
 init_module (void)
@@ -749,17 +958,24 @@
 void
 cleanup_module (void)
 {
-        tape_info_t *tape ,*temp;
+        tape_info_t *ti ,*temp;
         tape_frontend_t* frontend, *tempfe;
         tape_discipline_t* disc ,*tempdi;
+        int i;
 #ifdef TAPE_DEBUG
         debug_text_event (tape_debug_area,6,"cleaup mod");
 #endif /* TAPE_DEBUG */
 
-	tape = first_tape_info;
-	while (tape != NULL) {
-		temp = tape;
-		tape = tape->next;
+        if (*tape) {
+            // we are running with parameters. we'll now deregister from our devno's
+            for (i=0;i<devregct;i++) {
+                s390_device_unregister(tape_devreg[devregct]);
+            }
+        }
+	ti = first_tape_info;
+	while (ti != NULL) {
+		temp = ti;
+		ti = ti->next;
                 //cleanup a device 
 #ifdef TAPE_DEBUG
                 debug_text_event (tape_debug_area,6,"free irq:");
@@ -781,7 +997,7 @@
 #endif CONFIG_DEVFS_FS
 #ifdef CONFIG_PROC_FS
 #if (LINUX_VERSION_CODE > KERNEL_VERSION(2,3,98))
-	remove_proc_entry ("devices", &proc_root);
+	remove_proc_entry ("tapedevices", &proc_root);
 #else
 	proc_unregister (&proc_root, tape_devices_entry->low_ino);
 	kfree (tape_devices_entry);
@@ -801,6 +1017,10 @@
 	}
         disc=first_discipline;
 	while (disc != NULL) {
+                if (*tape)
+                    disc->shutdown(0);
+                else
+                    disc->shutdown(1);
 		tempdi = disc;
 		disc = disc->next;
 		kfree (tempdi);
@@ -814,9 +1034,9 @@
 #endif				/* MODULE */
 
 inline void
-tapestate_set (tape_info_t * tape, int newstate)
+tapestate_set (tape_info_t * ti, int newstate)
 {
-    if (tape->tape_state == TS_NOT_OPER) {
+    if (ti->tape_state == TS_NOT_OPER) {
 #ifdef TAPE_DEBUG
         debug_text_event (tape_debug_area,3,"ts_set err");
         debug_text_exception (tape_debug_area,3,"dev n.oper");
@@ -824,11 +1044,11 @@
     } else {
 #ifdef TAPE_DEBUG
         debug_text_event (tape_debug_area,4,"ts. dev:  ");
-        debug_int_event (tape_debug_area,4,tape->blk_minor);
+        debug_int_event (tape_debug_area,4,ti->blk_minor);
         debug_text_event (tape_debug_area,4,"old ts:   ");
-        debug_text_event (tape_debug_area,4,(((tapestate_get (tape) < TS_SIZE) &&
-                                             (tapestate_get (tape) >=0 )) ?
-                                            state_verbose[tapestate_get (tape)] :
+        debug_text_event (tape_debug_area,4,(((tapestate_get (ti) < TS_SIZE) &&
+                                             (tapestate_get (ti) >=0 )) ?
+                                            state_verbose[tapestate_get (ti)] :
                                             "UNKNOWN TS"));
         debug_text_event (tape_debug_area,4,"new ts:   ");
         debug_text_event (tape_debug_area,4,(((newstate < TS_SIZE) &&
@@ -836,46 +1056,46 @@
                                              state_verbose[newstate] :
                                              "UNKNOWN TS"));
 #endif /* TAPE_DEBUG */
-	tape->tape_state = newstate;
+	ti->tape_state = newstate;
     }
 }
 
 inline int
-tapestate_get (tape_info_t * tape)
+tapestate_get (tape_info_t * ti)
 {
-	return (tape->tape_state);
+	return (ti->tape_state);
 }
 
 void
-tapestate_event (tape_info_t * tape, int event)
+tapestate_event (tape_info_t * ti, int event)
 {
 #ifdef TAPE_DEBUG
         debug_text_event (tape_debug_area,6,"te! dev:  ");
-        debug_int_event (tape_debug_area,6,tape->blk_minor);
+        debug_int_event (tape_debug_area,6,ti->blk_minor);
         debug_text_event (tape_debug_area,6,"event:");
         debug_text_event (tape_debug_area,6,((event >=0) &&
                                             (event < TE_SIZE)) ?
                          event_verbose[event] : "TE UNKNOWN");
         debug_text_event (tape_debug_area,6,"state:");
-        debug_text_event (tape_debug_area,6,((tapestate_get(tape) >= 0) &&
-                                            (tapestate_get(tape) < TS_SIZE)) ?
-                         state_verbose[tapestate_get (tape)] :
+        debug_text_event (tape_debug_area,6,((tapestate_get(ti) >= 0) &&
+                                            (tapestate_get(ti) < TS_SIZE)) ?
+                         state_verbose[tapestate_get (ti)] :
                          "TS UNKNOWN");
 #endif /* TAPE_DEBUG */    
         if (event == TE_ERROR) { 
-            tape->discipline->error_recovery(tape);
+            ti->discipline->error_recovery(ti);
         } else {
             if ((event >= 0) &&
                 (event < TE_SIZE) &&
-                (tapestate_get (tape) >= 0) &&
-                (tapestate_get (tape) < TS_SIZE) &&
-                ((*(tape->discipline->event_table))[tapestate_get (tape)][event] != NULL))
-		((*(tape->discipline->event_table))[tapestate_get (tape)][event]) (tape);
+                (tapestate_get (ti) >= 0) &&
+                (tapestate_get (ti) < TS_SIZE) &&
+                ((*(ti->discipline->event_table))[tapestate_get (ti)][event] != NULL))
+		((*(ti->discipline->event_table))[tapestate_get (ti)][event]) (ti);
             else {
 #ifdef TAPE_DEBUG
                 debug_text_exception (tape_debug_area,3,"TE UNEXPEC");
 #endif /* TAPE_DEBUG */
-		tape->discipline->default_handler (tape);
+		ti->discipline->default_handler (ti);
             }
         }
 }
diff -u --recursive --new-file v2.4.7/linux/drivers/s390/char/tape.h linux/drivers/s390/char/tape.h
--- v2.4.7/linux/drivers/s390/char/tape.h	Wed Apr 11 19:02:28 2001
+++ linux/drivers/s390/char/tape.h	Wed Jul 25 14:12:02 2001
@@ -63,11 +63,12 @@
     TE_START=0, TE_DONE, TE_FAILED, TE_ERROR, TE_OTHER,
     TE_SIZE } tape_events;
 
+typedef void (*tape_disc_shutdown_t) (int);
 typedef void (*tape_event_handler_t) (struct _tape_info_t*);
-typedef ccw_req_t* (*tape_ccwgen_t)(struct _tape_info_t* tape,int count);
-typedef ccw_req_t* (*tape_reqgen_t)(struct request* req,struct _tape_info_t* tape,int tapeblock_major);
-typedef ccw_req_t* (*tape_rwblock_t)(const char* data,size_t count,struct _tape_info_t* tape);
-typedef void (*tape_freeblock_t)(ccw_req_t* cqr,struct _tape_info_t* tape);
+typedef ccw_req_t* (*tape_ccwgen_t)(struct _tape_info_t* ti,int count);
+typedef ccw_req_t* (*tape_reqgen_t)(struct request* req,struct _tape_info_t* ti,int tapeblock_major);
+typedef ccw_req_t* (*tape_rwblock_t)(const char* data,size_t count,struct _tape_info_t* ti);
+typedef void (*tape_freeblock_t)(ccw_req_t* cqr,struct _tape_info_t* ti);
 typedef void (*tape_setup_assist_t) (struct _tape_info_t*);
 #ifdef CONFIG_DEVFS_FS
 typedef void (*tape_devfs_handler_t) (struct _tape_info_t*);
@@ -108,6 +109,7 @@
     tape_ccwgen_t mtmkpart;
     tape_ccwgen_t mtiocget;
     tape_ccwgen_t mtiocpos;
+    tape_disc_shutdown_t shutdown;
     int (*discipline_ioctl_overload)(struct inode *,struct file*, unsigned int,unsigned long);
     tape_event_table_t* event_table;
     tape_event_handler_t default_handler;
@@ -145,6 +147,7 @@
     struct request* current_request;
     int blk_retries;
     long position;
+    int medium_is_unloaded;  // Becomes true when a unload-type operation was issued, false again when medium-insert was detected
     ccw_req_t* cqr;
rp_action_fn_t) (ccw_req_t * isn_t) (ccw_req_t *,=f (LINRT_UNITIOis devno deai +528,7 @USe operatm.o: $(tub3 was  {
-    CFG_TYPE type;
-    char *n01);
 }
vices online
-typ 3ef ccw_req_t* (*tape_reqgen_t)(struct resprintf(data+pos,"TapeNo\tDevNo\tC do_softirq();
              printf    PRSshutdoapeNo\_num o        prins_s                                   "UNKNOWN TS"));			-     ,