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;
     atomic_t bh_scheduled;
     struct tq_struct bh_tq;
@@ -167,7 +170,7 @@
 int tape_setup (tape_info_t * ti, int irq, int minor);
 
 /* functoins for alloc'ing ccw stuff */
-inline  ccw_req_t * tape_alloc_ccw_req (tape_info_t* tape, int cplength, int datasize);
+inline  ccw_req_t * tape_alloc_ccw_req (tape_info_t* ti, int cplength, int datasize);
 void tape_free_request (ccw_req_t * request);
 
 /* a function for dumping device sense info */
@@ -179,9 +182,9 @@
 #endif
 
 /* functions for handling the status of a device */
-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);
 extern char* state_verbose[TS_SIZE];
 extern char* event_verbose[TE_SIZE];
 
diff -u --recursive --new-file v2.4.7/linux/drivers/s390/char/tape3480.c linux/drivers/s390/char/tape3480.c
--- v2.4.7/linux/drivers/s390/char/tape3480.c	Wed Apr 11 19:02:28 2001
+++ linux/drivers/s390/char/tape3480.c	Wed Jul 25 14:12:02 2001
@@ -72,22 +72,29 @@
 
 
 void
-tape3480_setup_assist (tape_info_t * tape)
+tape3480_setup_assist (tape_info_t * ti)
 {
 	tape3480_disc_data_t *data = NULL;
 #ifdef TAPE_DEBUG
     debug_text_event (tape_debug_area,6,"3480 dsetu");
     debug_text_event (tape_debug_area,6,"dev:");
-    debug_int_event (tape_debug_area,6,tape->blk_minor);
+    debug_int_event (tape_debug_area,6,ti->blk_minor);
 #endif /* TAPE_DEBUG */
 	while (data == NULL)
 		data = kmalloc (sizeof (tape3480_disc_data_t), GFP_KERNEL);
 	data->modeset_byte = 0x00;
-	tape->discdata = (void *) data;
+	ti->discdata = (void *) data;
+}
+
+
+void
+tape3480_shutdown (int autoprobe) {
+    if (autoprobe)
+	s390_device_unregister(&tape3480_devreg);
 }
 
 tape_discipline_t *
-tape3480_init (void)
+tape3480_init (int autoprobe)
 {
 	tape_discipline_t *disc;
 #ifdef TAPE_DEBUG
@@ -132,6 +139,7 @@
 	disc->mtmkpart = tape34xx_mtmkpart;
 	disc->mtiocget = tape34xx_mtiocget;
 	disc->mtiocpos = tape34xx_mtiocpos;
+	disc->shutdown = tape3480_shutdown;
 	disc->discipline_ioctl_overload = tape34xx_ioctl_overload;
 	disc->event_table = &tape3480_event_handler_table;
 	disc->default_handler = tape34xx_default_handler;
@@ -139,7 +147,8 @@
 	disc->free_bread = tape34xx_free_bread;
 	disc->tape = NULL;	/* pointer for backreference */
 	disc->next = NULL;
-	s390_device_register(&tape3480_devreg);
+	if (autoprobe)
+	    s390_device_register(&tape3480_devreg);
 #ifdef TAPE_DEBUG
 	debug_text_event (tape_debug_area,3,"3480 regis");
 #endif /* TAPE_DEBUG */
diff -u --recursive --new-file v2.4.7/linux/drivers/s390/char/tape3480.h linux/drivers/s390/char/tape3480.h
--- v2.4.7/linux/drivers/s390/char/tape3480.h	Wed Apr 11 19:02:28 2001
+++ linux/drivers/s390/char/tape3480.h	Wed Jul 25 14:12:02 2001
@@ -19,5 +19,5 @@
 typedef struct _tape3480_disc_data_t {
     __u8 modeset_byte;
 } tape3480_disc_data_t  __attribute__ ((packed, aligned(8)));
-tape_discipline_t * tape3480_init (void);
+tape_discipline_t * tape3480_init (int);
 #endif // _TAPE3480_H
diff -u --recursive --new-file v2.4.7/linux/drivers/s390/char/tape3490.c linux/drivers/s390/char/tape3490.c
--- v2.4.7/linux/drivers/s390/char/tape3490.c	Wed Apr 11 19:02:28 2001
+++ linux/drivers/s390/char/tape3490.c	Wed Jul 25 14:12:02 2001
@@ -71,22 +71,30 @@
 };
 
 void
-tape3490_setup_assist (tape_info_t * tape)
+tape3490_setup_assist (tape_info_t * ti)
 {
 	tape3490_disc_data_t *data = NULL;
 #ifdef TAPE_DEBUG
     debug_text_event (tape_debug_area,6,"3490 dsetu");
     debug_text_event (tape_debug_area,6,"dev:");
-    debug_int_event (tape_debug_area,6,tape->blk_minor);
+    debug_int_event (tape_debug_area,6,ti->blk_minor);
 #endif /* TAPE_DEBUG */
 	while (data == NULL)
 		data = kmalloc (sizeof (tape3490_disc_data_t), GFP_KERNEL);
 	data->modeset_byte = 0x00;
-	tape->discdata = (void *) data;
+	ti->discdata = (void *) data;
 }
 
+
+void
+tape3490_shutdown (int autoprobe) {
+    if (autoprobe)
+	s390_device_unregister(&tape3490_devreg);
+}
+
+
 tape_discipline_t *
-tape3490_init (void)
+tape3490_init (int autoprobe)
 {
 	tape_discipline_t *disc;
 #ifdef TAPE_DEBUG
@@ -131,6 +139,7 @@
 	disc->mtmkpart = tape34xx_mtmkpart;
 	disc->mtiocget = tape34xx_mtiocget;
 	disc->mtiocpos = tape34xx_mtiocpos;
+	disc->shutdown = tape3490_shutdown;
 	disc->discipline_ioctl_overload = tape34xx_ioctl_overload;
 	disc->event_table = &tape3490_event_handler_table;
 	disc->default_handler = tape34xx_default_handler;
@@ -138,7 +147,8 @@
 	disc->free_bread = tape34xx_free_bread;
 	disc->tape = NULL;	/* pointer for backreference */
 	disc->next = NULL;
-	s390_device_register(&tape3490_devreg);
+	if (autoprobe)
+	    s390_device_register(&tape3490_devreg);
 #ifdef TAPE_DEBUG
 	debug_text_event (tape_debug_area,3,"3490 regis");
 #endif /* TAPE_DEBUG */
diff -u --recursive --new-file v2.4.7/linux/drivers/s390/char/tape3490.h linux/drivers/s390/char/tape3490.h
--- v2.4.7/linux/drivers/s390/char/tape3490.h	Wed Apr 11 19:02:28 2001
+++ linux/drivers/s390/char/tape3490.h	Wed Jul 25 14:12:02 2001
@@ -20,5 +20,5 @@
 typedef struct _tape3490_disc_data_t {
     __u8 modeset_byte;
 } tape3490_disc_data_t  __attribute__ ((packed, aligned(8)));
-tape_discipline_t * tape3490_init (void);
+tape_discipline_t * tape3490_init (int);
 #endif // _TAPE3490_H
diff -u --recursive --new-file v2.4.7/linux/drivers/s390/char/tape34xx.c linux/drivers/s390/char/tape34xx.c
--- v2.4.7/linux/drivers/s390/char/tape34xx.c	Wed Apr 11 19:02:28 2001
+++ linux/drivers/s390/char/tape34xx.c	Wed Jul 25 14:12:02 2001
@@ -82,13 +82,13 @@
 }
 
 ccw_req_t *
-tape34xx_write_block (const char *data, size_t count, tape_info_t * tape)
+tape34xx_write_block (const char *data, size_t count, tape_info_t * ti)
 {
 	long lockflags;
 	ccw_req_t *cqr;
 	ccw1_t *ccw;
 	void *mem;
-	cqr = tape_alloc_ccw_req (tape, 2, 0);
+	cqr = tape_alloc_ccw_req (ti, 2, 0);
 	if (!cqr) {
 #ifdef TAPE_DEBUG
 	        debug_text_exception (tape_debug_area,6,"xwbl nomem");
@@ -115,7 +115,7 @@
 	ccw->cmd_code = MODE_SET_DB;
 	ccw->flags = CCW_FLAG_CC;
 	ccw->count = 1;
-	set_normalized_cda (ccw, (unsigned long) (&(((tape34xx_disc_data_t *) tape->discdata)->modeset_byte)));
+	set_normalized_cda (ccw, (unsigned long) (&(((tape34xx_disc_data_t *) ti->discdata)->modeset_byte)));
 	ccw++;
 
 	ccw->cmd_code = WRITE_CMD;
@@ -127,11 +127,11 @@
 		tape_free_request (cqr);
 		return NULL;
 	}
-	s390irq_spin_lock_irqsave (tape->devinfo.irq, lockflags);
-	tape->kernbuf = mem;
-	tape->userbuf = (void *) data;
-	tapestate_set (tape, TS_WRI_INIT);
-	s390irq_spin_unlock_irqrestore (tape->devinfo.irq, lockflags);
+	s390irq_spin_lock_irqsave (ti->devinfo.irq, lockflags);
+	ti->kernbuf = mem;
+	ti->userbuf = (void *) data;
+	tapestate_set (ti, TS_WRI_INIT);
+	s390irq_spin_unlock_irqrestore (ti->devinfo.irq, lockflags);
 #ifdef TAPE_DEBUG
 	debug_text_event (tape_debug_area,6,"xwbl ccwg");
 #endif /* TAPE_DEBUG */
@@ -139,31 +139,31 @@
 }
 
 void 
-tape34xx_free_write_block (ccw_req_t * cqr, tape_info_t * tape)
+tape34xx_free_write_block (ccw_req_t * cqr, tape_info_t * ti)
 {
 	unsigned long lockflags;
 	ccw1_t *ccw;
-	s390irq_spin_lock_irqsave (tape->devinfo.irq, lockflags);
+	s390irq_spin_lock_irqsave (ti->devinfo.irq, lockflags);
 	ccw = cqr->cpaddr;
 	ccw++;
 	clear_normalized_cda (ccw);
-	kfree (tape->kernbuf);
+	kfree (ti->kernbuf);
 	tape_free_request (cqr);
-	tape->kernbuf = tape->userbuf = NULL;
-	s390irq_spin_unlock_irqrestore (tape->devinfo.irq, lockflags);
+	ti->kernbuf = ti->userbuf = NULL;
+	s390irq_spin_unlock_irqrestore (ti->devinfo.irq, lockflags);
 #ifdef TAPE_DEBUG
 	debug_text_event (tape_debug_area,6,"xfwb free");
 #endif /* TAPE_DEBUG */
 }
 
 ccw_req_t *
-tape34xx_read_block (const char *data, size_t count, tape_info_t * tape)
+tape34xx_read_block (const char *data, size_t count, tape_info_t * ti)
 {
 	long lockflags;
 	ccw_req_t *cqr;
 	ccw1_t *ccw;
 	void *mem;
-	cqr = tape_alloc_ccw_req (tape, 2, 0);
+	cqr = tape_alloc_ccw_req (ti, 2, 0);
 	if (!cqr) {
 #ifdef TAPE_DEBUG
 	        debug_text_exception (tape_debug_area,6,"xrbl nomem");
@@ -182,7 +182,7 @@
 	ccw->cmd_code = MODE_SET_DB;
 	ccw->flags = CCW_FLAG_CC;
 	ccw->count = 1;
-	set_normalized_cda (ccw, (unsigned long) (&(((tape34xx_disc_data_t *) tape->discdata)->modeset_byte)));
+	set_normalized_cda (ccw, (unsigned long) (&(((tape34xx_disc_data_t *) ti->discdata)->modeset_byte)));
 	ccw++;
 
 	ccw->cmd_code = READ_FORWARD;
@@ -194,24 +194,25 @@
 		tape_free_request (cqr);
 		return NULL;
 	}
-	s390irq_spin_lock_irqsave (tape->devinfo.irq, lockflags);
-	tape->kernbuf = mem;
-	tape->userbuf = (void *) data;
-	tapestate_set (tape, TS_RFO_INIT);
-	s390irq_spin_unlock_irqrestore (tape->devinfo.irq, lockflags);
+	s390irq_spin_lock_irqsave (ti->devinfo.irq, lockflags);
+	ti->kernbuf = mem;
+	ti->userbuf = (void *) data;
+	tapestate_set (ti, TS_RFO_INIT);
+	s390irq_spin_unlock_irqrestore (ti->devinfo.irq, lockflags);
 #ifdef TAPE_DEBUG
 	debug_text_event (tape_debug_area,6,"xrbl ccwg");
 #endif /* TAPE_DEBUG */
 	return cqr;
 }
+
 ccw_req_t *
-tape34xx_read_opposite (tape_info_t * tape,int novalue)
+tape34xx_read_opposite (tape_info_t * ti,int novalue)
 {
 	ccw_req_t *cqr;
 	ccw1_t *ccw;
 	size_t count;
 	// first, retrieve the count from the old cqr.
-	cqr = tape->cqr;
+	cqr = ti->cqr;
 	ccw = cqr->cpaddr;
 	ccw++;
 	count=ccw->count;
@@ -219,7 +220,7 @@
 	clear_normalized_cda (ccw);
 	tape_free_request (cqr);
 	// build new cqr
-	cqr = tape_alloc_ccw_req (tape, 3, 0);
+	cqr = tape_alloc_ccw_req (ti, 3, 0);
 	if (!cqr) {
 #ifdef TAPE_DEBUG
 	        debug_text_exception (tape_debug_area,6,"xrop nomem");
@@ -230,13 +231,13 @@
 	ccw->cmd_code = MODE_SET_DB;
 	ccw->flags = CCW_FLAG_CC;
 	ccw->count = 1;
-	set_normalized_cda (ccw, (unsigned long) (&(((tape34xx_disc_data_t *) tape->discdata)->modeset_byte)));
+	set_normalized_cda (ccw, (unsigned long) (&(((tape34xx_disc_data_t *) ti->discdata)->modeset_byte)));
 	ccw++;
 
 	ccw->cmd_code = READ_BACKWARD;
 	ccw->flags = CCW_FLAG_CC;
 	ccw->count = count;
-	set_normalized_cda (ccw, (unsigned long) tape->kernbuf);
+	set_normalized_cda (ccw, (unsigned long) ti->kernbuf);
 	if ((ccw->cda) == 0) {
 		tape_free_request (cqr);
 		return NULL;
@@ -251,7 +252,7 @@
 	ccw->flags = 0;
 	ccw->count = 1;
 	ccw->cda = (unsigned long)ccw;
-	tapestate_set (tape, TS_RBA_INIT);
+	tapestate_set (ti, TS_RBA_INIT);
 #ifdef TAPE_DEBUG
 	debug_text_event (tape_debug_area,6,"xrop ccwg");
 #endif /* TAPE_DEBUG */
@@ -259,27 +260,27 @@
 }
 
 void 
-tape34xx_free_read_block (ccw_req_t * cqr, tape_info_t * tape)
+tape34xx_free_read_block (ccw_req_t * cqr, tape_info_t * ti)
 {
 	unsigned long lockflags;
 	size_t cpysize;
 	ccw1_t *ccw;
-	s390irq_spin_lock_irqsave (tape->devinfo.irq, lockflags);
+	s390irq_spin_lock_irqsave (ti->devinfo.irq, lockflags);
 	ccw = cqr->cpaddr;
 	ccw++;
-	cpysize = ccw->count - tape->devstat.rescnt;
-	s390irq_spin_unlock_irqrestore (tape->devinfo.irq, lockflags);
-	if (copy_to_user (tape->userbuf, tape->kernbuf, cpysize)) {
+	cpysize = ccw->count - ti->devstat.rescnt;
+	s390irq_spin_unlock_irqrestore (ti->devinfo.irq, lockflags);
+	if (copy_to_user (ti->userbuf, ti->kernbuf, cpysize)) {
 #ifdef TAPE_DEBUG
 	    debug_text_exception (tape_debug_area,6,"xfrb segf.");
 #endif /* TAPE_DEBUG */
 	}
-	s390irq_spin_lock_irqsave (tape->devinfo.irq, lockflags);
+	s390irq_spin_lock_irqsave (ti->devinfo.irq, lockflags);
 	clear_normalized_cda (ccw);
-	kfree (tape->kernbuf);
+	kfree (ti->kernbuf);
 	tape_free_request (cqr);
-	tape->kernbuf = tape->userbuf = NULL;
-	s390irq_spin_unlock_irqrestore (tape->devinfo.irq, lockflags);
+	ti->kernbuf = ti->userbuf = NULL;
+	s390irq_spin_unlock_irqrestore (ti->devinfo.irq, lockflags);
 #ifdef TAPE_DEBUG
 	debug_text_event (tape_debug_area,6,"xfrb free");
 #endif /* TAPE_DEBUG */
@@ -294,7 +295,7 @@
  * at the EOT (End of Tape) side of the file mark.
  */
 ccw_req_t *
-tape34xx_mtfsf (tape_info_t * tape, int count)
+tape34xx_mtfsf (tape_info_t * ti, int count)
 {
 	long lockflags;
 	int i;
@@ -306,7 +307,7 @@
 #endif /* TAPE_DEBUG */
 		return NULL;
 	}
-	cqr = tape_alloc_ccw_req (tape, 2 + count, 0);
+	cqr = tape_alloc_ccw_req (ti, 2 + count, 0);
 	if (!cqr) {
 #ifdef TAPE_DEBUG
 	        debug_text_exception (tape_debug_area,6,"xfsf nomem");
@@ -317,7 +318,7 @@
 	ccw->cmd_code = MODE_SET_DB;
 	ccw->flags = CCW_FLAG_CC;
 	ccw->count = 1;
-	set_normalized_cda (ccw, (unsigned long) (&(((tape34xx_disc_data_t *) tape->discdata)->modeset_byte)));
+	set_normalized_cda (ccw, (unsigned long) (&(((tape34xx_disc_data_t *) ti->discdata)->modeset_byte)));
 	ccw++;
 	for (i = 0; i < count; i++) {
 		ccw->cmd_code = FORSPACEFILE;
@@ -330,11 +331,11 @@
 	ccw->flags = 0;
 	ccw->count = 0;
 	ccw->cda = (unsigned long) (&(ccw->cmd_code));
-	s390irq_spin_lock_irqsave (tape->devinfo.irq, lockflags);
-	tape->kernbuf = NULL;
-	tape->userbuf = NULL;
-	tapestate_set (tape, TS_FSF_INIT);
-	s390irq_spin_unlock_irqrestore (tape->devinfo.irq, lockflags);
+	s390irq_spin_lock_irqsave (ti->devinfo.irq, lockflags);
+	ti->kernbuf = NULL;
+	ti->userbuf = NULL;
+	tapestate_set (ti, TS_FSF_INIT);
+	s390irq_spin_unlock_irqrestore (ti->devinfo.irq, lockflags);
 #ifdef TAPE_DEBUG
 	debug_text_event (tape_debug_area,6,"xfsf ccwg");
 #endif /* TAPE_DEBUG */
@@ -346,7 +347,7 @@
  * the EOT (End of Tape) side of the last skipped file mark.
  */
 ccw_req_t *
-tape34xx_mtbsf (tape_info_t * tape, int count)
+tape34xx_mtbsf (tape_info_t * ti, int count)
 {
 	long lockflags;
 	int i;
@@ -358,7 +359,7 @@
 #endif /* TAPE_DEBUG */
 	        return NULL;
 	}
-	cqr = tape_alloc_ccw_req (tape, 2 + count, 0);
+	cqr = tape_alloc_ccw_req (ti, 2 + count, 0);
 	if (!cqr) {
 #ifdef TAPE_DEBUG
 	        debug_text_exception (tape_debug_area,6,"xbsf nomem");
@@ -369,7 +370,7 @@
 	ccw->cmd_code = MODE_SET_DB;
 	ccw->flags = CCW_FLAG_CC;
 	ccw->count = 1;
-	set_normalized_cda (ccw, (unsigned long) (&(((tape34xx_disc_data_t *) tape->discdata)->modeset_byte)));
+	set_normalized_cda (ccw, (unsigned long) (&(((tape34xx_disc_data_t *) ti->discdata)->modeset_byte)));
 	ccw++;
 	for (i = 0; i < count; i++) {
 		ccw->cmd_code = BACKSPACEFILE;
@@ -382,11 +383,11 @@
 	ccw->flags = 0;
 	ccw->count = 0;
 	ccw->cda = (unsigned long) (&(ccw->cmd_code));
-	s390irq_spin_lock_irqsave (tape->devinfo.irq, lockflags);
-	tape->kernbuf = NULL;
-	tape->userbuf = NULL;
-	tapestate_set (tape, TS_BSF_INIT);
-	s390irq_spin_unlock_irqrestore (tape->devinfo.irq, lockflags);
+	s390irq_spin_lock_irqsave (ti->devinfo.irq, lockflags);
+	ti->kernbuf = NULL;
+	ti->userbuf = NULL;
+	tapestate_set (ti, TS_BSF_INIT);
+	s390irq_spin_unlock_irqrestore (ti->devinfo.irq, lockflags);
 #ifdef TAPE_DEBUG
 	debug_text_event (tape_debug_area,6,"xbsf ccwg");
 #endif /* TAPE_DEBUG */
@@ -398,7 +399,7 @@
  * via MTSETBLK.
  */
 ccw_req_t *
-tape34xx_mtfsr (tape_info_t * tape, int count)
+tape34xx_mtfsr (tape_info_t * ti, int count)
 {
 	long lockflags;
 	int i;
@@ -410,7 +411,7 @@
 #endif /* TAPE_DEBUG */
 		return NULL;
 	}
-	cqr = tape_alloc_ccw_req (tape, 2 + count, 0);
+	cqr = tape_alloc_ccw_req (ti, 2 + count, 0);
 	if (!cqr) {
 #ifdef TAPE_DEBUG
 	        debug_text_exception (tape_debug_area,6,"xfsr nomem");
@@ -421,7 +422,7 @@
 	ccw->cmd_code = MODE_SET_DB;
 	ccw->flags = CCW_FLAG_CC;
 	ccw->count = 1;
-	set_normalized_cda (ccw, (unsigned long) (&(((tape34xx_disc_data_t *) tape->discdata)->modeset_byte)));
+	set_normalized_cda (ccw, (unsigned long) (&(((tape34xx_disc_data_t *) ti->discdata)->modeset_byte)));
 	ccw++;
 	for (i = 0; i < count; i++) {
 		ccw->cmd_code = FORSPACEBLOCK;
@@ -434,11 +435,11 @@
 	ccw->flags = 0;
 	ccw->count = 0;
 	ccw->cda = (unsigned long) (&(ccw->cmd_code));
-	s390irq_spin_lock_irqsave (tape->devinfo.irq, lockflags);
-	tape->kernbuf = NULL;
-	tape->userbuf = NULL;
-	tapestate_set (tape, TS_FSB_INIT);
-	s390irq_spin_unlock_irqrestore (tape->devinfo.irq, lockflags);
+	s390irq_spin_lock_irqsave (ti->devinfo.irq, lockflags);
+	ti->kernbuf = NULL;
+	ti->userbuf = NULL;
+	tapestate_set (ti, TS_FSB_INIT);
+	s390irq_spin_unlock_irqrestore (ti->devinfo.irq, lockflags);
 #ifdef TAPE_DEBUG
 	debug_text_event (tape_debug_area,6,"xfsr ccwgen");
 #endif /* TAPE_DEBUG */
@@ -450,7 +451,7 @@
  * (blocksize is set via MTSETBLK.
  */
 ccw_req_t *
-tape34xx_mtbsr (tape_info_t * tape, int count)
+tape34xx_mtbsr (tape_info_t * ti, int count)
 {
 	long lockflags;
 	int i;
@@ -462,7 +463,7 @@
 #endif /* TAPE_DEBUG */   
 	        return NULL;
 	}
-	cqr = tape_alloc_ccw_req (tape, 2 + count, 0);
+	cqr = tape_alloc_ccw_req (ti, 2 + count, 0);
 	if (!cqr) {
 #ifdef TAPE_DEBUG
 	        debug_text_exception (tape_debug_area,6,"xbsr nomem");
@@ -473,7 +474,7 @@
 	ccw->cmd_code = MODE_SET_DB;
 	ccw->flags = CCW_FLAG_CC;
 	ccw->count = 1;
-	set_normalized_cda (ccw, (unsigned long) (&(((tape34xx_disc_data_t *) tape->discdata)->modeset_byte)));
+	set_normalized_cda (ccw, (unsigned long) (&(((tape34xx_disc_data_t *) ti->discdata)->modeset_byte)));
 	ccw++;
 	for (i = 0; i < count; i++) {
 		ccw->cmd_code = BACKSPACEBLOCK;
@@ -486,11 +487,11 @@
 	ccw->flags = 0;
 	ccw->count = 0;
 	ccw->cda = (unsigned long) (&(ccw->cmd_code));
-	s390irq_spin_lock_irqsave (tape->devinfo.irq, lockflags);
-	tape->kernbuf = NULL;
-	tape->userbuf = NULL;
-	tapestate_set (tape, TS_BSB_INIT);
-	s390irq_spin_unlock_irqrestore (tape->devinfo.irq, lockflags);
+	s390irq_spin_lock_irqsave (ti->devinfo.irq, lockflags);
+	ti->kernbuf = NULL;
+	ti->userbuf = NULL;
+	tapestate_set (ti, TS_BSB_INIT);
+	s390irq_spin_unlock_irqrestore (ti->devinfo.irq, lockflags);
 #ifdef TAPE_DEBUG
 	debug_text_event (tape_debug_area,6,"xbsr ccwg");
 #endif /* TAPE_DEBUG */
@@ -501,7 +502,7 @@
  * MTWEOF: Write 'count' file marks at the current position.
  */
 ccw_req_t *
-tape34xx_mtweof (tape_info_t * tape, int count)
+tape34xx_mtweof (tape_info_t * ti, int count)
 {
 	long lockflags;
 	int i;
@@ -513,7 +514,7 @@
 #endif /* TAPE_DEBUG */
 		return NULL;
 	}
-	cqr = tape_alloc_ccw_req (tape, 2 + count, 0);
+	cqr = tape_alloc_ccw_req (ti, 2 + count, 0);
 	if (!cqr) {
 #ifdef TAPE_DEBUG
 	        debug_text_exception (tape_debug_area,6,"xweo nomem");
@@ -524,7 +525,7 @@
 	ccw->cmd_code = MODE_SET_DB;
 	ccw->flags = CCW_FLAG_CC;
 	ccw->count = 1;
-	set_normalized_cda (ccw, (unsigned long) (&(((tape34xx_disc_data_t *) tape->discdata)->modeset_byte)));
+	set_normalized_cda (ccw, (unsigned long) (&(((tape34xx_disc_data_t *) ti->discdata)->modeset_byte)));
 	ccw++;
 	for (i = 0; i < count; i++) {
 		ccw->cmd_code = WRITETAPEMARK;
@@ -538,11 +539,11 @@
 	ccw->count = 0;
 	ccw->cda = (unsigned long) (&(ccw->cmd_code));
 	ccw++;
-	s390irq_spin_lock_irqsave (tape->devinfo.irq, lockflags);
-	tape->kernbuf = NULL;
-	tape->userbuf = NULL;
-	tapestate_set (tape, TS_WTM_INIT);
-	s390irq_spin_unlock_irqrestore (tape->devinfo.irq, lockflags);
+	s390irq_spin_lock_irqsave (ti->devinfo.irq, lockflags);
+	ti->kernbuf = NULL;
+	ti->userbuf = NULL;
+	tapestate_set (ti, TS_WTM_INIT);
+	s390irq_spin_unlock_irqrestore (ti->devinfo.irq, lockflags);
 #ifdef TAPE_DEBUG
 	debug_text_event (tape_debug_area,6,"xweo ccwg");
 #endif /* TAPE_DEBUG */
@@ -553,12 +554,12 @@
  * MTREW: Rewind the tape.
  */
 ccw_req_t *
-tape34xx_mtrew (tape_info_t * tape, int count)
+tape34xx_mtrew (tape_info_t * ti, int count)
 {
 	long lockflags;
 	ccw_req_t *cqr;
 	ccw1_t *ccw;
-	cqr = tape_alloc_ccw_req (tape, 3, 0);
+	cqr = tape_alloc_ccw_req (ti, 3, 0);
 	if (!cqr) {
 #ifdef TAPE_DEBUG
 	        debug_text_exception (tape_debug_area,6,"xrew nomem");
@@ -569,7 +570,7 @@
 	ccw->cmd_code = MODE_SET_DB;
 	ccw->flags = CCW_FLAG_CC;
 	ccw->count = 1;
-	set_normalized_cda (ccw, (unsigned long) (&(((tape34xx_disc_data_t *) tape->discdata)->modeset_byte)));
+	set_normalized_cda (ccw, (unsigned long) (&(((tape34xx_disc_data_t *) ti->discdata)->modeset_byte)));
 	ccw++;
 	ccw->cmd_code = REWIND;
 	ccw->flags = CCW_FLAG_CC;
@@ -580,11 +581,11 @@
 	ccw->flags = 0;
 	ccw->count = 0;
 	ccw->cda = (unsigned long) (&(ccw->cmd_code));
-	s390irq_spin_lock_irqsave (tape->devinfo.irq, lockflags);
-	tape->kernbuf = NULL;
-	tape->userbuf = NULL;
-	tapestate_set (tape, TS_REW_INIT);
-	s390irq_spin_unlock_irqrestore (tape->devinfo.irq, lockflags);
+	s390irq_spin_lock_irqsave (ti->devinfo.irq, lockflags);
+	ti->kernbuf = NULL;
+	ti->userbuf = NULL;
+	tapestate_set (ti, TS_REW_INIT);
+	s390irq_spin_unlock_irqrestore (ti->devinfo.irq, lockflags);
 #ifdef TAPE_DEBUG
 	debug_text_event (tape_debug_area,6,"xrew ccwg");
 #endif /* TAPE_DEBUG */
@@ -596,12 +597,12 @@
  * Implement 'rewind unload'
  */
 ccw_req_t *
-tape34xx_mtoffl (tape_info_t * tape, int count)
+tape34xx_mtoffl (tape_info_t * ti, int count)
 {
 	long lockflags;
 	ccw_req_t *cqr;
 	ccw1_t *ccw;
-	cqr = tape_alloc_ccw_req (tape, 3, 32);
+	cqr = tape_alloc_ccw_req (ti, 3, 32);
 	if (!cqr) {
 #ifdef TAPE_DEBUG
 	        debug_text_exception (tape_debug_area,6,"xoff nomem");
@@ -612,7 +613,7 @@
 	ccw->cmd_code = MODE_SET_DB;
 	ccw->flags = CCW_FLAG_CC;
 	ccw->count = 1;
-	set_normalized_cda (ccw, (unsigned long) (&(((tape34xx_disc_data_t *) tape->discdata)->modeset_byte)));
+	set_normalized_cda (ccw, (unsigned long) (&(((tape34xx_disc_data_t *) ti->discdata)->modeset_byte)));
 	ccw++;
 	ccw->cmd_code = REWIND_UNLOAD;
 	ccw->flags = CCW_FLAG_CC;
@@ -623,11 +624,11 @@
 	ccw->flags = 0;
 	ccw->count = 32;
 	ccw->cda = (unsigned long) cqr->cpaddr;
-	s390irq_spin_lock_irqsave (tape->devinfo.irq, lockflags);
-	tape->kernbuf = NULL;
-	tape->userbuf = NULL;
-	tapestate_set (tape, TS_RUN_INIT);
-	s390irq_spin_unlock_irqrestore (tape->devinfo.irq, lockflags);
+	s390irq_spin_lock_irqsave (ti->devinfo.irq, lockflags);
+	ti->kernbuf = NULL;
+	ti->userbuf = NULL;
+	tapestate_set (ti, TS_RUN_INIT);
+	s390irq_spin_unlock_irqrestore (ti->devinfo.irq, lockflags);
 #ifdef TAPE_DEBUG
 	debug_text_event (tape_debug_area,6,"xoff ccwg");
 #endif /* TAPE_DEBUG */
@@ -638,12 +639,12 @@
  * MTNOP: 'No operation'.
  */
 ccw_req_t *
-tape34xx_mtnop (tape_info_t * tape, int count)
+tape34xx_mtnop (tape_info_t * ti, int count)
 {
 	long lockflags;
 	ccw_req_t *cqr;
 	ccw1_t *ccw;
-	cqr = tape_alloc_ccw_req (tape, 1, 0);
+	cqr = tape_alloc_ccw_req (ti, 1, 0);
 	if (!cqr) {
 #ifdef TAPE_DEBUG
 	        debug_text_exception (tape_debug_area,6,"xnop nomem");
@@ -655,11 +656,11 @@
 	ccw->flags = 0;
 	ccw->count = 0;
 	ccw->cda = (unsigned long) ccw->cmd_code;
-	s390irq_spin_lock_irqsave (tape->devinfo.irq, lockflags);
-	tape->kernbuf = NULL;
-	tape->userbuf = NULL;
-	tapestate_set (tape, TS_NOP_INIT);
-	s390irq_spin_unlock_irqrestore (tape->devinfo.irq, lockflags);
+	s390irq_spin_lock_irqsave (ti->devinfo.irq, lockflags);
+	ti->kernbuf = NULL;
+	ti->userbuf = NULL;
+	tapestate_set (ti, TS_NOP_INIT);
+	s390irq_spin_unlock_irqrestore (ti->devinfo.irq, lockflags);
 #ifdef TAPE_DEBUG
 	debug_text_event (tape_debug_area,6,"xnop ccwg");
 #endif /* TAPE_DEBUG */
@@ -672,7 +673,7 @@
  * last skipped file mark.
  */
 ccw_req_t *
-tape34xx_mtbsfm (tape_info_t * tape, int count)
+tape34xx_mtbsfm (tape_info_t * ti, int count)
 {
 	long lockflags;
 	int i;
@@ -684,7 +685,7 @@
 #endif /* TAPE_DEBUG */
 		return NULL;
 	}
-	cqr = tape_alloc_ccw_req (tape, 2 + count, 0);
+	cqr = tape_alloc_ccw_req (ti, 2 + count, 0);
 	if (!cqr) {
 #ifdef TAPE_DEBUG
 	        debug_text_exception (tape_debug_area,6,"xbsm nomem");
@@ -695,7 +696,7 @@
 	ccw->cmd_code = MODE_SET_DB;
 	ccw->flags = CCW_FLAG_CC;
 	ccw->count = 1;
-	set_normalized_cda (ccw, (unsigned long) (&(((tape34xx_disc_data_t *) tape->discdata)->modeset_byte)));
+	set_normalized_cda (ccw, (unsigned long) (&(((tape34xx_disc_data_t *) ti->discdata)->modeset_byte)));
 	ccw++;
 	for (i = 0; i < count; i++) {
 		ccw->cmd_code = BACKSPACEFILE;
@@ -708,11 +709,11 @@
 	ccw->flags = 0;
 	ccw->count = 0;
 	ccw->cda = (unsigned long) (&(ccw->cmd_code));
-	s390irq_spin_lock_irqsave (tape->devinfo.irq, lockflags);
-	tape->kernbuf = NULL;
-	tape->userbuf = NULL;
-	tapestate_set (tape, TS_BSF_INIT);
-	s390irq_spin_unlock_irqrestore (tape->devinfo.irq, lockflags);
+	s390irq_spin_lock_irqsave (ti->devinfo.irq, lockflags);
+	ti->kernbuf = NULL;
+	ti->userbuf = NULL;
+	tapestate_set (ti, TS_BSF_INIT);
+	s390irq_spin_unlock_irqrestore (ti->devinfo.irq, lockflags);
 #ifdef TAPE_DEBUG
 	debug_text_event (tape_debug_area,6,"xbsm ccwg");
 #endif /* TAPE_DEBUG */
@@ -725,7 +726,7 @@
  * of the last skipped file mark.
  */
 ccw_req_t *
-tape34xx_mtfsfm (tape_info_t * tape, int count)
+tape34xx_mtfsfm (tape_info_t * ti, int count)
 {
 	long lockflags;
 	int i;
@@ -737,7 +738,7 @@
 #endif /* TAPE_DEBUG */
 		return NULL;
 	}
-	cqr = tape_alloc_ccw_req (tape, 2 + count, 0);
+	cqr = tape_alloc_ccw_req (ti, 2 + count, 0);
 	if (!cqr) {
 #ifdef TAPE_DEBUG
 	        debug_text_exception (tape_debug_area,6,"xfsm nomem");
@@ -748,7 +749,7 @@
 	ccw->cmd_code = MODE_SET_DB;
 	ccw->flags = CCW_FLAG_CC;
 	ccw->count = 1;
-	set_normalized_cda (ccw, (unsigned long) (&(((tape34xx_disc_data_t *) tape->discdata)->modeset_byte)));
+	set_normalized_cda (ccw, (unsigned long) (&(((tape34xx_disc_data_t *) ti->discdata)->modeset_byte)));
 	ccw++;
 	for (i = 0; i < count; i++) {
 		ccw->cmd_code = FORSPACEFILE;
@@ -761,11 +762,11 @@
 	ccw->flags = 0;
 	ccw->count = 0;
 	ccw->cda = (unsigned long) (&(ccw->cmd_code));
-	s390irq_spin_lock_irqsave (tape->devinfo.irq, lockflags);
-	tape->kernbuf = NULL;
-	tape->userbuf = NULL;
-	tapestate_set (tape, TS_FSF_INIT);
-	s390irq_spin_unlock_irqrestore (tape->devinfo.irq, lockflags);
+	s390irq_spin_lock_irqsave (ti->devinfo.irq, lockflags);
+	ti->kernbuf = NULL;
+	ti->userbuf = NULL;
+	tapestate_set (ti, TS_FSF_INIT);
+	s390irq_spin_unlock_irqrestore (ti->devinfo.irq, lockflags);
 #ifdef TAPE_DEBUG
 	debug_text_event (tape_debug_area,6,"xfsm ccwg");
 #endif /* TAPE_DEBUG */
@@ -779,12 +780,12 @@
  * MTRETEN: Retension the tape, i.e. forward space to end of tape and rewind.
  */
 ccw_req_t *
-tape34xx_mteom (tape_info_t * tape, int count)
+tape34xx_mteom (tape_info_t * ti, int count)
 {
 	long lockflags;
 	ccw_req_t *cqr;
 	ccw1_t *ccw;
-	cqr = tape_alloc_ccw_req (tape, 4, 0);
+	cqr = tape_alloc_ccw_req (ti, 4, 0);
 	if (!cqr) {
 #ifdef TAPE_DEBUG
 	        debug_text_exception (tape_debug_area,6,"xeom nomem");
@@ -795,7 +796,7 @@
 	ccw->cmd_code = MODE_SET_DB;
 	ccw->flags = CCW_FLAG_CC;
 	ccw->count = 1;
-	set_normalized_cda (ccw, (unsigned long) (&(((tape34xx_disc_data_t *) tape->discdata)->modeset_byte)));
+	set_normalized_cda (ccw, (unsigned long) (&(((tape34xx_disc_data_t *) ti->discdata)->modeset_byte)));
 	ccw++;
 	ccw->cmd_code = FORSPACEFILE;
 	ccw->flags = CCW_FLAG_CC;
@@ -811,11 +812,11 @@
 	ccw->flags = 0;
 	ccw->count = 0;
 	ccw->cda = (unsigned long) (cqr->cpaddr);
-	s390irq_spin_lock_irqsave (tape->devinfo.irq, lockflags);
-	tape->kernbuf = NULL;
-	tape->userbuf = NULL;
-	tapestate_set (tape, TS_FSF_INIT);
-	s390irq_spin_unlock_irqrestore (tape->devinfo.irq, lockflags);
+	s390irq_spin_lock_irqsave (ti->devinfo.irq, lockflags);
+	ti->kernbuf = NULL;
+	ti->userbuf = NULL;
+	tapestate_set (ti, TS_FSF_INIT);
+	s390irq_spin_unlock_irqrestore (ti->devinfo.irq, lockflags);
 #ifdef TAPE_DEBUG
 	debug_text_event (tape_debug_area,6,"xeom ccwg");
 #endif /* TAPE_DEBUG */
@@ -826,12 +827,12 @@
  * MTERASE: erases the tape.
  */
 ccw_req_t *
-tape34xx_mterase (tape_info_t * tape, int count)
+tape34xx_mterase (tape_info_t * ti, int count)
 {
 	long lockflags;
 	ccw_req_t *cqr;
 	ccw1_t *ccw;
-	cqr = tape_alloc_ccw_req (tape, 5, 0);
+	cqr = tape_alloc_ccw_req (ti, 5, 0);
 	if (!cqr) {
 #ifdef TAPE_DEBUG
 	        debug_text_exception (tape_debug_area,6,"xera nomem");
@@ -842,7 +843,7 @@
 	ccw->cmd_code = MODE_SET_DB;
 	ccw->flags = CCW_FLAG_CC;
 	ccw->count = 1;
-	set_normalized_cda (ccw, (unsigned long) (&(((tape34xx_disc_data_t *) tape->discdata)->modeset_byte)));
+	set_normalized_cda (ccw, (unsigned long) (&(((tape34xx_disc_data_t *) ti->discdata)->modeset_byte)));
 	ccw++;
 	ccw->cmd_code = REWIND;
 	ccw->flags = CCW_FLAG_CC;
@@ -863,11 +864,11 @@
 	ccw->flags = 0;
 	ccw->count = 0;
 	ccw->cda = (unsigned long) (&(ccw->cmd_code));
-	s390irq_spin_lock_irqsave (tape->devinfo.irq, lockflags);
-	tape->kernbuf = NULL;
-	tape->userbuf = NULL;
-	tapestate_set (tape, TS_DSE_INIT);
-	s390irq_spin_unlock_irqrestore (tape->devinfo.irq, lockflags);
+	s390irq_spin_lock_irqsave (ti->devinfo.irq, lockflags);
+	ti->kernbuf = NULL;
+	ti->userbuf = NULL;
+	tapestate_set (ti, TS_DSE_INIT);
+	s390irq_spin_unlock_irqrestore (ti->devinfo.irq, lockflags);
 #ifdef TAPE_DEBUG
 	debug_text_event (tape_debug_area,6,"xera ccwg");
 #endif /* TAPE_DEBUG */
@@ -878,12 +879,12 @@
  * MTSETDENSITY: set tape density.
  */
 ccw_req_t *
-tape34xx_mtsetdensity (tape_info_t * tape, int count)
+tape34xx_mtsetdensity (tape_info_t * ti, int count)
 {
 	long lockflags;
 	ccw_req_t *cqr;
 	ccw1_t *ccw;
-	cqr = tape_alloc_ccw_req (tape, 2, 0);
+	cqr = tape_alloc_ccw_req (ti, 2, 0);
 	if (!cqr) {
 #ifdef TAPE_DEBUG
 	        debug_text_exception (tape_debug_area,6,"xden nomem");
@@ -894,17 +895,17 @@
 	ccw->cmd_code = MODE_SET_DB;
 	ccw->flags = CCW_FLAG_CC;
 	ccw->count = 1;
-	set_normalized_cda (ccw, (unsigned long) (&(((tape34xx_disc_data_t *) tape->discdata)->modeset_byte)));
+	set_normalized_cda (ccw, (unsigned long) (&(((tape34xx_disc_data_t *) ti->discdata)->modeset_byte)));
 	ccw++;
 	ccw->cmd_code = NOP;
 	ccw->flags = 0;
 	ccw->count = 0;
 	ccw->cda = (unsigned long) (&(ccw->cmd_code));
-	s390irq_spin_lock_irqsave (tape->devinfo.irq, lockflags);
-	tape->kernbuf = NULL;
-	tape->userbuf = NULL;
-	tapestate_set (tape, TS_NOP_INIT);
-	s390irq_spin_unlock_irqrestore (tape->devinfo.irq, lockflags);
+	s390irq_spin_lock_irqsave (ti->devinfo.irq, lockflags);
+	ti->kernbuf = NULL;
+	ti->userbuf = NULL;
+	tapestate_set (ti, TS_NOP_INIT);
+	s390irq_spin_unlock_irqrestore (ti->devinfo.irq, lockflags);
 #ifdef TAPE_DEBUG
 	debug_text_event (tape_debug_area,6,"xden ccwg");
 #endif /* TAPE_DEBUG */
@@ -915,7 +916,7 @@
  * MTSEEK: seek to the specified block.
  */
 ccw_req_t *
-tape34xx_mtseek (tape_info_t * tape, int count)
+tape34xx_mtseek (tape_info_t * ti, int count)
 {
 	long lockflags;
 	__u8 *data;
@@ -936,7 +937,7 @@
 		kfree(data);
 		return NULL;
 	}
-	if (((tape34xx_disc_data_t *) tape->discdata)->modeset_byte & 0x08)	// IDRC on
+	if (((tape34xx_disc_data_t *) ti->discdata)->modeset_byte & 0x08)	// IDRC on
 
 		data[1] = data[1] | 0x80;
 	data[3] += count % 256;
@@ -946,7 +947,7 @@
 	debug_text_event (tape_debug_area,6,"xsee id:");
 	debug_int_event (tape_debug_area,6,count);
 #endif /* TAPE_DEBUG */
-	cqr = tape_alloc_ccw_req (tape, 3, 0);
+	cqr = tape_alloc_ccw_req (ti, 3, 0);
 	if (!cqr) {
 #ifdef TAPE_DEBUG
 	        debug_text_exception (tape_debug_area,6,"xsee nomem");
@@ -958,7 +959,7 @@
 	ccw->cmd_code = MODE_SET_DB;
 	ccw->flags = CCW_FLAG_CC;
 	ccw->count = 1;
-	set_normalized_cda (ccw, (unsigned long) (&(((tape34xx_disc_data_t *) tape->discdata)->modeset_byte)));
+	set_normalized_cda (ccw, (unsigned long) (&(((tape34xx_disc_data_t *) ti->discdata)->modeset_byte)));
 	ccw++;
 	ccw->cmd_code = LOCATE;
 	ccw->flags = CCW_FLAG_CC;
@@ -969,11 +970,11 @@
 	ccw->flags = 0;
 	ccw->count = 0;
 	ccw->cda = (unsigned long) (&(ccw->cmd_code));
-	s390irq_spin_lock_irqsave (tape->devinfo.irq, lockflags);
-	tape->kernbuf = data;
-	tape->userbuf = NULL;
-	tapestate_set (tape, TS_LBL_INIT);
-	s390irq_spin_unlock_irqrestore (tape->devinfo.irq, lockflags);
+	s390irq_spin_lock_irqsave (ti->devinfo.irq, lockflags);
+	ti->kernbuf = data;
+	ti->userbuf = NULL;
+	tapestate_set (ti, TS_LBL_INIT);
+	s390irq_spin_unlock_irqrestore (ti->devinfo.irq, lockflags);
 #ifdef TAPE_DEBUG
 	debug_text_event (tape_debug_area,6,"xsee ccwg");
 #endif /* TAPE_DEBUG */
@@ -984,13 +985,13 @@
  * MTTELL: Tell block. Return the number of block relative to current file.
  */
 ccw_req_t *
-tape34xx_mttell (tape_info_t * tape, int count)
+tape34xx_mttell (tape_info_t * ti, int count)
 {
 	long lockflags;
 	ccw_req_t *cqr;
 	ccw1_t *ccw;
 	void *mem;
-	cqr = tape_alloc_ccw_req (tape, 2, 0);
+	cqr = tape_alloc_ccw_req (ti, 2, 0);
 	if (!cqr) {
 #ifdef TAPE_DEBUG
 	        debug_text_exception (tape_debug_area,6,"xtel nomem");
@@ -1009,18 +1010,18 @@
 	ccw->cmd_code = MODE_SET_DB;
 	ccw->flags = CCW_FLAG_CC;
 	ccw->count = 1;
-	set_normalized_cda (ccw, (unsigned long) (&(((tape34xx_disc_data_t *) tape->discdata)->modeset_byte)));
+	set_normalized_cda (ccw, (unsigned long) (&(((tape34xx_disc_data_t *) ti->discdata)->modeset_byte)));
 	ccw++;
 
 	ccw->cmd_code = READ_BLOCK_ID;
 	ccw->flags = 0;
 	ccw->count = 8;
 	set_normalized_cda (ccw, (unsigned long) mem);
-	s390irq_spin_lock_irqsave (tape->devinfo.irq, lockflags);
-	tape->kernbuf = mem;
-	tape->userbuf = NULL;
-	tapestate_set (tape, TS_RBI_INIT);
-	s390irq_spin_unlock_irqrestore (tape->devinfo.irq, lockflags);
+	s390irq_spin_lock_irqsave (ti->devinfo.irq, lockflags);
+	ti->kernbuf = mem;
+	ti->userbuf = NULL;
+	tapestate_set (ti, TS_RBI_INIT);
+	s390irq_spin_unlock_irqrestore (ti->devinfo.irq, lockflags);
 #ifdef TAPE_DEBUG
 	debug_text_event (tape_debug_area,6,"xtel ccwg");
 #endif /* TAPE_DEBUG */
@@ -1032,12 +1033,12 @@
  * Implement NOP.
  */
 ccw_req_t *
-tape34xx_mtsetdrvbuffer (tape_info_t * tape, int count)
+tape34xx_mtsetdrvbuffer (tape_info_t * ti, int count)
 {
 	long lockflags;
 	ccw_req_t *cqr;
 	ccw1_t *ccw;
-	cqr = tape_alloc_ccw_req (tape, 2, 0);
+	cqr = tape_alloc_ccw_req (ti, 2, 0);
 	if (!cqr) {
 #ifdef TAPE_DEBUG
 	        debug_text_exception (tape_debug_area,6,"xbuf nomem");
@@ -1048,17 +1049,17 @@
 	ccw->cmd_code = MODE_SET_DB;
 	ccw->flags = CCW_FLAG_CC;
 	ccw->count = 1;
-	set_normalized_cda (ccw, (unsigned long) (&(((tape34xx_disc_data_t *) tape->discdata)->modeset_byte)));
+	set_normalized_cda (ccw, (unsigned long) (&(((tape34xx_disc_data_t *) ti->discdata)->modeset_byte)));
 	ccw++;
 	ccw->cmd_code = NOP;
 	ccw->flags = 0;
 	ccw->count = 0;
 	ccw->cda = (unsigned long) (&(ccw->cmd_code));
-	s390irq_spin_lock_irqsave (tape->devinfo.irq, lockflags);
-	tape->kernbuf = NULL;
-	tape->userbuf = NULL;
-	tapestate_set (tape, TS_NOP_INIT);
-	s390irq_spin_unlock_irqrestore (tape->devinfo.irq, lockflags);
+	s390irq_spin_lock_irqsave (ti->devinfo.irq, lockflags);
+	ti->kernbuf = NULL;
+	ti->userbuf = NULL;
+	tapestate_set (ti, TS_NOP_INIT);
+	s390irq_spin_unlock_irqrestore (ti->devinfo.irq, lockflags);
 #ifdef TAPE_DEBUG
 	debug_text_event (tape_debug_area,6,"xbuf ccwg");
 #endif /* TAPE_DEBUG */
@@ -1070,12 +1071,12 @@
  * Implement NOP CCW command.
  */
 ccw_req_t *
-tape34xx_mtlock (tape_info_t * tape, int count)
+tape34xx_mtlock (tape_info_t * ti, int count)
 {
 	long lockflags;
 	ccw_req_t *cqr;
 	ccw1_t *ccw;
-	cqr = tape_alloc_ccw_req (tape, 2, 0);
+	cqr = tape_alloc_ccw_req (ti, 2, 0);
 	if (!cqr) {
 #ifdef TAPE_DEBUG
 	        debug_text_exception (tape_debug_area,6,"xloc nomem");
@@ -1086,17 +1087,17 @@
 	ccw->cmd_code = MODE_SET_DB;
 	ccw->flags = CCW_FLAG_CC;
 	ccw->count = 1;
-	set_normalized_cda (ccw, (unsigned long) (&(((tape34xx_disc_data_t *) tape->discdata)->modeset_byte)));
+	set_normalized_cda (ccw, (unsigned long) (&(((tape34xx_disc_data_t *) ti->discdata)->modeset_byte)));
 	ccw++;
 	ccw->cmd_code = NOP;
 	ccw->flags = 0;
 	ccw->count = 0;
 	ccw->cda = (unsigned long) (&(ccw->cmd_code));
-	s390irq_spin_lock_irqsave (tape->devinfo.irq, lockflags);
-	tape->kernbuf = NULL;
-	tape->userbuf = NULL;
-	tapestate_set (tape, TS_NOP_INIT);
-	s390irq_spin_unlock_irqrestore (tape->devinfo.irq, lockflags);
+	s390irq_spin_lock_irqsave (ti->devinfo.irq, lockflags);
+	ti->kernbuf = NULL;
+	ti->userbuf = NULL;
+	tapestate_set (ti, TS_NOP_INIT);
+	s390irq_spin_unlock_irqrestore (ti->devinfo.irq, lockflags);
 #ifdef TAPE_DEBUG
 	debug_text_event (tape_debug_area,6,"xloc ccwg");
 #endif /* TAPE_DEBUG */
@@ -1108,12 +1109,12 @@
  * Implement the NOP CCW command.
  */
 ccw_req_t *
-tape34xx_mtunlock (tape_info_t * tape, int count)
+tape34xx_mtunlock (tape_info_t * ti, int count)
 {
 	long lockflags;
 	ccw_req_t *cqr;
 	ccw1_t *ccw;
-	cqr = tape_alloc_ccw_req (tape, 2, 0);
+	cqr = tape_alloc_ccw_req (ti, 2, 0);
 	if (!cqr) {
 #ifdef TAPE_DEBUG
 	        debug_text_exception (tape_debug_area,6,"xulk nomem");
@@ -1124,17 +1125,17 @@
 	ccw->cmd_code = MODE_SET_DB;
 	ccw->flags = CCW_FLAG_CC;
 	ccw->count = 1;
-	set_normalized_cda (ccw, (unsigned long) (&(((tape34xx_disc_data_t *) tape->discdata)->modeset_byte)));
+	set_normalized_cda (ccw, (unsigned long) (&(((tape34xx_disc_data_t *) ti->discdata)->modeset_byte)));
 	ccw++;
 	ccw->cmd_code = NOP;
 	ccw->flags = 0;
 	ccw->count = 0;
 	ccw->cda = (unsigned long) (&(ccw->cmd_code));
-	s390irq_spin_lock_irqsave (tape->devinfo.irq, lockflags);
-	tape->kernbuf = NULL;
-	tape->userbuf = NULL;
-	tapestate_set (tape, TS_NOP_INIT);
-	s390irq_spin_unlock_irqrestore (tape->devinfo.irq, lockflags);
+	s390irq_spin_lock_irqsave (ti->devinfo.irq, lockflags);
+	ti->kernbuf = NULL;
+	ti->userbuf = NULL;
+	tapestate_set (ti, TS_NOP_INIT);
+	s390irq_spin_unlock_irqrestore (ti->devinfo.irq, lockflags);
 #ifdef TAPE_DEBUG
 	debug_text_event (tape_debug_area,6,"xulk ccwg");
 #endif /* TAPE_DEBUG */
@@ -1143,52 +1144,25 @@
 
 /*
  * MTLOAD: Loads the tape.
- * Implement the NOP CCW command.
+ * This function is not implemented and returns NULL, which causes the Frontend to wait for a medium being loaded.
+ *  The 3480/3490 type Tapes do not support a load command
  */
 ccw_req_t *
-tape34xx_mtload (tape_info_t * tape, int count)
+tape34xx_mtload (tape_info_t * ti, int count)
 {
-	long lockflags;
-	ccw_req_t *cqr;
-	ccw1_t *ccw;
-	cqr = tape_alloc_ccw_req (tape, 2, 0);
-	if (!cqr) {
-#ifdef TAPE_DEBUG
-	        debug_text_exception (tape_debug_area,6,"xloa nomem");
-#endif /* TAPE_DEBUG */
-		return NULL;
-	}
-	ccw = cqr->cpaddr;
-	ccw->cmd_code = MODE_SET_DB;
-	ccw->flags = CCW_FLAG_CC;
-	ccw->count = 1;
-	set_normalized_cda (ccw, (unsigned long) (&(((tape34xx_disc_data_t *) tape->discdata)->modeset_byte)));
-	ccw++;
-	ccw->cmd_code = NOP;
-	ccw->flags = 0;
-	ccw->count = 0;
-	ccw->cda = (unsigned long) (&(ccw->cmd_code));
-	s390irq_spin_lock_irqsave (tape->devinfo.irq, lockflags);
-	tape->kernbuf = NULL;
-	tape->userbuf = NULL;
-	tapestate_set (tape, TS_NOP_INIT);
-	s390irq_spin_unlock_irqrestore (tape->devinfo.irq, lockflags);
-#ifdef TAPE_DEBUG
-	debug_text_event (tape_debug_area,6,"xloa ccwg");
-#endif /* TAPE_DEBUG */
-	return cqr;
+         return NULL;
 }
 
 /*
  * MTUNLOAD: Rewind the tape and unload it.
  */
 ccw_req_t *
-tape34xx_mtunload (tape_info_t * tape, int count)
+tape34xx_mtunload (tape_info_t * ti, int count)
 {
 	long lockflags;
 	ccw_req_t *cqr;
 	ccw1_t *ccw;
-	cqr = tape_alloc_ccw_req (tape, 3, 32);
+	cqr = tape_alloc_ccw_req (ti, 3, 32);
 	if (!cqr) {
 #ifdef TAPE_DEBUG
 	        debug_text_exception (tape_debug_area,6,"xunl nomem");
@@ -1199,7 +1173,7 @@
 	ccw->cmd_code = MODE_SET_DB;
 	ccw->flags = CCW_FLAG_CC;
 	ccw->count = 1;
-	set_normalized_cda (ccw, (unsigned long) (&(((tape34xx_disc_data_t *) tape->discdata)->modeset_byte)));
+	set_normalized_cda (ccw, (unsigned long) (&(((tape34xx_disc_data_t *) ti->discdata)->modeset_byte)));
 	ccw++;
 	ccw->cmd_code = REWIND_UNLOAD;
 	ccw->flags = CCW_FLAG_CC;
@@ -1210,11 +1184,11 @@
 	ccw->flags = 0;
 	ccw->count = 32;
 	ccw->cda = (unsigned long) cqr->cpaddr;
-	s390irq_spin_lock_irqsave (tape->devinfo.irq, lockflags);
-	tape->kernbuf = NULL;
-	tape->userbuf = NULL;
-	tapestate_set (tape, TS_RUN_INIT);
-	s390irq_spin_unlock_irqrestore (tape->devinfo.irq, lockflags);
+	s390irq_spin_lock_irqsave (ti->devinfo.irq, lockflags);
+	ti->kernbuf = NULL;
+	ti->userbuf = NULL;
+	tapestate_set (ti, TS_RUN_INIT);
+	s390irq_spin_unlock_irqrestore (ti->devinfo.irq, lockflags);
 #ifdef TAPE_DEBUG
 	debug_text_event (tape_debug_area,6,"xunl ccwg");
 #endif /* TAPE_DEBUG */
@@ -1226,7 +1200,7 @@
  * Sets the IDRC on/off.
  */
 ccw_req_t *
-tape34xx_mtcompression (tape_info_t * tape, int count)
+tape34xx_mtcompression (tape_info_t * ti, int count)
 {
 	long lockflags;
 	ccw_req_t *cqr;
@@ -1238,12 +1212,12 @@
 		return NULL;
 	}
 	if (count == 0)
-		((tape34xx_disc_data_t *) tape->discdata)->modeset_byte = 0x00;		// IDRC off
+		((tape34xx_disc_data_t *) ti->discdata)->modeset_byte = 0x00;		// IDRC off
 
 	else
-		((tape34xx_disc_data_t *) tape->discdata)->modeset_byte = 0x08;		// IDRC on
+		((tape34xx_disc_data_t *) ti->discdata)->modeset_byte = 0x08;		// IDRC on
 
-	cqr = tape_alloc_ccw_req (tape, 2, 0);
+	cqr = tape_alloc_ccw_req (ti, 2, 0);
 	if (!cqr) {
 #ifdef TAPE_DEBUG
 	        debug_text_exception (tape_debug_area,6,"xcom nomem");
@@ -1254,17 +1228,17 @@
 	ccw->cmd_code = MODE_SET_DB;
 	ccw->flags = CCW_FLAG_CC;
 	ccw->count = 1;
-	set_normalized_cda (ccw, (unsigned long) (&(((tape34xx_disc_data_t *) tape->discdata)->modeset_byte)));
+	set_normalized_cda (ccw, (unsigned long) (&(((tape34xx_disc_data_t *) ti->discdata)->modeset_byte)));
 	ccw++;
 	ccw->cmd_code = NOP;
 	ccw->flags = 0;
 	ccw->count = 0;
 	ccw->cda = (unsigned long) (&(ccw->cmd_code));
-	s390irq_spin_lock_irqsave (tape->devinfo.irq, lockflags);
-	tape->kernbuf = NULL;
-	tape->userbuf = NULL;
-	tapestate_set (tape, TS_NOP_INIT);
-	s390irq_spin_unlock_irqrestore (tape->devinfo.irq, lockflags);
+	s390irq_spin_lock_irqsave (ti->devinfo.irq, lockflags);
+	ti->kernbuf = NULL;
+	ti->userbuf = NULL;
+	tapestate_set (ti, TS_NOP_INIT);
+	s390irq_spin_unlock_irqrestore (ti->devinfo.irq, lockflags);
 #ifdef TAPE_DEBUG
 	debug_text_event (tape_debug_area,6,"xcom ccwg");
 #endif /* TAPE_DEBUG */
@@ -1276,12 +1250,12 @@
  * Implement the NOP CCW command.
  */
 ccw_req_t *
-tape34xx_mtsetpart (tape_info_t * tape, int count)
+tape34xx_mtsetpart (tape_info_t * ti, int count)
 {
 	long lockflags;
 	ccw_req_t *cqr;
 	ccw1_t *ccw;
-	cqr = tape_alloc_ccw_req (tape, 2, 0);
+	cqr = tape_alloc_ccw_req (ti, 2, 0);
 	if (!cqr) {
 #ifdef TAPE_DEBUG
 	        debug_text_exception (tape_debug_area,6,"xspa nomem");
@@ -1292,17 +1266,17 @@
 	ccw->cmd_code = MODE_SET_DB;
 	ccw->flags = CCW_FLAG_CC;
 	ccw->count = 1;
-	set_normalized_cda (ccw, (unsigned long) (&(((tape34xx_disc_data_t *) tape->discdata)->modeset_byte)));
+	set_normalized_cda (ccw, (unsigned long) (&(((tape34xx_disc_data_t *) ti->discdata)->modeset_byte)));
 	ccw++;
 	ccw->cmd_code = NOP;
 	ccw->flags = 0;
 	ccw->count = 0;
 	ccw->cda = (unsigned long) (&(ccw->cmd_code));
-	s390irq_spin_lock_irqsave (tape->devinfo.irq, lockflags);
-	tape->kernbuf = NULL;
-	tape->userbuf = NULL;
-	tapestate_set (tape, TS_NOP_INIT);
-	s390irq_spin_unlock_irqrestore (tape->devinfo.irq, lockflags);
+	s390irq_spin_lock_irqsave (ti->devinfo.irq, lockflags);
+	ti->kernbuf = NULL;
+	ti->userbuf = NULL;
+	tapestate_set (ti, TS_NOP_INIT);
+	s390irq_spin_unlock_irqrestore (ti->devinfo.irq, lockflags);
 #ifdef TAPE_DEBUG
 	debug_text_event (tape_debug_area,6,"xspa ccwg");
 #endif /* TAPE_DEBUG */
@@ -1314,12 +1288,12 @@
  * Implement the NOP CCW command.
  */
 ccw_req_t *
-tape34xx_mtmkpart (tape_info_t * tape, int count)
+tape34xx_mtmkpart (tape_info_t * ti, int count)
 {
 	long lockflags;
 	ccw_req_t *cqr;
 	ccw1_t *ccw;
-	cqr = tape_alloc_ccw_req (tape, 2, 0);
+	cqr = tape_alloc_ccw_req (ti, 2, 0);
 	if (!cqr) {
 #ifdef TAPE_DEBUG
 	        debug_text_exception (tape_debug_area,6,"xnpa nomem");
@@ -1330,17 +1304,17 @@
 	ccw->cmd_code = MODE_SET_DB;
 	ccw->flags = CCW_FLAG_CC;
 	ccw->count = 1;
-	set_normalized_cda (ccw, (unsigned long) (&(((tape34xx_disc_data_t *) tape->discdata)->modeset_byte)));
+	set_normalized_cda (ccw, (unsigned long) (&(((tape34xx_disc_data_t *) ti->discdata)->modeset_byte)));
 	ccw++;
 	ccw->cmd_code = NOP;
 	ccw->flags = 0;
 	ccw->count = 0;
 	ccw->cda = (unsigned long) (&(ccw->cmd_code));
-	s390irq_spin_lock_irqsave (tape->devinfo.irq, lockflags);
-	tape->kernbuf = NULL;
-	tape->userbuf = NULL;
-	tapestate_set (tape, TS_NOP_INIT);
-	s390irq_spin_unlock_irqrestore (tape->devinfo.irq, lockflags);
+	s390irq_spin_lock_irqsave (ti->devinfo.irq, lockflags);
+	ti->kernbuf = NULL;
+	ti->userbuf = NULL;
+	tapestate_set (ti, TS_NOP_INIT);
+	s390irq_spin_unlock_irqrestore (ti->devinfo.irq, lockflags);
 #ifdef TAPE_DEBUG
 	debug_text_event (tape_debug_area,6,"xnpa ccwg");
 #endif /* TAPE_DEBUG */
@@ -1351,7 +1325,7 @@
  * MTIOCGET: query the tape drive status.
  */
 ccw_req_t *
-tape34xx_mtiocget (tape_info_t * tape, int count)
+tape34xx_mtiocget (tape_info_t * ti, int count)
 {
 	return NULL;
 }
@@ -1360,22 +1334,22 @@
  * MTIOCPOS: query the tape position.
  */
 ccw_req_t *
-tape34xx_mtiocpos (tape_info_t * tape, int count)
+tape34xx_mtiocpos (tape_info_t * ti, int count)
 {
 	return NULL;
 }
 
-ccw_req_t * tape34xx_bread (struct request *req,tape_info_t* tape,int tapeblock_major) {
+ccw_req_t * tape34xx_bread (struct request *req,tape_info_t* ti,int tapeblock_major) {
 	ccw_req_t *cqr;
 	ccw1_t *ccw;
 	__u8 *data;
-	int s2b = blksize_size[tapeblock_major][tape->blk_minor]/hardsect_size[tapeblock_major][tape->blk_minor];
+	int s2b = blksize_size[tapeblock_major][ti->blk_minor]/hardsect_size[tapeblock_major][ti->blk_minor];
 	int realcount;
 	int size,bhct = 0;
 	struct buffer_head* bh;
 	for (bh = req->bh; bh; bh = bh->b_reqnext) {
-		if (bh->b_size > blksize_size[tapeblock_major][tape->blk_minor])
-			for (size = 0; size < bh->b_size; size += blksize_size[tapeblock_major][tape->blk_minor])
+		if (bh->b_size > blksize_size[tapeblock_major][ti->blk_minor])
+			for (size = 0; size < bh->b_size; size += blksize_size[tapeblock_major][ti->blk_minor])
 				bhct++;
 		else
 			bhct++;
@@ -1389,7 +1363,7 @@
 	data[0] = 0x01;
 	data[1] = data[2] = data[3] = 0x00;
 	realcount=req->sector/s2b;
-	if (((tape34xx_disc_data_t *) tape->discdata)->modeset_byte & 0x08)	// IDRC on
+	if (((tape34xx_disc_data_t *) ti->discdata)->modeset_byte & 0x08)	// IDRC on
 
 		data[1] = data[1] | 0x80;
 	data[3] += realcount % 256;
@@ -1399,7 +1373,7 @@
 	debug_text_event (tape_debug_area,6,"xBREDid:");
 	debug_int_event (tape_debug_area,6,realcount);
 #endif /* TAPE_DEBUG */
-	cqr = tape_alloc_ccw_req (tape, 2+bhct+1, 0);
+	cqr = tape_alloc_ccw_req (ti, 2+bhct+1, 0);
 	if (!cqr) {
 #ifdef TAPE_DEBUG
 	        debug_text_exception (tape_debug_area,6,"xBREDnomem");
@@ -1411,28 +1385,28 @@
 	ccw->cmd_code = MODE_SET_DB;
 	ccw->flags = CCW_FLAG_CC;
 	ccw->count = 1;
-	set_normalized_cda (ccw, (unsigned long) (&(((tape34xx_disc_data_t *) tape->discdata)->modeset_byte)));
-	if (realcount!=tape->position) {
+	set_normalized_cda (ccw, (unsigned long) (&(((tape34xx_disc_data_t *) ti->discdata)->modeset_byte)));
+	if (realcount!=ti->position) {
 	    ccw++;
 	    ccw->cmd_code = LOCATE;
 	    ccw->flags = CCW_FLAG_CC;
 	    ccw->count = 4;
 	    set_normalized_cda (ccw, (unsigned long) data);
 	}
-	tape->position=realcount+req->nr_sectors/s2b;
+	ti->position=realcount+req->nr_sectors/s2b;
 	for (bh=req->bh;bh!=NULL;) {
 	        ccw->flags = CCW_FLAG_CC;
-		if (bh->b_size >= blksize_size[tapeblock_major][tape->blk_minor]) {
-			for (size = 0; size < bh->b_size; size += blksize_size[tapeblock_major][tape->blk_minor]) {
+		if (bh->b_size >= blksize_size[tapeblock_major][ti->blk_minor]) {
+			for (size = 0; size < bh->b_size; size += blksize_size[tapeblock_major][ti->blk_minor]) {
 			        ccw++;
 				ccw->flags = CCW_FLAG_CC;
 				ccw->cmd_code = READ_FORWARD;
-				ccw->count = blksize_size[tapeblock_major][tape->blk_minor];
+				ccw->count = blksize_size[tapeblock_major][ti->blk_minor];
 				set_normalized_cda (ccw, __pa (bh->b_data + size));
 			}
 			bh = bh->b_reqnext;
 		} else {	/* group N bhs to fit into byt_per_blk */
-			for (size = 0; bh != NULL && size < blksize_size[tapeblock_major][tape->blk_minor];) {
+			for (size = 0; bh != NULL && size < blksize_size[tapeblock_major][ti->blk_minor];) {
 				ccw++;
 				ccw->flags = CCW_FLAG_DC;
 				ccw->cmd_code = READ_FORWARD;
@@ -1441,10 +1415,10 @@
 				size += bh->b_size;
 				bh = bh->b_reqnext;
 			}
-			if (size != blksize_size[tapeblock_major][tape->blk_minor]) {
+			if (size != blksize_size[tapeblock_major][ti->blk_minor]) {
 				PRINT_WARN ("Cannot fulfill small request %d vs. %d (%ld sects)\n",
 					    size,
-					    blksize_size[tapeblock_major][tape->blk_minor],
+					    blksize_size[tapeblock_major][ti->blk_minor],
 					    req->nr_sectors);
 				kfree(data);
 				tape_free_request (cqr);
@@ -1459,15 +1433,15 @@
 	ccw->flags = 0;
 	ccw->count = 0;
 	ccw->cda = (unsigned long) (&(ccw->cmd_code));
-	tape->kernbuf = data;
-	tape->userbuf = NULL;
-	tapestate_set (tape, TS_BLOCK_INIT);
+	ti->kernbuf = data;
+	ti->userbuf = NULL;
+	tapestate_set (ti, TS_BLOCK_INIT);
 #ifdef TAPE_DEBUG
 	debug_text_event (tape_debug_area,6,"xBREDccwg");
 #endif /* TAPE_DEBUG */
 	return cqr;
 }
-void tape34xx_free_bread (ccw_req_t* cqr,struct _tape_info_t* tape) {
+void tape34xx_free_bread (ccw_req_t* cqr,struct _tape_info_t* ti) {
     ccw1_t* ccw;
     for (ccw=(ccw1_t*)cqr->cpaddr;(ccw->flags & CCW_FLAG_CC)||(ccw->flags & CCW_FLAG_DC);ccw++) 
 	if ((ccw->cmd_code == MODE_SET_DB) ||
@@ -1475,49 +1449,60 @@
 	    (ccw->cmd_code == READ_FORWARD))
 	    clear_normalized_cda(ccw);
     tape_free_request(cqr);
-    kfree(tape->kernbuf);
-    tape->kernbuf=NULL;
+    kfree(ti->kernbuf);
+    ti->kernbuf=NULL;
 }
 
 /* event handlers */
 void
-tape34xx_default_handler (tape_info_t * tape)
+tape34xx_default_handler (tape_info_t * ti)
 {
 #ifdef TAPE_DEBUG
     debug_text_event (tape_debug_area,6,"xdefhandle");
 #endif /* TAPE_DEBUG */
-	tapestate_set (tape, TS_FAILED);
 	PRINT_ERR ("TAPE34XX: An unexpected Unit Check occurred.\n");
 	PRINT_ERR ("TAPE34XX: Please read Documentation/s390/TAPE and report it!\n");
 	PRINT_ERR ("TAPE34XX: Current state is: %s",
-		   (((tapestate_get (tape) < TS_SIZE) && (tapestate_get (tape) >= 0)) ?
-		    state_verbose[tapestate_get (tape)] : "->UNKNOWN STATE<-"));
-	tape_dump_sense (&tape->devstat);
-	tape->rc = -EIO;
-	tape->wanna_wakeup=1;
-	wake_up_interruptible (&tape->wq);
+		   (((tapestate_get (ti) < TS_SIZE) && (tapestate_get (ti) >= 0)) ?
+		    state_verbose[tapestate_get (ti)] : "->UNKNOWN STATE<-"));
+	tape_dump_sense (&ti->devstat);
+	ti->rc = -EIO;
+	ti->wanna_wakeup=1;
+        switch (tapestate_get(ti)) {
+        case TS_REW_RELEASE_INIT:
+            tapestate_set(ti,TS_FAILED);
+            wake_up (&ti->wq);
+            break;
+        case TS_BLOCK_INIT:
+            tapestate_set(ti,TS_FAILED);
+            schedule_tapeblock_exec_IO(ti);
+            break;
+        default:
+            tapestate_set(ti,TS_FAILED);
+            wake_up_interruptible (&ti->wq);
+        }      
 }
 
 void
-tape34xx_unexpect_uchk_handler (tape_info_t * tape)
+tape34xx_unexpect_uchk_handler (tape_info_t * ti)
 {
-	if ((tape->devstat.ii.sense.data[0] == 0x40) &&
-	    (tape->devstat.ii.sense.data[1] == 0x40) &&
-	    (tape->devstat.ii.sense.data[3] == 0x43)) {
+	if ((ti->devstat.ii.sense.data[0] == 0x40) &&
+	    (ti->devstat.ii.sense.data[1] == 0x40) &&
+	    (ti->devstat.ii.sense.data[3] == 0x43)) {
 		// no tape in the drive
-	        PRINT_INFO ("Drive %d not ready. No volume loaded.\n", tape->rew_minor / 2);
+	        PRINT_INFO ("Drive %d not ready. No volume loaded.\n", ti->rew_minor / 2);
 #ifdef TAPE_DEBUG
 	        debug_text_event (tape_debug_area,3,"xuuh nomed");
 #endif /* TAPE_DEBUG */
-		tapestate_set (tape, TS_FAILED);
-		tape->rc = -ENOMEDIUM;
-		tape->wanna_wakeup=1;
-		wake_up_interruptible (&tape->wq);
-	} else if ((tape->devstat.ii.sense.data[0] == 0x42) &&
-		   (tape->devstat.ii.sense.data[1] == 0x44) &&
-		   (tape->devstat.ii.sense.data[3] == 0x3b)) {
+		tapestate_set (ti, TS_FAILED);
+		ti->rc = -ENOMEDIUM;
+		ti->wanna_wakeup=1;
+		wake_up_interruptible (&ti->wq);
+	} else if ((ti->devstat.ii.sense.data[0] == 0x42) &&
+		   (ti->devstat.ii.sense.data[1] == 0x44) &&
+		   (ti->devstat.ii.sense.data[3] == 0x3b)) {
        	        PRINT_INFO ("Media in drive %d was changed!\n",
-			    tape->rew_minor / 2);
+			    ti->rew_minor / 2);
 #ifdef TAPE_DEBUG
 		debug_text_event (tape_debug_area,3,"xuuh medchg");
 #endif
@@ -1526,261 +1511,273 @@
 #ifdef TAPE_DEBUG
 	        debug_text_event (tape_debug_area,3,"xuuh unexp");
 	        debug_text_event (tape_debug_area,3,"state:");
-	        debug_text_event (tape_debug_area,3,((tapestate_get (tape) < TS_SIZE) && 
-						     (tapestate_get (tape) >= 0)) ?
-				  state_verbose[tapestate_get (tape)] : 
+	        debug_text_event (tape_debug_area,3,((tapestate_get (ti) < TS_SIZE) && 
+						     (tapestate_get (ti) >= 0)) ?
+				  state_verbose[tapestate_get (ti)] : 
 				  "TS UNKNOWN");
 #endif /* TAPE_DEBUG */
-		tape34xx_default_handler (tape);
+		tape34xx_default_handler (ti);
 	}
 }
 
 void
-tape34xx_unused_done (tape_info_t * tape)
+tape34xx_unused_done (tape_info_t * ti)
 {
-	if ((tape->devstat.ii.sense.data[0] == 0x40) &&
-	    (tape->devstat.ii.sense.data[1] == 0x40) &&
-	    (tape->devstat.ii.sense.data[3] == 0x43)) {
-	    // A medium was inserted in the drive!
+    if (ti->medium_is_unloaded) {
+	// A medium was inserted in the drive!
 #ifdef TAPE_DEBUG
-	    debug_text_event (tape_debug_area,6,"xuud med");
+	debug_text_event (tape_debug_area,6,"xuui med");
 #endif /* TAPE_DEBUG */
-	} else {
+	PRINT_WARN ("A medium was inserted into the tape.\n");
+	ti->medium_is_unloaded=0;
+    } else {
 #ifdef TAPE_DEBUG
-	        debug_text_event (tape_debug_area,3,"unsol.irq!");
-	        debug_text_event (tape_debug_area,3,"dev end");
-	        debug_int_exception (tape_debug_area,3,tape->devinfo.irq);
+        debug_text_event (tape_debug_area,3,"unsol.irq!");
+        debug_text_event (tape_debug_area,3,"dev end");
+        debug_int_exception (tape_debug_area,3,ti->devinfo.irq);
 #endif /* TAPE_DEBUG */
-		PRINT_WARN ("Unsolicited IRQ (Device End) caught in unused state.\n");
-		tape_dump_sense (&tape->devstat);
-	}
+	PRINT_WARN ("Unsolicited IRQ (Device End) caught in unused state.\n");
+	tape_dump_sense (&ti->devstat);
+    }
 }
 
 
 void
-tape34xx_idle_done (tape_info_t * tape)
+tape34xx_idle_done (tape_info_t * ti)
 {
+    if (ti->medium_is_unloaded) {
+	// A medium was inserted in the drive!
+#ifdef TAPE_DEBUG
+	debug_text_event (tape_debug_area,6,"xuud med");
+#endif /* TAPE_DEBUG */
+	PRINT_WARN ("A medium was inserted into the tape.\n");
+	ti->medium_is_unloaded=0;
+	wake_up_interruptible (&ti->wq);
+    } else {
 #ifdef TAPE_DEBUG
         debug_text_event (tape_debug_area,3,"unsol.irq!");
         debug_text_event (tape_debug_area,3,"dev end");
-        debug_int_exception (tape_debug_area,3,tape->devinfo.irq);
+        debug_int_exception (tape_debug_area,3,ti->devinfo.irq);
 #endif /* TAPE_DEBUG */
 	PRINT_WARN ("Unsolicited IRQ (Device End) caught in idle state.\n");
-	tape_dump_sense (&tape->devstat);
+	tape_dump_sense (&ti->devstat);
+    }
 }
 
 void
-tape34xx_block_done (tape_info_t * tape)
+tape34xx_block_done (tape_info_t * ti)
 {
 #ifdef TAPE_DEBUG
         debug_text_event (tape_debug_area,6,"x:bREQdone");
 #endif /* TAPE_DEBUG */
-	tapestate_set(tape,TS_DONE);
-	schedule_tapeblock_exec_IO(tape);
+	tapestate_set(ti,TS_DONE);
+	schedule_tapeblock_exec_IO(ti);
 }
 
 void
-tape34xx_bsf_init_done (tape_info_t * tape)
+tape34xx_bsf_init_done (tape_info_t * ti)
 {
 #ifdef TAPE_DEBUG
         debug_text_event (tape_debug_area,6,"bsf done");
 #endif
-	tapestate_set (tape, TS_DONE);
-	tape->rc = 0;
-	tape->wanna_wakeup=1;
-	wake_up_interruptible (&tape->wq);
+	tapestate_set (ti, TS_DONE);
+	ti->rc = 0;
+	ti->wanna_wakeup=1;
+	wake_up_interruptible (&ti->wq);
 }
 
 void
-tape34xx_dse_init_done (tape_info_t * tape)
+tape34xx_dse_init_done (tape_info_t * ti)
 {
 #ifdef TAPE_DEBUG
         debug_text_event (tape_debug_area,6,"dse done");
 #endif
-	tapestate_set (tape, TS_DONE);
-	tape->rc = 0;
-	tape->wanna_wakeup=1;
-	wake_up_interruptible (&tape->wq);
+	tapestate_set (ti, TS_DONE);
+	ti->rc = 0;
+	ti->wanna_wakeup=1;
+	wake_up_interruptible (&ti->wq);
 }
 
 void
-tape34xx_fsf_init_done (tape_info_t * tape)
+tape34xx_fsf_init_done (tape_info_t * ti)
 {
 #ifdef TAPE_DEBUG
         debug_text_event (tape_debug_area,6,"fsf done");
 #endif
-	tapestate_set (tape, TS_DONE);
-	tape->rc = 0;
-	tape->wanna_wakeup=1;
-	wake_up_interruptible (&tape->wq);
+	tapestate_set (ti, TS_DONE);
+	ti->rc = 0;
+	ti->wanna_wakeup=1;
+	wake_up_interruptible (&ti->wq);
 }
 
 void
-tape34xx_fsb_init_done (tape_info_t * tape)
+tape34xx_fsb_init_done (tape_info_t * ti)
 {
 #ifdef TAPE_DEBUG
         debug_text_event (tape_debug_area,6,"fsb done");
 #endif
-	tapestate_set (tape, TS_DONE);
-	tape->rc = 0;
-	tape->wanna_wakeup=1;
-	wake_up_interruptible (&tape->wq);
+	tapestate_set (ti, TS_DONE);
+	ti->rc = 0;
+	ti->wanna_wakeup=1;
+	wake_up_interruptible (&ti->wq);
 }
 
 void
-tape34xx_bsb_init_done (tape_info_t * tape)
+tape34xx_bsb_init_done (tape_info_t * ti)
 {
 #ifdef TAPE_DEBUG
         debug_text_event (tape_debug_area,6,"bsb done");
 #endif
-	tapestate_set (tape, TS_DONE);
-	tape->rc = 0;
-	tape->wanna_wakeup=1;
-	wake_up_interruptible (&tape->wq);
+	tapestate_set (ti, TS_DONE);
+	ti->rc = 0;
+	ti->wanna_wakeup=1;
+	wake_up_interruptible (&ti->wq);
 }
 
 void
-tape34xx_lbl_init_done (tape_info_t * tape)
+tape34xx_lbl_init_done (tape_info_t * ti)
 {
 #ifdef TAPE_DEBUG
         debug_text_event (tape_debug_area,6,"lbl done");
 #endif
-	tapestate_set (tape, TS_DONE);
-	tape->rc = 0;
+	tapestate_set (ti, TS_DONE);
+	ti->rc = 0;
 	//s390irq_spin_unlock(tape->devinfo.irq);
-	tape->wanna_wakeup=1;
-	wake_up (&tape->wq);
+	ti->wanna_wakeup=1;
+	wake_up (&ti->wq);
 }
 
 void
-tape34xx_nop_init_done (tape_info_t * tape)
+tape34xx_nop_init_done (tape_info_t * ti)
 {
 #ifdef TAPE_DEBUG
         debug_text_event (tape_debug_area,6,"nop done..");
         debug_text_exception (tape_debug_area,6,"or rew/rel");
 #endif
-	tapestate_set (tape, TS_DONE);
-	tape->rc = 0;
+	tapestate_set (ti, TS_DONE);
+	ti->rc = 0;
 	//s390irq_spin_unlock(tape->devinfo.irq);
-	tape->wanna_wakeup=1;
-	wake_up (&tape->wq);
+	ti->wanna_wakeup=1;
+	wake_up (&ti->wq);
 }
 
 void
-tape34xx_rfo_init_done (tape_info_t * tape)
+tape34xx_rfo_init_done (tape_info_t * ti)
 {
 #ifdef TAPE_DEBUG
         debug_text_event (tape_debug_area,6,"rfo done");
 #endif
-	tapestate_set (tape, TS_DONE);
-	tape->rc = 0;
-	tape->wanna_wakeup=1;
-	wake_up_interruptible (&tape->wq);
+	tapestate_set (ti, TS_DONE);
+	ti->rc = 0;
+	ti->wanna_wakeup=1;
+	wake_up_interruptible (&ti->wq);
 }
 
 void
-tape34xx_rbi_init_done (tape_info_t * tape)
+tape34xx_rbi_init_done (tape_info_t * ti)
 {
 	__u8 *data;
+#ifdef TAPE_DEBUG
 	int i;
-	tapestate_set (tape, TS_FAILED);
-	data = tape->kernbuf;
-	tape->rc = data[3];
-	tape->rc += 256 * data[2];
-	tape->rc += 65536 * (data[1] & 0x3F);
+#endif
+	tapestate_set (ti, TS_FAILED);
+	data = ti->kernbuf;
+	ti->rc = data[3];
+	ti->rc += 256 * data[2];
+	ti->rc += 65536 * (data[1] & 0x3F);
 #ifdef TAPE_DEBUG
         debug_text_event (tape_debug_area,6,"rbi done");
         debug_text_event (tape_debug_area,6,"data:");
 	for (i=0;i<8;i++)
 	    debug_int_event (tape_debug_area,6,data[i]);
 #endif
-	tape->wanna_wakeup=1;
-	wake_up_interruptible (&tape->wq);
+	ti->wanna_wakeup=1;
+	wake_up_interruptible (&ti->wq);
 }
 
 void
-tape34xx_rew_init_done (tape_info_t * tape)
+tape34xx_rew_init_done (tape_info_t * ti)
 {
 #ifdef TAPE_DEBUG
         debug_text_event (tape_debug_area,6,"rew done");
 #endif
 	//BH: use irqsave
 	//s390irq_spin_lock(tape->devinfo.irq);
-	tapestate_set (tape, TS_DONE);
-	tape->rc = 0;
+	tapestate_set (ti, TS_DONE);
+	ti->rc = 0;
 	//s390irq_spin_unlock(tape->devinfo.irq);
-	tape->wanna_wakeup=1;
-	wake_up_interruptible (&tape->wq);
+	ti->wanna_wakeup=1;
+	wake_up_interruptible (&ti->wq);
 }
 
 void
-tape34xx_rew_release_init_done (tape_info_t * tape)
+tape34xx_rew_release_init_done (tape_info_t * ti)
 {
 #ifdef TAPE_DEBUG
         debug_text_event (tape_debug_area,6,"rewR done");
 #endif
-	tapestate_set (tape, TS_DONE);
-	tape->rc = 0;
+	tapestate_set (ti, TS_DONE);
+	ti->rc = 0;
 	//s390irq_spin_unlock(tape->devinfo.irq);
-	tape->wanna_wakeup=1;
-	wake_up (&tape->wq);
+	ti->wanna_wakeup=1;
+	wake_up (&ti->wq);
 }
 
 void
-tape34xx_run_init_done (tape_info_t * tape)
+tape34xx_run_init_done (tape_info_t * ti)
 {
 #ifdef TAPE_DEBUG
         debug_text_event (tape_debug_area,6,"rew done");
 #endif
-	tapestate_set (tape, TS_DONE);
-	tape->rc = 0;
-	tape->wanna_wakeup=1;
-	wake_up_interruptible (&tape->wq);
+	tapestate_set (ti, TS_DONE);
+	ti->rc = 0;
+	ti->wanna_wakeup=1;
+	wake_up_interruptible (&ti->wq);
 }
 
 void
-tape34xx_wri_init_done (tape_info_t * tape)
+tape34xx_wri_init_done (tape_info_t * ti)
 {
 #ifdef TAPE_DEBUG
         debug_text_event (tape_debug_area,6,"wri done");
 #endif
 	//BH: use irqsave
-	//s390irq_spin_lock(tape->devinfo.irq);
-	tapestate_set (tape, TS_DONE);
-	tape->rc = 0;
-	//s390irq_spin_unlock(tape->devinfo.irq);
-	tape->wanna_wakeup=1;
-	wake_up_interruptible (&tape->wq);
+	//s390irq_spin_lock(ti->devinfo.irq);
+	tapestate_set (ti, TS_DONE);
+	ti->rc = 0;
+	//s390irq_spin_unlock(ti->devinfo.irq);
+	ti->wanna_wakeup=1;
+	wake_up_interruptible (&ti->wq);
 }
 
 void
-tape34xx_wtm_init_done (tape_info_t * tape)
+tape34xx_wtm_init_done (tape_info_t * ti)
 {
 #ifdef TAPE_DEBUG
         debug_text_event (tape_debug_area,3,"wtm done");
 #endif
-	tapestate_set (tape, TS_DONE);
-	tape->rc = 0;
-	tape->wanna_wakeup=1;
-	wake_up_interruptible (&tape->wq);
+	tapestate_set (ti, TS_DONE);
+	ti->rc = 0;
+	ti->wanna_wakeup=1;
+	wake_up_interruptible (&ti->wq);
 }
 
 /* This function analyses the tape's sense-data in case of a unit-check. If possible,
    it tries to recover from the error. Else the user is informed about the problem. */
 void
-tape34xx_error_recovery (tape_info_t* tape)
+tape34xx_error_recovery (tape_info_t* ti)
 {
-    __u8* sense=tape->devstat.ii.sense.data;
+    __u8* sense=ti->devstat.ii.sense.data;
     int inhibit_cu_recovery=0;
-    int cu_type=tape->discipline->cu_type;
-    if ((((tape34xx_disc_data_t *) tape->discdata)->modeset_byte)&0x80) inhibit_cu_recovery=1;
-    if (tapestate_get(tape)==TS_BLOCK_INIT) {
+    int cu_type=ti->discipline->cu_type;
+    if ((((tape34xx_disc_data_t *) ti->discdata)->modeset_byte)&0x80) inhibit_cu_recovery=1;
+    if (tapestate_get(ti)==TS_BLOCK_INIT) {
 	// no recovery for block device, bottom half will retry...
-	tape34xx_error_recovery_has_failed(tape,EIO);
+	tape34xx_error_recovery_has_failed(ti,EIO);
 	return;
     }
     if (sense[0]&SENSE_COMMAND_REJECT)
-	switch (tapestate_get(tape)) {
+	switch (tapestate_get(ti)) {
 	case TS_BLOCK_INIT:
 	case TS_DSE_INIT:
 	case TS_EGA_INIT:
@@ -1788,33 +1785,33 @@
 	case TS_WTM_INIT:
 	    if (sense[1]&SENSE_WRITE_PROTECT) {
 		// trying to write, but medium is write protected
-		tape34xx_error_recovery_has_failed(tape,EACCES);
+		tape34xx_error_recovery_has_failed(ti,EACCES);
 		return;
 	    }
 	default:
-	    tape34xx_error_recovery_HWBUG(tape,1);
+	    tape34xx_error_recovery_HWBUG(ti,1);
 	    return;
 	}
     // special cases for various tape-states when reaching end of recorded area
     if (((sense[0]==0x08) || (sense[0]==0x10) || (sense[0]==0x12)) &&
 	((sense[1]==0x40) || (sense[1]==0x0c)))
-	switch (tapestate_get(tape)) {
+	switch (tapestate_get(ti)) {
 	case TS_FSF_INIT:
 	    // Trying to seek beyond end of recorded area
-	    tape34xx_error_recovery_has_failed(tape,EIO);
+	    tape34xx_error_recovery_has_failed(ti,EIO);
 	    return;
 	case TS_LBL_INIT:
 	    // Block could not be located.
-	    tape34xx_error_recovery_has_failed(tape,EIO);
+	    tape34xx_error_recovery_has_failed(ti,EIO);
 	    return;
 	case TS_RFO_INIT:
 	    // Try to read beyond end of recorded area -> 0 bytes read
-	    tape34xx_error_recovery_has_failed(tape,0);
+	    tape34xx_error_recovery_has_failed(ti,0);
 	    return;
 	}
     // Sensing special bits
     if (sense[0]&SENSE_BUS_OUT_CHECK) {
-	tape34xx_error_recovery_do_retry(tape);
+	tape34xx_error_recovery_do_retry(ti);
 	return;
     }
     if (sense[0]&SENSE_DATA_CHECK) {
@@ -1826,12 +1823,12 @@
 		(inhibit_cu_recovery)) {
 		// data check is not permanent, may be recovered. 
 		// We always use async-mode with cu-recovery, so this should *never* happen.
-		tape34xx_error_recovery_HWBUG(tape,2);
+		tape34xx_error_recovery_HWBUG(ti,2);
 		return;
 	    } else {
 		// data check is permanent, CU recovery has failed
 		PRINT_WARN("Permanent read error, recovery failed!\n");
-		tape34xx_error_recovery_has_failed(tape,EIO);
+		tape34xx_error_recovery_has_failed(ti,EIO);
 		return;
 	    }
 	case 0x25:
@@ -1840,38 +1837,38 @@
 		(inhibit_cu_recovery)) {
 		// data check is not permanent, may be recovered.
 		// We always use async-mode with cu-recovery, so this should *never* happen.
-		tape34xx_error_recovery_HWBUG(tape,3);
+		tape34xx_error_recovery_HWBUG(ti,3);
 		return;
 	    } else {
 		// data check is permanent, cu-recovery has failed
 		PRINT_WARN("Permanent write error, recovery failed!\n");
-		tape34xx_error_recovery_has_failed(tape,EIO);
+		tape34xx_error_recovery_has_failed(ti,EIO);
 		return;
 	    }
 	case 0x26:
 	    // Data Check (read opposite) occurred. We'll recover this.
-	    tape34xx_error_recovery_read_opposite(tape);
+	    tape34xx_error_recovery_read_opposite(ti);
 	    return;
 	case 0x28:
 	    // The ID-Mark at the beginning of the tape could not be written. This is fatal, we'll report and exit.
 	    PRINT_WARN("ID-Mark could not be written. Check your hardware!\n");
-	    tape34xx_error_recovery_has_failed(tape,EIO);
+	    tape34xx_error_recovery_has_failed(ti,EIO);
 	    return;
 	case 0x31:
 	    // Tape void. Tried to read beyond end of device. We'll report and exit.
 	    PRINT_WARN("Try to read beyond end of recorded area!\n");
-	    tape34xx_error_recovery_has_failed(tape,ENOSPC);
+	    tape34xx_error_recovery_has_failed(ti,ENOSPC);
 	    return;
 	case 0x41:
 	    // Record sequence error. cu detected incorrect block-id sequence on tape. We'll report and exit.
 	    PRINT_WARN("Illegal block-id sequence found!\n");
-	    tape34xx_error_recovery_has_failed(tape,EIO);
+	    tape34xx_error_recovery_has_failed(ti,EIO);
 	    return;
 	    default:
 	    // well, all data checks for 3480 should result in one of the above erpa-codes. if not -> bug
 	    // On 3490, other data-check conditions do exist.
 		if (cu_type==0x3480) {
-		    tape34xx_error_recovery_HWBUG(tape,4);
+		    tape34xx_error_recovery_HWBUG(ti,4);
 		    return;
 		}
 	}
@@ -1881,11 +1878,11 @@
 	switch (sense[3]) {
 	case 0x40: // overrun error
 	    PRINT_WARN ("Data overrun error between control-unit and drive. Use a faster channel connection, if possible! \n");
-	    tape34xx_error_recovery_has_failed(tape,EIO);
+	    tape34xx_error_recovery_has_failed(ti,EIO);
 	    return;
 	default:
 	    // Overrun bit is set, but erpa does not show overrun error. This is a bug.
-	    tape34xx_error_recovery_HWBUG(tape,5);
+	    tape34xx_error_recovery_HWBUG(ti,5);
 	    return;
 	}
     }
@@ -1894,11 +1891,11 @@
 	case 0x41:
 	    // Record sequence error. cu detected incorrect block-id sequence on tape. We'll report and exit.
 	    PRINT_WARN("Illegal block-id sequence found!\n");
-	    tape34xx_error_recovery_has_failed(tape,EIO);
+	    tape34xx_error_recovery_has_failed(ti,EIO);
 	    return;
 	default:
 	    // Record sequence error bit is set, but erpa does not show record sequence error. This is a bug.
-	    tape34xx_error_recovery_HWBUG(tape,6);
+	    tape34xx_error_recovery_HWBUG(ti,6);
 	    return;
 	}
     }
@@ -1911,119 +1908,119 @@
     case 0x21:
 	// Data streaming not operational. Cu switches to interlock mode, we reissue the command.
 	PRINT_WARN ("Data streaming not operational. Switching to interlock-mode! \n");
-	tape34xx_error_recovery_do_retry(tape);
+	tape34xx_error_recovery_do_retry(ti);
 	return;
     case 0x22:
 	// Path equipment check. Might be drive adapter error, buffer error on the lower interface, internal path not useable, or error during cartridge load.
 	// All of the above are not recoverable
 	PRINT_WARN ("A path equipment check occurred. One of the following conditions occurred:\n");
 	PRINT_WARN ("drive adapter error,buffer error on the lower interface, internal path not useable, error during cartridge load.\n");
-	tape34xx_error_recovery_has_failed(tape,EIO);
+	tape34xx_error_recovery_has_failed(ti,EIO);
 	return;
     case 0x23:
 	// Read data check. Should have been be covered earlier -> Bug!
-	tape34xx_error_recovery_HWBUG(tape,7);
+	tape34xx_error_recovery_HWBUG(ti,7);
 	return;
     case 0x24:
 	// Load display check. Load display was command was issued, but the drive is displaying a drive check message. Can be threated as "device end".
-	tape34xx_error_recovery_succeded(tape);
+	tape34xx_error_recovery_succeded(ti);
 	return;
     case 0x25:
 	// Write data check. Should have been covered earlier -> Bug!
-	tape34xx_error_recovery_HWBUG(tape,8);
+	tape34xx_error_recovery_HWBUG(ti,8);
 	return;
     case 0x26:
 	// Data check (read opposite). Should have been covered earlier -> Bug!
-	tape34xx_error_recovery_HWBUG(tape,9);
+	tape34xx_error_recovery_HWBUG(ti,9);
 	return;
     case 0x27:
 	// Command reject. May indicate illegal channel program or buffer over/underrun. 
 	// Since all channel programms are issued by this driver and ought be correct,
 	// we assume a over/underrun situaltion and retry the channel program.
-	tape34xx_error_recovery_do_retry(tape);
+	tape34xx_error_recovery_do_retry(ti);
 	return;
     case 0x28:
 	// Write id mark check. Should have beed covered earlier -> bug!
-	tape34xx_error_recovery_HWBUG(tape,10);
+	tape34xx_error_recovery_HWBUG(ti,10);
 	return;
     case 0x29:
 	// Function incompatible. Either idrc is on but hardware not capable doing idrc 
 	// or a perform subsystem func is issued and the cu is not online. Anyway, this 
 	// cannot be recovered and is an I/O error.
 	PRINT_WARN ("Function incompatible. Try to switch off idrc! \n");
-	tape34xx_error_recovery_has_failed(tape,EIO);
+	tape34xx_error_recovery_has_failed(ti,EIO);
 	return;
     case 0x2a:
 	// Unsolicited environmental data. An internal counter overflows, we can ignore
 	// this and reissue the cmd.
-	tape34xx_error_recovery_do_retry(tape);
+	tape34xx_error_recovery_do_retry(ti);
 	return;
     case 0x2b:
 	// Environmental data present. Indicates either unload completed ok or read buffered 
 	// log command completed ok. 
-	if (tapestate_get(tape)==TS_RUN_INIT) {
+	if (tapestate_get(ti)==TS_RUN_INIT) {
 	    // Rewind unload completed ok.
-	    tape34xx_error_recovery_succeded(tape);
+	    tape34xx_error_recovery_succeded(ti);
 	    return;
 	}
 	// Since we do not issue read buffered log commands, this should never occur -> bug.
-	tape34xx_error_recovery_HWBUG(tape,11);
+	tape34xx_error_recovery_HWBUG(ti,11);
 	return;
     case 0x2c:
 	// Permanent equipment check. cu has tried recovery, but did not succeed. This is an
 	// I/O error.
-	tape34xx_error_recovery_has_failed(tape,EIO);
+	tape34xx_error_recovery_has_failed(ti,EIO);
 	return;
     case 0x2d:
 	// Data security erase failure.
-	if (tapestate_get(tape)==TS_DSE_INIT) {
+	if (tapestate_get(ti)==TS_DSE_INIT) {
 	    // report an I/O error
-	    tape34xx_error_recovery_has_failed(tape,EIO);
+	    tape34xx_error_recovery_has_failed(ti,EIO);
 	    return;
 	}
 	// Data security erase failure, but no such command issued. This is a bug.
-	tape34xx_error_recovery_HWBUG(tape,12);
+	tape34xx_error_recovery_HWBUG(ti,12);
 	return;
     case 0x2e:
 	// Not capable. This indicates either that the drive fails reading the format id mark
 	// or that that format specified is not supported by the drive. We write a message and
 	// return an I/O error.
 	PRINT_WARN("Drive not capable processing the tape format!");
-	tape34xx_error_recovery_has_failed(tape,EMEDIUMTYPE);
+	tape34xx_error_recovery_has_failed(ti,EMEDIUMTYPE);
 	return;
     case 0x2f:
 	// This erpa is reserved. This is a bug.
-	tape34xx_error_recovery_HWBUG(tape,13);
+	tape34xx_error_recovery_HWBUG(ti,13);
 	return;
     case 0x30:
 	// The medium is write protected, while trying to write on it. We'll report this.
 	PRINT_WARN("Medium is write protected!\n");
-	tape34xx_error_recovery_has_failed(tape,EACCES);
+	tape34xx_error_recovery_has_failed(ti,EACCES);
 	return;
     case 0x31:
 	// Tape void. Should have beed covered ealier -> bug
-	tape34xx_error_recovery_HWBUG(tape,14);
+	tape34xx_error_recovery_HWBUG(ti,14);
 	return;
     case 0x32:
 	// Tension loss. We cannot recover this, it's an I/O error.
 	PRINT_WARN("The drive lost tape tension.\n");
-	tape34xx_error_recovery_has_failed(tape,EIO);
+	tape34xx_error_recovery_has_failed(ti,EIO);
 	return;
     case 0x33:
 	// Load Failure. The catridge was not inserted correctly or the tape is not threaded
 	// correctly. We cannot recover this, the user has to reload the catridge.
 	PRINT_WARN("Cartridge load failure. Reload the cartridge and try again.\n");
-	tape34xx_error_recovery_has_failed(tape,EIO);
+	tape34xx_error_recovery_has_failed(ti,EIO);
 	return;
     case 0x34:
 	// Unload failure. The drive cannot maintain tape tension and control tape movement 
 	// during an unload operation. 
 	PRINT_WARN("Failure during cartridge unload. Please try manually.\n");
-	if (tapestate_get(tape)!=TS_RUN_INIT) {
-	    tape34xx_error_recovery_HWBUG(tape,15);
+	if (tapestate_get(ti)!=TS_RUN_INIT) {
+	    tape34xx_error_recovery_HWBUG(ti,15);
 	    return;
 	}
-	tape34xx_error_recovery_has_failed(tape,EIO);
+	tape34xx_error_recovery_has_failed(ti,EIO);
 	return;
     case 0x35:
 	// Drive equipment check. One of the following:
@@ -2032,335 +2029,335 @@
 	// - the cartridge loader does not respond correctly
 	// - a failure occurs during an index, load, or unload cycle
 	PRINT_WARN("Equipment check! Please check the drive and the cartridge loader.\n");
-	tape34xx_error_recovery_has_failed(tape,EIO);
+	tape34xx_error_recovery_has_failed(ti,EIO);
 	return;
     case 0x36:
 	switch (cu_type) {
 	case 0x3480:
 	    // This erpa is reserved for 3480 -> BUG
-	    tape34xx_error_recovery_HWBUG(tape,16);
+	    tape34xx_error_recovery_HWBUG(ti,16);
 	    return;
 	case 0x3490:
 	    // End of data. This is a permanent I/O error, which cannot be recovered.
 	    // A read-type command has reached the end-of-data mark.
-	    tape34xx_error_recovery_has_failed(tape,EIO);
+	    tape34xx_error_recovery_has_failed(ti,EIO);
 	    return;
 	}
     case 0x37:
 	// Tape length error. The tape is shorter than reported in the beginning-of-tape data.
 	PRINT_WARN("Tape length error.\n");
-	tape34xx_error_recovery_has_failed(tape,EIO);
+	tape34xx_error_recovery_has_failed(ti,EIO);
 	return;
     case 0x38:
 	// Physical end of tape. A read/write operation reached the physical end of tape.
-	if (tapestate_get(tape)==TS_WRI_INIT) {
- 	    tape34xx_error_recovery_has_failed(tape,ENOSPC);
+	if (tapestate_get(ti)==TS_WRI_INIT) {
+ 	    tape34xx_error_recovery_has_failed(ti,ENOSPC);
 	}
 	return;
     case 0x39:
 	// Backward at BOT. The drive is at BOT and is requestet to move backward.
-	tape34xx_error_recovery_has_failed(tape,EIO);
+	tape34xx_error_recovery_has_failed(ti,EIO);
 	return;
     case 0x3a:
 	// Drive switched not ready, but the command needs the drive to be ready.
 	PRINT_WARN("Drive not ready. Turn the ready/not ready switch to ready position and try again.\n");
-	tape34xx_error_recovery_has_failed(tape,EIO);
+	tape34xx_error_recovery_has_failed(ti,EIO);
 	return;
     case 0x3b:
 	// Manual rewind or unload. This causes an I/O error.
-	PRINT_WARN("Medium is rewinded or unloaded manually.\n");
-	tape34xx_error_recovery_has_failed(tape,EIO);
+	PRINT_WARN("Medium was rewound or unloaded manually. Expect errors! Please do only use the mtoffl and mtrew ioctl to unload tapes or rewind tapes.\n");
+	tape34xx_error_recovery_has_failed(ti,EIO);
 	return;
     case 0x3c:
     case 0x3d:
     case 0x3e:
     case 0x3f:
 	// These erpas are reserved -> BUG
-	tape34xx_error_recovery_HWBUG(tape,17);
+	tape34xx_error_recovery_HWBUG(ti,17);
 	return;
     case 0x40:
 	// Overrun error. This should have been covered earlier -> bug.
-	tape34xx_error_recovery_HWBUG(tape,18);
+	tape34xx_error_recovery_HWBUG(ti,18);
 	return;
     case 0x41:
 	// Record sequence error. This should have been covered earlier -> bug.
-	tape34xx_error_recovery_HWBUG(tape,19);
+	tape34xx_error_recovery_HWBUG(ti,19);
 	return;
     case 0x42:
 	// Degraded mode. A condition that can cause degraded performace is detected.
 	PRINT_WARN("Subsystem is running in degraded mode. This may compromise your performace.\n");
-	tape34xx_error_recovery_do_retry(tape);
+	tape34xx_error_recovery_do_retry(ti);
 	return;
     case 0x43:
 	// Drive not ready. Probably swith the ready/not ready switch to ready?
 	PRINT_WARN("The drive is not ready. Maybe no medium in?\n");
-	tape34xx_error_recovery_has_failed(tape,ENOMEDIUM);
+	tape34xx_error_recovery_has_failed(ti,ENOMEDIUM);
 	return;
     case 0x44:
 	// Locate Block unsuccessfull. We'll report this.
-	if ((tapestate_get(tape)!=TS_BLOCK_INIT) &&
-	    (tapestate_get(tape)!=TS_LBL_INIT)) {
-	    tape34xx_error_recovery_HWBUG(tape,20); // No locate block was issued...
+	if ((tapestate_get(ti)!=TS_BLOCK_INIT) &&
+	    (tapestate_get(ti)!=TS_LBL_INIT)) {
+	    tape34xx_error_recovery_HWBUG(ti,20); // No locate block was issued...
 	    return;
 	}
-	tape34xx_error_recovery_has_failed(tape,EIO);
+	tape34xx_error_recovery_has_failed(ti,EIO);
 	return;
     case 0x45:
 	// The drive is assigned elsewhere [to a different channel path/computer].
 	PRINT_WARN("The drive is assigned elsewhere.\n");
-	tape34xx_error_recovery_has_failed(tape,EIO);
+	tape34xx_error_recovery_has_failed(ti,EIO);
 	return;
     case 0x46:
 	// Drive not online. Drive may be switched offline, the power supply may be switched off 
 	// or the drive address may not be set correctly.
 	PRINT_WARN("The drive is not online.");
-	tape34xx_error_recovery_has_failed(tape,EIO);
+	tape34xx_error_recovery_has_failed(ti,EIO);
 	return;
     case 0x47:
 	// Volume fenced. cu reports volume integrity is lost! 
 	PRINT_WARN("Volume fenced. The volume integrity is lost! \n");
-	tape34xx_error_recovery_has_failed(tape,EIO);
+	tape34xx_error_recovery_has_failed(ti,EIO);
 	return;
     case 0x48:
 	// Log sense data and retry request. We'll do so...
-	tape34xx_error_recovery_do_retry(tape);
+	tape34xx_error_recovery_do_retry(ti);
 	return;
     case 0x49:
 	// Bus out check. A parity check error on the bus was found.	PRINT_WARN("Bus out check. A data transfer over the bus was corrupted.\n");
-	tape34xx_error_recovery_has_failed(tape,EIO);
+	tape34xx_error_recovery_has_failed(ti,EIO);
 	return;
     case 0x4a:
 	// Control unit erp failed. We'll report this.
 	PRINT_WARN("The control unit failed recovering an I/O error.\n");
-	tape34xx_error_recovery_has_failed(tape,EIO);
+	tape34xx_error_recovery_has_failed(ti,EIO);
 	return;
     case 0x4b:
 	// Cu and drive incompatible. The drive requests micro-program patches, which are not available on the cu.
 	PRINT_WARN("The drive needs microprogram patches from the control unit, which are not available.\n");
-	tape34xx_error_recovery_has_failed(tape,EIO);
+	tape34xx_error_recovery_has_failed(ti,EIO);
 	return;
     case 0x4c:
 	// Recovered Check-One failure. Cu develops a hardware error, but is able to recover. We'll reissue the command.
-	tape34xx_error_recovery_do_retry(tape);
+	tape34xx_error_recovery_do_retry(ti);
 	return;
     case 0x4d:
 	switch (cu_type) {
 	case 0x3480:
 	    // This erpa is reserved for 3480 -> bug
-      	    tape34xx_error_recovery_HWBUG(tape,21);
+      	    tape34xx_error_recovery_HWBUG(ti,21);
 	    return;
 	case 0x3490:
 	    // Resetting event recieved. Since the driver does not support resetting event recovery
 	    // (which has to be handled by the I/O Layer), we'll report and retry our command.
-	    tape34xx_error_recovery_do_retry(tape);
+	    tape34xx_error_recovery_do_retry(ti);
 	    return;
 	}
     case 0x4e:
 	switch (cu_type) {
 	case 0x3480:
 	    // This erpa is reserved for 3480 -> bug.
-	    tape34xx_error_recovery_HWBUG(tape,22);
+	    tape34xx_error_recovery_HWBUG(ti,22);
 	    return;
 	case 0x3490:
 	    // Maximum block size exeeded. This indicates, that the block to be written is larger
 	    // than allowed for buffered mode. We'll report this...
 	    PRINT_WARN("Maximum block size for buffered mode exceeded.\n");
-	    tape34xx_error_recovery_has_failed(tape,ENOBUFS);
+	    tape34xx_error_recovery_has_failed(ti,ENOBUFS);
 	    return;
 	}
     case 0x4f:
 	// These erpas are reserved -> bug
-	tape34xx_error_recovery_HWBUG(tape,23);
+	tape34xx_error_recovery_HWBUG(ti,23);
 	return;
     case 0x50:
 	// Read buffered log (Overflow). Cu is running in extended beffered log mode, and a counter overflows.
 	// This should never happen, since we're never running in extended buffered log mode -> bug.
-	tape34xx_error_recovery_do_retry(tape);
+	tape34xx_error_recovery_do_retry(ti);
 	return;
     case 0x51:
 	// Read buffered log (EOV). EOF processing occurs while the cu is in extended buffered log mode.
 	// This should never happen, since we're never running in extended buffered log mode -> bug.
-	tape34xx_error_recovery_do_retry(tape);
+	tape34xx_error_recovery_do_retry(ti);
 	return;
     case 0x52:
 	// End of Volume complete. Rewind unload completed ok. We'll report to the user...
-	if (tapestate_get(tape)!=TS_RUN_INIT) {
-	    tape34xx_error_recovery_HWBUG(tape,24);
+	if (tapestate_get(ti)!=TS_RUN_INIT) {
+	    tape34xx_error_recovery_HWBUG(ti,24);
 	    return;
 	}
-	tape34xx_error_recovery_succeded(tape);
+	tape34xx_error_recovery_succeded(ti);
 	return;
     case 0x53:
 	// Global command intercept. We'll have to reissue our command.
-	tape34xx_error_recovery_do_retry(tape);
+	tape34xx_error_recovery_do_retry(ti);
 	return;
     case 0x54:
 	// Channel interface recovery (temporary). This can be recovered by reissuing the command.
-	tape34xx_error_recovery_do_retry(tape);
+	tape34xx_error_recovery_do_retry(ti);
 	return;
     case 0x55:
 	// Channel interface recovery (permanent). This cannot be recovered, we'll inform the user.
 	PRINT_WARN("A permanent channel interface error occurred.\n");
-	tape34xx_error_recovery_has_failed(tape,EIO);
+	tape34xx_error_recovery_has_failed(ti,EIO);
 	return;
     case 0x56:
 	// Channel protocol error. This cannot be recovered.
 	PRINT_WARN("A channel protocol error occurred.\n");
-	tape34xx_error_recovery_has_failed(tape,EIO);
+	tape34xx_error_recovery_has_failed(ti,EIO);
 	return;
     case 0x57:
 	switch (cu_type) {
 	case 0x3480:
 	    // Attention intercept. We have to reissue the command.
 	    PRINT_WARN("An attention intercept occurred, which will be recovered.\n");
-	    tape34xx_error_recovery_do_retry(tape);
+	    tape34xx_error_recovery_do_retry(ti);
 	    return;
 	case 0x3490:
 	    // Global status intercept. We have to reissue the command.
 	    PRINT_WARN("An global status intercept was recieved, which will be recovered.\n");
-	    tape34xx_error_recovery_do_retry(tape);
+	    tape34xx_error_recovery_do_retry(ti);
 	    return;
 	}
     case 0x58:
     case 0x59:
 	// These erpas are reserved -> bug.
-	tape34xx_error_recovery_HWBUG(tape,25);
+	tape34xx_error_recovery_HWBUG(ti,25);
 	return;
     case 0x5a:
 	// Tape length incompatible. The tape inserted is too long, 
 	// which could cause damage to the tape or the drive.
 	PRINT_WARN("Tape length incompatible [should be IBM Cartridge System Tape]. May cause damage to drive or tape.n");
-	tape34xx_error_recovery_has_failed(tape,EIO);
+	tape34xx_error_recovery_has_failed(ti,EIO);
 	return;
     case 0x5b:
 	// Format 3480 XF incompatible
 	if (sense[1]&SENSE_BEGINNING_OF_TAPE) {
 	    // Everything is fine. The tape will be overwritten in a different format.
-	    tape34xx_error_recovery_do_retry(tape);
+	    tape34xx_error_recovery_do_retry(ti);
 	    return;
 	}
 	PRINT_WARN("Tape format is incompatible to the drive, which writes 3480-2 XF.\n");
-	tape34xx_error_recovery_has_failed(tape,EIO);
+	tape34xx_error_recovery_has_failed(ti,EIO);
 	return;
     case 0x5c:
 	// Format 3480-2 XF incompatible
 	PRINT_WARN("Tape format is incompatible to the drive. The drive cannot access 3480-2 XF volumes.\n");
-	tape34xx_error_recovery_has_failed(tape,EIO);
+	tape34xx_error_recovery_has_failed(ti,EIO);
 	return;
     case 0x5d:
 	// Tape length violation. 
 	PRINT_WARN("Tape length violation [should be IBM Enhanced Capacity Cartridge System Tape]. May cause damage to drive or tape.\n");
-	tape34xx_error_recovery_has_failed(tape,EMEDIUMTYPE);
+	tape34xx_error_recovery_has_failed(ti,EMEDIUMTYPE);
 	return;
     case 0x5e:
 	// Compaction algorithm incompatible.
 	PRINT_WARN("The volume is recorded using an incompatible compaction algorith, which is not supported by the control unit.\n");
-	tape34xx_error_recovery_has_failed(tape,EMEDIUMTYPE);
+	tape34xx_error_recovery_has_failed(ti,EMEDIUMTYPE);
 	return;
     default:
 	// Reserved erpas -> bug
-	tape34xx_error_recovery_HWBUG(tape,26);
+	tape34xx_error_recovery_HWBUG(ti,26);
 	return;
     }
 }
 
-void tape34xx_error_recovery_has_failed (tape_info_t* tape,int error_id) {
+void tape34xx_error_recovery_has_failed (tape_info_t* ti,int error_id) {
 #ifdef TAPE_DEBUG
     debug_text_event (tape_debug_area,3,"xerp fail");
-    debug_text_event (tape_debug_area,3,(((tapestate_get (tape) < TS_SIZE) && 
-		      (tapestate_get (tape) >= 0)) ?
-	state_verbose[tapestate_get (tape)] : "UNKNOWN"));
+    debug_text_event (tape_debug_area,3,(((tapestate_get (ti) < TS_SIZE) && 
+		      (tapestate_get (ti) >= 0)) ?
+	state_verbose[tapestate_get (ti)] : "UNKNOWN"));
 #endif
-    if ((tapestate_get(tape)!=TS_UNUSED) && (tapestate_get(tape)!=TS_IDLE)) {
-	tape_dump_sense(&tape->devstat);
-	tape->rc = -error_id;
-	tape->wanna_wakeup=1;
-	switch (tapestate_get(tape)) {
+    if ((tapestate_get(ti)!=TS_UNUSED) && (tapestate_get(ti)!=TS_IDLE)) {
+	tape_dump_sense(&ti->devstat);
+	ti->rc = -error_id;
+	ti->wanna_wakeup=1;
+	switch (tapestate_get(ti)) {
 	case TS_REW_RELEASE_INIT:
-	    tapestate_set(tape,TS_FAILED);
-	    wake_up (&tape->wq);
+	    tapestate_set(ti,TS_FAILED);
+	    wake_up (&ti->wq);
 	    break;
 	case TS_BLOCK_INIT:
-	    tapestate_set(tape,TS_FAILED);
-	    schedule_tapeblock_exec_IO(tape);
+	    tapestate_set(ti,TS_FAILED);
+	    schedule_tapeblock_exec_IO(ti);
 	    break;
 	default:
-	    tapestate_set(tape,TS_FAILED);
-	    wake_up_interruptible (&tape->wq);
+	    tapestate_set(ti,TS_FAILED);
+	    wake_up_interruptible (&ti->wq);
 	}
     } else {
 	PRINT_WARN("Recieved an unsolicited IRQ.\n");
-	tape_dump_sense(&tape->devstat);
+	tape_dump_sense(&ti->devstat);
     }
 }    
 
-void tape34xx_error_recovery_succeded(tape_info_t* tape) {
+void tape34xx_error_recovery_succeded(tape_info_t* ti) {
 #ifdef TAPE_DEBUG
     debug_text_event (tape_debug_area,3,"xerp done");
-    debug_text_event (tape_debug_area,3,(((tapestate_get (tape) < TS_SIZE) && 
-		      (tapestate_get (tape) >= 0)) ?
-	state_verbose[tapestate_get (tape)] : "UNKNOWN"));
+    debug_text_event (tape_debug_area,3,(((tapestate_get (ti) < TS_SIZE) && 
+		      (tapestate_get (ti) >= 0)) ?
+	state_verbose[tapestate_get (ti)] : "UNKNOWN"));
 #endif
-    if ((tapestate_get(tape)!=TS_UNUSED) && (tapestate_get(tape)!=TS_DONE)) {
-	tapestate_event (tape, TE_DONE);
+    if ((tapestate_get(ti)!=TS_UNUSED) && (tapestate_get(ti)!=TS_DONE)) {
+	tapestate_event (ti, TE_DONE);
     } else {
 	PRINT_WARN("Recieved an unsolicited IRQ.\n");
-	tape_dump_sense(&tape->devstat);
+	tape_dump_sense(&ti->devstat);
     }
 }
 
-void tape34xx_error_recovery_do_retry(tape_info_t* tape) {
+void tape34xx_error_recovery_do_retry(tape_info_t* ti) {
 #ifdef TAPE_DEBUG
     debug_text_event (tape_debug_area,3,"xerp retr");
-    debug_text_event (tape_debug_area,3,(((tapestate_get (tape) < TS_SIZE) && 
-					  (tapestate_get (tape) >= 0)) ?
-					 state_verbose[tapestate_get (tape)] : "UNKNOWN"));
+    debug_text_event (tape_debug_area,3,(((tapestate_get (ti) < TS_SIZE) && 
+					  (tapestate_get (ti) >= 0)) ?
+					 state_verbose[tapestate_get (ti)] : "UNKNOWN"));
 #endif
-    if ((tapestate_get(tape)!=TS_UNUSED) && (tapestate_get(tape)!=TS_IDLE)) {
-	tape_dump_sense(&tape->devstat);
-	while (do_IO (tape->devinfo.irq, tape->cqr->cpaddr, (unsigned long) tape->cqr, 0x00, tape->cqr->options));
+    if ((tapestate_get(ti)!=TS_UNUSED) && (tapestate_get(ti)!=TS_IDLE)) {
+	tape_dump_sense(&ti->devstat);
+	while (do_IO (ti->devinfo.irq, ti->cqr->cpaddr, (unsigned long) ti->cqr, 0x00, ti->cqr->options));
     } else {
 	PRINT_WARN("Recieved an unsolicited IRQ.\n");
-	tape_dump_sense(&tape->devstat);
+	tape_dump_sense(&ti->devstat);
     }
 }
     
 void 
-tape34xx_error_recovery_read_opposite (tape_info_t* tape) {
-    switch (tapestate_get(tape)) {
+tape34xx_error_recovery_read_opposite (tape_info_t* ti) {
+    switch (tapestate_get(ti)) {
     case TS_RFO_INIT:
 	// We did read forward, but the data could not be read *correctly*.
 	// We will read backward and then skip forward again.
-	tape->cqr=tape34xx_read_opposite(tape,0);
-	if (tape->cqr==NULL)
-	    tape34xx_error_recovery_has_failed(tape,EIO);
+	ti->cqr=tape34xx_read_opposite(ti,0);
+	if (ti->cqr==NULL)
+	    tape34xx_error_recovery_has_failed(ti,EIO);
 	else
-	    tape34xx_error_recovery_do_retry(tape);
+	    tape34xx_error_recovery_do_retry(ti);
 	break;
     case TS_RBA_INIT:
 	// We tried to read forward and backward, but hat no success -> failed.
-	tape34xx_error_recovery_has_failed(tape,EIO);
+	tape34xx_error_recovery_has_failed(ti,EIO);
 	break;
     case TS_BLOCK_INIT:
-	tape34xx_error_recovery_do_retry(tape);
+	tape34xx_error_recovery_do_retry(ti);
 	break;
     default:
 	PRINT_WARN("read_opposite_recovery_called_with_state:%s\n",
-		   (((tapestate_get (tape) < TS_SIZE) && 
-		     (tapestate_get (tape) >= 0)) ?
-		    state_verbose[tapestate_get (tape)] : "UNKNOWN"));
+		   (((tapestate_get (ti) < TS_SIZE) && 
+		     (tapestate_get (ti) >= 0)) ?
+		    state_verbose[tapestate_get (ti)] : "UNKNOWN"));
     }
 }
 
 void 
-tape34xx_error_recovery_HWBUG (tape_info_t* tape,int condno) {
-    devstat_t* stat=&tape->devstat;
+tape34xx_error_recovery_HWBUG (tape_info_t* ti,int condno) {
+    devstat_t* stat=&ti->devstat;
     PRINT_WARN("An unexpected condition #%d was caught in tape error recovery.\n",condno);
     PRINT_WARN("Please report this incident.\n");
     PRINT_WARN("State of the tape:%s\n",
-	       (((tapestate_get (tape) < TS_SIZE) && 
-		 (tapestate_get (tape) >= 0)) ?
-		state_verbose[tapestate_get (tape)] : "UNKNOWN"));
+	       (((tapestate_get (ti) < TS_SIZE) && 
+		 (tapestate_get (ti) >= 0)) ?
+		state_verbose[tapestate_get (ti)] : "UNKNOWN"));
     PRINT_INFO ("Sense data: %02X%02X%02X%02X %02X%02X%02X%02X "
 		" %02X%02X%02X%02X %02X%02X%02X%02X \n",
 		stat->ii.sense.data[0], stat->ii.sense.data[1],
@@ -2381,5 +2378,5 @@
 		stat->ii.sense.data[26], stat->ii.sense.data[27],
 		stat->ii.sense.data[28], stat->ii.sense.data[29],
 		stat->ii.sense.data[30], stat->ii.sense.data[31]);
-    tape34xx_error_recovery_has_failed(tape,EIO);
+    tape34xx_error_recovery_has_failed(ti,EIO);
 }
diff -u --recursive --new-file v2.4.7/linux/drivers/s390/char/tape34xx.h linux/drivers/s390/char/tape34xx.h
--- v2.4.7/linux/drivers/s390/char/tape34xx.h	Wed Apr 11 19:02:28 2001
+++ linux/drivers/s390/char/tape34xx.h	Wed Jul 25 14:12:02 2001
@@ -115,69 +115,69 @@
 
 /* discipline functions */
 int tape34xx_ioctl_overload (struct inode *inode, struct file *filp, unsigned int cmd, unsigned long arg);
-ccw_req_t * tape34xx_write_block (const char *data, size_t count, tape_info_t * tape);
-void tape34xx_free_write_block (ccw_req_t * cqr, tape_info_t * tape);
-ccw_req_t * tape34xx_read_block (const char *data, size_t count, tape_info_t * tape);
-void  tape34xx_free_read_block (ccw_req_t * cqr, tape_info_t * tape);
-void  tape34xx_clear_read_block (ccw_req_t * cqr, tape_info_t * tape);
-ccw_req_t * tape34xx_mtfsf (tape_info_t * tape, int count);
-ccw_req_t * tape34xx_mtbsf (tape_info_t * tape, int count);
-ccw_req_t * tape34xx_mtfsr (tape_info_t * tape, int count);
-ccw_req_t * tape34xx_mtbsr (tape_info_t * tape, int count);
-ccw_req_t * tape34xx_mtweof (tape_info_t * tape, int count);
-ccw_req_t * tape34xx_mtrew (tape_info_t * tape, int count);
-ccw_req_t * tape34xx_mtoffl (tape_info_t * tape, int count);
-ccw_req_t * tape34xx_mtnop (tape_info_t * tape, int count);
-ccw_req_t * tape34xx_mtbsfm (tape_info_t * tape, int count);
-ccw_req_t * tape34xx_mtfsfm (tape_info_t * tape, int count);
-ccw_req_t * tape34xx_mteom (tape_info_t * tape, int count);
-ccw_req_t * tape34xx_mterase (tape_info_t * tape, int count);
-ccw_req_t * tape34xx_mtsetdensity (tape_info_t * tape, int count);
-ccw_req_t * tape34xx_mtseek (tape_info_t * tape, int count);
-ccw_req_t * tape34xx_mttell (tape_info_t * tape, int count);
-ccw_req_t * tape34xx_mtsetdrvbuffer (tape_info_t * tape, int count);
-ccw_req_t * tape34xx_mtlock (tape_info_t * tape, int count);
-ccw_req_t * tape34xx_mtunlock (tape_info_t * tape, int count);
-ccw_req_t * tape34xx_mtload (tape_info_t * tape, int count);
-ccw_req_t * tape34xx_mtunload (tape_info_t * tape, int count);
-ccw_req_t * tape34xx_mtcompression (tape_info_t * tape, int count);
-ccw_req_t * tape34xx_mtsetpart (tape_info_t * tape, int count);
-ccw_req_t * tape34xx_mtmkpart (tape_info_t * tape, int count);
-ccw_req_t * tape34xx_mtiocget (tape_info_t * tape, int count);
-ccw_req_t * tape34xx_mtiocpos (tape_info_t * tape, int count);
-ccw_req_t * tape34xx_bread (struct request *req, tape_info_t* tape,int tapeblock_major);
-ccw_req_t * tape34xx_bwrite (struct request *req, tape_info_t* tape,int tapeblock_major);
+ccw_req_t * tape34xx_write_block (const char *data, size_t count, tape_info_t * ti);
+void tape34xx_free_write_block (ccw_req_t * cqr, tape_info_t * ti);
+ccw_req_t * tape34xx_read_block (const char *data, size_t count, tape_info_t * ti);
+void  tape34xx_free_read_block (ccw_req_t * cqr, tape_info_t * ti);
+void  tape34xx_clear_read_block (ccw_req_t * cqr, tape_info_t * ti);
+ccw_req_t * tape34xx_mtfsf (tape_info_t * ti, int count);
+ccw_req_t * tape34xx_mtbsf (tape_info_t * ti, int count);
+ccw_req_t * tape34xx_mtfsr (tape_info_t * ti, int count);
+ccw_req_t * tape34xx_mtbsr (tape_info_t * ti, int count);
+ccw_req_t * tape34xx_mtweof (tape_info_t * ti, int count);
+ccw_req_t * tape34xx_mtrew (tape_info_t * ti, int count);
+ccw_req_t * tape34xx_mtoffl (tape_info_t * ti, int count);
+ccw_req_t * tape34xx_mtnop (tape_info_t * ti, int count);
+ccw_req_t * tape34xx_mtbsfm (tape_info_t * ti, int count);
+ccw_req_t * tape34xx_mtfsfm (tape_info_t * ti, int count);
+ccw_req_t * tape34xx_mteom (tape_info_t * ti, int count);
+ccw_req_t * tape34xx_mterase (tape_info_t * ti, int count);
+ccw_req_t * tape34xx_mtsetdensity (tape_info_t * ti, int count);
+ccw_req_t * tape34xx_mtseek (tape_info_t * ti, int count);
+ccw_req_t * tape34xx_mttell (tape_info_t * ti, int count);
+ccw_req_t * tape34xx_mtsetdrvbuffer (tape_info_t * ti, int count);
+ccw_req_t * tape34xx_mtlock (tape_info_t * ti, int count);
+ccw_req_t * tape34xx_mtunlock (tape_info_t * ti, int count);
+ccw_req_t * tape34xx_mtload (tape_info_t * ti, int count);
+ccw_req_t * tape34xx_mtunload (tape_info_t * ti, int count);
+ccw_req_t * tape34xx_mtcompression (tape_info_t * ti, int count);
+ccw_req_t * tape34xx_mtsetpart (tape_info_t * ti, int count);
+ccw_req_t * tape34xx_mtmkpart (tape_info_t * ti, int count);
+ccw_req_t * tape34xx_mtiocget (tape_info_t * ti, int count);
+ccw_req_t * tape34xx_mtiocpos (tape_info_t * ti, int count);
+ccw_req_t * tape34xx_bread (struct request *req, tape_info_t* ti,int tapeblock_major);
+ccw_req_t * tape34xx_bwrite (struct request *req, tape_info_t* ti,int tapeblock_major);
 void tape34xx_free_bread (ccw_req_t*,struct _tape_info_t*);
 void tape34xx_free_bwrite (ccw_req_t*,struct _tape_info_t*);
 
 /* Event handlers */
-void tape34xx_default_handler (tape_info_t * tape);
-void tape34xx_unexpect_uchk_handler (tape_info_t * tape);
-void tape34xx_unused_done(tape_info_t* tape);
-void tape34xx_idle_done(tape_info_t* tape);
-void tape34xx_block_done(tape_info_t* tape);
-void tape34xx_bsf_init_done(tape_info_t* tape);
-void tape34xx_dse_init_done(tape_info_t* tape);
-void tape34xx_fsf_init_done(tape_info_t* tape);
-void tape34xx_bsb_init_done(tape_info_t* tape);
-void tape34xx_fsb_init_done(tape_info_t* tape);
-void tape34xx_lbl_init_done(tape_info_t* tape);
-void tape34xx_nop_init_done(tape_info_t* tape);
-void tape34xx_rfo_init_done(tape_info_t* tape);
-void tape34xx_rbi_init_done(tape_info_t* tape);
-void tape34xx_rew_init_done(tape_info_t* tape);
-void tape34xx_rew_release_init_done(tape_info_t* tape);
-void tape34xx_run_init_done(tape_info_t* tape);
-void tape34xx_wri_init_done(tape_info_t* tape);
-void tape34xx_wtm_init_done(tape_info_t* tape);
+void tape34xx_default_handler (tape_info_t * ti);
+void tape34xx_unexpect_uchk_handler (tape_info_t * ti);
+void tape34xx_unused_done(tape_info_t* ti);
+void tape34xx_idle_done(tape_info_t* ti);
+void tape34xx_block_done(tape_info_t* ti);
+void tape34xx_bsf_init_done(tape_info_t* ti);
+void tape34xx_dse_init_done(tape_info_t* ti);
+void tape34xx_fsf_init_done(tape_info_t* ti);
+void tape34xx_bsb_init_done(tape_info_t* ti);
+void tape34xx_fsb_init_done(tape_info_t* ti);
+void tape34xx_lbl_init_done(tape_info_t* ti);
+void tape34xx_nop_init_done(tape_info_t* ti);
+void tape34xx_rfo_init_done(tape_info_t* ti);
+void tape34xx_rbi_init_done(tape_info_t* ti);
+void tape34xx_rew_init_done(tape_info_t* ti);
+void tape34xx_rew_release_init_done(tape_info_t* ti);
+void tape34xx_run_init_done(tape_info_t* ti);
+void tape34xx_wri_init_done(tape_info_t* ti);
+void tape34xx_wtm_init_done(tape_info_t* ti);
 
-extern void schedule_tapeblock_exec_IO (tape_info_t *tape);
+extern void schedule_tapeblock_exec_IO (tape_info_t *ti);
 
 // the error recovery stuff:
-void tape34xx_error_recovery (tape_info_t* tape);
-void tape34xx_error_recovery_has_failed (tape_info_t* tape,int error_id);
-void tape34xx_error_recovery_succeded(tape_info_t* tape);
-void tape34xx_error_recovery_do_retry(tape_info_t* tape);
-void tape34xx_error_recovery_read_opposite (tape_info_t* tape);
-void  tape34xx_error_recovery_HWBUG (tape_info_t* tape,int condno);
+void tape34xx_error_recovery (tape_info_t* ti);
+void tape34xx_error_recovery_has_failed (tape_info_t* ti,int error_id);
+void tape34xx_error_recovery_succeded(tape_info_t* ti);
+void tape34xx_error_recovery_do_retry(tape_info_t* ti);
+void tape34xx_error_recovery_read_opposite (tape_info_t* ti);
+void  tape34xx_error_recovery_HWBUG (tape_info_t* ti,int condno);
 #endif // _TAPE34XX_H
diff -u --recursive --new-file v2.4.7/linux/drivers/s390/char/tape3590.c linux/drivers/s390/char/tape3590.c
--- v2.4.7/linux/drivers/s390/char/tape3590.c	Wed Dec 31 16:00:00 1969
+++ linux/drivers/s390/char/tape3590.c	Wed Jul 25 14:12:02 2001
@@ -0,0 +1 @@
+// tbd
diff -u --recursive --new-file v2.4.7/linux/drivers/s390/char/tape3590.h linux/drivers/s390/char/tape3590.h
--- v2.4.7/linux/drivers/s390/char/tape3590.h	Wed Dec 31 16:00:00 1969
+++ linux/drivers/s390/char/tape3590.h	Wed Jul 25 14:12:02 2001
@@ -0,0 +1 @@
+// tbd
diff -u --recursive --new-file v2.4.7/linux/drivers/s390/char/tapeblock.c linux/drivers/s390/char/tapeblock.c
--- v2.4.7/linux/drivers/s390/char/tapeblock.c	Thu Apr 12 12:16:35 2001
+++ linux/drivers/s390/char/tapeblock.c	Wed Jul 25 14:12:02 2001
@@ -56,29 +56,29 @@
 
 #ifdef CONFIG_DEVFS_FS
 void
-tapeblock_mkdevfstree (tape_info_t* tape) {
-    tape->devfs_block_dir=devfs_mk_dir (tape->devfs_dir, "block", tape);
-    tape->devfs_disc=devfs_register(tape->devfs_block_dir, "disc",DEVFS_FL_DEFAULT,
-				    tapeblock_major, tape->blk_minor,
-				    TAPEBLOCK_DEFAULTMODE, &tapeblock_fops, tape);
+tapeblock_mkdevfstree (tape_info_t* ti) {
+    ti->devfs_block_dir=devfs_mk_dir (ti->devfs_dir, "block", ti);
+    ti->devfs_disc=devfs_register(ti->devfs_block_dir, "disc",DEVFS_FL_DEFAULT,
+				    tapeblock_major, ti->blk_minor,
+				    TAPEBLOCK_DEFAULTMODE, &tapeblock_fops, ti);
 }
 
 void
-tapeblock_rmdevfstree (tape_info_t* tape) {
-    devfs_unregister(tape->devfs_disc);
-    devfs_unregister(tape->devfs_block_dir);
+tapeblock_rmdevfstree (tape_info_t* ti) {
+    devfs_unregister(ti->devfs_disc);
+    devfs_unregister(ti->devfs_block_dir);
 }
 #endif
 
 void 
-tapeblock_setup(tape_info_t* tape) {
-    blk_size[tapeblock_major][tape->blk_minor]=0; // this will be detected
-    blksize_size[tapeblock_major][tape->blk_minor]=2048; // blocks are 2k by default.
-    hardsect_size[tapeblock_major][tape->blk_minor]=512;
-    blk_init_queue (&tape->request_queue, tape_request_fn); 
-    blk_queue_headactive (&tape->request_queue, 0); 
+tapeblock_setup(tape_info_t* ti) {
+    blk_size[tapeblock_major][ti->blk_minor]=0; // this will be detected
+    blksize_size[tapeblock_major][ti->blk_minor]=2048; // blocks are 2k by default.
+    hardsect_size[tapeblock_major][ti->blk_minor]=512;
+    blk_init_queue (&ti->request_queue, tape_request_fn); 
+    blk_queue_headactive (&ti->request_queue, 0); 
 #ifdef CONFIG_DEVFS_FS
-    tapeblock_mkdevfstree(tape);
+    tapeblock_mkdevfstree(ti);
 #endif
 }
 
@@ -86,7 +86,7 @@
 tapeblock_init(void) {
     int result;
     tape_frontend_t* blkfront,*temp;
-    tape_info_t* tape;
+    tape_info_t* ti;
 
     tape_init();
     /* Register the tape major number to the kernel */
@@ -127,10 +127,10 @@
 	temp=temp->next;
 	temp->next=blkfront;
     }
-    tape=first_tape_info;
-    while (tape!=NULL) {
-	tapeblock_setup(tape);
-	tape=tape->next;
+    ti=first_tape_info;
+    while (ti!=NULL) {
+	tapeblock_setup(ti);
+	ti=ti->next;
     }
     return 0;
 }
@@ -171,7 +171,12 @@
         
 	s390irq_spin_unlock_irqrestore (ti->devinfo.irq, lockflags);
         rc=tapeblock_mediumdetect(ti);
-        if (rc) return rc; // in case of errors, we don't have a size of the medium
+        if (rc) {
+	    s390irq_spin_lock_irqsave (ti->devinfo.irq, lockflags);
+	    tapestate_set (ti, TS_UNUSED);
+	    s390irq_spin_unlock_irqrestore (ti->devinfo.irq, lockflags);
+	    return rc; // in case of errors, we don't have a size of the medium
+	}
 	dev = MKDEV (tapeblock_major, MINOR (inode->i_rdev));	/* Get the device */
 	s390irq_spin_lock_irqsave (ti->devinfo.irq, lockflags);
 	ti->blk_filp = filp;
@@ -224,171 +229,171 @@
 }
 
 static void
-tapeblock_end_request(tape_info_t* tape) {
+tapeblock_end_request(tape_info_t* ti) {
     struct buffer_head *bh;
     int uptodate;
-    if ((tapestate_get(tape)!=TS_FAILED) &&
-	(tapestate_get(tape)!=TS_DONE))
+    if ((tapestate_get(ti)!=TS_FAILED) &&
+	(tapestate_get(ti)!=TS_DONE))
        BUG(); // A request has to be completed to end it
-    uptodate=(tapestate_get(tape)==TS_DONE); // is the buffer up to date?
+    uptodate=(tapestate_get(ti)==TS_DONE); // is the buffer up to date?
 #ifdef TAPE_DEBUG
     if (uptodate) {
 	debug_text_event (tape_debug_area,6,"b:done:");
-	debug_int_event (tape_debug_area,6,(long)tape->cqr);
+	debug_int_event (tape_debug_area,6,(long)ti->cqr);
     } else {
 	debug_text_event (tape_debug_area,3,"b:failed:");
-	debug_int_event (tape_debug_area,3,(long)tape->cqr);
+	debug_int_event (tape_debug_area,3,(long)ti->cqr);
     }
 #endif
     // now inform ll_rw_block about a request status
-    while ((bh = tape->current_request->bh) != NULL) {
-	tape->current_request->bh = bh->b_reqnext;
+    while ((bh = ti->current_request->bh) != NULL) {
+	ti->current_request->bh = bh->b_reqnext;
 	bh->b_reqnext = NULL;
 	bh->b_end_io (bh, uptodate);
     }
-    if (!end_that_request_first (tape->current_request, uptodate, "tBLK")) {
+    if (!end_that_request_first (ti->current_request, uptodate, "tBLK")) {
 #ifndef DEVICE_NO_RANDOM
-	add_blkdev_randomness (MAJOR (tape->current_request->rq_dev));
+	add_blkdev_randomness (MAJOR (ti->current_request->rq_dev));
 #endif
-	end_that_request_last (tape->current_request);
+	end_that_request_last (ti->current_request);
     }
-    tape->discipline->free_bread(tape->cqr,tape);
-    tape->cqr=NULL;
-    tape->current_request=NULL;
-    if (tapestate_get(tape)!=TS_NOT_OPER) tapestate_set(tape,TS_IDLE);
+    ti->discipline->free_bread(ti->cqr,ti);
+    ti->cqr=NULL;
+    ti->current_request=NULL;
+    if (tapestate_get(ti)!=TS_NOT_OPER) tapestate_set(ti,TS_IDLE);
     return;
 }
 
 static void
-tapeblock_exec_IO (tape_info_t* tape) {
+tapeblock_exec_IO (tape_info_t* ti) {
     int rc;
     struct request* req;
-    if (tape->cqr) { // process done/failed request
-	while ((tapestate_get(tape)==TS_FAILED) &&
-	    tape->blk_retries>0) {
-	    tape->blk_retries--;
-	    tape->position=-1;
-	    tapestate_set(tape,TS_BLOCK_INIT);
+    if (ti->cqr) { // process done/failed request
+	while ((tapestate_get(ti)==TS_FAILED) &&
+	    ti->blk_retries>0) {
+	    ti->blk_retries--;
+	    ti->position=-1;
+	    tapestate_set(ti,TS_BLOCK_INIT);
 #ifdef TAPE_DEBUG
 	    debug_text_event (tape_debug_area,3,"b:retryreq:");
-	    debug_int_event (tape_debug_area,3,(long)tape->cqr);
+	    debug_int_event (tape_debug_area,3,(long)ti->cqr);
 #endif
-	    rc = do_IO (tape->devinfo.irq, tape->cqr->cpaddr, (unsigned long) tape->cqr, 
-			0x00, tape->cqr->options);
+	    rc = do_IO (ti->devinfo.irq, ti->cqr->cpaddr, (unsigned long) ti->cqr, 
+			0x00, ti->cqr->options);
 	    if (rc) {
 #ifdef TAPE_DEBUG
 		debug_text_event (tape_debug_area,3,"b:doIOfail:");
-		debug_int_event (tape_debug_area,3,(long)tape->cqr);
+		debug_int_event (tape_debug_area,3,(long)ti->cqr);
 #endif 
 		continue; // one retry lost 'cause doIO failed
 	    }
 	    return;
 	}
-	tapeblock_end_request (tape); // check state, inform user, free mem, dev=idl
+	tapeblock_end_request (ti); // check state, inform user, free mem, dev=idl
     }
-    if (tape->cqr!=NULL) BUG(); // tape should be idle now, request should be freed!
-    if (tapestate_get (tape) == TS_NOT_OPER) {
-	tape->blk_minor=tape->rew_minor=tape->nor_minor=-1;
-	tape->devinfo.irq=-1;
+    if (ti->cqr!=NULL) BUG(); // tape should be idle now, request should be freed!
+    if (tapestate_get (ti) == TS_NOT_OPER) {
+	ti->blk_minor=ti->rew_minor=ti->nor_minor=-1;
+	ti->devinfo.irq=-1;
 	return;
     }
 #if (LINUX_VERSION_CODE > KERNEL_VERSION(2,3,98))
-	if (list_empty (&tape->request_queue.queue_head)) {
+	if (list_empty (&ti->request_queue.queue_head)) {
 #else
-	if (tape->request_queue==NULL) {
+	if (ti->request_queue==NULL) {
 #endif
 	// nothing more to do or device has dissapeared;)
 #ifdef TAPE_DEBUG
 	debug_text_event (tape_debug_area,6,"b:Qempty");
 #endif
-	tapestate_set(tape,TS_IDLE);
+	tapestate_set(ti,TS_IDLE);
 	return;
     }
     // queue is not empty, fetch a request and start IO!
-    req=tape->current_request=tape_next_request(&tape->request_queue);
+    req=ti->current_request=tape_next_request(&ti->request_queue);
     if (req==NULL) {
 	BUG(); // Yo. The queue was not reported empy, but no request found. This is _bad_.
     }
     if (req->cmd!=READ) { // we only support reading
-	tapestate_set(tape,TS_FAILED);
-	tapeblock_end_request (tape); // check state, inform user, free mem, dev=idl
-	tapestate_set(tape,TS_BLOCK_INIT);
-	schedule_tapeblock_exec_IO(tape);
+	tapestate_set(ti,TS_FAILED);
+	tapeblock_end_request (ti); // check state, inform user, free mem, dev=idl
+	tapestate_set(ti,TS_BLOCK_INIT);
+	schedule_tapeblock_exec_IO(ti);
 	return;
     }
-    tape->cqr=tape->discipline->bread(req,tape,tapeblock_major); //build channel program from request
-    if (!tape->cqr) {
+    ti->cqr=ti->discipline->bread(req,ti,tapeblock_major); //build channel program from request
+    if (!ti->cqr) {
 	// ccw generation failed. we try again later.
 #ifdef TAPE_DEBUG
 	debug_text_event (tape_debug_area,3,"b:cqrNULL");
 #endif
-	schedule_tapeblock_exec_IO(tape);
-	tape->current_request=NULL;
+	schedule_tapeblock_exec_IO(ti);
+	ti->current_request=NULL;
 	return;
     }
-    tape->blk_retries = TAPEBLOCK_RETRIES;
-    rc= do_IO (tape->devinfo.irq, tape->cqr->cpaddr, 
-	       (unsigned long) tape->cqr, 0x00, tape->cqr->options);
+    ti->blk_retries = TAPEBLOCK_RETRIES;
+    rc= do_IO (ti->devinfo.irq, ti->cqr->cpaddr, 
+	       (unsigned long) ti->cqr, 0x00, ti->cqr->options);
     if (rc) {
 	// okay. ssch failed. we try later.
 #ifdef TAPE_DEBUG
 	debug_text_event (tape_debug_area,3,"b:doIOfail");
 #endif
-	tape->discipline->free_bread(tape->cqr,tape);
-	tape->cqr=NULL;
-	tape->current_request=NULL;
-	schedule_tapeblock_exec_IO(tape);
+	ti->discipline->free_bread(ti->cqr,ti);
+	ti->cqr=NULL;
+	ti->current_request=NULL;
+	schedule_tapeblock_exec_IO(ti);
 	return;
     }
     // our request is in IO. we remove it from the queue and exit
-    tape_dequeue_request (&tape->request_queue,req);
+    tape_dequeue_request (&ti->request_queue,req);
 }
 
 static void 
 do_tape_request (request_queue_t * queue) {
-    tape_info_t* tape;
+    tape_info_t* ti;
     long lockflags;
-    for (tape=first_tape_info;
-	 ((tape!=NULL) && ((&tape->request_queue)!=queue));
-	 tape=tape->next);
-    if (tape==NULL) BUG();
-    s390irq_spin_lock_irqsave (tape->devinfo.irq, lockflags);
-    if (tapestate_get(tape)!=TS_IDLE) {
-	s390irq_spin_unlock_irqrestore(tape->devinfo.irq,lockflags);
+    for (ti=first_tape_info;
+	 ((ti!=NULL) && ((&ti->request_queue)!=queue));
+	 ti=ti->next);
+    if (ti==NULL) BUG();
+    s390irq_spin_lock_irqsave (ti->devinfo.irq, lockflags);
+    if (tapestate_get(ti)!=TS_IDLE) {
+	s390irq_spin_unlock_irqrestore(ti->devinfo.irq,lockflags);
 	return;
     }
-    if (tapestate_get(tape)!=TS_IDLE) BUG();
-    tapestate_set(tape,TS_BLOCK_INIT);
-    tapeblock_exec_IO(tape);
-    s390irq_spin_unlock_irqrestore(tape->devinfo.irq,lockflags);
+    if (tapestate_get(ti)!=TS_IDLE) BUG();
+    tapestate_set(ti,TS_BLOCK_INIT);
+    tapeblock_exec_IO(ti);
+    s390irq_spin_unlock_irqrestore(ti->devinfo.irq,lockflags);
 }
 
 static void
-run_tapeblock_exec_IO (tape_info_t* tape) {
+run_tapeblock_exec_IO (tape_info_t* ti) {
     long flags_390irq,flags_ior;
     spin_lock_irqsave (&io_request_lock, flags_ior);
-    s390irq_spin_lock_irqsave(tape->devinfo.irq,flags_390irq);
-    atomic_set(&tape->bh_scheduled,0);
-    tapeblock_exec_IO(tape);
-    s390irq_spin_unlock_irqrestore(tape->devinfo.irq,flags_390irq);
+    s390irq_spin_lock_irqsave(ti->devinfo.irq,flags_390irq);
+    atomic_set(&ti->bh_scheduled,0);
+    tapeblock_exec_IO(ti);
+    s390irq_spin_unlock_irqrestore(ti->devinfo.irq,flags_390irq);
     spin_unlock_irqrestore (&io_request_lock, flags_ior);
 }
 
 void
-schedule_tapeblock_exec_IO (tape_info_t *tape)
+schedule_tapeblock_exec_IO (tape_info_t *ti)
 {
 	/* Protect against rescheduling, when already running */
-        if (atomic_compare_and_swap(0,1,&tape->bh_scheduled)) {
+        if (atomic_compare_and_swap(0,1,&ti->bh_scheduled)) {
                 return;
         }
 #if (LINUX_VERSION_CODE > KERNEL_VERSION(2,3,98))
-	INIT_LIST_HEAD(&tape->bh_tq.list);
+	INIT_LIST_HEAD(&ti->bh_tq.list);
 #endif
-	tape->bh_tq.sync = 0;
-	tape->bh_tq.routine = (void *) (void *) run_tapeblock_exec_IO;
-	tape->bh_tq.data = tape;
+	ti->bh_tq.sync = 0;
+	ti->bh_tq.routine = (void *) (void *) run_tapeblock_exec_IO;
+	ti->bh_tq.data = ti;
 
-	queue_task (&tape->bh_tq, &tq_immediate);
+	queue_task (&ti->bh_tq, &tq_immediate);
 	mark_bh (IMMEDIATE_BH);
 	return;
 }
@@ -396,10 +401,10 @@
 /* wrappers around do_tape_request for different kernel versions */
 #if (LINUX_VERSION_CODE < KERNEL_VERSION(2,3,98))
 static void tape_request_fn (void) {
-    tape_info_t* tape=first_tape_info;
-    while (tape!=NULL) {
-	do_tape_request(&tape->request_queue);
-	tape=tape->next;
+    tape_info_t* ti=first_tape_info;
+    while (ti!=NULL) {
+	do_tape_request(&ti->request_queue);
+	ti=ti->next;
     }
 }
 #else
@@ -409,14 +414,14 @@
 #endif
 
 static request_queue_t* tapeblock_getqueue (kdev_t kdev) {
-    tape_info_t* tape=first_tape_info;
-    while ((tape!=NULL) && (MINOR(kdev)!=tape->blk_minor)) 
-        tape=tape->next;
-    if (tape!=NULL) return &tape->request_queue;
+    tape_info_t* ti=first_tape_info;
+    while ((ti!=NULL) && (MINOR(kdev)!=ti->blk_minor)) 
+        ti=ti->next;
+    if (ti!=NULL) return &ti->request_queue;
     return NULL;
 }
 
-int tapeblock_mediumdetect(tape_info_t* tape) {
+int tapeblock_mediumdetect(tape_info_t* ti) {
         ccw_req_t* cqr;
     int losize=1,hisize=1,rc;
     long lockflags;
@@ -426,168 +431,168 @@
     PRINT_WARN("Detecting media size. This will take _long_, so get yourself a coffee...\n");
     while (1) { //is interruped by break
 	hisize=hisize << 1; // try twice the size tested before 
-	cqr=tape->discipline->mtseek (tape, hisize);
+	cqr=ti->discipline->mtseek (ti, hisize);
 	if (cqr == NULL) {
 #ifdef TAPE_DEBUG
 	    debug_text_event (tape_debug_area,6,"b:ccwg fail");
 #endif
 	    return -ENOSPC;
 	}
-	s390irq_spin_lock_irqsave (tape->devinfo.irq, lockflags);
-	tape->cqr = cqr;
-	tape->wanna_wakeup=0;
-	rc = do_IO (tape->devinfo.irq, cqr->cpaddr, (unsigned long) cqr, 0x00, cqr->options);
-	s390irq_spin_unlock_irqrestore (tape->devinfo.irq, lockflags);
+	s390irq_spin_lock_irqsave (ti->devinfo.irq, lockflags);
+	ti->cqr = cqr;
+	ti->wanna_wakeup=0;
+	rc = do_IO (ti->devinfo.irq, cqr->cpaddr, (unsigned long) cqr, 0x00, cqr->options);
+	s390irq_spin_unlock_irqrestore (ti->devinfo.irq, lockflags);
 	if (rc) return -EIO;
-	wait_event_interruptible (tape->wq,tape->wanna_wakeup);
-	tape->cqr = NULL;
+	wait_event_interruptible (ti->wq,ti->wanna_wakeup);
+	ti->cqr = NULL;
 	tape_free_request (cqr);
-	if (tape->kernbuf) {
-	    kfree (tape->kernbuf);
-	    tape->kernbuf=NULL;
+	if (ti->kernbuf) {
+	    kfree (ti->kernbuf);
+	    ti->kernbuf=NULL;
 	}
 	if (signal_pending (current)) {
-		tapestate_set (tape, TS_IDLE);
+		tapestate_set (ti, TS_IDLE);
 		return -ERESTARTSYS;
 	}
-	s390irq_spin_lock_irqsave (tape->devinfo.irq, lockflags);
-	if (tapestate_get (tape) == TS_FAILED) {
-		tapestate_set (tape, TS_IDLE);
-		s390irq_spin_unlock_irqrestore (tape->devinfo.irq, lockflags);
+	s390irq_spin_lock_irqsave (ti->devinfo.irq, lockflags);
+	if (tapestate_get (ti) == TS_FAILED) {
+		tapestate_set (ti, TS_IDLE);
+		s390irq_spin_unlock_irqrestore (ti->devinfo.irq, lockflags);
 		break;
 	}
-	if (tapestate_get (tape) == TS_NOT_OPER) {
-	    tape->blk_minor=tape->rew_minor=tape->nor_minor=-1;
-	    tape->devinfo.irq=-1;
-	    s390irq_spin_unlock_irqrestore (tape->devinfo.irq,lockflags);
+	if (tapestate_get (ti) == TS_NOT_OPER) {
+	    ti->blk_minor=ti->rew_minor=ti->nor_minor=-1;
+	    ti->devinfo.irq=-1;
+	    s390irq_spin_unlock_irqrestore (ti->devinfo.irq,lockflags);
 	    return -ENODEV;
 	}
-	if (tapestate_get (tape) != TS_DONE) {
-		tapestate_set (tape, TS_IDLE);
-		s390irq_spin_unlock_irqrestore (tape->devinfo.irq, lockflags);
+	if (tapestate_get (ti) != TS_DONE) {
+		tapestate_set (ti, TS_IDLE);
+		s390irq_spin_unlock_irqrestore (ti->devinfo.irq, lockflags);
 		return -EIO;
 	}
-	tapestate_set (tape, TS_IDLE);
-	s390irq_spin_unlock_irqrestore (tape->devinfo.irq, lockflags);
+	tapestate_set (ti, TS_IDLE);
+	s390irq_spin_unlock_irqrestore (ti->devinfo.irq, lockflags);
 	losize=hisize;
     }
-    cqr = tape->discipline->mtrew (tape, 1);
+    cqr = ti->discipline->mtrew (ti, 1);
     if (cqr == NULL) {
 #ifdef TAPE_DEBUG
 	debug_text_event (tape_debug_area,6,"b:ccwg fail");
 #endif
 	return -ENOSPC;
     }
-    s390irq_spin_lock_irqsave (tape->devinfo.irq, lockflags);
-    tape->cqr = cqr;
-    tape->wanna_wakeup=0;
-    rc = do_IO (tape->devinfo.irq, cqr->cpaddr, (unsigned long) cqr, 0x00, cqr->options);
-    s390irq_spin_unlock_irqrestore (tape->devinfo.irq, lockflags);
-    wait_event_interruptible (tape->wq,tape->wanna_wakeup);
-    tape->cqr = NULL;
+    s390irq_spin_lock_irqsave (ti->devinfo.irq, lockflags);
+    ti->cqr = cqr;
+    ti->wanna_wakeup=0;
+    rc = do_IO (ti->devinfo.irq, cqr->cpaddr, (unsigned long) cqr, 0x00, cqr->options);
+    s390irq_spin_unlock_irqrestore (ti->devinfo.irq, lockflags);
+    wait_event_interruptible (ti->wq,ti->wanna_wakeup);
+    ti->cqr = NULL;
     tape_free_request (cqr);
     if (signal_pending (current)) {
-	tapestate_set (tape, TS_IDLE);
+	tapestate_set (ti, TS_IDLE);
 	return -ERESTARTSYS;
     }
-    s390irq_spin_lock_irqsave (tape->devinfo.irq, lockflags);
-    if (tapestate_get (tape) == TS_FAILED) {
-	tapestate_set (tape, TS_IDLE);
-	s390irq_spin_unlock_irqrestore (tape->devinfo.irq, lockflags);
+    s390irq_spin_lock_irqsave (ti->devinfo.irq, lockflags);
+    if (tapestate_get (ti) == TS_FAILED) {
+	tapestate_set (ti, TS_IDLE);
+	s390irq_spin_unlock_irqrestore (ti->devinfo.irq, lockflags);
 	return -EIO;
     }
-    if (tapestate_get (tape) == TS_NOT_OPER) {
-	tape->blk_minor=tape->rew_minor=tape->nor_minor=-1;
-	tape->devinfo.irq=-1;
-	s390irq_spin_unlock_irqrestore (tape->devinfo.irq,lockflags);
+    if (tapestate_get (ti) == TS_NOT_OPER) {
+	ti->blk_minor=ti->rew_minor=ti->nor_minor=-1;
+	ti->devinfo.irq=-1;
+	s390irq_spin_unlock_irqrestore (ti->devinfo.irq,lockflags);
 	return -ENODEV;
     }
-    if (tapestate_get (tape) != TS_DONE) {
-	tapestate_set (tape, TS_IDLE);
-	s390irq_spin_unlock_irqrestore (tape->devinfo.irq, lockflags);
+    if (tapestate_get (ti) != TS_DONE) {
+	tapestate_set (ti, TS_IDLE);
+	s390irq_spin_unlock_irqrestore (ti->devinfo.irq, lockflags);
 	return -EIO;
     }
-    tapestate_set (tape, TS_IDLE);
-    s390irq_spin_unlock_irqrestore (tape->devinfo.irq, lockflags);
+    tapestate_set (ti, TS_IDLE);
+    s390irq_spin_unlock_irqrestore (ti->devinfo.irq, lockflags);
     while (losize!=hisize) {
-	cqr=tape->discipline->mtseek (tape, (hisize+losize)/2+1);
+	cqr=ti->discipline->mtseek (ti, (hisize+losize)/2+1);
 	if (cqr == NULL) {
 #ifdef TAPE_DEBUG
 	    debug_text_event (tape_debug_area,6,"b:ccwg fail");
 #endif
 	    return -ENOSPC;
 	}
-	s390irq_spin_lock_irqsave (tape->devinfo.irq, lockflags);
-	tape->cqr = cqr;
-	tape->wanna_wakeup=0;
-	rc = do_IO (tape->devinfo.irq, cqr->cpaddr, (unsigned long) cqr, 0x00, cqr->options);
-	s390irq_spin_unlock_irqrestore (tape->devinfo.irq, lockflags);
+	s390irq_spin_lock_irqsave (ti->devinfo.irq, lockflags);
+	ti->cqr = cqr;
+	ti->wanna_wakeup=0;
+	rc = do_IO (ti->devinfo.irq, cqr->cpaddr, (unsigned long) cqr, 0x00, cqr->options);
+	s390irq_spin_unlock_irqrestore (ti->devinfo.irq, lockflags);
 	if (rc) return -EIO;
-	wait_event_interruptible (tape->wq,tape->wanna_wakeup);
-	tape->cqr = NULL;
+	wait_event_interruptible (ti->wq,ti->wanna_wakeup);
+	ti->cqr = NULL;
 	tape_free_request (cqr);
-	if (tape->kernbuf) {
-	    kfree (tape->kernbuf);
-	    tape->kernbuf=NULL;
+	if (ti->kernbuf) {
+	    kfree (ti->kernbuf);
+	    ti->kernbuf=NULL;
 	}
 	if (signal_pending (current)) {
-		tapestate_set (tape, TS_IDLE);
+		tapestate_set (ti, TS_IDLE);
 		return -ERESTARTSYS;
 	}
-	s390irq_spin_lock_irqsave (tape->devinfo.irq, lockflags);
-	if (tapestate_get (tape) == TS_NOT_OPER) {
-	    tape->blk_minor=tape->rew_minor=tape->nor_minor=-1;
-	    tape->devinfo.irq=-1;
-	    s390irq_spin_unlock_irqrestore (tape->devinfo.irq,lockflags);
+	s390irq_spin_lock_irqsave (ti->devinfo.irq, lockflags);
+	if (tapestate_get (ti) == TS_NOT_OPER) {
+	    ti->blk_minor=ti->rew_minor=ti->nor_minor=-1;
+	    ti->devinfo.irq=-1;
+	    s390irq_spin_unlock_irqrestore (ti->devinfo.irq,lockflags);
 	    return -ENODEV;
 	}
-	if (tapestate_get (tape) == TS_FAILED) {
-		tapestate_set (tape, TS_IDLE);
-		s390irq_spin_unlock_irqrestore (tape->devinfo.irq, lockflags);
+	if (tapestate_get (ti) == TS_FAILED) {
+		tapestate_set (ti, TS_IDLE);
+		s390irq_spin_unlock_irqrestore (ti->devinfo.irq, lockflags);
 		hisize=(hisize+losize)/2;
-		cqr = tape->discipline->mtrew (tape, 1);
+		cqr = ti->discipline->mtrew (ti, 1);
 		if (cqr == NULL) {
 #ifdef TAPE_DEBUG
 		    debug_text_event (tape_debug_area,6,"b:ccwg fail");
 #endif
 		    return -ENOSPC;
 		}
-		s390irq_spin_lock_irqsave (tape->devinfo.irq, lockflags);
-		tape->cqr = cqr;
-		tape->wanna_wakeup=0;
-		rc = do_IO (tape->devinfo.irq, cqr->cpaddr, (unsigned long) cqr, 0x00, cqr->options);
-		s390irq_spin_unlock_irqrestore (tape->devinfo.irq, lockflags);
-		wait_event_interruptible (tape->wq,tape->wanna_wakeup);
-		tape->cqr = NULL;
+		s390irq_spin_lock_irqsave (ti->devinfo.irq, lockflags);
+		ti->cqr = cqr;
+		ti->wanna_wakeup=0;
+		rc = do_IO (ti->devinfo.irq, cqr->cpaddr, (unsigned long) cqr, 0x00, cqr->options);
+		s390irq_spin_unlock_irqrestore (ti->devinfo.irq, lockflags);
+		wait_event_interruptible (ti->wq,ti->wanna_wakeup);
+		ti->cqr = NULL;
 		tape_free_request (cqr);
 		if (signal_pending (current)) {
-		    tapestate_set (tape, TS_IDLE);
+		    tapestate_set (ti, TS_IDLE);
 		    return -ERESTARTSYS;
 		}
-		s390irq_spin_lock_irqsave (tape->devinfo.irq, lockflags);
-		if (tapestate_get (tape) == TS_FAILED) {
-		    tapestate_set (tape, TS_IDLE);
-		    s390irq_spin_unlock_irqrestore (tape->devinfo.irq, lockflags);
+		s390irq_spin_lock_irqsave (ti->devinfo.irq, lockflags);
+		if (tapestate_get (ti) == TS_FAILED) {
+		    tapestate_set (ti, TS_IDLE);
+		    s390irq_spin_unlock_irqrestore (ti->devinfo.irq, lockflags);
 		    return -EIO;
 		}
-		if (tapestate_get (tape) != TS_DONE) {
-		    tapestate_set (tape, TS_IDLE);
-		    s390irq_spin_unlock_irqrestore (tape->devinfo.irq, lockflags);
+		if (tapestate_get (ti) != TS_DONE) {
+		    tapestate_set (ti, TS_IDLE);
+		    s390irq_spin_unlock_irqrestore (ti->devinfo.irq, lockflags);
 		    return -EIO;
 		}
-		tapestate_set (tape, TS_IDLE);
-		s390irq_spin_unlock_irqrestore (tape->devinfo.irq, lockflags);
+		tapestate_set (ti, TS_IDLE);
+		s390irq_spin_unlock_irqrestore (ti->devinfo.irq, lockflags);
 		continue;
 	}
-	if (tapestate_get (tape) != TS_DONE) {
-		tapestate_set (tape, TS_IDLE);
-		s390irq_spin_unlock_irqrestore (tape->devinfo.irq, lockflags);
+	if (tapestate_get (ti) != TS_DONE) {
+		tapestate_set (ti, TS_IDLE);
+		s390irq_spin_unlock_irqrestore (ti->devinfo.irq, lockflags);
 		return -EIO;
 	}
-	tapestate_set (tape, TS_IDLE);
-	s390irq_spin_unlock_irqrestore (tape->devinfo.irq, lockflags);
+	tapestate_set (ti, TS_IDLE);
+	s390irq_spin_unlock_irqrestore (ti->devinfo.irq, lockflags);
 	losize=(hisize+losize)/2+1;
     }
-    blk_size[tapeblock_major][tape->blk_minor]=(losize)*(blksize_size[tapeblock_major][tape->blk_minor]/1024);
+    blk_size[tapeblock_major][ti->blk_minor]=(losize)*(blksize_size[tapeblock_major][ti->blk_minor]/1024);
     return 0;
 }
diff -u --recursive --new-file v2.4.7/linux/drivers/s390/char/tapeblock.h linux/drivers/s390/char/tapeblock.h
--- v2.4.7/linux/drivers/s390/char/tapeblock.h	Thu Apr 12 12:16:35 2001
+++ linux/drivers/s390/char/tapeblock.h	Wed Jul 25 14:12:02 2001
@@ -25,11 +25,11 @@
 
 int tapeblock_open(struct inode *, struct file *);
 int tapeblock_release(struct inode *, struct file *);
-void tapeblock_setup(tape_info_t* tape);
-void schedule_tapeblock_exec_IO (tape_info_t *tape);
-int tapeblock_mediumdetect(tape_info_t* tape);
+void tapeblock_setup(tape_info_t* ti);
+void schedule_tapeblock_exec_IO (tape_info_t *ti);
+int tapeblock_mediumdetect(tape_info_t* ti);
 #ifdef CONFIG_DEVFS_FS
-void tapeblock_mkdevfstree (tape_info_t* tape);
+void tapeblock_mkdevfstree (tape_info_t* ti);
 #endif
 int tapeblock_init (void);
 void tapeblock_uninit (void);
diff -u --recursive --new-file v2.4.7/linux/drivers/s390/char/tapechar.c linux/drivers/s390/char/tapechar.c
--- v2.4.7/linux/drivers/s390/char/tapechar.c	Thu Apr 12 12:16:35 2001
+++ linux/drivers/s390/char/tapechar.c	Wed Jul 25 14:12:02 2001
@@ -58,30 +58,30 @@
 
 #ifdef CONFIG_DEVFS_FS
 void
-tapechar_mkdevfstree (tape_info_t* tape) {
-    tape->devfs_char_dir=devfs_mk_dir (tape->devfs_dir, "char", tape);
-    tape->devfs_nonrewinding=devfs_register(tape->devfs_char_dir, "nonrewinding",
+tapechar_mkdevfstree (tape_info_t* ti) {
+    ti->devfs_char_dir=devfs_mk_dir (ti->devfs_dir, "char", ti);
+    ti->devfs_nonrewinding=devfs_register(ti->devfs_char_dir, "nonrewinding",
 					    DEVFS_FL_DEFAULT,tape_major, 
-					    tape->nor_minor, TAPECHAR_DEFAULTMODE, 
-					    &tape_fops, tape);
-    tape->devfs_rewinding=devfs_register(tape->devfs_char_dir, "rewinding",
-					 DEVFS_FL_DEFAULT, tape_major, tape->rew_minor,
-					 TAPECHAR_DEFAULTMODE, &tape_fops, tape);
+					    ti->nor_minor, TAPECHAR_DEFAULTMODE, 
+					    &tape_fops, ti);
+    ti->devfs_rewinding=devfs_register(ti->devfs_char_dir, "rewinding",
+					 DEVFS_FL_DEFAULT, tape_major, ti->rew_minor,
+					 TAPECHAR_DEFAULTMODE, &tape_fops, ti);
 }
 
 void
-tapechar_rmdevfstree (tape_info_t* tape) {
-    devfs_unregister(tape->devfs_nonrewinding);
-    devfs_unregister(tape->devfs_rewinding);
-    devfs_unregister(tape->devfs_char_dir);
+tapechar_rmdevfstree (tape_info_t* ti) {
+    devfs_unregister(ti->devfs_nonrewinding);
+    devfs_unregister(ti->devfs_rewinding);
+    devfs_unregister(ti->devfs_char_dir);
 }
 #endif
 
 void
-tapechar_setup (tape_info_t * tape)
+tapechar_setup (tape_info_t * ti)
 {
 #ifdef CONFIG_DEVFS_FS
-    tapechar_mkdevfstree(tape);
+    tapechar_mkdevfstree(ti);
 #endif
 }
 
@@ -90,7 +90,7 @@
 {
 	int result;
 	tape_frontend_t *charfront,*temp;
-	tape_info_t* tape;
+	tape_info_t* ti;
 
 	tape_init();
 
@@ -137,10 +137,10 @@
 		temp=temp->next;
 	    temp->next=charfront;
 	}
-	tape=first_tape_info;
-	while (tape!=NULL) {
-	    tapechar_setup(tape);
-	    tape=tape->next;
+	ti=first_tape_info;
+	while (ti!=NULL) {
+	    tapechar_setup(ti);
+	    ti=ti->next;
 	}
 }
 
@@ -157,17 +157,17 @@
 tape_read (struct file *filp, char *data, size_t count, loff_t * ppos)
 {
 	long lockflags;
-	tape_info_t *tape;
+	tape_info_t *ti;
 	size_t block_size;
 	ccw_req_t *cqr;
 	int rc;
 #ifdef TAPE_DEBUG
         debug_text_event (tape_debug_area,6,"c:read");
 #endif /* TAPE_DEBUG */
-	tape = first_tape_info;
-	while ((tape != NULL) && (tape->rew_filp != filp) && (tape->nor_filp != filp))
-		tape = (tape_info_t *) tape->next;
-	if (tape == NULL) {
+	ti = first_tape_info;
+	while ((ti != NULL) && (ti->rew_filp != filp) && (ti->nor_filp != filp))
+		ti = (tape_info_t *) ti->next;
+	if (ti == NULL) {
 #ifdef TAPE_DEBUG
 	        debug_text_event (tape_debug_area,6,"c:nodev");
 #endif /* TAPE_DEBUG */
@@ -180,62 +180,62 @@
 #endif /* TAPE_DEBUG */
 		return -EOVERFLOW;	/* errno=75 Value too large for def. data type */
 	}
-	if (tape->block_size == 0) {
+	if (ti->block_size == 0) {
 		block_size = count;
 	} else {
-		block_size = tape->block_size;
+		block_size = ti->block_size;
 	}
 #ifdef TAPE_DEBUG
 	debug_text_event (tape_debug_area,6,"c:nbytes:");
 	debug_int_event (tape_debug_area,6,block_size);
 #endif
-	cqr = tape->discipline->read_block (data, block_size, tape);
+	cqr = ti->discipline->read_block (data, block_size, ti);
 	if (!cqr) {
 		return -ENOBUFS;
 	}
-	s390irq_spin_lock_irqsave (tape->devinfo.irq, lockflags);
-	tape->cqr = cqr;
-	tape->wanna_wakeup=0;
-	rc = do_IO (tape->devinfo.irq, cqr->cpaddr, (unsigned long) cqr, 0x00, cqr->options);
+	s390irq_spin_lock_irqsave (ti->devinfo.irq, lockflags);
+	ti->cqr = cqr;
+	ti->wanna_wakeup=0;
+	rc = do_IO (ti->devinfo.irq, cqr->cpaddr, (unsigned long) cqr, 0x00, cqr->options);
 	if (rc) {
-	    tapestate_set(tape,TS_IDLE);
+	    tapestate_set(ti,TS_IDLE);
 	    kfree (cqr);
-	    s390irq_spin_unlock_irqrestore (tape->devinfo.irq, lockflags);
+	    s390irq_spin_unlock_irqrestore (ti->devinfo.irq, lockflags);
 	    return rc;
 	}
-	s390irq_spin_unlock_irqrestore (tape->devinfo.irq, lockflags);
-	wait_event_interruptible (tape->wq,tape->wanna_wakeup);
-	tape->cqr = NULL;
-	tape->discipline->free_read_block (cqr, tape);
+	s390irq_spin_unlock_irqrestore (ti->devinfo.irq, lockflags);
+	wait_event_interruptible (ti->wq,ti->wanna_wakeup);
+	ti->cqr = NULL;
+	ti->discipline->free_read_block (cqr, ti);
 	if (signal_pending (current)) {
-		tapestate_set (tape, TS_IDLE);
+		tapestate_set (ti, TS_IDLE);
 		return -ERESTARTSYS;
 	}
-	s390irq_spin_lock_irqsave (tape->devinfo.irq, lockflags);
-	if (tapestate_get (tape) == TS_FAILED) {
-		tapestate_set (tape, TS_IDLE);
-		s390irq_spin_unlock_irqrestore (tape->devinfo.irq, lockflags);
-		return tape->rc;
-	}
-	if (tapestate_get (tape) == TS_NOT_OPER) {
-	    tape->blk_minor=tape->rew_minor=tape->nor_minor=-1;
-	    tape->devinfo.irq=-1;
-	    s390irq_spin_unlock_irqrestore (tape->devinfo.irq,lockflags);
+	s390irq_spin_lock_irqsave (ti->devinfo.irq, lockflags);
+	if (tapestate_get (ti) == TS_FAILED) {
+		tapestate_set (ti, TS_IDLE);
+		s390irq_spin_unlock_irqrestore (ti->devinfo.irq, lockflags);
+		return ti->rc;
+	}
+	if (tapestate_get (ti) == TS_NOT_OPER) {
+	    ti->blk_minor=ti->rew_minor=ti->nor_minor=-1;
+	    ti->devinfo.irq=-1;
+	    s390irq_spin_unlock_irqrestore (ti->devinfo.irq,lockflags);
 	    return -ENODEV;
 	}
-	if (tapestate_get (tape) != TS_DONE) {
-		tapestate_set (tape, TS_IDLE);
-		s390irq_spin_unlock_irqrestore (tape->devinfo.irq, lockflags);
+	if (tapestate_get (ti) != TS_DONE) {
+		tapestate_set (ti, TS_IDLE);
+		s390irq_spin_unlock_irqrestore (ti->devinfo.irq, lockflags);
 		return -EIO;
 	}
-	tapestate_set (tape, TS_IDLE);
-	s390irq_spin_unlock_irqrestore (tape->devinfo.irq, lockflags);
+	tapestate_set (ti, TS_IDLE);
+	s390irq_spin_unlock_irqrestore (ti->devinfo.irq, lockflags);
 #ifdef TAPE_DEBUG
 	debug_text_event (tape_debug_area,6,"c:rbytes:");
-	debug_int_event (tape_debug_area,6,block_size - tape->devstat.rescnt);
+	debug_int_event (tape_debug_area,6,block_size - ti->devstat.rescnt);
 #endif	/* TAPE_DEBUG */
-	filp->f_pos += block_size - tape->devstat.rescnt;
-	return block_size - tape->devstat.rescnt;
+	filp->f_pos += block_size - ti->devstat.rescnt;
+	return block_size - ti->devstat.rescnt;
 }
 
 /*
@@ -245,7 +245,7 @@
 tape_write (struct file *filp, const char *data, size_t count, loff_t * ppos)
 {
 	long lockflags;
-	tape_info_t *tape;
+	tape_info_t *ti;
 	size_t block_size;
 	ccw_req_t *cqr;
 	int nblocks, i, rc;
@@ -253,10 +253,10 @@
 #ifdef TAPE_DEBUG
 	debug_text_event (tape_debug_area,6,"c:write");
 #endif
-	tape = first_tape_info;
-	while ((tape != NULL) && (tape->nor_filp != filp) && (tape->rew_filp != filp))
-		tape = (tape_info_t *) tape->next;
-	if (tape == NULL)
+	ti = first_tape_info;
+	while ((ti != NULL) && (ti->nor_filp != filp) && (ti->rew_filp != filp))
+		ti = (tape_info_t *) ti->next;
+	if (ti == NULL)
 		return -ENODEV;
 	if (ppos != &filp->f_pos) {
 		/* "A request was outside the capabilities of the device." */
@@ -265,14 +265,14 @@
 #endif
 		return -EOVERFLOW;	/* errno=75 Value too large for def. data type */
 	}
-	if ((tape->block_size != 0) && (count % tape->block_size != 0))
+	if ((ti->block_size != 0) && (count % ti->block_size != 0))
 		return -EIO;
-	if (tape->block_size == 0) {
+	if (ti->block_size == 0) {
 		block_size = count;
 		nblocks = 1;
 	} else {
-		block_size = tape->block_size;
-		nblocks = count / (tape->block_size);
+		block_size = ti->block_size;
+		nblocks = count / (ti->block_size);
 	}
 #ifdef TAPE_DEBUG
 	        debug_text_event (tape_debug_area,6,"c:nbytes:");
@@ -281,50 +281,50 @@
 	        debug_int_event (tape_debug_area,6,nblocks);
 #endif
 	for (i = 0; i < nblocks; i++) {
-		cqr = tape->discipline->write_block (data + i * block_size, block_size, tape);
+		cqr = ti->discipline->write_block (data + i * block_size, block_size, ti);
 		if (!cqr) {
 			return -ENOBUFS;
 		}
-		s390irq_spin_lock_irqsave (tape->devinfo.irq, lockflags);
-		tape->cqr = cqr;
-		tape->wanna_wakeup=0;
-		rc = do_IO (tape->devinfo.irq, cqr->cpaddr, (unsigned long) cqr, 0x00, cqr->options);
-		s390irq_spin_unlock_irqrestore (tape->devinfo.irq, lockflags);
-		wait_event_interruptible (tape->wq,tape->wanna_wakeup);
-		tape->cqr = NULL;
-		tape->discipline->free_write_block (cqr, tape);
+		s390irq_spin_lock_irqsave (ti->devinfo.irq, lockflags);
+		ti->cqr = cqr;
+		ti->wanna_wakeup=0;
+		rc = do_IO (ti->devinfo.irq, cqr->cpaddr, (unsigned long) cqr, 0x00, cqr->options);
+		s390irq_spin_unlock_irqrestore (ti->devinfo.irq, lockflags);
+		wait_event_interruptible (ti->wq,ti->wanna_wakeup);
+		ti->cqr = NULL;
+		ti->discipline->free_write_block (cqr, ti);
 		if (signal_pending (current)) {
-			tapestate_set (tape, TS_IDLE);
+			tapestate_set (ti, TS_IDLE);
 			return -ERESTARTSYS;
 		}
-		s390irq_spin_lock_irqsave (tape->devinfo.irq, lockflags);
-		if (tapestate_get (tape) == TS_FAILED) {
-			tapestate_set (tape, TS_IDLE);
-			s390irq_spin_unlock_irqrestore (tape->devinfo.irq, lockflags);
-                        if ((tape->rc==-ENOSPC) && (i!=0))
+		s390irq_spin_lock_irqsave (ti->devinfo.irq, lockflags);
+		if (tapestate_get (ti) == TS_FAILED) {
+			tapestate_set (ti, TS_IDLE);
+			s390irq_spin_unlock_irqrestore (ti->devinfo.irq, lockflags);
+                        if ((ti->rc==-ENOSPC) && (i!=0))
 			  return i*block_size;
-			return tape->rc;
+			return ti->rc;
 		}
-		if (tapestate_get (tape) == TS_NOT_OPER) {
-		    tape->blk_minor=tape->rew_minor=tape->nor_minor=-1;
-		    tape->devinfo.irq=-1;
-		    s390irq_spin_unlock_irqrestore (tape->devinfo.irq,lockflags);
+		if (tapestate_get (ti) == TS_NOT_OPER) {
+		    ti->blk_minor=ti->rew_minor=ti->nor_minor=-1;
+		    ti->devinfo.irq=-1;
+		    s390irq_spin_unlock_irqrestore (ti->devinfo.irq,lockflags);
 		    return -ENODEV;
 		}
-		if (tapestate_get (tape) != TS_DONE) {
-			tapestate_set (tape, TS_IDLE);
-			s390irq_spin_unlock_irqrestore (tape->devinfo.irq, lockflags);
+		if (tapestate_get (ti) != TS_DONE) {
+			tapestate_set (ti, TS_IDLE);
+			s390irq_spin_unlock_irqrestore (ti->devinfo.irq, lockflags);
 			return -EIO;
 		}
-		tapestate_set (tape, TS_IDLE);
-		s390irq_spin_unlock_irqrestore (tape->devinfo.irq, lockflags);
+		tapestate_set (ti, TS_IDLE);
+		s390irq_spin_unlock_irqrestore (ti->devinfo.irq, lockflags);
 #ifdef TAPE_DEBUG
 	        debug_text_event (tape_debug_area,6,"c:wbytes:"); 
-		debug_int_event (tape_debug_area,6,block_size - tape->devstat.rescnt);
+		debug_int_event (tape_debug_area,6,block_size - ti->devstat.rescnt);
 #endif
-		filp->f_pos += block_size - tape->devstat.rescnt;
-		written += block_size - tape->devstat.rescnt;
-		if (tape->devstat.rescnt > 0)
+		filp->f_pos += block_size - ti->devstat.rescnt;
+		written += block_size - ti->devstat.rescnt;
+		if (ti->devstat.rescnt > 0)
 			return written;
 	}
 #ifdef TAPE_DEBUG
@@ -337,7 +337,7 @@
 static int
 tape_mtioctop (struct file *filp, short mt_op, int mt_count)
 {
-	tape_info_t *tape;
+	tape_info_t *ti;
 	ccw_req_t *cqr = NULL;
 	int rc;
 	long lockflags;
@@ -348,113 +348,118 @@
 	debug_text_event (tape_debug_area,6,"c:arg:");
 	debug_int_event (tape_debug_area,6,mt_count);
 #endif
-	tape = first_tape_info;
-	while ((tape != NULL) && (tape->rew_filp != filp) && (tape->nor_filp != filp))
-		tape = (tape_info_t *) tape->next;
-	if (tape == NULL)
+	ti = first_tape_info;
+	while ((ti != NULL) && (ti->rew_filp != filp) && (ti->nor_filp != filp))
+		ti = (tape_info_t *) ti->next;
+	if (ti == NULL)
 		return -ENODEV;
 	switch (mt_op) {
 	case MTREW:		// rewind
 
-		cqr = tape->discipline->mtrew (tape, mt_count);
+		cqr = ti->discipline->mtrew (ti, mt_count);
 		break;
 	case MTOFFL:		// put drive offline
 
-		cqr = tape->discipline->mtoffl (tape, mt_count);
+		cqr = ti->discipline->mtoffl (ti, mt_count);
 		break;
 	case MTUNLOAD:		// unload the tape
 
-		cqr = tape->discipline->mtunload (tape, mt_count);
+		cqr = ti->discipline->mtunload (ti, mt_count);
 		break;
 	case MTWEOF:		// write tapemark
 
-		cqr = tape->discipline->mtweof (tape, mt_count);
+		cqr = ti->discipline->mtweof (ti, mt_count);
 		break;
 	case MTFSF:		// forward space file
 
-		cqr = tape->discipline->mtfsf (tape, mt_count);
+		cqr = ti->discipline->mtfsf (ti, mt_count);
 		break;
 	case MTBSF:		// backward space file
 
-		cqr = tape->discipline->mtbsf (tape, mt_count);
+		cqr = ti->discipline->mtbsf (ti, mt_count);
 		break;
 	case MTFSFM:		// forward space file, stop at BOT side
 
-		cqr = tape->discipline->mtfsfm (tape, mt_count);
+		cqr = ti->discipline->mtfsfm (ti, mt_count);
 		break;
 	case MTBSFM:		// backward space file, stop at BOT side
 
-		cqr = tape->discipline->mtbsfm (tape, mt_count);
+		cqr = ti->discipline->mtbsfm (ti, mt_count);
 		break;
 	case MTFSR:		// forward space file
 
-		cqr = tape->discipline->mtfsr (tape, mt_count);
+		cqr = ti->discipline->mtfsr (ti, mt_count);
 		break;
 	case MTBSR:		// backward space file
 
-		cqr = tape->discipline->mtbsr (tape, mt_count);
+		cqr = ti->discipline->mtbsr (ti, mt_count);
 		break;
 	case MTNOP:
-		cqr = tape->discipline->mtnop (tape, mt_count);
+		cqr = ti->discipline->mtnop (ti, mt_count);
 		break;
 	case MTEOM:		// postion at the end of portion
 
 	case MTRETEN:		// retension the tape
 
-		cqr = tape->discipline->mteom (tape, mt_count);
+		cqr = ti->discipline->mteom (ti, mt_count);
 		break;
 	case MTERASE:
-		cqr = tape->discipline->mterase (tape, mt_count);
+		cqr = ti->discipline->mterase (ti, mt_count);
 		break;
 	case MTSETDENSITY:
-		cqr = tape->discipline->mtsetdensity (tape, mt_count);
+		cqr = ti->discipline->mtsetdensity (ti, mt_count);
 		break;
 	case MTSEEK:
-		cqr = tape->discipline->mtseek (tape, mt_count);
+		cqr = ti->discipline->mtseek (ti, mt_count);
 		break;
 	case MTSETDRVBUFFER:
-		cqr = tape->discipline->mtsetdrvbuffer (tape, mt_count);
+		cqr = ti->discipline->mtsetdrvbuffer (ti, mt_count);
 		break;
 	case MTLOCK:
-		cqr = tape->discipline->mtsetdrvbuffer (tape, mt_count);
+		cqr = ti->discipline->mtsetdrvbuffer (ti, mt_count);
 		break;
 	case MTUNLOCK:
-		cqr = tape->discipline->mtsetdrvbuffer (tape, mt_count);
+		cqr = ti->discipline->mtsetdrvbuffer (ti, mt_count);
 		break;
 	case MTLOAD:
-		cqr = tape->discipline->mtload (tape, mt_count);
-		break;
+		cqr = ti->discipline->mtload (ti, mt_count);
+		if (cqr!=NULL) break; // if backend driver has an load function ->use it
+		// if no medium is in, wait until it gets inserted
+		if (ti->medium_is_unloaded) {
+		    wait_event_interruptible (ti->wq,ti->medium_is_unloaded==0);
+		}
+		return 0;
 	case MTCOMPRESSION:
-		cqr = tape->discipline->mtcompression (tape, mt_count);
+		cqr = ti->discipline->mtcompression (ti, mt_count);
 		break;
 	case MTSETPART:
-		cqr = tape->discipline->mtsetpart (tape, mt_count);
+		cqr = ti->discipline->mtsetpart (ti, mt_count);
 		break;
 	case MTMKPART:
-		cqr = tape->discipline->mtmkpart (tape, mt_count);
+		cqr = ti->discipline->mtmkpart (ti, mt_count);
 		break;
 	case MTTELL:		// return number of block relative to current file
 
-		cqr = tape->discipline->mttell (tape, mt_count);
+		cqr = ti->discipline->mttell (ti, mt_count);
 		break;
 	case MTSETBLK:
-		s390irq_spin_lock_irqsave (tape->devinfo.irq, lockflags);
-		tape->block_size = mt_count;
-		s390irq_spin_unlock_irqrestore (tape->devinfo.irq, lockflags);
+		s390irq_spin_lock_irqsave (ti->devinfo.irq, lockflags);
+		ti->block_size = mt_count;
+		s390irq_spin_unlock_irqrestore (ti->devinfo.irq, lockflags);
 #ifdef TAPE_DEBUG
 		debug_text_event (tape_debug_area,6,"c:setblk:");
 	        debug_int_event (tape_debug_area,6,mt_count);
 #endif
 		return 0;
 	case MTRESET:
-		s390irq_spin_lock_irqsave (tape->devinfo.irq, lockflags);
-		tape->kernbuf = tape->userbuf = NULL;
-		tapestate_set (tape, TS_IDLE);
-		tape->block_size = 0;
-		s390irq_spin_unlock_irqrestore (tape->devinfo.irq, lockflags);
+		s390irq_spin_lock_irqsave (ti->devinfo.irq, lockflags);
+		ti->kernbuf = ti->userbuf = NULL;
+		tapestate_set (ti, TS_IDLE);
+		ti->block_size = 0;
+		s390irq_spin_unlock_irqrestore (ti->devinfo.irq, lockflags);
 #ifdef TAPE_DEBUG
 		debug_text_event (tape_debug_area,6,"c:devreset:");
-		debug_int_event (tape_debug_area,6,tape->blk_minor);
+		debug_int_event (tape_debug_area,6,ti->blk_minor);
 #endif
 		return 0;
 	default:
@@ -469,43 +474,49 @@
 #endif
 		return -ENOSPC;
 	}
-	s390irq_spin_lock_irqsave (tape->devinfo.irq, lockflags);
-	tape->cqr = cqr;
-	tape->wanna_wakeup=0;
-	rc = do_IO (tape->devinfo.irq, cqr->cpaddr, (unsigned long) cqr, 0x00, cqr->options);
-	s390irq_spin_unlock_irqrestore (tape->devinfo.irq, lockflags);
-	wait_event_interruptible (tape->wq,tape->wanna_wakeup);
-	tape->cqr = NULL;
-	if (tape->kernbuf != NULL) {
-		kfree (tape->kernbuf);
-		tape->kernbuf = NULL;
+	s390irq_spin_lock_irqsave (ti->devinfo.irq, lockflags);
+	ti->cqr = cqr;
+	ti->wanna_wakeup=0;
+	rc = do_IO (ti->devinfo.irq, cqr->cpaddr, (unsigned long) cqr, 0x00, cqr->options);
+	s390irq_spin_unlock_irqrestore (ti->devinfo.irq, lockflags);
+	wait_event_interruptible (ti->wq,ti->wanna_wakeup);
+	ti->cqr = NULL;
+	if (ti->kernbuf != NULL) {
+		kfree (ti->kernbuf);
+		ti->kernbuf = NULL;
 	}
 	tape_free_request (cqr);
+	// if medium was unloaded, update the corresponding variable.
+	switch (mt_op) {
+	case MTOFFL:
+	case MTUNLOAD:
+	    ti->medium_is_unloaded=1;
+	}
 	if (signal_pending (current)) {
-		tapestate_set (tape, TS_IDLE);
+		tapestate_set (ti, TS_IDLE);
 		return -ERESTARTSYS;
 	}
-	s390irq_spin_lock_irqsave (tape->devinfo.irq, lockflags);
-	if (((mt_op == MTEOM) || (mt_op == MTRETEN)) && (tapestate_get (tape) == TS_FAILED))
-		tapestate_set (tape, TS_DONE);
-	if (tapestate_get (tape) == TS_FAILED) {
-		tapestate_set (tape, TS_IDLE);
-		s390irq_spin_unlock_irqrestore (tape->devinfo.irq, lockflags);
-		return tape->rc;
-	}
-	if (tapestate_get (tape) == TS_NOT_OPER) {
-	    tape->blk_minor=tape->rew_minor=tape->nor_minor=-1;
-	    tape->devinfo.irq=-1;
-	    s390irq_spin_unlock_irqrestore (tape->devinfo.irq,lockflags);
+	s390irq_spin_lock_irqsave (ti->devinfo.irq, lockflags);
+	if (((mt_op == MTEOM) || (mt_op == MTRETEN)) && (tapestate_get (ti) == TS_FAILED))
+		tapestate_set (ti, TS_DONE);
+	if (tapestate_get (ti) == TS_FAILED) {
+		tapestate_set (ti, TS_IDLE);
+		s390irq_spin_unlock_irqrestore (ti->devinfo.irq, lockflags);
+		return ti->rc;
+	}
+	if (tapestate_get (ti) == TS_NOT_OPER) {
+	    ti->blk_minor=ti->rew_minor=ti->nor_minor=-1;
+	    ti->devinfo.irq=-1;
+	    s390irq_spin_unlock_irqrestore (ti->devinfo.irq,lockflags);
 	    return -ENODEV;
 	}
-	if (tapestate_get (tape) != TS_DONE) {
-		tapestate_set (tape, TS_IDLE);
-		s390irq_spin_unlock_irqrestore (tape->devinfo.irq, lockflags);
+	if (tapestate_get (ti) != TS_DONE) {
+		tapestate_set (ti, TS_IDLE);
+		s390irq_spin_unlock_irqrestore (ti->devinfo.irq, lockflags);
 		return -EIO;
 	}
-	tapestate_set (tape, TS_IDLE);
-	s390irq_spin_unlock_irqrestore (tape->devinfo.irq, lockflags);
+	tapestate_set (ti, TS_IDLE);
+	s390irq_spin_unlock_irqrestore (ti->devinfo.irq, lockflags);
 	switch (mt_op) {
 	case MTRETEN:		//need to rewind the tape after moving to eom
 
@@ -531,7 +542,7 @@
 	    unsigned int cmd, unsigned long arg)
 {
 	long lockflags;
-	tape_info_t *tape;
+	tape_info_t *ti;
 	ccw_req_t *cqr;
 	struct mtop op;		/* structure for MTIOCTOP */
 	struct mtpos pos;	/* structure for MTIOCPOS */
@@ -541,19 +552,19 @@
 #ifdef TAPE_DEBUG
 	debug_text_event (tape_debug_area,6,"c:ioct");
 #endif
-	tape = first_tape_info;
-	while ((tape != NULL) &&
-	       (tape->rew_minor != MINOR (inode->i_rdev)) &&
-	       (tape->nor_minor != MINOR (inode->i_rdev)))
-		tape = (tape_info_t *) tape->next;
-	if (tape == NULL) {
+	ti = first_tape_info;
+	while ((ti != NULL) &&
+	       (ti->rew_minor != MINOR (inode->i_rdev)) &&
+	       (ti->nor_minor != MINOR (inode->i_rdev)))
+		ti = (tape_info_t *) ti->next;
+	if (ti == NULL) {
 #ifdef TAPE_DEBUG
 	        debug_text_event (tape_debug_area,6,"c:nodev");
 #endif
 		return -ENODEV;
 	}
 	// check for discipline ioctl overloading
-	if ((rc = tape->discipline->discipline_ioctl_overload (inode, filp, cmd, arg))
+	if ((rc = ti->discipline->discipline_ioctl_overload (inode, filp, cmd, arg))
 	    != -EINVAL) {
 #ifdef TAPE_DEBUG
 	    debug_text_event (tape_debug_area,6,"c:ioverloa");
@@ -563,71 +574,72 @@
 
 	switch (cmd) {
 	case MTIOCTOP:		/* tape op command */
-		if (copy_from_user (&op, (char *) arg, sizeof (struct mtop)))
+		if (copy_from_user (&op, (char *) arg, sizeof (struct mtop))) {
 			 return -EFAULT;
+		}
 		return (tape_mtioctop (filp, op.mt_op, op.mt_count));
 	case MTIOCPOS:		/* query tape position */
-		cqr = tape->discipline->mttell (tape, 0);
-		s390irq_spin_lock_irqsave (tape->devinfo.irq, lockflags);
-		tape->cqr = cqr;
-		tape->wanna_wakeup=0;
-		do_IO (tape->devinfo.irq, cqr->cpaddr, (unsigned long) cqr, 0x00, cqr->options);
-		s390irq_spin_unlock_irqrestore (tape->devinfo.irq, lockflags);
-		wait_event_interruptible (tape->wq,tape->wanna_wakeup);
-		pos.mt_blkno = tape->rc;
-		tape->cqr = NULL;
-		if (tape->kernbuf != NULL) {
-			kfree (tape->kernbuf);
-			tape->kernbuf = NULL;
+		cqr = ti->discipline->mttell (ti, 0);
+		s390irq_spin_lock_irqsave (ti->devinfo.irq, lockflags);
+		ti->cqr = cqr;
+		ti->wanna_wakeup=0;
+		do_IO (ti->devinfo.irq, cqr->cpaddr, (unsigned long) cqr, 0x00, cqr->options);
+		s390irq_spin_unlock_irqrestore (ti->devinfo.irq, lockflags);
+		wait_event_interruptible (ti->wq,ti->wanna_wakeup);
+		pos.mt_blkno = ti->rc;
+		ti->cqr = NULL;
+		if (ti->kernbuf != NULL) {
+			kfree (ti->kernbuf);
+			ti->kernbuf = NULL;
 		}
 		tape_free_request (cqr);
 		if (signal_pending (current)) {
-			tapestate_set (tape, TS_IDLE);
+			tapestate_set (ti, TS_IDLE);
 			return -ERESTARTSYS;
 		}
-		s390irq_spin_lock_irqsave (tape->devinfo.irq, lockflags);
-		tapestate_set (tape, TS_IDLE);
-		s390irq_spin_unlock_irqrestore (tape->devinfo.irq, lockflags);
+		s390irq_spin_lock_irqsave (ti->devinfo.irq, lockflags);
+		tapestate_set (ti, TS_IDLE);
+		s390irq_spin_unlock_irqrestore (ti->devinfo.irq, lockflags);
 		if (copy_to_user ((char *) arg, &pos, sizeof (struct mtpos)))
 			 return -EFAULT;
 		return 0;
 	case MTIOCGET:
-		get.mt_erreg = tape->rc;
-		cqr = tape->discipline->mttell (tape, 0);
-		s390irq_spin_lock_irqsave (tape->devinfo.irq, lockflags);
-		tape->cqr = cqr;
-		tape->wanna_wakeup=0;
-		do_IO (tape->devinfo.irq, cqr->cpaddr, (unsigned long) cqr, 0x00, cqr->options);
-		s390irq_spin_unlock_irqrestore (tape->devinfo.irq, lockflags);
-		wait_event_interruptible (tape->wq,tape->wanna_wakeup);
-		get.mt_blkno = tape->rc;
+		get.mt_erreg = ti->rc;
+		cqr = ti->discipline->mttell (ti, 0);
+		s390irq_spin_lock_irqsave (ti->devinfo.irq, lockflags);
+		ti->cqr = cqr;
+		ti->wanna_wakeup=0;
+		do_IO (ti->devinfo.irq, cqr->cpaddr, (unsigned long) cqr, 0x00, cqr->options);
+		s390irq_spin_unlock_irqrestore (ti->devinfo.irq, lockflags);
+		wait_event_interruptible (ti->wq,ti->wanna_wakeup);
+		get.mt_blkno = ti->rc;
 		get.mt_fileno = 0;
 		get.mt_type = MT_ISUNKNOWN;
-		get.mt_resid = tape->devstat.rescnt;
-		get.mt_dsreg = tape->devstat.ii.sense.data[3];
+		get.mt_resid = ti->devstat.rescnt;
+		get.mt_dsreg = ti->devstat.ii.sense.data[3];
 		get.mt_gstat = 0;
-		if (tape->devstat.ii.sense.data[1] & 0x08)
+		if (ti->devstat.ii.sense.data[1] & 0x08)
 			get.mt_gstat &= GMT_BOT (1);	// BOT
 
-		if (tape->devstat.ii.sense.data[1] & 0x02)
+		if (ti->devstat.ii.sense.data[1] & 0x02)
 			get.mt_gstat &= GMT_WR_PROT (1);	// write protected
 
-		if (tape->devstat.ii.sense.data[1] & 0x40)
+		if (ti->devstat.ii.sense.data[1] & 0x40)
 			get.mt_gstat &= GMT_ONLINE (1);		//drive online
 
-		tape->cqr = NULL;
-		if (tape->kernbuf != NULL) {
-			kfree (tape->kernbuf);
-			tape->kernbuf = NULL;
+		ti->cqr = NULL;
+		if (ti->kernbuf != NULL) {
+			kfree (ti->kernbuf);
+			ti->kernbuf = NULL;
 		}
 		tape_free_request (cqr);
 		if (signal_pending (current)) {
-			tapestate_set (tape, TS_IDLE);
+			tapestate_set (ti, TS_IDLE);
 			return -ERESTARTSYS;
 		}
-		s390irq_spin_lock_irqsave (tape->devinfo.irq, lockflags);
-		tapestate_set (tape, TS_IDLE);
-		s390irq_spin_unlock_irqrestore (tape->devinfo.irq, lockflags);
+		s390irq_spin_lock_irqsave (ti->devinfo.irq, lockflags);
+		tapestate_set (ti, TS_IDLE);
+		s390irq_spin_unlock_irqrestore (ti->devinfo.irq, lockflags);
 		if (copy_to_user ((char *) arg, &get, sizeof (struct mtget)))
 			 return -EFAULT;
 		return 0;
diff -u --recursive --new-file v2.4.7/linux/drivers/s390/char/tapechar.h linux/drivers/s390/char/tapechar.h
--- v2.4.7/linux/drivers/s390/char/tapechar.h	Thu Apr 12 12:16:35 2001
+++ linux/drivers/s390/char/tapechar.h	Wed Jul 25 14:12:02 2001
@@ -27,7 +27,7 @@
 int tape_open (struct inode *,struct file *);
 int tape_release (struct inode *,struct file *);
 #ifdef CONFIG_DEVFS_FS
-void tapechar_mkdevfstree (tape_info_t* tape);
+void tapechar_mkdevfstree (tape_info_t* ti);
 #endif
 void tapechar_init (void);
 void tapechar_uninit (void);
diff -u --recursive --new-file v2.4.7/linux/drivers/s390/char/tapedefs.h linux/drivers/s390/char/tapedefs.h
--- v2.4.7/linux/drivers/s390/char/tapedefs.h	Wed Apr 11 19:02:28 2001
+++ linux/drivers/s390/char/tapedefs.h	Wed Jul 25 14:12:02 2001
@@ -11,15 +11,28 @@
  ***********************************************************************
  */
 
+/* Kernel Version Compatibility section */
+#include <linux/version.h>
+#include <linux/blkdev.h>
+#include <linux/blk.h>
+#include <asm/irq.h>
+
+#if (LINUX_VERSION_CODE > KERNEL_VERSION(2,2,17))
 #define TAPE_DEBUG               // use s390 debug feature
+#else
+#undef TAPE_DEBUG                // debug feature not supported by our 2.2.16 code
+static inline void set_normalized_cda ( ccw1_t * cp, unsigned long address ) {
+    cp -> cda = address;
+}
+static inline void clear_normalized_cda ( ccw1_t * ccw ) {
+    ccw -> cda = 0;
+}
+#define BUG() PRINT_FATAL("tape390: CRITICAL INTERNAL ERROR OCCURED. REPORT THIS BACK TO LINUX390@DE.IBM.COM\n")
+#endif
 #define CONFIG_S390_TAPE_DYNAMIC // allow devices to be attached or detached on the fly
 #define TAPEBLOCK_RETRIES 20     // number of retries, when a block-dev request fails.
 
 
-/* Kernel Version Compatibility section */
-#include <linux/version.h>
-#include <linux/blkdev.h>
-#include <linux/blk.h>
 #if (LINUX_VERSION_CODE > KERNEL_VERSION(2,3,98))
 #define INIT_BLK_DEV(d_major,d_request_fn,d_queue_fn,d_current) \
 do { \
diff -u --recursive --new-file v2.4.7/linux/drivers/s390/char/tuball.c linux/drivers/s390/char/tuball.c
--- v2.4.7/linux/drivers/s390/char/tuball.c	Wed Apr 18 11:49:11 2001
+++ linux/drivers/s390/char/tuball.c	Wed Jul 25 14:12:02 2001
@@ -23,8 +23,7 @@
 
 /* Module parameters */
 int tubdebug;
-int tubscrolltime;
-int tubscrollparm;
+int tubscrolltime = -1;
 int tubxcorrect = 1;            /* Do correct ebc<->asc tables */
 #ifdef MODULE
 MODULE_PARM(tubdebug, "i");
@@ -67,14 +66,14 @@
 	  0xf0, 0xf1, 0xf2, 0xf3, 0xf4, 0xf5, 0xf6, 0xf7,
 	  0xf8, 0xf9, 0x7a, 0x7b, 0x7c, 0x7d, 0x7e, 0x7f };
 
-static int tub3270_init(void);
+int tub3270_init(void);
 
 #ifndef MODULE
 
 /*
  * Can't have this driver a module & support console at the same time
  */
-#ifdef CONFIG_3270_CONSOLE
+#ifdef CONFIG_TN3270_CONSOLE
 static kdev_t tub3270_con_device(struct console *);
 static void tub3270_con_unblank(void);
 static void tub3270_con_write(struct console *, const char *,
@@ -94,7 +93,6 @@
 	NULL			/* next */
 };
 
-int tub3270_con_devno = -1;		/* set by tub3270_con_setup() */
 bcb_t tub3270_con_bcb;			/* Buffer that receives con writes */
 spinlock_t tub3270_con_bcblock;		/* Lock for the buffer */
 int tub3270_con_irq = -1;		/* set nonneg by _activate() */
@@ -102,54 +100,45 @@
 struct tty_driver tty3270_con_driver;	/* for /dev/console at 4, 64 */
 
 #if (LINUX_VERSION_CODE < KERNEL_VERSION(2,3,0))
+int tub3270_con_devno = -1;		/* set by tub3270_con_setup() */
 __initfunc(void tub3270_con_setup(char *str, int *ints))
-#else
-static int __init tub3270_con_setup(char *str)
-#endif
 {
 	int vdev;
 
 	vdev = simple_strtoul(str, 0, 16);
 	if (vdev >= 0 && vdev < 65536)
 		tub3270_con_devno = vdev;
-#if (LINUX_VERSION_CODE < KERNEL_VERSION(2,3,0))
 	return;
-#else
-	return 1;
-#endif
 }
 
-#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2,3,0))
-__setup("condev=", tub3270_con_setup);
-#endif
-
-#if (LINUX_VERSION_CODE < KERNEL_VERSION(2,3,0))
 __initfunc (long tub3270_con_init(long kmem_start, long kmem_end))
-#else
-void __init tub3270_con_init(void)
-#endif
 {
 	tub3270_con_bcb.bc_len = 65536;
-#if (LINUX_VERSION_CODE < KERNEL_VERSION(2,3,0))
 	if (!MACHINE_IS_VM && !MACHINE_IS_P390)
 		return kmem_start;
 	tub3270_con_bcb.bc_buf = (void *)kmem_start;
 	kmem_start += tub3270_con_bcb.bc_len;
 	register_console(&tub3270_con);
 	return kmem_start;
+}
 #else
-	if (!MACHINE_IS_VM && !MACHINE_IS_P390)
+#define tub3270_con_devno console_device
+
+void __init tub3270_con_init(void)
+{
+	tub3270_con_bcb.bc_len = 65536;
+	if (!CONSOLE_IS_3270)
 		return;
 	tub3270_con_bcb.bc_buf = (void *)alloc_bootmem_low(
 		tub3270_con_bcb.bc_len);
 	register_console(&tub3270_con);
-#endif
 }
+#endif
 
 static kdev_t
 tub3270_con_device(struct console *conp)
 {
-	return MKDEV(IBM_TTY3270_MAJOR, conp->index);
+	return MKDEV(IBM_TTY3270_MAJOR, conp->index + 1);
 }
 
 static void
@@ -164,7 +153,7 @@
 tub3270_con_write(struct console *conp,
 	const char *buf, unsigned int count)
 {
-	int flags;
+	long flags;
 	tub_t *tubp = tub3270_con_tubp;
 	void tty3270_sched_bh(tub_t *);
 	int rc;
@@ -176,7 +165,7 @@
 	obcb.bc_rd = 0;
 
 	spin_lock_irqsave(&tub3270_con_bcblock, flags);
-	rc = tub3270_movedata(&obcb, &tub3270_con_bcb);
+	rc = tub3270_movedata(&obcb, &tub3270_con_bcb, 0);
 	spin_unlock_irqrestore(&tub3270_con_bcblock, flags);
 
 	if (tubp && rc && TUBTRYLOCK(tubp->irq, flags)) {
@@ -187,27 +176,15 @@
 	
 int tub3270_con_copy(tub_t *tubp)
 {
-	int flags;
+	long flags;
 	int rc;
 
 	spin_lock_irqsave(&tub3270_con_bcblock, flags);
-	rc = tub3270_movedata(&tub3270_con_bcb, &tubp->tty_bcb);
+	rc = tub3270_movedata(&tub3270_con_bcb, &tubp->tty_bcb, 0);
 	spin_unlock_irqrestore(&tub3270_con_bcblock, flags);
 	return rc;
 }
-#endif /* CONFIG_3270_CONSOLE */
-
-
-
-
-#if (LINUX_VERSION_CODE < KERNEL_VERSION(2,3,0))
-__initfunc(void tub3270_initfunc(void))
-#else
-void __init tub3270_initfunc(void)
-#endif
-{
-	tub3270_init();
-}
+#endif /* CONFIG_TN3270_CONSOLE */
 #else /* If generated as a MODULE */
 /*
  * module init:  find tubes; get a major nbr
@@ -249,22 +226,13 @@
 /*
  * tub3270_init() called by kernel or module initialization
  */
-static int
+int
 tub3270_init(void)
 {
 	s390_dev_info_t d;
 	int i, rc;
 
 	/*
-	 * Initialize default scrolltime to either -1 or the
-	 * module parameter tubscrolltime.
-	 */
-	if (tubscrolltime)
-		tubscrollparm = tubscrolltime;
-	else
-		tubscrollparm = -1;
-
-	/*
 	 * Copy and correct ebcdic - ascii translate tables
 	 */
 	memcpy(tub_ascebc, _ascebc, sizeof tub_ascebc);
@@ -283,30 +251,41 @@
 	if (rc != 0)
 		return rc;
 
+	if (fs3270_init() || tty3270_init()) {
+		printk(KERN_ERR "fs3270_init() or tty3270_init() failed\n");
+		fs3270_fini();
+		tty3270_fini();
+		tubfiniminors();
+		return -1;
+	}
+
 	for (i = get_irq_first(); i >= 0; i = get_irq_next(i)) {
 		if ((rc = get_dev_info_by_irq(i, &d)))
 			continue;
 		if (d.status)
 			continue;
-#ifdef CONFIG_3270_CONSOLE
+
+#ifdef CONFIG_TN3270_CONSOLE
+#if (LINUX_VERSION_CODE < KERNEL_VERSION(2,3,0))
 		if (d.sid_data.cu_type == 0x3215 && MACHINE_IS_VM) {
 			cpcmd("TERM CONMODE 3270", NULL, 0);
 			d.sid_data.cu_type = 0x3270;
 		}
-#endif /* CONFIG_3270_CONSOLE */
+#else
+		if (d.sid_data.cu_type == 0x3215 && CONSOLE_IS_3270) {
+			cpcmd("TERM CONMODE 3270", NULL, 0);
+			d.sid_data.cu_type = 0x3270;
+		}
+#endif /* LINUX_VERSION_CODE */
+#endif /* CONFIG_TN3270_CONSOLE */
 		if ((d.sid_data.cu_type & 0xfff0) != 0x3270)
 			continue;
 
 		rc = tubmakemin(i, &d);
 		if (rc < 0) {
-			if (tubnummins == 1) {  /* if first time */
-				tubfiniminors();
-				printk(KERN_ERR "No kernel memory available"
-					" for 3270 tube devices.\n");
-				return rc;
-			}
-			printk(KERN_WARNING "3270 tube registration ran out of memory"
-				" after %d devices\n", tubnummins - 1);
+			printk(KERN_WARNING 
+			       "3270 tube registration ran out of memory"
+			       " after %d devices\n", tubnummins - 1);
 			break;
 		} else {
 			printk(KERN_INFO "3270: %.4x on sch %d, minor %d\n",
@@ -314,14 +293,6 @@
 		}
 	}
 
-	if (fs3270_init() || tty3270_init()) {
-		printk(KERN_ERR "fs3270_init() or tty3270_init() failed\n");
-		fs3270_fini();
-		tty3270_fini();
-		tubfiniminors();
-		return -1;
-	}
-
 	return 0;
 }
 
@@ -329,7 +300,7 @@
  * tub3270_movedata(bcb_t *, bcb_t *) -- Move data stream
  */
 int
-tub3270_movedata(bcb_t *ib, bcb_t *ob)
+tub3270_movedata(bcb_t *ib, bcb_t *ob, int fromuser)
 {
 	int count;			/* Total move length */
 	int rc;
@@ -354,11 +325,21 @@
 				len2 = ob->bc_len - ob->bc_wr;
 			if (len2 > len1)
 				len2 = len1;
-
-			memcpy(ob->bc_buf + ob->bc_wr,
-				ib->bc_buf + ib->bc_rd,
-				len2);
-
+			
+			if (fromuser) {
+				len2 -= copy_from_user(ob->bc_buf + ob->bc_wr,
+						       ib->bc_buf + ib->bc_rd,
+						       len2);
+				if (len2 == 0) {
+					if (!rc)
+						rc = -EFAULT;
+					break;
+				}
+			} else
+				memcpy(ob->bc_buf + ob->bc_wr,
+				       ib->bc_buf + ib->bc_rd,
+				       len2);
+			
 			ib->bc_rd += len2;
 			if (ib->bc_rd == ib->bc_len)
 				ib->bc_rd = 0;
@@ -422,7 +403,7 @@
 {
 	tub_t *tubp;
 	int minor;
-	int flags;
+	long flags;
 
 	if ((minor = ++tubnummins) == TUBMAXMINS)
 		return -ENODEV;
@@ -446,7 +427,7 @@
 
 	tubp->tty_bcb.bc_len = TTY_OUTPUT_SIZE;
 	tubp->tty_bcb.bc_buf = (void *)kmalloc(tubp->tty_bcb.bc_len,
-		GFP_KERNEL);
+		GFP_KERNEL|GFP_DMA);
 	if (tubp->tty_bcb.bc_buf == NULL) {
 		TUBUNLOCK(tubp->irq, flags);
 		tubdelbyirq(tubp, irq);
@@ -457,24 +438,34 @@
 	tubp->tty_bcb.bc_wr = 0;
 	tubp->tty_bcb.bc_rd = 0;
 	(*tubminors)[minor] = tubp;
-#ifdef CONFIG_3270_CONSOLE
-	if (tub3270_con_tubp == NULL && tub3270_con_bcb.bc_buf != NULL &&
-	    (tub3270_con_devno == -1 ||
-	     tub3270_con_devno == dp->devno)) {
-		extern void tty3270_int(tub_t *, devstat_t *);
- 
-		tubp->cmd = TBC_CONOPEN;
-		tubp->flags |= TUB_OPEN_STET;
-		tty3270_size(tubp, &flags);
-		tty3270_aid_init(tubp);
-		tty3270_scl_init(tubp);
-		tub3270_con_irq = tubp->irq;
-		tub3270_con_tubp = tubp;
-		tubp->intv = tty3270_int;
-		tubp->cmd = TBC_UPDSTAT;
-		tty3270_build(tubp);
+
+#ifdef CONFIG_TN3270_CONSOLE
+	if (CONSOLE_IS_3270) {
+		if (tub3270_con_tubp == NULL && 
+		    tub3270_con_bcb.bc_buf != NULL &&
+		    (tub3270_con_devno == -1 ||
+		     tub3270_con_devno == dp->devno)) {
+			extern void tty3270_int(tub_t *, devstat_t *);
+			
+			tub3270_con_devno = dp->devno;
+			tubp->cmd = TBC_CONOPEN;
+			tubp->flags |= TUB_OPEN_STET;
+			tty3270_size(tubp, &flags);
+			tty3270_aid_init(tubp);
+			tty3270_scl_init(tubp);
+			tub3270_con_irq = tubp->irq;
+			tub3270_con_tubp = tubp;
+			tubp->intv = tty3270_int;
+			tubp->cmd = TBC_UPDSTAT;
+			tty3270_build(tubp);
+		}
 	}
-#endif /* CONFIG_3270_CONSOLE */
+#endif /* CONFIG_TN3270_CONSOLE */
+
+#ifdef CONFIG_DEVFS_FS
+	fs3270_devfs_register(tubp);
+#endif
+
 	TUBUNLOCK(tubp->irq, flags);
 	return minor;
 }
@@ -495,6 +486,9 @@
 	for (i = 0; i < TUBMAXMINS; i++) {
 		tubpp = &(*tubminors)[i];
 		if ((tubp = *tubpp)) {
+#ifdef CONFIG_DEVFS_FS
+			fs3270_devfs_unregister(tubp);
+#endif
 			tubdelbyirq(tubp, tubp->irq);
 			tty3270_rcl_fini(tubp);
 			kfree(tubp->tty_bcb.bc_buf);
diff -u --recursive --new-file v2.4.7/linux/drivers/s390/char/tubfs.c linux/drivers/s390/char/tubfs.c
--- v2.4.7/linux/drivers/s390/char/tubfs.c	Wed Apr 11 19:02:28 2001
+++ linux/drivers/s390/char/tubfs.c	Wed Jul 25 14:12:02 2001
@@ -16,9 +16,9 @@
 static int fs3270_open(struct inode *, struct file *);
 static int fs3270_close(struct inode *, struct file *);
 static int fs3270_ioctl(struct inode *, struct file *, unsigned int, unsigned long);
-static int fs3270_read(struct file *, char *, size_t, loff_t *);
-static int fs3270_write(struct file *, const char *, size_t, loff_t *);
-static int fs3270_wait(tub_t *, int *);
+static ssize_t fs3270_read(struct file *, char *, size_t, loff_t *);
+static ssize_t fs3270_write(struct file *, const char *, size_t, loff_t *);
+static int fs3270_wait(tub_t *, long *);
 static void fs3270_int(tub_t *tubp, devstat_t *dsp);
 extern void tty3270_refresh(tub_t *);
 
@@ -33,6 +33,42 @@
 	release:fs3270_close,	/* release */
 };
 
+#ifdef CONFIG_DEVFS_FS
+devfs_handle_t fs3270_devfs_dir;
+devfs_handle_t fs3270_devfs_tub;
+extern struct file_operations tty_fops;
+
+void fs3270_devfs_register(tub_t *tubp)
+{
+	char name[16];
+
+	sprintf(name, "tub%x", tubp->devno);
+	devfs_register(fs3270_devfs_dir, name, DEVFS_FL_DEFAULT,
+		       IBM_FS3270_MAJOR, tubp->minor,
+		       S_IFCHR | S_IRUSR | S_IWUSR, &fs3270_fops, NULL);
+	sprintf(name, "tty%x", tubp->devno);
+	tty_register_devfs_name(&tty3270_driver, 0, tubp->minor,
+				fs3270_devfs_dir, name);
+}
+
+void fs3270_devfs_unregister(tub_t *tubp)
+{
+	char name[16];
+	devfs_handle_t handle;
+
+	sprintf(name, "tub%x", tubp->devno);
+	handle = devfs_find_handle (fs3270_devfs_dir, name,
+				    IBM_FS3270_MAJOR, tubp->minor,
+				    DEVFS_SPECIAL_CHR, 0);
+	devfs_unregister (handle);
+	sprintf(name, "tty%x", tubp->devno);
+	handle = devfs_find_handle (fs3270_devfs_dir, name,
+				    IBM_TTY3270_MAJOR, tubp->minor,
+				    DEVFS_SPECIAL_CHR, 0);
+	devfs_unregister(handle);
+}
+#endif
+
 /*
  * fs3270_init() -- Initialize fullscreen tubes
  */
@@ -41,15 +77,29 @@
 {
 	int rc;
 
+#ifdef CONFIG_DEVFS_FS
+	rc = devfs_register_chrdev (IBM_FS3270_MAJOR, "fs3270", &fs3270_fops);
+	if (rc) {
+		printk(KERN_ERR "tubmod can't get major nbr %d: error %d\n",
+			IBM_FS3270_MAJOR, rc);
+		return -1;
+	}
+	fs3270_devfs_dir = devfs_mk_dir(NULL, "3270", NULL);
+	fs3270_devfs_tub = 
+		devfs_register(fs3270_devfs_dir, "tub", DEVFS_FL_DEFAULT,
+			       IBM_FS3270_MAJOR, 0,
+			       S_IFCHR | S_IRUSR | S_IWUSR, 
+			       &fs3270_fops, NULL);
+#else
 	rc = register_chrdev(IBM_FS3270_MAJOR, "fs3270", &fs3270_fops);
 	if (rc) {
 		printk(KERN_ERR "tubmod can't get major nbr %d: error %d\n",
 			IBM_FS3270_MAJOR, rc);
 		return -1;
-	} else {
-		fs3270_major = IBM_FS3270_MAJOR;
-		return 0;
 	}
+#endif
+	fs3270_major = IBM_FS3270_MAJOR;
+	return 0;
 }
 
 /*
@@ -59,6 +109,10 @@
 fs3270_fini(void)
 {
 	if (fs3270_major != -1) {
+#ifdef CONFIG_DEVFS_FS
+		devfs_unregister(fs3270_devfs_tub);
+		devfs_unregister(fs3270_devfs_dir);
+#endif
 		unregister_chrdev(fs3270_major, "fs3270");
 		fs3270_major = -1;
 	}
@@ -71,7 +125,7 @@
 fs3270_open(struct inode *ip, struct file *fp)
 {
 	tub_t *tubp;
-	int flags;
+	long flags;
 
 	/* See INODE2TUB(ip) for handling of "/dev/3270/tub" */
 	if ((tubp = INODE2TUB(ip)) == NULL)
@@ -101,7 +155,7 @@
 fs3270_close(struct inode *ip, struct file *fp)
 {
 	tub_t *tubp;
-	int flags;
+	long flags;
 
 	if ((tubp = INODE2TUB(ip)) == NULL)
 		return -ENODEV;
@@ -123,7 +177,7 @@
 void
 fs3270_release(tub_t *tubp)
 {
-	int flags;
+	long flags;
 
 	if (tubp->mode != TBM_FS)
 		return;
@@ -145,7 +199,7 @@
  *      * Value is 0 or -ERESTARTSYS
  */
 static int
-fs3270_wait(tub_t *tubp, int *flags)
+fs3270_wait(tub_t *tubp, long *flags)
 {
 	DECLARE_WAITQUEUE(wait, current);
 
@@ -185,7 +239,7 @@
 static void
 fs3270_bh(void *data)
 {
-	int flags;
+	long flags;
 	tub_t *tubp;
 
 	tubp = data;
@@ -283,7 +337,8 @@
 	unsigned int cmd, unsigned long arg)
 {
 	tub_t *tubp;
-	int rc = 0, flags;
+	int rc = 0;
+	long flags;
 
 	if ((tubp = INODE2TUB(ip)) == NULL)
 		return -ENODEV;
@@ -310,13 +365,14 @@
 /*
  * process read commands for the tube driver
  */
-static int
+static ssize_t
 fs3270_read(struct file *fp, char *dp, size_t len, loff_t *off)
 {
 	tub_t *tubp;
 	char *kp;
 	ccw1_t *cp;
-	int rc, flags;
+	int rc;
+	long flags;
 
 	if ((tubp = INODE2TUB((struct inode *)fp->private_data)) == NULL)
 		return -ENODEV;
@@ -325,7 +381,7 @@
 		return rc;
 	}
 
-	kp = kmalloc(len, GFP_KERNEL);
+	kp = kmalloc(len, GFP_KERNEL|GFP_DMA);
 	if (kp == NULL) {
 		TUBUNLOCK(tubp->irq, flags);
 		return -ENOMEM;
@@ -352,10 +408,10 @@
 	if (tubdebug & 1)
 		printk(KERN_DEBUG "minor %d: %.8x %.8x %.8x %.8x\n",
 			tubp->minor,
-			*(int*)((int)kp + 0),
-			*(int*)((int)kp + 4),
-			*(int*)((int)kp + 8),
-			*(int*)((int)kp + 12));
+			*(int*)((long)kp + 0),
+			*(int*)((long)kp + 4),
+			*(int*)((long)kp + 8),
+			*(int*)((long)kp + 12));
 	copy_to_user(dp, kp, len);
 	kfree(kp);
 	return len;
@@ -364,12 +420,13 @@
 /*
  * process write commands for the tube driver
  */
-static int
+static ssize_t
 fs3270_write(struct file *fp, const char *dp, size_t len, loff_t *off)
 {
 	tub_t *tubp;
 	ccw1_t *cp;
-	int rc, flags;
+	int rc;
+	long flags;
 	void *kb;
 
 	/* Locate the tube */
@@ -377,7 +434,7 @@
 		return -ENODEV;
 
 	/* Copy data to write from user address space */
-	if ((kb = kmalloc(len, GFP_KERNEL)) == NULL)
+	if ((kb = kmalloc(len, GFP_KERNEL|GFP_DMA)) == NULL)
 		return -ENOMEM;
 	if (copy_from_user(kb, dp, len) != 0) {
 		kfree(kb);
diff -u --recursive --new-file v2.4.7/linux/drivers/s390/char/tubio.h linux/drivers/s390/char/tubio.h
--- v2.4.7/linux/drivers/s390/char/tubio.h	Wed Apr 11 19:02:28 2001
+++ linux/drivers/s390/char/tubio.h	Wed Jul 25 14:12:02 2001
@@ -23,7 +23,7 @@
 #endif /* IBM_FS3270_MAJOR */
 
 
-#include <linux/malloc.h>
+#include <linux/slab.h>
 #include <asm/irq.h>
 #include <asm/io.h>
 #include <linux/console.h>
@@ -31,6 +31,9 @@
 #include <asm/ebcdic.h>
 #include <asm/uaccess.h>
 #include <linux/proc_fs.h>
+#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2,3,0))
+#include <linux/devfs_fs_kernel.h>
+#endif
 
 #define TUB(x) (('3'<<8)|(x))
 #define TUBICMD TUB(3)
@@ -280,11 +283,15 @@
 #define	TUB_OPEN_STET	0x0400		/* No screen clear on open */
 #define	TUB_UE_BUSY	0x0800
 
-#ifdef CONFIG_3270_CONSOLE
+#ifdef CONFIG_TN3270_CONSOLE
 /*
  * Extra stuff for 3270 console support
  */
+#if (LINUX_VERSION_CODE < KERNEL_VERSION(2,3,0))
 #define	S390_CONSOLE_DEV MKDEV(TTY_MAJOR, 64)
+#else
+#define	S390_CONSOLE_DEV MKDEV(TTYAUX_MAJOR, 1)
+#endif
 extern int tub3270_con_devno;
 extern char (*tub3270_con_output)[];
 extern int tub3270_con_outputl;
@@ -293,7 +300,7 @@
 extern int tub3270_con_irq;
 extern tub_t *tub3270_con_tubp;
 extern struct tty_driver tty3270_con_driver;
-#endif /* CONFIG_3270_CONSOLE */
+#endif /* CONFIG_TN3270_CONSOLE */
 
 extern int tubnummins;
 extern tub_t *(*tubminors)[TUBMAXMINS];
@@ -306,6 +313,12 @@
 extern int tty3270_major;
 extern int tty3270_proc_misc;
 extern enum tubwhat tty3270_proc_what;
+extern struct tty_driver tty3270_driver;
+#ifdef CONFIG_DEVFS_FS
+extern devfs_handle_t fs3270_devfs_dir;
+extern void fs3270_devfs_register(tub_t *);
+extern void fs3270_devfs_unregister(tub_t *);
+#endif
 
 #ifndef spin_trylock_irqsave
 #define spin_trylock_irqsave(lock, flags) \
@@ -343,67 +356,50 @@
  * Find tub_t * given fullscreen device's inode pointer
  * This algorithm takes into account /dev/3270/tub.
  */
-#ifdef CONFIG_3270_CONSOLE
-#define INODE2TUB(ip) \
-({ \
-	unsigned int minor; \
-	tub_t *tubp = NULL; \
-	minor = MINOR((ip)->i_rdev); \
-	if (minor == 0 && current->tty != NULL) { \
-		if (tub3270_con_tubp != NULL && \
-		    current->tty->device == S390_CONSOLE_DEV) \
-			minor = tub3270_con_tubp->minor; \
-		else if (MAJOR(current->tty->device) == IBM_TTY3270_MAJOR) \
-			minor = MINOR(current->tty->device); \
-	} \
-	if (minor <= tubnummins && minor > 0) \
-		tubp = (*tubminors)[minor]; \
-	tubp; \
-})
-#else /* not CONFIG_3270_CONSOLE */
-#define INODE2TUB(ip) \
-({ \
-	unsigned int minor; \
-	tub_t *tubp = NULL; \
-	minor = MINOR((ip)->i_rdev); \
-	if (minor == 0 && current->tty != NULL && \
-	    MAJOR(current->tty->device) == IBM_TTY3270_MAJOR) \
-		minor = MINOR(current->tty->device); \
-	if (minor <= tubnummins && minor > 0) \
-		tubp = (*tubminors)[minor]; \
-	tubp; \
-})
-#endif /* CONFIG_3270_CONSOLE or not */
+extern inline tub_t *INODE2TUB(struct inode *ip)
+{
+	unsigned int minor = MINOR(ip->i_rdev);
+	tub_t *tubp = NULL;
+	if (minor == 0 && current->tty != NULL) {
+#if (LINUX_VERSION_CODE < KERNEL_VERSION(2,3,0))
+#ifdef CONFIG_TN3270_CONSOLE
+		if (tub3270_con_tubp != NULL &&
+		    current->tty->device == S390_CONSOLE_DEV)
+			minor = tub3270_con_tubp->minor;
+		else
+#endif
+#endif
+		if (MAJOR(current->tty->device) == IBM_TTY3270_MAJOR)
+			minor = MINOR(current->tty->device);
+	}
+	if (minor >= tubnummins && minor > 0)
+		tubp = (*tubminors)[minor];
+	return tubp;
+}
+
 /*
  * Find tub_t * given non-fullscreen (tty) device's tty_struct pointer
  */
-#ifdef CONFIG_3270_CONSOLE
-#define TTY2TUB(tty) \
-({ \
-	unsigned int minor; \
-	tub_t *tubp = NULL; \
-	minor = MINOR(tty->device); \
-	if (tty->device == S390_CONSOLE_DEV) \
-		tubp = tub3270_con_tubp; \
-	else if (minor <= tubnummins && minor > 0) \
-		tubp = (*tubminors)[minor]; \
-	tubp; \
-})
-#else /* if not CONFIG_3270_CONSOLE */
-#define TTY2TUB(tty) \
-({ \
-	unsigned int minor; \
-	tub_t *tubp = NULL; \
-	minor = MINOR(tty->device); \
-	if (minor <= tubnummins && minor > 0) \
-		tubp = (*tubminors)[minor]; \
-	tubp; \
-})
-#endif /* CONFIG_3270_CONSOLE or not */
+extern inline tub_t *TTY2TUB(struct tty_struct *tty)
+{
+	unsigned int minor = MINOR(tty->device);
+	tub_t *tubp = NULL;
+
+#if (LINUX_VERSION_CODE < KERNEL_VERSION(2,3,0))
+#ifdef CONFIG_TN3270_CONSOLE
+	if (tty->device == S390_CONSOLE_DEV)
+		tubp = tub3270_con_tubp;
+	else
+#endif
+#endif
+	if (minor <= tubnummins && minor > 0)
+		tubp = (*tubminors)[minor];
+	return tubp;
+}
 
 extern void tub_inc_use_count(void);
 extern void tub_dec_use_count(void);
-extern int tub3270_movedata(bcb_t *, bcb_t *);
+extern int tub3270_movedata(bcb_t *, bcb_t *, int);
 #if (LINUX_VERSION_CODE < KERNEL_VERSION(2,3,0))
 extern int tubmakemin(int, dev_info_t *);
 #else
@@ -418,7 +414,7 @@
 extern void tty3270_rcl_sync(tub_t *);
 extern void tty3270_rcl_purge(tub_t *);
 extern int tty3270_rcl_resize(tub_t *, int);
-extern int tty3270_size(tub_t *, int *);
+extern int tty3270_size(tub_t *, long *);
 extern int tty3270_aid_init(tub_t *);
 extern void tty3270_aid_fini(tub_t *);
 extern void tty3270_aid_reinit(tub_t *);
diff -u --recursive --new-file v2.4.7/linux/drivers/s390/char/tubtty.c linux/drivers/s390/char/tubtty.c
--- v2.4.7/linux/drivers/s390/char/tubtty.c	Wed Apr 11 19:02:28 2001
+++ linux/drivers/s390/char/tubtty.c	Wed Jul 25 14:12:02 2001
@@ -37,7 +37,7 @@
 /* tty3270 utility functions */
 static void tty3270_bh(void *);
        void tty3270_sched_bh(tub_t *);
-static int tty3270_wait(tub_t *, int *);
+static int tty3270_wait(tub_t *, long *);
        void tty3270_int(tub_t *, devstat_t *);
        int tty3270_try_logging(tub_t *);
 static void tty3270_start_input(tub_t *);
@@ -48,20 +48,19 @@
 static int tty3270_show_tube(int, char *, int);
 
 int tty3270_major = -1;
-char tty3270_major_string[16];
 struct tty_driver tty3270_driver;
 int tty3270_refcount;
 struct tty_struct *tty3270_table[TUBMAXMINS];
 struct termios *tty3270_termios[TUBMAXMINS];
 struct termios *tty3270_termios_locked[TUBMAXMINS];
-#ifdef CONFIG_3270_CONSOLE
+#ifdef CONFIG_TN3270_CONSOLE
 int con3270_major = -1;
 struct tty_driver con3270_driver;
 int con3270_refcount;
 struct tty_struct *con3270_table[1];
 struct termios *con3270_termios[1];
 struct termios *con3270_termios_locked[1];
-#endif /* CONFIG_3270_CONSOLE */
+#endif /* CONFIG_TN3270_CONSOLE */
 
 int tty3270_proc_index;
 int tty3270_proc_data;
@@ -88,6 +87,9 @@
 	td->subtype = SYSTEM_TYPE_TTY;
 	td->init_termios = tty_std_termios;
 	td->flags = TTY_DRIVER_RESET_TERMIOS;
+#ifdef CONFIG_DEVFS_FS
+	td->flags |= TTY_DRIVER_NO_DEVFS;
+#endif
 	td->refcount = &tty3270_refcount;
 	td->table = tty3270_table;
 	td->termios = tty3270_termios;
@@ -121,32 +123,36 @@
 		printk(KERN_ERR "tty3270 registration failed with %d\n", rc);
 	} else {
 		tty3270_major = IBM_TTY3270_MAJOR;
-		sprintf(tty3270_major_string, "%d", tty3270_major);
 		if (td->proc_entry != NULL)
 			td->proc_entry->mode = S_IRUGO | S_IWUGO;
 	}
-#ifdef CONFIG_3270_CONSOLE
-	tty3270_con_driver = *td;
-	td = &tty3270_con_driver;
-	td->driver_name = "con3270";
-	td->name = "con3270";
-	td->major = MAJOR(S390_CONSOLE_DEV);
-	td->minor_start = MINOR(S390_CONSOLE_DEV);
-	td->num = 1;
-	td->refcount = &con3270_refcount;
-	td->table = con3270_table;
-	td->termios = con3270_termios;
-	td->termios_locked = con3270_termios_locked;
-
-	rc = tty_register_driver(td);
-	if (rc) {
-		printk(KERN_ERR "con3270 registration failed with %d\n", rc);
-	} else {
-		con3270_major = MAJOR(S390_CONSOLE_DEV);
-		if (td->proc_entry != NULL)
-			td->proc_entry->mode = S_IRUGO | S_IWUGO;
+#if (LINUX_VERSION_CODE < KERNEL_VERSION(2,3,0))
+#ifdef CONFIG_TN3270_CONSOLE
+	if (CONSOLE_IS_3270) {
+		tty3270_con_driver = *td;
+		td = &tty3270_con_driver;
+		td->driver_name = "con3270";
+		td->name = "con3270";
+		td->major = MAJOR(S390_CONSOLE_DEV);
+		td->minor_start = MINOR(S390_CONSOLE_DEV);
+		td->num = 1;
+		td->refcount = &con3270_refcount;
+		td->table = con3270_table;
+		td->termios = con3270_termios;
+		td->termios_locked = con3270_termios_locked;
+
+		rc = tty_register_driver(td);
+		if (rc) {
+			printk(KERN_ERR
+			       "con3270 registration failed with %d\n", rc);
+		} else {
+			con3270_major = MAJOR(S390_CONSOLE_DEV);
+			if (td->proc_entry != NULL)
+				td->proc_entry->mode = S_IRUGO | S_IWUGO;
+		}
 	}
-#endif /* if CONFIG_3270_CONSOLE */
+#endif /* ifdef CONFIG_TN3270_CONSOLE */
+#endif /* if LINUX_VERSION_CODE */
 
 	return rc;
 }
@@ -161,8 +167,8 @@
 		tty_unregister_driver(&tty3270_driver);
 		tty3270_major = -1;
 	}
-#ifdef CONFIG_3270_CONSOLE
-	if (con3270_major != -1) {
+#ifdef CONFIG_TN3270_CONSOLE
+	if (CONSOLE_IS_3270 && con3270_major != -1) {
 		tty_unregister_driver(&con3270_driver);
 		con3270_major = -1;
 	}
@@ -173,7 +179,7 @@
 tty3270_open(struct tty_struct *tty, struct file *filp)
 {
 	tub_t *tubp;
-	int flags;
+	long flags;
 	int rc;
 	int cmd;
 
@@ -229,7 +235,7 @@
 tty3270_close(struct tty_struct *tty, struct file *filp)
 {
 	tub_t *tubp;
-	int flags;
+	long flags;
 
 	if ((tubp = tty->driver_data) == NULL)
 		return;
@@ -252,24 +258,24 @@
 		const unsigned char *buf, int count)
 {
 	tub_t *tubp;
-	int flags;
+	long flags;
 	bcb_t obcb;
 	int rc = 0;
 
 	if ((tubp = tty->driver_data) == NULL)
 		return -1;
 
-#ifdef CONFIG_3270_CONSOLE
-	if (tub3270_con_tubp == tubp)
+#ifdef CONFIG_TN3270_CONSOLE
+	if (CONSOLE_IS_3270 && tub3270_con_tubp == tubp)
 		tub3270_con_copy(tubp);
-#endif /* CONFIG_3270_CONSOLE */
+#endif /* CONFIG_TN3270_CONSOLE */
 
 	obcb.bc_buf = (char *)buf;
 	obcb.bc_len = obcb.bc_cnt = obcb.bc_wr = count;
 	obcb.bc_rd = 0;
 
 	TUBLOCK(tubp->irq, flags);
-	rc = tub3270_movedata(&obcb, &tubp->tty_bcb);
+	rc = tub3270_movedata(&obcb, &tubp->tty_bcb, fromuser);
 	tty3270_try_logging(tubp);
 	TUBUNLOCK(tubp->irq, flags);
 	return rc;
@@ -278,7 +284,7 @@
 static void
 tty3270_put_char(struct tty_struct *tty, unsigned char ch)
 {
-	int flags;
+	long flags;
 	tub_t *tubp;
 	bcb_t *ob;
 
@@ -301,7 +307,7 @@
 tty3270_flush_chars(struct tty_struct *tty)
 {
 	tub_t *tubp;
-	int flags;
+	long flags;
 
 	if ((tubp = tty->driver_data) == NULL)
 		return;
@@ -342,7 +348,7 @@
 		unsigned int cmd, unsigned long arg)
 {
 	tub_t *tubp;
-	int flags;
+	long flags;
 	int ret = 0;
 	struct termios termios;
 
@@ -394,7 +400,7 @@
 tty3270_set_termios(struct tty_struct *tty, struct termios *old)
 {
 	tub_t *tubp;
-	int flags;
+	long flags;
 	int new;
 
 	if ((tubp = tty->driver_data) == NULL)
@@ -420,7 +426,7 @@
 {
 	tub_t *tubp;
 	bcb_t *ob;
-	int flags;
+	long flags;
 
 	if ((tubp = tty->driver_data) == NULL)
 		return;
@@ -452,7 +458,6 @@
 	int i;
 	int rc;
 	int len = 0;
-	char *majstr;
 
 	if (tty3270_proc_what == TW_CONFIG) {
 		/*
@@ -464,13 +469,14 @@
 		len += sprintf(buf + len, "0 %d 0\n", fs3270_major);
 		for (i = 1; i <= tubnummins; i++) {
 			tubp = (*tubminors)[i];
-			majstr = tty3270_major_string;
-#ifdef CONFIG_3270_CONSOLE
-			if (tubp == tub3270_con_tubp)
-				majstr = "CONSOLE";
-#endif /* CONFIG_3270_CONSOLE */
-			len += sprintf(buf + len, "%.3x %s %d\n",
-				tubp->devno, majstr, i);
+#ifdef CONFIG_TN3270_CONSOLE
+			if (CONSOLE_IS_3270 && tubp == tub3270_con_tubp)
+				len += sprintf(buf + len, "%.3x CONSOLE %d\n",
+					       tubp->devno, i);
+			else
+#endif
+				len += sprintf(buf + len, "%.3x %d %d\n",
+					       tubp->devno, tty3270_major, i);
 			if (begin + len > off + count)
 				break;
 			if (begin + len < off) {
@@ -536,10 +542,12 @@
 	if (device) {
 		if (MAJOR(device) == IBM_TTY3270_MAJOR)
 			tubp = (*tubminors)[MINOR(device)];
-#ifdef CONFIG_3270_CONSOLE
-		if (device == S390_CONSOLE_DEV)
+#ifdef CONFIG_TN3270_CONSOLE
+#if (LINUX_VERSION_CODE < KERNEL_VERSION(2,3,0))
+		if (CONSOLE_IS_3270 && device == S390_CONSOLE_DEV)
 			tubp = tub3270_con_tubp;
-#endif /* CONFIG_3270_CONSOLE */
+#endif /* LINUX_VERSION_CODE */
+#endif /* CONFIG_TN3270_CONSOLE */
 	}
 	if (tubp) {
 		if ((rc = tty3270_aid_set(tubp, mybuf, mycount + 1)))
@@ -595,7 +603,7 @@
 static void
 tty3270_bh(void *data)
 {
-	int flags;
+	long flags;
 	tub_t *tubp;
 	struct tty_struct *tty;
 
@@ -675,7 +683,7 @@
  * On entry the lock must not be held; on exit it is held.
  */
 static int
-tty3270_wait(tub_t *tubp, int *flags)
+tty3270_wait(tub_t *tubp, long *flags)
 {
 	DECLARE_WAITQUEUE(wait, current);
 
@@ -766,10 +774,10 @@
 		return 0;
 	if (tubp->stat == TBS_MORE)
 		return 0;
-#ifdef CONFIG_3270_CONSOLE
-	if (tub3270_con_tubp == tubp)
+#ifdef CONFIG_TN3270_CONSOLE
+	if (CONSOLE_IS_3270 && tub3270_con_tubp == tubp)
 		tub3270_con_copy(tubp);
-#endif /* CONFIG_3270_CONSOLE */
+#endif /* CONFIG_TN3270_CONSOLE */
 	if (tubp->tty_bcb.bc_cnt == 0)
 		return 0;
 	if (tubp->intv != tty3270_int)
@@ -953,48 +961,44 @@
 	if (minor < 0 || minor > tubnummins ||
 	    (tubp = (*tubminors)[minor]) == NULL)
 		return sprintf(buf, "No tube at index=%d\n", minor);
-
+	
 	tty = tubp->tty;
 	len = 0;
 
-	len += sprintf(buf+len,
-"Info for tub_t[%d] at %.8x:\n",
-	minor, (int)tubp);
+	len += sprintf(buf+len, "Info for tub_t[%d] at %p:\n", minor, tubp);
 
-	len += sprintf(buf+len, "inattr is at %.8x\n",
-		(int)&tubp->tty_inattr);
+	len += sprintf(buf+len, "inattr is at %p\n", &tubp->tty_inattr);
 
 
-	len += sprintf(buf+len,
-"    geom:  rows=%.2d cols=%.2d model=%.1d\n",
-	tubp->geom_rows, tubp->geom_cols, tubp->tubiocb.model);
+	len += sprintf(buf+len, "    geom:  rows=%.2d cols=%.2d model=%.1d\n",
+		       tubp->geom_rows, tubp->geom_cols, tubp->tubiocb.model);
 
 	len += sprintf(buf+len,
-"    lnopen=%-2d     fsopen=%-2d   waitq=%.8x\n",
-	tubp->lnopen, tubp->fsopen, (int)&tubp->waitq);
+		       "    lnopen=%-2d     fsopen=%-2d   waitq=%p\n",
+		       tubp->lnopen, tubp->fsopen, &tubp->waitq);
 
-	len += sprintf(buf+len,
-"    dstat=%.2x      mode=%-2d     stat=%-2d     flags=%-4x\n",
-	tubp->dstat, tubp->mode, tubp->stat, tubp->flags);
+	len += sprintf(buf+len, "    dstat=%.2x      mode=%-2d     "
+		       "stat=%-2d     flags=%-4x\n", tubp->dstat,
+		       tubp->mode, tubp->stat, tubp->flags);
 
 #ifdef RBH_FIXTHIS
 	len += sprintf(buf+len,
-"    oucount=%-4d  ourd=%-5d  ouwr=%-5d  nextlogx=%-5d\n",
-	tubp->tty_oucount, tubp->tty_ourd, tubp->tty_ouwr,
-	tubp->tty_nextlogx);
+		       "    oucount=%-4d  ourd=%-5d  ouwr=%-5d"
+		       "  nextlogx=%-5d\n", tubp->tty_oucount,
+		       tubp->tty_ourd, tubp->tty_ouwr, tubp->tty_nextlogx);
 #endif
 
-	len += sprintf(buf+len,
-"    tty=%.8x\n",
-	(int)tubp->tty);
+	len += sprintf(buf+len, "    tty=%p\n",tubp->tty);
 
-	if (tty) len += sprintf(buf+len,
-"    write_wait=%.8x read_wait=%.8x\n",
-	(int)&tty->write_wait, (int)&tty->read_wait);
-
-	if (tty && ((mp = tty->termios))) len += sprintf(buf+len,
-"    iflag=%.8x oflag=%.8x cflag=%.8x lflag=%.8x\n",
-	mp->c_iflag, mp->c_oflag, mp->c_cflag, mp->c_lflag);
+	if (tty)
+		len += sprintf(buf+len,
+				"    write_wait=%.8x read_wait=%.8x\n",
+				tty->write_wait, tty->read_wait);
+
+	if (tty && ((mp = tty->termios)))
+		len += sprintf(buf+len,"    iflag=%.8x oflag=%.8x "
+			       "cflag=%.8x lflag=%.8x\n", mp->c_iflag,
+			       mp->c_oflag, mp->c_cflag, mp->c_lflag);
 
 
 	return len;
diff -u --recursive --new-file v2.4.7/linux/drivers/s390/char/tubttyscl.c linux/drivers/s390/char/tubttyscl.c
--- v2.4.7/linux/drivers/s390/char/tubttyscl.c	Wed Apr 11 19:02:28 2001
+++ linux/drivers/s390/char/tubttyscl.c	Wed Jul 25 14:12:02 2001
@@ -48,7 +48,7 @@
 tty3270_scl_timeout(unsigned long data)
 {
 	tub_t *tubp = (void *)data;
-	int flags;
+	long flags;
 
 	TUBLOCK(tubp->irq, flags);
 	tubp->stat = TBS_RUNNING;
@@ -72,9 +72,9 @@
 int
 tty3270_scl_init(tub_t *tubp)
 {
-	extern int tubscrollparm;
+	extern int tubscrolltime;
 
-	tubp->tty_scrolltime = tubscrollparm;
+	tubp->tty_scrolltime = tubscrolltime;
 	if (tubp->tty_scrolltime < 0)
 		tubp->tty_scrolltime = DEFAULT_SCROLLTIME;
 	return 0;
diff -u --recursive --new-file v2.4.7/linux/drivers/s390/char/tubttysiz.c linux/drivers/s390/char/tubttysiz.c
--- v2.4.7/linux/drivers/s390/char/tubttysiz.c	Wed Apr 11 19:02:28 2001
+++ linux/drivers/s390/char/tubttysiz.c	Wed Jul 25 14:12:02 2001
@@ -12,7 +12,7 @@
 #include "tubio.h"
 static int tty3270_size_io(tub_t *tubp);
 static void tty3270_size_int(tub_t *tubp, devstat_t *dsp);
-static int tty3270_size_wait(tub_t *tubp, int *flags, int stat);
+static int tty3270_size_wait(tub_t *tubp, long *flags, int stat);
 
 /*
  * Structure representing Usable Area Query Reply Base
@@ -71,7 +71,7 @@
  * Try to determine screen size using Read Partition (Query)
  */
 int
-tty3270_size(tub_t *tubp, int *flags)
+tty3270_size(tub_t *tubp, long *flags)
 {
 	char wbuf[7] = { 0x00, 0x07, 0x01, 0xff, 0x03, 0x00, 0x81 };
 	int     rc = 0;
@@ -285,7 +285,7 @@
  * Return 0 unless signal pending, in which case -ERESTARTSYS.
  */
 static int
-tty3270_size_wait(tub_t *tubp, int *flags, int stat)
+tty3270_size_wait(tub_t *tubp, long *flags, int stat)
 {
 	DECLARE_WAITQUEUE(wait, current);
 
diff -u --recursive --new-file v2.4.7/linux/drivers/s390/idals.c linux/drivers/s390/idals.c
--- v2.4.7/linux/drivers/s390/idals.c	Wed Apr 11 19:02:28 2001
+++ linux/drivers/s390/idals.c	Wed Jul 25 14:12:02 2001
@@ -11,44 +11,33 @@
 
 #include <linux/module.h>
 #include <linux/config.h>
-#include <linux/malloc.h>
+#include <linux/slab.h>
 
 #include <asm/irq.h>
 #include <asm/idals.h>
 
 #ifdef CONFIG_ARCH_S390X
-#define IDA_SIZE_LOG 12 /* 11 for 2k , 12 for 4k */
-#define IDA_BLOCK_SIZE (1L<<IDA_SIZE_LOG)
-void 
-set_normalized_cda ( ccw1_t * cp, unsigned long address )
+
+unsigned long __create_idal (unsigned long address, int count)
 {
 	int nridaws;
-	idaw_t *idal;
-        int count = cp->count;
+	unsigned long *idal, *tmp;
 
-	if (cp->flags & CCW_FLAG_IDA)
-		BUG();
-	if (((address + count) >> 31) == 0) { 
-		cp -> cda = address;
-		return;
-	}
         nridaws = ((address & (IDA_BLOCK_SIZE-1)) + count + 
 		   (IDA_BLOCK_SIZE-1)) >> IDA_SIZE_LOG;
 	idal = idal_alloc(nridaws);
-	if ( idal == NULL ) {
-		/* probably we should have a fallback here */
-		panic ("Cannot allocate memory for IDAL\n");
+	if (idal != NULL) {
+		tmp = idal;
+		*tmp++ = address;
+		address &= -IDA_BLOCK_SIZE;
+		while (--nridaws > 0) {
+			address += IDA_BLOCK_SIZE;
+			*tmp++ = address;
+		}
 	}
-	cp->flags |= CCW_FLAG_IDA;
-	cp->cda = (__u32)(unsigned long)(idaw_t *)idal;
-        do {
-		*idal++ = address;
-		address = (address & -(IDA_BLOCK_SIZE)) + (IDA_BLOCK_SIZE);
-		nridaws --;
-        } while ( nridaws > 0 );
-	return;
+	return (unsigned long) idal;
 }
 
-EXPORT_SYMBOL (set_normalized_cda);
+EXPORT_SYMBOL (__create_idal);
 
 #endif
diff -u --recursive --new-file v2.4.7/linux/drivers/s390/misc/chandev.c linux/drivers/s390/misc/chandev.c
--- v2.4.7/linux/drivers/s390/misc/chandev.c	Wed Apr 11 19:02:28 2001
+++ linux/drivers/s390/misc/chandev.c	Wed Jul 25 14:12:02 2001
@@ -24,6 +24,14 @@
 #include <asm/s390dyn.h>
 #include <asm/queue.h>
 #include <linux/kmod.h>
+#ifndef MIN
+#define MIN(a,b) ((a<b)?a:b)
+#endif
+#ifndef MAX
+#define MAX(a,b) ((a>b)?a:b)
+#endif
+
+
 
 typedef struct chandev_model_info chandev_model_info;
 struct chandev_model_info
@@ -35,7 +43,9 @@
 	s32 dev_type;     /* device type -1 = don't care */
 	s16 dev_model;    /* device model -1 = don't care */
 	u8  max_port_no;
-	int      auto_msck_recovery;
+	int auto_msck_recovery;
+	u8  default_checksum_received_ip_pkts;
+	u8  default_use_hw_stats; /* where available e.g. lcs */
 	devreg_t drinfo;
 };
 
@@ -44,12 +54,7 @@
 {
 	struct chandev *next;
 	chandev_model_info *model_info;
-	u16 cu_type;      /* control unit type */
-	u8  cu_model;     /* control unit model */
-	u16 dev_type;     /* device type */
-	u8  dev_model;    /* device model */
-	u16 devno;
-	unsigned int irq;
+	chandev_subchannel_info sch;
 	int owned;
 };
 
@@ -66,28 +71,32 @@
 {
 	struct chandev_force *next;
 	chandev_type chan_type;
-	s32     devif_num; /* -1 don't care e.g. tr0 implies 0 */
-        u16     read_devno;
-	u16     write_devno;
+	s32     devif_num; /* -1 don't care, -2 we are forcing a range e.g. tr0 implies 0 */
+        u16     read_lo_devno;
+	u16     write_hi_devno;
+	u16     data_devno; /* only used by gigabit ethernet */
+	s32     memory_usage_in_k;
         s16     port_protocol_no; /* where available e.g. lcs,-1 don't care */
 	u8      checksum_received_ip_pkts;
 	u8      use_hw_stats; /* where available e.g. lcs */
+	/* claw specific stuff */
+	chandev_claw_info  claw;
 };
 
 typedef struct chandev_probelist chandev_probelist;
 struct chandev_probelist
 {
-	struct chandev_probelist *next;
-	chandev_probefunc       probefunc;
-	chandev_shutdownfunc    shutdownfunc;
-	chandev_reoperfunc      reoperfunc;
-	chandev_type            chan_type;
-	int                     devices_found;
+	struct chandev_probelist            *next;
+	chandev_probefunc                   probefunc;
+	chandev_shutdownfunc                shutdownfunc;
+	chandev_msck_notification_func      msck_notfunc;
+	chandev_type                        chan_type;
+	int                                 devices_found;
 };
 
 
 
-#define default_msck_bits ((1<<(not_oper-1))|(1<<(no_path-1))|(1<<(revalidate-1))|(1<<(gone-1)))
+#define default_msck_bits ((1<<(chandev_status_not_oper-1))|(1<<(chandev_status_no_path-1))|(1<<(chandev_status_revalidate-1))|(1<<(chandev_status_gone-1)))
 
 
 static char *msck_status_strs[]=
@@ -113,14 +122,13 @@
 typedef struct chandev_irqinfo chandev_irqinfo;
 struct chandev_irqinfo
 {
-	chandev_irqinfo      *next;
-	chandev_msck_status  msck_status;
-	u16                  devno;
-	unsigned int         irq;
-	void                 (*handler)(int, void *, struct pt_regs *);
-	unsigned long        irqflags;
-	void                 *dev_id;
-	char                 devname[0];
+	chandev_irqinfo         *next;
+	chandev_subchannel_info sch;
+	chandev_msck_status     msck_status;
+	void                    (*handler)(int, void *, struct pt_regs *);
+	unsigned long           irqflags;
+	void                    *dev_id;
+	char                    devname[0];
 };
 
 
@@ -131,34 +139,33 @@
 {
 	chandev_parms      *next;
 	chandev_type       chan_type;
+	u16                lo_devno;
+	u16                hi_devno;
 	char               parmstr[0];
 };
 
+static chandev_type chandev_persistent=0; 
+
 chandev_parms *chandev_parms_head=NULL;
 
 
 typedef struct chandev_activelist chandev_activelist;
 struct chandev_activelist
 {
-	struct chandev_activelist *next;
-	chandev_irqinfo         *read_irqinfo;
-	chandev_irqinfo         *write_irqinfo;
-	u16                     cu_type;      /* control unit type */
-	u8                      cu_model;     /* control unit model */
-	u16                     dev_type;     /* device type */
-	u8                      dev_model;    /* device model */
-	chandev_probefunc       probefunc;
-	chandev_shutdownfunc    shutdownfunc;
-	chandev_reoperfunc      reoperfunc;
-	chandev_unregfunc       unreg_dev;
-	chandev_type            chan_type;
-	u8                      port_no;
-	chandev_category        category;
-	int                     saved_busy_flag;
-	
-
-	void                    *dev_ptr;
-	char                    devname[0];
+	struct chandev_activelist        *next;
+	chandev_irqinfo                  *read_irqinfo;
+	chandev_irqinfo                  *write_irqinfo;
+	chandev_irqinfo                  *data_irqinfo;
+	chandev_probefunc                probefunc;
+	chandev_shutdownfunc             shutdownfunc;
+	chandev_msck_notification_func   msck_notfunc;
+	chandev_unregfunc                unreg_dev;
+	chandev_type                     chan_type;
+	u8                               port_no;
+	chandev_category                 category;
+	s32                              memory_usage_in_k;
+	void                             *dev_ptr;
+	char                             devname[0];
 };
 
 
@@ -172,10 +179,11 @@
 static chandev_probelist *chandev_probelist_head=NULL;
 static chandev_activelist *chandev_activelist_head=NULL;
 #if LINUX_VERSION_CODE>=KERNEL_VERSION(2,3,0)
-static int use_devno_names=FALSE;
+int chandev_use_devno_names=FALSE;
 #endif
-static int chandev_conf_read=FALSE;
-static int chandev_initialised=FALSE;
+static int chandev_cautious_auto_detect=TRUE;
+static atomic_t chandev_conf_read=ATOMIC_INIT(FALSE);
+static atomic_t chandev_initialised=ATOMIC_INIT(FALSE);
 
 
 static unsigned long chandev_last_machine_check;
@@ -186,22 +194,38 @@
 static atomic_t chandev_new_msck;
 static unsigned long chandev_last_startmsck_list_update;
 
-typedef struct chandev_startmsck_list chandev_startmsck_list;
-struct chandev_startmsck_list
+
+typedef enum
+{
+	chandev_start,
+	chandev_first_tag=chandev_start,
+	chandev_msck,
+	chandev_num_notify_tags
+} chandev_userland_notify_tag;
+
+static char *userland_notify_strs[]=
 {
-	chandev_startmsck_list    *next;
-	chandev_msck_status       pre_recovery_action_status;
-	chandev_msck_status       post_recovery_action_status;
+	"start",
+	"machine_check"
+};
+
+typedef struct chandev_userland_notify_list chandev_userland_notify_list;
+struct chandev_userland_notify_list
+{
+	chandev_userland_notify_list    *next;
+	chandev_userland_notify_tag      tag;
+	chandev_msck_status              prev_status;
+	chandev_msck_status              curr_status;
 	char                      devname[0];
 };
 
 
-static chandev_startmsck_list *startlist_head=NULL;
-static chandev_startmsck_list *mscklist_head=NULL;
+static chandev_userland_notify_list *chandev_userland_notify_head=NULL;
 
 
 
 
+static void chandev_read_conf_if_necessary(void);
 static void chandev_read_conf(void);
 
 #if LINUX_VERSION_CODE >=KERNEL_VERSION(2,3,0)
@@ -233,7 +257,56 @@
 static long                 chandev_lock_owner;
 static int                  chandev_lock_cnt; 
 static spinlock_t           chandev_spinlock;
-void                        *chandev_firstlock_addr,*chandev_lastlock_addr; 
+#define CHANDEV_LOCK_DEBUG 0
+#if CHANDEV_LOCK_DEBUG && !defined(CONFIG_ARCH_S390X)
+#define CHANDEV_BACKTRACE_LOOPCNT 10
+void                        *chandev_first_lock_addr[CHANDEV_BACKTRACE_LOOPCNT],
+	                    *chandev_last_lock_addr[CHANDEV_BACKTRACE_LOOPCNT],
+	                    *chandev_last_unlock_addr[CHANDEV_BACKTRACE_LOOPCNT];
+#define CHANDEV_BACKTRACE(variable) \
+memset((variable),0,sizeof(void *)*CHANDEV_BACKTRACE_LOOPCNT); \
+(variable)[0]=__builtin_return_address(0); \
+if(((long)variable[0])&0x80000000)         \
+{                                          \
+(variable)[1]=__builtin_return_address(1); \
+if(((long)variable[1])&0x80000000)         \
+{                                          \
+(variable)[2]=__builtin_return_address(2); \
+if(((long)variable[2])&0x80000000)         \
+{                                          \
+(variable)[3]=__builtin_return_address(3); \
+if(((long)variable[3])&0x80000000)         \
+{                                          \
+(variable)[4]=__builtin_return_address(4); \
+if(((long)variable[4])&0x80000000)         \
+{                                          \
+(variable)[5]=__builtin_return_address(5); \
+if(((long)variable[5])&0x80000000)         \
+{                                          \
+(variable)[6]=__builtin_return_address(6); \
+if(((long)variable[6])&0x80000000)         \
+{                                          \
+(variable)[7]=__builtin_return_address(7); \
+if(((long)variable[7])&0x80000000)         \
+{                                          \
+(variable)[8]=__builtin_return_address(8); \
+if(((long)variable[8])&0x80000000)         \
+{                                          \
+(variable)[9]=__builtin_return_address(9); \
+} \
+} \
+} \
+} \
+} \
+} \
+} \
+} \
+}
+#else
+#define CHANDEV_BACKTRACE(variable)
+#endif
+
+
 
 typedef struct chandev_not_oper_struct chandev_not_oper_struct;
 
@@ -250,7 +323,6 @@
  */
 static qheader chandev_not_oper_head={NULL,NULL};
 static spinlock_t           chandev_not_oper_spinlock;
-static char           exec_script[]="/bin/chandev";
 
 #define chandev_interrupt_check() \
 if(in_interrupt())                \
@@ -260,22 +332,30 @@
 #define for_each(variable,head) \
 for((variable)=(head);(variable)!=NULL;(variable)=(variable)->next)
 
+#define for_each_allow_delete(variable,nextmember,head) \
+for((variable)=(head),(nextmember)=((head) ? (head)->next:NULL); \
+(variable)!=NULL; (variable)=(nextmember),(nextmember)=((nextmember) ? (nextmember->next) : NULL))
+
+#define for_each_allow_delete2(variable,nextmember,head) \
+for((variable)=(head);(variable)!=NULL;(variable)=(nextmember))
+
 
 static void chandev_lock(void)
 {
-	chandev_interrupt_check();
 	eieio();
+	chandev_interrupt_check();
 	if(chandev_lock_owner!=(long)current)
 	{
-		spin_lock(&chandev_spinlock);
+		while(!spin_trylock(&chandev_spinlock))
+			schedule();
 		chandev_lock_cnt=1;
 		chandev_lock_owner=(long)current;
-		chandev_firstlock_addr=__builtin_return_address(0);
+		CHANDEV_BACKTRACE(chandev_first_lock_addr)
 	}
 	else
 	{
 		chandev_lock_cnt++;
-		chandev_lastlock_addr=__builtin_return_address(0);
+		CHANDEV_BACKTRACE(chandev_last_lock_addr)
 	}
 	if(chandev_lock_cnt<0||chandev_lock_cnt>100)
 	{
@@ -301,6 +381,7 @@
 		      (long)current,
 		      chandev_lock_owner,
 		      chandev_lock_cnt);
+	CHANDEV_BACKTRACE(chandev_last_unlock_addr)
 	if(--chandev_lock_cnt==0)
 	{
 		chandev_lock_owner=CHANDEV_INVALID_LOCK_OWNER;
@@ -315,13 +396,6 @@
 }
 
 
-void chandev_relock(int saved_lock_cnt)
-{
-	
-	chandev_lock();
-	chandev_lock_cnt=saved_lock_cnt;
-}
-
 
 void *chandev_alloc(size_t size)
 {
@@ -369,6 +443,7 @@
 
 void chandev_free_listmember(list **listhead,list *member)
 {
+	chandev_lock();
 	if(member)
 	{
 		if(chandev_remove_from_list(listhead,member))
@@ -377,18 +452,21 @@
 			printk(KERN_CRIT"chandev_free_listmember detected nonexistant"
 			       "listmember listhead=%p member %p\n",listhead,member);
 	}
+	chandev_unlock();
 }
 
 void chandev_free_queuemember(qheader *qhead,queue *member)
 {
+	chandev_lock();
 	if(member)
 	{
 		if(chandev_remove_from_queue(qhead,member))
 			kfree(member);
 		else
-			printk(KERN_CRIT"chandev_free_listmember detected nonexistant"
-			       "listmember qhead=%p member %p\n",qhead,member);
+			printk(KERN_CRIT"chandev_free_queuemember detected nonexistant"
+			       "queuemember qhead=%p member %p\n",qhead,member);
 	}
+	chandev_unlock();
 }
 
 
@@ -397,27 +475,45 @@
 {
 	list *head;
 
+	chandev_lock();
 	while((head=remove_listhead(listhead)))
 		kfree(head);
+	chandev_unlock();
 }
 
 void chandev_free_all_queue(qheader *qhead)
 {
+	chandev_lock();
 	while(qhead->head)
 		chandev_free_queuemember(qhead,qhead->head);
+	chandev_unlock();
 }
 
+static void chandev_wait_for_root_fs(void)
+{
+	wait_queue_head_t      wait;
 
+	init_waitqueue_head(&wait);
+	/* We need to wait till there is a root filesystem */
+	while(init_task.fs->root==NULL)
+	{
+		sleep_on_timeout(&wait,HZ);
+	}
+}
 
+/* We are now hotplug compliant i.e. */
+/* we typically get called in /sbin/hotplug chandev our parameters */
 static int chandev_exec_start_script(void *unused)
 {
 	
 	char **argv,*tempname;
 	int retval=-ENOMEM;
-	int loopcnt,argc;
+	int argc,loopcnt;
 	size_t allocsize;
-	chandev_startmsck_list *member;
+	chandev_userland_notify_list *member;
 	wait_queue_head_t      wait;
+	int                    have_tag[chandev_num_notify_tags]={FALSE,};
+	chandev_userland_notify_tag tagidx;
 	static char * envp[] = { "HOME=/", "TERM=linux", "PATH=/sbin:/usr/sbin:/bin:/usr/bin", NULL };
 	
 	init_waitqueue_head(&wait);
@@ -427,17 +523,33 @@
 	{
 		sleep_on_timeout(&wait,HZ);
 	}
+	if(!chandev_userland_notify_head)
+		return(0);
 	chandev_lock();
-	argc=1;
-	if(startlist_head)
-		argc++;
-	for_each(member,startlist_head)
-		argc++;
-	if(mscklist_head)
-		argc+=3;
-	for_each(member,mscklist_head)
-		argc++;
+	argc=2;
+	for(tagidx=chandev_first_tag;tagidx<chandev_num_notify_tags;tagidx++)
+	{
+		for_each(member,chandev_userland_notify_head)
+		{
+			if(member->tag==tagidx)
+			{
+				switch(tagidx)
+				{
+				case chandev_start:
+					argc++;
+					break;
+				case chandev_msck:
+					argc+=3;
+					break;
+				default:
+				}
+				if(have_tag[tagidx]==FALSE)
+					argc++;
+				have_tag[tagidx]=TRUE;
 
+			}
+		}
+	}
 	allocsize=(argc+1)*sizeof(char *);
         /* Warning possible stack overflow */
 	/* We can't kmalloc the parameters here as execve will */
@@ -446,58 +558,51 @@
 	if(argv)
 	{
 		memset(argv,0,allocsize);
-		argc=0;
-		argv[argc++]=exec_script;
-		if(startlist_head)
-			argv[argc++]="start";
-		for_each(member,startlist_head)
-		{
-			tempname=alloca(strlen(member->devname)+1);
-			if(tempname)
-			{
-				strcpy(tempname,member->devname);
-				argv[argc++]=tempname;
-			}
-			else
-				goto Fail;
-		}
-		if(mscklist_head)
-			argv[argc++]="machine_check";
-		for_each(member,mscklist_head)
+		argv[0]=hotplug_path;
+		argv[1]="chandev";
+		argc=2;
+		for(tagidx=chandev_first_tag;tagidx<chandev_num_notify_tags;tagidx++)
 		{
-			tempname=alloca(strlen(member->devname)+1);
-			if(tempname)
+			if(have_tag[tagidx])
 			{
-				strcpy(tempname,member->devname);
-				argv[argc++]=tempname;
+				argv[argc++]=userland_notify_strs[tagidx];
+				for_each(member,chandev_userland_notify_head)
+				{
+					if(member->tag==tagidx)
+					{
+						tempname=alloca(strlen(member->devname)+1);
+						if(tempname)
+						{
+							strcpy(tempname,member->devname);
+							argv[argc++]=tempname;
+						}
+						else
+							goto Fail;
+						if(member->tag==chandev_msck)
+						{
+							argv[argc++]=msck_status_strs[member->prev_status];
+							argv[argc++]=msck_status_strs[member->curr_status];
+						}
+					}
+				}
 			}
-			else
-				goto Fail;
-			argv[loopcnt++]=msck_status_strs[member->pre_recovery_action_status];
-			argv[loopcnt++]=msck_status_strs[member->post_recovery_action_status];
 		}
-		chandev_free_all_list((list **)&startlist_head);
-		chandev_free_all_list((list **)&mscklist_head);
+		chandev_free_all_list((list **)&chandev_userland_notify_head);
 		chandev_unlock();
-
-		/* We need to wait till there is a root filesystem */
-		while(init_task.fs->root==NULL)
-		{
-			sleep_on_timeout(&wait,HZ);
-		}
+		chandev_wait_for_root_fs();
 		/* We are basically execve'ing here there normally is no */
 		/* return */
-		retval=exec_usermodehelper(exec_script, argv, envp);
+		retval=exec_usermodehelper(hotplug_path, argv, envp);
 		goto Fail2;
 	}
  Fail:
 	
 	chandev_unlock();
  Fail2:
-	/* We don't really need to report /bin/chandev not existing */
+	/* We don't really need to report /sbin/hotplug not existing */
 	if(retval!=-ENOENT)
 	   printk("chandev_exec_start_script failed retval=%d\n",retval);
-	return(0);
+	return(retval);
 }
 
 
@@ -513,27 +618,25 @@
 }
 
 
-static int chandev_add_to_startmsck_list(chandev_startmsck_list **listhead,char *devname,
-chandev_msck_status pre_recovery_action_status,chandev_msck_status post_recovery_action_status)
+static int chandev_add_to_userland_notify_list(chandev_userland_notify_tag tag,
+char *devname, chandev_msck_status prev_status,chandev_msck_status curr_status)
 {
-	chandev_startmsck_list *member;
+	chandev_userland_notify_list *member,*nextmember;
 	int pid;
 	
 	chandev_lock();
 	/* remove operations still outstanding for this device */
-	for_each(member,startlist_head)
+	for_each_allow_delete(member,nextmember,chandev_userland_notify_head)
 		if(strcmp(member->devname,devname)==0)
-			chandev_remove_from_list((list **)&startlist_head,(list *)member);
-	for_each(member,mscklist_head)
-		if(strcmp(member->devname,devname)==0)
-			chandev_remove_from_list((list **)&mscklist_head,(list *)member);
+			chandev_free_listmember((list **)&chandev_userland_notify_head,(list *)member);
 	
 
-	if((member=chandev_allocstr(devname,offsetof(chandev_startmsck_list,devname))))
+	if((member=chandev_allocstr(devname,offsetof(chandev_userland_notify_list,devname))))
 	{
-		member->pre_recovery_action_status=pre_recovery_action_status;
-		member->post_recovery_action_status=post_recovery_action_status;
-		add_to_list((list **)listhead,(list *)member);
+		member->tag=tag;
+		member->prev_status=prev_status;
+		member->curr_status=curr_status;
+		add_to_list((list **)&chandev_userland_notify_head,(list *)member);
 		chandev_last_startmsck_list_update=jiffies;
 		chandev_unlock();
 		pid = kernel_thread(chandev_exec_start_script,NULL,SIGCHLD);
@@ -596,7 +699,7 @@
 {
 	chandev_irqinfo *curr_irqinfo;
 	for_each(curr_irqinfo,chandev_irqinfo_head)
-		if(irq==curr_irqinfo->irq)
+		if(irq==curr_irqinfo->sch.irq)
 			return(curr_irqinfo);
 	return(NULL);
 }
@@ -606,7 +709,7 @@
 	chandev *curr_chandev;
 
 	for_each(curr_chandev,(chandev *)chandev_head.head)
-		if(curr_chandev->irq==irq)
+		if(curr_chandev->sch.irq==irq)
 		{
 			return(curr_chandev);
 		}
@@ -619,8 +722,9 @@
 
 	for_each(curr_device,chandev_activelist_head)
 	{
-			if(curr_device->read_irqinfo->irq==irq||
-			   curr_device->write_irqinfo->irq==irq)
+			if(curr_device->read_irqinfo->sch.irq==irq||
+			   curr_device->write_irqinfo->sch.irq==irq||
+			   (curr_device->data_irqinfo&&curr_device->data_irqinfo->sch.irq==irq))
 				return(curr_device);
 	}
 	return(NULL);
@@ -630,16 +734,50 @@
 void chandev_remove_irqinfo_by_irq(unsigned int irq)
 {
 	chandev_irqinfo *remove_irqinfo;
+	chandev_activelist *curr_device;
 
 	chandev_lock();
 	/* remove any orphan irqinfo left lying around. */
         if((remove_irqinfo=chandev_get_irqinfo_by_irq(irq)))
-		chandev_remove_from_list((list **)&chandev_irqinfo_head,
+	{
+		for_each(curr_device,chandev_activelist_head)
+		{
+			if(curr_device->read_irqinfo==remove_irqinfo)
+			{
+				curr_device->read_irqinfo=NULL;
+				break;
+			}
+			if(curr_device->write_irqinfo==remove_irqinfo)
+			{
+				curr_device->write_irqinfo=NULL;
+				break;
+			}
+			if(curr_device->data_irqinfo&&curr_device->data_irqinfo==remove_irqinfo)
+			{
+				curr_device->data_irqinfo=NULL;
+				break;
+			}
+		}
+		chandev_free_listmember((list **)&chandev_irqinfo_head,
 					 (list *)remove_irqinfo);
+	}
 	chandev_unlock();
 	
 }
 
+int chandev_add_schib_info(int irq,chandev_subchannel_info *sch)
+{
+	schib_t *new_schib;
+	
+	if((new_schib=s390_get_schib(irq)))
+	{
+		sch->pim=new_schib->pmcw.pim;
+		memcpy(&sch->chpid,&new_schib->pmcw.chpid,sizeof(sch->chpid));
+		return(0);
+	}
+	return(-ENODEV);
+}
+
 int chandev_request_irq(unsigned int   irq,
                       void           (*handler)(int, void *, struct pt_regs *),
                       unsigned long  irqflags,
@@ -674,10 +812,16 @@
 			kfree(new_irqinfo);
 		else
 		{
-			new_irqinfo->irq=irq;
+			new_irqinfo->msck_status=chandev_status_good;
+			new_irqinfo->sch.devno=devinfo.devno;
+			new_irqinfo->sch.irq=irq;
+			new_irqinfo->sch.cu_type=devinfo.sid_data.cu_type; /* control unit type */
+			new_irqinfo->sch.cu_model=devinfo.sid_data.cu_model; /* control unit model */
+			new_irqinfo->sch.dev_type=devinfo.sid_data.dev_type; /* device type */
+			new_irqinfo->sch.dev_model=devinfo.sid_data.dev_model; /* device model */
+			chandev_add_schib_info(irq,&new_irqinfo->sch);
 			new_irqinfo->handler=handler;
 			new_irqinfo->dev_id=dev_id;
-			new_irqinfo->devno=devinfo.devno;
 			chandev_add_to_list((list **)&chandev_irqinfo_head,new_irqinfo);
 		}
 	}
@@ -689,13 +833,32 @@
 	return(retval);
 }
 
+/* This should be safe to call even multiple times. */
 void chandev_free_irq(unsigned int irq, void *dev_id)
 {
+	s390_dev_info_t devinfo;
+	int err;
+	
 	/* remove any orphan irqinfo left lying around. */
 	chandev_remove_irqinfo_by_irq(irq);
-	free_irq(irq,dev_id);
+	if((err=get_dev_info_by_irq(irq,&devinfo)))
+	{
+		printk("chandev_free_irq get_dev_info_by_irq reported err=%X on irq %d\n"
+		       "should not happen\n",err,irq);
+		return;
+	 }
+	if(devinfo.status&DEVSTAT_DEVICE_OWNED)
+	   free_irq(irq,dev_id);
 }
 
+/* This should be safe even if chandev_free_irq is already called by the device */
+void chandev_free_irq_by_irqinfo(chandev_irqinfo *irqinfo)
+{
+	if(irqinfo)
+		chandev_free_irq(irqinfo->sch.irq,irqinfo->dev_id);
+}
+
+
 
 void chandev_sprint_type_model(char *buff,s32 type,s16 model)
 {
@@ -716,37 +879,66 @@
 	chandev_sprint_type_model(&buff[strlen(buff)],dev_type,dev_model);
 }
 
-void chandev_remove_parms(chandev_type chan_type,int exact_match)
+void chandev_remove_parms(chandev_type chan_type,int exact_match,int lo_devno)
 {
-	chandev_parms      *curr_parms;
+	chandev_parms      *curr_parms,*next_parms;
 
 	chandev_lock();
-	for_each(curr_parms,chandev_parms_head)
+	for_each_allow_delete(curr_parms,next_parms,chandev_parms_head)
 	{
-		if((chan_type&(curr_parms->chan_type)&&!exact_match)||
-		    (chan_type==(curr_parms->chan_type)&&exact_match))
-		    chandev_free_listmember((list **)&chandev_parms_head,(list *)curr_parms);
+		if(((chan_type&(curr_parms->chan_type)&&!exact_match)||
+		   (chan_type==(curr_parms->chan_type)&&exact_match))&&
+		   (lo_devno==-1||lo_devno==curr_parms->lo_devno))
+			chandev_free_listmember((list **)&chandev_parms_head,(list *)curr_parms);
 	}
 	chandev_unlock();
 }
 
-void chandev_add_parms(chandev_type chan_type,char *parmstr)
+
+void chandev_add_parms(chandev_type chan_type,u16 lo_devno,u16 hi_devno,char *parmstr)
 {
-	chandev_parms      *new_parms;
-	
-	if((new_parms=chandev_allocstr(parmstr,offsetof(chandev_parms,parmstr))))
+	chandev_parms      *parms;
+
+	if(lo_devno>hi_devno)
 	{
-		chandev_remove_parms(chan_type,TRUE);
-		new_parms->chan_type=chan_type;
-		chandev_add_to_list((list **)&chandev_parms_head,(void *)new_parms);
+		printk("chandev_add_parms detected bad device range lo_devno=0x%04x  hi_devno=0x%04x\n,",
+		       (int)lo_devno,(int)hi_devno);
+		return;
+	}
+	chandev_lock();
+	for_each(parms,chandev_parms_head)
+	{
+		if(chan_type&(parms->chan_type))
+		{
+			u16 lomax=MAX(parms->lo_devno,lo_devno),
+				himin=MIN(parms->hi_devno,lo_devno);
+			if(lomax<=himin)
+			{
+				chandev_unlock();
+				printk("chandev_add_parms detected overlapping "
+				       "parameter definitions for chan_type=0x%02x"
+				       " lo_devno=0x%04x  hi_devno=0x%04x\n,"
+				       " do a del_parms.",chan_type,(int)lo_devno,(int)hi_devno);
+				return;
+			}
+		}
+	}
+	chandev_unlock();
+	if((parms=chandev_allocstr(parmstr,offsetof(chandev_parms,parmstr))))
+	{
+		parms->chan_type=chan_type;
+		parms->lo_devno=lo_devno;
+		parms->hi_devno=hi_devno;
+		chandev_add_to_list((list **)&chandev_parms_head,(void *)parms);
 	}
 	else
-		printk("chandev_add_parmstr memory request failed\n");
+		printk("chandev_add_parms memory request failed\n");
 }
 
 
 void chandev_add_model(chandev_type chan_type,s32 cu_type,s16 cu_model,
-		       s32 dev_type,s16 dev_model,u8 max_port_no,int auto_msck_recovery)
+		       s32 dev_type,s16 dev_model,u8 max_port_no,int auto_msck_recovery,
+		       u8 default_checksum_received_ip_pkts,u8 default_use_hw_stats)
 {
 	chandev_model_info *newmodel;
 	int                err;
@@ -762,7 +954,8 @@
 		newmodel->dev_model=dev_model;
 		newmodel->max_port_no=max_port_no;
 		newmodel->auto_msck_recovery=auto_msck_recovery;
-		
+		newmodel->default_checksum_received_ip_pkts=default_checksum_received_ip_pkts;
+		newmodel->default_use_hw_stats=default_use_hw_stats; /* where available e.g. lcs */
 		if(cu_type==-1&&dev_type==-1)
 		{
 			chandev_sprint_devinfo(buff,newmodel->cu_type,newmodel->cu_model,
@@ -771,17 +964,15 @@
 			kfree(newmodel);
 			return;
 		}
-		/* We ignore errors as they are likely to
-		   occur owing to incompatibilities with
-		   Ingos layer 
-		*/
 		drinfo->flag=DEVREG_TYPE_DEVCHARS;
-		if(dev_model==-1)
-			drinfo->flag|=(dev_type==-1 ? DEVREG_NO_DEV_INFO:DEVREG_MATCH_DEV_TYPE);
-		if(cu_model==-1)
-			drinfo->flag|=(cu_type==-1 ? DEVREG_NO_CU_INFO:DEVREG_MATCH_CU_TYPE);
-		else if(dev_model!=-1&&cu_type!=-1)
-			drinfo->flag|=DEVREG_EXACT_MATCH;
+		if(cu_type!=-1)
+			drinfo->flag|=DEVREG_MATCH_CU_TYPE;
+		if(cu_model!=-1)
+			drinfo->flag|=DEVREG_MATCH_CU_MODEL;
+		if(dev_type!=-1)
+			drinfo->flag|=DEVREG_MATCH_DEV_TYPE;
+		if(dev_model!=-1)
+			drinfo->flag|=DEVREG_MATCH_DEV_MODEL;
 		drinfo->ci.hc.ctype=cu_type;
 		drinfo->ci.hc.cmode=cu_model;
 		drinfo->ci.hc.dtype=dev_type;
@@ -813,10 +1004,10 @@
 
 void chandev_remove_model(chandev_model_info *model)
 {
-	chandev *curr_chandev;
+	chandev *curr_chandev,*next_chandev;
 
 	chandev_lock();
-	for_each(curr_chandev,(chandev *)chandev_head.head)
+	for_each_allow_delete(curr_chandev,next_chandev,(chandev *)chandev_head.head)
 		if(curr_chandev->model_info==model)
 			chandev_remove(curr_chandev);
 	if(model->drinfo.oper_func)
@@ -835,10 +1026,10 @@
 
 void chandev_del_model(s32 cu_type,s16 cu_model,s32 dev_type,s16 dev_model)
 {
-	chandev_model_info *curr_model;
+	chandev_model_info *curr_model,*next_model;
 	
 	chandev_lock();
-	for_each(curr_model,chandev_models_head)
+	for_each_allow_delete(curr_model,next_model,chandev_models_head)
 		if((curr_model->cu_type==cu_type||cu_type==-1)&&
 		   (curr_model->cu_model==cu_model||cu_model==-1)&&
 		   (curr_model->dev_type==dev_type||dev_type==-1)&&
@@ -849,31 +1040,34 @@
 
 static void chandev_init_default_models(void)
 {
-	/* P390/Planter 3172 emulation assume maximum 16 to be safe. */
-	chandev_add_model(lcs,0x3088,0x1,-1,-1,15,default_msck_bits);	
+	/* Usually P390/Planter 3172 emulation assume maximum 16 to be safe. */
+	chandev_add_model(chandev_type_lcs,0x3088,0x1,-1,-1,15,default_msck_bits,FALSE,FALSE);	
 
 	/* 3172/2216 Paralell the 2216 allows 16 ports per card the */
 	/* the original 3172 only allows 4 we will assume the max of 16 */
-	chandev_add_model(lcs|ctc,0x3088,0x8,-1,-1,15,default_msck_bits);
+	chandev_add_model(chandev_type_lcs|chandev_type_ctc,0x3088,0x8,-1,-1,15,default_msck_bits,FALSE,FALSE);
 
 	/* 3172/2216 Escon serial the 2216 allows 16 ports per card the */
 	/* the original 3172 only allows 4 we will assume the max of 16 */
-	chandev_add_model(lcs|escon,0x3088,0x1F,-1,-1,15,default_msck_bits);
+	chandev_add_model(chandev_type_lcs|chandev_type_escon,0x3088,0x1F,-1,-1,15,default_msck_bits,FALSE,FALSE);
 
 	/* Only 2 ports allowed on OSA2 cards model 0x60 */
-	chandev_add_model(lcs,0x3088,0x60,-1,-1,1,default_msck_bits);
-	/* qeth has relative adapter concept so we give it 16 */
-	chandev_add_model(qeth,0x1731,0x1,0x1732,0x1,15,default_msck_bits);
+	chandev_add_model(chandev_type_lcs,0x3088,0x60,-1,-1,1,default_msck_bits,FALSE,FALSE);
+	/* qeth gigabit ethernet */
+	chandev_add_model(chandev_type_qeth,0x1731,0x1,0x1732,0x1,0,default_msck_bits,FALSE,FALSE);
+	chandev_add_model(chandev_type_qeth,0x1731,0x5,0x1732,0x5,0,default_msck_bits,FALSE,FALSE);
 	/* Osa-D we currently aren't too emotionally involved with this */
-	chandev_add_model(osad,0x3088,0x62,-1,-1,0,default_msck_bits);
+	chandev_add_model(chandev_type_osad,0x3088,0x62,-1,-1,0,default_msck_bits,FALSE,FALSE);
+	/* claw */
+	chandev_add_model(chandev_type_claw,0x3088,0x61,-1,-1,0,default_msck_bits,FALSE,FALSE);
 }
 
 
 void chandev_del_noauto(u16 devno)
 {
-	chandev_noauto_range *curr_noauto;
+	chandev_noauto_range *curr_noauto,*next_noauto;
 	chandev_lock();
-	for_each(curr_noauto,chandev_noauto_head)
+	for_each_allow_delete(curr_noauto,next_noauto,chandev_noauto_head)
 		if(curr_noauto->lo_devno<=devno&&curr_noauto->hi_devno>=devno)
 			chandev_free_listmember((list **)&chandev_noauto_head,(list *)curr_noauto); 
 	chandev_unlock();
@@ -881,9 +1075,9 @@
 
 void chandev_del_msck(u16 devno)
 {
-	chandev_msck_range *curr_msck_range;
+	chandev_msck_range *curr_msck_range,*next_msck_range;
 	chandev_lock();
-	for_each(curr_msck_range,chandev_msck_range_head)
+	for_each_allow_delete(curr_msck_range,next_msck_range,chandev_msck_range_head)
 		if(curr_msck_range->lo_devno<=devno&&curr_msck_range->hi_devno>=devno)
 			chandev_free_listmember((list **)&chandev_msck_range_head,(list *)curr_msck_range); 
 	chandev_unlock();
@@ -897,12 +1091,13 @@
 	if((new_chandev=chandev_alloc(sizeof(chandev))))
 	{
 		new_chandev->model_info=newmodelinfo;
-		new_chandev->cu_type=newdevinfo->sid_data.cu_type; /* control unit type */
-		new_chandev->cu_model=newdevinfo->sid_data.cu_model; /* control unit model */
-		new_chandev->dev_type=newdevinfo->sid_data.dev_type; /* device type */
-		new_chandev->dev_model=newdevinfo->sid_data.dev_model; /* device model */
-		new_chandev->devno=newdevinfo->devno;
-		new_chandev->irq=newdevinfo->irq;
+		new_chandev->sch.devno=newdevinfo->devno;
+		new_chandev->sch.irq=newdevinfo->irq;
+		new_chandev->sch.cu_type=newdevinfo->sid_data.cu_type; /* control unit type */
+		new_chandev->sch.cu_model=newdevinfo->sid_data.cu_model; /* control unit model */
+		new_chandev->sch.dev_type=newdevinfo->sid_data.dev_type; /* device type */
+		new_chandev->sch.dev_model=newdevinfo->sid_data.dev_model; /* device model */
+		chandev_add_schib_info(newdevinfo->irq,&new_chandev->sch);
 		new_chandev->owned=(newdevinfo->status&DEVSTAT_DEVICE_OWNED ? TRUE:FALSE);
 		chandev_queuemember(&chandev_head,new_chandev);
 	}
@@ -910,16 +1105,29 @@
 
 void chandev_unregister_probe(chandev_probefunc probefunc)
 {
-	chandev_probelist *curr_probe;
+	chandev_probelist *curr_probe,*next_probe;
 
 	chandev_lock();
-	for_each(curr_probe,chandev_probelist_head)
+	for_each_allow_delete(curr_probe,next_probe,chandev_probelist_head)
 		if(curr_probe->probefunc==probefunc)
 			chandev_free_listmember((list **)&chandev_probelist_head,
 						(list *)curr_probe);
 	chandev_unlock();
 }
 
+void chandev_unregister_probe_by_chan_type(chandev_type chan_type)
+{
+	chandev_probelist *curr_probe,*next_probe;
+
+	chandev_lock();
+	for_each_allow_delete(curr_probe,next_probe,chandev_probelist_head)
+		if(curr_probe->chan_type==chan_type)
+			chandev_free_listmember((list **)&chandev_probelist_head,
+						(list *)curr_probe);
+	chandev_unlock();
+}
+
+
 
 void chandev_reset(void)
 {
@@ -928,36 +1136,62 @@
 	chandev_free_all_list((list **)&chandev_noauto_head);
 	chandev_free_all_list((list **)&chandev_msck_range_head);
 	chandev_free_all_list((list **)&chandev_force_head);
-	chandev_remove_parms(-1,FALSE);
+	chandev_remove_parms(-1,FALSE,-1);
 #if LINUX_VERSION_CODE>=KERNEL_VERSION(2,3,0)
-	use_devno_names=FALSE;
+	chandev_use_devno_names=FALSE;
 #endif
-	chandev_conf_read=FALSE;
 	chandev_unlock();
 }
 
 
-chandev_model_info *chandev_is_chandev(int irq,s390_dev_info_t *devinfo)
+int chandev_is_chandev(int irq,s390_dev_info_t *devinfo,chandev_force **forceinfo,chandev_model_info **ret_model)
 {
+	chandev_force *curr_force;
 	chandev_model_info *curr_model=NULL;
 	int err;
+	int retval=FALSE;
+
+	if(forceinfo)
+		*forceinfo=NULL;
+	if(ret_model)
+		*ret_model=NULL;
 	if((err=get_dev_info_by_irq(irq,devinfo)))
 	{
 		printk("chandev_is_chandev get_dev_info_by_irq reported err=%X on irq %d\n"
 		       "should not happen\n",err,irq);
-			return(NULL);
+			return FALSE;
 	}
 	chandev_lock();
+	
 	for_each(curr_model,chandev_models_head)
 	{
 		if(((curr_model->cu_type==devinfo->sid_data.cu_type)||(curr_model->cu_type==-1))&&
 		   ((curr_model->cu_model==devinfo->sid_data.cu_model)||(curr_model->cu_model==-1))&&
 		   ((curr_model->dev_type==devinfo->sid_data.dev_type)||(curr_model->dev_type==-1))&&
 		   ((curr_model->dev_model==devinfo->sid_data.dev_model)||(curr_model->dev_model==-1)))
+		{
+			retval=TRUE;
+			if(ret_model)
+				*ret_model=curr_model;
 			break;
+		}
+	}
+	for_each(curr_force,chandev_force_head)
+	{
+		if(((curr_force->read_lo_devno==devinfo->devno)&&
+		   (curr_force->write_hi_devno==devinfo->devno)&&
+		    (curr_force->devif_num!=-2))||
+		   ((curr_force->read_lo_devno>=devinfo->devno)&&
+		    (curr_force->write_hi_devno<=devinfo->devno)&&
+		    (curr_force->devif_num==-2)))
+		{
+			if(forceinfo)
+				*forceinfo=curr_force;
+			break;
+		}
 	}
 	chandev_unlock();
-	return(curr_model);
+	return(retval);
 }
 
 void chandev_collect_devices(void)
@@ -982,39 +1216,70 @@
 			break;
 		}
 		chandev_lock();
-		if((curr_model=chandev_is_chandev(curr_irq,&curr_devinfo)))
+		if(chandev_is_chandev(curr_irq,&curr_devinfo,NULL,&curr_model))
 			chandev_add(&curr_devinfo,curr_model);
 		chandev_unlock();
 	}
 }
 
-void chandev_add_force(chandev_type chan_type,s32 devif_num,u16 read_devno,
-u16 write_devno,s16 port_protocol_no,u8 checksum_received_ip_pkts,u8 use_hw_stats)
-
+int chandev_add_force(chandev_type chan_type,s32 devif_num,u16 read_lo_devno,
+u16 write_hi_devno,u16 data_devno,s32 memory_usage_in_k,s16 port_protocol_no,u8 checksum_received_ip_pkts,
+u8 use_hw_stats,char *host_name,char *adapter_name,char *api_type)
 {
 	chandev_force *new_chandev_force;
-
+	
+	if(devif_num==-2&&read_lo_devno>write_hi_devno)
+	{
+		printk("chandev_add_force detected bad device range lo_devno=0x%04x  hi_devno=0x%04x\n,",
+		       (int)read_lo_devno,(int)write_hi_devno);
+		return(-1);
+	}
+	if(memory_usage_in_k<0)
+	{
+		printk("chandev_add_force memory_usage_in_k is bad\n");
+		return(-1);
+	}
+	if(chan_type==chandev_type_claw)
+	{
+		int host_name_len=strlen(host_name),
+			adapter_name_len=strlen(adapter_name),
+			api_type_len=strlen(api_type);
+		if(host_name_len>=CLAW_NAMELEN||host_name_len==0||
+		   adapter_name_len>=CLAW_NAMELEN||adapter_name_len==0||
+		   api_type_len>=CLAW_NAMELEN||api_type_len==0)
+			return(-1);
+	}
 	if((new_chandev_force=chandev_alloc(sizeof(chandev_force))))
 	{
 		new_chandev_force->chan_type=chan_type;
 		new_chandev_force->devif_num=devif_num;
-		new_chandev_force->read_devno=read_devno;
-		new_chandev_force->write_devno=write_devno;
+		new_chandev_force->read_lo_devno=read_lo_devno;
+		new_chandev_force->write_hi_devno=write_hi_devno;
+		new_chandev_force->data_devno=data_devno;
+		new_chandev_force->memory_usage_in_k=memory_usage_in_k;
 		new_chandev_force->port_protocol_no=port_protocol_no;
 		new_chandev_force->checksum_received_ip_pkts=checksum_received_ip_pkts;
 		new_chandev_force->use_hw_stats=use_hw_stats;
+		
+		if(chan_type==chandev_type_claw)
+		{
+			strcpy(new_chandev_force->claw.host_name,host_name);
+			strcpy(new_chandev_force->claw.adapter_name,adapter_name);
+			strcpy(new_chandev_force->claw.api_type,api_type);
+		}
 		chandev_add_to_list((list **)&chandev_force_head,new_chandev_force);
 	}
+	return(0);
 }
 
-void chandev_del_force(u16 read_devno)
+void chandev_del_force(int read_lo_devno)
 {
-	chandev_force *curr_force;
+	chandev_force *curr_force,*next_force;
 	
 	chandev_lock();
-	for_each(curr_force,chandev_force_head)
+	for_each_allow_delete(curr_force,next_force,chandev_force_head)
 	{
-		if(curr_force->read_devno==read_devno)
+		if(curr_force->read_lo_devno==read_lo_devno||read_lo_devno==-1)
 			chandev_free_listmember((list **)&chandev_force_head,
 						(list *)curr_force);
 	}
@@ -1024,26 +1289,35 @@
 
 void chandev_shutdown(chandev_activelist *curr_device)
 {
-	int saved_lock_cnt;
+	int err=0;
 	chandev_lock();
 
-	if(curr_device->category==network_device)
+
+	/* unregister_netdev calls the dev->close so we shouldn't do this */
+	/* this otherwise we crash */
+	if(curr_device->unreg_dev)
 	{
-		/* unregister_netdev calls the dev->close so we shouldn't do this */
-		/* this otherwise we crash */
-		if(curr_device->unreg_dev)
-		{
-			saved_lock_cnt=chandev_full_unlock();
-			curr_device->unreg_dev(curr_device->dev_ptr);
-			chandev_relock(saved_lock_cnt);
-		}
+		curr_device->unreg_dev(curr_device->dev_ptr);
+		curr_device->unreg_dev=NULL;
+	}
+	if(curr_device->shutdownfunc)
+	{
+		err=curr_device->shutdownfunc(curr_device->dev_ptr);
 	}
-	saved_lock_cnt=chandev_full_unlock();
-	curr_device->shutdownfunc(curr_device->dev_ptr);
-	chandev_relock(saved_lock_cnt);
-	kfree(curr_device->dev_ptr);
-	chandev_free_listmember((list **)&chandev_activelist_head,
+	if(err)
+		printk("chandev_shutdown unable to fully shutdown & unload %s err=%d\n"
+		       "probably some upper layer still requires the device to exist\n",
+		       curr_device->devname,err);
+	else
+	{
+		
+		chandev_free_irq_by_irqinfo(curr_device->read_irqinfo);
+		chandev_free_irq_by_irqinfo(curr_device->write_irqinfo);
+		if(curr_device->data_irqinfo)
+			chandev_free_irq_by_irqinfo(curr_device->data_irqinfo);
+		chandev_free_listmember((list **)&chandev_activelist_head,
 				(list *)curr_device);
+	}
 	chandev_unlock();
 }
 
@@ -1071,8 +1345,9 @@
 	chandev_activelist *curr_device;
 
 	for_each(curr_device,chandev_activelist_head)
-		if(curr_device->read_irqinfo->devno==devno||
-		   curr_device->write_irqinfo->devno==devno)
+		if(curr_device->read_irqinfo->sch.devno==devno||
+		   curr_device->write_irqinfo->sch.devno==devno||
+		   (curr_device->data_irqinfo&&curr_device->data_irqinfo->sch.devno==devno))
 		{
 			return(curr_device);
 		}
@@ -1105,7 +1380,7 @@
 			str++;
 			continue;
 		}
-		if(isspace(*str)||((*str)=='-'))
+		if(isspace(*str))
 		{
 			*str=',';
 			goto pack_dn;
@@ -1159,7 +1434,7 @@
 
 int chandev_initdevice(chandev_probeinfo *probeinfo,void *dev_ptr,u8 port_no,char *devname,chandev_category category,chandev_unregfunc unreg_dev)
 {
-	chandev_activelist *newdevice;
+	chandev_activelist *newdevice,*curr_device;
 
 	chandev_interrupt_check();
 	if(probeinfo->newdevice!=NULL)
@@ -1167,70 +1442,117 @@
 		printk("probeinfo->newdevice!=NULL in chandev_initdevice for %s",devname);
 		return(-EPERM);
 	}
-	
 
+
+	chandev_lock();
+	for_each(curr_device,chandev_activelist_head)
+	{
+		if(strcmp(curr_device->devname,devname)==0)
+		{
+			printk("chandev_initdevice detected duplicate devicename %s\n",devname);
+			chandev_unlock();
+			return(-EPERM);
+		}
+	}
 	if((newdevice=chandev_allocstr(devname,offsetof(chandev_activelist,devname))))
 	{
-		probeinfo->newdevice=newdevice;
-		chandev_lock();
-		newdevice->read_irqinfo=chandev_get_irqinfo_by_irq(probeinfo->read_irq);
-		newdevice->write_irqinfo=chandev_get_irqinfo_by_irq(probeinfo->write_irq);
+		newdevice->read_irqinfo=chandev_get_irqinfo_by_irq(probeinfo->read.irq);
+		newdevice->write_irqinfo=chandev_get_irqinfo_by_irq(probeinfo->write.irq);
+		if(probeinfo->data_exists)
+			newdevice->data_irqinfo=chandev_get_irqinfo_by_irq(probeinfo->data.irq);
 		chandev_unlock();
-		if(newdevice->read_irqinfo==NULL||newdevice->write_irqinfo==NULL)
+		if(newdevice->read_irqinfo==NULL||newdevice->write_irqinfo==NULL||
+		   (probeinfo->data_exists&&newdevice->data_irqinfo==NULL))
 		{
 			printk("chandev_initdevice, it appears that chandev_request_irq was not "
-			       "called for devname=%s read_irq=%d write_irq=%d\n",devname,probeinfo->read_irq,probeinfo->write_irq);
+			       "called for devname=%s read_irq=%d write_irq=%d data_irq=%d\n",
+			       devname,probeinfo->read.irq,probeinfo->write.irq,probeinfo->data.irq);
 			kfree(newdevice);
 			return(-EPERM);
 		}
-		newdevice->cu_type=probeinfo->cu_type;
-		newdevice->cu_model=probeinfo->cu_model;
-		newdevice->dev_type=probeinfo->dev_type;
-		newdevice->dev_model=probeinfo->dev_model;
 		newdevice->chan_type=probeinfo->chan_type;		
 		newdevice->dev_ptr=dev_ptr;
 		newdevice->port_no=port_no;
+		newdevice->memory_usage_in_k=probeinfo->memory_usage_in_k;
 		newdevice->category=category;
 		newdevice->unreg_dev=unreg_dev;
+		probeinfo->newdevice=newdevice;
 		return(0);
 	}
+	chandev_unlock();
 	return(-ENOMEM);
 }
 
+
+char *chandev_build_device_name(chandev_probeinfo *probeinfo,char *destnamebuff,char *basename,int buildfullname)
+{
+	if (chandev_use_devno_names&&(!probeinfo->device_forced||probeinfo->devif_num==-1)) 
+		sprintf(destnamebuff,"%s%04x",basename,(int)probeinfo->read.devno);
+	else
+	{
+		if(probeinfo->devif_num==-1)
+		{
+			if(buildfullname)
+			{
+				int idx,len=strlen(basename);
+				
+				chandev_activelist *curr_device;
+				for(idx=0;idx<0xffff;idx++)
+				{
+					for_each(curr_device,chandev_activelist_head)
+					{
+						if(strncmp(curr_device->devname,basename,len)==0)
+						{
+							char numbuff[10];
+							sprintf(numbuff,"%d",idx);
+							if(strcmp(&curr_device->devname[len],numbuff)==0)
+								goto next_idx;
+						}
+					}
+					sprintf(destnamebuff,"%s%d",basename,idx);
+					return(destnamebuff);
+				next_idx:
+				}
+				printk("chandev_build_device_name was usable to build a unique name for %s\n",basename);
+				return(NULL);
+			}
+			else
+				sprintf(destnamebuff,"%s%%d",basename);
+		}
+		else
+		{
+			sprintf(destnamebuff,"%s%d",basename,(int)probeinfo->devif_num);
+		}
+	}
+	return(destnamebuff);
+}
+
 #if LINUX_VERSION_CODE>=KERNEL_VERSION(2,3,0)
-struct net_device *chandev_initnetdevice(chandev_probeinfo *probeinfo,u8 port_no,
-struct net_device *dev, int sizeof_priv, char *basename, 
-struct net_device *(*init_netdevfunc)(struct net_device *dev, int sizeof_priv),
-void (*unreg_netdevfunc)(struct net_device *dev))
+struct net_device *chandev_init_netdev(chandev_probeinfo *probeinfo,char *basename,
+struct net_device *dev, int sizeof_priv,
+struct net_device *(*init_netdevfunc)(struct net_device *dev, int sizeof_priv))
 #else
-struct device *chandev_initnetdevice(chandev_probeinfo *probeinfo,u8 port_no,
-struct device *dev, int sizeof_priv, char *basename,
-struct device *(*init_netdevfunc)(struct device *dev, int sizeof_priv),
-void (*unreg_netdevfunc)(struct device *dev))
+struct device *chandev_init_netdev(chandev_probeinfo *probeinfo,char *basename,
+struct device *dev, int sizeof_priv,
+struct device *(*init_netdevfunc)(struct device *dev, int sizeof_priv))
 #endif
 {
 #if LINUX_VERSION_CODE>=KERNEL_VERSION(2,3,0)
 	struct net_device *retdevice=NULL;
-	int new_device = 0;
+	int new_device = FALSE;
 #else
 	struct device *retdevice=NULL;
 #endif
+	
 
+	chandev_interrupt_check();
 	if (!init_netdevfunc) 
 	{
-		printk("init_netdevfunc=NULL in chandev_initnetdevice, it should not be valid.\n");
-		return NULL;
-	}
-	if (!unreg_netdevfunc) 
-	{
-		printk("unreg_netdevfunc=NULL in chandev_initnetdevice, it should not be valid.\n");
+		printk("init_netdevfunc=NULL in chandev_init_netdev, it should not be valid.\n");
 		return NULL;
 	}
-
-	chandev_interrupt_check();
-
 #if LINUX_VERSION_CODE>=KERNEL_VERSION(2,3,0)
-        /* Allocate a device if one is not provided. */
+	/* Allocate a device if one is not provided. */
         if (dev == NULL) 
 	{
 		/* ensure 32-byte alignment of the private area */
@@ -1247,48 +1569,101 @@
 
 		if (sizeof_priv)
 			dev->priv = (void *) (((long)(dev + 1) + 31) & ~31);
-
-		if (probeinfo->devif_num != -1) 
-			sprintf(dev->name,"%s%d",basename,(int)probeinfo->devif_num);
-		else if (use_devno_names) 
-			sprintf(dev->name,"%s0x%04x",basename,(int)probeinfo->read_devno);
-
-		new_device = 1;
+		new_device=TRUE;
 	}
+	chandev_build_device_name(probeinfo,dev->name,basename,FALSE);
 #endif
-
 	retdevice=init_netdevfunc(dev,sizeof_priv);
-
 #if LINUX_VERSION_CODE>=KERNEL_VERSION(2,3,0)
 	/* Register device if necessary */
+	/* we need to do this as init_netdev doesn't call register_netdevice */
+	/* for already allocated devices */
 	if (retdevice && new_device)
 		register_netdev(retdevice);
 #endif
+#if LINUX_VERSION_CODE>=KERNEL_VERSION(2,3,0)
+	/* We allocated it, so we should free it on error */
+	if (!retdevice && new_device) 
+		kfree(dev);
+#endif
+	return retdevice;
+}
+
+
+
+
+#if LINUX_VERSION_CODE>=KERNEL_VERSION(2,3,0)
+struct net_device *chandev_initnetdevice(chandev_probeinfo *probeinfo,u8 port_no,
+struct net_device *dev, int sizeof_priv, char *basename, 
+struct net_device *(*init_netdevfunc)(struct net_device *dev, int sizeof_priv),
+void (*unreg_netdevfunc)(struct net_device *dev))
+#else
+struct device *chandev_initnetdevice(chandev_probeinfo *probeinfo,u8 port_no,
+struct device *dev, int sizeof_priv, char *basename,
+struct device *(*init_netdevfunc)(struct device *dev, int sizeof_priv),
+void (*unreg_netdevfunc)(struct device *dev))
+#endif
+{
+#if LINUX_VERSION_CODE>=KERNEL_VERSION(2,3,0)
+	struct net_device *retdevice=NULL;
+	int new_device=(dev==NULL);
+#else
+	struct device *retdevice=NULL;
+#endif
 
+	if (!unreg_netdevfunc) 
+	{
+		printk("unreg_netdevfunc=NULL in chandev_initnetdevice, it should not be valid.\n");
+		return NULL;
+	}
+	chandev_interrupt_check();
+	retdevice=chandev_init_netdev(probeinfo,basename,dev,sizeof_priv,init_netdevfunc);
 	if (retdevice) 
 	{
 		if (chandev_initdevice(probeinfo,retdevice,port_no,retdevice->name,
-				      network_device,(chandev_unregfunc)unreg_netdevfunc)) 
+				      chandev_category_network_device,(chandev_unregfunc)unreg_netdevfunc)) 
 		{
 			unreg_netdevfunc(retdevice);
+#if LINUX_VERSION_CODE>=KERNEL_VERSION(2,3,0)
+			/* We allocated it, so we should free it on error */
+			if(new_device)
+				kfree(dev);
+#endif
+
 			retdevice = NULL;
 		}
 	}
+	return retdevice;
+}
 
-#if LINUX_VERSION_CODE>=KERNEL_VERSION(2,3,0)
-	/* We allocated it, so we should free it on error */
-	if (!retdevice && new_device) 
-		kfree(dev);
-#endif
 
-	return retdevice;
+int chandev_compare_chpid_info(chandev_subchannel_info *chan1,chandev_subchannel_info *chan2)
+{
+	return (chan1->pim!=chan2->pim || *chan1->chpid!=*chan2->chpid);
 }
 
+int chandev_compare_cu_dev_info(chandev_subchannel_info *chan1,chandev_subchannel_info *chan2)
+{
+	return ((chan1->cu_type != chan2->cu_type)||
+		(chan1->cu_model != chan2->cu_model)||
+		(chan1->dev_type != chan2->dev_type)||
+		(chan1->dev_model != chan2->dev_model));
+}
 
+int chandev_compare_subchannel_info(chandev_subchannel_info *chan1,chandev_subchannel_info *chan2)
+{
+	return((chan1->devno == chan2->devno) &&
+	       (chan1->cu_type == chan2->cu_type) &&
+	       (chan1->cu_model == chan2->cu_model) &&
+	       (chan1->dev_type == chan2->dev_type) &&
+	       (chan1->dev_model == chan2->dev_model) &&
+	       (chan1->pim == chan2->pim) &&
+	       (*chan1->chpid == *chan2->chpid));
+}
 
 
-int chandev_doprobe(chandev_force *force,chandev *read_chandev,
-chandev *write_chandev)
+int chandev_doprobe(chandev_force *force,chandev *read,
+chandev *write,chandev *data)
 {
 	chandev_probelist *probe;
 	chandev_model_info *model_info;
@@ -1296,41 +1671,60 @@
 	int               rc=-1,hint=-1;
 	chandev_activelist *newdevice;
 	chandev_probefunc  probefunc;
-	int                saved_lock_cnt;
 	chandev_parms      *curr_parms;
+	chandev_model_info dummy_model_info;
 
 	memset(&probeinfo,0,sizeof(probeinfo));
-	model_info=read_chandev->model_info;
-	if(read_chandev->model_info!=write_chandev->model_info||
-	   (force&&((force->chan_type&model_info->chan_type)==0))||
-	   (!force&&((read_chandev->cu_type!=write_chandev->cu_type)||
-		    (read_chandev->cu_model!=write_chandev->cu_model)||
-		    (read_chandev->dev_type!=write_chandev->dev_type)||
-		   (read_chandev->dev_model!=write_chandev->dev_model))))
-		return(-1); /* inconsistent */
+	memset(&dummy_model_info,0,sizeof(dummy_model_info));
+	probeinfo.device_forced=(force!=NULL);
+	probeinfo.chpid_info_inconsistent=chandev_compare_chpid_info(&read->sch,&write->sch)||
+		 (data&&chandev_compare_chpid_info(&read->sch,&data->sch));
+	probeinfo.cu_dev_info_inconsistent=chandev_compare_cu_dev_info(&read->sch,&write->sch)||
+		 (data&&chandev_compare_cu_dev_info(&read->sch,&data->sch));
+	if(read->model_info)
+		model_info=read->model_info;
+	else
+	{
+		dummy_model_info.chan_type=chandev_type_none;
+		dummy_model_info.max_port_no=16;
+		model_info=&dummy_model_info;
+	}
 	for_each(probe,chandev_probelist_head)
 	{
-		probeinfo.chan_type=(probe->chan_type&model_info->chan_type);
-		if(probeinfo.chan_type)
+		if(force)
+			probeinfo.chan_type = ( probe->chan_type & force->chan_type );
+		else
+		{
+			if(chandev_cautious_auto_detect)
+				probeinfo.chan_type = ( probe->chan_type == model_info->chan_type ? 
+						       probe->chan_type : chandev_type_none );
+			else
+				probeinfo.chan_type = ( probe->chan_type & model_info->chan_type );
+		}
+		if(probeinfo.chan_type && (force || ( !probeinfo.cu_dev_info_inconsistent &&
+		  ((probe->chan_type&(chandev_type_ctc|chandev_type_escon)) ||
+		   !probeinfo.chpid_info_inconsistent))))
 		{
 #if LINUX_VERSION_CODE>=KERNEL_VERSION(2,3,0)
-			if(use_devno_names)
-				probeinfo.devif_num=read_chandev->devno;
+			if(chandev_use_devno_names)
+				probeinfo.devif_num=read->sch.devno;
 			else
 #endif
 				probeinfo.devif_num=-1;
-			probeinfo.read_irq=read_chandev->irq;
-			probeinfo.write_irq=write_chandev->irq;
-			probeinfo.read_devno=read_chandev->devno;
-			probeinfo.write_devno=write_chandev->devno;
-			probeinfo.max_port_no=model_info->max_port_no;
-			probeinfo.cu_type=read_chandev->cu_type;
-			probeinfo.cu_model=read_chandev->cu_model;
-			probeinfo.dev_type=read_chandev->dev_type;
-			probeinfo.dev_model=read_chandev->dev_model;
+			probeinfo.read=read->sch;
+			probeinfo.write=write->sch;
+			if(data)
+			{
+				probeinfo.data=data->sch;
+				probeinfo.data_exists=TRUE;
+			}
+			probeinfo.max_port_no=(force&&(force->port_protocol_no!=-1) ? 
+			      force->port_protocol_no : model_info->max_port_no);
 			for_each(curr_parms,chandev_parms_head)
 			{
-				if(probe->chan_type==curr_parms->chan_type)
+				if(probe->chan_type==curr_parms->chan_type&&
+				   read->sch.devno>=curr_parms->lo_devno&&
+					read->sch.devno<=curr_parms->hi_devno)
 				{
 					probeinfo.parmstr=curr_parms->parmstr;
 					break;
@@ -1338,25 +1732,26 @@
 			}
 			if(force)
 			{
+				if(force->chan_type==chandev_type_claw)
+					memcpy(&probeinfo.claw,&force->claw,sizeof(chandev_claw_info));
 				probeinfo.port_protocol_no=force->port_protocol_no;
-				if(force->devif_num!=-1)
+				if(force->devif_num==-1&&force->devif_num==-2)
+					probeinfo.devif_num=-1;
+				else
 					probeinfo.devif_num=force->devif_num;
+				probeinfo.memory_usage_in_k=force->memory_usage_in_k;
 				probeinfo.checksum_received_ip_pkts=force->checksum_received_ip_pkts;
 				probeinfo.use_hw_stats=force->use_hw_stats;
-				
 			}
 			else
 			{
-				probeinfo.port_protocol_no=-1;
-				probeinfo.checksum_received_ip_pkts=FALSE;
-				probeinfo.use_hw_stats=FALSE;
-				if(probe->chan_type&lcs)
-				{
-					if((probeinfo.read_devno&1)||
-					   ((probeinfo.read_devno|1)!=
-					    (probeinfo.write_devno)))
-						return(-1);
-					hint=(read_chandev->devno&0xFF)>>1;
+				probeinfo.port_protocol_no=0;
+				probeinfo.checksum_received_ip_pkts=model_info->default_checksum_received_ip_pkts;
+				probeinfo.use_hw_stats=model_info->default_use_hw_stats;
+				probeinfo.memory_usage_in_k=0;
+				if(probe->chan_type&chandev_type_lcs)
+				{
+					hint=(read->sch.devno&0xFF)>>1;
 					if(hint>model_info->max_port_no)
 					{
 				/* The card is possibly emulated e.g P/390 */
@@ -1368,12 +1763,7 @@
 			}
 			probeinfo.hint_port_no=hint;
 			probefunc=probe->probefunc;
-			saved_lock_cnt=chandev_full_unlock();
-			/* We have to leave the lock go here */
-			/* as probefunctions can call schedule & */
-                        /* reenter to do a kernel thread & we may deadlock */
 			rc=probefunc(&probeinfo);
-			chandev_relock(saved_lock_cnt);
 			if(rc==0)
 			{
 				newdevice=probeinfo.newdevice;
@@ -1381,47 +1771,174 @@
 				{
 					newdevice->probefunc=probe->probefunc;
 					newdevice->shutdownfunc=probe->shutdownfunc;
-					newdevice->reoperfunc=probe->reoperfunc;
+					newdevice->msck_notfunc=probe->msck_notfunc;
 					probe->devices_found++;
 					chandev_add_to_list((list **)&chandev_activelist_head,
 							    newdevice);
-					chandev_add_to_startmsck_list(&startlist_head,
-								      newdevice->devname,good,good);
-					
+					chandev_add_to_userland_notify_list(chandev_start,
+								      newdevice->devname,chandev_status_good,chandev_status_good);
 				}
 				else
 				{
-					printk("chandev_initdevice either failed or wasn't called for device read_irq=0x%04x\n",probeinfo.read_irq);
+					printk("chandev_initdevice either failed or wasn't called for device read_irq=0x%04x\n",probeinfo.read.irq);
 				}
 				break;
+				
 			}
 		}
 	}
+	chandev_remove(read);
+	chandev_remove(write);
+	if(data)
+		chandev_remove(data);
 	return(rc);
 }
 
 
 int chandev_request_irq_from_irqinfo(chandev_irqinfo *irqinfo,chandev *this_chandev)
 {
-	int retval=s390_request_irq_special(irqinfo->irq,
+	int retval=s390_request_irq_special(irqinfo->sch.irq,
 				   irqinfo->handler,
 				   chandev_not_oper_handler,
 				   irqinfo->irqflags,
 				   irqinfo->devname,
 				   irqinfo->dev_id);
 	if(retval==0)
+	{
+		irqinfo->msck_status=chandev_status_good;
 		this_chandev->owned=TRUE;
+	}
 	return(retval);
 }
 
 void chandev_irqallocerr(chandev_irqinfo *irqinfo,int err)
 {
-	printk("chandev_probe failed to realloc irq=%d for %s err=%d\n",irqinfo->irq,irqinfo->devname,err);
+	printk("chandev_probe failed to realloc irq=%d for %s err=%d\n",irqinfo->sch.irq,irqinfo->devname,err);
+}
+
+
+void chandev_call_notification_func(chandev_activelist *curr_device,chandev_irqinfo *curr_irqinfo,
+chandev_msck_status prevstatus)
+{
+	if(curr_irqinfo->msck_status!=prevstatus)
+	{
+		chandev_msck_status new_msck_status=curr_irqinfo->msck_status;
+		if(curr_irqinfo->msck_status==chandev_status_good)
+		{
+			if(curr_device->read_irqinfo->msck_status==chandev_status_good&&
+			   curr_device->write_irqinfo->msck_status==chandev_status_good)
+			{
+				if(curr_device->data_irqinfo)
+				{
+					if(curr_device->data_irqinfo->msck_status==chandev_status_good)
+						new_msck_status=chandev_status_all_chans_good;
+				}
+				else
+					new_msck_status=chandev_status_all_chans_good;
+			}
+		}
+		if(curr_device->msck_notfunc)
+		{
+			curr_device->msck_notfunc(curr_device->dev_ptr,
+					      curr_irqinfo->sch.irq,
+					      prevstatus,new_msck_status);
+		}
+		if(new_msck_status!=chandev_status_good)
+		{
+			/* No point in sending a machine check if only one channel is good */
+			chandev_add_to_userland_notify_list(chandev_msck,curr_device->devname,
+						      prevstatus,curr_irqinfo->msck_status);
+		}
+	}
+}
+
+int chandev_find_eligible_channels(chandev *first_chandev_to_check,
+			       chandev **read,chandev **write,chandev **data,chandev **next,
+				   chandev_type chan_type)
+{
+	chandev *curr_chandev;
+	int eligible_found=FALSE,changed;
+	
+	*next=first_chandev_to_check->next;
+	*read=*write=*data=NULL;
+	for_each(curr_chandev,first_chandev_to_check)
+		if((curr_chandev->sch.devno&1)==0&&curr_chandev->model_info->chan_type!=chandev_type_claw)
+		{
+			*read=curr_chandev;
+			if(chan_type==chandev_type_none)
+				chan_type=(*read)->model_info->chan_type;
+			break;
+		}
+	if(*read)
+	{
+		for_each(curr_chandev,(chandev *)chandev_head.head)
+			if((((*read)->sch.devno|1)==curr_chandev->sch.devno)&&
+			   (chandev_compare_cu_dev_info(&(*read)->sch,&curr_chandev->sch)==0)&&
+			   ((chan_type&(chandev_type_ctc|chandev_type_escon))||
+			    chandev_compare_chpid_info(&(*read)->sch,&curr_chandev->sch)==0))
+			{
+				*write=curr_chandev;
+				break;
+			}
+	}
+	if((chan_type&chandev_type_qeth))
+	{
+		if(*write)
+		{
+			for_each(curr_chandev,(chandev *)chandev_head.head)
+				if((curr_chandev!=*read&&curr_chandev!=*write)&&
+				   (chandev_compare_cu_dev_info(&(*read)->sch,&curr_chandev->sch)==0)&&
+				   (chandev_compare_chpid_info(&(*read)->sch,&curr_chandev->sch)==0))
+				{
+					*data=curr_chandev;
+					break;
+				}
+			if(*data)
+				eligible_found=TRUE;
+		}
+		
+	}
+	else
+		if(*write)
+			eligible_found=TRUE;
+	if(eligible_found)
+	{
+		do
+		{
+			changed=FALSE;
+			if(*next&&
+			   ((*read&&(*read==*next))||
+			   (*write&&(*write==*next))||
+			   (*data&&(*data==*next))))
+			{
+				*next=(*next)->next;
+				changed=TRUE;
+			}
+		}while(changed==TRUE);
+	}
+	return(eligible_found);
+}
+
+chandev *chandev_get_free_chandev_by_devno(int devno)
+{
+	chandev *curr_chandev;
+	if(devno==-1)
+		return(NULL);
+	for_each(curr_chandev,(chandev *)chandev_head.head)
+		if(curr_chandev->sch.devno==devno)
+		{
+			if(chandev_active(devno))
+				return(NULL);
+			else
+				return(curr_chandev);
+		}
+	return(NULL);
+
 }
 
 void chandev_probe(void)
 {
-	chandev *read_chandev,*write_chandev,*curr_chandev;
+	chandev *read_chandev,*write_chandev,*data_chandev,*curr_chandev,*next_chandev;
 	chandev_force *curr_force;
 	chandev_noauto_range *curr_noauto;
 	chandev_activelist *curr_device;
@@ -1434,16 +1951,17 @@
 
 
 	chandev_interrupt_check();
+	chandev_read_conf_if_necessary();
 	chandev_collect_devices();
 	chandev_lock();
 	for_each(curr_irqinfo,chandev_irqinfo_head)
 	{
-		if((curr_device=chandev_get_activelist_by_irq(curr_irqinfo->irq)))
+		if((curr_device=chandev_get_activelist_by_irq(curr_irqinfo->sch.irq)))
 		{
 			prevstatus=curr_irqinfo->msck_status;
-			if(curr_irqinfo->msck_status!=good)
+			if(curr_irqinfo->msck_status!=chandev_status_good)
 			{
-				curr_chandev=chandev_get_by_irq(curr_irqinfo->irq);
+				curr_chandev=chandev_get_by_irq(curr_irqinfo->sch.irq);
 				if(curr_chandev)
 				{
 					auto_msck_recovery=curr_chandev->model_info->
@@ -1454,9 +1972,9 @@
 				for_each(curr_msck_range,chandev_msck_range_head)
 				{
 					if(curr_msck_range->lo_devno<=
-					   curr_irqinfo->devno&&
+					   curr_irqinfo->sch.devno&&
 					   curr_msck_range->hi_devno>=
-					   curr_irqinfo->devno)
+					   curr_irqinfo->sch.devno)
 					{
 						auto_msck_recovery=
 							curr_msck_range->
@@ -1466,28 +1984,32 @@
 				}
 				if((1<<(curr_irqinfo->msck_status-1))&auto_msck_recovery)
 				{
-					if(curr_irqinfo->msck_status==revalidate)
+					if(curr_irqinfo->msck_status==chandev_status_revalidate)
 					{
-						if((get_dev_info_by_irq(curr_irqinfo->irq,&curr_devinfo)==0))
+						if((get_dev_info_by_irq(curr_irqinfo->sch.irq,&curr_devinfo)==0))
 						{
-							curr_irqinfo->devno=curr_devinfo.devno;
-							curr_irqinfo->msck_status=good;
-							goto remove;
+							curr_irqinfo->sch.devno=curr_devinfo.devno;
+							curr_irqinfo->msck_status=chandev_status_good;
 						}
 					}
 					else
 					{
-						if((curr_chandev=chandev_get_by_irq(curr_irqinfo->irq)))
+						if(curr_chandev)
 						{
 							/* Has the device reappeared */
-							if(curr_chandev->cu_type==curr_device->cu_type&&
-							   curr_chandev->cu_model==curr_device->cu_model&&
-							   curr_chandev->dev_type==curr_device->dev_type&&
-							   curr_chandev->dev_model==curr_device->dev_model&&
-							   curr_chandev->devno==curr_irqinfo->devno)
+							if(chandev_compare_subchannel_info(
+								&curr_chandev->sch,
+								&curr_device->read_irqinfo->sch)||
+							   chandev_compare_subchannel_info(
+								&curr_chandev->sch,
+								&curr_device->write_irqinfo->sch)||
+							   (curr_device->data_irqinfo&&
+							    chandev_compare_subchannel_info(
+								    &curr_chandev->sch,
+								    &curr_device->data_irqinfo->sch)))
 							{
 								if((err=chandev_request_irq_from_irqinfo(curr_irqinfo,curr_chandev))==0)
-									curr_irqinfo->msck_status=good;
+									curr_irqinfo->msck_status=chandev_status_good;
 								else
 									chandev_irqallocerr(curr_irqinfo,err);
 							}
@@ -1496,86 +2018,89 @@
 					}
 				}
 			}
-			if(curr_irqinfo->msck_status==good&&prevstatus!=good)
-			{
-				if(curr_device->reoperfunc)
-				{
-					int saved_lock_cnt=chandev_full_unlock();
-					curr_device->reoperfunc(curr_device->dev_ptr,
-								(curr_device->read_irqinfo==curr_irqinfo),
-								prevstatus);
-					chandev_relock(saved_lock_cnt);
-				}
-				if(curr_device->category==network_device&&
-				   curr_device->write_irqinfo==curr_irqinfo)
-				{
-					net_device *dev=(net_device *)curr_device->dev_ptr;
-					if(dev->flags&IFF_UP)
-						netif_start_queue(dev);
-				}
-				chandev_add_to_startmsck_list(&mscklist_head,curr_device->devname,
-							      prevstatus,curr_irqinfo->msck_status);
-			}
+			chandev_call_notification_func(curr_device,curr_irqinfo,prevstatus);
 		}
 		/* This is required because the device can go & come back */
                 /* even before we realize it is gone owing to the waits in our kernel threads */
 		/* & the device will be marked as not owned but its status will be good */
                 /* & an attempt to accidently reprobe it may be done. */ 
 		remove:
-		chandev_remove(chandev_get_by_irq(curr_irqinfo->irq));
+		chandev_remove(chandev_get_by_irq(curr_irqinfo->sch.irq));
 		
 	}
 	/* extra sanity */
-	for_each(curr_chandev,(chandev *)chandev_head.head)
+	for_each_allow_delete(curr_chandev,next_chandev,(chandev *)chandev_head.head)
 		if(curr_chandev->owned)
 			chandev_remove(curr_chandev);
 	for_each(curr_force,chandev_force_head)
 	{
-		for_each(read_chandev,(chandev *)chandev_head.head)
-			if(read_chandev->devno==curr_force->read_devno&&
-				!chandev_active(curr_force->read_devno))
-			{
-				for_each(write_chandev,(chandev *)chandev_head.head)
-					if(write_chandev->devno==
-					   curr_force->write_devno&&
-					   !chandev_active(curr_force->write_devno))
+		if(curr_force->devif_num==-2)
+		{
+			for_each_allow_delete2(curr_chandev,next_chandev,(chandev *)chandev_head.head)
+			{
+				if(chandev_find_eligible_channels(curr_chandev,&read_chandev,
+								  &write_chandev,&data_chandev,
+								  &next_chandev,
+								  curr_force->chan_type));
+				{
+					if((curr_force->read_lo_devno>=read_chandev->sch.devno)&&
+					   (curr_force->write_hi_devno<=read_chandev->sch.devno)&&
+					   (curr_force->read_lo_devno>=write_chandev->sch.devno)&&
+					   (curr_force->write_hi_devno<=write_chandev->sch.devno)&&
+					   (!data_chandev||(data_chandev&&
+					   (curr_force->read_lo_devno>=data_chandev->sch.devno)&&
+					   (curr_force->write_hi_devno<=data_chandev->sch.devno))))
+						chandev_doprobe(curr_force,read_chandev,write_chandev,
+								data_chandev);
+				}
+			}
+		}
+		else
+		{
+			read_chandev=chandev_get_free_chandev_by_devno(curr_force->read_lo_devno);
+			if(read_chandev)
+			{
+				write_chandev=chandev_get_free_chandev_by_devno(curr_force->write_hi_devno);
+				if(write_chandev)
+				{
+					if(curr_force->chan_type==chandev_type_qeth)
 					{
-						if(chandev_doprobe(curr_force,
-								read_chandev,
-								write_chandev)==0)
-						{
-							chandev_remove(read_chandev);
-							chandev_remove(write_chandev);
-							goto chandev_probe_skip;
-						}
+
+						data_chandev=chandev_get_free_chandev_by_devno(curr_force->data_devno);
+						if(data_chandev==NULL)
+							printk("chandev_probe unable to force gigabit_ethernet driver invalid device  no 0x%04x given\n",curr_force->data_devno);
 					}
+					else
+						data_chandev=NULL;
+					chandev_doprobe(curr_force,read_chandev,write_chandev,
+							data_chandev);
+				}
 			}
-	chandev_probe_skip:
+		}
 	}
-	for_each(curr_chandev,(chandev *)chandev_head.head)
+	for_each_allow_delete(curr_chandev,next_chandev,(chandev *)chandev_head.head)
 	{
 		for_each(curr_noauto,chandev_noauto_head)
 		{
-			if(curr_chandev->devno>=curr_noauto->lo_devno&&
-			   curr_chandev->devno<=curr_noauto->hi_devno)
+			if(curr_chandev->sch.devno>=curr_noauto->lo_devno&&
+			   curr_chandev->sch.devno<=curr_noauto->hi_devno)
 			{
 				chandev_remove(curr_chandev);
 				break;
 			}
 		}
 	}
-	for_each(curr_chandev,(chandev *)chandev_head.head)
+	for_each_allow_delete2(curr_chandev,next_chandev,(chandev *)chandev_head.head)
 	{
-		if(curr_chandev->next&&curr_chandev->model_info==
-		   curr_chandev->next->model_info)
-		{
-			
-			chandev_doprobe(NULL,curr_chandev,curr_chandev->next);
-			curr_chandev=curr_chandev->next;
-		}
+		if(chandev_find_eligible_channels(curr_chandev,&read_chandev,
+						  &write_chandev,&data_chandev,
+						  &next_chandev,
+						  chandev_type_none))
+			chandev_doprobe(NULL,read_chandev,write_chandev,
+					data_chandev);
 	}
-	chandev_unlock();
 	chandev_remove_all();
+	chandev_unlock();
 }
 
 static void chandev_not_oper_func(int irq,int status)
@@ -1585,49 +2110,40 @@
 	
 	chandev_lock();
 	for_each(curr_irqinfo,chandev_irqinfo_head)
-		if(curr_irqinfo->irq==irq)
+		if(curr_irqinfo->sch.irq==irq)
 		{
+			chandev_msck_status prevstatus=curr_irqinfo->msck_status;
 			switch(status)
 			{
 				/* Currently defined but not used in kernel */
 				/* Despite being in specs */
 			case DEVSTAT_NOT_OPER:
-				curr_irqinfo->msck_status=not_oper;
+				curr_irqinfo->msck_status=chandev_status_not_oper;
 				break;
 #ifdef DEVSTAT_NO_PATH
 				/* Kernel hasn't this defined currently. */
 				/* Despite being in specs */
 			case DEVSTAT_NO_PATH:
-				curr_irqinfo->msck_status=no_path;
+				curr_irqinfo->msck_status=chandev_status_no_path;
 				break;
 #endif
 			case DEVSTAT_REVALIDATE:
-				curr_irqinfo->msck_status=revalidate;
+				curr_irqinfo->msck_status=chandev_status_revalidate;
 				break;
 			case DEVSTAT_DEVICE_GONE:
-				curr_irqinfo->msck_status=gone;
-				break;
-			}
-			for_each(curr_device,chandev_activelist_head)
-			{
-				if(curr_device->write_irqinfo==curr_irqinfo)
-				{
-					if(curr_device->category==network_device)
-					{
-						net_device *dev=(net_device *)curr_device->dev_ptr;
-						if(dev->flags&IFF_UP)
-							netif_stop_queue(dev);
-					}
-				}
+				curr_irqinfo->msck_status=chandev_status_gone;
 				break;
-			}
-			break;
+                        }
+                        if((curr_device=chandev_get_activelist_by_irq(irq)))
+					chandev_call_notification_func(curr_device,curr_irqinfo,prevstatus);
+ 			else
+				printk("chandev_not_oper_func received channel check for unowned irq %d",irq);
 		}
 	chandev_unlock();
 }
 
 
-static void chandev_msck_task(void *unused)
+static int chandev_msck_thread(void *unused)
 {
 	int loopcnt,not_oper_probe_required=FALSE;
 	wait_queue_head_t    wait;
@@ -1663,9 +2179,17 @@
 	}
 	if(not_oper_probe_required)
 		chandev_probe();
+	return(0);
 }
 
-
+static void chandev_msck_task(void *unused)
+{
+	if(kernel_thread(chandev_msck_thread,NULL,SIGCHLD)<0)
+	{
+		atomic_set(&chandev_msck_thread_lock,1);
+		printk("error making chandev_msck_thread kernel thread\n");
+	}
+}
 
 
 
@@ -1686,6 +2210,8 @@
 	"use_devno_names",
 	"dont_use_devno_names",
 #endif
+	"cautious_auto_detect",
+	"non_cautious_auto_detect",
 	"add_model",
 	"del_model",
 	"auto_msck",
@@ -1696,8 +2222,10 @@
 	"shutdown",
 	"reprobe",
 	"unregister_probe",
+	"unregister_probe_by_chan_type",
 	"read_conf",
 	"dont_read_conf",
+	"persistent"
 };
 
 typedef enum
@@ -1719,6 +2247,8 @@
 	use_devno_names_stridx,
 	dont_use_devno_names_stridx,
 #endif
+	cautious_auto_detect_stridx,
+	non_cautious_auto_detect_stridx,
 	add_model_stridx,
 	del_model_stridx,
 	auto_msck_stridx,
@@ -1729,8 +2259,10 @@
 	shutdown_stridx,
 	reprobe_stridx,
 	unregister_probe_stridx,
+	unregister_probe_by_chan_type_stridx,
 	read_conf_stridx,
 	dont_read_conf_stridx,
+	persistent_stridx,
 	last_stridx,
 } chandev_str_enum;
 
@@ -1799,16 +2331,18 @@
     return 1;
 }
 
+
 static char *chandev_get_options(char *str, int nints, chandev_int *ints)
 {
 	int res,i=1;
 
-    while (i<nints) {
-        res = chandev_get_option(&str, ints+i);
-        if (res==0) break;
-        i++;
-        if (res==1) break;
-    }
+	while (i<nints) 
+	{
+		res = chandev_get_option(&str, ints+i);
+		if (res==0) break;
+		i++;
+		if (res==1) break;
+	}
 	ints[0] = i-1;
 	return(str);
 }
@@ -1816,6 +2350,43 @@
 #define chandev_get_option get_option
 #define chandev_get_options get_options
 #endif
+/*
+ * Read an string from an option string; if available accept a subsequent
+ * comma as well & set this comma to a null character when returning the string.
+ *
+ * Return values:
+ * 0 : no string found
+ * 1 : string found, no subsequent comma
+ * 2 : string found including a subsequent comma
+ */
+static int chandev_get_string(char **instr,char **outstr)
+{
+	char *cur = *instr;
+
+	if (!cur ||*cur==0)
+	{
+		*outstr=NULL;
+		return 0;
+	}
+	*outstr=*instr;
+	for(;;)
+	{
+		if(*(++cur)==',')
+		{
+			*cur=0;
+			*instr=cur+1;
+			return 2;
+		}
+		else if(*cur==0)
+		{
+			*instr=cur+1;
+			return 1;
+		}
+	}
+}
+
+
+
 
 static int chandev_setup(char *instr,char *errstr,int lineno)
 {
@@ -1826,15 +2397,15 @@
 	char             *str,*currstr,*interpretstr=NULL;
 	int              cnt,strcnt;
 	int              retval=0;
-#define CHANDEV_MAX_EXTRA_INTS 8
+#define CHANDEV_MAX_EXTRA_INTS 12
 	chandev_int ints[CHANDEV_MAX_EXTRA_INTS+1];
-	memset(ints,0,sizeof(ints));
 	currstr=alloca(strlen(instr)+1);
 	strcpy(currstr,instr);
 	strcnt=chandev_pack_args(currstr);
 	for(cnt=1;cnt<=strcnt;cnt++)
 	{
 		interpretstr=currstr;
+		memset(ints,0,sizeof(ints));
 		for(stridx=first_stridx;stridx<last_stridx;stridx++)
 		{
 			str=currstr;
@@ -1844,29 +2415,36 @@
 		currstr=str;
 		if(val)
 		{
-			if(val&iscomma)
+			val=(((chandev_strval)stridx)*stridx_mult)+(val&~isstr);
+			switch(val)
 			{
-				if(stridx==add_parms_stridx&&(val==(isstr|iscomma)))
+			case (add_parms_stridx*stridx_mult)|iscomma:
+				currstr=chandev_get_options(currstr,4,ints);
+				if(*currstr&&ints[0]>=1)
 				{
-					str=currstr;
-					if(chandev_get_option(&str,&ints[0])==2)
+					if(ints[0]==1)
 					{
-						chandev_add_parms(ints[0],str);
-						currstr=str+strlen(str)+1;
-						continue;
+						ints[2]=0;
+						ints[3]=0xffff;
 					}
-					else
-						goto BadArgs;
+					else if(ints[0]==2)
+						ints[3]=ints[2];
+					chandev_add_parms(ints[1],ints[2],ints[3],currstr);
+//					currstr=currstr+strlen(currstr)+1;
+					continue;
 				}
 				else
-					currstr=chandev_get_options(str,CHANDEV_MAX_EXTRA_INTS,ints)+1;
-			}
-			else
-			{
-				ints[0]=0;
-				currstr++;
+					goto BadArgs;
+				break;
+			case (claw_stridx*stridx_mult)|isnum|iscomma:
+			case (claw_stridx*stridx_mult)|iscomma:
+				currstr=chandev_get_options(str,6,ints);
+				break;
+			default:
+				if(val&iscomma)
+					currstr=chandev_get_options(str,CHANDEV_MAX_EXTRA_INTS,ints);
+				break;
 			}
-			val=(((chandev_strval)stridx)*stridx_mult)+(val&~isstr);
 			switch(val)
 			{
 			case noauto_stridx*stridx_mult:
@@ -1924,59 +2502,105 @@
 				else
 					goto BadArgs;
 				break;
+			case (qeth_stridx*stridx_mult)|isnum|iscomma:
+				if(ints[0]<3||ints[0]>7)
+					goto BadArgs;
+				chandev_add_force(chandev_type_qeth,endlong,ints[1],ints[2],
+						  ints[3],ints[4],ints[5],ints[6],ints[7],
+						  NULL,NULL,NULL);
+				break;
 			case (ctc_stridx*stridx_mult)|isnum|iscomma:
 			case (escon_stridx*stridx_mult)|isnum|iscomma:
 			case (lcs_stridx*stridx_mult)|isnum|iscomma:
 			case (osad_stridx*stridx_mult)|isnum|iscomma:
-			case (qeth_stridx*stridx_mult)|isnum|iscomma:
-			case (claw_stridx*stridx_mult)|isnum|iscomma:
-				switch(val)
+			case (ctc_stridx*stridx_mult)|iscomma:
+			case (escon_stridx*stridx_mult)|iscomma:
+			case (lcs_stridx*stridx_mult)|iscomma:
+			case (osad_stridx*stridx_mult)|iscomma:
+				switch(val&~(isnum|iscomma))
 				{
-				case (ctc_stridx*stridx_mult)|isnum|iscomma:
-					chan_type=ctc;
-					break;
-				case (escon_stridx*stridx_mult)|isnum|iscomma:
-					chan_type=escon;
+				case (ctc_stridx*stridx_mult):
+					chan_type=chandev_type_ctc;
 					break;
-				case (lcs_stridx*stridx_mult)|isnum|iscomma:
-					chan_type=lcs;
+				case (escon_stridx*stridx_mult):
+					chan_type=chandev_type_escon;
 					break;
-				case (osad_stridx*stridx_mult)|isnum|iscomma:
-					chan_type=osad;
+				case (lcs_stridx*stridx_mult):
+					chan_type=chandev_type_lcs;
 					break;
-				case (qeth_stridx*stridx_mult)|isnum|iscomma:
-					chan_type=qeth;
+				case (osad_stridx*stridx_mult):
+					chan_type=chandev_type_osad;
 					break;
-				case (claw_stridx*stridx_mult)|isnum|iscomma:
-					chan_type=claw;
+				case (qeth_stridx*stridx_mult):
+					chan_type=chandev_type_qeth;
 					break;
 				default:
 					goto BadArgs;
 				}
+				if((val&isnum)==0)
+					endlong=-2;
+				if(ints[0]<2||ints[0]>6)
+					goto BadArgs;
 				chandev_add_force(chan_type,endlong,ints[1],ints[2],
-						  ints[3],ints[4],ints[5]);
+						  0,ints[3],ints[4],ints[5],ints[6],
+						  NULL,NULL,NULL);
+				break;
+			case (claw_stridx*stridx_mult)|isnum|iscomma:
+			case (claw_stridx*stridx_mult)|iscomma:
+				if(ints[0]>=2&&ints[0]<=5)
+				{
+					char    *host_name,*adapter_name,*api_type;
+					char    *clawstr=alloca(strlen(currstr)+1);
+					
+					strcpy(clawstr,currstr);
+					if(!(chandev_get_string(&clawstr,&host_name)==2&&
+					     chandev_get_string(&clawstr,&adapter_name)==2&&
+					     chandev_get_string(&clawstr,&api_type)==1&&
+					     chandev_add_force(chandev_type_claw,
+							       endlong,ints[1],ints[2],0,
+							       ints[3],0,ints[4],ints[5],
+							       host_name,adapter_name,api_type)==0))
+						goto BadArgs;
+						
+				}
+				else
+					goto BadArgs;
 				break;
 			case (del_parms_stridx*stridx_mult):
 				ints[1]=-1;
 			case (del_parms_stridx*stridx_mult)|iscomma:
-				if(ints[0]==1)
+				if(ints[0]==0)
+					ints[1]=-1;
+				if(ints[0]<=1)
 					ints[2]=FALSE;
-				if(ints[0]>2)
+				if(ints[0]<=2)
+					ints[3]=-1;
+				if(ints[0]>3)
 					goto BadArgs;
-				chandev_remove_parms(ints[1],ints[2]);
+				chandev_remove_parms(ints[1],ints[2],ints[3]);
 				break;
 			case (del_force_stridx*stridx_mult)|iscomma:
 				if(ints[0]!=1)
 					goto BadArgs;
 				chandev_del_force(ints[1]);
 				break;
+			case (del_force_stridx*stridx_mult):
+				chandev_del_force(-1);
+				break;
 #if LINUX_VERSION_CODE>=KERNEL_VERSION(2,3,0)
 			case (use_devno_names_stridx*stridx_mult):
-				use_devno_names=1;
+				chandev_use_devno_names=TRUE;
 				break;
 			case (dont_use_devno_names_stridx*stridx_mult):
-				use_devno_names=0;
+				chandev_use_devno_names=FALSE;
+				break;
 #endif
+			case (cautious_auto_detect_stridx*stridx_mult):
+				chandev_cautious_auto_detect=TRUE;
+				break;
+			case (non_cautious_auto_detect_stridx*stridx_mult):
+				chandev_cautious_auto_detect=FALSE;
+				break;
 			case (add_model_stridx*stridx_mult)|iscomma:
 				if(ints[0]<3)
 					goto BadArgs;
@@ -1988,9 +2612,13 @@
 					ints[6]=-1;
 				if(ints[0]<=6)
 					ints[7]=default_msck_bits;
+				if(ints[0]<=7)
+					ints[8]=FALSE;
+				if(ints[0]<=8)
+					ints[9]=FALSE;
 				ints[0]=7;
 				chandev_add_model(ints[1],ints[2],ints[3],
-						  ints[4],ints[5],ints[6],ints[7]);
+						  ints[4],ints[5],ints[6],ints[7],ints[8],ints[9]);
 				break;
 			case (del_model_stridx*stridx_mult)|iscomma:
 				if(ints[0]<2||ints[0]>4)
@@ -2042,41 +2670,53 @@
 					goto BadArgs;
 				chandev_unregister_probe((chandev_probefunc)ints[1]);
 				break;
+			case (unregister_probe_by_chan_type_stridx*stridx_mult)|iscomma:
+				if(ints[0]!=1)
+					goto BadArgs;
+				chandev_unregister_probe_by_chan_type((chandev_type)ints[1]);
+				break;
 			case read_conf_stridx*stridx_mult:
 				chandev_read_conf();
 				break;
 			case dont_read_conf_stridx*stridx_mult:
-				chandev_conf_read=TRUE;
+				atomic_set(&chandev_conf_read,TRUE);
+				break;
+			case (persistent_stridx*stridx_mult)|iscomma:
+				if(ints[0]==1)
+					chandev_persistent=ints[1];
+				else
+					goto BadArgs;
 				break;
 			default:
 				goto BadArgs;
-			}		
+			}
 		}
 		else
 			goto BadArgs;
+		if(cnt<strcnt)
+		{
+			/* eat up stuff till next string */
+			while(*(currstr++));
+		}
 	}
 	retval=1;
  BadArgs:
 	if(!retval)
 	{
-		printk("chandev_setup bad argument %s",instr);
+		printk("chandev_setup %s %s",(val==0 ? "unknown verb":"bad argument"),instr);
 		if(errstr)
 		{
 			printk("%s %d interpreted as %s",errstr,lineno,interpretstr);
 			if(strcnt>1)
-				printk(" before semicolon no %d",cnt);
+			{
+				if(cnt==strcnt)
+					printk(" after the last semicolon\n");
+				else
+					printk(" before semicolon no %d",cnt);
+			}
 		}
 		printk(".\n Type man chandev for more info.\n\n");
 	}
-	eieio();
-	if(chandev_lock_owner==(long)current)
-	{
-		printk("chandev_setup bug chandev_lock_cnt=%d lock_owner=%lx\n"
-                       "firstlock_retaddr=%p last_lock_returnaddr=%p\n",
-		       chandev_lock_cnt,chandev_lock_owner,chandev_firstlock_addr,
-		       chandev_lastlock_addr);
-		chandev_full_unlock();
-        }
 	return(retval);
 }
 #define CHANDEV_KEYWORD "chandev="
@@ -2166,9 +2806,15 @@
 	char        *buff;
 	int         curr,left,len,fd;
 
+	/* if called from chandev_register_and_probe & 
+	   the driver is compiled into the kernel the
+	   parameters will need to be passed in from
+	   the kernel boot parameter line as the root
+	   fs is not mounted yet, we can't wait here.
+	*/
 	if(in_interrupt()||current->fs->root==NULL)
 		return;
-	chandev_conf_read=TRUE;
+	atomic_set(&chandev_conf_read,TRUE);
 	set_fs(KERNEL_DS);
 	if(stat(CHANDEV_FILE,&statbuf)==0)
 	{
@@ -2198,7 +2844,9 @@
 
 static void chandev_read_conf_if_necessary(void)
 {
-	if(!chandev_conf_read)
+	if(in_interrupt()||current->fs->root==NULL)
+		return;
+	if(!atomic_compare_and_swap(FALSE,TRUE,&chandev_conf_read))
 		chandev_read_conf();
 }
 
@@ -2218,7 +2866,7 @@
 	chandev_msck_status idx;
 	int first_time=TRUE;
 	buff[0]=0;
-	for(idx=first_msck;idx<last_msck;idx++)
+	for(idx=chandev_status_first_msck;idx<chandev_status_last_msck;idx++)
 	{
 		if((1<<(idx-1))&auto_msck_recovery)
 		{
@@ -2243,34 +2891,39 @@
 	chandev_msck_range *curr_msck_range;
 	s390_dev_info_t   curr_devinfo;
 	int pass,chandevs_detected,curr_irq,loopcnt;
-	chandev_irqinfo *read_irqinfo,*write_irqinfo;
-	char buff[40],buff2[80];    
+	chandev_irqinfo *read_irqinfo,*write_irqinfo,*data_irqinfo;
+	char buff[3][80];    
 
 	chandev_lock();
-	chandev_read_conf_if_necessary();
 	chandev_printf(chan_exit,"\n%s\n"
 		       "*'s for cu/dev type/models indicate don't cares\n",chandev_keydescript);
+	chandev_printf(chan_exit,"\ncautious_auto_detect: %s\n",chandev_cautious_auto_detect ? "on":"off");
+	chandev_printf(chan_exit,"\nchandev_persistent = 0x%02x\n",chandev_persistent);
 #if LINUX_VERSION_CODE>=KERNEL_VERSION(2,3,0)
-	chandev_printf(chan_exit,"\nuse_devno_names: %s\n\n",use_devno_names ? "on":"off");
+	chandev_printf(chan_exit,"\nuse_devno_names: %s\n\n",chandev_use_devno_names ? "on":"off");
 #endif
+	
 	if(chandev_models_head)
 	{
 		chandev_printf(chan_exit,"Channels enabled for detection\n");      
-		chandev_printf(chan_exit,"  chan     cu      cu     dev   dev    max     auto recovery\n");
-		chandev_printf(chan_exit,"  type    type    model  type  model  port_no.      type    \n");
-		chandev_printf(chan_exit,"============================================================\n");
+		chandev_printf(chan_exit,"  chan     cu      cu     dev   dev    max     checksum  use hw  auto recovery\n");
+		chandev_printf(chan_exit,"  type    type    model  type  model  port_no. received   stats      type\n");
+		chandev_printf(chan_exit,"==============================================================================\n");
 		for_each(curr_model,chandev_models_head)
 		{
 			
 			
-			chandev_sprint_devinfo(buff,curr_model->cu_type,
+			chandev_sprint_devinfo(buff[0],curr_model->cu_type,
 					       curr_model->cu_model,
 					       curr_model->dev_type,
 					       curr_model->dev_model);
-			sprintf_msck(buff2,curr_model->auto_msck_recovery);
-			chandev_printf(chan_exit,"  0x%02x  %s%3d %s\n",
-				       curr_model->chan_type,buff,
-				       (int)curr_model->max_port_no,buff2);         
+			sprintf_msck(buff[1],curr_model->auto_msck_recovery);
+			chandev_printf(chan_exit,"  0x%02x  %s%3d %s     %s     %s\n",
+				       curr_model->chan_type,buff[0],
+				       (int)curr_model->max_port_no,
+				       curr_model->default_checksum_received_ip_pkts ? "yes":"no ",
+				       curr_model->default_use_hw_stats ? "yes":"no ",
+				       buff[1]);         
 		}
 	}
         
@@ -2294,65 +2947,78 @@
 		chandev_printf(chan_exit,"===========================================\n");
 		for_each(curr_msck_range,chandev_msck_range_head)
 		{
-			sprintf_msck(buff2,curr_msck_range->auto_msck_recovery);
+			sprintf_msck(buff[0],curr_msck_range->auto_msck_recovery);
 			chandev_printf(chan_exit,"  0x%04x     0x%04x %s\n",
 				       curr_msck_range->lo_devno,
-				       curr_msck_range->hi_devno,buff2)
+				       curr_msck_range->hi_devno,buff[0])
 		}
 	}
 	if(chandev_force_head)
 	{
 		chandev_printf(chan_exit,"\nForced devices\n");
-		chandev_printf(chan_exit,"  chan defif read   write     port         ip    hw\n");
-		chandev_printf(chan_exit,"  type  num  devno  devno  protocol no.  chksum stats\n");
-		chandev_printf(chan_exit,"======================================================\n");
+		chandev_printf(chan_exit,"  chan defif read   write  data   memory      port         ip    hw   host       adapter   api\n");
+		chandev_printf(chan_exit,"  type  num  devno  devno  devno  usage(k) protocol no.  chksum stats name        name     name\n");
+		chandev_printf(chan_exit,"===============================================================================================\n");
 		for_each(curr_force,chandev_force_head)
 		{
-			chandev_printf(chan_exit,"  0x%02x  %3d  0x%04x 0x%04x       %3d       %1d    %1d\n",
-				       curr_force->chan_type,curr_force->devif_num,
-				       curr_force->read_devno,curr_force->write_devno,
-				       curr_force->port_protocol_no,curr_force->checksum_received_ip_pkts,
-				       curr_force->use_hw_stats);
+			if(curr_force->memory_usage_in_k==0)
+				strcpy(buff[0],"default");
+			else
+				sprintf(buff[0],"%6d",curr_force->memory_usage_in_k);
+			chandev_printf(chan_exit,"  0x%02x  %3d  0x%04x 0x%04x 0x%04x %7s       %3d       %1d    %1d%s",
+				       (int)curr_force->chan_type,(int)curr_force->devif_num,
+				       (int)curr_force->read_lo_devno,(int)curr_force->write_hi_devno,
+				       (int)curr_force->data_devno,buff[0],
+				       (int)curr_force->port_protocol_no,(int)curr_force->checksum_received_ip_pkts,
+				       (int)curr_force->use_hw_stats,curr_force->chan_type==chandev_type_claw ? "":"\n");
+			if(curr_force->chan_type==chandev_type_claw)
+			{
+				chandev_printf(chan_exit," %9s %9s %9s\n",
+					       curr_force->claw.host_name,
+					       curr_force->claw.adapter_name,
+					       curr_force->claw.api_type);
+			}
+
 		}
 	}
 	if(chandev_probelist_head)
 	{
 #if CONFIG_ARCH_S390X
 		chandev_printf(chan_exit,"\nRegistered probe functions\n"
-			       		 "probefunc            shutdownfunc         reoperfunc         chan  devices\n"
-                                         "                                                             type   found\n"
-			                 "==========================================================================\n");
+			       		 "probefunc            shutdownfunc        msck_notfunc        chan  devices devices\n"
+                                         "                                                             type   found  active\n"
+			                 "==================================================================================\n");
 #else
 		chandev_printf(chan_exit,"\nRegistered probe functions\n"
-			                 "probefunc   shutdownfunc  reoperfunc chan  devices\n"
-                                         "                                     type   found\n"
-			                 "==================================================\n");
+			                 "probefunc   shutdownfunc   msck_notfunc   chan  devices devices\n"
+                                         "                                          type   found  active\n"
+			                 "===============================================================\n");
 #endif
 		for_each(curr_probe,chandev_probelist_head)
 		{
-			chandev_printf(chan_exit,"0x%p   0x%p   0x%p   0x%02x      %d\n",
+			int devices_active=0;
+			for_each(curr_device,chandev_activelist_head)
+			{
+				if(curr_device->probefunc==curr_probe->probefunc)
+					devices_active++;
+			}
+			chandev_printf(chan_exit,"0x%p   0x%p   0x%p       0x%02x     %d      %d\n",
 				       curr_probe->probefunc,
 				       curr_probe->shutdownfunc,
-				       curr_probe->reoperfunc,
+				       curr_probe->msck_notfunc,
 				       curr_probe->chan_type,
-				       curr_probe->devices_found);
+				       curr_probe->devices_found,
+				       devices_active);
 		}
 	}
 	if(chandev_activelist_head)
 	{
-#if CONFIG_ARCH_S390X
+		unsigned long long total_memory_usage_in_k=0;
 		chandev_printf(chan_exit,
 			       "\nInitialised Devices\n"
-			       " read   write  read   write chan port  dev             dev        read msck   write msck\n"
-			       " irq    irq    devno  devno type no.   ptr             name        status      status   \n"
-			       "========================================================================================\n");
-#else
-		chandev_printf(chan_exit,
-			       "\nInitialised Devices\n"
-			       " read   write  read   write chan port  dev     dev        read msck   write msck\n"
-			       " irq    irq    devno  devno type no.   ptr     name        status      status   \n"
-			       "================================================================================\n");
-#endif
+			       " read   write  data  read   write  data  chan port  dev     dev         memory   read msck    write msck    data msck\n"
+			       " irq     irq    irq  devno  devno  devno type no.   ptr     name        usage(k)  status       status        status\n"
+			       "=====================================================================================================================\n");
 		/* We print this list backwards for cosmetic reasons */
 		for(curr_device=chandev_activelist_head;
 		    curr_device->next!=NULL;curr_device=curr_device->next);
@@ -2360,19 +3026,44 @@
 		{
 			read_irqinfo=curr_device->read_irqinfo;
 			write_irqinfo=curr_device->write_irqinfo;
+			data_irqinfo=curr_device->data_irqinfo;
+			if(data_irqinfo)
+			{
+				sprintf(buff[0],"0x%04x",data_irqinfo->sch.irq);
+				sprintf(buff[1],"0x%04x",(int)data_irqinfo->sch.devno);
+			}
+			else
+			{
+				strcpy(buff[0],"  n/a ");
+				strcpy(buff[1],"  n/a ");
+			}
+			if(curr_device->memory_usage_in_k<0)
+			{
+				sprintf(buff[2],"%d",(int)-curr_device->memory_usage_in_k);
+				total_memory_usage_in_k-=curr_device->memory_usage_in_k;
+			}
+			else
+				strcpy(buff[2],"  n/a ");
 			chandev_printf(chan_exit,
-				       "0x%04x 0x%04x 0x%04x 0x%04x 0x%02x %2d 0x%p %-10s   %-12s %-12s\n",
-				       curr_device->read_irqinfo->irq,curr_device->write_irqinfo->irq,
-				       (int)read_irqinfo->devno,
-				       (int)write_irqinfo->devno,
+				       "0x%04x 0x%04x %s 0x%04x 0x%04x %s 0x%02x %2d 0x%p %-10s  %6s   %-12s %-12s %-12s\n",
+				       read_irqinfo->sch.irq,
+				       write_irqinfo->sch.irq,
+				       buff[0],
+				       (int)read_irqinfo->sch.devno,
+				       (int)write_irqinfo->sch.devno,
+				       buff[1],
 				       curr_device->chan_type,(int)curr_device->port_no,
 				       curr_device->dev_ptr,curr_device->devname,
+				       buff[2],
 				       msck_status_strs[read_irqinfo->msck_status],
-				       msck_status_strs[write_irqinfo->msck_status]);
+				       msck_status_strs[write_irqinfo->msck_status],
+				       data_irqinfo ? msck_status_strs[data_irqinfo->msck_status] :
+				       "not applicable");
 			get_prev((list *)chandev_activelist_head,
 				 (list *)curr_device,
 				 (list **)&curr_device);
 		}
+		chandev_printf(chan_exit,"\nTotal device memory usage %Luk.\n",total_memory_usage_in_k);
 	}
 	chandevs_detected=FALSE;
 	for(pass=FALSE;pass<=TRUE;pass++)
@@ -2380,9 +3071,9 @@
 		if(pass&&chandevs_detected)
 		{
 			chandev_printf(chan_exit,"\nchannels detected\n");
-			chandev_printf(chan_exit,"              chan    cu    cu   dev    dev   in   chandev\n");
-			chandev_printf(chan_exit,"  irq  devno  type   type  model type  model  use    reg.\n");
-			chandev_printf(chan_exit,"==========================================================\n");
+			chandev_printf(chan_exit,"              chan    cu    cu   dev    dev                          in chandev\n");
+			chandev_printf(chan_exit,"  irq  devno  type   type  model type  model pim      chpids         use  reg.\n");
+			chandev_printf(chan_exit,"===============================================================================\n");
 		}
 		for(curr_irq=get_irq_first(),loopcnt=0;curr_irq>=0; curr_irq=get_irq_next(curr_irq),loopcnt++)
 		{
@@ -2391,20 +3082,26 @@
 				printk(KERN_ERR"chandev_read_proc detected infinite loop bug in get_irq_next\n");
 				goto chan_error;
 			}
-			if((curr_model=chandev_is_chandev(curr_irq,&curr_devinfo)))
+			if(chandev_is_chandev(curr_irq,&curr_devinfo,&curr_force,&curr_model))
 			{
+				schib_t *curr_schib;
+				curr_schib=s390_get_schib(curr_irq);
 				chandevs_detected=TRUE;
 				if(pass)
 				{
-					chandev_printf(chan_exit,"0x%04x 0x%04x 0x%02x  0x%04x 0x%02x  0x%04x 0x%02x  %-5s %-5s\n",
+					chandev_printf(chan_exit,"0x%04x 0x%04x 0x%02x  0x%04x 0x%02x  0x%04x 0x%02x 0x%02x 0x%016Lx  %-5s %-5s\n",
 						       curr_irq,curr_devinfo.devno,
-						       curr_model->chan_type,
+						       ( curr_force ? curr_force->chan_type : 
+						       ( curr_model ? curr_model->chan_type : 
+							 chandev_type_none )),
 						       (int)curr_devinfo.sid_data.cu_type,
 						       (int)curr_devinfo.sid_data.cu_model,
 						       (int)curr_devinfo.sid_data.dev_type,
 						       (int)curr_devinfo.sid_data.dev_model,
-						       (curr_devinfo.status&DEVSTAT_DEVICE_OWNED) ? "yes":"no",
-						       (chandev_get_irqinfo_by_irq(curr_irq) ? "yes":"no"));
+						       (int)(curr_schib ? curr_schib->pmcw.pim : 0),
+						       *(long long *)(curr_schib ? &curr_schib->pmcw.chpid[0] : 0),
+						       (curr_devinfo.status&DEVSTAT_DEVICE_OWNED) ? "yes":"no ",
+						       (chandev_get_irqinfo_by_irq(curr_irq) ? "yes":"no "));
 						       
 						       
 				}
@@ -2418,14 +3115,14 @@
 		chandev_parms      *curr_parms;
 
 		chandev_printf(chan_exit,"\n driver specific parameters\n");
-		chandev_printf(chan_exit,"chan    driver\n");
-		chandev_printf(chan_exit,"type  parameters\n");
+		chandev_printf(chan_exit,"chan    lo    hi      driver\n");
+		chandev_printf(chan_exit,"type  devno  devno  parameters\n");
 		chandev_printf(chan_exit,"=============================================================================\n");
 		for_each(curr_parms,chandev_parms_head)
 		{
-			chandev_printf(chan_exit,"0x%02x    %s\n",
-				       curr_parms->chan_type,
-				       curr_parms->parmstr);
+			chandev_printf(chan_exit,"0x%02x 0x%04x 0x%04x  %s\n",
+				       curr_parms->chan_type,(int)curr_parms->lo_devno,
+				       (int)curr_parms->hi_devno,curr_parms->parmstr);
 		}
 	}
  chan_error:
@@ -2448,7 +3145,6 @@
 	int         rc;
 	char        *buff;
 	
-	chandev_read_conf_if_necessary();
 	buff=vmalloc(count+1);
 	if(buff)
 	{
@@ -2485,29 +3181,26 @@
 #endif
 int __init chandev_init(void)
 {
-	if(!chandev_initialised)
-	{
-		chandev_parse_args();
-		chandev_init_default_models();
+	atomic_set(&chandev_initialised,TRUE);
+	chandev_parse_args();
+	chandev_init_default_models();
 #if CONFIG_PROC_FS
-		chandev_create_proc();
+	chandev_create_proc();
 #endif
-		chandev_msck_task_tq.routine=
+	chandev_msck_task_tq.routine=
 		chandev_msck_task;
 #if LINUX_VERSION_CODE>=KERNEL_VERSION(2,3,0)
-		INIT_LIST_HEAD(&chandev_msck_task_tq.list);
-		chandev_msck_task_tq.sync=0;
+	INIT_LIST_HEAD(&chandev_msck_task_tq.list);
+	chandev_msck_task_tq.sync=0;
 #endif
-		chandev_msck_task_tq.data=NULL;
-		chandev_last_startmsck_list_update=chandev_last_machine_check=jiffies-HZ;
-		atomic_set(&chandev_msck_thread_lock,1);
-		chandev_lock_owner=CHANDEV_INVALID_LOCK_OWNER;
-		chandev_lock_cnt=0;
-		spin_lock_init(&chandev_spinlock);
-		spin_lock_init(&chandev_not_oper_spinlock);
-		chandev_initialised=TRUE;
-		atomic_set(&chandev_new_msck,FALSE);
-	}
+	chandev_msck_task_tq.data=NULL;
+	chandev_last_startmsck_list_update=chandev_last_machine_check=jiffies-HZ;
+	atomic_set(&chandev_msck_thread_lock,1);
+	chandev_lock_owner=CHANDEV_INVALID_LOCK_OWNER;
+	chandev_lock_cnt=0;
+	spin_lock_init(&chandev_spinlock);
+	spin_lock_init(&chandev_not_oper_spinlock);
+	atomic_set(&chandev_new_msck,FALSE);
 	return(0);
 }
 #if LINUX_VERSION_CODE>=KERNEL_VERSION(2,3,0)
@@ -2516,7 +3209,7 @@
 
 int chandev_register_and_probe(chandev_probefunc probefunc,
 			       chandev_shutdownfunc shutdownfunc,
-			       chandev_reoperfunc reoperfunc,
+			       chandev_msck_notification_func msck_notfunc,
 			       chandev_type chan_type)
 {
 	chandev_probelist *new_probe;
@@ -2524,14 +3217,13 @@
 	/* are initialised. */
 
 	chandev_interrupt_check();
-	if(!chandev_initialised)
+	if(!atomic_compare_and_swap(FALSE,TRUE,&chandev_initialised))
 		chandev_init();
-	chandev_read_conf_if_necessary();
 	if((new_probe=chandev_alloc(sizeof(chandev_probelist))))
 	{
 		new_probe->probefunc=probefunc;
 		new_probe->shutdownfunc=shutdownfunc;
-		new_probe->reoperfunc=reoperfunc;
+		new_probe->msck_notfunc=msck_notfunc;
 		new_probe->chan_type=chan_type;
 		new_probe->devices_found=0;
 		chandev_add_to_list((list **)&chandev_probelist_head,new_probe);
@@ -2543,7 +3235,7 @@
 void chandev_unregister(chandev_probefunc probefunc,int call_shutdown)
 {
 	chandev_probelist *curr_probe=NULL;
-	chandev_activelist *curr_device;
+	chandev_activelist *curr_device,*next_device;
 	
 	chandev_interrupt_check();
 	chandev_lock();
@@ -2551,27 +3243,33 @@
 	{
 		if(curr_probe->probefunc==probefunc)
 		{
-			for_each(curr_device,chandev_activelist_head)
-				if(curr_device->probefunc==probefunc)
-				{
-					if(call_shutdown)
-					{
-						chandev_shutdown(curr_device);
-					}
-				}
+			for_each_allow_delete(curr_device,next_device,chandev_activelist_head)
+				if(curr_device->probefunc==probefunc&&call_shutdown)
+					chandev_shutdown(curr_device);
 			chandev_free_listmember((list **)&chandev_probelist_head,
 						(list *)curr_probe);
+			break;
 		}
 	}
 	chandev_unlock();
 }
 
+
+int chandev_persist(chandev_type chan_type)
+{
+	return((chandev_persistent&chan_type) ? TRUE:FALSE);
+}
+
 EXPORT_SYMBOL(chandev_register_and_probe);
 EXPORT_SYMBOL(chandev_request_irq);
-EXPORT_SYMBOL(chandev_free_irq);
 EXPORT_SYMBOL(chandev_unregister);
 EXPORT_SYMBOL(chandev_initdevice);
+EXPORT_SYMBOL(chandev_build_device_name);
 EXPORT_SYMBOL(chandev_initnetdevice);
-
-
+EXPORT_SYMBOL(chandev_init_netdev);
+EXPORT_SYMBOL(chandev_use_devno_names);
+EXPORT_SYMBOL(chandev_free_irq);
+EXPORT_SYMBOL(chandev_add_model);
+EXPORT_SYMBOL(chandev_del_model);
+EXPORT_SYMBOL(chandev_persist);
 
diff -u --recursive --new-file v2.4.7/linux/drivers/s390/net/Makefile linux/drivers/s390/net/Makefile
--- v2.4.7/linux/drivers/s390/net/Makefile	Wed Apr 11 19:02:28 2001
+++ linux/drivers/s390/net/Makefile	Wed Jul 25 14:12:02 2001
@@ -5,11 +5,11 @@
 O_TARGET := s390-net.o
 
 list-multi := ctc.o
-export-objs := iucv.o
+export-objs := iucv.o fsm.o
 
-ctc-objs := ctcmain.o ctctty.o fsm.o
+ctc-objs := ctcmain.o ctctty.o
 
-obj-y += iucv.o
+obj-y += iucv.o fsm.o
 obj-$(CONFIG_CTC) += ctc.o
 obj-$(CONFIG_IUCV) += netiucv.o
 
diff -u --recursive --new-file v2.4.7/linux/drivers/s390/net/ctcmain.c linux/drivers/s390/net/ctcmain.c
--- v2.4.7/linux/drivers/s390/net/ctcmain.c	Wed Apr 18 14:40:07 2001
+++ linux/drivers/s390/net/ctcmain.c	Wed Jul 25 14:12:02 2001
@@ -1,5 +1,5 @@
 /*
- * $Id: ctcmain.c,v 1.17 2001/01/23 14:23:51 felfert Exp $
+ * $Id: ctcmain.c,v 1.46 2001/07/05 17:36:41 felfert Exp $
  *
  * CTC / ESCON network driver
  *
@@ -35,70 +35,15 @@
  * along with this program; if not, write to the Free Software
  * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
  *
- * $Log: ctcmain.c,v $
- * Revision 1.17  2001/01/23 14:23:51  felfert
- * Added ctc based tty.
+ * RELEASE-TAG: CTC/ESCON network driver $Revision: 1.46 $
  *
- * Revision 1.16  2001/01/18 16:10:53  felfert
- * Added fixes by acme@conectiva.com.br.
- *
- * Revision 1.15  2001/01/12 15:40:11  felfert
- * Fixed ITPM# PL030052IME (Unitchecks when using real escon).
- *
- * Revision 1.14  2001/01/11 17:43:52  felfert
- * Fixed ITPM# PL030051IME (Initialization of escon).
- *
- * Revision 1.13  2001/01/11 16:40:26  smolinsk
- * resolved name space conflict with LVM and renamed
- *  dev_info_t to s390_dev_info_t
- * worked around a bug in OSA microcode by stepping back to 2k IDALS in idals.c
- *
- * Revision 1.12  2000/12/27 09:40:45  tonn
- * upgrade to test12
- *
- * Revision 1.11  2000/12/15 19:34:54  bird
- * struct ctc_priv_t: set type of tbusy to "unsigned long"
- *
- * Revision 1.10  2000/12/14 16:49:50  bird
- * ch_action_txretry(): added missing clear_normalized_cda()
- *
- * Revision 1.9  2000/12/14 13:56:53  felfert
- * Eliminated a compiler warning when building in old kernel.
- *
- * Revision 1.8  2000/12/14 13:11:59  felfert
- * static ccws now separately allocated.
- * remove locally allocated ccw for setup.
- *
- * Revision 1.7  2000/12/14 03:32:15  bird
- * Fixes for >2GB memory.   Switch on checksumming.
- *
- * Revision 1.6  2000/12/07 20:08:30  felfert
- * Modified RX channel initialization to be compatible with VM TCP
- *
- * Revision 1.5  2000/12/07 18:15:05  felfert
- * Added workaround against VM TCP bug.
- * Fixed an error message.
- *
- * Revision 1.4  2000/12/06 16:55:57  felfert
- * Removed check for double call of ctc_setup().
- * ctc_setup can now handle mutiple calls.
- *
- * Revision 1.3  2000/12/06 16:48:44  felfert
- * New initialization.
- * Removed old cvs log from 2.2 kernel.
- *
- * Revision 1.2  2000/12/06 14:13:46  felfert
- * New unified configuration.
- *
- * Revision 1.1  2000/11/30 11:21:08  bird
- * Support for new ctc driver
  */
 
 #include <linux/version.h>
 #include <linux/module.h>
 #include <linux/init.h>
 #include <linux/kernel.h>
-#include <linux/malloc.h>
+#include <linux/slab.h>
 #include <linux/errno.h>
 #include <linux/types.h>
 #include <linux/interrupt.h>
@@ -119,14 +64,29 @@
 #include <asm/io.h>
 #include <asm/bitops.h>
 #include <asm/uaccess.h>
+#ifdef CONFIG_CHANDEV
+#define CTC_CHANDEV
+#endif
 
-#define CTC_USE_IDALS 1
-#if CTC_USE_IDALS
+#ifdef CTC_CHANDEV
+#include <asm/chandev.h>
+#define REQUEST_IRQ chandev_request_irq
+#define FREE_IRQ chandev_free_irq
+#else
+#define REQUEST_IRQ request_irq
+#define FREE_IRQ free_irq
+#endif
+
+#if LINUX_VERSION_CODE >= 0x020213
 #  include <asm/idals.h>
 #else
 #  define set_normalized_cda(ccw, addr) ((ccw)->cda = (addr))
 #  define clear_normalized_cda(ccw)
 #endif
+#if LINUX_VERSION_CODE < 0x020400
+#  define s390_dev_info_t dev_info_t
+#  define dev_kfree_skb_irq(a) dev_kfree_skb(a)
+#endif
 
 #include <asm/irq.h>
 
@@ -136,12 +96,14 @@
 #ifdef MODULE
 MODULE_AUTHOR("(C) 2000 IBM Corp. by Fritz Elfert (felfert@millenux.com)");
 MODULE_DESCRIPTION("Linux for S/390 CTC/Escon Driver");
+#ifndef CTC_CHANDEV
 MODULE_PARM(ctc, "s");
 MODULE_PARM_DESC(ctc,
 "One or more definitions in the same format like the kernel param for ctc.\n"
 "E.g.: ctc0:0x700:0x701:0:ctc1:0x702:0x703:0\n");
 
 char *ctc = NULL;
+#endif
 #else
 /**
  * Number of devices in monolithic (not module) driver version.
@@ -162,7 +124,8 @@
 #define CTC_PROTO_S390          0
 #define CTC_PROTO_LINUX         1
 #define CTC_PROTO_LINUX_TTY     2
-#define CTC_PROTO_MAX           2
+#define CTC_PROTO_OS390         3
+#define CTC_PROTO_MAX           3
 
 #define CTC_BUFSIZE_LIMIT       65535
 #define CTC_BUFSIZE_DEFAULT     32768
@@ -206,13 +169,16 @@
 
 typedef enum channel_types channel_type_t;
 
+#ifndef CTC_CHANDEV
 static int ctc_no_auto = 0;
+#endif
 
 /**
  * If running on 64 bit, this must be changed. XXX Why? (bird)
  */
 typedef unsigned long intparm_t;
 
+#ifndef CTC_CHANDEV
 /**
  * Definition of a per device parameter block
  */
@@ -226,6 +192,7 @@
 } param;
 
 static param *params = NULL;
+#endif
 
 typedef struct {
 	unsigned long maxmulti;
@@ -246,7 +213,6 @@
 	 * Pointer to next channel in list.
 	 */
 	struct channel_t    *next;
-
 	__u16               devno;
 	int                 irq;
 
@@ -278,19 +244,14 @@
 	struct tq_struct    tq;
 
 	/**
-	 * RX/TX buffer for init sequence.
-	 */
-	__u16               dummy_buf;
-
-	/**
-	 * RX buffer size
+	 * RX/TX buffer size
 	 */
 	int                 max_bufsize;
 
 	/**
-	 * Receive buffer.
+	 * Transmit/Receive buffer.
 	 */
-	struct sk_buff      *rx_skb;
+	struct sk_buff      *trans_skb;
 
 	/**
 	 * Universal I/O queue.
@@ -313,16 +274,6 @@
 	spinlock_t          collect_lock;
 
 	/**
-	 * Pointer to dynamic allocated CCWs for TX
-	 */
-	ccw1_t              *dccw;
-
-	/**
-	 * Number of dynamic allocated CCWs needed for clearing IDALs.
-	 */
-	int                 dccw_count;
-
-	/**
 	 * Timer for detecting unresposive
 	 * I/O operations.
 	 */
@@ -347,9 +298,10 @@
 	ctc_profile         prof;
 } channel;
 
-#define CHANNEL_FLAGS_READ   0
-#define CHANNEL_FLAGS_WRITE  1
-#define CHANNEL_FLAGS_INUSE  2
+#define CHANNEL_FLAGS_READ            0
+#define CHANNEL_FLAGS_WRITE           1
+#define CHANNEL_FLAGS_INUSE           2
+#define CHANNEL_FLAGS_BUFSIZE_CHANGED 4
 #define CHANNEL_FLAGS_RWMASK 1
 #define CHANNEL_DIRECTION(f) (f & CHANNEL_FLAGS_RWMASK)
 
@@ -358,6 +310,10 @@
  */
 static channel *channels = NULL;
 
+#ifdef CTC_CHANDEV
+static int activated;
+#endif
+
 typedef struct ctc_priv_t {
 	struct net_device_stats stats;
 #if LINUX_VERSION_CODE >= 0x02032D
@@ -375,6 +331,7 @@
 	struct proc_dir_entry   *proc_dentry;
 	struct proc_dir_entry   *proc_stat_entry;
 	struct proc_dir_entry   *proc_ctrl_entry;
+	int                     proc_registered;
 } ctc_priv;
 
 /**
@@ -425,7 +382,7 @@
  */
 static void print_banner(void) {
 	static int printed = 0;
-	char vbuf[] = "$Revision: 1.17 $";
+	char vbuf[] = "$Revision: 1.46 $";
 	char *version = vbuf;
 
 	if (printed)
@@ -440,6 +397,8 @@
 	printed = 1;
 }
 
+
+#ifndef CTC_CHANDEV
 /**
  * Return type of a detected device.
  */
@@ -502,6 +461,8 @@
 	}
 	return type;
 }
+#endif
+
 
 /**
  * States of the interface statemachine.
@@ -593,6 +554,12 @@
 	CH_EVENT_SC_UNKNOWN,
 
 	/**
+	 * Events, representing machine checks
+	 */
+	CH_EVENT_MC_FAIL,
+	CH_EVENT_MC_GOOD,
+
+	/**
 	 * Event, representing normal IRQ
 	 */
 	CH_EVENT_IRQ,
@@ -637,6 +604,9 @@
 
 	"SubChannel check Unknown",
 
+	"Machine check failure",
+	"Machine check operational",
+
 	"IRQ normal",
 	"IRQ final",
 
@@ -673,6 +643,7 @@
 	CH_STATE_TXERR,
 	CH_STATE_TERM,
 	CH_STATE_DTERM,
+	CH_STATE_NOTOP,
 
 	/**
 	 * MUST be always the last element!!
@@ -696,9 +667,11 @@
 	"TX error",
 	"Terminating",
 	"Restarting",
+	"Not operational",
 };
 
 
+#ifdef DEBUG
 /**
  * Dump header and first 16 bytes of an sk_buff for debugging purposes.
  *
@@ -729,114 +702,120 @@
 		bl = 16;
 	printk(KERN_DEBUG "data: ");
 	for (i = 0; i < bl; i++)
-		printk("%02x ", *p++);
+		printk("%02x%s", *p++, (i % 16) ? " " : "\n<7>");
 	printk("\n");
 }
+#endif
 
 /**
- * Bottom half routine.
+ * Unpack a just received skb and hand it over to
+ * upper layers.
  *
- * @param ch The channel to work on.
+ * @param ch The channel where this skb has been received.
+ * @param pskb The received skb.
  */
-static void ctc_bh(channel *ch)
+static __inline__ void ctc_unpack_skb(channel *ch, struct sk_buff *pskb)
 {
 	net_device     *dev = ch->netdev;
 	ctc_priv       *privptr = (ctc_priv *)dev->priv;
-	struct sk_buff *skb;
 
-	while ((skb = skb_dequeue(&ch->io_queue))) {
-		__u16 len = *((__u16*)skb->data);
+	__u16 len = *((__u16*)pskb->data);
+	skb_put(pskb, 2 + LL_HEADER_LENGTH);
+	skb_pull(pskb, 2);
+	pskb->dev = dev;
+	pskb->ip_summed = CHECKSUM_UNNECESSARY;
+	while (len > 0) {
+		struct sk_buff *skb;
+		ll_header *header = (ll_header *)pskb->data;
 
-		skb_put(skb, 2 + LL_HEADER_LENGTH);
-		skb_pull(skb, 2);
-		skb->dev = dev;
-		skb->ip_summed = CHECKSUM_NONE;
-		while (len > 0) {
-			ll_header *header = (ll_header *)skb->data;
-			skb_pull(skb, LL_HEADER_LENGTH);
-			if ((ch->protocol == CTC_PROTO_S390) &&
-			    (header->type != ETH_P_IP)) {
-				/**
-				 * Check packet type only if we stick strictly
-				 * to S/390's protocol of OS390. This only
-				 * supports IP. Otherwise allow any packet
-				 * type.
-				 */
-				printk(KERN_WARNING
-				       "%s Illegal packet type 0x%04x "
-				       "received, dropping\n",
-				       dev->name, header->type);
-				ctc_dump_skb(skb, -6);
-				privptr->stats.rx_dropped++;
-				privptr->stats.rx_frame_errors++;
-				dev_kfree_skb(skb);
-				goto again;
-			}
-			skb->protocol = ntohs(header->type);
-			header->length -= LL_HEADER_LENGTH;
-			if ((header->length > dev->mtu) ||
-			    (header->length == 0)) {
-				printk(KERN_WARNING
-				       "%s Illegal packet size %d "
-				       "received (MTU=%d), "
-				       "dropping\n", dev->name, header->length,
-				       dev->mtu);
-				ctc_dump_skb(skb, -6);
-				privptr->stats.rx_dropped++;
-				privptr->stats.rx_length_errors++;
-				dev_kfree_skb(skb);
-				goto again;
-			}
-			skb_put(skb, header->length);
-			skb->mac.raw = skb->data;
+		skb_pull(pskb, LL_HEADER_LENGTH);
+		if ((ch->protocol == CTC_PROTO_S390) &&
+		    (header->type != ETH_P_IP)) {
 			/**
-			 * Set truesize here to make the kernel's
-			 * socket layer happy. If this is not done,
-			 * the RX-routines of the socket code are dropping
-			 * most of the received packets, because they "think"
-			 * there isn't enough buffer space for the incoming
-			 * data.
+			 * Check packet type only if we stick strictly
+			 * to S/390's protocol of OS390. This only
+			 * supports IP. Otherwise allow any packet
+			 * type.
 			 */
-			skb->truesize = skb->len;
-			len -= (LL_HEADER_LENGTH + header->length);
-			if (len > 0) {
-				/**
-				 * Clone the skb only if there are still
-				 * sub-packets.
-				 */
-				struct sk_buff *skb2 =
-					skb_clone(skb, GFP_ATOMIC);
-				if (!skb2) {
-					printk(KERN_WARNING "%s Out of memory"
-					       " in ctc_bh\n",
-					       dev->name);
-					privptr->stats.rx_dropped++;
-					dev_kfree_skb(skb);
-					goto again;
-				}
-				if (ch->protocol == CTC_PROTO_LINUX_TTY)
-					ctc_tty_netif_rx(skb2);
-				else
-					netif_rx(skb2);
-				privptr->stats.rx_packets++;
-				privptr->stats.rx_bytes += skb2->len;
-				/**
-				 * Advance pointers to next sub-packet.
-				 */
-				skb_pull(skb, header->length);
-				skb_put(skb, LL_HEADER_LENGTH);
-			} else {
-				if (ch->protocol == CTC_PROTO_LINUX_TTY)
-					ctc_tty_netif_rx(skb);
-				else
-					netif_rx(skb);
-				privptr->stats.rx_packets++;
-				privptr->stats.rx_bytes += skb->len;
-			}
+			printk(KERN_WARNING
+			       "%s Illegal packet type 0x%04x "
+			       "received, dropping\n",
+			       dev->name, header->type);
+#ifdef DEBUG
+			ctc_dump_skb(pskb, -6);
+#endif
+			privptr->stats.rx_dropped++;
+			privptr->stats.rx_frame_errors++;
+			return;
+		}
+		pskb->protocol = ntohs(header->type);
+		header->length -= LL_HEADER_LENGTH;
+		if ((header->length == 0) ||
+		    (header->length > skb_tailroom(pskb))) {
+			printk(KERN_WARNING
+			       "%s Illegal packet size %d "
+			       "received (MTU=%d), "
+			       "dropping\n", dev->name, header->length,
+			       dev->mtu);
+#ifdef DEBUG
+			ctc_dump_skb(pskb, -6);
+#endif
+			privptr->stats.rx_dropped++;
+			privptr->stats.rx_length_errors++;
+			return;
+		}
+		if (header->length > skb_tailroom(pskb)) {
+			printk(KERN_WARNING
+			       "%s Illegal packet size %d "
+			       "(beyond the end of received data), "
+			       "dropping\n", dev->name, header->length);
+#ifdef DEBUG
+			ctc_dump_skb(pskb, -6);
+#endif
+			privptr->stats.rx_dropped++;
+			privptr->stats.rx_length_errors++;
+			return;
+		}
+		skb_put(pskb, header->length);
+		pskb->mac.raw = pskb->data;
+		len -= (LL_HEADER_LENGTH + header->length);
+		skb = dev_alloc_skb(pskb->len);
+		if (!skb) {
+			printk(KERN_WARNING
+			       "%s Out of memory in ctc_unpack_skb\n",
+			       dev->name);
+			privptr->stats.rx_dropped++;
+			return;
+		}
+		memcpy(skb_put(skb, pskb->len), pskb->data, pskb->len);
+		skb->mac.raw = skb->data;
+		skb->dev = pskb->dev;
+		skb->protocol = pskb->protocol;
+		pskb->ip_summed = CHECKSUM_UNNECESSARY;
+		if (ch->protocol == CTC_PROTO_LINUX_TTY)
+			ctc_tty_netif_rx(skb);
+		else
+			netif_rx(skb);
+		privptr->stats.rx_packets++;
+		privptr->stats.rx_bytes += skb->len;
+		if (len > 0) {
+			skb_pull(pskb, header->length);
+			skb_put(pskb, LL_HEADER_LENGTH);
 		}
-	again:
 	}
-	return;
+}
+
+/**
+ * Bottom half routine.
+ *
+ * @param ch The channel to work on.
+ */
+static void ctc_bh(channel *ch)
+{
+	struct sk_buff *skb;
+
+	while ((skb = skb_dequeue(&ch->io_queue)))
+		ctc_unpack_skb(ch, skb);
 }
 
 /**
@@ -883,9 +862,10 @@
 static void inline ccw_unit_check (channel *ch, unsigned char sense) {
 	if (sense & SNS0_INTERVENTION_REQ) {
 		if (sense & 0x01)  {
-			printk(KERN_DEBUG
-			       "ch-%04x: Interface disc. or Sel. reset "
-			       "(remote)\n", ch->devno);
+			if (ch->protocol != CTC_PROTO_LINUX_TTY)
+				printk(KERN_DEBUG
+				       "ch-%04x: Interface disc. or Sel. reset "
+				       "(remote)\n", ch->devno);
 			fsm_event(ch->fsm, CH_EVENT_UC_RCRESET, ch);
 		} else {
 			printk(KERN_DEBUG "ch-%04x: System reset (remote)\n",
@@ -917,7 +897,8 @@
 			fsm_event(ch->fsm, CH_EVENT_UC_TXPARITY, ch);
 		}
 	} else if (sense & SNS0_CMD_REJECT) {
-			printk(KERN_WARNING "ch-%04x: Command reject\n", ch->devno);
+			printk(KERN_WARNING "ch-%04x: Command reject\n",
+			       ch->devno);
 	} else if (sense == 0) {
 		printk(KERN_DEBUG "ch-%04x: Unit check ZERO\n", ch->devno);
 		fsm_event(ch->fsm, CH_EVENT_UC_ZERO, ch);
@@ -935,8 +916,42 @@
 
 	while ((skb = skb_dequeue(q))) {
 		atomic_dec(&skb->users);
-		dev_kfree_skb(skb);
+		dev_kfree_skb_irq(skb);
+	}
+}
+
+static __inline__ int ctc_checkalloc_buffer(channel *ch, int warn) {
+	if ((ch->trans_skb == NULL) ||
+	    (ch->flags & CHANNEL_FLAGS_BUFSIZE_CHANGED)) {
+		if (ch->trans_skb != NULL)
+			dev_kfree_skb(ch->trans_skb);
+		ch->trans_skb = dev_alloc_skb(ch->max_bufsize);
+		if (ch->trans_skb == NULL) {
+			if (warn)
+				printk(KERN_WARNING
+				       "ch-%04x: Couldn't alloc %s trans_skb\n",
+				       ch->devno,
+				       (CHANNEL_DIRECTION(ch->flags) == READ) ?
+				       "RX" : "TX");
+			return -ENOMEM;
+		}
+		set_normalized_cda(&ch->ccw[1],
+				   virt_to_phys(ch->trans_skb->data));
+		if (ch->ccw[1].cda == 0) {
+			dev_kfree_skb(ch->trans_skb);
+			ch->trans_skb = NULL;
+			if (warn)
+				printk(KERN_WARNING
+				       "ch-%04x: set_normalized_cda for %s "
+				       "trans_skb failed, dropping packets\n",
+				       ch->devno,
+				       (CHANNEL_DIRECTION(ch->flags) == READ) ?
+				       "RX" : "TX");
+			return -ENOMEM;
+		}
+		ch->flags &= ~CHANNEL_FLAGS_BUFSIZE_CHANGED;
 	}
+	return 0;
 }
 
 /**
@@ -988,73 +1003,47 @@
 			first = 0;
 		}
 		atomic_dec(&skb->users);
-		dev_kfree_skb(skb);
+		dev_kfree_skb_irq(skb);
 	}
 	spin_lock(&ch->collect_lock);
-	if (ch->dccw) {
-		for (i = 0; i < ch->dccw_count; i++)
-			clear_normalized_cda(&ch->dccw[i]);
-		kfree(ch->dccw);
-		ch->dccw = NULL;
-	}
+	clear_normalized_cda(&ch->ccw[4]);
 	if (ch->collect_len > 0) {
 		int rc;
 
-		ch->dccw_count = skb_queue_len(&ch->collect_queue) + 1;
-		if (ch->prof.maxmulti < (ch->collect_len + 2))
-			ch->prof.maxmulti = ch->collect_len + 2;
-		if (ch->prof.maxcqueue < ch->dccw_count)
-			ch->prof.maxcqueue = ch->dccw_count;
-
-		ch->dccw = kmalloc(ch->dccw_count *
-				   sizeof(ccw1_t), GFP_ATOMIC|GFP_DMA);
-		if (!ch->dccw) {
+		if (ctc_checkalloc_buffer(ch, 1)) {
 			spin_unlock(&ch->collect_lock);
-			printk(KERN_WARNING
-			       "%s: Unable to alloc dynamic ccws\n",
-			       dev->name);
 			return;
 		}
-
-		ch->dccw[0].cmd_code = CCW_CMD_PREPARE;
-		ch->dccw[0].flags    = CCW_FLAG_SLI | CCW_FLAG_CC;
-		ch->dccw[0].count    = 0;
-		ch->dccw[0].cda	     = 0;
-		i = 1;
+		ch->trans_skb->tail = ch->trans_skb->data;
+		ch->trans_skb->len = 0;
+		if (ch->prof.maxmulti < (ch->collect_len + 2))
+			ch->prof.maxmulti = ch->collect_len + 2;
+		if (ch->prof.maxcqueue < skb_queue_len(&ch->collect_queue))
+			ch->prof.maxcqueue = skb_queue_len(&ch->collect_queue);
+		ch->ccw[1].count = ch->collect_len + 2;
+		*((__u16 *)skb_put(ch->trans_skb, 2)) = ch->collect_len + 2;
+		i = 0;
 		while ((skb = skb_dequeue(&ch->collect_queue))) {
-			ch->prof.txlen += (skb->len - LL_HEADER_LENGTH);
-			if (i == 1)
-				*((__u16 *)skb_push(skb, 2)) =
-					ch->collect_len + 2;
-			ch->dccw[i].cmd_code = CCW_CMD_WRITE;
-			ch->dccw[i].flags    = CCW_FLAG_SLI |
-				((skb_queue_len(&ch->collect_queue))
-				 ? CCW_FLAG_DC : 0);
-			ch->dccw[i].count    = skb->len;
-			set_normalized_cda(&ch->dccw[i],
-					   virt_to_phys(skb->data));
-			skb_queue_tail(&ch->io_queue, skb);
+			memcpy(skb_put(ch->trans_skb, skb->len), skb->data,
+			       skb->len);
+			privptr->stats.tx_packets++;
+			privptr->stats.tx_bytes += skb->len - LL_HEADER_LENGTH;
+			atomic_dec(&skb->users);
+			dev_kfree_skb_irq(skb);
 			i++;
 		}
 		ch->collect_len = 0;
 		fsm_addtimer(&ch->timer, CTC_TIMEOUT_5SEC, CH_EVENT_TIMER, ch);
 		ch->prof.send_stamp = xtime;
-		rc = do_IO(ch->irq, ch->dccw, (intparm_t)ch, 0xff, 0);
+#ifdef DEBUG
+	printk(KERN_DEBUG "ccw[1].cda = %08x\n", ch->ccw[1].cda);
+#endif
+		rc = do_IO(ch->irq, &ch->ccw[0], (intparm_t)ch, 0xff, 0);
 		ch->prof.doios_multi++;
 		if (rc != 0) {
+			privptr->stats.tx_dropped += i;
+			privptr->stats.tx_errors += i;
 			fsm_deltimer(&ch->timer);
-			i = 0;
-			while ((skb = skb_dequeue(&ch->io_queue))) {
-				privptr->stats.tx_dropped++;
-				privptr->stats.tx_errors++;
-				atomic_dec(&skb->users);
-				dev_kfree_skb(skb);
-				i++;
-			}
-			kfree(ch->dccw);
-			ch->dccw = NULL;
-			if (i != ch->dccw_count)
-				printk(KERN_WARNING "ctc: i != nccws !!!\n");
 			ccw_check_return_code(ch, rc);
 		}
 	} else
@@ -1096,10 +1085,10 @@
 	net_device     *dev = ch->netdev;
 	ctc_priv       *privptr = dev->priv;
 	int            len = ch->max_bufsize - ch->devstat->rescnt;
-	struct sk_buff *skb = ch->rx_skb;
+	struct sk_buff *skb = ch->trans_skb;
 	__u16          block_len = *((__u16*)skb->data);
 	char           *saved_data = skb->data;
-	int            queued = 0;
+	int            check_len;
 	int            rc;
 
 	fsm_deltimer(&ch->timer);
@@ -1117,17 +1106,26 @@
 		privptr->stats.rx_length_errors++;
 		goto again;
 	}
+
 	/**
 	 * VM TCP seems to have a bug sending 2 trailing bytes of garbage.
 	 */
-	if ((len < block_len) ||
-	    ((len > block_len) && (ch->protocol != CTC_PROTO_S390)) ||
-	    ((len > (block_len + 2)) && (ch->protocol == CTC_PROTO_S390))) {
-		printk(KERN_WARNING
-		       "%s: got block length %d != rx length %d\n", dev->name,
-		       block_len, len);
-		*((__u16*)skb->data) = len;
+	switch (ch->protocol) {
+		case CTC_PROTO_S390:
+		case CTC_PROTO_OS390:
+			check_len = block_len + 2;
+			break;
+		default:
+			check_len = block_len;
+			break;
+	}
+	if ((len < block_len) || (len > check_len)) {
+		printk(KERN_WARNING "%s: got block length %d != rx length %d\n",
+		       dev->name, block_len, len);
+#ifdef DEBUG
 		ctc_dump_skb(skb, 0);
+#endif
+		*((__u16*)skb->data) = len;
 		privptr->stats.rx_dropped++;
 		privptr->stats.rx_length_errors++;
 		goto again;
@@ -1135,31 +1133,24 @@
 	block_len -= 2;
 	if (block_len > 0) {
 		*((__u16*)skb->data) = block_len;
-		skb_queue_tail(&ch->io_queue, skb);
-		queued++;
+		ctc_unpack_skb(ch, skb);
 	}
  again:
-	if (queued) {
-		queue_task(&ch->tq, &tq_immediate);
-		mark_bh(IMMEDIATE_BH);
-		ch->rx_skb = dev_alloc_skb(ch->max_bufsize);
-		if (ch->rx_skb == NULL) {
-			printk(KERN_WARNING "%s: Couldn't alloc rx_skb in "
-			       "ch_action_rx\n", dev->name);
-			/* TODO: retry after bottom half */
-			return;
-		}
-	} else {
-		skb->data = skb->tail = saved_data;
-		skb->len = 0;
-	}
+	skb->data = skb->tail = saved_data;
+	skb->len = 0;
+	if (ctc_checkalloc_buffer(ch, 1))
+		return;
 	ch->ccw[1].count = ch->max_bufsize;
-	set_normalized_cda(&ch->ccw[1], virt_to_phys(ch->rx_skb->data));
+#ifdef DEBUG
+	printk(KERN_DEBUG "ccw[1].cda = %08x\n", ch->ccw[1].cda);
+#endif
 	rc = do_IO(ch->irq, &ch->ccw[0], (intparm_t)ch, 0xff, 0);
 	if (rc != 0)
 		ccw_check_return_code(ch, rc);
 }
 
+static void ch_action_rxidle(fsm_instance *fi, int event, void *arg);
+
 /**
  * Initialize connection by sending a __u16 of value 0.
  *
@@ -1176,6 +1167,25 @@
 		printk(KERN_DEBUG "ch-%04x: remote side issued READ?, "
 		       "init ...\n", ch->devno);
 	fsm_deltimer(&ch->timer);
+	if (ctc_checkalloc_buffer(ch, 1))
+		return;
+	if ((fsm_getstate(fi) == CH_STATE_SETUPWAIT) &&
+	    (ch->protocol == CTC_PROTO_OS390)) {
+		/* OS/390 resp. z/OS */
+		if (CHANNEL_DIRECTION(ch->flags) == READ) {
+			*((__u16 *)ch->trans_skb->data) = CTC_INITIAL_BLOCKLEN;
+			fsm_addtimer(&ch->timer, CTC_TIMEOUT_5SEC,
+				     CH_EVENT_TIMER, ch);
+			ch_action_rxidle(fi, event, arg);
+		} else {
+			net_device *dev = ch->netdev;
+			fsm_newstate(fi, CH_STATE_TXIDLE);
+			fsm_event(((ctc_priv *)dev->priv)->fsm,
+				  DEV_EVENT_TXUP, dev);
+		}
+		return;
+	}
+
 	/**
 	 * Don´t setup a timer for receiving the initial RX frame
 	 * if in compatibility mode, since VM TCP delays the initial
@@ -1185,9 +1195,12 @@
 	    (ch->protocol != CTC_PROTO_S390))
 		fsm_addtimer(&ch->timer, CTC_TIMEOUT_5SEC, CH_EVENT_TIMER, ch);
 
-	ch->dummy_buf    = CTC_INITIAL_BLOCKLEN;
+	*((__u16 *)ch->trans_skb->data) = CTC_INITIAL_BLOCKLEN;
 	ch->ccw[1].count = 2; /* Transfer only length */
-	set_normalized_cda(&ch->ccw[1], virt_to_phys(&ch->dummy_buf));
+
+#ifdef DEBUG
+	printk(KERN_DEBUG "ccw[1].cda = %08x\n", ch->ccw[1].cda);
+#endif
 	fsm_newstate(fi, (CHANNEL_DIRECTION(ch->flags) == READ)
 		     ? CH_STATE_RXINIT : CH_STATE_TXINIT);
 	rc = do_IO(ch->irq, &ch->ccw[0], (intparm_t)ch, 0xff, 0);
@@ -1223,20 +1236,22 @@
 {
 	channel    *ch = (channel *)arg;
 	net_device *dev = ch->netdev;
+	__u16      buflen;
 	int        rc;
 
 	fsm_deltimer(&ch->timer);
-	if (ch->dummy_buf >= CTC_INITIAL_BLOCKLEN) {
-		ch->rx_skb = dev_alloc_skb(ch->max_bufsize);
-		if (ch->rx_skb == NULL) {
-			printk(KERN_WARNING "%s: Couldn't alloc rx_skb in "
-			       "ch_action_rxidle\n", dev->name);
+	buflen = *((__u16 *)ch->trans_skb->data);
+#ifdef DEBUG
+	printk(KERN_DEBUG "%s: Initial RX count %d\n", dev->name, buflen);
+#endif
+	if (buflen >= CTC_INITIAL_BLOCKLEN) {
+		if (ctc_checkalloc_buffer(ch, 1))
 			return;
-		}
 		ch->ccw[1].count = ch->max_bufsize;
-		set_normalized_cda(&ch->ccw[1],
-				   virt_to_phys(ch->rx_skb->data));
 		fsm_newstate(fi, CH_STATE_RXIDLE);
+#ifdef DEBUG
+	printk(KERN_DEBUG "ccw[1].cda = %08x\n", ch->ccw[1].cda);
+#endif
 		rc = do_IO(ch->irq, &ch->ccw[0], (intparm_t)ch, 0xff, 0);
 		if (rc != 0) {
 			fsm_newstate(fi, CH_STATE_RXINIT);
@@ -1246,7 +1261,7 @@
 				  DEV_EVENT_RXUP, dev);
 	} else {
 		printk(KERN_DEBUG "%s: Initial RX count %d not %d\n",
-		       dev->name, ch->dummy_buf, CTC_INITIAL_BLOCKLEN);
+		       dev->name, buflen, CTC_INITIAL_BLOCKLEN);
 		ch_action_firstio(fi, event, arg);
 	}
 }
@@ -1269,7 +1284,7 @@
 	fsm_newstate(fi, CH_STATE_SETUPWAIT);
 	if (event == CH_EVENT_TIMER)
 		s390irq_spin_lock_irqsave(ch->irq, saveflags);
-	rc = do_IO(ch->irq, &ch->ccw[3], (intparm_t)ch, 0xff, 0);
+	rc = do_IO(ch->irq, &ch->ccw[6], (intparm_t)ch, 0xff, 0);
 	if (event == CH_EVENT_TIMER)
 		s390irq_spin_unlock_irqrestore(ch->irq, saveflags);
 	if (rc != 0) {
@@ -1303,15 +1318,30 @@
 		       ch->irq);
 		return;
 	}
-
- dev = ch->netdev;
+	dev = ch->netdev;
 
 #ifdef DEBUG
 	printk(KERN_DEBUG "%s: %s channel start\n", dev->name,
 	       (CHANNEL_DIRECTION(ch->flags) == READ) ? "RX" : "TX");
 #endif
 
+	if (ch->trans_skb != NULL) {
+		clear_normalized_cda(&ch->ccw[1]);
+		dev_kfree_skb(ch->trans_skb);
+		ch->trans_skb = NULL;
+	}
+	if (ctc_checkalloc_buffer(ch, 0))
+		printk(KERN_NOTICE
+		       "%s: Could not allocate %s trans_skb, delaying "
+		       "allocation until first transfer\n",
+		       dev->name, 
+		       (CHANNEL_DIRECTION(ch->flags) == READ) ? "RX" : "TX");
+
+#if LINUX_VERSION_CODE >= 0x020400
 	INIT_LIST_HEAD(&ch->tq.list);
+#else
+	ch->tq.next = NULL;
+#endif
 	ch->tq.sync    = 0;
 	ch->tq.routine = (void *)(void *)ctc_bh;
 	ch->tq.data    = ch;
@@ -1324,17 +1354,18 @@
 		ch->ccw[1].cmd_code = CCW_CMD_READ;
 		ch->ccw[1].flags    = CCW_FLAG_SLI;
 		ch->ccw[1].count    = 0;
-		ch->ccw[1].cda	    = 0;
 	} else {
 		ch->ccw[1].cmd_code = CCW_CMD_WRITE;
 		ch->ccw[1].flags    = CCW_FLAG_SLI | CCW_FLAG_CC;
 		ch->ccw[1].count    = 0;
-		ch->ccw[1].cda	    = 0;
 	}
 	ch->ccw[2].cmd_code = CCW_CMD_NOOP;	 /* jointed CE + DE */
 	ch->ccw[2].flags    = CCW_FLAG_SLI;
 	ch->ccw[2].count    = 0;
 	ch->ccw[2].cda	    = 0;
+	memcpy(&ch->ccw[3], &ch->ccw[0], sizeof(ccw1_t) * 3);
+	ch->ccw[4].cda	    = 0;
+
 	fsm_newstate(fi, CH_STATE_STARTWAIT);
 	fsm_addtimer(&ch->timer, 1000, CH_EVENT_TIMER, ch);
 	s390irq_spin_lock_irqsave(ch->irq, saveflags);
@@ -1392,26 +1423,62 @@
 	channel *ch = (channel *)arg;
 	net_device *dev = ch->netdev;
 
-	if (ch->dccw) {
-		printk(KERN_WARNING "ch_action_stopped: dccw !NULL\n");
-		return;
-	}
 	fsm_deltimer(&ch->timer);
 	fsm_newstate(fi, CH_STATE_STOPPED);
+	if (ch->trans_skb != NULL) {
+		clear_normalized_cda(&ch->ccw[1]);
+		dev_kfree_skb(ch->trans_skb);
+		ch->trans_skb = NULL;
+	}
+	if (CHANNEL_DIRECTION(ch->flags) == READ) {
+		skb_queue_purge(&ch->io_queue);
+		fsm_event(((ctc_priv *)dev->priv)->fsm, DEV_EVENT_RXDOWN, dev);
+	} else {
+		ctc_purge_skb_queue(&ch->io_queue);
+		spin_lock(&ch->collect_lock);
+		ctc_purge_skb_queue(&ch->collect_queue);
+		ch->collect_len = 0;
+		spin_unlock(&ch->collect_lock);
+		fsm_event(((ctc_priv *)dev->priv)->fsm, DEV_EVENT_TXDOWN, dev);
+	}
+}
+
+/**
+ * A stop command from device statemachine arrived and we are in
+ * not operational mode. Set state to stopped.
+ *
+ * @param fi    An instance of a channel statemachine.
+ * @param event The event, just happened.
+ * @param arg   Generic pointer, casted from channel * upon call.
+ */
+static void ch_action_stop(fsm_instance *fi, int event, void *arg)
+{
+	fsm_newstate(fi, CH_STATE_STOPPED);
+}
+
+/**
+ * A machine check for no path, not operational status or gone device has
+ * happened.
+ * Cleanup queue and notify interface statemachine.
+ *
+ * @param fi    An instance of a channel statemachine.
+ * @param event The event, just happened.
+ * @param arg   Generic pointer, casted from channel * upon call.
+ */
+static void ch_action_fail(fsm_instance *fi, int event, void *arg)
+{
+	channel *ch = (channel *)arg;
+	net_device *dev = ch->netdev;
+
+	fsm_deltimer(&ch->timer);
+	fsm_newstate(fi, CH_STATE_NOTOP);
 	if (CHANNEL_DIRECTION(ch->flags) == READ) {
 		skb_queue_purge(&ch->io_queue);
-		if (ch->rx_skb != NULL) {
-			dev_kfree_skb(ch->rx_skb);
-			ch->rx_skb = NULL;
-		}
 		fsm_event(((ctc_priv *)dev->priv)->fsm, DEV_EVENT_RXDOWN, dev);
 	} else {
 		ctc_purge_skb_queue(&ch->io_queue);
 		spin_lock(&ch->collect_lock);
 		ctc_purge_skb_queue(&ch->collect_queue);
-		if (ch->dccw)
-			kfree(ch->dccw);
-		ch->dccw = NULL;
 		ch->collect_len = 0;
 		spin_unlock(&ch->collect_lock);
 		fsm_event(((ctc_priv *)dev->priv)->fsm, DEV_EVENT_TXDOWN, dev);
@@ -1629,20 +1696,25 @@
 		if ((skb = skb_peek(&ch->io_queue))) {
 			int rc = 0;
 
+			set_normalized_cda(&ch->ccw[4],
+					   virt_to_phys(skb->data));
+			if (ch->ccw[4].cda == 0) {
+				printk(KERN_DEBUG "%s: IDAL alloc failed, "
+				       "restarting channel\n", dev->name);
+				fsm_event(((ctc_priv *)dev->priv)->fsm,
+					  DEV_EVENT_TXDOWN, dev);
+				ch_action_restart(fi, event, arg);
+				return;
+			}
 			fsm_addtimer(&ch->timer, 1000, CH_EVENT_TIMER, ch);
 			if (event == CH_EVENT_TIMER)
 				s390irq_spin_lock_irqsave(ch->irq, saveflags);
-			if (ch->dccw)
-				rc = do_IO(ch->irq, ch->dccw, (intparm_t)ch,
-					   0xff, 0);
-			else {
-				clear_normalized_cda(&ch->ccw[1]);
-				ch->ccw[1].count = skb->len;
-				set_normalized_cda(&ch->ccw[1],
-						   virt_to_phys(skb->data));
-				rc = do_IO(ch->irq, &ch->ccw[0],
-					   (intparm_t)ch, 0xff, 0);
-			}
+			ch->ccw[4].count = skb->len;
+#ifdef DEBUG
+	printk(KERN_DEBUG "ccw[4].cda = %08x\n", ch->ccw[4].cda);
+#endif
+			rc = do_IO(ch->irq, &ch->ccw[3],
+				   (intparm_t)ch, 0xff, 0);
 			if (event == CH_EVENT_TIMER)
 				s390irq_spin_unlock_irqrestore(ch->irq,
 							       saveflags);
@@ -1687,6 +1759,13 @@
 	{ CH_STATE_STOPPED,    CH_EVENT_STOP,       fsm_action_nop       },
 	{ CH_STATE_STOPPED,    CH_EVENT_START,      ch_action_start      },
 	{ CH_STATE_STOPPED,    CH_EVENT_FINSTAT,    fsm_action_nop       },
+	{ CH_STATE_STOPPED,    CH_EVENT_MC_FAIL,    fsm_action_nop       },
+
+	{ CH_STATE_NOTOP,      CH_EVENT_STOP,       ch_action_stop       },
+	{ CH_STATE_NOTOP,      CH_EVENT_START,      fsm_action_nop       },
+	{ CH_STATE_NOTOP,      CH_EVENT_FINSTAT,    fsm_action_nop       },
+	{ CH_STATE_NOTOP,      CH_EVENT_MC_FAIL,    fsm_action_nop       },
+	{ CH_STATE_NOTOP,      CH_EVENT_MC_GOOD,    ch_action_start      },
 
 	{ CH_STATE_STARTWAIT,  CH_EVENT_STOP,       ch_action_haltio     },
 	{ CH_STATE_STARTWAIT,  CH_EVENT_START,      fsm_action_nop       },
@@ -1694,10 +1773,12 @@
 	{ CH_STATE_STARTWAIT,  CH_EVENT_TIMER,      ch_action_setuperr   },
 	{ CH_STATE_STARTWAIT,  CH_EVENT_IO_ENODEV,  ch_action_iofatal    },
 	{ CH_STATE_STARTWAIT,  CH_EVENT_IO_EIO,     ch_action_iofatal    },
+	{ CH_STATE_STARTWAIT,  CH_EVENT_MC_FAIL,    ch_action_fail       },
 
 	{ CH_STATE_STARTRETRY, CH_EVENT_STOP,       ch_action_haltio     },
 	{ CH_STATE_STARTRETRY, CH_EVENT_TIMER,      ch_action_setmode    },
 	{ CH_STATE_STARTRETRY, CH_EVENT_FINSTAT,    fsm_action_nop       },
+	{ CH_STATE_STARTRETRY, CH_EVENT_MC_FAIL,    ch_action_fail       },
 
 	{ CH_STATE_SETUPWAIT,  CH_EVENT_STOP,       ch_action_haltio     },
 	{ CH_STATE_SETUPWAIT,  CH_EVENT_START,      fsm_action_nop       },
@@ -1707,6 +1788,7 @@
 	{ CH_STATE_SETUPWAIT,  CH_EVENT_TIMER,      ch_action_setmode    },
 	{ CH_STATE_SETUPWAIT,  CH_EVENT_IO_ENODEV,  ch_action_iofatal    },
 	{ CH_STATE_SETUPWAIT,  CH_EVENT_IO_EIO,     ch_action_iofatal    },
+	{ CH_STATE_SETUPWAIT,  CH_EVENT_MC_FAIL,    ch_action_fail       },
 
 	{ CH_STATE_RXINIT,     CH_EVENT_STOP,       ch_action_haltio     },
 	{ CH_STATE_RXINIT,     CH_EVENT_START,      fsm_action_nop       },
@@ -1718,6 +1800,7 @@
 	{ CH_STATE_RXINIT,     CH_EVENT_IO_ENODEV,  ch_action_iofatal    },
 	{ CH_STATE_RXINIT,     CH_EVENT_IO_EIO,     ch_action_iofatal    },
 	{ CH_STATE_RXINIT,     CH_EVENT_UC_ZERO,    ch_action_firstio    },
+	{ CH_STATE_RXINIT,     CH_EVENT_MC_FAIL,    ch_action_fail       },
 
 	{ CH_STATE_RXIDLE,     CH_EVENT_STOP,       ch_action_haltio     },
 	{ CH_STATE_RXIDLE,     CH_EVENT_START,      fsm_action_nop       },
@@ -1726,6 +1809,8 @@
 //	{ CH_STATE_RXIDLE,     CH_EVENT_UC_RSRESET, ch_action_rxretry    },
 	{ CH_STATE_RXIDLE,     CH_EVENT_IO_ENODEV,  ch_action_iofatal    },
 	{ CH_STATE_RXIDLE,     CH_EVENT_IO_EIO,     ch_action_iofatal    },
+	{ CH_STATE_RXIDLE,     CH_EVENT_MC_FAIL,    ch_action_fail       },
+	{ CH_STATE_RXIDLE,     CH_EVENT_UC_ZERO,    ch_action_rx         },
 
 	{ CH_STATE_TXINIT,     CH_EVENT_STOP,       ch_action_haltio     },
 	{ CH_STATE_TXINIT,     CH_EVENT_START,      fsm_action_nop       },
@@ -1735,6 +1820,7 @@
 	{ CH_STATE_TXINIT,     CH_EVENT_TIMER,      ch_action_txiniterr  },
 	{ CH_STATE_TXINIT,     CH_EVENT_IO_ENODEV,  ch_action_iofatal    },
 	{ CH_STATE_TXINIT,     CH_EVENT_IO_EIO,     ch_action_iofatal    },
+	{ CH_STATE_TXINIT,     CH_EVENT_MC_FAIL,    ch_action_fail       },
 
 	{ CH_STATE_TXIDLE,     CH_EVENT_STOP,       ch_action_haltio     },
 	{ CH_STATE_TXIDLE,     CH_EVENT_START,      fsm_action_nop       },
@@ -1743,18 +1829,21 @@
 	{ CH_STATE_TXIDLE,     CH_EVENT_UC_RSRESET, fsm_action_nop       },
 	{ CH_STATE_TXIDLE,     CH_EVENT_IO_ENODEV,  ch_action_iofatal    },
 	{ CH_STATE_TXIDLE,     CH_EVENT_IO_EIO,     ch_action_iofatal    },
+	{ CH_STATE_TXIDLE,     CH_EVENT_MC_FAIL,    ch_action_fail       },
 
 	{ CH_STATE_TERM,       CH_EVENT_STOP,       fsm_action_nop       },
 	{ CH_STATE_TERM,       CH_EVENT_START,      ch_action_restart    },
 	{ CH_STATE_TERM,       CH_EVENT_FINSTAT,    ch_action_stopped    },
 	{ CH_STATE_TERM,       CH_EVENT_UC_RCRESET, fsm_action_nop       },
 	{ CH_STATE_TERM,       CH_EVENT_UC_RSRESET, fsm_action_nop       },
+	{ CH_STATE_TERM,       CH_EVENT_MC_FAIL,    ch_action_fail       },
 
 	{ CH_STATE_DTERM,      CH_EVENT_STOP,       ch_action_haltio     },
 	{ CH_STATE_DTERM,      CH_EVENT_START,      ch_action_restart    },
 	{ CH_STATE_DTERM,      CH_EVENT_FINSTAT,    ch_action_setmode    },
 	{ CH_STATE_DTERM,      CH_EVENT_UC_RCRESET, fsm_action_nop       },
 	{ CH_STATE_DTERM,      CH_EVENT_UC_RSRESET, fsm_action_nop       },
+	{ CH_STATE_DTERM,      CH_EVENT_MC_FAIL,    ch_action_fail       },
 
 	{ CH_STATE_TX,         CH_EVENT_STOP,       ch_action_haltio     },
 	{ CH_STATE_TX,         CH_EVENT_START,      fsm_action_nop       },
@@ -1764,9 +1853,12 @@
 	{ CH_STATE_TX,         CH_EVENT_TIMER,      ch_action_txretry    },
 	{ CH_STATE_TX,         CH_EVENT_IO_ENODEV,  ch_action_iofatal    },
 	{ CH_STATE_TX,         CH_EVENT_IO_EIO,     ch_action_iofatal    },
+	{ CH_STATE_TX,         CH_EVENT_MC_FAIL,    ch_action_fail       },
 
 	{ CH_STATE_RXERR,      CH_EVENT_STOP,       ch_action_haltio     },
 	{ CH_STATE_TXERR,      CH_EVENT_STOP,       ch_action_haltio     },
+	{ CH_STATE_TXERR,      CH_EVENT_MC_FAIL,    ch_action_fail       },
+	{ CH_STATE_RXERR,      CH_EVENT_MC_FAIL,    ch_action_fail       },
 };
 
 static const int CH_FSM_LEN = sizeof(ch_fsm) / sizeof(fsm_node);
@@ -1796,7 +1888,7 @@
 		return -1;
 	}
 	memset(ch, 0, sizeof(channel));
-	if ((ch->ccw = (ccw1_t *)kmalloc(sizeof(ccw1_t) * 5,
+	if ((ch->ccw = (ccw1_t *)kmalloc(sizeof(ccw1_t) * 8,
 					 GFP_KERNEL|GFP_DMA)) == NULL) {
 		kfree(ch);
 		printk(KERN_WARNING "ctc: Out of memory in add_channel\n");
@@ -1808,24 +1900,29 @@
 	 *
 	 * ccw[0..2] (Channel program for generic I/O):
 	 *           0: prepare
-	 *           1: read or write (depending on direction)
+	 *           1: read or write (depending on direction) with fixed
+	 *              buffer (idal allocated once when buffer is allocated)
 	 *           2: nop
-	 * ccw[3..4] (Channel program for initial channel setup):
+	 * ccw[3..5] (Channel program for direct write of packets)
+	 *           3: prepare
+	 *           4: write (idal allocated on every write).
+	 *           5: nop
+	 * ccw[6..7] (Channel program for initial channel setup):
 	 *           3: set extended mode
 	 *           4: nop
 	 *
-	 * ch->ccw[0..2] are initialized in ch_action_start because
+	 * ch->ccw[0..5] are initialized in ch_action_start because
 	 * the channel's direction is yet unknown here.
 	 */
-	ch->ccw[3].cmd_code = CCW_CMD_SET_EXTENDED;
-	ch->ccw[3].flags    = CCW_FLAG_SLI;
-	ch->ccw[3].count    = 0;
-	ch->ccw[3].cda      = 0;
+	ch->ccw[6].cmd_code = CCW_CMD_SET_EXTENDED;
+	ch->ccw[6].flags    = CCW_FLAG_SLI;
+	ch->ccw[6].count    = 0;
+	ch->ccw[6].cda      = 0;
 	
-	ch->ccw[4].cmd_code = CCW_CMD_NOOP;
-	ch->ccw[4].flags    = CCW_FLAG_SLI;
-	ch->ccw[4].count    = 0;
-	ch->ccw[4].cda      = 0;
+	ch->ccw[7].cmd_code = CCW_CMD_NOOP;
+	ch->ccw[7].flags    = CCW_FLAG_SLI;
+	ch->ccw[7].count    = 0;
+	ch->ccw[7].cda      = 0;
 
 	ch->irq = irq;
 	ch->devno = devno;
@@ -1835,7 +1932,8 @@
 			ch_event_names, NR_CH_STATES, NR_CH_EVENTS,
 			ch_fsm, CH_FSM_LEN, GFP_KERNEL);
 	if (ch->fsm == NULL) {
-		printk(KERN_WARNING "ctc: Could not create FSM in add_channel\n");
+		printk(KERN_WARNING
+		       "ctc: Could not create FSM in add_channel\n");
 		kfree(ch);
 		return -1;
 	}
@@ -1852,8 +1950,8 @@
 		c = &(*c)->next;
 	if ((*c)->devno == devno) {
 		printk(KERN_DEBUG
-		       "ctc: add_channel: device %04x already in list\n",
-		       (*c)->devno);
+		       "ctc: add_channel: device %04x already in list, "
+		       "using old entry\n", (*c)->devno);
 		kfree(ch->devstat);
 		kfree_fsm(ch->fsm);
 		kfree(ch);
@@ -1867,14 +1965,14 @@
 	return 0;
 }
 
+#ifndef CTC_CHANDEV
 /**
  * scan for all channels and create an entry in the channels list
  * for every supported channel.
- *
- * @param print_result Flag: If !0, print a final result.
  */
-static void channel_scan(int print_result)
+static void channel_scan(void)
 {
+	static int      print_result = 1;
 	int	        irq;
 	int             nr_escon = 0;
 	int             nr_ctca  = 0;
@@ -1912,7 +2010,9 @@
 		else
 			printk(KERN_INFO "ctc: No channel devices found.\n");
 	}
+	print_result = 0;
 }
+#endif
 
 /**
  * Release a specific channel in the channel list.
@@ -1925,6 +2025,40 @@
 	fsm_newstate(ch->fsm, CH_STATE_IDLE);
 }
 
+/**
+ * Remove a specific channel in the channel list.
+ *
+ * @param ch Pointer to channel struct to be released.
+ */
+static void channel_remove(channel *ch)
+{
+	channel **c = &channels;
+
+	if (ch == NULL)
+		return;
+
+#ifndef CTC_CHANDEV
+	if (ch->flags & CHANNEL_FLAGS_INUSE)
+		FREE_IRQ(ch->irq, ch->devstat);
+#endif
+	channel_free(ch);
+	while (*c) {
+		if (*c == ch) {
+			*c = ch->next;
+			fsm_deltimer(&ch->timer);
+			kfree_fsm(ch->fsm);
+			clear_normalized_cda(&ch->ccw[4]);
+			if (ch->trans_skb != NULL) {
+				clear_normalized_cda(&ch->ccw[1]);
+				dev_kfree_skb(ch->trans_skb);
+			}
+			kfree(ch->ccw);
+			return;
+		}
+		c = &((*c)->next);
+	}
+}
+
 
 /**
  * Get a specific channel from the channel list.
@@ -1977,7 +2111,7 @@
 	return ch;
 }
 
-
+#ifndef CTC_CHANDEV
 /**
  * Get the next free channel from the channel list
  *
@@ -2001,6 +2135,7 @@
 	}
 	return ch;
 }
+#endif
 
 /**
  * Return the channel type by name.
@@ -2065,7 +2200,6 @@
 		}
 	}
 
-	clear_normalized_cda(&ch->ccw[1]);
 	dev = (net_device *)(ch->netdev);
 	if (dev == NULL) {
 		printk(KERN_CRIT
@@ -2173,6 +2307,7 @@
 static void dev_action_chup(fsm_instance *fi, int event, void *arg)
 {
 	net_device *dev = (net_device *)arg;
+	ctc_priv   *privptr = dev->priv;
 
 	switch (fsm_getstate(fi)) {
 		case DEV_STATE_STARTWAIT_RXTX:
@@ -2187,6 +2322,8 @@
 				printk(KERN_INFO
 				       "%s: connected with remote side\n",
 				       dev->name);
+				if (privptr->protocol == CTC_PROTO_LINUX_TTY)
+					ctc_tty_setcarrier(dev, 1);
 				ctc_clear_busy(dev);
 			}
 			break;
@@ -2196,6 +2333,8 @@
 				printk(KERN_INFO
 				       "%s: connected with remote side\n",
 				       dev->name);
+				if (privptr->protocol == CTC_PROTO_LINUX_TTY)
+					ctc_tty_setcarrier(dev, 1);
 				ctc_clear_busy(dev);
 			}
 			break;
@@ -2220,8 +2359,13 @@
  */
 static void dev_action_chdown(fsm_instance *fi, int event, void *arg)
 {
+	net_device *dev = (net_device *)arg;
+	ctc_priv   *privptr = dev->priv;
+
 	switch (fsm_getstate(fi)) {
 		case DEV_STATE_RUNNING:
+			if (privptr->protocol == CTC_PROTO_LINUX_TTY)
+				ctc_tty_setcarrier(dev, 0);
 			if (event == DEV_EVENT_TXDOWN)
 				fsm_newstate(fi, DEV_STATE_STARTWAIT_TX);
 			else
@@ -2313,8 +2457,6 @@
 	if (fsm_getstate(ch->fsm) != CH_STATE_TXIDLE) {
 		int l = skb->len + LL_HEADER_LENGTH;
 
-		if (ch->type == channel_type_escon)
-			return -EBUSY;
 		spin_lock_irqsave(&ch->collect_lock, saveflags);
 		if (ch->collect_len + l > ch->max_bufsize - 2)
 			rc = -EBUSY;
@@ -2331,6 +2473,7 @@
 		spin_unlock_irqrestore(&ch->collect_lock, saveflags);
 	} else {
 		__u16 block_len;
+		int ccw_idx;
 
 		/**
 		 * Protect skb against beeing free'd by upper
@@ -2345,17 +2488,52 @@
 		       LL_HEADER_LENGTH);
 		block_len = skb->len + 2;
 		*((__u16 *)skb_push(skb, 2)) = block_len;
-		skb_queue_tail(&ch->io_queue, skb);
+		set_normalized_cda(&ch->ccw[4], virt_to_phys(skb->data));
+		if (ch->ccw[4].cda == 0) {
+			/**
+			 * idal allocation failed, try via copying to
+			 * trans_skb. trans_skb usually has a pre-allocated
+			 * idal.
+			 */
+			if (ctc_checkalloc_buffer(ch, 1)) {
+				/**
+				 * Remove our header. It gets added
+				 * again on retransmit.
+				 */
+				skb_pull(skb, LL_HEADER_LENGTH + 2);
+				return -EBUSY;
+			}
+
+			ch->trans_skb->tail = ch->trans_skb->data;
+			ch->trans_skb->len = 0;
+			ch->ccw[1].count = skb->len;
+			memcpy(skb_put(ch->trans_skb, skb->len), skb->data,
+			       skb->len);
+			atomic_dec(&skb->users);
+			dev_kfree_skb_irq(skb);
+			ccw_idx = 0;
+		} else {
+			ch->ccw[4].count = block_len;
+			skb_queue_tail(&ch->io_queue, skb);
+			ccw_idx = 3;
+		}
 		ch->retry = 0;
+#ifdef DEBUG
+		ctc_dump_skb(skb, 0);
+#endif
 		fsm_newstate(ch->fsm, CH_STATE_TX);
-		fsm_addtimer(&ch->timer, CTC_TIMEOUT_5SEC, CH_EVENT_TIMER, ch);
-		ch->ccw[1].count = block_len;
-		set_normalized_cda(&ch->ccw[1], virt_to_phys(skb->data));
+		fsm_addtimer(&ch->timer, CTC_TIMEOUT_5SEC,
+			     CH_EVENT_TIMER, ch);
 		s390irq_spin_lock_irqsave(ch->irq, saveflags);
 		ch->prof.send_stamp = xtime;
-		rc = do_IO(ch->irq, &ch->ccw[0], (intparm_t)ch, 0xff, 0);
+#ifdef DEBUG
+	printk(KERN_DEBUG "ccw[%d].cda = %08x\n", ccw_idx+1,
+	       ch->ccw[ccw_idx+1].cda);
+#endif
+		rc = do_IO(ch->irq, &ch->ccw[ccw_idx], (intparm_t)ch, 0xff, 0);
 		s390irq_spin_unlock_irqrestore(ch->irq, saveflags);
-		ch->prof.doios_single++;
+		if (ccw_idx == 3)
+			ch->prof.doios_single++;
 		if (rc != 0) {
 			fsm_deltimer(&ch->timer);
 			ccw_check_return_code(ch, rc);
@@ -2365,6 +2543,14 @@
 			 * again on retransmit.
 			 */
 			skb_pull(skb, LL_HEADER_LENGTH + 2);
+		} else {
+			if (ccw_idx == 0) {
+				net_device *dev = ch->netdev;
+				ctc_priv   *privptr = dev->priv;
+				privptr->stats.tx_packets++;
+				privptr->stats.tx_bytes +=
+					skb->len - LL_HEADER_LENGTH;
+			}
 		}
 	}
 
@@ -2429,8 +2615,9 @@
 		return 0;
 	}
 	if (skb_headroom(skb) < (LL_HEADER_LENGTH + 2)) {
-		printk(KERN_WARNING "%s: Got sk_buff with head room < %ld bytes\n",
-				dev->name, LL_HEADER_LENGTH + 2);
+		printk(KERN_WARNING
+		       "%s: Got sk_buff with head room < %ld bytes\n",
+		       dev->name, LL_HEADER_LENGTH + 2);
 		dev_kfree_skb(skb);
 		privptr->stats.tx_dropped++;
 		return 0;
@@ -2443,6 +2630,8 @@
 	 */
 	if (fsm_getstate(privptr->fsm) != DEV_STATE_RUNNING) {
 		fsm_event(privptr->fsm, DEV_EVENT_START, dev);
+		if (privptr->protocol == CTC_PROTO_LINUX_TTY)
+			return -EBUSY;
 		dst_link_failure(skb);
 		dev_kfree_skb(skb);
 		privptr->stats.tx_dropped++;
@@ -2577,12 +2766,23 @@
 		return -EFAULT;
 	tmp[count+1] = '\0';
 	bs1 = simple_strtoul(tmp, &e, 0);
+
 	if ((bs1 > CTC_BUFSIZE_LIMIT) ||
-	    (bs1 < (dev->mtu - LL_HEADER_LENGTH - 2)) ||
 	    (e && (!isspace(*e))))
 		return -EINVAL;
+	if ((dev->flags & IFF_RUNNING) &&
+	    (bs1 < (dev->mtu + LL_HEADER_LENGTH + 2)))
+		return -EINVAL;
+	if (bs1 < (576 + LL_HEADER_LENGTH + 2))
+		return -EINVAL;
+
+
 	privptr->channel[READ]->max_bufsize =
 		privptr->channel[WRITE]->max_bufsize = bs1;
+	if (!(dev->flags & IFF_RUNNING))
+		dev->mtu = bs1 - LL_HEADER_LENGTH - 2;
+	privptr->channel[READ]->flags |= CHANNEL_FLAGS_BUFSIZE_CHANGED;
+	privptr->channel[WRITE]->flags |= CHANNEL_FLAGS_BUFSIZE_CHANGED;
 
 	return count;
 }
@@ -2685,7 +2885,7 @@
 			     fsm_getstate_str(privptr->channel[WRITE]->fsm));
 		p += sprintf(p, "Max. TX buffer used: %ld\n",
 			     privptr->channel[WRITE]->prof.maxmulti);
-		p += sprintf(p, "Max. chained CCWs: %ld\n",
+		p += sprintf(p, "Max. chained SKBs: %ld\n",
 			     privptr->channel[WRITE]->prof.maxcqueue);
 		p += sprintf(p, "TX single write ops: %ld\n",
 			     privptr->channel[WRITE]->prof.doios_single);
@@ -2853,15 +3053,18 @@
 	proc_register(privptr->proc_dentry, privptr->proc_stat_entry);
 	proc_register(privptr->proc_dentry, privptr->proc_ctrl_entry);
 #endif
+	privptr->proc_registered = 1;
 }
 
-#ifdef MODULE
+
 /**
  * Destroy a device specific subdirectory.
  *
  * @param privptr Pointer to device private data.
  */
 static void ctc_proc_destroy_sub(ctc_priv *privptr) {
+	if (!privptr->proc_registered)
+		return;
 #if LINUX_VERSION_CODE > 0x020362
 	remove_proc_entry("statistics", privptr->proc_dentry);
 	remove_proc_entry("buffersize", privptr->proc_dentry);
@@ -2874,9 +3077,12 @@
 	proc_unregister(&ctc_dir,
 			privptr->proc_dentry->low_ino);
 #endif
+	privptr->proc_registered = 0;
 }
-#endif MODULE
+
 
+
+#ifndef CTC_CHANDEV
 /**
  * Setup related routines
  *****************************************************************************/
@@ -2991,7 +3197,8 @@
 #else
 static param parms_array[MAX_STATIC_DEVICES];
 static param *next_param = parms_array;
-#define alloc_param() ((next_param<parms_array+MAX_STATIC_DEVICES)?next_param++:NULL)
+#define alloc_param() \
+        ((next_param<parms_array+MAX_STATIC_DEVICES)?next_param++:NULL)
 #endif MODULE
 
 /**
@@ -3159,7 +3366,313 @@
 #if LINUX_VERSION_CODE >= 0x020300
 __setup("ctc=", ctc_setup);
 #endif
+#endif /* !CTC_CHANDEV */
 
+
+static void
+ctc_netdev_unregister(net_device *dev)
+{
+	ctc_priv *privptr;
+
+	if (!dev)
+		return;
+	privptr = (ctc_priv *)dev->priv;
+	if (privptr->protocol != CTC_PROTO_LINUX_TTY)
+		unregister_netdev(dev);
+	else
+		ctc_tty_unregister_netdev(dev);
+}
+
+static int
+ctc_netdev_register(net_device *dev)
+{
+	ctc_priv *privptr = (ctc_priv *)dev->priv;
+	if (privptr->protocol != CTC_PROTO_LINUX_TTY)
+		return register_netdev(dev);
+	else
+		return ctc_tty_register_netdev(dev);
+}
+
+static void
+ctc_free_netdevice(net_device *dev, int free_dev)
+{
+	ctc_priv *privptr;
+	if (!dev)
+		return;
+	privptr = dev->priv;
+	if (privptr) {
+		if (privptr->fsm)
+			kfree_fsm(privptr->fsm);
+		ctc_proc_destroy_sub(privptr);
+		kfree(privptr);
+	}
+#ifdef MODULE
+	if (free_dev)
+		kfree(dev);
+#endif
+}
+
+#ifdef CTC_CHANDEV
+static int
+ctc_shutdown(net_device *dev)
+{
+	ctc_priv *privptr;
+
+	if (!dev)
+		return 0;
+	privptr = (ctc_priv *)dev->priv;
+	channel_remove(privptr->channel[READ]);
+	channel_remove(privptr->channel[WRITE]);
+	ctc_free_netdevice(dev, 0);
+	return 0;
+}
+#endif
+
+/**
+ * Initialize everything of the net device except the name and the
+ * channel structs.
+ */
+static net_device *
+ctc_init_netdevice(net_device *dev, int alloc_device)
+{
+	ctc_priv *privptr;
+	int      priv_size;
+	if (alloc_device) {
+		dev = kmalloc(sizeof(net_device)
+#if LINUX_VERSION_CODE < 0x020300
+			      + 11 /* name + zero */
+#endif
+			      , GFP_KERNEL);
+		if (!dev)
+			return NULL;
+		memset(dev, 0, sizeof(net_device));
+	}
+	priv_size = sizeof(ctc_priv) + sizeof(ctc_template) +
+		sizeof(stat_entry) + sizeof(ctrl_entry);
+	dev->priv = kmalloc(priv_size, GFP_KERNEL);
+	if (dev->priv == NULL) {
+		if (alloc_device)
+			kfree(dev);
+		return NULL;
+	}
+        memset(dev->priv, 0, priv_size);
+        privptr = (ctc_priv *)dev->priv;
+        privptr->proc_dentry = (struct proc_dir_entry *)
+		(((char *)privptr) + sizeof(ctc_priv));
+        privptr->proc_stat_entry = (struct proc_dir_entry *)
+		(((char *)privptr) + sizeof(ctc_priv) +
+		 sizeof(ctc_template));
+        privptr->proc_ctrl_entry = (struct proc_dir_entry *)
+		(((char *)privptr) + sizeof(ctc_priv) +
+		 sizeof(ctc_template) + sizeof(stat_entry));
+	memcpy(privptr->proc_dentry, &ctc_template, sizeof(ctc_template));
+	memcpy(privptr->proc_stat_entry, &stat_entry, sizeof(stat_entry));
+	memcpy(privptr->proc_ctrl_entry, &ctrl_entry, sizeof(ctrl_entry));
+	privptr->fsm = init_fsm("ctcdev", dev_state_names,
+			dev_event_names, NR_DEV_STATES, NR_DEV_EVENTS,
+			dev_fsm, DEV_FSM_LEN, GFP_KERNEL);
+	if (privptr->fsm == NULL) {
+		kfree(privptr);
+		if (alloc_device)
+			kfree(dev);
+		return NULL;
+	}
+	fsm_newstate(privptr->fsm, DEV_STATE_STOPPED);
+	dev->mtu	         = CTC_BUFSIZE_DEFAULT - LL_HEADER_LENGTH - 2;
+	dev->hard_start_xmit     = ctc_tx;
+	dev->open	         = ctc_open;
+	dev->stop	         = ctc_close;
+	dev->get_stats	         = ctc_stats;
+	dev->change_mtu          = ctc_change_mtu;
+	dev->hard_header_len     = LL_HEADER_LENGTH + 2;
+	dev->addr_len            = 0;
+	dev->type                = ARPHRD_SLIP;
+	dev->tx_queue_len        = 100;
+	SET_DEVICE_START(dev, 1);
+	dev_init_buffers(dev);
+	dev->flags	         = IFF_POINTOPOINT | IFF_NOARP;
+	return dev;
+}
+
+#ifdef CTC_CHANDEV
+static void
+ctc_chandev_msck_notify(void *dev, int msck_irq,
+			chandev_msck_status prevstatus,
+			chandev_msck_status newstatus)
+{
+	net_device *device = (net_device *)dev;
+	ctc_priv *privptr;
+	int direction;
+
+	if (!dev)
+		return;
+
+	privptr = device->priv;
+	if (prevstatus == chandev_status_revalidate)
+		for (direction = READ; direction <= WRITE; direction++) {
+			channel *ch = privptr->channel[direction];
+			if(ch->irq == msck_irq) {
+				s390_dev_info_t devinfo;
+
+				if (get_dev_info_by_irq(ch->irq, &devinfo))
+					ch->devno = devinfo.devno;
+				else
+					printk(KERN_WARNING
+					       "ctc_chandev_msck_notify: "
+					       "get_dev_info_by_irq failed for "
+					       "irq %d\n", ch->irq);
+			}
+		}
+	switch (newstatus) {
+		case chandev_status_not_oper:
+		case chandev_status_no_path:
+		case chandev_status_gone:
+			for (direction = READ; direction <= WRITE; direction++) {
+				channel *ch = privptr->channel[direction];
+				fsm_event(ch->fsm, CH_EVENT_MC_FAIL, ch);
+			}
+			printk(KERN_WARNING
+			       "ctc: %s channel deactivated\n", device->name);
+			break;
+		case chandev_status_all_chans_good:
+			for (direction = READ; direction <= WRITE; direction++) {
+				channel *ch = privptr->channel[direction];
+				fsm_event(ch->fsm, CH_EVENT_MC_GOOD, ch);
+			}
+			printk(KERN_WARNING
+			       "ctc: %s channel activated\n", device->name);
+			break;
+		default:
+			break;
+	}
+}
+
+/**
+ *
+ * Setup an interface.
+ *
+ * Like ctc_setup(), ctc_probe() can be called from two different locations:
+ *  - If built as module, it is called from within init_module().
+ *  - If built in monolithic kernel, it is called from within generic network
+ *    layer during initialization for every corresponding device, declared in
+ *    drivers/net/Space.c
+ *
+ * @param dev Pointer to net_device to be initialized.
+ *
+ * @returns 0 on success, !0 on failure.
+ */
+static int ctc_chandev_probe(chandev_probeinfo *info)
+{
+	int               devno[2];
+	__u16             proto;
+	int               rc;
+	int               direction;
+	channel_type_t    type;
+	ctc_priv          *privptr;
+	net_device        *dev;
+
+	ctc_proc_create_main();
+
+
+	switch (info->chan_type) {
+		case chandev_type_ctc:
+			type = channel_type_ctca;
+			break;
+		case chandev_type_escon:
+			type = channel_type_escon;
+			break;
+		default:
+			printk(KERN_WARNING "ctc_chandev_probe called with "
+			       "unsupported channel type %d\n", info->chan_type);
+			return -ENODEV;
+	}
+	devno[READ]  = info->read.devno;
+	devno[WRITE] = info->write.devno;
+	proto        = info->port_protocol_no;
+
+	if (add_channel(info->read.irq, info->read.devno, type))
+		return -ENOMEM;
+	if (add_channel(info->write.irq, info->write.devno, type))
+		return -ENOMEM;
+
+	dev = ctc_init_netdevice(NULL, 1);
+
+	
+	if (!dev) {
+		printk(KERN_WARNING "ctc_init_netdevice failed\n");
+		return -ENODEV;
+	}
+	
+	if (proto == CTC_PROTO_LINUX_TTY)
+		chandev_build_device_name(info, dev->name, "ctctty", 1);
+	else
+		chandev_build_device_name(info, dev->name, "ctc", 1);
+
+	privptr = (ctc_priv *)dev->priv;
+	privptr->protocol = proto;
+	for (direction = READ; direction <= WRITE; direction++) {
+		privptr->channel[direction] =
+			channel_get(type, devno[direction], direction);
+		if (privptr->channel[direction] == NULL) {
+			if (direction == WRITE) {
+				FREE_IRQ(privptr->channel[READ]->irq,
+					 privptr->channel[READ]->devstat);
+				channel_free(privptr->channel[READ]);
+			}
+			ctc_free_netdevice(dev, 1);
+			return -ENODEV;
+		}
+		privptr->channel[direction]->netdev = dev;
+		privptr->channel[direction]->protocol = proto;
+		privptr->channel[direction]->max_bufsize = CTC_BUFSIZE_DEFAULT;
+		rc = REQUEST_IRQ(privptr->channel[direction]->irq,
+				 (void *)ctc_irq_handler, SA_INTERRUPT,
+				 dev->name,
+				 privptr->channel[direction]->devstat);
+		if (rc) {
+			printk(KERN_WARNING
+			       "%s: requested irq %d is busy rc=%02x\n",
+			       dev->name, privptr->channel[direction]->irq,
+			       rc);
+			if (direction == WRITE) {
+				FREE_IRQ(privptr->channel[READ]->irq,
+					 privptr->channel[READ]->devstat);
+				channel_free(privptr->channel[READ]);
+			}
+			channel_free(privptr->channel[direction]);
+			ctc_free_netdevice(dev, 1);
+			return -EBUSY;
+		}
+	}
+	if (ctc_netdev_register(dev) != 0) {
+		ctc_free_netdevice(dev, 1);
+		return -ENODEV;
+	}
+
+	/**
+	 * register subdir in /proc/net/ctc
+	 */
+	ctc_proc_create_sub(dev);
+	strncpy(privptr->fsm->name, dev->name, sizeof(privptr->fsm->name));
+	activated++;
+
+	print_banner();
+
+	printk(KERN_INFO
+	       "%s: read: ch %04x (irq %04x), "
+	       "write: ch %04x (irq %04x) proto: %d\n",
+	       dev->name, privptr->channel[READ]->devno,
+	       privptr->channel[READ]->irq, privptr->channel[WRITE]->devno,
+	       privptr->channel[WRITE]->irq, proto);
+
+	chandev_initdevice(info, dev, 0, dev->name,
+			   (proto == CTC_PROTO_LINUX_TTY)
+			   ? chandev_category_serial_device :
+			   chandev_category_network_device,
+			   (chandev_unregfunc)ctc_netdev_unregister);
+	return 0;
+}
+#else /* ! CHANDEV */
 /**
  *
  * Setup an interface.
@@ -3191,7 +3704,7 @@
 	 * ctc_probe gets control.
 	 */
 	if (channels == NULL)
-		channel_scan(1);
+		channel_scan();
 
 	type = extract_channel_media(dev->name);
 	if (type == channel_type_unknown)
@@ -3212,47 +3725,13 @@
 		}
 	}
 
-	dev->priv = kmalloc(sizeof(ctc_priv)
-			    + sizeof(ctc_template)
-			    + sizeof(stat_entry)
-			    + sizeof(ctrl_entry)
-			    , GFP_KERNEL);
-	if (dev->priv == NULL)
-		return -ENOMEM;
-	memset(dev->priv, 0, sizeof(ctc_priv));
+#ifndef MODULE
+	if (ctc_init_netdevice(dev, 0) == NULL)
+		return -ENODEV;
+#endif
 	privptr = (ctc_priv *)dev->priv;
 	privptr->protocol = proto;
-        privptr->proc_dentry = (struct proc_dir_entry *)
-		(((char *)privptr) + sizeof(ctc_priv));
-        privptr->proc_stat_entry = (struct proc_dir_entry *)
-		(((char *)privptr) + sizeof(ctc_priv) +
-		 sizeof(ctc_template));
-        privptr->proc_ctrl_entry = (struct proc_dir_entry *)
-		(((char *)privptr) + sizeof(ctc_priv) +
-		 sizeof(ctc_template) + sizeof(stat_entry));
-	memcpy(privptr->proc_dentry, &ctc_template, sizeof(ctc_template));
-	memcpy(privptr->proc_stat_entry, &stat_entry, sizeof(stat_entry));
-	memcpy(privptr->proc_ctrl_entry, &ctrl_entry, sizeof(ctrl_entry));
-	privptr->fsm = init_fsm(dev->name, dev_state_names,
-			dev_event_names, NR_DEV_STATES, NR_DEV_EVENTS,
-			dev_fsm, DEV_FSM_LEN, GFP_KERNEL);
-	fsm_newstate(privptr->fsm, DEV_STATE_STOPPED);
-	if (privptr->fsm == NULL) {
-		kfree(privptr);
-		return -ENOMEM;
-	}
-	dev->mtu	         = CTC_BUFSIZE_DEFAULT - LL_HEADER_LENGTH - 2; 
-	dev->hard_start_xmit     = ctc_tx;
-	dev->open	         = ctc_open;
-	dev->stop	         = ctc_close;
-	dev->get_stats	         = ctc_stats;
-	dev->change_mtu          = ctc_change_mtu;
-	dev->hard_header_len     = LL_HEADER_LENGTH + 2;
-	dev->addr_len            = 0;
-	dev->type                = ARPHRD_SLIP;
-	dev->tx_queue_len        = 100;
-	SET_DEVICE_START(dev, 1);
-	dev->flags	         = IFF_POINTOPOINT | IFF_NOARP;
+
 	for (direction = READ; direction <= WRITE; direction++) {
 		if ((ctc_no_auto == 0) || (devno[direction] == -1))
 			privptr->channel[direction] =
@@ -3262,19 +3741,17 @@
 				channel_get(type, devno[direction], direction);
 		if (privptr->channel[direction] == NULL) {
 			if (direction == WRITE) {
-				free_irq(privptr->channel[READ]->irq,
+				FREE_IRQ(privptr->channel[READ]->irq,
 					 privptr->channel[READ]->devstat);
 				channel_free(privptr->channel[READ]);
 			}
-			kfree_fsm(privptr->fsm);
-			kfree(dev->priv);
-			dev->priv = NULL;
+			ctc_free_netdevice(dev, 1);
 			return -ENODEV;
 		}
 		privptr->channel[direction]->netdev = dev;
 		privptr->channel[direction]->protocol = proto;
 		privptr->channel[direction]->max_bufsize = CTC_BUFSIZE_DEFAULT;
-		rc = request_irq(privptr->channel[direction]->irq,
+		rc = REQUEST_IRQ(privptr->channel[direction]->irq,
 				 (void *)ctc_irq_handler, SA_INTERRUPT,
 				 dev->name,
 				 privptr->channel[direction]->devstat);
@@ -3284,14 +3761,12 @@
 			       dev->name, privptr->channel[direction]->irq,
 			       rc);
 			if (direction == WRITE) {
-				free_irq(privptr->channel[READ]->irq,
+				FREE_IRQ(privptr->channel[READ]->irq,
 					 privptr->channel[READ]->devstat);
 				channel_free(privptr->channel[READ]);
 			}
 			channel_free(privptr->channel[direction]);
-			kfree_fsm(privptr->fsm);
-			kfree(dev->priv);
-			dev->priv = NULL;
+			ctc_free_netdevice(dev, 1);
 			return -EBUSY;
 		}
 	}
@@ -3304,13 +3779,15 @@
 	print_banner();
 
 	printk(KERN_INFO
-	       "%s: read: ch %04x (irq %04x), write: ch %04x (irq %04x) proto: %d\n",
+	       "%s: read: ch %04x (irq %04x), "
+	       "write: ch %04x (irq %04x) proto: %d\n",
 	       dev->name, privptr->channel[READ]->devno,
 	       privptr->channel[READ]->irq, privptr->channel[WRITE]->devno,
 	       privptr->channel[WRITE]->irq, proto);
 
 	return 0;
 }
+#endif
 
 /**
  * Module related routines
@@ -3324,46 +3801,35 @@
  * for that.
  */
 void cleanup_module(void) {
-	channel *c = channels;
 
-	ctc_tty_cleanup();
+	ctc_tty_cleanup(0);
 	/* we are called if all interfaces are down only, so no need
 	 * to bother around with locking stuff
 	 */
-	channels = NULL;
-	while (c) {
-		channel *oldc = c;
-		if (c->netdev && c->netdev->priv) {
-			net_device *nd = c->netdev;
-			ctc_priv *privptr = (ctc_priv *)nd->priv;
-
-			fsm_deltimer(&privptr->channel[READ]->timer);
-			fsm_deltimer(&privptr->channel[WRITE]->timer);
-			free_irq(privptr->channel[READ]->irq,
-				 privptr->channel[READ]->devstat);
-			free_irq(privptr->channel[WRITE]->irq,
-				 privptr->channel[WRITE]->devstat);
-			kfree_fsm(privptr->channel[READ]->fsm);
-			kfree_fsm(privptr->channel[WRITE]->fsm);
-			if (privptr->protocol != CTC_PROTO_LINUX_TTY)
-				unregister_netdev(nd);
-			else
-				ctc_tty_unregister_netdev(nd);
-			kfree_fsm(privptr->fsm);
-			privptr->channel[READ]->netdev = NULL;
-			privptr->channel[WRITE]->netdev = NULL;
-			ctc_proc_destroy_sub(privptr);
-			kfree(privptr);
-			kfree(nd);
-			if (c->netdev != NULL)
-				printk(KERN_EMERG
-				       "ctc: PANIC: channel list corrupted\n");
-		}
-		c = c->next;
-		kfree(oldc->ccw);
-		kfree(oldc);
+#ifndef CTC_CHANDEV
+	while (channels) {
+		if ((channels->flags & CHANNEL_FLAGS_INUSE) &&
+		    (channels->netdev != NULL)) {
+			net_device *dev = channels->netdev;
+			ctc_priv *privptr = dev->priv;
+
+			if (privptr) {
+				privptr->channel[READ]->netdev = NULL;
+				privptr->channel[WRITE]->netdev = NULL;
+			}
+			channels->netdev = NULL;
+			ctc_netdev_unregister(dev);
+			ctc_free_netdevice(dev, 1);
+		}
+		channel_remove(channels);
 	}
+	channels = NULL;
+#endif
+	ctc_tty_cleanup(1);
 	ctc_proc_destroy_main();
+#ifdef CTC_CHANDEV
+	chandev_unregister(ctc_chandev_probe, 1);
+#endif
 	printk(KERN_INFO "CTC driver unloaded\n");
 }
 
@@ -3377,41 +3843,48 @@
  * @return 0 on success, !0 on error.
  */
 int ctc_init(void) {
+#ifndef CTC_CHANDEV
 	int   cnt[2];
 	int   itype;
 	int   activated;
-	int   ret = 0;
 	param *par;
+#endif
+	int   ret = 0;
+	int   probed = 0;
 
 	print_banner();
 
-#ifdef DEBUG
+#if defined(DEBUG) && !defined(CTC_CHANDEV)
 	printk(KERN_DEBUG
-	       "ctc: init_module(): got string '%s'\n", setup);
+	       "ctc: init_module(): got string '%s'\n", ctc);
 #endif
 
+#ifndef CTC_CHANDEV
 #ifdef MODULE
 	ctc_setup(ctc);
 #endif
-	activated = 0;
 	par = params;
+#endif
+
+	activated = 0;
 	ctc_tty_init();
+#ifdef CTC_CHANDEV
+	chandev_register_and_probe(ctc_chandev_probe,
+				   (chandev_shutdownfunc)ctc_shutdown,
+				   ctc_chandev_msck_notify,
+				   chandev_type_ctc|chandev_type_escon);
+#else /* CTC_CHANDEV */
 	for (itype = 0; itype < 2; itype++) {
 		net_device *dev = NULL;
 		char       *bname = (itype) ? "escon" : "ctc";
 
 		cnt[itype] = 0;
 		do {
-			dev = kmalloc(sizeof(net_device)
-#if LINUX_VERSION_CODE < 0x020300
-				      + 11 /* name + zero */
-#endif
-				      , GFP_KERNEL);
+			dev = ctc_init_netdevice(NULL, 1);
 			if (!dev) {
 				ret = -ENOMEM;
 				break;
 			}
-			memset(dev, 0, sizeof(net_device));
 #if LINUX_VERSION_CODE < 0x020300
 			dev->name = (unsigned char *)dev + sizeof(net_device);
 #endif
@@ -3425,7 +3898,9 @@
 					if (isdigit(*p))
 						break;
 				if (p && *p) {
-					int it = (strncmp(dev->name, "escon", 5)) ? 1 : 0;
+					int it =
+						(strncmp(dev->name, "escon", 5))
+						? 1 : 0;
 					n = simple_strtoul(p, NULL, 0);
 					if (n >= cnt[it])
 						cnt[it] = n + 1;
@@ -3433,7 +3908,7 @@
 			} else {
 				if (ctc_no_auto) {
 					itype = 3;
-					kfree(dev);
+					ctc_free_netdevice(dev, 1);
 					dev = NULL;
 					break;
 				}
@@ -3444,6 +3919,7 @@
 			printk(KERN_DEBUG "ctc: %s(): probing for device %s\n",
 						 __FUNCTION__, dev->name);
 #endif			
+			probed = 1;
 			if (ctc_probe(dev) == 0) {
 				ctc_priv *privptr = (ctc_priv *)dev->priv;
 #ifdef DEBUG
@@ -3454,67 +3930,56 @@
 				       "ctc: %s(): registering device %s\n",
 				       __FUNCTION__, dev->name);
 #endif
-				if (privptr->protocol != CTC_PROTO_LINUX_TTY) {
-					if (register_netdev(dev) != 0) {
-						printk(KERN_WARNING
-						       "ctc: Couldn't register netdev %s\n",
-						       dev->name);
-						free_irq(privptr->channel[READ]->irq,
-							 privptr->channel[READ]->devstat);
-						free_irq(privptr->channel[WRITE]->irq,
-							 privptr->channel[WRITE]->devstat);
-						channel_free(privptr->channel[READ]);
-						channel_free(privptr->channel[WRITE]);
-						kfree(dev->priv);
-						kfree(dev);
-					} else {
-#ifdef DEBUG
-						printk(KERN_DEBUG
-						       "ctc: %s(): register succeed\n",
-						       __FUNCTION__);
-#endif			
-						activated++;
-					}
+				if (ctc_netdev_register(dev) != 0) {
+					printk(KERN_WARNING
+					       "ctc: Couldn't register %s\n",
+					       dev->name);
+					FREE_IRQ(
+						privptr->channel[READ]->irq,
+						privptr->channel[READ]->devstat);
+					FREE_IRQ(
+						privptr->channel[WRITE]->irq,
+						privptr->channel[WRITE]->devstat);
+					channel_free(privptr->channel[READ]);
+					channel_free(privptr->channel[WRITE]);
+					ctc_free_netdevice(dev, 1);
+					dev = NULL;
 				} else {
-					if (ctc_tty_register_netdev(dev) != 0) {
-						printk(KERN_WARNING
-						       "ctc: Couldn't register ttydev %s\n",
-						       dev->name);
-						free_irq(privptr->channel[READ]->irq,
-							 privptr->channel[READ]->devstat);
-						free_irq(privptr->channel[WRITE]->irq,
-							 privptr->channel[WRITE]->devstat);
-						channel_free(privptr->channel[READ]);
-						channel_free(privptr->channel[WRITE]);
-						kfree(dev->priv);
-						kfree(dev);
-					} else {
-#ifdef DEBUG
-						printk(KERN_DEBUG
-						       "ctc: %s(): register succeed\n",
-						       __FUNCTION__);
+#ifdef DEBUG
+					printk(KERN_DEBUG
+					       "ctc: %s(): register succeed\n",
+					       __FUNCTION__);
 #endif			
-						activated++;
-					}
+					activated++;
 				}
-				
 			} else {
 #ifdef DEBUG
 				printk(KERN_DEBUG
 				       "ctc: %s(): probing failed\n",
 				       __FUNCTION__);
 #endif			
-				kfree(dev);
 				dev = NULL;
 			}
 		} while (dev && (ret == 0));
 	}
+#endif /* CHANDEV */
+#if !defined(CTC_CHANDEV) && defined(MODULE)
 	if (!activated) {
 		printk(KERN_WARNING "ctc: No devices registered\n");
 		ret = -ENODEV;
 	}
-	if (ret)
-		ctc_tty_cleanup();
+#endif
+	if (ret) {
+		ctc_tty_cleanup(0);
+		ctc_tty_cleanup(1);
+#if defined(CTC_CHANDEV) && defined(MODULE)
+		chandev_unregister(ctc_chandev_probe, 0);
+#endif
+#ifdef MODULE
+		if (probed)
+			ctc_proc_destroy_main();
+#endif
+	}
 	return ret;
 }
 
diff -u --recursive --new-file v2.4.7/linux/drivers/s390/net/ctctty.c linux/drivers/s390/net/ctctty.c
--- v2.4.7/linux/drivers/s390/net/ctctty.c	Wed Apr 11 19:02:28 2001
+++ linux/drivers/s390/net/ctctty.c	Wed Jul 25 14:12:02 2001
@@ -1,5 +1,5 @@
 /*
- * $Id: ctctty.c,v 1.1 2001/01/23 14:23:51 felfert Exp $
+ * $Id: ctctty.c,v 1.8 2001/05/16 16:28:31 felfert Exp $
  *
  * CTC / ESCON network driver, tty interface.
  *
@@ -33,7 +33,23 @@
 #  include <linux/devfs_fs_kernel.h>
 #endif
 #include "ctctty.h"
-#include <net/dst.h>
+
+#if LINUX_VERSION_CODE < 0x020212
+typedef struct wait_queue wait_queue_t;
+typedef struct wait_queue *wait_queue_head_t;
+#define DECLARE_WAITQUEUE(wait, current) \
+	struct wait_queue wait = { current, NULL }
+#define init_waitqueue_head(x) *(x)=NULL
+#define __set_current_state(state_value) \
+	do { current->state = state_value; } while (0)
+#ifdef __SMP__
+#define set_current_state(state_value) \
+	do { __set_current_state(state_value); mb(); } while (0)
+#else
+#define set_current_state(state_value) __set_current_state(state_value)
+#endif
+#define init_MUTEX(x) *(x)=MUTEX
+#endif
 
 #define CTC_TTY_MAJOR       43
 #define CTC_TTY_MAX_DEVICES 64
@@ -45,6 +61,8 @@
 #define CTC_ASYNC_CTS_FLOW       0x04000000 /* Do CTS flow control          */
 #define CTC_ASYNC_CHECK_CD       0x02000000 /* i.e., CLOCAL                 */
 #define CTC_ASYNC_HUP_NOTIFY         0x0001 /* Notify tty on hangups/closes */
+#define CTC_ASYNC_NETDEV_OPEN        0x0002 /* Underlying netdev is open    */
+#define CTC_ASYNC_TX_LINESTAT        0x0004 /* Must send line status        */
 #define CTC_ASYNC_SPLIT_TERMIOS      0x0008 /* Sep. termios for dialin/out  */
 #define CTC_TTY_XMIT_SIZE              1024 /* Default bufsize for write    */
 #define CTC_SERIAL_XMIT_MAX            4000 /* Maximum bufsize for write    */
@@ -54,14 +72,13 @@
 typedef struct {
   int			magic;
   int			flags;		 /* defined in tty.h               */
-  int			x_char;		 /* xon/xoff character             */
   int			mcr;		 /* Modem control register         */
   int                   msr;             /* Modem status register          */
   int                   lsr;             /* Line status register           */
   int			line;
   int			count;		 /* # of fd on device              */
   int			blocked_open;	 /* # of blocked opens             */
-	net_device            *netdev;
+  net_device            *netdev;
   struct sk_buff_head   tx_queue;        /* transmit queue                 */
   struct sk_buff_head   rx_queue;        /* receive queue                  */
   struct tty_struct 	*tty;            /* Pointer to corresponding tty   */
@@ -69,7 +86,8 @@
   wait_queue_head_t	open_wait;
   wait_queue_head_t	close_wait;
   struct semaphore      write_sem;
-	struct tq_struct tq;
+  struct tq_struct      tq;
+  struct timer_list     stoptimer;
 } ctc_tty_info;
 
 /* Description of one CTC-tty */
@@ -88,7 +106,7 @@
 #define MODEM_PARANOIA_CHECK
 #define MODEM_DO_RESTART
 
-#define CTC_TTY_NAME "ttyZ"
+#define CTC_TTY_NAME "ctctty"
 
 #ifdef CONFIG_DEVFS_FS
 static char *ctc_ttyname = "ctc/" CTC_TTY_NAME "%d";
@@ -96,7 +114,12 @@
 static char *ctc_ttyname = CTC_TTY_NAME;
 #endif
 
-char *ctc_tty_revision = "$Revision: 1.1 $";
+char *ctc_tty_revision = "$Revision: 1.8 $";
+
+static __u32 ctc_tty_magic = CTC_ASYNC_MAGIC;
+static int ctc_tty_shuttingdown = 0;
+
+static spinlock_t ctc_tty_lock;
 
 /* ctc_tty_try_read() is called from within ctc_tty_rcv_skb()
  * to stuff incoming data directly into a tty's flip-buffer. If the
@@ -120,11 +143,11 @@
 			len = skb->len;
 			if (c >= len) {
 				memcpy(tty->flip.char_buf_ptr, skb->data, len);
+				memset(tty->flip.flag_buf_ptr, 0, len);
 				tty->flip.count += len;
 				tty->flip.char_buf_ptr += len;
-				memset(tty->flip.flag_buf_ptr, 0, len);
 				tty->flip.flag_buf_ptr += len;
-				queue_task(&tty->flip.tqueue, &tq_timer);
+				tty_flip_buffer_push(tty);
 				kfree_skb(skb);
 				return 1;
 			}
@@ -140,7 +163,7 @@
 static int
 ctc_tty_readmodem(ctc_tty_info *info)
 {
-	int ret = 0;
+	int ret = 1;
 	struct tty_struct *tty;
 
 	if ((tty = info->tty)) {
@@ -152,16 +175,19 @@
 				int len = skb->len;
 				if (len > c)
 					len = c;
-				memcpy(tty->flip.char_buf_ptr, skb_pull(skb, len), len);
-				tty->flip.count += len;
+				memcpy(tty->flip.char_buf_ptr, skb->data, len);
+				skb_pull(skb, len);
 				memset(tty->flip.flag_buf_ptr, 0, len);
+				tty->flip.count += len;
+				tty->flip.char_buf_ptr += len;
 				tty->flip.flag_buf_ptr += len;
-				queue_task(&tty->flip.tqueue, &tq_timer);
-				if (skb->len) {
+				tty_flip_buffer_push(tty);
+				if (skb->len > 0)
 					skb_queue_head(&info->rx_queue, skb);
-					ret = 1;
-				} else
+				else {
 					kfree_skb(skb);
+					ret = skb_queue_len(&info->rx_queue);
+				}
 			}
 		}
 	}
@@ -169,6 +195,25 @@
 }
 
 void
+ctc_tty_setcarrier(net_device *netdev, int on)
+{
+	int i;
+
+	if ((!driver) || ctc_tty_shuttingdown)
+		return;
+	for (i = 0; i < CTC_TTY_MAX_DEVICES; i++)
+		if (driver->info[i].netdev == netdev) {
+			ctc_tty_info *info = &driver->info[i];
+			if (on)
+				info->msr |= UART_MSR_DCD;
+			else
+				info->msr &= ~UART_MSR_DCD;
+			if ((info->flags & CTC_ASYNC_CHECK_CD) && (!on))
+				tty_hangup(info->tty);
+		}
+}
+
+void
 ctc_tty_netif_rx(struct sk_buff *skb)
 {
 	int i;
@@ -176,7 +221,7 @@
 
 	if (!skb)
 		return;
-	if (!skb->dev) {
+	if ((!skb->dev) || (!driver) || ctc_tty_shuttingdown) {
 		dev_kfree_skb(skb);
 		return;
 	}
@@ -189,7 +234,35 @@
 		dev_kfree_skb(skb);
 		return;
 	}
-	skb_pull(skb, sizeof(int));
+	if (skb->len < 6) {
+		dev_kfree_skb(skb);
+		return;
+	}
+	if (memcmp(skb->data, &ctc_tty_magic, sizeof(__u32))) {
+		dev_kfree_skb(skb);
+		return;
+	}
+	skb_pull(skb, sizeof(__u32));
+
+	i = *((int *)skb->data);
+	skb_pull(skb, sizeof(info->mcr));
+	if (i & UART_MCR_RTS) {
+		info->msr |= UART_MSR_CTS;
+		if (info->flags & CTC_ASYNC_CTS_FLOW)
+			info->tty->hw_stopped = 0;
+	} else {
+		info->msr &= ~UART_MSR_CTS;
+		if (info->flags & CTC_ASYNC_CTS_FLOW)
+			info->tty->hw_stopped = 1;
+	}
+	if (i & UART_MCR_DTR)
+		info->msr |= UART_MSR_DSR;
+	else
+		info->msr &= ~UART_MSR_DSR;
+	if (skb->len <= 0) {
+		kfree_skb(skb);
+		return;
+	}
 	/* Try to deliver directly via tty-flip-buf if queue is empty */
 	if (skb_queue_empty(&info->rx_queue))
 		if (ctc_tty_try_read(info, skb))
@@ -203,46 +276,70 @@
 	mark_bh(IMMEDIATE_BH);
 }
 
-static void
-ctc_tty_dstfail(struct sk_buff *skb) {
-	if (!skb)
-		return;
-	dev_kfree_skb(skb);
-	return;
-}
-
-static struct dst_entry dst_e;
-static struct dst_ops   dst_o;
-
 static int
 ctc_tty_tint(ctc_tty_info * info)
 {
 	struct sk_buff *skb = skb_dequeue(&info->tx_queue);
+	int stopped = (info->tty->hw_stopped || info->tty->stopped);
+	int wake = 1;
 	int rc;
-	int l;
-	char c;
 
-	if (!skb)
-		return 0;
 	if (!info->netdev) {
-		kfree(skb);
+		if (skb)
+			kfree(skb);
 		return 0;
 	}
-	skb->dst = &dst_e;
-	l = skb->len;
-	c = *(skb->data);
-	rc = info->netdev->hard_start_xmit(skb, info->netdev);
-printk(KERN_DEBUG "xmit: l=%d rc=%d '%02x'\n", l, rc, c);
-	if (rc) {
+	if (info->flags & CTC_ASYNC_TX_LINESTAT) {
+		int skb_res = info->netdev->hard_header_len +
+			sizeof(info->mcr) + sizeof(__u32);
+		/* If we must update line status,
+		 * create an empty dummy skb and insert it.
+		 */
+		if (skb)
+			skb_queue_head(&info->tx_queue, skb);
+
+		skb = dev_alloc_skb(skb_res);
+		if (!skb) {
+			printk(KERN_WARNING
+			       "ctc_tty: Out of memory in %s%d tint\n",
+			       CTC_TTY_NAME, info->line);
+			return 1;
+		}
+		skb_reserve(skb, skb_res);
+		stopped = 0;
+		wake = 0;
+	}
+	if (!skb)
+		return 0;
+	if (stopped) {
 		skb_queue_head(&info->tx_queue, skb);
 		return 1;
+	}
+#if 0
+	if (skb->len > 0)
+		printk(KERN_DEBUG "tint: %d %02x\n", skb->len, *(skb->data));
+	else
+		printk(KERN_DEBUG "tint: %d STAT\n", skb->len);
+#endif
+	memcpy(skb_push(skb, sizeof(info->mcr)), &info->mcr, sizeof(info->mcr));
+	memcpy(skb_push(skb, sizeof(__u32)), &ctc_tty_magic, sizeof(__u32));
+	rc = info->netdev->hard_start_xmit(skb, info->netdev);
+	if (rc) {
+		skb_pull(skb, sizeof(info->mcr) + sizeof(__u32));
+		if (skb->len > 0)
+			skb_queue_head(&info->tx_queue, skb);
+		else
+			kfree_skb(skb);
 	} else {
 		struct tty_struct *tty = info->tty;
-		info->lsr |= UART_LSR_TEMT;
-		if ((tty->flags & (1 << TTY_DO_WRITE_WAKEUP)) &&
-		    tty->ldisc.write_wakeup)
-			(tty->ldisc.write_wakeup)(tty);
-		wake_up_interruptible(&tty->write_wait);
+
+		info->flags &= ~CTC_ASYNC_TX_LINESTAT;
+		if (tty) {
+			if (wake && (tty->flags & (1 << TTY_DO_WRITE_WAKEUP)) &&
+			    tty->ldisc.write_wakeup)
+				(tty->ldisc.write_wakeup)(tty);
+			wake_up_interruptible(&tty->write_wait);
+		}
 	}
 	return (skb_queue_empty(&info->tx_queue) ? 0 : 1);
 }
@@ -274,6 +371,40 @@
 }
 
 static void
+ctc_tty_inject(ctc_tty_info *info, char c)
+{
+	int skb_res;
+	struct sk_buff *skb;
+	
+	if (ctc_tty_shuttingdown)
+		return;
+	skb_res = info->netdev->hard_header_len + sizeof(info->mcr) +
+		sizeof(__u32) + 1;
+	skb = dev_alloc_skb(skb_res);
+	if (!skb) {
+		printk(KERN_WARNING
+		       "ctc_tty: Out of memory in %s%d tx_inject\n",
+		       CTC_TTY_NAME, info->line);
+		return;
+	}
+	skb_reserve(skb, skb_res);
+	*(skb_put(skb, 1)) = c;
+	skb_queue_head(&info->tx_queue, skb);
+	queue_task(&info->tq, &tq_immediate);
+	mark_bh(IMMEDIATE_BH);
+}
+
+static void
+ctc_tty_transmit_status(ctc_tty_info *info)
+{
+	if (ctc_tty_shuttingdown)
+		return;
+	info->flags |= CTC_ASYNC_TX_LINESTAT;
+	queue_task(&info->tq, &tq_immediate);
+	mark_bh(IMMEDIATE_BH);
+}
+
+static void
 ctc_tty_change_speed(ctc_tty_info * info)
 {
 	unsigned int cflag;
@@ -294,8 +425,12 @@
 	}
 	if (quot) {
 		info->mcr |= UART_MCR_DTR;
+		info->mcr |= UART_MCR_RTS;
+		ctc_tty_transmit_status(info);
 	} else {
 		info->mcr &= ~UART_MCR_DTR;
+		info->mcr &= ~UART_MCR_RTS;
+		ctc_tty_transmit_status(info);
 		return;
 	}
 
@@ -331,11 +466,24 @@
 	ctc_tty_change_speed(info);
 
 	info->flags |= CTC_ASYNC_INITIALIZED;
-	info->msr |= (UART_MSR_DSR | UART_MSR_CTS);
-	info->netdev->open(info->netdev);
+	if (!(info->flags & CTC_ASYNC_NETDEV_OPEN))
+		info->netdev->open(info->netdev);
+	info->flags |= CTC_ASYNC_NETDEV_OPEN;
 	return 0;
 }
 
+static void
+ctc_tty_stopdev(unsigned long data)
+{
+	ctc_tty_info *info = (ctc_tty_info *)data;
+
+	if ((!info) || (!info->netdev) ||
+	    (info->flags & CTC_ASYNC_INITIALIZED))
+		return;
+	info->netdev->stop(info->netdev);
+	info->flags &= ~CTC_ASYNC_NETDEV_OPEN;
+}
+
 /*
  * This routine will shutdown a serial port; interrupts are disabled, and
  * DTR is dropped if the hangup on close termio flag is on.
@@ -349,12 +497,11 @@
 	printk(KERN_DEBUG "Shutting down %s%d ....\n", CTC_TTY_NAME, info->line);
 #endif
 	info->msr &= ~UART_MSR_RI;
-	if (!info->tty || (info->tty->termios->c_cflag & HUPCL)) {
+	if (!info->tty || (info->tty->termios->c_cflag & HUPCL))
 		info->mcr &= ~(UART_MCR_DTR | UART_MCR_RTS);
-	}
 	if (info->tty)
 		set_bit(TTY_IO_ERROR, &info->tty->flags);
-	info->netdev->stop(info->netdev);
+	mod_timer(&info->stoptimer, jiffies + (10 * HZ));
 	skb_queue_purge(&info->tx_queue);
 	skb_queue_purge(&info->rx_queue);
 	info->flags &= ~CTC_ASYNC_INITIALIZED;
@@ -376,6 +523,8 @@
 	int total = 0;
 	ctc_tty_info *info = (ctc_tty_info *) tty->driver_data;
 
+	if (ctc_tty_shuttingdown)
+		return 0;
 	if (ctc_tty_paranoia_check(info, tty->device, "ctc_tty_write"))
 		return 0;
 	if (!tty)
@@ -392,7 +541,8 @@
 		if (c <= 0)
 			break;
 		
-		skb_res = info->netdev->hard_header_len + sizeof(int);
+		skb_res = info->netdev->hard_header_len + sizeof(info->mcr) +
+			+ sizeof(__u32);
 		skb = dev_alloc_skb(skb_res + c);
 		if (!skb) {
 			printk(KERN_WARNING
@@ -411,6 +561,7 @@
 		count -= c;
 	}
 	if (skb_queue_len(&info->tx_queue)) {
+		info->lsr &= ~UART_LSR_TEMT;
 		queue_task(&info->tq, &tq_immediate);
 		mark_bh(IMMEDIATE_BH);
 	}
@@ -457,6 +608,7 @@
 		return;
 	}
 	skb_queue_purge(&info->tx_queue);
+	info->lsr |= UART_LSR_TEMT;
 	restore_flags(flags);
 	wake_up_interruptible(&tty->write_wait);
 	if ((tty->flags & (1 << TTY_DO_WRITE_WAKEUP)) &&
@@ -469,12 +621,14 @@
 {
 	ctc_tty_info *info = (ctc_tty_info *) tty->driver_data;
 
+	if (ctc_tty_shuttingdown)
+		return;
 	if (ctc_tty_paranoia_check(info, tty->device, "ctc_tty_flush_chars"))
 		return;
-	if (skb_queue_len(&info->tx_queue)) {
-		queue_task(&info->tq, &tq_immediate);
-		mark_bh(IMMEDIATE_BH);
-	}
+	if (tty->stopped || tty->hw_stopped || (!skb_queue_len(&info->tx_queue)))
+		return;
+	queue_task(&info->tq, &tq_immediate);
+	mark_bh(IMMEDIATE_BH);
 }
 
 /*
@@ -492,9 +646,10 @@
 
 	if (ctc_tty_paranoia_check(info, tty->device, "ctc_tty_throttle"))
 		return;
-	if (I_IXOFF(tty))
-		info->x_char = STOP_CHAR(tty);
 	info->mcr &= ~UART_MCR_RTS;
+	if (I_IXOFF(tty))
+		ctc_tty_inject(info, STOP_CHAR(tty));
+	ctc_tty_transmit_status(info);
 }
 
 static void
@@ -504,13 +659,10 @@
 
 	if (ctc_tty_paranoia_check(info, tty->device, "ctc_tty_unthrottle"))
 		return;
-	if (I_IXOFF(tty)) {
-		if (info->x_char)
-			info->x_char = 0;
-		else
-			info->x_char = START_CHAR(tty);
-	}
 	info->mcr |= UART_MCR_RTS;
+	if (I_IXOFF(tty))
+		ctc_tty_inject(info, START_CHAR(tty));
+	ctc_tty_transmit_status(info);
 }
 
 /*
@@ -573,6 +725,7 @@
 ctc_tty_set_ctc_tty_info(ctc_tty_info * info, uint cmd, uint * value)
 {
 	uint arg;
+	int old_mcr = info->mcr & (UART_MCR_RTS | UART_MCR_DTR);
 
 	get_user(arg, (uint *) value);
 	switch (cmd) {
@@ -581,24 +734,20 @@
 			printk(KERN_DEBUG "%s%d ioctl TIOCMBIS\n", CTC_TTY_NAME,
 			       info->line);
 #endif
-			if (arg & TIOCM_RTS) {
+			if (arg & TIOCM_RTS)
 				info->mcr |= UART_MCR_RTS;
-			}
-			if (arg & TIOCM_DTR) {
+			if (arg & TIOCM_DTR)
 				info->mcr |= UART_MCR_DTR;
-			}
 			break;
 		case TIOCMBIC:
 #ifdef CTC_DEBUG_MODEM_IOCTL
 			printk(KERN_DEBUG "%s%d ioctl TIOCMBIC\n", CTC_TTY_NAME,
 			       info->line);
 #endif
-			if (arg & TIOCM_RTS) {
+			if (arg & TIOCM_RTS)
 				info->mcr &= ~UART_MCR_RTS;
-			}
-			if (arg & TIOCM_DTR) {
+			if (arg & TIOCM_DTR)
 				info->mcr &= ~UART_MCR_DTR;
-			}
 			break;
 		case TIOCMSET:
 #ifdef CTC_DEBUG_MODEM_IOCTL
@@ -612,6 +761,8 @@
 		default:
 			return -EINVAL;
 	}
+	if ((info->mcr  & (UART_MCR_RTS | UART_MCR_DTR)) != old_mcr)
+		ctc_tty_transmit_status(info);
 	return 0;
 }
 
@@ -709,18 +860,30 @@
 ctc_tty_set_termios(struct tty_struct *tty, struct termios *old_termios)
 {
 	ctc_tty_info *info = (ctc_tty_info *) tty->driver_data;
+	unsigned int cflag = tty->termios->c_cflag;
 
-	if (!old_termios)
-		ctc_tty_change_speed(info);
-	else {
-		if (tty->termios->c_cflag == old_termios->c_cflag)
-			return;
-		ctc_tty_change_speed(info);
-		if ((old_termios->c_cflag & CRTSCTS) &&
-		    !(tty->termios->c_cflag & CRTSCTS)) {
-			tty->hw_stopped = 0;
-		}
+	ctc_tty_change_speed(info);
+
+	/* Handle transition to B0 */
+	if ((old_termios->c_cflag & CBAUD) && !(cflag & CBAUD)) {
+		info->mcr &= ~(UART_MCR_DTR|UART_MCR_RTS);
+		ctc_tty_transmit_status(info);
+	}
+
+	/* Handle transition from B0 to other */
+	if (!(old_termios->c_cflag & CBAUD) && (cflag & CBAUD)) {
+		info->mcr |= UART_MCR_DTR;
+		if (!(tty->termios->c_cflag & CRTSCTS) ||
+                    !test_bit(TTY_THROTTLED, &tty->flags)) {
+                        info->mcr |= UART_MCR_RTS;
+                }
+		ctc_tty_transmit_status(info);
 	}
+
+	/* Handle turning off CRTSCTS */
+	if ((old_termios->c_cflag & CRTSCTS) &&
+            !(tty->termios->c_cflag & CRTSCTS))
+                tty->hw_stopped = 0;
 }
 
 /*
@@ -836,6 +999,7 @@
 ctc_tty_open(struct tty_struct *tty, struct file *filp)
 {
 	ctc_tty_info *info;
+	unsigned long saveflags;
 	int retval,
 	 line;
 
@@ -851,9 +1015,11 @@
 	printk(KERN_DEBUG "ctc_tty_open %s%d, count = %d\n", tty->driver.name,
 	       info->line, info->count);
 #endif
+	spin_lock_irqsave(&ctc_tty_lock, saveflags);
 	info->count++;
 	tty->driver_data = info;
 	info->tty = tty;
+	spin_unlock_irqrestore(&ctc_tty_lock, saveflags);
 	/*
 	 * Start up serial port
 	 */
@@ -885,6 +1051,7 @@
 ctc_tty_close(struct tty_struct *tty, struct file *filp)
 {
 	ctc_tty_info *info = (ctc_tty_info *) tty->driver_data;
+	unsigned long saveflags;
 	ulong flags;
 	ulong timeout;
 
@@ -958,7 +1125,9 @@
 		tty->driver.flush_buffer(tty);
 	if (tty->ldisc.flush_buffer)
 		tty->ldisc.flush_buffer(tty);
+	spin_lock_irqsave(&ctc_tty_lock, saveflags);
 	info->tty = 0;
+	spin_unlock_irqrestore(&ctc_tty_lock, saveflags);
 	tty->closing = 0;
 	if (info->blocked_open) {
 		set_current_state(TASK_INTERRUPTIBLE);
@@ -980,13 +1149,16 @@
 ctc_tty_hangup(struct tty_struct *tty)
 {
 	ctc_tty_info *info = (ctc_tty_info *)tty->driver_data;
+	unsigned long saveflags;
 
 	if (ctc_tty_paranoia_check(info, tty->device, "ctc_tty_hangup"))
 		return;
 	ctc_tty_shutdown(info);
 	info->count = 0;
 	info->flags &= ~CTC_ASYNC_NORMAL_ACTIVE;
+	spin_lock_irqsave(&ctc_tty_lock, saveflags);
 	info->tty = 0;
+	spin_unlock_irqrestore(&ctc_tty_lock, saveflags);
 	wake_up_interruptible(&info->open_wait);
 }
 
@@ -998,14 +1170,21 @@
 static void
 ctc_tty_task(ctc_tty_info *info)
 {
+	unsigned long saveflags;
 	int again;
 
-	again = ctc_tty_tint(info);
-	again |= ctc_tty_readmodem(info);
-	if (again) {
-		queue_task(&info->tq, &tq_immediate);
-		mark_bh(IMMEDIATE_BH);
+	spin_lock_irqsave(&ctc_tty_lock, saveflags);
+	if ((!ctc_tty_shuttingdown) && info) {
+		again = ctc_tty_tint(info);
+		if (!again)
+			info->lsr |= UART_LSR_TEMT;
+		again |= ctc_tty_readmodem(info);
+		if (again) {
+			queue_task(&info->tq, &tq_immediate);
+			mark_bh(IMMEDIATE_BH);
+		}
 	}
+	spin_unlock_irqrestore(&ctc_tty_lock, saveflags);
 }
 
 int
@@ -1015,8 +1194,6 @@
 	ctc_tty_info *info;
 	struct tty_driver *device;
 
-	dst_e.ops = &dst_o;
-	dst_o.link_failure = ctc_tty_dstfail;
 	driver = kmalloc(sizeof(ctc_tty_driver), GFP_KERNEL);
 	if (driver == NULL) {
 		printk(KERN_WARNING "Out of memory in ctc_tty_modem_init\n");
@@ -1064,14 +1241,17 @@
 	for (i = 0; i < CTC_TTY_MAX_DEVICES; i++) {
 		info = &driver->info[i];
 		init_MUTEX(&info->write_sem);
+#if LINUX_VERSION_CODE >= 0x020400
 		INIT_LIST_HEAD(&info->tq.list);
+#else
+		info->tq.next    = NULL;
+#endif
 		info->tq.sync    = 0;
 		info->tq.routine = (void *)(void *)ctc_tty_task;
 		info->tq.data    = info;
 		info->magic = CTC_ASYNC_MAGIC;
 		info->line = i;
 		info->tty = 0;
-		info->x_char = 0;
 		info->count = 0;
 		info->blocked_open = 0;
 		info->normal_termios = device->init_termios;
@@ -1079,6 +1259,10 @@
 		init_waitqueue_head(&info->close_wait);
 		skb_queue_head_init(&info->tx_queue);
 		skb_queue_head_init(&info->rx_queue);
+		init_timer(&info->stoptimer);
+		info->stoptimer.function = ctc_tty_stopdev;
+		info->stoptimer.data = (unsigned long)info;
+		info->mcr = UART_MCR_RTS;
 	}
 	return 0;
 }
@@ -1118,8 +1302,10 @@
 void
 ctc_tty_unregister_netdev(net_device *dev) {
 	int i;
+	unsigned long saveflags;
 	ctc_tty_info *info = NULL;
 
+	spin_lock_irqsave(&ctc_tty_lock, saveflags);
 	for (i = 0; i < CTC_TTY_MAX_DEVICES; i++)
 		if (driver->info[i].netdev == dev) {
 			info = &driver->info[i];
@@ -1130,10 +1316,24 @@
 		skb_queue_purge(&info->tx_queue);
 		skb_queue_purge(&info->rx_queue);
 	}
+	spin_unlock_irqrestore(&ctc_tty_lock, saveflags);
 }
 
 void
-ctc_tty_cleanup(void) {
-	tty_unregister_driver(&driver->ctc_tty_device);
-	kfree(driver);
+ctc_tty_cleanup(int final) {
+	unsigned long saveflags;
+	
+	spin_lock_irqsave(&ctc_tty_lock, saveflags);
+	ctc_tty_shuttingdown = 1;
+	if (final) {
+		kfree(driver);
+		driver = NULL;
+	} else {
+		int i;
+
+		for (i = 0; i < CTC_TTY_MAX_DEVICES; i++)
+			driver->info[i].tq.routine = NULL;
+		tty_unregister_driver(&driver->ctc_tty_device);
+	}
+	spin_unlock_irqrestore(&ctc_tty_lock, saveflags);
 }
diff -u --recursive --new-file v2.4.7/linux/drivers/s390/net/ctctty.h linux/drivers/s390/net/ctctty.h
--- v2.4.7/linux/drivers/s390/net/ctctty.h	Wed Apr 11 19:02:28 2001
+++ linux/drivers/s390/net/ctctty.h	Wed Jul 25 14:12:02 2001
@@ -1,5 +1,5 @@
 /*
- * $Id: ctctty.h,v 1.2 2001/01/30 22:09:28 uweigand Exp $
+ * $Id: ctctty.h,v 1.4 2001/03/22 12:46:01 felfert Exp $
  *
  * CTC / ESCON network driver, tty interface.
  *
@@ -34,10 +34,11 @@
 typedef struct net_device  net_device;
 #endif
 
-extern int  ctc_tty_register_netdev(net_device *dev);
-extern void ctc_tty_unregister_netdev(net_device *dev);
-extern void ctc_tty_netif_rx(struct sk_buff *skb);
+extern int  ctc_tty_register_netdev(net_device *);
+extern void ctc_tty_unregister_netdev(net_device *);
+extern void ctc_tty_netif_rx(struct sk_buff *);
 extern int  ctc_tty_init(void);
-extern void ctc_tty_cleanup(void);
+extern void ctc_tty_cleanup(int);
+extern void ctc_tty_setcarrier(net_device *, int);
 
 #endif
diff -u --recursive --new-file v2.4.7/linux/drivers/s390/net/fsm.c linux/drivers/s390/net/fsm.c
--- v2.4.7/linux/drivers/s390/net/fsm.c	Tue Feb 13 14:13:44 2001
+++ linux/drivers/s390/net/fsm.c	Wed Jul 25 14:12:02 2001
@@ -1,23 +1,14 @@
 /**
- * $Id: fsm.c,v 1.1 2000/11/30 11:21:08 bird Exp $
+ * $Id: fsm.c,v 1.3 2001/06/18 16:49:19 felfert Exp $
  *
  * A generic FSM based on fsm used in isdn4linux
  *
- * $Log: fsm.c,v $
- * Revision 1.1  2000/11/30 11:21:08  bird
- * Support for new ctc driver
- *
- * Revision 1.2  2000/11/10 17:25:11  felfert
- * Changes for kernel 2.4
- *
- * Revision 1.1  2000/11/03 16:58:45  felfert
- * Initial import
- *
- *
  */
 
 #include "fsm.h"
 #include <linux/version.h>
+#include <linux/config.h>
+#include <linux/module.h>
 
 fsm_instance *
 init_fsm(char *name, const char **state_names, const char **event_names, int nr_states,
@@ -228,3 +219,16 @@
 	this->tl.expires = jiffies + (millisec * HZ) / 1000;
 	add_timer(&this->tl);
 }
+
+EXPORT_SYMBOL(init_fsm);
+EXPORT_SYMBOL(kfree_fsm);
+EXPORT_SYMBOL(fsm_settimer);
+EXPORT_SYMBOL(fsm_deltimer);
+EXPORT_SYMBOL(fsm_addtimer);
+EXPORT_SYMBOL(fsm_modtimer);
+EXPORT_SYMBOL(fsm_getstate_str);
+
+#if FSM_DEBUG_HISTORY
+EXPORT_SYMBOL(fsm_print_history);
+EXPORT_SYMBOL(fsm_record_history);
+#endif
diff -u --recursive --new-file v2.4.7/linux/drivers/s390/net/fsm.h linux/drivers/s390/net/fsm.h
--- v2.4.7/linux/drivers/s390/net/fsm.h	Tue Feb 13 14:13:44 2001
+++ linux/drivers/s390/net/fsm.h	Wed Jul 25 14:12:02 2001
@@ -1,13 +1,4 @@
-/* $Id: fsm.h,v 1.1 2000/11/30 11:21:08 bird Exp $
- *
- * $Log: fsm.h,v $
- * Revision 1.1  2000/11/30 11:21:08  bird
- * Support for new ctc driver
- *
- * Revision 1.1  2000/11/03 16:58:45  felfert
- * Initial import
- *
- *
+/* $Id: fsm.h,v 1.3 2001/06/18 16:49:19 felfert Exp $
  */
 #ifndef _FSM_H_
 #define _FSM_H_
@@ -16,7 +7,7 @@
 #include <linux/types.h>
 #include <linux/timer.h>
 #include <linux/time.h>
-#include <linux/malloc.h>
+#include <linux/slab.h>
 #include <linux/sched.h>
 #include <linux/string.h>
 #include <asm/atomic.h>
@@ -115,10 +106,11 @@
  * @param tmpl_len    Length of the describing array.
  * @param order       Parameter for allocation of the FSM data structs.
  */
-fsm_instance * init_fsm(char *name, const char **state_names,
-			const char **event_names,
-			int nr_states, int nr_events, const fsm_node *tmpl,
-			int tmpl_len, int order);
+extern fsm_instance *
+init_fsm(char *name, const char **state_names,
+	 const char **event_names,
+	 int nr_states, int nr_events, const fsm_node *tmpl,
+	 int tmpl_len, int order);
 
 /**
  * Releases an FSM
diff -u --recursive --new-file v2.4.7/linux/drivers/s390/net/iucv.c linux/drivers/s390/net/iucv.c
--- v2.4.7/linux/drivers/s390/net/iucv.c	Thu Apr 12 12:16:35 2001
+++ linux/drivers/s390/net/iucv.c	Wed Jul 25 14:12:02 2001
@@ -1,15 +1,30 @@
-/*
- *  drivers/s390/net/iucv.c
+/*                                                                                             
+ *   drivers/s390/net/iucv.c
  *    Support for VM IUCV functions for use by other part of the
  *    kernel or loadable modules.
  *
  *  S390 version
  *    Copyright (C) 2000 IBM Corporation
- *    Author(s): Xenia Tkatschow (xenia@us.ibm.com)
- *               Alan Altmark (Alan_Altmark@us.ibm.com)
- */
-
+ *    Author(s): Alan Altmark (Alan_Altmark@us.ibm.com)
+ *               Xenia Tkatschow (xenia@us.ibm.com)
+ * Functionality:                                                    
+ * To explore any of the IUCV functions, one must first register     
+ * their program using iucv_register(). Once your program has        
+ * successfully completed a register, it can use the other functions.
+ * For furthur reference on all IUCV functionality, refer to the     
+ * CP Programming Services book, also available on the web            
+ * thru www.ibm.com/s390/vm/pubs , manual # SC24-5760.               
+ *                                                                    
+ *      Definition of Return Codes                                    
+ *      -All positive return codes including zero are reflected back 
+ *       from CP and the definition can be found in CP Programming    
+ *       Services book.                  
+ *      - (-ENOMEM) Out of memory
+ *      - (-EINVAL) Invalid value                             
+*/
+/* #define DEBUG 1 */
 #include <linux/module.h>
+#include <linux/config.h>
 #include <linux/version.h>
 #include <linux/spinlock.h>
 #include <linux/kernel.h>
@@ -20,25 +35,67 @@
 #include <asm/atomic.h>
 #include "iucv.h"
 #include <asm/io.h>
+#include <asm/irq.h>
 #include <asm/s390_ext.h>
 #include <asm/ebcdic.h>
 
+#ifndef min
+#define min(a,b) (((a)<(b))?(a):(b))
+#endif
+#ifndef max
+#define max(a,b) (((a)>(b))?(a):(b))
+#endif
+
+#ifdef DEBUG
+#undef KERN_INFO
 #undef KERN_DEBUG
+#define KERN_INFO KERN_EMERG
 #define KERN_DEBUG KERN_EMERG
-//#define DEBUG3
-//#define DEBUG         /* Turns Printk's on                         */
-//#define DEBUG2        /* This prints the parameter list before and */
-		      /* after the b2f0 call to cp                 */
+#endif
+
 #undef NULL
 #define NULL 0
-#define ADDED_STOR 64		/* ADDITIONAL STORAGE FOR PATHID @'S */
-ulong declare_flag = 0;
+
+#define PRRTY_PRMTD    0x01	/* priority permitted */
+#define RPY_RQRD       0x01	/* reply required */
+#define ADDED_STOR  64		/* ADDITIONAL STORAGE FOR PATHID @'S */
+#define BUFFER_SIZE 40		/* Size of 31-bit iparml */
+
+/* FLAGS:
+ * All flags are defined in the field IPFLAGS1 of each function
+ * and can be found in CP Programming Services.
+ * IPSRCCLS - Indicates you have specified a source class
+ * IPFGMCL  - Indicates you have specified a target class
+ * IPFGPID  - Indicates you have specified a pathid
+ * IPFGMID  - Indicates you have specified a message ID
+ * IPANSLST - Indicates that you are using an address list for
+ *            reply data
+ * IPBUFLST - Indicates that you are using an address list for
+ *            message data
+ */
+
+#define IPSRCCLS 	0x01
+#define IPFGMCL         0x01
+#define IPFGPID         0x02
+#define IPFGMID         0x04
+#define IPANSLST        0x08
+#define IPBUFLST        0x40
+
 static uchar iucv_external_int_buffer[40];
+
+/* Spin Lock declaration */
 struct tq_struct short_task;	/* automatically initialized to zero */
-static iucv_interrupt_ops_t my_ops;
-spinlock_t lock = SPIN_LOCK_UNLOCKED;
+static spinlock_t iucv_lock = SPIN_LOCK_UNLOCKED;
 
-static void do_int (iucv_ConnectionPending *);
+/* General IUCV interrupt structure */
+typedef struct {
+	u16 ippathid;
+	uchar res1;
+	uchar iptype;
+	u32 res2;
+	uchar ipvmid[8];
+	uchar res3[24];
+} iucv_GeneralInterrupt;
 
 /***************INTERRUPT HANDLING DEFINITIONS***************/
 typedef struct _iucv_packet {
@@ -46,1984 +103,2323 @@
 	uchar data[40];
 } iucv_packet;
 struct tq_struct short_task;
+
 static spinlock_t iucv_packets_lock = SPIN_LOCK_UNLOCKED;
+
 iucv_packet *iucv_packets_head, *iucv_packets_tail;
 
 static atomic_t bh_scheduled = ATOMIC_INIT (0);
+
+/* 
+ *Internal function prototypes 
+ */
+
+static ulong iucv_vmsize (void);
+
+int iucv_declare_buffer (void);
+
+int iucv_retrieve_buffer (void);
+
+static int iucv_add_pathid (u16 pathid, iucv_handle_t handle, void *pgm_data);
+
+static void iucv_remove_pathid (u16 pathid);
+
 void bottom_half_interrupt (void);
 
+static void do_int (iucv_GeneralInterrupt *);
+
+inline void top_half_interrupt (struct pt_regs *regs, __u16 code);
 /************FUNCTION ID'S****************************/
-#define accept          10
-#define connect         11
-#define declare_buffer  12
-#define purge           9
-#define query           0
-#define quiesc          13
-#define receive         5
-#define reject          8
-#define reply           6
-#define resume          14
-#define retrieve_buffer 2
-#define send            4
-#define setmask         16
-#define sever           15
-
-/*****************************************************************/
-/*  Structure: handler                                           */
-/*  members: next - is a pointer to next handler on chain        */
-/*           prev - is a pointer to prev handler on chain        */
-/*           vmid - 8 char array of machine identification       */
-/*           user_data - 16 char array for user identification   */
-/*           mask - 24 char array used to compare the 2 previous */
-/*           interrupt_table - functions for interrupts          */
-/*           start - pointer to start of block of pointers to    */
-/*                   handler_table_entries                       */
-/*           end - pointer to end of block of pointers to        */
-/*                 handler_table_entries                         */
-/*           size - ulong, size of block                         */
-/*           pgm_data - ulong, program data                      */
-/* NOTE: Keep vmid and user_data together in this order          */
-/*****************************************************************/
+
+#define ACCEPT          10
+#define CONNECT         11
+#define DECLARE_BUFFER  12
+#define PURGE           9
+#define QUERY           0
+#define QUIESCE         13
+#define RECEIVE         5
+#define REJECT          8
+#define REPLY           6
+#define RESUME          14
+#define RETRIEVE_BUFFER 2
+#define SEND            4
+#define SETMASK         16
+#define SEVER           15
+
+/*                                                               
+ * Structure: handler                                            
+ * members: next - is a pointer to next handler on chain         
+ *          prev - is a pointer to prev handler on chain         
+ *          structure: id                                        
+ *             vmid - 8 char array of machine identification     
+ *             user_data - 16 char array for user identification 
+ *             mask - 24 char array used to compare the 2 previous  
+ *          interrupt_table - vector of interrupt functions.     
+ *          pathid_head - pointer to start of user_pathid_table  
+ *          pathid_tail - pointer to end of user_pathid_table    
+ *          entries -  ulong, size of user_pathid_table          
+ *          pgm_data -  ulong, application data that is passed   
+ *                      to the interrupt handlers                
+*/
 typedef struct {
 	ulong *next;
 	ulong *prev;
-	uchar vmid[8];
-	uchar user_data[16];
-	uchar mask[24];
+	struct {
+		uchar userid[8];
+		uchar user_data[16];
+		uchar mask[24];
+	} id;
 	iucv_interrupt_ops_t *interrupt_table;
-	ulong *start;
-	ulong *end;
-	ulong size;
-	ulong pgm_data;
+	ulong *pathid_head;
+	ulong *pathid_tail;
+	ulong entries;
+	void *pgm_data;
 } handler;
 
-/*******************************************************************/
-/* Structure: handler_table_entry                                  */
-/* members: addrs - pointer to a handler                           */
-/*          pathid - ushort containing path identification         */
-/*          pgm_data - ulong, program data                         */
-/*******************************************************************/
+/*                                                         
+ * Structure: handler_table_entry                          
+ * members: addrs - pointer to a handler                   
+ *          pathid - ushort containing path identification 
+ *          pgm_data - ulong, application data that is     
+ *                     passed to the interrupt handlers    
+ *          ops - pointer to iucv interrupt vector         
+ */
+
 typedef struct {
 	handler *addrs;
-	ushort pathid;
-	ulong pgm_data;
+	u16 pathid;
+	void *pgm_data;
+	iucv_interrupt_ops_t *ops;
 } handler_table_entry;
 
-/* main_table: array of pointers to handler_tables         */
-static handler_table_entry *main_table[128];
-/* handler_anchor: points to first handler on chain        */
-static handler *handler_anchor;
-
-/****************FIVE  STRUCTURES************************************/
-/* Data struct 1: iparml_control                                    */
-/*                Used for iucv_accept                              */
-/*                         iucv_connect                             */
-/*                         iucv_quiesce                             */
-/*                         iucv_resume                              */
-/*                         iucv_sever                               */
-/*                         iucv_retrieve_buffer                     */
-/* Data struct 2: iparml_dpl  (data in parameter list)              */
-/*                Used for iucv_send_prmmsg                         */
-/*                         iucv_send2way_prmmsg                     */
-/*                         iucv_send2way_prmmsg_array               */
-/*                         iucv_reply_prmmsg                        */
-/* Data struct 3: iparml_db    (data in a buffer)                   */
-/*                Used for iucv_receive                             */
-/*                         iucv_receive_array                       */
-/*                         iucv_receive_simple                      */
-/*                         iucv_reject                              */
-/*                         iucv_reply                               */
-/*                         iucv_reply_array                         */
-/*                         iucv_send                                */
-/*                         iucv_send_simple                         */
-/*                         iucv_send_array                          */
-/*                         iucv_send2way                            */
-/*                         iucv_send2way_array                      */
-/*                         iucv_declare_buffer                      */
-/* Data struct 4: iparml_purge                                      */
-/*                Used for iucv_purge                               */
-/*                         iucv_query                               */
-/* Data struct 5: iparml_set_mask                                   */
-/*                Used for iucv_set_mask                            */
-/********************************************************************/
+/* 
+ * Internal function prototypes 
+ */
+
+static int iucv_add_handler (handler * new_handler);
+
+static void iucv_remove_handler (handler * users_handler);
+
+/* handler_anchor: points to first handler on chain */
+/* handler_tail: points to last handler on chain */
+/* handler_table_anchor: points to beginning of handler_table_entries*/
+
+static handler *handler_anchor = NULL;
+
+static handler *handler_tail = NULL;
+
+static handler_table_entry *handler_table_anchor = NULL;
+
+/* declare_flag: is 0 when iucv_declare_buffer has not been called */
+
+static ulong declare_flag = 0;
+
+/****************FIVE 40-BYTE PARAMETER STRUCTURES******************/
+/* Data struct 1: iparml_control                                      
+ * Used for iucv_accept                                               
+ *          iucv_connect                                              
+ *          iucv_quiesce                                              
+ *          iucv_resume                                               
+ *          iucv_sever                                                
+ *          iucv_retrieve_buffer                                      
+ * Data struct 2: iparml_dpl     (data in parameter list)             
+ * Used for iucv_send_prmmsg                                          
+ *          iucv_send2way_prmmsg                                      
+ *          iucv_send2way_prmmsg_array                                
+ *          iucv_reply_prmmsg                                         
+ * Data struct 3: iparml_db       (data in a buffer)                  
+ * Used for iucv_receive                                              
+ *          iucv_receive_array                                        
+ *          iucv_reject                                               
+ *          iucv_reply                                                
+ *          iucv_reply_array                
+ *          iucv_send                       
+ *          iucv_send_array                 
+ *          iucv_send2way                   
+ *          iucv_send2way_array             
+ *          iucv_declare_buffer             
+ * Data struct 4: iparml_purge              
+ * Used for iucv_purge                      
+ *          iucv_query                      
+ * Data struct 5: iparml_set_mask           
+ * Used for iucv_set_mask                   
+*/
+
 typedef struct {
-	ushort ippathid;
+	u16 ippathid;
 	uchar ipflags1;
 	uchar iprcode;
-	ushort ipmsglim;
-	ushort res1;
+	u16 ipmsglim;
+	u16 res1;
 	uchar ipvmid[8];
 	uchar ipuser[16];
 	uchar iptarget[8];
 } iparml_control;
 
-/******************/
 typedef struct {
-	ushort ippathid;
+	u16 ippathid;
 	uchar ipflags1;
 	uchar iprcode;
-	ulong ipmsgid;
-	ulong iptrgcls;
+	u32 ipmsgid;
+	u32 iptrgcls;
 	uchar iprmmsg[8];
-	ulong ipsrccls;
-	ulong ipmsgtag;
-	ulong ipbfadr2;
-	ulong ipbfln2f;
-	ulong res;
+	u32 ipsrccls;
+	u32 ipmsgtag;
+	u32 ipbfadr2;
+	u32 ipbfln2f;
+	u32 res;
 } iparml_dpl;
 
-/*******************/
 typedef struct {
-	ushort ippathid;
+	u16 ippathid;
 	uchar ipflags1;
 	uchar iprcode;
-	ulong ipmsgid;
-	ulong iptrgcls;
-	ulong ipbfadr1;
-	ulong ipbfln1f;
-	ulong ipsrccls;
-	ulong ipmsgtag;
-	ulong ipbfadr2;
-	ulong ipbfln2f;
-	ulong res;
+	u32 ipmsgid;
+	u32 iptrgcls;
+	u32 ipbfadr1;
+	u32 ipbfln1f;
+	u32 ipsrccls;
+	u32 ipmsgtag;
+	u32 ipbfadr2;
+	u32 ipbfln2f;
+	u32 res;
 } iparml_db;
 
-/********************/
 typedef struct {
-	ushort ippathid;
+	u16 ippathid;
 	uchar ipflags1;
 	uchar iprcode;
-	ulong ipmsgid;
-	uchar ipaudit[4];
-	uchar res1[4];
-	ulong res2;
-	ulong ipsrccls;
-	ulong ipmsgtag;
-	ulong res3[3];
+	u32 ipmsgid;
+	uchar ipaudit[3];
+	uchar res1[5];
+	u32 res2;
+	u32 ipsrccls;
+	u32 ipmsgtag;
+	u32 res3[3];
 } iparml_purge;
 
-/*******************/
 typedef struct {
 	uchar ipmask;
 	uchar res1[2];
 	uchar iprcode;
-	ulong res2[9];
+	u32 res2[9];
 } iparml_set_mask;
 
 /*********************INTERNAL FUNCTIONS*****************************/
-/********************************************************************/
-/* Name: b2f0                                                       */
-/* Purpose: this function calls cp to execute iucv commands.        */
-/* Input: code - int, identifier of iucv call to cp.                */
-/*        parm - void *, pointer to 40 byte iparml area passed to cp */
-/* Output: iprcode- return code from iucv call to cp                */
-/********************************************************************/
-/* Assembler code performing iucv call                             */
-/*******************************************************************/
-inline ulong
-b2f0 (int code, void *parm)
+
+static ulong
+iucv_vmsize (void)
+{
+	extern unsigned long memory_size;
+	return memory_size;
+}
+
+/*
+ * Name: dumpit                                                     
+ * Purpose: print to the console buffers of a given length          
+ * Input: buf - (* uchar) - pointer to buffer to be printed         
+ *        len - int - length of buffer being printed                
+ * Output: void                                                     
+ */
+
+#ifdef DEBUG
+
+static void
+iucv_dumpit (uchar * buf, int len)
 {
-	uchar *iprcode;		/* used to extract iprcode */
-#ifdef DEBUG2
 	int i;
-	uchar *prt_parm;
-	prt_parm = (uchar *) (parm);
-	printk (KERN_DEBUG "parameter list before b2f0 call\n");
-	for (i = 0; i < 40; i++)
-		printk (KERN_DEBUG "%02x ", prt_parm[i]);
-	printk (KERN_DEBUG "\n");
-#endif
-	asm volatile ("LRA   1,0(%1)\n\t"
-		      "LR    0,%0\n\t"
-		      ".long 0xb2f01000"
-		      : : "d" (code), "a" (parm) : "0", "1");
-#ifdef DEBUG2
-	printk (KERN_DEBUG "parameter list after b2f0 call\n");
-	for (i = 0; i < 40; i++)
-		printk (KERN_DEBUG "%02x ", prt_parm[i]);
-	printk (KERN_DEBUG "\n");
-#endif
-	iprcode = (uchar *) (parm + 3);
-	return (ulong) (*iprcode);
+	for (i = 0; i < len; i++) {
+		if (!(i % 16) && i != 0)
+			printk ("\n");
+		else if (!(i % 4) && i != 0)
+			printk (" ");
+		printk ("%02X", buf[i]);
+	}
+	if (len % 16)
+		printk ("\n");
+	return;
 }
 
-/**************************************************************/
-/* Name: iucv_retrieve_buffer                                 */
-/* Purpose: terminates all use of iucv                        */
-/* Input: void                                                */
-/* Output: Return code from CP                                */
-/**************************************************************/
-int
-iucv_retrieve_buffer (void)
+#else
+static void
+iucv_dumpit (uchar * buf, int len)
 {
-	iparml_control parm;
-	ulong b2f0_result;
-#ifdef DEBUG
-	printk (KERN_DEBUG "entering iucv_retrieve_buffer\n");
-#endif
-	memset (&(parm), 0, sizeof (parm));
-	b2f0_result = b2f0 (retrieve_buffer, &parm);
-	if (b2f0_result == NULL)
-		declare_flag = 0;
-#ifdef DEBUG
-	printk (KERN_DEBUG "exiting iucv_retrieve_buffer\n");
-#endif
-	return b2f0_result;
 }
 
-/**************************************************************/
-/* Name: iucv_declare_buffer                                  */
-/* Purpose: specifies the guests real address of an external  */
-/*          interrupt.                                        */
-/* Input: bfr - pointer to  buffer                            */
-/* Output: iprcode - return code from b2f0 call               */
-/* Note : See output options for b2f0 call                    */
-/**************************************************************/
+#endif
+
+/*
+ * Name iucv_add_handler
+ * Purpose: Place new handle on handler_anchor chain, if identical handler is not
+ *	    found. Handlers are ordered with largest mask integer value first.
+ * Input: new_handler - handle that is being entered into chain
+ * Return: int
+ *	   0 - handler added
+ *	   1 - identical handler found, handler not added to chain
+*/
 int
-iucv_declare_buffer (uchar * bfr)
+iucv_add_handler (handler * new_handler)
 {
-	iparml_db parm;
-	ulong b2f0_result;
-#ifdef DEBUG
-	printk (KERN_DEBUG "Entering iucv_declare_buffer\n");
-#endif
-	memset (&(parm), 0, sizeof (parm));
-	parm.ipbfadr1 = virt_to_phys (bfr);
-	b2f0_result = b2f0 (declare_buffer, &parm);
-#ifdef DEBUG
-	printk (KERN_DEBUG "Address of EIB = %p\n", bfr);
-	printk (KERN_DEBUG "Exiting iucv_declare_buffer\n");
-#endif
-	return b2f0_result;
+	handler *R = new_handler;
+	int rc = 1, comp = 0;	/* return code (rc = 1 not added) or (rc = 0 added) */
+	ulong flags;
+	pr_debug ("iucv_add_handler: entering\n");
+	iucv_dumpit ((uchar *) new_handler, sizeof (handler));
+	spin_lock_irqsave (&iucv_lock, flags);
+	if (handler_anchor == NULL) {
+		/* add to beginning of chain */
+		handler_anchor = handler_tail = new_handler;
+		rc = 0;
+	} else
+		for (R = handler_anchor; R != NULL; R = (handler *) R->next) {
+			comp = memcmp ((void *) &(new_handler->id),
+				       (void *) &(R->id), sizeof (R->id));
+			pr_debug ("comp = %d\n", comp);
+			if (comp == 0)	/* identicle handler found */
+				break;	/* break out of for loop */
+			else if (comp > 0) {	/* new_handler > R */
+				pr_debug
+				    ("iucv_add_handler: Found a place to add,"
+				     "R is\n");
+				iucv_dumpit ((uchar *) R, sizeof (handler));
+				if ((R->prev != NULL)) {
+					/* add to middle of chain */
+					pr_debug
+					    ("iucv_add_handler: added to middle\n");
+					new_handler->prev = R->prev;
+					new_handler->next = (ulong *) R;
+					((handler *) (R->prev))->next =
+					    (ulong *) new_handler;
+					R->prev = (ulong *) new_handler;
+					rc = 0;
+					break;	/* break out of FOR loop */
+				} else {	/* R->prev == NULL */
+					/* add to start of chain;  */
+					pr_debug ("iucv_add_handler:"
+						  "added to beginning\n");
+					R->prev = (ulong *) new_handler;
+					new_handler->next = (ulong *) R;
+					handler_anchor = new_handler;
+					rc = 0;
+					break;	/* break out of FOR loop */
+				}
+			}	/* end of else if */
+		}		/* end of for loop */
+	if (R == NULL) {
+		/* add to end of chain */
+		pr_debug ("iucv_add_handler: added to end\n");
+		handler_tail->next = (ulong *) new_handler;
+		new_handler->prev = (ulong *) handler_tail;
+		handler_tail = new_handler;
+		rc = 0;
+	}
+	spin_unlock_irqrestore (&iucv_lock, flags);
+
+	pr_debug ("Current Chain of handlers is\n");
+	for (R = handler_anchor; R != NULL; R = (handler *) R->next)
+		iucv_dumpit ((uchar *) R, (int) sizeof (handler));
+
+	pr_debug ("iucv_add_handler: exiting\n");
+	return rc;
+}
+
+/* 
+ * Name: iucv_remove_handler
+ * Purpose: Remove handler when application unregisters.
+ * Input: users_handler - handler to be removed
+ * Output: void
+*/
+void
+iucv_remove_handler (handler * users_handler)
+{
+	handler *R;		/* used for Debugging */
+	pr_debug ("iucv_remove_handler: entering\n");
+	if ((users_handler->next != NULL) & (users_handler->prev != NULL)) {
+		/* remove from middle of chain */
+		((handler *) (users_handler->next))->prev =
+		    (ulong *) users_handler->prev;
+		((handler *) (users_handler->prev))->next =
+		    (ulong *) users_handler->next;
+	} else if ((users_handler->next != NULL) &
+		   (users_handler->prev == NULL)) {
+		/* remove from start of chain */
+		((handler *) (users_handler->next))->prev = NULL;
+		handler_anchor = (handler *) users_handler->next;
+	} else if ((users_handler->next == NULL) &
+		   (users_handler->prev != NULL)) {
+		/* remove from end of chain */
+		((handler *) (users_handler->prev))->next = NULL;
+		handler_tail = (handler *) users_handler->prev;
+	} else {
+		handler_anchor = NULL;
+		handler_tail = NULL;
+	}
+
+	pr_debug ("Current Chain of handlers is\n");
+	for (R = handler_anchor; R != NULL; R = (handler *) R->next)
+		iucv_dumpit ((uchar *) R, (int) sizeof (handler));
+
+	pr_debug ("iucv_remove_handler: exiting\n");
+	return;
+}
+
+/*
+ * Name: b2f0
+ * Purpose: This function calls CP to execute IUCV commands.
+ * Input: code -  identifier of IUCV call to CP.
+ *        parm -  pointer to 40 byte iparml area
+ *               passed to CP
+ * Output: iprcode- return code from CP's IUCV call
+ * NOTE: Assembler code performing IUCV call
+*/
+inline ulong
+b2f0 (u32 code, void *parm)
+{
+	uchar *iprcode;
+	pr_debug ("iparml before b2f0 call\n");
+	iucv_dumpit ((uchar *) parm, (int) BUFFER_SIZE);
+	asm volatile ("LRA   1,0(%1)\n\t"
+		      "LR    0,%0\n\t"
+		      ".long 0xb2f01000"::"d" (code), "a" (parm):"0", "1");
+	pr_debug ("iparml after b2f0 call\n");
+	iucv_dumpit ((uchar *) parm, (int) BUFFER_SIZE);
+	iprcode = (uchar *) (parm + 3);
+	return (ulong) (*iprcode);
 }
 
-/**************************************************************/
-/* Name: add_pathid                                           */
-/* Purpose: adds a path id to the system                      */
-/* Input: pathid - ushort, pathid to enter system             */
-/*        handle - iucv_handle_t, address of handler to add to */
-/*        pgm_data - ulong, pathid identifier.                */
-/* Output: 0: successful addition of pathid                   */
-/**************************************************************/
+/*
+ * Name: iucv_add_pathid                                            
+ * Purpose: Adds a path id to the system.                       
+ * Input: pathid -  pathid that is going to be entered into system              
+ *        handle -  address of handler that the pathid will be associated
+ *		   with.
+ *        pgm_data - token passed in by application.                
+ * Output: 0: successful addition of pathid
+ *	   - EINVAL - pathid entry is being used by another application
+ *	   - ENOMEM - storage allocation for a new pathid table failed      
+*/
 int
-add_pathid (ushort pathid, iucv_handle_t handle, ulong pgm_data)
+iucv_add_pathid (u16 pathid, iucv_handle_t handle, void *pgm_data)
 {
-	ulong index1, index2;	/* index1 into main_table */
 	ulong add_flag = 0;
 	ulong old_size = 0, new_size = 0;
+	ulong flags;
 	uchar *to, *from;	/* pointer for copying the table */
-	handler_table_entry *P = 0;	/*P is a pointer to H_T_E */
-	handler *Q = 0;		/*Q is a pointer to handler */
-	ulong *X = 0;		/*Points to array of pointers */
-#ifdef DEBUG
-	printk (KERN_DEBUG "entering add_pathid\n");
-#endif
-	Q = (handler *) handle;	/* Q points to a handler    */
-	/*
-	 * main_table has 128 entries.
-	 * 128*512 = 65536 maximum number of pathid's allowed
-	 */
-	index1 = ((ulong) pathid) / 512;
-	index2 = ((ulong) pathid) % 512;
-#ifdef DEBUG
-	printk (KERN_DEBUG "index1 = %d\n ", (int) index1);
-	printk (KERN_DEBUG "index2 = %d\n ", (int) index2);
-	printk (KERN_DEBUG "Q is pointing to %p ", Q);
-#endif
-	spin_lock (&lock);
-	/*
-	 * If NULL then handler table does not exist and need to get storage
-	 *  and have main_table[index1] point to it
-	 * If allocating storage failed, return
-	 */
-	if (main_table[index1] == NULL) {
-		main_table[index1] = (handler_table_entry *) kmalloc
-		    (512 * sizeof (handler_table_entry), GFP_KERNEL);
-		if (main_table[index1] == NULL) {
-			spin_unlock (&lock);
-			return -ENOBUFS;
-		}
-		memset (main_table[index1], 0,
-			512 * sizeof (handler_table_entry));
-#ifdef DEBUG
-		printk (KERN_DEBUG "address of table H_T is %p \n",
-			main_table[index1]);
-#endif
-	}
+	handler_table_entry *P = 0;	/*P is a pointer to the users H_T_E */
+	handler *users_handler = 0;
+	ulong *X = 0;		/* Points to array of pointers to H-T_E */
+
+	pr_debug ("iucv_add_pathid: entering\n");
+
+	users_handler = (handler *) handle;
+
+	pr_debug ("iucv_add_pathid: users_handler is pointing to %p ",
+		  users_handler);
+
+	spin_lock_irqsave (&iucv_lock, flags);
+
 	/*
-	 * P points to a handler table entry (H_T_E) in which all entries in
+	 * P points to the users handler table entry (H_T_E) in which all entries in
 	 * that structure should be NULL. If they're not NULL, then there
-	 * is a bad pointer and it will return(-2) immediately, otherwise
+	 * is a bad pointer and it will return(-EINVAL) immediately, otherwise users
 	 * data will be entered into H_T_E.
 	 */
-	P = main_table[index1];
-	if ((P + index2)->addrs) {
-#ifdef DEBUG
-		printk (KERN_DEBUG "main_table[index1] = %p \n",
-			main_table[index1]);
-		printk (KERN_DEBUG "P+index2 = %p \n", P + index2);
-		printk (KERN_DEBUG "(P+index2)->addrs is %p \n",
-			(P + index2)->addrs);
-#endif
-		spin_unlock (&lock);
-		printk (KERN_DEBUG "bad pointer1\n");
-		return (-2);
+
+	P = handler_table_anchor + pathid;	/* index into users handler table */
+
+	pr_debug ("handler_table_anchor is %p\n", handler_table_anchor);
+	pr_debug ("P=handler_table_anchor+pathid = %p\n", P);
+
+	if (P->addrs) {
+		pr_debug ("iucv_add_pathid: P = %p \n", P);
+		pr_debug ("iucv_add_pathid: P->addrs is %p \n", P->addrs);
+		spin_unlock_irqrestore (&iucv_lock, flags);
+		/* This message should be sent to syslog */
+		printk (KERN_WARNING "iucv_add_pathid: Pathid being used,"
+			"error.\n");
+		return (-EINVAL);
 	}
-	(P + index2)->addrs = handle;
+
+	P->addrs = handle;
+	P->pathid = pathid;
+
 	/*
-	 * checking if address of handle is valid, if it's not valid,
-	 * unlock the lock and return(-2) immediately.
+	 * pgm_data provided in iucv_register may be overwritten on a connect, accept. 
 	 */
-	if ((P + index2)->addrs == NULL) {
-		spin_unlock (&lock);
-		printk (KERN_DEBUG "bad pointer2\n");
-		return (-2);
-	}
-	(P + index2)->pathid = pathid;
+
 	if (pgm_data)
-		(P + index2)->pgm_data = pgm_data;
+		P->pgm_data = pgm_data;
 	else
-		(P + index2)->pgm_data = Q->pgm_data;
+		P->pgm_data = users_handler->pgm_data;
+
+	/*
+	 * Address of pathid's iucv_interrupt_ops is taken from the associated handler
+	 * and added here for quicker access to the interrupt tables during interrupt
+	 * handling.
+	 */
+
+	P->ops = (P->addrs)->interrupt_table;
+
+	pr_debug ("Complete users H_T_E is\n");
+	iucv_dumpit ((uchar *) P, sizeof (handler_table_entry));
+
 	/*
 	 * Step thru the table of addresses of pathid's to find the first
 	 * available entry (NULL). If an entry is found, add the pathid,
 	 * unlock and exit. If an available entry is not found, allocate a
-	 * new, larger table, copy over the old table and deallocate the
-	 * old table and add the pathid.
+	 * new, larger table, copy over the old table to the new table. De-allocate the
+	 * old table and enter the new pathid.
 	 */
-#ifdef DEBUG
-	printk (KERN_DEBUG "address of handle is %p\n", handle);
-	printk (KERN_DEBUG "&(Q->start) is %p\n", &(Q->start));
-	printk (KERN_DEBUG "&(Q->end) is %p\n", &(Q->end));
-	printk (KERN_DEBUG "start of pathid table is %p\n", (Q->start));
-	printk (KERN_DEBUG "end of pathid table is %p\n", (Q->end));
-	for (X = (Q->start); X < (Q->end); X++)
-		printk (KERN_DEBUG "X = %p ", X);
-	printk (KERN_DEBUG "\n");
-#endif
-	for (X = (Q->start); X < (Q->end); X++) {
+
+	pr_debug ("iucv_add_pathid: address of handle is %p\n", handle);
+	pr_debug ("iucv_add_pathid: &(users_handler->pathid_head) is %p\n",
+		  &(users_handler->pathid_head));
+	pr_debug ("iucv_add_pathid: &(users_handler->pathid_tail) is %p\n",
+		  &(users_handler->pathid_tail));
+	pr_debug ("iucv_add_pathid: start of pathid table is %p\n",
+		  (users_handler->pathid_head));
+	pr_debug ("iucv_add_pathid: end of pathid table is %p\n",
+		  (users_handler->pathid_tail));
+	iucv_dumpit ((uchar *) users_handler->pathid_head,
+		     (int) (users_handler->pathid_tail -
+			    users_handler->pathid_head));
+
+	for (X = (users_handler->pathid_head);
+	     X <
+	     (users_handler->pathid_head +
+	      users_handler->entries * sizeof (ulong)); X++)
 		if (*X == NULL) {
-#ifdef DEBUG
-			printk (KERN_DEBUG "adding pathid, %p = P+index2\n",
-				(P + index2));
-#endif
-			*X = (ulong) (P + index2);
+			pr_debug ("adding pathid, %p = P\n", P);
+			*X = (ulong) P;
 			add_flag = 1;
+			break;	/* breaks out of for loop */
 		}
-		if (add_flag == 1)
-			break;
-	}
-	if (add_flag == 0) {	/* element not added to list */
-		X = Q->start;
-		old_size = Q->size;
-		new_size = old_size + ADDED_STOR;	/* size of new table */
-		from = (uchar *) (Q->start);	/* address of old table */
-		(*Q).start = kmalloc (new_size * sizeof (ulong), GFP_KERNEL);
-		if ((Q->start) == NULL) {
-			spin_unlock (&lock);
-			return -ENOBUFS;
+
+	pr_debug ("Addresses of HTE's are\n");
+	iucv_dumpit ((uchar *) users_handler->pathid_head,
+		     users_handler->entries * sizeof (ulong));
+
+	if (add_flag == 0) {	/* element not added to list: must get a new table */
+		X = users_handler->pathid_head;
+		old_size = users_handler->entries;
+		new_size = old_size + ADDED_STOR;	/*number of entries of new table */
+		from = (uchar *) (users_handler->pathid_head);	/*address of old table */
+		users_handler->pathid_head =
+		    kmalloc (new_size * sizeof (ulong), GFP_ATOMIC);
+
+		if (users_handler->pathid_head == NULL) {
+			users_handler->pathid_head = X;	/*setting old condition */
+			spin_unlock_irqrestore (&iucv_lock, flags);
+			printk (KERN_WARNING
+				"iucv_add_pathid: storage allocation"
+				"failed for new pathid table \n ");
+			memset (P, 0, sizeof (handler_table_entry));
+			return -ENOMEM;
 		}
-		memset ((*Q).start, 0, new_size * sizeof (ulong));
-		to = (uchar *) (Q->start);	/* address of new table */
+
+		memset (users_handler->pathid_head, 0,
+			new_size * sizeof (ulong));
+		to = (uchar *) (users_handler->pathid_head);	/* address of new table */
 		/* copy old table to new  */
 		memcpy (to, from, old_size * (sizeof (ulong)));
-#ifdef DEBUG
-		printk (KERN_DEBUG "Getting a new pathid table\n");
-		printk (KERN_DEBUG "to is %p \n", to);
-		printk (KERN_DEBUG "from is %p \n", from);
-#endif
-		Q->size = new_size;	/* storing new size of table */
-		Q->end = (Q->start) + (Q->size);
-		X = Q->start + old_size;	/* next blank in table */
-		*X = (ulong) (P + index2);	/* adding element to new table */
-#ifdef DEBUG
-		printk (KERN_DEBUG "Q->size is %u \n", (int) (Q->size));
-		printk (KERN_DEBUG "Q->end is %p \n", Q->end);
-		printk (KERN_DEBUG "Q->start is %p \n", Q->start);
-		printk (KERN_DEBUG "X is %p \n", X);
-		printk (KERN_DEBUG "*X is %u \n", (int) (*X));
-#endif
+
+		pr_debug ("iucv: add_pathid: Getting a new pathid table\n");
+		pr_debug ("iucv: add_pathid: to is %p \n", to);
+		pr_debug ("iucv: add_pathid: from is %p \n", from);
+
+		users_handler->entries = new_size;	/* storing new size of table */
+		users_handler->pathid_tail =
+		    (users_handler->pathid_head) + (users_handler->entries);
+		X = users_handler->pathid_head + old_size;
+		*X = (ulong) P;	/* adding element to new table */
+
+		pr_debug ("iucv: add_pathid: users_handler->entries is %u \n",
+			  (int) (users_handler->entries));
+		pr_debug
+		    ("iucv: add_pathid: users_handler->pathid_tail is %p\n",
+		     users_handler->pathid_tail);
+		pr_debug ("users_handler->pathid_head is %p \n",
+			  users_handler->pathid_head);
+		pr_debug ("iucv: add_pathid: X is %p \n", X);
+		pr_debug ("iucv: add_pathid: *X is %u \n", (int) (*X));
+		pr_debug ("Addresses of HTE's after getting new table is\n");
+		iucv_dumpit ((uchar *) users_handler->pathid_head,
+			     users_handler->entries * sizeof (ulong));
+		pr_debug ("New handler is\n");
+		iucv_dumpit ((uchar *) users_handler, sizeof (handler));
+
 		kfree (from);	/* free old table */
 	}
-	spin_unlock (&lock);
-#ifdef DEBUG
-	printk (KERN_DEBUG "exiting add_pathid\n");
-#endif
+	spin_unlock_irqrestore (&iucv_lock, flags);
+	pr_debug ("iucv_dd_pathid: exiting\n");
 	return (0);
 }				/* end of add_pathid function */
 
-/***********************EXTERNAL FUNCTIONS***************************/
-/**************************************************************/
-/* Name: iucv_query                                           */
-/* Purpose: determines how large an external interrupt buffer */
-/*          IUCV requires to store information                */
-/* Input : bufsize - ulong: size of interrupt buffer          */
-/*         - filled in by function and returned to caller     */
-/*         conmax  - ulong: maximum number of connections that */
-/*           can be outstanding for this VM                   */
-/*         - filled in by function and returned to caller     */
-/* Output: void                                               */
-/**************************************************************/
-void
-iucv_query (ulong * bufsize, ulong * conmax)
-{
-	iparml_purge parm;	/* DOESN'T MATTER WHICH IPARML IS USED    */
-#ifdef DEBUG
-	printk (KERN_DEBUG "entering iucv_purge\n");
-#endif
-	memset (&(parm), 0, sizeof (parm));
-	/*
-	 * Assembler instruction calling b2f0  and storing R0 and R1
-	 */
-	asm volatile ("LRA   1,0(%3)\n\t"
-		      "LR    0,%2\n\t"
-		      ".long 0xb2f01000\n\t"
-		      "ST    0,%0\n\t"
-		      "ST    1,%1\n\t":"=m" (*bufsize),
-		      "=m" (*conmax):"d" (query), "a" (&parm):"0", "1");
-	return;
-}
-
-/**************************************************************/
-/* Name: iucv_purge                                           */
-/* Purpose: cancels a message you have sent                   */
-/* Input: pathid - ushort, pathid                             */
-/*        msgid  - ulong, mid of message                      */
-/*        srccls - ulong, sourse message class                */
-/*        audit  - uchar[4], info about ansync. error condit. */
-/*                 filled in by function and passed back      */
-/* Output: void                                               */
-/* NOTE: pathid is required, flag is always turned on         */
-/**************************************************************/
+/*
+ * Name: iucv_declare_buffer                                    
+ * Purpose: Specifies the guests real address of an external  
+ *          interrupt.                                        
+ * Input: void                             
+ * Output: iprcode - return code from b2f0 call               
+*/
 int
-iucv_purge (ulong msgid, ushort pathid, ulong srccls, uchar audit[4])
+iucv_declare_buffer (void)
 {
-	iparml_purge parm;
+	iparml_db parm;
 	ulong b2f0_result;
-#ifdef DEBUG
-	printk (KERN_DEBUG "entering iucv_purge\n");
-#endif
-	memset (&(parm), 0, sizeof (parm));
-	parm.ipmsgid = msgid;
-	parm.ippathid = pathid;
-	parm.ipsrccls = srccls;
-	parm.ipflags1 |= specify_pathid;	/* pathid id flag */
-	if (parm.ipmsgid)
-		parm.ipflags1 |= specify_msgid;
-	if (parm.ipsrccls)
-		parm.ipflags1 |= source_class;
-	b2f0_result = b2f0 (purge, &parm);
-	if (b2f0_result != NULL)
-		return b2f0_result;
-	memcpy (audit, parm.ipaudit, 4);
-#ifdef DEBUG
-	printk (KERN_DEBUG "exiting iucv_purge\n");
-#endif
+	pr_debug ("iucv_declare_buffer: entering\n");
+	memset (&parm, 0, sizeof (parm));
+	parm.ipbfadr1 = virt_to_phys ((uchar *) iucv_external_int_buffer);
+	b2f0_result = b2f0 (DECLARE_BUFFER, &parm);
+	pr_debug ("iucv_declare_buffer: Address of EIB = %p\n",
+		  iucv_external_int_buffer);
+	pr_debug ("iucv_declare_buffer: exiting\n");
 	return b2f0_result;
 }
 
-/**************************************************************/
-/* Name: iucv_quiesce                                         */
-/* Purpose: temporarily suspends incoming messages            */
-/* Input: pathid - ushort, pathid                             */
-/*        user_data - uchar[16], user id                      */
-/* Output: iprcode - return code from b2f0 call               */
-/* NOTE: see b2f0 output list                                 */
-/**************************************************************/
+/*
+ * Name: iucv_retrieve_buffer
+ * Purpose: Terminates all use of IUCV.
+ * Input: void
+ * Output:
+ *      b2f0_result: return code from CP
+*/
 int
-iucv_quiesce (ushort pathid, uchar user_data[16])
+iucv_retrieve_buffer (void)
 {
 	iparml_control parm;
-	ulong b2f0_result;
-#ifdef DEBUG
-	printk (KERN_DEBUG "entering iucv_quiesce\n");
-#endif
-	memset (&(parm), 0, sizeof (parm));
-	memcpy (parm.ipuser, user_data, 16);
-	parm.ippathid = pathid;
-	b2f0_result = b2f0 (quiesc, &parm);
-#ifdef DEBUG
-	printk (KERN_DEBUG "exiting iucv_quiesce\n");
-#endif
+	ulong b2f0_result = 0;
+	pr_debug ("iucv_retrieve_buffer: entering\n");
+	memset (&parm, 0, sizeof (parm));
+	b2f0_result = b2f0 (RETRIEVE_BUFFER, &parm);
+	if (b2f0_result == NULL) {
+		kfree (handler_table_anchor);
+		handler_table_anchor = NULL;
+		declare_flag = 0;
+	}
+	pr_debug ("iucv_retrieve_buffer: exiting\n");
 	return b2f0_result;
 }
 
-/**************************************************************/
-/* Name: iucv_resume                                          */
-/* Purpose: restores communication over a quiesced path       */
-/* Input: pathid - ushort, pathid                             */
-/*        user_data - uchar[16], user id                      */
-/* Output: iprcode - return code from b2f0 call               */
-/* NOTE: see b2f0 output list                                 */
-/**************************************************************/
-int
-iucv_resume (ushort pathid, uchar user_data[16])
-{
-	iparml_control parm;
-	ulong b2f0_result;
-#ifdef DEBUG
-	printk (KERN_DEBUG "entering iucv_resume\n");
-#endif
-	memset (&(parm), 0, sizeof (parm));
-	memcpy (parm.ipuser, user_data, 16);
-	parm.ippathid = pathid;
-	b2f0_result = b2f0 (resume, &parm);
-#ifdef DEBUG
-	printk (KERN_DEBUG "exiting iucv_resume\n");
-#endif
-	return b2f0_result;
-}
+/*
+ * Name: iucv_register_program
+ * Purpose: Registers an application with IUCV.   
+ * Input: prmname - user identification
+ *        userid  - machine identification
+ *        pgmmask - indicates which bits in the prmname and userid combined will be used
+ *	   to determine who is given control
+ *        ops - address of vector of interrupt handlers
+ *        pgm_data- application data passed to interrupt handlers
+ * Output: NA
+ * Return: type: iucv_handle_t
+ *          address of handler
+ *         (0) - registration failed
+ *	       - Machine size > 2GB
+ *	       - new_handler kmalloc failed
+ * 	       - pgmname was not provided
+ *	       - pathid_table kmalloc failed
+ *             - application with identical pgmname, userid, and pgmmask is registered
+ * 	       - iucv_declare_buffer failed
+ * NOTE: pgmmask
+ *	When pgmname, userid, pgmmask is provided, mask is entered into the handler
+ *	as is.
+ *	When pgmname, userid is provided, pgmmask is all 0xff's
+ *	When pgmname, pgmmask is provided, the first 8 bytes = 0x00 and the last 16
+ *      bytes are as provided by pgmmask. 
+ *	When pgmname is provided is provided, the first 8 bytes = 0x00 and the last
+ *	16 bytes are 0xff.   
+*/
 
-/**************************************************************/
-/* Name: iucv_reject                                          */
-/* Purpose: rejects a message                                 */
-/* Input: pathid - ushort, pathid                             */
-/*        msgid  - ulong, mid of message                      */
-/*        trgcls - ulong, target message class                */
-/* Output: iprcode - return code from b2f0 call               */
-/* NOTE: pathid is required field, flag always turned on      */
-/*       RESTRICTION: target class cannot be zero             */
-/* NOTE: see b2f0 output list                                 */
-/**************************************************************/
-int
-iucv_reject (ushort pathid, ulong msgid, ulong trgcls)
+iucv_handle_t
+iucv_register_program (uchar pgmname[16],
+		       uchar userid[8],
+		       uchar pgmmask[24],
+		       iucv_interrupt_ops_t * ops, void *pgm_data)
 {
-	iparml_db parm;
-	ulong b2f0_result;
-#ifdef DEBUG
-	printk (KERN_DEBUG "entering iucv_reject\n");
-#endif
-	memset (&(parm), 0, sizeof (parm));
-	parm.ipmsgid = msgid;
-	parm.ippathid = pathid;
-	parm.iptrgcls = trgcls;
-	parm.ipflags1 |= specify_pathid;	/* flag for pathid */
-	if (parm.ipmsgid)
-		parm.ipflags1 |= specify_msgid;
-	if (parm.iptrgcls)
-		parm.ipflags1 |= target_class;
-	b2f0_result = b2f0 (reject, &parm);
-#ifdef DEBUG
-	printk (KERN_DEBUG "exiting iucv_reject\n");
-#endif
-	return b2f0_result;
-}
+	ulong rc = 0;		/* return code from function calls */
+	ulong machine_size = 0;	/* size of virtual machine */
+	static u32 maxconn1;
+	handler *new_handler = NULL;
+
+	pr_debug ("iucv_register_program:entering\n");
+
+	if (ops == NULL) {
+		/* interrupt table is not defined */
+		printk (KERN_WARNING "iucv_register_program:"
+			"Interrupt table is not defined, exiting\n");
+		return NULL;
+	}
 
-/**************************************************************/
-/* Name: iucv_setmask                                         */
-/* Purpose: enables or disables certain iucv external interr. */
-/* Input: non_priority_interrupts - uchar                     */
-/*        priority_interrupts - uchar                         */
-/*        non_priority_completion_interrupts - uchar          */
-/*        priority_completion_interrupts) - uchar             */
-/* Output: iprcode - return code from b2f0 call               */
-/* NOTE: see b2f0 output list                                 */
-/**************************************************************/
-int
-iucv_setmask (uchar non_priority_interrupts,
-	      uchar priority_interrupts,
-	      uchar non_priority_completion_interrupts,
-	      uchar priority_completion_interrupts)
-{
-	iparml_set_mask parm;
-	ulong b2f0_result;
-#ifdef DEBUG
-	printk (KERN_DEBUG "entering iucv_setmask\n");
-#endif
-	memset (&(parm), 0, sizeof (parm));
-	if (non_priority_interrupts)
-		parm.ipmask |= 0x80;
-	if (priority_interrupts)
-		parm.ipmask |= 0x40;
-	if (non_priority_completion_interrupts)
-		parm.ipmask |= 0x20;
-	if (priority_completion_interrupts)
-		parm.ipmask |= 0x10;
-	b2f0_result = b2f0 (setmask, &parm);
-#ifdef DEBUG
-	printk (KERN_DEBUG "exiting iucv_setmask\n");
-#endif
-	return b2f0_result;
-}
+	if (declare_flag == 0) {
+		/* check size of virtual machine */
+		if ((machine_size = iucv_vmsize ()) > 0x100000000) {	/* 2GB */
+			printk (KERN_WARNING "iucv_register_progam: Virtual"
+				"storage = %lx hex," "exiting\n", machine_size);
+			return NULL;
+		}
 
-/**************************************************************/
-/* Name: iucv_sever                                           */
-/* Purpose: terminates an iucv path to another machine        */
-/* Input: pathid - ushort, pathid                             */
-/*        user_data - uchar[16], user id                      */
-/* Output: iprcode - return code from b2f0 call               */
-/* NOTE: see b2f0 output list                                 */
-/**************************************************************/
-int
-iucv_sever (ushort pathid, uchar user_data[16])
-{
-	ulong index1, index2;
-	ulong b2f0_result;
-	handler_table_entry *P = 0;
-	handler *Q = 0;
-	ulong *X;
-	iparml_control parm;
-#ifdef DEBUG
-	printk (KERN_DEBUG "entering iucv_sever\n");
-#endif
-	memset (&(parm), 0, sizeof (parm));
-	memcpy (parm.ipuser, user_data, 16);
-	parm.ippathid = pathid;
-	b2f0_result = b2f0 (sever, &parm);
-	if (b2f0_result)
-		return b2f0_result;
-	index1 = ((ulong) pathid) / 512;
-	index2 = ((ulong) pathid) % 512;
-	spin_lock (&lock);
-	P = main_table[index1];
-	if (((P + index2)->addrs) == NULL) {	/* called from interrupt code */
-		spin_unlock (&lock);
-		return (-2);	/* bad pointer */
-	}
-	Q = (*(P + index2)).addrs;
-#ifdef DEBUG
-	printk (KERN_DEBUG "pathid is %d\n", pathid);
-	printk (KERN_DEBUG "index1 is %d\n", (int) index1);
-	printk (KERN_DEBUG "index2 is %d\n", (int) index2);
-	printk (KERN_DEBUG "H_T_E is %p\n", P);
-	printk (KERN_DEBUG "address of handler is %p\n", Q);
-	for (X = ((*Q).start); X < ((*Q).end); X++)
-		printk (KERN_DEBUG " %x ", (int) (*X));
-	printk (KERN_DEBUG "\n above is pathid table\n");
-#endif
-/********************************************************************/
-/* Searching the pathid address table for matching address, once    */
-/* found, NULL the field. Then Null the H_T_E fields.               */
-/********************************************************************/
-	for (X = ((*Q).start); X < ((*Q).end); X++)
-		if (*X == (ulong) (P + index2)) {
-#ifdef DEBUG
-			printk (KERN_DEBUG "found a path to sever\n");
-			printk (KERN_DEBUG "severing %d \n", (int) (*X));
-#endif
-			*X = NULL;
-			(*(P + index2)).addrs = NULL;	/*clearing the fields */
-			(*(P + index2)).pathid = 0;
-			(*(P + index2)).pgm_data = 0;
+		pr_debug ("machine_size is %lx\n", machine_size);
+
+		maxconn1 = iucv_query_maxconn ();
+		handler_table_anchor = kmalloc (maxconn1 * sizeof
+						(handler_table_entry),
+						GFP_KERNEL);
+
+		if (handler_table_anchor == NULL) {
+			printk (KERN_WARNING "iucv_register_program:"
+				"handler_table_anchor"
+				"storage allocation failed\n");
+			return NULL;
 		}
-	spin_unlock (&lock);
-#ifdef DEBUG
-	printk (KERN_DEBUG "exiting iucv_sever\n");
-#endif
-	return b2f0_result;
-}
 
-/**************************************************************/
-/* Name: iucv_receive                                         */
-/* Purpose: receives incoming message                         */
-/* Input: pathid - ushort, pathid                             */
-/*        msgid  - *ulong, mid of message                     */
-/*        trgcls - *ulong, target message class               */
-/*        buffer - pointer of buffer                          */
-/*        buflen - length of buffer                           */
-/*        adds_curr_buffer - pointer to updated buffer address*/
-/*                           to write to                      */
-/*        adds_curr_length - pointer to updated length in     */
-/*                           buffer available to write to     */
-/*        reply_required - uchar *, flag                      */
-/*        priority_msg - uchar *, flag                        */
-/* Output: iprcode - return code from b2f0 call               */
-/* NOTE: pathid must be specified, flag being turned on       */
-/* RESTRICTIONS: target class CANNOT be zero because the code */
-/* checks for a non-NULL value to turn flag on, therefore if  */
-/* target class = zero, flag will not be turned on.           */
-/**************************************************************/
-int
-iucv_receive (ushort pathid, ulong * msgid, ulong * trgcls,
-	      void *buffer, ulong buflen,
-	      uchar * reply_required,
-	      uchar * priority_msg,
-	      ulong * adds_curr_buffer, ulong * adds_curr_length)
-{
-	iparml_db parm;
-	ulong b2f0_result;
-#ifdef DEBUG
-	printk (KERN_DEBUG "entering iucv_receive\n");
-#endif
-	memset (&(parm), 0, sizeof (parm));
-	parm.ipmsgid = *msgid;
+		memset (handler_table_anchor, 0,
+			maxconn1 * sizeof (handler_table_entry));
+
+	}
+	/* Allocate handler table */
+	new_handler = (handler *) kmalloc (sizeof (handler), GFP_KERNEL);
+	if (new_handler == NULL) {
+		printk (KERN_WARNING "iucv_register_program: storage allocation"
+			"for new handler failed. \n ");
+		return NULL;
+	}
+	memset (new_handler, 0, sizeof (handler));
+	if (pgmname) {
+		memcpy (new_handler->id.user_data, pgmname,
+			sizeof (new_handler->id.user_data));
+		if (userid) {
+			memcpy (new_handler->id.userid, userid,
+				sizeof (new_handler->id.userid));
+			ASCEBC (new_handler->id.userid,
+				sizeof (new_handler->id.userid));
+			EBC_TOUPPER (new_handler->id.userid,
+				     sizeof (new_handler->id.userid));
+
+			if (pgmmask) {
+				memcpy (new_handler->id.mask, pgmmask,
+					sizeof (new_handler->id.mask));
+			} else {
+				memset (new_handler->id.mask, 0xFF,
+					sizeof (new_handler->id.mask));
+			}
+		} else {
+			if (pgmmask) {
+				memcpy (new_handler->id.mask, pgmmask,
+					sizeof (new_handler->id.mask));
+			} else {
+				memset (new_handler->id.mask, 0xFF,
+					sizeof (new_handler->id.mask));
+			}
+			memset (new_handler->id.mask, 0x00,
+				sizeof (new_handler->id.userid));
+		}
+	} else {
+		kfree (new_handler);
+		printk (KERN_WARNING "iucv_register_program: pgmname not"
+			"provided\n");
+		return NULL;
+	}
+	/* fill in the rest of handler */
+	new_handler->pgm_data = pgm_data;
+	new_handler->interrupt_table = ops;
+	new_handler->entries = ADDED_STOR;
+	/* Allocate storage for pathid table */
+	new_handler->pathid_head =
+	    kmalloc (new_handler->entries * sizeof (ulong), GFP_KERNEL);
+	if (new_handler->pathid_head == NULL) {
+		printk (KERN_WARNING "iucv_register_program: storage allocation"
+			"failed\n");
+		kfree (new_handler);
+		return NULL;
+	}
+
+	memset (new_handler->pathid_head, 0,
+		new_handler->entries * sizeof (ulong));
+	new_handler->pathid_tail =
+	    new_handler->pathid_head + new_handler->entries;
+	/* 
+	 * Check if someone else is registered with same pgmname, userid, and mask. 
+	 * If someone is already registered with same pgmname, userid, and mask 
+	 * registration will fail and NULL will be returned to the application. 
+	 * If identical handler not found, then handler is added to list.
+	 */
+	rc = iucv_add_handler (new_handler);
+	if (rc) {
+		printk (KERN_WARNING "iucv_register_program: Someone already"
+			"registered with same pgmname, userid, pgmmask\n");
+		kfree (new_handler->pathid_head);
+		kfree (new_handler);
+		return NULL;
+	}
+
+	if (declare_flag == 0) {
+		rc = iucv_declare_buffer ();
+		if (rc) {
+			kfree (handler_table_anchor);
+			kfree (new_handler->pathid_head);
+			kfree (new_handler);
+			handler_table_anchor = NULL;
+			printk (KERN_WARNING "iucv_register_program: rc from"
+				"iucv_declare_buffer is:% ld \n ", rc);
+			return NULL;
+		}
+		/* request the 0x4000 external interrupt */
+		rc = register_external_interrupt (0x4000, top_half_interrupt);
+		if (rc) {
+			iucv_retrieve_buffer ();
+			kfree (new_handler->pathid_head);
+			kfree (new_handler);
+			printk (KERN_WARNING "iucv_register_program: rc from"
+				"register_external_interrupt is:% ld \n ", rc);
+			return NULL;
+
+		}
+		declare_flag = 1;
+	}
+	pr_debug ("iucv_register_program: exiting\n");
+	return new_handler;
+}				/* end of register function */
+
+/*
+ * Name: iucv_unregister_program
+ * Purpose: Unregister application with IUCV.
+ * Input: handle address of handler
+ * Output: NA
+ * Return: (0) - Normal return
+ *         (-EINVAL)- Matching handler was not found
+*/
+
+int
+iucv_unregister_program (iucv_handle_t handle)
+{
+	handler *users_handler = 0, *R;
+	handler_table_entry *H_T_E = 0;
+	ulong *S = 0;		/*points to the beginning of block of h_t_e's */
+	ulong flags;
+	u16 pathid_sever = 0;
+	pr_debug ("iucv_unregister_program: entering\n");
+	pr_debug ("iucv_unregister_program: address of handle is %p\n", handle);
+	spin_lock_irqsave (&iucv_lock, flags);
+	users_handler = (handler *) handle;
+	/* 
+	 * Checking if handle is still registered: if yes, continue
+	 *  if not registered, return.
+	 */
+	for (R = handler_anchor; R != NULL; R = (handler *) R->next)
+		if (users_handler == R) {
+			pr_debug ("iucv_unregister_program: found a matching"
+				  "handler\n");
+			break;
+		}
+	if (!R) {
+		pr_debug ("You are not registered\n");
+		spin_unlock_irqrestore (&iucv_lock, flags);
+		return (0);
+	}
+	S = users_handler->pathid_head;
+	while (S < (users_handler->pathid_tail)) {	/* index thru table */
+		if (*S) {
+			H_T_E = (handler_table_entry *) (*S);
+
+			pr_debug ("iucv_unregister_program: pointer to H_T_E is"
+				  "%p\n", H_T_E);
+			pr_debug
+			    ("iucv_unregister_program: address of handle in"
+			     "H_T_E is %p", (H_T_E->addrs));
+			pathid_sever = H_T_E->pathid;
+			spin_unlock_irqrestore (&iucv_lock, flags);
+			iucv_sever (pathid_sever, users_handler->id.user_data);
+			spin_lock_irqsave (&iucv_lock, flags);
+		}
+
+		S++;		/* index by address */
+	}
+
+	kfree (users_handler->pathid_head);
+	iucv_remove_handler (users_handler);
+	spin_unlock_irqrestore (&iucv_lock, flags);
+	kfree (handle);
+	pr_debug ("iucv_unregister_program: exiting\n");
+	return 0;
+}
+
+/*
+ * Name: iucv_accept
+ * Purpose: This function is issued after the user receives a Connection Pending external
+ *          interrupt and now wishes to complete the IUCV communication path.
+ * Input:  pathid - u16 , path identification number   
+ *         msglim_reqstd - u16, The number of outstanding messages requested.
+ *         user_data - uchar[16], Data specified by the iucv_connect function.
+ *	   flags1 - int, Contains options for this path.
+ *           -IPPRTY - 0x20- Specifies if you want to send priority message.
+ *           -IPRMDATA - 0x80, Specifies whether your program can handle a message
+ *            	in  the parameter list.
+ *           -IPQUSCE - 0x40, Specifies whether you want to quiesce the path being
+ *		established.
+ *         handle - iucv_handle_t, Address of handler.
+ *         pgm_data - ulong, Application data passed to interrupt handlers.
+ *	   flags1_out - int *, Options for path.
+ *           IPPRTY - 0x20 - Indicates you may send a priority message.
+ *         priority_permitted -uchar *, Indicates you may send priority messages.
+ *         msglim - *u16, Number of outstanding messages.
+ * Output: b2f0_result - return code from CP
+*/
+int
+iucv_accept (u16 pathid, u16 msglim_reqstd,
+	     uchar user_data[16], int flags1,
+	     iucv_handle_t handle, void *pgm_data,
+	     int *flags1_out, u16 * msglim)
+{
+	iparml_control parm;
+	ulong b2f0_result = 0;
+	ulong flags;
+	handler *R = NULL;
+	pr_debug ("iucv_accept: entering \n");
+	pr_debug ("iucv_accept: pathid = %d\n", pathid);
+
+	/* Checking if handle is valid  */
+	spin_lock_irqsave (&iucv_lock, flags);
+
+	for (R = handler_anchor; R != NULL; R = (handler *) R->next)
+		if (R == handle)
+			break;
+
+	spin_unlock_irqrestore (&iucv_lock, flags);
+	if (R == NULL) {
+		printk (KERN_WARNING "iucv_connect: NULL handle passed by"
+			"application\n");
+		return -EINVAL;
+	}
+
+	memset (&parm, 0, sizeof (parm));
 	parm.ippathid = pathid;
-	parm.iptrgcls = *trgcls;
-	parm.ipflags1 |= specify_pathid;	/* turning pathid flag */
-	if (parm.ipmsgid)
-		parm.ipflags1 |= 0x05;
-	if (parm.iptrgcls)
-		parm.ipflags1 |= target_class;
-	parm.ipbfadr1 = (ulong) buffer;
-	parm.ipbfln1f = buflen;
-	b2f0_result = b2f0 (receive, &parm);
+	parm.ipmsglim = msglim_reqstd;
+	if (user_data)
+		memcpy (parm.ipuser, user_data, sizeof (parm.ipuser));
+	parm.ipflags1 = (uchar) flags1;
+	b2f0_result = b2f0 (ACCEPT, &parm);
+
+	if (b2f0_result == 0) {
+		if (pgm_data)
+			(handler_table_anchor + pathid)->pgm_data = pgm_data;
+		if (parm.ipflags1 & IPPRTY)
+			if (flags1_out) {
+				pr_debug ("*flags1_out = %d\n", *flags1_out);
+				*flags1_out = 0;
+				*flags1_out |= IPPRTY;
+				pr_debug (" *flags1_out = %d\n", *flags1_out);
+			}
+	}
+
+	pr_debug ("iucv_accept: exiting\n");
+	return b2f0_result;
+}
+
+/*
+ * Name: iucv_connect                                         
+ * Purpose: This function establishes an IUCV path. Although the connect may complete
+ *	    successfully, you are not able to use the path until you receive an IUCV 
+ *          Connection Complete external interrupt.            
+ * Input: pathid - u16 *, path identification number          
+ *        msglim_reqstd - u16, number of outstanding messages requested       
+ *        user_data - uchar[16], 16-byte user data                    
+ *        userid - uchar[8], 8-byte of user identification                        
+ *        system_name - uchar[8], 8-byte identifying the system name 
+ *        flags1 - int, Contains options for this path.
+ *          -IPPRTY - 0x20- Specifies if you want to send priority message.
+ *          -IPRMDATA - 0x80, Specifies whether your program can handle a message
+ *               in  the parameter list.
+ *          -IPQUSCE - 0x40, Specifies whether you want to quiesce the path being
+ *              established.
+ *          -IPLOCAL - 0X01, allows an application to force the partner to be on the
+ *              local system. If local is specified then target class cannot be
+ *              specified.  
+ *         flags1_out - int *, Options for path. 
+ *           IPPRTY - 0x20 - Indicates you may send a priority message.
+ *        msglim - * u16, number of outstanding messages
+ *        handle - iucv_handle_t, address of handler                         
+ *        pgm_data - *void, application data passed to interrupt handlers                  
+ * Output: b2f0_result - return code from CP
+ *         -ENOMEM
+ *         rc - return code from iucv_declare_buffer
+ *         -EINVAL - invalid handle passed by application 
+ *         -EINVAL - pathid address is NULL 
+ *	   -ENOMEM - pathid table storage allocation failed
+ *         add_pathid_result - return code from internal function add_pathid             
+*/
+int
+iucv_connect (u16 * pathid, u16 msglim_reqstd,
+	      uchar user_data[16], uchar userid[8],
+	      uchar system_name[8], int flags1,
+	      int *flags1_out, u16 * msglim,
+	      iucv_handle_t handle, void *pgm_data)
+{
+	iparml_control parm;
+	ulong b2f0_result = 0;
+	ulong flags;
+	int add_pathid_result = 0;
+	handler *R = NULL;
+	uchar no_memory[16] = "NO MEMORY";
+
+	pr_debug ("iucv_connect: entering \n");
+
+	/* Checking if handle is valid  */
+	spin_lock_irqsave (&iucv_lock, flags);
+
+	for (R = handler_anchor; R != NULL; R = (handler *) R->next)
+		if (R == handle)
+			break;
+
+	spin_unlock_irqrestore (&iucv_lock, flags);
+
+	if (R == NULL) {
+		printk (KERN_WARNING "iucv_connect: NULL handle passed by"
+			"application\n");
+		return -EINVAL;
+	}
+
+	if (pathid == NULL) {
+		printk (KERN_WARNING "iucv_connect: NULL pathid pointer\n");
+		return -EINVAL;
+	}
+	memset (&parm, 0, sizeof (iparml_control));
+	parm.ipmsglim = msglim_reqstd;
+
+	if (user_data)
+		memcpy (parm.ipuser, user_data, sizeof (parm.ipuser));
+
+	if (userid) {
+		memcpy (parm.ipvmid, userid, sizeof (parm.ipvmid));
+		ASCEBC (parm.ipvmid, sizeof (parm.ipvmid));
+		EBC_TOUPPER (parm.ipvmid, sizeof (parm.ipvmid));
+	}
+
+	if (system_name) {
+		memcpy (parm.iptarget, system_name, sizeof (parm.iptarget));
+		ASCEBC (parm.iptarget, sizeof (parm.iptarget));
+		EBC_TOUPPER (parm.iptarget, sizeof (parm.iptarget));
+	}
+
+	parm.ipflags1 = (uchar) flags1;
+	b2f0_result = b2f0 (CONNECT, &parm);
 	if (b2f0_result)
 		return b2f0_result;
-	if (msgid)
-		*msgid = parm.ipmsgid;
-	if (trgcls)
-		*trgcls = parm.iptrgcls;
-	if (parm.ipflags1 & prior_msg)
-		if (priority_msg)
-			*priority_msg = 0x01;	/*yes, priority msg */
-	if (!(parm.ipflags1 & 0x10))	/*& with X'10'     */
-		if (reply_required)
-			*reply_required = 0x01;	/*yes, reply required */
-	if (!(parm.ipflags1 & parm_data)) {	/*msg not in parmlist */
-		if (adds_curr_length)
-			*adds_curr_length = parm.ipbfln1f;
-		if (adds_curr_buffer)
-			*adds_curr_buffer = parm.ipbfadr1;
-	} else {
-		if ((buflen) >= 8) {
-			if (buffer)
-				memcpy ((char *) buffer,
-					(char *) parm.ipbfadr1, 8);
-			if (adds_curr_length)
-				*adds_curr_length = ((buflen) - 8);
-			if (adds_curr_buffer)
-				*adds_curr_buffer = (ulong) buffer + 8;
-		} else {
-			parm.iprcode |= 0x05;
-			b2f0_result = (ulong) parm.iprcode;
-		}
+
+	add_pathid_result = iucv_add_pathid (parm.ippathid, handle, pgm_data);
+	if (add_pathid_result) {
+
+		iucv_sever (parm.ippathid, no_memory);
+		printk (KERN_WARNING "iucv_connect: add_pathid failed with rc ="
+			"%d\n", add_pathid_result);
+		return (add_pathid_result);
 	}
-#ifdef DEBUG
-	printk (KERN_DEBUG "exiting iucv_receive\n");
-#endif
+
+	*pathid = parm.ippathid;
+
+	if (msglim)
+		*msglim = parm.ipmsglim;
+
+	if (parm.ipflags1 & IPPRTY)
+		if (flags1_out) {
+			*flags1_out = 0;
+			*flags1_out |= IPPRTY;
+		}
+
+	pr_debug ("iucv_connect: exiting\n");
 	return b2f0_result;
 }
 
-/**************************************************************/
-/* Name: iucv_receive_simple                                  */
-/* Purpose: receives fully-qualified message                  */
-/* Input: pathid - ushort, pathid                             */
-/*        msgid  - ulong, id of message                       */
-/*        trgcls - ulong, target message class                */
-/*        buffer - pointer of buffer                          */
-/*        buflen - length of buffer                           */
-/* Output: iprcode - return code from b2f0 call               */
-/**************************************************************/
+/*
+ * Name: iucv_purge                                           
+ * Purpose: Cancels a message you have sent.                   
+ * Input: pathid -   address of pathid                                  
+ *        msgid  -   address of message identification             
+ *        srccls -   address of source message class                     
+ *        audit  -  contains information about                              
+ *                 asynchronous error that may have affected                           
+ *                 the normal completion of this message.                  
+ * Output:b2f0_result - return code from CP                   
+*/
 int
-iucv_receive_simple (ushort pathid, ulong msgid, ulong trgcls,
-		     void *buffer, ulong buflen)
+iucv_purge (u16 pathid, u32 msgid, u32 srccls, uchar audit[3])
+{
+	iparml_purge parm;
+	ulong b2f0_result = 0;
+	pr_debug ("iucv_purge: entering\n");
+	pr_debug ("iucv_purge: pathid = %d \n", pathid);
+	memset (&parm, 0, sizeof (parm));
+	parm.ipmsgid = msgid;
+	parm.ippathid = pathid;
+	parm.ipsrccls = srccls;
+	parm.ipflags1 |= (IPSRCCLS | IPFGMID | IPFGPID);
+	b2f0_result = b2f0 (PURGE, &parm);
+
+	if ((b2f0_result == 0) && (audit))
+		memcpy (audit, parm.ipaudit, sizeof (parm.ipaudit));
+
+	pr_debug ("iucv_purge: b2f0_result = %ld \n", b2f0_result);
+	pr_debug ("iucv_purge: exiting\n");
+	return b2f0_result;
+}
+
+/*
+ * Name: iucv_query_maxconn                                            
+ * Purpose: Determines the maximum number of connections thay may be established.
+ * Output: maxconn - ulong: Maximum number of connections that can be.     
+*/
+ulong
+iucv_query_maxconn (void)
+{
+	iparml_purge parm;	/* DOESN'T MATTER WHICH IPARML IS USED    */
+	static u32 maxconn1, bufsize1;
+
+	pr_debug ("iucv_query_maxconn: entering\n");
+
+	memset (&parm, 0, sizeof (parm));
+
+	/* Assembler instruction calling b2f0  and storing R0 and R1 */
+	asm volatile ("LRA   1,0(%3)\n\t"
+		      "LR    0,%2\n\t"
+		      ".long 0xb2f01000\n\t"
+		      "ST    0,%0\n\t"
+		      "ST    1,%1\n\t":"=m" (bufsize1),
+		      "=m" (maxconn1):"d" (QUERY), "a" (&parm):"0", "1");
+
+	pr_debug (" bufsize1 = %d and maxconn1 = %d \n", bufsize1, maxconn1);
+	pr_debug ("iucv_query_maxconn: exiting\n");
+
+	return maxconn1;
+}
+
+/*
+ * Name: iucv_query_bufsize
+ * Purpose: Determines the size of the external interrupt buffer.
+ * Output: bufsize - ulong: Size of external interrupt buffer.
+ */
+ulong
+iucv_query_bufsize (void)
+{
+	iparml_purge parm;	/* DOESN'T MATTER WHICH IPARML IS USED    */
+	static u32 maxconn1, bufsize1;
+
+	pr_debug ("iucv_query_bufsize: entering\n");
+	pr_debug ("iucv_query_maxconn: entering\n");
+
+	memset (&parm, 0, sizeof (parm));
+
+	/* Assembler instruction calling b2f0  and storing R0 and R1 */
+	asm volatile ("LRA   1,0(%3)\n\t"
+		      "LR    0,%2\n\t"
+		      ".long 0xb2f01000\n\t"
+		      "ST    0,%0\n\t"
+		      "ST    1,%1\n\t":"=m" (bufsize1),
+		      "=m" (maxconn1):"d" (QUERY), "a" (&parm):"0", "1");
+
+	pr_debug (" bufsize1 = %d and maxconn1 = %d \n", bufsize1, maxconn1);
+	pr_debug ("iucv_query_bufsize: exiting\n");
+
+	return bufsize1;
+}
+
+/*
+ * Name: iucv_quiesce                                         
+ * Purpose: temporarily suspends incoming messages on an IUCV path.
+ *          You can later reactivate the path by invoking the iucv_resume function        
+ * Input: pathid - u16, path identification number                             
+ *        user_data - uchar[16], 16-byte user data                      
+ * Output: b2f0_result - return code from CP               
+ */
+int
+iucv_quiesce (u16 pathid, uchar user_data[16])
+{
+	iparml_control parm;
+	ulong b2f0_result = 0;
+
+	pr_debug ("iucv_quiesce: entering \n");
+	pr_debug ("iucv_quiesce: pathid = %d\n", pathid);
+
+	memset (&parm, 0, sizeof (parm));
+	memcpy (parm.ipuser, user_data, sizeof (parm.ipuser));
+	parm.ippathid = pathid;
+
+	b2f0_result = b2f0 (QUIESCE, &parm);
+
+	pr_debug ("iucv_quiesce: b2f0_result = %ld\n", b2f0_result);
+	pr_debug ("iucv_quiesce: exiting\n");
+
+	return b2f0_result;
+}
+
+/*
+ * Name: iucv_receive
+ * Purpose: This function receives messages that are being sent to you
+ *          over established paths. 
+ * Input:
+ *        pathid - path identification number
+ *        buffer - address of buffer to receive
+ *        buflen - length of buffer to receive
+ *        msgid - specifies the message ID.
+ *        trgcls - specifies target class
+ * Output:
+ *	 flags1_out: Options for path.
+ *         IPNORPY - 0x10 specifies whether a reply is required
+ *         IPPRTY - 0x20 specifies if you want to send priority message
+ *         IPRMDATA - 0x80 specifies the data is contained in the parameter list
+ *       residual_buffer - address of buffer updated by the number
+ *                         of bytes you have received.
+ *       residual_length - 
+ *		Contains one of the following values, if the receive buffer is:
+ *		 The same length as the message, this field is zero.
+ *		 Longer than the message, this field contains the number of
+ *		  bytes remaining in the buffer.
+ *		 Shorter than the message, this field contains the residual
+ *		  count (that is, the number of bytes remaining in the
+ *		  message that does not fit into the buffer. In this
+ *		  case b2f0_result = 5. 
+ * Return: b2f0_result - return code from CP IUCV call.
+ *         (-EINVAL) - buffer address is pointing to NULL
+ */
+int
+iucv_receive (u16 pathid, u32 msgid, u32 trgcls,
+	      void *buffer, ulong buflen,
+	      int *flags1_out, ulong * residual_buffer, ulong * residual_length)
 {
 	iparml_db parm;
 	ulong b2f0_result;
-	pr_debug ("entering iucv_receive_simple\n");
+	int moved = 0;		/* number of bytes moved from parmlist to buffer */
+	pr_debug ("iucv_receive: entering\n");
+
+	if (!buffer)
+		return -EINVAL;
 
-	memset (&(parm), 0, sizeof (parm));
+	memset (&parm, 0, sizeof (parm));
+	parm.ipbfadr1 = (u32) buffer;
+	parm.ipbfln1f = (u32) ((ulong) buflen);
 	parm.ipmsgid = msgid;
 	parm.ippathid = pathid;
 	parm.iptrgcls = trgcls;
-	parm.ipflags1 = IPFGMID + IPFGPID + IPFGMCL;
-	parm.ipbfadr1 = (ulong) buffer;
-	parm.ipbfln1f = buflen;
+	parm.ipflags1 = (IPFGPID | IPFGMID | IPFGMCL);
 
-	b2f0_result = b2f0 (receive, &parm);
-	if (b2f0_result)
-		return b2f0_result;
+	b2f0_result = b2f0 (RECEIVE, &parm);
+
+	if (b2f0_result == 0 || b2f0_result == 5) {
+		if (flags1_out) {
+			pr_debug ("*flags1_out = %d\n", *flags1_out);
+			*flags1_out = (parm.ipflags1 & (~0x07));
+			pr_debug ("*flags1_out = %d\n", *flags1_out);
+		}
+
+		if (!(parm.ipflags1 & IPRMDATA)) {	/*msg not in parmlist */
+			if (residual_length)
+				*residual_length = parm.ipbfln1f;
 
-	if (parm.ipflags1 & IPRMDATA) {	/*msg in parmlist */
-		if ((buflen) >= 8)
-			memcpy ((char *) buffer, (char *) parm.ipbfadr1, 8);
-		else
-			b2f0_result = 5;
-	}
-	pr_debug ("exiting iucv_receive_simple\n");
+			if (residual_buffer)
+				*residual_buffer = parm.ipbfadr1;
+		} else {
+			moved = min (buflen, 8);
+
+			memcpy ((char *) buffer,
+				(char *) &parm.ipbfadr1, moved);
+
+			if (buflen < 8)
+				b2f0_result = 5;
+
+			if (residual_length)
+				*residual_length = abs (buflen - 8);
+
+			if (residual_buffer)
+				*residual_buffer = (ulong) (buffer + moved);
+		}
+	}
+	pr_debug ("iucv_receive: exiting \n");
 	return b2f0_result;
 }
 
-/**************************************************************/
-/* Name: iucv_receive_array                                   */
-/* Purpose: receives incoming message                         */
-/* Input: pathid - ushort, pathid                             */
-/*        msgid  -* ulong, mid of message                     */
-/*        trgcls -* ulong, target message class               */
-/*        buffer - pointer of iucv_array_t                    */
-/*        buflen - ulong , length of buffer                   */
-/*        reply_required - uchar *, flag returned to caller   */
-/*        priority_msg - uchar *, flag returned to caller     */
-/*        adds_curr_buffer - pointer to updated buffer array  */
-/*                   to write to                              */
-/*        adds_curr_length - pointer to updated length in     */
-/*                   buffer available to write to             */
-/* Output: iprcode - return code from b2f0 call               */
-/* NOTE: pathid must be specified, flag being turned on       */
-/* RESTRICTIONS: target class CANNOT be zero because the code */
-/* checks for a non-NULL value to turn flag on, therefore if  */
-/* target class = if target class = zero flag will not be     */
-/* turned on, therefore if target class is specified it cannot */
-/* be zero.                                                   */
-/**************************************************************/
-int
-iucv_receive_array (ushort pathid, ulong * msgid, ulong * trgcls,
-		    iucv_array_t * buffer, ulong * buflen,
-		    uchar * reply_required,
-		    uchar * priority_msg,
-		    ulong * adds_curr_buffer, ulong * adds_curr_length)
+/*
+ * Name: iucv_receive_array
+ * Purpose: This function receives messages that are being sent to you
+ *          over established paths. 
+ * Input: pathid - path identification number
+ *        buffer - address of array of buffers
+ *        buflen - total length of buffers
+ *        msgid - specifies the message ID.
+ *        trgcls - specifies target class
+ * Output:
+ *        flags1_out: Options for path.
+ *          IPNORPY - 0x10 specifies whether a reply is required
+ *          IPPRTY - 0x20 specifies if you want to send priority message
+ *         IPRMDATA - 0x80 specifies the data is contained in the parameter list
+ *       residual_buffer - address points to the current list entry IUCV
+ *                         is working on.
+ *       residual_length -
+ *              Contains one of the following values, if the receive buffer is:
+ *               The same length as the message, this field is zero.
+ *               Longer than the message, this field contains the number of
+ *                bytes remaining in the buffer.
+ *               Shorter than the message, this field contains the residual
+ *                count (that is, the number of bytes remaining in the
+ *                message that does not fit into the buffer. In this case
+ *		  b2f0_result = 5.
+ * Return: b2f0_result - return code from CP
+ *         (-EINVAL) - buffer address is NULL
+ */
+int
+iucv_receive_array (u16 pathid,
+		    u32 msgid, u32 trgcls,
+		    iucv_array_t * buffer, ulong buflen,
+		    int *flags1_out,
+		    ulong * residual_buffer, ulong * residual_length)
 {
 	iparml_db parm;
 	ulong b2f0_result;
-#ifdef DEBUG
-	printk (KERN_DEBUG "entering iucv_receive_array\n");
-#endif
-	memset (&(parm), 0, sizeof (parm));
-	parm.ipmsgid = *msgid;
+	int i = 0, moved = 0, need_to_move = 8, dyn_len;
+	pr_debug ("iucv_receive_array: entering\n");
+
+	if (!buffer)
+		return -EINVAL;
+
+	memset (&parm, 0, sizeof (parm));
+	parm.ipbfadr1 = (u32) ((ulong) buffer);
+	parm.ipbfln1f = (u32) buflen;
+	parm.ipmsgid = msgid;
 	parm.ippathid = pathid;
-	parm.iptrgcls = *trgcls;
-	parm.ipflags1 |= array;	/* using an address list  */
-	parm.ipflags1 |= specify_pathid;	/*turning on pathid flag */
-	if (parm.ipmsgid)
-		parm.ipflags1 |= 0x05;
-	if (parm.iptrgcls)
-		parm.ipflags1 |= target_class;
-	parm.ipbfadr1 = (ulong) buffer;
-	parm.ipbfln1f = *buflen;
-	b2f0_result = b2f0 (receive, &parm);
-	if (b2f0_result)
-		return b2f0_result;
-	if (msgid)
-		*msgid = parm.ipmsgid;
-	if (trgcls)
-		*trgcls = parm.iptrgcls;
-	if (parm.ipflags1 & prior_msg)
-		if (priority_msg)
-			*priority_msg = 0x01;	/*yes, priority msg */
-	if (!(parm.ipflags1 & 0x10))	/*& with X'10'     */
-		if (reply_required)
-			*reply_required = 0x01;	/*yes, reply required */
-	if (!(parm.ipflags1 & parm_data)) {	/*msg not in parmlist */
-		if (adds_curr_length)
-			*adds_curr_length = parm.ipbfln1f;
-		if (adds_curr_buffer)
-			*adds_curr_buffer = parm.ipbfadr1;
-	} else {
-		if ((buffer->length) >= 8) {
-			memcpy ((char *) buffer->address,
-				(char *) parm.ipbfadr1, 8);
-			if (adds_curr_buffer)
-				*adds_curr_buffer =
-				    (ulong) ((buffer->address) + 8);
-			if (adds_curr_length)
-				*adds_curr_length = ((buffer->length) - 8);
+	parm.iptrgcls = trgcls;
+	parm.ipflags1 = (IPBUFLST | IPFGPID | IPFGMID | IPFGMCL);
+
+	b2f0_result = b2f0 (RECEIVE, &parm);
+
+	if (b2f0_result == 0 || b2f0_result == 5) {
+
+		if (flags1_out) {
+			pr_debug ("*flags1_out = %d\n", *flags1_out);
+			*flags1_out = (parm.ipflags1 & (~0x07));
+			pr_debug ("*flags1_out = %d\n", *flags1_out);
+		}
+
+		if (!(parm.ipflags1 & IPRMDATA)) {	/*msg not in parmlist */
+
+			if (residual_length)
+				*residual_length = parm.ipbfln1f;
+
+			if (residual_buffer)
+				*residual_buffer = parm.ipbfadr1;
 
 		} else {
-			parm.iprcode |= 0x05;
-			b2f0_result = (ulong) parm.iprcode;
+			/* copy msg from parmlist to users array. */
+
+			while ((moved < 8) && (moved < buflen)) {
+				dyn_len =
+				    min ((buffer + i)->length, need_to_move);
+
+				memcpy ((char *)((ulong)((buffer + i)->address)),
+					((char *) &parm.ipbfadr1) + moved,
+					dyn_len);
+
+				moved += dyn_len;
+				need_to_move -= dyn_len;
+
+				(buffer + i)->address =
+				    	(u32)  
+				((ulong)(uchar *) ((ulong)(buffer + i)->address) 
+						+ dyn_len);
+
+				(buffer + i)->length -= dyn_len;
+				i++;
+			}
+
+			if (need_to_move)	/* buflen < 8 bytes */
+				b2f0_result = 5;
+
+			if (residual_length)
+				*residual_length = abs (buflen - 8);
+
+			if (residual_buffer) {
+				if (moved == 0)
+					*residual_buffer = (ulong) buffer;
+				else
+					*residual_buffer =
+					    (ulong) (buffer + (i - 1));
+			}
+
 		}
 	}
-#ifdef DEBUG
-	printk (KERN_DEBUG "exiting iucv_receive\n");
-#endif
+
+	pr_debug ("iucv_receive_array: exiting\n");
 	return b2f0_result;
 }
 
-/**************************************************************/
-/* Name: iucv_send                                            */
-/* Purpose: sends messages                                    */
-/* Input: pathid - ushort, pathid                             */
-/*        msgid  - ulong *, id of message returned to caller  */
-/*        trgcls - ulong, target message class                */
-/*        srccls - ulong, source message class                */
-/*        msgtag - ulong, message tag                         */
-/*        priority_msg - uchar, flag                          */
-/*        buffer - pointer to buffer                          */
-/*        buflen - ulong, length of buffer                    */
-/* Output: iprcode - return code from b2f0 call               */
-/*         msgid - returns message id                         */
-/**************************************************************/
-int
-iucv_send (ushort pathid, ulong * msgid,
-	   ulong trgcls, ulong srccls,
-	   ulong msgtag, uchar priority_msg, void *buffer, ulong buflen)
+/*
+ * Name: iucv_reject                                          
+ * Purpose: Refuses a specified message. Between the time you are notified of a 
+ *          message and the time that you complete the message, the message may
+ *          be rejected.                                 
+ * Input: pathid - u16, path identification number.                            
+ *        msgid  - u32, specifies the message ID.
+ *        trgcls - u32, specifies target class.                
+ * Output: b2f0_result - return code from CP
+ * NOTE: see b2f0 output list                                 
+*/
+int
+iucv_reject (u16 pathid, u32 msgid, u32 trgcls)
+{
+	iparml_db parm;
+	ulong b2f0_result = 0;
+
+	pr_debug ("iucv_reject: entering \n");
+	pr_debug ("iucv_reject: pathid = %d\n", pathid);
+
+	memset (&parm, 0, sizeof (parm));
+	parm.ippathid = pathid;
+	parm.ipmsgid = msgid;
+	parm.iptrgcls = trgcls;
+	parm.ipflags1 = (IPFGMCL | IPFGMID | IPFGPID);
+
+	b2f0_result = b2f0 (REJECT, &parm);
+
+	pr_debug ("iucv_reject: b2f0_result = %ld\n", b2f0_result);
+	pr_debug ("iucv_reject: exiting\n");
+
+	return b2f0_result;
+}
+
+/* 
+ * Name: iucv_reply
+ * Purpose: This function responds to the two-way messages that you
+ *          receive. You must identify completely the message to
+ *          which you wish to reply. ie, pathid, msgid, and trgcls.
+ * Input: pathid - path identification number
+ *        msgid - specifies the message ID. 
+ *        trgcls - specifies target class
+ *        flags1 - option for path
+ *                 IPPRTY- 0x20 - specifies if you want to send priority message
+ *        buffer - address of reply buffer
+ *        buflen - length of reply buffer
+ * Output: ipbfadr2 - Address of buffer updated by the number
+ *                    of bytes you have moved.
+ *         ipbfln2f - Contains on the the following values
+ *              If the answer buffer is the same length as the reply, this field
+ *               contains zero.
+ *              If the answer buffer is longer than the reply, this field contains
+ *               the number of bytes remaining in the buffer.
+ *              If the answer buffer is shorter than the reply, this field contains
+ *               a residual count (that is, the number of bytes remianing in the
+ *               reply that does not fit into the buffer. In this
+ *                case b2f0_result = 5.
+ * Return: b2f0_result - return code from CP
+ *         (-EINVAL) - buffer address is NULL
+ */
+int
+iucv_reply (u16 pathid,
+	    u32 msgid, u32 trgcls,
+	    int flags1,
+	    void *buffer, ulong buflen, ulong * ipbfadr2, ulong * ipbfln2f)
 {
 	iparml_db parm;
 	ulong b2f0_result;
-#ifdef DEBUG
-	printk (KERN_DEBUG "entering iucv_send\n");
-#endif
-	memset (&(parm), 0, sizeof (parm));
+
+	pr_debug ("iucv_reply: entering\n");
+
+	if (!buffer)
+		return -EINVAL;
+
+	memset (&parm, 0, sizeof (parm));
+	parm.ipbfadr2 = (u32) ((ulong) buffer);
+	parm.ipbfln2f = (u32) buflen;	/* length of message */
 	parm.ippathid = pathid;
+	parm.ipmsgid = msgid;
 	parm.iptrgcls = trgcls;
-	parm.ipbfadr1 = (ulong) buffer;
-	parm.ipbfln1f = buflen;	/* length of message */
-	parm.ipsrccls = srccls;
-	parm.ipmsgtag = msgtag;
-	parm.ipflags1 |= one_way_msg;	/* one way message */
-	if (priority_msg)
-		parm.ipflags1 |= prior_msg;	/* priority message */
-	b2f0_result = b2f0 (send, &parm);
-	if (b2f0_result)
-		return b2f0_result;
-	if (msgid)
-		*msgid = parm.ipmsgid;
-#ifdef DEBUG
-	printk (KERN_DEBUG "exiting iucv_send\n");
-#endif
+	parm.ipflags1 = (uchar) flags1;	/* priority message */
+
+	b2f0_result = b2f0 (REPLY, &parm);
+
+	if ((b2f0_result == 0) || (b2f0_result == 5)) {
+		if (ipbfadr2)
+			*ipbfadr2 = parm.ipbfadr2;
+		if (ipbfln2f)
+			*ipbfln2f = parm.ipbfln2f;
+	}
+
+	pr_debug ("iucv_reply: exiting\n");
+
 	return b2f0_result;
 }
 
-/**************************************************************/
-/* Name: iucv_send_array                                      */
-/* Purpose: sends messages in buffer array                    */
-/* Input: pathid - ushort, pathid                             */
-/*        msgid  - ulong *, id of message returned to caller  */
-/*        trgcls - ulong, target message class                */
-/*        srccls - ulong, source message class                */
-/*        msgtag - ulong, message tag                         */
-/*        priority_msg - uchar, flag                          */
-/*        buffer - pointer to iucv_array_t                    */
-/*        buflen - ulong, length of buffer                    */
-/* Output: iprcode - return code from b2f0 call               */
-/*         msgid - returns message id                         */
-/**************************************************************/
-int
-iucv_send_array (ushort pathid, ulong * msgid,
-		 ulong trgcls, ulong srccls,
-		 ulong msgtag, uchar priority_msg,
-		 iucv_array_t * buffer, ulong buflen)
+/*
+ * Name: iucv_reply_array
+ * Purpose: This function responds to the two-way messages that you
+ *          receive. You must identify completely the message to   
+ *          which you wish to reply. ie, pathid, msgid, and trgcls.
+ *          The array identifies a list of addresses and lengths of
+ *          discontiguous buffers that contains the reply data.
+ * Input: pathid - path identification number
+ *        msgid - specifies the message ID. 
+ *        trgcls - specifies target class 
+ *        flags1 - option for path
+ *                 IPPRTY- specifies if you want to send priority message
+ *        buffer - address of array of reply buffers
+ *        buflen - total length of reply buffers
+ * Output: ipbfadr2 - Address of buffer which IUCV is currently working on.
+ *         ipbfln2f - Contains on the the following values
+ *              If the answer buffer is the same length as the reply, this field
+ *               contains zero.
+ *              If the answer buffer is longer than the reply, this field contains
+ *               the number of bytes remaining in the buffer.
+ *              If the answer buffer is shorter than the reply, this field contains
+ *               a residual count (that is, the number of bytes remianing in the
+ *               reply that does not fit into the buffer. In this
+ *               case b2f0_result = 5.
+ * Return: b2f0_result - return code from CP
+ *             (-EINVAL) - buffer address is NULL
+*/
+int
+iucv_reply_array (u16 pathid,
+		  u32 msgid, u32 trgcls,
+		  int flags1,
+		  iucv_array_t * buffer,
+		  ulong buflen, ulong * ipbfadr2, ulong * ipbfln2f)
 {
 	iparml_db parm;
 	ulong b2f0_result;
-#ifdef DEBUG
-	printk (KERN_DEBUG "entering iucv_send_array\n");
-#endif
-	memset (&(parm), 0, sizeof (parm));
+
+	pr_debug ("iucv_reply_array: entering\n");
+
+	if (!buffer)
+		return -EINVAL;
+
+	memset (&parm, 0, sizeof (parm));
+	parm.ipbfadr2 = (u32) ((ulong) buffer);
+	parm.ipbfln2f = buflen;	/* length of message */
 	parm.ippathid = pathid;
+	parm.ipmsgid = msgid;
 	parm.iptrgcls = trgcls;
-	parm.ipbfadr1 = (ulong) buffer;
-	parm.ipbfln1f = buflen;	/* length of message */
-	parm.ipsrccls = srccls;
-	parm.ipmsgtag = msgtag;
-	parm.ipflags1 |= one_way_msg;	/* one way message */
-	parm.ipflags1 |= array;	/* one way w/ array */
-	if (priority_msg)
-		parm.ipflags1 |= prior_msg;	/* priority message */
-	b2f0_result = b2f0 (send, &parm);
-	if (msgid)
-		*msgid = parm.ipmsgid;
-#ifdef DEBUG
-	printk (KERN_DEBUG "exiting iucv_send_array\n");
-#endif
+	parm.ipflags1 = (IPANSLST | flags1);
+
+	b2f0_result = b2f0 (REPLY, &parm);
+
+	if ((b2f0_result == 0) || (b2f0_result == 5)) {
+
+		if (ipbfadr2)
+			*ipbfadr2 = parm.ipbfadr2;
+		if (ipbfln2f)
+			*ipbfln2f = parm.ipbfln2f;
+	}
+
+	pr_debug ("iucv_reply_array: exiting\n");
+
 	return b2f0_result;
 }
 
-/**************************************************************/
-/* Name: iucv_send_prmmsg                                     */
-/* Purpose: sends messages in parameter list                  */
-/* Input: pathid - ushort, pathid                             */
-/*        msgid  - ulong *, id of message                     */
-/*        trgcls - ulong, target message class                */
-/*        srccls - ulong, source message class                */
-/*        msgtag - ulong, message tag                         */
-/*        priority_msg - uchar, flag                          */
-/*        prmmsg - uchar[8], message being sent               */
-/* Output: iprcode - return code from b2f0 call               */
-/*         msgid - returns message id                         */
-/**************************************************************/
-int
-iucv_send_prmmsg (ushort pathid, ulong * msgid,
-		  ulong trgcls, ulong srccls,
-		  ulong msgtag, uchar priority_msg, uchar prmmsg[8])
+/*
+ * Name: iucv_reply_prmmsg
+ * Purpose: This function responds to the two-way messages that you
+ *          receive. You must identify completely the message to
+ *          which you wish to reply. ie, pathid, msgid, and trgcls.
+ *          Prmmsg signifies the data is moved into the
+ *          parameter list.
+ * Input: pathid - path identification number
+ *        msgid - specifies the message ID. 
+ *        trgcls - specifies target class
+ *        flags1 - option for path
+ *                 IPPRTY- specifies if you want to send priority message
+ *        prmmsg - 8-bytes of data to be placed into the parameter
+ *                 list.
+ * Output: NA
+ * Return: b2f0_result - return code from CP
+*/
+int
+iucv_reply_prmmsg (u16 pathid,
+		   u32 msgid, u32 trgcls, int flags1, uchar prmmsg[8])
 {
 	iparml_dpl parm;
 	ulong b2f0_result;
-#ifdef DEBUG
-	printk (KERN_DEBUG "entering iucv_send_prmmsg\n");
-#endif
-	memset (&(parm), 0, sizeof (parm));
+
+	pr_debug ("iucv_reply_prmmsg: entering\n");
+
+	memset (&parm, 0, sizeof (parm));
 	parm.ippathid = pathid;
+	parm.ipmsgid = msgid;
 	parm.iptrgcls = trgcls;
-	parm.ipsrccls = srccls;
-	parm.ipmsgtag = msgtag;
-	parm.ipflags1 |= parm_data;	/* message in prmlist */
-	parm.ipflags1 |= one_way_msg;	/* one way message */
-	if (priority_msg)
-		parm.ipflags1 |= prior_msg;	/* priority message */
-	memcpy (parm.iprmmsg, prmmsg, 8);
-	b2f0_result = b2f0 (send, &parm);
-	if (msgid)
-		*msgid = parm.ipmsgid;
-#ifdef DEBUG
-	printk (KERN_DEBUG "exiting iucv_send_prmmsg\n");
-#endif
+	memcpy (parm.iprmmsg, prmmsg, sizeof (parm.iprmmsg));
+	parm.ipflags1 = (IPRMDATA | flags1);
+
+	b2f0_result = b2f0 (REPLY, &parm);
+
+	pr_debug ("iucv_reply_prmmsg: exiting\n");
+
 	return b2f0_result;
 }
 
-/**************************************************************/
-/* Name: iucv_send2way                                        */
-/* Purpose: sends messages in both directions                 */
-/* Input: pathid - ushort, pathid                             */
-/*        msgid  - ulong *, id of message                     */
-/*        trgcls - ulong, target message class                */
-/*        srccls - ulong, source message class                */
-/*        msgtag - ulong, message tag                         */
-/*        priority_msg - uchar, flag                          */
-/*        buffer - pointer to buffer                          */
-/*        buflen - ulong, length of buffer                    */
-/*        ansbuf - pointer to buffer on reply                 */
-/*        anslen - length of ansbuf buffer                    */
-/* Output: iprcode - return code from b2f0 call               */
-/*         msgid - returns message id                         */
-/**************************************************************/
-int
-iucv_send2way (ushort pathid, ulong * msgid,
-	       ulong trgcls, ulong srccls,
-	       ulong msgtag, uchar priority_msg,
-	       void *buffer, ulong buflen, void *ansbuf, ulong anslen)
+/*
+ * Name: iucv_resume                                          
+ * Purpose: This function restores communication over a quiesced path.       
+ * Input: pathid - u16, path identification number                             
+ *        user_data - uchar[16], 16-byte of user data                     
+ * Output: b2f0_result - return code from CP               
+ */
+int
+iucv_resume (u16 pathid, uchar user_data[16])
+{
+	iparml_control parm;
+	ulong b2f0_result = 0;
+
+	pr_debug ("iucv_resume: entering\n");
+	pr_debug ("iucv_resume: pathid = %d\n", pathid);
+
+	memset (&parm, 0, sizeof (parm));
+	memcpy (parm.ipuser, user_data, sizeof (*user_data));
+	parm.ippathid = pathid;
+
+	b2f0_result = b2f0 (RESUME, &parm);
+
+	pr_debug ("iucv_resume: exiting \n");
+
+	return b2f0_result;
+}
+
+/*
+ * Name: iucv_send                                             
+ * Purpose: sends messages                                    
+ * Input: pathid - ushort, pathid                            
+ *        msgid  - ulong *, id of message returned to caller   
+ *        trgcls - ulong, target message class              
+ *        srccls - ulong, source message class              
+ *        msgtag - ulong, message tag                    
+ *	  flags1  - Contains options for this path.
+ *		IPPRTY - Ox20 - specifies if you want to send a priority message.
+ *        buffer - pointer to buffer                           
+ *        buflen - ulong, length of buffer                     
+ * Output: b2f0_result - return code from b2f0 call               
+ *         msgid - returns message id                         
+ */
+int
+iucv_send (u16 pathid, u32 * msgid,
+	   u32 trgcls, u32 srccls,
+	   u32 msgtag, int flags1, void *buffer, ulong buflen)
 {
 	iparml_db parm;
 	ulong b2f0_result;
-#ifdef DEBUG
-	printk (KERN_DEBUG "entering iucv_send2way\n");
-#endif
-	memset (&(parm), 0, sizeof (parm));
+
+	pr_debug ("iucv_send: entering\n");
+
+	if (!buffer)
+		return -EINVAL;
+
+	memset (&parm, 0, sizeof (parm));
+	parm.ipbfadr1 = (u32) ((ulong) buffer);
 	parm.ippathid = pathid;
 	parm.iptrgcls = trgcls;
-	parm.ipbfadr1 = (ulong) buffer;
-	parm.ipbfln1f = buflen;	/* length of message */
-	parm.ipbfadr2 = (ulong) ansbuf;
-	parm.ipbfln2f = anslen;
+	parm.ipbfln1f = (u32) buflen;	/* length of message */
 	parm.ipsrccls = srccls;
 	parm.ipmsgtag = msgtag;
-	if (priority_msg)
-		parm.ipflags1 |= prior_msg;	/* priority message */
-	b2f0_result = b2f0 (send, &parm);
-	if (msgid)
+	parm.ipflags1 = (IPNORPY | flags1);	/* one way priority message */
+
+	b2f0_result = b2f0 (SEND, &parm);
+
+	if ((b2f0_result == 0) && (msgid))
 		*msgid = parm.ipmsgid;
-#ifdef DEBUG
-	printk (KERN_DEBUG "exiting iucv_send2way\n");
-#endif
+
+	pr_debug ("iucv_send: exiting\n");
+
 	return b2f0_result;
 }
 
-/**************************************************************/
-/* Name: iucv_send2way_array                                  */
-/* Purpose: sends messages in both directions in arrays       */
-/* Input: pathid - ushort, pathid                             */
-/*        msgid  - ulong *, id of message                     */
-/*        trgcls - ulong, target message class                */
-/*        srccls - ulong, source message class                */
-/*        msgtag - ulong, message tag                         */
-/*        priority_msg - uchar, flag                          */
-/*        buffer - pointer to iucv_array_t                    */
-/*        buflen - ulong, length of buffer                    */
-/*        ansbuf - pointer to iucv_array_t on reply           */
-/*        anslen - length of ansbuf buffer                    */
-/* Output: iprcode - return code from b2f0 call               */
-/*         msgid - returns message id                         */
-/**************************************************************/
-int
-iucv_send2way_array (ushort pathid, ulong * msgid,
-		     ulong trgcls, ulong srccls,
-		     ulong msgtag, uchar priority_msg,
-		     iucv_array_t * buffer, ulong buflen,
-		     iucv_array_t * ansbuf, ulong anslen)
+/*
+ * Name: iucv_send_array
+ * Purpose: This function transmits data to another application.
+ *          The contents of buffer is the address of the array of
+ *          addresses and lengths of discontiguous buffers that hold
+ *          the message text. This is a one-way message and the
+ *          receiver will not reply to the message.
+ * Input: pathid - path identification number
+ *        trgcls - specifies target class
+ *        srccls - specifies the source message class
+ *        msgtag - specifies a tag to be associated witht the message
+ *        flags1 - option for path
+ *                 IPPRTY- specifies if you want to send priority message
+ *        buffer - address of array of send buffers
+ *        buflen - total length of send buffers
+ * Output: msgid - specifies the message ID.
+ * Return: b2f0_result - return code from CP 
+ *         (-EINVAL) - buffer address is NULL
+ */
+int
+iucv_send_array (u16 pathid,
+		 u32 * msgid,
+		 u32 trgcls,
+		 u32 srccls,
+		 u32 msgtag, int flags1, iucv_array_t * buffer, ulong buflen)
 {
 	iparml_db parm;
 	ulong b2f0_result;
-#ifdef DEBUG
-	printk (KERN_DEBUG "entering iucv_send2way_array\n");
-#endif
-	memset (&(parm), 0, sizeof (parm));
+
+	pr_debug ("iucv_send_array: entering\n");
+
+	if (!buffer)
+		return -EINVAL;
+
+	memset (&parm, 0, sizeof (parm));
 	parm.ippathid = pathid;
 	parm.iptrgcls = trgcls;
-	parm.ipbfadr1 = (ulong) buffer;
-	parm.ipbfln1f = buflen;	/* length of message */
-	parm.ipbfadr2 = (ulong) ansbuf;
-	parm.ipbfln2f = anslen;
+	parm.ipbfadr1 = (u32) ((ulong) buffer);
+	parm.ipbfln1f = (u32) buflen;	/* length of message */
 	parm.ipsrccls = srccls;
 	parm.ipmsgtag = msgtag;
-	parm.ipflags1 |= array;	/* send  w/ array  */
-	parm.ipflags1 |= reply_array;	/* reply w/ array  */
-	if (priority_msg)
-		parm.ipflags1 |= prior_msg;	/* priority message */
-	b2f0_result = b2f0 (send, &parm);
-	if (msgid)
+	parm.ipflags1 = (IPNORPY | IPBUFLST | flags1);
+	b2f0_result = b2f0 (SEND, &parm);
+
+	if ((b2f0_result == 0) && (msgid))
 		*msgid = parm.ipmsgid;
-#ifdef DEBUG
-	printk (KERN_DEBUG "exiting iucv_send2way_array\n");
-#endif
+	pr_debug ("iucv_send_array: exiting\n");
 	return b2f0_result;
 }
 
-/**************************************************************/
-/* Name: iucv_send2way_prmmsg                                 */
-/* Purpose: sends messages in both directions w/parameter lst */
-/* Input: pathid - ushort, pathid                             */
-/*        msgid  - ulong *, id of message                     */
-/*        trgcls - ulong, target message class                */
-/*        srccls - ulong, source message class                */
-/*        msgtag - ulong, message tag                         */
-/*        priority_msg - uchar, flag                          */
-/*        prmmsg - uchar[8], message being sent in parameter  */
-/*        ansbuf - pointer to buffer                          */
-/*        anslen - length of ansbuf buffer                    */
-/* Output: iprcode - return code from b2f0 call               */
-/*         msgid - returns message id                         */
-/**************************************************************/
-int
-iucv_send2way_prmmsg (ushort pathid, ulong * msgid,
-		      ulong trgcls, ulong srccls,
-		      ulong msgtag, uchar priority_msg,
-		      uchar prmmsg[8], void *ansbuf, ulong anslen)
+/*
+ * Name: iucv_send_prmmsg
+ * Purpose: This function transmits data to another application. 
+ *          Prmmsg specifies that the 8-bytes of data are to be moved
+ *          into the parameter list. This is a one-way message and the
+ *          receiver will not reply to the message.
+ * Input: pathid - path identification number
+ *        trgcls - specifies target class
+ *        srccls - specifies the source message class
+ *        msgtag - specifies a tag to be associated with the message
+ *        flags1 - option for path
+ *                 IPPRTY- specifies if you want to send priority message
+ *        prmmsg - 8-bytes of data to be placed into parameter list
+ * Output: msgid - specifies the message ID.   
+ * Return: b2f0_result - return code from CP
+*/
+int
+iucv_send_prmmsg (u16 pathid,
+		  u32 * msgid,
+		  u32 trgcls,
+		  u32 srccls, u32 msgtag, int flags1, uchar prmmsg[8])
 {
 	iparml_dpl parm;
 	ulong b2f0_result;
-#ifdef DEBUG
-	printk (KERN_DEBUG "entering iucv_send2way_prmmsg\n");
-#endif
-	memset (&(parm), 0, sizeof (parm));
+
+	pr_debug ("iucv_send_prmmsg: entering\n");
+
+	memset (&parm, 0, sizeof (parm));
 	parm.ippathid = pathid;
 	parm.iptrgcls = trgcls;
 	parm.ipsrccls = srccls;
 	parm.ipmsgtag = msgtag;
-	parm.ipbfadr2 = (ulong) ansbuf;
-	parm.ipbfln2f = anslen;
-	parm.ipflags1 |= parm_data;	/* message in prmlist */
-	if (priority_msg)
-		parm.ipflags1 |= prior_msg;	/* priority message */
-	memcpy (parm.iprmmsg, prmmsg, 8);
-	b2f0_result = b2f0 (send, &parm);
-	if (msgid)
+	parm.ipflags1 = (IPRMDATA | IPNORPY | flags1);
+	memcpy (parm.iprmmsg, prmmsg, sizeof (parm.iprmmsg));
+
+	b2f0_result = b2f0 (SEND, &parm);
+
+	if ((b2f0_result == 0) && (msgid))
 		*msgid = parm.ipmsgid;
-#ifdef DEBUG
-	printk (KERN_DEBUG "exiting iucv_send2way_prmmsg\n");
-#endif
+
+	pr_debug ("iucv_send_prmmsg: exiting\n");
 	return b2f0_result;
 }
 
-/**************************************************************/
-/* Name: iucv_reply                                           */
-/* Purpose: responds to the two-way messages that you receive */
-/* Input: pathid - ushort, pathid                             */
-/*        msgid  - ulong, id of message                       */
-/*        trgcls - ulong, target message class                */
-/*        priority_msg - uchar, flag                          */
-/*        buf    - pointer, address of buffer                 */
-/*        buflen - length of buffer                           */
-/* Output: iprcode - return code from b2f0 call               */
-/**************************************************************/
+/*
+ * Name: iucv_send2way
+ * Purpose: This function transmits data to another application.
+ *          Data to be transmitted is in a buffer. The receiver
+ *          of the send is expected to reply to the message and
+ *          a buffer is provided into which IUCV moves the reply 
+ *          to this message.
+ * Input: pathid - path identification number
+ *        trgcls - specifies target class
+ *        srccls - specifies the source message class
+ *        msgtag - specifies a tag associated with the message
+ *        flags1 - option for path
+ *                 IPPRTY- specifies if you want to send priority message
+ *        buffer - address of send buffer
+ *        buflen - length of send buffer
+ *        ansbuf - address of buffer to reply with
+ *        anslen - length of buffer to reply with
+ * Output: msgid - specifies the message ID.
+ * Return: b2f0_result - return code from CP
+ *         (-EINVAL) - buffer or ansbuf address is NULL
+ */
 int
-iucv_reply (ushort pathid, ulong msgid, ulong trgcls,
-	    uchar priority_msg, void *buf, ulong buflen)
+iucv_send2way (u16 pathid,
+	       u32 * msgid,
+	       u32 trgcls,
+	       u32 srccls,
+	       u32 msgtag,
+	       int flags1,
+	       void *buffer, ulong buflen, void *ansbuf, ulong anslen)
 {
 	iparml_db parm;
 	ulong b2f0_result;
-#ifdef DEBUG
-	printk (KERN_DEBUG "entering iucv_reply\n");
-#endif
-	memset (&(parm), 0, sizeof (parm));
+	pr_debug ("iucv_send2way: entering\n");
+
+	if (!buffer || !ansbuf)
+		return -EINVAL;
+
+	memset (&parm, 0, sizeof (parm));
 	parm.ippathid = pathid;
-	parm.ipmsgid = msgid;
 	parm.iptrgcls = trgcls;
-	parm.ipbfadr2 = (ulong) buf;
-	parm.ipbfln2f = buflen;	/* length of message */
-	if (priority_msg)
-		parm.ipflags1 |= prior_msg;	/* priority message */
-	b2f0_result = b2f0 (reply, &parm);
-#ifdef DEBUG
-	printk (KERN_DEBUG "exiting iucv_reply\n");
-#endif
+	parm.ipbfadr1 = (u32) ((ulong) buffer);
+	parm.ipbfln1f = (u32) buflen;	/* length of message */
+	parm.ipbfadr2 = (u32) ((ulong) ansbuf);
+	parm.ipbfln2f = (u32) anslen;
+	parm.ipsrccls = srccls;
+	parm.ipmsgtag = msgtag;
+	parm.ipflags1 = flags1;	/* priority message */
+
+	b2f0_result = b2f0 (SEND, &parm);
+
+	if ((b2f0_result == 0) && (msgid))
+		*msgid = parm.ipmsgid;
+
+	pr_debug ("iucv_send2way: exiting\n");
+
 	return b2f0_result;
 }
 
-/**************************************************************/
-/* Name: iucv_reply_array                                     */
-/* Purpose: responds to the two-way messages that you receive */
-/* Input: pathid - ushort, pathid                             */
-/*        msgid  - ulong, id of message                       */
-/*        trgcls - ulong, target message class                */
-/*        priority_msg - uchar, flag                          */
-/*        buf    - pointer, address of array                  */
-/*        buflen - length of buffer                           */
-/* Output: iprcode - return code from b2f0 call               */
-/**************************************************************/
+/*
+ * Name: iucv_send2way_array
+ * Purpose: This function transmits data to another application.
+ *          The contents of buffer is the address of the array of
+ *          addresses and lengths of discontiguous buffers that hold
+ *          the message text. The receiver of the send is expected to
+ *          reply to the message and a buffer is provided into which
+ *          IUCV moves the reply to this message.
+ * Input: pathid - path identification number
+ *        trgcls - specifies target class
+ *        srccls - specifies the source message class
+ *        msgtag - spcifies a tag to be associated with the message
+ *        flags1 - option for path
+ *                 IPPRTY- specifies if you want to send priority message
+ *        buffer - address of array of send buffers
+ *        buflen - total length of send buffers
+ *        ansbuf - address of buffer to reply with                       
+ *        anslen - length of buffer to reply with     
+ * Output: msgid - specifies the message ID.
+ * Return: b2f0_result - return code from CP
+ *         (-EINVAL) - buffer address is NULL
+ */
 int
-iucv_reply_array (ushort pathid, ulong msgid, ulong trgcls,
-		  uchar priority_msg, iucv_array_t * buffer, ulong buflen)
+iucv_send2way_array (u16 pathid,
+		     u32 * msgid,
+		     u32 trgcls,
+		     u32 srccls,
+		     u32 msgtag,
+		     int flags1,
+		     iucv_array_t * buffer,
+		     ulong buflen, iucv_array_t * ansbuf, ulong anslen)
 {
 	iparml_db parm;
 	ulong b2f0_result;
-#ifdef DEBUG
-	printk (KERN_DEBUG "entering iucv_reply_array\n");
-#endif
-	memset (&(parm), 0, sizeof (parm));
+
+	pr_debug ("iucv_send2way_array: entering\n");
+
+	if (!buffer || !ansbuf)
+		return -EINVAL;
+
+	memset (&parm, 0, sizeof (parm));
 	parm.ippathid = pathid;
-	parm.ipmsgid = msgid;
 	parm.iptrgcls = trgcls;
-	parm.ipbfadr2 = (ulong) buffer;
-	parm.ipbfln2f = buflen;	/* length of message */
-	parm.ipflags1 |= reply_array;	/* reply w/ array  */
-	if (priority_msg)
-		parm.ipflags1 |= prior_msg;	/* priority message */
-	b2f0_result = b2f0 (reply, &parm);
-#ifdef DEBUG
-	printk (KERN_DEBUG "exiting iucv_reply_array\n");
-#endif
+	parm.ipbfadr1 = (u32) ((ulong) buffer);
+	parm.ipbfln1f = (u32) buflen;	/* length of message */
+	parm.ipbfadr2 = (u32) ((ulong) ansbuf);
+	parm.ipbfln2f = (u32) anslen;
+	parm.ipsrccls = srccls;
+	parm.ipmsgtag = msgtag;
+	parm.ipflags1 = (IPBUFLST | IPANSLST | flags1);
+	b2f0_result = b2f0 (SEND, &parm);
+	if ((b2f0_result == 0) && (msgid))
+		*msgid = parm.ipmsgid;
+	pr_debug ("iucv_send2way_array: exiting\n");
+	return b2f0_result;
+}
+
+/*
+ * Name: iucv_send2way_prmmsg
+ * Purpose: This function transmits data to another application.
+ *          Prmmsg specifies that the 8-bytes of data are to be moved
+ *          into the parameter list. This is a two-way message and the
+ *          receiver of the message is expected to reply. A buffer
+ *          is provided into which IUCV moves the reply to this
+ *          message.
+ * Input: pathid - path identification number  
+ *        trgcls - specifies target class
+ *        srccls - specifies the source message class
+ *        msgtag - specifies a tag to be associated with the message
+ *        flags1 - option for path
+ *                 IPPRTY- specifies if you want to send priority message
+ *        prmmsg - 8-bytes of data to be placed in parameter list
+ *        ansbuf - address of buffer to reply with                       
+ *        anslen - length of buffer to reply with     
+ * Output: msgid - specifies the message ID.
+ * Return: b2f0_result - return code from CP
+ *         (-EINVAL) - buffer address is NULL
+*/
+int
+iucv_send2way_prmmsg (u16 pathid,
+		      u32 * msgid,
+		      u32 trgcls,
+		      u32 srccls,
+		      u32 msgtag,
+		      ulong flags1, uchar prmmsg[8], void *ansbuf, ulong anslen)
+{
+	iparml_dpl parm;
+	ulong b2f0_result;
+	pr_debug ("iucv_send2way_prmmsg: entering\n");
+
+	if (!ansbuf)
+		return -EINVAL;
+
+	memset (&parm, 0, sizeof (parm));
+	parm.ippathid = pathid;
+	parm.iptrgcls = trgcls;
+	parm.ipsrccls = srccls;
+	parm.ipmsgtag = msgtag;
+	parm.ipbfadr2 = (u32) ((ulong) ansbuf);
+	parm.ipbfln2f = (u32) anslen;
+	parm.ipflags1 = (IPRMDATA | flags1);	/* message in prmlist */
+	memcpy (parm.iprmmsg, prmmsg, sizeof (parm.iprmmsg));
+
+	b2f0_result = b2f0 (SEND, &parm);
+
+	if ((b2f0_result == 0) && (msgid))
+		*msgid = parm.ipmsgid;
+
+	pr_debug ("iucv_send2way_prmmsg: exiting\n");
+
 	return b2f0_result;
 }
 
-/**************************************************************/
-/* Name: iucv_reply_prmmsg                                    */
-/* Purpose: responds to the two-way messages in parameter list */
-/* Input: pathid - ushort, pathid                             */
-/*        msgid  - ulong, id of message                       */
-/*        trgcls - ulong, target message class                */
-/*        priority_msg - uchar, flag                          */
-/*        prmmsg - uchar[8], message in parameter list        */
-/* Output: iprcode - return code from b2f0 call               */
-/**************************************************************/
+/*
+ * Name: iucv_send2way_prmmsg_array
+ * Purpose: This function transmits data to another application.
+ *          Prmmsg specifies that the 8-bytes of data are to be moved
+ *          into the parameter list. This is a two-way message and the
+ *          receiver of the message is expected to reply. A buffer
+ *          is provided into which IUCV moves the reply to this
+ *          message. The contents of ansbuf is the address of the
+ *          array of addresses and lengths of discontiguous buffers
+ *          that contain the reply.
+ * Input: pathid - path identification number
+ *        trgcls - specifies target class
+ *        srccls - specifies the source message class   
+ *        msgtag - specifies a tag to be associated with the message
+ *        flags1 - option for path
+ *                 IPPRTY- specifies if you want to send priority message
+ *        prmmsg - 8-bytes of data to be placed into the parameter list
+ *        ansbuf - address of buffer to reply with                       
+ *        anslen - length of buffer to reply with     
+ * Output: msgid - specifies the message ID.
+ * Return: b2f0_result - return code from CP
+ *         (-EINVAL) - ansbuf address is NULL
+ */
 int
-iucv_reply_prmmsg (ushort pathid, ulong msgid, ulong trgcls,
-		   uchar priority_msg, uchar prmmsg[8])
+iucv_send2way_prmmsg_array (u16 pathid,
+			    u32 * msgid,
+			    u32 trgcls,
+			    u32 srccls,
+			    u32 msgtag,
+			    int flags1,
+			    uchar prmmsg[8],
+			    iucv_array_t * ansbuf, ulong anslen)
 {
 	iparml_dpl parm;
 	ulong b2f0_result;
-#ifdef DEBUG
-	printk (KERN_DEBUG "entering iucv_reply_prmmsg\n");
-#endif
-	memset (&(parm), 0, sizeof (parm));
+
+	pr_debug ("iucv_send2way_prmmsg_array: entering\n");
+
+	if (!ansbuf)
+		return -EINVAL;
+
+	memset (&parm, 0, sizeof (parm));
 	parm.ippathid = pathid;
-	parm.ipmsgid = msgid;
 	parm.iptrgcls = trgcls;
-	memcpy (parm.iprmmsg, prmmsg, 8);
-	parm.ipflags1 |= parm_data;
-	if (priority_msg)
-		parm.ipflags1 |= prior_msg;	/* priority message */
-	b2f0_result = b2f0 (reply, &parm);
-#ifdef DEBUG
-	printk (KERN_DEBUG "exiting iucv_reply_prmmsg\n");
-#endif
+	parm.ipsrccls = srccls;
+	parm.ipmsgtag = msgtag;
+	parm.ipbfadr2 = (u32) ((ulong) ansbuf);
+	parm.ipbfln2f = (u32) anslen;
+	parm.ipflags1 = (IPRMDATA | IPANSLST | flags1);
+	memcpy (parm.iprmmsg, prmmsg, sizeof (parm.iprmmsg));
+	b2f0_result = b2f0 (SEND, &parm);
+	if ((b2f0_result == 0) && (msgid))
+		*msgid = parm.ipmsgid;
+	pr_debug ("iucv_send2way_prmmsg_array: exiting\n");
 	return b2f0_result;
 }
 
-/**************************************************************/
-/* Name: iucv_connect                                         */
-/* Purpose: establishes an IUCV path to another vm            */
-/* Input: pathid - ushort *, pathid returned to user          */
-/*        msglim - ushort, limit of outstanding messages      */
-/*        user_data - uchar[16], user data                    */
-/*        userid - uchar[8], user's id                        */
-/*        system_name - uchar[8], system identification       */
-/*        priority_requested - uchar- flag                    */
-/*        prmdata - uchar, flag prgrm can handler messages    */
-/*                  in parameter list                         */
-/*        quiesce - uchar, flag to quiesce a path being establ */
-/*        control - uchar, flag, option not used              */
-/*        local   - uchar, flag, establish connection only on */
-/*                  local system                              */
-/*        priority_permitted - uchar *, flag returned to user */
-/*        handle - address of handler                         */
-/*        pgm_data - ulong                                    */
-/* Output: iprcode - return code from b2f0 call               */
-/**************************************************************/
-int
-iucv_connect (ushort * pathid, ushort msglim, uchar user_data[16],
-	      uchar userid[8], uchar system_name[8],
-	      uchar priority_requested, uchar prmdata,
-	      uchar quiesce, uchar control,
-	      uchar local, uchar * priority_permitted,
-	      iucv_handle_t handle, ulong pgm_data)
+/*
+ * Name: iucv_setmask
+ * Purpose: This function enables or disables the following IUCV   
+ *          external interruptions: Nonpriority and priority message
+ *          interrupts, nonpriority and priority reply interrupts.
+ * Input: SetMaskFlag - options for interrupts
+ *           0x80 - Nonpriority_MessagePendingInterruptsFlag
+ *           0x40 - Priority_MessagePendingInterruptsFlag
+ *           0x20 - Nonpriority_MessageCompletionInterruptsFlag
+ *           0x10 - Priority_MessageCompletionInterruptsFlag
+ * Output: NA
+ * Return: b2f0_result - return code from CP
+*/
+int
+iucv_setmask (int SetMaskFlag)
 {
-	iparml_control parm;
-	ulong b2f0_result;
-	int add_pathid_result, rc;
-	handler *R;
-#ifdef DEBUG
-	printk (KERN_DEBUG "entering iucv_connect\n");
-#endif
+	iparml_set_mask parm;
+	ulong b2f0_result = 0;
+	pr_debug ("iucv_setmask: entering \n");
+
 	memset (&parm, 0, sizeof (parm));
-	if (declare_flag == NULL) {
-		rc = iucv_declare_buffer (iucv_external_int_buffer);
-		if (rc) {
-			printk (KERN_DEBUG "IUCV: registration failed\n");
-#ifdef DEBUG
-			printk (KERN_DEBUG "rc from declare buffer is: %i\n",
-				rc);
-#endif
-			return rc;
-		} else
-			declare_flag = 1;
-	}
-	/* Checking if handle is valid  */
-	spin_lock (&lock);
-	for (R = handler_anchor; R != NULL; R = (handler *) R->next)
-		if (R == handle)
-			break;
-	if (R == NULL) {
-		spin_unlock (&lock);
-#ifdef DEBUG
-		printk (KERN_DEBUG "iucv_connect: Invalid Handle\n");
-#endif
-		return (-2);
-	}
-	if (pathid == NULL) {
-		spin_unlock (&lock);
-#ifdef DEBUG
-		printk (KERN_DEBUG "iucv_connect: invalid pathid pointer\n");
-#endif
-		return (-3);
-	}
-	spin_unlock (&lock);
-	parm.ipmsglim = msglim;
-	memcpy (parm.ipuser, user_data, 16);
-	memcpy (parm.ipvmid, userid, 8);
-	memcpy (parm.iptarget, system_name, 8);
-	if (parm.iptarget)
-		ASCEBC (parm.iptarget, 8);
-	if (parm.ipvmid) {
-		ASCEBC (parm.ipvmid, 8);
-		EBC_TOUPPER(parm.ipvmid, 8);
-	}
-	if (priority_requested)
-		parm.ipflags1 |= prior_msg;
-	if (prmdata)
-		parm.ipflags1 |= parm_data;	/*data in parameter list */
-	if (quiesce)
-		parm.ipflags1 |= quiesce_msg;
-	if (control) {
-		/* do nothing at the time being  */
-		/*control not provided yet */
-	}
-	if (local)
-		parm.ipflags1 |= local_conn;	/*connect on local system */
-	b2f0_result = b2f0 (connect, &parm);
-	if (b2f0_result)
-		return b2f0_result;
-	add_pathid_result = add_pathid (parm.ippathid, handle, pgm_data);
-	if (add_pathid_result) {
-#ifdef DEBUG
-		printk (KERN_DEBUG "iucv_connect: add_pathid failed \n");
-#endif
-		return (add_pathid_result);
-	}
-	*pathid = parm.ippathid;
-	if (parm.ipflags1 & prior_msg)
-		if (priority_permitted)
-			*priority_permitted = 0x01;
-#ifdef DEBUG
-	printk (KERN_DEBUG "exiting iucv_connect\n");
-#endif
+	parm.ipmask = (uchar) SetMaskFlag;
+
+	b2f0_result = b2f0 (SETMASK, &parm);
+
+	pr_debug ("iucv_setmask: b2f0_result = %ld\n", b2f0_result);
+	pr_debug ("iucv_setmask: exiting\n");
+
 	return b2f0_result;
 }
 
-/**************************************************************/
-/* Name: iucv_accept                                          */
-/* Purpose: completes the iucv communication path             */
-/* Input: pathid - ushort , pathid                            */
-/*        msglim - ushort, limit of outstanding messages      */
-/*        user_data - uchar[16], user data                    */
-/*        priority_requested - uchar- flag                    */
-/*        prmdata - uchar, flag prgrm can handler messages    */
-/*                  in parameter list                         */
-/*        quiesce - uchar, flag to quiesce a path being establ*/
-/*        control - uchar, flag, option not used              */
-/*        priority_permitted -uchar *, flag returned to caller*/
-/*        handle - address of handler                         */
-/*        pgm_data - ulong                                    */
-/* Output: iprcode - return code from b2f0 call               */
-/**************************************************************/
-int
-iucv_accept (ushort pathid, ushort msglim, uchar user_data[16],
-	     uchar priority_requested,
-	     uchar prmdata, uchar quiesce, uchar control,
-	     uchar * priority_permitted, iucv_handle_t handle, ulong pgm_data)
+/*
+ * Name: iucv_sever                                           
+ * Purpose: This function terminates an iucv path         
+ * Input: pathid - u16, path identification number                             
+ *        user_data - uchar[16], 16-byte of user data                     
+ * Output: b2f0_result - return code from CP          
+ *         -EINVAL - NULL address found for handler                                 
+ */
+int
+iucv_sever (u16 pathid, uchar user_data[16])
 {
-	ulong index1, index2;
-	handler_table_entry *P = 0;
 	iparml_control parm;
-	ulong b2f0_result;
-#ifdef DEBUG
-	printk (KERN_DEBUG "entering iucv_accept\n");
-#endif
-	memset (&(parm), 0, sizeof (parm));
+	ulong b2f0_result = 0;
+	pr_debug ("iucv_sever: entering\n");
+	memset (&parm, 0, sizeof (parm));
+	memcpy (parm.ipuser, user_data, sizeof (parm.ipuser));
 	parm.ippathid = pathid;
-	parm.ipmsglim = msglim;
-	memcpy (parm.ipuser, user_data, 16);
-	if (priority_requested)
-		parm.ipflags1 |= prior_msg;
-	if (prmdata)
-		parm.ipflags1 |= parm_data;	/*data in parameter list */
-	if (quiesce)
-		parm.ipflags1 |= quiesce_msg;
-	if (control) {
-		/* do nothing at the time being  */
-		/*control not provided yet */
-	}
-	b2f0_result = b2f0 (accept, &parm);
-	if (b2f0_result)
-		return b2f0_result;
-	index1 = ((ulong) pathid) / 512;
-	index2 = ((ulong) pathid) % 512;
-	spin_lock (&lock);
-	if (pgm_data) {
-		P = main_table[index1];
-		(P + index2)->pgm_data = pgm_data;
-	}
-	spin_unlock (&lock);
-	if (parm.ipflags1 & prior_msg)
-		if (priority_permitted)
-			*priority_permitted = 0x01;
-#ifdef DEBUG
-	printk (KERN_DEBUG "exiting iucv_accept\n");
-#endif
+
+	b2f0_result = b2f0 (SEVER, &parm);
+
+	if (!b2f0_result)
+		iucv_remove_pathid (pathid);
+
+	pr_debug ("iucv_sever: exiting \n");
 	return b2f0_result;
 }
 
-/**************************************************************/
-/* Name: iucv_send2way_prmmsg_array                           */
-/* Purpose: sends messages in both directions w/parameter lst */
-/* Input: pathid - ushort, pathid                             */
-/*        msgid  - ulong *, id of message returned to caller  */
-/*        trgcls - ulong, target message class                */
-/*        srccls - ulong, source message class                */
-/*        msgtag - ulong, message tag                         */
-/*        priority_msg - uchar, flag                          */
-/*        prmmsg - uchar[8], message being sent in parameter  */
-/*        ansbuf - pointer to array of buffers                */
-/*        anslen - length of ansbuf buffer                    */
-/* Output: iprcode - return code from b2f0 call               */
-/*         msgid - returns message id                         */
-/**************************************************************/
-int
-iucv_send2way_prmmsg_array (ushort pathid, ulong * msgid,
-			    ulong trgcls, ulong srccls,
-			    ulong msgtag, uchar priority_msg,
-			    uchar prmmsg[8],
-			    iucv_array_t * ansbuf, ulong anslen)
+static void
+iucv_remove_pathid (u16 pathid)
 {
-	iparml_dpl parm;
-	ulong b2f0_result;
-#ifdef DEBUG
-	printk (KERN_DEBUG "entering iucv_send2way_prmmsg\n");
-#endif
-	memset (&(parm), 0, sizeof (parm));
-	parm.ippathid = pathid;
-	parm.iptrgcls = trgcls;
-	parm.ipsrccls = srccls;
-	parm.ipmsgtag = msgtag;
-	parm.ipbfadr2 = (ulong) ansbuf;
-	parm.ipbfln2f = anslen;
-	parm.ipflags1 |= 0x88;	/* message in prmlist */
-	if (priority_msg)
-		parm.ipflags1 |= prior_msg;	/* priority message */
-	memcpy (parm.iprmmsg, prmmsg, 8);
-	b2f0_result = b2f0 (send, &parm);
-	if (msgid)
-		*msgid = parm.ipmsgid;
-#ifdef DEBUG
-	printk (KERN_DEBUG "exiting iucv_send2way_prmmsg\n");
-#endif
-	return b2f0_result;
+	handler_table_entry *users_hte = NULL;	/*users handler_table_entry */
+	handler *users_handler = NULL;
+	ulong *users_pathid = NULL;
+	ulong flags;
+	spin_lock_irqsave (&iucv_lock, flags);
+	users_hte = handler_table_anchor + (int) pathid;
+
+	if ((users_hte->addrs) == NULL) {
+		spin_unlock_irqrestore (&iucv_lock, flags);
+		return;		/* wild pointer has been found */
+	}
+
+	users_handler = users_hte->addrs;
+
+	pr_debug ("iucv_sever: pathid is %d\n", pathid);
+	pr_debug ("iucv_sever: H_T_E is %p\n", users_hte);
+	pr_debug ("iucv_sever: address of handler is %p\n", users_handler);
+	pr_debug ("iucv_sever: below is pathid table\n");
+	iucv_dumpit ((uchar *) users_handler->pathid_head,
+		     (int) users_handler->entries * sizeof (ulong));
+
+/*
+ * Searching the pathid address table for matching address, once    
+ * found, NULL the handler_table_entry field and then zero the H_T_E fields.               
+ */
+
+	for (users_pathid = (users_handler->pathid_head);
+	     users_pathid < (users_handler->pathid_tail); users_pathid++)
+
+		if (*users_pathid == (ulong) users_hte) {
+			pr_debug ("iucv_sever: found a path to remove from"
+				  "table\n");
+			pr_debug ("iucv_sever: removing %d \n",
+				  (int) (*users_pathid)); *users_pathid = NULL;
+
+			memset (users_hte, 0, sizeof (handler_table_entry));
+		}
+	spin_unlock_irqrestore (&iucv_lock, flags);
+	return;
 }
 
-/******************************************************************/
-/* Name: top_half_handler                                         */
-/* Purpose: handle minimum amount of interrupt in fastest time    */
-/*  possible and then pass interrupt to bottom half handler.      */
-/* Input: external interrupt buffer                               */
-/* Output: void                                                   */
-/******************************************************************/
+/*
+ * Interrupt Handling Functions
+ * 	top_half_interrupt
+ * 	bottom_half_interrupt
+ * 	do_int
+ */
+
+/*
+ * Name: top_half_interrupt                                         
+ * Purpose: Handles interrupts coming in from CP.  Places the interrupt on a queue and  
+ * 	    calls bottom_half_interrupt          
+ * Input: external interrupt buffer                                
+ * Output: void                                                    
+ */
 
 inline void
 top_half_interrupt (struct pt_regs *regs, __u16 code)
 {
 	iucv_packet *pkt;
-	pkt = (iucv_packet *) kmalloc
-	    (sizeof (iucv_packet), GFP_ATOMIC);
+	int cpu = smp_processor_id();
+
+	irq_enter(cpu, 0x4000);
+
+	pkt = (iucv_packet *) kmalloc (sizeof (iucv_packet), GFP_ATOMIC);
 	if (pkt == NULL) {
-		printk (KERN_DEBUG "out of memory\n");
+		printk (KERN_WARNING
+			"iucv:top_half_interrupt: out of memory\n");
+		irq_exit(cpu, 0x4000);
 		return;
 	}
-	memcpy (pkt->data, iucv_external_int_buffer, 40);
-#ifdef DEBUG3
-printk (KERN_EMERG "TH: Got INT: %08x\n", *(int *)(pkt->data+4));
-#endif
+
+	memcpy (pkt->data, iucv_external_int_buffer, BUFFER_SIZE);
+
+	pr_debug ("TH: Got INT: %08x\n", *(int *) (pkt->data + 4));
+
 	/* put new packet on the list */
 	spin_lock (&iucv_packets_lock);
 	pkt->next = NULL;
+
 	if (iucv_packets_tail != NULL)
 		iucv_packets_tail->next = pkt;
 	else
 		iucv_packets_head = pkt;
+
 	iucv_packets_tail = pkt;
 	spin_unlock (&iucv_packets_lock);
 
 	if (atomic_compare_and_swap (0, 1, &bh_scheduled) == 0) {
-#ifdef DEBUG3
-printk (KERN_EMERG "TH: Queuing BH\n");
-#endif
-		INIT_LIST_HEAD(&short_task.list);
-		short_task.sync = 0;
 		short_task.routine = (void *) bottom_half_interrupt;
 		queue_task (&short_task, &tq_immediate);
 		mark_bh (IMMEDIATE_BH);
 	}
+	irq_exit(cpu, 0x4000);
 	return;
 }
 
-/*******************************************************************/
-/* Name: bottom_half_interrupt                                     */
-/* Purpose: Handle interrupt at a more safer time                  */
-/* Input: void                                                     */
-/* Output: void                                                    */
-/*******************************************************************/
+/*
+ * Name: bottom_half_interrupt                                      
+ * Purpose: Handle interrupt at a more safer time                  
+ * Input: void                                                     
+ * Output: void                                                    
+ */
 void
 bottom_half_interrupt (void)
 {
 	iucv_packet *iucv_packet_list;
 	iucv_packet *tmp;
 	ulong flags;
-
 	atomic_set (&bh_scheduled, 0);
+
 	spin_lock_irqsave (&iucv_packets_lock, flags);
 	iucv_packet_list = iucv_packets_head;
 	iucv_packets_head = iucv_packets_tail = NULL;
 	spin_unlock_irqrestore (&iucv_packets_lock, flags);
 
 	/* now process all the request in the iucv_packet_list */
-#ifdef DEBUG3
-	printk (KERN_EMERG "BH: Process all packets\n");
-#endif
+	pr_debug ("BH: Process all packets\n");
 	while (iucv_packet_list != NULL) {
-#ifdef DEBUG3
-		printk( KERN_EMERG "BH:>  %08x\n", 
-			*(int *)(iucv_packet_list->data+4));
-#endif
-		do_int ((iucv_ConnectionPending *) iucv_packet_list->data);
-#ifdef DEBUG3
-		printk( KERN_EMERG "BH:<  %08x\n",
-			*(int *)(iucv_packet_list->data+4));
-#endif
+		pr_debug ("BH:>  %08x\n",
+			  *(int *) (iucv_packet_list->data + 4));
+
+		do_int ((iucv_GeneralInterrupt *) iucv_packet_list->data);
+
+		pr_debug ("BH:<  %08x\n",
+			  *(int *) (iucv_packet_list->data + 4));
 		tmp = iucv_packet_list;
 		iucv_packet_list = iucv_packet_list->next;
 		kfree (tmp);
 	}
-#ifdef DEBUG3
-	printk (KERN_EMERG "BH: Done\n");
-#endif
+	pr_debug ("BH: Done\n");
 	return;
 }
-/*******************************************************************/
-/* Name: do_int                                                    */
-/* Purpose: Handle interrupt in a more safe environment            */
-/* Inuput: int_buf - pointer to copy of external interrupt buffer  */
-/* Output: void                                                    */
-/*******************************************************************/
+
+/*
+ * Name: do_int                                                     
+ * Purpose: Handles the interrupts in a more safe environment             
+ * Input: int_buf - pointer to copy of external interrupt buffer  
+ * Output: void                                                     
+ */
 void
-do_int (iucv_ConnectionPending * int_buf)
+do_int (iucv_GeneralInterrupt * int_buf)
 {
-	ulong index1 = 0, index2 = 0;
-	handler_table_entry *P = 0;	/* P is a pointer */
-	handler *Q = 0, *R;	/* Q and R are pointers */
+	handler_table_entry *P = 0;
+	ulong flags;
+	handler *Q = 0, *R;
 	iucv_interrupt_ops_t *interrupt = 0;	/* interrupt addresses */
 	uchar temp_buff1[24], temp_buff2[24];	/* masked handler id. */
 	int add_pathid_result = 0, j = 0;
 	uchar no_listener[16] = "NO LISTENER";
-#ifdef DEBUG
-	int i;
-	uchar *prt_parm;
-#endif
-#ifdef DEBUG3
-	printk (KERN_DEBUG "BH:-  Entered do_int "
-	                   "pathid %d, type %02X\n",
-		int_buf->ippathid, int_buf->iptype);
-#endif
-#ifdef DEBUG
-	prt_parm = (uchar *) (int_buf);
-	printk (KERN_DEBUG "External Interrupt Buffer\n");
-	for (i = 0; i < 40; i++)
-		printk (KERN_DEBUG "%02x ", prt_parm[i]);
-	printk (KERN_DEBUG "\n");
-#endif
+
+	pr_debug ("IUCV: BHI: -  Entered do_int "
+		  "pathid %d, type %02X\n", int_buf->ippathid, int_buf->iptype);
+	pr_debug ("BHI:External Interrupt Buffer\n");
+	iucv_dumpit ((uchar *) int_buf, sizeof (iucv_GeneralInterrupt));
+
 	ASCEBC (no_listener, 16);
 	if (int_buf->iptype != 01) {
-		index1 = ((ulong) (int_buf->ippathid)) / 512;
-		index2 = ((ulong) (int_buf->ippathid)) % 512;
-		spin_lock (&lock);
-
-		P = main_table[index1];
-		Q = (P + index2)->addrs;
-		interrupt = Q->interrupt_table;	/* interrupt functions */
-		spin_unlock (&lock);
-#ifdef DEBUG
-		printk (KERN_DEBUG "Handler is: \n");
-		prt_parm = (uchar *) Q;
-		for (i = 0; i < sizeof (handler); i++)
-			printk (KERN_DEBUG " %02x ", prt_parm[i]);
-		printk (KERN_DEBUG "\n");
-#endif
-	}			/* end of if statement */
+		spin_lock_irqsave (&iucv_lock, flags);
+		P = handler_table_anchor + int_buf->ippathid;
+		Q = P->addrs;
+		interrupt = P->ops;	/* interrupt functions */
+
+		pr_debug ("iucv: do_int: Handler\n");
+		iucv_dumpit ((uchar *) Q, sizeof (handler));
+		spin_unlock_irqrestore (&iucv_lock, flags);
+	}
+	/* end of if statement */
 	switch (int_buf->iptype) {
 	case 0x01:		/* connection pending */
-		spin_lock (&lock);
+		spin_lock_irqsave (&iucv_lock, flags);
 		for (R = handler_anchor; R != NULL; R = (handler *) R->next) {
 			memcpy (temp_buff1, &(int_buf->ipvmid), 24);
-			memcpy (temp_buff2, &(R->vmid), 24);
+			memcpy (temp_buff2, &(R->id.userid), 24);
 			for (j = 0; j < 24; j++) {
-				temp_buff1[j] = (temp_buff1[j]) & (R->mask)[j];
-				temp_buff2[j] = (temp_buff2[j]) & (R->mask)[j];
+				temp_buff1[j] =
+				    (temp_buff1[j]) & (R->id.mask)[j];
+				temp_buff2[j] =
+				    (temp_buff2[j]) & (R->id.mask)[j];
 			}
-#ifdef DEBUG
-			for (i = 0; i < sizeof (temp_buff1); i++)
-				printk (KERN_DEBUG " %c ", temp_buff1[i]);
-			printk (KERN_DEBUG "\n");
-			for (i = 0; i < sizeof (temp_buff2); i++)
-				printk (KERN_DEBUG " %c ", temp_buff2[i]);
-			printk (KERN_DEBUG "\n");
-#endif
-			if (memcmp((void *) temp_buff1,
-				   (void *) temp_buff2, 24) == 0) {
-#ifdef DEBUG
-				printk (KERN_DEBUG
-					"found a matching handler\n");
-#endif
+
+			pr_debug ("iucv:do_int: temp_buff1\n");
+			iucv_dumpit (temp_buff1, sizeof (temp_buff1));
+			pr_debug ("iucv:do_int: temp_buff2\n");
+			iucv_dumpit (temp_buff2, sizeof (temp_buff2));
+
+			if (memcmp ((void *) temp_buff1,
+				    (void *) temp_buff2, 24) == 0) {
+
+				pr_debug
+				    ("iucv:do_int: found a matching handler\n");
 				break;
 			}
 		}
-		spin_unlock (&lock);
+		spin_unlock_irqrestore (&iucv_lock, flags);
+
 		if (R) {
 			/* ADD PATH TO PATHID TABLE */
-			add_pathid_result =
-			    add_pathid (int_buf->ippathid, R, R->pgm_data);
+			add_pathid_result = iucv_add_pathid (int_buf->ippathid,
+							     R, R->pgm_data);
 			if (add_pathid_result == NULL) {
 				interrupt = R->interrupt_table;
-				if ((*interrupt).ConnectionPending) {
+				if (interrupt->ConnectionPending) {
+
 					EBCASC (int_buf->ipvmid, 8);
-					
-					    ((*interrupt).
-					 ConnectionPending) (int_buf,
-							     R->pgm_data);
+
+					(interrupt->ConnectionPending)
+					    ((iucv_ConnectionPending *) int_buf,
+					     (R->pgm_data));
 				} else {
 					iucv_sever (int_buf->ippathid,
 						    no_listener);
 				}
-			} /* end if if(add_p...... */
+			} /* end of if(add_p...... */
 			else {
 				iucv_sever (int_buf->ippathid, no_listener);
-#ifdef DEBUG
-				printk (KERN_DEBUG
-					"add_pathid failed with rc = %d\n",
-					(int) add_pathid_result);
-#endif
+				pr_debug ("iucv:do_int:add_pathid failed"
+					  "with rc = %d\n",
+					  (int) add_pathid_result);
 			}
 		} else
 			iucv_sever (int_buf->ippathid, no_listener);
 		break;
+
 	case 0x02:		/*connection complete */
 		if (Q) {
-			if ((*interrupt).ConnectionComplete)
-				((*interrupt).ConnectionComplete)
-				    
-				    ((iucv_ConnectionComplete *) int_buf,
-				     (P + index2)->pgm_data);
-			else {
-#ifdef DEBUG
-				printk (KERN_DEBUG
-					"ConnectionComplete not called\n");
-				printk (KERN_DEBUG "routine@ is %p\n",
-					(*interrupt).ConnectionComplete);
-#endif
-			}
+			if (interrupt->ConnectionComplete)
+				(interrupt->ConnectionComplete)
+				    ((iucv_ConnectionComplete *) int_buf, (P->pgm_data));
+			else
+				pr_debug ("iucv:do_int:"
+					  "ConnectionComplete not called\n");
 		}
+		
 		break;
+
 	case 0x03:		/* connection severed */
 		if (Q) {
-			if ((*interrupt).ConnectionSevered)
-				((*interrupt).ConnectionSevered)
-				    
+			if (interrupt->ConnectionSevered)
+				(interrupt->ConnectionSevered)
 				    ((iucv_ConnectionSevered *) int_buf,
-				     (P + index2)->pgm_data);
+				     (P->pgm_data));
+
 			else
 				iucv_sever (int_buf->ippathid, no_listener);
 		} else
 			iucv_sever (int_buf->ippathid, no_listener);
 		break;
+
 	case 0x04:		/* connection quiesced */
 		if (Q) {
-			if ((*interrupt).ConnectionQuiesced)
-				((*interrupt).ConnectionQuiesced)
-				    
+			if (interrupt->ConnectionQuiesced)
+				(interrupt->ConnectionQuiesced)
 				    ((iucv_ConnectionQuiesced *) int_buf,
-				     (P + index2)->pgm_data);
-			else {
-#ifdef DEBUG
-				printk (KERN_DEBUG
-					"ConnectionQuiesced not called\n");
-				printk (KERN_DEBUG "routine@ is %p\n",
-					(*interrupt).ConnectionQuiesced);
-#endif
-			}
+				     (P->pgm_data));
+			else
+				pr_debug ("iucv:do_int:"
+					  "ConnectionQuiesced not called\n");
 		}
 		break;
+
 	case 0x05:		/* connection resumed */
 		if (Q) {
-			if ((*interrupt).ConnectionResumed)
-				((*interrupt).ConnectionResumed)
-				    
-				    ((iucv_ConnectionResumed *) int_buf,
-				     (P + index2)->pgm_data);
-			else {
-#ifdef DEBUG
-				printk (KERN_DEBUG
-					"ConnectionResumed not called\n");
-				printk (KERN_DEBUG "routine@ is %p\n",
-					(*interrupt).ConnectionResumed);
-#endif
-			}
+			if (interrupt->ConnectionResumed)
+				(interrupt->ConnectionResumed)
+				    ((iucv_ConnectionResumed *) int_buf, (P->pgm_data));
+			else
+				pr_debug ("iucv:do_int:"
+					  "ConnectionResumed not called\n");
 		}
 		break;
+
 	case 0x06:		/* priority message complete */
 	case 0x07:		/* nonpriority message complete */
 		if (Q) {
-			if ((*interrupt).MessageComplete)
-				((*interrupt).MessageComplete)
-				    
-				    ((iucv_MessageComplete *) int_buf,
-				     (P + index2)->pgm_data);
-			else {
-#ifdef DEBUG
-				printk (KERN_DEBUG
-					"MessageComplete not called\n");
-				printk (KERN_DEBUG "routine@ is %p\n",
-					(*interrupt).MessageComplete);
-#endif
-			}
+			if (interrupt->MessageComplete)
+				(interrupt->MessageComplete)
+				    ((iucv_MessageComplete *) int_buf, (P->pgm_data));
+			else
+				pr_debug ("iucv:do_int:"
+					  "MessageComplete not called\n");
 		}
 		break;
+
 	case 0x08:		/* priority message pending  */
 	case 0x09:		/* nonpriority message pending  */
 		if (Q) {
-			if ((*interrupt).MessagePending)
-				((*interrupt).MessagePending)
-				    
-				    ((iucv_MessagePending *) int_buf,
-				     (P + index2)->pgm_data);
-			else {
-#ifdef DEBUG
-				printk (KERN_DEBUG
-					"MessagePending not called\n");
-				printk (KERN_DEBUG "routine@ is %p\n",
-					(*interrupt).MessagePending);
-#endif
-			}
+			if (interrupt->MessagePending)
+				(interrupt->MessagePending)
+				    ((iucv_MessagePending *) int_buf, (P->pgm_data));
+			else
+				pr_debug ("iucv:do_int:"
+					  "MessagePending not called\n");
 		}
 		break;
 	default:		/* unknown iucv type */
-		printk (KERN_DEBUG "unknown iucv interrupt \n");
+		printk (KERN_WARNING "iucv:do_int: unknown iucv interrupt \n");
 		break;
 	}			/* end switch */
-#ifdef DEBUG3
-	printk (KERN_DEBUG "BH:-  Exiting do_int "
-	                   "pathid %d, type %02X\n",
-		int_buf->ippathid, int_buf->iptype);
-#endif
-	return;
-}				/* end of function call */
 
-/**************************************************************/
-/* Name: iucv_register_program                                */
-/* Purpose: registers a new handler                           */
-/* Input: pgmname- uchar[16], user id                         */
-/*        userid - uchar[8], machine id                       */
-/*        prmmask- mask                                       */
-/*        ops    - pointer to iucv_interrupt_ops buffer       */
-/* Output: new_handler - address of new handler               */
-/**************************************************************/
-iucv_handle_t
-iucv_register_program (uchar pgmname[16],
-		       uchar userid[8],
-		       uchar pgmmask[24],
-		       iucv_interrupt_ops_t * ops, ulong pgm_data)
-{
-	int rc;
-	handler *new_handler = 0;
-#ifdef DEBUG
-	int i;
-	uchar *prt_parm;
-	printk (KERN_DEBUG "enter iucv_register_program\n");
-#endif
-	my_ops = *ops;
-	/* Allocate handler table */
-	new_handler = (handler *) kmalloc (sizeof (handler), GFP_KERNEL);
-	if (new_handler == NULL) {
-#ifdef DEBUG
-		printk (KERN_DEBUG
-			"IUCV: returned NULL address for new handle \n");
-#endif
-		return NULL;
-	}
-	/* fill in handler table */
-	memcpy (new_handler->user_data, pgmname, 16);
-	memcpy (new_handler->vmid, userid, 8);
-	memcpy (new_handler->mask, pgmmask, 24);
-	new_handler->pgm_data = pgm_data;
-	/* Convert from ASCII to EBCDIC */
-	if (new_handler->vmid) {
-		ASCEBC (new_handler->vmid, 8);
-		EBC_TOUPPER(new_handler->vmid, 8);
-	}
-	/* fill in handler table */
-	new_handler->interrupt_table = ops;
-	new_handler->size = ADDED_STOR;
-	/* Allocate storage for pathid table */
-	new_handler->start = kmalloc (ADDED_STOR * sizeof (ulong), GFP_KERNEL);
-	if (new_handler->start == NULL) {
-#ifdef DEBUG
-		printk (KERN_DEBUG
-			"IUCV: returned NULL address for pathid table,"
-			" exiting\n");
-#endif
-		kfree(new_handler);
-		return NULL;
-	}
-	memset (new_handler->start, 0, ADDED_STOR * sizeof (ulong));
-	new_handler->end = (*new_handler).start + ADDED_STOR;
-	new_handler->next = 0;
-	new_handler->prev = 0;
-	/* Place handler at beginning of chain */
-	spin_lock (&lock);
-	if (handler_anchor == NULL)
-		handler_anchor = new_handler;
-	else {
-		handler_anchor->prev = (ulong *) new_handler;
-		new_handler->next = (ulong *) handler_anchor;
-		handler_anchor = new_handler;
-#ifdef DEBUG
-		printk (KERN_DEBUG "adding a another handler to list\n");
-		printk (KERN_DEBUG "handler_anchor->prev is %p \n",
-			handler_anchor->prev);
-		printk (KERN_DEBUG "new_handler->next is %p \n",
-			new_handler->next);
-		printk (KERN_DEBUG "handler_anchor is %p \n", handler_anchor);
-#endif
-	}
-	spin_unlock (&lock);
-	if (declare_flag == NULL) {
-		rc = iucv_declare_buffer (iucv_external_int_buffer);
-		if (rc == 0) {
-			declare_flag = 1;
-			/* request the 0x4000 external interrupt */
-			rc =
-			    register_external_interrupt (0x4000,
-							 top_half_interrupt);
-		} else {
-			panic ("Registration failed");
-#ifdef DEBUG
-			printk (KERN_DEBUG "rc from declare buffer is: %i\n",
-				rc);
-#endif
-		}
-	}
-#ifdef DEBUG
-	printk (KERN_DEBUG "address of handle is %p ", new_handler);
-	printk (KERN_DEBUG "size of handle is %d ", (int) (sizeof (handler)));
-	printk (KERN_DEBUG "exit iucv_register_program\n");
-	printk (KERN_DEBUG "main_table is %p \n", main_table);
-	printk (KERN_DEBUG "handler_anchor is %p \n", handler_anchor);
-	printk (KERN_DEBUG "Handler is: \n");
-	prt_parm = (uchar *) new_handler;
-	for (i = 0; i < sizeof (handler); i++)
-		printk (KERN_DEBUG " %02x ", prt_parm[i]);
-	printk (KERN_DEBUG "\n");
-#endif
-	return new_handler;	/* send buffer address back */
-}				/* end of register function */
+	pr_debug ("BH:-  Exiting do_int "
+		  "pathid %d, type %02X\n", int_buf->ippathid, int_buf->iptype);
 
-/**************************************************************/
-/* Name: iucv_unregister                                      */
-/* Purpose: remove handler from chain and sever all paths     */
-/* Input: handle - address of handler to be severed           */
-/* Output: returns 0                                          */
-/**************************************************************/
-int
-iucv_unregister (iucv_handle_t handle)
-{
-	handler *temp_next = 0, *temp_prev = 0;
-	handler *Q = 0, *R;
-	handler_table_entry *H_T_E = 0;
-	ulong *S = 0;		/*points to the beginning of block of h_t_e's*/
-#ifdef DEBUG
-	printk (KERN_DEBUG "enter iucv_unregister\n");
-	printk (KERN_DEBUG "address of handle is %p ", handle);
-	printk (KERN_DEBUG "size of handle is %u ", (int) (sizeof (handle)));
-#endif
-	spin_lock (&lock);
-	Q = (handler *) handle;
-	/*
-	 * Checking if handle is still registered: if yes, continue
-	 *  if not registered, return.
-	 */
-	for (R = handler_anchor; R != NULL; R = (handler *) R->next)
-		if (Q == R) {
-#ifdef DEBUG
-			printk (KERN_DEBUG "found a matching handler\n");
-#endif
-			break;
-		}
-	if (!R) {
-		spin_unlock (&lock);
-		return (0);
-	}
-	S = Q->start;
-#ifdef DEBUG
-	printk (KERN_DEBUG "Q is handle? %p ", Q);
-	printk (KERN_DEBUG "Q->start is %p ", Q->start);
-	printk (KERN_DEBUG "&(Q->start) is %p ", &(Q->start));
-	printk (KERN_DEBUG "Q->end is %p ", Q->end);
-	printk (KERN_DEBUG "&(Q->end) is %p ", &(Q->end));
-#endif
-	while (S < (Q->end)) {	/* index thru table */
-		if (*S) {
-			H_T_E = (handler_table_entry *) (*S);
-#ifdef DEBUG
-			printk (KERN_DEBUG "Pointer to H_T_E is %p ", H_T_E);
-			printk (KERN_DEBUG "Address of handle in H_T_E is %p",
-				(H_T_E->addrs));
-#endif
-			if ((H_T_E->addrs) != handle) {
-				spin_unlock (&lock);
-				return (-2);	/*handler addresses don't match */
-			} else {
-				spin_unlock (&lock);
-				iucv_sever (H_T_E->pathid, Q->user_data);
-				spin_lock (&lock);
-			}
-		}
-		S++;		/* index by size of ulong */
-	}
-	kfree (Q->start);
-	temp_next = (handler *) Q->next;	/* address of next handler on list */
-	temp_prev = (handler *) Q->prev;	/* address of prev handler on list */
-	if ((temp_next != NULL) & (temp_prev != NULL)) {
-		(*temp_next).prev = (ulong *) temp_prev;
-		(*temp_prev).next = (ulong *) temp_next;
-	} else if ((temp_next != NULL) & (temp_prev == NULL)) {
-		(*temp_next).prev = NULL;
-		handler_anchor = temp_next;
-	} else if ((temp_next == NULL) & (temp_prev != NULL))
-		(*temp_prev).next = NULL;
-	else
-		handler_anchor = NULL;
-	if (handler_anchor == NULL)
-		iucv_retrieve_buffer ();
-	kfree (handle);
-	spin_unlock (&lock);
-#ifdef DEBUG
-	printk (KERN_DEBUG "exit iucv_unregister\n");
-#endif
-	return 0;
+	return;
 }
+/* end of function call */
 
 EXPORT_SYMBOL (iucv_accept);
 EXPORT_SYMBOL (iucv_connect);
 EXPORT_SYMBOL (iucv_purge);
-EXPORT_SYMBOL (iucv_query);
+EXPORT_SYMBOL (iucv_query_maxconn);
+EXPORT_SYMBOL (iucv_query_bufsize);
 EXPORT_SYMBOL (iucv_quiesce);
 EXPORT_SYMBOL (iucv_receive);
-EXPORT_SYMBOL (iucv_receive_simple);
 EXPORT_SYMBOL (iucv_receive_array);
 EXPORT_SYMBOL (iucv_reject);
 EXPORT_SYMBOL (iucv_reply);
@@ -2040,5 +2436,4 @@
 EXPORT_SYMBOL (iucv_setmask);
 EXPORT_SYMBOL (iucv_sever);
 EXPORT_SYMBOL (iucv_register_program);
-EXPORT_SYMBOL (iucv_unregister);
-
+EXPORT_SYMBOL (iucv_unregister_program);
diff -u --recursive --new-file v2.4.7/linux/drivers/s390/net/iucv.h linux/drivers/s390/net/iucv.h
--- v2.4.7/linux/drivers/s390/net/iucv.h	Tue Feb 13 14:13:44 2001
+++ linux/drivers/s390/net/iucv.h	Wed Jul 25 14:12:02 2001
@@ -1,353 +1,754 @@
 /*
- *  drivers/s390/net/netiucv.h
+ *  drivers/s390/net/iucv.h
  *    IUCV base support.
  *
  *  S390 version
  *    Copyright (C) 2000 IBM Corporation
- *    Author(s): Xenia Tkatschow (xenia@us.ibm.com)
+ *    Author(s):Alan Altmark (Alan_Altmark@us.ibm.com) 
+ *		Xenia Tkatschow (xenia@us.ibm.com)
  *
  *
+ * Linux Kernel IUCV will not support a machine with storage > 2 GB. 
+ *
  * Functionality:
  * To explore any of the IUCV functions, one must first register
- * their program using iucv_register(). Once your program has
- * successfully completed a register, it can use the other functions.
+ * their program using iucv_register_program(). Once your program has
+ * successfully completed a register, it can exploit the other functions.
  * For furthur reference on all IUCV functionality, refer to the
  * CP Programming Services book, also available on the web
- * thru www.ibm.com/s390/vm.
+ * thru www.ibm.com/s390/vm/pubs, manual # SC24-5760
+ *
+ *      Definition of Return Codes                                    
+ *      -All positive return codes including zero are reflected back  
+ *       from CP except for iucv_register_program. The definition of each 
+ *       return code can be found in CP Programming Services book.    
+ *       Also available on the web thru www.ibm.com/s390/vm/pubs, manual # SC24-5760          
+ *      - Return Code of:         
+ *             (-EINVAL) Invalid value       
+ *             (-ENOMEM) storage allocation failed              
+ *	pgmask defined in iucv_register_program will be set depending on input
+ *	paramters. 
+ *	
  */
-#ifndef _IUCV_H
-#define _IUCV_H
+
+#include <linux/types.h>
 #define uchar  unsigned char
 #define ushort unsigned short
 #define ulong  unsigned long
 #define iucv_handle_t void *
-/***********************FLAGS*************************************/
-#define  source_class   0x01
-#define  target_class   0x01
-#define  local_conn     0x01
-#define  specify_pathid 0x02
-#define  specify_msgid  0x04
-#define  reply_array    0x08
-#define  one_way_msg    0x10
-#define  prior_msg      0x20
-#define  array          0x40
-#define  quiesce_msg    0x40
-#define  parm_data      0x80
-#define  IPRMDATA	 0x80
-#define  IPBUFLST	 0x40
-#define  IPPRTY	 0x20
-#define  IPNORPY	 0x10
-#define  IPANSLST	 0x08
-#define  IPFGMID	 0x04
-#define  IPFGPID	 0x02
-#define  IPFGMCL	 0x01
-
-/*---------------------------------------------------------*/
-/* Mapping of external interrupt buffers                   */
-/* Names: iucv_ConnectionPending    ->  connection pending */
-/*        iucv_ConnectionComplete   ->  connection complete */
-/*        iucv_ConnectionSevered    ->  connection severed */
-/*        iucv_ConnectionQuiesced   ->  connection quiesced */
-/*        iucv_ConnectionResumed    ->  connection resumed */
-/*        iucv_MessagePending       ->  message pending    */
-/*        iucv_MessageComplete      ->  message complete   */
-/*---------------------------------------------------------*/
+
+/* flags1:
+ * All flags are defined in the field IPFLAGS1 of each function   
+ * and can be found in CP Programming Services.                  
+ * IPLOCAL  - Indicates the connect can only be satisfied on the 
+ *            local system                                       
+ * IPPRTY   - Indicates a priority message                       
+ * IPQUSCE  - Indicates you do not want to receive messages on a 
+ *            path until an iucv_resume is issued                
+ * IPRMDATA - Indicates that the message is in the parameter list
+ */
+#define IPLOCAL   	0x01
+#define IPPRTY         	0x20
+#define IPQUSCE        	0x40
+#define IPRMDATA       	0x80
+
+/* flags1_out:
+ * All flags are defined in the output field of IPFLAGS1 for each function
+ * and can be found in CP Programming Services.
+ * IPNORPY - Specifies this is a one-way message and no reply is expected.
+ * IPPRTY   - Indicates a priority message is permitted. Defined in flags1.
+ */
+#define IPNORPY         0x10
+
+#define Nonpriority_MessagePendingInterruptsFlag         0x80
+#define Priority_MessagePendingInterruptsFlag            0x40
+#define Nonpriority_MessageCompletionInterruptsFlag      0x20
+#define Priority_MessageCompletionInterruptsFlag         0x10
+/*
+ * Mapping of external interrupt buffers should be used with the corresponding
+ * interrupt types.                  
+ * Names: iucv_ConnectionPending    ->  connection pending 
+ *        iucv_ConnectionComplete   ->  connection complete
+ *        iucv_ConnectionSevered    ->  connection severed 
+ *        iucv_ConnectionQuiesced   ->  connection quiesced 
+ *        iucv_ConnectionResumed    ->  connection resumed 
+ *        iucv_MessagePending       ->  message pending    
+ *        iucv_MessageComplete      ->  message complete   
+ */
 typedef struct {
-	ushort ippathid;
+	u16 ippathid;
 	uchar ipflags1;
 	uchar iptype;
-	ushort ipmsglim;
-	ushort res1;
+	u16 ipmsglim;
+	u16 res1;
 	uchar ipvmid[8];
 	uchar ipuser[16];
-	ulong res3;
+	u32 res3;
 	uchar ippollfg;
 	uchar res4[3];
 } iucv_ConnectionPending;
 
 typedef struct {
-	ushort ippathid;
+	u16 ippathid;
 	uchar ipflags1;
 	uchar iptype;
-	ushort ipmsglim;
-	ushort res1;
+	u16 ipmsglim;
+	u16 res1;
 	uchar res2[8];
 	uchar ipuser[16];
-	ulong res3;
+	u32 res3;
 	uchar ippollfg;
 	uchar res4[3];
 } iucv_ConnectionComplete;
 
 typedef struct {
-	ushort ippathid;
+	u16 ippathid;
 	uchar res1;
 	uchar iptype;
-	ulong res2;
+	u32 res2;
 	uchar res3[8];
 	uchar ipuser[16];
-	ulong res4;
+	u32 res4;
 	uchar ippollfg;
 	uchar res5[3];
 } iucv_ConnectionSevered;
 
 typedef struct {
-	ushort ippathid;
+	u16 ippathid;
 	uchar res1;
 	uchar iptype;
-	ulong res2;
+	u32 res2;
 	uchar res3[8];
 	uchar ipuser[16];
-	ulong res4;
+	u32 res4;
 	uchar ippollfg;
 	uchar res5[3];
 } iucv_ConnectionQuiesced;
 
 typedef struct {
-	ushort ippathid;
+	u16 ippathid;
 	uchar res1;
 	uchar iptype;
-	ulong res2;
+	u32 res2;
 	uchar res3[8];
 	uchar ipuser[16];
-	ulong res4;
+	u32 res4;
 	uchar ippollfg;
 	uchar res5[3];
 } iucv_ConnectionResumed;
 
 typedef struct {
-	ushort ippathid;
+	u16 ippathid;
 	uchar ipflags1;
 	uchar iptype;
-	ulong ipmsgid;
-	ulong iptrgcls;
-	ulong iprmmsg1;
+	u32 ipmsgid;
+	u32 iptrgcls;
+	uchar iprmmsg1[4];
 	union u1 {
-		ulong ipbfln1f;
-		ulong iprmmsg2;
+		u32 ipbfln1f;
+		uchar iprmmsg2[4];
 	} ln1msg2;
-	ulong res1[3];
-	ulong ipbfln2f;
+	u32 res1[3];
+	u32 ipbfln2f;
 	uchar ippollfg;
 	uchar res2[3];
 } iucv_MessagePending;
 
 typedef struct {
-	ushort ippathid;
+	u16 ippathid;
 	uchar ipflags1;
 	uchar iptype;
-	ulong ipmsgid;
-	ulong ipaudit;
-	ulong iprmmsg1;
-	ulong iprmmsg2;
-	ulong ipsrccls;
-	ulong ipmsgtag;
-	ulong res;
-	ulong ipbfln2f;
+	u32 ipmsgid;
+	u32 ipaudit;
+	uchar iprmmsg[8];
+	u32 ipsrccls;
+	u32 ipmsgtag;
+	u32 res;
+	u32 ipbfln2f;
 	uchar ippollfg;
 	uchar res2[3];
 } iucv_MessageComplete;
 
-/************************structures*************************/
-/*---------------------------------------------------------*/
-/*iucv_interrupt_ops_t: List of functions for interrupt    */
-/* handling.                                               */
-/*---------------------------------------------------------*/
-
+/* 
+ * iucv_interrupt_ops_t: Is a vector of functions that handle 
+ * IUCV interrupts.                                          
+ * Parameter list:                                           
+ *         eib - is a pointer to a 40-byte area described    
+ *               with one of the structures above.           
+ *         pgm_data - this data is strictly for the          
+ *                    interrupt handler that is passed by    
+ *                    the application. This may be an address 
+ *                    or token.                              
+*/
 typedef struct {
 	void (*ConnectionPending) (iucv_ConnectionPending * eib,
-				   ulong pgm_data);
+				   void *pgm_data);
 	void (*ConnectionComplete) (iucv_ConnectionComplete * eib,
-				    ulong pgm_data);
+				    void *pgm_data);
 	void (*ConnectionSevered) (iucv_ConnectionSevered * eib,
-				   ulong pgm_data);
+				   void *pgm_data);
 	void (*ConnectionQuiesced) (iucv_ConnectionQuiesced * eib,
-				    ulong pgm_data);
+				    void *pgm_data);
 	void (*ConnectionResumed) (iucv_ConnectionResumed * eib,
-				   ulong pgm_data);
-	void (*MessagePending) (iucv_MessagePending * eib,
-				ulong pgm_data);
-	void (*MessageComplete) (iucv_MessageComplete * eib,
-				 ulong pgm_data);
+				   void *pgm_data);
+	void (*MessagePending) (iucv_MessagePending * eib, void *pgm_data);
+	void (*MessageComplete) (iucv_MessageComplete * eib, void *pgm_data);
 } iucv_interrupt_ops_t;
 
-/*---------------------------------------------------------*/
-/*iucv_array_t : Defines buffer array                      */
-/*---------------------------------------------------------*/
-
+/*
+ *iucv_array_t : Defines buffer array.                      
+ * Inside the array may be 31- bit addresses and 31-bit lengths. 
+*/
 typedef struct {
-	void *address;
-	int length;
+	u32 address;
+	u32 length;
 } iucv_array_t __attribute__ ((aligned (8)));
 
-/*************************-prototypes-******************************/
-
+/*   -prototypes-    */
+/*                                                                
+ * Name: iucv_register_program                                    
+ * Purpose: Registers an application with IUCV                    
+ * Input: prmname - user identification                           
+ *        userid  - machine identification
+ *        pgmmask - indicates which bits in the prmname and userid combined will be
+ *  		    used to determine who is given control
+ *        ops     - address of vector of interrupt handlers       
+ *        pgm_data- application data passed to interrupt handlers 
+ * Output: NA                                                     
+ * Return: address of handler                                     
+ *         (0) - Error occured, registration not completed.
+ * NOTE: Exact cause of failure will be recorded in syslog.                        
+*/
 iucv_handle_t iucv_register_program (uchar pgmname[16],
 				     uchar userid[8],
 				     uchar pgmmask[24],
 				     iucv_interrupt_ops_t * ops,
-				     ulong pgm_data);
-
-int iucv_unregister (iucv_handle_t handle);
-
-int iucv_purge (ulong msgid,
-		ushort pathid,
-		ulong srccls,
-		uchar audit[4]);
-
-void iucv_query (ulong * bufsize,
-		 ulong * conmax);
+				     void *pgm_data);
 
-int iucv_quiesce (ushort pathid,
-		  uchar user_data[16]);
+/*                                                
+ * Name: iucv_unregister_program                  
+ * Purpose: Unregister application with IUCV      
+ * Input: address of handler                      
+ * Output: NA                                     
+ * Return: (0) - Normal return                    
+ *         (-EINVAL) - Internal error, wild pointer     
+*/
+int iucv_unregister_program (iucv_handle_t handle);
+
+/*
+ * Name: iucv_accept
+ * Purpose: This function is issued after the user receives a Connection Pending external
+ *          interrupt and now wishes to complete the IUCV communication path.
+ * Input:  pathid - u16 , Path identification number   
+ *         msglim_reqstd - u16, The number of outstanding messages requested.
+ *         user_data - uchar[16], Data specified by the iucv_connect function.
+ *	   flags1 - int, Contains options for this path.
+ *           -IPPRTY   - 0x20- Specifies if you want to send priority message.
+ *           -IPRMDATA - 0x80, Specifies whether your program can handle a message
+ *            	in  the parameter list.
+ *           -IPQUSCE  - 0x40, Specifies whether you want to quiesce the path being
+ *		established.
+ *         handle - iucv_handle_t, Address of handler.
+ *         pgm_data - void *, Application data passed to interrupt handlers.
+ *         flags1_out - int * Contains information about the path
+ *           - IPPRTY - 0x20, Indicates you may send priority messages.
+ *         msglim - *u16, Number of outstanding messages.
+ * Output: return code from CP IUCV call.
+*/
 
-int iucv_resume (ushort pathid,
-		 uchar user_data[16]);
-
-int iucv_reject (ushort pathid,
-		 ulong msgid,
-		 ulong trgcls);
-
-int iucv_setmask (uchar non_priority_interrupts,
-		  uchar priority_interrupts,
-		  uchar non_priority_completion_interrupts,
-		  uchar priority_completion_interrupts);
+int iucv_accept (u16 pathid,
+		 u16 msglim_reqstd,
+		 uchar user_data[16],
+		 int flags1,
+		 iucv_handle_t handle,
+		 void *pgm_data, int *flags1_out, u16 * msglim);
 
-int iucv_connect (ushort * pathid,
-		  ushort msglim,
+/*
+ * Name: iucv_connect                                         
+ * Purpose: This function establishes an IUCV path. Although the connect may complete
+ *	    successfully, you are not able to use the path until you receive an IUCV 
+ *          Connection Complete external interrupt.            
+ * Input: pathid - u16 *, Path identification number          
+ *        msglim_reqstd - u16, Number of outstanding messages requested       
+ *        user_data - uchar[16], 16-byte user data                    
+ *	  userid - uchar[8], User identification
+ *        system_name - uchar[8], 8-byte identifying the system name 
+ *	  flags1 - int, Contains options for this path.
+ *          -IPPRTY -   0x20, Specifies if you want to send priority message.
+ *          -IPRMDATA - 0x80, Specifies whether your program can handle a message
+ *            	 in  the parameter list.
+ *          -IPQUSCE -  0x40, Specifies whether you want to quiesce the path being	 
+ *		established.
+ *          -IPLOCAL -  0X01, Allows an application to force the partner to be on 
+ *		the local system. If local is specified then target class cannot be
+ *		specified.                       
+ *        flags1_out - int * Contains information about the path
+ *           - IPPRTY - 0x20, Indicates you may send priority messages.
+ *        msglim - * u16, Number of outstanding messages
+ *        handle - iucv_handle_t, Address of handler                         
+ *        pgm_data - void *, Application data passed to interrupt handlers              
+ * Output: return code from CP IUCV call
+ *         rc - return code from iucv_declare_buffer
+ *         -EINVAL - Invalid handle passed by application 
+ *         -EINVAL - Pathid address is NULL 
+ *         add_pathid_result - Return code from internal function add_pathid         
+*/
+int
+    iucv_connect (u16 * pathid,
+		  u16 msglim_reqstd,
 		  uchar user_data[16],
 		  uchar userid[8],
 		  uchar system_name[8],
-		  uchar priority_requested,
-		  uchar prmdata,
-		  uchar quiesce,
-		  uchar control,
-		  uchar local,
-		  uchar * priority_permitted,
-		  iucv_handle_t handle,
-		  ulong pgm_data);
-
-int iucv_accept (ushort pathid,
-		 ushort msglim,
-		 uchar user_data[16],
-		 uchar priority_requested,
-		 uchar prmdata,
-		 uchar quiesce,
-		 uchar control,
-		 uchar * priority_permitted,
-		 iucv_handle_t handle,
-		 ulong pgm_data);
-
-int iucv_sever (ushort pathid,
-		uchar user_data[16]);
+		  int flags1,
+		  int *flags1_out,
+		  u16 * msglim, iucv_handle_t handle, void *pgm_data);
+
+/*                                                                     
+ * Name: iucv_purge                                                    
+ * Purpose: This function cancels a message that you have sent.        
+ * Input: pathid - Path identification number.                          
+ *        msgid - Specifies the message ID of the message to be purged.
+ *        srccls - Specifies the source message class.                  
+ * Output: audit - Contains information about asynchronous error       
+ *                 that may have affected the normal completion        
+ *                 of this message.                                    
+ * Return: Return code from CP IUCV call.                           
+*/
+int iucv_purge (u16 pathid, u32 msgid, u32 srccls, uchar audit[3]);
+/*
+ * Name: iucv_query_maxconn
+ * Purpose: This function determines the maximum number of communication paths you
+ *	    may establish.
+ * Return:  maxconn - ulong, Maximum number of connection the virtual machine may
+ *          establish.
+*/
+ulong iucv_query_maxconn (void);
+
+/*
+ * Name: iucv_query_bufsize
+ * Purpose: This function determines how large an external interrupt
+ *          buffer IUCV requires to store information.
+ * Return:  bufsize - ulong, Size of external interrupt buffer.
+ */
+ulong iucv_query_bufsize (void);
 
-int iucv_receive (ushort pathid,
-		  ulong * msgid,
-		  ulong * trgcls,
-		  void *buffer, ulong buflen,
-		  uchar * reply_required,
-		  uchar * priority_msg,
-		  ulong * adds_curr_buffer,
-		  ulong * adds_curr_length);
-
-int iucv_receive_simple (ushort pathid,
-			 ulong msgid,
-			 ulong trgcls,
-			 void *buffer, ulong buflen);
-
-int iucv_receive_array (ushort pathid,
-			ulong * msgid,
-			ulong * trgcls,
+/*                                                                     
+ * Name: iucv_quiesce                                                  
+ * Purpose: This function temporarily suspends incoming messages on an 
+ *          IUCV path. You can later reactivate the path by invoking   
+ *          the iucv_resume function.                                  
+ * Input: pathid - Path identification number                          
+ *        user_data  - 16-bytes of user data                           
+ * Output: NA                                                          
+ * Return: Return code from CP IUCV call.                           
+*/
+int iucv_quiesce (u16 pathid, uchar user_data[16]);
+
+/*                                                                     
+ * Name: iucv_receive                                                  
+ * Purpose: This function receives messages that are being sent to you 
+ *          over established paths. Data will be returned in buffer for length of
+ *          buflen.
+ * Input: 
+ *       pathid - Path identification number.                          
+ *       buffer - Address of buffer to receive.                        
+ *       buflen - Length of buffer to receive.                         
+ *       msgid - Specifies the message ID.          
+ *       trgcls - Specifies target class.                       
+ * Output: 
+ *	 flags1_out: int *, Contains information about this path.
+ *         IPNORPY - 0x10 Specifies this is a one-way message and no reply is
+ *	   expected.      
+ *         IPPRTY  - 0x20 Specifies if you want to send priority message.       
+ *         IPRMDATA - 0x80 specifies the data is contained in the parameter list
+ *       residual_buffer - address of buffer updated by the number
+ *                         of bytes you have received.
+ *       residual_length -      
+ *              Contains one of the following values, if the receive buffer is:
+ *               The same length as the message, this field is zero.
+ *               Longer than the message, this field contains the number of
+ *                bytes remaining in the buffer.
+ *               Shorter than the message, this field contains the residual
+ *                count (that is, the number of bytes remaining in the
+ *                message that does not fit into the buffer. In this
+ *                case b2f0_result = 5.
+ * Return: Return code from CP IUCV call.                           
+ *         (-EINVAL) - buffer address is pointing to NULL                   
+*/
+int iucv_receive (u16 pathid,
+		  u32 msgid,
+		  u32 trgcls,
+		  void *buffer,
+		  ulong buflen,
+		  int *flags1_out,
+		  ulong * residual_buffer, ulong * residual_length);
+
+ /*                                                                     
+  * Name: iucv_receive_array                                            
+  * Purpose: This function receives messages that are being sent to you 
+  *          over established paths. Data will be returned in first buffer for
+  *          length of first buffer.
+  * Input: pathid - Path identification number.                          
+  *        msgid - specifies the message ID.
+  *        trgcls - Specifies target class.
+  *        buffer - Address of array of buffers.                         
+  *        buflen - Total length of buffers.                             
+  * Output:
+  *        flags1_out: int *, Contains information about this path.
+  *          IPNORPY - 0x10 Specifies this is a one-way message and no reply is
+  *          expected.
+  *          IPPRTY  - 0x20 Specifies if you want to send priority message.
+  *          IPRMDATA - 0x80 specifies the data is contained in the parameter list
+  *       residual_buffer - address points to the current list entry IUCV
+  *                         is working on.
+  *       residual_length -
+  *              Contains one of the following values, if the receive buffer is:
+  *               The same length as the message, this field is zero.
+  *               Longer than the message, this field contains the number of
+  *                bytes remaining in the buffer.
+  *               Shorter than the message, this field contains the residual
+  *                count (that is, the number of bytes remaining in the
+  *                message that does not fit into the buffer. In this
+  *                case b2f0_result = 5.
+  * Return: Return code from CP IUCV call.                           
+  *         (-EINVAL) - Buffer address is NULL.       
+  */
+int iucv_receive_array (u16 pathid,
+			u32 msgid,
+			u32 trgcls,
 			iucv_array_t * buffer,
-			ulong * buflen,
-			uchar * reply_required,
-			uchar * priority_msg,
-			ulong * adds_curr_buffer,
-			ulong * adds_curr_length);
-
-int iucv_send (ushort pathid,
-	       ulong * msgid,
-	       ulong trgcls,
-	       ulong srccls,
-	       ulong msgtag,
-	       uchar priority_msg,
-	       void *buffer,
-	       ulong buflen);
-
-int iucv_send_array (ushort pathid,
-		     ulong * msgid,
-		     ulong trgcls,
-		     ulong srccls,
-		     ulong msgtag,
-		     uchar priority_msg,
-		     iucv_array_t * buffer,
-		     ulong buflen);
-
-int iucv_send_prmmsg (ushort pathid,
-		      ulong * msgid,
-		      ulong trgcls,
-		      ulong srccls,
-		      ulong msgtag,
-		      uchar priority_msg,
-		      uchar prmmsg[8]);
-
-int iucv_send2way (ushort pathid,
-		   ulong * msgid,
-		   ulong trgcls,
-		   ulong srccls,
-		   ulong msgtag,
-		   uchar priority_msg,
-		   void *buffer,
-		   ulong buflen,
-		   void *ansbuf,
-		   ulong anslen);
-
-int iucv_send2way_array (ushort pathid,
-			 ulong * msgid,
-			 ulong trgcls,
-			 ulong srccls,
-			 ulong msgtag,
-			 uchar priority_msg,
-			 iucv_array_t * buffer,
-			 ulong buflen,
-			 iucv_array_t * ansbuf,
-			 ulong anslen);
-
-int iucv_send2way_prmmsg (ushort pathid,
-			  ulong * msgid,
-			  ulong trgcls,
-			  ulong srccls,
-			  ulong msgtag,
-			  uchar priority_msg,
-			  uchar prmmsg[8],
-			  void *ansbuf,
-			  ulong anslen);
-
-int iucv_send2way_prmmsg_array (ushort pathid,
-				ulong * msgid,
-				ulong trgcls, ulong srccls,
-				ulong msgtag,
-				uchar priority_msg,
-				uchar prmmsg[8],
-				iucv_array_t * ansbuf,
-				ulong anslen);
-int iucv_reply (ushort pathid,
-		ulong msgid,
-		ulong trgcls,
-		uchar priority_msg,
-		void *buf,
-		ulong buflen);
-
-int iucv_reply_array (ushort pathid,
-		      ulong msgid,
-		      ulong trgcls,
-		      uchar priority_msg,
+			ulong buflen,
+			int *flags1_out,
+			ulong * residual_buffer, ulong * residual_length);
+
+/*                                                                       
+ * Name: iucv_reject                                                     
+ * Purpose: The reject function refuses a specified message. Between the 
+ *          time you are notified of a message and the time that you     
+ *          complete the message, the message may be rejected.           
+ * Input: pathid - Path identification number.                            
+ *        msgid - Specifies the message ID.                   
+ *        trgcls - Specifies target class.                                
+ * Output: NA                                                            
+ * Return: Return code from CP IUCV call.                             
+*/
+int iucv_reject (u16 pathid, u32 msgid, u32 trgcls);
+
+/*                                                                     
+ * Name: iucv_reply                                                    
+ * Purpose: This function responds to the two-way messages that you    
+ *          receive. You must identify completely the message to       
+ *          which you wish to reply. ie, pathid, msgid, and trgcls.    
+ * Input: pathid - Path identification number.                          
+ *        msgid - Specifies the message ID.                
+ *        trgcls - Specifies target class.                              
+ *        flags1 - Option for path.
+ *          IPPRTY- 0x20, Specifies if you want to send priority message.        
+ *        buffer - Address of reply buffer.                             
+ *        buflen - Length of reply buffer.                              
+ * Output: residual_buffer - Address of buffer updated by the number 
+ *                    of bytes you have moved.              
+ *         residual_length - Contains on the the following values
+ *		If the answer buffer is the same length as the reply, this field
+ *		 contains zero.
+ *		If the answer buffer is longer than the reply, this field contains
+ *		 the number of bytes remaining in the buffer.  
+ *		If the answer buffer is shorter than the reply, this field contains
+ *		 a residual count (that is, the number of bytes remianing in the
+ *		 reply that does not fit into the buffer. In this
+ *               case b2f0_result = 5.
+ * Return: Return code from CP IUCV call.                           
+ *         (-EINVAL) - Buffer address is NULL.                               
+*/
+int iucv_reply (u16 pathid,
+		u32 msgid,
+		u32 trgcls,
+		int flags1,
+		void *buffer, ulong buflen, ulong * residual_buffer,
+		ulong * residual_length);
+
+/*                                                                       
+ * Name: iucv_reply_array                                                
+ * Purpose: This function responds to the two-way messages that you      
+ *          receive. You must identify completely the message to         
+ *          which you wish to reply. ie, pathid, msgid, and trgcls.      
+ *          The array identifies a list of addresses and lengths of      
+ *          discontiguous buffers that contains the reply data.          
+ * Input: pathid - Path identification number                            
+ *        msgid - Specifies the message ID. 
+ *        trgcls - Specifies target class.                                
+ *        flags1 - Option for path.
+ *          IPPRTY- 0x20, Specifies if you want to send priority message.
+ *        buffer - Address of array of reply buffers.                     
+ *        buflen - Total length of reply buffers.                         
+ * Output: residual_buffer - Address of buffer which IUCV is currently working on.
+ *         residual_length - Contains on the the following values
+ *              If the answer buffer is the same length as the reply, this field
+ *               contains zero.
+ *              If the answer buffer is longer than the reply, this field contains
+ *               the number of bytes remaining in the buffer.
+ *              If the answer buffer is shorter than the reply, this field contains
+ *               a residual count (that is, the number of bytes remianing in the
+ *               reply that does not fit into the buffer. In this
+ *               case b2f0_result = 5.
+ * Return: Return code from CP IUCV call.                             
+ *         (-EINVAL) - Buffer address is NULL.              
+*/
+int iucv_reply_array (u16 pathid,
+		      u32 msgid,
+		      u32 trgcls,
+		      int flags1,
 		      iucv_array_t * buffer,
-		      ulong buflen);
+		      ulong buflen, ulong * residual_address,
+		      ulong * residual_length);
 
-int iucv_reply_prmmsg (ushort pathid,
-		       ulong msgid,
-		       ulong trgcls,
-		       uchar priority_msg,
-		       uchar prmmsg[8]);
+/*                                                                  
+ * Name: iucv_reply_prmmsg                                          
+ * Purpose: This function responds to the two-way messages that you 
+ *          receive. You must identify completely the message to    
+ *          which you wish to reply. ie, pathid, msgid, and trgcls. 
+ *          Prmmsg signifies the data is moved into the             
+ *          parameter list.                                         
+ * Input: pathid - Path identification number.                       
+ *        msgid - Specifies the message ID.              
+ *        trgcls - Specifies target class.                           
+ *        flags1 - Option for path.
+ *          IPPRTY- 0x20 Specifies if you want to send priority message.
+ *        prmmsg - 8-bytes of data to be placed into the parameter.  
+ *                 list.                                            
+ * Output: NA                                                       
+ * Return: Return code from CP IUCV call.                        
+*/
+int iucv_reply_prmmsg (u16 pathid,
+		       u32 msgid, u32 trgcls, int flags1, uchar prmmsg[8]);
+
+/*                                                                     
+ * Name: iucv_resume                                                   
+ * Purpose: This function restores communications over a quiesced path 
+ * Input: pathid - Path identification number.                          
+ *        user_data  - 16-bytes of user data.                           
+ * Output: NA                                                          
+ * Return: Return code from CP IUCV call.                           
+*/
+int iucv_resume (u16 pathid, uchar user_data[16]);
+
+/*                                                                   
+ * Name: iucv_send                                                   
+ * Purpose: This function transmits data to another application.     
+ *          Data to be transmitted is in a buffer and this is a      
+ *          one-way message and the receiver will not reply to the   
+ *          message.                                                 
+ * Input: pathid - Path identification number.                        
+ *        trgcls - Specifies target class.                            
+ *        srccls - Specifies the source message class.                
+ *        msgtag - Specifies a tag to be associated with the message. 
+ *        flags1 - Option for path.
+ *          IPPRTY- 0x20 Specifies if you want to send priority message.
+ *        buffer - Address of send buffer.                            
+ *        buflen - Length of send buffer.                             
+ * Output: msgid - Specifies the message ID.                         
+ * Return: Return code from CP IUCV call.                         
+ *         (-EINVAL) - Buffer address is NULL.                             
+*/
+int iucv_send (u16 pathid,
+	       u32 * msgid,
+	       u32 trgcls,
+	       u32 srccls, u32 msgtag, int flags1, void *buffer, ulong buflen);
+
+/*                                                                   
+ * Name: iucv_send_array                                             
+ * Purpose: This function transmits data to another application.     
+ *          The contents of buffer is the address of the array of    
+ *          addresses and lengths of discontiguous buffers that hold 
+ *          the message text. This is a one-way message and the      
+ *          receiver will not reply to the message.                  
+ * Input: pathid - Path identification number.                        
+ *        trgcls - Specifies target class.                            
+ *        srccls - Specifies the source message class.                
+ *        msgtag - Specifies a tag to be associated witht the message.
+ *        flags1 - Option for path.
+ *          IPPRTY- specifies if you want to send priority message. 
+ *        buffer - Address of array of send buffers.                  
+ *        buflen - Total length of send buffers.                      
+ * Output: msgid - Specifies the message ID.                         
+ * Return: Return code from CP IUCV call.                         
+ *         (-EINVAL) - Buffer address is NULL.                             
+*/
+int iucv_send_array (u16 pathid,
+		     u32 * msgid,
+		     u32 trgcls,
+		     u32 srccls,
+		     u32 msgtag,
+		     int flags1, iucv_array_t * buffer, ulong buflen);
+
+/*                                                                     
+ * Name: iucv_send_prmmsg                                              
+ * Purpose: This function transmits data to another application.       
+ *          Prmmsg specifies that the 8-bytes of data are to be moved  
+ *          into the parameter list. This is a one-way message and the 
+ *          receiver will not reply to the message.                    
+ * Input: pathid - Path identification number.                          
+ *        trgcls - Specifies target class.                              
+ *        srccls - Specifies the source message class.                  
+ *        msgtag - Specifies a tag to be associated with the message.   
+ *        flags1 - Option for path.
+ *          IPPRTY- 0x20 specifies if you want to send priority message.
+ *        prmmsg - 8-bytes of data to be placed into parameter list.    
+ * Output: msgid - Specifies the message ID.                           
+ * Return: Return code from CP IUCV call.                           
+*/
+int iucv_send_prmmsg (u16 pathid,
+		      u32 * msgid,
+		      u32 trgcls,
+		      u32 srccls, u32 msgtag, int flags1, uchar prmmsg[8]);
+
+/*                                                                
+ * Name: iucv_send2way                                            
+ * Purpose: This function transmits data to another application.  
+ *          Data to be transmitted is in a buffer. The receiver   
+ *          of the send is expected to reply to the message and   
+ *          a buffer is provided into which IUCV moves the reply  
+ *          to this message.                                      
+ * Input: pathid - Path identification number.                     
+ *        trgcls - Specifies target class.                         
+ *        srccls - Specifies the source message class.             
+ *        msgtag - Specifies a tag associated with the message.    
+ *        flags1 - Option for path.
+ *          IPPRTY- 0x20 Specifies if you want to send priority message.
+ *        buffer - Address of send buffer.                         
+ *        buflen - Length of send buffer.                          
+ *        ansbuf - Address of buffer into which IUCV moves the reply of 
+ *                 this message.        
+ *        anslen - Address of length of buffer.          
+ * Output: msgid - Specifies the message ID.                      
+ * Return: Return code from CP IUCV call.                      
+ *         (-EINVAL) - Buffer or ansbuf address is NULL.    
+*/
+int iucv_send2way (u16 pathid,
+		   u32 * msgid,
+		   u32 trgcls,
+		   u32 srccls,
+		   u32 msgtag,
+		   int flags1,
+		   void *buffer, ulong buflen, void *ansbuf, ulong anslen);
+
+/*                                                                    
+ * Name: iucv_send2way_array                                          
+ * Purpose: This function transmits data to another application.      
+ *          The contents of buffer is the address of the array of     
+ *          addresses and lengths of discontiguous buffers that hold  
+ *          the message text. The receiver of the send is expected to 
+ *          reply to the message and a buffer is provided into which  
+ *          IUCV moves the reply to this message.                     
+ * Input: pathid - Path identification number.                         
+ *        trgcls - Specifies target class.                             
+ *        srccls - Specifies the source message class.                 
+ *        msgtag - Specifies a tag to be associated with the message.   
+ *        flags1 - Option for path.
+ *          IPPRTY- 0x20 Specifies if you want to send priority message.
+ *        buffer - Sddress of array of send buffers.                   
+ *        buflen - Total length of send buffers.                       
+ *        ansbuf - Address of array of buffer into which IUCV moves the reply            
+ *                 of this message.                         
+ *        anslen - Address of length reply buffers.              
+ * Output: msgid - Specifies the message ID.                          
+ * Return: Return code from CP IUCV call.                          
+ *         (-EINVAL) - Buffer address is NULL.                              
+*/
+int iucv_send2way_array (u16 pathid,
+			 u32 * msgid,
+			 u32 trgcls,
+			 u32 srccls,
+			 u32 msgtag,
+			 int flags1,
+			 iucv_array_t * buffer,
+			 ulong buflen, iucv_array_t * ansbuf, ulong anslen);
+
+/*                                                                     
+ * Name: iucv_send2way_prmmsg                                          
+ * Purpose: This function transmits data to another application.       
+ *          Prmmsg specifies that the 8-bytes of data are to be moved  
+ *          into the parameter list. This is a two-way message and the 
+ *          receiver of the message is expected to reply. A buffer     
+ *          is provided into which IUCV moves the reply to this        
+ *          message.                                                   
+ * Input: pathid - Rath identification number.                          
+ *        trgcls - Specifies target class.                              
+ *        srccls - Specifies the source message class.                  
+ *        msgtag - Specifies a tag to be associated with the message.   
+ *        flags1 - Option for path.
+ *          IPPRTY- 0x20 Specifies if you want to send priority message.
+ *        prmmsg - 8-bytes of data to be placed in parameter list.      
+ *        ansbuf - Address of buffer into which IUCV moves the reply of    
+ *                 this message.
+ *        anslen - Address of length of buffer.               
+ * Output: msgid - Specifies the message ID.                           
+ * Return: Return code from CP IUCV call.                           
+ *         (-EINVAL) - Buffer address is NULL.         
+*/
+int iucv_send2way_prmmsg (u16 pathid,
+			  u32 * msgid,
+			  u32 trgcls,
+			  u32 srccls,
+			  u32 msgtag,
+			  ulong flags1,
+			  uchar prmmsg[8], void *ansbuf, ulong anslen);
+
+/*                                                                      
+ * Name: iucv_send2way_prmmsg_array                                     
+ * Purpose: This function transmits data to another application.        
+ *          Prmmsg specifies that the 8-bytes of data are to be moved   
+ *          into the parameter list. This is a two-way message and the  
+ *          receiver of the message is expected to reply. A buffer      
+ *          is provided into which IUCV moves the reply to this         
+ *          message. The contents of ansbuf is the address of the       
+ *          array of addresses and lengths of discontiguous buffers     
+ *          that contain the reply.                                     
+ * Input: pathid - Path identification number.                           
+ *        trgcls - Specifies target class.                               
+ *        srccls - Specifies the source message class.                   
+ *        msgtag - Specifies a tag to be associated with the message.    
+ *        flags1 - Option for path.
+ *          IPPRTY- 0x20 specifies if you want to send priority message.
+ *        prmmsg - 8-bytes of data to be placed into the parameter list. 
+ *        ansbuf - Address of array of buffer into which IUCV moves the reply
+ *                 of this message.  
+ *        anslen - Address of length of reply buffers.                
+ * Output: msgid - Specifies the message ID.      
+ * Return: Return code from CP IUCV call.      
+ *         (-EINVAL) - Ansbuf address is NULL.          
+*/
+int iucv_send2way_prmmsg_array (u16 pathid,
+				u32 * msgid,
+				u32 trgcls,
+				u32 srccls,
+				u32 msgtag,
+				int flags1,
+				uchar prmmsg[8],
+				iucv_array_t * ansbuf, ulong anslen);
 
-#endif
+/*                                                                   
+ * Name: iucv_setmask                                                
+ * Purpose: This function enables or disables the following IUCV     
+ *          external interruptions: Nonpriority and priority message 
+ *          interrupts, nonpriority and priority reply interrupts.   
+ * Input: SetMaskFlag - options for interrupts
+ *           0x80 - Nonpriority_MessagePendingInterruptsFlag         
+ *           0x40 - Priority_MessagePendingInterruptsFlag            
+ *           0x20 - Nonpriority_MessageCompletionInterruptsFlag      
+ *           0x10 - Priority_MessageCompletionInterruptsFlag         
+ * Output: NA                                                        
+ * Return: Return code from CP IUCV call.                         
+*/
+int iucv_setmask (int SetMaskFlag);
+
+/*                                                  
+ * Name: iucv_sever                                 
+ * Purpose: This function terminates an IUCV path.  
+ * Input: pathid - Path identification number.       
+ *        user_data - 16-bytes of user data.         
+ * Output: NA       
+ * Return: Return code from CP IUCV call.                                
+ *         (-EINVAL) - Interal error, wild pointer.       
+*/
+int iucv_sever (u16 pathid, uchar user_data[16]);
diff -u --recursive --new-file v2.4.7/linux/drivers/s390/net/netiucv.c linux/drivers/s390/net/netiucv.c
--- v2.4.7/linux/drivers/s390/net/netiucv.c	Wed Apr 18 14:40:07 2001
+++ linux/drivers/s390/net/netiucv.c	Wed Jul 25 14:12:02 2001
@@ -14,16 +14,19 @@
  *    Re-write:   Alan Altmark (Alan_Altmark@us.ibm.com)  Sept. 2000
  *                Uses iucv.c kernel module for IUCV services. 
  *
+ *    2.4 Updates Alan Altmark (Alan_Altmark@us.ibm.com)  June 2001
+ *                Update to use changed IUCV (iucv.c) interface.
+ *
  * -------------------------------------------------------------------------- 
  *  An IUCV frame consists of one or more packets preceded by a 16-bit
  *  header.   The header contains the offset to the next packet header,
  *  measured from the beginning of the _frame_.  If zero, there are no more
  *  packets in the frame.  Consider a frame which contains a 10-byte packet
  *  followed by a 20-byte packet:
- *        +-----+----------------+-----+----------------------------+-----+
- *        |h'12'| 10-byte packet |h'34'|  20-byte packet            |h'00'|
- *        +-----+----------------+-----+----------------------------+-----+
- * Offset: 0     2                12    14                           34  
+ *        +-----+----------------+--------------------------------+-----+
+ *        |h'12'| 10-byte packet |h'34'|  20-byte packet          |h'00'|
+ *        +-----+----------------+-----+--------------------------+-----+
+ * Offset: 0     2                12    14                         34  
  *
  *  This means that each header will always have a larger value than the
  *  previous one (except for the final zero header, of course).
@@ -46,10 +49,13 @@
  * --------------------------------------------------------------------------
 */
 //#define DEBUG 1
+//#define DEBUG2 1
+//#define IPDEBUG 1
+#define LEVEL "1.1"
 
 /* If MAX_DEVICES increased, add initialization data to iucv_netdev[] array */
 /* (See bottom of program.)						    */
-#define MAX_DEVICES 10		/* Allows "iucv0" to "iucv9"    */
+#define MAX_DEVICES 20		/* Allows "iucv0" to "iucv19"   */
 #define MAX_VM_MTU 32764	/* 32K IUCV buffer, minus 4     */
 #define MAX_TX_Q 50		/* Maximum pending TX           */
 
@@ -60,11 +66,14 @@
 #include <linux/module.h>
 MODULE_AUTHOR
     ("(C) 2000 IBM Corporation by Alan Altmark (Alan_Altmark@us.ibm.com)");
-MODULE_DESCRIPTION ("Linux for S/390 IUCV network driver");
+MODULE_DESCRIPTION ("Linux for S/390 IUCV network driver " LEVEL);
 MODULE_PARM (iucv, "1-" __MODULE_STRING (MAX_DEVICES) "s");
 MODULE_PARM_DESC (iucv,
 		  "Specify the userids associated with iucv0-iucv9:\n"
 		  "iucv=userid1,userid2,...,userid10\n");
+#ifdef MODVERSIONS
+#include <linux/modversions.h>
+#endif
 #else
 #define MOD_INC_USE_COUNT
 #define MOD_DEC_USE_COUNT
@@ -77,18 +86,22 @@
 #include <linux/interrupt.h>	/* mark_bh                      */
 #include <linux/netdevice.h>	/* struct net_device, etc.      */
 #include <linux/if_arp.h>	/* ARPHRD_SLIP                  */
+#include <linux/ip.h>		/* IP header                    */
 #include <linux/skbuff.h>	/* skb                          */
 #include <linux/init.h>		/* __setup()                    */
-#include <asm/io.h>		/* virt_to_phys()               */
 #include <asm/string.h>		/* memset, memcpy, etc.         */
 #include "iucv.h"
 #define min(a,b) (a < b) ? a : b
 
-#ifdef DEBUG
+#if defined( DEBUG )
 #undef KERN_INFO
 #undef KERN_DEBUG
+#undef KERN_NOTICE
+#undef KERN_ERR
 #define KERN_INFO    KERN_EMERG
 #define KERN_DEBUG   KERN_EMERG
+#define KERN_NOTICE  KERN_EMERG
+#define KERN_ERR     KERN_EMERG
 #endif
 
 #if (LINUX_VERSION_CODE >= KERNEL_VERSION(2,3,0))
@@ -145,14 +158,14 @@
 static int iucv_stop (net_device *);
 static int iucv_change_mtu (net_device *, int);
 static int iucv_init (net_device *);
-static void iucv_rx (net_device *, uchar *, int);
+static void iucv_rx (net_device *, u32, uchar *, int);
 static int iucv_tx (struct sk_buff *, net_device *);
 
-static void connection_severed (iucv_ConnectionSevered *, ulong);
-static void connection_pending (iucv_ConnectionPending *, ulong);
-static void connection_complete (iucv_ConnectionComplete *, ulong);
-static void message_pending (iucv_MessagePending *, ulong);
-static void send_complete (iucv_MessageComplete *, ulong);
+static void connection_severed (iucv_ConnectionSevered *, void *);
+static void connection_pending (iucv_ConnectionPending *, void *);
+static void connection_complete (iucv_ConnectionComplete *, void *);
+static void message_pending (iucv_MessagePending *, void *);
+static void send_complete (iucv_MessageComplete *, void *);
 
 void register_iucv_dev (int, char *);
 
@@ -168,7 +181,6 @@
 
 static char iucv_userid[MAX_DEVICES][8];
 net_device iucv_netdev[MAX_DEVICES];
-static char eodata[2] = { '\0', '\0' };
 
 /* This structure is private to each device. It contains the    */
 /* information necessary to do IUCV operations.                 */
@@ -188,12 +200,6 @@
 	u16 pathid;
 };
 
-struct iucvtag {
-	iucv_array_t iucvvec[3];
-	u16 framelen;
-	struct sk_buff *skb;
-};
-
 uchar iucv_host[8] = { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 };
 uchar iucvMagic[16] = { 0xF0, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40,
 	0xF0, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40
@@ -207,7 +213,7 @@
 	0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff
 };
 
-#ifdef DEBUG
+#if defined( DEBUG2 ) || defined( IPDEBUG )
 /*--------------------------*/
 /* Dump buffer formatted    */
 /*--------------------------*/
@@ -260,8 +266,6 @@
 iucv_start (net_device * dev)
 {
 	int rc, i;
-	uchar pri;
-	uchar unused = '\0';
 	struct iucv_priv *p = (struct iucv_priv *) dev->priv;
 
 	pr_debug ("iucv_start(%s)\n", dev->name);
@@ -269,7 +273,7 @@
 	if (p == NULL) {
 		/* Allocate priv data */
 		p = (struct iucv_priv *) kmalloc (sizeof (struct iucv_priv),
-						  GFP_KERNEL);
+						  GFP_ATOMIC);
 		if (p == NULL) {
 			printk (KERN_CRIT "%s: no memory for dev->priv.\n",
 				dev->name);
@@ -292,11 +296,11 @@
 		atomic_set (&p->state, FREE);
 		p->handle =
 		    iucv_register_program (iucvMagic, p->userid2, (char *) mask,
-					   &netiucv_ops, (ulong) dev);
+					   &netiucv_ops, (void *) dev);
 		if (p->handle <= 0) {
 			printk (KERN_ERR
-				"%s: iucv_register_program error, rc=%i\n",
-				dev->name, (int) p->handle);
+				"%s: iucv_register_program error, rc=%p\n",
+				dev->name, p->handle);
 			dev->priv = NULL;
 			kfree (p);
 			return -ENODEV;
@@ -312,8 +316,7 @@
 
 	rc =
 	    iucv_connect (&(p->pathid), MAX_TX_Q, iucvMagic, p->userid2,
-			  iucv_host, unused, unused, unused, unused, unused,
-			  &pri, p->handle, (ulong) p);
+			  iucv_host, 0, NULL, NULL, p->handle, p);
 
 	/* Some errors are not fatal.  In these cases we will report "OK". */
 	switch (rc) {
@@ -321,30 +324,30 @@
 		pr_debug ("...waiting for connection to complete...");
 		return 0;
 	case 11:		/* Wait for parter to connect */
-		printk (KERN_NOTICE "Device %s: "
+		printk (KERN_NOTICE "%s: "
 			"User %s is not available now.\n",
 			dev->name, p->userid);
 		atomic_set (&p->state, FREE);
 		return 0;
 	case 12:		/* Wait for partner to connect */
-		printk (KERN_NOTICE "Device %s: "
+		printk (KERN_NOTICE "%s: "
 			"User %s is not ready to talk now.\n",
 			dev->name, p->userid);
 		atomic_set (&p->state, FREE);
 		return 0;
 	case 13:		/* Fatal */
-		printk (KERN_ERR "Device %s: "
+		printk (KERN_ERR "%s: "
 			"You have too many IUCV connections."
 			"Check MAXCONN in CP directory.\n", dev->name);
 		break;
 	case 14:		/* Fatal */
-		printk (KERN_ERR "Device %s: "
+		printk (KERN_ERR "%s: "
 			"User %s has too many IUCV connections."
 			"Check MAXCONN in CP directory.\n",
 			dev->name, p->userid);
 		break;
 	case 15:		/* Fatal */
-		printk (KERN_ERR "Device %s: "
+		printk (KERN_ERR "%s: "
 			"No IUCV authorization found in CP directory.\n",
 			dev->name);
 		break;
@@ -353,7 +356,7 @@
 			"return code %i from iucv_connect()\n", dev->name, rc);
 	}
 
-	rc = iucv_unregister (p->handle);
+	rc = iucv_unregister_program (p->handle);
 	dev->priv = NULL;
 	kfree (p);
 	MOD_DEC_USE_COUNT;
@@ -364,7 +367,7 @@
 /* Our connection TO another stack has been accepted.                */
 /*********************************************************************/
 static void
-connection_complete (iucv_ConnectionComplete * cci, ulong pgm_data)
+connection_complete (iucv_ConnectionComplete * cci, void *pgm_data)
 {
 	struct iucv_priv *p = (struct iucv_priv *) pgm_data;
 	pr_debug ("...%s connection complete... txq=%u\n",
@@ -374,7 +377,7 @@
 	p->dev->tx_queue_len = cci->ipmsglim;
 	netif_start (p->dev);
 	netif_start_queue (p->dev);
-	printk (KERN_INFO "%s: Connection to user %s is up\n",
+	printk (KERN_NOTICE "%s: Connection to user %s is up\n",
 		p->dev->name, p->userid);
 }				/* end connection_complete() */
 
@@ -386,7 +389,7 @@
 /* the remote user is the correct user.                              */
 /*********************************************************************/
 static void
-connection_pending (iucv_ConnectionPending * cpi, ulong pgm_data)
+connection_pending (iucv_ConnectionPending * cpi, void *pgm_data)
 {
 	/* Only get this far if handler is set up, so we know userid is ok. */
 	/* and the device is started.                                       */
@@ -394,9 +397,8 @@
 	net_device *dev = (net_device *) pgm_data;
 	struct iucv_priv *p = (struct iucv_priv *) dev->priv;
 	int rc;
+	u16 msglimit;
 	uchar udata[16];
-	uchar no = '\0';
-	uchar na;
 
 	/* If we're not waiting on a connect, reject the connection */
 	if (atomic_compare_and_swap (FREE, CONNECTING, &p->state) != 0) {
@@ -404,27 +406,25 @@
 		return;
 	}
 
-	rc = iucv_accept (cpi->ippathid,	/* Path id              */
-			  MAX_TX_Q,	/* msglimit                     */
+	rc = iucv_accept (cpi->ippathid,	/* Path id                      */
+			  MAX_TX_Q,	/* desired IUCV msg limit       */
 			  udata,	/* user_Data                    */
-			  no,	/* will we send priority msgs?  */
-			  no,	/* do we accept prmdata?        */
-			  no,	/* quiece immediately?          */
-			  no,	/* control path?                */
-			  &na,	/* other side accept prmdata?   */
-			  p->handle,	/* registration handle  */
-			  (ulong) p);	/* private data         */
+			  0,	/* No flags                     */
+			  p->handle,	/* registration handle          */
+			  p,	/* private data                 */
+			  NULL,	/* don't care about output flags */
+			  &msglimit);	/* Actual IUCV msg limit        */
 	if (rc != 0) {
 		atomic_set (&p->state, FREE);
 		printk (KERN_ERR "%s: iucv accept failed rc=%i\n",
 			p->dev->name, rc);
 	} else {
+		atomic_set (&p->state, CONNECTED);
 		p->pathid = cpi->ippathid;
-		p->dev->tx_queue_len = cpi->ipmsglim;
+		p->dev->tx_queue_len = (u32) msglimit;
 		netif_start (p->dev);
 		netif_start_queue (p->dev);
-		atomic_set (&p->state, CONNECTED);
-		printk (KERN_INFO "Device %s: Connection to user %s is up\n",
+		printk (KERN_NOTICE "%s: Connection to user %s is up\n",
 			p->dev->name, p->userid);
 	}
 }				/* end connection_pending() */
@@ -433,15 +433,21 @@
 /* Our connection to another stack has been severed.                 */
 /*********************************************************************/
 static void
-connection_severed (iucv_ConnectionSevered * eib, ulong pgm_data)
+connection_severed (iucv_ConnectionSevered * eib, void *pgm_data)
 {
 	struct iucv_priv *p = (struct iucv_priv *) pgm_data;
 
 	printk (KERN_INFO "%s: Connection to user %s is down\n",
 		p->dev->name, p->userid);
 
+	/* FIXME: We can also get a severed interrupt while in
+	          state CONNECTING!  Fix the state machine ... */
+#if 0
 	if (atomic_compare_and_swap (CONNECTED, FREE, &p->state) != 0)
 		return;		/* In case reconnect in progress already */
+#else
+	atomic_set (&p->state, FREE);
+#endif
 
 	netif_stop_queue (p->dev);
 	netif_stop (p->dev);
@@ -464,7 +470,8 @@
 	if (p == NULL)
 		return 0;
 
-	rc = iucv_unregister (p->handle);	/* Will sever connections */
+	/* Unregister will sever associated connections */
+	rc = iucv_unregister_program (p->handle);
 	dev->priv = NULL;
 	kfree (p);
 	MOD_DEC_USE_COUNT;
@@ -477,7 +484,7 @@
 /* separate packets, and send them to the "generic" packet processor.  */
 /*---------------------------------------------------------------------*/
 static void
-message_pending (iucv_MessagePending * mpi, ulong pgm_data)
+message_pending (iucv_MessagePending * mpi, void *pgm_data)
 {
 	struct iucv_priv *p = (struct iucv_priv *) pgm_data;
 	int rc;
@@ -486,22 +493,21 @@
 	void *buffer;
 
 	buffer_length = mpi->ln1msg2.ipbfln1f;
-	pr_debug ("message_pending: ID=%p Length=%u\n", (void *) mpi->ipmsgid,
-		  buffer_length);
+	pr_debug ("%s: MP id=%i Length=%u\n",
+		  p->dev->name, mpi->ipmsgid, buffer_length);
 
 	buffer = kmalloc (buffer_length, GFP_ATOMIC | GFP_DMA);
 	if (buffer == NULL) {
 		p->stats.rx_dropped++;
 		return;
 	}
-
-	rc = iucv_receive_simple (p->pathid, mpi->ipmsgid, mpi->iptrgcls,
-				  buffer, buffer_length);
+	rc = iucv_receive (p->pathid, mpi->ipmsgid, mpi->iptrgcls,
+			   buffer, buffer_length, NULL, NULL, NULL);
 
 	if (rc != 0 || buffer_length < 5) {
 		printk (KERN_INFO
-			"%s: iucv_receive error. rc=%X, length=%u\n",
-			p->dev->name, rc, buffer_length);
+			"%s: IUCV rcv error. rc=%X ID=%i length=%u\n",
+			p->dev->name, rc, mpi->ipmsgid, buffer_length);
 		p->stats.rx_errors++;
 		kfree (buffer);
 		return;
@@ -519,7 +525,7 @@
 			break;
 		} else {
 			/* Kick the packet upstairs */
-			iucv_rx (p->dev,
+			iucv_rx (p->dev, mpi->ipmsgid,
 				 buffer + prev_offset + 2,
 				 packet_offset - prev_offset - 2);
 			prev_offset = packet_offset;
@@ -535,20 +541,23 @@
 /* Add meta-data to packet and send upstairs.                  */
 /*-------------------------------------------------------------*/
 static void
-iucv_rx (net_device * dev, uchar * buf, int len)
+iucv_rx (net_device * dev, u32 msgid, uchar * buf, int len)
 {
 	struct iucv_priv *p = (struct iucv_priv *) dev->priv;
 	struct sk_buff *skb;
 
-	pr_debug ("%s: iucv_rx len=%u\n", p->dev->name, len);
-#ifdef DEBUG
+#ifdef IPDEBUG
+	printk (KERN_DEBUG "RX id=%i\n", msgid);
 	dumpit (buf, 20);
+	dumpit (buf + 20, 20);
 #endif
 
+	pr_debug ("%s: RX len=%u\n", p->dev->name, len);
+
 	if (len > p->dev->mtu) {
 		printk (KERN_INFO
-			"%s: inbound packet length %u exceeds MTU %i\n",
-			p->dev->name, len, p->dev->mtu);
+			"%s: inbound packet id# %i length %u exceeds MTU %i\n",
+			p->dev->name, msgid, len, p->dev->mtu);
 		p->stats.rx_errors++;
 		return;
 	}
@@ -585,81 +594,86 @@
 iucv_tx (struct sk_buff *skb, net_device * dev)
 {
 	int rc, pktlen;
-	struct iucvtag *tag;
+	u32 framelen, msgid;
+	void *frame;
 	struct iucv_priv *p = (struct iucv_priv *) dev->priv;
 
-	if (skb == NULL)	/* Nothing to do */
-		return 0;
-
-	if (netif_is_busy (dev)) {
-		p->stats.tx_dropped++;
-		dev_kfree_skb (skb);
-		printk (KERN_ERR "%s: tx conflict! leave iucv_tx.\n",
+	if (skb == NULL) {	/* Nothing to do */
+		printk (KERN_WARNING "%s: TX Kernel passed null sk_buffer\n",
 			dev->name);
-		return -EBUSY;
+		p->stats.tx_dropped++;
+		return -EIO;
 	}
 
-	netif_stop_queue (dev);	/* transmission is busy */
+	if (netif_is_busy (dev))
+		return -EBUSY;
 
 	dev->trans_start = jiffies;	/* save the timestamp */
 
-	/* Tag contains data that must survive exit from this */
-	/* routine.  MessageComplete exit will free the tag   */
-	/* and any structures it points to.                   */
-	tag =
-	    (struct iucvtag *) kmalloc (sizeof (struct iucvtag),
-					GFP_DMA | GFP_KERNEL);
-	if (!tag) {
+	/* IUCV frame will be released when MessageComplete   */
+	/* interrupt is received.                             */
+	pktlen = skb->len;
+	framelen = pktlen + 4;
+
+	frame = kmalloc (framelen, GFP_ATOMIC | GFP_DMA);
+	if (!frame) {
 		p->stats.tx_dropped++;
 		dev_kfree_skb (skb);
-		return -ENOMEM;
+		return 0;
 	}
 
-	pktlen = skb->len;
-	tag->framelen = (u16) pktlen + 2;
-	tag->skb = skb;
-	tag->iucvvec[0].address = &tag->framelen;
-	tag->iucvvec[0].length = 2;
-	tag->iucvvec[1].address = (void *) virt_to_phys (skb->data);
-	tag->iucvvec[1].length = pktlen;
-	tag->iucvvec[2].address = (void *) virt_to_phys (eodata);
-	tag->iucvvec[2].length = 2;
-	pr_debug ("iucv_tx: length=%i, skb=%p tag=%p\n", pktlen, tag->skb, tag);
+	netif_stop_queue (dev);	/* transmission is busy */
 
-	/* Ok, now the packet is ready for transmission: send it. */
-	rc =
-	    iucv_send_array (p->pathid, NULL, 0, 0, (ulong) tag, 0,
-			     tag->iucvvec, pktlen + 4);
-	if (rc == 0)
+	*(u16 *) frame = pktlen + 2;	/* Set header   */
+	memcpy (frame + 2, skb->data, pktlen);	/* Copy data    */
+	memset (frame + pktlen + 2, 0, 2);	/* Set trailer  */
+
+	/* Ok, now the frame is ready for transmission: send it. */
+	rc = iucv_send (p->pathid, &msgid, 0, 0,
+			(u32) frame,	/* Msg tag      */
+			0,	/* No flags     */
+			frame, framelen);
+	if (rc == 0) {
+#ifdef IPDEBUG
+		printk (KERN_DEBUG "TX id=%i\n", msgid);
+		dumpit (skb->data, 20);
+		dumpit (skb->data + 20, 20);
+#endif
+		pr_debug ("%s: tx START %i.%i @=%p len=%i\n",
+			  p->dev->name, p->pathid, msgid, frame, framelen);
 		p->stats.tx_packets++;
-	else {
+	} else {
 		if (rc == 3)	/* Exceeded MSGLIMIT */
 			p->stats.tx_dropped++;
 		else {
 			p->stats.tx_errors++;
-			printk (KERN_INFO "%s: iucv send failed, rc=%i\n",
-				p->dev->name, rc);
+			printk (KERN_INFO "%s: tx ERROR id=%i.%i rc=%i\n",
+				p->dev->name, p->pathid, msgid, rc);
 		}
-		dev_kfree_skb (skb);
-		kfree (tag);
+		/* We won't get interrupt.  Free frame now. */
+		kfree (frame);
 	}
+	dev_kfree_skb (skb);	/* Finished with skb            */
 
 	netif_wake_queue (p->dev);
-	return rc;		/* zero == done; nonzero == fail */
+	return 0;
 }				/* end iucv_tx() */
 
 /*-----------------------------------------------------------*/
 /* SEND COMPLETE                    Called by IUCV handler.  */
-/* Free SKB associated with this transmission and free       */
-/* the IUCV buffer list and SKB pointer.                     */
+/* Free the IUCV frame that was used for this transmission.  */
 /*-----------------------------------------------------------*/
 static void
-send_complete (iucv_MessageComplete * mci, ulong pgm_data)
+send_complete (iucv_MessageComplete * mci, void *pgm_data)
 {
-	struct iucvtag *tag = (struct iucvtag *) mci->ipmsgtag;
-	pr_debug ("TX COMPLETE: Tag=%p skb=%p\n", tag, tag->skb);
-	dev_kfree_skb (tag->skb);
-	kfree (tag);
+	void *frame;
+#ifdef DEBUG
+	struct iucv_priv *p = (struct iucv_priv *) pgm_data;
+#endif
+	frame = (void *) (ulong) mci->ipmsgtag;
+	kfree (frame);
+	pr_debug ("%s: TX DONE %i.%i @=%p\n",
+		  p->dev->name, mci->ippathid, mci->ipmsgid, frame);
 }				/* end send_complete() */
 
 /*-----------------------------------------------------------*/
@@ -704,9 +718,10 @@
 	dev->type = ARPHRD_SLIP;
 	dev->tx_queue_len = MAX_TX_Q;	/* Default - updated based on IUCV */
 	/* keep the default flags, just add NOARP and POINTOPOINT */
-	dev->flags = IFF_NOARP | IFF_POINTOPOINT;
+	dev->flags |= IFF_NOARP | IFF_POINTOPOINT;
 	dev->mtu = 9216;
 
+	dev_init_buffers (dev);
 	pr_debug ("%s: iucv_init  dev@=%p\n", dev->name, dev);
 	return 0;
 }
@@ -734,6 +749,7 @@
 	i = devnumber = 0;
 	memset (temp_userid, ' ', 8);
 	temp_userid[8] = '\0';
+	printk (KERN_NOTICE "netiucv: IUCV network driver " LEVEL "\n");
 
 	if (!iucv)
 		init_return (0);
@@ -784,6 +800,7 @@
 init_module (void)
 {
 	int i;
+	printk (KERN_NOTICE "netiucv: IUCV network driver " LEVEL "\n");
 	for (i = 0; i < MAX_DEVICES; i++) {
 		if (iucv[i] == NULL)
 			break;
@@ -838,60 +855,120 @@
 #if (LINUX_VERSION_CODE < KERNEL_VERSION(2,3,0))
 		name: &iucv_names[0][0],  /* Name filled in at load time  */
 #endif
-		init: iucv_init 	  /* probe function               */
+		init: iucv_init           /* probe function               */
 	},
 	{
 #if (LINUX_VERSION_CODE < KERNEL_VERSION(2,3,0))
 		name: &iucv_names[1][0],  /* Name filled in at load time  */
 #endif
-		init: iucv_init 	  /* probe function               */
+		init: iucv_init           /* probe function               */
 	},
 	{
 #if (LINUX_VERSION_CODE < KERNEL_VERSION(2,3,0))
 		name: &iucv_names[2][0],  /* Name filled in at load time  */
 #endif
-		init: iucv_init 	  /* probe function               */
+		init: iucv_init           /* probe function               */
 	},
 	{
 #if (LINUX_VERSION_CODE < KERNEL_VERSION(2,3,0))
 		name: &iucv_names[3][0],  /* Name filled in at load time  */
 #endif
-		init: iucv_init 	  /* probe function               */
+		init: iucv_init           /* probe function               */
 	},
 	{
 #if (LINUX_VERSION_CODE < KERNEL_VERSION(2,3,0))
 		name: &iucv_names[4][0],  /* Name filled in at load time  */
 #endif
-		init: iucv_init 	  /* probe function               */
+		init: iucv_init           /* probe function               */
 	},
 	{
 #if (LINUX_VERSION_CODE < KERNEL_VERSION(2,3,0))
 		name: &iucv_names[5][0],  /* Name filled in at load time  */
 #endif
-		init: iucv_init 	  /* probe function               */
+		init: iucv_init           /* probe function               */
 	},
 	{
 #if (LINUX_VERSION_CODE < KERNEL_VERSION(2,3,0))
 		name: &iucv_names[6][0],  /* Name filled in at load time  */
 #endif
-		init: iucv_init 	  /* probe function               */
+		init: iucv_init           /* probe function               */
 	},
 	{
 #if (LINUX_VERSION_CODE < KERNEL_VERSION(2,3,0))
 		name: &iucv_names[7][0],  /* Name filled in at load time  */
 #endif
-		init: iucv_init 	  /* probe function               */
+		init: iucv_init           /* probe function               */
 	},
 	{
 #if (LINUX_VERSION_CODE < KERNEL_VERSION(2,3,0))
 		name: &iucv_names[8][0],  /* Name filled in at load time  */
 #endif
-		init: iucv_init 	  /* probe function               */
+		init: iucv_init           /* probe function               */
 	},
 	{
 #if (LINUX_VERSION_CODE < KERNEL_VERSION(2,3,0))
 		name: &iucv_names[9][0],  /* Name filled in at load time  */
 #endif
-		init: iucv_init 	  /* probe function               */
+		init: iucv_init           /* probe function               */
+	},
+	{
+#if (LINUX_VERSION_CODE < KERNEL_VERSION(2,3,0))
+		name: &iucv_names[10][0], /* Name filled in at load time  */
+#endif
+		init: iucv_init           /* probe function               */
+	},
+	{
+#if (LINUX_VERSION_CODE < KERNEL_VERSION(2,3,0))
+		name: &iucv_names[11][0], /* Name filled in at load time  */
+#endif
+		init: iucv_init           /* probe function               */
+	},
+	{
+#if (LINUX_VERSION_CODE < KERNEL_VERSION(2,3,0))
+		name: &iucv_names[12][0], /* Name filled in at load time  */
+#endif
+		init: iucv_init           /* probe function               */
+	},
+	{
+#if (LINUX_VERSION_CODE < KERNEL_VERSION(2,3,0))
+		name: &iucv_names[13][0], /* Name filled in at load time  */
+#endif
+		init: iucv_init           /* probe function               */
+	},
+	{
+#if (LINUX_VERSION_CODE < KERNEL_VERSION(2,3,0))
+		name: &iucv_names[14][0], /* Name filled in at load time  */
+#endif
+		init: iucv_init           /* probe function               */
+	},
+	{
+#if (LINUX_VERSION_CODE < KERNEL_VERSION(2,3,0))
+		name: &iucv_names[15][0], /* Name filled in at load time  */
+#endif
+		init: iucv_init           /* probe function               */
+	},
+	{
+#if (LINUX_VERSION_CODE < KERNEL_VERSION(2,3,0))
+		name: &iucv_names[16][0], /* Name filled in at load time  */
+#endif
+		init: iucv_init           /* probe function               */
+	},
+	{
+#if (LINUX_VERSION_CODE < KERNEL_VERSION(2,3,0))
+		name: &iucv_names[17][0], /* Name filled in at load time  */
+#endif
+		init: iucv_init           /* probe function               */
+	},
+	{
+#if (LINUX_VERSION_CODE < KERNEL_VERSION(2,3,0))
+		name: &iucv_names[18][0], /* Name filled in at load time  */
+#endif
+		init: iucv_init           /* probe function               */
+	},
+	{
+#if (LINUX_VERSION_CODE < KERNEL_VERSION(2,3,0))
+		name: &iucv_names[19][0], /* Name filled in at load time  */
+#endif
+		init: iucv_init           /* probe function               */
 	},
 };
diff -u --recursive --new-file v2.4.7/linux/drivers/s390/s390dyn.c linux/drivers/s390/s390dyn.c
--- v2.4.7/linux/drivers/s390/s390dyn.c	Wed Apr 11 19:02:28 2001
+++ linux/drivers/s390/s390dyn.c	Wed Jul 25 14:12:02 2001
@@ -112,32 +112,23 @@
                         if (ioinfo->ui.flags.dval != 1 ||
 		            ioinfo->devno != pdevreg->ci.devno)
 				continue;
-                } else if ((flag & DEVREG_TYPE_DEVCHARS) &&
-		           (flag & DEVREG_EXACT_MATCH)) {
-			if (pdevreg->ci.hc.ctype != sid->cu_type ||
-			    pdevreg->ci.hc.cmode != sid->cu_model ||
-			    pdevreg->ci.hc.dtype != sid->dev_type ||
-			    pdevreg->ci.hc.dmode != sid->dev_model)
-				continue;
 		} else if (flag & DEVREG_TYPE_DEVCHARS) {
-			if (!(flag & DEVREG_NO_CU_INFO) &&
-			    pdevreg->ci.hc.ctype != sid->cu_type)
+			if ( (flag & DEVREG_MATCH_CU_TYPE) &&
+			     pdevreg->ci.hc.ctype != sid->cu_type )
+				continue;
+			if ( (flag & DEVREG_MATCH_CU_MODEL) &&
+			     pdevreg->ci.hc.cmode != sid->cu_model )
+				continue;
+			if ( (flag & DEVREG_MATCH_DEV_TYPE) &&
+			     pdevreg->ci.hc.dtype != sid->dev_type )
+				continue;
+			if ( (flag & DEVREG_MATCH_DEV_MODEL) &&
+			     pdevreg->ci.hc.dmode != sid->dev_model )
 				continue;
-
-                        if (!(flag & DEVREG_NO_CU_INFO) &&
-			    !(flag & DEVREG_MATCH_CU_TYPE) &&
-                            pdevreg->ci.hc.cmode != sid->cu_model)
-                                continue;
-
-                        if (!(flag & DEVREG_NO_DEV_INFO) &&
-                            pdevreg->ci.hc.dtype != sid->dev_type)
-                                continue;
-
-                        if (!(flag & DEVREG_NO_DEV_INFO) &&
-                            !(flag & DEVREG_MATCH_DEV_TYPE) &&
-                            pdevreg->ci.hc.dmode != sid->dev_model)
-                                continue;
+		} else {
+			continue;
 		}
+		
 		return pdevreg;
 	}
 	return NULL;
diff -u --recursive --new-file v2.4.7/linux/drivers/s390/s390io.c linux/drivers/s390/s390io.c
--- v2.4.7/linux/drivers/s390/s390io.c	Wed Jul 25 17:10:22 2001
+++ linux/drivers/s390/s390io.c	Wed Jul 25 14:12:02 2001
@@ -15,6 +15,11 @@
  *                                       decrease retry2 on busy while 
  *                                        disabling sync_isc; reset isc_cnt
  *                                        on io error during sync_isc enablement
+ *               05/09/2001 Cornelia Huck added exploitation of debug feature
+ *               05/16/2001 Cornelia Huck added /proc/deviceinfo/<devno>/
+ *               05/22/2001 Cornelia Huck added /proc/cio_ignore
+ *                                        un-ignore blacklisted devices by piping 
+ *                                        to /proc/cio_ignore
  */
 
 #include <linux/module.h>
@@ -24,7 +29,7 @@
 #include <linux/signal.h>
 #include <linux/sched.h>
 #include <linux/interrupt.h>
-#include <linux/malloc.h>
+#include <linux/slab.h>
 #include <linux/string.h>
 #include <linux/smp.h>
 #include <linux/threads.h>
@@ -49,6 +54,7 @@
 #include <asm/s390io.h>
 #include <asm/s390dyn.h>
 #include <asm/s390mach.h>
+#include <asm/debug.h>
 
 #ifndef TRUE
 #define TRUE  1
@@ -79,10 +85,17 @@
 static __u64      irq_IPL_TOD;
 static adapter_int_handler_t adapter_handler   = NULL;
 
+/* for use of debug feature */
+debug_info_t *cio_debug_msg_id = NULL;  
+debug_info_t *cio_debug_trace_id = NULL;
+debug_info_t *cio_debug_crw_id = NULL;
+int cio_debug_initialized = 0;
+
 static void init_IRQ_handler( int irq, void *dev_id, struct pt_regs *regs);
 static void s390_process_subchannels( void);
 static void s390_device_recognition_all( void);
 static void s390_device_recognition_irq( int irq);
+static void s390_redo_validation(void);
 static int  s390_validate_subchannel( int irq, int enable);
 static int  s390_SenseID( int irq, senseid_t *sid, __u8 lpm);
 static int  s390_SetPGID( int irq, __u8 lpm, pgid_t *pgid);
@@ -91,7 +104,7 @@
 static int  enable_subchannel( unsigned int irq);
 static int  disable_subchannel( unsigned int irq);
 
-void chan_proc_init( void );
+static int chan_proc_init( void );
 
 static inline void do_adapter_IO( __u32 intparm );
 
@@ -105,6 +118,16 @@
 
 asmlinkage void do_IRQ( struct pt_regs regs );
 
+#define MAX_CIO_PROCFS_ENTRIES 0x300
+/* magic number; we want to have some room to spare */
+
+int cio_procfs_device_create(int devno);
+int cio_procfs_device_remove(int devno);
+int cio_procfs_device_purge(void);
+
+int cio_notoper_msg = 1;
+int cio_proc_devinfo = 0; /* switch off the /proc/deviceinfo/ stuff by default
+			     until problems are dealt with */
 
 /* 
  * "Blacklisting" of certain devices:
@@ -123,6 +146,7 @@
 
 static dev_blacklist_range_t *dev_blacklist_range_head = NULL; /* Anchor for list of ranges */
 static spinlock_t blacklist_lock = SPIN_LOCK_UNLOCKED;
+static int nr_blacklisted_ranges = 0;
 
 /* Handling of the blacklist ranges */
 
@@ -133,7 +157,16 @@
 static inline dev_blacklist_range_t *blacklist_range_create( int from, int to)
 {
      dev_blacklist_range_t *range = NULL;
-     range = ( dev_blacklist_range_t *) alloc_bootmem( sizeof( dev_blacklist_range_t ) );
+
+     if (to && (from>to)) {
+	     printk("Invalid blacklist range %x to %x, skipping\n", from, to);
+	     return NULL;
+     }
+     if (init_IRQ_complete) {
+	     range = ( dev_blacklist_range_t *) kmalloc( sizeof( dev_blacklist_range_t ), GFP_KERNEL);
+     } else {
+	     range = ( dev_blacklist_range_t *) alloc_bootmem( sizeof( dev_blacklist_range_t ) );
+     }
      if (range == NULL)
 	  return NULL;
      memset( range, 0, sizeof( dev_blacklist_range_t ));
@@ -143,6 +176,7 @@
      } else {
 	  range->to = to;
      }
+     nr_blacklisted_ranges++;
      return range;
 }
 
@@ -153,7 +187,12 @@
 
 static inline void blacklist_range_destroy( dev_blacklist_range_t *range )
 {
-     kfree( range );
+	nr_blacklisted_ranges--;
+	/*
+	 * FIXME: the memory was allocated as bootmem, 
+	 * how to get it free again ?! 
+	 */
+	/* kfree( range ); */
 }
 
 /*
@@ -207,7 +246,7 @@
 /* 
  * Function: blacklist_range_add
  * Creates a range from the specified arguments and appends it to the list of
- * blacklisted devices 
+ * blacklisted devices
  */
 
 static inline dev_blacklist_range_t *blacklist_range_add( int from, int to )
@@ -342,6 +381,9 @@
 #ifdef CONFIG_DEBUG_IO     
      printk( "Reading blacklist...\n");
 #endif
+     if (cio_debug_initialized)
+	     debug_sprintf_event(cio_debug_msg_id, 6,
+				 "Reading blacklist\n");
      blacklist_split_parm_string( blacklist_parm_string );
      blacklist_parse( blacklist );
 }
@@ -366,6 +408,9 @@
 #ifdef CONFIG_DEBUG_IO
 	printk( "Reading blacklist parameters...\n" );
 #endif
+	if (cio_debug_initialized)
+		debug_sprintf_event(cio_debug_msg_id, 6,
+				    "Reading blacklist parameters\n");
         blacklist_setup(str,&dummy);
 	
 	blacklist_init(); /* Blacklist ranges must be ready when device recognition starts */
@@ -401,10 +446,107 @@
      return 0;
 }
 
+/*
+ * Function: blacklist_free_all_ranges
+ * set all blacklisted devices free...
+ */
+
+void blacklist_free_all_ranges(void) 
+{
+	dev_blacklist_range_t *tmp = dev_blacklist_range_head;
+
+	while (tmp) {
+		blacklist_range_dechain(tmp);
+		blacklist_range_destroy(tmp);
+		tmp = dev_blacklist_range_head;
+	}
+}
+
+/*
+ * Function: blacklist_parse_proc_parameters
+ * parse the stuff which is piped to /proc/cio_ignore
+ */
+void blacklist_parse_proc_parameters(char *buf)
+{
+	char *tmp;
+	int i;
+	char *end;
+	int len = -1;
+	char *param;
+	int from = 0;
+	int to = 0;
+	int changed = 0;
+	dev_blacklist_range_t *range, *temp;
+
+	tmp = buf;
+	if (strstr(tmp, "free ")) {
+		for (i=0; i<5; i++) {
+			tmp++;
+		}
+		if (strstr(tmp, "all")) {
+			blacklist_free_all_ranges();
+			s390_redo_validation();
+		} else {
+			while (tmp != NULL) {
+				end = strchr(tmp, ',');
+				if (end == NULL) {
+					len = strlen(tmp) + 1;
+				} else {
+					len = (long)end - (long) tmp + 1;
+					*end = '\0';
+					end++;
+				}
+				param =  (char*) kmalloc(len * sizeof(char) + 1, GFP_KERNEL);
+				strncpy(param, (const char *) tmp, len);
+				tmp = end;
+				from = blacklist_strtoul(param, &param);
+				if (*param == '-') {
+					param++;
+					to = blacklist_strtoul(param, &param);
+				} else {
+					to = from;
+				}
+				range = dev_blacklist_range_head;
+				while (range != NULL) {
+					temp = range->next;
+					if ((from <= range->from) && (to >= range->to)) {
+						blacklist_range_dechain(range);
+						blacklist_range_destroy(range);
+						changed = 1;
+					} else if ((from <= range->from) && (to>=range->from) && (to < range->to)) {
+						blacklist_range_add(to+1, range->to);
+						blacklist_range_dechain(range);
+						blacklist_range_destroy(range);
+						changed = 1;
+					} else if ((from > range->from) && (from<=range->to) && (to >= range->to)) {
+						blacklist_range_add(range->from, from-1);
+						blacklist_range_dechain(range);
+						blacklist_range_destroy(range);
+						changed = 1;
+					} else if ((from > range->from) && (to < range->to)) {
+						blacklist_range_add(range->from, from-1);
+						blacklist_range_add(to+1, range->to);
+						blacklist_range_dechain(range);
+						blacklist_range_destroy(range);
+						changed = 1;
+					}
+					range = temp;
+				}
+				kfree(param);
+			}
+			if (changed)
+				s390_redo_validation();
+		}
+	} else {
+		printk("cio_ignore: Parse error; try using 'free all|<devno-range>,<devno-range>,...'\n");
+	}
+}
+
 /* End of blacklist handling */
 
 
 void s390_displayhex(char *str,void *ptr,s32 cnt);
+void s390_displayhex2(char *str, void *ptr, s32 cnt, int level);
 
 void s390_displayhex(char *str,void *ptr,s32 cnt)
 {
@@ -425,6 +567,23 @@
 	}
 }
 
+void s390_displayhex2(char *str, void *ptr, s32 cnt, int level)
+{
+	s32 cnt1, cnt2, maxcnt2;
+	u32 *currptr = (__u32 *)ptr;
+
+	debug_sprintf_event(cio_debug_msg_id, level, "%s\n", str);
+
+	for (cnt1 = 0; cnt1<cnt; cnt1+=16) {
+		debug_sprintf_event(cio_debug_msg_id, level, "%08lX ", (unsigned long)currptr);
+		maxcnt2 = cnt - cnt1;
+		if (maxcnt2 > 16)
+			maxcnt2 = 16;
+		for (cnt2 = 0; cnt2 < maxcnt2; cnt2 += 4)
+			debug_sprintf_event(cio_debug_msg_id, level, "%08X ", *currptr++);
+	}
+}
+
 static int __init cio_setup( char *parm )
 {
 	if ( !strcmp( parm, "yes") )
@@ -446,6 +605,35 @@
 
 __setup("cio_msg=", cio_setup);
 
+static int __init cio_notoper_setup(char *parm)
+{
+	if (!strcmp(parm, "yes")) {
+		cio_notoper_msg = 1;
+	} else if (!strcmp(parm, "no")) {
+		cio_notoper_msg = 0;
+	} else {
+		printk("cio_notoper_setup: invalid cio_notoper_msg parameter '%s'", parm);
+	}
+
+	return 1;
+}
+	
+__setup("cio_notoper_msg=", cio_notoper_setup);
+
+static int __init cio_proc_devinfo_setup(char *parm)
+{
+	if (!strcmp(parm, "yes")) {
+		cio_proc_devinfo = 1;
+	} else if (!strcmp(parm, "no")) {
+		cio_proc_devinfo = 0;
+	} else {
+		printk("cio_proc_devinfo_setup: invalid parameter '%s'\n",parm);
+	}
+
+	return 1;
+}
+
+__setup("cio_proc_devinfo=", cio_proc_devinfo_setup);
 
 /*
  * register for adapter interrupts
@@ -461,6 +649,9 @@
 int  s390_register_adapter_interrupt( adapter_int_handler_t handler )
 {
 	int ret = 0;
+	
+	if (cio_debug_initialized)
+		debug_text_event(cio_debug_trace_id, 4, "rgaint");
 
 	spin_lock( &adapter_lock );
 
@@ -480,6 +671,9 @@
 int  s390_unregister_adapter_interrupt( adapter_int_handler_t handler )
 {
 	int ret = 0;
+	
+	if (cio_debug_initialized)
+		debug_text_event(cio_debug_trace_id, 4, "urgaint");
 
 	spin_lock( &adapter_lock ); 	
 
@@ -497,6 +691,9 @@
 
 static inline void do_adapter_IO( __u32 intparm )
 {
+	if (cio_debug_initialized)
+		debug_text_event(cio_debug_trace_id, 4, "doaio");
+	
 	spin_lock( &adapter_lock ); 	
 
 	if ( adapter_handler )
@@ -507,7 +704,6 @@
 	return;  	
 }
 
-
 int s390_request_irq_special( int                      irq,
                               io_handler_func_t        io_handler,
                               not_oper_handler_func_t  not_oper_handler,
@@ -517,6 +713,7 @@
 {
 	int		retval = 0;
 	unsigned long	flags;
+	char            dbf_txt[15];
 
 	if (irq >= __MAX_SUBCHANNELS)
 		return -EINVAL;
@@ -528,6 +725,12 @@
 		return -ENODEV;
 
 
+	if (cio_debug_initialized) {
+		debug_text_event(cio_debug_trace_id, 4, "reqsp");
+		sprintf(dbf_txt, "%x", irq);
+		debug_text_event(cio_debug_trace_id, 4, dbf_txt);
+	}
+
 	/*
 	 * The following block of code has to be executed atomically
 	 */
@@ -598,6 +801,7 @@
 	int          ret;
 
 	unsigned int count = 0;
+	char dbf_txt[15];
 
 	if ( irq >= __MAX_SUBCHANNELS || ioinfo[irq] == INVALID_STORAGE_AREA )
 	{
@@ -605,6 +809,12 @@
 
 	} /* endif */
 
+	if (cio_debug_initialized) {
+		debug_text_event(cio_debug_trace_id, 2, "free");
+		sprintf(dbf_txt, "%x", irq);
+		debug_text_event(cio_debug_trace_id, 2, dbf_txt);
+	}
+
 	s390irq_spin_lock_irqsave( irq, flags);
 
 #ifdef  CONFIG_KERNEL_DEBUG
@@ -614,6 +824,8 @@
 
 	} /* endif */
 #endif
+	if (cio_debug_initialized)
+		debug_sprintf_event(cio_debug_msg_id, 2, "Trying to free IRQ %d\n", irq);
 
 	/*
 	 * disable the device and reset all IRQ info if
@@ -687,6 +899,10 @@
 							       "count exceeded\n",
 						   	    irq,
 						      	 ioinfo[irq]->devstat.devno);
+							if (cio_debug_initialized)
+								debug_sprintf_event(cio_debug_msg_id, 0,
+										    "free_irq(%04X) - device %04X busy, retry count exceeded\n",
+										    irq, ioinfo[irq]->devstat.devno);
 
                   } /* endif */
 						
@@ -710,7 +926,10 @@
 			s390irq_spin_unlock_irqrestore( irq, flags);
 
 			printk( "free_irq(%04X) : error, "
-			        "dev_id does not match !", irq);
+			        "dev_id does not match !\n", irq);
+			if (cio_debug_initialized)
+				debug_sprintf_event(cio_debug_msg_id, 0, 
+						    "free_irq(%04X) : error, dev_id does not match !\n", irq);
 
 		} /* endif */
 
@@ -721,6 +940,9 @@
 
 		printk( "free_irq(%04X) : error, "
 		        "no action block ... !\n", irq);
+		if (cio_debug_initialized)
+			debug_sprintf_event(cio_debug_msg_id, 0,
+					    "free_irq(%04X) : error, no action block ... !\n", irq);
 
 	} /* endif */
 
@@ -733,6 +955,7 @@
 {
 	unsigned long flags;
 	int           ret;
+	char dbf_txt[15];
 
 	if ( ioinfo[irq] == INVALID_STORAGE_AREA )
 		return( -ENODEV);
@@ -740,6 +963,12 @@
 	if ( !ioinfo[irq]->ui.flags.ready )
 		return -ENODEV;
 
+	if (cio_debug_initialized) {
+		debug_text_event(cio_debug_trace_id, 4, "disirq");
+		sprintf(dbf_txt, "%x", irq);
+		debug_text_event(cio_debug_trace_id, 4, dbf_txt);
+	}
+
 	s390irq_spin_lock_irqsave(irq, flags);
 	ret = disable_subchannel(irq);
 	s390irq_spin_unlock_irqrestore(irq, flags);
@@ -753,6 +982,7 @@
 {
 	unsigned long flags;
 	int           ret;
+	char dbf_txt[15];
 
 	if ( ioinfo[irq] == INVALID_STORAGE_AREA )
 		return( -ENODEV);
@@ -760,6 +990,12 @@
 	if ( !ioinfo[irq]->ui.flags.ready )
 		return -ENODEV;
 
+	if (cio_debug_initialized) {
+		debug_text_event(cio_debug_trace_id, 4, "enirq");
+		sprintf(dbf_txt, "%x", irq);
+		debug_text_event(cio_debug_trace_id, 4, dbf_txt);
+	}
+
 	s390irq_spin_lock_irqsave(irq, flags);
 	ret = enable_subchannel(irq);
 	s390irq_spin_unlock_irqrestore(irq, flags);
@@ -775,6 +1011,7 @@
 	int   ret;
 	int   ccode;
 	int   retry = 5;
+	char dbf_txt[15];
 
 	if ( irq > highest_subchannel || irq < 0 )
 	{
@@ -785,6 +1022,12 @@
 	if ( ioinfo[irq] == INVALID_STORAGE_AREA )
 		return( -ENODEV);
 
+	if (cio_debug_initialized) {
+		debug_text_event(cio_debug_trace_id, 2, "ensch");
+		sprintf(dbf_txt, "%x", irq);
+		debug_text_event(cio_debug_trace_id, 2, dbf_txt);
+	}
+
 	/*
 	 * If a previous disable request is pending we reset it. However, this
 	 *  status implies that the device may (still) be not-operational.
@@ -862,6 +1105,10 @@
 					        "%04X received !\n",
 					        irq,
 					        ioinfo[irq]->devstat.devno);
+					if (cio_debug_initialized)
+						debug_sprintf_event(cio_debug_msg_id, 0,
+								    "enable_subchannel(%04X) : ccode 2 on msch() for device %04X received !\n",
+								    irq, ioinfo[irq]->devstat.devno);
 
 					ret = -ENODEV; // never reached
 				}
@@ -884,6 +1131,7 @@
 	int  cc;          /* condition code */
 	int  ret;         /* function return value */
 	int  retry = 5;
+	char dbf_txt[15];
 
 	if ( irq > highest_subchannel )
 	{
@@ -903,6 +1151,12 @@
 	}
 	else
 	{
+		if (cio_debug_initialized) {
+			debug_text_event(cio_debug_trace_id, 2, "dissch");
+			sprintf(dbf_txt, "%x", irq);
+			debug_text_event(cio_debug_trace_id, 2, dbf_txt);
+		}
+		
 		/*
 		 * If device isn't operational we have to perform delayed
 		 *  disabling when the next interrupt occurs - unless the
@@ -962,6 +1216,10 @@
 							  "device %04X received !\n",
 					        irq,
 					        ioinfo[irq]->devstat.devno);
+					if (cio_debug_initialized)
+						debug_sprintf_event(cio_debug_msg_id, 0, 
+								    "disable_subchannel(%04X) - unexpected busy condition for device %04X received !\n",
+								    irq, ioinfo[irq]->devstat.devno);
 					ret = -EBUSY;
 					break;
 
@@ -998,14 +1256,6 @@
 	unsigned long flags;     /* PSW flags */
 	long          cr6 __attribute__ ((aligned (8)));
 
-	// Hopefully bh_count's will get set when we copy the prefix lowcore
-	// structure to other CPI's ( DJB )
-	softirq_active(smp_processor_id()) = 0;
-	softirq_mask(smp_processor_id()) = 0;
-	local_bh_count(smp_processor_id()) = 0;
-	local_irq_count(smp_processor_id()) = 0;
-	syscall_count(smp_processor_id()) = 0;
-
 	asm volatile ("STCK %0" : "=m" (irq_IPL_TOD));
 
 	p_init_schib = alloc_bootmem_low( sizeof(schib_t));
@@ -1065,6 +1315,8 @@
 {
 	int            ccode;
 	int            ret = 0;
+	char buffer[80];
+	char dbf_txt[15];
 
 	/*
 	 * The flag usage is mutal exclusive ...
@@ -1076,6 +1328,12 @@
 
 	} /* endif */
 
+	if (cio_debug_initialized) {
+		debug_text_event(cio_debug_trace_id, 4, "stIO");
+		sprintf(dbf_txt, "%x", irq);
+		debug_text_event(cio_debug_trace_id, 4, dbf_txt);
+	}
+
 	/*
 	 * setup ORB
 	 */
@@ -1367,18 +1625,17 @@
 			{
 				ret                         = -ENODEV;
 				ioinfo[irq]->ui.flags.oper  = 0;
-         }
+			}
 			else
 			{
 				ret = -EIO;
 
-         } /* endif */
+			} /* endif */
 
 			ioinfo[irq]->devstat.flag  |= DEVSTAT_NOT_OPER;
 
 #ifdef CONFIG_DEBUG_IO
 			{
-			char buffer[80];
 
 			stsch(irq, &(ioinfo[irq]->schib) );
 
@@ -1416,6 +1673,41 @@
 			} /* endif */
 			}
 #endif
+			if (cio_debug_initialized) {
+				stsch(irq, &(ioinfo[irq]->schib) );
+				
+				sprintf( buffer, "s390_start_IO(%04X) - irb for "
+					 "device %04X, after status pending\n",
+					 irq,
+					 ioinfo[irq]->devstat.devno );
+				
+				s390_displayhex2( buffer,
+						 &(ioinfo[irq]->devstat.ii.irb) ,
+						 sizeof(irb_t), 2);
+				
+				sprintf( buffer, "s390_start_IO(%04X) - schib for "
+					 "device %04X, after status pending\n",
+					 irq,
+					 ioinfo[irq]->devstat.devno );
+				
+				s390_displayhex2( buffer,
+						 &(ioinfo[irq]->schib) ,
+						 sizeof(schib_t), 2);
+				
+				
+				if (ioinfo[irq]->devstat.flag & DEVSTAT_FLAG_SENSE_AVAIL) {
+					sprintf( buffer, "s390_start_IO(%04X) - sense "
+						 "data for "
+						 "device %04X, after status pending\n",
+						 irq,
+						 ioinfo[irq]->devstat.devno );
+					
+					s390_displayhex2( buffer,
+							  ioinfo[irq]->irq_desc.dev_id->ii.sense.data,
+							  ioinfo[irq]->irq_desc.dev_id->rescnt, 2);
+					
+				} /* endif */
+			}
 		}
 		else
 		{
@@ -1457,9 +1749,8 @@
 		        &(ioinfo[irq]->devstat),
 		        sizeof( devstat_t) );
 
+
 #ifdef CONFIG_DEBUG_IO
-		{
-			char buffer[80];
 
    			stsch(irq, &(ioinfo[irq]->schib) );
 
@@ -1471,8 +1762,20 @@
 			s390_displayhex( buffer,
 			                 &(ioinfo[irq]->schib),
 			                 sizeof(schib_t));
-      	}
 #endif
+		if (cio_debug_initialized) {
+			stsch(irq, &(ioinfo[irq]->schib) );
+
+			sprintf( buffer, "s390_start_IO(%04X) - schib for "
+			         "device %04X, after 'not oper' status\n",
+			         irq,
+			         ioinfo[irq]->devstat.devno );
+
+			s390_displayhex2( buffer,
+			                 &(ioinfo[irq]->schib),
+			                 sizeof(schib_t), 2);
+		}
+			
 		break;
 
 	} /* endswitch */
@@ -1499,6 +1802,7 @@
            unsigned long  flag)         /* flags : see above */
 {
 	int ret = 0;
+	char dbf_txt[15];
 
 	if ( irq > highest_subchannel || irq < 0 )
 	{
@@ -1518,6 +1822,12 @@
 
 	} /* endif */
 
+	if (cio_debug_initialized) {
+		debug_text_event(cio_debug_trace_id, 4, "doIO");
+		sprintf(dbf_txt, "%x", irq);
+		debug_text_event(cio_debug_trace_id, 4, dbf_txt);
+	}
+
 	/*
 	 * Note: We ignore the device operational status - if not operational,
 	 *        the SSCH will lead to an -ENODEV condition ...
@@ -1567,6 +1877,7 @@
 int resume_IO( int irq)
 {
 	int ret = 0;
+	char dbf_txt[15];
 
 	if ( irq > highest_subchannel || irq < 0 )
 	{
@@ -1579,6 +1890,12 @@
 		return( -ENODEV);
 	}
 
+	if (cio_debug_initialized) {
+		debug_text_event(cio_debug_trace_id, 4, "resIO");
+		sprintf(dbf_txt, "%x", irq);
+		debug_text_event(cio_debug_trace_id, 4, dbf_txt);
+	}
+
 	/*
 	 * We allow for 'resume' requests only for active I/O operations
 	 */
@@ -1635,16 +1952,17 @@
 {
 	int            ret;
 	int            ccode;
+	char dbf_txt[15];
 
 	if ( irq > highest_subchannel || irq < 0 )
 	{
-		ret = -ENODEV;
+		return -ENODEV;
 	}
 
 	if ( ioinfo[irq] == INVALID_STORAGE_AREA )
 	{
 		return( -ENODEV);
-   }
+	}
 
 	/*
 	 * we only allow for halt_IO if the device has an I/O handler associated
@@ -1671,6 +1989,11 @@
 	}
 	else
 	{
+		if (cio_debug_initialized) {
+			debug_text_event(cio_debug_trace_id, 2, "haltIO");
+			sprintf(dbf_txt, "%x", irq);
+			debug_text_event(cio_debug_trace_id, 2, dbf_txt);
+		}
 		/*
 		 * If sync processing was requested we lock the sync ISC,
 		 *  modify the device to present interrupts for this ISC only
@@ -1895,10 +2218,11 @@
 {
 	int            ret;
 	int            ccode;
+	char dbf_txt[15];
 
 	if ( irq > highest_subchannel || irq < 0 )
 	{
-		ret = -ENODEV;
+		return -ENODEV;
 	}
 
 	if ( ioinfo[irq] == INVALID_STORAGE_AREA )
@@ -1932,6 +2256,11 @@
 	}
 	else
 	{
+		if (cio_debug_initialized) {
+			debug_text_event(cio_debug_trace_id, 2, "clearIO");
+			sprintf(dbf_txt, "%x", irq);
+			debug_text_event(cio_debug_trace_id, 2, dbf_txt);
+		}
 		/*
 		 * If sync processing was requested we lock the sync ISC,
 		 *  modify the device to present interrupts for this ISC only
@@ -2066,7 +2395,7 @@
 			break;
 
 		case 1 :            /* status pending */
-	
+
 			ioinfo[irq]->devstat.flag |= DEVSTAT_STATUS_PENDING;
 
 			/*
@@ -2117,7 +2446,7 @@
 				ioinfo[irq]->devstat.flag  &= ~DEVSTAT_NOT_OPER;
 				ioinfo[irq]->ui.flags.oper  = 1;
 
-			} /* endif */
+			} /* endif */ 
 
 			break;
 
@@ -2172,7 +2501,6 @@
 		return;
 	} /* endif */
 
-	
 #ifdef CONFIG_FAST_IRQ
 	do {
 #endif /*  CONFIG_FAST_IRQ */
@@ -2252,12 +2580,20 @@
 	int               chnchk          = 0;
 	devstat_t        *dp;
 	devstat_t        *udp;
+
+	char dbf_txt[15];
 #if 0
 	int               cpu             = smp_processor_id();
 
 	kstat.irqs[cpu][irq]++;
 #endif
 
+	if (cio_debug_initialized) {
+		debug_text_event(cio_debug_trace_id, 3, "procIRQ");
+		sprintf(dbf_txt, "%x", irq);
+		debug_text_event(cio_debug_trace_id, 3, dbf_txt);
+	}
+
 	if ( ioinfo[irq] == INVALID_STORAGE_AREA )
 	{
 		/* we can't properly process the interrupt ... */
@@ -2270,7 +2606,6 @@
 	udp = ioinfo[irq]->irq_desc.dev_id;
 	
 
-#ifdef CONFIG_DEBUG_IO
 	/*
 	 * It might be possible that a device was not-oper. at the time
 	 *  of free_irq() processing. This means the handler is no longer
@@ -2281,16 +2616,20 @@
 	{
 		if ( !ioinfo[irq]->ui.flags.d_disable )
 		{
+#ifdef CONFIG_DEBUG_IO
 			printk( KERN_CRIT"s390_process_IRQ(%04X) "
 			        "- no interrupt handler registered "
 					  "for device %04X !\n",
 			        irq,
 			        ioinfo[irq]->devstat.devno);
-
+#endif /* CONFIG_DEBUG_IO */
+			if (cio_debug_initialized)
+				debug_sprintf_event(cio_debug_msg_id, 0,
+						    "s390_process_IRQ(%04X) - no interrupt handler registered for device %04X !\n",
+						    irq, ioinfo[irq]->devstat.devno);
 		} /* endif */
 
 	} /* endif */
-#endif
 
 	/*
 	 * retrieve the i/o interrupt information (irb),
@@ -2360,6 +2699,10 @@
 			        "residual count from irb after tsch() %d\n",
 			        irq, dp->rescnt );
 #endif
+		if (cio_debug_initialized)
+			debug_sprintf_event(cio_debug_msg_id, 6,
+					    "s390_process_IRQ( %04X ) : residual count from irq after tsch() %d\n",
+					    irq, dp->rescnt);
 
 	} /* endif */
 
@@ -2372,17 +2715,24 @@
 	if (    (dp->ii.irb.scsw.cstat
 	            & (  SCHN_STAT_CHN_DATA_CHK
 	               | SCHN_STAT_CHN_CTRL_CHK
-	               | SCHN_STAT_INTF_CTRL_CHK )       )
-	     && (irq != cons_dev                         ) )
+			 | SCHN_STAT_INTF_CTRL_CHK )))
 	{
-		printk( "Channel-Check or Interface-Control-Check "
-		        "received\n"
-		        " ... device %04X on subchannel %04X, dev_stat "
-		        ": %02X sch_stat : %02X\n",
-		        ioinfo[irq]->devstat.devno,
-		        irq,
-		        dp->dstat,
-		        dp->cstat);
+		if (irq != cons_dev)
+			printk( "Channel-Check or Interface-Control-Check "
+				"received\n"
+				" ... device %04X on subchannel %04X, dev_stat "
+				": %02X sch_stat : %02X\n",
+				ioinfo[irq]->devstat.devno,
+				irq,
+				dp->dstat,
+				dp->cstat);
+		if (cio_debug_initialized) {
+			debug_sprintf_event(cio_debug_msg_id, 0,
+					    "Channel-Check or Interface-Control-Check received\n");
+			debug_sprintf_event(cio_debug_msg_id, 0,
+					    "... device %04X on subchannel %04X, dev_stat: %02X sch_stat: %02X\n",
+					    ioinfo[irq]->devstat.devno, irq, dp->dstat, dp->cstat);
+		}
 
 		chnchk = 1;
 
@@ -2422,6 +2772,10 @@
 			        "concurrent sense bytes avail %d\n",
 			        irq, dp->scnt );
 #endif
+		if (cio_debug_initialized)
+			debug_sprintf_event(cio_debug_msg_id, 4,
+					    "s390_process_IRQ( %04X ): concurrent sense bytes avail %d\n",
+					    irq, dp->scnt);
 	}
 	else
 	{
@@ -2453,6 +2807,17 @@
 			s390_displayhex( buffer,
 			                 &(dp->ii.irb) ,
 			                 sizeof(irb_t));
+			if (cio_debug_initialized) {
+				
+				sprintf( buffer, "s390_process_IRQ(%04X) - irb for "
+			         "device %04X after channel check\n",
+			         irq,
+			         dp->devno );
+
+				s390_displayhex2( buffer,
+						  &(dp->ii.irb) ,
+						  sizeof(irb_t), 0);
+			}
 		} /* endif */
 			
 		ioinfo[irq]->stctl |= stctl;
@@ -2473,20 +2838,19 @@
 		 *       unsolicited interrupt applies to the console device
 		 *       itself !
 		 */
-#ifdef CONFIG_DEBUG_IO
-		if (     ( irq != cons_dev                 )
-			 && !( stctl & SCSW_STCTL_ALERT_STATUS )
-			 &&  ( ioinfo[irq]->ui.flags.busy == 0  ) )
+		if ( !( stctl & SCSW_STCTL_ALERT_STATUS )
+		     &&  ( ioinfo[irq]->ui.flags.busy == 0  ) )
 		{
 			char buffer[80];
-
-			printk( "Unsolicited interrupt received for device %04X on subchannel %04X\n"
-				" ... device status : %02X subchannel status : %02X\n",
-				dp->devno,
-				irq,
-				dp->dstat,
-				dp->cstat);
-
+#ifdef CONFIG_DEBUG_IO
+			if (irq != cons_dev)
+				printk( "Unsolicited interrupt received for device %04X on subchannel %04X\n"
+					" ... device status : %02X subchannel status : %02X\n",
+					dp->devno,
+					irq,
+					dp->dstat,
+					dp->cstat);
+			
 			sprintf( buffer, "s390_process_IRQ(%04X) - irb for "
 			         "device %04X, ending_status %d\n",
 			         irq,
@@ -2496,10 +2860,27 @@
 			s390_displayhex( buffer,
 			                 &(dp->ii.irb) ,
 			                 sizeof(irb_t));
-
+#endif
+			if (cio_debug_initialized) {
+				debug_sprintf_event(cio_debug_msg_id, 2, 
+						    "Unsolicited interrupt received for device %04X on subchannel %04X\n"
+						    " ... device status : %02X subchannel status : %02X\n",
+						    dp->devno,
+						    irq,
+						    dp->dstat,
+						    dp->cstat);
+				sprintf( buffer, "s390_process_IRQ(%04X) - irb for "
+					 "device %04X, ending_status %d\n",
+					 irq,
+					 dp->devno,
+					 ending_status);
+				
+				s390_displayhex2( buffer,
+						 &(dp->ii.irb) ,
+						 sizeof(irb_t), 2);	
+			}
 		} /* endif */
 
-#endif
 		/*
 		 * take fast exit if no handler is available
 		 */
@@ -2639,11 +3020,15 @@
 				int sense_count = SENSE_MAX_COUNT-ioinfo[irq]->devstat.rescnt;
 
 #ifdef CONFIG_DEBUG_IO
-      if ( irq != cons_dev )
-         printk( "s390_process_IRQ( %04X ) : "
-                 "BASIC SENSE bytes avail %d\n",
-                 irq, sense_count );
-#endif
+				if ( irq != cons_dev )
+					printk( "s390_process_IRQ( %04X ) : "
+						"BASIC SENSE bytes avail %d\n",
+						irq, sense_count );
+#endif
+				if (cio_debug_initialized)
+					debug_sprintf_event(cio_debug_msg_id, 4,
+							    "s390_process_IRQ( %04X ): BASIC SENSE bytes avail %d\n",
+							    irq, sense_count);
 				ioinfo[irq]->ui.flags.w4sense = 0;
 				udp->flag |= DEVSTAT_FLAG_SENSE_AVAIL;
 				udp->scnt  = sense_count;
@@ -2664,6 +3049,11 @@
 					printk( KERN_CRIT"s390_process_IRQ(%04x) encountered "
 					        "negative sense count\n",
 					        irq);
+					if (cio_debug_initialized)
+						debug_sprintf_event(cio_debug_msg_id, 0,
+								    "s390_process_IRQ(%04x) encountered "
+								    "negative sense count\n",
+								    irq);		    
 #endif
 				} /* endif */
 			}
@@ -2906,6 +3296,7 @@
 	int           ccode;
 	unsigned long cr6 __attribute__ ((aligned (8)));
 	int           rc = 0;
+	char dbf_txt[15];
 
 	if ( cons_dev != -1  )
 	{
@@ -2921,6 +3312,12 @@
    }
 	else
 	{
+		if (cio_debug_initialized) {
+			debug_text_event(cio_debug_trace_id, 4, "scons");
+			sprintf(dbf_txt, "%x", irq);
+			debug_text_event(cio_debug_trace_id, 4, dbf_txt);
+		}
+		
 		/*
 		 * modify the indicated console device to operate
 		 *  on special console interrupt sublass 7
@@ -2967,6 +3364,7 @@
 	int     rc = 0;
 	int     ccode;
 	long    cr6 __attribute__ ((aligned (8)));
+	char dbf_txt[15];
 
 	if ( cons_dev != -1  )
 	{
@@ -2982,6 +3380,12 @@
    }
 	else
 	{
+		if (cio_debug_initialized) {
+			debug_text_event(cio_debug_trace_id, 4, "rcons");
+			sprintf(dbf_txt, "%x", irq);
+			debug_text_event(cio_debug_trace_id, 4, dbf_txt);
+		}
+
 		/*
 		 * reset the indicated console device to operate
 		 *  on default console interrupt sublass 3
@@ -3028,10 +3432,17 @@
 {
 	int              rc = 0;
 	long             save_cr6;
+	char dbf_txt[15];
 
 	if ( irq == cons_dev )
 	{
 
+		if (cio_debug_initialized) {
+			debug_text_event(cio_debug_trace_id, 4, "wcons");
+			sprintf(dbf_txt, "%x", irq);
+			debug_text_event(cio_debug_trace_id, 4, dbf_txt);
+		}
+
 		/*
 		 * before entering the spinlock we may already have
 		 *  processed the interrupt on a different CPU ...
@@ -3087,6 +3498,13 @@
 
 	int             count = 0;
 	int             rc    = 0;
+	char dbf_txt[15];
+
+	if (cio_debug_initialized) {
+		debug_text_event(cio_debug_trace_id, 4, "enisc");
+		sprintf(dbf_txt, "%x", irq);
+		debug_text_event(cio_debug_trace_id, 4, dbf_txt);
+	}
 
 	/* This one spins until it can get the sync_isc lock for irq# irq */
 
@@ -3171,6 +3589,7 @@
 
 		} /* endif */
 
+
 		if ( rc )	/* can only happen if stsch/msch fails */
 		{
 			sync_isc_cnt = 0;
@@ -3200,6 +3619,14 @@
 	int     ccode;
 	long    cr6 __attribute__ ((aligned (8)));
 
+	char dbf_txt[15];
+
+	if (cio_debug_initialized) {
+		debug_text_event(cio_debug_trace_id, 4, "disisc");
+		sprintf(dbf_txt, "%x", irq);
+		debug_text_event(cio_debug_trace_id, 4, dbf_txt);
+	}
+
 	if ( irq <= highest_subchannel && ioinfo[irq] != INVALID_STORAGE_AREA )
 	{
 		/*
@@ -3311,6 +3738,9 @@
 
 	int        error = 0;
 
+	if (cio_debug_initialized) 
+		debug_text_event(cio_debug_trace_id, 4, "VMvdinf");
+
 	if ( init_IRQ_complete )
 	{
 		p_diag_data = kmalloc( sizeof( diag210_t), GFP_DMA );
@@ -3596,6 +4026,19 @@
 			p_diag_data->vrdcrccl,
 			p_diag_data->vrdccrty,
 			p_diag_data->vrdccrmd );
+		if (cio_debug_initialized)
+			debug_sprintf_event( cio_debug_msg_id, 0,
+					     "DIAG X'210' for "
+					     "device %04X returned "
+					     "(cc = %d): vdev class : %02X, "
+					     "vdev type : %04X \n ...  rdev class : %02X, rdev type : %04X, rdev model: %02X\n",
+					     devno,
+					     ccode,
+					     p_diag_data->vrdcvcla,
+					     p_diag_data->vrdcvtyp,
+					     p_diag_data->vrdcrccl,
+					     p_diag_data->vrdccrty,
+					     p_diag_data->vrdccrmd );
 
 	} /* endif */
 
@@ -3636,6 +4079,8 @@
 	int           emulated = 0;
 	int           retry    = 5;
 
+	char dbf_txt[15];
+
 	if ( !buffer || !length )
 	{
 		return( -EINVAL );
@@ -3650,7 +4095,7 @@
 	else if ( ioinfo[irq] == INVALID_STORAGE_AREA )
 	{
 		return( -ENODEV);
-   }
+	}
 
 	if ( ioinfo[irq]->ui.flags.oper == 0 )
 	{
@@ -3658,6 +4103,12 @@
 
 	} /* endif */
 
+	if (cio_debug_initialized) {
+		debug_text_event(cio_debug_trace_id, 4, "rddevch");
+		sprintf(dbf_txt, "%x", irq);
+		debug_text_event(cio_debug_trace_id, 4, dbf_txt);
+	}
+
 	/*
 	 * Before playing around with irq locks we should assure
 	 *   running disabled on (just) our CPU. Sync. I/O requests
@@ -3769,6 +4220,8 @@
 	int           found  = 0; // RCD CIW found
 	int           ret    = 0; // return code
 
+	char dbf_txt[15];
+
 	if ( (irq > highest_subchannel) || (irq < 0 ) )
 	{
 		return( -ENODEV );
@@ -3791,6 +4244,12 @@
 
 	} /* endif */
 
+	if (cio_debug_initialized) {
+		debug_text_event(cio_debug_trace_id, 4, "rdconf");
+		sprintf(dbf_txt, "%x", irq);
+		debug_text_event(cio_debug_trace_id, 4, dbf_txt);
+	}
+
 	/*
 	 * scan for RCD command in extended SenseID data
 	 */
@@ -4262,6 +4721,13 @@
 void s390_device_recognition_irq( int irq )
 {
 	int           ret;
+	char dbf_txt[15];
+
+	if (cio_debug_initialized) {
+		debug_text_event(cio_debug_trace_id, 4, "devrec");
+		sprintf(dbf_txt, "%x", irq);
+		debug_text_event(cio_debug_trace_id, 4, dbf_txt);
+	}
 
 	/*
 	 * We issue the SenseID command on I/O subchannels we think are
@@ -4274,7 +4740,7 @@
 		int       irq_ret;
 		devstat_t devstat;
 
-	   irq_ret = request_irq( irq,
+		irq_ret = request_irq( irq,
 		                       init_IRQ_handler,
 		                       0,
 		                       "INIT",
@@ -4284,7 +4750,7 @@
 		{
 			ret = enable_cpu_sync_isc( irq );
 
-			if ( !ret )
+			if ( !ret ) 
 			{
 				ioinfo[irq]->ui.flags.unknown = 0;
 
@@ -4305,9 +4771,8 @@
 
 					if ( !ret )	// on success only ...
 					{
-#ifdef CONFIG_DEBUG_IO
 						char buffer[80];
-
+#ifdef CONFIG_DEBUG_IO
 						sprintf( buffer,
 						         "RCD for device(%04X)/"
 						         "subchannel(%04X) returns :\n",
@@ -4316,6 +4781,15 @@
 
 						s390_displayhex( buffer, prcd, lrcd );
 #endif      				
+						if (cio_debug_initialized) {
+							sprintf( buffer,
+								 "RCD for device(%04X)/"
+								 "subchannel(%04X) returns :\n",
+								 ioinfo[irq]->schib.pmcw.dev,
+								 irq );
+							
+							s390_displayhex2( buffer, prcd, lrcd, 2);
+						}
 						if ( init_IRQ_complete )
 						{
 							kfree( prcd );
@@ -4326,9 +4800,9 @@
 
  			  			} /* endif */
 
-	   			} /* endif */
-
-     	      } /* endif */
+					} /* endif */
+					
+				} /* endif */
 #endif
 				s390_DevicePathVerification( irq, 0 );
 
@@ -4364,6 +4838,44 @@
 
 }
 
+/*
+ * Function: s390_redo_validation
+ * Look for no longer blacklisted devices
+ * FIXME: there must be a better way to do this...
+ */
+
+void s390_redo_validation(void) 
+{
+	int irq = 0;
+	int ret;
+
+	if (cio_debug_initialized) {
+		debug_text_event(cio_debug_trace_id, 0, "redoval");
+	}
+	do {
+		if (ioinfo[irq] == INVALID_STORAGE_AREA) {
+			ret = s390_validate_subchannel(irq, 0);
+			if (!ret) {
+				s390_device_recognition_irq(irq);
+				if (ioinfo[irq]->ui.flags.oper) {
+					devreg_t *pdevreg;
+					
+					pdevreg = s390_search_devreg( ioinfo[irq] );
+					if ( pdevreg != NULL ) {
+						if ( pdevreg->oper_func != NULL )
+							pdevreg->oper_func( irq, pdevreg );
+						
+					} 
+				}
+				if (cio_proc_devinfo) 
+					if (irq < MAX_CIO_PROCFS_ENTRIES) {
+						cio_procfs_device_create(ioinfo[irq]->devno);
+				}
+			}
+		}
+		irq++;
+	} while (irq<=highest_subchannel);
+}
 
 /*
  * s390_search_devices
@@ -4389,6 +4901,10 @@
 
 	printk( "Highest subchannel number detected (hex) : %04X\n",
 	        highest_subchannel);
+	if (cio_debug_initialized)
+		debug_sprintf_event(cio_debug_msg_id, 0, 
+				    "Highest subchannel number detected (hex) : %04X\n",
+				    highest_subchannel);	
 }
 
 /*
@@ -4405,6 +4921,14 @@
 	int      ccode2;    /* condition code for other I/O routines */
 	schib_t *p_schib;
 	int      ret;
+	
+	char dbf_txt[15];
+
+	if (cio_debug_initialized) {
+		debug_text_event(cio_debug_trace_id, 4, "valsch");
+		sprintf(dbf_txt, "%x", irq);
+		debug_text_event(cio_debug_trace_id, 4, dbf_txt);
+	}
 
 	/*
 	 * The first subchannel that is not-operational (ccode==3)
@@ -4444,6 +4968,10 @@
 			        "non-I/O subchannel type %04X\n",
 			        irq,
 			        p_schib->pmcw.st);
+			if (cio_debug_initialized)
+				debug_sprintf_event(cio_debug_msg_id, 0,
+						    "Subchannel %04X reports non-I/O subchannel type %04X\n",
+						    irq, p_schib->pmcw.st);
 
 			if ( ioinfo[irq] != INVALID_STORAGE_AREA )
 				ioinfo[irq]->ui.flags.oper = 0;
@@ -4460,6 +4988,10 @@
 #ifdef CONFIG_DEBUG_IO
 			  printk( "Blacklisted device detected at devno %04X\n", p_schib->pmcw.dev );
 #endif
+			  if (cio_debug_initialized)
+				  debug_sprintf_event(cio_debug_msg_id, 0,
+						      "Blacklisted device detected at devno %04X\n",
+						      p_schib->pmcw.dev);
 			  ret = -ENODEV;
 		     } else {
 		        if ( ioinfo[irq] == INVALID_STORAGE_AREA )
@@ -4547,6 +5079,16 @@
 			 	       ioinfo[irq]->schib.pmcw.pom);
 
 			} /* endif */
+			if (cio_debug_initialized)
+				debug_sprintf_event(cio_debug_msg_id, 0,
+						    "Detected device %04X "
+						    "on subchannel %04X"
+						    " - PIM = %02X, PAM = %02X, POM = %02X\n",
+						    ioinfo[irq]->schib.pmcw.dev,
+						    irq,
+						    ioinfo[irq]->schib.pmcw.pim,
+						    ioinfo[irq]->schib.pmcw.pam,
+						    ioinfo[irq]->schib.pmcw.pom);
 
 			/*
 			 * initialize ioinfo structure
@@ -4661,6 +5203,10 @@
 							{
 								printk( " ... msch() (2) failed with CC = %X\n",
 								        ccode2 );
+								if (cio_debug_initialized)
+									debug_sprintf_event(cio_debug_msg_id, 0,
+											    "msch() (2) failed with CC=%X\n",
+											    ccode2);
 								ioinfo[irq]->ui.flags.oper = 0;
 								ret                        = -EIO;
 							}
@@ -4676,6 +5222,10 @@
 						{
 							printk( " ... msch() (1) failed with CC = %X\n",
 							        ccode2);
+							if (cio_debug_initialized)
+								debug_sprintf_event(cio_debug_msg_id, 0,
+										    "msch() (1) failed with CC = %X\n",
+										    ccode2);
 							ioinfo[irq]->ui.flags.oper = 0;
 							ret                        = -EIO;
 
@@ -4694,6 +5244,11 @@
 					        "subchannel %04X exceeded, CC = %d\n",
 					        irq,
 					        ccode2);
+					if (cio_debug_initialized)
+						debug_sprintf_event(cio_debug_msg_id, 0,
+								    " ... msch() retry count for "
+								    "subchannel %04X exceeded, CC = %d\n",
+								    irq, ccode2);		    
 
 				} /* endif */
 			}
@@ -4750,6 +5305,8 @@
 	senseid_t *psid     = sid;/* start with the external buffer */	
 	int        sbuffer  = 0; /* switch SID data buffer */
 
+	char dbf_txt[15];
+
 	if ( (irq > highest_subchannel) || (irq < 0 ) )
 	{
 		return( -ENODEV );
@@ -4767,6 +5324,12 @@
 
 	} /* endif */
 
+	if (cio_debug_initialized) {
+		debug_text_event(cio_debug_trace_id, 4, "snsID");
+		sprintf(dbf_txt, "%x", irq);
+		debug_text_event(cio_debug_trace_id, 4, dbf_txt);
+	}
+
 	if ( !ioinfo[irq]->ui.flags.ready )
 	{
 
@@ -4792,8 +5355,8 @@
   	} /* endif */
 
 	if ( irq_ret == 0 )
-   {
-      int i;
+	{
+		int i;
 
 		s390irq_spin_lock( irq);
 
@@ -4888,6 +5451,15 @@
 					   		     irq,
 							        retry);
 #endif
+							if (cio_debug_initialized)
+								debug_sprintf_event(cio_debug_msg_id, 2,
+										    "SenseID : device %04X on "
+										    "Subchannel %04X "
+										    "reports pending status, "
+										    "retry : %d\n",
+										    ioinfo[irq]->schib.pmcw.dev,
+										    irq,
+										    retry);		    
 						} /* endif */
 
 						if ( pdevstat->flag & DEVSTAT_FLAG_SENSE_AVAIL )
@@ -4907,11 +5479,20 @@
 								        ioinfo[irq]->schib.pmcw.dev,
 								        irq);
 #endif
+								if (cio_debug_initialized)
+									debug_sprintf_event(cio_debug_msg_id, 2,
+											    "SenseID : device %04X on "
+											    "Subchannel %04X "
+											    "reports cmd reject or "
+											    "intervention required\n",
+											    ioinfo[irq]->schib.pmcw.dev,
+											    irq);		    
 								io_retry = 1;
 							}
-#ifdef CONFIG_DEBUG_IO
+
 							else
 							{
+#ifdef CONFIG_DEBUG_IO							
 								printk( "SenseID : UC on "
 								        "dev %04X, "
 								        "retry %d, "
@@ -4932,9 +5513,31 @@
 								        pdevstat->ii.sense.data[5],
 								        pdevstat->ii.sense.data[6],
 								        pdevstat->ii.sense.data[7]);
-
-							} /* endif */
 #endif
+								if (cio_debug_initialized)
+									debug_sprintf_event(cio_debug_msg_id, 2,
+											    "SenseID : UC on "
+											    "dev %04X, "
+											    "retry %d, "
+											    "lpum %02X, "
+											    "cnt %02d, "
+											    "sns :"
+											    " %02X%02X%02X%02X "
+											    "%02X%02X%02X%02X ...\n",
+											    ioinfo[irq]->schib.pmcw.dev,
+											    retry,
+											    pdevstat->lpum,
+											    pdevstat->scnt,
+											    pdevstat->ii.sense.data[0],
+											    pdevstat->ii.sense.data[1],
+											    pdevstat->ii.sense.data[2],
+											    pdevstat->ii.sense.data[3],
+											    pdevstat->ii.sense.data[4],
+											    pdevstat->ii.sense.data[5],
+											    pdevstat->ii.sense.data[6],
+											    pdevstat->ii.sense.data[7]);	    
+							} /* endif */
+
 						}
 						else if (    ( pdevstat->flag & DEVSTAT_NOT_OPER )
 					             || ( irq_ret        == -ENODEV         ) )
@@ -4948,18 +5551,28 @@
 							        ioinfo[irq]->schib.pmcw.dev,
 							        irq);
 #endif
+							if (cio_debug_initialized)
+								debug_sprintf_event(cio_debug_msg_id, 2, 
+										    "SenseID : path %02X for "
+										    "device %04X on "
+										    "subchannel %04X "
+										    "is 'not operational'\n",
+										    domask,
+										    ioinfo[irq]->schib.pmcw.dev,
+										    irq);		    
 
 							io_retry          = 0;
 							ioinfo[irq]->opm &= ~domask;
       	
 						}
-#ifdef CONFIG_DEBUG_IO
+
 						else if (     (pdevstat->flag !=
 						                    (   DEVSTAT_START_FUNCTION
 						                      | DEVSTAT_FINAL_STATUS    ) )
 						           && !(pdevstat->flag &
 						                    DEVSTAT_STATUS_PENDING        ) )
 						{
+#ifdef CONFIG_DEBUG_IO
 							printk( "SenseID : start_IO() for "
 							        "device %04X on "
 							        "subchannel %04X "
@@ -4970,9 +5583,22 @@
 							        irq_ret,
 							        retry,
 							        pdevstat->flag);
+#endif
+							if (cio_debug_initialized)
+								debug_sprintf_event(cio_debug_msg_id, 2,
+										    "SenseID : start_IO() for "
+										    "device %04X on "
+										    "subchannel %04X "
+										    "returns %d, retry %d, "
+										    "status %04X\n",
+										    ioinfo[irq]->schib.pmcw.dev,
+										    irq,
+										    irq_ret,
+										    retry,
+										    pdevstat->flag);		    
 
 						} /* endif */
-#endif
+
 					}
 					else   // we got it ...
 					{
@@ -5079,38 +5705,54 @@
 			        ioinfo[irq]->schib.pmcw.dev,
 			        irq);
 #endif
+			if (cio_debug_initialized)
+				debug_sprintf_event(cio_debug_msg_id, 2,
+						    "SenseID : unknown device %04X on subchannel %04X\n",
+						    ioinfo[irq]->schib.pmcw.dev,
+						    irq);		    
 			ioinfo[irq]->ui.flags.unknown = 1;
 
 		} /* endif */
 
-		if ( cio_show_msg )
-		{
+	
 			/*
 			 * Issue device info message if unit was operational .
 			 */
-			if ( !ioinfo[irq]->ui.flags.unknown )
-			{
-				if ( sid->dev_type != 0 )
-				{
+		if ( !ioinfo[irq]->ui.flags.unknown ) {
+			if ( sid->dev_type != 0 ) {
+				if ( cio_show_msg ) 
 					printk( KERN_INFO"SenseID : device %04X reports: "
-					        "CU  Type/Mod = %04X/%02X,"
-				      	  " Dev Type/Mod = %04X/%02X\n",
-				   	     ioinfo[irq]->schib.pmcw.dev,
-					        sid->cu_type,
-					        sid->cu_model,
-					        sid->dev_type,
-					        sid->dev_model);
-				}
-				else
-				{
+						"CU  Type/Mod = %04X/%02X,"
+						" Dev Type/Mod = %04X/%02X\n",
+						ioinfo[irq]->schib.pmcw.dev,
+						sid->cu_type,
+						sid->cu_model,
+						sid->dev_type,
+						sid->dev_model);
+				if (cio_debug_initialized)
+					debug_sprintf_event(cio_debug_msg_id, 2,
+							    "SenseID : device %04X reports: "
+							    "CU  Type/Mod = %04X/%02X,"
+							    " Dev Type/Mod = %04X/%02X\n",
+							    ioinfo[irq]->schib.pmcw.dev,
+							    sid->cu_type,
+							    sid->cu_model,
+							    sid->dev_type,
+							    sid->dev_model);
+			} else {
+				if ( cio_show_msg ) 
 					printk( KERN_INFO"SenseID : device %04X reports:"
-				   	     " Dev Type/Mod = %04X/%02X\n",
-					        ioinfo[irq]->schib.pmcw.dev,
-					        sid->cu_type,
-					        sid->cu_model);
-
-				} /* endif */
-
+						" Dev Type/Mod = %04X/%02X\n",
+						ioinfo[irq]->schib.pmcw.dev,
+						sid->cu_type,
+						sid->cu_model);
+				if (cio_debug_initialized)
+					debug_sprintf_event(cio_debug_msg_id, 2,
+							    "SenseID : device %04X reports:"
+							    " Dev Type/Mod = %04X/%02X\n",
+							    ioinfo[irq]->schib.pmcw.dev,
+							    sid->cu_type,
+							    sid->cu_model);		    
 			} /* endif */
 
 		} /* endif */
@@ -5159,6 +5801,14 @@
 
 	int ret = 0;
 
+	char dbf_txt[15];
+
+	if (cio_debug_initialized) {
+		debug_text_event(cio_debug_trace_id, 4, "dpver");
+		sprintf(dbf_txt, "%x", irq);
+		debug_text_event(cio_debug_trace_id, 4, dbf_txt);
+	}
+
 	if ( ioinfo[irq]->ui.flags.pgid_supp == 0 )
 	{
 		return( 0);	// just exit ...
@@ -5270,16 +5920,30 @@
 						        irq,
 						        ioinfo[irq]->schib.pmcw.dev);
 #endif
+						if (cio_debug_initialized)
+							debug_sprintf_event(cio_debug_msg_id, 2,
+									    "PathVerification(%04X) "
+									    "- Device %04X doesn't "
+									    " support path grouping\n",
+									    irq,
+									    ioinfo[irq]->schib.pmcw.dev);		    
 
 					} /* endif */
 				}
-				else if ( ret == -EIO )
+				else if ( ret == -EIO ) 
 				{
 #ifdef CONFIG_DEBUG_IO
 					printk("PathVerification(%04X) - I/O error "
 					       "on device %04X\n", irq,
 					       ioinfo[irq]->schib.pmcw.dev);
 #endif
+
+					if (cio_debug_initialized)
+						debug_sprintf_event(cio_debug_msg_id, 2,
+								    "PathVerification(%04X) - I/O error "
+								    "on device %04X\n", irq,
+								    ioinfo[irq]->schib.pmcw.dev);
+
 					ioinfo[irq]->ui.flags.pgid_supp = 0;
 		    
 				} else {
@@ -5289,6 +5953,13 @@
 						irq,
 						ioinfo[irq]->schib.pmcw.dev);
 #endif
+					if (cio_debug_initialized)
+						debug_sprintf_event(cio_debug_msg_id, 2,
+								    "PathVerification(%04X) - "
+								    "Unexpected error on device %04X\n",
+								    irq,
+								    ioinfo[irq]->schib.pmcw.dev);		    
+					
 					ioinfo[irq]->ui.flags.pgid_supp = 0;
 					
 				} /* endif */
@@ -5357,7 +6028,7 @@
 
 		if ( irq_ret == 0 )
 			inlreq = 1;
-   }
+	}
 	else
 	{
 		pdevstat = ioinfo[irq]->irq_desc.dev_id;
@@ -5419,6 +6090,15 @@
 					        irq,
 					        retry);
 #endif
+					if (cio_debug_initialized)
+						debug_sprintf_event(cio_debug_msg_id, 2,
+								    "SPID - Device %04X "
+								    "on Subchannel %04X "
+								    "reports pending status, "
+								    "retry : %d\n",
+								    ioinfo[irq]->schib.pmcw.dev,
+								    irq,
+								    retry);	    
 				} /* endif */
 
 				if ( pdevstat->flag == (   DEVSTAT_START_FUNCTION
@@ -5468,19 +6148,50 @@
 						        pdevstat->ii.sense.data[5],
 						        pdevstat->ii.sense.data[6],
 						        pdevstat->ii.sense.data[7]);
-
 #endif
-						retry--;
 
+						if (cio_debug_initialized)
+							debug_sprintf_event(cio_debug_msg_id, 2,
+									    "SPID - device %04X,"
+									    " unit check,"
+									    " retry %d, cnt %02d,"
+									    " sns :"
+									    " %02X%02X%02X%02X %02X%02X%02X%02X ...\n",
+									    ioinfo[irq]->schib.pmcw.dev,
+									    retry,
+									    pdevstat->scnt,
+									    pdevstat->ii.sense.data[0],
+									    pdevstat->ii.sense.data[1],
+									    pdevstat->ii.sense.data[2],
+									    pdevstat->ii.sense.data[3],
+									    pdevstat->ii.sense.data[4],
+									    pdevstat->ii.sense.data[5],
+									    pdevstat->ii.sense.data[6],
+									    pdevstat->ii.sense.data[7]);
+
+						retry--;
+		    
 					} /* endif */
+
 				}
 				else if ( pdevstat->flag & DEVSTAT_NOT_OPER )
 				{
-					printk( "SPID - Device %04X "
-					        "on Subchannel %04X "
-					        "became 'not operational'\n",
-					        ioinfo[irq]->schib.pmcw.dev,
-					        irq);
+					/* don't issue warnings during startup unless requested*/
+					if (init_IRQ_complete || cio_notoper_msg) {   
+						
+						printk( "SPID - Device %04X "
+							"on Subchannel %04X "
+							"became 'not operational'\n",
+							ioinfo[irq]->schib.pmcw.dev,
+							irq);
+						if (cio_debug_initialized)
+							debug_sprintf_event(cio_debug_msg_id, 2,
+									    "SPID - Device %04X "
+									    "on Subchannel %04X "
+									    "became 'not operational'\n",
+									    ioinfo[irq]->schib.pmcw.dev,
+									    irq);		    
+					}
 
 					retry = 0;
 					irq_ret = -EIO;
@@ -5503,7 +6214,7 @@
 		{
 			irq_ret = -EIO;
 
-		} /* endif */		
+		} /* endif */
 
 		if ( init_IRQ_complete )
 		{
@@ -5659,17 +6370,47 @@
 						        pdevstat->ii.sense.data[7]);
 
 #endif
+						if (cio_debug_initialized)
+							debug_sprintf_event(cio_debug_msg_id, 2,
+									    "SNID - device %04X,"
+									    " unit check,"
+									    " flag %04X, "
+									    " retry %d, cnt %02d,"
+									    " sns :"
+									    " %02X%02X%02X%02X %02X%02X%02X%02X ...\n",
+									    ioinfo[irq]->schib.pmcw.dev,
+									    pdevstat->flag,
+									    retry,
+									    pdevstat->scnt,
+									    pdevstat->ii.sense.data[0],
+									    pdevstat->ii.sense.data[1],
+									    pdevstat->ii.sense.data[2],
+									    pdevstat->ii.sense.data[3],
+									    pdevstat->ii.sense.data[4],
+									    pdevstat->ii.sense.data[5],
+									    pdevstat->ii.sense.data[6],
+									    pdevstat->ii.sense.data[7]);		    
 						retry--;
 
 					} /* endif */
 				}
 				else if ( pdevstat->flag & DEVSTAT_NOT_OPER )
 				{
-					printk( "SNID - Device %04X "
-					        "on Subchannel %04X "
-					        "became 'not operational'\n",
-					        ioinfo[irq]->schib.pmcw.dev,
-					        irq);
+					/* don't issue warnings during startup unless requested*/
+					if (init_IRQ_complete || cio_notoper_msg) {  
+						printk( "SNID - Device %04X "
+							"on Subchannel %04X "
+							"became 'not operational'\n",
+							ioinfo[irq]->schib.pmcw.dev,
+							irq);
+						if (cio_debug_initialized)
+							debug_sprintf_event(cio_debug_msg_id, 2,
+									    "SNID - Device %04X "
+									    "on Subchannel %04X "
+									    "became 'not operational'\n",
+									    ioinfo[irq]->schib.pmcw.dev,
+									    irq);		    
+					}
 
 					retry = 0;
 
@@ -5682,9 +6423,10 @@
 			}
 			else if ( irq_ret != -ENODEV ) // -EIO, or -EBUSY
 			{
-#ifdef CONFIG_DEBUG_IO
+
 				if ( pdevstat->flag & DEVSTAT_STATUS_PENDING )
 				{
+#ifdef CONFIG_DEBUG_IO
 					printk( "SNID - Device %04X "
 					        "on Subchannel %04X "
 					        "reports pending status, "
@@ -5692,13 +6434,29 @@
 					        ioinfo[irq]->schib.pmcw.dev,
 					        irq,
 					        retry);
-				} /* endif */
 #endif
+					if (cio_debug_initialized)
+						debug_sprintf_event(cio_debug_msg_id, 2,
+								    "SNID - Device %04X "
+								    "on Subchannel %04X "
+								    "reports pending status, "
+								    "retry : %d\n",
+								    ioinfo[irq]->schib.pmcw.dev,
+								    irq,
+								    retry);		    
+				} /* endif */
+
 
 				printk( "SNID - device %04X,"
 				        " start_io() reports rc : %d, retrying ...\n",
 				        ioinfo[irq]->schib.pmcw.dev,
 				        irq_ret);
+				if (cio_debug_initialized)
+					debug_sprintf_event(cio_debug_msg_id, 2, 
+							    "SNID - device %04X,"
+							    " start_io() reports rc : %d, retrying ...\n",
+							    ioinfo[irq]->schib.pmcw.dev,
+							    irq_ret);
 				retry--;
 			}
 			else	// -ENODEV ...
@@ -5758,7 +6516,9 @@
 #ifdef CONFIG_DEBUG_CRW
 	printk( "do_crw_pending : starting ...\n");
 #endif
-
+	if (cio_debug_initialized) 
+		debug_sprintf_event(cio_debug_crw_id, 2, 
+				    "do_crw_pending: starting\n");
 	while ( pcrwe != NULL )
 	{
 		int is_owned = 0;
@@ -5772,7 +6532,9 @@
 			printk( KERN_INFO"do_crw_pending : source is "
 			        "subchannel %04X\n", irq);
 #endif
-
+			if (cio_debug_initialized)
+				debug_sprintf_event(cio_debug_crw_id, 2,
+						    "source is subchannel %04X\n", irq);
 			/*
 			 * If the device isn't known yet
 			 *   we can't lock it ...
@@ -5794,6 +6556,9 @@
 #ifdef CONFIG_DEBUG_CRW
 			printk( "do_crw_pending : subchannel validation - start ...\n");
 #endif
+			if (cio_debug_initialized)
+				debug_sprintf_event(cio_debug_crw_id, 4,
+						    "subchannel validation - start\n");
 			s390_validate_subchannel( irq, is_owned );
 
 			if ( irq > highest_subchannel )
@@ -5802,6 +6567,9 @@
 #ifdef CONFIG_DEBUG_CRW
 			printk( "do_crw_pending : subchannel validation - done\n");
 #endif
+			if (cio_debug_initialized)
+				debug_sprintf_event(cio_debug_crw_id, 4,
+						    "subchannel validation - done\n");
 			/*
 			 * After the validate processing
 			 *   the ioinfo control block
@@ -5813,26 +6581,34 @@
 
 			} /* endif */
 
-#ifdef CONFIG_DEBUG_CRW
+
 			if ( ioinfo[irq] != INVALID_STORAGE_AREA )
 			{
+#ifdef CONFIG_DEBUG_CRW
 				printk( "do_crw_pending : ioinfo at %08X\n",
 				        (unsigned)ioinfo[irq]);
-
-			} /* endif */
 #endif
+				if (cio_debug_initialized)
+					debug_sprintf_event(cio_debug_crw_id, 4,
+							    "ioinfo at %08X\n");
+			} /* endif */
+
 
 			if ( ioinfo[irq] != INVALID_STORAGE_AREA )
 			{
 				if ( ioinfo[irq]->ui.flags.oper == 0 )
 				{
 					 not_oper_handler_func_t nopfunc=ioinfo[irq]->nopfunc;
+					 
+					 /* remove procfs entry */
+					 if (cio_proc_devinfo)
+						 cio_procfs_device_remove(dev_no);
 					/*
 					 * If the device has gone
 					 *  call not oper handler        	
 					 */       	
-					if (    (             dev_oper == 1    )
-					     && ( nopfunc != NULL ) )
+					 if (( dev_oper == 1 )
+					     && ( nopfunc != NULL))
 					{
 						
 						free_irq( irq,ioinfo[irq]->irq_desc.dev_id );
@@ -5846,13 +6622,18 @@
 					printk( "do_crw_pending : device "
 					        "recognition - start ...\n");
 #endif
+					if (cio_debug_initialized)
+						debug_sprintf_event(cio_debug_crw_id, 4,
+								    "device recognition - start\n");
 					s390_device_recognition_irq( irq );
 
 #ifdef CONFIG_DEBUG_CRW
 					printk( "do_crw_pending : device "
 					        "recognition - done\n");
 #endif
-		
+					if (cio_debug_initialized)
+						debug_sprintf_event(cio_debug_crw_id, 4,
+								    "device recognition - done\n");
 					/*
 					 * the device became operational
 					 */
@@ -5868,6 +6649,12 @@
 								pdevreg->oper_func( irq, pdevreg );
 
 						} /* endif */
+
+						/* add new procfs entry */
+						if (cio_proc_devinfo) 
+							if (highest_subchannel < MAX_CIO_PROCFS_ENTRIES) {
+								cio_procfs_device_create(ioinfo[irq]->devno);
+							}
 					}
 					/*
 					 * ... it is and was operational, but
@@ -5875,13 +6662,23 @@
 					 */
 					else if ((ioinfo[irq]->devno != dev_no) && ( ioinfo[irq]->nopfunc != NULL ))   					
 					{
+						int devno_old = ioinfo[irq]->devno;
 						ioinfo[irq]->nopfunc( irq,
 						                      DEVSTAT_REVALIDATE );				
 
+						/* remove old entry, add new */
+						if (cio_proc_devinfo) {
+							cio_procfs_device_remove(devno_old);
+							cio_procfs_device_create(ioinfo[irq]->devno);
+						}
 					} /* endif */
 
 				} /* endif */
 
+				/* get rid of dead procfs entries */
+				if (cio_proc_devinfo) 
+					cio_procfs_device_purge();
+
 			} /* endif */
 
 			break;
@@ -5892,6 +6689,9 @@
 			printk( "do_crw_pending : source is "
 			        "monitoring facility\n");
 #endif
+			if (cio_debug_initialized)
+				debug_sprintf_event(cio_debug_crw_id, 2,
+						    "source is monitoring facility\n");
 			break;
 
 		case CRW_RSC_CPATH :   	
@@ -5902,6 +6702,9 @@
 			printk( "do_crw_pending : source is "
 			        "channel path %02X\n", chpid);
 #endif
+			if (cio_debug_initialized)
+				debug_sprintf_event(cio_debug_crw_id, 2,
+						    "source is channel path %02X\n");
 			break;
 
 		case CRW_RSC_CONFIG : 	
@@ -5910,6 +6713,9 @@
 			printk( "do_crw_pending : source is "
 			        "configuration-alert facility\n");
 #endif
+			if (cio_debug_initialized)
+				debug_sprintf_event(cio_debug_crw_id, 2,
+						    "source is configuration-alert facility\n");
 			break;
 
 		case CRW_RSC_CSS :
@@ -5918,6 +6724,9 @@
 			printk( "do_crw_pending : source is "
 			        "channel subsystem\n");
 #endif
+			if (cio_debug_initialized)
+				debug_sprintf_event(cio_debug_crw_id, 2,
+						    "source is channel subsystem\n");
 			break;
 
 		default :
@@ -5925,6 +6734,9 @@
 #ifdef CONFIG_DEBUG_CRW
 			printk( "do_crw_pending : unknown source\n");
 #endif
+			if (cio_debug_initialized)
+				debug_sprintf_event(cio_debug_crw_id, 2,
+						    "unknown source\n");
 			break;		
 
 		} /* endswitch */
@@ -5936,7 +6748,9 @@
 #ifdef CONFIG_DEBUG_CRW
 	printk( "do_crw_pending : done\n");
 #endif
-
+	if (cio_debug_initialized)
+		debug_sprintf_event(cio_debug_crw_id, 2,
+				    "do_crw_pending: done\n");
    return;
 }
 
@@ -5964,8 +6778,64 @@
 		do_reipl( 0x10000 | sch );
 }
 
-/* Display info on subchannels in /proc/subchannels. *
- * Adapted from procfs stuff in dasd.c by Cornelia Huck, 02/28/01.      */
+
+/*
+ * Function: cio_debug_init
+ * Initializes three debug logs (under /proc/s390dbf) for common I/O:
+ * - cio_msg logs the messages which are printk'ed when CONFIG_DEBUG_IO is on
+ * - cio_trace logs the calling of different functions
+ * - cio_crw logs the messages which are printk'ed when CONFIG_DEBUG_CRW is on
+ * debug levels depend on CONFIG_DEBUG_IO resp. CONFIG_DEBUG_CRW
+ */
+int cio_debug_init( void )
+{
+	int ret = 0;
+
+	cio_debug_msg_id = debug_register("cio_msg",2,4,16*sizeof(long));
+	if (cio_debug_msg_id != NULL) {
+		debug_register_view(cio_debug_msg_id, &debug_sprintf_view);
+#ifdef CONFIG_DEBUG_IO
+		debug_set_level(cio_debug_msg_id, 6);
+#else /* CONFIG_DEBUG_IO */
+		debug_set_level(cio_debug_msg_id, 2);
+#endif /* CONFIG_DEBUG_IO */
+	} else {
+		ret = -1;
+	}
+	cio_debug_trace_id = debug_register("cio_trace",4,4,8);
+	if (cio_debug_trace_id != NULL) {
+		debug_register_view(cio_debug_trace_id, &debug_hex_ascii_view);
+#ifdef CONFIG_DEBUG_IO
+		debug_set_level(cio_debug_trace_id, 6);
+#else /* CONFIG_DEBUG_IO */
+		debug_set_level(cio_debug_trace_id, 2);
+#endif /* CONFIG_DEBUG_IO */
+	} else {
+		ret = -1;
+	}
+	cio_debug_crw_id = debug_register("cio_crw",2,4,16*sizeof(long));
+	if (cio_debug_crw_id != NULL) {
+		debug_register_view(cio_debug_crw_id, &debug_sprintf_view);
+#ifdef CONFIG_DEBUG_CRW
+		debug_set_level(cio_debug_crw_id, 6);
+#else /* CONFIG_DEBUG_CRW */
+		debug_set_level(cio_debug_crw_id, 2);
+#endif /* CONFIG_DEBUG_CRW */
+	} else {
+		ret = -1;
+	}
+	if (ret)
+		return ret;
+	cio_debug_initialized = 1;
+	return 0;
+}
+
+__initcall(cio_debug_init);
+
+/* 
+ * Display info on subchannels in /proc/subchannels. 
+ * Adapted from procfs stuff in dasd.c by Cornelia Huck, 02/28/01.      
+ */
 
 typedef struct {
      char *data;
@@ -6090,10 +6960,12 @@
      release:chan_subch_close,
 };
 
-void chan_proc_init( void )
+static int chan_proc_init( void )
 {
      chan_subch_entry = create_proc_entry( "subchannels", S_IFREG|S_IRUGO, &proc_root);
      chan_subch_entry->proc_fops = &chan_subch_file_ops;
+
+     return 1;
 }
 
 __initcall(chan_proc_init);
@@ -6103,6 +6975,531 @@
      remove_proc_entry( "subchannels", &proc_root);
 }
 
+/* 
+ * Display device specific information under /proc/deviceinfo/<devno>
+ */
+
+static struct proc_dir_entry *cio_procfs_deviceinfo_root = NULL;
+
+/* 
+ * cio_procfs_device_list holds all devno-specific procfs directories
+ */
+
+typedef struct {
+	int devno;
+	struct proc_dir_entry *cio_device_entry;
+	struct proc_dir_entry *cio_sensedata_entry;
+	struct proc_dir_entry *cio_in_use_entry;
+	struct proc_dir_entry *cio_chpid_entry;
+} cio_procfs_entry_t;
+
+typedef struct _cio_procfs_device{
+	struct _cio_procfs_device *next;
+	cio_procfs_entry_t *entry;
+} cio_procfs_device_t;
+
+cio_procfs_device_t *cio_procfs_device_list = NULL;
+
+/*
+ * File operations
+ */
+
+static int cio_device_entry_close( struct inode *inode, struct file *file)
+{
+     int rc = 0;
+     tempinfo_t *p_info = (tempinfo_t *) file->private_data;
+
+     if (p_info) {
+	  if (p_info->data)
+	       vfree( p_info->data );
+	  vfree( p_info );
+     }
+     
+     return rc;
+}
+
+static ssize_t cio_device_entry_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;
+     
+     if ( *offset>=p_info->len) {
+	  return 0;
+     } else {
+	  len = MIN(user_len, (p_info->len - *offset));
+	  if (copy_to_user( user_buf, &(p_info->data[*offset]), len))
+	       return -EFAULT; 
+	  (* offset) += len;
+	  return len;
+     }
+}
+
+int cio_search_devno_by_inode(struct inode *inode)
+{
+	int devno = -1;
+	struct proc_dir_entry *pde;
+	cio_procfs_device_t *tmp;
+	
+	pde = (struct proc_dir_entry *)inode->u.generic_ip;
+	tmp = cio_procfs_device_list;
+
+	while (tmp) {
+		if ((tmp->entry->cio_device_entry == pde) ||
+		    (tmp->entry->cio_sensedata_entry == pde) ||
+		    (tmp->entry->cio_in_use_entry == pde) ||
+		    (tmp->entry->cio_chpid_entry == pde))
+			break;
+		tmp = tmp->next;
+	}
+
+	if (tmp)
+		devno = tmp->entry->devno;
+		
+	return devno;
+}
+
+
+static int cio_sensedata_entry_open( struct inode *inode, struct file *file)
+{
+	int rc = 0;
+	int size = 1;
+	int len = 0;
+	tempinfo_t *info;
+	int irq;
+	int devno;
+
+	info = (tempinfo_t *) vmalloc(sizeof(tempinfo_t));
+	if (info == NULL) {
+		printk( KERN_WARNING "No memory available for data\n");
+		rc = -ENOMEM;
+	} else {
+		file->private_data = (void *) info;
+		size += 2 * 32;
+		info->data = (char *) vmalloc(size);
+		if (size && info->data == NULL) {
+			printk(KERN_WARNING "No memory available for data\n");
+			vfree(info);
+			rc = -ENOMEM;
+		} else {
+			devno = cio_search_devno_by_inode(inode);
+			if (devno != 0xFFFF) {
+				irq = get_irq_by_devno(devno);
+				if (irq != -1) {
+					len += sprintf(info->data+len, "Dev Type/Mod: ");
+					if (ioinfo[irq]->senseid.dev_type == 0) {
+						len += sprintf(info->data+len, "%04X/%02X\n",
+							       ioinfo[irq]->senseid.cu_type,
+							       ioinfo[irq]->senseid.cu_model);
+					} else {
+						len += sprintf(info->data+len, "%04X/%02X\n",
+							       ioinfo[irq]->senseid.dev_type,
+							       ioinfo[irq]->senseid.dev_model);
+						len+= sprintf(info->data+len, "CU Type/Mod:  %04X/%02X\n",
+							      ioinfo[irq]->senseid.cu_type,
+							      ioinfo[irq]->senseid.cu_model);
+					}
+				}
+			}
+			info->len = len;
+		}
+	}
+	
+	return rc;
+}
+
+static int cio_in_use_entry_open( struct inode *inode, struct file *file)
+{
+	int rc = 0;
+	int size = 1;
+	int len = 0;
+	tempinfo_t *info;
+	int irq;
+	int devno;
+
+	info = (tempinfo_t *) vmalloc(sizeof(tempinfo_t));
+	if (info == NULL) {
+		printk( KERN_WARNING "No memory available for data\n");
+		rc = -ENOMEM;
+	} else {
+		file->private_data = (void *) info;
+		size += 8;
+		info->data = (char *) vmalloc(size);
+		if (size && info->data == NULL) {
+			printk(KERN_WARNING "No memory available for data\n");
+			vfree(info);
+			rc = -ENOMEM;
+		} else {
+			devno = cio_search_devno_by_inode(inode);
+			if (devno != -1) {
+				irq = get_irq_by_devno(devno);
+				if (irq != -1) {
+					len += sprintf(info->data+len, "%s\n", ioinfo[irq]->ui.flags.ready?"yes":"no");
+				}
+			}
+			info->len = len;
+		}
+	}
+	
+	return rc;
+}
+
+static int cio_chpid_entry_open( struct inode *inode, struct file *file)
+{
+	int rc = 0;
+	int size = 1;
+	int len = 0;
+	tempinfo_t *info;
+	int irq;
+	int devno;
+	int i;
+
+	info = (tempinfo_t *) vmalloc(sizeof(tempinfo_t));
+	if (info == NULL) {
+		printk( KERN_WARNING "No memory available for data\n");
+		rc = -ENOMEM;
+	} else {
+		file->private_data = (void *) info;
+		size += 8*16;
+		info->data = (char *) vmalloc(size);
+		if (size && info->data == NULL) {
+			printk(KERN_WARNING "No memory available for data\n");
+			vfree(info);
+			rc = -ENOMEM;
+		} else {
+			devno = cio_search_devno_by_inode(inode);
+			if (devno != -1) {
+				irq = get_irq_by_devno(devno);
+				if (irq != -1) {
+					for (i=0; i<8; i++) {
+						len += sprintf(info->data+len, "CHPID[%d]: ", i);
+						len += sprintf(info->data+len, "%02X\n", ioinfo[irq]->schib.pmcw.chpid[i]);
+					}
+				}
+			}
+			info->len = len;
+		}
+	}
+
+	return rc;
+}
+
+static struct file_operations cio_sensedata_entry_file_ops =
+{
+     read:cio_device_entry_read,
+     open:cio_sensedata_entry_open,
+     release:cio_device_entry_close,
+};
+
+static struct file_operations cio_in_use_entry_file_ops =
+{
+     read:cio_device_entry_read,
+     open:cio_in_use_entry_open,
+     release:cio_device_entry_close,
+};
+
+static struct file_operations cio_chpid_entry_file_ops =
+{
+     read:cio_device_entry_read,
+     open:cio_chpid_entry_open,
+     release:cio_device_entry_close,
+};
+
+/*
+ * Function: cio_procfs_device_create
+ * create procfs entry for given device number
+ * and insert it into list
+ */
+int cio_procfs_device_create(int devno)
+{
+	cio_procfs_entry_t *entry;
+	cio_procfs_device_t *tmp;
+	cio_procfs_device_t *where;
+	char buf[8];
+	int i;
+	int rc = 0;
+
+
+	/* create the directory entry */
+	entry = (cio_procfs_entry_t *)kmalloc(sizeof(cio_procfs_entry_t), GFP_KERNEL);
+	if (entry) {
+		entry->devno = devno;
+		sprintf(buf, "%x", devno);
+		entry->cio_device_entry = proc_mkdir(buf, cio_procfs_deviceinfo_root);
+		
+		if (entry->cio_device_entry) {
+			tmp = (cio_procfs_device_t *)kmalloc(sizeof(cio_procfs_device_t), GFP_KERNEL);
+			if (tmp) {
+				tmp->entry = entry;
+				
+				if (cio_procfs_device_list == NULL) {
+					cio_procfs_device_list = tmp;
+					tmp->next = NULL;
+				} else {
+					where = cio_procfs_device_list;
+					i = where->entry->devno;
+					while ((devno>i) && (where->next != NULL)) {
+						where = where->next;
+						i = where->entry->devno;
+					}
+					if (where->next == NULL) {
+						where->next = tmp;
+						tmp->next = NULL;
+					} else {
+						tmp->next = where->next;
+						where->next = tmp;
+					}
+				}
+				/* create the different entries */
+				entry->cio_sensedata_entry = create_proc_entry( "sensedata", S_IFREG|S_IRUGO, entry->cio_device_entry);
+				entry->cio_sensedata_entry->proc_fops = &cio_sensedata_entry_file_ops;
+				entry->cio_in_use_entry = create_proc_entry( "in_use", S_IFREG|S_IRUGO, entry->cio_device_entry);
+				entry->cio_in_use_entry->proc_fops = &cio_in_use_entry_file_ops;
+				entry->cio_chpid_entry = create_proc_entry( "chpids", S_IFREG|S_IRUGO, entry->cio_device_entry);
+				entry->cio_chpid_entry->proc_fops = &cio_chpid_entry_file_ops;
+			} else {
+				printk("Error, could not allocate procfs structure!\n");
+				remove_proc_entry(buf, cio_procfs_deviceinfo_root);
+				kfree(entry);
+				rc = -ENOMEM;
+			}
+		} else {
+			printk("Error, could not allocate procfs structure!\n");
+			kfree(entry);
+			rc = -ENOMEM;
+		}
+
+	} else {
+		printk("Error, could not allocate procfs structure!\n");
+		rc = -ENOMEM;
+	}
+	return rc;
+}
+
+/*
+ * Function: cio_procfs_device_remove
+ * remove procfs entry for given device number
+ */
+int cio_procfs_device_remove(int devno)
+{
+	int rc = 0;
+	cio_procfs_device_t *tmp;
+	cio_procfs_device_t *prev = NULL;
+
+	tmp=cio_procfs_device_list;
+	while (tmp) {
+		if (tmp->entry->devno == devno)
+			break;
+		prev = tmp;
+		tmp = tmp->next;
+	}
+
+	if (tmp) {
+		char buf[8];
+		
+		remove_proc_entry("sensedata", tmp->entry->cio_device_entry);
+		remove_proc_entry("in_use", tmp->entry->cio_device_entry);
+		remove_proc_entry("chpid", tmp->entry->cio_device_entry);
+		sprintf(buf, "%x", devno);
+		remove_proc_entry(buf, cio_procfs_deviceinfo_root);
+		
+		if (tmp == cio_procfs_device_list) {
+			cio_procfs_device_list = tmp->next;
+		} else {
+			prev->next = tmp->next;
+		}
+		kfree(tmp->entry);
+		kfree(tmp);
+	} else {
+		rc = -ENODEV;
+	}
+
+	return rc;
+}
+
+/*
+ * Function: cio_procfs_purge
+ * purge /proc/deviceinfo of entries for gone devices
+ */
+
+int cio_procfs_device_purge(void) 
+{
+	int i;
+
+	for (i=0; i<=highest_subchannel; i++) {
+		if (ioinfo[i] != INVALID_STORAGE_AREA) {
+			if (!ioinfo[i]->ui.flags.oper) 
+				cio_procfs_device_remove(ioinfo[i]->devno);
+		}
+	}
+
+	return 0;
+}
+
+/*
+ * Function: cio_procfs_create
+ * create /proc/deviceinfo/ and subdirs for the devices
+ */
+static int cio_procfs_create( void )
+{
+	int irq;
+
+	if (cio_proc_devinfo) {
+
+		cio_procfs_deviceinfo_root = proc_mkdir( "deviceinfo", &proc_root);
+		
+		if (highest_subchannel >= MAX_CIO_PROCFS_ENTRIES) {
+			printk(KERN_ALERT "Warning: Not enough inodes for creating all entries under /proc/deviceinfo/. "
+			       "Not every device will get an entry.\n");
+		}
+		
+		for (irq=0; irq<=highest_subchannel; irq++) {
+			if (irq >= MAX_CIO_PROCFS_ENTRIES)
+				break;
+			if (ioinfo[irq] != INVALID_STORAGE_AREA) {
+				if (ioinfo[irq]->ui.flags.oper) 
+					if (cio_procfs_device_create(ioinfo[irq]->devno) == -ENOMEM) {
+						printk(KERN_CRIT "Out of memory while creating entries in /proc/deviceinfo/, "
+						       "not all devices might show up\n");
+					break;
+					}
+			}
+		}
+	
+	}
+	
+	return 1;
+}
+
+__initcall(cio_procfs_create);
+
+/*
+ * Entry /proc/cio_ignore to display blacklisted ranges of devices.
+ * un-ignore devices by piping to /proc/cio_ignore:
+ * free all frees all blacklisted devices, free <range>,<range>,...
+ * frees specified ranges of devnos
+ */
+
+static struct proc_dir_entry *cio_ignore_proc_entry;
+
+static int cio_ignore_proc_open(struct inode *inode, struct file *file)
+{
+	int rc = 0;
+	int size = 1;
+	int len = 0;
+	tempinfo_t *info;
+	dev_blacklist_range_t *tmp;
+
+	info = (tempinfo_t *) vmalloc(sizeof(tempinfo_t));
+	if (info == NULL) {
+		printk( KERN_WARNING "No memory available for data\n");
+		rc = -ENOMEM;
+	} else {
+		file->private_data = (void *) info;
+		size += nr_blacklisted_ranges * 32;
+		info->data = (char *) vmalloc(size);
+		if (size && info->data == NULL) {
+			printk( KERN_WARNING "No memory available for data\n");
+			vfree (info);
+			rc = -ENOMEM;
+		} else {
+			tmp = dev_blacklist_range_head;
+			while (tmp) {
+				len += sprintf(info->data+len, "%04x ", tmp->from);
+				if (tmp->to != tmp->from) 
+					len += sprintf(info->data+len, "- %04x", tmp->to);
+				len += sprintf(info->data+len, "\n");
+				tmp = tmp->next;
+			}
+			info->len = len;
+		}
+	}
+	return rc;
+}
+
+static int cio_ignore_proc_close(struct inode *inode, struct file *file)
+{
+	int rc = 0;
+	tempinfo_t *p_info = (tempinfo_t *) file->private_data;
+
+     if (p_info) {
+	  if (p_info->data)
+	       vfree( p_info->data );
+	  vfree( p_info );
+     }
+     
+     return rc;
+}
+
+static ssize_t cio_ignore_proc_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;
+     
+     if ( *offset>=p_info->len) {
+	  return 0;
+     } else {
+	  len = MIN(user_len, (p_info->len - *offset));
+	  if (copy_to_user( user_buf, &(p_info->data[*offset]), len))
+	       return -EFAULT; 
+	  (* offset) += len;
+	  return len;
+     }
+}
+
+static ssize_t cio_ignore_proc_write (struct file *file, const char *user_buf,
+				      size_t user_len, loff_t * offset)
+{
+	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';
+#ifdef CIO_DEBUG_IO
+	printk ("/proc/cio_ignore: '%s'\n", buffer);
+#endif /* CIO_DEBUG_IO */
+	if (cio_debug_initialized)
+		debug_sprintf_event(cio_debug_msg_id, 2, "/proc/cio_ignore: '%s'\n",buffer);
+
+	blacklist_parse_proc_parameters(buffer);
+
+	return user_len;
+}
+
+static struct file_operations cio_ignore_proc_file_ops =
+{
+	read:cio_ignore_proc_read,
+	open:cio_ignore_proc_open,
+	write:cio_ignore_proc_write,
+	release:cio_ignore_proc_close,
+};
+
+static int cio_ignore_proc_init(void)
+{
+	cio_ignore_proc_entry = create_proc_entry("cio_ignore", S_IFREG|S_IRUGO|S_IWUSR, &proc_root);
+	cio_ignore_proc_entry->proc_fops = &cio_ignore_proc_file_ops;
+
+	return 1;
+}
+
+__initcall(cio_ignore_proc_init);
+
+/* end of procfs stuff */
+
+schib_t *s390_get_schib( int irq )
+{
+	if ( (irq > highest_subchannel) || (irq < 0) )
+		return NULL;
+	if ( ioinfo[irq] == INVALID_STORAGE_AREA )
+		return NULL;
+	return &ioinfo[irq]->schib;
+
+}
+
+
 EXPORT_SYMBOL(halt_IO);
 EXPORT_SYMBOL(clear_IO);
 EXPORT_SYMBOL(do_IO);
@@ -6117,3 +7514,6 @@
 EXPORT_SYMBOL(read_conf_data);
 EXPORT_SYMBOL(read_dev_chars);
 EXPORT_SYMBOL(s390_request_irq_special);
+EXPORT_SYMBOL(s390_get_schib);
+EXPORT_SYMBOL(s390_register_adapter_interrupt);
+EXPORT_SYMBOL(s390_unregister_adapter_interrupt);
diff -u --recursive --new-file v2.4.7/linux/drivers/s390/s390mach.c linux/drivers/s390/s390mach.c
--- v2.4.7/linux/drivers/s390/s390mach.c	Fri Mar  2 11:12:07 2001
+++ linux/drivers/s390/s390mach.c	Wed Jul 25 14:12:02 2001
@@ -11,7 +11,7 @@
 #include <linux/config.h>
 #include <linux/spinlock.h>
 #include <linux/init.h>
-#include <linux/malloc.h>
+#include <linux/slab.h>
 #ifdef CONFIG_SMP
 #include <linux/smp.h>
 #endif
diff -u --recursive --new-file v2.4.7/linux/drivers/scsi/aha152x.c linux/drivers/scsi/aha152x.c
--- v2.4.7/linux/drivers/scsi/aha152x.c	Wed Jul 25 17:10:23 2001
+++ linux/drivers/scsi/aha152x.c	Sun Aug  5 13:12:40 2001
@@ -624,7 +624,7 @@
 static void parerr_run(struct Scsi_Host *shpnt);
 static void rsti_run(struct Scsi_Host *shpnt);
 
-static void complete(struct Scsi_Host *shpnt);
+static void is_complete(struct Scsi_Host *shpnt);
 
 /*
  * driver states
@@ -1869,7 +1869,7 @@
 		struct Scsi_Host *shpnt = aha152x_host[i];
 		if (shpnt && HOSTDATA(shpnt)->service) {
 			HOSTDATA(shpnt)->service=0;
-			complete(shpnt);
+			is_complete(shpnt);
 		}
 	}
 }
@@ -2935,7 +2935,7 @@
  * bottom-half handler
  *
  */
-static void complete(struct Scsi_Host *shpnt)
+static void is_complete(struct Scsi_Host *shpnt)
 {
 	int dataphase;
 	unsigned long flags;
diff -u --recursive --new-file v2.4.7/linux/drivers/scsi/aic7xxx/aic7xxx.c linux/drivers/scsi/aic7xxx/aic7xxx.c
--- v2.4.7/linux/drivers/scsi/aic7xxx/aic7xxx.c	Fri May  4 15:16:28 2001
+++ linux/drivers/scsi/aic7xxx/aic7xxx.c	Sun Aug  5 13:12:41 2001
@@ -1343,22 +1343,21 @@
 	       hscb->scsiid,
 	       hscb->lun,
 	       hscb->cdb_len);
-	i = 0;
 	printf("Shared Data: %#02x %#02x %#02x %#02x\n",
-	       hscb->shared_data.cdb[i++],
-	       hscb->shared_data.cdb[i++],
-	       hscb->shared_data.cdb[i++],
-	       hscb->shared_data.cdb[i++]);
+	       hscb->shared_data.cdb[0],
+	       hscb->shared_data.cdb[1],
+	       hscb->shared_data.cdb[2],
+	       hscb->shared_data.cdb[3]);
 	printf("             %#02x %#02x %#02x %#02x\n",
-	       hscb->shared_data.cdb[i++],
-	       hscb->shared_data.cdb[i++],
-	       hscb->shared_data.cdb[i++],
-	       hscb->shared_data.cdb[i++]);
+	       hscb->shared_data.cdb[4],
+	       hscb->shared_data.cdb[5],
+	       hscb->shared_data.cdb[6],
+	       hscb->shared_data.cdb[7]);
 	printf("             %#02x %#02x %#02x %#02x\n",
-	       hscb->shared_data.cdb[i++],
-	       hscb->shared_data.cdb[i++],
-	       hscb->shared_data.cdb[i++],
-	       hscb->shared_data.cdb[i++]);
+	       hscb->shared_data.cdb[8],
+	       hscb->shared_data.cdb[9],
+	       hscb->shared_data.cdb[10],
+	       hscb->shared_data.cdb[11]);
 	printf("        dataptr:%#x datacnt:%#x sgptr:%#x tag:%#x\n",
 		ahc_le32toh(hscb->dataptr),
 		ahc_le32toh(hscb->datacnt),
diff -u --recursive --new-file v2.4.7/linux/drivers/scsi/atp870u.c linux/drivers/scsi/atp870u.c
--- v2.4.7/linux/drivers/scsi/atp870u.c	Wed Jul 25 17:10:23 2001
+++ linux/drivers/scsi/atp870u.c	Sun Aug  5 13:12:41 2001
@@ -11,7 +11,7 @@
  *		   enable 32 bit fifo transfer
  *		   support cdrom & remove device run ultra speed
  *		   fix disconnect bug  2000/12/21
- *		   support atp880 chip lvd u160 2001/05/15
+ *		   support atp880 chip lvd u160 2001/05/15 (7.1)
  */
 
 #include <linux/module.h>
@@ -65,8 +65,10 @@
 	unsigned short wide_idu;
 	unsigned short active_idu;
 	unsigned short ultra_map;
+	unsigned short async;
 	unsigned short deviceid;
 	unsigned char ata_cdbu[16];
+	unsigned char sp[16];
 	Scsi_Cmnd *querequ[qcnt];
 	struct atp_id
 	{
@@ -1694,8 +1696,9 @@
 	static unsigned char satn[9] =	{0, 0, 0, 0, 0, 0, 0, 6, 6};
 	static unsigned char inqd[9] =	{0x12, 0, 0, 0, 0x24, 0, 0, 0x24, 6};
 	static unsigned char synn[6] =	{0x80, 1, 3, 1, 0x19, 0x0e};
-	static unsigned char synu[6] =	{0x80, 1, 3, 1, 0x0a, 0x0e};
-	static unsigned char synw[6] =	{0x80, 1, 3, 1, 0x0a, 0x0e};
+	unsigned char synu[6] =  {0x80, 1, 3, 1, 0x0a, 0x0e};
+	static unsigned char synw[6] =	{0x80, 1, 3, 1, 0x19, 0x0e};
+	unsigned char synuw[6] =  {0x80, 1, 3, 1, 0x0a, 0x0e};
 	static unsigned char wide[6] =	{0x80, 1, 2, 3, 1, 0};
 	static unsigned char u3[9] = { 0x80,1,6,4,0x09,00,0x0e,0x01,0x02 };
 	struct atp_unit *dev = &atp_unit[host];
@@ -1834,17 +1837,18 @@
 		if ((mbuf[7] & 0x60) == 0) {
 			goto not_wide;
 		}
-		if ((dev->global_map & 0x20) == 0) {
+		if ((i < 8) && ((dev->global_map & 0x20) == 0)) {
 			goto not_wide;
 		}
 		if (lvdmode == 0)
 		{
 		   goto chg_wide;
 		}
-		if ((mbuf[2] & 0x07) < 0x03)	      // force u2
+		if (dev->sp[i] != 0x04) 	 // force u2
 		{
 		   goto chg_wide;
 		}
+
 		tmport = wkport + 0x5b;
 		outb(0x01, tmport);
 		tmport = wkport + 0x43;
@@ -2129,10 +2133,28 @@
 		if ((dev->id[i].devtypeu == 0x00) || (dev->id[i].devtypeu == 0x07) ||
 		    ((dev->id[i].devtypeu == 0x05) && ((n & 0x10) != 0)))
 		{
-			goto set_sync;
+			m = 1;
+			m = m << i;
+			if ((dev->async & m) != 0)
+			{
+			   goto set_sync;
+			}
 		}
 		continue;
 set_sync:
+		if (dev->sp[i] == 0x02)
+		{
+		   synu[4]=0x0c;
+		   synuw[4]=0x0c;
+		}
+		else
+		{
+		   if (dev->sp[i] >= 0x03)
+		   {
+		      synu[4]=0x0a;
+		      synuw[4]=0x0a;
+		   }
+		}
 		tmport = wkport + 0x5b;
 		j = 0;
 		if ((m & dev->wide_idu) != 0) {
@@ -2175,7 +2197,11 @@
 			if ((inb(tmport) & 0x01) != 0) {
 				tmport -= 0x06;
 				if ((m & dev->wide_idu) != 0) {
-					outb(synw[j++], tmport);
+					if ((m & dev->ultra_map) != 0) {
+						outb(synuw[j++], tmport);
+					} else {
+						outb(synw[j++], tmport);
+					}
 				} else {
 					if ((m & dev->ultra_map) != 0) {
 						outb(synu[j++], tmport);
@@ -2321,13 +2347,13 @@
 /* return non-zero on detection */
 int atp870u_detect(Scsi_Host_Template * tpnt)
 {
-	unsigned char irq, h, k;
+	unsigned char irq, h, k, m;
 	unsigned long flags;
 	unsigned int base_io, error, tmport;
 	unsigned short index = 0;
 	struct pci_dev *pdev[3];
 	unsigned char chip_ver[3], host_id;
-	unsigned short dev_id[3];
+	unsigned short dev_id[3], n;
 	struct Scsi_Host *shpnt = NULL;
 	int tmpcnt = 0;
 	int count = 0;
@@ -2368,6 +2394,7 @@
 		}
 		for (k = 0; k < 16; k++) {
 			dev->id[k].curr_req = 0;
+			dev->sp[k] = 0x04;
 		}
 	}
 	h = 0;
@@ -2500,7 +2527,7 @@
 		   host_id = inb(base_io + 0x39);
 		   host_id >>= 0x04;
 
-		   printk(KERN_INFO "   ACARD AEC-67160 PCI Ultra3 LVD Host Adapter: %d    IO:%x, IRQ:%d.\n"
+		   printk(KERN_INFO "   ACARD AEC-67160 PCI Ultra160 LVD/SE SCSI Adapter: %d    IO:%x, IRQ:%d.\n"
 			  ,h, base_io, irq);
 		   dev->ioport = base_io + 0x40;
 		   dev->pciport = base_io + 0x28;
@@ -2515,11 +2542,67 @@
 		   dev->global_map = inb(tmport);
 		   tmport += 0x07;
 		   dev->ultra_map = inw(tmport);
-		   if (dev->ultra_map == 0) {
-			   dev->scam_on = 0x00;
-			   dev->global_map = 0x20;
-			   dev->ultra_map = 0xffff;
+
+		   n=0x3f09;
+next_fblk:
+		   if (n >= 0x4000)
+		   {
+		      goto flash_ok;
 		   }
+		   m=0;
+		   outw(n,base_io + 0x34);
+		   n += 0x0002;
+		   if (inb(base_io + 0x30) == 0xff)
+		   {
+		      goto flash_ok;
+		   }
+		   dev->sp[m++]=inb(base_io + 0x30);
+		   dev->sp[m++]=inb(base_io + 0x31);
+		   dev->sp[m++]=inb(base_io + 0x32);
+		   dev->sp[m++]=inb(base_io + 0x33);
+		   outw(n,base_io + 0x34);
+		   n += 0x0002;
+		   dev->sp[m++]=inb(base_io + 0x30);
+		   dev->sp[m++]=inb(base_io + 0x31);
+		   dev->sp[m++]=inb(base_io + 0x32);
+		   dev->sp[m++]=inb(base_io + 0x33);
+		   outw(n,base_io + 0x34);
+		   n += 0x0002;
+		   dev->sp[m++]=inb(base_io + 0x30);
+		   dev->sp[m++]=inb(base_io + 0x31);
+		   dev->sp[m++]=inb(base_io + 0x32);
+		   dev->sp[m++]=inb(base_io + 0x33);
+		   outw(n,base_io + 0x34);
+		   n += 0x0002;
+		   dev->sp[m++]=inb(base_io + 0x30);
+		   dev->sp[m++]=inb(base_io + 0x31);
+		   dev->sp[m++]=inb(base_io + 0x32);
+		   dev->sp[m++]=inb(base_io + 0x33);
+		   n += 0x0018;
+		   goto next_fblk;
+flash_ok:
+		   outw(0,base_io + 0x34);
+		   dev->ultra_map=0;
+		   dev->async = 0;
+		   for (k=0; k < 16; k++)
+		   {
+		       n=1;
+		       n = n << k;
+		       if (dev->sp[k] > 1)
+		       {
+			  dev->ultra_map |= n;
+		       }
+		       else
+		       {
+			  if (dev->sp[k] == 0)
+			  {
+			     dev->async |= n;
+			  }
+		       }
+		   }
+		   dev->async = ~(dev->async);
+		   outb(dev->global_map,base_io + 0x35);
+
 		   shpnt = scsi_register(tpnt, 4);
 		   if(shpnt==NULL)
 			   return count;
@@ -2557,6 +2640,7 @@
 		   tmport = base_io + 0x51;
 		   outb(0x20, tmport);
 
+		   tscam(h);
 		   is880(h, base_io);
 		   tmport = base_io + 0x38;
 		   outb(0xb0, tmport);
@@ -2680,7 +2764,7 @@
 {
 	static char buffer[128];
 
-	strcpy(buffer, "ACARD AEC-6710/6712/67160 PCI Ultra/W/LVD SCSI-3 Adapter Driver V2.4+ac ");
+	strcpy(buffer, "ACARD AEC-6710/6712/67160 PCI Ultra/W/LVD SCSI-3 Adapter Driver V2.5+ac ");
 
 	return buffer;
 }
@@ -2725,7 +2809,7 @@
 	if (offset == 0) {
 		memset(buff, 0, sizeof(buff));
 	}
-	size += sprintf(BLS, "ACARD AEC-671X Driver Version: 2.4+ac\n");
+	size += sprintf(BLS, "ACARD AEC-671X Driver Version: 2.5+ac\n");
 	len += size;
 	pos = begin + len;
 	size = 0;
@@ -2791,4 +2875,3 @@
 
 static Scsi_Host_Template driver_template = ATP870U;
 #include "scsi_module.c"
-
diff -u --recursive --new-file v2.4.7/linux/drivers/scsi/cpqfc.Readme linux/drivers/scsi/cpqfc.Readme
--- v2.4.7/linux/drivers/scsi/cpqfc.Readme	Tue Sep 19 08:01:34 2000
+++ linux/drivers/scsi/cpqfc.Readme	Sun Aug  5 13:12:41 2001
@@ -6,6 +6,23 @@
 33 and 66MHz.  Only supports FC-AL.
 SEST size 512 Exchanges (simultaneous I/Os) limited by module kmalloc() 
 	max of 128k bytes contiguous.
+
+Ver 2.0.2  July 23, 2001
+   Changed the semiphore changes so the driver would compile in 2.4.7. 
+   This version is for 2.4.7 and beyond. 
+ 
+Ver 2.0.1  May 	7, 2001
+   Merged version 1.3.6 fixes into version 2.0.0.   
+
+Ver 2.0.0  May   7, 2001
+  Fixed problem so spinlock is being initialized to UNLOCKED. 
+  Fixed updated driver so it compiles in the 2.4 tree. 
+ 
+ Ver 1.3.6  Feb  27, 2001
+   Added Target_Device_Reset function for SCSI error handling
+   Fixed problem with not reseting addressing mode after implicit logout
+ 
+
 Ver 1.3.4  Sep   7, 2000
   Added Modinfo information
   Fixed problem with statically linking the driver
@@ -212,5 +229,5 @@
 
 
 Send questions/comments to:
-donald.zimmerman@compaq.com
-dszimmerman@yahoo.com
+Amy Vanzant-Hodge (fibrechannel@compaq.com)
+
diff -u --recursive --new-file v2.4.7/linux/drivers/scsi/cpqfcTS.h linux/drivers/scsi/cpqfcTS.h
--- v2.4.7/linux/drivers/scsi/cpqfcTS.h	Tue Sep 19 08:01:34 2000
+++ linux/drivers/scsi/cpqfcTS.h	Sun Aug  5 13:12:41 2001
@@ -5,11 +5,13 @@
 // These functions are required by the Linux SCSI layers
 extern int cpqfcTS_detect(Scsi_Host_Template *);
 extern int cpqfcTS_release(struct Scsi_Host *);
-const char * cpqfcTS_info(struct Scsi_Host *);
+extern const char * cpqfcTS_info(struct Scsi_Host *);
 extern int cpqfcTS_proc_info(char *, char **, off_t, int, int, int);
 extern int cpqfcTS_queuecommand(Scsi_Cmnd *, void (* done)(Scsi_Cmnd *));
 extern int cpqfcTS_abort(Scsi_Cmnd *);
 extern int cpqfcTS_reset(Scsi_Cmnd *, unsigned int);
+extern int cpqfcTS_eh_abort(Scsi_Cmnd *Cmnd);
+extern int cpqfcTS_eh_device_reset(Scsi_Cmnd *);
 extern int cpqfcTS_biosparam(Disk *, kdev_t, int[]);
 extern int cpqfcTS_ioctl( Scsi_Device *ScsiDev, int Cmnd, void *arg);
 
@@ -24,8 +26,10 @@
  proc_info:              cpqfcTS_proc_info,      \
  ioctl:                  cpqfcTS_ioctl,          \
  queuecommand:           cpqfcTS_queuecommand,   \
- eh_abort_handler:       cpqfcTS_abort,          \
+ eh_device_reset_handler:   cpqfcTS_eh_device_reset,   \
+ eh_abort_handler:       cpqfcTS_eh_abort,       \
  reset:                  cpqfcTS_reset,          \
+ abort:                  cpqfcTS_abort,		 \
  bios_param:             cpqfcTS_biosparam,      \
  can_queue:              CPQFCTS_REQ_QUEUE_LEN,  \
  this_id:                -1,                     \
@@ -33,7 +37,8 @@
  cmd_per_lun:            CPQFCTS_CMD_PER_LUN,    \
  present:                0,                      \
  unchecked_isa_dma:      0,                      \
- use_clustering:         ENABLE_CLUSTERING       \
+ use_clustering:         ENABLE_CLUSTERING,      \
+ use_new_eh_code:        1			 \
 }
 
 #endif /* CPQFCTS_H */ 
diff -u --recursive --new-file v2.4.7/linux/drivers/scsi/cpqfcTScontrol.c linux/drivers/scsi/cpqfcTScontrol.c
--- v2.4.7/linux/drivers/scsi/cpqfcTScontrol.c	Fri Mar  2 18:38:38 2001
+++ linux/drivers/scsi/cpqfcTScontrol.c	Sun Aug  5 13:12:41 2001
@@ -42,11 +42,7 @@
 #include <linux/unistd.h>
 #include <asm/io.h>  // struct pt_regs for IRQ handler & Port I/O
 #include <asm/irq.h>
-#if LINUX_VERSION_CODE < LinuxVersionCode(2,3,18)
-#include <asm/spinlock.h>
-#else
 #include <linux/spinlock.h>
-#endif
 
 #include "sd.h"
 #include "hosts.h"   // Scsi_Host definition for INT handler
diff -u --recursive --new-file v2.4.7/linux/drivers/scsi/cpqfcTSinit.c linux/drivers/scsi/cpqfcTSinit.c
--- v2.4.7/linux/drivers/scsi/cpqfcTSinit.c	Wed Jul 25 17:10:23 2001
+++ linux/drivers/scsi/cpqfcTSinit.c	Sun Aug  5 13:12:41 2001
@@ -49,11 +49,7 @@
 #include <asm/io.h>
 #include <asm/uaccess.h>   // ioctl related
 #include <asm/irq.h>
-#if LINUX_VERSION_CODE < LinuxVersionCode(2,3,18)
-#include <asm/spinlock.h>
-#else
 #include <linux/spinlock.h>
-#endif
 #include "sd.h"
 #include <scsi/scsi_ioctl.h>
 #include "hosts.h"
@@ -62,10 +58,15 @@
 
 #include "cpqfcTS.h"
 
+#include <linux/config.h>  
 #include <linux/module.h>
+#include <linux/version.h> 
+
 /* Embedded module documentation macros - see module.h */
 MODULE_AUTHOR("Compaq Computer Corporation");
 MODULE_DESCRIPTION("Driver for Compaq 64-bit/66Mhz PCI Fibre Channel HBA");
+  
+int cpqfcTS_TargetDeviceReset( Scsi_Device *ScsiDev, unsigned int reset_flags);
 
 // This struct was originally defined in 
 // /usr/src/linux/include/linux/proc_fs.h
@@ -104,24 +105,24 @@
 
   // since x86 port space is 64k, we only need the lower 16 bits
   cpqfcHBAdata->fcChip.Registers.IOBaseL = 
-    PciDev->base_address[1] & PCI_BASE_ADDRESS_IO_MASK;
+    PciDev->resource[1].start & PCI_BASE_ADDRESS_IO_MASK;
   
   cpqfcHBAdata->fcChip.Registers.IOBaseU = 
-    PciDev->base_address[2] & PCI_BASE_ADDRESS_IO_MASK;
+    PciDev->resource[2].start & PCI_BASE_ADDRESS_IO_MASK;
   
   // 32-bit memory addresses
   cpqfcHBAdata->fcChip.Registers.MemBase = 
-    PciDev->base_address[3] & PCI_BASE_ADDRESS_MEM_MASK;
+    PciDev->resource[3].start & PCI_BASE_ADDRESS_MEM_MASK;
 
   cpqfcHBAdata->fcChip.Registers.ReMapMemBase = 
-    ioremap( PciDev->base_address[3] & PCI_BASE_ADDRESS_MEM_MASK,
+    ioremap( PciDev->resource[3].start & PCI_BASE_ADDRESS_MEM_MASK,
              0x200);
   
   cpqfcHBAdata->fcChip.Registers.RAMBase = 
-    PciDev->base_address[4];
+    PciDev->resource[4].start;
   
   cpqfcHBAdata->fcChip.Registers.SROMBase =  // NULL for HP TS adapter
-    PciDev->base_address[5];
+    PciDev->resource[5].start;
   
   // now the Tachlite chip registers
   // the REGISTER struct holds both the physical address & last
@@ -296,10 +297,14 @@
       	continue;
       DEBUG_PCI( printk("  HBA found!\n"));
       DEBUG_PCI( printk("  HostAdapter->PciDev->irq = %u\n", PciDev->irq) );
-      DEBUG_PCI(printk("  PciDev->baseaddress[]= %lx\n", PciDev->base_address[0]));
-      DEBUG_PCI(printk("  PciDev->baseaddress[]= %lx\n", PciDev->base_address[1]));
-      DEBUG_PCI(printk("  PciDev->baseaddress[]= %lx\n", PciDev->base_address[2]));
-      DEBUG_PCI(printk("  PciDev->baseaddress[]= %lx\n", PciDev->base_address[3]));
+      DEBUG_PCI(printk("  PciDev->baseaddress[0]= %lx\n", 
+				PciDev->resource[0].start));
+      DEBUG_PCI(printk("  PciDev->baseaddress[1]= %lx\n", 
+				PciDev->resource[1].start));
+      DEBUG_PCI(printk("  PciDev->baseaddress[2]= %lx\n", 
+				PciDev->resource[2].start));
+      DEBUG_PCI(printk("  PciDev->baseaddress[3]= %lx\n", 
+				PciDev->resource[3].start));
 
       scsi_set_pci_device(HostAdapter, PciDev);      
       HostAdapter->irq = PciDev->irq;  // copy for Scsi layers
@@ -308,7 +313,7 @@
       // for a total I/O port address space of 512 bytes.
       // mask out the I/O port address (lower) & record
       HostAdapter->io_port = (unsigned int)
-	     PciDev->base_address[1] & PCI_BASE_ADDRESS_IO_MASK;
+	     PciDev->resource[1].start & PCI_BASE_ADDRESS_IO_MASK;
       HostAdapter->n_io_port = 0xff;
       
       // i.e., expect 128 targets (arbitrary number), while the
@@ -316,7 +321,6 @@
       HostAdapter->max_id =  0;   // incremented as devices log in    
       HostAdapter->max_lun = CPQFCTS_MAX_LUN;         // LUNs per FC device
       HostAdapter->max_channel = CPQFCTS_MAX_CHANNEL; // multiple busses?
-      HostAdapter->hostt->use_new_eh_code = 1; // new error handling
       
       // get the pointer to our HBA specific data... (one for
       // each HBA on the PCI bus(ses)).
@@ -333,7 +337,7 @@
       Cpqfc_initHBAdata( cpqfcHBAdata, PciDev ); // fill MOST fields
      
       cpqfcHBAdata->HBAnum = NumberOfAdapters;
-
+      cpqfcHBAdata->hba_spinlock = SPIN_LOCK_UNLOCKED;
 
       // request necessary resources and check for conflicts
       if( request_irq( HostAdapter->irq,
@@ -414,9 +418,12 @@
 	// slowest(worst) case, measured on 1Gb Finisar GT analyzer
 	
 	int wait_time;
+	unsigned long flags=0;
+ 
+        spin_unlock_irqrestore(&io_request_lock, flags);
         for( wait_time = jiffies + 4*HZ; wait_time > jiffies; )
 	  schedule();  // (our worker task needs to run)
-
+	spin_lock_irqsave(&io_request_lock, flags);
       }
       
       NumberOfAdapters++; 
@@ -458,7 +465,7 @@
   Scsi_Cmnd *ScsiPassThruCmnd;
   unsigned long flags;
 
-  ENTER("cpqfcTS_ioctl");
+  ENTER("cpqfcTS_ioctl ");
   
   // can we find an FC device mapping to this SCSI target?
   DumCmnd.channel = ScsiDev->channel;		// For searching
@@ -476,6 +483,7 @@
  
   else  // we know what FC device to operate on...
   {
+	// printk("ioctl CMND %d", Cmnd);
     switch (Cmnd) 
     {
       // Passthrough provides a mechanism to bypass the RAID
@@ -496,8 +504,8 @@
 	  return -EPERM;
 
 	// copy the caller's struct to our space.
-        copy_from_user_ret( &ioc, arg, 
-			  sizeof( VENDOR_IOCTL_REQ), -EFAULT);
+        if( copy_from_user( &ioc, arg, sizeof( VENDOR_IOCTL_REQ)))
+		return( -EFAULT);
 
 	vendor_cmd = ioc.argp;  // i.e., CPQ specific command struct
 
@@ -512,13 +520,14 @@
         // Now build a SCSI_CMND to pass down...
 	// This function allocates and sets Scsi_Cmnd ptrs such as
 	//  ->channel, ->target, ->host
-        ScsiPassThruCmnd = scsi_allocate_device(NULL, ScsiDev, 1);
+        ScsiPassThruCmnd = scsi_allocate_device(ScsiDev, 1, 1);
 
         // Need data from user?
 	// make sure caller's buffer is in kernel space.
 	if( (vendor_cmd->rw_flag == VENDOR_WRITE_OPCODE) &&
 	    vendor_cmd->len)
-          copy_from_user_ret( buf, vendor_cmd->bufp, vendor_cmd->len, -EFAULT);
+        if(  copy_from_user( buf, vendor_cmd->bufp, vendor_cmd->len))
+		return( -EFAULT);
 	    
 	// copy the CDB (if/when MAX_COMMAND_SIZE is 16, remove copy below)
         memcpy( &ScsiPassThruCmnd->cmnd[0], 
@@ -590,16 +599,17 @@
         scsi_release_command(ScsiPassThruCmnd); // "de-allocate"
         ScsiPassThruCmnd = NULL;
 
-        if (!SDpnt->was_reset && SDpnt->scsi_request_fn)
-          (*SDpnt->scsi_request_fn)();
+        // if (!SDpnt->was_reset && SDpnt->scsi_request_fn)
+        //  (*SDpnt->scsi_request_fn)();
 
-        wake_up(&SDpnt->device_wait);
+        wake_up(&SDpnt->scpnt_wait);
         spin_unlock_irqrestore(&io_request_lock, flags);
 
 	// need to pass data back to user (space)?
 	if( (vendor_cmd->rw_flag == VENDOR_READ_OPCODE) &&
 	     vendor_cmd->len )
-          copy_to_user_ret( vendor_cmd->bufp, buf, vendor_cmd->len, -EFAULT);
+        if(  copy_to_user( vendor_cmd->bufp, buf, vendor_cmd->len))
+		return( -EFAULT);
 
         if( buf) 
 	  kfree( buf);
@@ -621,8 +631,8 @@
 	pciinfo.board_id = cpqfcHBAdata->PciDev->device |
 			  (cpqfcHBAdata->PciDev->vendor <<16); 
 	      
-        copy_to_user_ret( arg, &pciinfo, 
-			  sizeof(cpqfc_pci_info_struct), -EFAULT);
+        if(copy_to_user( arg, &pciinfo, sizeof(cpqfc_pci_info_struct)))
+		return( -EFAULT);
         return 0;
       }
 
@@ -634,8 +644,8 @@
 	if( !arg)
 	  return -EINVAL;
 
-        copy_to_user_ret( arg, &DriverVer, 
-			  sizeof(DriverVer), -EFAULT);
+        if(copy_to_user( arg, &DriverVer, sizeof(DriverVer)))
+		return( -EFAULT);
         return 0;
       }
 
@@ -657,6 +667,17 @@
         put_user(pLoggedInPort->u.ucWWN[i], 
 		&((Scsi_FCTargAddress *) arg)->host_wwn[j++]);
         break;
+
+
+      case SCSI_IOCTL_FC_TDR:
+          
+        result = cpqfcTS_TargetDeviceReset( ScsiDev, 0);
+
+        break;
+
+
+
+
     default:
       result = -EINVAL;
       break;
@@ -1351,13 +1372,20 @@
 
 int cpqfcTS_abort(Scsi_Cmnd *Cmnd)
 {
+//	printk(" cpqfcTS_abort called?? \n");
+ 	return 0;
+}
+ 
+int cpqfcTS_eh_abort(Scsi_Cmnd *Cmnd)
+{
+
   struct Scsi_Host *HostAdapter = Cmnd->host;
   // get the pointer to our Scsi layer HBA buffer  
   CPQFCHBA *cpqfcHBAdata = (CPQFCHBA *)HostAdapter->hostdata;
   PTACHYON fcChip = &cpqfcHBAdata->fcChip;
   FC_EXCHANGES *Exchanges = fcChip->Exchanges;
   int i;
-  ENTER("cpqfcTS_abort");
+  ENTER("cpqfcTS_eh_abort");
 
   Cmnd->result = DID_ABORT <<16;  // assume we'll find it
 
@@ -1443,28 +1471,117 @@
 Done:
   
 //    panic("_abort");
-  LEAVE("cpqfcTS_abort");
+  LEAVE("cpqfcTS_eh_abort");
   return 0;  // (see scsi.h)
 }    
 
 
+// FCP-SCSI Target Device Reset
+// See dpANS Fibre Channel Protocol for SCSI
+// X3.269-199X revision 12, pg 25
+
+int cpqfcTS_TargetDeviceReset( Scsi_Device *ScsiDev, 
+                               unsigned int reset_flags)
+{
+  int timeout = 10*HZ;
+  int retries = 1;
+  char scsi_cdb[12];
+  unsigned long flags;
+  int result;
+  Scsi_Cmnd * SCpnt;
+  Scsi_Device * SDpnt;
 
 
-// To be done...	
-int cpqfcTS_reset(Scsi_Cmnd *Cmnd, unsigned int reset_flags)
-{
-  int return_status = SUCCESS;
+  // printk("   ENTERING cpqfcTS_TargetDeviceReset() - flag=%d \n",reset_flags);
 
-  ENTER("cpqfcTS_reset");
+  if (ScsiDev->host->eh_active) return FAILED;
 
+  memset( scsi_cdb, 0, sizeof( scsi_cdb));
 
-            
+  scsi_cdb[0] = RELEASE;
 
-  LEAVE("cpqfcTS_reset");
-  return return_status;
-}    
+  spin_lock_irqsave(&io_request_lock, flags);
 
+  // allocate with wait = true, interruptible = false 
+  SCpnt = scsi_allocate_device(ScsiDev, 1, 0);
+  {
+    DECLARE_COMPLETION(wait);
+        
+    SCpnt->SCp.buffers_residual = FCP_TARGET_RESET;
+
+	SCpnt->request.waiting = &wait;
+	scsi_do_cmd(SCpnt,  scsi_cdb, NULL,  0, my_ioctl_done,  timeout, retries);
+	spin_unlock_irqrestore(&io_request_lock, flags);
+	wait_for_completion(&wait);
+    spin_lock_irqsave(&io_request_lock, flags);
+    SCpnt->request.waiting = NULL;
+  }
+    
+/*
+      if(driver_byte(SCpnt->result) != 0)
+	  switch(SCpnt->sense_buffer[2] & 0xf) {
+	case ILLEGAL_REQUEST:
+	    if(cmd[0] == ALLOW_MEDIUM_REMOVAL) dev->lockable = 0;
+	    else printk("SCSI device (ioctl) reports ILLEGAL REQUEST.\n");
+	    break;
+	case NOT_READY: // This happens if there is no disc in drive 
+	    if(dev->removable && (cmd[0] != TEST_UNIT_READY)){
+		printk(KERN_INFO "Device not ready.  Make sure there is a disc in the drive.\n");
+		break;
+	    }
+	case UNIT_ATTENTION:
+	    if (dev->removable){
+		dev->changed = 1;
+		SCpnt->result = 0; // This is no longer considered an error
+		// gag this error, VFS will log it anyway /axboe 
+		// printk(KERN_INFO "Disc change detected.\n"); 
+		break;
+	    };
+	default: // Fall through for non-removable media
+	    printk("SCSI error: host %d id %d lun %d return code = %x\n",
+		   dev->host->host_no,
+		   dev->id,
+		   dev->lun,
+		   SCpnt->result);
+	    printk("\tSense class %x, sense error %x, extended sense %x\n",
+		   sense_class(SCpnt->sense_buffer[0]),
+		   sense_error(SCpnt->sense_buffer[0]),
+		   SCpnt->sense_buffer[2] & 0xf);
+	    
+      };
+*/    
+  result = SCpnt->result;
+
+  SDpnt = SCpnt->device;
+  scsi_release_command(SCpnt);
+  SCpnt = NULL;
+
+  // if (!SDpnt->was_reset && SDpnt->scsi_request_fn)
+  // 	(*SDpnt->scsi_request_fn)();
+
+  wake_up(&SDpnt->scpnt_wait);
+  spin_unlock_irqrestore(&io_request_lock, flags);
+  // printk("   LEAVING cpqfcTS_TargetDeviceReset() - return SUCCESS \n");
+  return SUCCESS;
+}
+
+
+int cpqfcTS_eh_device_reset(Scsi_Cmnd *Cmnd)
+{
+  Scsi_Device *SDpnt = Cmnd->device;
+  // printk("   ENTERING cpqfcTS_eh_device_reset() \n");
+  return cpqfcTS_TargetDeviceReset( SDpnt, 0);
+}
+
+	
+int cpqfcTS_reset(Scsi_Cmnd *Cmnd, unsigned int reset_flags)
+{
 
+  ENTER("cpqfcTS_reset");
+
+  LEAVE("cpqfcTS_reset");
+  return SCSI_RESET_ERROR;      /* Bus Reset Not supported */
+}
 
 /* This function determines the bios parameters for a given
    harddisk. These tend to be numbers that are made up by the
@@ -1805,15 +1922,7 @@
 }
 
 
-
-
-#ifdef MODULE
-
 static Scsi_Host_Template driver_template = CPQFCTS;
 
 #include "scsi_module.c"
-
-
-#endif
-
 
diff -u --recursive --new-file v2.4.7/linux/drivers/scsi/cpqfcTSstructs.h linux/drivers/scsi/cpqfcTSstructs.h
--- v2.4.7/linux/drivers/scsi/cpqfcTSstructs.h	Tue Sep 19 08:01:34 2000
+++ linux/drivers/scsi/cpqfcTSstructs.h	Sun Aug  5 13:12:41 2001
@@ -29,9 +29,9 @@
                          for( wait_time=jiffies + (secs*HZ); \
 		         wait_time > jiffies ;) ; }
 #define CPQFCTS_DRIVER_VER(maj,min,submin) ((maj<<16)|(min<<8)|(submin))
-#define VER_MAJOR 1
-#define VER_MINOR 3
-#define VER_SUBMINOR 4
+#define VER_MAJOR 2
+#define VER_MINOR 0
+#define VER_SUBMINOR 2
 
 // Macros for kernel (esp. SMP) tracing using a PCI analyzer
 // (e.g. x86).
@@ -225,6 +225,7 @@
 #define ELS_RJT 0x1000000
 #define SCSI_REPORT_LUNS 0x0A0
 #define REPORT_LUNS 0xA0 // SCSI-3 command op-code
+#define FCP_TARGET_RESET 0x200
 
 #define ELS_LILP_FRAME 0x00000711 // 1st payload word of LILP frame
 
diff -u --recursive --new-file v2.4.7/linux/drivers/scsi/cpqfcTSworker.c linux/drivers/scsi/cpqfcTSworker.c
--- v2.4.7/linux/drivers/scsi/cpqfcTSworker.c	Fri Mar  2 18:38:38 2001
+++ linux/drivers/scsi/cpqfcTSworker.c	Sun Aug  5 13:12:41 2001
@@ -149,7 +149,6 @@
               CPQFCHBA* cpqfcHBAdata, 
 	      TachFCHDR_GCMND* fchs);
 
-
 // (see scsi_error.c comments on kernel task creation)
 
 void cpqfcTSWorkerThread( void *host)
@@ -1069,6 +1068,7 @@
   pFcPort->flogi = FALSE;
   pFcPort->LOGO_timer = 0;
   pFcPort->device_blocked = TRUE; // block Scsi Requests
+  pFcPort->ScsiNexus.VolumeSetAddressing=0;	
 }
 
   
@@ -2934,7 +2934,6 @@
   ULONG ulStatus;
   UCHAR *ucBuff;
 
-
   if( !cpqfcHBAdata->PortDiscDone) // cleared by LDn
   {
     printk("Discard Q'd ReportLun command\n");
@@ -2976,7 +2975,7 @@
 
     Cmnd->channel = pLoggedInPort->ScsiNexus.channel;
     Cmnd->target = pLoggedInPort->ScsiNexus.target;
-    
+
 	    
     ulStatus = cpqfcTSBuildExchange(
       cpqfcHBAdata,
@@ -3404,7 +3403,7 @@
     if( port_id_valid ) // look for alpa first
     {
       if( pLoggedInPort->port_id == port_id )
-        break;  // found it!
+          break;  // found it!
     }
     if( wwn_valid ) // look for wwn second
     {
@@ -4326,7 +4325,6 @@
       break;
     
     
-    
     case BLS_ABTS:   // FC defined basic link service command ABTS 
                      // Abort Sequence
                      
@@ -4498,6 +4496,7 @@
 
                          // Fibre Channel SCSI 'originator' sequences...
                          // (originator means 'initiator' in FCP-SCSI)
+
     case SCSI_IWE: // TachLite Initiator Write Entry
     {
       PFC_LOGGEDIN_PORT pLoggedInPort = 
@@ -6171,7 +6170,18 @@
       // 4 bytes Control Field FCP_CNTL
       *payload++ = 0;    // byte 0: (MSB) reserved
       *payload++ = 0;    // byte 1: task codes
-      *payload++ = 0;    // byte 2: task management flags
+
+                         // byte 2: task management flags
+      // another "use" of the spare field to accomplish TDR
+      // note combination needed
+      if( (Cmnd->cmnd[0] == RELEASE) &&
+          (Cmnd->SCp.buffers_residual == FCP_TARGET_RESET) )
+      {
+        Cmnd->cmnd[0] = 0;    // issue "Test Unit Ready" for TDR
+        *payload++ = 0x20;    // target device reset bit
+      }
+      else
+        *payload++ = 0;    // no TDR
 		      // byte 3: (LSB) execution management codes
 		      // bit 0 write, bit 1 read (don't set together)
       
diff -u --recursive --new-file v2.4.7/linux/drivers/scsi/g_NCR5380.c linux/drivers/scsi/g_NCR5380.c
--- v2.4.7/linux/drivers/scsi/g_NCR5380.c	Tue Mar  6 19:44:37 2001
+++ linux/drivers/scsi/g_NCR5380.c	Wed Jul 25 14:12:02 2001
@@ -399,6 +399,7 @@
 		release_mem_region(overrides[current_override].NCR5380_map_name,
 	                                  	NCR5380_region_size);
 #endif
+		continue;
 	}
 	
 	instance->NCR5380_instance_name = overrides[current_override].NCR5380_map_name;
diff -u --recursive --new-file v2.4.7/linux/drivers/scsi/gdth_proc.c linux/drivers/scsi/gdth_proc.c
--- v2.4.7/linux/drivers/scsi/gdth_proc.c	Wed Jul 25 17:10:23 2001
+++ linux/drivers/scsi/gdth_proc.c	Wed Jul 25 14:12:02 2001
@@ -47,6 +47,8 @@
 #if LINUX_VERSION_CODE >= 0x020322
     sdev = scsi_get_host_dev(gdth_ctr_vtab[vh]);
     scp  = scsi_allocate_device(sdev, 1, FALSE);
+    if (!scp)
+	    return -ENOMEM;
     scp->cmd_len = 12;
     scp->use_sg = 0;
 #else
diff -u --recursive --new-file v2.4.7/linux/drivers/scsi/megaraid.c linux/drivers/scsi/megaraid.c
--- v2.4.7/linux/drivers/scsi/megaraid.c	Wed Jul 25 17:10:23 2001
+++ linux/drivers/scsi/megaraid.c	Wed Jul 25 14:12:02 2001
@@ -9,7 +9,7 @@
  *              as published by the Free Software Foundation; either version
  *              2 of the License, or (at your option) any later version.
  *
- * Version : v1.15d(May 30, 2001)
+ * Version : v1.17a (July 13, 2001)
  *
  * Description: Linux device driver for AMI MegaRAID controller
  *
@@ -21,7 +21,7 @@
  *     Original source contributed by Dell; integrated it into the kernel and
  *     cleaned up some things.  Added support for 438/466 controllers.
  * Version 0.91:
- *     Aligned mailbox area on 16-byte boundry.
+ *     Aligned mailbox area on 16-byte boundary.
  *     Added schedule() at the end to properly clean up.
  *     Made improvements for conformity to linux driver standards.
  *
@@ -105,13 +105,13 @@
  *    Added new ioctl command 0x81 to support NEW_READ/WRITE_CONFIG with
  *      data area greater than 4 KB, which is the upper bound for data
  *      tranfer through scsi_ioctl interface.
- *    The addtional 32 bit field for 64bit address in the newly defined
+ *    The additional 32 bit field for 64bit address in the newly defined
  *      mailbox64 structure is set to 0 at this point.
  *
  * Version 1.05
  *    Changed the queing implementation for handling SCBs and completed
  *      commands.
- *    Added spinlocks in the interrupt service routine to enable the dirver
+ *    Added spinlocks in the interrupt service routine to enable the driver
  *      function in the SMP environment.
  *    Fixed the problem of unnecessary aborts in the abort entry point, which
  *      also enables the driver to handle large amount of I/O requests for
@@ -189,18 +189,18 @@
  *                 MEGA_HP_FIX)
  *
  *      Version 1a12
- *      I.      reboot notifer and new ioctl changes ported from 1c09
+ *      I.      reboot notifier and new ioctl changes ported from 1c09
  *
- *      Veriosn 1b12
+ *      Version 1b12
  *      I.      Changes in new ioctl interface routines ( Nov 06, 2000 )
  *
- *      Veriosn 1c12
+ *      Version 1c12
  *      I.      Changes in new ioctl interface routines ( Nov 07, 2000 )
  *
- *      Veriosn 1d12
+ *      Version 1d12
  *      I.      Compilation error under kernel 2.4.0 for 32-bit machine in mega_ioctl
  *
- *      Veriosn 1e12, 1f12
+ *      Version 1e12, 1f12
  *      1.  Fixes for pci_map_single, pci_alloc_consistent along with mailbox
  *          alignment
  *
@@ -228,7 +228,7 @@
  * 	
  *	Version 1.13j
  *	Moved some code to megaraid.h file, replaced some hard coded values 
- *      with respective macros. Chaged some funtions to static
+ *      with respective macros. Changed some functions to static
  *
  *	Version 1.13k
  *	Only some idendation correction to 1.13j 
@@ -327,10 +327,38 @@
  *	Assorted changes to remove compilation error in 1.14k when compiled
  *	with kernel < 2.4.0
  *
+ *	Version 1.14m
+ *	Tue Mar 27 12:09:22 EST 2001 - AM
+ *
+ *	Added support for extended CDBs ( > 10 bytes ) and OBDR ( One Button
+ *	Disaster Recovery ) feature.
+ *
+ *
+ *	Version 1.14n
+ *	Tue Apr 10 14:28:13 EDT 2001 - AM
+ *
+ *	"modeversions.h" is no longer included in the code.
+ *	2.4.xx style mutex initialization used for older kernels also
+ *
+ *	Version 1.14o
+ *	Wed Apr 18 17:47:26 EDT 2001 - PJ
+ *
+ *	Before returning status for 'inquiry', we first check if request buffer
+ *	is SG list, and then return appropriate status
+ *
+ *	Version 1.14p
+ *	Wed Apr 25 13:44:48 EDT 2001 - PJ
+ *
+ *	SCSI result made appropriate in case of check conditions for extended
+ *	passthru commands
+ *
+ *	Do not support lun >7 for physically accessed devices 
+ *
+ *	
  *	Version 1.15
  *	Thu Apr 19 09:38:38 EDT 2001 - AM
  *
- *	1.14l rollover to 1.15
+ *	1.14l rollover to 1.15 - merged with main trunk after 1.15d
  *
  *	Version 1.15b
  *  Wed May 16 20:10:01 EDT 2001 - AM
@@ -338,7 +366,7 @@
  *	"modeversions.h" is no longer included in the code.
  *	2.4.xx style mutex initialization used for older kernels also
  *	Brought in-sync with Alan's changes in 2.4.4
- *	Note: 1.15a is on OBDR brabch(main trunk), and is not merged with yet.
+ *	Note: 1.15a is on OBDR branch(main trunk), and is not merged with yet.
  *
  * Version 1.15c
  * Mon May 21 23:10:42 EDT 2001 - AM
@@ -352,7 +380,53 @@
  * NULL is not a valid first argument for pci_alloc_consistent() on
  * IA64(2.4.3-2.10.1). Code shuffling done in ioctl interface to get
  * "pci_dev" before making calls to pci interface routines.
-
+ *
+ * Version 1.16pre
+ * Fri Jun  1 19:40:48 EDT 2001 - AM
+ *
+ * 1.14p and 1.15d merged
+ * ROMB support added
+ *
+ * Version 1.16-pre1
+ * Mon Jun  4 15:01:01 EDT 2001 - AM
+ *
+ * Non-ROMB firmware do no DMA support 0xA9 command. Value 0xFF
+ * (all channels are raid ) is chosen for those firmware.
+ *
+ * Version 1.16-pre2
+ * Mon Jun 11 18:15:31 EDT 2001 - AM
+ *
+ * Changes for boot from any logical drive
+ *
+ * Version 1.16
+ * Tue Jun 26 18:07:02 EDT 2001 - AM
+ *
+ * branched at 1.14p
+ *
+ * Check added for HP 1M/2M controllers if having firmware H.01.07 or
+ * H.01.08. If found, disable 64 bit support since these firmware have
+ * limitations for 64 bit addressing
+ *
+ *
+ * Version 1.17
+ * Thu Jul 12 11:14:09 EDT 2001 - AM
+ *
+ * 1.16pre2 and 1.16 merged.
+ *
+ * init_MUTEX and init_MUTEX_LOCKED are defined in 2.2.19. Pre-processor
+ * statements are added for them
+ *
+ * Linus's 2.4.7pre3 kernel introduces a new field 'max_sectors' in Scsi_Host
+ * structure, to improve IO performance.
+ *
+ *
+ * Version 1.17a
+ * Fri Jul 13 18:44:01 EDT 2001 - AM
+ *
+ * Starting from kernel 2.4.x, LUN is not < 8 - following SCSI-III. So to have
+ * our current formula working to calculate logical drive number, return
+ * failure for LUN > 7
+ *
  * BUGS:
  *     Some older 2.1 kernels (eg. 2.1.90) have a bug in pci.c that
  *     fails to detect the controller as a pci device on the system.
@@ -509,16 +583,17 @@
 
 #define pci_free_consistent(a,b,c,d)
 #define pci_unmap_single(a,b,c,d)
-
-#define init_MUTEX_LOCKED(x)    (*(x)=MUTEX_LOCKED)
-#define init_MUTEX(x)           (*(x)=MUTEX)
-
 #define pci_enable_device(x) (0)
-
 #define queue_task_irq(a,b)     queue_task(a,b)
 #define queue_task_irq_off(a,b) queue_task(a,b)
 
+#if LINUX_VERSION_CODE < KERNEL_VERSION(2,2,19)	/* 0x020219 */
+#define init_MUTEX_LOCKED(x)    (*(x)=MUTEX_LOCKED)
+#define init_MUTEX(x)           (*(x)=MUTEX)
 #define DECLARE_WAIT_QUEUE_HEAD(x)	struct wait_queue *x = NULL
+#endif
+
+
 #else
 
 /*
@@ -577,7 +652,9 @@
 #define dma_alloc_consistent pci_alloc_consistent
 #define dma_free_consistent pci_free_consistent
 #else
+#if LINUX_VERSION_CODE < KERNEL_VERSION(2,2,19)	/* 0x020219 */
 typedef unsigned long dma_addr_t;
+#endif
 void *dma_alloc_consistent(void *, size_t, dma_addr_t *);
 void dma_free_consistent(void *, size_t, void *, dma_addr_t);
 int mega_get_order(int);
@@ -661,7 +738,7 @@
 static struct mcontroller mcontroller[MAX_CONTROLLERS];
 
 /* The current driver version */
-static u32 driver_ver = 114;
+static u32 driver_ver = 117;
 
 /* major number used by the device for character interface */
 static int major;
@@ -684,6 +761,8 @@
 extern struct proc_dir_entry proc_root;
 #endif
 
+static char mega_ch_class;	/* channels are raid or scsi */
+#define	IS_RAID_CH(ch)	( (mega_ch_class >> (ch)) & 0x01 )
 
 #if SERDEBUG
 static char strbuf[MAX_SERBUF + 1];
@@ -782,6 +861,11 @@
 				  pScb->pthru->dataxferlen,
 				  pScb->dma_direction);
 		break;
+	case M_RD_EPTHRU_WITH_BULK_DATA:
+		pci_unmap_single (megaCfg->dev, pScb->dma_h_bulkdata,
+				  pScb->epthru->dataxferlen,
+				  pScb->dma_direction);
+		break;
 	case M_RD_PTHRU_WITH_SGLIST:
 	{
 		int count;
@@ -928,7 +1012,10 @@
 	int islogical;
 	Scsi_Cmnd *SCpnt;
 	mega_passthru *pthru;
+	mega_ext_passthru *epthru;
 	mega_mailbox *mbox;
+	struct scatterlist *sgList;
+	u8	c;
 
 	if (pScb == NULL) {
 		TRACE (("NULL pScb in mega_cmd_done!"));
@@ -939,8 +1026,10 @@
 
 #if LINUX_VERSION_CODE >= KERNEL_VERSION(2,4,0)
 	pthru = pScb->pthru;
+	epthru = pScb->epthru;
 #else
 	pthru = &pScb->pthru;
+	epthru = &pScb->epthru;
 #endif
 
 	mbox = (mega_mailbox *) & pScb->mboxData;
@@ -968,9 +1057,33 @@
 
 	mega_freeSCB (megaCfg, pScb);
 
+	/*
+	 * Do not return the presence of hard disk on the channel so, inquiry
+	 * sent, and returned data==hard disk or removable hard disk and not
+	 * logical, request should return failure! - PJ
+	 */
+#if 0
 	if (SCpnt->cmnd[0] == INQUIRY && ((((u_char *) SCpnt->request_buffer)[0] & 0x1F) == TYPE_DISK) && !islogical) {
 		status = 0xF0;
 	}
+#endif
+	if (SCpnt->cmnd[0] == INQUIRY && !islogical) {
+		if ( SCpnt->use_sg ) {
+			sgList = (struct scatterlist *)SCpnt->request_buffer;
+			memcpy(&c, sgList[0].address, 0x1);
+		} else {
+			memcpy(&c, SCpnt->request_buffer, 0x1);
+		}
+#if 0
+		if( (c & 0x1F ) == TYPE_DISK ) {
+			status = 0xF0;
+		}
+#endif
+		if( IS_RAID_CH(SCpnt->channel) && ((c & 0x1F ) == TYPE_DISK) ) {
+			status = 0xF0;
+		}
+	}
+
 
 	/* clear result; otherwise, success returns corrupt value */
 	SCpnt->result = 0;
@@ -997,7 +1110,16 @@
 			/*set sense_buffer and result fields */
 			if (mbox->cmd == MEGA_MBOXCMD_PASSTHRU) {
 				memcpy (SCpnt->sense_buffer, pthru->reqsensearea, 14);
-				SCpnt->result = (DRIVER_SENSE << 24) | (DID_ERROR << 16) | status;
+			} else if (mbox->cmd == MEGA_MBOXCMD_EXTPASSTHRU) {
+				SCpnt->result = (DRIVER_SENSE << 24) | (DID_OK << 16) | (CHECK_CONDITION < 1);
+				memcpy(
+					SCpnt->sense_buffer,
+					epthru->reqsensearea, 14
+				);
+				SCpnt->result = (DRIVER_SENSE << 24) | (DID_OK << 16) | (CHECK_CONDITION < 1);
+				/*SCpnt->result =
+					(DRIVER_SENSE << 24) |
+					(DID_ERROR << 16) | status;*/
 			} else {
 				SCpnt->sense_buffer[0] = 0x70;
 				SCpnt->sense_buffer[2] = ABORTED_COMMAND;
@@ -1041,6 +1163,7 @@
 	mega_scb *pScb;
 	mega_mailbox *mbox;
 	mega_passthru *pthru;
+	mega_ext_passthru *epthru;
 	long seg;
 	char islogical;
 	char lun = SCpnt->lun;
@@ -1060,27 +1183,56 @@
 	}
 #endif
 
-	islogical = (SCpnt->channel == megaCfg->host->max_channel);
+	islogical = (IS_RAID_CH(SCpnt->channel) && /* virtual ch is raid - AM */
+						(SCpnt->channel == megaCfg->host->max_channel));
+
+	if ( ! megaCfg->support_ext_cdb ) {
+		if (!islogical && lun != 0) {
+			SCpnt->result = (DID_BAD_TARGET << 16);
+			callDone (SCpnt);
+			return NULL;
+		}
+	}
 
-	if (!islogical && lun != 0) {
+	if (!islogical && SCpnt->target == skip_id) {
 		SCpnt->result = (DID_BAD_TARGET << 16);
 		callDone (SCpnt);
 		return NULL;
 	}
 
-	if (!islogical && SCpnt->target == skip_id) {
+	/*
+	 * Return error for LUN > 7. The way we calculate logical drive number
+	 * requires it to be so.
+	 */
+	if( lun > 7 ) {
 		SCpnt->result = (DID_BAD_TARGET << 16);
 		callDone (SCpnt);
 		return NULL;
 	}
 
 	if (islogical) {
+
 		lun = (SCpnt->target * 8) + lun;
-		if (lun > FC_MAX_LOGICAL_DRIVES) {
+
+		if(lun >= megaCfg->numldrv ) {
 			SCpnt->result = (DID_BAD_TARGET << 16);
 			callDone (SCpnt);
 			return NULL;
 		}
+
+		/*
+		 * If we have a logical drive with boot enabled, project it first
+		 */
+		if( megaCfg->boot_ldrv_enabled ) {
+			if( lun == 0 ) {
+				lun = megaCfg->boot_ldrv;
+			}
+			else {
+				if( lun <= megaCfg->boot_ldrv ) {
+					lun--;
+				}
+			}
+		}
 	}
 	/*-----------------------------------------------------
 	 *
@@ -1232,8 +1384,35 @@
 					    mbox->numsectors;
 				}
 			}
+
+			/* 12-byte */
+			if (*SCpnt->cmnd == READ_12 || *SCpnt->cmnd == WRITE_12) {
+				mbox->lba =
+				    ((u32) SCpnt->cmnd[2] << 24) |
+				    ((u32) SCpnt->cmnd[3] << 16) |
+				    ((u32) SCpnt->cmnd[4] << 8) |
+				    (u32) SCpnt->cmnd[5];
+
+				mbox->numsectors =
+				    ((u32) SCpnt->cmnd[6] << 24) |
+				    ((u32) SCpnt->cmnd[7] << 16) |
+				    ((u32) SCpnt->cmnd[8] << 8) |
+				    (u32) SCpnt->cmnd[9];
+
+				if (*SCpnt->cmnd == READ_12) {
+					megaCfg->nReads[(int) lun]++;
+					megaCfg->nReadBlocks[(int) lun] +=
+					    mbox->numsectors;
+				} else {
+					megaCfg->nWrites[(int) lun]++;
+					megaCfg->nWriteBlocks[(int) lun] +=
+					    mbox->numsectors;
+				}
+			}
+
 #if LINUX_VERSION_CODE >= KERNEL_VERSION(2,4,0)
-			if (*SCpnt->cmnd == READ_6 || *SCpnt->cmnd == READ_10) {
+			if (*SCpnt->cmnd == READ_6 || *SCpnt->cmnd == READ_10
+					|| *SCpnt->cmnd == READ_12) {
 				pScb->dma_direction = PCI_DMA_FROMDEVICE;
 			} else {	/*WRITE_6 or WRITE_10 */
 				pScb->dma_direction = PCI_DMA_TODEVICE;
@@ -1242,9 +1421,7 @@
 
 			/* Calculate Scatter-Gather info */
 			mbox->numsgelements = mega_build_sglist (megaCfg, pScb,
-								 (u32 *) &
-								 mbox->xferaddr,
-								 (u32 *) & seg);
+								 (u32 *)&mbox->xferaddr, (u32 *)&seg);
 
 #if LINUX_VERSION_CODE >= KERNEL_VERSION(2,4,0)
 			pScb->iDataSize = seg;
@@ -1277,80 +1454,157 @@
 			callDone (SCpnt);
 			return NULL;
 		}
-#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,4,0)
-		pthru = pScb->pthru;
-#else
-		pthru = &pScb->pthru;
-#endif
-		mbox = (mega_mailbox *) pScb->mboxData;
 
+		mbox = (mega_mailbox *) pScb->mboxData;
 		memset (mbox, 0, sizeof (pScb->mboxData));
-		memset (pthru, 0, sizeof (mega_passthru));
 
-		/* set adapter timeout value to 10 min. for tape drive	*/
-		/* 0=6sec/1=60sec/2=10min/3=3hrs 			*/
-		pthru->timeout = 2;
-		pthru->ars = 1;
-		pthru->reqsenselen = 14;
-		pthru->islogical = 0;
-		pthru->channel =
-		    (megaCfg->flag & BOARD_40LD) ? 0 : SCpnt->channel;
-		pthru->target = (megaCfg->flag & BOARD_40LD) ?	/*BOARD_40LD */
-		    (SCpnt->channel << 4) | SCpnt->target : SCpnt->target;
-		pthru->cdblen = SCpnt->cmd_len;
+		if ( megaCfg->support_ext_cdb && SCpnt->cmd_len > 10 ) {
+			epthru = mega_prepare_extpassthru(megaCfg, pScb, SCpnt);
+			mbox->cmd = MEGA_MBOXCMD_EXTPASSTHRU;
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,4,0)
+			mbox->xferaddr = pScb->dma_ext_passthruhandle64;
 
-		memcpy (pthru->cdb, SCpnt->cmnd, SCpnt->cmd_len);
+			if(epthru->numsgelements) {
+				pScb->dma_type = M_RD_PTHRU_WITH_SGLIST;
+			} else {
+				pScb->dma_type = M_RD_EPTHRU_WITH_BULK_DATA;
+			}
+#else
+			mbox->xferaddr = virt_to_bus(epthru);
+#endif
+		}
+		else {
+			pthru = mega_prepare_passthru(megaCfg, pScb, SCpnt);
 
+			/* Initialize mailbox */
+			mbox->cmd = MEGA_MBOXCMD_PASSTHRU;
 #if LINUX_VERSION_CODE >= KERNEL_VERSION(2,4,0)
-		/* Not sure about the direction */
-		pScb->dma_direction = PCI_DMA_BIDIRECTIONAL;
+			mbox->xferaddr = pScb->dma_passthruhandle64;
 
-		/* Special Code for Handling READ_CAPA/ INQ using bounce buffers */
-		switch (SCpnt->cmnd[0]) {
-		case INQUIRY:
-		case READ_CAPACITY:
-			pthru->numsgelements = 0;
-			pthru->dataxferaddr = pScb->dma_bounce_buffer;
-			pthru->dataxferlen = SCpnt->request_bufflen;
-			break;
-		default:
-			pthru->numsgelements = mega_build_sglist (megaCfg, pScb,
-								  (u32 *) &
-								  pthru->
-								  dataxferaddr,
-								  (u32 *) &
-								  pthru->
-								  dataxferlen);
-			break;
+			if (pthru->numsgelements) {
+				pScb->dma_type = M_RD_PTHRU_WITH_SGLIST;
+			} else {
+				pScb->dma_type = M_RD_PTHRU_WITH_BULK_DATA;
+			}
+#else
+			mbox->xferaddr = virt_to_bus(pthru);
+#endif
 		}
+		return pScb;
+	}
+	return NULL;
+}
+
+static mega_passthru *
+mega_prepare_passthru(mega_host_config *megacfg, mega_scb *scb, Scsi_Cmnd *sc)
+{
+	mega_passthru *pthru;
+
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,4,0)
+	pthru = scb->pthru;
 #else
-		pthru->numsgelements = mega_build_sglist (megaCfg, pScb,
-							  (u32 *) & pthru->
-							  dataxferaddr,
-							  (u32 *) & pthru->
-							  dataxferlen);
+	pthru = &scb->pthru;
 #endif
+	memset (pthru, 0, sizeof (mega_passthru));
 
-		/* Initialize mailbox */
-		mbox->cmd = MEGA_MBOXCMD_PASSTHRU;
+	/* set adapter timeout value to 10 min. for tape drive	*/
+	/* 0=6sec/1=60sec/2=10min/3=3hrs 			*/
+	pthru->timeout = 2;
+	pthru->ars = 1;
+	pthru->reqsenselen = 14;
+	pthru->islogical = 0;
+	pthru->channel = (megacfg->flag & BOARD_40LD) ? 0 : sc->channel;
+	pthru->target = (megacfg->flag & BOARD_40LD) ?
+	    (sc->channel << 4) | sc->target : sc->target;
+	pthru->cdblen = sc->cmd_len;
+	pthru->logdrv = sc->lun;
+
+	memcpy (pthru->cdb, sc->cmnd, sc->cmd_len);
 
 #if LINUX_VERSION_CODE >= KERNEL_VERSION(2,4,0)
-		mbox->xferaddr = pScb->dma_passthruhandle64;
+	/* Not sure about the direction */
+	scb->dma_direction = PCI_DMA_BIDIRECTIONAL;
 
-		if (pthru->numsgelements) {
-			pScb->dma_type = M_RD_PTHRU_WITH_SGLIST;
-			TRACE1 (("M_RD_PTHRU_WITH_SGLIST Enabled \n"));
-		} else {
-			pScb->dma_type = M_RD_PTHRU_WITH_BULK_DATA
-			    TRACE1 (("M_RD_PTHRU_WITH_BULK_DATA Enabled \n"));
-		}
+	/* Special Code for Handling READ_CAPA/ INQ using bounce buffers */
+	switch (sc->cmnd[0]) {
+	case INQUIRY:
+	case READ_CAPACITY:
+		pthru->numsgelements = 0;
+		pthru->dataxferaddr = scb->dma_bounce_buffer;
+		pthru->dataxferlen = sc->request_bufflen;
+		break;
+	default:
+		pthru->numsgelements =
+			mega_build_sglist(
+				megacfg, scb, (u32 *)&pthru->dataxferaddr,
+				(u32 *)&pthru->dataxferlen
+			);
+		break;
+	}
 #else
-		mbox->xferaddr = virt_to_bus (pthru);
+	pthru->numsgelements =
+		mega_build_sglist(
+			megacfg, scb, (u32 *)&pthru->dataxferaddr,
+			(u32 *)&pthru->dataxferlen
+		);
 #endif
+	return pthru;
+}
 
-		return pScb;
+static mega_ext_passthru *
+mega_prepare_extpassthru(mega_host_config *megacfg, mega_scb *scb, Scsi_Cmnd *sc)
+{
+	mega_ext_passthru *epthru;
+
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,4,0)
+	epthru = scb->epthru;
+#else
+	epthru = &scb->epthru;
+#endif
+	memset(epthru, 0, sizeof(mega_ext_passthru));
+
+	/* set adapter timeout value to 10 min. for tape drive	*/
+	/* 0=6sec/1=60sec/2=10min/3=3hrs 			*/
+	epthru->timeout = 2;
+	epthru->ars = 1;
+	epthru->reqsenselen = 14;
+	epthru->islogical = 0;
+	epthru->channel = (megacfg->flag & BOARD_40LD) ? 0 : sc->channel;
+	epthru->target = (megacfg->flag & BOARD_40LD) ?
+	    (sc->channel << 4) | sc->target : sc->target;
+	epthru->cdblen = sc->cmd_len;
+	epthru->logdrv = sc->lun;
+
+	memcpy(epthru->cdb, sc->cmnd, sc->cmd_len);
+
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,4,0)
+	/* Not sure about the direction */
+	scb->dma_direction = PCI_DMA_BIDIRECTIONAL;
+
+	/* Special Code for Handling READ_CAPA/ INQ using bounce buffers */
+	switch (sc->cmnd[0]) {
+	case INQUIRY:
+	case READ_CAPACITY:
+		epthru->numsgelements = 0;
+		epthru->dataxferaddr = scb->dma_bounce_buffer;
+		epthru->dataxferlen = sc->request_bufflen;
+		break;
+	default:
+		epthru->numsgelements =
+			mega_build_sglist(
+				megacfg, scb, (u32 *)&epthru->dataxferaddr,
+				(u32 *)&epthru->dataxferlen
+			);
+		break;
 	}
-	return NULL;
+#else
+	epthru->numsgelements =
+		mega_build_sglist(
+			megacfg, scb, (u32 *)&epthru->dataxferaddr,
+			(u32 *)&epthru->dataxferlen
+		);
+#endif
+	return epthru;
 }
 
 /* Handle Driver Level IOCTLs
@@ -1906,7 +2160,7 @@
  *   int intr         - if 1, interrupt, 0 is blocking
  * Return Value: (added on 7/26 for 40ld/64bit)
  *   -1: the command was not actually issued out
- *   othercases:
+ *   other cases:
  *     intr==0, return ScsiStatus, i.e. mbox->status
  *     intr==1, return 0
  *=====================================================
@@ -2082,7 +2336,7 @@
 				      scb->SCpnt->request_bufflen,
 				      scb->dma_direction);
 		/* We need to handle special commands like READ64, WRITE64
-		   as they need a minimum of 1 SG irrespective of actaully SG
+		   as they need a minimum of 1 SG irrespective of actually SG
 		 */
 		if ((megaCfg->flag & BOARD_64BIT) &&
 		    ((mbox->cmd == MEGA_MBOXCMD_LREAD64) ||
@@ -2183,7 +2437,7 @@
 }
 
 /*--------------------------------------------------------------------
- * Initializes the adress of the controller's mailbox register
+ * Initializes the address of the controller's mailbox register
  *  The mailbox register is used to issue commands to the card.
  *  Format of the mailbox area:
  *   00 01 command
@@ -2201,7 +2455,7 @@
 static int
 mega_register_mailbox (mega_host_config * megaCfg, u32 paddr)
 {
-	/* align on 16-byte boundry */
+	/* align on 16-byte boundary */
 #if LINUX_VERSION_CODE >= KERNEL_VERSION(2,4,0)
 	megaCfg->mbox = &megaCfg->mailbox64ptr->mailbox;
 #else
@@ -2303,7 +2557,7 @@
 
 /*
  * Try to issue Enquiry3 command
- * if not suceeded, then issue MEGA_MBOXCMD_ADAPTERINQ command and
+ * if not succeeded, then issue MEGA_MBOXCMD_ADAPTERINQ command and
  * update enquiry3 structure
  */
 #if LINUX_VERSION_CODE >= KERNEL_VERSION(2,4,0)
@@ -2428,9 +2682,15 @@
 	memcpy (megaCfg->biosVer, (char *) megaCfg->productInfo.BiosVer, 4);
 	megaCfg->biosVer[4] = 0;
 #endif
+	megaCfg->support_ext_cdb = mega_support_ext_cdb(megaCfg);
 
 	printk (KERN_NOTICE "megaraid: [%s:%s] detected %d logical drives" M_RD_CRLFSTR,
 		megaCfg->fwVer, megaCfg->biosVer, megaCfg->numldrv);
+
+	if ( megaCfg->support_ext_cdb ) {
+		printk(KERN_NOTICE "megaraid: supports extended CDBs.\n");
+	}
+
 	/*
 	 * I hope that I can unmap here, reason DMA transaction is not required any more
 	 * after this
@@ -2506,16 +2766,11 @@
 				continue;	/* not an AMI board */
 			}
 #if LINUX_VERSION_CODE >= KERNEL_VERSION(2,4,0)
-#if 0
-/*
- *	This leads to corruption on some HP boards so disable it
- */
 			pcibios_read_config_dword (pciBus, pciDevFun,
 						   PCI_CONF_AMISIG64, &magic64);
 
 			if (magic64 == AMI_64BIT_SIGNATURE)
 				flag |= BOARD_64BIT;
-#endif				
 #endif
 		}
 
@@ -2537,17 +2792,14 @@
 			pci_read_config_word (pdev,
 					      PCI_SUBSYSTEM_ID, &subsysid);
 #endif
-			if ((subsysid == 0x1111) && (subsysvid == 0x1111)) {
-				printk (KERN_WARNING
-					"megaraid: Your card is a Dell PERC 2/SC RAID controller with firmware\n"
-					"megaraid: 3.00 or 3.01.  This driver is known to have corruption issues\n"
-					"megaraid: with those firmware versions on this specific card.  In order\n"
-					"megaraid: to protect your data, please upgrade your firmware to version\n"
-					"megaraid: 3.10 or later, available from the Dell Technical Support web\n"
-					"megaraid: site at\n"
-					"http://support.dell.com/us/en/filelib/download/index.asp?fileid=2940\n");
-				continue;
-			}
+
+#if 0
+			/*
+			 * This routine is called with well know values and we
+			 * should not be getting what we have not asked.
+			 * Also, the check is not right. It should have been for
+			 * pci_vendor_id not subsysvid - AM
+			 */
 
 			/* If we dont detect this valid subsystem vendor id's 
 			   we refuse to load the driver 
@@ -2558,6 +2810,7 @@
 			    && (subsysvid != DELL_SUBSYS_ID)
 			    && (subsysvid != HP_SUBSYS_ID))
 				continue;
+#endif
 		}
 
 		printk (KERN_NOTICE
@@ -2597,6 +2850,14 @@
 		if (!host)
 			goto err_unmap;
 
+		/*
+		 * Comment the following initialization if you know 'max_sectors' is
+		 * not defined for this kernel.
+		 * This field was introduced in Linus's kernel 2.4.7pre3 and it
+		 * greatly increases the IO performance - AM
+		 */
+		host->max_sectors = 1024;
+
 		scsi_set_pci_device(host, pdev);
 		megaCfg = (mega_host_config *) host->hostdata;
 		memset (megaCfg, 0, sizeof (mega_host_config));
@@ -2667,7 +2928,6 @@
 				       virt_to_bus ((void *) megaCfg->
 						    mailbox64ptr));
 #else
-		/*Taken care */
 		mega_register_mailbox (megaCfg,
 				       virt_to_bus ((void *) &megaCfg->
 						    mailbox64));
@@ -2675,9 +2935,74 @@
 
 		mega_i_query_adapter (megaCfg);
 
+		if ((subsysid == 0x1111) && (subsysvid == 0x1111)) {
+
+			/*
+			 * Which firmware
+			 */
+			if( strcmp(megaCfg->fwVer, "3.00") == 0 ||
+					strcmp(megaCfg->fwVer, "3.01") == 0 ) {
+
+				printk( KERN_WARNING
+					"megaraid: Your  card is a Dell PERC 2/SC RAID controller "
+					"with  firmware\nmegaraid: 3.00 or 3.01.  This driver is "
+					"known to have corruption issues\nmegaraid: with those "
+					"firmware versions on this specific card.  In order\n"
+					"megaraid: to protect your data, please upgrade your "
+					"firmware to version\nmegaraid: 3.10 or later, available "
+					"from the Dell Technical Support web\nmegaraid: site at\n"
+					"http://support.dell.com/us/en/filelib/download/"
+					"index.asp?fileid=2940\n"
+				);
+			}
+		}
+
+#ifdef MEGA_HP_FIX
+		/*
+		 * If we have a HP 1M(0x60E7)/2M(0x60E8) controller with
+		 * firmware H.01.07 or H.01.08, disable 64 bit support,
+		 * since this firmware cannot handle 64 bit addressing
+		 */
+
+		if( (subsysvid == HP_SUBSYS_ID) &&
+				((subsysid == 0x60E7)||(subsysid == 0x60E8)) ) {
+
+			/*
+			 * which firmware
+			 */
+			if( strcmp(megaCfg->fwVer, "H01.07") == 0 ||
+					strcmp(megaCfg->fwVer, "H01.08") == 0 ) {
+				printk(KERN_WARNING
+						"megaraid: Firmware H.01.07 or H.01.08 on 1M/2M "
+						"controllers\nmegaraid: do not support 64 bit "
+						"addressing.\n"
+						"megaraid: DISABLING 64 bit support.\n");
+				megaCfg->flag &= ~BOARD_64BIT;
+			}
+		}
+#endif
+
 		if (mega_is_bios_enabled (megaCfg)) {
 			mega_hbas[numCtlrs].is_bios_enabled = 1;
 		}
+
+		/*
+		 * Find out which channel is raid and which is scsi
+		 */
+		mega_enum_raid_scsi(megaCfg);
+		for( i = 0; i < megaCfg->host->max_channel; i++ ) {
+			if(IS_RAID_CH(i))
+				printk(KERN_NOTICE"megaraid: channel[%d] is raid.\n", i+1);
+			else
+				printk(KERN_NOTICE"megaraid: channel[%d] is scsi.\n", i+1);
+		}
+
+		/*
+		 * Find out if a logical drive is set as the boot drive. If there is
+		 * one, will make that as the first logical drive.
+		 */
+		mega_get_boot_ldrv(megaCfg);
+
 		mega_hbas[numCtlrs].hostdata_addr = megaCfg;
 
 		/* Initialize SCBs */
@@ -2800,7 +3125,7 @@
 #endif
 
 	/*
-	 * Register the driver as a character device, for appliactions to access
+	 * Register the driver as a character device, for applications to access
 	 * it for ioctls.
 	 * Ideally, this should go in the init_module() routine, but since it is
 	 * hidden in the file "scsi_module.c" ( included in the end ), we define
@@ -2816,6 +3141,7 @@
 	if (register_reboot_notifier (&mega_notifier)) {
 		printk ("MegaRAID Shutdown routine not registered!!\n");
 	}
+
 	init_MUTEX (&mimd_entry_mtx);
 
 	return count;
@@ -2910,7 +3236,7 @@
 		0, sizeof (megacfg->mega_buffer));
 
 	/*
-	 * issue command to find out if the BIOS is enbled for this controller
+	 * issue command to find out if the BIOS is enabled for this controller
 	 */
 	mbox[0] = IS_BIOS_ENABLED;
 	mbox[2] = GET_BIOS;
@@ -2922,6 +3248,123 @@
 	return (*(char *) megacfg->mega_buffer);
 }
 
+/*
+ * Find out what channels are RAID/SCSI
+ */
+void
+mega_enum_raid_scsi(mega_host_config *megacfg)
+{
+	mega_mailbox *mboxp;
+	unsigned char mbox[16];
+
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,4,0)
+	dma_addr_t	dma_handle;
+#endif
+
+	mboxp = (mega_mailbox *)mbox;
+
+	memset(mbox, 0, sizeof(mbox));
+	/*
+	 * issue command to find out what channels are raid/scsi
+	 */
+	mbox[0] = CHNL_CLASS;
+	mbox[2] = GET_CHNL_CLASS;
+
+	memset((void *)megacfg->mega_buffer, 0, sizeof(megacfg->mega_buffer));
+
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,4,0)
+	dma_handle = pci_map_single(megacfg->dev, (void *)megacfg->mega_buffer,
+			      (2 * 1024L), PCI_DMA_FROMDEVICE);
+
+	mboxp->xferaddr = dma_handle;
+#else
+	mboxp->xferaddr = virt_to_bus((void *)megacfg->mega_buffer);
+#endif
+
+	/*
+	 * Non-ROMB firware fail this command, so all channels
+	 * must be shown RAID
+	 */
+	if( megaIssueCmd(megacfg, mbox, NULL, 0) == 0 ) {
+		mega_ch_class = *((char *)megacfg->mega_buffer);
+
+		/* logical drives channel is RAID */
+		mega_ch_class |= (0x01 << megacfg->host->max_channel);
+	}
+	else {
+		mega_ch_class = 0xFF;
+	}
+
+
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,4,0)
+	pci_unmap_single(megacfg->dev, dma_handle,
+				  (2 * 1024L), PCI_DMA_FROMDEVICE);
+#endif
+
+}
+
+
+/*
+ * get the boot logical drive number if enabled
+ */
+void
+mega_get_boot_ldrv(mega_host_config *megacfg)
+{
+	mega_mailbox *mboxp;
+	unsigned char mbox[16];
+	struct private_bios_data *prv_bios_data;
+	u16		cksum = 0;
+	char	*cksum_p;
+	int		i;
+
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,4,0)
+	dma_addr_t	dma_handle;
+#endif
+
+	mboxp = (mega_mailbox *)mbox;
+
+	memset(mbox, 0, sizeof(mbox));
+
+	mbox[0] = BIOS_PVT_DATA;
+	mbox[2] = GET_BIOS_PVT_DATA;
+
+	memset((void *)megacfg->mega_buffer, 0, sizeof(megacfg->mega_buffer));
+
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,4,0)
+	dma_handle = pci_map_single(megacfg->dev, (void *)megacfg->mega_buffer,
+			      (2 * 1024L), PCI_DMA_FROMDEVICE);
+
+	mboxp->xferaddr = dma_handle;
+#else
+	mboxp->xferaddr = virt_to_bus((void *)megacfg->mega_buffer);
+#endif
+
+	megacfg->boot_ldrv_enabled = 0;
+	megacfg->boot_ldrv = 0;
+	if( megaIssueCmd(megacfg, mbox, NULL, 0) == 0 ) {
+
+		prv_bios_data = (struct private_bios_data *)megacfg->mega_buffer;
+
+		cksum = 0;
+		cksum_p = (char *)prv_bios_data;
+		for( i = 0; i < 14; i++ ) {
+			cksum += (u16)(*cksum_p++);
+		}
+
+		if( prv_bios_data->cksum == (u16)(0-cksum) ) {
+			megacfg->boot_ldrv_enabled = 1;
+			megacfg->boot_ldrv = prv_bios_data->boot_ldrv;
+		}
+	}
+
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,4,0)
+	pci_unmap_single(megacfg->dev, dma_handle,
+				  (2 * 1024L), PCI_DMA_FROMDEVICE);
+#endif
+
+}
+
+
 static void mega_reorder_hosts (void)
 {
 	struct Scsi_Host *shpnt;
@@ -3492,36 +3935,19 @@
 	*start = page;
 
 	proc_printf (megaCfg, "Statistical Information for this controller\n");
-#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,4,0)	/* 0x020400 */
-	proc_printf (megaCfg, "Interrupts Collected = %Lu\n",
+	proc_printf (megaCfg, "Interrupts Collected = %lu\n",
 		     megaCfg->nInterrupts);
-#else
-	proc_printf (megaCfg, "Interrupts Collected = %u\n",
-		     (u32) megaCfg->nInterrupts);
-#endif
 
 	for (i = 0; i < megaCfg->numldrv; i++) {
 		proc_printf (megaCfg, "Logical Drive %d:\n", i);
 
-#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,4,0)
 		proc_printf (megaCfg,
-			     "\tReads Issued = %Lu, Writes Issued = %Lu\n",
+			     "\tReads Issued = %lu, Writes Issued = %lu\n",
 			     megaCfg->nReads[i], megaCfg->nWrites[i]);
 
 		proc_printf (megaCfg,
-			     "\tSectors Read = %Lu, Sectors Written = %Lu\n\n",
+			     "\tSectors Read = %lu, Sectors Written = %lu\n\n",
 			     megaCfg->nReadBlocks[i], megaCfg->nWriteBlocks[i]);
-#else
-		proc_printf (megaCfg,
-			     "\tReads Issued = %10u, Writes Issued = %10u\n",
-			     (u32) megaCfg->nReads[i],
-			     (u32) megaCfg->nWrites[i]);
-
-		proc_printf (megaCfg,
-			     "\tSectors Read = %10u, Sectors Written = %10u\n\n",
-			     (u32) megaCfg->nReadBlocks[i],
-			     (u32) megaCfg->nWriteBlocks[i]);
-#endif
 
 	}
 
@@ -3670,27 +4096,121 @@
 	/* Get pointer to host config structure */
 	megaCfg = (mega_host_config *) disk->device->host->hostdata;
 
-	/* Default heads (64) & sectors (32) */
-	heads = 64;
-	sectors = 32;
-	cylinders = disk->capacity / (heads * sectors);
-
-	/* Handle extended translation size for logical drives > 1Gb */
-	if (disk->capacity >= 0x200000) {
-		heads = 255;
-		sectors = 63;
-		cylinders = disk->capacity / (heads * sectors);
+	if( IS_RAID_CH(disk->device->channel)) {
+			/* Default heads (64) & sectors (32) */
+			heads = 64;
+			sectors = 32;
+			cylinders = disk->capacity / (heads * sectors);
+
+			/* Handle extended translation size for logical drives > 1Gb */
+			if (disk->capacity >= 0x200000) {
+				heads = 255;
+				sectors = 63;
+				cylinders = disk->capacity / (heads * sectors);
+			}
+
+			/* return result */
+			geom[0] = heads;
+			geom[1] = sectors;
+			geom[2] = cylinders;
 	}
+	else {
+		if( mega_partsize(disk, dev, geom) == 0 ) return 0;
+
+		printk(KERN_WARNING
+				"megaraid: invalid partition on this disk on channel %d\n",
+				disk->device->channel);
+
+		/* Default heads (64) & sectors (32) */
+		heads = 64;
+		sectors = 32;
+		cylinders = disk->capacity / (heads * sectors);
+
+		/* Handle extended translation size for logical drives > 1Gb */
+		if (disk->capacity >= 0x200000) {
+			heads = 255;
+			sectors = 63;
+			cylinders = disk->capacity / (heads * sectors);
+		}
 
-	/* return result */
-	geom[0] = heads;
-	geom[1] = sectors;
-	geom[2] = cylinders;
+		/* return result */
+		geom[0] = heads;
+		geom[1] = sectors;
+		geom[2] = cylinders;
+	}
 
 	return 0;
 }
 
 /*
+ * Function : static int mega_partsize(Disk * disk, kdev_t dev, int *geom)
+ *
+ * Purpose : to determine the BIOS mapping used to create the partition
+ *			table, storing the results (cyls, hds, and secs) in geom
+ *
+ * Note:	Code is picked from scsicam.h
+ *
+ * Returns : -1 on failure, 0 on success.
+ */
+static int
+mega_partsize(Disk * disk, kdev_t dev, int *geom)
+{
+	struct buffer_head *bh;
+	struct partition *p, *largest = NULL;
+	int i, largest_cyl;
+	int heads, cyls, sectors;
+	int capacity = disk->capacity;
+
+	int ma = MAJOR(dev);
+	int mi = (MINOR(dev) & ~0xf);
+
+	int block = 1024; 
+
+	if(blksize_size[ma])
+		block = blksize_size[ma][mi];
+		
+	if(!(bh = bread(MKDEV(ma,mi), 0, block)))
+		return -1;
+
+	if( *(unsigned short *)(bh->b_data + 510) == 0xAA55 ) {
+		for( largest_cyl = -1, p = (struct partition *)(0x1BE + bh->b_data),
+				i = 0; i < 4; ++i, ++p) {
+
+			if (!p->sys_ind) continue;
+
+			cyls = p->end_cyl + ((p->end_sector & 0xc0) << 2);
+
+			if(cyls >= largest_cyl) {
+				largest_cyl = cyls;
+				largest = p;
+			}
+		}
+	}
+	if (largest) {
+		heads = largest->end_head + 1;
+		sectors = largest->end_sector & 0x3f;
+
+		if (heads == 0 || sectors == 0) {
+			brelse(bh);
+			return -1;
+		}
+
+		cyls = capacity/(heads * sectors);
+
+		geom[0] = heads;
+		geom[1] = sectors;
+		geom[2] = cyls;
+
+		brelse(bh);
+		return 0;
+	}
+
+	brelse(bh);
+	return -1;
+}
+
+
+/*
  * This routine will be called when the use has done a forced shutdown on the
  * system. Flush the Adapter cache, that's the most we can do.
  */
@@ -3779,6 +4299,17 @@
 			printk (KERN_WARNING
 				"Can't allocate passthru for id %d\n", idx);
 		}
+
+		megacfg->scbList[idx].epthru =
+			pci_alloc_consistent(
+				megacfg->dev, sizeof(mega_ext_passthru),
+				&(megacfg->scbList[idx].dma_ext_passthruhandle64)
+			);
+
+		if (megacfg->scbList[idx].epthru == NULL) {
+			printk (KERN_WARNING
+				"Can't allocate extended passthru for id %d\n", idx);
+		}
 		/* 
 		 * Allocate a 256 Byte Bounce Buffer for handling INQ/RD_CAPA 
 		 */
@@ -3888,7 +4419,7 @@
 	struct uioctl_t *uioc;
 	dma_addr_t	dma_addr;
 	u32		length;
-	mega_host_config *megacfg;
+	mega_host_config *megacfg = NULL;
 #if LINUX_VERSION_CODE >= KERNEL_VERSION(2,4,0)	/* 0x020400 */
 	struct pci_dev pdev;
 	struct pci_dev *pdevp = &pdev;
@@ -4355,6 +4886,28 @@
 }
 
 
+static int
+mega_support_ext_cdb(mega_host_config *this_hba)
+{
+	mega_mailbox *mboxpnt;
+	unsigned char mbox[16];
+	int ret;
+
+	mboxpnt = (mega_mailbox *) mbox;
+
+	memset(mbox, 0, sizeof (mbox));
+	/*
+	 * issue command to find out if controller supports extended CDBs.
+	 */
+	mbox[0] = 0xA4;
+	mbox[2] = 0x16;
+
+	ret = megaIssueCmd(this_hba, mbox, NULL, 0);
+
+	return !ret;
+}
+
+
 #if LINUX_VERSION_CODE < KERNEL_VERSION(2,4,0)
 void *
 dma_alloc_consistent(void *dev, size_t size, dma_addr_t *dma_addr)
@@ -4450,3 +5003,5 @@
 
 #include "scsi_module.c"
 #endif				/* LINUX VERSION 2.4.XX || MODULE */
+
+/* vi: set ts=4: */
diff -u --recursive --new-file v2.4.7/linux/drivers/scsi/megaraid.h linux/drivers/scsi/megaraid.h
--- v2.4.7/linux/drivers/scsi/megaraid.h	Wed Jul 25 17:10:23 2001
+++ linux/drivers/scsi/megaraid.h	Wed Jul 25 14:12:02 2001
@@ -10,7 +10,7 @@
 #define IN_RESET		0x20000000L
 #define IN_QUEUE		0x10000000L
 
-#define BOARD_QUARTZ		0x08000000L
+#define BOARD_QUARTZ	0x08000000L
 #define BOARD_40LD	   	0x04000000L
 #define BOARD_64BIT		0x02000000L
 
@@ -27,7 +27,7 @@
 #define M_RD_IOCTL_CMD_NEW		0x81
 #define M_RD_DRIVER_IOCTL_INTERFACE	0x82
 
-#define MEGARAID_VERSION "v1.15d (Release Date: Wed May 30 17:30:41 EDT 2001)"
+#define MEGARAID_VERSION "v1.17a (Release Date: Fri Jul 13 18:44:01 EDT 2001)"
 
 #define MEGARAID_IOCTL_VERSION 	114
 
@@ -64,12 +64,14 @@
 #define FROMTO_DEVICE		0x2
 
 /* Mailbox commands */
-#define MEGA_MBOXCMD_LREAD      0x01
-#define MEGA_MBOXCMD_LWRITE     0x02
-#define MEGA_MBOXCMD_LREAD64    0xA7
-#define MEGA_MBOXCMD_LWRITE64   0xA8
-#define MEGA_MBOXCMD_PASSTHRU   0x03
-#define MEGA_MBOXCMD_ADAPTERINQ 0x05
+#define MEGA_MBOXCMD_LREAD		0x01
+#define MEGA_MBOXCMD_LWRITE		0x02
+#define MEGA_MBOXCMD_LREAD64		0xA7
+#define MEGA_MBOXCMD_LWRITE64		0xA8
+#define MEGA_MBOXCMD_PASSTHRU		0x03
+#define MEGA_MBOXCMD_EXTPASSTHRU	0xE3
+#define MEGA_MBOXCMD_ADAPTERINQ		0x05
+
 
 /* Offsets into Mailbox */
 #define COMMAND_PORT       	0x00
@@ -472,6 +474,7 @@
 #define M_RD_PTHRU_WITH_SGLIST	  	0x0002
 #define M_RD_BULK_DATA_ONLY	     	0x0004
 #define M_RD_SGLIST_ONLY		0x0008
+#define M_RD_EPTHRU_WITH_BULK_DATA   	0x0010
 #endif
 /********************************************
  * ENQUIRY3
@@ -564,6 +567,38 @@
 	u32 dataxferlen;
 } mega_passthru;
 
+/*
+ * Extended passthru: support CDB > 10 bytes
+ */
+typedef struct {
+	u8 timeout:3;		/* 0=6sec/1=60sec/2=10min/3=3hrs */
+	u8 ars:1;
+	u8 rsvd1:1;
+	u8 cd_rom:1;
+	u8 rsvd2:1;
+	u8 islogical:1;
+
+	u8 logdrv;		/* if islogical == 1 */
+	u8 channel;		/* if islogical == 0 */
+	u8 target;		/* if islogical == 0 */
+
+	u8 queuetag;		/* unused */
+	u8 queueaction;		/* unused */
+
+	u8 cdblen;
+	u8 rsvd3;
+	u8 cdb[16];
+
+	u8 numsgelements;
+	u8 status;
+	u8 reqsenselen;
+	u8 reqsensearea[MAX_REQ_SENSE_LEN];
+	u8 rsvd4;
+
+	u32 dataxferaddr;
+	u32 dataxferlen;
+}mega_ext_passthru;
+
 struct _mega_mailbox {
 	/* 0x0 */ u8 cmd;
 	/* 0x1 */ u8 cmdid;
@@ -635,14 +670,17 @@
 	u8 sglist_count;
 	dma_addr_t dma_sghandle64;
 	dma_addr_t dma_passthruhandle64;
+	dma_addr_t dma_ext_passthruhandle64;
 	dma_addr_t dma_bounce_buffer;
 	u8 *bounce_buffer;
 #endif
 
 #if LINUX_VERSION_CODE >= KERNEL_VERSION(2,4,0)
 	mega_passthru *pthru;
+	mega_ext_passthru *epthru;
 #else
 	mega_passthru pthru;
+	mega_ext_passthru epthru;
 #endif
 
 	Scsi_Cmnd *SCpnt;
@@ -726,6 +764,9 @@
 	int procidx;
 	struct proc_dir_entry *controller_proc_dir_entry;
 	struct proc_dir_entry *proc_read, *proc_stat, *proc_status, *proc_mbox;
+	int		support_ext_cdb;
+	int		boot_ldrv_enabled;
+	int		boot_ldrv;
 } mega_host_config;
 
 typedef struct _driver_info {
@@ -840,6 +881,36 @@
 
 #define		IS_BIOS_ENABLED		0x62
 #define		GET_BIOS		0x01
+#define		CHNL_CLASS		0xA9
+#define		GET_CHNL_CLASS	0x00
+#define		SET_CHNL_CLASS	0x01
+#define		CH_RAID			0x01
+#define		CH_SCSI			0x00
+
+
+#define BIOS_PVT_DATA		0x40
+#define GET_BIOS_PVT_DATA	0x00
+
+#pragma pack(1)
+struct private_bios_data {
+	u8		geometry:4;		/*
+							 * bits 0-3 - BIOS geometry
+							 * 0x0001 - 1GB
+							 * 0x0010 - 2GB
+							 * 0x1000 - 8GB
+							 * Others values are invalid
+							 */
+	u8		unused:4;		/* bits 4-7 are unused */
+	u8		boot_ldrv;		/*
+							 * logical drive set as boot drive
+							 * 0..7 - for 8LD cards
+							 * 0..39 - for 40LD cards
+							 */
+	u8		rsvd[12];
+	u16		cksum;			/* 0-(sum of first 13 bytes of this structure) */
+};
+#pragma pack()
+
 
 /*================================================================
  *
@@ -896,5 +967,15 @@
 static void mega_swap_hosts (struct Scsi_Host *, struct Scsi_Host *);
 
 static void mega_create_proc_entry (int index, struct proc_dir_entry *);
+static int mega_support_ext_cdb(mega_host_config *);
+static mega_passthru* mega_prepare_passthru(mega_host_config *, mega_scb *,
+		Scsi_Cmnd *);
+static mega_ext_passthru* mega_prepare_extpassthru(mega_host_config *,
+		mega_scb *, Scsi_Cmnd *);
+static void mega_enum_raid_scsi(mega_host_config *);
+static int mega_partsize(Disk *, kdev_t, int *);
+static void mega_get_boot_ldrv(mega_host_config *);
 
 #endif
+
+/* vi: set ts=4: */
diff -u --recursive --new-file v2.4.7/linux/drivers/scsi/pcmcia/nsp_cs.c linux/drivers/scsi/pcmcia/nsp_cs.c
--- v2.4.7/linux/drivers/scsi/pcmcia/nsp_cs.c	Wed Jul 25 17:10:23 2001
+++ linux/drivers/scsi/pcmcia/nsp_cs.c	Sun Aug  5 13:12:41 2001
@@ -9,7 +9,7 @@
     Ver.0.1   Initial version
 
     This software may be used and distributed according to the terms of
-    the GNU General Public License.
+    the GNU Public License.
 
 ======================================================================*/
 
@@ -23,7 +23,7 @@
 
 ***********************************************************************/
 
-/* $Id: nsp_cs.c,v 1.28 2001/02/15 02:56:32 elca Exp $ */
+/* $Id: nsp_cs.c,v 1.35 2001/07/05 16:58:24 elca Exp $ */
 
 #ifdef NSP_KERNEL_2_2
 #include <pcmcia/config.h>
@@ -41,6 +41,7 @@
 #include <linux/delay.h>
 #include <linux/tqueue.h>
 #include <linux/interrupt.h>
+#include <linux/module.h>
 #include <linux/major.h>
 #include <linux/blk.h>
 #include <linux/stat.h>
@@ -71,7 +72,7 @@
 static int pc_debug = PCMCIA_DEBUG;
 MODULE_PARM(pc_debug, "i");
 MODULE_PARM_DESC(pc_debug, "set debug level");
-static char *version = "$Id: nsp_cs.c,v 1.28 2001/02/15 02:56:32 elca Exp $";
+static char *version = "$Id: nsp_cs.c,v 1.35 2001/07/05 16:58:24 elca Exp $";
 #define DEBUG(n, args...) if (pc_debug>(n)) printk(KERN_DEBUG args)
 #else
 #define DEBUG(n, args...) /* */
@@ -90,13 +91,14 @@
 	struct bus_operations *bus;
 } scsi_info_t;
 
-static void nsp_release(u_long arg);
-static int nsp_event(event_t event, int priority,
+static void nsp_cs_release(u_long arg);
+static int nsp_cs_event(event_t event, int priority,
 		     event_callback_args_t *args);
-static dev_link_t *nsp_attach(void);
-static void nsp_detach(dev_link_t *);
+static dev_link_t *nsp_cs_attach(void);
+static void nsp_cs_detach(dev_link_t *);
 static int nsp_detect(Scsi_Host_Template * );
-static const char * nsp_info(struct Scsi_Host *);
+static int nsp_release(struct Scsi_Host *shpnt);
+static const char * nsp_info(struct Scsi_Host *shpnt);
 static int nsp_queuecommand(Scsi_Cmnd *, void (* done)(Scsi_Cmnd *));
 static int nsp_abort(Scsi_Cmnd *);
 static int nsp_reset(Scsi_Cmnd *, unsigned int);
@@ -130,25 +132,29 @@
 /* /usr/src/linux/drivers/scsi/hosts.h */
 static Scsi_Host_Template driver_template = {
 /*	next:			NULL,*/
-/*	proc_dir:		NULL,*/
+#if (KERNEL_VERSION(2,3,99) > LINUX_VERSION_CODE)
+	proc_dir:	       &proc_scsi_nsp, /* kernel 2.2 */
+#else
+	proc_name:	       "nsp_cs",       /* kernel 2.4 */
+#endif
 /*	proc_info:		NULL,*/
 	name:			"WorkBit NinjaSCSI-3/32Bi",
 	detect:			nsp_detect,
-/*	release:		NULL,*/
+	release:		nsp_release,
 	info:			nsp_info,
 /*	command:		NULL,*/
 	queuecommand:		nsp_queuecommand,
 /*	eh_strategy_handler:	nsp_eh_strategy,*/
-/*	eh_abort_handler:	nsp_eh_abort,*/
-/*	eh_device_reset_handler: nsp_eh_device_reset,*/
+	eh_abort_handler:	nsp_eh_abort,
+	eh_device_reset_handler: nsp_eh_device_reset,
 	eh_bus_reset_handler:	nsp_eh_bus_reset,
-/*	eh_host_reset_handler:	nsp_eh_host_reset,*/
+	eh_host_reset_handler:	nsp_eh_host_reset,
 	abort:			nsp_abort,
 	reset:			nsp_reset,
 /*	slave_attach:		NULL,*/
-/*	bios_param:		nsp_biosparam,*/
+/*	bios_param:		NULL,*/
 	can_queue:		1,
-	this_id:		-1,
+	this_id:		SCSI_INITIATOR_ID,
 	sg_tablesize:		SG_ALL,
 	cmd_per_lun:		1,
 /*	present:		0,*/
@@ -172,25 +178,24 @@
 	//unsigned int base    = SCpnt->host->io_port;
 	unsigned char target = SCpnt->target;
 #endif
+	nsp_hw_data *data = &nsp_data;
 
 	DEBUG(0, __FUNCTION__ "() SCpnt=0x%p target=%d lun=%d buff=0x%p bufflen=%d use_sg=%d\n",
 	      SCpnt, target, SCpnt->lun, SCpnt->request_buffer, SCpnt->request_bufflen, SCpnt->use_sg);
-	//DEBUG(0, " before CurrentSC=0x%p\n", nsp_data.CurrentSC);
+	//DEBUG(0, " before CurrentSC=0x%p\n", data->CurrentSC);
 
-	if(nsp_data.CurrentSC != NULL) {
+	if(data->CurrentSC != NULL) {
 		printk(KERN_DEBUG " " __FUNCTION__ "() CurrentSC!=NULL this can't be happen\n");
-		nsp_data.CurrentSC = NULL;
-		SCpnt->result	   = DID_BAD_TARGET << 16;
+		data->CurrentSC = NULL;
+		SCpnt->result   = DID_BAD_TARGET << 16;
 		done(SCpnt);
-		return FAILED;
+		return FALSE;
 	}
 
-#ifdef PCMCIA_DEBUG
 	show_command(SCpnt);
-#endif
 
 	SCpnt->scsi_done	= done;
-	nsp_data.CurrentSC	= SCpnt;
+	data->CurrentSC		= SCpnt;
 	RESID		        = SCpnt->request_bufflen;
 
 	SCpnt->SCp.Status	= -1;
@@ -217,62 +222,63 @@
 		SCpnt->SCp.buffers_residual = 0;
 	}
 
-	if(nsphw_start_selection(SCpnt) == FALSE) {
+	if(nsphw_start_selection(SCpnt, data) == FALSE) {
 		DEBUG(0, " selection fail\n");
-		nsp_data.CurrentSC = NULL;
-		SCpnt->result	   = DID_NO_CONNECT << 16;
+		data->CurrentSC = NULL;
+		SCpnt->result   = DID_NO_CONNECT << 16;
 		done(SCpnt);
-		return FAILED;
+		return FALSE;
 	}
 
 
 	//DEBUG(0, __FUNCTION__ "() out\n");
-	return SUCCESS;
+	return TRUE;
 }
 
 /*
  * setup PIO FIFO transfer mode and enable/disable to data out
  */
-static void nsp_setup_fifo(unsigned int base, int enabled)
+static void nsp_setup_fifo(nsp_hw_data *data, int enabled)
 {
-	unsigned char transfer_mode;
+	unsigned int  base = data->BaseAddress;
+	unsigned char transfer_mode_reg;
 
 	//DEBUG(0, __FUNCTION__ "() enabled=%d\n", enabled);
 
 	if (enabled != FALSE) {
-		transfer_mode = TRANSFER_GO | BRAIND;
+		transfer_mode_reg = TRANSFER_GO | BRAIND;
 	} else {
-		transfer_mode = 0;
+		transfer_mode_reg = 0;
 	}
 
-	transfer_mode |= nsp_data.TransferMode;
+	transfer_mode_reg |= data->TransferMode;
 
-	nsp_index_write(base, TRANSFERMODE, transfer_mode);
+	nsp_index_write(base, TRANSFERMODE, transfer_mode_reg);
 }
 
 /*
  * Initialize Ninja hardware
  */
-static int nsphw_init(void)
+static int nsphw_init(nsp_hw_data *data)
 {
-	unsigned int base     = nsp_data.BaseAddress;
+	unsigned int base     = data->BaseAddress;
 	int	     i, j;
 	sync_data    tmp_sync = { SyncNegotiation: SYNC_NOT_YET,
 				  SyncPeriod:	   0,
 				  SyncOffset:	   0
 	};
 
-	//DEBUG(0, __FUNCTION__ "() in\n");
+	DEBUG(0, __FUNCTION__ "() in base=0x%x\n", base);
 
-	nsp_data.ScsiClockDiv = CLOCK_40M;
-	nsp_data.CurrentSC    = NULL;
-	nsp_data.FifoCount    = 0;
-	nsp_data.TransferMode = MODE_IO8;
+	data->ScsiClockDiv = CLOCK_40M;
+	data->CurrentSC    = NULL;
+	data->FifoCount    = 0;
+	data->TransferMode = MODE_IO8;
 
 	/* setup sync data */
 	for ( i = 0; i < N_TARGET; i++ ) {
 		for ( j = 0; j < N_LUN; j++ ) {
-			nsp_data.Sync[i][j] = tmp_sync;
+			data->Sync[i][j] = tmp_sync;
 		}
 	}
 
@@ -285,7 +291,7 @@
 	nsp_index_write(base, SCSIIRQMODE,  0);
 
 	nsp_index_write(base, TRANSFERMODE, MODE_IO8);
-	nsp_index_write(base, CLOCKDIV,	    nsp_data.ScsiClockDiv);
+	nsp_index_write(base, CLOCKDIV,	    data->ScsiClockDiv);
 
 	nsp_index_write(base, PARITYCTRL,   0);
 	nsp_index_write(base, POINTERCLR,   POINTER_CLEAR     |
@@ -313,7 +319,7 @@
 					    SCSI_RESET_IRQ_EI	 );
 	nsp_write(base,	      IRQCONTROL,   IRQCONTROL_ALLCLEAR);
 
-	nsp_setup_fifo(base, FALSE);
+	nsp_setup_fifo(data, FALSE);
 
 	return TRUE;
 }
@@ -321,7 +327,8 @@
 /*
  * Start selection phase
  */
-static unsigned int nsphw_start_selection(Scsi_Cmnd *SCpnt)
+static unsigned int nsphw_start_selection(Scsi_Cmnd   *SCpnt,
+					  nsp_hw_data *data)
 {
 	unsigned int  host_id	 = SCpnt->host->this_id;
 	unsigned int  base	 = SCpnt->host->io_port;
@@ -331,7 +338,6 @@
 
 	//DEBUG(0, __FUNCTION__ "()in\n");
 
-
 	phase = nsp_index_read(base, SCSIBUSMON);
 	if(phase != BUSMON_BUS_FREE) {
 		//DEBUG(0, " bus busy\n");
@@ -371,8 +377,8 @@
 	nsp_index_write(base, SCSIBUSCTRL,   SCSI_SEL | SCSI_DATAOUT_ENB | SCSI_ATN);
 
 	/* check selection timeout */
-	nsp_start_timer(SCpnt, 1000/51);
-	nsp_data.SelectionTimeOut = 1;
+	nsp_start_timer(SCpnt, data, 1000/51);
+	data->SelectionTimeOut = 1;
 
 	return TRUE;
 }
@@ -402,11 +408,11 @@
 /*
  * setup synchronous data transfer mode
  */
-static int nsp_msg(Scsi_Cmnd *SCpnt)
+static int nsp_msg(Scsi_Cmnd *SCpnt, nsp_hw_data *data)
 {
 	unsigned char	       target = SCpnt->target;
 	unsigned char	       lun    = SCpnt->lun;
-	sync_data	      *sync   = &(nsp_data.Sync[target][lun]);
+	sync_data	      *sync   = &(data->Sync[target][lun]);
 	struct nsp_sync_table *sync_table;
 	unsigned int	       period, offset;
 	int		       i;
@@ -421,7 +427,7 @@
 
 	DEBUG(0, " period=0x%x, offset=0x%x\n", period, offset);
 
-	if (nsp_data.ScsiClockDiv == CLOCK_20M) {
+	if (data->ScsiClockDiv == CLOCK_20M) {
 		sync_table = &nsp_sync_table_20M[0];
 	} else {
 		sync_table = &nsp_sync_table_40M[0];
@@ -440,17 +446,19 @@
 		 */
 		DEBUG(0, " no proper period/offset\n");
 
-		sync->SyncPeriod   = 0;
-		sync->SyncOffset   = 0;
-		sync->SyncRegister = 0;
-		sync->AckWidth	   = 0;
+		sync->SyncPeriod      = 0;
+		sync->SyncOffset      = 0;
+		sync->SyncRegister    = 0;
+		sync->AckWidth	      = 0;
+		sync->SyncNegotiation = SYNC_OK;
 
 		return FALSE;
 	}
 
-	sync->SyncRegister = (sync_table->chip_period << SYNCREG_PERIOD_SHIFT) |
-			     (offset & SYNCREG_OFFSET_MASK);
-	sync->AckWidth	   = sync_table->ack_width;
+	sync->SyncRegister    = (sync_table->chip_period << SYNCREG_PERIOD_SHIFT) |
+		                (offset & SYNCREG_OFFSET_MASK);
+	sync->AckWidth	      = sync_table->ack_width;
+	sync->SyncNegotiation = SYNC_OK;
 
 	DEBUG(0, " sync_reg=0x%x, ack_width=0x%x\n", sync->SyncRegister, sync->AckWidth);
 
@@ -461,12 +469,12 @@
 /*
  * start ninja hardware timer
  */
-static void nsp_start_timer(Scsi_Cmnd *SCpnt, int time)
+static void nsp_start_timer(Scsi_Cmnd *SCpnt, nsp_hw_data *data, int time)
 {
 	unsigned int base = SCpnt->host->io_port;
 
 	//DEBUG(0, __FUNCTION__ "() in SCpnt=0x%p, time=%d\n", SCpnt, time);
-	nsp_data.TimerCount = time;
+	data->TimerCount = time;
 	nsp_index_write(base, TIMERCOUNT, time);
 }
 
@@ -535,16 +543,15 @@
 /*
  * transfer SCSI message
  */
-static int nsp_xfer(Scsi_Cmnd *SCpnt, int phase)
+static int nsp_xfer(Scsi_Cmnd *SCpnt, nsp_hw_data *data, int phase)
 {
 	unsigned int  base = SCpnt->host->io_port;
-	char	     *buf  = nsp_data.MsgBuffer;
-	int	      len  = MIN(MSGBUF_SIZE, nsp_data.MsgLen);
+	char	     *buf  = data->MsgBuffer;
+	int	      len  = MIN(MSGBUF_SIZE, data->MsgLen);
 	int	      ptr;
 	int	      ret;
 
 	//DEBUG(0, __FUNCTION__ "()\n");
-/**!**/
 	for (ptr = 0; len > 0; len --, ptr ++) {
 
 		ret = nsp_expect_signal(SCpnt, phase, BUSMON_REQ);
@@ -554,16 +561,16 @@
 		}
 
 		/* if last byte, negate ATN */
-		if (len == 1) {
+		if (len == 1 && SCpnt->SCp.phase == PH_MSG_OUT) {
 			nsp_index_write(base, SCSIBUSCTRL, AUTODIRECTION | ACKENB);
 		}
 
 		/* read & write message */
 		if (phase & BUSMON_IO) {
-			//DEBUG(0, " read msg\n");
+			DEBUG(0, " read msg\n");
 			buf[ptr] = nsp_index_read(base, SCSIDATAWITHACK);
 		} else {
-			//DEBUG(0, " write msg\n");
+			DEBUG(0, " write msg\n");
 			nsp_index_write(base, SCSIDATAWITHACK, buf[ptr]);
 		}
 		nsp_negate_signal(SCpnt, BUSMON_ACK, "xfer<ack>");
@@ -575,9 +582,8 @@
 /*
  * get extra SCSI data from fifo
  */
-static int nsp_dataphase_bypass(Scsi_Cmnd *SCpnt)
+static int nsp_dataphase_bypass(Scsi_Cmnd *SCpnt, nsp_hw_data *data)
 {
-	unsigned int base = SCpnt->host->io_port;
 	unsigned int count;
 
 	//DEBUG(0, __FUNCTION__ "()\n");
@@ -587,7 +593,7 @@
 	}
 
 	count = nsp_fifo_count(SCpnt);
-	if (nsp_data.FifoCount == count) {
+	if (data->FifoCount == count) {
 		//DEBUG(0, " not use bypass quirk\n");
 		return 0;
 	}
@@ -597,8 +603,8 @@
 	 * data phase skip only occures in case of SCSI_LOW_READ
 	 */
 	SCpnt->SCp.phase = PH_DATA;
-	nsp_pio_read(SCpnt);
-	nsp_setup_fifo(base, FALSE);
+	nsp_pio_read(SCpnt, data);
+	nsp_setup_fifo(data, FALSE);
 
 	DEBUG(0, " use bypass quirk\n");
 	return 0;
@@ -607,7 +613,7 @@
 /*
  * accept reselection
  */
-static int nsp_reselected(Scsi_Cmnd *SCpnt)
+static int nsp_reselected(Scsi_Cmnd *SCpnt, nsp_hw_data *data)
 {
 	unsigned int  base = SCpnt->host->io_port;
 	unsigned char reg;
@@ -616,7 +622,7 @@
 
 	nsp_negate_signal(SCpnt, BUSMON_SEL, "reselect<SEL>");
 
-	nsp_nexus(SCpnt);
+	nsp_nexus(SCpnt, data);
 	reg = nsp_index_read(base, SCSIBUSCTRL) & ~(SCSI_BSY | SCSI_ATN);
 	nsp_index_write(base, SCSIBUSCTRL, reg);
 	nsp_index_write(base, SCSIBUSCTRL, reg | AUTODIRECTION | ACKENB);
@@ -653,14 +659,14 @@
 /*
  * read data in DATA IN phase
  */
-static void nsp_pio_read(Scsi_Cmnd *SCpnt)
+static void nsp_pio_read(Scsi_Cmnd *SCpnt, nsp_hw_data *data)
 {
 	unsigned int  base     = SCpnt->host->io_port;
 	int	      time_out, i;
 	int	      ocount, res;
 	unsigned char stat, fifo_stat;
 
-	ocount = nsp_data.FifoCount;
+	ocount = data->FifoCount;
 
 	DEBUG(0, __FUNCTION__ "() in SCpnt=0x%p resid=%d ocount=%d ptr=0x%p this_residual=%d buffers=0x%p nbuf=%d\n", SCpnt, RESID, ocount, SCpnt->SCp.ptr, SCpnt->SCp.this_residual, SCpnt->SCp.buffer, SCpnt->SCp.buffers_residual);
 
@@ -693,7 +699,7 @@
 
 		res = MIN(res, SCpnt->SCp.this_residual);
 
-		switch (nsp_data.TransferMode) {
+		switch (data->TransferMode) {
 		case MODE_IO32:
 			res &= ~(BIT(1)|BIT(0)); /* align 4 */
 			nsp_fifo32_read(base, SCpnt->SCp.ptr, res >> 2);
@@ -725,7 +731,7 @@
 		time_out = jiffies + 10 * HZ;
 	}
 
-	nsp_data.FifoCount = ocount;
+	data->FifoCount = ocount;
 
 	if (!i) {
 		printk(KERN_DEBUG __FUNCTION__ "() pio read timeout resid=%d this_residual=%d buffers_residual=%d\n", RESID, SCpnt->SCp.this_residual, SCpnt->SCp.buffers_residual);
@@ -736,16 +742,16 @@
 /*
  * write data in DATA OUT phase
  */
-static void nsp_pio_write(Scsi_Cmnd *SCpnt)
+static void nsp_pio_write(Scsi_Cmnd *SCpnt, nsp_hw_data *data)
 {
 	unsigned int  base     = SCpnt->host->io_port;
 	int	      time_out, i;
 	unsigned int  ocount, res;
 	unsigned char stat;
 
-	ocount	 = nsp_data.FifoCount;
+	ocount	 = data->FifoCount;
 
-	DEBUG(0, __FUNCTION__ "() in fifocount=%d ptr=0x%p this_residual=%d buffers=0x%p nbuf=%d resid=0x%x\n", nsp_data.FifoCount, SCpnt->SCp.ptr, SCpnt->SCp.this_residual, SCpnt->SCp.buffer, SCpnt->SCp.buffers_residual, SCpnt->resid);
+	DEBUG(0, __FUNCTION__ "() in fifocount=%d ptr=0x%p this_residual=%d buffers=0x%p nbuf=%d resid=0x%x\n", data->FifoCount, SCpnt->SCp.ptr, SCpnt->SCp.this_residual, SCpnt->SCp.buffer, SCpnt->SCp.buffers_residual, RESID);
 
 	time_out = jiffies + 10 * HZ;
 
@@ -767,7 +773,7 @@
 		res = MIN(SCpnt->SCp.this_residual, WFIFO_CRIT);
 
 		//DEBUG(0, " ptr=0x%p this=0x%x res=0x%x\n", SCpnt->SCp.ptr, SCpnt->SCp.this_residual, res);
-		switch (nsp_data.TransferMode) {
+		switch (data->TransferMode) {
 		case MODE_IO32:
 			res &= ~(BIT(1)|BIT(0)); /* align 4 */
 			nsp_fifo32_write(base, SCpnt->SCp.ptr, res >> 2);
@@ -798,7 +804,7 @@
 		time_out = jiffies + 10 * HZ;
 	}
 
-	nsp_data.FifoCount = ocount;
+	data->FifoCount = ocount;
 
 	if (!i) {
 		printk(KERN_DEBUG __FUNCTION__ "() pio write timeout resid=%d\n", RESID);
@@ -812,12 +818,12 @@
 /*
  * setup synchronous/asynchronous data transfer mode
  */
-static int nsp_nexus(Scsi_Cmnd *SCpnt)
+static int nsp_nexus(Scsi_Cmnd *SCpnt, nsp_hw_data *data)
 {
-	unsigned int  base   = SCpnt->host->io_port;
-	unsigned char target = SCpnt->target;
-	unsigned char lun    = SCpnt->lun;
-	sync_data *sync = &(nsp_data.Sync[target][lun]);
+	unsigned int   base   = SCpnt->host->io_port;
+	unsigned char  target = SCpnt->target;
+	unsigned char  lun    = SCpnt->lun;
+	sync_data     *sync   = &(data->Sync[target][lun]);
 
 	//DEBUG(0, __FUNCTION__ "() in SCpnt=0x%p\n", SCpnt);
 
@@ -827,16 +833,16 @@
 
 	if (RESID % 4 != 0   ||
 	    RESID     <= 256 ) {
-		nsp_data.TransferMode = MODE_IO8;
+		data->TransferMode = MODE_IO8;
 	} else {
-		nsp_data.TransferMode = MODE_IO32;
+		data->TransferMode = MODE_IO32;
 	}
 
 	/* setup pdma fifo */
-	nsp_setup_fifo(base, TRUE);
+	nsp_setup_fifo(data, TRUE);
 
 	/* clear ack counter */
-	nsp_data.FifoCount = 0;
+	data->FifoCount = 0;
 	nsp_index_write(base, POINTERCLR, POINTER_CLEAR	    |
 					  ACK_COUNTER_CLEAR |
 					  REQ_COUNTER_CLEAR |
@@ -845,6 +851,7 @@
 	return 0;
 }
 
+#include "nsp_message.c"
 /*
  * interrupt handler
  */
@@ -853,13 +860,25 @@
 	unsigned int   base;
 	unsigned char  i_src, irq_phase, phase;
 	Scsi_Cmnd     *tmpSC;
-	int	       ret, len;
-	unsigned char  data_reg, control_reg;
-
-
-	//DEBUG(0, __FUNCTION__ "(%d) CurrentSC=0x%p\n", irq, nsp_data.CurrentSC);
+	int            len;
+	unsigned char  target, lun;
+	unsigned int  *sync_neg;
+	int            i, tmp;
+	nsp_hw_data   *data;
+
+	//printk("&nsp_data=0x%p, dev_id=0x%p\n", &nsp_data, dev_id);
+
+	/* sanity check */
+	if (&nsp_data != dev_id) {
+		DEBUG(0, " irq conflict? this can't happen\n");
+		return;
+	}
+	data = dev_id;
+	if (irq != data->IrqNumber) {
+		return;
+	}
 
-	base = nsp_data.BaseAddress;
+	base = data->BaseAddress;
 	//DEBUG(0, " base=0x%x\n", base);
 
 	/*
@@ -891,16 +910,16 @@
 	/*
 	 * timer interrupt handler (scsi vs timer interrupts)
 	 */
-	//DEBUG(0, " timercount=%d\n", nsp_data.TimerCount);
-	if (nsp_data.TimerCount != 0) {
+	//DEBUG(0, " timercount=%d\n", data->TimerCount);
+	if (data->TimerCount != 0) {
 		//DEBUG(0, " stop timer\n");
 		nsp_index_write(base, TIMERCOUNT, 0);
 		nsp_index_write(base, TIMERCOUNT, 0);
-		nsp_data.TimerCount = 0;
+		data->TimerCount = 0;
 	}
 
 	if ((i_src & IRQSTATUS_MASK) == IRQSTATUS_TIMER &&
-	    nsp_data.SelectionTimeOut == 0) {
+	    data->SelectionTimeOut == 0) {
 		//DEBUG(0, " timer start\n");
 		nsp_write(base, IRQCONTROL, IRQCONTROL_TIMER_CLEAR);
 		return;
@@ -908,11 +927,14 @@
 
 	nsp_write(base, IRQCONTROL, IRQCONTROL_TIMER_CLEAR | IRQCONTROL_FIFO_CLEAR);
 
-	if (nsp_data.CurrentSC == NULL) {
+	if (data->CurrentSC == NULL) {
 		printk(KERN_DEBUG __FUNCTION__ " CurrentSC==NULL irq_status=0x%x phase=0x%x irq_phase=0x%x this can't be happen\n", i_src, phase, irq_phase);
 		return;
 	} else {
-		tmpSC = nsp_data.CurrentSC;
+		tmpSC    = data->CurrentSC;
+		target   = tmpSC->target;
+		lun      = tmpSC->lun;
+		sync_neg = &(data->Sync[target][lun].SyncNegotiation);
 	}
 
 	/*
@@ -921,8 +943,8 @@
 	if ((i_src & IRQSTATUS_SCSI) != 0) {
 		if ((irq_phase & SCSI_RESET_IRQ) != 0) {
 			printk(KERN_DEBUG " " __FUNCTION__ "() bus reset (power off?)\n");
-
-			nsp_data.CurrentSC = NULL;
+			*sync_neg          = SYNC_NOT_YET;
+			data->CurrentSC    = NULL;
 			tmpSC->result	   = DID_RESET << 16;
 			tmpSC->scsi_done(tmpSC);
 			return;
@@ -931,7 +953,7 @@
 		if ((irq_phase & RESELECT_IRQ) != 0) {
 			DEBUG(0, " reselect\n");
 			nsp_write(base, IRQCONTROL, IRQCONTROL_RESELECT_CLEAR);
-			if (nsp_reselected(tmpSC) != FALSE) {
+			if (nsp_reselected(tmpSC, data) != FALSE) {
 				return;
 			}
 		}
@@ -945,28 +967,29 @@
 
 	switch(tmpSC->SCp.phase) {
 	case PH_SELSTART:
+		*sync_neg = SYNC_NOT_YET;
 		if ((phase & BUSMON_BSY) == 0) {
-			//DEBUG(0, " selection count=%d\n", nsp_data.SelectionTimeOut);
-			if (nsp_data.SelectionTimeOut >= NSP_SELTIMEOUT) {
+			//DEBUG(0, " selection count=%d\n", data->SelectionTimeOut);
+			if (data->SelectionTimeOut >= NSP_SELTIMEOUT) {
 				DEBUG(0, " selection time out\n");
-				nsp_data.SelectionTimeOut = 0;
+				data->SelectionTimeOut = 0;
 				nsp_index_write(base, SCSIBUSCTRL, 0);
 
-				nsp_data.CurrentSC = NULL;
-				tmpSC->result	   = DID_NO_CONNECT << 16;
+				data->CurrentSC = NULL;
+				tmpSC->result   = DID_NO_CONNECT << 16;
 				tmpSC->scsi_done(tmpSC);
 
 				return;
 			}
-			nsp_data.SelectionTimeOut += 1;
-			nsp_start_timer(tmpSC, 1000/51);
+			data->SelectionTimeOut += 1;
+			nsp_start_timer(tmpSC, data, 1000/51);
 			return;
 		}
 
 		/* attention assert */
 		//DEBUG(0, " attention assert\n");
-		nsp_data.SelectionTimeOut = 0;
-		tmpSC->SCp.phase	  = PH_SELECTED;
+		data->SelectionTimeOut = 0;
+		tmpSC->SCp.phase       = PH_SELECTED;
 		nsp_index_write(base, SCSIBUSCTRL, SCSI_ATN);
 		udelay(1);
 		nsp_index_write(base, SCSIBUSCTRL, SCSI_ATN | AUTODIRECTION | ACKENB);
@@ -976,16 +999,17 @@
 
 	case PH_RESELECT:
 		//DEBUG(0, " phase reselect\n");
+		*sync_neg = SYNC_NOT_YET;
 		if ((phase & BUSMON_PHASE_MASK) != BUSPHASE_MESSAGE_IN) {
 
-			nsp_data.CurrentSC = NULL;
-			tmpSC->result	   = DID_ABORT << 16;
+			data->CurrentSC = NULL;
+			tmpSC->result	= DID_ABORT << 16;
 			tmpSC->scsi_done(tmpSC);
 			return;
 		}
 		/* fall thru */
 	default:
-		if (( i_src & (IRQSTATUS_SCSI | IRQSTATUS_FIFO)) == 0) {
+		if ((i_src & (IRQSTATUS_SCSI | IRQSTATUS_FIFO)) == 0) {
 			return;
 		}
 		break;
@@ -999,8 +1023,9 @@
 	/* normal disconnect */
 	if ((irq_phase & LATCHED_BUS_FREE) != 0) {
 		//DEBUG(0, " normal disconnect i_src=0x%x, phase=0x%x, irq_phase=0x%x\n", i_src, phase, irq_phase);
-		if ((tmpSC->SCp.Message == 0)) {     /* all command complete and return status */
-			nsp_data.CurrentSC = NULL;
+		if ((tmpSC->SCp.Message == MSG_COMMAND_COMPLETE)) {     /* all command complete and return status */
+			*sync_neg       = SYNC_NOT_YET;
+			data->CurrentSC = NULL;
 			tmpSC->result = (DID_OK		    << 16) |
 					(tmpSC->SCp.Message <<	8) |
 					(tmpSC->SCp.Status  <<	0);
@@ -1017,8 +1042,9 @@
 	if (phase == 0) {
 		printk(KERN_DEBUG " " __FUNCTION__ " unexpected bus free. i_src=0x%x, phase=0x%x, irq_phase=0x%x\n", i_src, phase, irq_phase);
 
-		nsp_data.CurrentSC = NULL;
-		tmpSC->result	   = DID_ERROR << 16;
+		*sync_neg       = SYNC_NOT_YET;
+		data->CurrentSC = NULL;
+		tmpSC->result   = DID_ERROR << 16;
 		tmpSC->scsi_done(tmpSC);
 		return;
 	}
@@ -1033,7 +1059,7 @@
 
 		tmpSC->SCp.phase = PH_COMMAND;
 
-		nsp_nexus(tmpSC);
+		nsp_nexus(tmpSC, data);
 
 		/* write scsi command */
 		nsp_index_write(base, COMMANDCTRL, CLEAR_COMMAND_POINTER);
@@ -1049,7 +1075,7 @@
 		tmpSC->SCp.phase = PH_DATA;
 		tmpSC->SCp.have_data_in = IO_OUT;
 
-		nsp_pio_write(tmpSC);
+		nsp_pio_write(tmpSC, data);
 
 		break;
 
@@ -1059,12 +1085,12 @@
 		tmpSC->SCp.phase = PH_DATA;
 		tmpSC->SCp.have_data_in = IO_IN;
 
-		nsp_pio_read(tmpSC);
+		nsp_pio_read(tmpSC, data);
 
 		break;
 
 	case BUSPHASE_STATUS:
-		nsp_dataphase_bypass(tmpSC);
+		nsp_dataphase_bypass(tmpSC, data);
 		DEBUG(0, " BUSPHASE_STATUS\n");
 
 		tmpSC->SCp.phase = PH_STATUS;
@@ -1082,78 +1108,64 @@
 
 		tmpSC->SCp.phase = PH_MSG_OUT;
 
-		/*
-		 * XXX: NSP QUIRK
-		 * NSP invoke interrupts only in the case of scsi phase changes,
-		 * therefore we should poll the scsi phase here to catch 
-		 * the next "msg out" if exists (no scsi phase changes).
-		 */
-		ret = 16;
-		len = 0;
-
-		nsp_msg(tmpSC);
-
-		nsp_data.MsgBuffer[len] = IDENTIFY(TRUE, tmpSC->lun); len++;
-		nsp_data.MsgLen		= len;
-
-		do {
-			DEBUG(0, " msgout loop\n");
-
-			if (nsp_xfer(tmpSC, BUSPHASE_MESSAGE_OUT)) {
-				printk(KERN_DEBUG " " __FUNCTION__ " msgout: xfer short\n");
-			}
-
-			/* catch a next signal */
-			ret = nsp_expect_signal(tmpSC, BUSPHASE_MESSAGE_OUT, BUSMON_REQ);
-		} while (ret > 0 && len-- > 0);
+		data->MsgLen = len = 0;
+		if (*sync_neg == SYNC_NOT_YET) {
+			data->Sync[target][lun].SyncPeriod = 0;
+			data->Sync[target][lun].SyncOffset = 0;
+			nsp_msg(tmpSC, data);
+
+			data->MsgBuffer[len] = IDENTIFY(TRUE, lun); len++;
+			/*
+			data->MsgBuffer[len] = MSG_EXTENDED;        len++;
+			data->MsgBuffer[len] = 3;                   len++;
+			data->MsgBuffer[len] = MSG_EXT_SDTR;        len++;
+			data->MsgBuffer[len] = 0x0c;                len++;
+			data->MsgBuffer[len] = 15;                  len++;
+			*/
+		}
+		if (len == 0) {
+			data->MsgBuffer[len] = MSG_NO_OPERATION; len++;
+		}
+		data->MsgLen = len;
 
+		show_message(data);
+		nsp_message_out(tmpSC, data);
 		break;
 
 	case BUSPHASE_MESSAGE_IN:
-		nsp_dataphase_bypass(tmpSC);
+		nsp_dataphase_bypass(tmpSC, data);
 		DEBUG(0, " BUSPHASE_MESSAGE_IN\n");
 		if ((phase & BUSMON_REQ) == 0) {
 			goto timer_out;
 		}
 
 		tmpSC->SCp.phase = PH_MSG_IN;
+		nsp_message_in(tmpSC, data);
 
 		/*
-		 * XXX: NSP QUIRK
-		 * NSP invoke interrupts only in the case of scsi phase changes,
-		 * therefore we should poll the scsi phase here to catch 
-		 * the next "msg in" if exists (no scsi phase changes).
-		 */
-		ret = 16;
-		len = 0;
-
-		do {
-			//DEBUG(0, " msgin loop\n");
-			/* read data */
-			data_reg = nsp_index_read(base, SCSIDATAIN);
-
-			/* assert ACK */
-			control_reg = nsp_index_read(base, SCSIBUSCTRL);
-			control_reg |= SCSI_ACK;
-			nsp_index_write(base, SCSIBUSCTRL, control_reg);
-			nsp_negate_signal(tmpSC, BUSMON_REQ, "msgin<REQ>");
-
-			nsp_data.MsgBuffer[len] = data_reg; len++;
-			DEBUG(0, " msg=0x%x\n", data_reg);
-
-			/* deassert ACK */
-			control_reg =  nsp_index_read(base, SCSIBUSCTRL);
-			control_reg &= ~SCSI_ACK;
-			nsp_index_write(base, SCSIBUSCTRL, control_reg);
-
-			/* catch a next signal */
-			ret = nsp_expect_signal(tmpSC, BUSPHASE_MESSAGE_IN, BUSMON_REQ);
-		} while (ret > 0 && MSGBUF_SIZE > len);
+		if (data->MsgLen       >= 5            &&
+		    data->MsgBuffer[0] == MSG_EXTENDED &&
+		    data->MsgBuffer[1] == 3            &&
+		    data->MsgBuffer[2] == MSG_EXT_SDTR ) {
+			data->Sync[target][lun].SyncPeriod = data->MsgBuffer[3];
+			data->Sync[target][lun].SyncOffset = data->MsgBuffer[4];
+			nsp_msg(tmpSC, data);
+		}
+		*/
+
+		/* search last messeage byte */
+		tmp = -1;
+		for (i = 0; i < data->MsgLen; i++) {
+			tmp = data->MsgBuffer[i];
+			if (data->MsgBuffer[i] == MSG_EXTENDED) {
+				i += (1 + data->MsgBuffer[i+1]);
+			}
+		}
+		tmpSC->SCp.Message = tmp;
 
-		nsp_data.MsgLen	   = len;
-		tmpSC->SCp.Message = nsp_data.MsgBuffer[len-1];
+		DEBUG(0, " message=0x%x len=%d\n", tmpSC->SCp.Message, data->MsgLen);
+		show_message(data);
 
-		//DEBUG(0, " message=0x%x len=%d\n", tmpSC->SCp.Message, nsp_data.MsgLen);
 		break;
 
 	case BUSPHASE_SELECT:
@@ -1167,7 +1179,7 @@
 	return;	
 
 timer_out:
-	nsp_start_timer(tmpSC, 1000/102);
+	nsp_start_timer(tmpSC, data, 1000/102);
 	return;
 }
 
@@ -1175,6 +1187,136 @@
 #include "nsp_debug.c"
 #endif	/* DBG_SHOWCOMMAND */
 
+/*----------------------------------------------------------------*/
+/* look for ninja3 card and init if found			  */
+/*----------------------------------------------------------------*/
+static int nsp_detect(Scsi_Host_Template *sht)
+{
+	struct Scsi_Host *host;	/* registered host structure */
+	nsp_hw_data *data = &nsp_data;
+
+	DEBUG(0, __FUNCTION__ " this_id=%d\n", sht->this_id);
+
+	request_region(data->BaseAddress, data->NumAddress, "nsp_cs");
+	host		  = scsi_register(sht, 0);
+	host->io_port	  = data->BaseAddress;
+	host->unique_id	  = data->BaseAddress;
+	host->n_io_port	  = data->NumAddress;
+	host->irq	  = data->IrqNumber;
+	host->dma_channel = -1;
+
+	sprintf(nspinfo,
+/* Buffer size is 100 bytes */
+/*  0         1         2         3         4         5         6         7         8         9         0*/
+/*  01234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890*/
+   "NinjaSCSI-3/32Bi Driver version 2.7, I/O 0x%04lx-0x%04lx IRQ %2d",
+		host->io_port, host->io_port + host->n_io_port,
+		host->irq);
+	sht->name	  = nspinfo;
+
+	DEBUG(0, __FUNCTION__ " end\n");
+
+	return 1; /* detect done. */
+}
+
+static int nsp_release(struct Scsi_Host *shpnt)
+{
+	nsp_hw_data *data = &nsp_data;
+
+        if (shpnt->irq) {
+                free_irq(shpnt->irq, data);
+	}
+        if (shpnt->io_port) {
+		release_region(shpnt->io_port, shpnt->n_io_port);
+	}
+	return 0;
+}
+
+/*----------------------------------------------------------------*/
+/* return info string						  */
+/*----------------------------------------------------------------*/
+static const char *nsp_info(struct Scsi_Host *shpnt)
+{
+	return nspinfo;
+}
+
+/*---------------------------------------------------------------*/
+/* error handler                                                 */
+/*---------------------------------------------------------------*/
+static int nsp_reset(Scsi_Cmnd *SCpnt, unsigned int why)
+{
+	DEBUG(0, __FUNCTION__ " SCpnt=0x%p why=%d\n", SCpnt, why);
+
+	return nsp_eh_bus_reset(SCpnt);
+}
+
+static int nsp_abort(Scsi_Cmnd *SCpnt)
+{
+	DEBUG(0, __FUNCTION__ " SCpnt=0x%p\n", SCpnt);
+
+	nsp_eh_bus_reset(SCpnt);
+
+	return SUCCESS;
+}
+
+/*static int nsp_eh_strategy(struct Scsi_Host *Shost)
+{
+	return FAILED;
+}*/
+
+static int nsp_eh_abort(Scsi_Cmnd *SCpnt)
+{
+	DEBUG(0, __FUNCTION__ " SCpnt=0x%p\n", SCpnt);
+
+	nsp_eh_bus_reset(SCpnt);
+	return SUCCESS;
+}
+
+static int nsp_eh_device_reset(Scsi_Cmnd *SCpnt)
+{
+	DEBUG(0, __FUNCTION__ " SCpnt=0x%p\n", SCpnt);
+
+	return FAILED;
+}
+
+static int nsp_eh_bus_reset(Scsi_Cmnd *SCpnt)
+{
+	unsigned int base = SCpnt->host->io_port;
+	int	     i;
+
+	DEBUG(0, __FUNCTION__ "() SCpnt=0x%p base=0x%x\n", SCpnt, base);
+
+	nsp_write(base, IRQCONTROL, IRQCONTROL_ALLMASK);
+
+	nsp_index_write(base, SCSIBUSCTRL, SCSI_RST);
+	mdelay(100); /* 100ms */
+	nsp_index_write(base, SCSIBUSCTRL, 0);
+	for(i = 0; i < 5; i++) {
+		nsp_index_read(base, IRQPHASESENCE); /* dummy read */
+	}
+
+	nsp_write(base, IRQCONTROL, IRQCONTROL_ALLCLEAR);
+
+	return SUCCESS;
+}
+
+static int nsp_eh_host_reset(Scsi_Cmnd *SCpnt)
+{
+	nsp_hw_data *data = &nsp_data;
+
+	DEBUG(0, __FUNCTION__ "\n");
+
+	nsphw_init(data);
+	nsp_eh_bus_reset(SCpnt);
+
+	return SUCCESS;
+}
+
+
+/**********************************************************************
+  PCMCIA functions
+  *********************************************************************/
+
 /*====================================================================*/
 static void cs_error(client_handle_t handle, int func, int ret)
 {
@@ -1183,7 +1325,7 @@
 }
 
 /*======================================================================
-    nsp_attach() creates an "instance" of the driver, allocating
+    nsp_cs_attach() creates an "instance" of the driver, allocating
     local data structures for one device.  The device is registered
     with Card Services.
 
@@ -1191,7 +1333,7 @@
     configure the card at this point -- we wait until we receive a
     card insertion event.
 ======================================================================*/
-static dev_link_t *nsp_attach(void)
+static dev_link_t *nsp_cs_attach(void)
 {
 	scsi_info_t  *info;
 	client_reg_t  client_reg;
@@ -1202,13 +1344,13 @@
 
 	/* Create new SCSI device */
 	info = kmalloc(sizeof(*info), GFP_KERNEL);
-	if (!info) return NULL;
+	if (!info) { return NULL; }
 	memset(info, 0, sizeof(*info));
 	link = &info->link;
 	link->priv = info;
 
 	/* Initialize the dev_link_t structure */
-	link->release.function	 = &nsp_release;
+	link->release.function	 = &nsp_cs_release;
 	link->release.data	 = (u_long)link;
 
 	/* The io structure describes IO port mapping */
@@ -1227,6 +1369,7 @@
 		}
 	}
 	link->irq.Handler	 = &nspintr;
+	link->irq.Instance       = &nsp_data;
 
 	/* General socket configuration */
 	link->conf.Attributes	 = CONF_ENABLE_IRQ;
@@ -1244,18 +1387,18 @@
 		CS_EVENT_CARD_INSERTION | CS_EVENT_CARD_REMOVAL |
 		CS_EVENT_RESET_PHYSICAL | CS_EVENT_CARD_RESET	|
 		CS_EVENT_PM_SUSPEND	| CS_EVENT_PM_RESUME	 ;
-	client_reg.event_handler = &nsp_event;
+	client_reg.event_handler = &nsp_cs_event;
 	client_reg.Version	 = 0x0210;
 	client_reg.event_callback_args.client_data = link;
 	ret = CardServices(RegisterClient, &link->handle, &client_reg);
 	if (ret != CS_SUCCESS) {
 		cs_error(link->handle, RegisterClient, ret);
-		nsp_detach(link);
+		nsp_cs_detach(link);
 		return NULL;
 	}
 
 	return link;
-} /* nsp_attach */
+} /* nsp_cs_attach */
 
 
 /*======================================================================
@@ -1264,7 +1407,7 @@
     structures are freed.  Otherwise, the structures will be freed
     when the device is released.
 ======================================================================*/
-static void nsp_detach(dev_link_t *link)
+static void nsp_cs_detach(dev_link_t *link)
 {
 	dev_link_t **linkp;
 
@@ -1282,7 +1425,7 @@
 
 	del_timer(&link->release);
 	if (link->state & DEV_CONFIG) {
-		nsp_release((u_long)link);
+		nsp_cs_release((u_long)link);
 		if (link->state & DEV_STALE_CONFIG) {
 			link->state |= DEV_STALE_LINK;
 			return;
@@ -1298,11 +1441,11 @@
 	*linkp = link->next;
 	kfree(link->priv);
 
-} /* nsp_detach */
+} /* nsp_cs_detach */
 
 
 /*======================================================================
-    nsp_config() is scheduled to run after a CARD_INSERTION event
+    nsp_cs_config() is scheduled to run after a CARD_INSERTION event
     is received, to configure the PCMCIA socket, and to make the
     ethernet device available to the system.
 ======================================================================*/
@@ -1312,7 +1455,7 @@
 if (CardServices(fn, args) != 0) goto next_entry
 /*====================================================================*/
 
-static void nsp_config(dev_link_t *link)
+static void nsp_cs_config(dev_link_t *link)
 {
 	client_handle_t	  handle = link->handle;
 	scsi_info_t	 *info	 = link->priv;
@@ -1324,6 +1467,7 @@
 	Scsi_Device	 *dev;
 	dev_node_t	**tail, *node;
 	struct Scsi_Host *host;
+	nsp_hw_data      *data = &nsp_data;
 
 	DEBUG(0, __FUNCTION__ "() in\n");
 
@@ -1369,14 +1513,14 @@
 	release_region(link->io.BasePort1, link->io.NumPorts1);
 
 	/* Set port and IRQ */
-	nsp_data.BaseAddress = link->io.BasePort1;
-	nsp_data.NumAddress  = link->io.NumPorts1;
-	nsp_data.IrqNumber   = link->irq.AssignedIRQ;
+	data->BaseAddress = link->io.BasePort1;
+	data->NumAddress  = link->io.NumPorts1;
+	data->IrqNumber   = link->irq.AssignedIRQ;
 
 	DEBUG(0, __FUNCTION__ " I/O[0x%x+0x%x] IRQ %d\n",
-	      nsp_data.BaseAddress, nsp_data.NumAddress, nsp_data.IrqNumber);
+	      data->BaseAddress, data->NumAddress, data->IrqNumber);
 
-	if(nsphw_init() == FALSE) {
+	if(nsphw_init(data) == FALSE) {
 		goto cs_failed;
 	}
 
@@ -1446,19 +1590,19 @@
 
 cs_failed:
 	cs_error(link->handle, last_fn, last_ret);
-	nsp_release((u_long)link);
+	nsp_cs_release((u_long)link);
 	return;
 
-} /* nsp_config */
+} /* nsp_cs_config */
 #undef CS_CHECK
 #undef CFG_CHECK
 
 /*======================================================================
-    After a card is removed, nsp_release() will unregister the net
+    After a card is removed, nsp_cs_release() will unregister the net
     device, and release the PCMCIA configuration.  If the device is
     still open, this will be postponed until it is closed.
 ======================================================================*/
-static void nsp_release(u_long arg)
+static void nsp_cs_release(u_long arg)
 {
 	dev_link_t *link = (dev_link_t *)arg;
 
@@ -1492,9 +1636,9 @@
 	link->state &= ~DEV_CONFIG;
 
 	if (link->state & DEV_STALE_LINK) {
-		nsp_detach(link);
+		nsp_cs_detach(link);
 	}
-} /* nsp_release */
+} /* nsp_cs_release */
 
 /*======================================================================
 
@@ -1509,7 +1653,7 @@
     the card is still present.
     
 ======================================================================*/
-static int nsp_event(event_t		    event,
+static int nsp_cs_event(event_t		    event,
 		     int		    priority,
 		     event_callback_args_t *args)
 {
@@ -1532,7 +1676,7 @@
 		DEBUG(0, " event: insert\n");
 		link->state |= DEV_PRESENT | DEV_CONFIG_PENDING;
 		info->bus    =  args->bus;
-		nsp_config(link);
+		nsp_cs_config(link);
 		break;
 
 	case CS_EVENT_PM_SUSPEND:
@@ -1556,11 +1700,9 @@
 
 			CardServices(RequestConfiguration, link->handle, &link->conf);
 			tmp.host = info->host;
-			nsp_reset(&tmp, 0);
+			nsp_eh_host_reset(&tmp);
 		}
 		info->stop = 0;
-		/* restart IO */
-		nsphw_init();
 		break;
 
 	default:
@@ -1569,110 +1711,12 @@
 	}
 	DEBUG(0, __FUNCTION__ " end\n");
 	return 0;
-} /* nsp_event */
-
-/*----------------------------------------------------------------*/
-/* look for ninja3 card and init if found			  */
-/*----------------------------------------------------------------*/
-static int nsp_detect(Scsi_Host_Template *sht)
-{
-	struct Scsi_Host *host;	/* registered host structure */
-
-	DEBUG(0, __FUNCTION__ " this_id=%d\n", sht->this_id);
-
-#if (KERNEL_VERSION(2,3,99) > LINUX_VERSION_CODE)
-	sht->proc_dir	  = &proc_scsi_nsp; /* kernel 2.2 */
-#else
-	sht->proc_name	  = "nsp_cs";	    /* kernel 2.4 */
-#endif
-
-	sht->this_id	  = SCSI_INITIATOR_ID;
-
-	request_region(nsp_data.BaseAddress, nsp_data.NumAddress,"nsp_cs");
-	host		  = scsi_register(sht, 0);
-	host->io_port	  = nsp_data.BaseAddress;
-	host->unique_id	  = nsp_data.BaseAddress;
-	host->n_io_port	  = nsp_data.NumAddress;
-	host->irq	  = nsp_data.IrqNumber;
-	host->dma_channel = -1;
-
-	sprintf(nspinfo,
-/* Buffer size is 100 bytes */
-/*  0         1         2         3         4         5         6         7         8         9         0*/
-/*  01234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890*/
-   "NinjaSCSI-3/32Bi Driver version 2.0, I/O 0x%04lx-0x%04lx IRQ %2d",
-		host->io_port, host->io_port + host->n_io_port,
-		host->irq);
-	sht->name	  = nspinfo;
-
-	DEBUG(0, __FUNCTION__ " end\n");
-
-	return 1; /* detect done. */
-}
-
-
-/*----------------------------------------------------------------*/
-/* return info string						  */
-/*----------------------------------------------------------------*/
-static const char *nsp_info(struct Scsi_Host *host)
-{
-	return nspinfo;
-}
-
-static int nsp_reset(Scsi_Cmnd *SCpnt, unsigned int why)
-{
-	DEBUG(0, __FUNCTION__ "() SCpnt=0x%p why=%d\n", SCpnt, why);
-
-	return nsp_eh_bus_reset(SCpnt);
-}
-
-static int nsp_abort(Scsi_Cmnd *SCpnt)
-{
-	DEBUG(0, __FUNCTION__ "() SCpnt=0x%p\n", SCpnt);
-	return FAILED;
-}
-
-/*static int nsp_eh_strategy(struct Scsi_Host *Shost)
-{
-}
-static int nsp_eh_abort(Scsi_Cmnd * cmd)
-{
-	DEBUG(0, __FUNCTION__"() SCpnt\n");
-}
-
-static nsp_eh_device_reset(Scsi_Cmnd *)
-{
-}
-*/
-static int nsp_eh_bus_reset(Scsi_Cmnd *SCpnt)
-{
-	unsigned int base = SCpnt->host->io_port;
-	int	     i;
-
-	DEBUG(0, __FUNCTION__ "() SCpnt=0x%p\n", SCpnt);
-
-	nsp_write(base, IRQCONTROL, IRQCONTROL_ALLMASK);
-
-	nsp_index_write(base, SCSIBUSCTRL, SCSI_RST);
-	mdelay(100); /* 100ms */
-	nsp_index_write(base, SCSIBUSCTRL, 0);
-	for(i = 0; i < 5; i++) {
-		(void) nsp_index_read(base, IRQPHASESENCE); /* dummy read */
-	}
-
-	nsp_write(base, IRQCONTROL, IRQCONTROL_ALLCLEAR);
-
-	return 0;
-}
-/*
-static nsp_eh_host_reset(Scsi_Cmnd *)
-{
-}*/
+} /* nsp_cs_event */
 
 /*======================================================================*
  *	module entry point
  *====================================================================*/
-static int __init nsp_init(void)
+static int __init nsp_cs_init(void)
 {
 	servinfo_t serv;
 
@@ -1684,27 +1728,27 @@
 		       "does not match!\n");
 		return -1;
 	}
-	register_pcmcia_driver(&dev_info, &nsp_attach, &nsp_detach);
+	register_pcmcia_driver(&dev_info, &nsp_cs_attach, &nsp_cs_detach);
 
 	DEBUG(0, __FUNCTION__ "() out\n");
 	return 0;
 }
 
 
-static void __exit nsp_cleanup(void)
+static void __exit nsp_cs_cleanup(void)
 {
-	DEBUG(0, "nsp_cs: unloading\n");
+	DEBUG(0, __FUNCTION__ "() unloading\n");
 	unregister_pcmcia_driver(&dev_info);
 	while (dev_list != NULL) {
 		if (dev_list->state & DEV_CONFIG) {
-			nsp_release((u_long)dev_list);
+			nsp_cs_release((u_long)dev_list);
 		}
-		nsp_detach(dev_list);
+		nsp_cs_detach(dev_list);
 	}
 }
 
-module_init(nsp_init);
-module_exit(nsp_cleanup);
+module_init(nsp_cs_init);
+module_exit(nsp_cs_cleanup);
 
 /*
  *
diff -u --recursive --new-file v2.4.7/linux/drivers/scsi/pcmcia/nsp_cs.h linux/drivers/scsi/pcmcia/nsp_cs.h
--- v2.4.7/linux/drivers/scsi/pcmcia/nsp_cs.h	Wed Jul 25 17:10:23 2001
+++ linux/drivers/scsi/pcmcia/nsp_cs.h	Sun Aug  5 13:12:41 2001
@@ -6,11 +6,11 @@
     Ver 0.1 : Initial version.
 
     This software may be used and distributed according to the terms of
-    the GNU General Public License.
+    the GNU Public License.
 
 =========================================================*/
 
-/* $Id: nsp_cs.h,v 1.18 2001/02/09 04:42:19 elca Exp $ */
+/* $Id: nsp_cs.h,v 1.21 2001/07/04 14:45:31 elca Exp $ */
 
 #ifndef  __nsp_cs__
 #define  __nsp_cs__
@@ -38,6 +38,8 @@
 /* SCSI initiator must be 7 */
 #define SCSI_INITIATOR_ID  7
 
+#define NSP_SELTIMEOUT 200
+
 /* base register */
 #define	IRQCONTROL	0x00
 #  define IRQCONTROL_RESELECT_CLEAR     BIT(0)
@@ -239,9 +241,9 @@
 	Scsi_Cmnd    *CurrentSC;
 
 	int           FifoCount;
-#if (KERNEL_VERSION(2,4,0) > LINUX_VERSION_CODE)
+#if (LINUX_VERSION_CODE < KERNEL_VERSION(2,4,0))
 	int           Residual;
-#define RESID nsp_data.Residual
+#define RESID data->Residual
 #else
 #define RESID SCpnt->resid
 #endif
@@ -256,21 +258,30 @@
 } nsp_hw_data;
 
 
-static unsigned int nsphw_start_selection(Scsi_Cmnd *SCpnt);
-static void nsp_start_timer(Scsi_Cmnd *SCpnt, int time);
+static unsigned int nsphw_start_selection(Scsi_Cmnd *SCpnt, nsp_hw_data *data);
+static void nsp_start_timer(Scsi_Cmnd *SCpnt, nsp_hw_data *data, int time);
 
+static int nsp_eh_abort(Scsi_Cmnd * SCpnt);
+static int nsp_eh_device_reset(Scsi_Cmnd *SCpnt);
 static int nsp_eh_bus_reset(Scsi_Cmnd *SCpnt);
+static int nsp_eh_host_reset(Scsi_Cmnd *SCpnt);
 
 static int nsp_fifo_count(Scsi_Cmnd *SCpnt);
-static void nsp_pio_read(Scsi_Cmnd *SCpnt);
-static int nsp_nexus(Scsi_Cmnd *SCpnt);
+static void nsp_pio_read(Scsi_Cmnd *SCpnt, nsp_hw_data *data);
+static int nsp_nexus(Scsi_Cmnd *SCpnt, nsp_hw_data *data);
 
 #ifdef PCMCIA_DEBUG
 # ifdef DBG_SHOWCOMMAND
 static void show_command(Scsi_Cmnd *ptr);
 static void show_phase(Scsi_Cmnd *SCpnt);
 static void show_busphase(unsigned char stat);
+static void show_message(nsp_hw_data *data);
 # endif /* DBG_SHOWCOMMAND */
+#else
+# define show_command(ptr)   /* */
+# define show_phase(SCpnt)   /* */
+# define show_busphase(stat) /* */
+# define show_message(data)  /* */
 #endif
 
 /*
@@ -297,6 +308,11 @@
 };
 
 
-#define NSP_SELTIMEOUT 200
+/* SCSI messaage */
+#define MSG_COMMAND_COMPLETE 0x00
+#define MSG_EXTENDED         0x01
+#define MSG_NO_OPERATION     0x08
+
+#define MSG_EXT_SDTR         0x01
 
 #endif  /*__nsp_cs__*/
diff -u --recursive --new-file v2.4.7/linux/drivers/scsi/pcmcia/nsp_debug.c linux/drivers/scsi/pcmcia/nsp_debug.c
--- v2.4.7/linux/drivers/scsi/pcmcia/nsp_debug.c	Wed Jul 25 17:10:23 2001
+++ linux/drivers/scsi/pcmcia/nsp_debug.c	Sun Aug  5 13:12:41 2001
@@ -3,10 +3,10 @@
       By: YOKOTA Hiroshi <yokota@netlab.is.tsukuba.ac.jp>
 
     This software may be used and distributed according to the terms of
-    the GNU General Public License.
+    the GNU Public License.
 =========================================================================*/
 
-/* $Id: nsp_debug.c,v 1.5 2001/02/08 08:08:58 elca Exp $ */
+/* $Id: nsp_debug.c,v 1.6 2001/07/04 14:43:53 elca Exp $ */
 
 /*
  * Show the command data of a command
@@ -193,3 +193,16 @@
 		break;
 	}
 }
+
+static void show_message(nsp_hw_data *data)
+{
+	int i;
+
+	printk(KERN_DEBUG "msg:");
+	for(i=0; i < data->MsgLen; i++) {
+		printk(" %02x", data->MsgBuffer[i]);
+	}
+	printk("\n");
+}
+
+/* end */
diff -u --recursive --new-file v2.4.7/linux/drivers/scsi/pcmcia/nsp_io.h linux/drivers/scsi/pcmcia/nsp_io.h
--- v2.4.7/linux/drivers/scsi/pcmcia/nsp_io.h	Wed Jul 25 17:10:23 2001
+++ linux/drivers/scsi/pcmcia/nsp_io.h	Sun Aug  5 13:12:41 2001
@@ -3,7 +3,7 @@
       By: YOKOTA Hiroshi <yokota@netlab.is.tsukuba.ac.jp>
  
   This software may be used and distributed according to the terms of
-  the GNU General Public License.
+  the GNU Public License.
 
   */
 
diff -u --recursive --new-file v2.4.7/linux/drivers/scsi/pcmcia/nsp_message.c linux/drivers/scsi/pcmcia/nsp_message.c
--- v2.4.7/linux/drivers/scsi/pcmcia/nsp_message.c	Wed Dec 31 16:00:00 1969
+++ linux/drivers/scsi/pcmcia/nsp_message.c	Sun Aug  5 13:12:41 2001
@@ -0,0 +1,76 @@
+/*==========================================================================
+  NinjaSCSI-3 message handler
+      By: YOKOTA Hiroshi <yokota@netlab.is.tsukuba.ac.jp>
+
+   This software may be used and distributed according to the terms of
+   the GNU Public License.
+ */
+
+/* $Id: nsp_message.c,v 1.6 2001/07/05 10:56:37 elca Exp $ */
+
+static void nsp_message_in(Scsi_Cmnd *SCpnt, nsp_hw_data *data)
+{
+	unsigned int  base = SCpnt->host->io_port;
+	unsigned char data_reg, control_reg;
+	int           ret, len;
+
+	/*
+	 * XXX: NSP QUIRK
+	 * NSP invoke interrupts only in the case of scsi phase changes,
+	 * therefore we should poll the scsi phase here to catch 
+	 * the next "msg in" if exists (no scsi phase changes).
+	 */
+	ret = 16;
+	len = 0;
+
+	DEBUG(0, " msgin loop\n");
+	do {
+		/* read data */
+		data_reg = nsp_index_read(base, SCSIDATAIN);
+
+		/* assert ACK */
+		control_reg = nsp_index_read(base, SCSIBUSCTRL);
+		control_reg |= SCSI_ACK;
+		nsp_index_write(base, SCSIBUSCTRL, control_reg);
+		nsp_negate_signal(SCpnt, BUSMON_REQ, "msgin<REQ>");
+
+		data->MsgBuffer[len] = data_reg; len++;
+
+		/* deassert ACK */
+		control_reg =  nsp_index_read(base, SCSIBUSCTRL);
+		control_reg &= ~SCSI_ACK;
+		nsp_index_write(base, SCSIBUSCTRL, control_reg);
+
+		/* catch a next signal */
+		ret = nsp_expect_signal(SCpnt, BUSPHASE_MESSAGE_IN, BUSMON_REQ);
+	} while (ret > 0 && MSGBUF_SIZE > len);
+
+	data->MsgLen = len;
+
+}
+
+static void nsp_message_out(Scsi_Cmnd *SCpnt, nsp_hw_data *data)
+{
+	int ret = 1;
+	int len = data->MsgLen;
+
+	/*
+	 * XXX: NSP QUIRK
+	 * NSP invoke interrupts only in the case of scsi phase changes,
+	 * therefore we should poll the scsi phase here to catch 
+	 * the next "msg out" if exists (no scsi phase changes).
+	 */
+
+	DEBUG(0, " msgout loop\n");
+	do {
+		if (nsp_xfer(SCpnt, data, BUSPHASE_MESSAGE_OUT)) {
+			printk(KERN_DEBUG " " __FUNCTION__ " msgout: xfer short\n");
+		}
+
+		/* catch a next signal */
+		ret = nsp_expect_signal(SCpnt, BUSPHASE_MESSAGE_OUT, BUSMON_REQ);
+	} while (ret > 0 && len-- > 0);
+
+}
+
+/* end */
diff -u --recursive --new-file v2.4.7/linux/drivers/scsi/qlogicfc.c linux/drivers/scsi/qlogicfc.c
--- v2.4.7/linux/drivers/scsi/qlogicfc.c	Fri Apr 27 13:59:19 2001
+++ linux/drivers/scsi/qlogicfc.c	Sun Aug  5 13:12:41 2001
@@ -1337,21 +1337,10 @@
 		cmd->segment_cnt = cpu_to_le16(1); /* Shouldn't this be 0? */
 	}
 
-	switch (Cmnd->cmnd[0]) {
-	case TEST_UNIT_READY:
-	case START_STOP:
-	        break;
-	case WRITE_10:
-	case WRITE_6:
-	case WRITE_BUFFER:
-	case MODE_SELECT:
+	if (Cmnd->sc_data_direction == SCSI_DATA_WRITE)
 		cmd->control_flags = cpu_to_le16(CFLAG_WRITE);
-		break;
-	default:
+	else 
 		cmd->control_flags = cpu_to_le16(CFLAG_READ);
-		break;
-	}
-
 
 	if (Cmnd->device->tagged_supported) {
 		if ((jiffies - hostdata->tag_ages[Cmnd->target]) > (2 * SCSI_TIMEOUT)) {
@@ -1870,6 +1859,11 @@
 
 	hostdata = (struct isp2x00_hostdata *) host->hostdata;
 
+	/*
+	 *	This cannot be right - PCI writes are posted
+	 *	(apparently this is hardware design flaw not software ?)
+	 */
+	 
 	outw(0x01, host->io_port + ISP_CTRL_STATUS);
 	udelay(100);
 	outw(HCCR_RESET, host->io_port + HOST_HCCR);
diff -u --recursive --new-file v2.4.7/linux/drivers/scsi/scsi_lib.c linux/drivers/scsi/scsi_lib.c
--- v2.4.7/linux/drivers/scsi/scsi_lib.c	Wed Jul 25 17:10:23 2001
+++ linux/drivers/scsi/scsi_lib.c	Wed Aug  1 15:31:15 2001
@@ -655,24 +655,34 @@
 			}
 #endif
 		}
-		if ((SCpnt->sense_buffer[0] & 0x7f) == 0x70
-		    && (SCpnt->sense_buffer[2] & 0xf) == UNIT_ATTENTION) {
-			if (SCpnt->device->removable) {
-				/* detected disc change.  set a bit and quietly refuse
-				 * further access.
-				 */
-				SCpnt->device->changed = 1;
-				SCpnt = scsi_end_request(SCpnt, 0, this_count);
-				return;
-			} else {
-				/*
-				 * Must have been a power glitch, or a
-				 * bus reset.  Could not have been a
-				 * media change, so we just retry the
-				 * request and see what happens.  
-				 */
+		if ((SCpnt->sense_buffer[0] & 0x7f) == 0x70) {
+			/*
+			 * If the device is in the process of becoming ready,
+			 * retry.
+			 */
+			if (SCpnt->sense_buffer[12] == 0x04 &&
+			    SCpnt->sense_buffer[13] == 0x01) {
 				scsi_queue_next_request(q, SCpnt);
 				return;
+			}
+			if ((SCpnt->sense_buffer[2] & 0xf) == UNIT_ATTENTION) {
+				if (SCpnt->device->removable) {
+					/* detected disc change.  set a bit 
+					 * and quietly refuse further access.
+		 			 */
+					SCpnt->device->changed = 1;
+					SCpnt = scsi_end_request(SCpnt, 0, this_count);
+					return;
+				} else {
+					/*
+				 	* Must have been a power glitch, or a
+				 	* bus reset.  Could not have been a
+				 	* media change, so we just retry the
+				 	* request and see what happens.  
+				 	*/
+					scsi_queue_next_request(q, SCpnt);
+					return;
+				}
 			}
 		}
 		/* If we had an ILLEGAL REQUEST returned, then we may have
diff -u --recursive --new-file v2.4.7/linux/drivers/scsi/sd.c linux/drivers/scsi/sd.c
--- v2.4.7/linux/drivers/scsi/sd.c	Wed Jul 25 17:10:23 2001
+++ linux/drivers/scsi/sd.c	Sun Aug  5 13:12:41 2001
@@ -762,8 +762,17 @@
 	 */
 
 	SRpnt = scsi_allocate_request(rscsi_disks[i].device);
+	if (!SRpnt) {
+		printk(KERN_WARNING "(sd_init_onedisk:) Request allocation failure.\n");
+		return i;
+	}
 
 	buffer = (unsigned char *) scsi_malloc(512);
+	if (!buffer) {
+		printk(KERN_WARNING "(sd_init_onedisk:) Memory allocation failure.\n");
+		scsi_release_request(SRpnt);
+		return i;
+	}
 
 	spintime = 0;
 
diff -u --recursive --new-file v2.4.7/linux/drivers/scsi/ultrastor.c linux/drivers/scsi/ultrastor.c
--- v2.4.7/linux/drivers/scsi/ultrastor.c	Wed Jul 25 17:10:23 2001
+++ linux/drivers/scsi/ultrastor.c	Wed Jul 25 14:12:02 2001
@@ -602,6 +602,12 @@
       tpnt->sg_tablesize = ULTRASTOR_24F_MAX_SG;
 
       shpnt = scsi_register(tpnt, 0);
+      if (!shpnt) {
+             printk(KERN_WARNING "(ultrastor:) Could not register scsi device. Aborting registration.\n");
+             free_irq(config.interrupt, do_ultrastor_interrupt);
+             return FALSE;
+      }
+
       shpnt->irq = config.interrupt;
       shpnt->dma_channel = config.dma_channel;
       shpnt->io_port = config.port_address;
diff -u --recursive --new-file v2.4.7/linux/drivers/sound/sb_card.c linux/drivers/sound/sb_card.c
--- v2.4.7/linux/drivers/sound/sb_card.c	Tue Jul  3 17:08:21 2001
+++ linux/drivers/sound/sb_card.c	Wed Jul 25 14:12:02 2001
@@ -299,10 +299,20 @@
 		0,0,0,0,
 		0,1,1,-1},
 	{"Sound Blaster 16", 
+		ISAPNP_VENDOR('C','T','L'), ISAPNP_DEVICE(0x002c), 
+		ISAPNP_VENDOR('C','T','L'), ISAPNP_FUNCTION(0x0031),
+		0,0,0,0,
+		0,1,1,-1},
+	{"Sound Blaster 16", 
 		ISAPNP_VENDOR('C','T','L'), ISAPNP_DEVICE(0x00ed), 
 		ISAPNP_VENDOR('C','T','L'), ISAPNP_FUNCTION(0x0041),
 		0,0,0,0,
 		0,1,1,-1},
+	{"Sound Blaster 16", 
+		ISAPNP_VENDOR('C','T','L'), ISAPNP_DEVICE(0x0086), 
+		ISAPNP_VENDOR('C','T','L'), ISAPNP_FUNCTION(0x0041),
+		0,0,0,0,
+		0,1,1,-1},
 	{"Sound Blaster Vibra16S", 
 		ISAPNP_VENDOR('C','T','L'), ISAPNP_DEVICE(0x0051), 
 		ISAPNP_VENDOR('C','T','L'), ISAPNP_FUNCTION(0x0001),
@@ -524,7 +534,13 @@
 	{	ISAPNP_VENDOR('C','T','L'), ISAPNP_DEVICE(0x002b), 
 		ISAPNP_VENDOR('C','T','L'), ISAPNP_FUNCTION(0x0031), 0 },
 
+	{	ISAPNP_VENDOR('C','T','L'), ISAPNP_DEVICE(0x002c), 
+		ISAPNP_VENDOR('C','T','L'), ISAPNP_FUNCTION(0x0031), 0 },
+
 	{	ISAPNP_VENDOR('C','T','L'), ISAPNP_DEVICE(0x00ed), 
+		ISAPNP_VENDOR('C','T','L'), ISAPNP_FUNCTION(0x0041), 0 },
+
+	{	ISAPNP_VENDOR('C','T','L'), ISAPNP_DEVICE(0x0086), 
 		ISAPNP_VENDOR('C','T','L'), ISAPNP_FUNCTION(0x0041), 0 },
 
 	{	ISAPNP_VENDOR('C','T','L'), ISAPNP_DEVICE(0x0051), 
diff -u --recursive --new-file v2.4.7/linux/drivers/sound/sb_mixer.c linux/drivers/sound/sb_mixer.c
--- v2.4.7/linux/drivers/sound/sb_mixer.c	Fri Aug 11 08:26:43 2000
+++ linux/drivers/sound/sb_mixer.c	Wed Jul 25 14:12:02 2001
@@ -748,6 +748,7 @@
 
 void sb_mixer_unload(sb_devc *devc)
 {
+	kfree(mixer_devs[devc->my_mixerdev]);
 	sound_unload_mixerdev(devc->my_mixerdev);
 	sbmixnum--;
 }
diff -u --recursive --new-file v2.4.7/linux/drivers/sound/via82cxxx_audio.c linux/drivers/sound/via82cxxx_audio.c
--- v2.4.7/linux/drivers/sound/via82cxxx_audio.c	Tue Jul  3 17:08:21 2001
+++ linux/drivers/sound/via82cxxx_audio.c	Wed Jul 25 14:12:02 2001
@@ -1640,7 +1640,8 @@
 	if (!(status32 & VIA_INTR_MASK))
         {
 #ifdef CONFIG_MIDI_VIA82CXXX
-                uart401intr(irq, card->midi_devc, regs);
+	    	 if (card->midi_devc)
+                    	uart401intr(irq, card->midi_devc, regs);
 #endif
 		return;
     	}	    
diff -u --recursive --new-file v2.4.7/linux/drivers/usb/ibmcam.c linux/drivers/usb/ibmcam.c
--- v2.4.7/linux/drivers/usb/ibmcam.c	Tue Jul  3 17:08:21 2001
+++ linux/drivers/usb/ibmcam.c	Tue Jul 24 14:20:56 2001
@@ -2591,11 +2591,11 @@
 		{
 			struct video_window vw;
 
+			memset(&vw, 0, sizeof(vw));
 			vw.x = 0;
 			vw.y = 0;
 			vw.width = imgwidth;
 			vw.height = imgheight;
-			vw.chromakey = 0;
 			vw.flags = usb_ibmcam_calculate_fps();
 
 			if (copy_to_user(arg, &vw, sizeof(vw)))
@@ -2658,6 +2658,11 @@
 			if (copy_from_user((void *)&frame, arg, sizeof(int)))
 				return -EFAULT;
 
+			if ((unsigned)frame >= IBMCAM_NUMFRAMES) {
+				err("VIDIOCSYNC: invalid frame %d.", frame);
+				return -EINVAL;
+			}
+
 			if (debug >= 1)
 				printk(KERN_DEBUG "ibmcam: syncing to frame %d\n", frame);
 
@@ -3161,5 +3166,3 @@
 
 MODULE_AUTHOR( DRIVER_AUTHOR );
 MODULE_DESCRIPTION( DRIVER_DESC );
-
-
diff -u --recursive --new-file v2.4.7/linux/drivers/usb/ov511.c linux/drivers/usb/ov511.c
--- v2.4.7/linux/drivers/usb/ov511.c	Wed Jul 25 17:10:23 2001
+++ linux/drivers/usb/ov511.c	Tue Jul 24 14:20:56 2001
@@ -2254,6 +2254,7 @@
 
 		PDEBUG (4, "VIDIOCGCAP");
 
+		memset(&b, 0, sizeof(b));
 		strcpy(b.name, "OV511 USB Camera");
 		b.type = VID_TYPE_CAPTURE | VID_TYPE_SUBCAPTURE;
 		b.channels = 1;
@@ -2305,9 +2306,11 @@
 
 		PDEBUG (4, "VIDIOCGPICT");
 
+		memset(&p, 0, sizeof(p));
+
 		if (ov7610_get_picture(ov511, &p))
 			return -EIO;
-							
+
 		if (copy_to_user(arg, &p, sizeof(p)))
 			return -EFAULT;
 
@@ -2422,11 +2425,11 @@
 	{
 		struct video_window vw;
 
+		memset(&vw, 0, sizeof(vw));
 		vw.x = 0;		/* FIXME */
 		vw.y = 0;
 		vw.width = ov511->frame[0].width;
 		vw.height = ov511->frame[0].height;
-		vw.chromakey = 0;
 		vw.flags = 30;
 
 		PDEBUG (4, "VIDIOCGWIN: %dx%d", vw.width, vw.height);
@@ -2439,12 +2442,16 @@
 	case VIDIOCGMBUF:
 	{
 		struct video_mbuf vm;
-
+		int i;
+		
 		memset(&vm, 0, sizeof(vm));
 		vm.size = OV511_NUMFRAMES * MAX_DATA_SIZE;
 		vm.frames = OV511_NUMFRAMES;
 		vm.offsets[0] = 0;
-		vm.offsets[1] = MAX_FRAME_SIZE + sizeof (struct timeval);
+		for (i = 1; i < OV511_NUMFRAMES; i++) {
+			vm.offsets[i] = vm.offsets[i-1] + MAX_FRAME_SIZE
+				+ sizeof (struct timeval);
+		}
 
 		if (copy_to_user((void *)arg, (void *)&vm, sizeof(vm)))
 			return -EFAULT;
@@ -2469,7 +2476,7 @@
 			return -EINVAL;
 		}
 
-		if ((vm.frame != 0) && (vm.frame != 1)) {
+		if ((unsigned)vm.frame >= OV511_NUMFRAMES) {
 			err("VIDIOCMCAPTURE: invalid frame (%d)", vm.frame);
 			return -EINVAL;
 		}
@@ -2518,6 +2525,11 @@
 
 		if (copy_from_user((void *)&frame, arg, sizeof(int)))
 			return -EFAULT;
+
+		if ((unsigned)frame >= OV511_NUMFRAMES) {
+			err("VIDIOCSYNC: invalid frame (%d)", frame);
+			return -EINVAL;
+		}
 
 		PDEBUG(4, "syncing to frame %d, grabstate = %d", frame,
 		       ov511->frame[frame].grabstate);
diff -u --recursive --new-file v2.4.7/linux/drivers/usb/rio500.c linux/drivers/usb/rio500.c
--- v2.4.7/linux/drivers/usb/rio500.c	Tue Jul  3 17:08:21 2001
+++ linux/drivers/usb/rio500.c	Wed Jul 25 14:12:03 2001
@@ -38,13 +38,14 @@
 #include <linux/spinlock.h>
 #include <linux/usb.h>
 #include <linux/smp_lock.h>
+#include <linux/devfs_fs_kernel.h>
 
 #include "rio500_usb.h"
 
 /*
  * Version Information
  */
-#define DRIVER_VERSION "v1.0.0"
+#define DRIVER_VERSION "v1.1"
 #define DRIVER_AUTHOR "Cesar Miquel <miquel@df.uba.ar>"
 #define DRIVER_DESC "USB Rio 500 driver"
 
@@ -60,6 +61,7 @@
 
 struct rio_usb_data {
         struct usb_device *rio_dev;     /* init: probe_rio */
+        devfs_handle_t devfs;           /* devfs device */
         unsigned int ifnum;             /* Interface number of the USB device */
         int isopen;                     /* nz if open */
         int present;                    /* Device is present on the bus */
@@ -69,6 +71,8 @@
 	struct semaphore lock;          /* general race avoidance */
 };
 
+extern devfs_handle_t usb_devfs_handle;	/* /dev/usb dir. */
+
 static struct rio_usb_data rio_instance;
 
 static int open_rio(struct inode *inode, struct file *file)
@@ -350,7 +354,7 @@
 	int this_read;
 	int result;
 	int maxretry = 10;
-	char *ibuf = rio->ibuf;
+	char *ibuf;
 
         /* Sanity check to make sure rio is connected, powered, etc */
         if ( rio == NULL ||
@@ -358,6 +362,8 @@
              rio->rio_dev == NULL )
           return -1;
 
+	ibuf = rio->ibuf;
+
 	read_count = 0;
 
 	down(&(rio->lock));
@@ -416,6 +422,15 @@
 	return read_count;
 }
 
+static struct
+file_operations usb_rio_fops = {
+	read:		read_rio,
+	write:		write_rio,
+	ioctl:		ioctl_rio,
+	open:		open_rio,
+	release:	close_rio,
+};
+
 static void *probe_rio(struct usb_device *dev, unsigned int ifnum,
 		       const struct usb_device_id *id)
 {
@@ -439,6 +454,14 @@
 	}
 	dbg("probe_rio: ibuf address:%p", rio->ibuf);
 
+	rio->devfs = devfs_register(usb_devfs_handle, "rio500",
+				    DEVFS_FL_DEFAULT, USB_MAJOR,
+				    RIO_MINOR,
+				    S_IFCHR | S_IRUSR | S_IWUSR | S_IRGRP |
+				    S_IWGRP, &usb_rio_fops, NULL);
+	if (rio->devfs == NULL)
+		dbg("probe_rio: device node registration failed");
+	
 	init_MUTEX(&(rio->lock));
 
 	return rio;
@@ -448,6 +471,8 @@
 {
 	struct rio_usb_data *rio = (struct rio_usb_data *) ptr;
 
+	devfs_unregister(rio->devfs);
+
 	if (rio->isopen) {
 		rio->isopen = 0;
 		/* better let it finish - the release will do whats needed */
@@ -461,15 +486,6 @@
 
 	rio->present = 0;
 }
-
-static struct
-file_operations usb_rio_fops = {
-	read:		read_rio,
-	write:		write_rio,
-	ioctl:		ioctl_rio,
-	open:		open_rio,
-	release:	close_rio,
-};
 
 static struct usb_device_id rio_table [] = {
 	{ USB_DEVICE(0x0841, 1) }, 		/* Rio 500 */
diff -u --recursive --new-file v2.4.7/linux/drivers/usb/scanner.c linux/drivers/usb/scanner.c
--- v2.4.7/linux/drivers/usb/scanner.c	Wed Jul 25 17:10:24 2001
+++ linux/drivers/usb/scanner.c	Tue Jul 24 14:20:56 2001
@@ -858,6 +858,10 @@
 
 	switch (cmd)
 	{
+	case IOCTL_SCANNER_VENDOR :
+		return (put_user(dev->descriptor.idVendor, (unsigned int *) arg));
+	case IOCTL_SCANNER_PRODUCT :
+		return (put_user(dev->descriptor.idProduct, (unsigned int *) arg));
 	case PV8630_IOCTL_INREQUEST :
 	{
 		struct {
diff -u --recursive --new-file v2.4.7/linux/drivers/usb/scanner.h linux/drivers/usb/scanner.h
--- v2.4.7/linux/drivers/usb/scanner.h	Thu May 24 15:14:08 2001
+++ linux/drivers/usb/scanner.h	Tue Jul 24 14:20:56 2001
@@ -53,7 +53,7 @@
 
 /* Enable to activate the ioctl interface.  This is mainly meant for */
 /* development purposes until an ioctl number is officially registered */
-// #define SCN_IOCTL
+#define SCN_IOCTL
 
 /* WARNING: These DATA_DUMP's can produce a lot of data. Caveat Emptor. */
 // #define RD_DATA_DUMP /* Enable to dump data - limited to 24 bytes */
@@ -123,6 +123,7 @@
 	{ USB_DEVICE(0x04b8, 0x010a) }, /* Perfection 1640SU and 1640SU Photo */
 	{ USB_DEVICE(0x04b8, 0x010b) }, /* Perfection 1240U */
 	{ USB_DEVICE(0x04b8, 0x010c) }, /* Perfection 640U */
+	{ USB_DEVICE(0x04b8, 0x010e) }, /* Expression 1680 */
 	/* Umax */
 	{ USB_DEVICE(0x1606, 0x0010) },	/* Astra 1220U */
 	{ USB_DEVICE(0x1606, 0x0030) },	/* Astra 2000U */
@@ -163,6 +164,10 @@
 /* FIXME: These are NOT registered ioctls()'s */
 #define PV8630_IOCTL_INREQUEST 69
 #define PV8630_IOCTL_OUTREQUEST 70
+
+/* read vendor and product IDs */
+#define IOCTL_SCANNER_VENDOR _IOR('u', 0xa0, int)
+#define IOCTL_SCANNER_PRODUCT _IOR('u', 0xa1, int)
 
 #define SCN_MAX_MNR 16		/* We're allocated 16 minors */
 #define SCN_BASE_MNR 48		/* USB Scanners start at minor 48 */
diff -u --recursive --new-file v2.4.7/linux/drivers/usb/se401.c linux/drivers/usb/se401.c
--- v2.4.7/linux/drivers/usb/se401.c	Tue Jul  3 17:08:21 2001
+++ linux/drivers/usb/se401.c	Wed Jul 25 14:12:03 2001
@@ -486,12 +486,8 @@
 /* irq handler for snapshot button */
 static void se401_button_irq(struct urb *urb)
 {
-	struct usb_se401 *se401=urb->context;
+	struct usb_se401 *se401 = urb->context;
 	
-	if (!urb) {
-		info("ohoh: null urb");
-		return;
-	}
 	if (!se401->dev) {
 		info("ohoh: device vapourished");
 		return;
@@ -505,17 +501,13 @@
 
 static void se401_video_irq(struct urb *urb)
 {
-	struct usb_se401 *se401=urb->context;
-	int length=urb->actual_length;
+	struct usb_se401 *se401 = urb->context;
+	int length = urb->actual_length;
 
 	/* ohoh... */
-	if (!se401->streaming) {
-		return;
-	}
-	if (!urb) {
-		info ("ohoh: null urb");
+	if (!se401->streaming)
 		return;
-	}
+
 	if (!se401->dev) {
 		info ("ohoh: device vapourished");
 		return;
diff -u --recursive --new-file v2.4.7/linux/drivers/usb/serial/empeg.c linux/drivers/usb/serial/empeg.c
--- v2.4.7/linux/drivers/usb/serial/empeg.c	Wed Jul 25 17:10:24 2001
+++ linux/drivers/usb/serial/empeg.c	Tue Jul 24 14:20:56 2001
@@ -13,6 +13,10 @@
  *
  * See Documentation/usb/usb-serial.txt for more information on using this driver
  * 
+ * (07/16/2001) gb
+ *	remove unused code in empeg_close() (thanks to Oliver Neukum for pointing this
+ *	out) and rewrote empeg_set_termios().
+ * 
  * (05/30/2001) gkh
  *	switched from using spinlock to a semaphore, which fixes lots of problems.
  *
@@ -74,7 +78,7 @@
 /*
  * Version Information
  */
-#define DRIVER_VERSION "v1.1"
+#define DRIVER_VERSION "v1.2"
 #define DRIVER_AUTHOR "Greg Kroah-Hartman <greg@kroah.com>, Gary Brubaker <xavyer@ix.netcom.com>"
 #define DRIVER_DESC "USB Empeg Mark I/II Driver"
 
@@ -164,55 +168,8 @@
 
 	if (!port->active) {
 
-		/* gb - 2000/11/05
-		 * personally, I think these termios should be set in
-		 * empeg_startup(), but it appears doing so leads to one
-		 * of those chicken/egg problems. :)
-		 */
-		port->tty->termios->c_iflag
-			&= ~(IGNBRK
-			| BRKINT
-			| PARMRK
-			| ISTRIP
-			| INLCR
-			| IGNCR
-			| ICRNL
-			| IXON);
-
-		port->tty->termios->c_oflag
-			&= ~OPOST;
-
-		port->tty->termios->c_lflag
-			&= ~(ECHO
-			| ECHONL
-			| ICANON
-			| ISIG
-			| IEXTEN);
-
-		port->tty->termios->c_cflag
-			&= ~(CSIZE
-			| PARENB);
-
-		port->tty->termios->c_cflag
-			|= CS8;
-
-		/* gb - 2000/12/03
-		 * Contributed by Borislav Deianov
-		 * Notify the tty driver that the termios have changed!!
-		 */
-		port->tty->ldisc.set_termios(port->tty, NULL);
-
-		/* gb - 2000/11/05
-		 * force low_latency on
-		 *
-		 * The tty_flip_buffer_push()'s in empeg_read_bulk_callback() will actually
-		 * force the data through if low_latency is set.  Otherwise the pushes are
-		 * scheduled; this is bad as it opens up the possibility of dropping bytes
-		 * on the floor.  We are trying to sustain high data transfer rates; and
-		 * don't want to drop bytes on the floor.
-		 * Moral: use low_latency - drop no bytes - life is good. :)
-		 */
-		port->tty->low_latency = 1;
+		/* Force default termio settings */
+		empeg_set_termios (port, NULL) ;
 
 		port->active = 1;
 		bytes_in = 0;
@@ -578,65 +535,63 @@
 }
 
 
-/* This function is all nice and good, but we don't change anything based on it :) */
 static void empeg_set_termios (struct usb_serial_port *port, struct termios *old_termios)
 {
-	unsigned int cflag = port->tty->termios->c_cflag;
 
 	dbg(__FUNCTION__ " - port %d", port->number);
 
-	/* check that they really want us to change something */
-	if (old_termios) {
-		if ((cflag == old_termios->c_cflag) &&
-		    (RELEVANT_IFLAG(port->tty->termios->c_iflag) == RELEVANT_IFLAG(old_termios->c_iflag))) {
-			dbg(__FUNCTION__ " - nothing to change...");
-			return;
-		}
-	}
-
 	if ((!port->tty) || (!port->tty->termios)) {
 		dbg(__FUNCTION__" - no tty structures");
 		return;
 	}
 
-	/* get the byte size */
-	switch (cflag & CSIZE) {
-		case CS5:	dbg(__FUNCTION__ " - data bits = 5");   break;
-		case CS6:	dbg(__FUNCTION__ " - data bits = 6");   break;
-		case CS7:	dbg(__FUNCTION__ " - data bits = 7");   break;
-		default:
-		case CS8:	dbg(__FUNCTION__ " - data bits = 8");   break;
-	}
-
-	/* determine the parity */
-	if (cflag & PARENB)
-		if (cflag & PARODD)
-			dbg(__FUNCTION__ " - parity = odd");
-		else
-			dbg(__FUNCTION__ " - parity = even");
-	else
-		dbg(__FUNCTION__ " - parity = none");
-
-	/* figure out the stop bits requested */
-	if (cflag & CSTOPB)
-		dbg(__FUNCTION__ " - stop bits = 2");
-	else
-		dbg(__FUNCTION__ " - stop bits = 1");
-
-	/* figure out the flow control settings */
-	if (cflag & CRTSCTS)
-		dbg(__FUNCTION__ " - RTS/CTS is enabled");
-	else
-		dbg(__FUNCTION__ " - RTS/CTS is disabled");
-
-	/* determine software flow control */
-	if (I_IXOFF(port->tty))
-		dbg(__FUNCTION__ " - XON/XOFF is enabled, XON = %2x, XOFF = %2x", START_CHAR(port->tty), STOP_CHAR(port->tty));
-	else
-		dbg(__FUNCTION__ " - XON/XOFF is disabled");
+	/*
+         * The empeg-car player wants these particular tty settings.
+         * You could, for example, change the baud rate, however the
+         * player only supports 115200 (currently), so there is really
+         * no point in support for changes to the tty settings.
+         * (at least for now)
+         *
+         * The default requirements for this device are:
+         */
+	port->tty->termios->c_iflag
+		&= ~(IGNBRK	/* disable ignore break */
+		| BRKINT	/* disable break causes interrupt */
+		| PARMRK	/* disable mark parity errors */
+		| ISTRIP	/* disable clear high bit of input characters */
+		| INLCR		/* disable translate NL to CR */
+		| IGNCR		/* disable ignore CR */
+		| ICRNL		/* disable translate CR to NL */
+		| IXON);	/* disable enable XON/XOFF flow control */
+
+	port->tty->termios->c_oflag
+		&= ~OPOST;	/* disable postprocess output characters */
+
+	port->tty->termios->c_lflag
+		&= ~(ECHO	/* disable echo input characters */
+		| ECHONL	/* disable echo new line */
+		| ICANON	/* disable erase, kill, werase, and rprnt special characters */
+		| ISIG		/* disable interrupt, quit, and suspend special characters */
+		| IEXTEN);	/* disable non-POSIX special characters */
+
+	port->tty->termios->c_cflag
+		&= ~(CSIZE	/* no size */
+		| PARENB	/* disable parity bit */
+		| CBAUD);	/* clear current baud rate */
+
+	port->tty->termios->c_cflag
+		|= (CS8		/* character size 8 bits */
+		| B115200);	/* baud rate 115200 */
+
+	/*
+	 * Force low_latency on; otherwise the pushes are scheduled;
+	 * this is bad as it opens up the possibility of dropping bytes
+	 * on the floor.  We don't want to drop bytes on the floor. :)
+	 */
+	port->tty->low_latency = 1;
 
-	/* get the baud rate wanted */
-	dbg(__FUNCTION__ " - baud rate = %d", tty_get_baud_rate(port->tty));
+	/* Notify the tty driver that the termios have changed. */
+	port->tty->ldisc.set_termios(port->tty, NULL);
 
 	return;
 
diff -u --recursive --new-file v2.4.7/linux/drivers/usb/storage/Makefile linux/drivers/usb/storage/Makefile
--- v2.4.7/linux/drivers/usb/storage/Makefile	Fri Dec 29 14:07:23 2000
+++ linux/drivers/usb/storage/Makefile	Sun Jul 29 21:11:50 2001
@@ -19,6 +19,9 @@
 usb-storage-obj-$(CONFIG_USB_STORAGE_SHUTTLE_SMARTMEDIA)   += shuttle_sm.o
 usb-storage-obj-$(CONFIG_USB_STORAGE_SHUTTLE_COMPACTFLASH) += shuttle_cf.o
 usb-storage-obj-$(CONFIG_USB_STORAGE_DPCM)	+= dpcm.o
+usb-storage-obj-$(CONFIG_USB_STORAGE_ISD200)	+= isd200.o
+usb-storage-obj-$(CONFIG_USB_STORAGE_DATAFAB)   += datafab.o
+usb-storage-obj-$(CONFIG_USB_STORAGE_JUMPSHOT)  += jumpshot.o
 
 usb-storage-objs :=	scsiglue.o protocol.o transport.o usb.o \
 			initializers.o $(usb-storage-obj-y)
diff -u --recursive --new-file v2.4.7/linux/drivers/usb/storage/datafab.c linux/drivers/usb/storage/datafab.c
--- v2.4.7/linux/drivers/usb/storage/datafab.c	Wed Dec 31 16:00:00 1969
+++ linux/drivers/usb/storage/datafab.c	Sun Jul 29 21:11:50 2001
@@ -0,0 +1,806 @@
+/* Driver for Datafab USB Compact Flash reader
+ *
+ * datafab driver v0.1:
+ *
+ * First release
+ *
+ * Current development and maintenance by:
+ *   (c) 2000 Jimmie Mayfield (mayfield+datafab@sackheads.org)
+ *   many thanks to Robert Baruch for the SanDisk SmartMedia reader driver
+ *   which I used as a template for this driver.
+ *   Some bugfixes and scatter-gather code by Gregory P. Smith 
+ *   (greg-usb@electricrain.com)
+ *
+ * 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, 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.
+ */
+
+/*
+ * This driver attempts to support USB CompactFlash reader/writer devices
+ * based on Datafab USB-to-ATA chips.  It was specifically developed for the 
+ * Datafab MDCFE-B USB CompactFlash reader but has since been found to work 
+ * with a variety of Datafab-based devices from a number of manufacturers.
+ * I've received a report of this driver working with a Datafab-based
+ * SmartMedia device though please be aware that I'm personally unable to
+ * test SmartMedia support.
+ *
+ * This driver supports reading and writing.  If you're truly paranoid,
+ * however, you can force the driver into a write-protected state by setting
+ * the WP enable bits in datafab_handle_mode_sense().  Basically this means
+ * setting mode_param_header[3] = 0x80.
+ */
+
+#include "transport.h"
+#include "protocol.h"
+#include "usb.h"
+#include "debug.h"
+#include "datafab.h"
+
+#include <linux/sched.h>
+#include <linux/errno.h>
+#include <linux/malloc.h>
+
+extern int usb_stor_bulk_msg(struct us_data *us, void *data, int pipe,
+			     unsigned int len, unsigned int *act_len);
+
+static int datafab_determine_lun(struct us_data *us, struct datafab_info *info);
+
+
+static void datafab_dump_data(unsigned char *data, int len)
+{
+	unsigned char buf[80];
+	int sofar = 0;
+
+	if (!data)
+		return;
+
+	memset(buf, 0, sizeof(buf));
+
+	for (sofar = 0; sofar < len; sofar++) {
+		sprintf(buf + strlen(buf), "%02x ",
+			((unsigned int) data[sofar]) & 0xFF);
+
+		if (sofar % 16 == 15) {
+			US_DEBUGP("datafab:  %s\n", buf);
+			memset(buf, 0, sizeof(buf));
+		}
+	}
+
+	if (strlen(buf) != 0)
+		US_DEBUGP("datafab:  %s\n", buf);
+}
+
+
+static int datafab_raw_bulk(int direction,
+			    struct us_data *us,
+			    unsigned char *data, 
+		            unsigned int len)
+{
+	int result;
+	int act_len;
+	int pipe;
+
+	if (direction == SCSI_DATA_READ)
+		pipe = usb_rcvbulkpipe(us->pusb_dev, us->ep_in);
+	else
+		pipe = usb_sndbulkpipe(us->pusb_dev, us->ep_out);
+
+	result = usb_stor_bulk_msg(us, data, pipe, len, &act_len);
+
+	// if we stall, we need to clear it before we go on 
+	if (result == -EPIPE) {
+		US_DEBUGP("datafab_raw_bulk: EPIPE. clearing endpoint halt for"
+			  " pipe 0x%x, stalled at %d bytes\n", pipe, act_len);
+		usb_clear_halt(us->pusb_dev, pipe);
+	}
+
+	if (result) {
+		// NAK - that means we've retried a few times already 
+		if (result == -ETIMEDOUT) {
+			US_DEBUGP("datafab_raw_bulk:  device NAKed\n");
+			return US_BULK_TRANSFER_FAILED;
+		}
+
+		// -ENOENT -- we canceled this transfer
+		if (result == -ENOENT) {
+			US_DEBUGP("datafab_raw_bulk:  transfer aborted\n");
+			return US_BULK_TRANSFER_ABORTED;
+		}
+
+		if (result == -EPIPE) {
+			US_DEBUGP("datafab_raw_bulk:  output pipe stalled\n");
+			return USB_STOR_TRANSPORT_FAILED;
+		}
+
+		// the catch-all case
+		US_DEBUGP("datafab_raw_bulk:  unknown error\n");
+		return US_BULK_TRANSFER_FAILED;
+	}
+
+	if (act_len != len) {
+		US_DEBUGP("datafab_raw_bulk:  Warning. Transferred only %d bytes\n", act_len);
+		return US_BULK_TRANSFER_SHORT;
+	}
+
+	US_DEBUGP("datafab_raw_bulk:  Transfered %d of %d bytes\n", act_len, len);
+	return US_BULK_TRANSFER_GOOD;
+}
+
+static inline int datafab_bulk_read(struct us_data *us,
+			            unsigned char *data, 
+		                    unsigned int len)
+{
+	if (len == 0)
+		return USB_STOR_TRANSPORT_GOOD;
+
+	US_DEBUGP("datafab_bulk_read:  len = %d\n", len);
+	return datafab_raw_bulk(SCSI_DATA_READ, us, data, len);
+}
+
+
+static inline int datafab_bulk_write(struct us_data *us,
+			             unsigned char *data, 
+		                     unsigned int len)
+{
+	if (len == 0)
+		return USB_STOR_TRANSPORT_GOOD;
+
+	US_DEBUGP("datafab_bulk_write:  len = %d\n", len);
+	return datafab_raw_bulk(SCSI_DATA_WRITE, us, data, len);
+}
+
+
+static int datafab_read_data(struct us_data *us,
+		             struct datafab_info *info,
+		             u32 sector,
+		             u32 sectors, 
+		             unsigned char *dest, 
+		             int use_sg)
+{
+	unsigned char command[8] = { 0, 0, 0, 0, 0, 0xE0, 0x20, 0x01 };
+	unsigned char *buffer = NULL;
+	unsigned char *ptr;
+	unsigned char  thistime;
+	struct scatterlist *sg = NULL;
+	int totallen, len, result;
+	int sg_idx = 0, current_sg_offset = 0;
+	int transferred, rc;
+
+	// we're working in LBA mode.  according to the ATA spec, 
+	// we can support up to 28-bit addressing.  I don't know if Datafab
+	// supports beyond 24-bit addressing.  It's kind of hard to test 
+	// since it requires > 8GB CF card.
+	//
+	if (sectors > 0x0FFFFFFF)
+		return USB_STOR_TRANSPORT_ERROR;
+
+	if (info->lun == -1) {
+		rc = datafab_determine_lun(us, info);
+		if (rc != USB_STOR_TRANSPORT_GOOD)
+			return rc;
+	}
+
+	command[5] += (info->lun << 4);
+
+	// If we're using scatter-gather, we have to create a new
+	// buffer to read all of the data in first, since a
+	// scatter-gather buffer could in theory start in the middle
+	// of a page, which would be bad. A developer who wants a
+	// challenge might want to write a limited-buffer
+	// version of this code.
+
+	totallen = sectors * info->ssize;
+
+	do {
+		// loop, never allocate or transfer more than 64k at once (min(128k, 255*info->ssize) is the real limit)
+		len = min(totallen, 65536);
+
+		if (use_sg) {
+			sg = (struct scatterlist *) dest;
+			buffer = kmalloc(len, GFP_KERNEL);
+			if (buffer == NULL)
+				return USB_STOR_TRANSPORT_ERROR;
+			ptr = buffer;
+		} else {
+			ptr = dest;
+		}
+
+		thistime = (len / info->ssize) & 0xff;
+
+		command[0] = 0;
+		command[1] = thistime;
+		command[2] = sector & 0xFF;
+		command[3] = (sector >> 8) & 0xFF;
+		command[4] = (sector >> 16) & 0xFF;
+	
+		command[5] |= (sector >> 24) & 0x0F;
+
+		// send the command
+		US_DEBUGP("datafab_read_data:  sending following command\n");
+		datafab_dump_data(command, sizeof(command));
+
+		result = datafab_bulk_write(us, command, sizeof(command));
+		if (result != USB_STOR_TRANSPORT_GOOD) {
+			if (use_sg)
+				kfree(buffer);
+			return result;
+		}
+
+		// read the result
+		result = datafab_bulk_read(us, ptr, len);
+		if (result != USB_STOR_TRANSPORT_GOOD) {
+			if (use_sg)
+				kfree(buffer);
+			return result;
+		}
+
+		US_DEBUGP("datafab_read_data results:  %d bytes\n", len);
+		// datafab_dump_data(ptr, len);
+
+		sectors -= thistime;
+		sector  += thistime;
+
+		if (use_sg) {
+			transferred = 0;
+			while (sg_idx < use_sg && transferred < len) {
+				if (len - transferred >= sg[sg_idx].length - current_sg_offset) {
+					US_DEBUGP("datafab_read_data:  adding %d bytes to %d byte sg buffer\n", sg[sg_idx].length - current_sg_offset, sg[sg_idx].length);
+					memcpy(sg[sg_idx].address + current_sg_offset,
+					       buffer + transferred,
+					       sg[sg_idx].length - current_sg_offset);
+					transferred += sg[sg_idx].length - current_sg_offset;
+					current_sg_offset = 0;
+					// on to the next sg buffer
+					++sg_idx;
+				} else {
+					US_DEBUGP("datafab_read_data:  adding %d bytes to %d byte sg buffer\n", len - transferred, sg[sg_idx].length);
+					memcpy(sg[sg_idx].address + current_sg_offset,
+					       buffer + transferred,
+					       len - transferred);
+					current_sg_offset += len - transferred;
+					// this sg buffer is only partially full and we're out of data to copy in
+					break;
+				}
+			}
+			kfree(buffer);
+		} else {
+			dest += len;
+		}
+
+		totallen -= len;
+	} while (totallen > 0);
+
+	return USB_STOR_TRANSPORT_GOOD;
+}
+
+
+static int datafab_write_data(struct us_data *us,
+		              struct datafab_info *info,
+		              u32 sector,
+		              u32 sectors, 
+		              unsigned char *src, 
+		              int use_sg)
+{
+	unsigned char command[8] = { 0, 0, 0, 0, 0, 0xE0, 0x30, 0x02 };
+	unsigned char reply[2] = { 0, 0 };
+	unsigned char *buffer = NULL;
+	unsigned char *ptr;
+	unsigned char thistime;
+	struct scatterlist *sg = NULL;
+	int totallen, len, result;
+	int sg_idx = 0, current_sg_offset = 0;
+	int transferred, rc;
+
+	// we're working in LBA mode.  according to the ATA spec, 
+	// we can support up to 28-bit addressing.  I don't know if Datafab
+	// supports beyond 24-bit addressing.  It's kind of hard to test 
+	// since it requires > 8GB CF card.
+	//
+	if (sectors > 0x0FFFFFFF)
+		return USB_STOR_TRANSPORT_ERROR;
+
+	if (info->lun == -1) {
+		rc = datafab_determine_lun(us, info);
+		if (rc != USB_STOR_TRANSPORT_GOOD)
+			return rc;
+	}
+
+	command[5] += (info->lun << 4);
+
+	// If we're using scatter-gather, we have to create a new
+	// buffer to read all of the data in first, since a
+	// scatter-gather buffer could in theory start in the middle
+	// of a page, which would be bad. A developer who wants a
+	// challenge might want to write a limited-buffer
+	// version of this code.
+
+	totallen = sectors * info->ssize;
+
+	do {
+		// loop, never allocate or transfer more than 64k at once (min(128k, 255*info->ssize) is the real limit)
+		len = min(totallen, 65536);
+
+		if (use_sg) {
+			sg = (struct scatterlist *) src;
+			buffer = kmalloc(len, GFP_KERNEL);
+			if (buffer == NULL)
+				return USB_STOR_TRANSPORT_ERROR;
+			ptr = buffer;
+
+			memset(buffer, 0, len);
+
+			// copy the data from the sg bufs into the big contiguous buf
+			//
+			transferred = 0;
+			while (transferred < len) {
+				if (len - transferred >= sg[sg_idx].length - current_sg_offset) {
+					US_DEBUGP("datafab_write_data:  getting %d bytes from %d byte sg buffer\n", sg[sg_idx].length - current_sg_offset, sg[sg_idx].length);
+					memcpy(ptr + transferred,
+					       sg[sg_idx].address + current_sg_offset,
+					       sg[sg_idx].length - current_sg_offset);
+					transferred += sg[sg_idx].length - current_sg_offset;
+					current_sg_offset = 0;
+					// on to the next sg buffer
+					++sg_idx;
+				} else {
+					US_DEBUGP("datafab_write_data:  getting %d bytes from %d byte sg buffer\n", len - transferred, sg[sg_idx].length);
+					memcpy(ptr + transferred,
+					       sg[sg_idx].address + current_sg_offset,
+					       len - transferred);
+					current_sg_offset += len - transferred;
+					// we only copied part of this sg buffer
+					break;
+				}
+			}
+		} else {
+			ptr = src;
+		}
+
+		thistime = (len / info->ssize) & 0xff;
+
+		command[0] = 0;
+		command[1] = thistime;
+		command[2] = sector & 0xFF;
+		command[3] = (sector >> 8) & 0xFF;
+		command[4] = (sector >> 16) & 0xFF;
+
+		command[5] |= (sector >> 24) & 0x0F;
+
+		// send the command
+		US_DEBUGP("datafab_write_data:  sending following command\n");
+		datafab_dump_data(command, sizeof(command));
+
+		result = datafab_bulk_write(us, command, sizeof(command));
+		if (result != USB_STOR_TRANSPORT_GOOD) {
+			if (use_sg)
+				kfree(buffer);
+			return result;
+		}
+
+		// send the data
+		result = datafab_bulk_write(us, ptr, len);
+		if (result != USB_STOR_TRANSPORT_GOOD) {
+			if (use_sg)
+				kfree(buffer);
+			return result;
+		}
+
+		// read the result
+		result = datafab_bulk_read(us, reply, sizeof(reply));
+		if (result != USB_STOR_TRANSPORT_GOOD) {
+			if (use_sg)
+				kfree(buffer);
+			return result;
+		}
+
+		if (reply[0] != 0x50 && reply[1] != 0) {
+			US_DEBUGP("datafab_write_data:  Gah! write return code: %02x %02x\n", reply[0], reply[1]);
+			if (use_sg)
+				kfree(buffer);
+			return USB_STOR_TRANSPORT_ERROR;
+		}
+
+		sectors -= thistime;
+		sector  += thistime;
+
+		if (use_sg) {
+			kfree(buffer);
+		} else {
+			src += len;
+		}
+
+		totallen -= len;
+	} while (totallen > 0);
+
+	return USB_STOR_TRANSPORT_GOOD;
+}
+
+
+static int datafab_determine_lun(struct us_data *us,
+				 struct datafab_info *info)
+{
+	// dual-slot readers can be thought of as dual-LUN devices.  we need to
+	// determine which card slot is being used.  we'll send an IDENTIFY DEVICE
+	// command and see which LUN responds...
+	//
+	// there might be a better way of doing this?
+	//
+	unsigned char command[8] = { 0, 1, 0, 0, 0, 0xa0, 0xec, 1 };
+	unsigned char buf[512];
+	int count = 0, rc;
+
+	if (!us || !info)
+		return USB_STOR_TRANSPORT_ERROR;
+
+	US_DEBUGP("datafab_determine_lun:  locating...\n");
+
+	// we'll try 10 times before giving up...
+	//
+	while (count++ < 10) {
+		command[5] = 0xa0;
+
+		rc = datafab_bulk_write(us, command, 8);
+		if (rc != USB_STOR_TRANSPORT_GOOD) 
+			return rc;
+
+		rc = datafab_bulk_read(us, buf, sizeof(buf));
+		if (rc == USB_STOR_TRANSPORT_GOOD) {
+			info->lun = 0;
+			return USB_STOR_TRANSPORT_GOOD;
+		}
+
+		command[5] = 0xb0;
+
+		rc = datafab_bulk_write(us, command, 8);
+		if (rc != USB_STOR_TRANSPORT_GOOD) 
+			return rc;
+
+		rc = datafab_bulk_read(us, buf, sizeof(buf));
+		if (rc == USB_STOR_TRANSPORT_GOOD) {
+			info->lun = 1;
+			return USB_STOR_TRANSPORT_GOOD;
+		}
+
+                wait_ms(20);
+	}
+
+	return USB_STOR_TRANSPORT_FAILED;
+}
+
+static int datafab_id_device(struct us_data *us,
+			     struct datafab_info *info)
+{
+	// this is a variation of the ATA "IDENTIFY DEVICE" command...according
+	// to the ATA spec, 'Sector Count' isn't used but the Windows driver
+	// sets this bit so we do too...
+	//
+	unsigned char command[8] = { 0, 1, 0, 0, 0, 0xa0, 0xec, 1 };
+	unsigned char reply[512];
+	int rc;
+
+	if (!us || !info)
+		return USB_STOR_TRANSPORT_ERROR;
+
+	if (info->lun == -1) {
+		rc = datafab_determine_lun(us, info);
+		if (rc != USB_STOR_TRANSPORT_GOOD)
+			return rc;
+	}
+
+	command[5] += (info->lun << 4);
+
+	rc = datafab_bulk_write(us, command, 8);
+	if (rc != USB_STOR_TRANSPORT_GOOD) 
+		return rc;
+
+	// we'll go ahead and extract the media capacity while we're here...
+	//
+	rc = datafab_bulk_read(us, reply, sizeof(reply));
+	if (rc == USB_STOR_TRANSPORT_GOOD) {
+		// capacity is at word offset 57-58
+		//
+		info->sectors = ((u32)(reply[117]) << 24) | 
+				((u32)(reply[116]) << 16) |
+				((u32)(reply[115]) <<  8) | 
+				((u32)(reply[114])      );
+	}
+		
+	return rc;
+}
+
+
+static int datafab_handle_mode_sense(struct us_data *us,
+				     Scsi_Cmnd * srb, 
+		                     unsigned char *ptr,
+				     int sense_6)
+{
+	unsigned char mode_param_header[8] = {
+		0, 0, 0, 0, 0, 0, 0, 0
+	};
+	unsigned char rw_err_page[12] = {
+		0x1, 0xA, 0x21, 1, 0, 0, 0, 0, 1, 0, 0, 0
+	};
+	unsigned char cache_page[12] = {
+		0x8, 0xA, 0x1, 0, 0, 0, 0, 0, 0, 0, 0, 0
+	};
+	unsigned char rbac_page[12] = {
+		0x1B, 0xA, 0, 0x81, 0, 0, 0, 0, 0, 0, 0, 0
+	};
+	unsigned char timer_page[8] = {
+		0x1C, 0x6, 0, 0, 0, 0
+	};
+	unsigned char pc, page_code;
+	unsigned short total_len = 0;
+	unsigned short param_len, i = 0;
+
+	// most of this stuff is just a hack to get things working.  the
+	// datafab reader doesn't present a SCSI interface so we
+	// fudge the SCSI commands...
+	//
+        
+	if (sense_6)
+		param_len = srb->cmnd[4];
+	else
+		param_len = ((u16) (srb->cmnd[7]) >> 8) | ((u16) (srb->cmnd[8]));
+
+	pc = srb->cmnd[2] >> 6;
+	page_code = srb->cmnd[2] & 0x3F;
+
+	switch (pc) {
+	   case 0x0:
+		US_DEBUGP("datafab_handle_mode_sense:  Current values\n");
+		break;
+	   case 0x1:
+		US_DEBUGP("datafab_handle_mode_sense:  Changeable values\n");
+		break;
+	   case 0x2:
+		US_DEBUGP("datafab_handle_mode_sense:  Default values\n");
+		break;
+	   case 0x3:
+		US_DEBUGP("datafab_handle_mode_sense:  Saves values\n");
+		break;
+	}
+
+	mode_param_header[3] = 0x80;	// write enable
+
+	switch (page_code) {
+	   case 0x0:
+		// vendor-specific mode
+		return USB_STOR_TRANSPORT_ERROR;
+
+	   case 0x1:
+		total_len = sizeof(rw_err_page);
+		mode_param_header[0] = total_len >> 8;
+		mode_param_header[1] = total_len & 0xFF;
+		mode_param_header[3] = 0x00;	// WP enable: 0x80
+
+		memcpy(ptr, mode_param_header, sizeof(mode_param_header));
+		i += sizeof(mode_param_header);
+		memcpy(ptr + i, rw_err_page, sizeof(rw_err_page));
+		break;
+
+	   case 0x8:
+		total_len = sizeof(cache_page);
+		mode_param_header[0] = total_len >> 8;
+		mode_param_header[1] = total_len & 0xFF;
+		mode_param_header[3] = 0x00;	// WP enable: 0x80
+
+		memcpy(ptr, mode_param_header, sizeof(mode_param_header));
+		i += sizeof(mode_param_header);
+		memcpy(ptr + i, cache_page, sizeof(cache_page));
+		break;
+
+	   case 0x1B:
+		total_len = sizeof(rbac_page);
+		mode_param_header[0] = total_len >> 8;
+		mode_param_header[1] = total_len & 0xFF;
+		mode_param_header[3] = 0x00;	// WP enable: 0x80
+
+		memcpy(ptr, mode_param_header, sizeof(mode_param_header));
+		i += sizeof(mode_param_header);
+		memcpy(ptr + i, rbac_page, sizeof(rbac_page));
+		break;
+
+	   case 0x1C:
+		total_len = sizeof(timer_page);
+		mode_param_header[0] = total_len >> 8;
+		mode_param_header[1] = total_len & 0xFF;
+		mode_param_header[3] = 0x00;	// WP enable: 0x80
+
+		memcpy(ptr, mode_param_header, sizeof(mode_param_header));
+		i += sizeof(mode_param_header);
+		memcpy(ptr + i, timer_page, sizeof(timer_page));
+		break;
+
+	   case 0x3F:		// retrieve all pages
+		total_len = sizeof(timer_page) + sizeof(rbac_page) +
+		    sizeof(cache_page) + sizeof(rw_err_page);
+		mode_param_header[0] = total_len >> 8;
+		mode_param_header[1] = total_len & 0xFF;
+		mode_param_header[3] = 0x00;	// WP enable
+
+		memcpy(ptr, mode_param_header, sizeof(mode_param_header));
+		i += sizeof(mode_param_header);
+		memcpy(ptr + i, timer_page, sizeof(timer_page));
+		i += sizeof(timer_page);
+		memcpy(ptr + i, rbac_page, sizeof(rbac_page));
+		i += sizeof(rbac_page);
+		memcpy(ptr + i, cache_page, sizeof(cache_page));
+		i += sizeof(cache_page);
+		memcpy(ptr + i, rw_err_page, sizeof(rw_err_page));
+		break;
+	}
+
+	return USB_STOR_TRANSPORT_GOOD;
+}
+
+void datafab_info_destructor(void *extra)
+{
+	// this routine is a placeholder...
+	// currently, we don't allocate any extra memory so we're okay
+}
+
+
+// Transport for the Datafab MDCFE-B
+//
+int datafab_transport(Scsi_Cmnd * srb, struct us_data *us)
+{
+	struct datafab_info *info;
+	int rc;
+	unsigned long block, blocks;
+	unsigned char *ptr = NULL;
+	unsigned char inquiry_reply[36] = {
+		0x00, 0x80, 0x00, 0x01, 0x1F, 0x00, 0x00, 0x00
+	};
+
+	if (!us->extra) {
+		us->extra = kmalloc(sizeof(struct datafab_info), GFP_KERNEL);
+		if (!us->extra) {
+			US_DEBUGP("datafab_transport:  Gah! Can't allocate storage for Datafab info struct!\n");
+			return USB_STOR_TRANSPORT_ERROR;
+		}
+		memset(us->extra, 0, sizeof(struct datafab_info));
+		us->extra_destructor = datafab_info_destructor;
+  		((struct datafab_info *)us->extra)->lun = -1;
+	}
+
+	info = (struct datafab_info *) (us->extra);
+	ptr = (unsigned char *) srb->request_buffer;
+
+	if (srb->cmnd[0] == INQUIRY) {
+		US_DEBUGP("datafab_transport:  INQUIRY.  Returning bogus response");
+		memset( inquiry_reply + 8, 0, 28 );
+		fill_inquiry_response(us, inquiry_reply, 36);
+		return USB_STOR_TRANSPORT_GOOD;
+	}
+
+	if (srb->cmnd[0] == READ_CAPACITY) {
+		info->ssize = 0x200;  // hard coded 512 byte sectors as per ATA spec
+		rc = datafab_id_device(us, info);
+		if (rc != USB_STOR_TRANSPORT_GOOD)
+			return rc;
+
+		US_DEBUGP("datafab_transport:  READ_CAPACITY:  %ld sectors, %ld bytes per sector\n",
+			  info->sectors, info->ssize);
+
+		// build the reply
+		//
+		ptr[0] = (info->sectors >> 24) & 0xFF;
+		ptr[1] = (info->sectors >> 16) & 0xFF;
+		ptr[2] = (info->sectors >> 8) & 0xFF;
+		ptr[3] = (info->sectors) & 0xFF;
+
+		ptr[4] = (info->ssize >> 24) & 0xFF;
+		ptr[5] = (info->ssize >> 16) & 0xFF;
+		ptr[6] = (info->ssize >> 8) & 0xFF;
+		ptr[7] = (info->ssize) & 0xFF;
+
+		return USB_STOR_TRANSPORT_GOOD;
+	}
+
+	if (srb->cmnd[0] == MODE_SELECT_10) {
+		US_DEBUGP("datafab_transport:  Gah! MODE_SELECT_10.\n");
+		return USB_STOR_TRANSPORT_ERROR;
+	}
+
+	// don't bother implementing READ_6 or WRITE_6.  Just set MODE_XLATE and
+	// let the usb storage code convert to READ_10/WRITE_10
+	//
+	if (srb->cmnd[0] == READ_10) {
+		block = ((u32)(srb->cmnd[2]) << 24) | ((u32)(srb->cmnd[3]) << 16) |
+		        ((u32)(srb->cmnd[4]) <<  8) | ((u32)(srb->cmnd[5]));
+
+		blocks = ((u32)(srb->cmnd[7]) << 8) | ((u32)(srb->cmnd[8]));
+
+		US_DEBUGP("datafab_transport:  READ_10: read block 0x%04lx  count %ld\n", block, blocks);
+		return datafab_read_data(us, info, block, blocks, ptr, srb->use_sg);
+	}
+
+	if (srb->cmnd[0] == READ_12) {
+		// we'll probably never see a READ_12 but we'll do it anyway...
+		//
+		block = ((u32)(srb->cmnd[2]) << 24) | ((u32)(srb->cmnd[3]) << 16) |
+		        ((u32)(srb->cmnd[4]) <<  8) | ((u32)(srb->cmnd[5]));
+
+		blocks = ((u32)(srb->cmnd[6]) << 24) | ((u32)(srb->cmnd[7]) << 16) |
+		         ((u32)(srb->cmnd[8]) <<  8) | ((u32)(srb->cmnd[9]));
+
+		US_DEBUGP("datafab_transport:  READ_12: read block 0x%04lx  count %ld\n", block, blocks);
+		return datafab_read_data(us, info, block, blocks, ptr, srb->use_sg);
+	}
+
+	if (srb->cmnd[0] == WRITE_10) {
+		block = ((u32)(srb->cmnd[2]) << 24) | ((u32)(srb->cmnd[3]) << 16) |
+		        ((u32)(srb->cmnd[4]) <<  8) | ((u32)(srb->cmnd[5]));
+
+		blocks = ((u32)(srb->cmnd[7]) << 8) | ((u32)(srb->cmnd[8]));
+
+		US_DEBUGP("datafab_transport:  WRITE_10: write block 0x%04lx  count %ld\n", block, blocks);
+		return datafab_write_data(us, info, block, blocks, ptr, srb->use_sg);
+	}
+
+	if (srb->cmnd[0] == WRITE_12) {
+		// we'll probably never see a WRITE_12 but we'll do it anyway...
+		//
+		block = ((u32)(srb->cmnd[2]) << 24) | ((u32)(srb->cmnd[3]) << 16) |
+		        ((u32)(srb->cmnd[4]) <<  8) | ((u32)(srb->cmnd[5]));
+
+		blocks = ((u32)(srb->cmnd[6]) << 24) | ((u32)(srb->cmnd[7]) << 16) |
+		         ((u32)(srb->cmnd[8]) <<  8) | ((u32)(srb->cmnd[9]));
+
+		US_DEBUGP("datafab_transport:  WRITE_12: write block 0x%04lx  count %ld\n", block, blocks);
+		return datafab_write_data(us, info, block, blocks, ptr, srb->use_sg);
+	}
+
+	if (srb->cmnd[0] == TEST_UNIT_READY) {
+		US_DEBUGP("datafab_transport:  TEST_UNIT_READY.\n");
+		return datafab_id_device(us, info);
+	}
+
+	if (srb->cmnd[0] == REQUEST_SENSE) {
+		US_DEBUGP("datafab_transport:  REQUEST_SENSE.  Returning faked response\n");
+
+		// this response is pretty bogus right now.  eventually if necessary
+		// we can set the correct sense data.  so far though it hasn't been
+		// necessary
+		//
+		ptr[0] = 0xF0;
+		ptr[2] = info->sense_key;
+		ptr[7] = 11;
+		ptr[12] = info->sense_asc;
+		ptr[13] = info->sense_ascq;
+
+		return USB_STOR_TRANSPORT_GOOD;
+	}
+
+	if (srb->cmnd[0] == MODE_SENSE) {
+		US_DEBUGP("datafab_transport:  MODE_SENSE_6 detected\n");
+		return datafab_handle_mode_sense(us, srb, ptr, TRUE);
+	}
+
+	if (srb->cmnd[0] == MODE_SENSE_10) {
+		US_DEBUGP("datafab_transport:  MODE_SENSE_10 detected\n");
+		return datafab_handle_mode_sense(us, srb, ptr, FALSE);
+	}
+
+	if (srb->cmnd[0] == ALLOW_MEDIUM_REMOVAL) {
+		// sure.  whatever.  not like we can stop the user from
+		// popping the media out of the device (no locking doors, etc)
+		//
+		return USB_STOR_TRANSPORT_GOOD;
+	}
+
+	US_DEBUGP("datafab_transport:  Gah! Unknown command: %d (0x%x)\n", srb->cmnd[0], srb->cmnd[0]);
+	return USB_STOR_TRANSPORT_ERROR;
+}
diff -u --recursive --new-file v2.4.7/linux/drivers/usb/storage/datafab.h linux/drivers/usb/storage/datafab.h
--- v2.4.7/linux/drivers/usb/storage/datafab.h	Wed Dec 31 16:00:00 1969
+++ linux/drivers/usb/storage/datafab.h	Sun Jul 29 21:11:50 2001
@@ -0,0 +1,42 @@
+/* Driver for Datafab MDCFE-B USB Compact Flash reader
+ * Header File
+ *
+ * Current development and maintenance by:
+ *   (c) 2000 Jimmie Mayfield (mayfield+datafab@sackheads.org)
+ *
+ * See datafab.c for more explanation
+ *
+ * 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, 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.
+ */
+
+#ifndef _USB_DATAFAB_MDCFE_B_H
+#define _USB_DATAFAB_MDCFE_B_H
+
+#define min(a,b) (((a)<(b))?(a):(b))  // this is defined in tons of header files, i wish it had a standard single definition...
+
+extern int datafab_transport(Scsi_Cmnd *srb, struct us_data *us);
+
+struct datafab_info {
+	unsigned long   sectors;     // total sector count
+	unsigned long   ssize;       // sector size in bytes
+	char            lun;         // used for dual-slot readers
+        
+        // the following aren't used yet
+	unsigned char   sense_key;
+	unsigned long   sense_asc;   // additional sense code
+	unsigned long   sense_ascq;  // additional sense code qualifier
+};
+
+#endif
diff -u --recursive --new-file v2.4.7/linux/drivers/usb/storage/debug.c linux/drivers/usb/storage/debug.c
--- v2.4.7/linux/drivers/usb/storage/debug.c	Tue Jul  3 17:08:21 2001
+++ linux/drivers/usb/storage/debug.c	Sun Jul 29 21:11:50 2001
@@ -1,7 +1,7 @@
 /* Driver for USB Mass Storage compliant devices
  * Debugging Functions Source Code File
  *
- * $Id: debug.c,v 1.4 2000/09/04 02:12:47 groovyjava Exp $
+ * $Id: debug.c,v 1.5 2001/06/27 23:20:45 mdharm Exp $
  *
  * Current development and maintenance by:
  *   (c) 1999, 2000 Matthew Dharm (mdharm-usb@one-eyed-alien.net)
@@ -302,12 +302,10 @@
 	case 0x1C00: what="defect list not found"; break;
 	case 0x2400: what="invalid field in CDB"; break;
 	case 0x2703: what="associated write protect"; break;
-	case 0x2800: what="not ready to ready transition (media change?)";
-		break;
+	case 0x2800: what="not ready to ready transition"; break;
 	case 0x2903: what="bus device reset function occurred"; break;
 	case 0x2904: what="device internal reset"; break;
-	case 0x2B00: what="copy can't execute since host can't disconnect"; 
-									break;
+	case 0x2B00: what="copy can't execute / host can't disconnect"; break;
 	case 0x2C00: what="command sequence error"; break;
 	case 0x2C03: what="current program area is not empty"; break;
 	case 0x2C04: what="current program area is empty"; break;
diff -u --recursive --new-file v2.4.7/linux/drivers/usb/storage/dpcm.c linux/drivers/usb/storage/dpcm.c
--- v2.4.7/linux/drivers/usb/storage/dpcm.c	Sat Apr 28 11:28:08 2001
+++ linux/drivers/usb/storage/dpcm.c	Sun Jul 29 21:11:50 2001
@@ -1,6 +1,6 @@
 /* Driver for Microtech DPCM-USB CompactFlash/SmartMedia reader
  *
- * $Id: dpcm.c,v 1.3 2000/08/25 00:13:51 mdharm Exp $
+ * $Id: dpcm.c,v 1.4 2001/06/11 02:54:25 mdharm Exp $
  *
  * DPCM driver v0.1:
  *
diff -u --recursive --new-file v2.4.7/linux/drivers/usb/storage/freecom.c linux/drivers/usb/storage/freecom.c
--- v2.4.7/linux/drivers/usb/storage/freecom.c	Wed Jul 25 17:10:24 2001
+++ linux/drivers/usb/storage/freecom.c	Sun Jul 29 21:11:50 2001
@@ -1,6 +1,6 @@
 /* Driver for Freecom USB/IDE adaptor
  *
- * $Id: freecom.c,v 1.14 2000/11/13 22:27:57 mdharm Exp $
+ * $Id: freecom.c,v 1.15 2001/06/27 23:50:28 mdharm Exp $
  *
  * Freecom v0.1:
  *
diff -u --recursive --new-file v2.4.7/linux/drivers/usb/storage/isd200.c linux/drivers/usb/storage/isd200.c
--- v2.4.7/linux/drivers/usb/storage/isd200.c	Wed Dec 31 16:00:00 1969
+++ linux/drivers/usb/storage/isd200.c	Sun Jul 29 21:11:50 2001
@@ -0,0 +1,1747 @@
+/* Transport & Protocol Driver for In-System Design, Inc. ISD200 ASIC
+ *
+ * First release
+ *
+ * Current development and maintenance by:
+ *   (c) 2000 In-System Design, Inc. (support@in-system.com)
+ *
+ * The ISD200 ASIC does not natively support ATA devices.  The chip
+ * does implement an interface, the ATA Command Block (ATACB) which provides
+ * a means of passing ATA commands and ATA register accesses to a device.
+ *
+ * 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, 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.
+ *
+ * History:
+ *
+ *  2001-02-24: Removed lots of duplicate code and simplified the structure.
+ *              (bjorn@haxx.se)
+ */
+
+
+/* Include files */
+
+#include "transport.h"
+#include "protocol.h"
+#include "usb.h"
+#include "debug.h"
+#include "scsiglue.h"
+#include "isd200.h"
+
+#include <linux/sched.h>
+#include <linux/errno.h>
+#include <linux/malloc.h>
+#include <linux/hdreg.h>
+#include <linux/ide.h>
+
+/*
+ * Inquiry defines. Used to interpret data returned from target as result
+ * of inquiry command.
+ *
+ * DeviceType field
+ */
+
+#define DIRECT_ACCESS_DEVICE            0x00    /* disks */
+
+/* Timeout defines (in Seconds) */
+
+#define ISD200_ENUM_BSY_TIMEOUT         35
+#define ISD200_ENUM_DETECT_TIMEOUT      30
+#define ISD200_DEFAULT_TIMEOUT          30
+
+/* device flags */
+#define DF_ATA_DEVICE               0x0001
+#define DF_MEDIA_STATUS_ENABLED     0x0002
+#define DF_REMOVABLE_MEDIA          0x0004
+
+/* capability bit definitions */
+#define CAPABILITY_DMA		0x01
+#define CAPABILITY_LBA		0x02
+
+/* command_setX bit definitions */
+#define COMMANDSET_REMOVABLE	0x02
+#define COMMANDSET_MEDIA_STATUS 0x10
+
+/* ATA Vendor Specific defines */
+#define ATA_ADDRESS_DEVHEAD_STD      0xa0
+#define ATA_ADDRESS_DEVHEAD_LBA_MODE 0x40    
+#define ATA_ADDRESS_DEVHEAD_SLAVE    0x10
+
+/* Action Select bits */
+#define ACTION_SELECT_0             0x01
+#define ACTION_SELECT_1             0x02
+#define ACTION_SELECT_2             0x04
+#define ACTION_SELECT_3             0x08
+#define ACTION_SELECT_4             0x10
+#define ACTION_SELECT_5             0x20
+#define ACTION_SELECT_6             0x40
+#define ACTION_SELECT_7             0x80
+
+/* ATA error definitions not in <linux/hdreg.h> */
+#define ATA_ERROR_MEDIA_CHANGE       0x20
+
+/* ATA command definitions not in <linux/hdreg.h> */
+#define ATA_COMMAND_GET_MEDIA_STATUS        0xDA
+#define ATA_COMMAND_MEDIA_EJECT             0xED
+
+/* ATA drive control definitions */
+#define ATA_DC_DISABLE_INTERRUPTS    0x02
+#define ATA_DC_RESET_CONTROLLER      0x04
+#define ATA_DC_REENABLE_CONTROLLER   0x00
+
+/*
+ *  General purpose return codes
+ */ 
+
+#define ISD200_ERROR                -1
+#define ISD200_GOOD                 0
+
+/*
+ * Transport return codes
+ */
+
+#define ISD200_TRANSPORT_GOOD       0   /* Transport good, command good     */
+#define ISD200_TRANSPORT_FAILED     1   /* Transport good, command failed   */
+#define ISD200_TRANSPORT_ERROR      2   /* Transport bad (i.e. device dead) */
+#define ISD200_TRANSPORT_ABORTED    3   /* Transport aborted                */
+#define ISD200_TRANSPORT_SHORT      4   /* Transport short                  */
+
+/* driver action codes */
+#define	ACTION_READ_STATUS	0
+#define	ACTION_RESET		1
+#define	ACTION_REENABLE		2
+#define	ACTION_SOFT_RESET	3
+#define	ACTION_ENUM		4
+#define	ACTION_IDENTIFY		5
+
+
+/*
+ * ata_cdb struct
+ */
+
+
+union ata_cdb {
+	struct {
+		unsigned char SignatureByte0;
+		unsigned char SignatureByte1;
+		unsigned char ActionSelect;
+		unsigned char RegisterSelect;
+		unsigned char TransferBlockSize;
+		unsigned char WriteData3F6;
+		unsigned char WriteData1F1;
+		unsigned char WriteData1F2;
+		unsigned char WriteData1F3;
+		unsigned char WriteData1F4;
+		unsigned char WriteData1F5;
+		unsigned char WriteData1F6;
+		unsigned char WriteData1F7;
+		unsigned char Reserved[3];
+	} generic;
+        
+	struct {
+		unsigned char SignatureByte0;
+		unsigned char SignatureByte1;
+		unsigned char ReadRegisterAccessBit : 1;
+		unsigned char NoDeviceSelectionBit : 1;
+		unsigned char NoBSYPollBit : 1;
+		unsigned char IgnorePhaseErrorBit : 1;
+		unsigned char IgnoreDeviceErrorBit : 1;
+		unsigned char Reserved0Bit : 3;
+		unsigned char SelectAlternateStatus : 1;
+		unsigned char SelectError : 1;
+		unsigned char SelectSectorCount : 1;
+		unsigned char SelectSectorNumber : 1;
+		unsigned char SelectCylinderLow : 1;
+		unsigned char SelectCylinderHigh : 1;
+		unsigned char SelectDeviceHead : 1;
+		unsigned char SelectStatus : 1;
+		unsigned char TransferBlockSize;
+		unsigned char AlternateStatusByte;
+		unsigned char ErrorByte;
+		unsigned char SectorCountByte;
+		unsigned char SectorNumberByte;
+		unsigned char CylinderLowByte;
+		unsigned char CylinderHighByte;
+		unsigned char DeviceHeadByte;
+		unsigned char StatusByte;
+		unsigned char Reserved[3];
+	} read;
+
+        struct {
+		unsigned char SignatureByte0;
+		unsigned char SignatureByte1;
+		unsigned char ReadRegisterAccessBit : 1;
+		unsigned char NoDeviceSelectionBit : 1;
+		unsigned char NoBSYPollBit : 1;
+		unsigned char IgnorePhaseErrorBit : 1;
+		unsigned char IgnoreDeviceErrorBit : 1;
+		unsigned char Reserved0Bit : 3;
+		unsigned char SelectDeviceControl : 1;
+		unsigned char SelectFeatures : 1;
+		unsigned char SelectSectorCount : 1;
+		unsigned char SelectSectorNumber : 1;
+		unsigned char SelectCylinderLow : 1;
+		unsigned char SelectCylinderHigh : 1;
+		unsigned char SelectDeviceHead : 1;
+		unsigned char SelectCommand : 1;
+		unsigned char TransferBlockSize;
+		unsigned char DeviceControlByte;
+		unsigned char FeaturesByte;
+		unsigned char SectorCountByte;
+		unsigned char SectorNumberByte;
+		unsigned char CylinderLowByte;
+		unsigned char CylinderHighByte;
+		unsigned char DeviceHeadByte;
+		unsigned char CommandByte;
+		unsigned char Reserved[3];
+	} write;
+};
+
+
+/*
+ * Inquiry data structure. This is the data returned from the target
+ * after it receives an inquiry.
+ *
+ * This structure may be extended by the number of bytes specified
+ * in the field AdditionalLength. The defined size constant only
+ * includes fields through ProductRevisionLevel.
+ */
+
+struct inquiry_data {
+	unsigned char DeviceType : 5;
+	unsigned char DeviceTypeQualifier : 3;
+	unsigned char DeviceTypeModifier : 7;
+	unsigned char RemovableMedia : 1;
+	unsigned char Versions;
+	unsigned char ResponseDataFormat : 4;
+	unsigned char HiSupport : 1;
+	unsigned char NormACA : 1;
+	unsigned char ReservedBit : 1;
+	unsigned char AERC : 1;
+	unsigned char AdditionalLength;
+	unsigned char Reserved[2];
+	unsigned char SoftReset : 1;
+	unsigned char CommandQueue : 1;
+	unsigned char Reserved2 : 1;
+	unsigned char LinkedCommands : 1;
+	unsigned char Synchronous : 1;
+	unsigned char Wide16Bit : 1;
+	unsigned char Wide32Bit : 1;
+	unsigned char RelativeAddressing : 1;
+	unsigned char VendorId[8];
+	unsigned char ProductId[16];
+	unsigned char ProductRevisionLevel[4];
+	unsigned char VendorSpecific[20];
+	unsigned char Reserved3[40];
+} __attribute__ ((packed));
+
+/*
+ * INQUIRY data buffer size
+ */
+
+#define INQUIRYDATABUFFERSIZE 36
+
+
+/*
+ * ISD200 CONFIG data struct
+ */
+
+struct isd200_config {
+        unsigned char EventNotification;
+        unsigned char ExternalClock;
+        unsigned char ATAInitTimeout;
+        unsigned char ATATiming : 4;
+        unsigned char ATAPIReset : 1;
+        unsigned char MasterSlaveSelection : 1;
+        unsigned char ATAPICommandBlockSize : 2;
+        unsigned char ATAMajorCommand;
+        unsigned char ATAMinorCommand;
+        unsigned char LastLUNIdentifier : 3;
+        unsigned char DescriptOverride : 1;
+        unsigned char ATA3StateSuspend : 1;
+        unsigned char SkipDeviceBoot : 1;
+        unsigned char ConfigDescriptor2 : 1;
+        unsigned char InitStatus : 1;
+        unsigned char SRSTEnable : 1;
+        unsigned char Reserved0 : 7;
+};
+
+
+/*
+ * ISD200 driver information struct
+ */
+
+struct isd200_info {
+	struct inquiry_data InquiryData;
+	struct hd_driveid drive;
+	struct isd200_config ConfigData;
+	unsigned char ATARegs[8];
+	unsigned char DeviceHead;
+	unsigned char DeviceFlags;
+
+	/* maximum number of LUNs supported */
+	unsigned char MaxLUNs;
+};
+
+
+/*
+ * Read Capacity Data - returned in Big Endian format
+ */
+
+struct read_capacity_data {
+	unsigned long LogicalBlockAddress;
+	unsigned long BytesPerBlock;
+};
+
+/*
+ * Read Block Limits Data - returned in Big Endian format
+ * This structure returns the maximum and minimum block
+ * size for a TAPE device.
+ */
+
+struct read_block_limits {
+	unsigned char Reserved;
+	unsigned char BlockMaximumSize[3];
+	unsigned char BlockMinimumSize[2];
+};
+
+
+/*
+ * Sense Data Format
+ */
+
+struct sense_data {
+        unsigned char ErrorCode:7;
+        unsigned char Valid:1;
+        unsigned char SegmentNumber;
+        unsigned char SenseKey:4;
+        unsigned char Reserved:1;
+        unsigned char IncorrectLength:1;
+        unsigned char EndOfMedia:1;
+        unsigned char FileMark:1;
+        unsigned char Information[4];
+        unsigned char AdditionalSenseLength;
+        unsigned char CommandSpecificInformation[4];
+        unsigned char AdditionalSenseCode;
+        unsigned char AdditionalSenseCodeQualifier;
+        unsigned char FieldReplaceableUnitCode;
+        unsigned char SenseKeySpecific[3];
+} __attribute__ ((packed));
+
+/*
+ * Default request sense buffer size
+ */
+
+#define SENSE_BUFFER_SIZE 18
+
+/***********************************************************************
+ * Helper routines
+ ***********************************************************************/
+
+
+/**************************************************************************
+ * isd200_build_sense
+ *                                                                         
+ *  Builds an artificial sense buffer to report the results of a 
+ *  failed command.
+ *                                                                       
+ * RETURNS:
+ *    void
+ */                                                                        
+void isd200_build_sense(struct us_data *us, Scsi_Cmnd *srb)
+{
+        struct isd200_info *info = (struct isd200_info *)us->extra;
+        struct sense_data *buf = (struct sense_data *) &srb->sense_buffer[0];
+        unsigned char error = info->ATARegs[IDE_ERROR_OFFSET];
+
+	if(error & ATA_ERROR_MEDIA_CHANGE) {
+		buf->ErrorCode = 0x70;
+		buf->Valid     = 1;
+		buf->AdditionalSenseLength = 0xb;
+		buf->SenseKey =  UNIT_ATTENTION;
+		buf->AdditionalSenseCode = 0;
+		buf->AdditionalSenseCodeQualifier = 0;
+        } else if(error & MCR_ERR) {
+		buf->ErrorCode = 0x70;
+		buf->Valid     = 1;
+		buf->AdditionalSenseLength = 0xb;
+		buf->SenseKey =  UNIT_ATTENTION;
+		buf->AdditionalSenseCode = 0;
+		buf->AdditionalSenseCodeQualifier = 0;
+        } else if(error & TRK0_ERR) {
+		buf->ErrorCode = 0x70;
+		buf->Valid     = 1;
+		buf->AdditionalSenseLength = 0xb;
+		buf->SenseKey =  NOT_READY;
+		buf->AdditionalSenseCode = 0;
+		buf->AdditionalSenseCodeQualifier = 0;
+        } else if(error & ECC_ERR) {
+		buf->ErrorCode = 0x70;
+		buf->Valid     = 1;
+		buf->AdditionalSenseLength = 0xb;
+		buf->SenseKey =  DATA_PROTECT;
+		buf->AdditionalSenseCode = 0;
+		buf->AdditionalSenseCodeQualifier = 0;
+        } else {
+		buf->ErrorCode = 0;
+		buf->Valid     = 0;
+		buf->AdditionalSenseLength = 0;
+		buf->SenseKey =  0;
+		buf->AdditionalSenseCode = 0;
+		buf->AdditionalSenseCodeQualifier = 0;
+        }
+}
+
+/***********************************************************************
+ * Data transfer routines
+ ***********************************************************************/
+
+
+/**************************************************************************
+ * Transfer one SCSI scatter-gather buffer via bulk transfer
+ *
+ * Note that this function is necessary because we want the ability to
+ * use scatter-gather memory.  Good performance is achieved by a combination
+ * of scatter-gather and clustering (which makes each chunk bigger).
+ *
+ * Note that the lower layer will always retry when a NAK occurs, up to the
+ * timeout limit.  Thus we don't have to worry about it for individual
+ * packets.
+ */
+static int isd200_transfer_partial( struct us_data *us, 
+				    unsigned char dataDirection,
+				    char *buf, int length )
+{
+        int result;
+        int partial;
+        int pipe;
+
+        /* calculate the appropriate pipe information */
+	if (dataDirection == SCSI_DATA_READ)
+                pipe = usb_rcvbulkpipe(us->pusb_dev, us->ep_in);
+        else
+                pipe = usb_sndbulkpipe(us->pusb_dev, us->ep_out);
+
+        /* transfer the data */
+        US_DEBUGP("isd200_transfer_partial(): xfer %d bytes\n", length);
+        result = usb_stor_bulk_msg(us, buf, pipe, length, &partial);
+        US_DEBUGP("usb_stor_bulk_msg() returned %d xferred %d/%d\n",
+                  result, partial, length);
+
+        /* if we stall, we need to clear it before we go on */
+        if (result == -EPIPE) {
+                US_DEBUGP("clearing endpoint halt for pipe 0x%x\n", pipe);
+                usb_stor_clear_halt(us->pusb_dev, pipe);
+        }
+    
+        /* did we send all the data? */
+        if (partial == length) {
+                US_DEBUGP("isd200_transfer_partial(): transfer complete\n");
+                return ISD200_TRANSPORT_GOOD;
+        }
+
+        /* uh oh... we have an error code, so something went wrong. */
+        if (result) {
+                /* NAK - that means we've retried a few times already */
+                if (result == -ETIMEDOUT) {
+                        US_DEBUGP("isd200_transfer_partial(): device NAKed\n");
+                        return ISD200_TRANSPORT_FAILED;
+                }
+
+                /* -ENOENT -- we canceled this transfer */
+                if (result == -ENOENT) {
+                        US_DEBUGP("isd200_transfer_partial(): transfer aborted\n");
+                        return ISD200_TRANSPORT_ABORTED;
+                }
+
+                /* the catch-all case */
+                US_DEBUGP("isd200_transfer_partial(): unknown error\n");
+                return ISD200_TRANSPORT_FAILED;
+        }
+
+        /* no error code, so we must have transferred some data, 
+         * just not all of it */
+        return ISD200_TRANSPORT_SHORT;
+}
+
+
+/**************************************************************************
+ * Transfer an entire SCSI command's worth of data payload over the bulk
+ * pipe.
+ *
+ * Note that this uses us_transfer_partial to achieve it's goals -- this
+ * function simply determines if we're going to use scatter-gather or not,
+ * and acts appropriately.  For now, it also re-interprets the error codes.
+ */
+static void isd200_transfer( struct us_data *us, Scsi_Cmnd *srb )
+{
+        int i;
+        int result = -1;
+        struct scatterlist *sg;
+        unsigned int total_transferred = 0;
+        unsigned int transfer_amount;
+
+        /* calculate how much we want to transfer */
+	int dir = srb->sc_data_direction;
+	srb->sc_data_direction = SCSI_DATA_WRITE;
+        transfer_amount = usb_stor_transfer_length(srb);
+	srb->sc_data_direction = dir;
+
+        /* was someone foolish enough to request more data than available
+         * buffer space? */
+        if (transfer_amount > srb->request_bufflen)
+                transfer_amount = srb->request_bufflen;
+
+        /* are we scatter-gathering? */
+        if (srb->use_sg) {
+
+                /* loop over all the scatter gather structures and 
+                 * make the appropriate requests for each, until done
+                 */
+                sg = (struct scatterlist *) srb->request_buffer;
+                for (i = 0; i < srb->use_sg; i++) {
+
+                        /* transfer the lesser of the next buffer or the
+                         * remaining data */
+                        if (transfer_amount - total_transferred >= 
+                            sg[i].length) {
+                                result = isd200_transfer_partial(us, 
+                                                                 srb->sc_data_direction,
+                                                                 sg[i].address, 
+                                                                 sg[i].length);
+                                total_transferred += sg[i].length;
+                        } else
+                                result = isd200_transfer_partial(us, 
+                                                                 srb->sc_data_direction,                            
+                                                                 sg[i].address,
+                                                                 transfer_amount - total_transferred);
+
+                        /* if we get an error, end the loop here */
+                        if (result)
+                                break;
+                }
+        }
+        else
+                /* no scatter-gather, just make the request */
+                result = isd200_transfer_partial(us, 
+                                                 srb->sc_data_direction,
+                                                 srb->request_buffer, 
+                                                 transfer_amount);
+
+        /* return the result in the data structure itself */
+        srb->result = result;
+}
+
+
+/***********************************************************************
+ * Transport routines
+ ***********************************************************************/
+
+
+/**************************************************************************
+ *  ISD200 Bulk Transport
+ *
+ * Note:  This routine was copied from the usb_stor_Bulk_transport routine
+ * located in the transport.c source file.  The scsi command is limited to
+ * only 12 bytes while the CDB for the ISD200 must be 16 bytes.
+ */
+int isd200_Bulk_transport( struct us_data *us, Scsi_Cmnd *srb, 
+                           union ata_cdb *AtaCdb, unsigned char AtaCdbLength )
+{
+        struct bulk_cb_wrap bcb;
+        struct bulk_cs_wrap bcs;
+        int result;
+        int pipe;
+        int partial;
+        unsigned int transfer_amount;
+
+	int dir = srb->sc_data_direction;
+	srb->sc_data_direction = SCSI_DATA_WRITE;
+        transfer_amount = usb_stor_transfer_length(srb);
+	srb->sc_data_direction = dir;
+    
+        /* set up the command wrapper */
+        bcb.Signature = cpu_to_le32(US_BULK_CB_SIGN);
+        bcb.DataTransferLength = cpu_to_le32(transfer_amount);
+        bcb.Flags = srb->sc_data_direction == SCSI_DATA_READ ? 1 << 7 : 0;
+        bcb.Tag = srb->serial_number;
+        bcb.Lun = srb->cmnd[1] >> 5;
+        if (us->flags & US_FL_SCM_MULT_TARG)
+                bcb.Lun |= srb->target << 4;
+
+        bcb.Length = AtaCdbLength;
+    
+        /* construct the pipe handle */
+        pipe = usb_sndbulkpipe(us->pusb_dev, us->ep_out);
+    
+        /* copy the command payload */
+        memset(bcb.CDB, 0, sizeof(bcb.CDB));
+        memcpy(bcb.CDB, AtaCdb, bcb.Length);
+    
+        /* send it to out endpoint */
+        US_DEBUGP("Bulk command S 0x%x T 0x%x Trg %d LUN %d L %d F %d CL %d\n",
+                  le32_to_cpu(bcb.Signature), bcb.Tag,
+                  (bcb.Lun >> 4), (bcb.Lun & 0xFF), 
+                  bcb.DataTransferLength, bcb.Flags, bcb.Length);
+        result = usb_stor_bulk_msg(us, &bcb, pipe, US_BULK_CB_WRAP_LEN, 
+				   &partial);
+        US_DEBUGP("Bulk command transfer result=%d\n", result);
+    
+	if (result == -ENOENT)
+		return ISD200_TRANSPORT_ABORTED;
+	else if (result == -EPIPE) {
+		/* if we stall, we need to clear it before we go on */
+                US_DEBUGP("clearing endpoint halt for pipe 0x%x\n", pipe);
+                usb_stor_clear_halt(us->pusb_dev, pipe);
+	} else if (result)  
+                return ISD200_TRANSPORT_ERROR;
+    
+        /* if the command transfered well, then we go to the data stage */
+        if (!result && bcb.DataTransferLength) {
+		isd200_transfer(us, srb);
+		US_DEBUGP("Bulk data transfer result 0x%x\n", srb->result);
+		
+		if (srb->result == ISD200_TRANSPORT_ABORTED)
+			return ISD200_TRANSPORT_ABORTED;
+        }
+    
+        /* See flow chart on pg 15 of the Bulk Only Transport spec for
+         * an explanation of how this code works.
+         */
+    
+        /* construct the pipe handle */
+        pipe = usb_rcvbulkpipe(us->pusb_dev, us->ep_in);
+    
+        /* get CSW for device status */
+        US_DEBUGP("Attempting to get CSW...\n");
+        result = usb_stor_bulk_msg(us, &bcs, pipe, US_BULK_CS_WRAP_LEN, 
+				   &partial);
+        if (result == -ENOENT)
+                return ISD200_TRANSPORT_ABORTED;
+
+        /* did the attempt to read the CSW fail? */
+        if (result == -EPIPE) {
+                US_DEBUGP("clearing endpoint halt for pipe 0x%x\n", pipe);
+                usb_stor_clear_halt(us->pusb_dev, pipe);
+           
+                /* get the status again */
+                US_DEBUGP("Attempting to get CSW (2nd try)...\n");
+                result = usb_stor_bulk_msg(us, &bcs, pipe,
+                                           US_BULK_CS_WRAP_LEN, &partial);
+
+                /* if the command was aborted, indicate that */
+                if (result == -ENOENT)
+                        return ISD200_TRANSPORT_ABORTED;
+        
+                /* if it fails again, we need a reset and return an error*/
+                if (result == -EPIPE) {
+                        US_DEBUGP("clearing halt for pipe 0x%x\n", pipe);
+                        usb_stor_clear_halt(us->pusb_dev, pipe);
+                        return ISD200_TRANSPORT_ERROR;
+                }
+        }
+    
+        /* if we still have a failure at this point, we're in trouble */
+        US_DEBUGP("Bulk status result = %d\n", result);
+        if (result)
+                return ISD200_TRANSPORT_ERROR;
+    
+        /* check bulk status */
+        US_DEBUGP("Bulk status Sig 0x%x T 0x%x R %d Stat 0x%x\n",
+                  le32_to_cpu(bcs.Signature), bcs.Tag, 
+                  bcs.Residue, bcs.Status);
+        if (bcs.Signature != cpu_to_le32(US_BULK_CS_SIGN) || 
+            bcs.Tag != bcb.Tag || 
+            bcs.Status > US_BULK_STAT_PHASE || partial != 13) {
+                US_DEBUGP("Bulk logical error\n");
+                return ISD200_TRANSPORT_ERROR;
+        }
+    
+        /* based on the status code, we report good or bad */
+        switch (bcs.Status) {
+        case US_BULK_STAT_OK:
+                /* command good -- note that we could be short on data */
+                return ISD200_TRANSPORT_GOOD;
+
+        case US_BULK_STAT_FAIL:
+                /* command failed */
+                return ISD200_TRANSPORT_FAILED;
+        
+        case US_BULK_STAT_PHASE:
+                /* phase error */
+                usb_stor_Bulk_reset(us);
+                return ISD200_TRANSPORT_ERROR;
+        }
+    
+        /* we should never get here, but if we do, we're in trouble */
+        return ISD200_TRANSPORT_ERROR;
+}
+
+
+/**************************************************************************
+ *  isd200_action
+ *
+ * Routine for sending commands to the isd200
+ *
+ * RETURNS:
+ *    ISD status code
+ */
+static int isd200_action( struct us_data *us, int action, 
+			  void* pointer, int value )
+{
+	union ata_cdb ata;
+	struct scsi_cmnd srb;
+	struct isd200_info *info = (struct isd200_info *)us->extra;
+	int status;
+
+	memset(&ata, 0, sizeof(ata));
+	memset(&srb, 0, sizeof(srb));
+
+	ata.generic.SignatureByte0 = info->ConfigData.ATAMajorCommand;
+	ata.generic.SignatureByte1 = info->ConfigData.ATAMinorCommand;
+	ata.generic.TransferBlockSize = 1;
+
+	switch ( action ) {
+	case ACTION_READ_STATUS:
+		US_DEBUGP("   isd200_action(READ_STATUS)\n");
+		ata.generic.ActionSelect = ACTION_SELECT_0|ACTION_SELECT_2;
+		ata.read.SelectStatus = 1;
+		ata.read.SelectError = 1;
+		ata.read.SelectCylinderHigh = 1;
+		ata.read.SelectCylinderLow = 1;
+		srb.sc_data_direction = SCSI_DATA_READ;
+		srb.request_buffer = pointer;
+		srb.request_bufflen = value;
+		break;
+
+	case ACTION_ENUM:
+		US_DEBUGP("   isd200_action(ENUM,0x%02x)\n",value);
+		ata.generic.ActionSelect = ACTION_SELECT_1|ACTION_SELECT_2|
+			                   ACTION_SELECT_3|ACTION_SELECT_4|
+		                           ACTION_SELECT_5;
+		ata.write.SelectDeviceHead = 1;
+		ata.write.DeviceHeadByte = value;
+		srb.sc_data_direction = SCSI_DATA_NONE;
+		break;
+
+	case ACTION_RESET:
+		US_DEBUGP("   isd200_action(RESET)\n");
+		ata.generic.ActionSelect = ACTION_SELECT_1|ACTION_SELECT_2|
+			                   ACTION_SELECT_3|ACTION_SELECT_4;
+		ata.write.SelectDeviceControl = 1;
+		ata.write.DeviceControlByte = ATA_DC_RESET_CONTROLLER;
+		srb.sc_data_direction = SCSI_DATA_NONE;
+		break;
+
+	case ACTION_REENABLE:
+		US_DEBUGP("   isd200_action(REENABLE)\n");
+		ata.generic.ActionSelect = ACTION_SELECT_1|ACTION_SELECT_2|
+			                   ACTION_SELECT_3|ACTION_SELECT_4;
+		ata.write.SelectDeviceControl = 1;
+		ata.write.DeviceControlByte = ATA_DC_REENABLE_CONTROLLER;
+		srb.sc_data_direction = SCSI_DATA_NONE;
+		break;
+
+	case ACTION_SOFT_RESET:
+		US_DEBUGP("   isd200_action(SOFT_RESET)\n");
+		ata.generic.ActionSelect = ACTION_SELECT_1|ACTION_SELECT_5;
+		ata.write.SelectDeviceHead = 1;
+		ata.write.DeviceHeadByte = info->DeviceHead;
+		ata.write.SelectCommand = 1;
+		ata.write.CommandByte = WIN_SRST;
+		srb.sc_data_direction = SCSI_DATA_NONE;
+		break;
+
+	case ACTION_IDENTIFY:
+		US_DEBUGP("   isd200_action(IDENTIFY)\n");
+		ata.write.SelectCommand = 1;
+		ata.write.CommandByte = WIN_IDENTIFY;
+		srb.sc_data_direction = SCSI_DATA_READ;
+		srb.request_buffer = (void *)&info->drive;
+		srb.request_bufflen = sizeof(struct hd_driveid);
+		break;
+
+	default:
+		US_DEBUGP("Error: Undefined action %d\n",action);
+		break;
+	}
+
+	status = isd200_Bulk_transport(us, &srb, &ata, sizeof(ata.generic));
+	if (status != ISD200_TRANSPORT_GOOD) {
+		US_DEBUGP("   isd200_action(0x%02x) error: %d\n",action,status);
+		status = ISD200_ERROR;
+		/* need to reset device here */
+	}
+
+	return status;
+}
+
+/**************************************************************************
+ * isd200_read_regs
+ *                                                                         
+ * Read ATA Registers
+ *
+ * RETURNS:
+ *    ISD status code
+ */                                                                        
+int isd200_read_regs( struct us_data *us )
+{
+	struct isd200_info *info = (struct isd200_info *)us->extra;
+	int retStatus = ISD200_GOOD;
+	int transferStatus;
+
+	US_DEBUGP("Entering isd200_IssueATAReadRegs\n");
+
+	transferStatus = isd200_action( us, ACTION_READ_STATUS,
+				    info->ATARegs, sizeof(info->ATARegs) );
+	if (transferStatus != ISD200_TRANSPORT_GOOD) {
+		US_DEBUGP("   Error reading ATA registers\n");
+		retStatus = ISD200_ERROR;
+        } else {
+		US_DEBUGP("   Got ATA Register[IDE_ERROR_OFFSET] = 0x%x\n", 
+			  info->ATARegs[IDE_ERROR_OFFSET]);
+        }
+
+	return retStatus;
+}
+
+
+/**************************************************************************
+ * Invoke the transport and basic error-handling/recovery methods
+ *
+ * This is used by the protocol layers to actually send the message to
+ * the device and recieve the response.
+ */
+void isd200_invoke_transport( struct us_data *us, 
+			      Scsi_Cmnd *srb, 
+			      union ata_cdb *ataCdb )
+{
+	int need_auto_sense = 0;
+	int transferStatus;
+
+	/* send the command to the transport layer */
+	transferStatus = isd200_Bulk_transport(us, srb, ataCdb,
+					       sizeof(ataCdb->generic));
+	switch (transferStatus) {
+
+	case ISD200_TRANSPORT_GOOD:
+		/* Indicate a good result */
+		srb->result = GOOD;
+		break;
+
+	case ISD200_TRANSPORT_ABORTED:
+		/* if the command gets aborted by the higher layers, we need to
+		 * short-circuit all other processing
+		 */
+		US_DEBUGP("-- transport indicates command was aborted\n");
+		srb->result = DID_ABORT << 16;
+		break;
+
+	case ISD200_TRANSPORT_FAILED:
+		US_DEBUGP("-- transport indicates command failure\n");
+		need_auto_sense = 1;
+		break;
+
+	case ISD200_TRANSPORT_ERROR:
+		US_DEBUGP("-- transport indicates transport failure\n");
+		srb->result = DID_ERROR << 16;
+		break;
+
+	case ISD200_TRANSPORT_SHORT:
+		if (!((srb->cmnd[0] == REQUEST_SENSE) ||
+		      (srb->cmnd[0] == INQUIRY) ||
+		      (srb->cmnd[0] == MODE_SENSE) ||
+		      (srb->cmnd[0] == LOG_SENSE) ||
+		      (srb->cmnd[0] == MODE_SENSE_10))) {
+			US_DEBUGP("-- unexpectedly short transfer\n");
+			need_auto_sense = 1;
+		}
+		break;
+    
+	default:
+		US_DEBUGP("-- transport indicates unknown failure\n");   
+		srb->result = DID_ERROR << 16;
+       
+	}
+
+	if (need_auto_sense)
+		if (isd200_read_regs(us) == ISD200_GOOD)
+			isd200_build_sense(us, srb);
+
+	/* Regardless of auto-sense, if we _know_ we have an error
+	 * condition, show that in the result code
+	 */
+	if (transferStatus == ISD200_TRANSPORT_FAILED)
+		srb->result = CHECK_CONDITION;
+}
+
+
+/**************************************************************************
+ * isd200_write_config
+ *                                                                         
+ * Write the ISD200 Configuraton data
+ *
+ * RETURNS:
+ *    ISD status code
+ */                                                                        
+int isd200_write_config( struct us_data *us ) 
+{
+	struct isd200_info *info = (struct isd200_info *)us->extra;
+	int retStatus = ISD200_GOOD;
+	int result;
+
+
+	US_DEBUGP("Entering isd200_write_config\n");
+
+	US_DEBUGP("   Writing the following ISD200 Config Data:\n");
+	US_DEBUGP("      Event Notification: 0x%x\n", info->ConfigData.EventNotification);
+	US_DEBUGP("      External Clock: 0x%x\n", info->ConfigData.ExternalClock);
+	US_DEBUGP("      ATA Init Timeout: 0x%x\n", info->ConfigData.ATAInitTimeout);
+	US_DEBUGP("      ATAPI Command Block Size: 0x%x\n", info->ConfigData.ATAPICommandBlockSize);
+	US_DEBUGP("      Master/Slave Selection: 0x%x\n", info->ConfigData.MasterSlaveSelection);
+	US_DEBUGP("      ATAPI Reset: 0x%x\n", info->ConfigData.ATAPIReset);
+	US_DEBUGP("      ATA Timing: 0x%x\n", info->ConfigData.ATATiming);
+	US_DEBUGP("      ATA Major Command: 0x%x\n", info->ConfigData.ATAMajorCommand);
+	US_DEBUGP("      ATA Minor Command: 0x%x\n", info->ConfigData.ATAMinorCommand);
+	US_DEBUGP("      Init Status: 0x%x\n", info->ConfigData.InitStatus);
+	US_DEBUGP("      Config Descriptor 2: 0x%x\n", info->ConfigData.ConfigDescriptor2);
+	US_DEBUGP("      Skip Device Boot: 0x%x\n", info->ConfigData.SkipDeviceBoot);
+	US_DEBUGP("      ATA 3 State Supsend: 0x%x\n", info->ConfigData.ATA3StateSuspend);
+	US_DEBUGP("      Descriptor Override: 0x%x\n", info->ConfigData.DescriptOverride);
+	US_DEBUGP("      Last LUN Identifier: 0x%x\n", info->ConfigData.LastLUNIdentifier);
+	US_DEBUGP("      SRST Enable: 0x%x\n", info->ConfigData.SRSTEnable);
+
+	/* let's send the command via the control pipe */
+	result = usb_stor_control_msg(
+                us, 
+                usb_sndctrlpipe(us->pusb_dev,0),
+                0x01, 
+                USB_TYPE_VENDOR | USB_RECIP_DEVICE | USB_DIR_OUT,
+                0x0000, 
+                0x0002, 
+                (void *) &info->ConfigData, 
+                sizeof(info->ConfigData));
+
+	if (result >= 0) {
+		US_DEBUGP("   ISD200 Config Data was written successfully\n");
+        } else {
+		US_DEBUGP("   Request to write ISD200 Config Data failed!\n");
+
+		/* STALL must be cleared when they are detected */
+		if (result == -EPIPE) {
+			US_DEBUGP("-- Stall on control pipe. Clearing\n");
+			result = usb_stor_clear_halt(us->pusb_dev,
+						     usb_sndctrlpipe(us->pusb_dev, 0));
+			US_DEBUGP("-- usb_stor_clear_halt() returns %d\n", result);
+
+		}
+		retStatus = ISD200_ERROR;
+        }
+
+	US_DEBUGP("Leaving isd200_write_config %08X\n", retStatus);
+	return retStatus;
+}
+
+
+/**************************************************************************
+ * isd200_read_config
+ *                                                                         
+ * Reads the ISD200 Configuraton data
+ *
+ * RETURNS:
+ *    ISD status code
+ */                                                                        
+int isd200_read_config( struct us_data *us ) 
+{
+	struct isd200_info *info = (struct isd200_info *)us->extra;
+	int retStatus = ISD200_GOOD;
+	int result;
+
+	US_DEBUGP("Entering isd200_read_config\n");
+
+	/* read the configuration information from ISD200.  Use this to */
+	/* determine what the special ATA CDB bytes are.                */
+
+	result = usb_stor_control_msg(
+                us, 
+                usb_rcvctrlpipe(us->pusb_dev,0),
+                0x02, 
+                USB_TYPE_VENDOR | USB_RECIP_DEVICE | USB_DIR_IN,
+                0x0000, 
+                0x0002, 
+                (void *) &info->ConfigData, 
+                sizeof(info->ConfigData));
+
+
+	if (result >= 0) {
+		US_DEBUGP("   Retrieved the following ISD200 Config Data:\n");
+		US_DEBUGP("      Event Notification: 0x%x\n", info->ConfigData.EventNotification);
+		US_DEBUGP("      External Clock: 0x%x\n", info->ConfigData.ExternalClock);
+		US_DEBUGP("      ATA Init Timeout: 0x%x\n", info->ConfigData.ATAInitTimeout);
+		US_DEBUGP("      ATAPI Command Block Size: 0x%x\n", info->ConfigData.ATAPICommandBlockSize);
+		US_DEBUGP("      Master/Slave Selection: 0x%x\n", info->ConfigData.MasterSlaveSelection);
+		US_DEBUGP("      ATAPI Reset: 0x%x\n", info->ConfigData.ATAPIReset);
+		US_DEBUGP("      ATA Timing: 0x%x\n", info->ConfigData.ATATiming);
+		US_DEBUGP("      ATA Major Command: 0x%x\n", info->ConfigData.ATAMajorCommand);
+		US_DEBUGP("      ATA Minor Command: 0x%x\n", info->ConfigData.ATAMinorCommand);
+		US_DEBUGP("      Init Status: 0x%x\n", info->ConfigData.InitStatus);
+		US_DEBUGP("      Config Descriptor 2: 0x%x\n", info->ConfigData.ConfigDescriptor2);
+		US_DEBUGP("      Skip Device Boot: 0x%x\n", info->ConfigData.SkipDeviceBoot);
+		US_DEBUGP("      ATA 3 State Supsend: 0x%x\n", info->ConfigData.ATA3StateSuspend);
+		US_DEBUGP("      Descriptor Override: 0x%x\n", info->ConfigData.DescriptOverride);
+		US_DEBUGP("      Last LUN Identifier: 0x%x\n", info->ConfigData.LastLUNIdentifier);
+		US_DEBUGP("      SRST Enable: 0x%x\n", info->ConfigData.SRSTEnable);
+        } else {
+		US_DEBUGP("   Request to get ISD200 Config Data failed!\n");
+
+		/* STALL must be cleared when they are detected */
+		if (result == -EPIPE) {
+			US_DEBUGP("-- Stall on control pipe. Clearing\n");
+			result = usb_stor_clear_halt(us->pusb_dev,   
+						     usb_sndctrlpipe(us->pusb_dev, 0));
+			US_DEBUGP("-- usb_stor_clear_halt() returns %d\n", result);
+
+		}
+		retStatus = ISD200_ERROR;
+        }
+
+	US_DEBUGP("Leaving isd200_read_config %08X\n", retStatus);
+	return retStatus;
+}
+
+
+/**************************************************************************
+ * isd200_atapi_soft_reset
+ *                                                                         
+ * Perform an Atapi Soft Reset on the device
+ *
+ * RETURNS:
+ *    NT status code
+ */                                                                        
+int isd200_atapi_soft_reset( struct us_data *us ) 
+{
+	int retStatus = ISD200_GOOD;
+	int transferStatus;
+
+	US_DEBUGP("Entering isd200_atapi_soft_reset\n");
+
+	transferStatus = isd200_action( us, ACTION_SOFT_RESET, NULL, 0 );
+	if (transferStatus != ISD200_TRANSPORT_GOOD) {
+		US_DEBUGP("   Error issuing Atapi Soft Reset\n");
+		retStatus = ISD200_ERROR;
+        }
+
+	US_DEBUGP("Leaving isd200_atapi_soft_reset %08X\n", retStatus);
+	return retStatus;
+}
+
+
+/**************************************************************************
+ * isd200_srst
+ *                                                                         
+ * Perform an SRST on the device
+ *
+ * RETURNS:
+ *    ISD status code
+ */                                                                        
+int isd200_srst( struct us_data *us ) 
+{
+	int retStatus = ISD200_GOOD;
+	int transferStatus;
+
+	US_DEBUGP("Entering isd200_SRST\n");
+
+	transferStatus = isd200_action( us, ACTION_RESET, NULL, 0 );
+
+	/* check to see if this request failed */
+	if (transferStatus != ISD200_TRANSPORT_GOOD) {
+		US_DEBUGP("   Error issuing SRST\n");
+		retStatus = ISD200_ERROR;
+        } else {
+		/* delay 10ms to give the drive a chance to see it */
+		wait_ms(10);
+
+		transferStatus = isd200_action( us, ACTION_REENABLE, NULL, 0 );
+		if (transferStatus != ISD200_TRANSPORT_GOOD) {
+			US_DEBUGP("   Error taking drive out of reset\n");
+			retStatus = ISD200_ERROR;
+		} else {
+			/* delay 50ms to give the drive a chance to recover after SRST */
+			wait_ms(50);
+		}
+        }
+
+	US_DEBUGP("Leaving isd200_srst %08X\n", retStatus);
+	return retStatus;
+}
+
+
+/**************************************************************************
+ * isd200_try_enum
+ *                                                                         
+ * Helper function for isd200_manual_enum(). Does ENUM and READ_STATUS
+ * and tries to analyze the status registers
+ *
+ * RETURNS:
+ *    ISD status code
+ */                                                                        
+static int isd200_try_enum(struct us_data *us, unsigned char master_slave,
+			   int detect )
+{
+	int status = ISD200_GOOD;
+	unsigned char regs[8];
+	unsigned long endTime;
+	struct isd200_info *info = (struct isd200_info *)us->extra;
+	int recheckAsMaster = FALSE;
+
+	if ( detect )
+		endTime = jiffies + ISD200_ENUM_DETECT_TIMEOUT * HZ;
+	else
+		endTime = jiffies + ISD200_ENUM_BSY_TIMEOUT * HZ;
+
+	/* loop until we detect !BSY or timeout */
+	while(TRUE) {
+		char* mstr = master_slave == ATA_ADDRESS_DEVHEAD_STD ?
+			"Master" : "Slave";
+
+		status = isd200_action( us, ACTION_ENUM, NULL, master_slave );
+		if ( status != ISD200_GOOD )
+			break;
+
+		status = isd200_action( us, ACTION_READ_STATUS, 
+					regs, sizeof(regs) );
+		if ( status != ISD200_GOOD )
+			break;
+
+		if (!detect) {
+			if (regs[IDE_STATUS_OFFSET] & BUSY_STAT ) {
+				US_DEBUGP("   %s status is still BSY, try again...\n",mstr);
+			} else {
+				US_DEBUGP("   %s status !BSY, continue with next operation\n",mstr);
+				break;
+			}
+		}
+		/* check for BUSY_STAT and */
+		/* WRERR_STAT (workaround ATA Zip drive) and */ 
+		/* ERR_STAT (workaround for Archos CD-ROM) */
+		else if (regs[IDE_STATUS_OFFSET] & 
+			 (BUSY_STAT | WRERR_STAT | ERR_STAT )) {
+			US_DEBUGP("   Status indicates it is not ready, try again...\n");
+		}
+		/* check for DRDY, ATA devices set DRDY after SRST */
+		else if (regs[IDE_STATUS_OFFSET] & READY_STAT) {
+			US_DEBUGP("   Identified ATA device\n");
+			info->DeviceFlags |= DF_ATA_DEVICE;
+			info->DeviceHead = master_slave;
+			break;
+		} 
+		/* check Cylinder High/Low to
+		   determine if it is an ATAPI device
+		*/
+		else if ((regs[IDE_HCYL_OFFSET] == 0xEB) &&
+			 (regs[IDE_LCYL_OFFSET] == 0x14)) {
+			/* It seems that the RICOH 
+			   MP6200A CD/RW drive will 
+			   report itself okay as a
+			   slave when it is really a
+			   master. So this check again
+			   as a master device just to
+			   make sure it doesn't report
+			   itself okay as a master also
+			*/
+			if ((master_slave & ATA_ADDRESS_DEVHEAD_SLAVE) &&
+			    (recheckAsMaster == FALSE)) {
+				US_DEBUGP("   Identified ATAPI device as slave.  Rechecking again as master\n");
+				recheckAsMaster = TRUE;
+				master_slave = ATA_ADDRESS_DEVHEAD_STD;
+			} else {
+				US_DEBUGP("   Identified ATAPI device\n");
+				info->DeviceHead = master_slave;
+			      
+				status = isd200_atapi_soft_reset(us);
+				break;
+			}
+		} else {
+			US_DEBUGP("   Not ATA, not ATAPI. Weird.\n");
+		}
+
+		/* check for timeout on this request */
+		if (jiffies >= endTime) {
+			if (!detect)
+				US_DEBUGP("   BSY check timeout, just continue with next operation...\n");
+			else
+				US_DEBUGP("   Device detect timeout!\n");
+			break;
+		}
+	}
+
+	return status;
+}
+
+/**************************************************************************
+ * isd200_manual_enum
+ *                                                                         
+ * Determines if the drive attached is an ATA or ATAPI and if it is a
+ * master or slave.
+ *
+ * RETURNS:
+ *    ISD status code
+ */                                                                        
+int isd200_manual_enum(struct us_data *us)
+{
+	struct isd200_info *info = (struct isd200_info *)us->extra;
+	int retStatus = ISD200_GOOD;
+
+	US_DEBUGP("Entering isd200_manual_enum\n");
+
+	retStatus = isd200_read_config(us);
+	if (retStatus == ISD200_GOOD) {
+		int isslave;
+		/* master or slave? */
+		retStatus = isd200_try_enum( us, ATA_ADDRESS_DEVHEAD_STD, FALSE );
+		if (retStatus == ISD200_GOOD)
+			retStatus = isd200_try_enum( us, ATA_ADDRESS_DEVHEAD_SLAVE, FALSE );
+
+		if (retStatus == ISD200_GOOD) {
+			retStatus = isd200_srst(us);
+			if (retStatus == ISD200_GOOD)
+				/* ata or atapi? */
+				retStatus = isd200_try_enum( us, ATA_ADDRESS_DEVHEAD_STD, TRUE );
+		}
+
+		isslave = (info->DeviceHead & ATA_ADDRESS_DEVHEAD_SLAVE) ? 1 : 0;
+		if (info->ConfigData.MasterSlaveSelection != isslave) {
+			US_DEBUGP("   Setting Master/Slave selection to %d\n", isslave);
+			info->ConfigData.MasterSlaveSelection = isslave;
+			retStatus = isd200_write_config(us);
+		}
+	}
+
+	US_DEBUGP("Leaving isd200_manual_enum %08X\n", retStatus);
+	return(retStatus);
+}
+
+
+/**************************************************************************
+ * isd200_get_inquiry_data
+ *
+ * Get inquiry data
+ *
+ * RETURNS:
+ *    ISD status code
+ */
+int isd200_get_inquiry_data( struct us_data *us )
+{
+	struct isd200_info *info = (struct isd200_info *)us->extra;
+	int retStatus = ISD200_GOOD;
+
+	US_DEBUGP("Entering isd200_get_inquiry_data\n");
+
+	/* set default to Master */
+	info->DeviceHead = ATA_ADDRESS_DEVHEAD_STD;
+
+	/* attempt to manually enumerate this device */
+	retStatus = isd200_manual_enum(us);
+	if (retStatus == ISD200_GOOD) {
+		int transferStatus;
+
+		/* check for an ATA device */
+		if (info->DeviceFlags & DF_ATA_DEVICE) {
+			/* this must be an ATA device */
+			/* perform an ATA Commmand Identify */
+			transferStatus = isd200_action( us, ACTION_IDENTIFY,
+							&info->drive, 
+							sizeof(struct hd_driveid) );
+			if (transferStatus != ISD200_TRANSPORT_GOOD) {
+				/* Error issuing ATA Command Identify */
+				US_DEBUGP("   Error issuing ATA Command Identify\n");
+				retStatus = ISD200_ERROR;
+			} else {
+				/* ATA Command Identify successful */
+				int i;
+
+				US_DEBUGP("   Identify Data Structure:\n");
+				US_DEBUGP("      config = 0x%x\n", info->drive.config);
+				US_DEBUGP("      cyls = 0x%x\n", info->drive.cyls);
+				US_DEBUGP("      heads = 0x%x\n", info->drive.heads);
+				US_DEBUGP("      track_bytes = 0x%x\n", info->drive.track_bytes);
+				US_DEBUGP("      sector_bytes = 0x%x\n", info->drive.sector_bytes);
+				US_DEBUGP("      sectors = 0x%x\n", info->drive.sectors);
+				US_DEBUGP("      serial_no[0] = 0x%x\n", info->drive.serial_no[0]);
+				US_DEBUGP("      buf_type = 0x%x\n", info->drive.buf_type);
+				US_DEBUGP("      buf_size = 0x%x\n", info->drive.buf_size);
+				US_DEBUGP("      ecc_bytes = 0x%x\n", info->drive.ecc_bytes);
+				US_DEBUGP("      fw_rev[0] = 0x%x\n", info->drive.fw_rev[0]);
+				US_DEBUGP("      model[0] = 0x%x\n", info->drive.model[0]);
+				US_DEBUGP("      max_multsect = 0x%x\n", info->drive.max_multsect);
+				US_DEBUGP("      dword_io = 0x%x\n", info->drive.dword_io);
+				US_DEBUGP("      capability = 0x%x\n", info->drive.capability);
+				US_DEBUGP("      tPIO = 0x%x\n", info->drive.tPIO);
+				US_DEBUGP("      tDMA = 0x%x\n", info->drive.tDMA);
+				US_DEBUGP("      field_valid = 0x%x\n", info->drive.field_valid);
+				US_DEBUGP("      cur_cyls = 0x%x\n", info->drive.cur_cyls);
+				US_DEBUGP("      cur_heads = 0x%x\n", info->drive.cur_heads);
+				US_DEBUGP("      cur_sectors = 0x%x\n", info->drive.cur_sectors);
+				US_DEBUGP("      cur_capacity = 0x%x\n", (info->drive.cur_capacity1 << 16) + info->drive.cur_capacity0 );
+				US_DEBUGP("      multsect = 0x%x\n", info->drive.multsect);
+				US_DEBUGP("      lba_capacity = 0x%x\n", info->drive.lba_capacity);
+				US_DEBUGP("      command_set_1 = 0x%x\n", info->drive.command_set_1);
+				US_DEBUGP("      command_set_2 = 0x%x\n", info->drive.command_set_2);
+
+				memset(&info->InquiryData, 0, sizeof(info->InquiryData));
+
+				/* Standard IDE interface only supports disks */
+				info->InquiryData.DeviceType = DIRECT_ACCESS_DEVICE;
+
+				/* Fix-up the return data from an INQUIRY command to show 
+				 * ANSI SCSI rev 2 so we don't confuse the SCSI layers above us
+				 * in Linux.
+				 */
+				info->InquiryData.Versions = 0x2;
+
+				/* The length must be at least 36 (5 + 31) */
+				info->InquiryData.AdditionalLength = 0x1F;
+
+				if (info->drive.command_set_1 & COMMANDSET_MEDIA_STATUS) {
+					/* set the removable bit */
+					info->InquiryData.RemovableMedia = 1;
+					info->DeviceFlags |= DF_REMOVABLE_MEDIA;
+				}
+
+				/* Fill in vendor identification fields */
+				for (i = 0; i < 20; i += 2) {
+					info->InquiryData.VendorId[i] = 
+						info->drive.model[i + 1];
+					info->InquiryData.VendorId[i+1] = 
+						info->drive.model[i];
+				}
+
+				/* Initialize unused portion of product id */
+				for (i = 0; i < 4; i++) {
+					info->InquiryData.ProductId[12+i] = ' ';
+				}
+
+				/* Move firmware revision from IDENTIFY data to */
+				/* product revision in INQUIRY data             */
+				for (i = 0; i < 4; i += 2) {
+					info->InquiryData.ProductRevisionLevel[i] =
+						info->drive.fw_rev[i+1];
+					info->InquiryData.ProductRevisionLevel[i+1] =
+						info->drive.fw_rev[i];
+				}
+
+				/* determine if it supports Media Status Notification */
+				if (info->drive.command_set_2 & COMMANDSET_MEDIA_STATUS) {
+					US_DEBUGP("   Device supports Media Status Notification\n");
+
+					/* Indicate that it is enabled, even though it is not
+					 * This allows the lock/unlock of the media to work
+					 * correctly.
+					 */
+					info->DeviceFlags |= DF_MEDIA_STATUS_ENABLED;
+				}
+				else
+					info->DeviceFlags &= ~DF_MEDIA_STATUS_ENABLED;
+
+			}
+		} else {
+			/* 
+			 * this must be an ATAPI device 
+			 * use an ATAPI protocol (Transparent SCSI)
+			 */
+			us->protocol_name = "Transparent SCSI";
+			us->proto_handler = usb_stor_transparent_scsi_command;
+
+			US_DEBUGP("Protocol changed to: %s\n", us->protocol_name);
+            
+			/* Free driver structure */            
+			if (us->extra != NULL) {
+				kfree(us->extra);
+				us->extra = NULL;
+				us->extra_destructor = NULL;
+			}
+		}
+        }
+
+	US_DEBUGP("Leaving isd200_get_inquiry_data %08X\n", retStatus);
+
+	return(retStatus);
+}
+
+
+/**************************************************************************
+ * isd200_data_copy
+ *                                                                         
+ * Copy data into the srb request buffer.  Use scatter gather if required.
+ *
+ * RETURNS:
+ *    void
+ */                                                                        
+void isd200_data_copy(Scsi_Cmnd *srb, char * src, int length)
+{
+	unsigned int len = length;
+	struct scatterlist *sg;
+
+	if (srb->use_sg) {
+		int i;
+		unsigned int total = 0;
+
+		/* Add up the sizes of all the sg segments */
+		sg = (struct scatterlist *) srb->request_buffer;
+		for (i = 0; i < srb->use_sg; i++)
+			total += sg[i].length;
+
+		if (length > total)
+			len = total;
+
+		total = 0;
+
+		/* Copy data into sg buffer(s) */
+		for (i = 0; i < srb->use_sg; i++) {
+			if ((len > total) && (len > 0)) {
+				/* transfer the lesser of the next buffer or the
+				 * remaining data */
+				if (len - total >= sg[i].length) {
+					memcpy(sg[i].address, src + total, sg[i].length);
+					total += sg[i].length;
+				} else {
+					memcpy(sg[i].address, src + total, len - total);
+					total = len;
+				}
+			} 
+			else
+				break;
+		}
+	} else	{
+		/* Make sure length does not exceed buffer length */
+		if (length > srb->request_bufflen)
+			len = srb->request_bufflen;
+
+		if (len > 0)
+			memcpy(srb->request_buffer, src, len);
+	}
+}
+
+
+/**************************************************************************
+ * isd200_scsi_to_ata
+ *                                                                         
+ * Translate SCSI commands to ATA commands.
+ *
+ * RETURNS:
+ *    TRUE if the command needs to be sent to the transport layer
+ *    FALSE otherwise
+ */                                                                        
+int isd200_scsi_to_ata(Scsi_Cmnd *srb, struct us_data *us, 
+		       union ata_cdb * ataCdb)
+{
+	struct isd200_info *info = (struct isd200_info *)us->extra;
+	int sendToTransport = TRUE;
+	unsigned char sectnum, head;
+	unsigned short cylinder;
+	unsigned long lba;
+	unsigned long blockCount;
+	unsigned char senseData[8] = { 0, 0, 0, 0, 0, 0, 0, 0 };
+
+	memset(ataCdb, 0, sizeof(union ata_cdb));
+
+	/* SCSI Command */
+	switch (srb->cmnd[0]) {
+	case INQUIRY:
+		US_DEBUGP("   ATA OUT - INQUIRY\n");
+
+		if (srb->request_bufflen > sizeof(struct inquiry_data))
+			srb->request_bufflen = sizeof(struct inquiry_data);
+
+		/* copy InquiryData */
+		isd200_data_copy(srb, (char *) &info->InquiryData, srb->request_bufflen);
+		srb->result = GOOD;
+		sendToTransport = FALSE;
+		break;
+
+	case MODE_SENSE:
+		US_DEBUGP("   ATA OUT - SCSIOP_MODE_SENSE\n");
+
+		/* Initialize the return buffer */
+		isd200_data_copy(srb, (char *) &senseData, 8);
+
+		if (info->DeviceFlags & DF_MEDIA_STATUS_ENABLED)
+		{
+			ataCdb->generic.SignatureByte0 = info->ConfigData.ATAMajorCommand;
+			ataCdb->generic.SignatureByte1 = info->ConfigData.ATAMinorCommand;
+			ataCdb->generic.TransferBlockSize = 1;
+			ataCdb->write.SelectCommand = 1;
+			ataCdb->write.CommandByte = ATA_COMMAND_GET_MEDIA_STATUS;
+			srb->request_bufflen = 0;
+		} else {
+			US_DEBUGP("   Media Status not supported, just report okay\n");
+			srb->result = GOOD;
+			sendToTransport = FALSE;
+		}
+		break;
+
+	case TEST_UNIT_READY:
+		US_DEBUGP("   ATA OUT - SCSIOP_TEST_UNIT_READY\n");
+
+		/* Initialize the return buffer */
+		isd200_data_copy(srb, (char *) &senseData, 8);
+
+		if (info->DeviceFlags & DF_MEDIA_STATUS_ENABLED)
+		{
+			ataCdb->generic.SignatureByte0 = info->ConfigData.ATAMajorCommand;
+			ataCdb->generic.SignatureByte1 = info->ConfigData.ATAMinorCommand;
+			ataCdb->generic.TransferBlockSize = 1;
+			ataCdb->write.SelectCommand = 1;
+			ataCdb->write.CommandByte = ATA_COMMAND_GET_MEDIA_STATUS;
+			srb->request_bufflen = 0;
+		} else {
+			US_DEBUGP("   Media Status not supported, just report okay\n");
+			srb->result = GOOD;
+			sendToTransport = FALSE;
+		}
+		break;
+
+	case READ_CAPACITY:
+	{
+		unsigned long capacity;
+		struct read_capacity_data readCapacityData;
+
+		US_DEBUGP("   ATA OUT - SCSIOP_READ_CAPACITY\n");
+
+		if (info->drive.capability & CAPABILITY_LBA ) {
+			capacity = info->drive.lba_capacity - 1;
+		} else {
+			capacity = (info->drive.heads *
+				    info->drive.cyls *
+				    info->drive.sectors) - 1;
+		}
+		readCapacityData.LogicalBlockAddress = cpu_to_be32(capacity);
+		readCapacityData.BytesPerBlock = cpu_to_be32(0x200);
+
+		if (srb->request_bufflen > sizeof(struct read_capacity_data))
+			srb->request_bufflen = sizeof(struct read_capacity_data);
+
+		isd200_data_copy(srb, (char *) &readCapacityData, srb->request_bufflen);
+		srb->result = GOOD;
+		sendToTransport = FALSE;
+	}
+	break;
+
+	case READ_10:
+		US_DEBUGP("   ATA OUT - SCSIOP_READ\n");
+
+		lba = *(unsigned long *)&srb->cmnd[2]; 
+		lba = cpu_to_be32(lba);
+		blockCount = (unsigned long)srb->cmnd[7]<<8 | (unsigned long)srb->cmnd[8];
+
+		if (info->drive.capability & CAPABILITY_LBA) {
+			sectnum = (unsigned char)(lba);
+			cylinder = (unsigned short)(lba>>8);
+			head = ATA_ADDRESS_DEVHEAD_LBA_MODE | (unsigned char)(lba>>24 & 0x0F);
+		} else {
+			sectnum = (unsigned char)((lba % info->drive.sectors) + 1);
+			cylinder = (unsigned short)(lba / (info->drive.sectors *
+							   info->drive.heads));
+			head = (unsigned char)((lba / info->drive.sectors) %
+					       info->drive.heads);
+		}
+		ataCdb->generic.SignatureByte0 = info->ConfigData.ATAMajorCommand;
+		ataCdb->generic.SignatureByte1 = info->ConfigData.ATAMinorCommand;
+		ataCdb->generic.TransferBlockSize = 1;
+		ataCdb->write.SelectSectorCount = 1;
+		ataCdb->write.SectorCountByte = (unsigned char)blockCount;
+		ataCdb->write.SelectSectorNumber = 1;
+		ataCdb->write.SectorNumberByte = sectnum;
+		ataCdb->write.SelectCylinderHigh = 1;
+		ataCdb->write.CylinderHighByte = (unsigned char)(cylinder>>8);
+		ataCdb->write.SelectCylinderLow = 1;
+		ataCdb->write.CylinderLowByte = (unsigned char)cylinder;
+		ataCdb->write.SelectDeviceHead = 1;
+		ataCdb->write.DeviceHeadByte = (head | ATA_ADDRESS_DEVHEAD_STD);
+		ataCdb->write.SelectCommand = 1;
+		ataCdb->write.CommandByte = WIN_READ;
+		break;
+
+	case WRITE_10:
+		US_DEBUGP("   ATA OUT - SCSIOP_WRITE\n");
+
+		lba = *(unsigned long *)&srb->cmnd[2]; 
+		lba = cpu_to_be32(lba);
+		blockCount = (unsigned long)srb->cmnd[7]<<8 | (unsigned long)srb->cmnd[8];
+
+		if (info->drive.capability & CAPABILITY_LBA) {
+			sectnum = (unsigned char)(lba);
+			cylinder = (unsigned short)(lba>>8);
+			head = ATA_ADDRESS_DEVHEAD_LBA_MODE | (unsigned char)(lba>>24 & 0x0F);
+		} else {
+			sectnum = (unsigned char)((lba % info->drive.sectors) + 1);
+			cylinder = (unsigned short)(lba / (info->drive.sectors * info->drive.heads));
+			head = (unsigned char)((lba / info->drive.sectors) % info->drive.heads);
+		}
+		ataCdb->generic.SignatureByte0 = info->ConfigData.ATAMajorCommand;
+		ataCdb->generic.SignatureByte1 = info->ConfigData.ATAMinorCommand;
+		ataCdb->generic.TransferBlockSize = 1;
+		ataCdb->write.SelectSectorCount = 1;
+		ataCdb->write.SectorCountByte = (unsigned char)blockCount;
+		ataCdb->write.SelectSectorNumber = 1;
+		ataCdb->write.SectorNumberByte = sectnum;
+		ataCdb->write.SelectCylinderHigh = 1;
+		ataCdb->write.CylinderHighByte = (unsigned char)(cylinder>>8);
+		ataCdb->write.SelectCylinderLow = 1;
+		ataCdb->write.CylinderLowByte = (unsigned char)cylinder;
+		ataCdb->write.SelectDeviceHead = 1;
+		ataCdb->write.DeviceHeadByte = (head | ATA_ADDRESS_DEVHEAD_STD);
+		ataCdb->write.SelectCommand = 1;
+		ataCdb->write.CommandByte = WIN_WRITE;
+		break;
+
+	case ALLOW_MEDIUM_REMOVAL:
+		US_DEBUGP("   ATA OUT - SCSIOP_MEDIUM_REMOVAL\n");
+
+		if (info->DeviceFlags & DF_REMOVABLE_MEDIA) {
+			US_DEBUGP("   srb->cmnd[4] = 0x%X\n", srb->cmnd[4]);
+            
+			ataCdb->generic.SignatureByte0 = info->ConfigData.ATAMajorCommand;
+			ataCdb->generic.SignatureByte1 = info->ConfigData.ATAMinorCommand;
+			ataCdb->generic.TransferBlockSize = 1;
+			ataCdb->write.SelectCommand = 1;
+			ataCdb->write.CommandByte = (srb->cmnd[4] & 0x1) ?
+				WIN_DOORLOCK : WIN_DOORUNLOCK;
+			srb->request_bufflen = 0;
+		} else {
+			US_DEBUGP("   Not removeable media, just report okay\n");
+			srb->result = GOOD;
+			sendToTransport = FALSE;
+		}
+		break;
+
+	case START_STOP:    
+		US_DEBUGP("   ATA OUT - SCSIOP_START_STOP_UNIT\n");
+		US_DEBUGP("   srb->cmnd[4] = 0x%X\n", srb->cmnd[4]);
+
+		/* Initialize the return buffer */
+		isd200_data_copy(srb, (char *) &senseData, 8);
+
+		if ((srb->cmnd[4] & 0x3) == 0x2) {
+			US_DEBUGP("   Media Eject\n");
+			ataCdb->generic.SignatureByte0 = info->ConfigData.ATAMajorCommand;
+			ataCdb->generic.SignatureByte1 = info->ConfigData.ATAMinorCommand;
+			ataCdb->generic.TransferBlockSize = 0;
+			ataCdb->write.SelectCommand = 1;
+			ataCdb->write.CommandByte = ATA_COMMAND_MEDIA_EJECT;
+		} else if ((srb->cmnd[4] & 0x3) == 0x1) {
+			US_DEBUGP("   Get Media Status\n");
+			ataCdb->generic.SignatureByte0 = info->ConfigData.ATAMajorCommand;
+			ataCdb->generic.SignatureByte1 = info->ConfigData.ATAMinorCommand;
+			ataCdb->generic.TransferBlockSize = 1;
+			ataCdb->write.SelectCommand = 1;
+			ataCdb->write.CommandByte = ATA_COMMAND_GET_MEDIA_STATUS;
+			srb->request_bufflen = 0;
+		} else {
+			US_DEBUGP("   Nothing to do, just report okay\n");
+			srb->result = GOOD;
+			sendToTransport = FALSE;
+		}
+		break;
+
+	default:
+		US_DEBUGP("Unsupported SCSI command - 0x%X\n", srb->cmnd[0]);
+		srb->result = DID_ERROR << 16;
+		sendToTransport = FALSE;
+		break;
+	}
+
+	return(sendToTransport);
+}
+
+
+/**************************************************************************
+ * isd200_init_info
+ *                                                                         
+ * Allocates (if necessary) and initializes the driver structure.
+ *
+ * RETURNS:
+ *    ISD status code
+ */                                                                        
+int isd200_init_info(struct us_data *us)
+{
+	int retStatus = ISD200_GOOD;
+
+	if (!us->extra) {
+		us->extra = (void *) kmalloc(sizeof(struct isd200_info), GFP_KERNEL);
+		if (!us->extra) {
+			US_DEBUGP("ERROR - kmalloc failure\n");
+			retStatus = ISD200_ERROR;
+		}
+        }
+
+	if (retStatus == ISD200_GOOD) {
+		memset(us->extra, 0, sizeof(struct isd200_info));
+        }
+
+	return(retStatus);
+}
+
+/**************************************************************************
+ * Initialization for the ISD200 
+ */
+
+int isd200_Initialization(struct us_data *us)
+{
+	US_DEBUGP("ISD200 Initialization...\n");
+
+	/* Initialize ISD200 info struct */
+
+	if (isd200_init_info(us) == ISD200_ERROR) {
+		US_DEBUGP("ERROR Initializing ISD200 Info struct\n");
+        } else {
+		/* Get device specific data */
+
+		if (isd200_get_inquiry_data(us) != ISD200_GOOD)
+			US_DEBUGP("ISD200 Initialization Failure\n");
+		else
+			US_DEBUGP("ISD200 Initialization complete\n");
+        }
+
+	return 0;
+}
+
+
+/**************************************************************************
+ * Protocol and Transport for the ISD200 ASIC
+ *
+ * This protocol and transport are for ATA devices connected to an ISD200
+ * ASIC.  An ATAPI device that is conected as a slave device will be
+ * detected in the driver initialization function and the protocol will
+ * be changed to an ATAPI protocol (Transparent SCSI).
+ *
+ */
+
+void isd200_ata_command(Scsi_Cmnd *srb, struct us_data *us)
+{
+	int sendToTransport = TRUE;
+	union ata_cdb ataCdb;
+
+	/* Make sure driver was initialized */
+
+	if (us->extra == NULL)
+		US_DEBUGP("ERROR Driver not initialized\n");
+
+	/* Convert command */
+	sendToTransport = isd200_scsi_to_ata(srb, us, &ataCdb);
+
+	/* send the command to the transport layer */
+	if (sendToTransport)
+		isd200_invoke_transport(us, srb, &ataCdb);
+}
diff -u --recursive --new-file v2.4.7/linux/drivers/usb/storage/isd200.h linux/drivers/usb/storage/isd200.h
--- v2.4.7/linux/drivers/usb/storage/isd200.h	Wed Dec 31 16:00:00 1969
+++ linux/drivers/usb/storage/isd200.h	Sun Jul 29 21:11:50 2001
@@ -0,0 +1,31 @@
+/* Header File for In-System Design, Inc. ISD200 ASIC
+ *
+ * First release
+ *
+ * Current development and maintenance by:
+ *   (c) 2000 In-System Design, Inc. (support@in-system.com)
+ *
+ * See isd200.c for more information.
+ *
+ * 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, 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.
+ */
+
+#ifndef _USB_ISD200_H
+#define _USB_ISD200_H
+
+extern void isd200_ata_command(Scsi_Cmnd *srb, struct us_data *us);
+extern int isd200_Initialization(struct us_data *us);
+
+#endif
diff -u --recursive --new-file v2.4.7/linux/drivers/usb/storage/jumpshot.c linux/drivers/usb/storage/jumpshot.c
--- v2.4.7/linux/drivers/usb/storage/jumpshot.c	Wed Dec 31 16:00:00 1969
+++ linux/drivers/usb/storage/jumpshot.c	Sun Jul 29 21:11:50 2001
@@ -0,0 +1,804 @@
+/* Driver for Lexar "Jumpshot" Compact Flash reader
+ *
+ * jumpshot driver v0.1:
+ *
+ * First release
+ *
+ * Current development and maintenance by:
+ *   (c) 2000 Jimmie Mayfield (mayfield+usb@sackheads.org)
+ *   many thanks to Robert Baruch for the SanDisk SmartMedia reader driver
+ *   which I used as a template for this driver.
+ *   Some bugfixes and scatter-gather code by Gregory P. Smith 
+ *   (greg-usb@electricrain.com)
+ *
+ * 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, 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.
+ */
+ 
+ /*
+  * This driver attempts to support the Lexar Jumpshot USB CompactFlash 
+  * reader.  Like many other USB CompactFlash readers, the Jumpshot contains
+  * a USB-to-ATA chip. 
+  *
+  * This driver supports reading and writing.  If you're truly paranoid,
+  * however, you can force the driver into a write-protected state by setting
+  * the WP enable bits in jumpshot_handle_mode_sense.  Basically this means
+  * setting mode_param_header[3] = 0x80.  
+  */
+
+#include "transport.h"
+#include "protocol.h"
+#include "usb.h"
+#include "debug.h"
+#include "jumpshot.h"
+
+#include <linux/sched.h>
+#include <linux/errno.h>
+#include <linux/malloc.h>
+
+extern int usb_stor_control_msg(struct us_data *us, unsigned int pipe,
+				u8 request, u8 requesttype, u16 value,
+				u16 index, void *data, u16 size);
+extern int usb_stor_bulk_msg(struct us_data *us, void *data, int pipe,
+			     unsigned int len, unsigned int *act_len);
+
+#if 0
+static void jumpshot_dump_data(unsigned char *data, int len)
+{
+	unsigned char buf[80];
+	int sofar = 0;
+
+	if (!data)
+		return;
+
+	memset(buf, 0, sizeof(buf));
+
+	for (sofar = 0; sofar < len; sofar++) {
+		sprintf(buf + strlen(buf), "%02x ",
+			((unsigned int) data[sofar]) & 0xFF);
+
+		if (sofar % 16 == 15) {
+			US_DEBUGP("jumpshot:  %s\n", buf);
+			memset(buf, 0, sizeof(buf));
+		}
+	}
+
+	if (strlen(buf) != 0)
+		US_DEBUGP("jumpshot:  %s\n", buf);
+}
+#endif
+
+/*
+ * Send a control message and wait for the response.
+ *
+ * us - the pointer to the us_data structure for the device to use
+ *
+ * request - the URB Setup Packet's first 6 bytes. The first byte always
+ *  corresponds to the request type, and the second byte always corresponds
+ *  to the request.  The other 4 bytes do not correspond to value and index,
+ *  since they are used in a custom way by the SCM protocol.
+ *
+ * xfer_data - a buffer from which to get, or to which to store, any data
+ *  that gets send or received, respectively, with the URB. Even though
+ *  it looks like we allocate a buffer in this code for the data, xfer_data
+ *  must contain enough allocated space.
+ *
+ * xfer_len - the number of bytes to send or receive with the URB.
+ *
+ * This routine snarfed from the SanDisk SDDR-09 driver
+ *
+ */
+static int jumpshot_send_control(struct us_data  *us,
+				 int pipe,
+				 unsigned char request,
+				 unsigned char requesttype,
+				 unsigned short value,
+				 unsigned short index,
+				 unsigned char *xfer_data,
+				 unsigned int xfer_len)
+{
+	int result;
+
+	// Send the URB to the device and wait for a response.
+
+	/* Why are request and request type reversed in this call? */
+
+	result = usb_stor_control_msg(us, pipe,
+				      request, requesttype,
+				      value, index, xfer_data, xfer_len);
+
+	// Check the return code for the command.
+
+	if (result < 0) {
+		/* if the command was aborted, indicate that */
+		if (result == -ENOENT)
+			return USB_STOR_TRANSPORT_ABORTED;
+
+		/* a stall is a fatal condition from the device */
+		if (result == -EPIPE) {
+			US_DEBUGP("jumpshot_send_control:  -- Stall on control pipe. Clearing\n");
+			result = usb_clear_halt(us->pusb_dev, pipe);
+			US_DEBUGP("jumpshot_send_control:  -- usb_clear_halt() returns %d\n", result);
+			return USB_STOR_TRANSPORT_FAILED;
+		}
+
+		/* Uh oh... serious problem here */
+		return USB_STOR_TRANSPORT_ERROR;
+	}
+
+	return USB_STOR_TRANSPORT_GOOD;
+}
+
+
+static int jumpshot_raw_bulk(int direction,
+			     struct us_data *us,
+			     unsigned char *data, 
+		             unsigned int len)
+{
+	int result;
+	int act_len;
+	int pipe;
+
+	if (direction == SCSI_DATA_READ)
+		pipe = usb_rcvbulkpipe(us->pusb_dev, us->ep_in);
+	else
+		pipe = usb_sndbulkpipe(us->pusb_dev, us->ep_out);
+
+	result = usb_stor_bulk_msg(us, data, pipe, len, &act_len);
+
+	// if we stall, we need to clear it before we go on
+	if (result == -EPIPE) {
+		US_DEBUGP("jumpshot_raw_bulk:  EPIPE. clearing endpoint halt for"
+			  " pipe 0x%x, stalled at %d bytes\n", pipe, act_len);
+		usb_clear_halt(us->pusb_dev, pipe);
+	}
+
+	if (result) {
+		// NAK - that means we've retried a few times already
+		if (result == -ETIMEDOUT) {
+			US_DEBUGP("jumpshot_raw_bulk:  device NAKed\n");
+			return US_BULK_TRANSFER_FAILED;
+		}
+
+		// -ENOENT -- we canceled this transfer
+		if (result == -ENOENT) {
+			US_DEBUGP("jumpshot_raw_bulk:  transfer aborted\n");
+			return US_BULK_TRANSFER_ABORTED;
+		}
+
+		if (result == -EPIPE) {
+			US_DEBUGP("jumpshot_raw_bulk:  output pipe stalled\n");
+			return USB_STOR_TRANSPORT_FAILED;
+		}
+
+		// the catch-all case
+		US_DEBUGP("jumpshot_raw_bulk:  unknown error\n");
+		return US_BULK_TRANSFER_FAILED;
+	}
+
+	if (act_len != len) {
+		US_DEBUGP("jumpshot_raw_bulk:  Warning. Transferred only %d bytes\n", act_len);
+		return US_BULK_TRANSFER_SHORT;
+	}
+
+	US_DEBUGP("jumpshot_raw_bulk:  Transfered %d of %d bytes\n", act_len, len);
+	return US_BULK_TRANSFER_GOOD;
+}
+
+static inline int jumpshot_bulk_read(struct us_data *us,
+			             unsigned char *data, 
+		                     unsigned int len)
+{
+	if (len == 0)
+		return USB_STOR_TRANSPORT_GOOD;
+
+	US_DEBUGP("jumpshot_bulk_read:  len = %d\n", len);
+	return jumpshot_raw_bulk(SCSI_DATA_READ, us, data, len);
+}
+
+
+static inline int jumpshot_bulk_write(struct us_data *us,
+			              unsigned char *data, 
+		                      unsigned int len)
+{
+	if (len == 0)
+		return USB_STOR_TRANSPORT_GOOD;
+
+	US_DEBUGP("jumpshot_bulk_write:  len = %d\n", len);
+	return jumpshot_raw_bulk(SCSI_DATA_WRITE, us, data, len);
+}
+
+
+static int jumpshot_get_status(struct us_data  *us)
+{
+	unsigned char reply;
+	int rc;
+
+	if (!us)
+		return USB_STOR_TRANSPORT_ERROR;
+
+	// send the setup
+	rc = jumpshot_send_control(us,
+				   usb_rcvctrlpipe(us->pusb_dev, 0),
+				   0, 0xA0, 0, 7, &reply, 1);
+
+	if (rc != USB_STOR_TRANSPORT_GOOD)
+		return rc;
+
+	if (reply != 0x50) {
+		US_DEBUGP("jumpshot_get_status:  0x%2x\n",
+			  (unsigned short) (reply));
+		return USB_STOR_TRANSPORT_ERROR;
+	}
+
+	return USB_STOR_TRANSPORT_GOOD;
+}
+
+static int jumpshot_read_data(struct us_data *us,
+		              struct jumpshot_info *info,
+		              u32 sector,
+		              u32 sectors, 
+		              unsigned char *dest, 
+		              int use_sg)
+{
+	unsigned char command[] = { 0, 0, 0, 0, 0, 0xe0, 0x20 };
+	unsigned char *buffer = NULL;
+	unsigned char *ptr;
+	unsigned char  thistime;
+	struct scatterlist *sg = NULL;
+        int totallen, len, result;
+        int sg_idx = 0, current_sg_offset = 0;
+        int transferred;
+
+        // we're working in LBA mode.  according to the ATA spec, 
+        // we can support up to 28-bit addressing.  I don't know if Jumpshot
+        // supports beyond 24-bit addressing.  It's kind of hard to test 
+        // since it requires > 8GB CF card.
+	//
+	if (sector > 0x0FFFFFFF)
+		return USB_STOR_TRANSPORT_ERROR;
+
+	// If we're using scatter-gather, we have to create a new
+	// buffer to read all of the data in first, since a
+	// scatter-gather buffer could in theory start in the middle
+	// of a page, which would be bad. A developer who wants a
+	// challenge might want to write a limited-buffer
+	// version of this code.
+
+	totallen = sectors * info->ssize;
+
+	do {
+               // loop, never allocate or transfer more than 64k at once (min(128k, 255*info->ssize) is the real limit)
+                len = min(totallen, 65536);
+
+                if (use_sg) {
+                        sg = (struct scatterlist *) dest;
+                        buffer = kmalloc(len, GFP_KERNEL);
+                        if (buffer == NULL)
+                                return USB_STOR_TRANSPORT_ERROR;
+                        ptr = buffer;
+                } else {
+                        ptr = dest;
+                }
+
+                thistime = (len / info->ssize) & 0xff;
+
+		command[0] = 0;
+		command[1] = thistime;
+		command[2] = sector & 0xFF;
+		command[3] = (sector >>  8) & 0xFF;
+		command[4] = (sector >> 16) & 0xFF;
+
+		command[5] |= (sector >> 24) & 0x0F;
+
+		// send the setup + command
+		result = jumpshot_send_control(us,
+					       usb_sndctrlpipe(us->pusb_dev, 0),
+					       0, 0x20, 0, 1, command, 7);
+		if (result != USB_STOR_TRANSPORT_GOOD) {
+			if (use_sg)
+				kfree(buffer);
+			return result;
+		}
+
+		// read the result
+		result = jumpshot_bulk_read(us, ptr, len);
+		if (result != USB_STOR_TRANSPORT_GOOD) {
+			if (use_sg)
+				kfree(buffer);
+			return result;
+		}
+
+		US_DEBUGP("jumpshot_read_data:  %d bytes\n", len);
+		//jumpshot_dump_data(ptr, len);
+	
+		sectors -= thistime;
+		sector  += thistime;
+
+                if (use_sg) {
+                        transferred = 0;
+                        while (sg_idx < use_sg && transferred < len) {
+                                if (len - transferred >= sg[sg_idx].length - current_sg_offset) {
+                                        US_DEBUGP("jumpshot_read_data:  adding %d bytes to %d byte sg buffer\n", sg[sg_idx].length - current_sg_offset, sg[sg_idx].length);
+                                        memcpy(sg[sg_idx].address + current_sg_offset,
+                                               buffer + transferred,
+                                               sg[sg_idx].length - current_sg_offset);
+                                        transferred += sg[sg_idx].length - current_sg_offset;
+                                        current_sg_offset = 0;
+                                        // on to the next sg buffer
+                                        ++sg_idx;
+                                } else {
+                                        US_DEBUGP("jumpshot_read_data:  adding %d bytes to %d byte sg buffer\n", len - transferred, sg[sg_idx].length);
+                                        memcpy(sg[sg_idx].address + current_sg_offset,
+                                               buffer + transferred,
+                                               len - transferred);
+                                        current_sg_offset += len - transferred;
+                                        // this sg buffer is only partially full and we're out of data to copy in
+                                        break;
+                                }
+                        }
+                        kfree(buffer);
+                } else {
+                        dest += len;
+                }
+
+                totallen -= len;
+        } while (totallen > 0);
+
+	return USB_STOR_TRANSPORT_GOOD;
+}
+
+
+static int jumpshot_write_data(struct us_data *us,
+		               struct jumpshot_info *info,
+			       u32 sector,
+			       u32 sectors, 
+		               unsigned char *src, 
+		               int use_sg)
+{
+	unsigned char command[7] = { 0, 0, 0, 0, 0, 0xE0, 0x30 };
+	unsigned char *buffer = NULL;
+	unsigned char *ptr;
+	unsigned char  thistime;
+	struct scatterlist *sg = NULL;
+        int totallen, len, result, waitcount;
+        int sg_idx = 0, current_sg_offset = 0;
+        int transferred;
+
+        // we're working in LBA mode.  according to the ATA spec, 
+        // we can support up to 28-bit addressing.  I don't know if Jumpshot
+        // supports beyond 24-bit addressing.  It's kind of hard to test 
+        // since it requires > 8GB CF card.
+        //
+	if (sector > 0x0FFFFFFF)
+		return USB_STOR_TRANSPORT_ERROR;
+
+	// If we're using scatter-gather, we have to create a new
+	// buffer to read all of the data in first, since a
+	// scatter-gather buffer could in theory start in the middle
+	// of a page, which would be bad. A developer who wants a
+	// challenge might want to write a limited-buffer
+	// version of this code.
+
+	totallen = sectors * info->ssize;
+
+	do {
+                // loop, never allocate or transfer more than 64k at once (min(128k, 255*info->ssize) is the real limit)
+                len = min(totallen, 65536);
+
+                if (use_sg) {
+                        sg = (struct scatterlist *) src;
+                        buffer = kmalloc(len, GFP_KERNEL);
+                        if (buffer == NULL)
+                                return USB_STOR_TRANSPORT_ERROR;
+                        ptr = buffer;
+
+                        memset(buffer, 0, len);
+
+                        // copy the data from the sg bufs into the big contiguous buf
+                        //
+                        transferred = 0;
+                        while (transferred < len) {
+                                if (len - transferred >= sg[sg_idx].length - current_sg_offset) {
+                                        US_DEBUGP("jumpshot_write_data:  getting %d bytes from %d byte sg buffer\n", sg[sg_idx].length - current_sg_offset, sg[sg_idx].length);
+                                        memcpy(ptr + transferred,
+                                               sg[sg_idx].address + current_sg_offset,
+                                               sg[sg_idx].length - current_sg_offset);
+                                        transferred += sg[sg_idx].length - current_sg_offset;
+                                        current_sg_offset = 0;
+                                        // on to the next sg buffer
+                                        ++sg_idx;
+                                } else {
+                                        US_DEBUGP("jumpshot_write_data:  getting %d bytes from %d byte sg buffer\n", len - transferred, sg[sg_idx].length);
+                                        memcpy(ptr + transferred,
+                                               sg[sg_idx].address + current_sg_offset,
+                                               len - transferred);
+                                        current_sg_offset += len - transferred;
+                                        // we only copied part of this sg buffer
+                                        break;
+                                }
+                        }
+                } else {
+                        ptr = src;
+                }
+
+                thistime = (len / info->ssize) & 0xff;
+
+		command[0] = 0;
+		command[1] = thistime;
+		command[2] = sector & 0xFF;
+		command[3] = (sector >>  8) & 0xFF;
+		command[4] = (sector >> 16) & 0xFF;
+
+		command[5] |= (sector >> 24) & 0x0F;
+
+		// send the setup + command
+		result = jumpshot_send_control(us,
+					       usb_sndctrlpipe(us->pusb_dev, 0),
+					       0, 0x20, 0, 1, command, 7);
+
+		// send the data
+		result = jumpshot_bulk_write(us, ptr, len);
+		if (result != USB_STOR_TRANSPORT_GOOD) {
+			if (use_sg)
+				kfree(buffer);
+			return result;
+		}
+
+		// read the result.  apparently the bulk write can complete before the
+		// jumpshot drive is finished writing.  so we loop here until we
+		// get a good return code
+		waitcount = 0;
+		do {
+			result = jumpshot_get_status(us);
+			if (result != USB_STOR_TRANSPORT_GOOD) {
+				// I have not experimented to find the smallest value.
+				//
+				wait_ms(50); 
+			}
+		} while ((result != USB_STOR_TRANSPORT_GOOD) && (waitcount < 10));
+
+		if (result != USB_STOR_TRANSPORT_GOOD)
+			US_DEBUGP("jumpshot_write_data:  Gah!  Waitcount = 10.  Bad write!?\n");
+		
+		sectors -= thistime;
+		sector  += thistime;
+
+                if (use_sg) {
+                        kfree(buffer);
+                } else {
+                        src += len;
+                }
+
+                totallen -= len;
+        } while (totallen > 0);
+
+	return result;
+}
+
+static int jumpshot_id_device(struct us_data *us,
+		              struct jumpshot_info *info)
+{
+	unsigned char command[2] = { 0xe0, 0xec };
+	unsigned char reply[512];
+	int 	 rc;
+
+	if (!us || !info)
+		return USB_STOR_TRANSPORT_ERROR;
+
+	// send the setup
+	rc = jumpshot_send_control(us,
+				   usb_sndctrlpipe(us->pusb_dev, 0),
+				   0, 0x20, 0, 6, command, 2);
+
+	if (rc != USB_STOR_TRANSPORT_GOOD) {
+		US_DEBUGP("jumpshot_id_device:  Gah! send_control for read_capacity failed\n");
+		return rc;
+	}
+
+	// read the reply
+	rc = jumpshot_bulk_read(us, reply, sizeof(reply));
+	if (rc != USB_STOR_TRANSPORT_GOOD)
+		return rc;
+
+	info->sectors = ((u32)(reply[117]) << 24) |
+			((u32)(reply[116]) << 16) |
+			((u32)(reply[115]) <<  8) |
+			((u32)(reply[114])      );
+
+	return USB_STOR_TRANSPORT_GOOD;
+}
+
+static int jumpshot_handle_mode_sense(struct us_data *us,
+				      Scsi_Cmnd * srb, 
+			              unsigned char *ptr,
+			              int sense_6)
+{
+	unsigned char mode_param_header[8] = {
+		0, 0, 0, 0, 0, 0, 0, 0
+	};
+	unsigned char rw_err_page[12] = {
+		0x1, 0xA, 0x21, 1, 0, 0, 0, 0, 1, 0, 0, 0
+	};
+	unsigned char cache_page[12] = {
+		0x8, 0xA, 0x1, 0, 0, 0, 0, 0, 0, 0, 0, 0
+	};
+	unsigned char rbac_page[12] = {
+		0x1B, 0xA, 0, 0x81, 0, 0, 0, 0, 0, 0, 0, 0
+	};
+	unsigned char timer_page[8] = {
+		0x1C, 0x6, 0, 0, 0, 0
+	};
+	unsigned char pc, page_code;
+	unsigned short total_len = 0;
+	unsigned short param_len, i = 0;
+
+
+	if (sense_6)
+		param_len = srb->cmnd[4];
+	else
+		param_len = ((u32) (srb->cmnd[7]) >> 8) | ((u32) (srb->cmnd[8]));
+
+
+	pc = srb->cmnd[2] >> 6;
+	page_code = srb->cmnd[2] & 0x3F;
+
+	switch (pc) {
+	   case 0x0:
+		US_DEBUGP("jumpshot_handle_mode_sense:  Current values\n");
+		break;
+	   case 0x1:
+		US_DEBUGP("jumpshot_handle_mode_sense:  Changeable values\n");
+		break;
+	   case 0x2:
+		US_DEBUGP("jumpshot_handle_mode_sense:  Default values\n");
+		break;
+	   case 0x3:
+		US_DEBUGP("jumpshot_handle_mode_sense:  Saves values\n");
+		break;
+	}
+
+	mode_param_header[3] = 0x80;	// write enable
+
+	switch (page_code) {
+	   case 0x0:
+		// vendor-specific mode
+		return USB_STOR_TRANSPORT_ERROR;
+
+	   case 0x1:
+		total_len = sizeof(rw_err_page);
+		mode_param_header[0] = total_len >> 8;
+		mode_param_header[1] = total_len & 0xFF;
+		mode_param_header[3] = 0x00;	// WP enable: 0x80
+
+		memcpy(ptr, mode_param_header, sizeof(mode_param_header));
+		i += sizeof(mode_param_header);
+		memcpy(ptr + i, rw_err_page, sizeof(rw_err_page));
+		break;
+
+	   case 0x8:
+		total_len = sizeof(cache_page);
+		mode_param_header[0] = total_len >> 8;
+		mode_param_header[1] = total_len & 0xFF;
+		mode_param_header[3] = 0x00;	// WP enable: 0x80
+
+		memcpy(ptr, mode_param_header, sizeof(mode_param_header));
+		i += sizeof(mode_param_header);
+		memcpy(ptr + i, cache_page, sizeof(cache_page));
+		break;
+
+	   case 0x1B:
+		total_len = sizeof(rbac_page);
+		mode_param_header[0] = total_len >> 8;
+		mode_param_header[1] = total_len & 0xFF;
+		mode_param_header[3] = 0x00;	// WP enable: 0x80
+
+		memcpy(ptr, mode_param_header, sizeof(mode_param_header));
+		i += sizeof(mode_param_header);
+		memcpy(ptr + i, rbac_page, sizeof(rbac_page));
+		break;
+
+	   case 0x1C:
+		total_len = sizeof(timer_page);
+		mode_param_header[0] = total_len >> 8;
+		mode_param_header[1] = total_len & 0xFF;
+		mode_param_header[3] = 0x00;	// WP enable: 0x80
+
+		memcpy(ptr, mode_param_header, sizeof(mode_param_header));
+		i += sizeof(mode_param_header);
+		memcpy(ptr + i, timer_page, sizeof(timer_page));
+		break;
+
+	   case 0x3F:
+		total_len = sizeof(timer_page) + sizeof(rbac_page) +
+		    sizeof(cache_page) + sizeof(rw_err_page);
+		mode_param_header[0] = total_len >> 8;
+		mode_param_header[1] = total_len & 0xFF;
+		mode_param_header[3] = 0x00;	// WP enable: 0x80
+
+		memcpy(ptr, mode_param_header, sizeof(mode_param_header));
+		i += sizeof(mode_param_header);
+		memcpy(ptr + i, timer_page, sizeof(timer_page));
+		i += sizeof(timer_page);
+		memcpy(ptr + i, rbac_page, sizeof(rbac_page));
+		i += sizeof(rbac_page);
+		memcpy(ptr + i, cache_page, sizeof(cache_page));
+		i += sizeof(cache_page);
+		memcpy(ptr + i, rw_err_page, sizeof(rw_err_page));
+		break;
+	}
+
+	return USB_STOR_TRANSPORT_GOOD;
+}
+
+
+void jumpshot_info_destructor(void *extra)
+{
+	// this routine is a placeholder...
+	// currently, we don't allocate any extra blocks so we're okay
+}
+
+
+
+// Transport for the Lexar 'Jumpshot'
+//
+int jumpshot_transport(Scsi_Cmnd * srb, struct us_data *us)
+{
+	struct jumpshot_info *info;
+	int rc;
+	unsigned long block, blocks;
+	unsigned char *ptr = NULL;
+	unsigned char inquiry_response[36] = {
+		0x00, 0x80, 0x00, 0x01, 0x1F, 0x00, 0x00, 0x00
+	};
+
+
+	if (!us->extra) {
+		us->extra = kmalloc(sizeof(struct jumpshot_info), GFP_KERNEL);
+		if (!us->extra) {
+			US_DEBUGP("jumpshot_transport:  Gah! Can't allocate storage for jumpshot info struct!\n");
+			return USB_STOR_TRANSPORT_ERROR;
+		}
+		memset(us->extra, 0, sizeof(struct jumpshot_info));
+		us->extra_destructor = jumpshot_info_destructor;
+	}
+
+	info = (struct jumpshot_info *) (us->extra);
+	ptr = (unsigned char *) srb->request_buffer;
+
+	if (srb->cmnd[0] == INQUIRY) {
+		US_DEBUGP("jumpshot_transport:  INQUIRY.  Returning bogus response.\n");
+		memset(inquiry_response + 8, 0, 28);
+		fill_inquiry_response(us, inquiry_response, 36);
+		return USB_STOR_TRANSPORT_GOOD;
+	}
+
+	if (srb->cmnd[0] == READ_CAPACITY) {
+		info->ssize = 0x200;  // hard coded 512 byte sectors as per ATA spec
+
+		rc = jumpshot_get_status(us);
+		if (rc != USB_STOR_TRANSPORT_GOOD)
+			return rc;
+
+		rc = jumpshot_id_device(us, info);
+		if (rc != USB_STOR_TRANSPORT_GOOD)
+			return rc;
+
+		US_DEBUGP("jumpshot_transport:  READ_CAPACITY:  %ld sectors, %ld bytes per sector\n",
+			  info->sectors, info->ssize);
+
+		// build the reply
+		//
+		ptr[0] = (info->sectors >> 24) & 0xFF;
+		ptr[1] = (info->sectors >> 16) & 0xFF;
+		ptr[2] = (info->sectors >> 8) & 0xFF;
+		ptr[3] = (info->sectors) & 0xFF;
+
+		ptr[4] = (info->ssize >> 24) & 0xFF;
+		ptr[5] = (info->ssize >> 16) & 0xFF;
+		ptr[6] = (info->ssize >> 8) & 0xFF;
+		ptr[7] = (info->ssize) & 0xFF;
+
+		return USB_STOR_TRANSPORT_GOOD;
+	}
+
+	if (srb->cmnd[0] == MODE_SELECT_10) {
+		US_DEBUGP("jumpshot_transport:  Gah! MODE_SELECT_10.\n");
+		return USB_STOR_TRANSPORT_ERROR;
+	}
+
+	if (srb->cmnd[0] == READ_10) {
+		block = ((u32)(srb->cmnd[2]) << 24) | ((u32)(srb->cmnd[3]) << 16) |
+		        ((u32)(srb->cmnd[4]) <<  8) | ((u32)(srb->cmnd[5]));
+
+		blocks = ((u32)(srb->cmnd[7]) << 8) | ((u32)(srb->cmnd[8]));
+
+		US_DEBUGP("jumpshot_transport:  READ_10: read block 0x%04lx  count %ld\n", block, blocks);
+		return jumpshot_read_data(us, info, block, blocks, ptr, srb->use_sg);
+	}
+
+	if (srb->cmnd[0] == READ_12) {
+		// I don't think we'll ever see a READ_12 but support it anyway...
+		//
+		block = ((u32)(srb->cmnd[2]) << 24) | ((u32)(srb->cmnd[3]) << 16) |
+		        ((u32)(srb->cmnd[4]) <<  8) | ((u32)(srb->cmnd[5]));
+
+		blocks = ((u32)(srb->cmnd[6]) << 24) | ((u32)(srb->cmnd[7]) << 16) |
+		         ((u32)(srb->cmnd[8]) <<  8) | ((u32)(srb->cmnd[9]));
+
+		US_DEBUGP("jumpshot_transport:  READ_12: read block 0x%04lx  count %ld\n", block, blocks);
+		return jumpshot_read_data(us, info, block, blocks, ptr, srb->use_sg);
+	}
+
+	if (srb->cmnd[0] == WRITE_10) {
+		block = ((u32)(srb->cmnd[2]) << 24) | ((u32)(srb->cmnd[3]) << 16) |
+		        ((u32)(srb->cmnd[4]) <<  8) | ((u32)(srb->cmnd[5]));
+
+		blocks = ((u32)(srb->cmnd[7]) << 8) | ((u32)(srb->cmnd[8]));
+
+		US_DEBUGP("jumpshot_transport:  WRITE_10: write block 0x%04lx  count %ld\n", block, blocks);
+		return jumpshot_write_data(us, info, block, blocks, ptr, srb->use_sg);
+	}
+
+	if (srb->cmnd[0] == WRITE_12) {
+		// I don't think we'll ever see a WRITE_12 but support it anyway...
+		//
+		block = ((u32)(srb->cmnd[2]) << 24) | ((u32)(srb->cmnd[3]) << 16) |
+		        ((u32)(srb->cmnd[4]) <<  8) | ((u32)(srb->cmnd[5]));
+
+		blocks = ((u32)(srb->cmnd[6]) << 24) | ((u32)(srb->cmnd[7]) << 16) |
+		         ((u32)(srb->cmnd[8]) <<  8) | ((u32)(srb->cmnd[9]));
+
+		US_DEBUGP("jumpshot_transport:  WRITE_12: write block 0x%04lx  count %ld\n", block, blocks);
+		return jumpshot_write_data(us, info, block, blocks, ptr, srb->use_sg);
+	}
+
+
+	if (srb->cmnd[0] == TEST_UNIT_READY) {
+		US_DEBUGP("jumpshot_transport:  TEST_UNIT_READY.\n");
+		return jumpshot_get_status(us);
+	}
+
+	if (srb->cmnd[0] == REQUEST_SENSE) {
+		US_DEBUGP("jumpshot_transport:  REQUEST_SENSE.  Returning NO SENSE for now\n");
+
+		ptr[0] = 0xF0;
+		ptr[2] = info->sense_key;
+		ptr[7] = 11;
+		ptr[12] = info->sense_asc;
+		ptr[13] = info->sense_ascq;
+
+		return USB_STOR_TRANSPORT_GOOD;
+	}
+
+	if (srb->cmnd[0] == MODE_SENSE) {
+		US_DEBUGP("jumpshot_transport:  MODE_SENSE_6 detected\n");
+		return jumpshot_handle_mode_sense(us, srb, ptr, TRUE);
+	}
+
+	if (srb->cmnd[0] == MODE_SENSE_10) {
+		US_DEBUGP("jumpshot_transport:  MODE_SENSE_10 detected\n");
+		return jumpshot_handle_mode_sense(us, srb, ptr, FALSE);
+	}
+	
+	if (srb->cmnd[0] == ALLOW_MEDIUM_REMOVAL) {
+		// sure.  whatever.  not like we can stop the user from popping
+		// the media out of the device (no locking doors, etc)
+		//
+		return USB_STOR_TRANSPORT_GOOD;
+	}
+
+	US_DEBUGP("jumpshot_transport:  Gah! Unknown command: %d (0x%x)\n", srb->cmnd[0], srb->cmnd[0]);
+	return USB_STOR_TRANSPORT_ERROR;
+}
diff -u --recursive --new-file v2.4.7/linux/drivers/usb/storage/jumpshot.h linux/drivers/usb/storage/jumpshot.h
--- v2.4.7/linux/drivers/usb/storage/jumpshot.h	Wed Dec 31 16:00:00 1969
+++ linux/drivers/usb/storage/jumpshot.h	Sun Jul 29 21:11:50 2001
@@ -0,0 +1,41 @@
+/* Driver for Lexar "Jumpshot" USB Compact Flash reader
+ * Header File
+ *
+ * Current development and maintenance by:
+ *   (c) 2000 Jimmie Mayfield (mayfield+usb@sackheads.org)
+ *
+ * See jumpshot.c for more explanation
+ *
+ * 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, 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.
+ */
+
+#ifndef _USB_JUMPSHOT_H
+#define _USB_JUMPSHOT_H
+
+#define min(a,b) (((a)<(b))?(a):(b))  // this is defined in tons of header files, i wish it had a standar single definition...
+
+extern int jumpshot_transport(Scsi_Cmnd *srb, struct us_data *us);
+
+struct jumpshot_info {
+   unsigned long   sectors;     // total sector count
+   unsigned long   ssize;       // sector size in bytes
+ 
+   // the following aren't used yet
+   unsigned char   sense_key;
+   unsigned long   sense_asc;   // additional sense code
+   unsigned long   sense_ascq;  // additional sense code qualifier
+};
+
+#endif
diff -u --recursive --new-file v2.4.7/linux/drivers/usb/storage/protocol.c linux/drivers/usb/storage/protocol.c
--- v2.4.7/linux/drivers/usb/storage/protocol.c	Tue Nov 28 21:50:07 2000
+++ linux/drivers/usb/storage/protocol.c	Sun Jul 29 21:11:50 2001
@@ -1,6 +1,6 @@
 /* Driver for USB Mass Storage compliant devices
  *
- * $Id: protocol.c,v 1.7 2000/11/13 22:28:33 mdharm Exp $
+ * $Id: protocol.c,v 1.10 2001/07/30 00:27:59 mdharm Exp $
  *
  * Current development and maintenance by:
  *   (c) 1999, 2000 Matthew Dharm (mdharm-usb@one-eyed-alien.net)
@@ -274,71 +274,67 @@
 
 void usb_stor_transparent_scsi_command(Scsi_Cmnd *srb, struct us_data *us)
 {
+	int old_cmnd = 0;
+
 	/* This code supports devices which do not support {READ|WRITE}_6
 	 * Apparently, neither Windows or MacOS will use these commands,
 	 * so some devices do not support them
 	 */
 	if (us->flags & US_FL_MODE_XLATE) {
+		US_DEBUGP("Invoking Mode Translation\n");
+		/* save the old command for later */
+		old_cmnd = srb->cmnd[0];
 
-		/* translate READ_6 to READ_10 */
-		if (srb->cmnd[0] == 0x08) {
-
-			/* get the control */
-			srb->cmnd[9] = us->srb->cmnd[5];
-
-			/* get the length */
-			srb->cmnd[8] = us->srb->cmnd[6];
+		switch (srb->cmnd[0]) {
+		/* change READ_6/WRITE_6 to READ_10/WRITE_10 */
+		case WRITE_6:
+		case READ_6:
+			srb->cmd_len = 12;
+			srb->cmnd[11] = 0;
+			srb->cmnd[10] = 0;
+			srb->cmnd[9] = 0;
+			srb->cmnd[8] = srb->cmnd[4];
 			srb->cmnd[7] = 0;
-
-			/* set the reserved area to 0 */
-			srb->cmnd[6] = 0;	    
-
-			/* get LBA */
-			srb->cmnd[5] = us->srb->cmnd[3];
-			srb->cmnd[4] = us->srb->cmnd[2];
-			srb->cmnd[3] = 0;
+			srb->cmnd[6] = 0;
+			srb->cmnd[5] = srb->cmnd[3];
+			srb->cmnd[4] = srb->cmnd[2];
+			srb->cmnd[3] = srb->cmnd[1] & 0x1F;
 			srb->cmnd[2] = 0;
-
-			/* LUN and other info in cmnd[1] can stay */
-
-			/* fix command code */
-			srb->cmnd[0] = 0x28;
-
-			US_DEBUGP("Changing READ_6 to READ_10\n");
-			US_DEBUG(usb_stor_show_command(srb));
-		}
-
-		/* translate WRITE_6 to WRITE_10 */
-		if (srb->cmnd[0] == 0x0A) {
-
-			/* get the control */
-			srb->cmnd[9] = us->srb->cmnd[5];
-
-			/* get the length */
-			srb->cmnd[8] = us->srb->cmnd[4];
+			srb->cmnd[1] = srb->cmnd[1] & 0xE0;
+			srb->cmnd[0] = srb->cmnd[0] | 0x20;
+			break;
+
+		/* convert MODE_SELECT data here */
+		case MODE_SENSE:
+		case MODE_SELECT:
+			srb->cmd_len = 12;
+			srb->cmnd[11] = 0;
+			srb->cmnd[10] = 0;
+			srb->cmnd[9] = 0;
+			srb->cmnd[8] = srb->cmnd[4];
 			srb->cmnd[7] = 0;
-
-			/* set the reserved area to 0 */
-			srb->cmnd[6] = 0;	    
-
-			/* get LBA */
-			srb->cmnd[5] = us->srb->cmnd[3];
-			srb->cmnd[4] = us->srb->cmnd[2];
+			srb->cmnd[6] = 0;
+			srb->cmnd[5] = 0;
+			srb->cmnd[4] = 0;
 			srb->cmnd[3] = 0;
-			srb->cmnd[2] = 0;
-	    
-			/* LUN and other info in cmnd[1] can stay */
-
-			/* fix command code */
-			srb->cmnd[0] = 0x2A;
-
-			US_DEBUGP("Changing WRITE_6 to WRITE_10\n");
-			US_DEBUG(usb_stor_show_command(us->srb));
-		}
+			srb->cmnd[2] = srb->cmnd[2];
+			srb->cmnd[1] = srb->cmnd[1];
+			srb->cmnd[0] = srb->cmnd[0] | 0x40;
+			break;
+		} /* switch (srb->cmnd[0]) */
 	} /* if (us->flags & US_FL_MODE_XLATE) */
 
+	/* convert MODE_SELECT data here */
+	if ((us->flags & US_FL_MODE_XLATE) && (old_cmnd == MODE_SELECT))
+		usb_stor_scsiSense6to10(srb);
+
 	/* send the command to the transport layer */
 	usb_stor_invoke_transport(srb, us);
+
+	/* Fix the MODE_SENSE data if we translated the command */
+	if ((us->flags & US_FL_MODE_XLATE) && (old_cmnd == MODE_SENSE)
+			&& (status_byte(srb->result) == GOOD))
+		usb_stor_scsiSense10to6(srb);
 
 	/* fix the INQUIRY data if necessary */
 	fix_inquiry_data(srb);
diff -u --recursive --new-file v2.4.7/linux/drivers/usb/storage/protocol.h linux/drivers/usb/storage/protocol.h
--- v2.4.7/linux/drivers/usb/storage/protocol.h	Sat Jul 28 18:21:38 2001
+++ linux/drivers/usb/storage/protocol.h	Mon Aug  6 22:27:11 2001
@@ -1,7 +1,7 @@
 /* Driver for USB Mass Storage compliant devices
  * Protocol Functions Header File
  *
- * $Id: protocol.h,v 1.3 2000/08/25 00:13:51 mdharm Exp $
+ * $Id: protocol.h,v 1.4 2001/02/13 07:10:03 mdharm Exp $
  *
  * Current development and maintenance by:
  *   (c) 1999, 2000 Matthew Dharm (mdharm-usb@one-eyed-alien.net)
@@ -53,8 +53,9 @@
 #define US_SC_UFI	0x04		/* Floppy */
 #define US_SC_8070	0x05		/* Removable media */
 #define US_SC_SCSI	0x06		/* Transparent */
+#define US_SC_ISD200    0x07            /* ISD200 ATA */
 #define US_SC_MIN	US_SC_RBC
-#define US_SC_MAX	US_SC_SCSI
+#define US_SC_MAX	US_SC_ISD200
 
 extern void usb_stor_ATAPI_command(Scsi_Cmnd*, struct us_data*);
 extern void usb_stor_qic157_command(Scsi_Cmnd*, struct us_data*);
diff -u --recursive --new-file v2.4.7/linux/drivers/usb/storage/scsiglue.c linux/drivers/usb/storage/scsiglue.c
--- v2.4.7/linux/drivers/usb/storage/scsiglue.c	Fri Feb  9 11:30:23 2001
+++ linux/drivers/usb/storage/scsiglue.c	Sun Jul 29 21:11:50 2001
@@ -1,7 +1,7 @@
 /* Driver for USB Mass Storage compliant devices
  * SCSI layer glue code
  *
- * $Id: scsiglue.c,v 1.19 2000/11/13 22:28:55 mdharm Exp $
+ * $Id: scsiglue.c,v 1.21 2001/07/29 23:41:52 mdharm Exp $
  *
  * Current development and maintenance by:
  *   (c) 1999, 2000 Matthew Dharm (mdharm-usb@one-eyed-alien.net)
@@ -49,7 +49,7 @@
 #include "debug.h"
 #include "transport.h"
 
-#include <linux/slab.h>
+#include <linux/malloc.h>
 
 /*
  * kernel thread actions
@@ -122,8 +122,9 @@
 	 */
 	US_DEBUGP("-- sending US_ACT_EXIT command to thread\n");
 	us->action = US_ACT_EXIT;
-	wake_up(&(us->wqh));
-	down(&(us->notify));
+	
+	up(&(us->sema));
+	wait_for_completion(&(us->notify));
 
 	/* remove the pointer to the data structure we were using */
 	(struct us_data*)psh->hostdata[0] = NULL;
@@ -160,7 +161,7 @@
 	up(&(us->queue_exclusion));
 
 	/* wake up the process task */
-	wake_up(&(us->wqh));
+	up(&(us->sema));
 
 	return 0;
 }
@@ -194,7 +195,7 @@
 		usb_unlink_urb(us->current_urb);
 
 		/* wait for us to be done */
-		down(&(us->notify));
+		wait_for_completion(&(us->notify));
 		return SUCCESS;
 	}
 
@@ -248,7 +249,7 @@
         for (i = 0; i < us->pusb_dev->actconfig->bNumInterfaces; i++) {
  		struct usb_interface *intf =
 			&us->pusb_dev->actconfig->interface[i];
-		const struct usb_device_id *id;
+		struct usb_device_id *id;
 
 		/* if this is an unclaimed interface, skip it */
 		if (!intf->driver) {
@@ -331,7 +332,7 @@
 		return -ESRCH;
 	}
 
-	/* print the controler name */
+	/* print the controller name */
 	SPRINTF("   Host scsi%d: usb-storage\n", hostno);
 
 	/* print product, vendor, and serial number strings */
diff -u --recursive --new-file v2.4.7/linux/drivers/usb/storage/sddr09.c linux/drivers/usb/storage/sddr09.c
--- v2.4.7/linux/drivers/usb/storage/sddr09.c	Wed Apr 18 11:49:12 2001
+++ linux/drivers/usb/storage/sddr09.c	Sun Jul 29 21:11:50 2001
@@ -1,13 +1,13 @@
 /* Driver for SanDisk SDDR-09 SmartMedia reader
  *
- * $Id: sddr09.c,v 1.14 2000/11/21 02:58:26 mdharm Exp $
+ * $Id: sddr09.c,v 1.18 2001/06/11 02:54:25 mdharm Exp $
  *
  * SDDR09 driver v0.1:
  *
  * First release
  *
  * Current development and maintenance by:
- *   (c) 2000 Robert Baruch (autophile@dol.net)
+ *   (c) 2000, 2001 Robert Baruch (autophile@starband.net)
  *
  * The SanDisk SDDR-09 SmartMedia reader uses the Shuttle EUSB-01 chip.
  * This chip is a programmable USB controller. In the SDDR-09, it has
@@ -583,6 +583,10 @@
 		*blocksize = 32;
 		return 0x04000000;
 
+	case 0x79: // 128MB
+		*blocksize = 32;
+		return 0x08000000;
+
 	default: // unknown
 		return 0;
 
@@ -691,10 +695,17 @@
 	for (i=0; i<numblocks; i++) {
 		ptr = sg[i>>11].address+(i<<6);
 		if (ptr[0]!=0xFF || ptr[1]!=0xFF || ptr[2]!=0xFF ||
-		    ptr[3]!=0xFF || ptr[4]!=0xFF || ptr[5]!=0xFF)
+		    ptr[3]!=0xFF || ptr[4]!=0xFF || ptr[5]!=0xFF) {
+			US_DEBUGP("PBA %04X has no logical mapping: reserved area = "
+			  "%02X%02X%02X%02X data status %02X block status %02X\n",
+			  i, ptr[0], ptr[1], ptr[2], ptr[3], ptr[4], ptr[5]);
 			continue;
-		if ((ptr[6]>>4)!=0x01)
+		}
+		if ((ptr[6]>>4)!=0x01) {
+			US_DEBUGP("PBA %04X has invalid address field %02X%02X/%02X%02X\n",
+			  i, ptr[6], ptr[7], ptr[11], ptr[12]);
 			continue;
+		}
 
 		/* ensure even parity */
 
@@ -711,21 +722,23 @@
 
 		lba = (lba&0x07FF)>>1;
 
-			/* Every 1024 physical blocks, the LBA numbers
+			/* Every 1024 physical blocks ("zone"), the LBA numbers
 			 * go back to zero, but are within a higher
-			 * block of LBA's. In other words, in blocks
-			 * 1024-2047 you will find LBA 0-1023 which are
-			 * really LBA 1024-2047.
+			 * block of LBA's. Also, there is a maximum of
+			 * 1000 LBA's per zone. In other words, in PBA
+			 * 1024-2047 you will find LBA 0-999 which are
+			 * really LBA 1000-1999. Yes, this wastes 24
+			 * physical blocks per zone. Go figure.
 			 */
 
-		lba += (i&~0x3FF);
+		lba += 1000*(i/0x400);
 
 		if (lba>=numblocks) {
 			US_DEBUGP("Bad LBA %04X for block %04X\n", lba, i);
 			continue;
 		}
 
-		if (lba<0x10)
+		if (lba<0x10 || (lba>=0x3E0 && lba<0x3EF))
 			US_DEBUGP("LBA %04X <-> PBA %04X\n", lba, i);
 
 		info->pba_to_lba[i] = lba;
@@ -812,8 +825,10 @@
 	unsigned char inquiry_response[36] = {
 		0x00, 0x80, 0x00, 0x02, 0x1F, 0x00, 0x00, 0x00
 	};
-	unsigned char mode_page_01[4] = { // write-protected for now
-		0x03, 0x00, 0x80, 0x00
+	unsigned char mode_page_01[16] = { // write-protected for now
+		0x03, 0x00, 0x80, 0x00,
+		0x01, 0x0A,
+		0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
 	};
 	unsigned char *ptr;
 	unsigned long capacity;
@@ -890,10 +905,29 @@
 			// be a check for write-protect here
 
 		if ( (srb->cmnd[2] & 0x3F) == 0x01 ) {
-			if (ptr==NULL || srb->request_bufflen<4)
+
+			US_DEBUGP(
+			  "SDDR09: Dummy up request for mode page 1\n");
+
+			if (ptr==NULL || 
+			  srb->request_bufflen<sizeof(mode_page_01))
 				return USB_STOR_TRANSPORT_ERROR;
+
 			memcpy(ptr, mode_page_01, sizeof(mode_page_01));
 			return USB_STOR_TRANSPORT_GOOD;
+
+		} else if ( (srb->cmnd[2] & 0x3F) == 0x3F ) {
+
+			US_DEBUGP(
+			  "SDDR09: Dummy up request for all mode pages\n");
+
+			if (ptr==NULL || 
+			  srb->request_bufflen<sizeof(mode_page_01))
+				return USB_STOR_TRANSPORT_ERROR;
+
+			memcpy(ptr, mode_page_01, sizeof(mode_page_01));
+			return USB_STOR_TRANSPORT_GOOD;
+
 		}
 
 		// FIXME: sense buffer?
@@ -901,6 +935,17 @@
 		return USB_STOR_TRANSPORT_ERROR;
 	}
 
+	if (srb->cmnd[0] == ALLOW_MEDIUM_REMOVAL) {
+
+		US_DEBUGP(
+		  "SDDR09: %s medium removal. Not that I can do"
+		  " anything about it...\n",
+		  (srb->cmnd[4]&0x03) ? "Prevent" : "Allow");
+
+		return USB_STOR_TRANSPORT_GOOD;
+
+	}
+
 	if (srb->cmnd[0] == READ_10) {
 
 		page = short_pack(srb->cmnd[3], srb->cmnd[2]);
@@ -919,6 +964,10 @@
 			(info->capacity >> 
 				(info->pageshift + info->blockshift) ) ) {
 
+			US_DEBUGP("Error: Requested LBA %04X exceeds maximum "
+			  "block %04X\n", lba,
+			  (info->capacity >> (info->pageshift + info->blockshift))-1);
+
 			// FIXME: sense buffer?
 
 			return USB_STOR_TRANSPORT_ERROR;
@@ -933,6 +982,9 @@
 		if (pba==0 && info->pba_to_lba[0] != lba) {
 
 			// FIXME: sense buffer?
+
+			US_DEBUGP("Error: Requested LBA %04X has no physical block "
+			  "mapping.\n", lba);
 
 			return USB_STOR_TRANSPORT_ERROR;
 		}
diff -u --recursive --new-file v2.4.7/linux/drivers/usb/storage/shuttle_usbat.c linux/drivers/usb/storage/shuttle_usbat.c
--- v2.4.7/linux/drivers/usb/storage/shuttle_usbat.c	Fri Feb  9 11:30:23 2001
+++ linux/drivers/usb/storage/shuttle_usbat.c	Sun Jul 29 21:11:50 2001
@@ -1,9 +1,9 @@
 /* Driver for SCM Microsystems USB-ATAPI cable
  *
- * $Id: shuttle_usbat.c,v 1.11 2000/11/13 22:29:36 mdharm Exp $
+ * $Id: shuttle_usbat.c,v 1.14 2001/03/28 01:02:06 groovyjava Exp $
  *
  * Current development and maintenance by:
- *   (c) 2000 Robert Baruch (autophile@dol.net)
+ *   (c) 2000, 2001 Robert Baruch (autophile@starband.net)
  *
  * Many originally ATAPI devices were slightly modified to meet the USB
  * market by using some kind of translation from ATAPI to USB on the host,
@@ -18,8 +18,8 @@
  * as well. This driver is only guaranteed to work with the ATAPI
  * translation.
  *
- * The only peripheral that I know of (as of 8 Sep 2000) that uses this
- * device is the Hewlett-Packard 8200e/8210e CD-Writer Plus.
+ * The only peripheral that I know of (as of 27 Mar 2001) that uses this
+ * device is the Hewlett-Packard 8200e/8210e/8230e CD-Writer Plus.
  *
  * 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
@@ -344,12 +344,14 @@
 
 		if (result!=USB_STOR_TRANSPORT_GOOD)
 			return result;
-		if (status&0x01) // check condition
+		if (status&0x01) { // check condition
+			result = usbat_read(us, USBAT_ATA, 0x10, &status);
 			return USB_STOR_TRANSPORT_FAILED;
+		}
 		if (status&0x20) // device fault
 			return USB_STOR_TRANSPORT_FAILED;
 
-		if ((status&0x80)!=0x80) { // not busy
+		if ((status&0x80)==0x00) { // not busy
 			US_DEBUGP("Waited not busy for %d steps\n", i);
 			return USB_STOR_TRANSPORT_GOOD;
 		}
@@ -971,6 +973,9 @@
 		registers[i] = 0x10;
 		data[i] = (i-7 >= srb->cmd_len) ? 0 : srb->cmnd[i-7];
 	}
+
+	result = usbat_read(us, USBAT_ATA, 0x17, &status);
+	US_DEBUGP("Status = %02X\n", status);
 
 	if (srb->cmnd[0] == TEST_UNIT_READY)
 		transferred = 0;
diff -u --recursive --new-file v2.4.7/linux/drivers/usb/storage/transport.c linux/drivers/usb/storage/transport.c
--- v2.4.7/linux/drivers/usb/storage/transport.c	Wed Apr 18 11:49:12 2001
+++ linux/drivers/usb/storage/transport.c	Sun Jul 29 21:11:50 2001
@@ -1,6 +1,6 @@
 /* Driver for USB Mass Storage compliant devices
  *
- * $Id: transport.c,v 1.38 2000/11/21 00:52:10 mdharm Exp $
+ * $Id: transport.c,v 1.39 2001/03/10 16:46:28 zagor Exp $
  *
  * Current development and maintenance by:
  *   (c) 1999, 2000 Matthew Dharm (mdharm-usb@one-eyed-alien.net)
@@ -52,7 +52,7 @@
 
 #include <linux/sched.h>
 #include <linux/errno.h>
-#include <linux/slab.h>
+#include <linux/malloc.h>
 
 /***********************************************************************
  * Helper routines
@@ -342,7 +342,7 @@
  * the device -- this is because some devices crash their internal firmware
  * when the status is requested after a halt
  */
-static int clear_halt(struct usb_device *dev, int pipe)
+int usb_stor_clear_halt(struct usb_device *dev, int pipe)
 {
 	int result;
 	int endp = usb_pipeendpoint(pipe) | (usb_pipein(pipe) << 7);
@@ -536,7 +536,7 @@
 	/* if we stall, we need to clear it before we go on */
 	if (result == -EPIPE) {
 		US_DEBUGP("clearing endpoint halt for pipe 0x%x\n", pipe);
-		clear_halt(us->pusb_dev, pipe);
+		usb_stor_clear_halt(us->pusb_dev, pipe);
 	}
 
 	/* did we send all the data? */
@@ -577,7 +577,7 @@
  * function simply determines if we're going to use scatter-gather or not,
  * and acts appropriately.  For now, it also re-interprets the error codes.
  */
-static void us_transfer(Scsi_Cmnd *srb, struct us_data* us)
+void usb_stor_transfer(Scsi_Cmnd *srb, struct us_data* us)
 {
 	int i;
 	int result = -1;
@@ -635,7 +635,7 @@
 /* Invoke the transport and basic error-handling/recovery methods
  *
  * This is used by the protocol layers to actually send the message to
- * the device and receive the response.
+ * the device and recieve the response.
  */
 void usb_stor_invoke_transport(Scsi_Cmnd *srb, struct us_data *us)
 {
@@ -821,7 +821,7 @@
 {
 	struct us_data *us = (struct us_data *)urb->context;
 
-	US_DEBUGP("USB IRQ received for device on host %d\n", us->host_no);
+	US_DEBUGP("USB IRQ recieved for device on host %d\n", us->host_no);
 	US_DEBUGP("-- IRQ data length is %d\n", urb->actual_length);
 	US_DEBUGP("-- IRQ state is %d\n", urb->status);
 	US_DEBUGP("-- Interrupt Status (0x%x, 0x%x)\n",
@@ -895,10 +895,10 @@
 		/* STALL must be cleared when they are detected */
 		if (result == -EPIPE) {
 			US_DEBUGP("-- Stall on control pipe. Clearing\n");
-			result = clear_halt(us->pusb_dev,	
+			result = usb_stor_clear_halt(us->pusb_dev,	
 					    usb_sndctrlpipe(us->pusb_dev,
 							    0));
-			US_DEBUGP("-- clear_halt() returns %d\n", result);
+			US_DEBUGP("-- usb_stor_clear_halt() returns %d\n", result);
 			return USB_STOR_TRANSPORT_FAILED;
 		}
 
@@ -909,7 +909,7 @@
 	/* DATA STAGE */
 	/* transfer the data payload for this command, if one exists*/
 	if (usb_stor_transfer_length(srb)) {
-		us_transfer(srb, us);
+		usb_stor_transfer(srb, us);
 		US_DEBUGP("CBI data stage result is 0x%x\n", srb->result);
 
 		/* if it was aborted, we need to indicate that */
@@ -999,10 +999,10 @@
 		/* a stall is a fatal condition from the device */
 		if (result == -EPIPE) {
 			US_DEBUGP("-- Stall on control pipe. Clearing\n");
-			result = clear_halt(us->pusb_dev, 
+			result = usb_stor_clear_halt(us->pusb_dev, 
 					    usb_sndctrlpipe(us->pusb_dev,
 							    0));
-			US_DEBUGP("-- clear_halt() returns %d\n", result);
+			US_DEBUGP("-- usb_stor_clear_halt() returns %d\n", result);
 			return USB_STOR_TRANSPORT_FAILED;
 		}
 
@@ -1013,7 +1013,7 @@
 	/* DATA STAGE */
 	/* transfer the data payload for this command, if one exists*/
 	if (usb_stor_transfer_length(srb)) {
-		us_transfer(srb, us);
+		usb_stor_transfer(srb, us);
 		US_DEBUGP("CB data stage result is 0x%x\n", srb->result);
 
 		/* if it was aborted, we need to indicate that */
@@ -1057,7 +1057,7 @@
 	/* if we get a STALL, clear the stall */
 	if (result == -EPIPE) {
 		US_DEBUGP("clearing endpoint halt for pipe 0x%x\n", pipe);
-		clear_halt(us->pusb_dev, pipe);
+		usb_stor_clear_halt(us->pusb_dev, pipe);
 	}
 
 	/* return the default -- no LUNs */
@@ -1111,17 +1111,17 @@
 	/* if we stall, we need to clear it before we go on */
 	if (result == -EPIPE) {
 		US_DEBUGP("clearing endpoint halt for pipe 0x%x\n", pipe);
-		clear_halt(us->pusb_dev, pipe);
+		usb_stor_clear_halt(us->pusb_dev, pipe);
 	} else if (result) {
 		/* unknown error -- we've got a problem */
 		return USB_STOR_TRANSPORT_ERROR;
 	}
 
-	/* if the command transferred well, then we go to the data stage */
+	/* if the command transfered well, then we go to the data stage */
 	if (result == 0) {
 		/* send/receive data payload, if there is any */
 		if (bcb.DataTransferLength) {
-			us_transfer(srb, us);
+			usb_stor_transfer(srb, us);
 			US_DEBUGP("Bulk data transfer result 0x%x\n", 
 				  srb->result);
 
@@ -1150,7 +1150,7 @@
 	/* did the attempt to read the CSW fail? */
 	if (result == -EPIPE) {
 		US_DEBUGP("clearing endpoint halt for pipe 0x%x\n", pipe);
-		clear_halt(us->pusb_dev, pipe);
+		usb_stor_clear_halt(us->pusb_dev, pipe);
 	       
 		/* get the status again */
 		US_DEBUGP("Attempting to get CSW (2nd try)...\n");
@@ -1164,7 +1164,7 @@
 		/* if it fails again, we need a reset and return an error*/
 		if (result == -EPIPE) {
 			US_DEBUGP("clearing halt for pipe 0x%x\n", pipe);
-			clear_halt(us->pusb_dev, pipe);
+			usb_stor_clear_halt(us->pusb_dev, pipe);
 			return USB_STOR_TRANSPORT_ERROR;
 		}
 	}
@@ -1243,10 +1243,10 @@
 	set_current_state(TASK_RUNNING);
 
 	US_DEBUGP("CB_reset: clearing endpoint halt\n");
-	clear_halt(us->pusb_dev, 
-		   usb_rcvbulkpipe(us->pusb_dev, us->ep_in));
-	clear_halt(us->pusb_dev, 
-		   usb_rcvbulkpipe(us->pusb_dev, us->ep_out));
+	usb_stor_clear_halt(us->pusb_dev, 
+			    usb_rcvbulkpipe(us->pusb_dev, us->ep_in));
+	usb_stor_clear_halt(us->pusb_dev, 
+			    usb_rcvbulkpipe(us->pusb_dev, us->ep_out));
 
 	US_DEBUGP("CB_reset done\n");
 	/* return a result code based on the result of the control message */
@@ -1282,10 +1282,10 @@
 	schedule_timeout(HZ*6);
 	set_current_state(TASK_RUNNING);
 
-	clear_halt(us->pusb_dev, 
-		   usb_rcvbulkpipe(us->pusb_dev, us->ep_in));
-	clear_halt(us->pusb_dev, 
-		   usb_sndbulkpipe(us->pusb_dev, us->ep_out));
+	usb_stor_clear_halt(us->pusb_dev, 
+			    usb_rcvbulkpipe(us->pusb_dev, us->ep_in));
+	usb_stor_clear_halt(us->pusb_dev, 
+			    usb_sndbulkpipe(us->pusb_dev, us->ep_out));
 	US_DEBUGP("Bulk soft reset completed\n");
 	return SUCCESS;
 }
diff -u --recursive --new-file v2.4.7/linux/drivers/usb/storage/transport.h linux/drivers/usb/storage/transport.h
--- v2.4.7/linux/drivers/usb/storage/transport.h	Sat Jul 28 18:21:38 2001
+++ linux/drivers/usb/storage/transport.h	Mon Aug  6 22:27:10 2001
@@ -1,7 +1,7 @@
 /* Driver for USB Mass Storage compliant devices
  * Transport Functions Header File
  *
- * $Id: transport.h,v 1.13 2000/10/03 01:06:07 mdharm Exp $
+ * $Id: transport.h,v 1.15 2001/03/17 20:06:23 jrmayfield Exp $
  *
  * Current development and maintenance by:
  *   (c) 1999, 2000 Matthew Dharm (mdharm-usb@one-eyed-alien.net)
@@ -64,6 +64,14 @@
 #define US_PR_FREECOM   0xf1            /* Freecom */
 #endif
 
+#ifdef CONFIG_USB_STORAGE_DATAFAB
+#define US_PR_DATAFAB   0xf2            /* Datafab chipsets */
+#endif
+
+#ifdef CONFIG_USB_STORAGE_JUMPSHOT
+#define US_PR_JUMPSHOT  0xf3            /* Lexar Jumpshot */
+#endif
+
 /*
  * Bulk only data structures
  */
@@ -107,7 +115,7 @@
  * us_bulk_transfer() return codes
  */
 #define US_BULK_TRANSFER_GOOD		0  /* good transfer                 */
-#define US_BULK_TRANSFER_SHORT		1  /* transferred less than expected */
+#define US_BULK_TRANSFER_SHORT		1  /* transfered less than expected */
 #define US_BULK_TRANSFER_FAILED		2  /* transfer died in the middle   */
 #define US_BULK_TRANSFER_ABORTED	3  /* transfer canceled             */
 
@@ -143,4 +151,6 @@
 		unsigned int*);
 extern int usb_stor_control_msg(struct us_data*, unsigned int, u8, u8,
 		u16, u16, void*, u16);
+extern void usb_stor_transfer(Scsi_Cmnd*, struct us_data*);
+extern int usb_stor_clear_halt(struct usb_device*, int );
 #endif
diff -u --recursive --new-file v2.4.7/linux/drivers/usb/storage/unusual_devs.h linux/drivers/usb/storage/unusual_devs.h
--- v2.4.7/linux/drivers/usb/storage/unusual_devs.h	Sat Jul 28 18:21:38 2001
+++ linux/drivers/usb/storage/unusual_devs.h	Mon Aug  6 21:43:17 2001
@@ -1,7 +1,7 @@
 /* Driver for USB Mass Storage compliant devices
  * Ununsual Devices File
  *
- * $Id: unusual_devs.h,v 1.1 2000/12/05 05:38:31 mdharm Exp $
+ * $Id: unusual_devs.h,v 1.16 2001/07/30 00:27:59 mdharm Exp $
  *
  * Current development and maintenance by:
  *   (c) 2000 Matthew Dharm (mdharm-usb@one-eyed-alien.net)
@@ -42,6 +42,12 @@
 		"CD-R/RW Drive",
 		US_SC_8020, US_PR_CBI, NULL, 0), 
 
+UNUSUAL_DEV(  0x03ee, 0x6901, 0x0000, 0x0100,
+		"Mitsumi",
+		"USB FDD",
+		US_SC_UFI, US_PR_CBI, NULL,
+		US_FL_SINGLE_LUN ),
+
 UNUSUAL_DEV(  0x03f0, 0x0107, 0x0200, 0x0200, 
 		"HP",
 		"CD-Writer+",
@@ -54,6 +60,22 @@
 		US_SC_8070, US_PR_SCM_ATAPI, init_8200e, 0), 
 #endif
 
+#ifdef CONFIG_USB_STORAGE_DPCM
+UNUSUAL_DEV(  0x0436, 0x0005, 0x0100, 0x0100,
+		"Microtech",
+		"CameraMate (DPCM_USB)",
+ 		US_SC_SCSI, US_PR_DPCM_USB, NULL,
+		US_FL_START_STOP ),
+#endif
+
+UNUSUAL_DEV(  0x04cb, 0x0100, 0x0000, 0x2210,
+		"Fujifilm",
+		"FinePix 1400Zoom",
+		US_SC_8070, US_PR_CBI, NULL, US_FL_FIX_INQUIRY),
+
+/* Most of the following entries were developed with the help of
+ * Shuttle/SCM directly.
+ */
 UNUSUAL_DEV(  0x04e6, 0x0001, 0x0200, 0x0200, 
 		"Matshita",
 		"LS-120",
@@ -73,21 +95,14 @@
 		US_FL_SINGLE_LUN | US_FL_START_STOP ),
 #endif
 
-#ifdef CONFIG_USB_STORAGE_DPCM
-UNUSUAL_DEV(  0x0436, 0x0005, 0x0100, 0x0100,
-		"Microtech",
-		"CameraMate (DPCM_USB)",
- 		US_SC_SCSI, US_PR_DPCM_USB, NULL,
-		US_FL_START_STOP ),
-
-UNUSUAL_DEV(  0x04e6, 0x0005, 0x0100, 0x0208,
-		"SCM Microsystems Inc",
+/* This entry is from Andries.Brouwer@cwi.nl */
+UNUSUAL_DEV(  0x04e6, 0x0005, 0x0100, 0x0205, 
+		"SCM Microsystems",
 		"eUSB SmartMedia / CompactFlash Adapter",
-		US_SC_SCSI, US_PR_DPCM_USB, NULL,
-		US_FL_START_STOP ),
-#endif
+		US_SC_SCSI, US_PR_DPCM_USB, NULL, 
+		US_FL_START_STOP), 
 
-UNUSUAL_DEV(  0x04e6, 0x0006, 0x0100, 0x0200, 
+UNUSUAL_DEV(  0x04e6, 0x0006, 0x0100, 0x0205, 
 		"Shuttle",
 		"eUSB MMC Adapter",
 		US_SC_SCSI, US_PR_CB, NULL, 
@@ -126,9 +141,17 @@
 		"CD-RW Device",
 		US_SC_8020, US_PR_CB, NULL, 0),
 
-UNUSUAL_DEV(  0x054c, 0x0010, 0x0106, 0x0210, 
+/* Reported by Bob Sass <rls@vectordb.com> -- only rev 1.33 tested */
+UNUSUAL_DEV(  0x050d, 0x0115, 0x0133, 0x0133,
+		"Belkin",
+		"USB SCSI Adaptor",
+		US_SC_SCSI, US_PR_BULK, usb_stor_euscsi_init,
+		US_FL_SCM_MULT_TARG ),
+
+/* This entry is needed because the device reports Sub=ff */
+UNUSUAL_DEV(  0x054c, 0x0010, 0x0106, 0x0322, 
 		"Sony",
-		"DSC-S30/S70/505V/F505", 
+		"DSC-S30/S70/S75/505V/F505", 
 		US_SC_SCSI, US_PR_CB, NULL,
 		US_FL_SINGLE_LUN | US_FL_START_STOP | US_FL_MODE_XLATE ),
 
@@ -138,6 +161,19 @@
 		US_SC_UFI, US_PR_CB, NULL,
 		US_FL_SINGLE_LUN | US_FL_START_STOP ),
 
+/* Submitted by Klaus Mueller <k.mueller@intership.de> */
+UNUSUAL_DEV(  0x054c, 0x002e, 0x0106, 0x0310, 
+		"Sony",
+		"Handycam",
+		US_SC_SCSI, US_PR_CB, NULL,
+		US_FL_SINGLE_LUN | US_FL_START_STOP | US_FL_MODE_XLATE),
+
+UNUSUAL_DEV(  0x054c, 0x0032, 0x0000, 0x9999,
+                "Sony",
+		"Memorystick MSC-U01N",
+		US_SC_UFI, US_PR_CB, NULL,
+		US_FL_SINGLE_LUN | US_FL_START_STOP ),
+		
 UNUSUAL_DEV(  0x057b, 0x0000, 0x0000, 0x0299, 
 		"Y-E Data",
 		"Flashbuster-U",
@@ -155,10 +191,51 @@
 		"USB Hard Disk",
 		US_SC_RBC, US_PR_CB, NULL, 0 ), 
 
-UNUSUAL_DEV(  0x05ab, 0x0031, 0x0100, 0x0100, 
-		"In-System",
-		"USB/IDE Bridge (ATAPI ONLY!)",
-		US_SC_8070, US_PR_BULK, NULL, 0 ), 
+#ifdef CONFIG_USB_STORAGE_ISD200
+UNUSUAL_DEV(  0x05ab, 0x0031, 0x0100, 0x0110,
+                "In-System",
+                "USB/IDE Bridge (ATA/ATAPI)",
+                US_SC_ISD200, US_PR_BULK, isd200_Initialization,
+                0 ),
+
+UNUSUAL_DEV(  0x05ab, 0x0060, 0x0100, 0x0110,
+                "In-System",
+                "USB 2.0/IDE Bridge (ATA/ATAPI)",
+                US_SC_ISD200, US_PR_BULK, isd200_Initialization,
+                0 ),
+
+UNUSUAL_DEV(  0x05ab, 0x0301, 0x0100, 0x0110,
+                "In-System",
+                "Portable USB Harddrive V2",
+                US_SC_ISD200, US_PR_BULK, isd200_Initialization,
+                0 ),
+
+UNUSUAL_DEV(  0x05ab, 0x0351, 0x0100, 0x0110,
+                "In-System",
+                "Portable USB Harddrive V2",
+                US_SC_ISD200, US_PR_BULK, isd200_Initialization,
+                0 ),
+
+UNUSUAL_DEV(  0x05ab, 0x5701, 0x0100, 0x0110,
+                "In-System",
+                "USB Storage Adapter V2",
+                US_SC_ISD200, US_PR_BULK, isd200_Initialization,
+                0 ),
+
+UNUSUAL_DEV(  0x054c, 0x002b, 0x0100, 0x0110,
+                "Sony",
+                "Portable USB Harddrive V2",
+                US_SC_ISD200, US_PR_BULK, isd200_Initialization,
+                0 ),
+#endif
+
+#ifdef CONFIG_USB_STORAGE_JUMPSHOT
+UNUSUAL_DEV(  0x05dc, 0x0001, 0x0000, 0x0001,
+		"Lexar",
+		"Jumpshot USB CF Reader",
+		US_SC_SCSI, US_PR_JUMPSHOT, NULL,
+		US_FL_MODE_XLATE | US_FL_START_STOP ),
+#endif
 
 UNUSUAL_DEV(  0x0644, 0x0000, 0x0100, 0x0100, 
 		"TEAC",
@@ -189,25 +266,32 @@
 		US_SC_SCSI, US_PR_CB, NULL,
 		US_FL_SINGLE_LUN | US_FL_START_STOP),
 
-UNUSUAL_DEV( 0x0781, 0x0100, 0x0100, 0x0100,
+UNUSUAL_DEV(  0x0781, 0x0002, 0x0009, 0x0009, 
+		"Sandisk",
+		"ImageMate SDDR-31",
+		US_SC_SCSI, US_PR_BULK, NULL,
+		US_FL_IGNORE_SER),
+
+UNUSUAL_DEV(  0x0781, 0x0100, 0x0100, 0x0100,
                 "Sandisk",
                 "ImageMate SDDR-12",
                 US_SC_SCSI, US_PR_CB, NULL,
                 US_FL_SINGLE_LUN ),
 
 #ifdef CONFIG_USB_STORAGE_SDDR09
-UNUSUAL_DEV(  0x0781, 0x0200, 0x0100, 0x0100, 
+UNUSUAL_DEV(  0x0781, 0x0200, 0x0000, 0x9999, 
 		"Sandisk",
 		"ImageMate SDDR-09",
 		US_SC_SCSI, US_PR_EUSB_SDDR09, NULL,
 		US_FL_SINGLE_LUN | US_FL_START_STOP ),
 #endif
 
-UNUSUAL_DEV(  0x0781, 0x0002, 0x0009, 0x0009, 
-		"Sandisk",
-		"ImageMate SDDR-31",
-		US_SC_SCSI, US_PR_BULK, NULL,
-		US_FL_IGNORE_SER),
+#ifdef CONFIG_USB_STORAGE_FREECOM
+UNUSUAL_DEV(  0x07ab, 0xfc01, 0x0000, 0x9999,
+                "Freecom",
+                "USB-IDE",
+                US_SC_QIC, US_PR_FREECOM, freecom_init, 0),
+#endif
 
 UNUSUAL_DEV(  0x07af, 0x0004, 0x0100, 0x0100, 
 		"Microtech",
@@ -215,13 +299,6 @@
 		US_SC_SCSI, US_PR_BULK, usb_stor_euscsi_init,
 		US_FL_SCM_MULT_TARG ), 
 
-#ifdef CONFIG_USB_STORAGE_FREECOM
-UNUSUAL_DEV( 0x07ab, 0xfc01, 0x0000, 0x9999,
-                "Freecom",
-                "USB-IDE",
-                US_SC_QIC, US_PR_FREECOM, freecom_init, 0),
-#endif
-
 UNUSUAL_DEV(  0x07af, 0x0005, 0x0100, 0x0100, 
 		"Microtech",
 		"USB-SCSI-HD50",
@@ -236,3 +313,78 @@
 		US_FL_START_STOP ),
 #endif
 
+#ifdef CONFIG_USB_STORAGE_DATAFAB
+UNUSUAL_DEV(  0x07c4, 0xa000, 0x0000, 0x0015,
+		"Datafab",
+		"MDCFE-B USB CF Reader",
+		US_SC_SCSI, US_PR_DATAFAB, NULL,
+		US_FL_MODE_XLATE | US_FL_START_STOP ),
+
+	/*
+	 * The following Datafab-based devices may or may not work
+	 * using the current driver...the 0xffff is arbitrary since I
+	 * don't know what device versions exist for these guys.
+	 *
+	 * The 0xa003 and 0xa004 devices in particular I'm curious about.
+	 * I'm told they exist but so far nobody has come forward to say that
+	 * they work with this driver.  Given the success we've had getting
+	 * other Datafab-based cards operational with this driver, I've decided
+	 * to leave these two devices in the list.
+	 */
+UNUSUAL_DEV( 0x07c4, 0xa001, 0x0000, 0xffff,
+		"SIIG/Datafab",
+		"SIIG/Datafab Memory Stick+CF Reader/Writer",
+		US_SC_SCSI, US_PR_DATAFAB, NULL,
+		US_FL_MODE_XLATE | US_FL_START_STOP ),
+
+UNUSUAL_DEV( 0x07c4, 0xa003, 0x0000, 0xffff,
+		"Datafab/Unknown",
+		"Datafab-based Reader",
+		US_SC_SCSI, US_PR_DATAFAB, NULL,
+		US_FL_MODE_XLATE | US_FL_START_STOP ),
+
+UNUSUAL_DEV( 0x07c4, 0xa004, 0x0000, 0xffff,
+		"Datafab/Unknown",
+		"Datafab-based Reader",
+		US_SC_SCSI, US_PR_DATAFAB, NULL,
+		US_FL_MODE_XLATE | US_FL_START_STOP ),
+
+UNUSUAL_DEV( 0x07c4, 0xa005, 0x0000, 0xffff,
+		"PNY/Datafab",
+		"PNY/Datafab CF+SM Reader",
+		US_SC_SCSI, US_PR_DATAFAB, NULL,
+		US_FL_MODE_XLATE | US_FL_START_STOP ),
+
+UNUSUAL_DEV( 0x07c4, 0xa006, 0x0000, 0xffff,
+		"Simple Tech/Datafab",
+		"Simple Tech/Datafab CF+SM Reader",
+		US_SC_SCSI, US_PR_DATAFAB, NULL,
+		US_FL_MODE_XLATE | US_FL_START_STOP ),
+#endif
+
+/* Casio QV 2x00/3x00/8000 digital still cameras are not conformant
+ * to the USB storage specification in two ways:
+ * - They tell us they are using transport protocol CBI. In reality they
+ *   are using transport protocol CB.
+ * - They don't like the INQUIRY command. So we must handle this command
+ *   of the SCSI layer ourselves.
+ */
+UNUSUAL_DEV( 0x07cf, 0x1001, 0x9009, 0x9009,
+                "Casio",
+                "QV DigitalCamera",
+                US_SC_8070, US_PR_CB, NULL,
+                US_FL_FIX_INQUIRY ),
+
+UNUSUAL_DEV(  0x097a, 0x0001, 0x0000, 0x0001,
+		"Minds@Work",
+		"Digital Wallet",
+ 		US_SC_SCSI, US_PR_CB, NULL,
+		US_FL_MODE_XLATE ),
+
+#ifdef CONFIG_USB_STORAGE_ISD200
+UNUSUAL_DEV(  0x0bf6, 0xa001, 0x0100, 0x0110,
+                "ATI",
+                "USB Cable 205",
+                US_SC_ISD200, US_PR_BULK, isd200_Initialization,
+                0 ),
+#endif
diff -u --recursive --new-file v2.4.7/linux/drivers/usb/storage/usb.c linux/drivers/usb/storage/usb.c
--- v2.4.7/linux/drivers/usb/storage/usb.c	Fri Feb  9 11:30:23 2001
+++ linux/drivers/usb/storage/usb.c	Sun Jul 29 21:11:50 2001
@@ -1,6 +1,6 @@
 /* Driver for USB Mass Storage compliant devices
  *
- * $Id: usb.c,v 1.61 2001/01/13 00:10:59 mdharm Exp $
+ * $Id: usb.c,v 1.67 2001/07/29 23:41:52 mdharm Exp $
  *
  * Current development and maintenance by:
  *   (c) 1999, 2000 Matthew Dharm (mdharm-usb@one-eyed-alien.net)
@@ -53,6 +53,7 @@
 #include "protocol.h"
 #include "debug.h"
 #include "initializers.h"
+
 #ifdef CONFIG_USB_STORAGE_HP8200e
 #include "shuttle_usbat.h"
 #endif
@@ -65,12 +66,22 @@
 #ifdef CONFIG_USB_STORAGE_FREECOM
 #include "freecom.h"
 #endif
+#ifdef CONFIG_USB_STORAGE_ISD200
+#include "isd200.h"
+#endif
+#ifdef CONFIG_USB_STORAGE_DATAFAB
+#include "datafab.h"
+#endif
+#ifdef CONFIG_USB_STORAGE_JUMPSHOT
+#include "jumpshot.h"
+#endif
+
 
 #include <linux/module.h>
 #include <linux/sched.h>
 #include <linux/errno.h>
 #include <linux/init.h>
-#include <linux/slab.h>
+#include <linux/malloc.h>
 
 /* Some informational data */
 MODULE_AUTHOR("Matthew Dharm <mdharm-usb@one-eyed-alien.net>");
@@ -151,7 +162,7 @@
 
 /* The vendor name should be kept at eight characters or less, and
  * the product name should be kept at 16 characters or less. If a device
- * has the US_FL_DUMMY_INQUIRY flag, then the vendor and product names
+ * has the US_FL_FIX_INQUIRY flag, then the vendor and product names
  * normally generated by a device thorugh the INQUIRY response will be
  * taken from this list, and this is the reason for the above size
  * restriction. However, if the flag is not present, then you
@@ -281,7 +292,6 @@
 
 static int usb_stor_control_thread(void * __us)
 {
-	wait_queue_t wait;
 	struct us_data *us = (struct us_data *)__us;
 	int action;
 
@@ -302,17 +312,17 @@
 	unlock_kernel();
 
 	/* set up for wakeups by new commands */
-	init_waitqueue_entry(&wait, current);
-	init_waitqueue_head(&(us->wqh));
-	add_wait_queue(&(us->wqh), &wait);
+	init_MUTEX_LOCKED(&us->sema);
 
 	/* signal that we've started the thread */
-	up(&(us->notify));
+	complete(&(us->notify));
 	set_current_state(TASK_INTERRUPTIBLE);
 
 	for(;;) {
 		US_DEBUGP("*** thread sleeping.\n");
-		schedule();
+		if(down_interruptible(&us->sema))
+			break;
+			
 		US_DEBUGP("*** thread awakened.\n");
 
 		/* lock access to the queue element */
@@ -378,6 +388,24 @@
 				break;
 			}
 
+			/* Handle those devices which need us to fake their
+			 * inquiry data */
+			if ((us->srb->cmnd[0] == INQUIRY) &&
+			    (us->flags & US_FL_FIX_INQUIRY)) {
+			    	unsigned char data_ptr[36] = {
+				    0x00, 0x80, 0x02, 0x02,
+				    0x1F, 0x00, 0x00, 0x00};
+
+			    	US_DEBUGP("Faking INQUIRY command\n");
+				fill_inquiry_response(us, data_ptr, 36);
+				us->srb->result = GOOD << 1;
+
+				set_current_state(TASK_INTERRUPTIBLE);
+				us->srb->scsi_done(us->srb);
+				us->srb = NULL;
+				break;
+			}
+
 			/* lock the device pointers */
 			down(&(us->dev_semaphore));
 
@@ -417,7 +445,7 @@
 			} else {
 				US_DEBUGP("scsi command aborted\n");
 				set_current_state(TASK_INTERRUPTIBLE);
-				up(&(us->notify));
+				complete(&(us->notify));
 			}
 			us->srb = NULL;
 			break;
@@ -435,17 +463,16 @@
 
 		/* exit if we get a signal to exit */
 		if (action == US_ACT_EXIT) {
-			US_DEBUGP("-- US_ACT_EXIT command recieved\n");
+			US_DEBUGP("-- US_ACT_EXIT command received\n");
 			break;
 		}
 	} /* for (;;) */
 
 	/* clean up after ourselves */
 	set_current_state(TASK_INTERRUPTIBLE);
-	remove_wait_queue(&(us->wqh), &wait);
 
 	/* notify the exit routine that we're actually exiting now */
-	up(&(us->notify));
+	complete(&(us->notify));
 
 	return 0;
 }	
@@ -717,7 +744,7 @@
 		}
 
 		/* Initialize the mutexes only when the struct is new */
-		init_MUTEX_LOCKED(&(ss->notify));
+		init_completion(&(ss->notify));
 		init_MUTEX_LOCKED(&(ss->ip_waitq));
 		init_MUTEX(&(ss->queue_exclusion));
 		init_MUTEX(&(ss->irq_urb_sem));
@@ -831,6 +858,24 @@
                         break;
 #endif
 
+#ifdef CONFIG_USB_STORAGE_DATAFAB
+                case US_PR_DATAFAB:
+                        ss->transport_name  = "Datafab Bulk-Only";
+                        ss->transport = datafab_transport;
+                        ss->transport_reset = usb_stor_Bulk_reset;
+                        ss->max_lun = 1;
+                        break;
+#endif
+
+#ifdef CONFIG_USB_STORAGE_JUMPSHOT
+                case US_PR_JUMPSHOT:
+                        ss->transport_name  = "Lexar Jumpshot Control/Bulk";
+                        ss->transport = jumpshot_transport;
+                        ss->transport_reset = usb_stor_Bulk_reset;
+                        ss->max_lun = 1;
+                        break;
+#endif
+
 		default:
 			ss->transport_name = "Unknown";
 			kfree(ss->current_urb);
@@ -879,6 +924,13 @@
 			ss->proto_handler = usb_stor_ufi_command;
 			break;
 
+#ifdef CONFIG_USB_STORAGE_ISD200
+                case US_SC_ISD200:
+                        ss->protocol_name = "ISD200 ATA/ATAPI";
+                        ss->proto_handler = isd200_ata_command;
+                        break;
+#endif
+
 		default:
 			ss->protocol_name = "Unknown";
 			kfree(ss->current_urb);
@@ -907,7 +959,7 @@
 		ss->host_number = my_host_number++;
 
 		/* We abuse this pointer so we can pass the ss pointer to 
-		 * the host controler thread in us_detect.  But how else are
+		 * the host controller thread in us_detect.  But how else are
 		 * we to do it?
 		 */
 		(struct us_data *)ss->htmplt.proc_dir = ss; 
@@ -930,7 +982,7 @@
 		}
 
 		/* wait for the thread to start */
-		down(&(ss->notify));
+		wait_for_completion(&(ss->notify));
 
 		/* now register	 - our detect function will be called */
 		ss->htmplt.module = THIS_MODULE;
diff -u --recursive --new-file v2.4.7/linux/drivers/usb/storage/usb.h linux/drivers/usb/storage/usb.h
--- v2.4.7/linux/drivers/usb/storage/usb.h	Sat Jul 28 18:21:38 2001
+++ linux/drivers/usb/storage/usb.h	Mon Aug  6 22:27:10 2001
@@ -1,7 +1,7 @@
 /* Driver for USB Mass Storage compliant devices
  * Main Header File
  *
- * $Id: usb.h,v 1.12 2000/12/05 03:33:49 mdharm Exp $
+ * $Id: usb.h,v 1.18 2001/07/30 00:27:59 mdharm Exp $
  *
  * Current development and maintenance by:
  *   (c) 1999, 2000 Matthew Dharm (mdharm-usb@one-eyed-alien.net)
@@ -47,6 +47,7 @@
 #include <linux/usb.h>
 #include <linux/blk.h>
 #include <linux/smp_lock.h>
+#include <linux/completion.h>
 #include "scsi.h"
 #include "hosts.h"
 
@@ -94,11 +95,12 @@
 
 /* Flag definitions */
 #define US_FL_SINGLE_LUN      0x00000001 /* allow access to only LUN 0	    */
-#define US_FL_MODE_XLATE      0x00000002 /* translate _6 to _10 comands for
+#define US_FL_MODE_XLATE      0x00000002 /* translate _6 to _10 commands for
 						    Win/MacOS compatibility */
 #define US_FL_START_STOP      0x00000004 /* ignore START_STOP commands	    */
 #define US_FL_IGNORE_SER      0x00000010 /* Ignore the serial number given  */
 #define US_FL_SCM_MULT_TARG   0x00000020 /* supports multiple targets */
+#define US_FL_FIX_INQUIRY     0x00000040 /* INQUIRY response needs fixing */
 
 #define USB_STOR_STRING_LEN 32
 
@@ -165,11 +167,11 @@
 	struct semaphore	current_urb_sem; /* to protect irq_urb	 */
 	struct urb		*current_urb;	 /* non-int USB requests */
 
-	/* the waitqueue for sleeping the control thread */
-	wait_queue_head_t	wqh;		 /* to sleep thread on   */
+	/* the semaphore for sleeping the control thread */
+	struct semaphore	sema;		 /* to sleep thread on   */
 
 	/* mutual exclusion structures */
-	struct semaphore	notify;		 /* thread begin/end	    */
+	struct completion	notify;		 /* thread begin/end	    */
 	struct semaphore	queue_exclusion; /* to protect data structs */
 	struct us_unusual_dev   *unusual_dev;	 /* If unusual device       */
 	void			*extra;		 /* Any extra data          */
diff -u --recursive --new-file v2.4.7/linux/drivers/usb/usb-ohci.c linux/drivers/usb/usb-ohci.c
--- v2.4.7/linux/drivers/usb/usb-ohci.c	Wed Jul 25 17:10:24 2001
+++ linux/drivers/usb/usb-ohci.c	Tue Jul 24 14:20:56 2001
@@ -2,7 +2,7 @@
  * URB OHCI HCD (Host Controller Driver) for USB.
  *
  * (C) Copyright 1999 Roman Weissgaerber <weissg@vienna.at>
- * (C) Copyright 2000 David Brownell <david-b@pacbell.net>
+ * (C) Copyright 2000-2001 David Brownell <dbrownell@users.sourceforge.net>
  * 
  * [ Initialisation is based on Linus'  ]
  * [ uhci code and gregs ohci fragments ]
@@ -12,7 +12,7 @@
  * 
  * History:
  * 
- * 2001/04/08 Identify version on module load gb
+ * 2001/07/17 power management and pmac cleanup (Benjamin Herrenschmidt)
  * 2001/03/24 td/ed hashing to remove bus_to_virt (Steve Longerbeam);
  	pci_map_single (db)
  * 2001/03/21 td and dev/ed allocation uses new pci_pool API (db)
@@ -75,11 +75,8 @@
 
 
 #ifdef CONFIG_PMAC_PBOOK
-/* All this PMAC_PBOOK stuff should disappear when those
- * platforms fully support the 2.4 kernel PCI APIs.
- */
-#include <linux/adb.h>
-#include <linux/pmu.h>
+#include <asm/feature.h>
+#include <asm/pci-bridge.h>
 #ifndef CONFIG_PM
 #define CONFIG_PM
 #endif
@@ -89,7 +86,7 @@
 /*
  * Version Information
  */
-#define DRIVER_VERSION "v5.2"
+#define DRIVER_VERSION "v5.3"
 #define DRIVER_AUTHOR "Roman Weissgaerber <weissg@vienna.at>, David Brownell"
 #define DRIVER_DESC "USB OHCI Host Controller Driver"
 
@@ -136,28 +133,39 @@
 {
 	int		i;
 	int		last = urb_priv->length - 1;
+	int		len;
+	int		dir;
 	struct td	*td;
 
-	for (i = 0; i <= last; i++) {
-		td = urb_priv->td [i];
-		if (td) {
-			int		len;
-			int		dir;
-
-			if ((td->hwINFO & cpu_to_le32 (TD_DP)) == TD_DP_SETUP) {
-				len = 8;
-				dir = PCI_DMA_TODEVICE;
-			} else if (i == last) {
-				len = td->urb->transfer_buffer_length,
-				dir = usb_pipeout (td->urb->pipe)
+	if (last >= 0) {
+
+		/* ISOC, BULK, INTR data buffer starts at td 0 
+		 * CTRL setup starts at td 0 */
+		td = urb_priv->td [0];
+
+		len = td->urb->transfer_buffer_length,
+		dir = usb_pipeout (td->urb->pipe)
 					? PCI_DMA_TODEVICE
 					: PCI_DMA_FROMDEVICE;
-			} else
-				len = dir = 0;
-			if (len && td->data_dma)
-				pci_unmap_single (hc->ohci_dev,
-					td->data_dma, len, dir);
-			td_free (hc, urb_priv->td [i]);
+
+		/* unmap CTRL URB setup */
+		if (usb_pipecontrol (td->urb->pipe)) {
+			pci_unmap_single (hc->ohci_dev, 
+					td->data_dma, 8, PCI_DMA_TODEVICE);
+			
+			/* CTRL data buffer starts at td 1 if len > 0 */
+			if (len && last > 0)
+				td = urb_priv->td [1]; 		
+		} 
+
+		/* unmap data buffer */
+		if (len && td->data_dma)
+			pci_unmap_single (hc->ohci_dev, td->data_dma, len, dir);
+		
+		for (i = 0; i <= last; i++) {
+			td = urb_priv->td [i];
+			if (td)
+				td_free (hc, td);
 		}
 	}
 
@@ -981,7 +989,7 @@
 		}
 		ed->ed_prev = ohci->ed_controltail;
 		if (!ohci->ed_controltail && !ohci->ed_rm_list[0] &&
-			!ohci->ed_rm_list[1]) {
+			!ohci->ed_rm_list[1] && !ohci->sleeping) {
 			ohci->hc_control |= OHCI_CTRL_CLE;
 			writel (ohci->hc_control, &ohci->regs->control);
 		}
@@ -997,7 +1005,7 @@
 		}
 		ed->ed_prev = ohci->ed_bulktail;
 		if (!ohci->ed_bulktail && !ohci->ed_rm_list[0] &&
-			!ohci->ed_rm_list[1]) {
+			!ohci->ed_rm_list[1] && !ohci->sleeping) {
 			ohci->hc_control |= OHCI_CTRL_BLE;
 			writel (ohci->hc_control, &ohci->regs->control);
 		}
@@ -1260,7 +1268,7 @@
 	ed->ed_rm_list = ohci->ed_rm_list[frame];
 	ohci->ed_rm_list[frame] = ed;
 
-	if (!ohci->disabled) {
+	if (!ohci->disabled && !ohci->sleeping) {
 		/* enable SOF interrupt */
 		writel (OHCI_INTR_SF, &ohci->regs->intrstatus);
 		writel (OHCI_INTR_SF, &ohci->regs->intrenable);
@@ -1366,7 +1374,8 @@
 				TD_CC | TD_DP_OUT : TD_CC | TD_R | TD_DP_IN ;
 			td_fill (ohci, info | (cnt? TD_T_TOGGLE:toggle), data, data_len, urb, cnt);
 			cnt++;
-			writel (OHCI_BLF, &ohci->regs->cmdstatus); /* start bulk list */
+			if (!ohci->sleeping)
+				writel (OHCI_BLF, &ohci->regs->cmdstatus); /* start bulk list */
 			break;
 
 		case PIPE_INTERRUPT:
@@ -1391,7 +1400,8 @@
 			info = usb_pipeout (urb->pipe)? 
  				TD_CC | TD_DP_IN | TD_T_DATA1: TD_CC | TD_DP_OUT | TD_T_DATA1;
 			td_fill (ohci, info, data, 0, urb, cnt++);
-			writel (OHCI_CLF, &ohci->regs->cmdstatus); /* start Control list */
+			if (!ohci->sleeping)
+				writel (OHCI_CLF, &ohci->regs->cmdstatus); /* start Control list */
 			break;
 
 		case PIPE_ISOCHRONOUS:
@@ -1611,7 +1621,7 @@
 			writel (0, &ohci->regs->ed_controlcurrent);
 		if (bulk)	/* reset bulk list */
 			writel (0, &ohci->regs->ed_bulkcurrent);
-		if (!ohci->ed_rm_list[!frame]) {
+		if (!ohci->ed_rm_list[!frame] && !ohci->sleeping) {
 			if (ohci->ed_controltail)
 				ohci->hc_control |= OHCI_CTRL_CLE;
 			if (ohci->ed_bulktail)
@@ -2321,6 +2331,7 @@
         memset (ohci->hcca, 0, sizeof (struct ohci_hcca));
 
 	ohci->disabled = 1;
+	ohci->sleeping = 0;
 	ohci->irq = -1;
 	ohci->regs = mem_base;   
 
@@ -2480,6 +2491,7 @@
 		pci_write_config_byte (ohci->ohci_dev, PCI_LATENCY_TIMER, ohci->pci_latency);
 
 	ohci->disabled = 1;
+	ohci->sleeping = 0;
 	if (ohci->bus->root_hub)
 		usb_disconnect (&ohci->bus->root_hub);
 	
@@ -2588,7 +2600,9 @@
 static int
 ohci_pci_suspend (struct pci_dev *dev, u32 state)
 {
-	ohci_t		*ohci = (ohci_t *) dev->driver_data;
+	ohci_t			*ohci = (ohci_t *) dev->driver_data;
+	unsigned long		flags;
+	u16 cmd;
 
 	if ((ohci->hc_control & OHCI_CTRL_HCFS) != OHCI_USB_OPER) {
 		dbg ("can't suspend usb-%s (state is %s)", dev->slot_name,
@@ -2598,14 +2612,65 @@
 
 	/* act as if usb suspend can always be used */
 	info ("USB suspend: usb-%s", dev->slot_name);
+	ohci->sleeping = 1;
+
+	/* First stop processing */
+  	spin_lock_irqsave (&usb_ed_lock, flags);
+	ohci->hc_control &= ~(OHCI_CTRL_PLE|OHCI_CTRL_CLE|OHCI_CTRL_BLE|OHCI_CTRL_IE);
+	writel (ohci->hc_control, &ohci->regs->control);
+	writel (OHCI_INTR_SF, &ohci->regs->intrstatus);
+	(void) readl (&ohci->regs->intrstatus);
+  	spin_unlock_irqrestore (&usb_ed_lock, flags);
+
+	/* Wait a frame or two */
+	mdelay(1);
+	if (!readl (&ohci->regs->intrstatus) & OHCI_INTR_SF)
+		mdelay (1);
+		
 #ifdef CONFIG_PMAC_PBOOK
-	disable_irq (ohci->irq);
+	if (_machine == _MACH_Pmac)
+		disable_irq (ohci->irq);
 	/* else, 2.4 assumes shared irqs -- don't disable */
 #endif
+	/* Enable remote wakeup */
+	writel (readl(&ohci->regs->intrenable) | OHCI_INTR_RD, &ohci->regs->intrenable);
+
+	/* Suspend chip and let things settle down a bit */
 	ohci->hc_control = OHCI_USB_SUSPEND;
 	writel (ohci->hc_control, &ohci->regs->control);
-	wait_ms (10);
+	(void) readl (&ohci->regs->control);
+	mdelay (500); /* No schedule here ! */
+	switch (readl (&ohci->regs->control) & OHCI_CTRL_HCFS) {
+		case OHCI_USB_RESET:
+			dbg("Bus in reset phase ???");
+			break;
+		case OHCI_USB_RESUME:
+			dbg("Bus in resume phase ???");
+			break;
+		case OHCI_USB_OPER:
+			dbg("Bus in operational phase ???");
+			break;
+		case OHCI_USB_SUSPEND:
+			dbg("Bus suspended");
+			break;
+	}
+	/* In some rare situations, Apple's OHCI have happily trashed
+	 * memory during sleep. We disable it's bus master bit during
+	 * suspend
+	 */
+	pci_read_config_word (dev, PCI_COMMAND, &cmd);
+	cmd &= ~PCI_COMMAND_MASTER;
+	pci_write_config_word (dev, PCI_COMMAND, cmd);
+#ifdef CONFIG_PMAC_PBOOK
+	{
+   	struct device_node	*of_node;
 
+	/* Disable USB PAD & cell clock */
+	of_node = pci_device_to_OF_node (ohci->ohci_dev);
+	if (of_node && _machine == _MACH_Pmac)
+		feature_set_usb_power (of_node, 0);
+	}
+#endif
 	return 0;
 }
 
@@ -2616,15 +2681,27 @@
 {
 	ohci_t		*ohci = (ohci_t *) dev->driver_data;
 	int		temp;
+	unsigned long	flags;
 
 	/* guard against multiple resumes */
 	atomic_inc (&ohci->resume_count);
 	if (atomic_read (&ohci->resume_count) != 1) {
 		err ("concurrent PCI resumes for usb-%s", dev->slot_name);
 		atomic_dec (&ohci->resume_count);
-		return -EBUSY;
+		return 0;
 	}
 
+#ifdef CONFIG_PMAC_PBOOK
+	{
+	struct device_node *of_node;
+
+	/* Re-enable USB PAD & cell clock */
+	of_node = pci_device_to_OF_node (ohci->ohci_dev);
+	if (of_node && _machine == _MACH_Pmac)
+		feature_set_usb_power (of_node, 1);
+	}
+#endif
+
 	/* did we suspend, or were we powered off? */
 	ohci->hc_control = readl (&ohci->regs->control);
 	temp = ohci->hc_control & OHCI_CTRL_HCFS;
@@ -2634,6 +2711,9 @@
 	ohci_dump_status (ohci);
 #endif
 
+	/* Re-enable bus mastering */
+	pci_set_master(ohci->ohci_dev);
+	
 	switch (temp) {
 
 	case OHCI_USB_RESET:	// lost power
@@ -2648,8 +2728,10 @@
 				? "host" : "remote");
 		ohci->hc_control = OHCI_USB_RESUME;
 		writel (ohci->hc_control, &ohci->regs->control);
-		wait_ms (20);
-
+		(void) readl (&ohci->regs->control);
+		mdelay (20); /* no schedule here ! */
+		/* Some controllers (lucent) need a longer delay here */
+		mdelay (15);
 		temp = readl (&ohci->regs->control);
 		temp = ohci->hc_control & OHCI_CTRL_HCFS;
 		if (temp != OHCI_USB_RESUME) {
@@ -2658,18 +2740,38 @@
 			return -EIO;
 		}
 
+		/* Some chips likes being resumed first */
+		writel (OHCI_USB_OPER, &ohci->regs->control);
+		(void) readl (&ohci->regs->control);
+		mdelay (3);
+
+		/* Then re-enable operations */
+		spin_lock_irqsave (&usb_ed_lock, flags);
 		ohci->disabled = 0;
+		ohci->sleeping = 0;
 		ohci->hc_control = OHCI_CONTROL_INIT | OHCI_USB_OPER;
-		if (!ohci->ed_rm_list[0] & !ohci->ed_rm_list[1]) {
+		if (!ohci->ed_rm_list[0] && !ohci->ed_rm_list[1]) {
 			if (ohci->ed_controltail)
 				ohci->hc_control |= OHCI_CTRL_CLE;
 			if (ohci->ed_bulktail)
 				ohci->hc_control |= OHCI_CTRL_BLE;
 		}
 		writel (ohci->hc_control, &ohci->regs->control);
+		writel (OHCI_INTR_SF, &ohci->regs->intrstatus);
+		writel (OHCI_INTR_SF, &ohci->regs->intrenable);
+		/* Check for a pending done list */
+		writel (OHCI_INTR_WDH, &ohci->regs->intrdisable);	
+		(void) readl (&ohci->regs->intrdisable);
+		spin_unlock_irqrestore (&usb_ed_lock, flags);
 #ifdef CONFIG_PMAC_PBOOK
-		enable_irq (ohci->irq);
+		if (_machine == _MACH_Pmac)
+			enable_irq (ohci->irq);
 #endif
+		if (ohci->hcca->done_head)
+			dl_done_list (ohci, dl_reverse_done_list (ohci));
+		writel (OHCI_INTR_WDH, &ohci->regs->intrenable); 
+		writel (OHCI_BLF, &ohci->regs->cmdstatus); /* start bulk list */
+		writel (OHCI_CLF, &ohci->regs->cmdstatus); /* start Control list */
 		break;
 
 	default:
@@ -2724,71 +2826,24 @@
 	probe:		ohci_pci_probe,
 	remove:		ohci_pci_remove,
 
-#ifdef	CONFIG_PMAC_PBOOK
-	/* pbook PCI thinks different ... for now :-) */
-#else
 #ifdef	CONFIG_PM
 	suspend:	ohci_pci_suspend,
 	resume:		ohci_pci_resume,
 #endif	/* PM */
-#endif	/* PBOOK */
 };
 
  
-#ifdef CONFIG_PMAC_PBOOK
-
-/*-------------------------------------------------------------------------*/
-
-static int ohci_sleep_notify (struct pmu_sleep_notifier * self, int when)
-{
-	struct list_head * ohci_l;
-	ohci_t * ohci;
-       
-	for (ohci_l = ohci_hcd_list.next; ohci_l != &ohci_hcd_list; ohci_l = ohci_l->next) {
-	ohci = list_entry (ohci_l, ohci_t, ohci_hcd_list);
-
-		switch (when) {
-		case PBOOK_SLEEP_NOW:
-			ohci_pci_suspend (ohci->ohci_dev, 3);
-			break;
-		case PBOOK_WAKE:
-			ohci_pci_resume (ohci->ohci_dev);
-			break;
-		}
-	}
-	return PBOOK_SLEEP_OK;
-}
-
-static struct pmu_sleep_notifier ohci_sleep_notifier = {
-       ohci_sleep_notify, SLEEP_LEVEL_MISC,
-};
-#endif /* CONFIG_PMAC_PBOOK */
-
-
 /*-------------------------------------------------------------------------*/
 
 static int __init ohci_hcd_init (void) 
 {
-	int ret;
-
-	if ((ret = pci_module_init (&ohci_pci_driver)) < 0) {
-		return ret;
-	}
-
-#ifdef CONFIG_PMAC_PBOOK
-	pmu_register_sleep_notifier (&ohci_sleep_notifier);
-#endif  
-	info(DRIVER_VERSION ":" DRIVER_DESC);
-	return ret;
+	return pci_module_init (&ohci_pci_driver);
 }
 
 /*-------------------------------------------------------------------------*/
 
 static void __exit ohci_hcd_cleanup (void) 
 {	
-#ifdef CONFIG_PMAC_PBOOK
-	pmu_unregister_sleep_notifier (&ohci_sleep_notifier);
-#endif  
 	pci_unregister_driver (&ohci_pci_driver);
 }
 
diff -u --recursive --new-file v2.4.7/linux/drivers/usb/usb-ohci.h linux/drivers/usb/usb-ohci.h
--- v2.4.7/linux/drivers/usb/usb-ohci.h	Tue Jul  3 17:08:21 2001
+++ linux/drivers/usb/usb-ohci.h	Tue Jul 24 14:20:56 2001
@@ -2,7 +2,7 @@
  * URB OHCI HCD (Host Controller Driver) for USB.
  * 
  * (C) Copyright 1999 Roman Weissgaerber <weissg@vienna.at>
- * (C) Copyright 2000 David Brownell <david-b@pacbell.net>
+ * (C) Copyright 2000-2001 David Brownell <dbrownell@users.sourceforge.net>
  * 
  * usb-ohci.h
  */
@@ -380,6 +380,7 @@
 
 	int irq;
 	int disabled;			/* e.g. got a UE, we're hung */
+	int sleeping;
 	atomic_t resume_count;		/* defending against multiple resumes */
 	unsigned long flags;		/* for HC bugs */
 #define	OHCI_QUIRK_AMD756	0x01		/* erratum #4 */
diff -u --recursive --new-file v2.4.7/linux/drivers/usb/usb.c linux/drivers/usb/usb.c
--- v2.4.7/linux/drivers/usb/usb.c	Wed Jul 25 17:10:24 2001
+++ linux/drivers/usb/usb.c	Tue Jul 24 14:20:56 2001
@@ -2220,7 +2220,6 @@
 			dev->devnum, err);
 		clear_bit(dev->devnum, &dev->bus->devmap.devicemap);
 		dev->devnum = -1;
-		usb_free_dev(dev);
 		return 1;
 	}
 
diff -u --recursive --new-file v2.4.7/linux/drivers/usb/usbkbd.c linux/drivers/usb/usbkbd.c
--- v2.4.7/linux/drivers/usb/usbkbd.c	Tue Jul  3 17:08:21 2001
+++ linux/drivers/usb/usbkbd.c	Sun Aug  5 13:12:41 2001
@@ -1,7 +1,7 @@
 /*
- * $Id: usbkbd.c,v 1.16 2000/08/14 21:05:26 vojtech Exp $
+ * $Id: usbkbd.c,v 1.20 2001/04/26 08:34:49 vojtech Exp $
  *
- *  Copyright (c) 1999-2000 Vojtech Pavlik
+ *  Copyright (c) 1999-2001 Vojtech Pavlik
  *
  *  USB HIDBP Keyboard support
  *
@@ -249,7 +249,7 @@
 			
 	input_register_device(&kbd->dev);
 
-	printk(KERN_INFO "input%d: %s on on usb%d:%d.%d\n",
+	printk(KERN_INFO "input%d: %s on usb%d:%d.%d\n",
 		 kbd->dev.number, kbd->name, dev->bus->busnum, dev->devnum, ifnum);
 
 	return kbd;
diff -u --recursive --new-file v2.4.7/linux/drivers/video/Config.in linux/drivers/video/Config.in
--- v2.4.7/linux/drivers/video/Config.in	Wed Jul 25 17:10:24 2001
+++ linux/drivers/video/Config.in	Tue Jul 31 14:43:29 2001
@@ -59,6 +59,9 @@
    if [ "$CONFIG_ATARI" = "y" ]; then
       bool '  Atari native chipset support' CONFIG_FB_ATARI
       tristate '  ATI Mach64 display support' CONFIG_FB_ATY
+      if [ "$CONFIG_FB_ATY" != "n" ]; then
+	 define_bool CONFIG_FB_ATY_GX y
+      fi
    fi
    if [ "$CONFIG_PPC" = "y" ]; then
       bool '  Open Firmware frame buffer device support' CONFIG_FB_OF
@@ -122,6 +125,10 @@
 	    bool '    Multihead support' CONFIG_FB_MATROX_MULTIHEAD
 	 fi
 	 tristate '  ATI Mach64 display support (EXPERIMENTAL)' CONFIG_FB_ATY
+	 if [ "$CONFIG_FB_ATY" != "n" ]; then
+	    bool '    Mach64 GX support (EXPERIMENTAL)' CONFIG_FB_ATY_GX
+	    bool '    Mach64 CT/VT/GT/LT (incl. 3D RAGE) support' CONFIG_FB_ATY_CT
+	 fi
 	 tristate '  ATI Rage 128 display support (EXPERIMENTAL)' CONFIG_FB_ATY128
 	 tristate '  3Dfx Banshee/Voodoo3 display support (EXPERIMENTAL)' CONFIG_FB_3DFX
 	 tristate '  SIS 630/540 display support (EXPERIMENTAL)' CONFIG_FB_SIS
@@ -157,6 +164,9 @@
 	 bool '  PCI framebuffers' CONFIG_FB_PCI
 	 if [ "$CONFIG_FB_PCI" != "n" ]; then
 	    tristate '    ATI Mach64 display support' CONFIG_FB_ATY
+	    if [ "$CONFIG_FB_ATY" != "n" ]; then
+	       define_bool CONFIG_FB_ATY_CT y
+	    fi
 	 fi
       fi
    fi
diff -u --recursive --new-file v2.4.7/linux/drivers/video/Makefile linux/drivers/video/Makefile
--- v2.4.7/linux/drivers/video/Makefile	Wed Jul 25 17:10:24 2001
+++ linux/drivers/video/Makefile	Tue Jul 31 14:43:29 2001
@@ -46,7 +46,6 @@
 obj-$(CONFIG_FB_APOLLO)           += dnfb.o
 obj-$(CONFIG_FB_Q40)              += q40fb.o
 obj-$(CONFIG_FB_ATARI)            += atafb.o
-obj-$(CONFIG_FB_ATY)              += atyfb.o
 obj-$(CONFIG_FB_ATY128)           += aty128fb.o
 obj-$(CONFIG_FB_IGA)              += igafb.o
 obj-$(CONFIG_FB_CONTROL)          += controlfb.o
@@ -92,6 +91,11 @@
 subdir-$(CONFIG_FB_SIS)		  += sis
 ifeq ($(CONFIG_FB_SIS),y)
 obj-y				  += sis/sisfb.o
+endif
+
+subdir-$(CONFIG_FB_ATY)		  += aty
+ifeq ($(CONFIG_FB_ATY),y)
+obj-y				  += aty/atyfb.o
 endif
 
 obj-$(CONFIG_FB_SUN3)             += sun3fb.o
diff -u --recursive --new-file v2.4.7/linux/drivers/video/aty/Makefile linux/drivers/video/aty/Makefile
--- v2.4.7/linux/drivers/video/aty/Makefile	Wed Dec 31 16:00:00 1969
+++ linux/drivers/video/aty/Makefile	Tue Jul 31 14:43:29 2001
@@ -0,0 +1,12 @@
+
+O_TARGET := atyfb.o
+
+export-objs    :=  atyfb_base.o mach64_accel.o
+
+obj-y				:= atyfb_base.o mach64_accel.o
+obj-$(CONFIG_FB_ATY_GX)		+= mach64_gx.o
+obj-$(CONFIG_FB_ATY_CT)		+= mach64_ct.o mach64_cursor.o
+obj-m				:= $(O_TARGET)
+
+include $(TOPDIR)/Rules.make
+
diff -u --recursive --new-file v2.4.7/linux/drivers/video/aty/atyfb.h linux/drivers/video/aty/atyfb.h
--- v2.4.7/linux/drivers/video/aty/atyfb.h	Wed Dec 31 16:00:00 1969
+++ linux/drivers/video/aty/atyfb.h	Tue Jul 31 14:43:29 2001
@@ -0,0 +1,318 @@
+
+/*
+ *  ATI Frame Buffer Device Driver Core Definitions
+ */
+
+#include <linux/config.h>
+
+
+    /*
+     *  Elements of the hardware specific atyfb_par structure
+     */
+
+struct crtc {
+    u32 vxres;
+    u32 vyres;
+    u32 xoffset;
+    u32 yoffset;
+    u32 bpp;
+    u32 h_tot_disp;
+    u32 h_sync_strt_wid;
+    u32 v_tot_disp;
+    u32 v_sync_strt_wid;
+    u32 off_pitch;
+    u32 gen_cntl;
+    u32 dp_pix_width;	/* acceleration */
+    u32 dp_chain_mask;	/* acceleration */
+};
+
+struct pll_514 {
+    u8 m;
+    u8 n;
+};
+
+struct pll_18818
+{
+    u32 program_bits;
+    u32 locationAddr;
+    u32 period_in_ps;
+    u32 post_divider;
+};
+
+struct pll_ct {
+    u8 pll_ref_div;
+    u8 pll_gen_cntl;
+    u8 mclk_fb_div;
+    u8 pll_vclk_cntl;
+    u8 vclk_post_div;
+    u8 vclk_fb_div;
+    u8 pll_ext_cntl;
+    u32 dsp_config;	/* Mach64 GTB DSP */
+    u32 dsp_on_off;	/* Mach64 GTB DSP */
+    u8 mclk_post_div_real;
+    u8 vclk_post_div_real;
+};
+
+union aty_pll {
+    struct pll_ct ct;
+    struct pll_514 ibm514;
+    struct pll_18818 ics2595;
+};
+
+
+    /*
+     *  The hardware parameters for each card
+     */
+
+struct atyfb_par {
+    struct crtc crtc;
+    union aty_pll pll;
+    u32 accel_flags;
+};
+
+struct aty_cursor {
+    int	enable;
+    int on;
+    int vbl_cnt;
+    int blink_rate;
+    u32 offset;
+    struct {
+        u16 x, y;
+    } pos, hot, size;
+    u32 color[2];
+    u8 bits[8][64];
+    u8 mask[8][64];
+    u8 *ram;
+    struct timer_list *timer;
+};
+
+struct fb_info_aty {
+    struct fb_info fb_info;
+    struct fb_info_aty *next;
+    unsigned long ati_regbase_phys;
+    unsigned long ati_regbase;
+    unsigned long frame_buffer_phys;
+    unsigned long frame_buffer;
+    unsigned long clk_wr_offset;
+    struct pci_mmap_map *mmap_map;
+    struct aty_cursor *cursor;
+    struct aty_cmap_regs *aty_cmap_regs;
+    struct { u8 red, green, blue, pad; } palette[256];
+    struct atyfb_par default_par;
+    struct atyfb_par current_par;
+    u32 features;
+    u32 total_vram;
+    u32 ref_clk_per;
+    u32 pll_per;
+    u32 mclk_per;
+    u8 bus_type;
+    u8 ram_type;
+    u8 mem_refresh_rate;
+    const struct aty_dac_ops *dac_ops;
+    const struct aty_pll_ops *pll_ops;
+    struct display disp;
+    struct display_switch dispsw;
+    union {
+#ifdef FBCON_HAS_CFB16
+	u16 cfb16[16];
+#endif
+#ifdef FBCON_HAS_CFB24
+	u32 cfb24[16];
+#endif
+#ifdef FBCON_HAS_CFB32
+	u32 cfb32[16];
+#endif
+    } fbcon_cmap;
+    u8 blitter_may_be_busy;
+#ifdef __sparc__
+    u8 mmaped;
+    int open;
+    int vtconsole;
+    int consolecnt;
+#endif
+#ifdef CONFIG_PMAC_PBOOK
+    unsigned char *save_framebuffer;
+    unsigned long save_pll[64];
+#endif
+};
+
+
+    /*
+     *  ATI Mach64 features
+     */
+
+#define M64_HAS(feature)	((info)->features & (M64F_##feature))
+
+#define M64F_RESET_3D		0x00000001
+#define M64F_MAGIC_FIFO		0x00000002
+#define M64F_GTB_DSP		0x00000004
+#define M64F_FIFO_24		0x00000008
+#define M64F_SDRAM_MAGIC_PLL	0x00000010
+#define M64F_MAGIC_POSTDIV	0x00000020
+#define M64F_INTEGRATED		0x00000040
+#define M64F_CT_BUS		0x00000080
+#define M64F_VT_BUS		0x00000100
+#define M64F_MOBIL_BUS		0x00000200
+#define M64F_GX			0x00000400
+#define M64F_CT			0x00000800
+#define M64F_VT			0x00001000
+#define M64F_GT			0x00002000
+#define M64F_MAGIC_VRAM_SIZE	0x00004000
+#define M64F_G3_PB_1_1		0x00008000
+#define M64F_G3_PB_1024x768	0x00010000
+#define M64F_EXTRA_BRIGHT	0x00020000
+#define M64F_LT_SLEEP		0x00040000
+#define M64F_XL_DLL		0x00080000
+
+
+    /*
+     *  Register access
+     */
+
+static inline u32 aty_ld_le32(int regindex,
+			      const struct fb_info_aty *info)
+{
+    /* Hack for bloc 1, should be cleanly optimized by compiler */
+    if (regindex >= 0x400)
+    	regindex -= 0x800;
+
+#if defined(__mc68000__)
+    return le32_to_cpu(*((volatile u32 *)(info->ati_regbase+regindex)));
+#else
+    return readl (info->ati_regbase + regindex);
+#endif
+}
+
+static inline void aty_st_le32(int regindex, u32 val,
+			       const struct fb_info_aty *info)
+{
+    /* Hack for bloc 1, should be cleanly optimized by compiler */
+    if (regindex >= 0x400)
+    	regindex -= 0x800;
+
+#if defined(__mc68000__)
+    *((volatile u32 *)(info->ati_regbase+regindex)) = cpu_to_le32(val);
+#else
+    writel (val, info->ati_regbase + regindex);
+#endif
+}
+
+static inline u8 aty_ld_8(int regindex,
+			  const struct fb_info_aty *info)
+{
+    /* Hack for bloc 1, should be cleanly optimized by compiler */
+    if (regindex >= 0x400)
+    	regindex -= 0x800;
+
+    return readb (info->ati_regbase + regindex);
+}
+
+static inline void aty_st_8(int regindex, u8 val,
+			    const struct fb_info_aty *info)
+{
+    /* Hack for bloc 1, should be cleanly optimized by compiler */
+    if (regindex >= 0x400)
+    	regindex -= 0x800;
+
+    writeb (val, info->ati_regbase + regindex);
+}
+
+static inline u8 aty_ld_pll(int offset, const struct fb_info_aty *info)
+{
+    u8 res;
+
+    /* write addr byte */
+    aty_st_8(CLOCK_CNTL + 1, (offset << 2), info);
+    /* read the register value */
+    res = aty_ld_8(CLOCK_CNTL + 2, info);
+    return res;
+}
+
+
+    /*
+     *  DAC operations
+     */
+
+struct aty_dac_ops {
+    int (*set_dac)(const struct fb_info_aty *info, const union aty_pll *pll,
+		   u32 bpp, u32 accel);
+};
+
+extern const struct aty_dac_ops aty_dac_ibm514;		/* IBM RGB514 */
+extern const struct aty_dac_ops aty_dac_ati68860b;	/* ATI 68860-B */
+extern const struct aty_dac_ops aty_dac_att21c498;	/* AT&T 21C498 */
+extern const struct aty_dac_ops aty_dac_unsupported;	/* unsupported */
+extern const struct aty_dac_ops aty_dac_ct;		/* Integrated */
+
+
+    /*
+     *  Clock operations
+     */
+
+struct aty_pll_ops {
+    int (*var_to_pll)(const struct fb_info_aty *info, u32 vclk_per, u8 bpp,
+		      union aty_pll *pll);
+    u32 (*pll_to_var)(const struct fb_info_aty *info,
+	    	      const union aty_pll *pll);
+    void (*set_pll)(const struct fb_info_aty *info, const union aty_pll *pll);
+};
+
+extern const struct aty_pll_ops aty_pll_ati18818_1;	/* ATI 18818 */
+extern const struct aty_pll_ops aty_pll_stg1703;	/* STG 1703 */
+extern const struct aty_pll_ops aty_pll_ch8398;		/* Chrontel 8398 */
+extern const struct aty_pll_ops aty_pll_att20c408;	/* AT&T 20C408 */
+extern const struct aty_pll_ops aty_pll_ibm514;		/* IBM RGB514 */
+extern const struct aty_pll_ops aty_pll_unsupported;	/* unsupported */
+extern const struct aty_pll_ops aty_pll_ct;		/* Integrated */
+
+
+extern void aty_set_pll_ct(const struct fb_info_aty *info,
+			   const union aty_pll *pll);
+extern void aty_calc_pll_ct(const struct fb_info_aty *info,
+			    struct pll_ct *pll);
+
+
+    /*
+     *  Hardware cursor support
+     */
+
+extern struct aty_cursor *aty_init_cursor(struct fb_info_aty *fb);
+extern void atyfb_cursor(struct display *p, int mode, int x, int y);
+extern void aty_set_cursor_color(struct fb_info_aty *fb);
+extern void aty_set_cursor_shape(struct fb_info_aty *fb);
+extern int atyfb_set_font(struct display *d, int width, int height);
+
+
+    /*
+     *  Hardware acceleration
+     */
+
+static inline void wait_for_fifo(u16 entries, const struct fb_info_aty *info)
+{
+    while ((aty_ld_le32(FIFO_STAT, info) & 0xffff) >
+	   ((u32)(0x8000 >> entries)));
+}
+
+static inline void wait_for_idle(struct fb_info_aty *info)
+{
+    wait_for_fifo(16, info);
+    while ((aty_ld_le32(GUI_STAT, info) & 1)!= 0);
+    info->blitter_may_be_busy = 0;
+}
+
+extern void aty_reset_engine(const struct fb_info_aty *info);
+extern void aty_init_engine(const struct atyfb_par *par,
+			    struct fb_info_aty *info);
+extern void aty_rectfill(int dstx, int dsty, u_int width, u_int height,
+			 u_int color, struct fb_info_aty *info);
+
+
+    /*
+     *  Text console acceleration
+     */
+
+extern const struct display_switch fbcon_aty8;
+extern const struct display_switch fbcon_aty16;
+extern const struct display_switch fbcon_aty24;
+extern const struct display_switch fbcon_aty32;
+
diff -u --recursive --new-file v2.4.7/linux/drivers/video/aty/atyfb_base.c linux/drivers/video/aty/atyfb_base.c
--- v2.4.7/linux/drivers/video/aty/atyfb_base.c	Wed Dec 31 16:00:00 1969
+++ linux/drivers/video/aty/atyfb_base.c	Tue Jul 31 14:43:29 2001
@@ -0,0 +1,2893 @@
+
+/*
+ *  ATI Frame Buffer Device Driver Core
+ *
+ *	Copyright (C) 1997-2001  Geert Uytterhoeven
+ *	Copyright (C) 1998  Bernd Harries
+ *	Copyright (C) 1998  Eddie C. Dost  (ecd@skynet.be)
+ *
+ *  This driver supports the following ATI graphics chips:
+ *    - ATI Mach64
+ *
+ *  To do: add support for
+ *    - ATI Rage128 (from aty128fb.c)
+ *    - ATI Radeon (from radeonfb.c)
+ *
+ *  This driver is partly based on the PowerMac console driver:
+ *
+ *	Copyright (C) 1996 Paul Mackerras
+ *
+ *  and on the PowerMac ATI/mach64 display driver:
+ *
+ *	Copyright (C) 1997 Michael AK Tesch
+ *
+ *	      with work by Jon Howell
+ *			   Harry AC Eaton
+ *			   Anthony Tong <atong@uiuc.edu>
+ *
+ *  This file is subject to the terms and conditions of the GNU General Public
+ *  License. See the file COPYING in the main directory of this archive for
+ *  more details.
+ *  
+ *  Many thanks to Nitya from ATI devrel for support and patience !
+ */
+
+/******************************************************************************
+
+  TODO:
+
+    - cursor support on all cards and all ramdacs.
+    - cursor parameters controlable via ioctl()s.
+    - guess PLL and MCLK based on the original PLL register values initialized
+      by the BIOS or Open Firmware (if they are initialized).
+
+						(Anyone to help with this?)
+
+******************************************************************************/
+
+
+#include <linux/config.h>
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/errno.h>
+#include <linux/string.h>
+#include <linux/mm.h>
+#include <linux/malloc.h>
+#include <linux/vmalloc.h>
+#include <linux/delay.h>
+#include <linux/selection.h>
+#include <linux/console.h>
+#include <linux/fb.h>
+#include <linux/init.h>
+#include <linux/pci.h>
+#include <linux/vt_kern.h>
+
+#include <asm/io.h>
+#include <asm/uaccess.h>
+
+#include <video/fbcon.h>
+#include <video/fbcon-cfb8.h>
+#include <video/fbcon-cfb16.h>
+#include <video/fbcon-cfb24.h>
+#include <video/fbcon-cfb32.h>
+
+#include "mach64.h"
+#include "atyfb.h"
+
+#ifdef __powerpc__
+#include <asm/prom.h>
+#include <video/macmodes.h>
+#endif
+#ifdef __sparc__
+#include <asm/pbm.h>
+#include <asm/fbio.h>
+#endif
+
+#ifdef CONFIG_ADB_PMU
+#include <linux/adb.h>
+#include <linux/pmu.h>
+#endif
+#ifdef CONFIG_NVRAM
+#include <linux/nvram.h>
+#endif
+#ifdef CONFIG_FB_COMPAT_XPMAC
+#include <asm/vc_ioctl.h>
+#endif
+#ifdef CONFIG_PMAC_BACKLIGHT
+#include <asm/backlight.h>
+#endif
+
+
+/*
+ * Debug flags.
+ */
+#undef DEBUG
+
+/* Make sure n * PAGE_SIZE is protected at end of Aperture for GUI-regs */
+/*  - must be large enough to catch all GUI-Regs   */
+/*  - must be aligned to a PAGE boundary           */
+#define GUI_RESERVE	(1 * PAGE_SIZE)
+
+
+/* FIXME: remove the FAIL definition */
+#define FAIL(x) do { printk(x "\n"); return -EINVAL; } while (0)
+
+
+    /*
+     *  The Hardware parameters for each card
+     */
+
+struct aty_cmap_regs {
+    u8 windex;
+    u8 lut;
+    u8 mask;
+    u8 rindex;
+    u8 cntl;
+};
+
+struct pci_mmap_map {
+    unsigned long voff;
+    unsigned long poff;
+    unsigned long size;
+    unsigned long prot_flag;
+    unsigned long prot_mask;
+};
+
+
+    /*
+     *  Frame buffer device API
+     */
+
+static int atyfb_open(struct fb_info *info, int user);
+static int atyfb_release(struct fb_info *info, int user);
+static int atyfb_get_fix(struct fb_fix_screeninfo *fix, int con,
+			 struct fb_info *fb);
+static int atyfb_get_var(struct fb_var_screeninfo *var, int con,
+			 struct fb_info *fb);
+static int atyfb_set_var(struct fb_var_screeninfo *var, int con,
+			 struct fb_info *fb);
+static int atyfb_pan_display(struct fb_var_screeninfo *var, int con,
+			     struct fb_info *fb);
+static int atyfb_get_cmap(struct fb_cmap *cmap, int kspc, int con,
+			  struct fb_info *info);
+static int atyfb_set_cmap(struct fb_cmap *cmap, int kspc, int con,
+			  struct fb_info *info);
+static int atyfb_ioctl(struct inode *inode, struct file *file, u_int cmd,
+		       u_long arg, int con, struct fb_info *info);
+#ifdef __sparc__
+static int atyfb_mmap(struct fb_info *info, struct file *file,
+		      struct vm_area_struct *vma);
+#endif
+static int atyfb_rasterimg(struct fb_info *info, int start);
+
+
+    /*
+     *  Interface to the low level console driver
+     */
+
+static int atyfbcon_switch(int con, struct fb_info *fb);
+static int atyfbcon_updatevar(int con, struct fb_info *fb);
+static void atyfbcon_blank(int blank, struct fb_info *fb);
+
+
+    /*
+     *  Internal routines
+     */
+
+static int aty_init(struct fb_info_aty *info, const char *name);
+#ifdef CONFIG_ATARI
+static int store_video_par(char *videopar, unsigned char m64_num);
+static char *strtoke(char *s, const char *ct);
+#endif
+
+static void aty_set_crtc(const struct fb_info_aty *info,
+			 const struct crtc *crtc);
+static int aty_var_to_crtc(const struct fb_info_aty *info,
+			   const struct fb_var_screeninfo *var,
+			   struct crtc *crtc);
+static int aty_crtc_to_var(const struct crtc *crtc,
+			   struct fb_var_screeninfo *var);
+
+static void atyfb_set_par(const struct atyfb_par *par,
+			  struct fb_info_aty *info);
+static int atyfb_decode_var(const struct fb_var_screeninfo *var,
+			    struct atyfb_par *par,
+			    const struct fb_info_aty *info);
+static int atyfb_encode_var(struct fb_var_screeninfo *var,
+			    const struct atyfb_par *par,
+			    const struct fb_info_aty *info);
+static void set_off_pitch(struct atyfb_par *par,
+			  const struct fb_info_aty *info);
+static int encode_fix(struct fb_fix_screeninfo *fix,
+		      const struct atyfb_par *par,
+		      const struct fb_info_aty *info);
+static void atyfb_set_dispsw(struct display *disp, struct fb_info_aty *info,
+			     int bpp, int accel);
+static int atyfb_getcolreg(u_int regno, u_int *red, u_int *green, u_int *blue,
+			 u_int *transp, struct fb_info *fb);
+static int atyfb_setcolreg(u_int regno, u_int red, u_int green, u_int blue,
+			 u_int transp, struct fb_info *fb);
+static void do_install_cmap(int con, struct fb_info *info);
+#ifdef CONFIG_PPC
+static int read_aty_sense(const struct fb_info_aty *info);
+#endif
+
+
+    /*
+     *  Interface used by the world
+     */
+
+int atyfb_init(void);
+#ifndef MODULE
+int atyfb_setup(char*);
+#endif
+
+static int currcon = 0;
+
+static struct fb_ops atyfb_ops = {
+	owner:		THIS_MODULE,
+	fb_open:	atyfb_open,
+	fb_release:	atyfb_release,
+	fb_get_fix:	atyfb_get_fix,
+	fb_get_var:	atyfb_get_var,
+	fb_set_var:	atyfb_set_var,
+	fb_get_cmap:	atyfb_get_cmap,
+	fb_set_cmap:	atyfb_set_cmap,
+	fb_pan_display:	atyfb_pan_display,
+	fb_ioctl:	atyfb_ioctl,
+#ifdef __sparc__
+	fb_mmap:	atyfb_mmap,
+#endif
+	fb_rasterimg:	atyfb_rasterimg,
+};
+
+static char atyfb_name[16] = "ATY Mach64";
+static char fontname[40] __initdata = { 0 };
+static char curblink __initdata = 1;
+static char noaccel __initdata = 0;
+static u32 default_vram __initdata = 0;
+static int default_pll __initdata = 0;
+static int default_mclk __initdata = 0;
+
+#ifndef MODULE
+static const char *mode_option __initdata = NULL;
+#endif
+
+#ifdef CONFIG_PPC
+#ifdef CONFIG_NVRAM_NOT_DEFINED
+static int default_vmode __initdata = VMODE_NVRAM;
+static int default_cmode __initdata = CMODE_NVRAM;
+#else
+static int default_vmode __initdata = VMODE_CHOOSE;
+static int default_cmode __initdata = CMODE_CHOOSE;
+#endif
+#endif
+
+#ifdef CONFIG_ATARI
+static unsigned int mach64_count __initdata = 0;
+static unsigned long phys_vmembase[FB_MAX] __initdata = { 0, };
+static unsigned long phys_size[FB_MAX] __initdata = { 0, };
+static unsigned long phys_guiregbase[FB_MAX] __initdata = { 0, };
+#endif
+
+static const char m64n_gx[] __initdata = "mach64GX (ATI888GX00)";
+static const char m64n_cx[] __initdata = "mach64CX (ATI888CX00)";
+static const char m64n_ct[] __initdata = "mach64CT (ATI264CT)";
+static const char m64n_et[] __initdata = "mach64ET (ATI264ET)";
+static const char m64n_vta3[] __initdata = "mach64VTA3 (ATI264VT)";
+static const char m64n_vta4[] __initdata = "mach64VTA4 (ATI264VT)";
+static const char m64n_vtb[] __initdata = "mach64VTB (ATI264VTB)";
+static const char m64n_vt4[] __initdata = "mach64VT4 (ATI264VT4)";
+static const char m64n_gt[] __initdata = "3D RAGE (GT)";
+static const char m64n_gtb[] __initdata = "3D RAGE II+ (GTB)";
+static const char m64n_iic_p[] __initdata = "3D RAGE IIC (PCI)";
+static const char m64n_iic_a[] __initdata = "3D RAGE IIC (AGP)";
+static const char m64n_lt[] __initdata = "3D RAGE LT";
+static const char m64n_ltg[] __initdata = "3D RAGE LT-G";
+static const char m64n_gtc_ba[] __initdata = "3D RAGE PRO (BGA, AGP)";
+static const char m64n_gtc_ba1[] __initdata = "3D RAGE PRO (BGA, AGP, 1x only)";
+static const char m64n_gtc_bp[] __initdata = "3D RAGE PRO (BGA, PCI)";
+static const char m64n_gtc_pp[] __initdata = "3D RAGE PRO (PQFP, PCI)";
+static const char m64n_gtc_ppl[] __initdata = "3D RAGE PRO (PQFP, PCI, limited 3D)";
+static const char m64n_xl[] __initdata = "3D RAGE (XL)";
+static const char m64n_ltp_a[] __initdata = "3D RAGE LT PRO (AGP)";
+static const char m64n_ltp_p[] __initdata = "3D RAGE LT PRO (PCI)";
+static const char m64n_mob_p[] __initdata = "3D RAGE Mobility (PCI)";
+static const char m64n_mob_a[] __initdata = "3D RAGE Mobility (AGP)";
+
+
+static const struct {
+    u16 pci_id, chip_type;
+    u8 rev_mask, rev_val;
+    const char *name;
+    int pll, mclk;
+    u32 features;
+} aty_chips[] __initdata = {
+#ifdef CONFIG_FB_ATY_GX
+    /* Mach64 GX */
+    { 0x4758, 0x00d7, 0x00, 0x00, m64n_gx,      135,  50, M64F_GX },
+    { 0x4358, 0x0057, 0x00, 0x00, m64n_cx,      135,  50, M64F_GX },
+#endif /* CONFIG_FB_ATY_GX */
+
+#ifdef CONFIG_FB_ATY_CT
+    /* Mach64 CT */
+    { 0x4354, 0x4354, 0x00, 0x00, m64n_ct,      135,  60, M64F_CT | M64F_INTEGRATED | M64F_CT_BUS | M64F_MAGIC_FIFO },
+    { 0x4554, 0x4554, 0x00, 0x00, m64n_et,      135,  60, M64F_CT | M64F_INTEGRATED | M64F_CT_BUS | M64F_MAGIC_FIFO },
+
+    /* Mach64 VT */
+    { 0x5654, 0x5654, 0xc7, 0x00, m64n_vta3,    170,  67, M64F_VT | M64F_INTEGRATED | M64F_VT_BUS | M64F_MAGIC_FIFO | M64F_FIFO_24 },
+    { 0x5654, 0x5654, 0xc7, 0x40, m64n_vta4,    200,  67, M64F_VT | M64F_INTEGRATED | M64F_VT_BUS | M64F_MAGIC_FIFO | M64F_FIFO_24 | M64F_MAGIC_POSTDIV },
+    { 0x5654, 0x5654, 0x00, 0x00, m64n_vtb,     200,  67, M64F_VT | M64F_INTEGRATED | M64F_VT_BUS | M64F_GTB_DSP | M64F_FIFO_24 },
+    { 0x5655, 0x5655, 0x00, 0x00, m64n_vtb,     200,  67, M64F_VT | M64F_INTEGRATED | M64F_VT_BUS | M64F_GTB_DSP | M64F_FIFO_24 | M64F_SDRAM_MAGIC_PLL },
+    { 0x5656, 0x5656, 0x00, 0x00, m64n_vt4,     230,  83, M64F_VT | M64F_INTEGRATED | M64F_GTB_DSP },
+
+    /* Mach64 GT (3D RAGE) */
+    { 0x4754, 0x4754, 0x07, 0x00, m64n_gt,      135,  63, M64F_GT | M64F_INTEGRATED | M64F_MAGIC_FIFO | M64F_FIFO_24 | M64F_EXTRA_BRIGHT },
+    { 0x4754, 0x4754, 0x07, 0x01, m64n_gt,      170,  67, M64F_GT | M64F_INTEGRATED | M64F_GTB_DSP | M64F_FIFO_24 | M64F_SDRAM_MAGIC_PLL | M64F_EXTRA_BRIGHT },
+    { 0x4754, 0x4754, 0x07, 0x02, m64n_gt,      200,  67, M64F_GT | M64F_INTEGRATED | M64F_GTB_DSP | M64F_FIFO_24 | M64F_SDRAM_MAGIC_PLL | M64F_EXTRA_BRIGHT },
+    { 0x4755, 0x4755, 0x00, 0x00, m64n_gtb,     200,  67, M64F_GT | M64F_INTEGRATED | M64F_GTB_DSP | M64F_FIFO_24 | M64F_SDRAM_MAGIC_PLL | M64F_EXTRA_BRIGHT },
+    { 0x4756, 0x4756, 0x00, 0x00, m64n_iic_p,   230,  83, M64F_GT | M64F_INTEGRATED | M64F_GTB_DSP | M64F_FIFO_24 | M64F_SDRAM_MAGIC_PLL | M64F_EXTRA_BRIGHT },
+    { 0x4757, 0x4757, 0x00, 0x00, m64n_iic_a,   230,  83, M64F_GT | M64F_INTEGRATED | M64F_GTB_DSP | M64F_FIFO_24 | M64F_SDRAM_MAGIC_PLL | M64F_EXTRA_BRIGHT },
+    { 0x475a, 0x475a, 0x00, 0x00, m64n_iic_a,   230,  83, M64F_GT | M64F_INTEGRATED | M64F_GTB_DSP | M64F_FIFO_24 | M64F_SDRAM_MAGIC_PLL | M64F_EXTRA_BRIGHT },
+
+    /* Mach64 LT */
+    { 0x4c54, 0x4c54, 0x00, 0x00, m64n_lt,      135,  63, M64F_GT | M64F_INTEGRATED | M64F_GTB_DSP },
+    { 0x4c47, 0x4c47, 0x00, 0x00, m64n_ltg,     230,  63, M64F_GT | M64F_INTEGRATED | M64F_GTB_DSP | M64F_SDRAM_MAGIC_PLL | M64F_EXTRA_BRIGHT | M64F_LT_SLEEP | M64F_G3_PB_1024x768 },
+
+    /* Mach64 GTC (3D RAGE PRO) */
+    { 0x4742, 0x4742, 0x00, 0x00, m64n_gtc_ba,  230, 100, M64F_GT | M64F_INTEGRATED | M64F_RESET_3D | M64F_GTB_DSP | M64F_SDRAM_MAGIC_PLL | M64F_EXTRA_BRIGHT },
+    { 0x4744, 0x4744, 0x00, 0x00, m64n_gtc_ba1, 230, 100, M64F_GT | M64F_INTEGRATED | M64F_RESET_3D | M64F_GTB_DSP | M64F_SDRAM_MAGIC_PLL | M64F_EXTRA_BRIGHT },
+    { 0x4749, 0x4749, 0x00, 0x00, m64n_gtc_bp,  230, 100, M64F_GT | M64F_INTEGRATED | M64F_RESET_3D | M64F_GTB_DSP | M64F_SDRAM_MAGIC_PLL | M64F_EXTRA_BRIGHT | M64F_MAGIC_VRAM_SIZE },
+    { 0x4750, 0x4750, 0x00, 0x00, m64n_gtc_pp,  230, 100, M64F_GT | M64F_INTEGRATED | M64F_RESET_3D | M64F_GTB_DSP | M64F_SDRAM_MAGIC_PLL | M64F_EXTRA_BRIGHT },
+    { 0x4751, 0x4751, 0x00, 0x00, m64n_gtc_ppl, 230, 100, M64F_GT | M64F_INTEGRATED | M64F_RESET_3D | M64F_GTB_DSP | M64F_SDRAM_MAGIC_PLL | M64F_EXTRA_BRIGHT },
+
+    /* 3D RAGE XL */
+    { 0x4752, 0x4752, 0x00, 0x00, m64n_xl, 230, 120, M64F_GT | M64F_INTEGRATED | M64F_RESET_3D | M64F_GTB_DSP | M64F_SDRAM_MAGIC_PLL | M64F_EXTRA_BRIGHT | M64F_XL_DLL },
+
+    /* Mach64 LT PRO */
+    { 0x4c42, 0x4c42, 0x00, 0x00, m64n_ltp_a,   230, 100, M64F_GT | M64F_INTEGRATED | M64F_RESET_3D | M64F_GTB_DSP },
+    { 0x4c44, 0x4c44, 0x00, 0x00, m64n_ltp_p,   230, 100, M64F_GT | M64F_INTEGRATED | M64F_RESET_3D | M64F_GTB_DSP },
+    { 0x4c49, 0x4c49, 0x00, 0x00, m64n_ltp_p,   230, 100, M64F_GT | M64F_INTEGRATED | M64F_RESET_3D | M64F_GTB_DSP | M64F_EXTRA_BRIGHT | M64F_G3_PB_1_1 | M64F_G3_PB_1024x768 },
+    { 0x4c50, 0x4c50, 0x00, 0x00, m64n_ltp_p,   230, 100, M64F_GT | M64F_INTEGRATED | M64F_RESET_3D | M64F_GTB_DSP },
+
+    /* 3D RAGE Mobility */
+    { 0x4c4d, 0x4c4d, 0x00, 0x00, m64n_mob_p,   230,  50, M64F_GT | M64F_INTEGRATED | M64F_RESET_3D | M64F_GTB_DSP | M64F_MOBIL_BUS },
+    { 0x4c4e, 0x4c4e, 0x00, 0x00, m64n_mob_a,   230,  50, M64F_GT | M64F_INTEGRATED | M64F_RESET_3D | M64F_GTB_DSP | M64F_MOBIL_BUS },
+#endif /* CONFIG_FB_ATY_CT */
+};
+
+static const char ram_dram[] __initdata = "DRAM";
+static const char ram_vram[] __initdata = "VRAM";
+static const char ram_edo[] __initdata = "EDO";
+static const char ram_sdram[] __initdata = "SDRAM";
+static const char ram_sgram[] __initdata = "SGRAM";
+static const char ram_wram[] __initdata = "WRAM";
+static const char ram_off[] __initdata = "OFF";
+static const char ram_resv[] __initdata = "RESV";
+
+#ifdef CONFIG_FB_ATY_GX
+static const char *aty_gx_ram[8] __initdata = {
+    ram_dram, ram_vram, ram_vram, ram_dram,
+    ram_dram, ram_vram, ram_vram, ram_resv
+};
+#endif /* CONFIG_FB_ATY_GX */
+
+#ifdef CONFIG_FB_ATY_CT
+static const char *aty_ct_ram[8] __initdata = {
+    ram_off, ram_dram, ram_edo, ram_edo,
+    ram_sdram, ram_sgram, ram_wram, ram_resv
+};
+#endif /* CONFIG_FB_ATY_CT */
+
+
+#if defined(CONFIG_PPC)
+
+    /*
+     *  Apple monitor sense
+     */
+
+static int __init read_aty_sense(const struct fb_info_aty *info)
+{
+    int sense, i;
+
+    aty_st_le32(GP_IO, 0x31003100, info);	/* drive outputs high */
+    __delay(200);
+    aty_st_le32(GP_IO, 0, info);		/* turn off outputs */
+    __delay(2000);
+    i = aty_ld_le32(GP_IO, info);		/* get primary sense value */
+    sense = ((i & 0x3000) >> 3) | (i & 0x100);
+
+    /* drive each sense line low in turn and collect the other 2 */
+    aty_st_le32(GP_IO, 0x20000000, info);	/* drive A low */
+    __delay(2000);
+    i = aty_ld_le32(GP_IO, info);
+    sense |= ((i & 0x1000) >> 7) | ((i & 0x100) >> 4);
+    aty_st_le32(GP_IO, 0x20002000, info);	/* drive A high again */
+    __delay(200);
+
+    aty_st_le32(GP_IO, 0x10000000, info);	/* drive B low */
+    __delay(2000);
+    i = aty_ld_le32(GP_IO, info);
+    sense |= ((i & 0x2000) >> 10) | ((i & 0x100) >> 6);
+    aty_st_le32(GP_IO, 0x10001000, info);	/* drive B high again */
+    __delay(200);
+
+    aty_st_le32(GP_IO, 0x01000000, info);	/* drive C low */
+    __delay(2000);
+    sense |= (aty_ld_le32(GP_IO, info) & 0x3000) >> 12;
+    aty_st_le32(GP_IO, 0, info);		/* turn off outputs */
+
+    return sense;
+}
+
+#endif /* defined(CONFIG_PPC) */
+
+#if defined(CONFIG_PMAC_PBOOK) || defined(CONFIG_PMAC_BACKLIGHT)
+static void aty_st_lcd(int index, u32 val, const struct fb_info_aty *info)
+{
+    unsigned long temp;
+
+    /* write addr byte */
+    temp = aty_ld_le32(LCD_INDEX, info);
+    aty_st_le32(LCD_INDEX, (temp & ~LCD_INDEX_MASK) | index, info);
+    /* write the register value */
+    aty_st_le32(LCD_DATA, val, info);
+}
+
+static u32 aty_ld_lcd(int index, const struct fb_info_aty *info)
+{
+    unsigned long temp;
+
+    /* write addr byte */
+    temp = aty_ld_le32(LCD_INDEX, info);
+    aty_st_le32(LCD_INDEX, (temp & ~LCD_INDEX_MASK) | index, info);
+    /* read the register value */
+    return aty_ld_le32(LCD_DATA, info);
+}
+#endif /* CONFIG_PMAC_PBOOK || CONFIG_PMAC_BACKLIGHT */
+
+/* ------------------------------------------------------------------------- */
+
+    /*
+     *  CRTC programming
+     */
+
+static void aty_set_crtc(const struct fb_info_aty *info,
+			 const struct crtc *crtc)
+{
+    aty_st_le32(CRTC_H_TOTAL_DISP, crtc->h_tot_disp, info);
+    aty_st_le32(CRTC_H_SYNC_STRT_WID, crtc->h_sync_strt_wid, info);
+    aty_st_le32(CRTC_V_TOTAL_DISP, crtc->v_tot_disp, info);
+    aty_st_le32(CRTC_V_SYNC_STRT_WID, crtc->v_sync_strt_wid, info);
+    aty_st_le32(CRTC_VLINE_CRNT_VLINE, 0, info);
+    aty_st_le32(CRTC_OFF_PITCH, crtc->off_pitch, info);
+    aty_st_le32(CRTC_GEN_CNTL, crtc->gen_cntl, info);
+}
+
+static int aty_var_to_crtc(const struct fb_info_aty *info,
+			   const struct fb_var_screeninfo *var,
+			   struct crtc *crtc)
+{
+    u32 xres, yres, vxres, vyres, xoffset, yoffset, bpp;
+    u32 left, right, upper, lower, hslen, vslen, sync, vmode;
+    u32 h_total, h_disp, h_sync_strt, h_sync_dly, h_sync_wid, h_sync_pol;
+    u32 v_total, v_disp, v_sync_strt, v_sync_wid, v_sync_pol, c_sync;
+    u32 pix_width, dp_pix_width, dp_chain_mask;
+
+    /* input */
+    xres = var->xres;
+    yres = var->yres;
+    vxres = var->xres_virtual;
+    vyres = var->yres_virtual;
+    xoffset = var->xoffset;
+    yoffset = var->yoffset;
+    bpp = var->bits_per_pixel;
+    left = var->left_margin;
+    right = var->right_margin;
+    upper = var->upper_margin;
+    lower = var->lower_margin;
+    hslen = var->hsync_len;
+    vslen = var->vsync_len;
+    sync = var->sync;
+    vmode = var->vmode;
+
+    /* convert (and round up) and validate */
+    xres = (xres+7) & ~7;
+    xoffset = (xoffset+7) & ~7;
+    vxres = (vxres+7) & ~7;
+    if (vxres < xres+xoffset)
+	vxres = xres+xoffset;
+    h_disp = xres/8-1;
+    if (h_disp > 0xff)
+	FAIL("h_disp too large");
+    h_sync_strt = h_disp+(right/8);
+    if (h_sync_strt > 0x1ff)
+	FAIL("h_sync_start too large");
+    h_sync_dly = right & 7;
+    h_sync_wid = (hslen+7)/8;
+    if (h_sync_wid > 0x1f)
+	FAIL("h_sync_wid too large");
+    h_total = h_sync_strt+h_sync_wid+(h_sync_dly+left+7)/8;
+    if (h_total > 0x1ff)
+	FAIL("h_total too large");
+    h_sync_pol = sync & FB_SYNC_HOR_HIGH_ACT ? 0 : 1;
+
+    if (vyres < yres+yoffset)
+	vyres = yres+yoffset;
+    v_disp = yres-1;
+    if (v_disp > 0x7ff)
+	FAIL("v_disp too large");
+    v_sync_strt = v_disp+lower;
+    if (v_sync_strt > 0x7ff)
+	FAIL("v_sync_strt too large");
+    v_sync_wid = vslen;
+    if (v_sync_wid > 0x1f)
+	FAIL("v_sync_wid too large");
+    v_total = v_sync_strt+v_sync_wid+upper;
+    if (v_total > 0x7ff)
+	FAIL("v_total too large");
+    v_sync_pol = sync & FB_SYNC_VERT_HIGH_ACT ? 0 : 1;
+
+    c_sync = sync & FB_SYNC_COMP_HIGH_ACT ? CRTC_CSYNC_EN : 0;
+
+    if (bpp <= 8) {
+	bpp = 8;
+	pix_width = CRTC_PIX_WIDTH_8BPP;
+	dp_pix_width = HOST_8BPP | SRC_8BPP | DST_8BPP | BYTE_ORDER_LSB_TO_MSB;
+	dp_chain_mask = 0x8080;
+    } else if (bpp <= 16) {
+	bpp = 16;
+	pix_width = CRTC_PIX_WIDTH_15BPP;
+	dp_pix_width = HOST_15BPP | SRC_15BPP | DST_15BPP |
+		       BYTE_ORDER_LSB_TO_MSB;
+	dp_chain_mask = 0x4210;
+    } else if (bpp <= 24 && M64_HAS(INTEGRATED)) {
+	bpp = 24;
+	pix_width = CRTC_PIX_WIDTH_24BPP;
+	dp_pix_width = HOST_8BPP | SRC_8BPP | DST_8BPP | BYTE_ORDER_LSB_TO_MSB;
+	dp_chain_mask = 0x8080;
+    } else if (bpp <= 32) {
+	bpp = 32;
+	pix_width = CRTC_PIX_WIDTH_32BPP;
+	dp_pix_width = HOST_32BPP | SRC_32BPP | DST_32BPP |
+		       BYTE_ORDER_LSB_TO_MSB;
+	dp_chain_mask = 0x8080;
+    } else
+	FAIL("invalid bpp");
+
+    if (vxres*vyres*bpp/8 > info->total_vram)
+	FAIL("not enough video RAM");
+
+    if ((vmode & FB_VMODE_MASK) != FB_VMODE_NONINTERLACED)
+	FAIL("invalid vmode");
+
+    /* output */
+    crtc->vxres = vxres;
+    crtc->vyres = vyres;
+    crtc->xoffset = xoffset;
+    crtc->yoffset = yoffset;
+    crtc->bpp = bpp;
+    crtc->h_tot_disp = h_total | (h_disp<<16);
+    crtc->h_sync_strt_wid = (h_sync_strt & 0xff) | (h_sync_dly<<8) |
+			    ((h_sync_strt & 0x100)<<4) | (h_sync_wid<<16) |
+			    (h_sync_pol<<21);
+    crtc->v_tot_disp = v_total | (v_disp<<16);
+    crtc->v_sync_strt_wid = v_sync_strt | (v_sync_wid<<16) | (v_sync_pol<<21);
+    crtc->off_pitch = ((yoffset*vxres+xoffset)*bpp/64) | (vxres<<19);
+    crtc->gen_cntl = pix_width | c_sync | CRTC_EXT_DISP_EN | CRTC_ENABLE;
+    if (M64_HAS(MAGIC_FIFO)) {
+	/* Not VTB/GTB */
+	/* FIXME: magic FIFO values */
+	crtc->gen_cntl |= aty_ld_le32(CRTC_GEN_CNTL, info) & 0x000e0000;
+    }
+    crtc->dp_pix_width = dp_pix_width;
+    crtc->dp_chain_mask = dp_chain_mask;
+
+    return 0;
+}
+
+
+static int aty_crtc_to_var(const struct crtc *crtc,
+			   struct fb_var_screeninfo *var)
+{
+    u32 xres, yres, bpp, left, right, upper, lower, hslen, vslen, sync;
+    u32 h_total, h_disp, h_sync_strt, h_sync_dly, h_sync_wid, h_sync_pol;
+    u32 v_total, v_disp, v_sync_strt, v_sync_wid, v_sync_pol, c_sync;
+    u32 pix_width;
+
+    /* input */
+    h_total = crtc->h_tot_disp & 0x1ff;
+    h_disp = (crtc->h_tot_disp>>16) & 0xff;
+    h_sync_strt = (crtc->h_sync_strt_wid & 0xff) |
+		  ((crtc->h_sync_strt_wid>>4) & 0x100);
+    h_sync_dly = (crtc->h_sync_strt_wid>>8) & 0x7;
+    h_sync_wid = (crtc->h_sync_strt_wid>>16) & 0x1f;
+    h_sync_pol = (crtc->h_sync_strt_wid>>21) & 0x1;
+    v_total = crtc->v_tot_disp & 0x7ff;
+    v_disp = (crtc->v_tot_disp>>16) & 0x7ff;
+    v_sync_strt = crtc->v_sync_strt_wid & 0x7ff;
+    v_sync_wid = (crtc->v_sync_strt_wid>>16) & 0x1f;
+    v_sync_pol = (crtc->v_sync_strt_wid>>21) & 0x1;
+    c_sync = crtc->gen_cntl & CRTC_CSYNC_EN ? 1 : 0;
+    pix_width = crtc->gen_cntl & CRTC_PIX_WIDTH_MASK;
+
+    /* convert */
+    xres = (h_disp+1)*8;
+    yres = v_disp+1;
+    left = (h_total-h_sync_strt-h_sync_wid)*8-h_sync_dly;
+    right = (h_sync_strt-h_disp)*8+h_sync_dly;
+    hslen = h_sync_wid*8;
+    upper = v_total-v_sync_strt-v_sync_wid;
+    lower = v_sync_strt-v_disp;
+    vslen = v_sync_wid;
+    sync = (h_sync_pol ? 0 : FB_SYNC_HOR_HIGH_ACT) |
+	   (v_sync_pol ? 0 : FB_SYNC_VERT_HIGH_ACT) |
+	   (c_sync ? FB_SYNC_COMP_HIGH_ACT : 0);
+
+    switch (pix_width) {
+#if 0
+	case CRTC_PIX_WIDTH_4BPP:
+	    bpp = 4;
+	    var->red.offset = 0;
+	    var->red.length = 8;
+	    var->green.offset = 0;
+	    var->green.length = 8;
+	    var->blue.offset = 0;
+	    var->blue.length = 8;
+	    var->transp.offset = 0;
+	    var->transp.length = 0;
+	    break;
+#endif
+	case CRTC_PIX_WIDTH_8BPP:
+	    bpp = 8;
+	    var->red.offset = 0;
+	    var->red.length = 8;
+	    var->green.offset = 0;
+	    var->green.length = 8;
+	    var->blue.offset = 0;
+	    var->blue.length = 8;
+	    var->transp.offset = 0;
+	    var->transp.length = 0;
+	    break;
+	case CRTC_PIX_WIDTH_15BPP:	/* RGB 555 */
+	    bpp = 16;
+	    var->red.offset = 10;
+	    var->red.length = 5;
+	    var->green.offset = 5;
+	    var->green.length = 5;
+	    var->blue.offset = 0;
+	    var->blue.length = 5;
+	    var->transp.offset = 0;
+	    var->transp.length = 0;
+	    break;
+#if 0
+	case CRTC_PIX_WIDTH_16BPP:	/* RGB 565 */
+	    bpp = 16;
+	    var->red.offset = 11;
+	    var->red.length = 5;
+	    var->green.offset = 5;
+	    var->green.length = 6;
+	    var->blue.offset = 0;
+	    var->blue.length = 5;
+	    var->transp.offset = 0;
+	    var->transp.length = 0;
+	    break;
+#endif
+	case CRTC_PIX_WIDTH_24BPP:	/* RGB 888 */
+	    bpp = 24;
+	    var->red.offset = 16;
+	    var->red.length = 8;
+	    var->green.offset = 8;
+	    var->green.length = 8;
+	    var->blue.offset = 0;
+	    var->blue.length = 8;
+	    var->transp.offset = 0;
+	    var->transp.length = 0;
+	    break;
+	case CRTC_PIX_WIDTH_32BPP:	/* ARGB 8888 */
+	    bpp = 32;
+	    var->red.offset = 16;
+	    var->red.length = 8;
+	    var->green.offset = 8;
+	    var->green.length = 8;
+	    var->blue.offset = 0;
+	    var->blue.length = 8;
+	    var->transp.offset = 24;
+	    var->transp.length = 8;
+	    break;
+	default:
+	    FAIL("Invalid pixel width");
+    }
+
+    /* output */
+    var->xres = xres;
+    var->yres = yres;
+    var->xres_virtual = crtc->vxres;
+    var->yres_virtual = crtc->vyres;
+    var->bits_per_pixel = bpp;
+    var->xoffset = crtc->xoffset;
+    var->yoffset = crtc->yoffset;
+    var->left_margin = left;
+    var->right_margin = right;
+    var->upper_margin = upper;
+    var->lower_margin = lower;
+    var->hsync_len = hslen;
+    var->vsync_len = vslen;
+    var->sync = sync;
+    var->vmode = FB_VMODE_NONINTERLACED;
+
+    return 0;
+}
+
+/* ------------------------------------------------------------------------- */
+
+static void atyfb_set_par(const struct atyfb_par *par,
+			  struct fb_info_aty *info)
+{
+    u32 i;
+    int accelmode;
+    u8 tmp;
+
+    accelmode = par->accel_flags;  /* hack */
+
+    info->current_par = *par;
+
+    if (info->blitter_may_be_busy)
+	wait_for_idle(info);
+    tmp = aty_ld_8(CRTC_GEN_CNTL + 3, info);
+    aty_set_crtc(info, &par->crtc);
+    aty_st_8(CLOCK_CNTL + info->clk_wr_offset, 0, info);
+					/* better call aty_StrobeClock ?? */
+    aty_st_8(CLOCK_CNTL + info->clk_wr_offset, CLOCK_STROBE, info);
+
+    info->dac_ops->set_dac(info, &par->pll, par->crtc.bpp, accelmode);
+    info->pll_ops->set_pll(info, &par->pll);
+
+    if (!M64_HAS(INTEGRATED)) {
+	/* Don't forget MEM_CNTL */
+	i = aty_ld_le32(MEM_CNTL, info) & 0xf0ffffff;
+	switch (par->crtc.bpp) {
+	    case 8:
+		i |= 0x02000000;
+		break;
+	    case 16:
+		i |= 0x03000000;
+		break;
+	    case 32:
+		i |= 0x06000000;
+		break;
+	}
+	aty_st_le32(MEM_CNTL, i, info);
+    } else {
+	i = aty_ld_le32(MEM_CNTL, info) & 0xf00fffff;
+	if (!M64_HAS(MAGIC_POSTDIV))
+	    i |= info->mem_refresh_rate << 20;
+	switch (par->crtc.bpp) {
+	    case 8:
+	    case 24:
+		i |= 0x00000000;
+		break;
+	    case 16:
+		i |= 0x04000000;
+		break;
+	    case 32:
+		i |= 0x08000000;
+		break;
+	}
+	if (M64_HAS(CT_BUS)) {
+	    aty_st_le32(DAC_CNTL, 0x87010184, info);
+	    aty_st_le32(BUS_CNTL, 0x680000f9, info);
+	} else if (M64_HAS(VT_BUS)) {
+	    aty_st_le32(DAC_CNTL, 0x87010184, info);
+	    aty_st_le32(BUS_CNTL, 0x680000f9, info);
+	}  else if (M64_HAS(MOBIL_BUS)) {
+	    aty_st_le32(DAC_CNTL, 0x80010102, info);
+	    aty_st_le32(BUS_CNTL, 0x7b33a040, info);
+	} else {
+	    /* GT */
+	    aty_st_le32(DAC_CNTL, 0x86010102, info);
+	    aty_st_le32(BUS_CNTL, 0x7b23a040, info);
+	    aty_st_le32(EXT_MEM_CNTL,
+			aty_ld_le32(EXT_MEM_CNTL, info) | 0x5000001, info);
+	}
+	aty_st_le32(MEM_CNTL, i, info);
+    }
+    aty_st_8(DAC_MASK, 0xff, info);
+
+    /* Initialize the graphics engine */
+    if (par->accel_flags & FB_ACCELF_TEXT)
+	aty_init_engine(par, info);
+
+#ifdef CONFIG_FB_COMPAT_XPMAC
+    if (!console_fb_info || console_fb_info == &info->fb_info) {
+	struct fb_var_screeninfo var;
+	int vmode, cmode;
+	display_info.height = ((par->crtc.v_tot_disp>>16) & 0x7ff)+1;
+	display_info.width = (((par->crtc.h_tot_disp>>16) & 0xff)+1)*8;
+	display_info.depth = par->crtc.bpp;
+	display_info.pitch = par->crtc.vxres*par->crtc.bpp/8;
+	atyfb_encode_var(&var, par, info);
+	if (mac_var_to_vmode(&var, &vmode, &cmode))
+	    display_info.mode = 0;
+	else
+	    display_info.mode = vmode;
+	strcpy(display_info.name, atyfb_name);
+	display_info.fb_address = info->frame_buffer_phys;
+	display_info.cmap_adr_address = info->ati_regbase_phys+0xc0;
+	display_info.cmap_data_address = info->ati_regbase_phys+0xc1;
+	display_info.disp_reg_address = info->ati_regbase_phys;
+    }
+#endif /* CONFIG_FB_COMPAT_XPMAC */
+}
+
+static int atyfb_decode_var(const struct fb_var_screeninfo *var,
+			    struct atyfb_par *par,
+			    const struct fb_info_aty *info)
+{
+    int err;
+
+    if ((err = aty_var_to_crtc(info, var, &par->crtc)) ||
+	(err = info->pll_ops->var_to_pll(info, var->pixclock, par->crtc.bpp,
+		    			 &par->pll)))
+	return err;
+
+    if (var->accel_flags & FB_ACCELF_TEXT)
+	par->accel_flags = FB_ACCELF_TEXT;
+    else
+	par->accel_flags = 0;
+
+#if 0 /* fbmon is not done. uncomment for 2.5.x -brad */
+    if (!fbmon_valid_timings(var->pixclock, htotal, vtotal, info))
+	return -EINVAL;
+#endif
+
+    return 0;
+}
+
+static int atyfb_encode_var(struct fb_var_screeninfo *var,
+			    const struct atyfb_par *par,
+			    const struct fb_info_aty *info)
+{
+    int err;
+
+    memset(var, 0, sizeof(struct fb_var_screeninfo));
+
+    if ((err = aty_crtc_to_var(&par->crtc, var)))
+	return err;
+    var->pixclock = info->pll_ops->pll_to_var(info, &par->pll);
+
+    var->height = -1;
+    var->width = -1;
+    var->accel_flags = par->accel_flags;
+
+    return 0;
+}
+
+
+
+static void set_off_pitch(struct atyfb_par *par,
+			  const struct fb_info_aty *info)
+{
+    u32 xoffset = par->crtc.xoffset;
+    u32 yoffset = par->crtc.yoffset;
+    u32 vxres = par->crtc.vxres;
+    u32 bpp = par->crtc.bpp;
+
+    par->crtc.off_pitch = ((yoffset*vxres+xoffset)*bpp/64) | (vxres<<19);
+    aty_st_le32(CRTC_OFF_PITCH, par->crtc.off_pitch, info);
+}
+
+
+    /*
+     *  Open/Release the frame buffer device
+     */
+
+static int atyfb_open(struct fb_info *info, int user)
+
+{
+#ifdef __sparc__
+    struct fb_info_aty *fb = (struct fb_info_aty *)info;
+
+    if (user) {
+	fb->open++;
+	fb->mmaped = 0;
+	fb->vtconsole = -1;
+    } else {
+	fb->consolecnt++;
+    }
+#endif
+    return(0);
+}
+
+struct fb_var_screeninfo default_var = {
+    /* 640x480, 60 Hz, Non-Interlaced (25.175 MHz dotclock) */
+    640, 480, 640, 480, 0, 0, 8, 0,
+    {0, 8, 0}, {0, 8, 0}, {0, 8, 0}, {0, 0, 0},
+    0, 0, -1, -1, 0, 39722, 48, 16, 33, 10, 96, 2,
+    0, FB_VMODE_NONINTERLACED
+};
+
+static int atyfb_release(struct fb_info *info, int user)
+{
+#ifdef __sparc__
+    struct fb_info_aty *fb = (struct fb_info_aty *)info;
+
+    if (user) {
+	fb->open--;
+	mdelay(1);
+	wait_for_idle(fb);
+	if (!fb->open) {
+		int was_mmaped = fb->mmaped;
+
+		fb->mmaped = 0;
+		if (fb->vtconsole != -1)
+			vt_cons[fb->vtconsole]->vc_mode = KD_TEXT;
+		fb->vtconsole = -1;
+
+		if (was_mmaped) {
+			struct fb_var_screeninfo var;
+
+			/* Now reset the default display config, we have no
+			 * idea what the program(s) which mmap'd the chip did
+			 * to the configuration, nor whether it restored it
+			 * correctly.
+			 */
+			var = default_var;
+			if (noaccel)
+				var.accel_flags &= ~FB_ACCELF_TEXT;
+			else
+				var.accel_flags |= FB_ACCELF_TEXT;
+			if (var.yres == var.yres_virtual) {
+				u32 vram = (fb->total_vram - (PAGE_SIZE << 2));
+				var.yres_virtual = ((vram * 8) / var.bits_per_pixel) /
+					var.xres_virtual;
+				if (var.yres_virtual < var.yres)
+					var.yres_virtual = var.yres;
+			}
+			atyfb_set_var(&var, -1, &fb->fb_info);
+		}
+	}
+    } else {
+	fb->consolecnt--;
+    }
+#endif
+    return(0);
+}
+
+
+static int encode_fix(struct fb_fix_screeninfo *fix,
+		      const struct atyfb_par *par,
+		      const struct fb_info_aty *info)
+{
+    memset(fix, 0, sizeof(struct fb_fix_screeninfo));
+
+    strcpy(fix->id, atyfb_name);
+    fix->smem_start = info->frame_buffer_phys;
+    fix->smem_len = (u32)info->total_vram;
+
+    /*
+     *  Reg Block 0 (CT-compatible block) is at ati_regbase_phys
+     *  Reg Block 1 (multimedia extensions) is at ati_regbase_phys-0x400
+     */
+    if (M64_HAS(GX)) {
+	fix->mmio_start = info->ati_regbase_phys;
+	fix->mmio_len = 0x400;
+	fix->accel = FB_ACCEL_ATI_MACH64GX;
+    } else if (M64_HAS(CT)) {
+	fix->mmio_start = info->ati_regbase_phys;
+	fix->mmio_len = 0x400;
+	fix->accel = FB_ACCEL_ATI_MACH64CT;
+    } else if (M64_HAS(VT)) {
+	fix->mmio_start = info->ati_regbase_phys-0x400;
+	fix->mmio_len = 0x800;
+	fix->accel = FB_ACCEL_ATI_MACH64VT;
+    } else /* if (M64_HAS(GT)) */ {
+	fix->mmio_start = info->ati_regbase_phys-0x400;
+	fix->mmio_len = 0x800;
+	fix->accel = FB_ACCEL_ATI_MACH64GT;
+    }
+    fix->type = FB_TYPE_PACKED_PIXELS;
+    fix->type_aux = 0;
+    fix->line_length = par->crtc.vxres*par->crtc.bpp/8;
+    fix->visual = par->crtc.bpp <= 8 ? FB_VISUAL_PSEUDOCOLOR
+				     : FB_VISUAL_DIRECTCOLOR;
+    fix->ywrapstep = 0;
+    fix->xpanstep = 8;
+    fix->ypanstep = 1;
+
+    return 0;
+}
+
+
+    /*
+     *  Get the Fixed Part of the Display
+     */
+
+static int atyfb_get_fix(struct fb_fix_screeninfo *fix, int con,
+			 struct fb_info *fb)
+{
+    const struct fb_info_aty *info = (struct fb_info_aty *)fb;
+    struct atyfb_par par;
+
+    if (con == -1)
+	par = info->default_par;
+    else
+	atyfb_decode_var(&fb_display[con].var, &par, info);
+    encode_fix(fix, &par, info);
+    return 0;
+}
+
+
+    /*
+     *  Get the User Defined Part of the Display
+     */
+
+static int atyfb_get_var(struct fb_var_screeninfo *var, int con,
+			 struct fb_info *fb)
+{
+    const struct fb_info_aty *info = (struct fb_info_aty *)fb;
+
+    if (con == -1)
+	atyfb_encode_var(var, &info->default_par, info);
+    else
+	*var = fb_display[con].var;
+    return 0;
+}
+
+
+static void atyfb_set_dispsw(struct display *disp, struct fb_info_aty *info,
+			     int bpp, int accel)
+{
+	    switch (bpp) {
+#ifdef FBCON_HAS_CFB8
+		case 8:
+		    info->dispsw = accel ? fbcon_aty8 : fbcon_cfb8;
+		    disp->dispsw = &info->dispsw;
+		    break;
+#endif
+#ifdef FBCON_HAS_CFB16
+		case 16:
+		    info->dispsw = accel ? fbcon_aty16 : fbcon_cfb16;
+		    disp->dispsw = &info->dispsw;
+		    disp->dispsw_data = info->fbcon_cmap.cfb16;
+		    break;
+#endif
+#ifdef FBCON_HAS_CFB24
+		case 24:
+		    info->dispsw = accel ? fbcon_aty24 : fbcon_cfb24;
+		    disp->dispsw = &info->dispsw;
+		    disp->dispsw_data = info->fbcon_cmap.cfb24;
+		    break;
+#endif
+#ifdef FBCON_HAS_CFB32
+		case 32:
+		    info->dispsw = accel ? fbcon_aty32 : fbcon_cfb32;
+		    disp->dispsw = &info->dispsw;
+		    disp->dispsw_data = info->fbcon_cmap.cfb32;
+		    break;
+#endif
+		default:
+		    disp->dispsw = &fbcon_dummy;
+	    }
+#ifdef CONFIG_FB_ATY_CT
+	    if (info->cursor) {
+		info->dispsw.cursor = atyfb_cursor;
+		info->dispsw.set_font = atyfb_set_font;
+	    }
+#endif /* CONFIG_FB_ATY_CT */
+}
+
+
+    /*
+     *  Set the User Defined Part of the Display
+     */
+
+static int atyfb_set_var(struct fb_var_screeninfo *var, int con,
+			 struct fb_info *fb)
+{
+    struct fb_info_aty *info = (struct fb_info_aty *)fb;
+    struct atyfb_par par;
+    struct display *display;
+    int oldxres, oldyres, oldvxres, oldvyres, oldbpp, oldaccel, accel, err;
+    int activate = var->activate;
+
+    if (con >= 0)
+	display = &fb_display[con];
+    else
+	display = fb->disp;	/* used during initialization */
+
+    if ((err = atyfb_decode_var(var, &par, info)))
+	return err;
+
+    atyfb_encode_var(var, &par, (struct fb_info_aty *)info);
+
+    if ((activate & FB_ACTIVATE_MASK) == FB_ACTIVATE_NOW) {
+	oldxres = display->var.xres;
+	oldyres = display->var.yres;
+	oldvxres = display->var.xres_virtual;
+	oldvyres = display->var.yres_virtual;
+	oldbpp = display->var.bits_per_pixel;
+	oldaccel = display->var.accel_flags;
+	display->var = *var;
+	accel = var->accel_flags & FB_ACCELF_TEXT;
+	if (oldxres != var->xres || oldyres != var->yres ||
+	    oldvxres != var->xres_virtual || oldvyres != var->yres_virtual ||
+	    oldbpp != var->bits_per_pixel || oldaccel != var->accel_flags) {
+	    struct fb_fix_screeninfo fix;
+
+	    encode_fix(&fix, &par, info);
+	    display->screen_base = (char *)info->frame_buffer;
+	    display->visual = fix.visual;
+	    display->type = fix.type;
+	    display->type_aux = fix.type_aux;
+	    display->ypanstep = fix.ypanstep;
+	    display->ywrapstep = fix.ywrapstep;
+	    display->line_length = fix.line_length;
+	    display->can_soft_blank = 1;
+	    display->inverse = 0;
+	    if (accel)
+	    	display->scrollmode = (info->bus_type == PCI) ? SCROLL_YNOMOVE : 0;
+	    else
+	    	display->scrollmode = SCROLL_YREDRAW;
+	    if (info->fb_info.changevar)
+		(*info->fb_info.changevar)(con);
+	}
+	if (!info->fb_info.display_fg ||
+	    info->fb_info.display_fg->vc_num == con) {
+	    atyfb_set_par(&par, info);
+	    atyfb_set_dispsw(display, info, par.crtc.bpp, accel);
+	}
+	if (oldbpp != var->bits_per_pixel) {
+	    if ((err = fb_alloc_cmap(&display->cmap, 0, 0)))
+		return err;
+	    do_install_cmap(con, &info->fb_info);
+	}
+    }
+
+    return 0;
+}
+
+
+    /*
+     *  Pan or Wrap the Display
+     *
+     *  This call looks only at xoffset, yoffset and the FB_VMODE_YWRAP flag
+     */
+
+static int atyfb_pan_display(struct fb_var_screeninfo *var, int con,
+			     struct fb_info *fb)
+{
+    struct fb_info_aty *info = (struct fb_info_aty *)fb;
+    u32 xres, yres, xoffset, yoffset;
+    struct atyfb_par *par = &info->current_par;
+
+    xres = (((par->crtc.h_tot_disp>>16) & 0xff)+1)*8;
+    yres = ((par->crtc.v_tot_disp>>16) & 0x7ff)+1;
+    xoffset = (var->xoffset+7) & ~7;
+    yoffset = var->yoffset;
+    if (xoffset+xres > par->crtc.vxres || yoffset+yres > par->crtc.vyres)
+	return -EINVAL;
+    par->crtc.xoffset = xoffset;
+    par->crtc.yoffset = yoffset;
+    set_off_pitch(par, info);
+    return 0;
+}
+
+    /*
+     *  Get the Colormap
+     */
+
+static int atyfb_get_cmap(struct fb_cmap *cmap, int kspc, int con,
+			  struct fb_info *info)
+{
+    if (!info->display_fg || con == info->display_fg->vc_num) /* current console? */
+	return fb_get_cmap(cmap, kspc, atyfb_getcolreg, info);
+    else if (fb_display[con].cmap.len) /* non default colormap? */
+	fb_copy_cmap(&fb_display[con].cmap, cmap, kspc ? 0 : 2);
+    else {
+	int size = fb_display[con].var.bits_per_pixel == 16 ? 32 : 256;
+	fb_copy_cmap(fb_default_cmap(size), cmap, kspc ? 0 : 2);
+    }
+    return 0;
+}
+
+    /*
+     *  Set the Colormap
+     */
+
+static int atyfb_set_cmap(struct fb_cmap *cmap, int kspc, int con,
+			  struct fb_info *info)
+{
+    int err;
+    struct display *disp;
+
+    if (con >= 0)
+    	disp = &fb_display[con];
+    else
+        disp = info->disp;
+    if (!disp->cmap.len) {	/* no colormap allocated? */
+	int size = disp->var.bits_per_pixel == 16 ? 32 : 256;
+	if ((err = fb_alloc_cmap(&disp->cmap, size, 0)))
+	    return err;
+    }
+    if (!info->display_fg || con == info->display_fg->vc_num)			/* current console? */
+	return fb_set_cmap(cmap, kspc, atyfb_setcolreg, info);
+    else
+	fb_copy_cmap(cmap, &disp->cmap, kspc ? 0 : 1);
+    return 0;
+}
+
+
+#ifdef DEBUG
+#define ATYIO_CLKR		0x41545900	/* ATY\00 */
+#define ATYIO_CLKW		0x41545901	/* ATY\01 */
+
+struct atyclk {
+    u32 ref_clk_per;
+    u8 pll_ref_div;
+    u8 mclk_fb_div;
+    u8 mclk_post_div;		/* 1,2,3,4,8 */
+    u8 vclk_fb_div;
+    u8 vclk_post_div;		/* 1,2,3,4,6,8,12 */
+    u32 dsp_xclks_per_row;	/* 0-16383 */
+    u32 dsp_loop_latency;	/* 0-15 */
+    u32 dsp_precision;		/* 0-7 */
+    u32 dsp_on;			/* 0-2047 */
+    u32 dsp_off;		/* 0-2047 */
+};
+
+#define ATYIO_FEATR		0x41545902	/* ATY\02 */
+#define ATYIO_FEATW		0x41545903	/* ATY\03 */
+#endif
+
+static int atyfb_ioctl(struct inode *inode, struct file *file, u_int cmd,
+		       u_long arg, int con, struct fb_info *info2)
+{
+#if defined(__sparc__) || (defined(DEBUG) && defined(CONFIG_FB_ATY_CT))
+    struct fb_info_aty *info = (struct fb_info_aty *)info2;
+#endif /* __sparc__ || DEBUG */
+#ifdef __sparc__
+    struct fbtype fbtyp;
+    struct display *disp;
+
+    if (con >= 0)
+    	disp = &fb_display[con];
+    else
+        disp = info2->disp;
+#endif
+
+    switch (cmd) {
+#ifdef __sparc__
+    case FBIOGTYPE:
+	fbtyp.fb_type = FBTYPE_PCI_GENERIC;
+	fbtyp.fb_width = info->current_par.crtc.vxres;
+	fbtyp.fb_height = info->current_par.crtc.vyres;
+	fbtyp.fb_depth = info->current_par.crtc.bpp;
+	fbtyp.fb_cmsize = disp->cmap.len;
+	fbtyp.fb_size = info->total_vram;
+	if (copy_to_user((struct fbtype *)arg, &fbtyp, sizeof(fbtyp)))
+		return -EFAULT;
+	break;
+#endif /* __sparc__ */
+#if defined(DEBUG) && defined(CONFIG_FB_ATY_CT)
+    case ATYIO_CLKR:
+	if (M64_HAS(INTEGRATED)) {
+	    struct atyclk clk;
+	    union aty_pll *pll = &info->current_par.pll;
+	    u32 dsp_config = pll->ct.dsp_config;
+	    u32 dsp_on_off = pll->ct.dsp_on_off;
+	    clk.ref_clk_per = info->ref_clk_per;
+	    clk.pll_ref_div = pll->ct.pll_ref_div;
+	    clk.mclk_fb_div = pll->ct.mclk_fb_div;
+	    clk.mclk_post_div = pll->ct.mclk_post_div_real;
+	    clk.vclk_fb_div = pll->ct.vclk_fb_div;
+	    clk.vclk_post_div = pll->ct.vclk_post_div_real;
+	    clk.dsp_xclks_per_row = dsp_config & 0x3fff;
+	    clk.dsp_loop_latency = (dsp_config>>16) & 0xf;
+	    clk.dsp_precision = (dsp_config>>20) & 7;
+	    clk.dsp_on = dsp_on_off & 0x7ff;
+	    clk.dsp_off = (dsp_on_off>>16) & 0x7ff;
+	    if (copy_to_user((struct atyclk *)arg, &clk, sizeof(clk)))
+		    return -EFAULT;
+	} else
+	    return -EINVAL;
+	break;
+    case ATYIO_CLKW:
+	if (M64_HAS(INTEGRATED)) {
+	    struct atyclk clk;
+	    union aty_pll *pll = &info->current_par.pll;
+	    if (copy_from_user(&clk, (struct atyclk *)arg, sizeof(clk)))
+		    return -EFAULT;
+	    info->ref_clk_per = clk.ref_clk_per;
+	    pll->ct.pll_ref_div = clk.pll_ref_div;
+	    pll->ct.mclk_fb_div = clk.mclk_fb_div;
+	    pll->ct.mclk_post_div_real = clk.mclk_post_div;
+	    pll->ct.vclk_fb_div = clk.vclk_fb_div;
+	    pll->ct.vclk_post_div_real = clk.vclk_post_div;
+	    pll->ct.dsp_config = (clk.dsp_xclks_per_row & 0x3fff) |
+				 ((clk.dsp_loop_latency & 0xf)<<16) |
+				 ((clk.dsp_precision & 7)<<20);
+	    pll->ct.dsp_on_off = (clk.dsp_on & 0x7ff) |
+				 ((clk.dsp_off & 0x7ff)<<16);
+	    aty_calc_pll_ct(info, &pll->ct);
+	    aty_set_pll_ct(info, pll);
+	} else
+	    return -EINVAL;
+	break;
+    case ATYIO_FEATR:
+	if (get_user(info->features, (u32 *)arg))
+	    return -EFAULT;
+	break;
+    case ATYIO_FEATW:
+	if (put_user(info->features, (u32 *)arg))
+	    return -EFAULT;
+	break;
+#endif /* DEBUG && CONFIG_FB_ATY_CT */
+    default:
+	return -EINVAL;
+    }
+    return 0;
+}
+
+static int atyfb_rasterimg(struct fb_info *info, int start)
+{
+    struct fb_info_aty *fb = (struct fb_info_aty *)info;
+
+    if (fb->blitter_may_be_busy)
+	wait_for_idle(fb);
+    return 0;
+}
+
+#ifdef __sparc__
+static int atyfb_mmap(struct fb_info *info, struct file *file,
+		      struct vm_area_struct *vma)
+{
+	struct fb_info_aty *fb = (struct fb_info_aty *)info;
+	unsigned int size, page, map_size = 0;
+	unsigned long map_offset = 0;
+	unsigned long off;
+	int i;
+
+	if (!fb->mmap_map)
+		return -ENXIO;
+
+	if (vma->vm_pgoff > (~0UL >> PAGE_SHIFT))
+		return -EINVAL;
+
+	off = vma->vm_pgoff << PAGE_SHIFT;
+	size = vma->vm_end - vma->vm_start;
+
+	/* To stop the swapper from even considering these pages. */
+	vma->vm_flags |= (VM_SHM | VM_LOCKED);
+
+	if (((vma->vm_pgoff == 0) && (size == fb->total_vram)) ||
+	    ((off == fb->total_vram) && (size == PAGE_SIZE)))
+		off += 0x8000000000000000UL;
+
+	vma->vm_pgoff = off >> PAGE_SHIFT;	/* propagate off changes */
+
+	/* Each page, see which map applies */
+	for (page = 0; page < size; ) {
+		map_size = 0;
+		for (i = 0; fb->mmap_map[i].size; i++) {
+			unsigned long start = fb->mmap_map[i].voff;
+			unsigned long end = start + fb->mmap_map[i].size;
+			unsigned long offset = off + page;
+
+			if (start > offset)
+				continue;
+			if (offset >= end)
+				continue;
+
+			map_size = fb->mmap_map[i].size - (offset - start);
+			map_offset = fb->mmap_map[i].poff + (offset - start);
+			break;
+		}
+		if (!map_size) {
+			page += PAGE_SIZE;
+			continue;
+		}
+		if (page + map_size > size)
+			map_size = size - page;
+
+		pgprot_val(vma->vm_page_prot) &= ~(fb->mmap_map[i].prot_mask);
+		pgprot_val(vma->vm_page_prot) |= fb->mmap_map[i].prot_flag;
+
+		if (remap_page_range(vma->vm_start + page, map_offset,
+				     map_size, vma->vm_page_prot))
+			return -EAGAIN;
+
+		page += map_size;
+	}
+
+	if (!map_size)
+		return -EINVAL;
+
+	vma->vm_flags |= VM_IO;
+
+	if (!fb->mmaped) {
+		int lastconsole = 0;
+
+		if (info->display_fg)
+			lastconsole = info->display_fg->vc_num;
+		fb->mmaped = 1;
+		if (fb->consolecnt && fb_display[lastconsole].fb_info == info) {
+			fb->vtconsole = lastconsole;
+			vt_cons[lastconsole]->vc_mode = KD_GRAPHICS;
+		}
+	}
+	return 0;
+}
+
+static struct {
+	u32	yoffset;
+	u8	r[2][256];
+	u8	g[2][256];
+	u8	b[2][256];
+} atyfb_save;
+
+static void atyfb_save_palette(struct fb_info *fb, int enter)
+{
+	struct fb_info_aty *info = (struct fb_info_aty *)fb;
+	int i, tmp;
+
+	for (i = 0; i < 256; i++) {
+		tmp = aty_ld_8(DAC_CNTL, info) & 0xfc;
+		if (M64_HAS(EXTRA_BRIGHT))
+			tmp |= 0x2;
+		aty_st_8(DAC_CNTL, tmp, info);
+		aty_st_8(DAC_MASK, 0xff, info);
+
+		writeb(i, &info->aty_cmap_regs->rindex);
+		atyfb_save.r[enter][i] = readb(&info->aty_cmap_regs->lut);
+		atyfb_save.g[enter][i] = readb(&info->aty_cmap_regs->lut);
+		atyfb_save.b[enter][i] = readb(&info->aty_cmap_regs->lut);
+		writeb(i, &info->aty_cmap_regs->windex);
+		writeb(atyfb_save.r[1-enter][i], &info->aty_cmap_regs->lut);
+		writeb(atyfb_save.g[1-enter][i], &info->aty_cmap_regs->lut);
+		writeb(atyfb_save.b[1-enter][i], &info->aty_cmap_regs->lut);
+	}
+}
+
+static void atyfb_palette(int enter)
+{
+	struct fb_info_aty *info;
+	struct atyfb_par *par;
+	struct display *d;
+	int i;
+
+	for (i = 0; i < MAX_NR_CONSOLES; i++) {
+		d = &fb_display[i];
+		if (d->fb_info &&
+		    d->fb_info->fbops == &atyfb_ops &&
+		    d->fb_info->display_fg &&
+		    d->fb_info->display_fg->vc_num == i) {
+			atyfb_save_palette(d->fb_info, enter);
+			info = (struct fb_info_aty *)d->fb_info;
+			par = &info->current_par;
+			if (enter) {
+				atyfb_save.yoffset = par->crtc.yoffset;
+				par->crtc.yoffset = 0;
+				set_off_pitch(par, info);
+			} else {
+				par->crtc.yoffset = atyfb_save.yoffset;
+				set_off_pitch(par, info);
+			}
+			break;
+		}
+	}
+}
+#endif /* __sparc__ */
+
+
+
+#ifdef CONFIG_PMAC_PBOOK
+
+static struct fb_info_aty* first_display = NULL;
+
+/* Power management routines. Those are used for PowerBook sleep.
+ *
+ * It appears that Rage LT and Rage LT Pro have different power
+ * management registers. There's is some confusion about which
+ * chipID is a Rage LT or LT pro :(
+ */
+static int aty_power_mgmt_LT(int sleep, struct fb_info_aty *info)
+{
+ 	unsigned int pm;
+	int timeout;
+	
+	pm = aty_ld_le32(POWER_MANAGEMENT_LG, info);
+	pm = (pm & ~PWR_MGT_MODE_MASK) | PWR_MGT_MODE_REG;
+	aty_st_le32(POWER_MANAGEMENT_LG, pm, info);
+	pm = aty_ld_le32(POWER_MANAGEMENT_LG, info);
+	
+	timeout = 200000;
+	if (sleep) {
+		/* Sleep */
+		pm &= ~PWR_MGT_ON;
+		aty_st_le32(POWER_MANAGEMENT_LG, pm, info);
+		pm = aty_ld_le32(POWER_MANAGEMENT_LG, info);
+		udelay(10);
+		pm &= ~(PWR_BLON | AUTO_PWR_UP);
+		pm |= SUSPEND_NOW;
+		aty_st_le32(POWER_MANAGEMENT_LG, pm, info);
+		pm = aty_ld_le32(POWER_MANAGEMENT_LG, info);
+		udelay(10);
+		pm |= PWR_MGT_ON;
+		aty_st_le32(POWER_MANAGEMENT_LG, pm, info);
+		do {
+			pm = aty_ld_le32(POWER_MANAGEMENT_LG, info);
+			udelay(10);
+			if ((--timeout) == 0)
+				break;
+		} while ((pm & PWR_MGT_STATUS_MASK) != PWR_MGT_STATUS_SUSPEND);
+	} else {
+		/* Wakeup */
+		pm &= ~PWR_MGT_ON;
+		aty_st_le32(POWER_MANAGEMENT_LG, pm, info);
+		pm = aty_ld_le32(POWER_MANAGEMENT_LG, info);
+		udelay(10);
+		pm |=  (PWR_BLON | AUTO_PWR_UP);
+		pm &= ~SUSPEND_NOW;
+		aty_st_le32(POWER_MANAGEMENT_LG, pm, info);
+		pm = aty_ld_le32(POWER_MANAGEMENT_LG, info);
+		udelay(10);
+		pm |= PWR_MGT_ON;
+		aty_st_le32(POWER_MANAGEMENT_LG, pm, info);
+		do {
+			pm = aty_ld_le32(POWER_MANAGEMENT_LG, info);
+			udelay(10);
+			if ((--timeout) == 0)
+				break;
+		} while ((pm & PWR_MGT_STATUS_MASK) != 0);
+	}
+	mdelay(500);
+
+	return timeout ? PBOOK_SLEEP_OK : PBOOK_SLEEP_REFUSE;
+}
+
+static int aty_power_mgmt_LTPro(int sleep, struct fb_info_aty *info)
+{
+ 	unsigned int pm;
+	int timeout;
+	
+	pm = aty_ld_lcd(POWER_MANAGEMENT, info);
+	pm = (pm & ~PWR_MGT_MODE_MASK) | PWR_MGT_MODE_REG;
+	aty_st_lcd(POWER_MANAGEMENT, pm, info);
+	pm = aty_ld_lcd(POWER_MANAGEMENT, info);
+
+	timeout = 200;
+	if (sleep) {
+		/* Sleep */
+		pm &= ~PWR_MGT_ON;
+		aty_st_lcd(POWER_MANAGEMENT, pm, info);
+		pm = aty_ld_lcd(POWER_MANAGEMENT, info);
+		udelay(10);
+		pm &= ~(PWR_BLON | AUTO_PWR_UP);
+		pm |= SUSPEND_NOW;
+		aty_st_lcd(POWER_MANAGEMENT, pm, info);
+		pm = aty_ld_lcd(POWER_MANAGEMENT, info);
+		udelay(10);
+		pm |= PWR_MGT_ON;
+		aty_st_lcd(POWER_MANAGEMENT, pm, info);
+		do {
+			pm = aty_ld_lcd(POWER_MANAGEMENT, info);
+			mdelay(1);
+			if ((--timeout) == 0)
+				break;
+		} while ((pm & PWR_MGT_STATUS_MASK) != PWR_MGT_STATUS_SUSPEND);
+	} else {
+		/* Wakeup */
+		pm &= ~PWR_MGT_ON;
+		aty_st_lcd(POWER_MANAGEMENT, pm, info);
+		pm = aty_ld_lcd(POWER_MANAGEMENT, info);
+		udelay(10);
+		pm &= ~SUSPEND_NOW;
+		pm |= (PWR_BLON | AUTO_PWR_UP);
+		aty_st_lcd(POWER_MANAGEMENT, pm, info);
+		pm = aty_ld_lcd(POWER_MANAGEMENT, info);
+		udelay(10);
+		pm |= PWR_MGT_ON;
+		aty_st_lcd(POWER_MANAGEMENT, pm, info);
+		do {
+			pm = aty_ld_lcd(POWER_MANAGEMENT, info);			
+			mdelay(1);
+			if ((--timeout) == 0)
+				break;
+		} while ((pm & PWR_MGT_STATUS_MASK) != 0);
+	}
+
+	return timeout ? PBOOK_SLEEP_OK : PBOOK_SLEEP_REFUSE;
+}
+
+static int aty_power_mgmt(int sleep, struct fb_info_aty *info)
+{
+    return M64_HAS(LT_SLEEP) ? aty_power_mgmt_LT(sleep, info)
+			     : aty_power_mgmt_LTPro(sleep, info);
+}
+
+/*
+ * Save the contents of the frame buffer when we go to sleep,
+ * and restore it when we wake up again.
+ */
+static int aty_sleep_notify(struct pmu_sleep_notifier *self, int when)
+{
+	struct fb_info_aty *info;
+ 	int result;
+
+	result = PBOOK_SLEEP_OK;
+
+	for (info = first_display; info != NULL; info = info->next) {
+		struct fb_fix_screeninfo fix;
+		int nb;
+
+		atyfb_get_fix(&fix, fg_console, (struct fb_info *)info);
+		nb = fb_display[fg_console].var.yres * fix.line_length;
+
+		switch (when) {
+		case PBOOK_SLEEP_REQUEST:
+			info->save_framebuffer = vmalloc(nb);
+			if (info->save_framebuffer == NULL)
+				return PBOOK_SLEEP_REFUSE;
+			break;
+		case PBOOK_SLEEP_REJECT:
+			if (info->save_framebuffer) {
+				vfree(info->save_framebuffer);
+				info->save_framebuffer = 0;
+			}
+			break;
+		case PBOOK_SLEEP_NOW:
+			if (info->blitter_may_be_busy)
+				wait_for_idle(info);
+			/* Stop accel engine (stop bus mastering) */
+			if (info->current_par.accel_flags & FB_ACCELF_TEXT)
+				aty_reset_engine(info);
+
+			/* Backup fb content */	
+			if (info->save_framebuffer)
+				memcpy_fromio(info->save_framebuffer,
+				       (void *)info->frame_buffer, nb);
+
+			/* Blank display and LCD */
+			atyfbcon_blank(VESA_POWERDOWN+1, (struct fb_info *)info);
+
+			/* Set chip to "suspend" mode */
+			result = aty_power_mgmt(1, info);
+			break;
+		case PBOOK_WAKE:
+			/* Wakeup chip */
+			result = aty_power_mgmt(0, info);
+
+			/* Restore fb content */			
+			if (info->save_framebuffer) {
+				memcpy_toio((void *)info->frame_buffer,
+				       info->save_framebuffer, nb);
+				vfree(info->save_framebuffer);
+				info->save_framebuffer = 0;
+			}
+			/* Restore display */
+			atyfb_set_par(&info->current_par, info);
+			atyfbcon_blank(0, (struct fb_info *)info);
+			break;
+		}
+	}
+	return result;
+}
+
+static struct pmu_sleep_notifier aty_sleep_notifier = {
+        aty_sleep_notify, SLEEP_LEVEL_VIDEO,
+};
+#endif /* CONFIG_PMAC_PBOOK */
+
+#ifdef CONFIG_PMAC_BACKLIGHT
+
+    /*
+     *   LCD backlight control
+     */
+
+static int backlight_conv[] = {
+	0x00, 0x3f, 0x4c, 0x59, 0x66, 0x73, 0x80, 0x8d,
+	0x9a, 0xa7, 0xb4, 0xc1, 0xcf, 0xdc, 0xe9, 0xff
+};
+
+static int
+aty_set_backlight_enable(int on, int level, void* data)
+{
+	struct fb_info_aty *info = (struct fb_info_aty *)data;
+	unsigned int reg = aty_ld_lcd(LCD_MISC_CNTL, info);
+	
+	reg |= (BLMOD_EN | BIASMOD_EN);
+	if (on && level > BACKLIGHT_OFF) {
+		reg &= ~BIAS_MOD_LEVEL_MASK;
+		reg |= (backlight_conv[level] << BIAS_MOD_LEVEL_SHIFT);
+	} else {
+		reg &= ~BIAS_MOD_LEVEL_MASK;
+		reg |= (backlight_conv[0] << BIAS_MOD_LEVEL_SHIFT);
+	}
+	aty_st_lcd(LCD_MISC_CNTL, reg, info);
+
+	return 0;
+}
+
+static int
+aty_set_backlight_level(int level, void* data)
+{
+	return aty_set_backlight_enable(1, level, data);
+}
+
+static struct backlight_controller aty_backlight_controller = {
+	aty_set_backlight_enable,
+	aty_set_backlight_level
+};
+#endif /* CONFIG_PMAC_BACKLIGHT */
+
+
+
+    /*
+     *  Initialisation
+     */
+
+static struct fb_info_aty *fb_list = NULL;
+
+static int __init aty_init(struct fb_info_aty *info, const char *name)
+{
+    u32 chip_id;
+    u32 i;
+    int j, k;
+    struct fb_var_screeninfo var;
+    struct display *disp;
+    u16 type;
+    u8 rev;
+    const char *chipname = NULL, *ramname = NULL, *xtal;
+    int pll, mclk, gtb_memsize;
+#if defined(CONFIG_PPC)
+    int sense;
+#endif
+    u8 pll_ref_div;
+
+    info->aty_cmap_regs = (struct aty_cmap_regs *)(info->ati_regbase+0xc0);
+    chip_id = aty_ld_le32(CONFIG_CHIP_ID, info);
+    type = chip_id & CFG_CHIP_TYPE;
+    rev = (chip_id & CFG_CHIP_REV)>>24;
+    for (j = 0; j < (sizeof(aty_chips)/sizeof(*aty_chips)); j++)
+	if (type == aty_chips[j].chip_type &&
+	    (rev & aty_chips[j].rev_mask) == aty_chips[j].rev_val) {
+	    chipname = aty_chips[j].name;
+	    pll = aty_chips[j].pll;
+	    mclk = aty_chips[j].mclk;
+	    info->features = aty_chips[j].features;
+	    goto found;
+	}
+    printk("atyfb: Unknown mach64 0x%04x rev 0x%04x\n", type, rev);
+    return 0;
+
+found:
+    printk("atyfb: %s [0x%04x rev 0x%02x] ", chipname, type, rev);
+#ifdef CONFIG_FB_ATY_GX
+    if (!M64_HAS(INTEGRATED)) {
+	u32 stat0;
+	u8 dac_type, dac_subtype, clk_type;
+	stat0 = aty_ld_le32(CONFIG_STAT0, info);
+	info->bus_type = (stat0 >> 0) & 0x07;
+	info->ram_type = (stat0 >> 3) & 0x07;
+	ramname = aty_gx_ram[info->ram_type];
+	/* FIXME: clockchip/RAMDAC probing? */
+	dac_type = (aty_ld_le32(DAC_CNTL, info) >> 16) & 0x07;
+#ifdef CONFIG_ATARI
+	clk_type = CLK_ATI18818_1;
+	dac_type = (stat0 >> 9) & 0x07;
+	if (dac_type == 0x07)
+	    dac_subtype = DAC_ATT20C408;
+	else
+	    dac_subtype = (aty_ld_8(SCRATCH_REG1 + 1, info) & 0xF0) | dac_type;
+#else
+	dac_type = DAC_IBMRGB514;
+	dac_subtype = DAC_IBMRGB514;
+	clk_type = CLK_IBMRGB514;
+#endif
+	switch (dac_subtype) {
+	    case DAC_IBMRGB514:
+		info->dac_ops = &aty_dac_ibm514;
+		break;
+	    case DAC_ATI68860_B:
+	    case DAC_ATI68860_C:
+		info->dac_ops = &aty_dac_ati68860b;
+		break;
+	    case DAC_ATT20C408:
+	    case DAC_ATT21C498:
+		info->dac_ops = &aty_dac_att21c498;
+		break;
+	    default:
+		printk(" atyfb_set_par: DAC type not implemented yet!\n");
+		info->dac_ops = &aty_dac_unsupported;
+		break;
+	}
+	switch (clk_type) {
+	    case CLK_ATI18818_1:
+		info->pll_ops = &aty_pll_ati18818_1;
+		break;
+	    case CLK_STG1703:
+		info->pll_ops = &aty_pll_stg1703;
+		break;
+	    case CLK_CH8398:
+		info->pll_ops = &aty_pll_ch8398;
+		break;
+	    case CLK_ATT20C408:
+		info->pll_ops = &aty_pll_att20c408;
+		break;
+	    case CLK_IBMRGB514:
+		info->pll_ops = &aty_pll_ibm514;
+		break;
+	    default:
+		printk(" atyfb_set_par: CLK type not implemented yet!");
+		info->pll_ops = &aty_pll_unsupported;
+		break;
+	}
+    }
+#endif /* CONFIG_FB_ATY_GX */
+#ifdef CONFIG_FB_ATY_CT
+    if (M64_HAS(INTEGRATED)) {
+	info->bus_type = PCI;
+	info->ram_type = (aty_ld_le32(CONFIG_STAT0, info) & 0x07);
+	ramname = aty_ct_ram[info->ram_type];
+	info->dac_ops = &aty_dac_ct;
+	info->pll_ops = &aty_pll_ct;
+	/* for many chips, the mclk is 67 MHz for SDRAM, 63 MHz otherwise */
+	if (mclk == 67 && info->ram_type < SDRAM)
+	    mclk = 63;
+    }
+#endif /* CONFIG_FB_ATY_CT */
+
+    info->ref_clk_per = 1000000000000ULL/14318180;
+    xtal = "14.31818";
+    if (M64_HAS(GTB_DSP) && (pll_ref_div = aty_ld_pll(PLL_REF_DIV, info))) {
+	int diff1, diff2;
+	diff1 = 510*14/pll_ref_div-pll;
+	diff2 = 510*29/pll_ref_div-pll;
+	if (diff1 < 0)
+	    diff1 = -diff1;
+	if (diff2 < 0)
+	    diff2 = -diff2;
+	if (diff2 < diff1) {
+	    info->ref_clk_per = 1000000000000ULL/29498928;
+	    xtal = "29.498928";
+	}
+    }
+
+    i = aty_ld_le32(MEM_CNTL, info);
+    gtb_memsize = M64_HAS(GTB_DSP);
+    if (gtb_memsize)
+	switch (i & 0xF) {	/* 0xF used instead of MEM_SIZE_ALIAS */
+	    case MEM_SIZE_512K:
+		info->total_vram = 0x80000;
+		break;
+	    case MEM_SIZE_1M:
+		info->total_vram = 0x100000;
+		break;
+	    case MEM_SIZE_2M_GTB:
+		info->total_vram = 0x200000;
+		break;
+	    case MEM_SIZE_4M_GTB:
+		info->total_vram = 0x400000;
+		break;
+	    case MEM_SIZE_6M_GTB:
+		info->total_vram = 0x600000;
+		break;
+	    case MEM_SIZE_8M_GTB:
+		info->total_vram = 0x800000;
+		break;
+	    default:
+		info->total_vram = 0x80000;
+	}
+    else
+	switch (i & MEM_SIZE_ALIAS) {
+	    case MEM_SIZE_512K:
+		info->total_vram = 0x80000;
+		break;
+	    case MEM_SIZE_1M:
+		info->total_vram = 0x100000;
+		break;
+	    case MEM_SIZE_2M:
+		info->total_vram = 0x200000;
+		break;
+	    case MEM_SIZE_4M:
+		info->total_vram = 0x400000;
+		break;
+	    case MEM_SIZE_6M:
+		info->total_vram = 0x600000;
+		break;
+	    case MEM_SIZE_8M:
+		info->total_vram = 0x800000;
+		break;
+	    default:
+		info->total_vram = 0x80000;
+	}
+
+    if (M64_HAS(MAGIC_VRAM_SIZE)) {
+	if (aty_ld_le32(CONFIG_STAT1, info) & 0x40000000)
+	  info->total_vram += 0x400000;
+    }
+
+    if (default_vram) {
+	info->total_vram = default_vram*1024;
+	i = i & ~(gtb_memsize ? 0xF : MEM_SIZE_ALIAS);
+	if (info->total_vram <= 0x80000)
+	    i |= MEM_SIZE_512K;
+	else if (info->total_vram <= 0x100000)
+	    i |= MEM_SIZE_1M;
+	else if (info->total_vram <= 0x200000)
+	    i |= gtb_memsize ? MEM_SIZE_2M_GTB : MEM_SIZE_2M;
+	else if (info->total_vram <= 0x400000)
+	    i |= gtb_memsize ? MEM_SIZE_4M_GTB : MEM_SIZE_4M;
+	else if (info->total_vram <= 0x600000)
+	    i |= gtb_memsize ? MEM_SIZE_6M_GTB : MEM_SIZE_6M;
+	else
+	    i |= gtb_memsize ? MEM_SIZE_8M_GTB : MEM_SIZE_8M;
+	aty_st_le32(MEM_CNTL, i, info);
+    }
+    if (default_pll)
+	pll = default_pll;
+    if (default_mclk)
+	mclk = default_mclk;
+
+    printk("%d%c %s, %s MHz XTAL, %d MHz PLL, %d Mhz MCLK\n",
+    	   info->total_vram == 0x80000 ? 512 : (info->total_vram >> 20),
+    	   info->total_vram == 0x80000 ? 'K' : 'M', ramname, xtal, pll, mclk);
+
+    if (mclk < 44)
+	info->mem_refresh_rate = 0;	/* 000 = 10 Mhz - 43 Mhz */
+    else if (mclk < 50)
+	info->mem_refresh_rate = 1;	/* 001 = 44 Mhz - 49 Mhz */
+    else if (mclk < 55)
+	info->mem_refresh_rate = 2;	/* 010 = 50 Mhz - 54 Mhz */
+    else if (mclk < 66)
+	info->mem_refresh_rate = 3;	/* 011 = 55 Mhz - 65 Mhz */
+    else if (mclk < 75)
+	info->mem_refresh_rate = 4;	/* 100 = 66 Mhz - 74 Mhz */
+    else if (mclk < 80)
+	info->mem_refresh_rate = 5;	/* 101 = 75 Mhz - 79 Mhz */
+    else if (mclk < 100)
+	info->mem_refresh_rate = 6;	/* 110 = 80 Mhz - 100 Mhz */
+    else
+	info->mem_refresh_rate = 7;	/* 111 = 100 Mhz and above */
+    info->pll_per = 1000000/pll;
+    info->mclk_per = 1000000/mclk;
+
+#ifdef DEBUG
+    if (M64_HAS(INTEGRATED)) {
+	int i;
+	printk("BUS_CNTL DAC_CNTL MEM_CNTL EXT_MEM_CNTL CRTC_GEN_CNTL "
+	       "DSP_CONFIG DSP_ON_OFF\n"
+	       "%08x %08x %08x %08x     %08x      %08x   %08x\n"
+	       "PLL",
+	       aty_ld_le32(BUS_CNTL, info), aty_ld_le32(DAC_CNTL, info),
+	       aty_ld_le32(MEM_CNTL, info), aty_ld_le32(EXT_MEM_CNTL, info),
+	       aty_ld_le32(CRTC_GEN_CNTL, info), aty_ld_le32(DSP_CONFIG, info),
+	       aty_ld_le32(DSP_ON_OFF, info));
+	for (i = 0; i < 16; i++)
+	    printk(" %02x", aty_ld_pll(i, info));
+	printk("\n");
+    }
+#endif
+
+    /*
+     *  Last page of 8 MB (4 MB on ISA) aperture is MMIO
+     *  FIXME: we should use the auxiliary aperture instead so we can access
+     *  the full 8 MB of video RAM on 8 MB boards
+     */
+    if (info->total_vram == 0x800000 ||
+	(info->bus_type == ISA && info->total_vram == 0x400000))
+	    info->total_vram -= GUI_RESERVE;
+
+    /* Clear the video memory */
+    fb_memset((void *)info->frame_buffer, 0, info->total_vram);
+
+    disp = &info->disp;
+
+    strcpy(info->fb_info.modename, atyfb_name);
+    info->fb_info.node = -1;
+    info->fb_info.fbops = &atyfb_ops;
+    info->fb_info.disp = disp;
+    strcpy(info->fb_info.fontname, fontname);
+    info->fb_info.changevar = NULL;
+    info->fb_info.switch_con = &atyfbcon_switch;
+    info->fb_info.updatevar = &atyfbcon_updatevar;
+    info->fb_info.blank = &atyfbcon_blank;
+    info->fb_info.flags = FBINFO_FLAG_DEFAULT;
+
+#ifdef CONFIG_PMAC_BACKLIGHT
+    if (M64_HAS(G3_PB_1_1) && machine_is_compatible("PowerBook1,1")) {
+	/* these bits let the 101 powerbook wake up from sleep -- paulus */
+	aty_st_lcd(POWER_MANAGEMENT, aty_ld_lcd(POWER_MANAGEMENT, info)
+		| (USE_F32KHZ | TRISTATE_MEM_EN), info);
+    }
+    if (M64_HAS(MOBIL_BUS))
+	register_backlight_controller(&aty_backlight_controller, info, "ati");
+#endif /* CONFIG_PMAC_BACKLIGHT */
+
+#ifdef MODULE
+    var = default_var;
+#else /* !MODULE */
+    memset(&var, 0, sizeof(var));
+#ifdef CONFIG_PPC
+    if (_machine == _MACH_Pmac) {
+	    /*
+	     *  FIXME: The NVRAM stuff should be put in a Mac-specific file, as it
+	     *         applies to all Mac video cards
+	     */
+	    if (mode_option) {
+		if (!mac_find_mode(&var, &info->fb_info, mode_option, 8))
+		    var = default_var;
+	    } else {
+#ifdef CONFIG_NVRAM
+		if (default_vmode == VMODE_NVRAM) {
+		    default_vmode = nvram_read_byte(NV_VMODE);
+		    if (default_vmode <= 0 || default_vmode > VMODE_MAX)
+			default_vmode = VMODE_CHOOSE;
+		}
+#endif
+		if (default_vmode == VMODE_CHOOSE) {
+		    if (M64_HAS(G3_PB_1024x768))
+			/* G3 PowerBook with 1024x768 LCD */
+			default_vmode = VMODE_1024_768_60;
+		    else if (machine_is_compatible("iMac"))
+			default_vmode = VMODE_1024_768_75;
+		    else if (machine_is_compatible("PowerBook2,1"))
+			/* iBook with 800x600 LCD */
+			default_vmode = VMODE_800_600_60;
+		    else
+			default_vmode = VMODE_640_480_67;
+		    sense = read_aty_sense(info);
+		    printk(KERN_INFO "atyfb: monitor sense=%x, mode %d\n",
+			   sense, mac_map_monitor_sense(sense));
+		}
+		if (default_vmode <= 0 || default_vmode > VMODE_MAX)
+		    default_vmode = VMODE_640_480_60;
+#ifdef CONFIG_NVRAM
+		if (default_cmode == CMODE_NVRAM)
+		    default_cmode = nvram_read_byte(NV_CMODE);
+#endif
+		if (default_cmode < CMODE_8 || default_cmode > CMODE_32)
+		    default_cmode = CMODE_8;
+		if (mac_vmode_to_var(default_vmode, default_cmode, &var))
+		    var = default_var;
+	    }
+    }
+    else if (!fb_find_mode(&var, &info->fb_info, mode_option, NULL, 0, NULL, 8))
+	var = default_var;
+#else /* !CONFIG_PPC */
+#ifdef __sparc__
+    if (mode_option) {
+    	if (!fb_find_mode(&var, &info->fb_info, mode_option, NULL, 0, NULL, 8))
+	    var = default_var;
+    } else
+	var = default_var;
+#else
+    if (!fb_find_mode(&var, &info->fb_info, mode_option, NULL, 0, NULL, 8))
+	var = default_var;
+#endif /* !__sparc__ */
+#endif /* !CONFIG_PPC */
+#endif /* !MODULE */
+    if (noaccel)
+        var.accel_flags &= ~FB_ACCELF_TEXT;
+    else
+        var.accel_flags |= FB_ACCELF_TEXT;
+
+    if (var.yres == var.yres_virtual) {
+	u32 vram = (info->total_vram - (PAGE_SIZE << 2));
+	var.yres_virtual = ((vram * 8) / var.bits_per_pixel) / var.xres_virtual;
+	if (var.yres_virtual < var.yres)
+		var.yres_virtual = var.yres;
+    }
+
+    if (atyfb_decode_var(&var, &info->default_par, info)) {
+	printk("atyfb: can't set default video mode\n");
+	return 0;
+    }
+
+#ifdef __sparc__
+    atyfb_save_palette(&info->fb_info, 0);
+#endif
+    for (j = 0; j < 16; j++) {
+	k = color_table[j];
+	info->palette[j].red = default_red[k];
+	info->palette[j].green = default_grn[k];
+	info->palette[j].blue = default_blu[k];
+    }
+
+#ifdef CONFIG_FB_ATY_CT
+    if (curblink && M64_HAS(INTEGRATED)) {
+	info->cursor = aty_init_cursor(info);
+	if (info->cursor) {
+	    info->dispsw.cursor = atyfb_cursor;
+	    info->dispsw.set_font = atyfb_set_font;
+	}
+    }
+#endif /* CONFIG_FB_ATY_CT */
+
+    atyfb_set_var(&var, -1, &info->fb_info);
+
+    if (register_framebuffer(&info->fb_info) < 0)
+	return 0;
+
+    info->next = fb_list;
+    fb_list = info;
+
+    printk("fb%d: %s frame buffer device on %s\n",
+	   GET_FB_IDX(info->fb_info.node), atyfb_name, name);
+    return 1;
+}
+
+int __init atyfb_init(void)
+{
+#if defined(CONFIG_PCI)
+    struct pci_dev *pdev = NULL;
+    struct fb_info_aty *info;
+    unsigned long addr, res_start, res_size;
+    int i;
+#ifdef __sparc__
+    extern void (*prom_palette) (int);
+    extern int con_is_present(void);
+    struct pcidev_cookie *pcp;
+    char prop[128];
+    int node, len, j;
+    u32 mem, chip_id;
+
+    /* Do not attach when we have a serial console. */
+    if (!con_is_present())
+	return -ENXIO;
+#else
+    u16 tmp;
+#endif
+
+    while ((pdev = pci_find_device(PCI_VENDOR_ID_ATI, PCI_ANY_ID, pdev))) {
+	if ((pdev->class >> 16) == PCI_BASE_CLASS_DISPLAY) {
+	    struct resource *rp;
+
+	    for (i = sizeof(aty_chips)/sizeof(*aty_chips)-1; i >= 0; i--)
+		if (pdev->device == aty_chips[i].pci_id)
+		    break;
+	    if (i < 0)
+		continue;
+
+	    info = kmalloc(sizeof(struct fb_info_aty), GFP_ATOMIC);
+	    if (!info) {
+		printk("atyfb_init: can't alloc fb_info_aty\n");
+		return -ENXIO;
+	    }
+	    memset(info, 0, sizeof(struct fb_info_aty));
+
+	    rp = &pdev->resource[0];
+	    if (rp->flags & IORESOURCE_IO)
+		    rp = &pdev->resource[1];
+	    addr = rp->start;
+	    if (!addr)
+		continue;
+
+	    res_start = rp->start;
+	    res_size = rp->end-rp->start+1;
+	    if (!request_mem_region(res_start, res_size, "atyfb"))
+		continue;
+
+#ifdef __sparc__
+	    /*
+	     * Map memory-mapped registers.
+	     */
+	    info->ati_regbase = addr + 0x7ffc00UL;
+	    info->ati_regbase_phys = addr + 0x7ffc00UL;
+
+	    /*
+	     * Map in big-endian aperture.
+	     */
+	    info->frame_buffer = (unsigned long) addr + 0x800000UL;
+	    info->frame_buffer_phys = addr + 0x800000UL;
+
+	    /*
+	     * Figure mmap addresses from PCI config space.
+	     * Split Framebuffer in big- and little-endian halfs.
+	     */
+	    for (i = 0; i < 6 && pdev->resource[i].start; i++)
+		/* nothing */;
+	    j = i + 4;
+
+	    info->mmap_map = kmalloc(j * sizeof(*info->mmap_map), GFP_ATOMIC);
+	    if (!info->mmap_map) {
+		printk("atyfb_init: can't alloc mmap_map\n");
+		kfree(info);
+		release_mem_region(res_start, res_size);
+		return -ENXIO;
+	    }
+	    memset(info->mmap_map, 0, j * sizeof(*info->mmap_map));
+
+	    for (i = 0, j = 2; i < 6 && pdev->resource[i].start; i++) {
+		struct resource *rp = &pdev->resource[i];
+		int io, breg = PCI_BASE_ADDRESS_0 + (i << 2);
+		unsigned long base;
+		u32 size, pbase;
+
+		base = rp->start;
+
+		io = (rp->flags & IORESOURCE_IO);
+
+		size = rp->end - base + 1;
+
+		pci_read_config_dword(pdev, breg, &pbase);
+
+		if (io)
+			size &= ~1;
+
+		/*
+		 * Map the framebuffer a second time, this time without
+		 * the braindead _PAGE_IE setting. This is used by the
+		 * fixed Xserver, but we need to maintain the old mapping
+		 * to stay compatible with older ones...
+		 */
+		if (base == addr) {
+		    info->mmap_map[j].voff = (pbase + 0x10000000) & PAGE_MASK;
+		    info->mmap_map[j].poff = base & PAGE_MASK;
+		    info->mmap_map[j].size = (size + ~PAGE_MASK) & PAGE_MASK;
+		    info->mmap_map[j].prot_mask = _PAGE_CACHE;
+		    info->mmap_map[j].prot_flag = _PAGE_E;
+		    j++;
+		}
+
+		/*
+		 * Here comes the old framebuffer mapping with _PAGE_IE
+		 * set for the big endian half of the framebuffer...
+		 */
+		if (base == addr) {
+		    info->mmap_map[j].voff = (pbase + 0x800000) & PAGE_MASK;
+		    info->mmap_map[j].poff = (base+0x800000) & PAGE_MASK;
+		    info->mmap_map[j].size = 0x800000;
+		    info->mmap_map[j].prot_mask = _PAGE_CACHE;
+		    info->mmap_map[j].prot_flag = _PAGE_E|_PAGE_IE;
+		    size -= 0x800000;
+		    j++;
+		}
+
+		info->mmap_map[j].voff = pbase & PAGE_MASK;
+		info->mmap_map[j].poff = base & PAGE_MASK;
+		info->mmap_map[j].size = (size + ~PAGE_MASK) & PAGE_MASK;
+		info->mmap_map[j].prot_mask = _PAGE_CACHE;
+		info->mmap_map[j].prot_flag = _PAGE_E;
+		j++;
+	    }
+
+	    if (pdev->device != XL_CHIP_ID) {
+		    /*
+		     * Fix PROMs idea of MEM_CNTL settings...
+		     */
+		    mem = aty_ld_le32(MEM_CNTL, info);
+		    chip_id = aty_ld_le32(CONFIG_CHIP_ID, info);
+		    if (((chip_id & CFG_CHIP_TYPE) == VT_CHIP_ID) &&
+			!((chip_id >> 24) & 1)) {
+			switch (mem & 0x0f) {
+			    case 3:
+				mem = (mem & ~(0x0f)) | 2;
+				break;
+			    case 7:
+				mem = (mem & ~(0x0f)) | 3;
+				break;
+			    case 9:
+				mem = (mem & ~(0x0f)) | 4;
+				break;
+			    case 11:
+				mem = (mem & ~(0x0f)) | 5;
+				break;
+			    default:
+				break;
+			}
+			if ((aty_ld_le32(CONFIG_STAT0, info) & 7) >= SDRAM)
+				mem &= ~(0x00700000);
+		    }
+		    mem &= ~(0xcf80e000);	/* Turn off all undocumented bits. */
+		    aty_st_le32(MEM_CNTL, mem, info);
+	    }
+
+	    /*
+	     * If this is the console device, we will set default video
+	     * settings to what the PROM left us with.
+	     */
+	    node = prom_getchild(prom_root_node);
+	    node = prom_searchsiblings(node, "aliases");
+	    if (node) {
+		len = prom_getproperty(node, "screen", prop, sizeof(prop));
+		if (len > 0) {
+		    prop[len] = '\0';
+		    node = prom_finddevice(prop);
+		} else {
+		    node = 0;
+		}
+	    }
+
+	    pcp = pdev->sysdata;
+	    if (node == pcp->prom_node) {
+
+		struct fb_var_screeninfo *var = &default_var;
+		unsigned int N, P, Q, M, T, R;
+		u32 v_total, h_total;
+		struct crtc crtc;
+		u8 pll_regs[16];
+		u8 clock_cntl;
+
+		crtc.vxres = prom_getintdefault(node, "width", 1024);
+		crtc.vyres = prom_getintdefault(node, "height", 768);
+		crtc.bpp = prom_getintdefault(node, "depth", 8);
+		crtc.xoffset = crtc.yoffset = 0;
+		crtc.h_tot_disp = aty_ld_le32(CRTC_H_TOTAL_DISP, info);
+		crtc.h_sync_strt_wid = aty_ld_le32(CRTC_H_SYNC_STRT_WID, info);
+		crtc.v_tot_disp = aty_ld_le32(CRTC_V_TOTAL_DISP, info);
+		crtc.v_sync_strt_wid = aty_ld_le32(CRTC_V_SYNC_STRT_WID, info);
+		crtc.gen_cntl = aty_ld_le32(CRTC_GEN_CNTL, info);
+		aty_crtc_to_var(&crtc, var);
+
+		h_total = var->xres + var->right_margin +
+			  var->hsync_len + var->left_margin;
+		v_total = var->yres + var->lower_margin +
+			  var->vsync_len + var->upper_margin;
+
+		/*
+		 * Read the PLL to figure actual Refresh Rate.
+		 */
+    		clock_cntl = aty_ld_8(CLOCK_CNTL, info);
+		/* printk("atyfb: CLOCK_CNTL: %02x\n", clock_cntl); */
+		for (i = 0; i < 16; i++)
+			pll_regs[i] = aty_ld_pll(i, info);
+
+		/*
+		 * PLL Reference Divider M:
+		 */
+		M = pll_regs[2];
+
+		/*
+		 * PLL Feedback Divider N (Dependant on CLOCK_CNTL):
+		 */
+		N = pll_regs[7 + (clock_cntl & 3)];
+
+		/*
+		 * PLL Post Divider P (Dependant on CLOCK_CNTL):
+		 */
+		P = 1 << (pll_regs[6] >> ((clock_cntl & 3) << 1));
+
+		/*
+		 * PLL Divider Q:
+		 */
+		Q = N / P;
+
+		/*
+		 * Target Frequency:
+		 *
+		 *      T * M
+		 * Q = -------
+		 *      2 * R
+		 *
+		 * where R is XTALIN (= 14318 or 29498 kHz).
+		 */
+		if (pdev->device == XL_CHIP_ID)
+			R = 29498;
+		else
+			R = 14318;
+
+		T = 2 * Q * R / M;
+
+		default_var.pixclock = 1000000000 / T;
+	    }
+#else /* __sparc__ */
+
+	    info->ati_regbase_phys = 0x7ff000 + addr;
+	    info->ati_regbase = (unsigned long)
+				ioremap(info->ati_regbase_phys, 0x1000);
+
+	    if(!info->ati_regbase) {
+		    kfree(info);
+		    release_mem_region(res_start, res_size);
+		    return -ENOMEM;
+	    }
+
+	    info->ati_regbase_phys += 0xc00;
+	    info->ati_regbase += 0xc00;
+
+	    /*
+	     * Enable memory-space accesses using config-space
+	     * command register.
+	     */
+	    pci_read_config_word(pdev, PCI_COMMAND, &tmp);
+	    if (!(tmp & PCI_COMMAND_MEMORY)) {
+		tmp |= PCI_COMMAND_MEMORY;
+		pci_write_config_word(pdev, PCI_COMMAND, tmp);
+	    }
+
+#ifdef __BIG_ENDIAN
+	    /* Use the big-endian aperture */
+	    addr += 0x800000;
+#endif
+
+	    /* Map in frame buffer */
+	    info->frame_buffer_phys = addr;
+	    info->frame_buffer = (unsigned long)ioremap(addr, 0x800000);
+
+	    if(!info->frame_buffer) {
+		    kfree(info);
+		    release_mem_region(res_start, res_size);
+		    return -ENXIO;
+	    }
+
+#endif /* __sparc__ */
+
+	    if (!aty_init(info, "PCI")) {
+		if (info->mmap_map)
+		    kfree(info->mmap_map);
+		kfree(info);
+		release_mem_region(res_start, res_size);
+		return -ENXIO;
+	    }
+
+#ifdef __sparc__
+	    if (!prom_palette)
+		prom_palette = atyfb_palette;
+
+	    /*
+	     * Add /dev/fb mmap values.
+	     */
+	    info->mmap_map[0].voff = 0x8000000000000000UL;
+	    info->mmap_map[0].poff = info->frame_buffer & PAGE_MASK;
+	    info->mmap_map[0].size = info->total_vram;
+	    info->mmap_map[0].prot_mask = _PAGE_CACHE;
+	    info->mmap_map[0].prot_flag = _PAGE_E;
+	    info->mmap_map[1].voff = info->mmap_map[0].voff + info->total_vram;
+	    info->mmap_map[1].poff = info->ati_regbase & PAGE_MASK;
+	    info->mmap_map[1].size = PAGE_SIZE;
+	    info->mmap_map[1].prot_mask = _PAGE_CACHE;
+	    info->mmap_map[1].prot_flag = _PAGE_E;
+#endif /* __sparc__ */
+
+#ifdef CONFIG_PMAC_PBOOK
+	    if (first_display == NULL)
+		    pmu_register_sleep_notifier(&aty_sleep_notifier);
+	    info->next = first_display;
+	    first_display = info;
+#endif
+
+#ifdef CONFIG_FB_COMPAT_XPMAC
+	    if (!console_fb_info)
+		console_fb_info = &info->fb_info;
+#endif /* CONFIG_FB_COMPAT_XPMAC */
+	}
+    }
+
+#elif defined(CONFIG_ATARI)
+    u32 clock_r;
+    int m64_num;
+    struct fb_info_aty *info;
+
+    for (m64_num = 0; m64_num < mach64_count; m64_num++) {
+	if (!phys_vmembase[m64_num] || !phys_size[m64_num] ||
+	    !phys_guiregbase[m64_num]) {
+	    printk(" phys_*[%d] parameters not set => returning early. \n",
+		   m64_num);
+	    continue;
+	}
+
+	info = kmalloc(sizeof(struct fb_info_aty), GFP_ATOMIC);
+	if (!info) {
+	    printk("atyfb_init: can't alloc fb_info_aty\n");
+	    return -ENOMEM;
+	}
+	memset(info, 0, sizeof(struct fb_info_aty));
+
+	/*
+	 *  Map the video memory (physical address given) to somewhere in the
+	 *  kernel address space.
+	 */
+	info->frame_buffer = ioremap(phys_vmembase[m64_num], phys_size[m64_num]);
+	info->frame_buffer_phys = info->frame_buffer;  /* Fake! */
+	info->ati_regbase = ioremap(phys_guiregbase[m64_num], 0x10000)+0xFC00ul;
+	info->ati_regbase_phys = info->ati_regbase;  /* Fake! */
+
+	aty_st_le32(CLOCK_CNTL, 0x12345678, info);
+	clock_r = aty_ld_le32(CLOCK_CNTL, info);
+
+	switch (clock_r & 0x003F) {
+	    case 0x12:
+		info->clk_wr_offset = 3;  /*  */
+		break;
+	    case 0x34:
+		info->clk_wr_offset = 2;  /* Medusa ST-IO ISA Adapter etc. */
+		break;
+	    case 0x16:
+		info->clk_wr_offset = 1;  /*  */
+		break;
+	    case 0x38:
+		info->clk_wr_offset = 0;  /* Panther 1 ISA Adapter (Gerald) */
+		break;
+	}
+
+	if (!aty_init(info, "ISA bus")) {
+	    kfree(info);
+	    /* This is insufficient! kernel_map has added two large chunks!! */
+	    return -ENXIO;
+	}
+    }
+#endif /* CONFIG_ATARI */
+    return 0;
+}
+
+#ifndef MODULE
+int __init atyfb_setup(char *options)
+{
+    char *this_opt;
+
+    if (!options || !*options)
+	return 0;
+
+    for (this_opt = strtok(options, ","); this_opt;
+	 this_opt = strtok(NULL, ",")) {
+	if (!strncmp(this_opt, "font:", 5)) {
+		char *p;
+		int i;
+
+		p = this_opt + 5;
+		for (i = 0; i < sizeof(fontname) - 1; i++)
+			if (!*p || *p == ' ' || *p == ',')
+				break;
+		memcpy(fontname, this_opt + 5, i);
+		fontname[i] = 0;
+	} else if (!strncmp(this_opt, "noblink", 7)) {
+		curblink = 0;
+	} else if (!strncmp(this_opt, "noaccel", 7)) {
+		noaccel = 1;
+	} else if (!strncmp(this_opt, "vram:", 5))
+		default_vram = simple_strtoul(this_opt+5, NULL, 0);
+	else if (!strncmp(this_opt, "pll:", 4))
+		default_pll = simple_strtoul(this_opt+4, NULL, 0);
+	else if (!strncmp(this_opt, "mclk:", 5))
+		default_mclk = simple_strtoul(this_opt+5, NULL, 0);
+#ifdef CONFIG_PPC
+	else if (!strncmp(this_opt, "vmode:", 6)) {
+	    unsigned int vmode = simple_strtoul(this_opt+6, NULL, 0);
+	    if (vmode > 0 && vmode <= VMODE_MAX)
+		default_vmode = vmode;
+	} else if (!strncmp(this_opt, "cmode:", 6)) {
+	    unsigned int cmode = simple_strtoul(this_opt+6, NULL, 0);
+	    switch (cmode) {
+		case 0:
+		case 8:
+		    default_cmode = CMODE_8;
+		    break;
+		case 15:
+		case 16:
+		    default_cmode = CMODE_16;
+		    break;
+		case 24:
+		case 32:
+		    default_cmode = CMODE_32;
+		    break;
+	    }
+	}
+#endif
+#ifdef CONFIG_ATARI
+	/*
+	 * Why do we need this silly Mach64 argument?
+	 * We are already here because of mach64= so its redundant.
+	 */
+	else if (MACH_IS_ATARI && (!strncmp(this_opt, "Mach64:", 7))) {
+	    static unsigned char m64_num;
+	    static char mach64_str[80];
+	    strncpy(mach64_str, this_opt+7, 80);
+	    if (!store_video_par(mach64_str, m64_num)) {
+		m64_num++;
+		mach64_count = m64_num;
+	    }
+	}
+#endif
+	else
+	    mode_option = this_opt;
+    }
+    return 0;
+}
+#endif /* !MODULE */
+
+#ifdef CONFIG_ATARI
+static int __init store_video_par(char *video_str, unsigned char m64_num)
+{
+    char *p;
+    unsigned long vmembase, size, guiregbase;
+
+    printk("store_video_par() '%s' \n", video_str);
+
+    if (!(p = strtoke(video_str, ";")) || !*p)
+	goto mach64_invalid;
+    vmembase = simple_strtoul(p, NULL, 0);
+    if (!(p = strtoke(NULL, ";")) || !*p)
+	goto mach64_invalid;
+    size = simple_strtoul(p, NULL, 0);
+    if (!(p = strtoke(NULL, ";")) || !*p)
+	goto mach64_invalid;
+    guiregbase = simple_strtoul(p, NULL, 0);
+
+    phys_vmembase[m64_num] = vmembase;
+    phys_size[m64_num] = size;
+    phys_guiregbase[m64_num] = guiregbase;
+    printk(" stored them all: $%08lX $%08lX $%08lX \n", vmembase, size,
+	   guiregbase);
+    return 0;
+
+mach64_invalid:
+    phys_vmembase[m64_num]   = 0;
+    return -1;
+}
+
+static char __init *strtoke(char *s, const char *ct)
+{
+    static char *ssave = NULL;
+    char *sbegin, *send;
+
+    sbegin  = s ? s : ssave;
+    if (!sbegin)
+	return NULL;
+    if (*sbegin == '\0') {
+	ssave = NULL;
+	return NULL;
+    }
+    send = strpbrk(sbegin, ct);
+    if (send && *send != '\0')
+	*send++ = '\0';
+    ssave = send;
+    return sbegin;
+}
+#endif /* CONFIG_ATARI */
+
+static int atyfbcon_switch(int con, struct fb_info *fb)
+{
+    struct fb_info_aty *info = (struct fb_info_aty *)fb;
+    struct atyfb_par par;
+
+    /* Do we have to save the colormap? */
+    if (fb_display[currcon].cmap.len)
+	fb_get_cmap(&fb_display[currcon].cmap, 1, atyfb_getcolreg, fb);
+
+#ifdef CONFIG_FB_ATY_CT
+    /* Erase HW Cursor */
+    if (info->cursor)
+	atyfb_cursor(&fb_display[currcon], CM_ERASE,
+		     info->cursor->pos.x, info->cursor->pos.y);
+#endif /* CONFIG_FB_ATY_CT */
+
+    currcon = con;
+
+    atyfb_decode_var(&fb_display[con].var, &par, info);
+    atyfb_set_par(&par, info);
+    atyfb_set_dispsw(&fb_display[con], info, par.crtc.bpp,
+		     par.accel_flags & FB_ACCELF_TEXT);
+
+    /* Install new colormap */
+    do_install_cmap(con, fb);
+
+#ifdef CONFIG_FB_ATY_CT
+    /* Install hw cursor */
+    if (info->cursor) {
+	aty_set_cursor_color(info);
+	aty_set_cursor_shape(info);
+    }
+#endif /* CONFIG_FB_ATY_CT */
+    return 1;
+}
+
+    /*
+     *  Blank the display.
+     */
+
+static void atyfbcon_blank(int blank, struct fb_info *fb)
+{
+    struct fb_info_aty *info = (struct fb_info_aty *)fb;
+    u8 gen_cntl;
+
+#ifdef CONFIG_PMAC_BACKLIGHT
+    if ((_machine == _MACH_Pmac) && blank)
+    	set_backlight_enable(0);
+#endif /* CONFIG_PMAC_BACKLIGHT */
+
+    gen_cntl = aty_ld_8(CRTC_GEN_CNTL, info);
+    if (blank > 0)
+	switch (blank-1) {
+	    case VESA_NO_BLANKING:
+		gen_cntl |= 0x40;
+		break;
+	    case VESA_VSYNC_SUSPEND:
+		gen_cntl |= 0x8;
+		break;
+	    case VESA_HSYNC_SUSPEND:
+		gen_cntl |= 0x4;
+		break;
+	    case VESA_POWERDOWN:
+		gen_cntl |= 0x4c;
+		break;
+	}
+    else
+	gen_cntl &= ~(0x4c);
+    aty_st_8(CRTC_GEN_CNTL, gen_cntl, info);
+
+#ifdef CONFIG_PMAC_BACKLIGHT
+    if ((_machine == _MACH_Pmac) && !blank)
+    	set_backlight_enable(1);
+#endif /* CONFIG_PMAC_BACKLIGHT */
+}
+
+
+    /*
+     *  Read a single color register and split it into
+     *  colors/transparent. Return != 0 for invalid regno.
+     */
+
+static int atyfb_getcolreg(u_int regno, u_int *red, u_int *green, u_int *blue,
+			   u_int *transp, struct fb_info *fb)
+{
+    struct fb_info_aty *info = (struct fb_info_aty *)fb;
+
+    if (regno > 255)
+	return 1;
+    *red = (info->palette[regno].red<<8) | info->palette[regno].red;
+    *green = (info->palette[regno].green<<8) | info->palette[regno].green;
+    *blue = (info->palette[regno].blue<<8) | info->palette[regno].blue;
+    *transp = 0;
+    return 0;
+}
+
+
+    /*
+     *  Set a single color register. The values supplied are already
+     *  rounded down to the hardware's capabilities (according to the
+     *  entries in the var structure). Return != 0 for invalid regno.
+     */
+
+static int atyfb_setcolreg(u_int regno, u_int red, u_int green, u_int blue,
+			   u_int transp, struct fb_info *fb)
+{
+    struct fb_info_aty *info = (struct fb_info_aty *)fb;
+    int i, scale;
+
+    if (regno > 255)
+	return 1;
+    red >>= 8;
+    green >>= 8;
+    blue >>= 8;
+    info->palette[regno].red = red;
+    info->palette[regno].green = green;
+    info->palette[regno].blue = blue;
+    i = aty_ld_8(DAC_CNTL, info) & 0xfc;
+    if (M64_HAS(EXTRA_BRIGHT))
+	i |= 0x2;	/*DAC_CNTL|0x2 turns off the extra brightness for gt*/
+    aty_st_8(DAC_CNTL, i, info);
+    aty_st_8(DAC_MASK, 0xff, info);
+    scale = (M64_HAS(INTEGRATED) && info->current_par.crtc.bpp == 16) ? 3 : 0;
+    writeb(regno << scale, &info->aty_cmap_regs->windex);
+    writeb(red, &info->aty_cmap_regs->lut);
+    writeb(green, &info->aty_cmap_regs->lut);
+    writeb(blue, &info->aty_cmap_regs->lut);
+    if (regno < 16)
+	switch (info->current_par.crtc.bpp) {
+#ifdef FBCON_HAS_CFB16
+	    case 16:
+		info->fbcon_cmap.cfb16[regno] = (regno << 10) | (regno << 5) |
+						regno;
+		break;
+#endif
+#ifdef FBCON_HAS_CFB24
+	    case 24:
+		info->fbcon_cmap.cfb24[regno] = (regno << 16) | (regno << 8) |
+						regno;
+		break;
+#endif
+#ifdef FBCON_HAS_CFB32
+	    case 32:
+		i = (regno << 8) | regno;
+		info->fbcon_cmap.cfb32[regno] = (i << 16) | i;
+		break;
+#endif
+	    }
+    return 0;
+}
+
+
+static void do_install_cmap(int con, struct fb_info *info)
+{
+    if (con != currcon)
+	return;
+    if (fb_display[con].cmap.len)
+	fb_set_cmap(&fb_display[con].cmap, 1, atyfb_setcolreg, info);
+    else {
+	int size = fb_display[con].var.bits_per_pixel == 16 ? 32 : 256;
+	fb_set_cmap(fb_default_cmap(size), 1, atyfb_setcolreg, info);
+    }
+}
+
+
+    /*
+     *  Update the `var' structure (called by fbcon.c)
+     */
+
+static int atyfbcon_updatevar(int con, struct fb_info *fb)
+{
+    struct fb_info_aty *info = (struct fb_info_aty *)fb;
+    struct atyfb_par *par = &info->current_par;
+    struct display *p = &fb_display[con];
+    struct vc_data *conp = p->conp;
+    u32 yres, yoffset, sy, height;
+
+    yres = ((par->crtc.v_tot_disp >> 16) & 0x7ff) + 1;
+    yoffset = fb_display[con].var.yoffset;
+
+    sy = (conp->vc_rows + p->yscroll) * fontheight(p);
+    height = yres - conp->vc_rows * fontheight(p);
+
+    if (height && (yoffset + yres > sy)) {
+	u32 xres, xoffset;
+	u32 bgx;
+
+	xres = (((par->crtc.h_tot_disp >> 16) & 0xff) + 1) * 8;
+	xoffset = fb_display[con].var.xoffset;
+
+
+	bgx = attr_bgcol_ec(p, conp);
+	bgx |= (bgx << 8);
+	bgx |= (bgx << 16);
+
+	if (sy + height > par->crtc.vyres) {
+	    wait_for_fifo(1, info);
+	    aty_st_le32(SC_BOTTOM, sy + height - 1, info);
+	}
+	aty_rectfill(xoffset, sy, xres, height, bgx, info);
+    }
+
+#ifdef CONFIG_FB_ATY_CT
+    if (info->cursor && (yoffset + yres <= sy))
+	atyfb_cursor(p, CM_ERASE, info->cursor->pos.x, info->cursor->pos.y);
+#endif /* CONFIG_FB_ATY_CT */
+
+    info->current_par.crtc.yoffset = yoffset;
+    set_off_pitch(&info->current_par, info);
+    return 0;
+}
+
+
+
+#ifdef MODULE
+int __init init_module(void)
+{
+    atyfb_init();
+    return fb_list ? 0 : -ENXIO;
+}
+
+void cleanup_module(void)
+{
+    while (fb_list) {
+	struct fb_info_aty *info = fb_list;
+	fb_list = info->next;
+
+	unregister_framebuffer(&info->fb_info);
+
+#ifndef __sparc__
+	if (info->ati_regbase)
+	    iounmap((void *)info->ati_regbase);
+	if (info->frame_buffer)
+	    iounmap((void *)info->frame_buffer);
+#ifdef __BIG_ENDIAN
+	if (info->cursor && info->cursor->ram)
+	    iounmap(info->cursor->ram);
+#endif
+#endif
+
+	if (info->cursor) {
+	    if (info->cursor->timer)
+		kfree(info->cursor->timer);
+	    kfree(info->cursor);
+	}
+#ifdef __sparc__
+	if (info->mmap_map)
+	    kfree(info->mmap_map);
+#endif
+	kfree(info);
+    }
+}
+
+#endif
diff -u --recursive --new-file v2.4.7/linux/drivers/video/aty/mach64.h linux/drivers/video/aty/mach64.h
--- v2.4.7/linux/drivers/video/aty/mach64.h	Wed Dec 31 16:00:00 1969
+++ linux/drivers/video/aty/mach64.h	Tue Jul 31 14:43:29 2001
@@ -0,0 +1,1158 @@
+/*
+ * ATI Mach64 Register Definitions
+ *
+ * Copyright (C) 1997 Michael AK Tesch
+ *  written with much help from Jon Howell
+ *
+ * Updated for 3D RAGE PRO and 3D RAGE Mobility by Geert Uytterhoeven
+ *	
+ * 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.
+ */
+
+/*
+ * most of the rest of this file comes from ATI sample code
+ */
+#ifndef REGMACH64_H
+#define REGMACH64_H
+
+/* NON-GUI MEMORY MAPPED Registers - expressed in BYTE offsets */
+
+/* Accelerator CRTC */
+#define CRTC_H_TOTAL_DISP	0x0000	/* Dword offset 0_00 */
+#define CRTC2_H_TOTAL_DISP	0x0000	/* Dword offset 0_00 */
+#define CRTC_H_SYNC_STRT_WID	0x0004	/* Dword offset 0_01 */
+#define CRTC2_H_SYNC_STRT_WID	0x0004	/* Dword offset 0_01 */
+#define CRTC_H_SYNC_STRT	0x0004
+#define CRTC2_H_SYNC_STRT	0x0004
+#define CRTC_H_SYNC_DLY		0x0005
+#define CRTC2_H_SYNC_DLY	0x0005
+#define CRTC_H_SYNC_WID		0x0006
+#define CRTC2_H_SYNC_WID	0x0006
+#define CRTC_V_TOTAL_DISP	0x0008	/* Dword offset 0_02 */
+#define CRTC2_V_TOTAL_DISP	0x0008	/* Dword offset 0_02 */
+#define CRTC_V_TOTAL		0x0008
+#define CRTC2_V_TOTAL		0x0008
+#define CRTC_V_DISP		0x000A
+#define CRTC2_V_DISP		0x000A
+#define CRTC_V_SYNC_STRT_WID	0x000C	/* Dword offset 0_03 */
+#define CRTC2_V_SYNC_STRT_WID	0x000C	/* Dword offset 0_03 */
+#define CRTC_V_SYNC_STRT	0x000C
+#define CRTC2_V_SYNC_STRT	0x000C
+#define CRTC_V_SYNC_WID		0x000E
+#define CRTC2_V_SYNC_WID	0x000E
+#define CRTC_VLINE_CRNT_VLINE	0x0010	/* Dword offset 0_04 */
+#define CRTC2_VLINE_CRNT_VLINE	0x0010	/* Dword offset 0_04 */
+#define CRTC_OFF_PITCH		0x0014	/* Dword offset 0_05 */
+#define CRTC_OFFSET		0x0014
+#define CRTC_PITCH		0x0016
+#define CRTC_INT_CNTL		0x0018	/* Dword offset 0_06 */
+#define CRTC_GEN_CNTL		0x001C	/* Dword offset 0_07 */
+#define CRTC_PIX_WIDTH		0x001D
+#define CRTC_FIFO		0x001E
+#define CRTC_EXT_DISP		0x001F
+
+/* Memory Buffer Control */
+#define DSP_CONFIG		0x0020	/* Dword offset 0_08 */
+#define PM_DSP_CONFIG		0x0020	/* Dword offset 0_08 (Mobility Only) */
+#define DSP_ON_OFF		0x0024	/* Dword offset 0_09 */
+#define PM_DSP_ON_OFF		0x0024	/* Dword offset 0_09 (Mobility Only) */
+#define TIMER_CONFIG		0x0028	/* Dword offset 0_0A */
+#define MEM_BUF_CNTL		0x002C	/* Dword offset 0_0B */
+#define MEM_ADDR_CONFIG		0x0034	/* Dword offset 0_0D */
+
+/* Accelerator CRTC */
+#define CRT_TRAP		0x0038	/* Dword offset 0_0E */
+
+#define I2C_CNTL_0		0x003C	/* Dword offset 0_0F */
+
+/* Overscan */
+#define OVR_CLR			0x0040	/* Dword offset 0_10 */
+#define OVR2_CLR		0x0040	/* Dword offset 0_10 */
+#define OVR_WID_LEFT_RIGHT	0x0044	/* Dword offset 0_11 */
+#define OVR2_WID_LEFT_RIGHT	0x0044	/* Dword offset 0_11 */
+#define OVR_WID_TOP_BOTTOM	0x0048	/* Dword offset 0_12 */
+#define OVR2_WID_TOP_BOTTOM	0x0048	/* Dword offset 0_12 */
+
+/* Memory Buffer Control */
+#define VGA_DSP_CONFIG		0x004C	/* Dword offset 0_13 */
+#define PM_VGA_DSP_CONFIG	0x004C	/* Dword offset 0_13 (Mobility Only) */
+#define VGA_DSP_ON_OFF		0x0050	/* Dword offset 0_14 */
+#define PM_VGA_DSP_ON_OFF	0x0050	/* Dword offset 0_14 (Mobility Only) */
+#define DSP2_CONFIG		0x0054	/* Dword offset 0_15 */
+#define PM_DSP2_CONFIG		0x0054	/* Dword offset 0_15 (Mobility Only) */
+#define DSP2_ON_OFF		0x0058	/* Dword offset 0_16 */
+#define PM_DSP2_ON_OFF		0x0058	/* Dword offset 0_16 (Mobility Only) */
+
+/* Accelerator CRTC */
+#define CRTC2_OFF_PITCH		0x005C	/* Dword offset 0_17 */
+
+/* Hardware Cursor */
+#define CUR_CLR0		0x0060	/* Dword offset 0_18 */
+#define CUR2_CLR0		0x0060	/* Dword offset 0_18 */
+#define CUR_CLR1		0x0064	/* Dword offset 0_19 */
+#define CUR2_CLR1		0x0064	/* Dword offset 0_19 */
+#define CUR_OFFSET		0x0068	/* Dword offset 0_1A */
+#define CUR2_OFFSET		0x0068	/* Dword offset 0_1A */
+#define CUR_HORZ_VERT_POSN	0x006C	/* Dword offset 0_1B */
+#define CUR2_HORZ_VERT_POSN	0x006C	/* Dword offset 0_1B */
+#define CUR_HORZ_VERT_OFF	0x0070	/* Dword offset 0_1C */
+#define CUR2_HORZ_VERT_OFF	0x0070	/* Dword offset 0_1C */
+
+#define CONFIG_PANEL_LG		0x0074	/* Dword offset 0_1D */
+
+/* General I/O Control */
+#define GP_IO			0x0078	/* Dword offset 0_1E */
+
+/* Test and Debug */
+#define HW_DEBUG		0x007C	/* Dword offset 0_1F */
+
+/* Scratch Pad and Test */
+#define SCRATCH_REG0		0x0080	/* Dword offset 0_20 */
+#define SCRATCH_REG1		0x0084	/* Dword offset 0_21 */
+#define SCRATCH_REG2		0x0088	/* Dword offset 0_22 */
+#define SCRATCH_REG3		0x008C	/* Dword offset 0_23 */
+
+/* Clock Control */
+#define CLOCK_CNTL		0x0090	/* Dword offset 0_24 */
+#define CLOCK_SEL_CNTL		0x0090	/* Dword offset 0_24 */
+
+/* Configuration */
+#define CONFIG_STAT1		0x0094	/* Dword offset 0_25 */
+#define CONFIG_STAT2		0x0098	/* Dword offset 0_26 */
+
+/* Bus Control */
+#define BUS_CNTL		0x00A0	/* Dword offset 0_28 */
+
+#define LCD_INDEX		0x00A4	/* Dword offset 0_29 */
+#define LCD_DATA		0x00A8	/* Dword offset 0_2A */
+
+/* Memory Control */
+#define EXT_MEM_CNTL		0x00AC	/* Dword offset 0_2B */
+#define MEM_CNTL		0x00B0	/* Dword offset 0_2C */
+#define MEM_VGA_WP_SEL		0x00B4	/* Dword offset 0_2D */
+#define MEM_VGA_RP_SEL		0x00B8	/* Dword offset 0_2E */
+
+#define I2C_CNTL_1		0x00BC	/* Dword offset 0_2F */
+
+/* DAC Control */
+#define DAC_REGS		0x00C0	/* Dword offset 0_30 */
+#define DAC_W_INDEX		0x00C0	/* Dword offset 0_30 */
+#define DAC_DATA		0x00C1	/* Dword offset 0_30 */
+#define DAC_MASK		0x00C2	/* Dword offset 0_30 */
+#define DAC_R_INDEX		0x00C3	/* Dword offset 0_30 */
+#define DAC_CNTL		0x00C4	/* Dword offset 0_31 */
+
+#define EXT_DAC_REGS		0x00C8	/* Dword offset 0_32 */
+
+/* Test and Debug */
+#define GEN_TEST_CNTL		0x00D0	/* Dword offset 0_34 */
+
+/* Custom Macros */
+#define CUSTOM_MACRO_CNTL	0x00D4	/* Dword offset 0_35 */
+
+#define LCD_GEN_CNTL_LG		0x00D4	/* Dword offset 0_35 */
+
+#define POWER_MANAGEMENT_LG	0x00D8	/* Dword offset 0_36 (LG) */
+
+/* Configuration */
+#define CONFIG_CNTL		0x00DC	/* Dword offset 0_37 (CT, ET, VT) */
+#define CONFIG_CHIP_ID		0x00E0	/* Dword offset 0_38 */
+#define CONFIG_STAT0		0x00E4	/* Dword offset 0_39 */
+
+/* Test and Debug */
+#define CRC_SIG			0x00E8	/* Dword offset 0_3A */
+#define CRC2_SIG		0x00E8	/* Dword offset 0_3A */
+
+
+/* GUI MEMORY MAPPED Registers */
+
+/* Draw Engine Destination Trajectory */
+#define DST_OFF_PITCH		0x0100	/* Dword offset 0_40 */
+#define DST_X			0x0104	/* Dword offset 0_41 */
+#define DST_Y			0x0108	/* Dword offset 0_42 */
+#define DST_Y_X			0x010C	/* Dword offset 0_43 */
+#define DST_WIDTH		0x0110	/* Dword offset 0_44 */
+#define DST_HEIGHT		0x0114	/* Dword offset 0_45 */
+#define DST_HEIGHT_WIDTH	0x0118	/* Dword offset 0_46 */
+#define DST_X_WIDTH		0x011C	/* Dword offset 0_47 */
+#define DST_BRES_LNTH		0x0120	/* Dword offset 0_48 */
+#define DST_BRES_ERR		0x0124	/* Dword offset 0_49 */
+#define DST_BRES_INC		0x0128	/* Dword offset 0_4A */
+#define DST_BRES_DEC		0x012C	/* Dword offset 0_4B */
+#define DST_CNTL		0x0130	/* Dword offset 0_4C */
+#define DST_Y_X__ALIAS__	0x0134	/* Dword offset 0_4D */
+#define TRAIL_BRES_ERR		0x0138	/* Dword offset 0_4E */
+#define TRAIL_BRES_INC		0x013C	/* Dword offset 0_4F */
+#define TRAIL_BRES_DEC		0x0140	/* Dword offset 0_50 */
+#define LEAD_BRES_LNTH		0x0144	/* Dword offset 0_51 */
+#define Z_OFF_PITCH		0x0148	/* Dword offset 0_52 */
+#define Z_CNTL			0x014C	/* Dword offset 0_53 */
+#define ALPHA_TST_CNTL		0x0150	/* Dword offset 0_54 */
+#define SECONDARY_STW_EXP	0x0158	/* Dword offset 0_56 */
+#define SECONDARY_S_X_INC	0x015C	/* Dword offset 0_57 */
+#define SECONDARY_S_Y_INC	0x0160	/* Dword offset 0_58 */
+#define SECONDARY_S_START	0x0164	/* Dword offset 0_59 */
+#define SECONDARY_W_X_INC	0x0168	/* Dword offset 0_5A */
+#define SECONDARY_W_Y_INC	0x016C	/* Dword offset 0_5B */
+#define SECONDARY_W_START	0x0170	/* Dword offset 0_5C */
+#define SECONDARY_T_X_INC	0x0174	/* Dword offset 0_5D */
+#define SECONDARY_T_Y_INC	0x0178	/* Dword offset 0_5E */
+#define SECONDARY_T_START	0x017C	/* Dword offset 0_5F */
+
+/* Draw Engine Source Trajectory */
+#define SRC_OFF_PITCH		0x0180	/* Dword offset 0_60 */
+#define SRC_X			0x0184	/* Dword offset 0_61 */
+#define SRC_Y			0x0188	/* Dword offset 0_62 */
+#define SRC_Y_X			0x018C	/* Dword offset 0_63 */
+#define SRC_WIDTH1		0x0190	/* Dword offset 0_64 */
+#define SRC_HEIGHT1		0x0194	/* Dword offset 0_65 */
+#define SRC_HEIGHT1_WIDTH1	0x0198	/* Dword offset 0_66 */
+#define SRC_X_START		0x019C	/* Dword offset 0_67 */
+#define SRC_Y_START		0x01A0	/* Dword offset 0_68 */
+#define SRC_Y_X_START		0x01A4	/* Dword offset 0_69 */
+#define SRC_WIDTH2		0x01A8	/* Dword offset 0_6A */
+#define SRC_HEIGHT2		0x01AC	/* Dword offset 0_6B */
+#define SRC_HEIGHT2_WIDTH2	0x01B0	/* Dword offset 0_6C */
+#define SRC_CNTL		0x01B4	/* Dword offset 0_6D */
+
+#define SCALE_OFF		0x01C0	/* Dword offset 0_70 */
+#define SECONDARY_SCALE_OFF	0x01C4	/* Dword offset 0_71 */
+
+#define TEX_0_OFF		0x01C0	/* Dword offset 0_70 */
+#define TEX_1_OFF		0x01C4	/* Dword offset 0_71 */
+#define TEX_2_OFF		0x01C8	/* Dword offset 0_72 */
+#define TEX_3_OFF		0x01CC	/* Dword offset 0_73 */
+#define TEX_4_OFF		0x01D0	/* Dword offset 0_74 */
+#define TEX_5_OFF		0x01D4	/* Dword offset 0_75 */
+#define TEX_6_OFF		0x01D8	/* Dword offset 0_76 */
+#define TEX_7_OFF		0x01DC	/* Dword offset 0_77 */
+
+#define SCALE_WIDTH		0x01DC	/* Dword offset 0_77 */
+#define SCALE_HEIGHT		0x01E0	/* Dword offset 0_78 */
+
+#define TEX_8_OFF		0x01E0	/* Dword offset 0_78 */
+#define TEX_9_OFF		0x01E4	/* Dword offset 0_79 */
+#define TEX_10_OFF		0x01E8	/* Dword offset 0_7A */
+#define S_Y_INC			0x01EC	/* Dword offset 0_7B */
+
+#define SCALE_PITCH		0x01EC	/* Dword offset 0_7B */
+#define SCALE_X_INC		0x01F0	/* Dword offset 0_7C */
+
+#define RED_X_INC		0x01F0	/* Dword offset 0_7C */
+#define GREEN_X_INC		0x01F4	/* Dword offset 0_7D */
+
+#define SCALE_Y_INC		0x01F4	/* Dword offset 0_7D */
+#define SCALE_VACC		0x01F8	/* Dword offset 0_7E */
+#define SCALE_3D_CNTL		0x01FC	/* Dword offset 0_7F */
+
+/* Host Data */
+#define HOST_DATA0		0x0200	/* Dword offset 0_80 */
+#define HOST_DATA1		0x0204	/* Dword offset 0_81 */
+#define HOST_DATA2		0x0208	/* Dword offset 0_82 */
+#define HOST_DATA3		0x020C	/* Dword offset 0_83 */
+#define HOST_DATA4		0x0210	/* Dword offset 0_84 */
+#define HOST_DATA5		0x0214	/* Dword offset 0_85 */
+#define HOST_DATA6		0x0218	/* Dword offset 0_86 */
+#define HOST_DATA7		0x021C	/* Dword offset 0_87 */
+#define HOST_DATA8		0x0220	/* Dword offset 0_88 */
+#define HOST_DATA9		0x0224	/* Dword offset 0_89 */
+#define HOST_DATAA		0x0228	/* Dword offset 0_8A */
+#define HOST_DATAB		0x022C	/* Dword offset 0_8B */
+#define HOST_DATAC		0x0230	/* Dword offset 0_8C */
+#define HOST_DATAD		0x0234	/* Dword offset 0_8D */
+#define HOST_DATAE		0x0238	/* Dword offset 0_8E */
+#define HOST_DATAF		0x023C	/* Dword offset 0_8F */
+#define HOST_CNTL		0x0240	/* Dword offset 0_90 */
+
+/* GUI Bus Mastering */
+#define BM_HOSTDATA		0x0244	/* Dword offset 0_91 */
+#define BM_ADDR			0x0248	/* Dword offset 0_92 */
+#define BM_DATA			0x0248	/* Dword offset 0_92 */
+#define BM_GUI_TABLE_CMD	0x024C	/* Dword offset 0_93 */
+
+/* Pattern */
+#define PAT_REG0		0x0280	/* Dword offset 0_A0 */
+#define PAT_REG1		0x0284	/* Dword offset 0_A1 */
+#define PAT_CNTL		0x0288	/* Dword offset 0_A2 */
+
+/* Scissors */
+#define SC_LEFT			0x02A0	/* Dword offset 0_A8 */
+#define SC_RIGHT		0x02A4	/* Dword offset 0_A9 */
+#define SC_LEFT_RIGHT		0x02A8	/* Dword offset 0_AA */
+#define SC_TOP			0x02AC	/* Dword offset 0_AB */
+#define SC_BOTTOM		0x02B0	/* Dword offset 0_AC */
+#define SC_TOP_BOTTOM		0x02B4	/* Dword offset 0_AD */
+
+/* Data Path */
+#define USR1_DST_OFF_PITCH	0x02B8	/* Dword offset 0_AE */
+#define USR2_DST_OFF_PITCH	0x02BC	/* Dword offset 0_AF */
+#define DP_BKGD_CLR		0x02C0	/* Dword offset 0_B0 */
+#define DP_FOG_CLR		0x02C4	/* Dword offset 0_B1 */
+#define DP_FRGD_CLR		0x02C4	/* Dword offset 0_B1 */
+#define DP_WRITE_MASK		0x02C8	/* Dword offset 0_B2 */
+#define DP_CHAIN_MASK		0x02CC	/* Dword offset 0_B3 */
+#define DP_PIX_WIDTH		0x02D0	/* Dword offset 0_B4 */
+#define DP_MIX			0x02D4	/* Dword offset 0_B5 */
+#define DP_SRC			0x02D8	/* Dword offset 0_B6 */
+#define DP_FRGD_CLR_MIX		0x02DC	/* Dword offset 0_B7 */
+#define DP_FRGD_BKGD_CLR	0x02E0	/* Dword offset 0_B8 */
+
+/* Draw Engine Destination Trajectory */
+#define DST_X_Y			0x02E8	/* Dword offset 0_BA */
+#define DST_WIDTH_HEIGHT	0x02EC	/* Dword offset 0_BB */
+
+/* Data Path */
+#define USR_DST_PICTH		0x02F0	/* Dword offset 0_BC */
+#define DP_SET_GUI_ENGINE2	0x02F8	/* Dword offset 0_BE */
+#define DP_SET_GUI_ENGINE	0x02FC	/* Dword offset 0_BF */
+
+/* Color Compare */
+#define CLR_CMP_CLR		0x0300	/* Dword offset 0_C0 */
+#define CLR_CMP_MASK		0x0304	/* Dword offset 0_C1 */
+#define CLR_CMP_CNTL		0x0308	/* Dword offset 0_C2 */
+
+/* Command FIFO */
+#define FIFO_STAT		0x0310	/* Dword offset 0_C4 */
+
+#define CONTEXT_MASK		0x0320	/* Dword offset 0_C8 */
+#define CONTEXT_LOAD_CNTL	0x032C	/* Dword offset 0_CB */
+
+/* Engine Control */
+#define GUI_TRAJ_CNTL		0x0330	/* Dword offset 0_CC */
+
+/* Engine Status/FIFO */
+#define GUI_STAT		0x0338	/* Dword offset 0_CE */
+
+#define TEX_PALETTE_INDEX	0x0340	/* Dword offset 0_D0 */
+#define STW_EXP			0x0344	/* Dword offset 0_D1 */
+#define LOG_MAX_INC		0x0348	/* Dword offset 0_D2 */
+#define S_X_INC			0x034C	/* Dword offset 0_D3 */
+#define S_Y_INC__ALIAS__	0x0350	/* Dword offset 0_D4 */
+
+#define SCALE_PITCH__ALIAS__	0x0350	/* Dword offset 0_D4 */
+
+#define S_START			0x0354	/* Dword offset 0_D5 */
+#define W_X_INC			0x0358	/* Dword offset 0_D6 */
+#define W_Y_INC			0x035C	/* Dword offset 0_D7 */
+#define W_START			0x0360	/* Dword offset 0_D8 */
+#define T_X_INC			0x0364	/* Dword offset 0_D9 */
+#define T_Y_INC			0x0368	/* Dword offset 0_DA */
+
+#define SECONDARY_SCALE_PITCH	0x0368	/* Dword offset 0_DA */
+
+#define T_START			0x036C	/* Dword offset 0_DB */
+#define TEX_SIZE_PITCH		0x0370	/* Dword offset 0_DC */
+#define TEX_CNTL		0x0374	/* Dword offset 0_DD */
+#define SECONDARY_TEX_OFFSET	0x0378	/* Dword offset 0_DE */
+#define TEX_PALETTE		0x037C	/* Dword offset 0_DF */
+
+#define SCALE_PITCH_BOTH	0x0380	/* Dword offset 0_E0 */
+#define SECONDARY_SCALE_OFF_ACC	0x0384	/* Dword offset 0_E1 */
+#define SCALE_OFF_ACC		0x0388	/* Dword offset 0_E2 */
+#define SCALE_DST_Y_X		0x038C	/* Dword offset 0_E3 */
+
+/* Draw Engine Destination Trajectory */
+#define COMPOSITE_SHADOW_ID	0x0398	/* Dword offset 0_E6 */
+
+#define SECONDARY_SCALE_X_INC	0x039C	/* Dword offset 0_E7 */
+
+#define SPECULAR_RED_X_INC	0x039C	/* Dword offset 0_E7 */
+#define SPECULAR_RED_Y_INC	0x03A0	/* Dword offset 0_E8 */
+#define SPECULAR_RED_START	0x03A4	/* Dword offset 0_E9 */
+
+#define SECONDARY_SCALE_HACC	0x03A4	/* Dword offset 0_E9 */
+
+#define SPECULAR_GREEN_X_INC	0x03A8	/* Dword offset 0_EA */
+#define SPECULAR_GREEN_Y_INC	0x03AC	/* Dword offset 0_EB */
+#define SPECULAR_GREEN_START	0x03B0	/* Dword offset 0_EC */
+#define SPECULAR_BLUE_X_INC	0x03B4	/* Dword offset 0_ED */
+#define SPECULAR_BLUE_Y_INC	0x03B8	/* Dword offset 0_EE */
+#define SPECULAR_BLUE_START	0x03BC	/* Dword offset 0_EF */
+
+#define SCALE_X_INC__ALIAS__	0x03C0	/* Dword offset 0_F0 */
+
+#define RED_X_INC__ALIAS__	0x03C0	/* Dword offset 0_F0 */
+#define RED_Y_INC		0x03C4	/* Dword offset 0_F1 */
+#define RED_START		0x03C8	/* Dword offset 0_F2 */
+
+#define SCALE_HACC		0x03C8	/* Dword offset 0_F2 */
+#define SCALE_Y_INC__ALIAS__	0x03CC	/* Dword offset 0_F3 */
+
+#define GREEN_X_INC__ALIAS__	0x03CC	/* Dword offset 0_F3 */
+#define GREEN_Y_INC		0x03D0	/* Dword offset 0_F4 */
+
+#define SECONDARY_SCALE_Y_INC	0x03D0	/* Dword offset 0_F4 */
+#define SECONDARY_SCALE_VACC	0x03D4	/* Dword offset 0_F5 */
+
+#define GREEN_START		0x03D4	/* Dword offset 0_F5 */
+#define BLUE_X_INC		0x03D8	/* Dword offset 0_F6 */
+#define BLUE_Y_INC		0x03DC	/* Dword offset 0_F7 */
+#define BLUE_START		0x03E0	/* Dword offset 0_F8 */
+#define Z_X_INC			0x03E4	/* Dword offset 0_F9 */
+#define Z_Y_INC			0x03E8	/* Dword offset 0_FA */
+#define Z_START			0x03EC	/* Dword offset 0_FB */
+#define ALPHA_X_INC		0x03F0	/* Dword offset 0_FC */
+#define FOG_X_INC		0x03F0	/* Dword offset 0_FC */
+#define ALPHA_Y_INC		0x03F4	/* Dword offset 0_FD */
+#define FOG_Y_INC		0x03F4	/* Dword offset 0_FD */
+#define ALPHA_START		0x03F8	/* Dword offset 0_FE */
+#define FOG_START		0x03F8	/* Dword offset 0_FE */
+
+#define OVERLAY_Y_X_START		0x0400	/* Dword offset 1_00 */
+#define OVERLAY_Y_X_END			0x0404	/* Dword offset 1_01 */
+#define OVERLAY_VIDEO_KEY_CLR		0x0408	/* Dword offset 1_02 */
+#define OVERLAY_VIDEO_KEY_MSK		0x040C	/* Dword offset 1_03 */
+#define OVERLAY_GRAPHICS_KEY_CLR	0x0410	/* Dword offset 1_04 */
+#define OVERLAY_GRAPHICS_KEY_MSK	0x0414	/* Dword offset 1_05 */
+#define OVERLAY_KEY_CNTL		0x0418	/* Dword offset 1_06 */
+
+#define OVERLAY_SCALE_INC	0x0420	/* Dword offset 1_08 */
+#define OVERLAY_SCALE_CNTL	0x0424	/* Dword offset 1_09 */
+#define SCALER_HEIGHT_WIDTH	0x0428	/* Dword offset 1_0A */
+#define SCALER_TEST		0x042C	/* Dword offset 1_0B */
+#define SCALER_BUF0_OFFSET	0x0434	/* Dword offset 1_0D */
+#define SCALER_BUF1_OFFSET	0x0438	/* Dword offset 1_0E */
+#define SCALE_BUF_PITCH		0x043C	/* Dword offset 1_0F */
+
+#define CAPTURE_START_END	0x0440	/* Dword offset 1_10 */
+#define CAPTURE_X_WIDTH		0x0444	/* Dword offset 1_11 */
+#define VIDEO_FORMAT		0x0448	/* Dword offset 1_12 */
+#define VBI_START_END		0x044C	/* Dword offset 1_13 */
+#define CAPTURE_CONFIG		0x0450	/* Dword offset 1_14 */
+#define TRIG_CNTL		0x0454	/* Dword offset 1_15 */
+
+#define OVERLAY_EXCLUSIVE_HORZ	0x0458	/* Dword offset 1_16 */
+#define OVERLAY_EXCLUSIVE_VERT	0x045C	/* Dword offset 1_17 */
+
+#define VAL_WIDTH		0x0460	/* Dword offset 1_18 */
+#define CAPTURE_DEBUG		0x0464	/* Dword offset 1_19 */
+#define VIDEO_SYNC_TEST		0x0468	/* Dword offset 1_1A */
+
+/* GenLocking */
+#define SNAPSHOT_VH_COUNTS	0x0470	/* Dword offset 1_1C */
+#define SNAPSHOT_F_COUNT	0x0474	/* Dword offset 1_1D */
+#define N_VIF_COUNT		0x0478	/* Dword offset 1_1E */
+#define SNAPSHOT_VIF_COUNT	0x047C	/* Dword offset 1_1F */
+
+#define CAPTURE_BUF0_OFFSET	0x0480	/* Dword offset 1_20 */
+#define CAPTURE_BUF1_OFFSET	0x0484	/* Dword offset 1_21 */
+#define CAPTURE_BUF_PITCH	0x0488	/* Dword offset 1_22 */
+
+/* GenLocking */
+#define SNAPSHOT2_VH_COUNTS	0x04B0	/* Dword offset 1_2C */
+#define SNAPSHOT2_F_COUNT	0x04B4	/* Dword offset 1_2D */
+#define N_VIF2_COUNT		0x04B8	/* Dword offset 1_2E */
+#define SNAPSHOT2_VIF_COUNT	0x04BC	/* Dword offset 1_2F */
+
+#define MPP_CONFIG		0x04C0	/* Dword offset 1_30 */
+#define MPP_STROBE_SEQ		0x04C4	/* Dword offset 1_31 */
+#define MPP_ADDR		0x04C8	/* Dword offset 1_32 */
+#define MPP_DATA		0x04CC	/* Dword offset 1_33 */
+#define TVO_CNTL		0x0500	/* Dword offset 1_40 */
+
+/* Test and Debug */
+#define CRT_HORZ_VERT_LOAD	0x0544	/* Dword offset 1_51 */
+
+/* AGP */
+#define AGP_BASE		0x0548	/* Dword offset 1_52 */
+#define AGP_CNTL		0x054C	/* Dword offset 1_53 */
+
+#define SCALER_COLOUR_CNTL	0x0550	/* Dword offset 1_54 */
+#define SCALER_H_COEFF0		0x0554	/* Dword offset 1_55 */
+#define SCALER_H_COEFF1		0x0558	/* Dword offset 1_56 */
+#define SCALER_H_COEFF2		0x055C	/* Dword offset 1_57 */
+#define SCALER_H_COEFF3		0x0560	/* Dword offset 1_58 */
+#define SCALER_H_COEFF4		0x0564	/* Dword offset 1_59 */
+
+/* Command FIFO */
+#define GUI_CMDFIFO_DEBUG	0x0570	/* Dword offset 1_5C */
+#define GUI_CMDFIFO_DATA	0x0574	/* Dword offset 1_5D */
+#define GUI_CNTL		0x0578	/* Dword offset 1_5E */
+
+/* Bus Mastering */
+#define BM_FRAME_BUF_OFFSET	0x0580	/* Dword offset 1_60 */
+#define BM_SYSTEM_MEM_ADDR	0x0584	/* Dword offset 1_61 */
+#define BM_COMMAND		0x0588	/* Dword offset 1_62 */
+#define BM_STATUS		0x058C	/* Dword offset 1_63 */
+#define BM_GUI_TABLE		0x05B8	/* Dword offset 1_6E */
+#define BM_SYSTEM_TABLE		0x05BC	/* Dword offset 1_6F */
+
+#define SCALER_BUF0_OFFSET_U	0x05D4	/* Dword offset 1_75 */
+#define SCALER_BUF0_OFFSET_V	0x05D8	/* Dword offset 1_76 */
+#define SCALER_BUF1_OFFSET_U	0x05DC	/* Dword offset 1_77 */
+#define SCALER_BUF1_OFFSET_V	0x05E0	/* Dword offset 1_78 */
+
+/* Setup Engine */
+#define VERTEX_1_S		0x0640	/* Dword offset 1_90 */
+#define VERTEX_1_T		0x0644	/* Dword offset 1_91 */
+#define VERTEX_1_W		0x0648	/* Dword offset 1_92 */
+#define VERTEX_1_SPEC_ARGB	0x064C	/* Dword offset 1_93 */
+#define VERTEX_1_Z		0x0650	/* Dword offset 1_94 */
+#define VERTEX_1_ARGB		0x0654	/* Dword offset 1_95 */
+#define VERTEX_1_X_Y		0x0658	/* Dword offset 1_96 */
+#define ONE_OVER_AREA		0x065C	/* Dword offset 1_97 */
+#define VERTEX_2_S		0x0660	/* Dword offset 1_98 */
+#define VERTEX_2_T		0x0664	/* Dword offset 1_99 */
+#define VERTEX_2_W		0x0668	/* Dword offset 1_9A */
+#define VERTEX_2_SPEC_ARGB	0x066C	/* Dword offset 1_9B */
+#define VERTEX_2_Z		0x0670	/* Dword offset 1_9C */
+#define VERTEX_2_ARGB		0x0674	/* Dword offset 1_9D */
+#define VERTEX_2_X_Y		0x0678	/* Dword offset 1_9E */
+#define ONE_OVER_AREA		0x065C	/* Dword offset 1_9F */
+#define VERTEX_3_S		0x0680	/* Dword offset 1_A0 */
+#define VERTEX_3_T		0x0684	/* Dword offset 1_A1 */
+#define VERTEX_3_W		0x0688	/* Dword offset 1_A2 */
+#define VERTEX_3_SPEC_ARGB	0x068C	/* Dword offset 1_A3 */
+#define VERTEX_3_Z		0x0690	/* Dword offset 1_A4 */
+#define VERTEX_3_ARGB		0x0694	/* Dword offset 1_A5 */
+#define VERTEX_3_X_Y		0x0698	/* Dword offset 1_A6 */
+#define ONE_OVER_AREA		0x065C	/* Dword offset 1_A7 */
+#define VERTEX_1_S		0x0640	/* Dword offset 1_AB */
+#define VERTEX_1_T		0x0644	/* Dword offset 1_AC */
+#define VERTEX_1_W		0x0648	/* Dword offset 1_AD */
+#define VERTEX_2_S		0x0660	/* Dword offset 1_AE */
+#define VERTEX_2_T		0x0664	/* Dword offset 1_AF */
+#define VERTEX_2_W		0x0668	/* Dword offset 1_B0 */
+#define VERTEX_3_SECONDARY_S	0x06C0	/* Dword offset 1_B0 */
+#define VERTEX_3_S		0x0680	/* Dword offset 1_B1 */
+#define VERTEX_3_SECONDARY_T	0x06C4	/* Dword offset 1_B1 */
+#define VERTEX_3_T		0x0684	/* Dword offset 1_B2 */
+#define VERTEX_3_SECONDARY_W	0x06C8	/* Dword offset 1_B2 */
+#define VERTEX_3_W		0x0688	/* Dword offset 1_B3 */
+#define VERTEX_1_SPEC_ARGB	0x064C	/* Dword offset 1_B4 */
+#define VERTEX_2_SPEC_ARGB	0x066C	/* Dword offset 1_B5 */
+#define VERTEX_3_SPEC_ARGB	0x068C	/* Dword offset 1_B6 */
+#define VERTEX_1_Z		0x0650	/* Dword offset 1_B7 */
+#define VERTEX_2_Z		0x0670	/* Dword offset 1_B8 */
+#define VERTEX_3_Z		0x0690	/* Dword offset 1_B9 */
+#define VERTEX_1_ARGB		0x0654	/* Dword offset 1_BA */
+#define VERTEX_2_ARGB		0x0674	/* Dword offset 1_BB */
+#define VERTEX_3_ARGB		0x0694	/* Dword offset 1_BC */
+#define VERTEX_1_X_Y		0x0658	/* Dword offset 1_BD */
+#define VERTEX_2_X_Y		0x0678	/* Dword offset 1_BE */
+#define VERTEX_3_X_Y		0x0698	/* Dword offset 1_BF */
+#define ONE_OVER_AREA_UC	0x0700	/* Dword offset 1_C0 */
+#define SETUP_CNTL		0x0704	/* Dword offset 1_C1 */
+#define VERTEX_1_SECONDARY_S	0x0728	/* Dword offset 1_CA */
+#define VERTEX_1_SECONDARY_T	0x072C	/* Dword offset 1_CB */
+#define VERTEX_1_SECONDARY_W	0x0730	/* Dword offset 1_CC */
+#define VERTEX_2_SECONDARY_S	0x0734	/* Dword offset 1_CD */
+#define VERTEX_2_SECONDARY_T	0x0738	/* Dword offset 1_CE */
+#define VERTEX_2_SECONDARY_W	0x073C	/* Dword offset 1_CF */
+
+
+#define GTC_3D_RESET_DELAY	3	/* 3D engine reset delay in ms */
+
+/* CRTC control values (mostly CRTC_GEN_CNTL) */
+
+#define CRTC_H_SYNC_NEG		0x00200000
+#define CRTC_V_SYNC_NEG		0x00200000
+
+#define CRTC_DBL_SCAN_EN	0x00000001
+#define CRTC_INTERLACE_EN	0x00000002
+#define CRTC_HSYNC_DIS		0x00000004
+#define CRTC_VSYNC_DIS		0x00000008
+#define CRTC_CSYNC_EN		0x00000010
+#define CRTC_PIX_BY_2_EN	0x00000020	/* unused on RAGE */
+#define CRTC_DISPLAY_DIS	0x00000040
+#define CRTC_VGA_XOVERSCAN	0x00000040
+
+#define CRTC_PIX_WIDTH_MASK	0x00000700
+#define CRTC_PIX_WIDTH_4BPP	0x00000100
+#define CRTC_PIX_WIDTH_8BPP	0x00000200
+#define CRTC_PIX_WIDTH_15BPP	0x00000300
+#define CRTC_PIX_WIDTH_16BPP	0x00000400
+#define CRTC_PIX_WIDTH_24BPP	0x00000500
+#define CRTC_PIX_WIDTH_32BPP	0x00000600
+
+#define CRTC_BYTE_PIX_ORDER	0x00000800
+#define CRTC_PIX_ORDER_MSN_LSN	0x00000000
+#define CRTC_PIX_ORDER_LSN_MSN	0x00000800
+
+#define CRTC_FIFO_LWM		0x000f0000
+
+#define VGA_128KAP_PAGING	0x00100000
+#define VFC_SYNC_TRISTATE	0x00200000
+#define CRTC_LOCK_REGS		0x00400000
+#define CRTC_SYNC_TRISTATE	0x00800000
+
+#define CRTC_EXT_DISP_EN	0x01000000
+#define CRTC_ENABLE		0x02000000
+#define CRTC_DISP_REQ_ENB	0x04000000
+#define VGA_ATI_LINEAR		0x08000000
+#define CRTC_VSYNC_FALL_EDGE	0x10000000
+#define VGA_TEXT_132		0x20000000
+#define VGA_XCRT_CNT_EN		0x40000000
+#define VGA_CUR_B_TEST		0x80000000
+
+#define CRTC_CRNT_VLINE		0x07f00000
+#define CRTC_VBLANK		0x00000001
+
+
+/* DAC control values */
+
+#define DAC_EXT_SEL_RS2		0x01
+#define DAC_EXT_SEL_RS3		0x02
+#define DAC_8BIT_EN		0x00000100
+#define DAC_PIX_DLY_MASK	0x00000600
+#define DAC_PIX_DLY_0NS		0x00000000
+#define DAC_PIX_DLY_2NS		0x00000200
+#define DAC_PIX_DLY_4NS		0x00000400
+#define DAC_BLANK_ADJ_MASK	0x00001800
+#define DAC_BLANK_ADJ_0		0x00000000
+#define DAC_BLANK_ADJ_1		0x00000800
+#define DAC_BLANK_ADJ_2		0x00001000
+
+
+/* Mix control values */
+
+#define MIX_NOT_DST		0x0000
+#define MIX_0			0x0001
+#define MIX_1			0x0002
+#define MIX_DST			0x0003
+#define MIX_NOT_SRC		0x0004
+#define MIX_XOR			0x0005
+#define MIX_XNOR		0x0006
+#define MIX_SRC			0x0007
+#define MIX_NAND		0x0008
+#define MIX_NOT_SRC_OR_DST	0x0009
+#define MIX_SRC_OR_NOT_DST	0x000a
+#define MIX_OR			0x000b
+#define MIX_AND			0x000c
+#define MIX_SRC_AND_NOT_DST	0x000d
+#define MIX_NOT_SRC_AND_DST	0x000e
+#define MIX_NOR			0x000f
+
+/* Maximum engine dimensions */
+#define ENGINE_MIN_X		0
+#define ENGINE_MIN_Y		0
+#define ENGINE_MAX_X		4095
+#define ENGINE_MAX_Y		16383
+
+/* Mach64 engine bit constants - these are typically ORed together */
+
+/* BUS_CNTL register constants */
+#define BUS_FIFO_ERR_ACK	0x00200000
+#define BUS_HOST_ERR_ACK	0x00800000
+
+/* GEN_TEST_CNTL register constants */
+#define GEN_OVR_OUTPUT_EN	0x20
+#define HWCURSOR_ENABLE		0x80
+#define GUI_ENGINE_ENABLE	0x100
+#define BLOCK_WRITE_ENABLE	0x200
+
+/* DSP_CONFIG register constants */
+#define DSP_XCLKS_PER_QW	0x00003fff
+#define DSP_LOOP_LATENCY	0x000f0000
+#define DSP_PRECISION		0x00700000
+
+/* DSP_ON_OFF register constants */
+#define DSP_OFF			0x000007ff
+#define DSP_ON			0x07ff0000
+
+/* CLOCK_CNTL register constants */
+#define CLOCK_SEL		0x0f
+#define CLOCK_DIV		0x30
+#define CLOCK_DIV1		0x00
+#define CLOCK_DIV2		0x10
+#define CLOCK_DIV4		0x20
+#define CLOCK_STROBE		0x40
+#define PLL_WR_EN		0x02
+
+/* PLL register indices */
+#define MPLL_CNTL		0x00
+#define VPLL_CNTL		0x01
+#define PLL_REF_DIV		0x02
+#define PLL_GEN_CNTL		0x03
+#define MCLK_FB_DIV		0x04
+#define PLL_VCLK_CNTL		0x05
+#define VCLK_POST_DIV		0x06
+#define VCLK0_FB_DIV		0x07
+#define VCLK1_FB_DIV		0x08
+#define VCLK2_FB_DIV		0x09
+#define VCLK3_FB_DIV		0x0A
+#define PLL_EXT_CNTL		0x0B
+#define DLL_CNTL		0x0C
+#define DLL1_CNTL		0x0C
+#define VFC_CNTL		0x0D
+#define PLL_TEST_CNTL		0x0E
+#define PLL_TEST_COUNT		0x0F
+#define LVDS_CNTL0		0x10
+#define LVDS_CNTL1		0x11
+#define AGP1_CNTL		0x12
+#define AGP2_CNTL		0x13
+#define DLL2_CNTL		0x14
+#define SCLK_FB_DIV		0x15
+#define SPLL_CNTL1		0x16
+#define SPLL_CNTL2		0x17
+#define APLL_STRAPS		0x18
+#define EXT_VPLL_CNTL		0x19
+#define EXT_VPLL_REF_DIV	0x1A
+#define EXT_VPLL_FB_DIV		0x1B
+#define EXT_VPLL_MSB		0x1C
+#define HTOTAL_CNTL		0x1D
+#define BYTE_CLK_CNTL		0x1E
+#define TV_PLL_CNTL1		0x1F
+#define TV_PLL_CNTL2		0x20
+#define TV_PLL_CNTL		0x21
+#define EXT_TV_PLL		0x22
+#define V2PLL_CNTL		0x23
+#define PLL_V2CLK_CNTL		0x24
+#define EXT_V2PLL_REF_DIV	0x25
+#define EXT_V2PLL_FB_DIV	0x26
+#define EXT_V2PLL_MSB		0x27
+#define HTOTAL2_CNTL		0x28
+#define PLL_YCLK_CNTL		0x29
+#define PM_DYN_CLK_CNTL		0x2A
+
+/* Fields in PLL registers */
+#define PLL_PC_GAIN		0x07
+#define PLL_VC_GAIN		0x18
+#define PLL_DUTY_CYC		0xE0
+#define PLL_OVERRIDE		0x01
+#define PLL_MCLK_RST		0x02
+#define OSC_EN			0x04
+#define EXT_CLK_EN		0x08
+#define MCLK_SRC_SEL		0x70
+#define EXT_CLK_CNTL		0x80
+#define VCLK_SRC_SEL		0x03
+#define PLL_VCLK_RST		0x04
+#define VCLK_INVERT		0x08
+#define VCLK0_POST		0x03
+#define VCLK1_POST		0x0C
+#define VCLK2_POST		0x30
+#define VCLK3_POST		0xC0
+
+/* CONFIG_CNTL register constants */
+#define APERTURE_4M_ENABLE	1
+#define APERTURE_8M_ENABLE	2
+#define VGA_APERTURE_ENABLE	4
+
+/* CONFIG_STAT0 register constants (GX, CX) */
+#define CFG_BUS_TYPE		0x00000007
+#define CFG_MEM_TYPE		0x00000038
+#define CFG_INIT_DAC_TYPE	0x00000e00
+
+/* CONFIG_STAT0 register constants (CT, ET, VT) */
+#define CFG_MEM_TYPE_xT		0x00000007
+
+#define ISA			0
+#define EISA			1
+#define LOCAL_BUS		6
+#define PCI			7
+
+/* Memory types for GX, CX */
+#define DRAMx4			0
+#define VRAMx16			1
+#define VRAMx16ssr		2
+#define DRAMx16			3
+#define GraphicsDRAMx16		4
+#define EnhancedVRAMx16		5
+#define EnhancedVRAMx16ssr	6
+
+/* Memory types for CT, ET, VT, GT */
+#define DRAM			1
+#define EDO			2
+#define PSEUDO_EDO		3
+#define SDRAM			4
+#define SGRAM			5
+#define WRAM			6
+
+#define DAC_INTERNAL		0x00
+#define DAC_IBMRGB514		0x01
+#define DAC_ATI68875		0x02
+#define DAC_TVP3026_A		0x72
+#define DAC_BT476		0x03
+#define DAC_BT481		0x04
+#define DAC_ATT20C491		0x14
+#define DAC_SC15026		0x24
+#define DAC_MU9C1880		0x34
+#define DAC_IMSG174		0x44
+#define DAC_ATI68860_B		0x05
+#define DAC_ATI68860_C		0x15
+#define DAC_TVP3026_B		0x75
+#define DAC_STG1700		0x06
+#define DAC_ATT498		0x16
+#define DAC_STG1702		0x07
+#define DAC_SC15021		0x17
+#define DAC_ATT21C498		0x27
+#define DAC_STG1703		0x37
+#define DAC_CH8398		0x47
+#define DAC_ATT20C408		0x57
+
+#define CLK_ATI18818_0		0
+#define CLK_ATI18818_1		1
+#define CLK_STG1703		2
+#define CLK_CH8398		3
+#define CLK_INTERNAL		4
+#define CLK_ATT20C408		5
+#define CLK_IBMRGB514		6
+
+/* MEM_CNTL register constants */
+#define MEM_SIZE_ALIAS		0x00000007
+#define MEM_SIZE_512K		0x00000000
+#define MEM_SIZE_1M		0x00000001
+#define MEM_SIZE_2M		0x00000002
+#define MEM_SIZE_4M		0x00000003
+#define MEM_SIZE_6M		0x00000004
+#define MEM_SIZE_8M		0x00000005
+#define MEM_SIZE_ALIAS_GTB	0x0000000F
+#define MEM_SIZE_2M_GTB		0x00000003
+#define MEM_SIZE_4M_GTB		0x00000007
+#define MEM_SIZE_6M_GTB		0x00000009
+#define MEM_SIZE_8M_GTB		0x0000000B
+#define MEM_BNDRY		0x00030000
+#define MEM_BNDRY_0K		0x00000000
+#define MEM_BNDRY_256K		0x00010000
+#define MEM_BNDRY_512K		0x00020000
+#define MEM_BNDRY_1M		0x00030000
+#define MEM_BNDRY_EN		0x00040000
+
+/* ATI PCI constants */
+#define PCI_ATI_VENDOR_ID	0x1002
+
+
+/* CONFIG_CHIP_ID register constants */
+#define CFG_CHIP_TYPE		0x0000FFFF
+#define CFG_CHIP_CLASS		0x00FF0000
+#define CFG_CHIP_REV		0xFF000000
+#define CFG_CHIP_MAJOR		0x07000000
+#define CFG_CHIP_FND_ID		0x38000000
+#define CFG_CHIP_MINOR		0xC0000000
+
+
+/* Chip IDs read from CONFIG_CHIP_ID */
+
+/* mach64GX family */
+#define GX_CHIP_ID	0xD7	/* mach64GX (ATI888GX00) */
+#define CX_CHIP_ID	0x57	/* mach64CX (ATI888CX00) */
+
+#define GX_PCI_ID	0x4758	/* mach64GX (ATI888GX00) */
+#define CX_PCI_ID	0x4358	/* mach64CX (ATI888CX00) */
+
+/* mach64CT family */
+#define CT_CHIP_ID	0x4354	/* mach64CT (ATI264CT) */
+#define ET_CHIP_ID	0x4554	/* mach64ET (ATI264ET) */
+
+/* mach64CT family / mach64VT class */
+#define VT_CHIP_ID	0x5654	/* mach64VT (ATI264VT) */
+#define VU_CHIP_ID	0x5655	/* mach64VTB (ATI264VTB) */
+#define VV_CHIP_ID	0x5656	/* mach64VT4 (ATI264VT4) */
+
+/* mach64CT family / mach64GT (3D RAGE) class */
+#define LB_CHIP_ID	0x4c42	/* RAGE LT PRO, AGP */
+#define LD_CHIP_ID	0x4c44	/* RAGE LT PRO */
+#define LG_CHIP_ID	0x4c47	/* RAGE LT */
+#define LI_CHIP_ID	0x4c49	/* RAGE LT PRO */
+#define LP_CHIP_ID	0x4c50	/* RAGE LT PRO */
+#define LT_CHIP_ID	0x4c54	/* RAGE LT */
+#define XL_CHIP_ID	0x4752	/* RAGE (XL) */
+#define GT_CHIP_ID	0x4754	/* RAGE (GT) */
+#define GU_CHIP_ID	0x4755	/* RAGE II/II+ (GTB) */
+#define GV_CHIP_ID	0x4756	/* RAGE IIC, PCI */
+#define GW_CHIP_ID	0x4757	/* RAGE IIC, AGP */
+#define GZ_CHIP_ID	0x475a	/* RAGE IIC, AGP */
+#define GB_CHIP_ID	0x4742	/* RAGE PRO, BGA, AGP 1x and 2x */
+#define GD_CHIP_ID	0x4744	/* RAGE PRO, BGA, AGP 1x only */
+#define GI_CHIP_ID	0x4749	/* RAGE PRO, BGA, PCI33 only */
+#define GP_CHIP_ID	0x4750	/* RAGE PRO, PQFP, PCI33, full 3D */
+#define GQ_CHIP_ID	0x4751	/* RAGE PRO, PQFP, PCI33, limited 3D */
+#define LM_CHIP_ID	0x4c4d	/* RAGE Mobility PCI */
+#define LN_CHIP_ID	0x4c4e	/* RAGE Mobility AGP */
+
+
+/* Mach64 major ASIC revisions */
+#define MACH64_ASIC_NEC_VT_A3		0x08
+#define MACH64_ASIC_NEC_VT_A4		0x48
+#define MACH64_ASIC_SGS_VT_A4		0x40
+#define MACH64_ASIC_SGS_VT_B1S1		0x01
+#define MACH64_ASIC_SGS_GT_B1S1		0x01
+#define MACH64_ASIC_SGS_GT_B1S2		0x41
+#define MACH64_ASIC_UMC_GT_B2U1		0x1a
+#define MACH64_ASIC_UMC_GT_B2U2		0x5a
+#define MACH64_ASIC_UMC_VT_B2U3		0x9a
+#define MACH64_ASIC_UMC_GT_B2U3		0x9a
+#define MACH64_ASIC_UMC_R3B_D_P_A1	0x1b
+#define MACH64_ASIC_UMC_R3B_D_P_A2	0x5b
+#define MACH64_ASIC_UMC_R3B_D_P_A3	0x1c
+#define MACH64_ASIC_UMC_R3B_D_P_A4	0x5c
+
+/* Mach64 foundries */
+#define MACH64_FND_SGS		0
+#define MACH64_FND_NEC		1
+#define MACH64_FND_UMC		3
+
+/* Mach64 chip types */
+#define MACH64_UNKNOWN		0
+#define MACH64_GX		1
+#define MACH64_CX		2
+#define MACH64_CT		3
+#define MACH64_ET		4
+#define MACH64_VT		5
+#define MACH64_GT		6
+
+/* DST_CNTL register constants */
+#define DST_X_RIGHT_TO_LEFT	0
+#define DST_X_LEFT_TO_RIGHT	1
+#define DST_Y_BOTTOM_TO_TOP	0
+#define DST_Y_TOP_TO_BOTTOM	2
+#define DST_X_MAJOR		0
+#define DST_Y_MAJOR		4
+#define DST_X_TILE		8
+#define DST_Y_TILE		0x10
+#define DST_LAST_PEL		0x20
+#define DST_POLYGON_ENABLE	0x40
+#define DST_24_ROTATION_ENABLE	0x80
+
+/* SRC_CNTL register constants */
+#define SRC_PATTERN_ENABLE		1
+#define SRC_ROTATION_ENABLE		2
+#define SRC_LINEAR_ENABLE		4
+#define SRC_BYTE_ALIGN			8
+#define SRC_LINE_X_RIGHT_TO_LEFT	0
+#define SRC_LINE_X_LEFT_TO_RIGHT	0x10
+
+/* HOST_CNTL register constants */
+#define HOST_BYTE_ALIGN		1
+
+/* GUI_TRAJ_CNTL register constants */
+#define PAT_MONO_8x8_ENABLE	0x01000000
+#define PAT_CLR_4x2_ENABLE	0x02000000
+#define PAT_CLR_8x1_ENABLE	0x04000000
+
+/* DP_CHAIN_MASK register constants */
+#define DP_CHAIN_4BPP		0x8888
+#define DP_CHAIN_7BPP		0xD2D2
+#define DP_CHAIN_8BPP		0x8080
+#define DP_CHAIN_8BPP_RGB	0x9292
+#define DP_CHAIN_15BPP		0x4210
+#define DP_CHAIN_16BPP		0x8410
+#define DP_CHAIN_24BPP		0x8080
+#define DP_CHAIN_32BPP		0x8080
+
+/* DP_PIX_WIDTH register constants */
+#define DST_1BPP		0
+#define DST_4BPP		1
+#define DST_8BPP		2
+#define DST_15BPP		3
+#define DST_16BPP		4
+#define DST_32BPP		6
+#define SRC_1BPP		0
+#define SRC_4BPP		0x100
+#define SRC_8BPP		0x200
+#define SRC_15BPP		0x300
+#define SRC_16BPP		0x400
+#define SRC_32BPP		0x600
+#define HOST_1BPP		0
+#define HOST_4BPP		0x10000
+#define HOST_8BPP		0x20000
+#define HOST_15BPP		0x30000
+#define HOST_16BPP		0x40000
+#define HOST_32BPP		0x60000
+#define BYTE_ORDER_MSB_TO_LSB	0
+#define BYTE_ORDER_LSB_TO_MSB	0x1000000
+
+/* DP_MIX register constants */
+#define BKGD_MIX_NOT_D			0
+#define BKGD_MIX_ZERO			1
+#define BKGD_MIX_ONE			2
+#define BKGD_MIX_D			3
+#define BKGD_MIX_NOT_S			4
+#define BKGD_MIX_D_XOR_S		5
+#define BKGD_MIX_NOT_D_XOR_S		6
+#define BKGD_MIX_S			7
+#define BKGD_MIX_NOT_D_OR_NOT_S		8
+#define BKGD_MIX_D_OR_NOT_S		9
+#define BKGD_MIX_NOT_D_OR_S		10
+#define BKGD_MIX_D_OR_S			11
+#define BKGD_MIX_D_AND_S		12
+#define BKGD_MIX_NOT_D_AND_S		13
+#define BKGD_MIX_D_AND_NOT_S		14
+#define BKGD_MIX_NOT_D_AND_NOT_S	15
+#define BKGD_MIX_D_PLUS_S_DIV2		0x17
+#define FRGD_MIX_NOT_D			0
+#define FRGD_MIX_ZERO			0x10000
+#define FRGD_MIX_ONE			0x20000
+#define FRGD_MIX_D			0x30000
+#define FRGD_MIX_NOT_S			0x40000
+#define FRGD_MIX_D_XOR_S		0x50000
+#define FRGD_MIX_NOT_D_XOR_S		0x60000
+#define FRGD_MIX_S			0x70000
+#define FRGD_MIX_NOT_D_OR_NOT_S		0x80000
+#define FRGD_MIX_D_OR_NOT_S		0x90000
+#define FRGD_MIX_NOT_D_OR_S		0xa0000
+#define FRGD_MIX_D_OR_S			0xb0000
+#define FRGD_MIX_D_AND_S		0xc0000
+#define FRGD_MIX_NOT_D_AND_S		0xd0000
+#define FRGD_MIX_D_AND_NOT_S		0xe0000
+#define FRGD_MIX_NOT_D_AND_NOT_S	0xf0000
+#define FRGD_MIX_D_PLUS_S_DIV2		0x170000
+
+/* DP_SRC register constants */
+#define BKGD_SRC_BKGD_CLR	0
+#define BKGD_SRC_FRGD_CLR	1
+#define BKGD_SRC_HOST		2
+#define BKGD_SRC_BLIT		3
+#define BKGD_SRC_PATTERN	4
+#define FRGD_SRC_BKGD_CLR	0
+#define FRGD_SRC_FRGD_CLR	0x100
+#define FRGD_SRC_HOST		0x200
+#define FRGD_SRC_BLIT		0x300
+#define FRGD_SRC_PATTERN	0x400
+#define MONO_SRC_ONE		0
+#define MONO_SRC_PATTERN	0x10000
+#define MONO_SRC_HOST		0x20000
+#define MONO_SRC_BLIT		0x30000
+
+/* CLR_CMP_CNTL register constants */
+#define COMPARE_FALSE		0
+#define COMPARE_TRUE		1
+#define COMPARE_NOT_EQUAL	4
+#define COMPARE_EQUAL		5
+#define COMPARE_DESTINATION	0
+#define COMPARE_SOURCE		0x1000000
+
+/* FIFO_STAT register constants */
+#define FIFO_ERR		0x80000000
+
+/* CONTEXT_LOAD_CNTL constants */
+#define CONTEXT_NO_LOAD			0
+#define CONTEXT_LOAD			0x10000
+#define CONTEXT_LOAD_AND_DO_FILL	0x20000
+#define CONTEXT_LOAD_AND_DO_LINE	0x30000
+#define CONTEXT_EXECUTE			0
+#define CONTEXT_CMD_DISABLE		0x80000000
+
+/* GUI_STAT register constants */
+#define ENGINE_IDLE		0
+#define ENGINE_BUSY		1
+#define SCISSOR_LEFT_FLAG	0x10
+#define SCISSOR_RIGHT_FLAG	0x20
+#define SCISSOR_TOP_FLAG	0x40
+#define SCISSOR_BOTTOM_FLAG	0x80
+
+/* ATI VGA Extended Regsiters */
+#define sioATIEXT		0x1ce
+#define bioATIEXT		0x3ce
+
+#define ATI2E			0xae
+#define ATI32			0xb2
+#define ATI36			0xb6
+
+/* VGA Graphics Controller Registers */
+#define VGAGRA			0x3ce
+#define GRA06			0x06
+
+/* VGA Seququencer Registers */
+#define VGASEQ			0x3c4
+#define SEQ02			0x02
+#define SEQ04			0x04
+
+#define MACH64_MAX_X		ENGINE_MAX_X
+#define MACH64_MAX_Y		ENGINE_MAX_Y
+
+#define INC_X			0x0020
+#define INC_Y			0x0080
+
+#define RGB16_555		0x0000
+#define RGB16_565		0x0040
+#define RGB16_655		0x0080
+#define RGB16_664		0x00c0
+
+#define POLY_TEXT_TYPE		0x0001
+#define IMAGE_TEXT_TYPE		0x0002
+#define TEXT_TYPE_8_BIT		0x0004
+#define TEXT_TYPE_16_BIT	0x0008
+#define POLY_TEXT_TYPE_8	(POLY_TEXT_TYPE | TEXT_TYPE_8_BIT)
+#define IMAGE_TEXT_TYPE_8	(IMAGE_TEXT_TYPE | TEXT_TYPE_8_BIT)
+#define POLY_TEXT_TYPE_16	(POLY_TEXT_TYPE | TEXT_TYPE_16_BIT)
+#define IMAGE_TEXT_TYPE_16	(IMAGE_TEXT_TYPE | TEXT_TYPE_16_BIT)
+
+#define MACH64_NUM_CLOCKS	16
+#define MACH64_NUM_FREQS	50
+
+/* Power Management register constants (LT & LT Pro) */
+#define PWR_MGT_ON		0x00000001
+#define PWR_MGT_MODE_MASK	0x00000006
+#define AUTO_PWR_UP		0x00000008
+#define USE_F32KHZ		0x00000400
+#define TRISTATE_MEM_EN		0x00000800
+#define SELF_REFRESH		0x00000080
+#define PWR_BLON		0x02000000
+#define STANDBY_NOW		0x10000000
+#define SUSPEND_NOW		0x20000000
+#define PWR_MGT_STATUS_MASK	0xC0000000
+#define PWR_MGT_STATUS_SUSPEND	0x80000000
+
+/* PM Mode constants  */
+#define PWR_MGT_MODE_PIN	0x00000000
+#define PWR_MGT_MODE_REG	0x00000002
+#define PWR_MGT_MODE_TIMER	0x00000004
+#define PWR_MGT_MODE_PCI	0x00000006
+
+/* LCD registers (LT Pro) */
+
+/* LCD Index register */
+#define LCD_INDEX_MASK		0x0000003F
+#define LCD_DISPLAY_DIS		0x00000100
+#define LCD_SRC_SEL		0x00000200
+#define CRTC2_DISPLAY_DIS	0x00000400
+
+/* LCD register indices */
+#define CONFIG_PANEL		0x00
+#define LCD_GEN_CTRL		0x01
+#define DSTN_CONTROL		0x02
+#define HFB_PITCH_ADDR		0x03
+#define HORZ_STRETCHING		0x04
+#define VERT_STRETCHING		0x05
+#define EXT_VERT_STRETCH	0x06
+#define LT_GIO			0x07
+#define POWER_MANAGEMENT	0x08
+#define ZVGPIO			0x09
+#define ICON_CLR0		0x0A
+#define ICON_CLR1		0x0B
+#define ICON_OFFSET		0x0C
+#define ICON_HORZ_VERT_POSN	0x0D
+#define ICON_HORZ_VERT_OFF	0x0E
+#define ICON2_CLR0		0x0F
+#define ICON2_CLR1		0x10
+#define ICON2_OFFSET		0x11
+#define ICON2_HORZ_VERT_POSN	0x12
+#define ICON2_HORZ_VERT_OFF	0x13
+#define LCD_MISC_CNTL		0x14
+#define APC_CNTL		0x1C
+#define POWER_MANAGEMENT_2	0x1D
+#define ALPHA_BLENDING		0x25
+#define PORTRAIT_GEN_CNTL	0x26
+#define APC_CTRL_IO		0x27
+#define TEST_IO			0x28
+#define TEST_OUTPUTS		0x29
+#define DP1_MEM_ACCESS		0x2A
+#define DP0_MEM_ACCESS		0x2B
+#define DP0_DEBUG_A		0x2C
+#define DP0_DEBUG_B		0x2D
+#define DP1_DEBUG_A		0x2E
+#define DP1_DEBUG_B		0x2F
+#define DPCTRL_DEBUG_A		0x30
+#define DPCTRL_DEBUG_B		0x31
+#define MEMBLK_DEBUG		0x32
+#define APC_LUT_AB		0x33
+#define APC_LUT_CD		0x34
+#define APC_LUT_EF		0x35
+#define APC_LUT_GH		0x36
+#define APC_LUT_IJ		0x37
+#define APC_LUT_KL		0x38
+#define APC_LUT_MN		0x39
+#define APC_LUT_OP		0x3A
+
+
+/* Values in LCD_MISC_CNTL */
+#define BIAS_MOD_LEVEL_MASK	0x0000ff00
+#define BIAS_MOD_LEVEL_SHIFT	8
+#define BLMOD_EN		0x00010000
+#define BIASMOD_EN		0x00020000
+
+#endif /* REGMACH64_H */
diff -u --recursive --new-file v2.4.7/linux/drivers/video/aty/mach64_accel.c linux/drivers/video/aty/mach64_accel.c
--- v2.4.7/linux/drivers/video/aty/mach64_accel.c	Wed Dec 31 16:00:00 1969
+++ linux/drivers/video/aty/mach64_accel.c	Tue Jul 31 14:43:29 2001
@@ -0,0 +1,352 @@
+
+/*
+ *  ATI Mach64 Hardware Acceleration
+ */
+
+#include <linux/delay.h>
+#include <linux/fb.h>
+
+#include <video/fbcon.h>
+#include <video/fbcon-cfb8.h>
+#include <video/fbcon-cfb16.h>
+#include <video/fbcon-cfb24.h>
+#include <video/fbcon-cfb32.h>
+
+#include "mach64.h"
+#include "atyfb.h"
+
+    /*
+     *  Text console acceleration
+     */
+
+static void fbcon_aty_bmove(struct display *p, int sy, int sx, int dy, int dx,
+			    int height, int width);
+static void fbcon_aty_clear(struct vc_data *conp, struct display *p, int sy,
+			    int sx, int height, int width);
+
+
+    /*
+     *  Generic Mach64 routines
+     */
+
+void aty_reset_engine(const struct fb_info_aty *info)
+{
+    /* reset engine */
+    aty_st_le32(GEN_TEST_CNTL,
+		aty_ld_le32(GEN_TEST_CNTL, info) & ~GUI_ENGINE_ENABLE, info);
+    /* enable engine */
+    aty_st_le32(GEN_TEST_CNTL,
+		aty_ld_le32(GEN_TEST_CNTL, info) | GUI_ENGINE_ENABLE, info);
+    /* ensure engine is not locked up by clearing any FIFO or */
+    /* HOST errors */
+    aty_st_le32(BUS_CNTL, aty_ld_le32(BUS_CNTL, info) | BUS_HOST_ERR_ACK |
+			  BUS_FIFO_ERR_ACK, info);
+}
+
+static void reset_GTC_3D_engine(const struct fb_info_aty *info)
+{
+	aty_st_le32(SCALE_3D_CNTL, 0xc0, info);
+	mdelay(GTC_3D_RESET_DELAY);
+	aty_st_le32(SETUP_CNTL, 0x00, info);
+	mdelay(GTC_3D_RESET_DELAY);
+	aty_st_le32(SCALE_3D_CNTL, 0x00, info);
+	mdelay(GTC_3D_RESET_DELAY);
+}
+
+void aty_init_engine(const struct atyfb_par *par, struct fb_info_aty *info)
+{
+    u32 pitch_value;
+
+    /* determine modal information from global mode structure */
+    pitch_value = par->crtc.vxres;
+
+    if (par->crtc.bpp == 24) {
+	/* In 24 bpp, the engine is in 8 bpp - this requires that all */
+	/* horizontal coordinates and widths must be adjusted */
+	pitch_value = pitch_value * 3;
+    }
+
+    /* On GTC (RagePro), we need to reset the 3D engine before */
+    if (M64_HAS(RESET_3D))
+    	reset_GTC_3D_engine(info);
+
+    /* Reset engine, enable, and clear any engine errors */
+    aty_reset_engine(info);
+    /* Ensure that vga page pointers are set to zero - the upper */
+    /* page pointers are set to 1 to handle overflows in the */
+    /* lower page */
+    aty_st_le32(MEM_VGA_WP_SEL, 0x00010000, info);
+    aty_st_le32(MEM_VGA_RP_SEL, 0x00010000, info);
+
+    /* ---- Setup standard engine context ---- */
+
+    /* All GUI registers here are FIFOed - therefore, wait for */
+    /* the appropriate number of empty FIFO entries */
+    wait_for_fifo(14, info);
+
+    /* enable all registers to be loaded for context loads */
+    aty_st_le32(CONTEXT_MASK, 0xFFFFFFFF, info);
+
+    /* set destination pitch to modal pitch, set offset to zero */
+    aty_st_le32(DST_OFF_PITCH, (pitch_value / 8) << 22, info);
+
+    /* zero these registers (set them to a known state) */
+    aty_st_le32(DST_Y_X, 0, info);
+    aty_st_le32(DST_HEIGHT, 0, info);
+    aty_st_le32(DST_BRES_ERR, 0, info);
+    aty_st_le32(DST_BRES_INC, 0, info);
+    aty_st_le32(DST_BRES_DEC, 0, info);
+
+    /* set destination drawing attributes */
+    aty_st_le32(DST_CNTL, DST_LAST_PEL | DST_Y_TOP_TO_BOTTOM |
+			  DST_X_LEFT_TO_RIGHT, info);
+
+    /* set source pitch to modal pitch, set offset to zero */
+    aty_st_le32(SRC_OFF_PITCH, (pitch_value / 8) << 22, info);
+
+    /* set these registers to a known state */
+    aty_st_le32(SRC_Y_X, 0, info);
+    aty_st_le32(SRC_HEIGHT1_WIDTH1, 1, info);
+    aty_st_le32(SRC_Y_X_START, 0, info);
+    aty_st_le32(SRC_HEIGHT2_WIDTH2, 1, info);
+
+    /* set source pixel retrieving attributes */
+    aty_st_le32(SRC_CNTL, SRC_LINE_X_LEFT_TO_RIGHT, info);
+
+    /* set host attributes */
+    wait_for_fifo(13, info);
+    aty_st_le32(HOST_CNTL, 0, info);
+
+    /* set pattern attributes */
+    aty_st_le32(PAT_REG0, 0, info);
+    aty_st_le32(PAT_REG1, 0, info);
+    aty_st_le32(PAT_CNTL, 0, info);
+
+    /* set scissors to modal size */
+    aty_st_le32(SC_LEFT, 0, info);
+    aty_st_le32(SC_TOP, 0, info);
+    aty_st_le32(SC_BOTTOM, par->crtc.vyres-1, info);
+    aty_st_le32(SC_RIGHT, pitch_value-1, info);
+
+    /* set background color to minimum value (usually BLACK) */
+    aty_st_le32(DP_BKGD_CLR, 0, info);
+
+    /* set foreground color to maximum value (usually WHITE) */
+    aty_st_le32(DP_FRGD_CLR, 0xFFFFFFFF, info);
+
+    /* set write mask to effect all pixel bits */
+    aty_st_le32(DP_WRITE_MASK, 0xFFFFFFFF, info);
+
+    /* set foreground mix to overpaint and background mix to */
+    /* no-effect */
+    aty_st_le32(DP_MIX, FRGD_MIX_S | BKGD_MIX_D, info);
+
+    /* set primary source pixel channel to foreground color */
+    /* register */
+    aty_st_le32(DP_SRC, FRGD_SRC_FRGD_CLR, info);
+
+    /* set compare functionality to false (no-effect on */
+    /* destination) */
+    wait_for_fifo(3, info);
+    aty_st_le32(CLR_CMP_CLR, 0, info);
+    aty_st_le32(CLR_CMP_MASK, 0xFFFFFFFF, info);
+    aty_st_le32(CLR_CMP_CNTL, 0, info);
+
+    /* set pixel depth */
+    wait_for_fifo(2, info);
+    aty_st_le32(DP_PIX_WIDTH, par->crtc.dp_pix_width, info);
+    aty_st_le32(DP_CHAIN_MASK, par->crtc.dp_chain_mask, info);
+
+    wait_for_fifo(5, info);
+    aty_st_le32(SCALE_3D_CNTL, 0, info);
+    aty_st_le32(Z_CNTL, 0, info);
+    aty_st_le32(CRTC_INT_CNTL, aty_ld_le32(CRTC_INT_CNTL, info) & ~0x20, info);
+    aty_st_le32(GUI_TRAJ_CNTL, 0x100023, info);
+
+    /* insure engine is idle before leaving */
+    wait_for_idle(info);
+}
+
+
+    /*
+     *  Accelerated functions
+     */
+
+static inline void draw_rect(s16 x, s16 y, u16 width, u16 height,
+			     struct fb_info_aty *info)
+{
+    /* perform rectangle fill */
+    wait_for_fifo(2, info);
+    aty_st_le32(DST_Y_X, (x << 16) | y, info);
+    aty_st_le32(DST_HEIGHT_WIDTH, (width << 16) | height, info);
+    info->blitter_may_be_busy = 1;
+}
+
+static inline void aty_rectcopy(int srcx, int srcy, int dstx, int dsty,
+				u_int width, u_int height,
+				struct fb_info_aty *info)
+{
+    u32 direction = DST_LAST_PEL;
+    u32 pitch_value;
+
+    if (!width || !height)
+	return;
+
+    pitch_value = info->current_par.crtc.vxres;
+    if (info->current_par.crtc.bpp == 24) {
+	/* In 24 bpp, the engine is in 8 bpp - this requires that all */
+	/* horizontal coordinates and widths must be adjusted */
+	pitch_value *= 3;
+	srcx *= 3;
+	dstx *= 3;
+	width *= 3;
+    }
+
+    if (srcy < dsty) {
+	dsty += height - 1;
+	srcy += height - 1;
+    } else
+	direction |= DST_Y_TOP_TO_BOTTOM;
+
+    if (srcx < dstx) {
+	dstx += width - 1;
+	srcx += width - 1;
+    } else
+	direction |= DST_X_LEFT_TO_RIGHT;
+
+    wait_for_fifo(4, info);
+    aty_st_le32(DP_SRC, FRGD_SRC_BLIT, info);
+    aty_st_le32(SRC_Y_X, (srcx << 16) | srcy, info);
+    aty_st_le32(SRC_HEIGHT1_WIDTH1, (width << 16) | height, info);
+    aty_st_le32(DST_CNTL, direction, info);
+    draw_rect(dstx, dsty, width, height, info);
+}
+
+void aty_rectfill(int dstx, int dsty, u_int width, u_int height, u_int color,
+		  struct fb_info_aty *info)
+{
+    if (!width || !height)
+	return;
+
+    if (info->current_par.crtc.bpp == 24) {
+	/* In 24 bpp, the engine is in 8 bpp - this requires that all */
+	/* horizontal coordinates and widths must be adjusted */
+	dstx *= 3;
+	width *= 3;
+    }
+
+    wait_for_fifo(3, info);
+    aty_st_le32(DP_FRGD_CLR, color, info);
+    aty_st_le32(DP_SRC, BKGD_SRC_BKGD_CLR | FRGD_SRC_FRGD_CLR | MONO_SRC_ONE,
+		info);
+    aty_st_le32(DST_CNTL, DST_LAST_PEL | DST_Y_TOP_TO_BOTTOM |
+			  DST_X_LEFT_TO_RIGHT, info);
+    draw_rect(dstx, dsty, width, height, info);
+}
+
+
+    /*
+     *  Text console acceleration
+     */
+
+static void fbcon_aty_bmove(struct display *p, int sy, int sx, int dy, int dx,
+			    int height, int width)
+{
+#ifdef __sparc__
+    struct fb_info_aty *fb = (struct fb_info_aty *)(p->fb_info);
+
+    if (fb->mmaped && (!fb->fb_info.display_fg
+	|| fb->fb_info.display_fg->vc_num == fb->vtconsole))
+	return;
+#endif
+
+    sx *= fontwidth(p);
+    sy *= fontheight(p);
+    dx *= fontwidth(p);
+    dy *= fontheight(p);
+    width *= fontwidth(p);
+    height *= fontheight(p);
+
+    aty_rectcopy(sx, sy, dx, dy, width, height,
+		 (struct fb_info_aty *)p->fb_info);
+}
+
+static void fbcon_aty_clear(struct vc_data *conp, struct display *p, int sy,
+			    int sx, int height, int width)
+{
+    u32 bgx;
+#ifdef __sparc__
+    struct fb_info_aty *fb = (struct fb_info_aty *)(p->fb_info);
+
+    if (fb->mmaped && (!fb->fb_info.display_fg
+	|| fb->fb_info.display_fg->vc_num == fb->vtconsole))
+	return;
+#endif
+
+    bgx = attr_bgcol_ec(p, conp);
+    bgx |= (bgx << 8);
+    bgx |= (bgx << 16);
+
+    sx *= fontwidth(p);
+    sy *= fontheight(p);
+    width *= fontwidth(p);
+    height *= fontheight(p);
+
+    aty_rectfill(sx, sy, width, height, bgx,
+		 (struct fb_info_aty *)p->fb_info);
+}
+
+#ifdef __sparc__
+#define check_access \
+    if (fb->mmaped && (!fb->fb_info.display_fg \
+	|| fb->fb_info.display_fg->vc_num == fb->vtconsole)) \
+	return;
+#else
+#define check_access do { } while (0)
+#endif
+
+#define DEF_FBCON_ATY_OP(name, call, args...) \
+static void name(struct vc_data *conp, struct display *p, args) \
+{ \
+    struct fb_info_aty *fb = (struct fb_info_aty *)(p->fb_info); \
+    check_access; \
+    if (fb->blitter_may_be_busy) \
+	wait_for_idle((struct fb_info_aty *)p->fb_info); \
+    call; \
+}
+
+#define DEF_FBCON_ATY(width) \
+    DEF_FBCON_ATY_OP(fbcon_aty##width##_putc, \
+		     fbcon_cfb##width##_putc(conp, p, c, yy, xx), \
+		     int c, int yy, int xx) \
+    DEF_FBCON_ATY_OP(fbcon_aty##width##_putcs, \
+		     fbcon_cfb##width##_putcs(conp, p, s, count, yy, xx), \
+		     const unsigned short *s, int count, int yy, int xx) \
+    DEF_FBCON_ATY_OP(fbcon_aty##width##_clear_margins, \
+		     fbcon_cfb##width##_clear_margins(conp, p, bottom_only), \
+		     int bottom_only) \
+ \
+const struct display_switch fbcon_aty##width## = { \
+    setup:		fbcon_cfb##width##_setup, \
+    bmove:		fbcon_aty_bmove, \
+    clear:		fbcon_aty_clear, \
+    putc:		fbcon_aty##width##_putc, \
+    putcs:		fbcon_aty##width##_putcs, \
+    revc:		fbcon_cfb##width##_revc, \
+    clear_margins:	fbcon_aty##width##_clear_margins, \
+    fontwidthmask:	FONTWIDTH(4)|FONTWIDTH(8)|FONTWIDTH(12)|FONTWIDTH(16) \
+};
+
+#ifdef FBCON_HAS_CFB8
+DEF_FBCON_ATY(8)
+#endif
+#ifdef FBCON_HAS_CFB16
+DEF_FBCON_ATY(16)
+#endif
+#ifdef FBCON_HAS_CFB24
+DEF_FBCON_ATY(24)
+#endif
+#ifdef FBCON_HAS_CFB32
+DEF_FBCON_ATY(32)
+#endif
+
diff -u --recursive --new-file v2.4.7/linux/drivers/video/aty/mach64_ct.c linux/drivers/video/aty/mach64_ct.c
--- v2.4.7/linux/drivers/video/aty/mach64_ct.c	Wed Dec 31 16:00:00 1969
+++ linux/drivers/video/aty/mach64_ct.c	Tue Jul 31 14:43:29 2001
@@ -0,0 +1,272 @@
+
+/*
+ *  ATI Mach64 CT/VT/GT/LT Support
+ */
+
+#include <linux/fb.h>
+
+#include <asm/io.h>
+
+#include <video/fbcon.h>
+
+#include "mach64.h"
+#include "atyfb.h"
+
+
+/* FIXME: remove the FAIL definition */
+#define FAIL(x) do { printk(x "\n"); return -EINVAL; } while (0)
+
+static void aty_st_pll(int offset, u8 val, const struct fb_info_aty *info);
+
+static int aty_valid_pll_ct(const struct fb_info_aty *info, u32 vclk_per,
+			    struct pll_ct *pll);
+static int aty_dsp_gt(const struct fb_info_aty *info, u8 bpp,
+		      struct pll_ct *pll);
+static int aty_var_to_pll_ct(const struct fb_info_aty *info, u32 vclk_per,
+			     u8 bpp, union aty_pll *pll);
+static u32 aty_pll_ct_to_var(const struct fb_info_aty *info,
+			     const union aty_pll *pll);
+
+
+
+static void aty_st_pll(int offset, u8 val, const struct fb_info_aty *info)
+{
+    /* write addr byte */
+    aty_st_8(CLOCK_CNTL + 1, (offset << 2) | PLL_WR_EN, info);
+    /* write the register value */
+    aty_st_8(CLOCK_CNTL + 2, val, info);
+    aty_st_8(CLOCK_CNTL + 1, (offset << 2) & ~PLL_WR_EN, info);
+}
+
+
+/* ------------------------------------------------------------------------- */
+
+    /*
+     *  PLL programming (Mach64 CT family)
+     */
+
+static int aty_dsp_gt(const struct fb_info_aty *info, u8 bpp,
+		      struct pll_ct *pll)
+{
+    u32 dsp_xclks_per_row, dsp_loop_latency, dsp_precision, dsp_off, dsp_on;
+    u32 xclks_per_row, fifo_off, fifo_on, y, fifo_size, page_size;
+
+    /* xclocks_per_row<<11 */
+    xclks_per_row = (pll->mclk_fb_div*pll->vclk_post_div_real*64<<11)/
+		    (pll->vclk_fb_div*pll->mclk_post_div_real*bpp);
+    if (xclks_per_row < (1<<11))
+	FAIL("Dotclock to high");
+    if (M64_HAS(FIFO_24)) {
+	fifo_size = 24;
+	dsp_loop_latency = 0;
+    } else {
+	fifo_size = 32;
+	dsp_loop_latency = 2;
+    }
+    dsp_precision = 0;
+    y = (xclks_per_row*fifo_size)>>11;
+    while (y) {
+	y >>= 1;
+	dsp_precision++;
+    }
+    dsp_precision -= 5;
+    /* fifo_off<<6 */
+    fifo_off = ((xclks_per_row*(fifo_size-1))>>5)+(3<<6);
+
+    if (info->total_vram > 1*1024*1024) {
+	if (info->ram_type >= SDRAM) {
+	    /* >1 MB SDRAM */
+	    dsp_loop_latency += 8;
+	    page_size = 8;
+	} else {
+	    /* >1 MB DRAM */
+	    dsp_loop_latency += 6;
+	    page_size = 9;
+	}
+    } else {
+	if (info->ram_type >= SDRAM) {
+	    /* <2 MB SDRAM */
+	    dsp_loop_latency += 9;
+	    page_size = 10;
+	} else {
+	    /* <2 MB DRAM */
+	    dsp_loop_latency += 8;
+	    page_size = 10;
+	}
+    }
+    /* fifo_on<<6 */
+    if (xclks_per_row >= (page_size<<11))
+	fifo_on = ((2*page_size+1)<<6)+(xclks_per_row>>5);
+    else
+	fifo_on = (3*page_size+2)<<6;
+
+    dsp_xclks_per_row = xclks_per_row>>dsp_precision;
+    dsp_on = fifo_on>>dsp_precision;
+    dsp_off = fifo_off>>dsp_precision;
+
+    pll->dsp_config = (dsp_xclks_per_row & 0x3fff) |
+		      ((dsp_loop_latency & 0xf)<<16) |
+		      ((dsp_precision & 7)<<20);
+    pll->dsp_on_off = (dsp_on & 0x7ff) | ((dsp_off & 0x7ff)<<16);
+    return 0;
+}
+
+static int aty_valid_pll_ct(const struct fb_info_aty *info, u32 vclk_per,
+			    struct pll_ct *pll)
+{
+    u32 q, x;			/* x is a workaround for sparc64-linux-gcc */
+    x = x;			/* x is a workaround for sparc64-linux-gcc */
+
+    pll->pll_ref_div = info->pll_per*2*255/info->ref_clk_per;
+
+    /* FIXME: use the VTB/GTB /3 post divider if it's better suited */
+    q = info->ref_clk_per*pll->pll_ref_div*4/info->mclk_per;	/* actually 8*q */
+    if (q < 16*8 || q > 255*8)
+	FAIL("mclk out of range");
+    else if (q < 32*8)
+	pll->mclk_post_div_real = 8;
+    else if (q < 64*8)
+	pll->mclk_post_div_real = 4;
+    else if (q < 128*8)
+	pll->mclk_post_div_real = 2;
+    else
+	pll->mclk_post_div_real = 1;
+    pll->mclk_fb_div = q*pll->mclk_post_div_real/8;
+
+    /* FIXME: use the VTB/GTB /{3,6,12} post dividers if they're better suited */
+    q = info->ref_clk_per*pll->pll_ref_div*4/vclk_per;	/* actually 8*q */
+    if (q < 16*8 || q > 255*8)
+	FAIL("vclk out of range");
+    else if (q < 32*8)
+	pll->vclk_post_div_real = 8;
+    else if (q < 64*8)
+	pll->vclk_post_div_real = 4;
+    else if (q < 128*8)
+	pll->vclk_post_div_real = 2;
+    else
+	pll->vclk_post_div_real = 1;
+    pll->vclk_fb_div = q*pll->vclk_post_div_real/8;
+    return 0;
+}
+
+void aty_calc_pll_ct(const struct fb_info_aty *info, struct pll_ct *pll)
+{
+    u8 mpostdiv = 0;
+    u8 vpostdiv = 0;
+
+    if (M64_HAS(SDRAM_MAGIC_PLL) && (info->ram_type >= SDRAM))
+	pll->pll_gen_cntl = 0x04;
+    else
+	pll->pll_gen_cntl = 0x84;
+
+    switch (pll->mclk_post_div_real) {
+	case 1:
+	    mpostdiv = 0;
+	    break;
+	case 2:
+	    mpostdiv = 1;
+	    break;
+	case 3:
+	    mpostdiv = 4;
+	    break;
+	case 4:
+	    mpostdiv = 2;
+	    break;
+	case 8:
+	    mpostdiv = 3;
+	    break;
+    }
+    pll->pll_gen_cntl |= mpostdiv<<4;	/* mclk */
+
+    if (M64_HAS(MAGIC_POSTDIV))
+	pll->pll_ext_cntl = 0;
+    else
+    	pll->pll_ext_cntl = mpostdiv;	/* xclk == mclk */
+
+    switch (pll->vclk_post_div_real) {
+	case 2:
+	    vpostdiv = 1;
+	    break;
+	case 3:
+	    pll->pll_ext_cntl |= 0x10;
+	case 1:
+	    vpostdiv = 0;
+	    break;
+	case 6:
+	    pll->pll_ext_cntl |= 0x10;
+	case 4:
+	    vpostdiv = 2;
+	    break;
+	case 12:
+	    pll->pll_ext_cntl |= 0x10;
+	case 8:
+	    vpostdiv = 3;
+	    break;
+    }
+
+    pll->pll_vclk_cntl = 0x03;	/* VCLK = PLL_VCLK/VCLKx_POST */
+    pll->vclk_post_div = vpostdiv;
+}
+
+static int aty_var_to_pll_ct(const struct fb_info_aty *info, u32 vclk_per,
+			     u8 bpp, union aty_pll *pll)
+{
+    int err;
+
+    if ((err = aty_valid_pll_ct(info, vclk_per, &pll->ct)))
+	return err;
+    if (M64_HAS(GTB_DSP) && (err = aty_dsp_gt(info, bpp, &pll->ct)))
+	return err;
+    aty_calc_pll_ct(info, &pll->ct);
+    return 0;
+}
+
+static u32 aty_pll_ct_to_var(const struct fb_info_aty *info,
+			     const union aty_pll *pll)
+{
+    u32 ref_clk_per = info->ref_clk_per;
+    u8 pll_ref_div = pll->ct.pll_ref_div;
+    u8 vclk_fb_div = pll->ct.vclk_fb_div;
+    u8 vclk_post_div = pll->ct.vclk_post_div_real;
+
+    return ref_clk_per*pll_ref_div*vclk_post_div/vclk_fb_div/2;
+}
+
+void aty_set_pll_ct(const struct fb_info_aty *info, const union aty_pll *pll)
+{
+    aty_st_pll(PLL_REF_DIV, pll->ct.pll_ref_div, info);
+    aty_st_pll(PLL_GEN_CNTL, pll->ct.pll_gen_cntl, info);
+    aty_st_pll(MCLK_FB_DIV, pll->ct.mclk_fb_div, info);
+    aty_st_pll(PLL_VCLK_CNTL, pll->ct.pll_vclk_cntl, info);
+    aty_st_pll(VCLK_POST_DIV, pll->ct.vclk_post_div, info);
+    aty_st_pll(VCLK0_FB_DIV, pll->ct.vclk_fb_div, info);
+    aty_st_pll(PLL_EXT_CNTL, pll->ct.pll_ext_cntl, info);
+
+    if (M64_HAS(GTB_DSP)) {
+	if (M64_HAS(XL_DLL))
+	    aty_st_pll(DLL_CNTL, 0x80, info);
+	else if (info->ram_type >= SDRAM)
+	    aty_st_pll(DLL_CNTL, 0xa6, info);
+	else
+	    aty_st_pll(DLL_CNTL, 0xa0, info);
+	aty_st_pll(VFC_CNTL, 0x1b, info);
+	aty_st_le32(DSP_CONFIG, pll->ct.dsp_config, info);
+	aty_st_le32(DSP_ON_OFF, pll->ct.dsp_on_off, info);
+    }
+}
+
+static int dummy(void)
+{
+    return 0;
+}
+
+const struct aty_dac_ops aty_dac_ct = {
+    set_dac:	(void *)dummy,
+};
+
+const struct aty_pll_ops aty_pll_ct = {
+    var_to_pll:	aty_var_to_pll_ct,
+    pll_to_var:	aty_pll_ct_to_var,
+    set_pll:	aty_set_pll_ct,
+};
+
diff -u --recursive --new-file v2.4.7/linux/drivers/video/aty/mach64_cursor.c linux/drivers/video/aty/mach64_cursor.c
--- v2.4.7/linux/drivers/video/aty/mach64_cursor.c	Wed Dec 31 16:00:00 1969
+++ linux/drivers/video/aty/mach64_cursor.c	Tue Jul 31 14:43:29 2001
@@ -0,0 +1,305 @@
+
+/*
+ *  ATI Mach64 CT/VT/GT/LT Cursor Support
+ */
+
+#include <linux/malloc.h>
+#include <linux/console.h>
+#include <linux/fb.h>
+#include <linux/init.h>
+
+#include <asm/io.h>
+#include <asm/uaccess.h>
+
+#include <video/fbcon.h>
+
+#ifdef __sparc__
+#include <asm/pbm.h>
+#include <asm/fbio.h>
+#endif
+
+#include "mach64.h"
+#include "atyfb.h"
+
+
+#define DEFAULT_CURSOR_BLINK_RATE	(20)
+#define CURSOR_DRAW_DELAY		(2)
+
+
+    /*
+     *  Hardware Cursor support.
+     */
+
+static const u8 cursor_pixel_map[2] = { 0, 15 };
+static const u8 cursor_color_map[2] = { 0, 0xff };
+
+static const u8 cursor_bits_lookup[16] =
+{
+	0x00, 0x40, 0x10, 0x50, 0x04, 0x44, 0x14, 0x54,
+	0x01, 0x41, 0x11, 0x51, 0x05, 0x45, 0x15, 0x55
+};
+
+static const u8 cursor_mask_lookup[16] =
+{
+	0xaa, 0x2a, 0x8a, 0x0a, 0xa2, 0x22, 0x82, 0x02,
+	0xa8, 0x28, 0x88, 0x08, 0xa0, 0x20, 0x80, 0x00
+};
+
+void aty_set_cursor_color(struct fb_info_aty *fb)
+{
+	struct aty_cursor *c = fb->cursor;
+	const u8 *pixel = cursor_pixel_map;	/* ++Geert: Why?? */
+	const u8 *red = cursor_color_map;
+	const u8 *green = cursor_color_map;
+	const u8 *blue = cursor_color_map;
+	int i;
+
+	if (!c)
+		return;
+
+#ifdef __sparc__
+	if (fb->mmaped && (!fb->fb_info.display_fg
+	    || fb->fb_info.display_fg->vc_num == fb->vtconsole))
+		return;
+#endif
+
+	for (i = 0; i < 2; i++) {
+		c->color[i] =  (u32)red[i] << 24;
+		c->color[i] |= (u32)green[i] << 16;
+ 		c->color[i] |= (u32)blue[i] <<  8;
+ 		c->color[i] |= (u32)pixel[i];
+	}
+
+	wait_for_fifo(2, fb);
+	aty_st_le32(CUR_CLR0, c->color[0], fb);
+	aty_st_le32(CUR_CLR1, c->color[1], fb);
+}
+
+void aty_set_cursor_shape(struct fb_info_aty *fb)
+{
+	struct aty_cursor *c = fb->cursor;
+	u8 *ram, m, b;
+	int x, y;
+
+	if (!c)
+		return;
+
+#ifdef __sparc__
+	if (fb->mmaped && (!fb->fb_info.display_fg
+	    || fb->fb_info.display_fg->vc_num == fb->vtconsole))
+		return;
+#endif
+
+	ram = c->ram;
+	for (y = 0; y < c->size.y; y++) {
+		for (x = 0; x < c->size.x >> 2; x++) {
+			m = c->mask[x][y];
+			b = c->bits[x][y];
+			fb_writeb (cursor_mask_lookup[m >> 4] |
+				   cursor_bits_lookup[(b & m) >> 4],
+				   ram++);
+			fb_writeb (cursor_mask_lookup[m & 0x0f] |
+				   cursor_bits_lookup[(b & m) & 0x0f],
+				   ram++);
+		}
+		for ( ; x < 8; x++) {
+			fb_writeb (0xaa, ram++);
+			fb_writeb (0xaa, ram++);
+		}
+	}
+	fb_memset (ram, 0xaa, (64 - c->size.y) * 16);
+}
+
+static void
+aty_set_cursor(struct fb_info_aty *fb, int on)
+{
+	struct atyfb_par *par = &fb->current_par;
+	struct aty_cursor *c = fb->cursor;
+	u16 xoff, yoff;
+	int x, y;
+
+	if (!c)
+		return;
+
+#ifdef __sparc__
+	if (fb->mmaped && (!fb->fb_info.display_fg
+	    || fb->fb_info.display_fg->vc_num == fb->vtconsole))
+		return;
+#endif
+
+	if (on) {
+		x = c->pos.x - c->hot.x - par->crtc.xoffset;
+		if (x < 0) {
+			xoff = -x;
+			x = 0;
+		} else {
+			xoff = 0;
+		}
+
+		y = c->pos.y - c->hot.y - par->crtc.yoffset;
+		if (y < 0) {
+			yoff = -y;
+			y = 0;
+		} else {
+			yoff = 0;
+		}
+
+		wait_for_fifo(4, fb);
+		aty_st_le32(CUR_OFFSET, (c->offset >> 3) + (yoff << 1), fb);
+		aty_st_le32(CUR_HORZ_VERT_OFF,
+			    ((u32)(64 - c->size.y + yoff) << 16) | xoff, fb);
+		aty_st_le32(CUR_HORZ_VERT_POSN, ((u32)y << 16) | x, fb);
+		aty_st_le32(GEN_TEST_CNTL, aty_ld_le32(GEN_TEST_CNTL, fb)
+						       | HWCURSOR_ENABLE, fb);
+	} else {
+		wait_for_fifo(1, fb);
+		aty_st_le32(GEN_TEST_CNTL,
+			    aty_ld_le32(GEN_TEST_CNTL, fb) & ~HWCURSOR_ENABLE,
+			    fb);
+	}
+	if (fb->blitter_may_be_busy)
+		wait_for_idle(fb);
+}
+
+static void
+aty_cursor_timer_handler(unsigned long dev_addr)
+{
+	struct fb_info_aty *fb = (struct fb_info_aty *)dev_addr;
+
+	if (!fb->cursor)
+		return;
+
+	if (!fb->cursor->enable)
+		goto out;
+
+	if (fb->cursor->vbl_cnt && --fb->cursor->vbl_cnt == 0) {
+		fb->cursor->on ^= 1;
+		aty_set_cursor(fb, fb->cursor->on);
+		fb->cursor->vbl_cnt = fb->cursor->blink_rate;
+	}
+
+out:
+	fb->cursor->timer->expires = jiffies + (HZ / 50);
+	add_timer(fb->cursor->timer);
+}
+
+void atyfb_cursor(struct display *p, int mode, int x, int y)
+{
+	struct fb_info_aty *fb = (struct fb_info_aty *)p->fb_info;
+	struct aty_cursor *c = fb->cursor;
+
+	if (!c)
+		return;
+
+#ifdef __sparc__
+	if (fb->mmaped && (!fb->fb_info.display_fg
+	    || fb->fb_info.display_fg->vc_num == fb->vtconsole))
+		return;
+#endif
+
+	x *= fontwidth(p);
+	y *= fontheight(p);
+	if (c->pos.x == x && c->pos.y == y && (mode == CM_ERASE) == !c->enable)
+		return;
+
+	c->enable = 0;
+	if (c->on)
+		aty_set_cursor(fb, 0);
+	c->pos.x = x;
+	c->pos.y = y;
+
+	switch (mode) {
+	case CM_ERASE:
+		c->on = 0;
+		break;
+
+	case CM_DRAW:
+	case CM_MOVE:
+		if (c->on)
+			aty_set_cursor(fb, 1);
+		else
+			c->vbl_cnt = CURSOR_DRAW_DELAY;
+		c->enable = 1;
+		break;
+	}
+}
+
+struct aty_cursor * __init aty_init_cursor(struct fb_info_aty *fb)
+{
+	struct aty_cursor *cursor;
+	unsigned long addr;
+
+	cursor = kmalloc(sizeof(struct aty_cursor), GFP_ATOMIC);
+	if (!cursor)
+		return 0;
+	memset(cursor, 0, sizeof(*cursor));
+
+	cursor->timer = kmalloc(sizeof(*cursor->timer), GFP_KERNEL);
+	if (!cursor->timer) {
+		kfree(cursor);
+		return 0;
+	}
+	memset(cursor->timer, 0, sizeof(*cursor->timer));
+
+	cursor->blink_rate = DEFAULT_CURSOR_BLINK_RATE;
+	fb->total_vram -= PAGE_SIZE;
+	cursor->offset = fb->total_vram;
+
+#ifdef __sparc__
+	addr = fb->frame_buffer - 0x800000 + cursor->offset;
+	cursor->ram = (u8 *)addr;
+#else
+#ifdef __BIG_ENDIAN
+	addr = fb->frame_buffer_phys - 0x800000 + cursor->offset;
+	cursor->ram = (u8 *)ioremap(addr, 1024);
+#else
+	addr = fb->frame_buffer + cursor->offset;
+	cursor->ram = (u8 *)addr;
+#endif
+#endif
+
+	if (!cursor->ram) {
+		kfree(cursor);
+		return NULL;
+	}
+
+	init_timer(cursor->timer);
+	cursor->timer->expires = jiffies + (HZ / 50);
+	cursor->timer->data = (unsigned long)fb;
+	cursor->timer->function = aty_cursor_timer_handler;
+	add_timer(cursor->timer);
+
+	return cursor;
+}
+
+int atyfb_set_font(struct display *d, int width, int height)
+{
+    struct fb_info_aty *fb = (struct fb_info_aty *)d->fb_info;
+    struct aty_cursor *c = fb->cursor;
+    int i, j;
+
+    if (c) {
+	if (!width || !height) {
+	    width = 8;
+	    height = 16;
+	}
+
+	c->hot.x = 0;
+	c->hot.y = 0;
+	c->size.x = width;
+	c->size.y = height;
+
+	memset(c->bits, 0xff, sizeof(c->bits));
+	memset(c->mask, 0, sizeof(c->mask));
+
+	for (i = 0, j = width; j >= 0; j -= 8, i++) {
+	    c->mask[i][height-2] = (j >= 8) ? 0xff : (0xff << (8 - j));
+	    c->mask[i][height-1] = (j >= 8) ? 0xff : (0xff << (8 - j));
+	}
+
+	aty_set_cursor_color(fb);
+	aty_set_cursor_shape(fb);
+    }
+    return 1;
+}
+
diff -u --recursive --new-file v2.4.7/linux/drivers/video/aty/mach64_gx.c linux/drivers/video/aty/mach64_gx.c
--- v2.4.7/linux/drivers/video/aty/mach64_gx.c	Wed Dec 31 16:00:00 1969
+++ linux/drivers/video/aty/mach64_gx.c	Tue Jul 31 14:43:29 2001
@@ -0,0 +1,886 @@
+
+/*
+ *  ATI Mach64 GX Support
+ */
+
+#include <linux/delay.h>
+#include <linux/fb.h>
+
+#include <asm/io.h>
+
+#include <video/fbcon.h>
+
+#include "mach64.h"
+#include "atyfb.h"
+
+/* Definitions for the ICS 2595 == ATI 18818_1 Clockchip */
+
+#define REF_FREQ_2595       1432  /*  14.33 MHz  (exact   14.31818) */
+#define REF_DIV_2595          46  /* really 43 on ICS 2595 !!!  */
+                                  /* ohne Prescaler */
+#define MAX_FREQ_2595      15938  /* 159.38 MHz  (really 170.486) */
+#define MIN_FREQ_2595       8000  /*  80.00 MHz  (        85.565) */
+                                  /* mit Prescaler 2, 4, 8 */
+#define ABS_MIN_FREQ_2595   1000  /*  10.00 MHz  (really  10.697) */
+#define N_ADJ_2595           257
+
+#define STOP_BITS_2595     0x1800
+
+
+#define MIN_N_408		2
+
+#define MIN_N_1703		6
+
+#define MIN_M		2
+#define MAX_M		30
+#define MIN_N		35
+#define MAX_N		255-8
+
+
+    /*
+     *  Support Functions
+     */
+
+static void aty_dac_waste4(const struct fb_info_aty *info)
+{
+  (void)aty_ld_8(DAC_REGS, info);
+
+  (void)aty_ld_8(DAC_REGS + 2, info);
+  (void)aty_ld_8(DAC_REGS + 2, info);
+  (void)aty_ld_8(DAC_REGS + 2, info);
+  (void)aty_ld_8(DAC_REGS + 2, info);
+}
+
+static void aty_StrobeClock(const struct fb_info_aty *info)
+{
+    u8 tmp;
+
+    udelay(26);
+
+    tmp = aty_ld_8(CLOCK_CNTL, info);
+    aty_st_8(CLOCK_CNTL + info->clk_wr_offset, tmp | CLOCK_STROBE, info);
+
+    return;
+}
+
+
+    /*
+     *  IBM RGB514 DAC and Clock Chip
+     */
+
+static void aty_st_514(int offset, u8 val, const struct fb_info_aty *info)
+{
+    aty_st_8(DAC_CNTL, 1, info);
+    /* right addr byte */
+    aty_st_8(DAC_W_INDEX, offset & 0xff, info);
+    /* left addr byte */
+    aty_st_8(DAC_DATA, (offset >> 8) & 0xff, info);
+    aty_st_8(DAC_MASK, val, info);
+    aty_st_8(DAC_CNTL, 0, info);
+}
+
+static int aty_set_dac_514(const struct fb_info_aty *info,
+			   const union aty_pll *pll, u32 bpp, u32 accel)
+{
+    static struct {
+	u8 pixel_dly;
+	u8 misc2_cntl;
+	u8 pixel_rep;
+	u8 pixel_cntl_index;
+	u8 pixel_cntl_v1;
+    } tab[3] = {
+	{ 0, 0x41, 0x03, 0x71, 0x45 },	/* 8 bpp */
+	{ 0, 0x45, 0x04, 0x0c, 0x01 },	/* 555 */
+	{ 0, 0x45, 0x06, 0x0e, 0x00 },	/* XRGB */
+    };
+    int i;
+
+    switch (bpp) {
+	case 8:
+	default:
+	    i = 0;
+	    break;
+	case 16:
+	    i = 1;
+	    break;
+	case 32:
+	    i = 2;
+	    break;
+    }
+    aty_st_514(0x90, 0x00, info);		/* VRAM Mask Low */
+    aty_st_514(0x04, tab[i].pixel_dly, info);	/* Horizontal Sync Control */
+    aty_st_514(0x05, 0x00, info);		/* Power Management */
+    aty_st_514(0x02, 0x01, info);		/* Misc Clock Control */
+    aty_st_514(0x71, tab[i].misc2_cntl, info);	/* Misc Control 2 */
+    aty_st_514(0x0a, tab[i].pixel_rep, info);	/* Pixel Format */
+    aty_st_514(tab[i].pixel_cntl_index, tab[i].pixel_cntl_v1, info);
+			/* Misc Control 2 / 16 BPP Control / 32 BPP Control */
+    return 0;
+}
+
+static int aty_var_to_pll_514(const struct fb_info_aty *info, u32 vclk_per,
+			      u8 bpp, union aty_pll *pll)
+{
+    /*
+     *  FIXME: use real calculations instead of using fixed values from the old
+     *	       driver
+     */
+    static struct {
+	u32 limit;	/* pixlock rounding limit (arbitrary) */
+	u8 m;		/* (df<<6) | vco_div_count */
+	u8 n;		/* ref_div_count */
+    } RGB514_clocks[7] = {
+	{  8000, (3<<6) | 20, 9 },	/*  7395 ps / 135.2273 MHz */
+	{ 10000, (1<<6) | 19, 3 },	/*  9977 ps / 100.2273 MHz */
+	{ 13000, (1<<6) |  2, 3 },	/* 12509 ps /  79.9432 MHz */
+	{ 14000, (2<<6) |  8, 7 },	/* 13394 ps /  74.6591 MHz */
+	{ 16000, (1<<6) | 44, 6 },	/* 15378 ps /  65.0284 MHz */
+	{ 25000, (1<<6) | 15, 5 },	/* 17460 ps /  57.2727 MHz */
+	{ 50000, (0<<6) | 53, 7 },	/* 33145 ps /  30.1705 MHz */
+    };
+    int i;
+
+    for (i = 0; i < sizeof(RGB514_clocks)/sizeof(*RGB514_clocks); i++)
+	if (vclk_per <= RGB514_clocks[i].limit) {
+	    pll->ibm514.m = RGB514_clocks[i].m;
+	    pll->ibm514.n = RGB514_clocks[i].n;
+	    return 0;
+	}
+    return -EINVAL;
+}
+
+static u32 aty_pll_514_to_var(const struct fb_info_aty *info,
+	                      const union aty_pll *pll)
+{
+    u8 df, vco_div_count, ref_div_count;
+
+    df = pll->ibm514.m >> 6;
+    vco_div_count = pll->ibm514.m & 0x3f;
+    ref_div_count = pll->ibm514.n;
+
+    return ((info->ref_clk_per*ref_div_count)<<(3-df))/(vco_div_count+65);
+}
+
+static void aty_set_pll_514(const struct fb_info_aty *info,
+			    const union aty_pll *pll)
+{
+    aty_st_514(0x06, 0x02, info);	/* DAC Operation */
+    aty_st_514(0x10, 0x01, info);	/* PLL Control 1 */
+    aty_st_514(0x70, 0x01, info);	/* Misc Control 1 */
+    aty_st_514(0x8f, 0x1f, info);	/* PLL Ref. Divider Input */
+    aty_st_514(0x03, 0x00, info);	/* Sync Control */
+    aty_st_514(0x05, 0x00, info);	/* Power Management */
+    aty_st_514(0x20, pll->ibm514.m, info);	/* F0 / M0 */
+    aty_st_514(0x21, pll->ibm514.n, info);	/* F1 / N0 */
+}
+
+const struct aty_dac_ops aty_dac_ibm514 = {
+    set_dac:	aty_set_dac_514,
+};
+
+const struct aty_pll_ops aty_pll_ibm514 = {
+    var_to_pll:	aty_var_to_pll_514,
+    pll_to_var:	aty_pll_514_to_var,
+    set_pll:	aty_set_pll_514,
+};
+
+
+    /*
+     *  ATI 68860-B DAC
+     */
+
+static int aty_set_dac_ATI68860_B(const struct fb_info_aty *info,
+				  const union aty_pll *pll, u32 bpp, u32 accel)
+{
+    u32 gModeReg, devSetupRegA, temp, mask;
+
+    gModeReg = 0;
+    devSetupRegA = 0;
+
+    switch (bpp) {
+	case 8:
+	    gModeReg = 0x83;
+	    devSetupRegA = 0x60 | 0x00 /*(info->mach64DAC8Bit ? 0x00 : 0x01) */;
+	    break;
+	case 15:
+	    gModeReg = 0xA0;
+	    devSetupRegA = 0x60;
+	    break;
+	case 16:
+	    gModeReg = 0xA1;
+	    devSetupRegA = 0x60;
+	    break;
+	case 24:
+	    gModeReg = 0xC0;
+	    devSetupRegA = 0x60;
+	    break;
+	case 32:
+	    gModeReg = 0xE3;
+	    devSetupRegA = 0x60;
+	    break;
+    }
+
+    if (!accel) {
+	gModeReg = 0x80;
+	devSetupRegA = 0x61;
+    }
+
+    temp = aty_ld_8(DAC_CNTL, info);
+    aty_st_8(DAC_CNTL, (temp & ~DAC_EXT_SEL_RS2) | DAC_EXT_SEL_RS3, info);
+
+    aty_st_8(DAC_REGS + 2, 0x1D, info);
+    aty_st_8(DAC_REGS + 3, gModeReg, info);
+    aty_st_8(DAC_REGS, 0x02, info);
+
+    temp = aty_ld_8(DAC_CNTL, info);
+    aty_st_8(DAC_CNTL, temp | DAC_EXT_SEL_RS2 | DAC_EXT_SEL_RS3, info);
+
+    if (info->total_vram < MEM_SIZE_1M)
+	mask = 0x04;
+    else if (info->total_vram == MEM_SIZE_1M)
+	mask = 0x08;
+    else
+	mask = 0x0C;
+
+    /* The following assumes that the BIOS has correctly set R7 of the
+     * Device Setup Register A at boot time.
+     */
+#define A860_DELAY_L	0x80
+
+    temp = aty_ld_8(DAC_REGS, info);
+    aty_st_8(DAC_REGS, (devSetupRegA | mask) | (temp & A860_DELAY_L), info);
+    temp = aty_ld_8(DAC_CNTL, info);
+    aty_st_8(DAC_CNTL, (temp & ~(DAC_EXT_SEL_RS2 | DAC_EXT_SEL_RS3)), info);
+
+    aty_st_le32(BUS_CNTL, 0x890e20f1, info);
+    aty_st_le32(DAC_CNTL, 0x47052100, info);
+
+    return 0;
+}
+
+const struct aty_dac_ops aty_dac_ati68860b = {
+    set_dac:	aty_set_dac_ATI68860_B,
+};
+
+
+    /*
+     *  AT&T 21C498 DAC
+     */
+
+static int aty_set_dac_ATT21C498(const struct fb_info_aty *info,
+				 const union aty_pll *pll, u32 bpp, u32 accel)
+{
+    u32 dotClock;
+    int muxmode = 0;
+    int DACMask = 0;
+
+    dotClock = 100000000 / pll->ics2595.period_in_ps;
+
+    switch (bpp) {
+	case 8:
+	    if (dotClock > 8000) {
+		DACMask = 0x24;
+		muxmode = 1;
+	    } else
+		DACMask = 0x04;
+	    break;
+	case 15:
+	    DACMask = 0x16;
+	    break;
+	case 16:
+	    DACMask = 0x36;
+	    break;
+	case 24:
+	    DACMask = 0xE6;
+	    break;
+	case 32:
+	    DACMask = 0xE6;
+	    break;
+    }
+
+    if (1 /* info->mach64DAC8Bit */)
+	DACMask |= 0x02;
+
+    aty_dac_waste4(info);
+    aty_st_8(DAC_REGS + 2, DACMask, info);
+
+    aty_st_le32(BUS_CNTL, 0x890e20f1, info);
+    aty_st_le32(DAC_CNTL, 0x00072000, info);
+    return muxmode;
+}
+
+const struct aty_dac_ops aty_dac_att21c498 = {
+    set_dac:	aty_set_dac_ATT21C498,
+};
+
+
+    /*
+     *  ATI 18818 / ICS 2595 Clock Chip
+     */
+
+static int aty_var_to_pll_18818(const struct fb_info_aty *info, u32 vclk_per,
+				u8 bpp, union aty_pll *pll)
+{
+    u32 MHz100;		/* in 0.01 MHz */
+    u32 program_bits;
+    u32 post_divider;
+
+    /* Calculate the programming word */
+    MHz100 = 100000000 / vclk_per;
+
+    program_bits = -1;
+    post_divider = 1;
+
+    if (MHz100 > MAX_FREQ_2595) {
+	MHz100 = MAX_FREQ_2595;
+	return -EINVAL;
+    } else if (MHz100 < ABS_MIN_FREQ_2595) {
+	program_bits = 0;	/* MHz100 = 257 */
+	return -EINVAL;
+    } else {
+	while (MHz100 < MIN_FREQ_2595) {
+	    MHz100 *= 2;
+	    post_divider *= 2;
+	}
+    }
+    MHz100 *= 1000;
+    MHz100 = (REF_DIV_2595 * MHz100) / REF_FREQ_2595;
+
+    MHz100 += 500;    /* + 0.5 round */
+    MHz100 /= 1000;
+
+    if (program_bits == -1) {
+	program_bits = MHz100 - N_ADJ_2595;
+	switch (post_divider) {
+	    case 1:
+		program_bits |= 0x0600;
+		break;
+	    case 2:
+		program_bits |= 0x0400;
+		break;
+	    case 4:
+		program_bits |= 0x0200;
+		break;
+	    case 8:
+	    default:
+		break;
+	}
+    }
+
+    program_bits |= STOP_BITS_2595;
+
+    pll->ics2595.program_bits = program_bits;
+    pll->ics2595.locationAddr = 0;
+    pll->ics2595.post_divider = post_divider;
+    pll->ics2595.period_in_ps = vclk_per;
+
+    return 0;
+}
+
+static u32 aty_pll_18818_to_var(const struct fb_info_aty *info,
+				const union aty_pll *pll)
+{
+    return(pll->ics2595.period_in_ps);  /* default for now */
+}
+
+static void aty_ICS2595_put1bit(u8 data, const struct fb_info_aty *info)
+{
+    u8 tmp;
+
+    data &= 0x01;
+    tmp = aty_ld_8(CLOCK_CNTL, info);
+    aty_st_8(CLOCK_CNTL + info->clk_wr_offset, (tmp & ~0x04) | (data << 2),
+	     info);
+
+    tmp = aty_ld_8(CLOCK_CNTL, info);
+    aty_st_8(CLOCK_CNTL + info->clk_wr_offset, (tmp & ~0x08) | (0 << 3), info);
+
+    aty_StrobeClock(info);
+
+    tmp = aty_ld_8(CLOCK_CNTL, info);
+    aty_st_8(CLOCK_CNTL + info->clk_wr_offset, (tmp & ~0x08) | (1 << 3), info);
+
+    aty_StrobeClock(info);
+
+    return;
+}
+
+static void aty_set_pll18818(const struct fb_info_aty *info,
+			     const union aty_pll *pll)
+{
+    u32 program_bits;
+    u32 locationAddr;
+
+    u32 i;
+
+    u8 old_clock_cntl;
+    u8 old_crtc_ext_disp;
+
+    old_clock_cntl = aty_ld_8(CLOCK_CNTL, info);
+    aty_st_8(CLOCK_CNTL + info->clk_wr_offset, 0, info);
+
+    old_crtc_ext_disp = aty_ld_8(CRTC_GEN_CNTL + 3, info);
+    aty_st_8(CRTC_GEN_CNTL + 3, old_crtc_ext_disp | (CRTC_EXT_DISP_EN >> 24),
+	     info);
+
+    mdelay(15); /* delay for 50 (15) ms */
+
+    program_bits = pll->ics2595.program_bits;
+    locationAddr = pll->ics2595.locationAddr;
+
+    /* Program the clock chip */
+    aty_st_8(CLOCK_CNTL + info->clk_wr_offset, 0, info);  /* Strobe = 0 */
+    aty_StrobeClock(info);
+    aty_st_8(CLOCK_CNTL + info->clk_wr_offset, 1, info);  /* Strobe = 0 */
+    aty_StrobeClock(info);
+
+    aty_ICS2595_put1bit(1, info);    /* Send start bits */
+    aty_ICS2595_put1bit(0, info);    /* Start bit */
+    aty_ICS2595_put1bit(0, info);    /* Read / ~Write */
+
+    for (i = 0; i < 5; i++) {	/* Location 0..4 */
+	aty_ICS2595_put1bit(locationAddr & 1, info);
+	locationAddr >>= 1;
+    }
+
+    for (i = 0; i < 8 + 1 + 2 + 2; i++) {
+	aty_ICS2595_put1bit(program_bits & 1, info);
+	program_bits >>= 1;
+    }
+
+    mdelay(1); /* delay for 1 ms */
+
+    (void)aty_ld_8(DAC_REGS, info); /* Clear DAC Counter */
+    aty_st_8(CRTC_GEN_CNTL + 3, old_crtc_ext_disp, info);
+    aty_st_8(CLOCK_CNTL + info->clk_wr_offset, old_clock_cntl | CLOCK_STROBE,
+	     info);
+
+    mdelay(50); /* delay for 50 (15) ms */
+    aty_st_8(CLOCK_CNTL + info->clk_wr_offset,
+	     ((pll->ics2595.locationAddr & 0x0F) | CLOCK_STROBE), info);
+
+    return;
+}
+
+const struct aty_pll_ops aty_pll_ati18818_1 = {
+    var_to_pll:	aty_var_to_pll_18818,
+    pll_to_var:	aty_pll_18818_to_var,
+    set_pll:	aty_set_pll18818,
+};
+
+
+    /*
+     *  STG 1703 Clock Chip
+     */
+
+static int aty_var_to_pll_1703(const struct fb_info_aty *info, u32 vclk_per,
+			       u8 bpp, union aty_pll *pll)
+{
+    u32 mhz100;			/* in 0.01 MHz */
+    u32 program_bits;
+    /* u32 post_divider; */
+    u32 mach64MinFreq, mach64MaxFreq, mach64RefFreq;
+    u32 temp, tempB;
+    u16 remainder, preRemainder;
+    short divider = 0, tempA;
+
+    /* Calculate the programming word */
+    mhz100 = 100000000 / vclk_per;
+    mach64MinFreq = MIN_FREQ_2595;
+    mach64MaxFreq = MAX_FREQ_2595;
+    mach64RefFreq = REF_FREQ_2595;	/* 14.32 MHz */
+
+    /* Calculate program word */
+    if (mhz100 == 0)
+	program_bits = 0xE0;
+    else {
+	if (mhz100 < mach64MinFreq)
+	    mhz100 = mach64MinFreq;
+	if (mhz100 > mach64MaxFreq)
+	    mhz100 = mach64MaxFreq;
+
+	divider = 0;
+	while (mhz100 < (mach64MinFreq << 3)) {
+	    mhz100 <<= 1;
+	    divider += 0x20;
+	}
+
+	temp = (unsigned int)(mhz100);
+	temp = (unsigned int)(temp * (MIN_N_1703 + 2));
+	temp -= (short)(mach64RefFreq << 1);
+
+	tempA = MIN_N_1703;
+	preRemainder = 0xffff;
+
+	do {
+	    tempB = temp;
+	    remainder = tempB % mach64RefFreq;
+	    tempB = tempB / mach64RefFreq;
+
+	    if ((tempB & 0xffff) <= 127 && (remainder <= preRemainder)) {
+		preRemainder = remainder;
+		divider &= ~0x1f;
+		divider |= tempA;
+		divider = (divider & 0x00ff) + ((tempB & 0xff) << 8);
+	    }
+
+	    temp += mhz100;
+	    tempA++;
+	} while (tempA <= (MIN_N_1703 << 1));
+
+	program_bits = divider;
+    }
+
+      pll->ics2595.program_bits = program_bits;
+      pll->ics2595.locationAddr = 0;
+      pll->ics2595.post_divider = divider;  /* fuer nix */
+      pll->ics2595.period_in_ps = vclk_per;
+
+      return 0;
+}
+
+static u32 aty_pll_1703_to_var(const struct fb_info_aty *info,
+			       const union aty_pll *pll)
+{
+    return(pll->ics2595.period_in_ps);  /* default for now */
+}
+
+static void aty_set_pll_1703(const struct fb_info_aty *info,
+			     const union aty_pll *pll)
+{
+    u32 program_bits;
+    u32 locationAddr;
+
+    char old_crtc_ext_disp;
+
+    old_crtc_ext_disp = aty_ld_8(CRTC_GEN_CNTL + 3, info);
+    aty_st_8(CRTC_GEN_CNTL + 3, old_crtc_ext_disp | (CRTC_EXT_DISP_EN >> 24),
+	     info);
+
+    program_bits = pll->ics2595.program_bits;
+    locationAddr = pll->ics2595.locationAddr;
+
+    /* Program clock */
+    aty_dac_waste4(info);
+
+    (void)aty_ld_8(DAC_REGS + 2, info);
+    aty_st_8(DAC_REGS+2, (locationAddr << 1) + 0x20, info);
+    aty_st_8(DAC_REGS+2, 0, info);
+    aty_st_8(DAC_REGS+2, (program_bits & 0xFF00) >> 8, info);
+    aty_st_8(DAC_REGS+2, (program_bits & 0xFF), info);
+
+    (void)aty_ld_8(DAC_REGS, info); /* Clear DAC Counter */
+    aty_st_8(CRTC_GEN_CNTL + 3, old_crtc_ext_disp, info);
+
+    return;
+}
+
+const struct aty_pll_ops aty_pll_stg1703 = {
+    var_to_pll:	aty_var_to_pll_1703,
+    pll_to_var:	aty_pll_1703_to_var,
+    set_pll:	aty_set_pll_1703,
+};
+
+
+    /*
+     *  Chrontel 8398 Clock Chip
+     */
+
+static int aty_var_to_pll_8398(const struct fb_info_aty *info, u32 vclk_per,
+			       u8 bpp, union aty_pll *pll)
+{
+    u32 tempA, tempB, fOut, longMHz100, diff, preDiff;
+
+    u32 mhz100;				/* in 0.01 MHz */
+    u32 program_bits;
+    /* u32 post_divider; */
+    u32 mach64MinFreq, mach64MaxFreq, mach64RefFreq;
+    u16 m, n, k=0, save_m, save_n, twoToKth;
+
+    /* Calculate the programming word */
+    mhz100 = 100000000 / vclk_per;
+    mach64MinFreq = MIN_FREQ_2595;
+    mach64MaxFreq = MAX_FREQ_2595;
+    mach64RefFreq = REF_FREQ_2595;	/* 14.32 MHz */
+
+    save_m = 0;
+    save_n = 0;
+
+    /* Calculate program word */
+    if (mhz100 == 0)
+	program_bits = 0xE0;
+    else
+    {
+	if (mhz100 < mach64MinFreq)
+	    mhz100 = mach64MinFreq;
+	if (mhz100 > mach64MaxFreq)
+	    mhz100 = mach64MaxFreq;
+
+	longMHz100 = mhz100 * 256 / 100;   /* 8 bit scale this */
+
+	while (mhz100 < (mach64MinFreq << 3))
+        {
+	    mhz100 <<= 1;
+	    k++;
+	}
+
+	twoToKth = 1 << k;
+	diff = 0;
+	preDiff = 0xFFFFFFFF;
+
+	for (m = MIN_M; m <= MAX_M; m++)
+        {
+	    for (n = MIN_N; n <= MAX_N; n++)
+            {
+		tempA = (14.31818 * 65536);
+		tempA *= (n + 8);  /* 43..256 */
+		tempB = twoToKth * 256;
+		tempB *= (m + 2);  /* 4..32 */
+		fOut = tempA / tempB;  /* 8 bit scale */
+
+		if (longMHz100 > fOut)
+		    diff = longMHz100 - fOut;
+		else
+		    diff = fOut - longMHz100;
+
+		if (diff < preDiff)
+                {
+		    save_m = m;
+		    save_n = n;
+		    preDiff = diff;
+		}
+	    }
+	}
+
+	program_bits = (k << 6) + (save_m) + (save_n << 8);
+    }
+
+    pll->ics2595.program_bits = program_bits;
+    pll->ics2595.locationAddr = 0;
+    pll->ics2595.post_divider = 0;
+    pll->ics2595.period_in_ps = vclk_per;
+
+    return 0;
+}
+
+static u32 aty_pll_8398_to_var(const struct fb_info_aty *info,
+			       const union aty_pll *pll)
+{
+    return(pll->ics2595.period_in_ps);  /* default for now */
+}
+
+static void aty_set_pll_8398(const struct fb_info_aty *info,
+			     const union aty_pll *pll)
+{
+    u32 program_bits;
+    u32 locationAddr;
+
+    char old_crtc_ext_disp;
+    char tmp;
+
+    old_crtc_ext_disp = aty_ld_8(CRTC_GEN_CNTL + 3, info);
+    aty_st_8(CRTC_GEN_CNTL + 3, old_crtc_ext_disp | (CRTC_EXT_DISP_EN >> 24),
+	     info);
+
+    program_bits = pll->ics2595.program_bits;
+    locationAddr = pll->ics2595.locationAddr;
+
+    /* Program clock */
+    tmp = aty_ld_8(DAC_CNTL, info);
+    aty_st_8(DAC_CNTL, tmp | DAC_EXT_SEL_RS2 | DAC_EXT_SEL_RS3, info);
+
+    aty_st_8(DAC_REGS, locationAddr, info);
+    aty_st_8(DAC_REGS+1, (program_bits & 0xff00) >> 8, info);
+    aty_st_8(DAC_REGS+1, (program_bits & 0xff), info);
+
+    tmp = aty_ld_8(DAC_CNTL, info);
+    aty_st_8(DAC_CNTL, (tmp & ~DAC_EXT_SEL_RS2) | DAC_EXT_SEL_RS3, info);
+
+    (void)aty_ld_8(DAC_REGS, info); /* Clear DAC Counter */
+    aty_st_8(CRTC_GEN_CNTL + 3, old_crtc_ext_disp, info);
+
+    return;
+}
+
+const struct aty_pll_ops aty_pll_ch8398 = {
+    var_to_pll:	aty_var_to_pll_8398,
+    pll_to_var:	aty_pll_8398_to_var,
+    set_pll:	aty_set_pll_8398,
+};
+
+
+    /*
+     *  AT&T 20C408 Clock Chip
+     */
+
+static int aty_var_to_pll_408(const struct fb_info_aty *info, u32 vclk_per,
+			      u8 bpp, union aty_pll *pll)
+{
+    u32 mhz100;		/* in 0.01 MHz */
+    u32 program_bits;
+    /* u32 post_divider; */
+    u32 mach64MinFreq, mach64MaxFreq, mach64RefFreq;
+    u32 temp, tempB;
+    u16 remainder, preRemainder;
+    short divider = 0, tempA;
+
+    /* Calculate the programming word */
+    mhz100 = 100000000 / vclk_per;
+    mach64MinFreq = MIN_FREQ_2595;
+    mach64MaxFreq = MAX_FREQ_2595;
+    mach64RefFreq = REF_FREQ_2595;	/* 14.32 MHz */
+
+    /* Calculate program word */
+    if (mhz100 == 0)
+	program_bits = 0xFF;
+    else {
+	if (mhz100 < mach64MinFreq)
+	    mhz100 = mach64MinFreq;
+	if (mhz100 > mach64MaxFreq)
+	    mhz100 = mach64MaxFreq;
+
+	while (mhz100 < (mach64MinFreq << 3)) {
+	    mhz100 <<= 1;
+	    divider += 0x40;
+	}
+
+	temp = (unsigned int)mhz100;
+	temp = (unsigned int)(temp * (MIN_N_408 + 2));
+	temp -= ((short)(mach64RefFreq << 1));
+
+	tempA = MIN_N_408;
+	preRemainder = 0xFFFF;
+
+	do {
+	    tempB = temp;
+	    remainder = tempB % mach64RefFreq;
+	    tempB = tempB / mach64RefFreq;
+	    if (((tempB & 0xFFFF) <= 255) && (remainder <= preRemainder)) {
+		preRemainder = remainder;
+		divider &= ~0x3f;
+		divider |= tempA;
+		divider = (divider & 0x00FF) + ((tempB & 0xFF) << 8);
+	    }
+	    temp += mhz100;
+	    tempA++;
+	} while(tempA <= 32);
+
+	program_bits = divider;
+    }
+
+    pll->ics2595.program_bits = program_bits;
+    pll->ics2595.locationAddr = 0;
+    pll->ics2595.post_divider = divider;	/* fuer nix */
+    pll->ics2595.period_in_ps = vclk_per;
+
+    return 0;
+}
+
+static u32 aty_pll_408_to_var(const struct fb_info_aty *info,
+			      const union aty_pll *pll)
+{
+    return(pll->ics2595.period_in_ps);  /* default for now */
+}
+
+static void aty_set_pll_408(const struct fb_info_aty *info,
+			    const union aty_pll *pll)
+{
+    u32 program_bits;
+    u32 locationAddr;
+
+    u8 tmpA, tmpB, tmpC;
+    char old_crtc_ext_disp;
+
+    old_crtc_ext_disp = aty_ld_8(CRTC_GEN_CNTL + 3, info);
+    aty_st_8(CRTC_GEN_CNTL + 3, old_crtc_ext_disp | (CRTC_EXT_DISP_EN >> 24),
+	     info);
+
+    program_bits = pll->ics2595.program_bits;
+    locationAddr = pll->ics2595.locationAddr;
+
+    /* Program clock */
+    aty_dac_waste4(info);
+    tmpB = aty_ld_8(DAC_REGS + 2, info) | 1;
+    aty_dac_waste4(info);
+    aty_st_8(DAC_REGS + 2, tmpB, info);
+
+    tmpA = tmpB;
+    tmpC = tmpA;
+    tmpA |= 8;
+    tmpB = 1;
+
+    aty_st_8(DAC_REGS, tmpB, info);
+    aty_st_8(DAC_REGS + 2, tmpA, info);
+
+    udelay(400); /* delay for 400 us */
+
+    locationAddr = (locationAddr << 2) + 0x40;
+    tmpB = locationAddr;
+    tmpA = program_bits >> 8;
+
+    aty_st_8(DAC_REGS, tmpB, info);
+    aty_st_8(DAC_REGS + 2, tmpA, info);
+
+    tmpB = locationAddr + 1;
+    tmpA = (u8)program_bits;
+
+    aty_st_8(DAC_REGS, tmpB, info);
+    aty_st_8(DAC_REGS + 2, tmpA, info);
+
+    tmpB = locationAddr + 2;
+    tmpA = 0x77;
+
+    aty_st_8(DAC_REGS, tmpB, info);
+    aty_st_8(DAC_REGS + 2, tmpA, info);
+
+    udelay(400); /* delay for 400 us */
+    tmpA = tmpC & (~(1 | 8));
+    tmpB = 1;
+
+    aty_st_8(DAC_REGS, tmpB, info);
+    aty_st_8(DAC_REGS + 2, tmpA, info);
+
+    (void)aty_ld_8(DAC_REGS, info); /* Clear DAC Counter */
+    aty_st_8(CRTC_GEN_CNTL + 3, old_crtc_ext_disp, info);
+
+    return;
+}
+
+const struct aty_pll_ops aty_pll_att20c408 = {
+    var_to_pll:	aty_var_to_pll_408,
+    pll_to_var:	aty_pll_408_to_var,
+    set_pll:	aty_set_pll_408,
+};
+
+
+    /*
+     *  Unsupported DAC and Clock Chip
+     */
+
+static int aty_set_dac_unsupported(const struct fb_info_aty *info,
+				   const union aty_pll *pll, u32 bpp,
+				   u32 accel)
+{
+    aty_st_le32(BUS_CNTL, 0x890e20f1, info);
+    aty_st_le32(DAC_CNTL, 0x47052100, info);
+    /* new in 2.2.3p1 from Geert. ???????? */
+    aty_st_le32(BUS_CNTL, 0x590e10ff, info);
+    aty_st_le32(DAC_CNTL, 0x47012100, info);
+    return 0;
+}
+
+static int dummy(void)
+{
+    return 0;
+}
+
+const struct aty_dac_ops aty_dac_unsupported = {
+    set_dac:	aty_set_dac_unsupported,
+};
+
+const struct aty_pll_ops aty_pll_unsupported = {
+    var_to_pll:	(void *)dummy,
+    pll_to_var:	(void *)dummy,
+    set_pll:	(void *)dummy,
+};
+
diff -u --recursive --new-file v2.4.7/linux/drivers/video/aty.h linux/drivers/video/aty.h
--- v2.4.7/linux/drivers/video/aty.h	Wed May 16 10:31:23 2001
+++ linux/drivers/video/aty.h	Wed Dec 31 16:00:00 1969
@@ -1,1012 +0,0 @@
-/*
- * Exported procedures for the ATI/mach64 display driver on PowerMacs.
- *
- * Copyright (C) 1997 Michael AK Tesch
- *  written with much help from Jon Howell
- *
- * Updated for 3D RAGE PRO by Geert Uytterhoeven
- *	
- * 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.
- */
-
-/*
- * most of the rest of this file comes from ATI sample code
- */
-#ifndef REGMACH64_H
-#define REGMACH64_H
-
-/* NON-GUI MEMORY MAPPED Registers - expressed in BYTE offsets */
-
-#define CRTC_H_TOTAL_DISP	0x0000	/* Dword offset 0_00 */
-#define CRTC_H_SYNC_STRT_WID	0x0004	/* Dword offset 0_01 */
-#define CRTC_H_SYNC_STRT	0x0004
-#define CRTC_H_SYNC_DLY		0x0005
-#define CRTC_H_SYNC_WID		0x0006
-
-#define CRTC_V_TOTAL_DISP	0x0008	/* Dword offset 0_02 */
-#define CRTC_V_TOTAL		0x0008
-#define CRTC_V_DISP		0x000A
-#define CRTC_V_SYNC_STRT_WID	0x000C	/* Dword offset 0_03 */
-#define CRTC_V_SYNC_STRT	0x000C
-#define CRTC_V_SYNC_WID		0x000E
-
-#define CRTC_VLINE_CRNT_VLINE	0x0010	/* Dword offset 0_04 */
-#define CRTC_OFF_PITCH		0x0014	/* Dword offset 0_05 */
-#define CRTC_OFFSET		0x0014
-#define CRTC_PITCH		0x0016
-
-#define CRTC_INT_CNTL		0x0018	/* Dword offset 0_06 */
-#define CRTC_GEN_CNTL		0x001C	/* Dword offset 0_07 */
-#define CRTC_PIX_WIDTH		0x001D
-#define CRTC_FIFO		0x001E
-#define CRTC_EXT_DISP		0x001F
-
-#define DSP_CONFIG		0x0020	/* Dword offset 0_08 */
-#define DSP_ON_OFF		0x0024	/* Dword offset 0_09 */
-#define TIMER_CONFIG		0x0028	/* Dword offset 0_0A */
-#define MEM_BUF_CNTL		0x002C	/* Dword offset 0_0B */
-#define MEM_ADDR_CONFIG		0x0034	/* Dword offset 0_0D */
-
-#define CRT_TRAP		0x0038	/* Dword offset 0_0E */
-
-#define I2C_CNTL_0		0x003C	/* Dword offset 0_0F */
-
-#define OVR_CLR			0x0040	/* Dword offset 0_10 */
-#define OVR_WID_LEFT_RIGHT	0x0044	/* Dword offset 0_11 */
-#define OVR_WID_TOP_BOTTOM	0x0048	/* Dword offset 0_12 */
-
-#define VGA_DSP_CONFIG		0x004C	/* Dword offset 0_13 */
-#define VGA_DSP_ON_OFF		0x0050	/* Dword offset 0_14 */
-
-#define CUR_CLR0		0x0060	/* Dword offset 0_18 */
-#define CUR_CLR1		0x0064	/* Dword offset 0_19 */
-#define CUR_OFFSET		0x0068	/* Dword offset 0_1A */
-#define CUR_HORZ_VERT_POSN	0x006C	/* Dword offset 0_1B */
-#define CUR_HORZ_VERT_OFF	0x0070	/* Dword offset 0_1C */
-
-#define CONFIG_PANEL_LG		0x0074	/* Dword offset 0_1D */
-
-#define GP_IO			0x0078	/* Dword offset 0_1E */
-
-#define HW_DEBUG		0x007C	/* Dword offset 0_1F */
-
-#define SCRATCH_REG0		0x0080	/* Dword offset 0_20 */
-#define SCRATCH_REG1		0x0084	/* Dword offset 0_21 */
-
-#define CLOCK_CNTL		0x0090	/* Dword offset 0_24 */
-#define CLOCK_SEL_CNTL		0x0090	/* Dword offset 0_24 */
-
-#define CONFIG_STAT1		0x0094	/* Dword offset 0_25 */
-#define CONFIG_STAT2		0x0098	/* Dword offset 0_26 */
-
-#define BUS_CNTL		0x00A0	/* Dword offset 0_28 */
-
-#define LCD_INDEX		0x00A4	/* Dword offset 0_29 */
-#define LCD_DATA		0x00A8	/* Dword offset 0_2A */
-
-#define EXT_MEM_CNTL		0x00AC	/* Dword offset 0_2B */
-#define MEM_CNTL		0x00B0	/* Dword offset 0_2C */
-
-#define MEM_VGA_WP_SEL		0x00B4	/* Dword offset 0_2D */
-#define MEM_VGA_RP_SEL		0x00B8	/* Dword offset 0_2E */
-
-#define I2C_CNTL_1		0x00BC	/* Dword offset 0_2F */
-
-#define DAC_REGS		0x00C0	/* Dword offset 0_30 */
-#define DAC_W_INDEX		0x00C0	/* Dword offset 0_30 */
-#define DAC_DATA		0x00C1	/* Dword offset 0_30 */
-#define DAC_MASK		0x00C2	/* Dword offset 0_30 */
-#define DAC_R_INDEX		0x00C3	/* Dword offset 0_30 */
-#define DAC_CNTL		0x00C4	/* Dword offset 0_31 */
-
-#define EXT_DAC_REGS		0x00C8	/* Dword offset 0_32 */
-
-#define GEN_TEST_CNTL		0x00D0	/* Dword offset 0_34 */
-
-#define CUSTOM_MACRO_CNTL	0x00D4	/* Dword offset 0_35 */
-#define LCD_GEN_CNTL_LG		0x00D4	/* Dword offset 0_35 */
-
-#define POWER_MANAGEMENT_LG	0x00D8	/* Dword offset 0_36 (LG) */
-
-#define CONFIG_CNTL		0x00DC	/* Dword offset 0_37 (CT, ET, VT) */
-#define CONFIG_CHIP_ID		0x00E0	/* Dword offset 0_38 */
-#define CONFIG_STAT0		0x00E4	/* Dword offset 0_39 */
-#define CRC_SIG			0x00E8	/* Dword offset 0_3A */
-
-
-/* GUI MEMORY MAPPED Registers */
-
-#define DST_OFF_PITCH		0x0100	/* Dword offset 0_40 */
-#define DST_X			0x0104	/* Dword offset 0_41 */
-#define DST_Y			0x0108	/* Dword offset 0_42 */
-#define DST_Y_X			0x010C	/* Dword offset 0_43 */
-#define DST_WIDTH		0x0110	/* Dword offset 0_44 */
-#define DST_HEIGHT		0x0114	/* Dword offset 0_45 */
-#define DST_HEIGHT_WIDTH	0x0118	/* Dword offset 0_46 */
-#define DST_X_WIDTH		0x011C	/* Dword offset 0_47 */
-#define DST_BRES_LNTH		0x0120	/* Dword offset 0_48 */
-#define DST_BRES_ERR		0x0124	/* Dword offset 0_49 */
-#define DST_BRES_INC		0x0128	/* Dword offset 0_4A */
-#define DST_BRES_DEC		0x012C	/* Dword offset 0_4B */
-#define DST_CNTL		0x0130	/* Dword offset 0_4C */
-#define DST_Y_X__ALIAS__	0x0134	/* Dword offset 0_4D */
-#define TRAIL_BRES_ERR		0x0138	/* Dword offset 0_4E */
-#define TRAIL_BRES_INC		0x013C	/* Dword offset 0_4F */
-#define TRAIL_BRES_DEC		0x0140	/* Dword offset 0_50 */
-#define LEAD_BRES_LNTH		0x0144	/* Dword offset 0_51 */
-#define Z_OFF_PITCH		0x0148	/* Dword offset 0_52 */
-#define Z_CNTL			0x014C	/* Dword offset 0_53 */
-#define ALPHA_TST_CNTL		0x0150	/* Dword offset 0_54 */
-#define SECONDARY_STW_EXP	0x0158	/* Dword offset 0_56 */
-#define SECONDARY_S_X_INC	0x015C	/* Dword offset 0_57 */
-#define SECONDARY_S_Y_INC	0x0160	/* Dword offset 0_58 */
-#define SECONDARY_S_START	0x0164	/* Dword offset 0_59 */
-#define SECONDARY_W_X_INC	0x0168	/* Dword offset 0_5A */
-#define SECONDARY_W_Y_INC	0x016C	/* Dword offset 0_5B */
-#define SECONDARY_W_START	0x0170	/* Dword offset 0_5C */
-#define SECONDARY_T_X_INC	0x0174	/* Dword offset 0_5D */
-#define SECONDARY_T_Y_INC	0x0178	/* Dword offset 0_5E */
-#define SECONDARY_T_START	0x017C	/* Dword offset 0_5F */
-
-#define SRC_OFF_PITCH		0x0180	/* Dword offset 0_60 */
-#define SRC_X			0x0184	/* Dword offset 0_61 */
-#define SRC_Y			0x0188	/* Dword offset 0_62 */
-#define SRC_Y_X			0x018C	/* Dword offset 0_63 */
-#define SRC_WIDTH1		0x0190	/* Dword offset 0_64 */
-#define SRC_HEIGHT1		0x0194	/* Dword offset 0_65 */
-#define SRC_HEIGHT1_WIDTH1	0x0198	/* Dword offset 0_66 */
-#define SRC_X_START		0x019C	/* Dword offset 0_67 */
-#define SRC_Y_START		0x01A0	/* Dword offset 0_68 */
-#define SRC_Y_X_START		0x01A4	/* Dword offset 0_69 */
-#define SRC_WIDTH2		0x01A8	/* Dword offset 0_6A */
-#define SRC_HEIGHT2		0x01AC	/* Dword offset 0_6B */
-#define SRC_HEIGHT2_WIDTH2	0x01B0	/* Dword offset 0_6C */
-#define SRC_CNTL		0x01B4	/* Dword offset 0_6D */
-
-#define SCALE_OFF		0x01C0	/* Dword offset 0_70 */
-#define SECONDARY_SCALE_OFF	0x01C4	/* Dword offset 0_71 */
-
-#define TEX_0_OFF		0x01C0	/* Dword offset 0_70 */
-#define TEX_1_OFF		0x01C4	/* Dword offset 0_71 */
-#define TEX_2_OFF		0x01C8	/* Dword offset 0_72 */
-#define TEX_3_OFF		0x01CC	/* Dword offset 0_73 */
-#define TEX_4_OFF		0x01D0	/* Dword offset 0_74 */
-#define TEX_5_OFF		0x01D4	/* Dword offset 0_75 */
-#define TEX_6_OFF		0x01D8	/* Dword offset 0_76 */
-#define TEX_7_OFF		0x01DC	/* Dword offset 0_77 */
-
-#define SCALE_WIDTH		0x01DC	/* Dword offset 0_77 */
-#define SCALE_HEIGHT		0x01E0	/* Dword offset 0_78 */
-
-#define TEX_8_OFF		0x01E0	/* Dword offset 0_78 */
-#define TEX_9_OFF		0x01E4	/* Dword offset 0_79 */
-#define TEX_10_OFF		0x01E8	/* Dword offset 0_7A */
-#define S_Y_INC			0x01EC	/* Dword offset 0_7B */
-
-#define SCALE_PITCH		0x01EC	/* Dword offset 0_7B */
-#define SCALE_X_INC		0x01F0	/* Dword offset 0_7C */
-
-#define RED_X_INC		0x01F0	/* Dword offset 0_7C */
-#define GREEN_X_INC		0x01F4	/* Dword offset 0_7D */
-
-#define SCALE_Y_INC		0x01F4	/* Dword offset 0_7D */
-#define SCALE_VACC		0x01F8	/* Dword offset 0_7E */
-#define SCALE_3D_CNTL		0x01FC	/* Dword offset 0_7F */
-
-#define HOST_DATA0		0x0200	/* Dword offset 0_80 */
-#define HOST_DATA1		0x0204	/* Dword offset 0_81 */
-#define HOST_DATA2		0x0208	/* Dword offset 0_82 */
-#define HOST_DATA3		0x020C	/* Dword offset 0_83 */
-#define HOST_DATA4		0x0210	/* Dword offset 0_84 */
-#define HOST_DATA5		0x0214	/* Dword offset 0_85 */
-#define HOST_DATA6		0x0218	/* Dword offset 0_86 */
-#define HOST_DATA7		0x021C	/* Dword offset 0_87 */
-#define HOST_DATA8		0x0220	/* Dword offset 0_88 */
-#define HOST_DATA9		0x0224	/* Dword offset 0_89 */
-#define HOST_DATAA		0x0228	/* Dword offset 0_8A */
-#define HOST_DATAB		0x022C	/* Dword offset 0_8B */
-#define HOST_DATAC		0x0230	/* Dword offset 0_8C */
-#define HOST_DATAD		0x0234	/* Dword offset 0_8D */
-#define HOST_DATAE		0x0238	/* Dword offset 0_8E */
-#define HOST_DATAF		0x023C	/* Dword offset 0_8F */
-#define HOST_CNTL		0x0240	/* Dword offset 0_90 */
-
-#define BM_HOSTDATA		0x0244	/* Dword offset 0_91 */
-#define BM_ADDR			0x0248	/* Dword offset 0_92 */
-#define BM_DATA			0x0248	/* Dword offset 0_92 */
-#define BM_GUI_TABLE_CMD	0x024C	/* Dword offset 0_93 */
-
-#define PAT_REG0		0x0280	/* Dword offset 0_A0 */
-#define PAT_REG1		0x0284	/* Dword offset 0_A1 */
-#define PAT_CNTL		0x0288	/* Dword offset 0_A2 */
-
-#define SC_LEFT			0x02A0	/* Dword offset 0_A8 */
-#define SC_RIGHT		0x02A4	/* Dword offset 0_A9 */
-#define SC_LEFT_RIGHT		0x02A8	/* Dword offset 0_AA */
-#define SC_TOP			0x02AC	/* Dword offset 0_AB */
-#define SC_BOTTOM		0x02B0	/* Dword offset 0_AC */
-#define SC_TOP_BOTTOM		0x02B4	/* Dword offset 0_AD */
-
-#define DP_BKGD_CLR		0x02C0	/* Dword offset 0_B0 */
-#define DP_FOG_CLR		0x02C4	/* Dword offset 0_B1 */
-#define DP_FRGD_CLR		0x02C4	/* Dword offset 0_B1 */
-#define DP_WRITE_MASK		0x02C8	/* Dword offset 0_B2 */
-#define DP_CHAIN_MASK		0x02CC	/* Dword offset 0_B3 */
-#define DP_PIX_WIDTH		0x02D0	/* Dword offset 0_B4 */
-#define DP_MIX			0x02D4	/* Dword offset 0_B5 */
-#define DP_SRC			0x02D8	/* Dword offset 0_B6 */
-#define DP_FRGD_CLR_MIX		0x02DC	/* Dword offset 0_B7 */
-#define DP_FRGD_BLGD_CLR	0x02E0	/* Dword offset 0_B8 */
-
-#define DST_X_Y			0x02E8	/* Dword offset 0_BA */
-#define DST_WIDTH_HEIGHT	0x02EC	/* Dword offset 0_BB */
-#define USR_DST_PICTH		0x02F0	/* Dword offset 0_BC */
-#define DP_SET_GUI_ENGINE2	0x02F8	/* Dword offset 0_BE */
-#define DP_SET_GUI_ENGINE	0x02FC	/* Dword offset 0_BF */
-
-#define CLR_CMP_CLR		0x0300	/* Dword offset 0_C0 */
-#define CLR_CMP_MASK		0x0304	/* Dword offset 0_C1 */
-#define CLR_CMP_CNTL		0x0308	/* Dword offset 0_C2 */
-
-#define FIFO_STAT		0x0310	/* Dword offset 0_C4 */
-
-#define CONTEXT_MASK		0x0320	/* Dword offset 0_C8 */
-#define CONTEXT_LOAD_CNTL	0x032C	/* Dword offset 0_CB */
-
-#define GUI_TRAJ_CNTL		0x0330	/* Dword offset 0_CC */
-#define GUI_STAT		0x0338	/* Dword offset 0_CE */
-
-#define TEX_PALETTE_INDEX	0x0340	/* Dword offset 0_D0 */
-#define STW_EXP			0x0344	/* Dword offset 0_D1 */
-#define LOG_MAX_INC		0x0348	/* Dword offset 0_D2 */
-#define S_X_INC			0x034C	/* Dword offset 0_D3 */
-#define S_Y_INC__ALIAS__	0x0350	/* Dword offset 0_D4 */
-
-#define SCALE_PITCH__ALIAS__	0x0350	/* Dword offset 0_D4 */
-
-#define S_START			0x0354	/* Dword offset 0_D5 */
-#define W_X_INC			0x0358	/* Dword offset 0_D6 */
-#define W_Y_INC			0x035C	/* Dword offset 0_D7 */
-#define W_START			0x0360	/* Dword offset 0_D8 */
-#define T_X_INC			0x0364	/* Dword offset 0_D9 */
-#define T_Y_INC			0x0368	/* Dword offset 0_DA */
-
-#define SECONDARY_SCALE_PITCH	0x0368	/* Dword offset 0_DA */
-
-#define T_START			0x036C	/* Dword offset 0_DB */
-#define TEX_SIZE_PITCH		0x0370	/* Dword offset 0_DC */
-#define TEX_CNTL		0x0374	/* Dword offset 0_DD */
-#define SECONDARY_TEX_OFFSET	0x0378	/* Dword offset 0_DE */
-#define TEX_PALETTE		0x037C	/* Dword offset 0_DF */
-
-#define SCALE_PITCH_BOTH	0x0380	/* Dword offset 0_E0 */
-#define SECONDARY_SCALE_OFF_ACC	0x0384	/* Dword offset 0_E1 */
-#define SCALE_OFF_ACC		0x0388	/* Dword offset 0_E2 */
-#define SCALE_DST_Y_X		0x038C	/* Dword offset 0_E3 */
-
-#define COMPOSITE_SHADOW_ID	0x0398	/* Dword offset 0_E6 */
-
-#define SECONDARY_SCALE_X_INC	0x039C	/* Dword offset 0_E7 */
-
-#define SPECULAR_RED_X_INC	0x039C	/* Dword offset 0_E7 */
-#define SPECULAR_RED_Y_INC	0x03A0	/* Dword offset 0_E8 */
-#define SPECULAR_RED_START	0x03A4	/* Dword offset 0_E9 */
-
-#define SECONDARY_SCALE_HACC	0x03A4	/* Dword offset 0_E9 */
-
-#define SPECULAR_GREEN_X_INC	0x03A8	/* Dword offset 0_EA */
-#define SPECULAR_GREEN_Y_INC	0x03AC	/* Dword offset 0_EB */
-#define SPECULAR_GREEN_START	0x03B0	/* Dword offset 0_EC */
-#define SPECULAR_BLUE_X_INC	0x03B4	/* Dword offset 0_ED */
-#define SPECULAR_BLUE_Y_INC	0x03B8	/* Dword offset 0_EE */
-#define SPECULAR_BLUE_START	0x03BC	/* Dword offset 0_EF */
-
-#define SCALE_X_INC__ALIAS__	0x03C0	/* Dword offset 0_F0 */
-
-#define RED_X_INC__ALIAS__	0x03C0	/* Dword offset 0_F0 */
-#define RED_Y_INC		0x03C4	/* Dword offset 0_F1 */
-#define RED_START		0x03C8	/* Dword offset 0_F2 */
-
-#define SCALE_HACC		0x03C8	/* Dword offset 0_F2 */
-#define SCALE_Y_INC__ALIAS__	0x03CC	/* Dword offset 0_F3 */
-
-#define GREEN_X_INC__ALIAS__	0x03CC	/* Dword offset 0_F3 */
-#define GREEN_Y_INC		0x03D0	/* Dword offset 0_F4 */
-
-#define SECONDARY_SCALE_Y_INC	0x03D0	/* Dword offset 0_F4 */
-#define SECONDARY_SCALE_VACC	0x03D4	/* Dword offset 0_F5 */
-
-#define GREEN_START		0x03D4	/* Dword offset 0_F5 */
-#define BLUE_X_INC		0x03D8	/* Dword offset 0_F6 */
-#define BLUE_Y_INC		0x03DC	/* Dword offset 0_F7 */
-#define BLUE_START		0x03E0	/* Dword offset 0_F8 */
-#define Z_X_INC			0x03E4	/* Dword offset 0_F9 */
-#define Z_Y_INC			0x03E8	/* Dword offset 0_FA */
-#define Z_START			0x03EC	/* Dword offset 0_FB */
-#define ALPHA_X_INC		0x03F0	/* Dword offset 0_FC */
-#define FOG_X_INC		0x03F0	/* Dword offset 0_FC */
-#define ALPHA_Y_INC		0x03F4	/* Dword offset 0_FD */
-#define FOG_Y_INC		0x03F4	/* Dword offset 0_FD */
-#define ALPHA_START		0x03F8	/* Dword offset 0_FE */
-#define FOG_START		0x03F8	/* Dword offset 0_FE */
-
-#define OVERLAY_Y_X_START		0x0400	/* Dword offset 1_00 */
-#define OVERLAY_Y_X_END			0x0404	/* Dword offset 1_01 */
-#define OVERLAY_VIDEO_KEY_CLR		0x0408	/* Dword offset 1_02 */
-#define OVERLAY_VIDEO_KEY_MSK		0x040C	/* Dword offset 1_03 */
-#define OVERLAY_GRAPHICS_KEY_CLR	0x0410	/* Dword offset 1_04 */
-#define OVERLAY_GRAPHICS_KEY_MSK	0x0414	/* Dword offset 1_05 */
-#define OVERLAY_KEY_CNTL		0x0418	/* Dword offset 1_06 */
-
-#define OVERLAY_SCALE_INC	0x0420	/* Dword offset 1_08 */
-#define OVERLAY_SCALE_CNTL	0x0424	/* Dword offset 1_09 */
-#define SCALER_HEIGHT_WIDTH	0x0428	/* Dword offset 1_0A */
-#define SCALER_TEST		0x042C	/* Dword offset 1_0B */
-#define SCALER_BUF0_OFFSET	0x0434	/* Dword offset 1_0D */
-#define SCALER_BUF1_OFFSET	0x0438	/* Dword offset 1_0E */
-#define SCALE_BUF_PITCH		0x043C	/* Dword offset 1_0F */
-
-#define CAPTURE_START_END	0x0440	/* Dword offset 1_10 */
-#define CAPTURE_X_WIDTH		0x0444	/* Dword offset 1_11 */
-#define VIDEO_FORMAT		0x0448	/* Dword offset 1_12 */
-#define VBI_START_END		0x044C	/* Dword offset 1_13 */
-#define CAPTURE_CONFIG		0x0450	/* Dword offset 1_14 */
-#define TRIG_CNTL		0x0454	/* Dword offset 1_15 */
-
-#define OVERLAY_EXCLUSIVE_HORZ	0x0458	/* Dword offset 1_16 */
-#define OVERLAY_EXCLUSIVE_VERT	0x045C	/* Dword offset 1_17 */
-
-#define VAL_WIDTH		0x0460	/* Dword offset 1_18 */
-#define CAPTURE_DEBUG		0x0464	/* Dword offset 1_19 */
-#define VIDEO_SYNC_TEST		0x0468	/* Dword offset 1_1A */
-
-#define SNAPSHOT_VH_COUNTS	0x0470	/* Dword offset 1_1C */
-#define SNAPSHOT_F_COUNT	0x0474	/* Dword offset 1_1D */
-#define N_VIF_COUNT		0x0478	/* Dword offset 1_1E */
-#define SNAPSHOT_VIF_COUNT	0x047C	/* Dword offset 1_1F */
-
-#define CAPTURE_BUF0_OFFSET	0x0480	/* Dword offset 1_20 */
-#define CAPTURE_BUF1_OFFSET	0x0484	/* Dword offset 1_21 */
-#define CAPTURE_BUF_PITCH	0x0488	/* Dword offset 1_22 */
-
-#define MPP_CONFIG		0x04C0	/* Dword offset 1_30 */
-#define MPP_STROBE_SEQ		0x04C4	/* Dword offset 1_31 */
-#define MPP_ADDR		0x04C8	/* Dword offset 1_32 */
-#define MPP_DATA		0x04CC	/* Dword offset 1_33 */
-#define TVO_CNTL		0x0500	/* Dword offset 1_40 */
-
-#define CRT_HORZ_VERT_LOAD	0x0544	/* Dword offset 1_51 */
-
-#define AGP_BASE		0x0548	/* Dword offset 1_52 */
-#define AGP_CNTL		0x054C	/* Dword offset 1_53 */
-
-#define SCALER_COLOUR_CNTL	0x0550	/* Dword offset 1_54 */
-#define SCALER_H_COEFF0		0x0554	/* Dword offset 1_55 */
-#define SCALER_H_COEFF1		0x0558	/* Dword offset 1_56 */
-#define SCALER_H_COEFF2		0x055C	/* Dword offset 1_57 */
-#define SCALER_H_COEFF3		0x0560	/* Dword offset 1_58 */
-#define SCALER_H_COEFF4		0x0564	/* Dword offset 1_59 */
-
-#define GUI_CNTL		0x0578	/* Dword offset 1_5E */
-
-#define BM_FRAME_BUF_OFFSET	0x0580	/* Dword offset 1_60 */
-#define BM_SYSTEM_MEM_ADDR	0x0584	/* Dword offset 1_61 */
-#define BM_COMMAND		0x0588	/* Dword offset 1_62 */
-#define BM_STATUS		0x058C	/* Dword offset 1_63 */
-#define BM_GUI_TABLE		0x05B8	/* Dword offset 1_6E */
-#define BM_SYSTEM_TABLE		0x05BC	/* Dword offset 1_6F */
-
-#define SCALER_BUF0_OFFSET_U	0x05D4	/* Dword offset 1_75 */
-#define SCALER_BUF0_OFFSET_V	0x05D8	/* Dword offset 1_76 */
-#define SCALER_BUF1_OFFSET_U	0x05DC	/* Dword offset 1_77 */
-#define SCALER_BUF1_OFFSET_V	0x05E0	/* Dword offset 1_78 */
-
-#define VERTEX_1_S		0x0640	/* Dword offset 1_90 */
-#define VERTEX_1_T		0x0644	/* Dword offset 1_91 */
-#define VERTEX_1_W		0x0648	/* Dword offset 1_92 */
-#define VERTEX_1_SPEC_ARGB	0x064C	/* Dword offset 1_93 */
-#define VERTEX_1_Z		0x0650	/* Dword offset 1_94 */
-#define VERTEX_1_ARGB		0x0654	/* Dword offset 1_95 */
-#define VERTEX_1_X_Y		0x0658	/* Dword offset 1_96 */
-#define ONE_OVER_AREA		0x065C	/* Dword offset 1_97 */
-#define VERTEX_2_S		0x0660	/* Dword offset 1_98 */
-#define VERTEX_2_T		0x0664	/* Dword offset 1_99 */
-#define VERTEX_2_W		0x0668	/* Dword offset 1_9A */
-#define VERTEX_2_SPEC_ARGB	0x066C	/* Dword offset 1_9B */
-#define VERTEX_2_Z		0x0670	/* Dword offset 1_9C */
-#define VERTEX_2_ARGB		0x0674	/* Dword offset 1_9D */
-#define VERTEX_2_X_Y		0x0678	/* Dword offset 1_9E */
-#define ONE_OVER_AREA		0x065C	/* Dword offset 1_9F */
-#define VERTEX_3_S		0x0680	/* Dword offset 1_A0 */
-#define VERTEX_3_T		0x0684	/* Dword offset 1_A1 */
-#define VERTEX_3_W		0x0688	/* Dword offset 1_A2 */
-#define VERTEX_3_SPEC_ARGB	0x068C	/* Dword offset 1_A3 */
-#define VERTEX_3_Z		0x0690	/* Dword offset 1_A4 */
-#define VERTEX_3_ARGB		0x0694	/* Dword offset 1_A5 */
-#define VERTEX_3_X_Y		0x0698	/* Dword offset 1_A6 */
-#define ONE_OVER_AREA		0x065C	/* Dword offset 1_A7 */
-#define VERTEX_1_S		0x0640	/* Dword offset 1_AB */
-#define VERTEX_1_T		0x0644	/* Dword offset 1_AC */
-#define VERTEX_1_W		0x0648	/* Dword offset 1_AD */
-#define VERTEX_2_S		0x0660	/* Dword offset 1_AE */
-#define VERTEX_2_T		0x0664	/* Dword offset 1_AF */
-#define VERTEX_2_W		0x0668	/* Dword offset 1_B0 */
-#define VERTEX_3_SECONDARY_S	0x06C0	/* Dword offset 1_B0 */
-#define VERTEX_3_S		0x0680	/* Dword offset 1_B1 */
-#define VERTEX_3_SECONDARY_T	0x06C4	/* Dword offset 1_B1 */
-#define VERTEX_3_T		0x0684	/* Dword offset 1_B2 */
-#define VERTEX_3_SECONDARY_W	0x06C8	/* Dword offset 1_B2 */
-#define VERTEX_3_W		0x0688	/* Dword offset 1_B3 */
-#define VERTEX_1_SPEC_ARGB	0x064C	/* Dword offset 1_B4 */
-#define VERTEX_2_SPEC_ARGB	0x066C	/* Dword offset 1_B5 */
-#define VERTEX_3_SPEC_ARGB	0x068C	/* Dword offset 1_B6 */
-#define VERTEX_1_Z		0x0650	/* Dword offset 1_B7 */
-#define VERTEX_2_Z		0x0670	/* Dword offset 1_B8 */
-#define VERTEX_3_Z		0x0690	/* Dword offset 1_B9 */
-#define VERTEX_1_ARGB		0x0654	/* Dword offset 1_BA */
-#define VERTEX_2_ARGB		0x0674	/* Dword offset 1_BB */
-#define VERTEX_3_ARGB		0x0694	/* Dword offset 1_BC */
-#define VERTEX_1_X_Y		0x0658	/* Dword offset 1_BD */
-#define VERTEX_2_X_Y		0x0678	/* Dword offset 1_BE */
-#define VERTEX_3_X_Y		0x0698	/* Dword offset 1_BF */
-#define ONE_OVER_AREA_UC	0x0700	/* Dword offset 1_C0 */
-#define SETUP_CNTL		0x0704	/* Dword offset 1_C1 */
-#define VERTEX_1_SECONDARY_S	0x0728	/* Dword offset 1_CA */
-#define VERTEX_1_SECONDARY_T	0x072C	/* Dword offset 1_CB */
-#define VERTEX_1_SECONDARY_W	0x0730	/* Dword offset 1_CC */
-#define VERTEX_2_SECONDARY_S	0x0734	/* Dword offset 1_CD */
-#define VERTEX_2_SECONDARY_T	0x0738	/* Dword offset 1_CE */
-#define VERTEX_2_SECONDARY_W	0x073C	/* Dword offset 1_CF */
-
-#define GTC_3D_RESET_DELAY	3	/* 3D engine reset delay in ms */
-
-/* CRTC control values (mostly CRTC_GEN_CNTL) */
-
-#define CRTC_H_SYNC_NEG		0x00200000
-#define CRTC_V_SYNC_NEG		0x00200000
-
-#define CRTC_DBL_SCAN_EN	0x00000001
-#define CRTC_INTERLACE_EN	0x00000002
-#define CRTC_HSYNC_DIS		0x00000004
-#define CRTC_VSYNC_DIS		0x00000008
-#define CRTC_CSYNC_EN		0x00000010
-#define CRTC_PIX_BY_2_EN	0x00000020	/* unused on RAGE */
-#define CRTC_DISPLAY_DIS	0x00000040
-#define CRTC_VGA_XOVERSCAN	0x00000040
-
-#define CRTC_PIX_WIDTH_MASK	0x00000700
-#define CRTC_PIX_WIDTH_4BPP	0x00000100
-#define CRTC_PIX_WIDTH_8BPP	0x00000200
-#define CRTC_PIX_WIDTH_15BPP	0x00000300
-#define CRTC_PIX_WIDTH_16BPP	0x00000400
-#define CRTC_PIX_WIDTH_24BPP	0x00000500
-#define CRTC_PIX_WIDTH_32BPP	0x00000600
-
-#define CRTC_BYTE_PIX_ORDER	0x00000800
-#define CRTC_PIX_ORDER_MSN_LSN	0x00000000
-#define CRTC_PIX_ORDER_LSN_MSN	0x00000800
-
-#define CRTC_FIFO_LWM		0x000f0000
-
-#define VGA_128KAP_PAGING	0x00100000
-#define VFC_SYNC_TRISTATE	0x00200000
-#define CRTC_LOCK_REGS		0x00400000
-#define CRTC_SYNC_TRISTATE	0x00800000
-
-#define CRTC_EXT_DISP_EN	0x01000000
-#define CRTC_ENABLE		0x02000000
-#define CRTC_DISP_REQ_ENB	0x04000000
-#define VGA_ATI_LINEAR		0x08000000
-#define CRTC_VSYNC_FALL_EDGE	0x10000000
-#define VGA_TEXT_132		0x20000000
-#define VGA_XCRT_CNT_EN		0x40000000
-#define VGA_CUR_B_TEST		0x80000000
-
-#define CRTC_CRNT_VLINE		0x07f00000
-#define CRTC_VBLANK		0x00000001
-
-
-/* DAC control values */
-
-#define DAC_EXT_SEL_RS2		0x01
-#define DAC_EXT_SEL_RS3		0x02
-#define DAC_8BIT_EN		0x00000100
-#define DAC_PIX_DLY_MASK	0x00000600
-#define DAC_PIX_DLY_0NS		0x00000000
-#define DAC_PIX_DLY_2NS		0x00000200
-#define DAC_PIX_DLY_4NS		0x00000400
-#define DAC_BLANK_ADJ_MASK	0x00001800
-#define DAC_BLANK_ADJ_0		0x00000000
-#define DAC_BLANK_ADJ_1		0x00000800
-#define DAC_BLANK_ADJ_2		0x00001000
-
-
-/* Mix control values */
-
-#define MIX_NOT_DST		0x0000
-#define MIX_0			0x0001
-#define MIX_1			0x0002
-#define MIX_DST			0x0003
-#define MIX_NOT_SRC		0x0004
-#define MIX_XOR			0x0005
-#define MIX_XNOR		0x0006
-#define MIX_SRC			0x0007
-#define MIX_NAND		0x0008
-#define MIX_NOT_SRC_OR_DST	0x0009
-#define MIX_SRC_OR_NOT_DST	0x000a
-#define MIX_OR			0x000b
-#define MIX_AND			0x000c
-#define MIX_SRC_AND_NOT_DST	0x000d
-#define MIX_NOT_SRC_AND_DST	0x000e
-#define MIX_NOR			0x000f
-
-/* Maximum engine dimensions */
-#define ENGINE_MIN_X		0
-#define ENGINE_MIN_Y		0
-#define ENGINE_MAX_X		4095
-#define ENGINE_MAX_Y		16383
-
-/* Mach64 engine bit constants - these are typically ORed together */
-
-/* BUS_CNTL register constants */
-#define BUS_FIFO_ERR_ACK	0x00200000
-#define BUS_HOST_ERR_ACK	0x00800000
-
-/* GEN_TEST_CNTL register constants */
-#define GEN_OVR_OUTPUT_EN	0x20
-#define HWCURSOR_ENABLE		0x80
-#define GUI_ENGINE_ENABLE	0x100
-#define BLOCK_WRITE_ENABLE	0x200
-
-/* DSP_CONFIG register constants */
-#define DSP_XCLKS_PER_QW	0x00003fff
-#define DSP_LOOP_LATENCY	0x000f0000
-#define DSP_PRECISION		0x00700000
-
-/* DSP_ON_OFF register constants */
-#define DSP_OFF			0x000007ff
-#define DSP_ON			0x07ff0000
-
-/* CLOCK_CNTL register constants */
-#define CLOCK_SEL		0x0f
-#define CLOCK_DIV		0x30
-#define CLOCK_DIV1		0x00
-#define CLOCK_DIV2		0x10
-#define CLOCK_DIV4		0x20
-#define CLOCK_STROBE		0x40
-#define PLL_WR_EN		0x02
-
-/* PLL registers */
-#define MPLL_CNTL		0x00
-#define VPLL_CNTL		0x01
-#define PLL_REF_DIV		0x02
-#define PLL_GEN_CNTL		0x03
-#define MCLK_FB_DIV		0x04
-#define PLL_VCLK_CNTL		0x05
-#define VCLK_POST_DIV		0x06
-#define VCLK0_FB_DIV		0x07
-#define VCLK1_FB_DIV		0x08
-#define VCLK2_FB_DIV		0x09
-#define VCLK3_FB_DIV		0x0A
-#define PLL_EXT_CNTL		0x0B
-#define DLL_CNTL		0x0C
-#define VFC_CNTL		0x0D
-#define PLL_TEST_CTRL		0x0E
-#define PLL_TEST_COUNT		0x0F
-
-/* Fields in PLL registers */
-#define PLL_PC_GAIN		0x07
-#define PLL_VC_GAIN		0x18
-#define PLL_DUTY_CYC		0xE0
-#define PLL_OVERRIDE		0x01
-#define PLL_MCLK_RST		0x02
-#define OSC_EN			0x04
-#define EXT_CLK_EN		0x08
-#define MCLK_SRC_SEL		0x70
-#define EXT_CLK_CNTL		0x80
-#define VCLK_SRC_SEL		0x03
-#define PLL_VCLK_RST		0x04
-#define VCLK_INVERT		0x08
-#define VCLK0_POST		0x03
-#define VCLK1_POST		0x0C
-#define VCLK2_POST		0x30
-#define VCLK3_POST		0xC0
-
-/* CONFIG_CNTL register constants */
-#define APERTURE_4M_ENABLE	1
-#define APERTURE_8M_ENABLE	2
-#define VGA_APERTURE_ENABLE	4
-
-/* CONFIG_STAT0 register constants (GX, CX) */
-#define CFG_BUS_TYPE		0x00000007
-#define CFG_MEM_TYPE		0x00000038
-#define CFG_INIT_DAC_TYPE	0x00000e00
-
-/* CONFIG_STAT0 register constants (CT, ET, VT) */
-#define CFG_MEM_TYPE_xT		0x00000007
-
-#define ISA			0
-#define EISA			1
-#define LOCAL_BUS		6
-#define PCI			7
-
-/* Memory types for GX, CX */
-#define DRAMx4			0
-#define VRAMx16			1
-#define VRAMx16ssr		2
-#define DRAMx16			3
-#define GraphicsDRAMx16		4
-#define EnhancedVRAMx16		5
-#define EnhancedVRAMx16ssr	6
-
-/* Memory types for CT, ET, VT, GT */
-#define DRAM			1
-#define EDO			2
-#define PSEUDO_EDO		3
-#define SDRAM			4
-#define SGRAM			5
-#define WRAM			6
-
-#define DAC_INTERNAL		0x00
-#define DAC_IBMRGB514		0x01
-#define DAC_ATI68875		0x02
-#define DAC_TVP3026_A		0x72
-#define DAC_BT476		0x03
-#define DAC_BT481		0x04
-#define DAC_ATT20C491		0x14
-#define DAC_SC15026		0x24
-#define DAC_MU9C1880		0x34
-#define DAC_IMSG174		0x44
-#define DAC_ATI68860_B		0x05
-#define DAC_ATI68860_C		0x15
-#define DAC_TVP3026_B		0x75
-#define DAC_STG1700		0x06
-#define DAC_ATT498		0x16
-#define DAC_STG1702		0x07
-#define DAC_SC15021		0x17
-#define DAC_ATT21C498		0x27
-#define DAC_STG1703		0x37
-#define DAC_CH8398		0x47
-#define DAC_ATT20C408		0x57
-
-#define CLK_ATI18818_0		0
-#define CLK_ATI18818_1		1
-#define CLK_STG1703		2
-#define CLK_CH8398		3
-#define CLK_INTERNAL		4
-#define CLK_ATT20C408		5
-#define CLK_IBMRGB514		6
-
-/* MEM_CNTL register constants */
-#define MEM_SIZE_ALIAS		0x00000007
-#define MEM_SIZE_512K		0x00000000
-#define MEM_SIZE_1M		0x00000001
-#define MEM_SIZE_2M		0x00000002
-#define MEM_SIZE_4M		0x00000003
-#define MEM_SIZE_6M		0x00000004
-#define MEM_SIZE_8M		0x00000005
-#define MEM_SIZE_ALIAS_GTB	0x0000000F
-#define MEM_SIZE_2M_GTB		0x00000003
-#define MEM_SIZE_4M_GTB		0x00000007
-#define MEM_SIZE_6M_GTB		0x00000009
-#define MEM_SIZE_8M_GTB		0x0000000B
-#define MEM_BNDRY		0x00030000
-#define MEM_BNDRY_0K		0x00000000
-#define MEM_BNDRY_256K		0x00010000
-#define MEM_BNDRY_512K		0x00020000
-#define MEM_BNDRY_1M		0x00030000
-#define MEM_BNDRY_EN		0x00040000
-
-/* ATI PCI constants */
-#define PCI_ATI_VENDOR_ID	0x1002
-
-
-/* CONFIG_CHIP_ID register constants */
-#define CFG_CHIP_TYPE		0x0000FFFF
-#define CFG_CHIP_CLASS		0x00FF0000
-#define CFG_CHIP_REV		0xFF000000
-#define CFG_CHIP_MAJOR		0x07000000
-#define CFG_CHIP_FND_ID		0x38000000
-#define CFG_CHIP_MINOR		0xC0000000
-
-
-/* Chip IDs read from CONFIG_CHIP_ID */
-
-/* mach64GX family */
-#define GX_CHIP_ID	0xD7	/* mach64GX (ATI888GX00) */
-#define CX_CHIP_ID	0x57	/* mach64CX (ATI888CX00) */
-
-#define GX_PCI_ID	0x4758	/* mach64GX (ATI888GX00) */
-#define CX_PCI_ID	0x4358	/* mach64CX (ATI888CX00) */
-
-/* mach64CT family */
-#define CT_CHIP_ID	0x4354	/* mach64CT (ATI264CT) */
-#define ET_CHIP_ID	0x4554	/* mach64ET (ATI264ET) */
-
-/* mach64CT family / mach64VT class */
-#define VT_CHIP_ID	0x5654	/* mach64VT (ATI264VT) */
-#define VU_CHIP_ID	0x5655	/* mach64VTB (ATI264VTB) */
-#define VV_CHIP_ID	0x5656	/* mach64VT4 (ATI264VT4) */
-
-/* mach64CT family / mach64GT (3D RAGE) class */
-#define LB_CHIP_ID	0x4c42	/* RAGE LT PRO, AGP */
-#define LD_CHIP_ID	0x4c44	/* RAGE LT PRO */
-#define LG_CHIP_ID	0x4c47	/* RAGE LT */
-#define LI_CHIP_ID	0x4c49	/* RAGE LT PRO */
-#define LP_CHIP_ID	0x4c50	/* RAGE LT PRO */
-#define LT_CHIP_ID	0x4c54	/* RAGE LT */
-#define XL_CHIP_ID	0x4752	/* RAGE (XL) */
-#define GT_CHIP_ID	0x4754	/* RAGE (GT) */
-#define GU_CHIP_ID	0x4755	/* RAGE II/II+ (GTB) */
-#define GV_CHIP_ID	0x4756	/* RAGE IIC, PCI */
-#define GW_CHIP_ID	0x4757	/* RAGE IIC, AGP */
-#define GZ_CHIP_ID	0x475a	/* RAGE IIC, AGP */
-#define GB_CHIP_ID	0x4742	/* RAGE PRO, BGA, AGP 1x and 2x */
-#define GD_CHIP_ID	0x4744	/* RAGE PRO, BGA, AGP 1x only */
-#define GI_CHIP_ID	0x4749	/* RAGE PRO, BGA, PCI33 only */
-#define GP_CHIP_ID	0x4750	/* RAGE PRO, PQFP, PCI33, full 3D */
-#define GQ_CHIP_ID	0x4751	/* RAGE PRO, PQFP, PCI33, limited 3D */
-#define LM_CHIP_ID	0x4c4d	/* RAGE Mobility PCI */
-#define LN_CHIP_ID	0x4c4e	/* RAGE Mobility AGP */
-
-
-/* Mach64 major ASIC revisions */
-#define MACH64_ASIC_NEC_VT_A3		0x08
-#define MACH64_ASIC_NEC_VT_A4		0x48
-#define MACH64_ASIC_SGS_VT_A4		0x40
-#define MACH64_ASIC_SGS_VT_B1S1		0x01
-#define MACH64_ASIC_SGS_GT_B1S1		0x01
-#define MACH64_ASIC_SGS_GT_B1S2		0x41
-#define MACH64_ASIC_UMC_GT_B2U1		0x1a
-#define MACH64_ASIC_UMC_GT_B2U2		0x5a
-#define MACH64_ASIC_UMC_VT_B2U3		0x9a
-#define MACH64_ASIC_UMC_GT_B2U3		0x9a
-#define MACH64_ASIC_UMC_R3B_D_P_A1	0x1b
-#define MACH64_ASIC_UMC_R3B_D_P_A2	0x5b
-#define MACH64_ASIC_UMC_R3B_D_P_A3	0x1c
-#define MACH64_ASIC_UMC_R3B_D_P_A4	0x5c
-
-/* Mach64 foundries */
-#define MACH64_FND_SGS		0
-#define MACH64_FND_NEC		1
-#define MACH64_FND_UMC		3
-
-/* Mach64 chip types */
-#define MACH64_UNKNOWN		0
-#define MACH64_GX		1
-#define MACH64_CX		2
-#define MACH64_CT		3
-#define MACH64_ET		4
-#define MACH64_VT		5
-#define MACH64_GT		6
-
-/* DST_CNTL register constants */
-#define DST_X_RIGHT_TO_LEFT	0
-#define DST_X_LEFT_TO_RIGHT	1
-#define DST_Y_BOTTOM_TO_TOP	0
-#define DST_Y_TOP_TO_BOTTOM	2
-#define DST_X_MAJOR		0
-#define DST_Y_MAJOR		4
-#define DST_X_TILE		8
-#define DST_Y_TILE		0x10
-#define DST_LAST_PEL		0x20
-#define DST_POLYGON_ENABLE	0x40
-#define DST_24_ROTATION_ENABLE	0x80
-
-/* SRC_CNTL register constants */
-#define SRC_PATTERN_ENABLE		1
-#define SRC_ROTATION_ENABLE		2
-#define SRC_LINEAR_ENABLE		4
-#define SRC_BYTE_ALIGN			8
-#define SRC_LINE_X_RIGHT_TO_LEFT	0
-#define SRC_LINE_X_LEFT_TO_RIGHT	0x10
-
-/* HOST_CNTL register constants */
-#define HOST_BYTE_ALIGN		1
-
-/* GUI_TRAJ_CNTL register constants */
-#define PAT_MONO_8x8_ENABLE	0x01000000
-#define PAT_CLR_4x2_ENABLE	0x02000000
-#define PAT_CLR_8x1_ENABLE	0x04000000
-
-/* DP_CHAIN_MASK register constants */
-#define DP_CHAIN_4BPP		0x8888
-#define DP_CHAIN_7BPP		0xD2D2
-#define DP_CHAIN_8BPP		0x8080
-#define DP_CHAIN_8BPP_RGB	0x9292
-#define DP_CHAIN_15BPP		0x4210
-#define DP_CHAIN_16BPP		0x8410
-#define DP_CHAIN_24BPP		0x8080
-#define DP_CHAIN_32BPP		0x8080
-
-/* DP_PIX_WIDTH register constants */
-#define DST_1BPP		0
-#define DST_4BPP		1
-#define DST_8BPP		2
-#define DST_15BPP		3
-#define DST_16BPP		4
-#define DST_32BPP		6
-#define SRC_1BPP		0
-#define SRC_4BPP		0x100
-#define SRC_8BPP		0x200
-#define SRC_15BPP		0x300
-#define SRC_16BPP		0x400
-#define SRC_32BPP		0x600
-#define HOST_1BPP		0
-#define HOST_4BPP		0x10000
-#define HOST_8BPP		0x20000
-#define HOST_15BPP		0x30000
-#define HOST_16BPP		0x40000
-#define HOST_32BPP		0x60000
-#define BYTE_ORDER_MSB_TO_LSB	0
-#define BYTE_ORDER_LSB_TO_MSB	0x1000000
-
-/* DP_MIX register constants */
-#define BKGD_MIX_NOT_D			0
-#define BKGD_MIX_ZERO			1
-#define BKGD_MIX_ONE			2
-#define BKGD_MIX_D			3
-#define BKGD_MIX_NOT_S			4
-#define BKGD_MIX_D_XOR_S		5
-#define BKGD_MIX_NOT_D_XOR_S		6
-#define BKGD_MIX_S			7
-#define BKGD_MIX_NOT_D_OR_NOT_S		8
-#define BKGD_MIX_D_OR_NOT_S		9
-#define BKGD_MIX_NOT_D_OR_S		10
-#define BKGD_MIX_D_OR_S			11
-#define BKGD_MIX_D_AND_S		12
-#define BKGD_MIX_NOT_D_AND_S		13
-#define BKGD_MIX_D_AND_NOT_S		14
-#define BKGD_MIX_NOT_D_AND_NOT_S	15
-#define BKGD_MIX_D_PLUS_S_DIV2		0x17
-#define FRGD_MIX_NOT_D			0
-#define FRGD_MIX_ZERO			0x10000
-#define FRGD_MIX_ONE			0x20000
-#define FRGD_MIX_D			0x30000
-#define FRGD_MIX_NOT_S			0x40000
-#define FRGD_MIX_D_XOR_S		0x50000
-#define FRGD_MIX_NOT_D_XOR_S		0x60000
-#define FRGD_MIX_S			0x70000
-#define FRGD_MIX_NOT_D_OR_NOT_S		0x80000
-#define FRGD_MIX_D_OR_NOT_S		0x90000
-#define FRGD_MIX_NOT_D_OR_S		0xa0000
-#define FRGD_MIX_D_OR_S			0xb0000
-#define FRGD_MIX_D_AND_S		0xc0000
-#define FRGD_MIX_NOT_D_AND_S		0xd0000
-#define FRGD_MIX_D_AND_NOT_S		0xe0000
-#define FRGD_MIX_NOT_D_AND_NOT_S	0xf0000
-#define FRGD_MIX_D_PLUS_S_DIV2		0x170000
-
-/* DP_SRC register constants */
-#define BKGD_SRC_BKGD_CLR	0
-#define BKGD_SRC_FRGD_CLR	1
-#define BKGD_SRC_HOST		2
-#define BKGD_SRC_BLIT		3
-#define BKGD_SRC_PATTERN	4
-#define FRGD_SRC_BKGD_CLR	0
-#define FRGD_SRC_FRGD_CLR	0x100
-#define FRGD_SRC_HOST		0x200
-#define FRGD_SRC_BLIT		0x300
-#define FRGD_SRC_PATTERN	0x400
-#define MONO_SRC_ONE		0
-#define MONO_SRC_PATTERN	0x10000
-#define MONO_SRC_HOST		0x20000
-#define MONO_SRC_BLIT		0x30000
-
-/* CLR_CMP_CNTL register constants */
-#define COMPARE_FALSE		0
-#define COMPARE_TRUE		1
-#define COMPARE_NOT_EQUAL	4
-#define COMPARE_EQUAL		5
-#define COMPARE_DESTINATION	0
-#define COMPARE_SOURCE		0x1000000
-
-/* FIFO_STAT register constants */
-#define FIFO_ERR		0x80000000
-
-/* CONTEXT_LOAD_CNTL constants */
-#define CONTEXT_NO_LOAD			0
-#define CONTEXT_LOAD			0x10000
-#define CONTEXT_LOAD_AND_DO_FILL	0x20000
-#define CONTEXT_LOAD_AND_DO_LINE	0x30000
-#define CONTEXT_EXECUTE			0
-#define CONTEXT_CMD_DISABLE		0x80000000
-
-/* GUI_STAT register constants */
-#define ENGINE_IDLE		0
-#define ENGINE_BUSY		1
-#define SCISSOR_LEFT_FLAG	0x10
-#define SCISSOR_RIGHT_FLAG	0x20
-#define SCISSOR_TOP_FLAG	0x40
-#define SCISSOR_BOTTOM_FLAG	0x80
-
-/* ATI VGA Extended Regsiters */
-#define sioATIEXT		0x1ce
-#define bioATIEXT		0x3ce
-
-#define ATI2E			0xae
-#define ATI32			0xb2
-#define ATI36			0xb6
-
-/* VGA Graphics Controller Registers */
-#define VGAGRA			0x3ce
-#define GRA06			0x06
-
-/* VGA Seququencer Registers */
-#define VGASEQ			0x3c4
-#define SEQ02			0x02
-#define SEQ04			0x04
-
-#define MACH64_MAX_X		ENGINE_MAX_X
-#define MACH64_MAX_Y		ENGINE_MAX_Y
-
-#define INC_X			0x0020
-#define INC_Y			0x0080
-
-#define RGB16_555		0x0000
-#define RGB16_565		0x0040
-#define RGB16_655		0x0080
-#define RGB16_664		0x00c0
-
-#define POLY_TEXT_TYPE		0x0001
-#define IMAGE_TEXT_TYPE		0x0002
-#define TEXT_TYPE_8_BIT		0x0004
-#define TEXT_TYPE_16_BIT	0x0008
-#define POLY_TEXT_TYPE_8	(POLY_TEXT_TYPE | TEXT_TYPE_8_BIT)
-#define IMAGE_TEXT_TYPE_8	(IMAGE_TEXT_TYPE | TEXT_TYPE_8_BIT)
-#define POLY_TEXT_TYPE_16	(POLY_TEXT_TYPE | TEXT_TYPE_16_BIT)
-#define IMAGE_TEXT_TYPE_16	(IMAGE_TEXT_TYPE | TEXT_TYPE_16_BIT)
-
-#define MACH64_NUM_CLOCKS	16
-#define MACH64_NUM_FREQS	50
-
-/* Power Management register constants (LT & LT Pro) */
-#define PWR_MGT_ON		0x00000001
-#define PWR_MGT_MODE_MASK	0x00000006
-#define AUTO_PWR_UP		0x00000008
-#define USE_F32KHZ		0x00000400
-#define TRISTATE_MEM_EN		0x00000800
-#define SELF_REFRESH		0x00000080
-#define PWR_BLON		0x02000000
-#define STANDBY_NOW		0x10000000
-#define SUSPEND_NOW		0x20000000
-#define PWR_MGT_STATUS_MASK	0xC0000000
-#define PWR_MGT_STATUS_SUSPEND	0x80000000
-
-/* PM Mode constants  */
-#define PWR_MGT_MODE_PIN	0x00000000
-#define PWR_MGT_MODE_REG	0x00000002
-#define PWR_MGT_MODE_TIMER	0x00000004
-#define PWR_MGT_MODE_PCI	0x00000006
-
-/* LCD registers (LT Pro) */
-
-/* LCD Index register */
-#define LCD_INDEX_MASK		0x0000003F
-#define LCD_DISPLAY_DIS		0x00000100
-#define LCD_SRC_SEL		0x00000200
-#define CRTC2_DISPLAY_DIS	0x00000400
-
-/* LCD register indices */
-#define LCD_CONFIG_PANEL	0x00
-#define LCD_GEN_CTRL		0x01
-#define LCD_DSTN_CONTROL	0x02
-#define LCD_HFB_PITCH_ADDR	0x03
-#define LCD_HORZ_STRETCHING	0x04
-#define LCD_VERT_STRETCHING	0x05
-#define LCD_EXT_VERT_STRETCH	0x06
-#define LCD_LT_GIO		0x07
-#define LCD_POWER_MANAGEMENT	0x08
-#define LCD_ZVGPIO		0x09
-#define LCD_MISC_CNTL		0x14
-
-/* Values in LCD_MISC_CNTL */
-#define BIAS_MOD_LEVEL_MASK	0x0000ff00
-#define BIAS_MOD_LEVEL_SHIFT	8
-#define BLMOD_EN		0x00010000
-#define BIASMOD_EN		0x00020000
-
-#endif /* REGMACH64_H */
diff -u --recursive --new-file v2.4.7/linux/drivers/video/atyfb.c linux/drivers/video/atyfb.c
--- v2.4.7/linux/drivers/video/atyfb.c	Tue Jul  3 17:08:21 2001
+++ linux/drivers/video/atyfb.c	Wed Dec 31 16:00:00 1969
@@ -1,5049 +0,0 @@
-/*  $Id: atyfb.c,v 1.147 2000/08/29 07:01:56 davem Exp $
- *  linux/drivers/video/atyfb.c -- Frame buffer device for ATI Mach64
- *
- *	Copyright (C) 1997-1998  Geert Uytterhoeven
- *	Copyright (C) 1998  Bernd Harries
- *	Copyright (C) 1998  Eddie C. Dost  (ecd@skynet.be)
- *
- *  This driver is partly based on the PowerMac console driver:
- *
- *	Copyright (C) 1996 Paul Mackerras
- *
- *  and on the PowerMac ATI/mach64 display driver:
- *
- *	Copyright (C) 1997 Michael AK Tesch
- *
- *	      with work by Jon Howell
- *			   Harry AC Eaton
- *			   Anthony Tong <atong@uiuc.edu>
- *
- *  This file is subject to the terms and conditions of the GNU General Public
- *  License. See the file COPYING in the main directory of this archive for
- *  more details.
- *  
- *  Many thanks to Nitya from ATI devrel for support and patience !
- */
-
-/******************************************************************************
-
-  TODO:
-
-    - cursor support on all cards and all ramdacs.
-    - cursor parameters controlable via ioctl()s.
-    - guess PLL and MCLK based on the original PLL register values initialized
-      by the BIOS or Open Firmware (if they are initialized).
-
-						(Anyone to help with this?)
-
-******************************************************************************/
-
-
-#include <linux/config.h>
-#include <linux/module.h>
-#include <linux/kernel.h>
-#include <linux/errno.h>
-#include <linux/string.h>
-#include <linux/mm.h>
-#include <linux/tty.h>
-#include <linux/slab.h>
-#include <linux/vmalloc.h>
-#include <linux/delay.h>
-#include <linux/interrupt.h>
-#include <linux/fb.h>
-#include <linux/selection.h>
-#include <linux/console.h>
-#include <linux/init.h>
-#include <linux/pci.h>
-#include <linux/kd.h>
-#include <linux/vt_kern.h>
-
-#ifdef CONFIG_FB_COMPAT_XPMAC
-#include <asm/vc_ioctl.h>
-#endif
-
-#include <asm/io.h>
-
-#ifdef __powerpc__
-#include <linux/adb.h>
-#include <asm/prom.h>
-#include <asm/pci-bridge.h>
-#include <video/macmodes.h>
-#endif
-#ifdef CONFIG_ADB_PMU
-#include <linux/pmu.h>
-#endif
-#ifdef CONFIG_NVRAM
-#include <linux/nvram.h>
-#endif
-#ifdef CONFIG_PMAC_BACKLIGHT
-#include <asm/backlight.h>
-#endif
-
-#ifdef __sparc__
-#include <asm/pbm.h>
-#include <asm/fbio.h>
-#endif
-#include <asm/uaccess.h>
-
-#include <video/fbcon.h>
-#include <video/fbcon-cfb8.h>
-#include <video/fbcon-cfb16.h>
-#include <video/fbcon-cfb24.h>
-#include <video/fbcon-cfb32.h>
-
-#include "aty.h"
-
-
-/*
- * Debug flags.
- */
-#undef DEBUG
-
-/* Definitions for the ICS 2595 == ATI 18818_1 Clockchip */
-
-#define REF_FREQ_2595       1432  /*  14.33 MHz  (exact   14.31818) */
-#define REF_DIV_2595          46  /* really 43 on ICS 2595 !!!  */
-                                  /* ohne Prescaler */
-#define MAX_FREQ_2595      15938  /* 159.38 MHz  (really 170.486) */
-#define MIN_FREQ_2595       8000  /*  80.00 MHz  (        85.565) */
-                                  /* mit Prescaler 2, 4, 8 */
-#define ABS_MIN_FREQ_2595   1000  /*  10.00 MHz  (really  10.697) */
-#define N_ADJ_2595           257
-
-#define STOP_BITS_2595     0x1800
-
-
-#define MIN_N_408		2
-
-#define MIN_N_1703		6
-
-#define MIN_M		2
-#define MAX_M		30
-#define MIN_N		35
-#define MAX_N		255-8
-
-
-/* Make sure n * PAGE_SIZE is protected at end of Aperture for GUI-regs */
-/*  - must be large enough to catch all GUI-Regs   */
-/*  - must be aligned to a PAGE boundary           */
-#define GUI_RESERVE	(1 * PAGE_SIZE)
-
-
-/* FIXME: remove the FAIL definition */
-#define FAIL(x) do { printk(x "\n"); return -EINVAL; } while (0)
-
-
-    /*
-     *  Elements of the Hardware specific atyfb_par structure
-     */
-
-struct crtc {
-    u32 vxres;
-    u32 vyres;
-    u32 xoffset;
-    u32 yoffset;
-    u32 bpp;
-    u32 h_tot_disp;
-    u32 h_sync_strt_wid;
-    u32 v_tot_disp;
-    u32 v_sync_strt_wid;
-    u32 off_pitch;
-    u32 gen_cntl;
-    u32 dp_pix_width;	/* acceleration */
-    u32 dp_chain_mask;	/* acceleration */
-};
-
-struct pll_gx {
-    u8 m;
-    u8 n;
-};
-
-struct pll_18818
-{
-    u32 program_bits;
-    u32 locationAddr;
-    u32 period_in_ps;
-    u32 post_divider;
-};
-
-struct pll_ct {
-    u8 pll_ref_div;
-    u8 pll_gen_cntl;
-    u8 mclk_fb_div;
-    u8 pll_vclk_cntl;
-    u8 vclk_post_div;
-    u8 vclk_fb_div;
-    u8 pll_ext_cntl;
-    u32 dsp_config;	/* Mach64 GTB DSP */
-    u32 dsp_on_off;	/* Mach64 GTB DSP */
-    u8 mclk_post_div_real;
-    u8 vclk_post_div_real;
-};
-
-
-    /*
-     *  The Hardware parameters for each card
-     */
-
-struct atyfb_par {
-    struct crtc crtc;
-    union {
-	struct pll_gx gx;
-	struct pll_ct ct;
-	struct pll_18818 ics2595;
-    } pll;
-    u32 accel_flags;
-};
-
-struct aty_cmap_regs {
-    u8 windex;
-    u8 lut;
-    u8 mask;
-    u8 rindex;
-    u8 cntl;
-};
-
-struct pci_mmap_map {
-    unsigned long voff;
-    unsigned long poff;
-    unsigned long size;
-    unsigned long prot_flag;
-    unsigned long prot_mask;
-};
-
-#define DEFAULT_CURSOR_BLINK_RATE	(20)
-#define CURSOR_DRAW_DELAY		(2)
-
-struct aty_cursor {
-    int	enable;
-    int on;
-    int vbl_cnt;
-    int blink_rate;
-    u32 offset;
-    struct {
-        u16 x, y;
-    } pos, hot, size;
-    u32 color[2];
-    u8 bits[8][64];
-    u8 mask[8][64];
-    u8 *ram;
-    struct timer_list *timer;
-};
-
-struct fb_info_aty {
-    struct fb_info fb_info;
-    struct fb_info_aty *next;
-    unsigned long ati_regbase_phys;
-    unsigned long ati_regbase;
-    unsigned long frame_buffer_phys;
-    unsigned long frame_buffer;
-    unsigned long clk_wr_offset;
-    struct pci_mmap_map *mmap_map;
-    struct aty_cursor *cursor;
-    struct aty_cmap_regs *aty_cmap_regs;
-    struct { u8 red, green, blue, pad; } palette[256];
-    struct atyfb_par default_par;
-    struct atyfb_par current_par;
-    u32 total_vram;
-    u32 ref_clk_per;
-    u32 pll_per;
-    u32 mclk_per;
-    u16 chip_type;
-#define Gx info->chip_type
-    u8 chip_rev;
-#define Rev info->chip_rev
-    u8 bus_type;
-    u8 ram_type;
-    u8 dac_type;
-    u8 dac_subtype;
-    u8 clk_type;
-    u8 mem_refresh_rate;
-    struct display disp;
-    struct display_switch dispsw;
-    union {
-#ifdef FBCON_HAS_CFB16
-	u16 cfb16[16];
-#endif
-#ifdef FBCON_HAS_CFB24
-	u32 cfb24[16];
-#endif
-#ifdef FBCON_HAS_CFB32
-	u32 cfb32[16];
-#endif
-    } fbcon_cmap;
-    u8 blitter_may_be_busy;
-#ifdef __sparc__
-    u8 mmaped;
-    int open;
-    int vtconsole;
-    int consolecnt;
-#endif
-#ifdef CONFIG_PMAC_PBOOK
-    unsigned char *save_framebuffer;
-    unsigned long save_pll[64];
-#endif
-};
-
-#ifdef CONFIG_PMAC_PBOOK
-  int aty_sleep_notify(struct pmu_sleep_notifier *self, int when);
-  static struct pmu_sleep_notifier aty_sleep_notifier = {
-  	aty_sleep_notify, SLEEP_LEVEL_VIDEO,
-  };
-  static struct fb_info_aty* first_display = NULL;
-#endif
-
-#ifdef CONFIG_PMAC_BACKLIGHT
-static int aty_set_backlight_enable(int on, int level, void* data);
-static int aty_set_backlight_level(int level, void* data);
-
-static struct backlight_controller aty_backlight_controller = {
-	aty_set_backlight_enable,
-	aty_set_backlight_level
-};
-#endif /* CONFIG_PMAC_BACKLIGHT */
-
-    /*
-     *  Frame buffer device API
-     */
-
-static int atyfb_open(struct fb_info *info, int user);
-static int atyfb_release(struct fb_info *info, int user);
-static int atyfb_get_fix(struct fb_fix_screeninfo *fix, int con,
-			 struct fb_info *fb);
-static int atyfb_get_var(struct fb_var_screeninfo *var, int con,
-			 struct fb_info *fb);
-static int atyfb_set_var(struct fb_var_screeninfo *var, int con,
-			 struct fb_info *fb);
-static int atyfb_pan_display(struct fb_var_screeninfo *var, int con,
-			     struct fb_info *fb);
-static int atyfb_get_cmap(struct fb_cmap *cmap, int kspc, int con,
-			  struct fb_info *info);
-static int atyfb_set_cmap(struct fb_cmap *cmap, int kspc, int con,
-			  struct fb_info *info);
-static int atyfb_ioctl(struct inode *inode, struct file *file, u_int cmd,
-		       u_long arg, int con, struct fb_info *info);
-#ifdef __sparc__
-static int atyfb_mmap(struct fb_info *info, struct file *file,
-		      struct vm_area_struct *vma);
-#endif
-static int atyfb_rasterimg(struct fb_info *info, int start);
-
-
-    /*
-     *  Interface to the low level console driver
-     */
-
-static int atyfbcon_switch(int con, struct fb_info *fb);
-static int atyfbcon_updatevar(int con, struct fb_info *fb);
-static void atyfbcon_blank(int blank, struct fb_info *fb);
-
-
-    /*
-     *  Text console acceleration
-     */
-
-static void fbcon_aty_bmove(struct display *p, int sy, int sx, int dy, int dx,
-			    int height, int width);
-static void fbcon_aty_clear(struct vc_data *conp, struct display *p, int sy,
-			    int sx, int height, int width);
-#ifdef FBCON_HAS_CFB8
-static struct display_switch fbcon_aty8;
-static void fbcon_aty8_putc(struct vc_data *conp, struct display *p, int c,
-			    int yy, int xx);
-static void fbcon_aty8_putcs(struct vc_data *conp, struct display *p,
-			     const unsigned short *s, int count, int yy,
-			     int xx);
-#endif
-#ifdef FBCON_HAS_CFB16
-static struct display_switch fbcon_aty16;
-static void fbcon_aty16_putc(struct vc_data *conp, struct display *p, int c,
-			     int yy, int xx);
-static void fbcon_aty16_putcs(struct vc_data *conp, struct display *p,
-			      const unsigned short *s, int count, int yy,
-			      int xx);
-#endif
-#ifdef FBCON_HAS_CFB24
-static struct display_switch fbcon_aty24;
-static void fbcon_aty24_putc(struct vc_data *conp, struct display *p, int c,
-			     int yy, int xx);
-static void fbcon_aty24_putcs(struct vc_data *conp, struct display *p,
-			      const unsigned short *s, int count, int yy,
-			      int xx);
-#endif
-#ifdef FBCON_HAS_CFB32
-static struct display_switch fbcon_aty32;
-static void fbcon_aty32_putc(struct vc_data *conp, struct display *p, int c,
-			     int yy, int xx);
-static void fbcon_aty32_putcs(struct vc_data *conp, struct display *p,
-			      const unsigned short *s, int count, int yy,
-			      int xx);
-#endif
-
-
-    /*
-     *  Internal routines
-     */
-
-static int aty_init(struct fb_info_aty *info, const char *name);
-static struct aty_cursor *aty_init_cursor(struct fb_info_aty *fb);
-#ifdef CONFIG_ATARI
-static int store_video_par(char *videopar, unsigned char m64_num);
-static char *strtoke(char *s, const char *ct);
-#endif
-
-static void reset_engine(const struct fb_info_aty *info);
-static void init_engine(const struct atyfb_par *par, struct fb_info_aty *info);
-
-static void aty_st_514(int offset, u8 val, const struct fb_info_aty *info);
-static void aty_st_pll(int offset, u8 val, const struct fb_info_aty *info);
-static u8 aty_ld_pll(int offset, const struct fb_info_aty *info);
-static void aty_set_crtc(const struct fb_info_aty *info,
-			 const struct crtc *crtc);
-static int aty_var_to_crtc(const struct fb_info_aty *info,
-			   const struct fb_var_screeninfo *var,
-			   struct crtc *crtc);
-static void aty_set_dac_514(const struct fb_info_aty *info, u32 bpp);
-static int aty_crtc_to_var(const struct crtc *crtc,
-			   struct fb_var_screeninfo *var);
-static void aty_set_pll_gx(const struct fb_info_aty *info,
-			   const struct pll_gx *pll);
-
-static int aty_set_dac_ATI68860_B(const struct fb_info_aty *info, u32 bpp,
-				  u32 AccelMode);
-static int aty_set_dac_ATT21C498(const struct fb_info_aty *info,
-				 const struct pll_18818 *pll, u32 bpp);
-void aty_dac_waste4(const struct fb_info_aty *info);
-
-static int aty_var_to_pll_18818(u32 period_in_ps, struct pll_18818 *pll);
-static u32 aty_pll_18818_to_var(const struct pll_18818 *pll);
-static void aty_set_pll18818(const struct fb_info_aty *info,
-			     const struct pll_18818 *pll);
-
-static void aty_StrobeClock(const struct fb_info_aty *info);
-
-static void aty_ICS2595_put1bit(u8 data, const struct fb_info_aty *info);
-
-static int aty_var_to_pll_408(u32 period_in_ps, struct pll_18818 *pll);
-static u32 aty_pll_408_to_var(const struct pll_18818 *pll);
-static void aty_set_pll_408(const struct fb_info_aty *info,
-			    const struct pll_18818 *pll);
-
-static int aty_var_to_pll_1703(u32 period_in_ps, struct pll_18818 *pll);
-static u32 aty_pll_1703_to_var(const struct pll_18818 *pll);
-static void aty_set_pll_1703(const struct fb_info_aty *info,
-			     const struct pll_18818 *pll);
-
-static int aty_var_to_pll_8398(u32 period_in_ps, struct pll_18818 *pll);
-static u32 aty_pll_8398_to_var(const struct pll_18818 *pll);
-static void aty_set_pll_8398(const struct fb_info_aty *info,
-			     const struct pll_18818 *pll);
-
-static int aty_var_to_pll_514(u32 vclk_per, struct pll_gx *pll);
-static u32 aty_pll_gx_to_var(const struct pll_gx *pll,
-			     const struct fb_info_aty *info);
-static void aty_set_pll_ct(const struct fb_info_aty *info,
-			   const struct pll_ct *pll);
-static int aty_valid_pll_ct(const struct fb_info_aty *info, u32 vclk_per,
-			    struct pll_ct *pll);
-static int aty_dsp_gt(const struct fb_info_aty *info, u8 bpp,
-		      struct pll_ct *pll);
-static void aty_calc_pll_ct(const struct fb_info_aty *info,
-			    struct pll_ct *pll);
-static int aty_var_to_pll_ct(const struct fb_info_aty *info, u32 vclk_per,
-			     u8 bpp, struct pll_ct *pll);
-static u32 aty_pll_ct_to_var(const struct pll_ct *pll,
-			     const struct fb_info_aty *info);
-static void atyfb_set_par(const struct atyfb_par *par,
-			  struct fb_info_aty *info);
-static int atyfb_decode_var(const struct fb_var_screeninfo *var,
-			    struct atyfb_par *par,
-			    const struct fb_info_aty *info);
-static int atyfb_encode_var(struct fb_var_screeninfo *var,
-			    const struct atyfb_par *par,
-			    const struct fb_info_aty *info);
-static void set_off_pitch(struct atyfb_par *par,
-			  const struct fb_info_aty *info);
-static int encode_fix(struct fb_fix_screeninfo *fix,
-		      const struct atyfb_par *par,
-		      const struct fb_info_aty *info);
-static void atyfb_set_dispsw(struct display *disp, struct fb_info_aty *info,
-			     int bpp, int accel);
-static int atyfb_getcolreg(u_int regno, u_int *red, u_int *green, u_int *blue,
-			 u_int *transp, struct fb_info *fb);
-static int atyfb_setcolreg(u_int regno, u_int red, u_int green, u_int blue,
-			 u_int transp, struct fb_info *fb);
-static void do_install_cmap(int con, struct fb_info *info);
-#ifdef CONFIG_PPC
-static int read_aty_sense(const struct fb_info_aty *info);
-#endif
-
-
-    /*
-     *  Interface used by the world
-     */
-
-int atyfb_init(void);
-#ifndef MODULE
-int atyfb_setup(char*);
-#endif
-
-static int currcon = 0;
-
-static struct fb_ops atyfb_ops = {
-	owner:		THIS_MODULE,
-	fb_open:	atyfb_open,
-	fb_release:	atyfb_release,
-	fb_get_fix:	atyfb_get_fix,
-	fb_get_var:	atyfb_get_var,
-	fb_set_var:	atyfb_set_var,
-	fb_get_cmap:	atyfb_get_cmap,
-	fb_set_cmap:	atyfb_set_cmap,
-	fb_pan_display:	atyfb_pan_display,
-	fb_ioctl:	atyfb_ioctl,
-#ifdef __sparc__
-	fb_mmap:	atyfb_mmap,
-#endif
-	fb_rasterimg:	atyfb_rasterimg,
-};
-
-static char atyfb_name[16] = "ATY Mach64";
-static char fontname[40] __initdata = { 0 };
-static char curblink __initdata = 1;
-static char noaccel __initdata = 0;
-static u32 default_vram __initdata = 0;
-static int default_pll __initdata = 0;
-static int default_mclk __initdata = 0;
-
-#ifndef MODULE
-static const char *mode_option __initdata = NULL;
-#endif
-
-#ifdef CONFIG_PPC
-#ifdef CONFIG_NVRAM_NOT_DEFINED
-static int default_vmode __initdata = VMODE_NVRAM;
-static int default_cmode __initdata = CMODE_NVRAM;
-#else
-static int default_vmode __initdata = VMODE_CHOOSE;
-static int default_cmode __initdata = CMODE_CHOOSE;
-#endif
-#endif
-
-#ifdef CONFIG_ATARI
-static unsigned int mach64_count __initdata = 0;
-static unsigned long phys_vmembase[FB_MAX] __initdata = { 0, };
-static unsigned long phys_size[FB_MAX] __initdata = { 0, };
-static unsigned long phys_guiregbase[FB_MAX] __initdata = { 0, };
-#endif
-
-
-static struct aty_features {
-    u16 pci_id;
-    u16 chip_type;
-    const char *name;
-} aty_features[] __initdata = {
-    /* mach64GX family */
-    { 0x4758, 0x00d7, "mach64GX (ATI888GX00)" },
-    { 0x4358, 0x0057, "mach64CX (ATI888CX00)" },
-
-    /* mach64CT family */
-    { 0x4354, 0x4354, "mach64CT (ATI264CT)" },
-    { 0x4554, 0x4554, "mach64ET (ATI264ET)" },
-
-    /* mach64CT family / mach64VT class */
-    { 0x5654, 0x5654, "mach64VT (ATI264VT)" },
-    { 0x5655, 0x5655, "mach64VTB (ATI264VTB)" },
-    { 0x5656, 0x5656, "mach64VT4 (ATI264VT4)" },
-
-    /* mach64CT family / mach64GT (3D RAGE) class */
-    { 0x4c42, 0x4c42, "3D RAGE LT PRO (AGP)" },
-    { 0x4c44, 0x4c44, "3D RAGE LT PRO" },
-    { 0x4c47, 0x4c47, "3D RAGE LT-G" },
-    { 0x4c49, 0x4c49, "3D RAGE LT PRO" },
-    { 0x4c50, 0x4c50, "3D RAGE LT PRO" },
-    { 0x4c54, 0x4c54, "3D RAGE LT" },
-    { 0x4752, 0x4752, "3D RAGE (XL)" },
-    { 0x4754, 0x4754, "3D RAGE (GT)" },
-    { 0x4755, 0x4755, "3D RAGE II+ (GTB)" },
-    { 0x4756, 0x4756, "3D RAGE IIC (PCI)" },
-    { 0x4757, 0x4757, "3D RAGE IIC (AGP)" },
-    { 0x475a, 0x475a, "3D RAGE IIC (AGP)" },
-    { 0x4742, 0x4742, "3D RAGE PRO (BGA, AGP)" },
-    { 0x4744, 0x4744, "3D RAGE PRO (BGA, AGP, 1x only)" },
-    { 0x4749, 0x4749, "3D RAGE PRO (BGA, PCI)" },
-    { 0x4750, 0x4750, "3D RAGE PRO (PQFP, PCI)" },
-    { 0x4751, 0x4751, "3D RAGE PRO (PQFP, PCI, limited 3D)" },
-    { 0x4c4d, 0x4c4d, "3D RAGE Mobility (PCI)" },
-    { 0x4c4e, 0x4c4e, "3D RAGE Mobility (AGP)" },
-};
-
-static const char *aty_gx_ram[8] __initdata = {
-    "DRAM", "VRAM", "VRAM", "DRAM", "DRAM", "VRAM", "VRAM", "RESV"
-};
-
-static const char *aty_ct_ram[8] __initdata = {
-    "OFF", "DRAM", "EDO", "EDO", "SDRAM", "SGRAM", "WRAM", "RESV"
-};
-
-
-static inline u32 aty_ld_le32(int regindex,
-			      const struct fb_info_aty *info)
-{
-    /* Hack for bloc 1, should be cleanly optimized by compiler */
-    if (regindex >= 0x400)
-    	regindex -= 0x800;
-
-#if defined(__mc68000__)
-    return le32_to_cpu(*((volatile u32 *)(info->ati_regbase+regindex)));
-#else
-    return readl (info->ati_regbase + regindex);
-#endif
-}
-
-static inline void aty_st_le32(int regindex, u32 val,
-			       const struct fb_info_aty *info)
-{
-    /* Hack for bloc 1, should be cleanly optimized by compiler */
-    if (regindex >= 0x400)
-    	regindex -= 0x800;
-
-#if defined(__mc68000__)
-    *((volatile u32 *)(info->ati_regbase+regindex)) = cpu_to_le32(val);
-#else
-    writel (val, info->ati_regbase + regindex);
-#endif
-}
-
-static inline u8 aty_ld_8(int regindex,
-			  const struct fb_info_aty *info)
-{
-    /* Hack for bloc 1, should be cleanly optimized by compiler */
-    if (regindex >= 0x400)
-    	regindex -= 0x800;
-
-    return readb (info->ati_regbase + regindex);
-}
-
-static inline void aty_st_8(int regindex, u8 val,
-			    const struct fb_info_aty *info)
-{
-    /* Hack for bloc 1, should be cleanly optimized by compiler */
-    if (regindex >= 0x400)
-    	regindex -= 0x800;
-
-    writeb (val, info->ati_regbase + regindex);
-}
-
-#if defined(CONFIG_PPC) || defined(CONFIG_PMAC_PBOOK)
-static void aty_st_lcd(int index, u32 val, const struct fb_info_aty *info)
-{
-    unsigned long temp;
-
-    /* write addr byte */
-    temp = aty_ld_le32(LCD_INDEX, info);
-    aty_st_le32(LCD_INDEX, (temp & ~LCD_INDEX_MASK) | index, info);
-    /* write the register value */
-    aty_st_le32(LCD_DATA, val, info);
-}
-
-static u32 aty_ld_lcd(int index, const struct fb_info_aty *info)
-{
-    unsigned long temp;
-
-    /* write addr byte */
-    temp = aty_ld_le32(LCD_INDEX, info);
-    aty_st_le32(LCD_INDEX, (temp & ~LCD_INDEX_MASK) | index, info);
-    /* read the register value */
-    return aty_ld_le32(LCD_DATA, info);
-}
-#endif
-
-    /*
-     *  Generic Mach64 routines
-     */
-
-    /*
-     *  All writes to draw engine registers are automatically routed through a
-     *  32-bit-wide, 16-entry-deep command FIFO ...
-     *  Register writes to registers with DWORD offsets less than 40h are not
-     *  FIFOed.
-     *  (from Chapter 5 of the Mach64 Programmer's Guide)
-     */
-
-static inline void wait_for_fifo(u16 entries, const struct fb_info_aty *info)
-{
-    while ((aty_ld_le32(FIFO_STAT, info) & 0xffff) >
-	   ((u32)(0x8000 >> entries)));
-}
-
-static inline void wait_for_idle(struct fb_info_aty *info)
-{
-    wait_for_fifo(16, info);
-    while ((aty_ld_le32(GUI_STAT, info) & 1)!= 0);
-    info->blitter_may_be_busy = 0;
-}
-
-static void reset_engine(const struct fb_info_aty *info)
-{
-    /* reset engine */
-    aty_st_le32(GEN_TEST_CNTL,
-		aty_ld_le32(GEN_TEST_CNTL, info) & ~GUI_ENGINE_ENABLE, info);
-    /* enable engine */
-    aty_st_le32(GEN_TEST_CNTL,
-		aty_ld_le32(GEN_TEST_CNTL, info) | GUI_ENGINE_ENABLE, info);
-    /* ensure engine is not locked up by clearing any FIFO or */
-    /* HOST errors */
-    aty_st_le32(BUS_CNTL, aty_ld_le32(BUS_CNTL, info) | BUS_HOST_ERR_ACK |
-			  BUS_FIFO_ERR_ACK, info);
-}
-
-static void reset_GTC_3D_engine(const struct fb_info_aty *info)
-{
-	aty_st_le32(SCALE_3D_CNTL, 0xc0, info);
-	mdelay(GTC_3D_RESET_DELAY);
-	aty_st_le32(SETUP_CNTL, 0x00, info);
-	mdelay(GTC_3D_RESET_DELAY);
-	aty_st_le32(SCALE_3D_CNTL, 0x00, info);
-	mdelay(GTC_3D_RESET_DELAY);
-}
-
-static void init_engine(const struct atyfb_par *par, struct fb_info_aty *info)
-{
-    u32 pitch_value;
-
-    /* determine modal information from global mode structure */
-    pitch_value = par->crtc.vxres;
-
-    if (par->crtc.bpp == 24) {
-	/* In 24 bpp, the engine is in 8 bpp - this requires that all */
-	/* horizontal coordinates and widths must be adjusted */
-	pitch_value = pitch_value * 3;
-    }
-
-    /* On GTC (RagePro), we need to reset the 3D engine before */
-    if (Gx == LB_CHIP_ID || Gx == LD_CHIP_ID || Gx == LI_CHIP_ID ||
-    	Gx == LP_CHIP_ID || Gx == GB_CHIP_ID || Gx == GD_CHIP_ID ||
-    	Gx == GI_CHIP_ID || Gx == GP_CHIP_ID || Gx == GQ_CHIP_ID ||
-    	Gx == LM_CHIP_ID || Gx == LN_CHIP_ID || Gx == XL_CHIP_ID)
-    	reset_GTC_3D_engine(info);
-
-    /* Reset engine, enable, and clear any engine errors */
-    reset_engine(info);
-    /* Ensure that vga page pointers are set to zero - the upper */
-    /* page pointers are set to 1 to handle overflows in the */
-    /* lower page */
-    aty_st_le32(MEM_VGA_WP_SEL, 0x00010000, info);
-    aty_st_le32(MEM_VGA_RP_SEL, 0x00010000, info);
-
-    /* ---- Setup standard engine context ---- */
-
-    /* All GUI registers here are FIFOed - therefore, wait for */
-    /* the appropriate number of empty FIFO entries */
-    wait_for_fifo(14, info);
-
-    /* enable all registers to be loaded for context loads */
-    aty_st_le32(CONTEXT_MASK, 0xFFFFFFFF, info);
-
-    /* set destination pitch to modal pitch, set offset to zero */
-    aty_st_le32(DST_OFF_PITCH, (pitch_value / 8) << 22, info);
-
-    /* zero these registers (set them to a known state) */
-    aty_st_le32(DST_Y_X, 0, info);
-    aty_st_le32(DST_HEIGHT, 0, info);
-    aty_st_le32(DST_BRES_ERR, 0, info);
-    aty_st_le32(DST_BRES_INC, 0, info);
-    aty_st_le32(DST_BRES_DEC, 0, info);
-
-    /* set destination drawing attributes */
-    aty_st_le32(DST_CNTL, DST_LAST_PEL | DST_Y_TOP_TO_BOTTOM |
-			  DST_X_LEFT_TO_RIGHT, info);
-
-    /* set source pitch to modal pitch, set offset to zero */
-    aty_st_le32(SRC_OFF_PITCH, (pitch_value / 8) << 22, info);
-
-    /* set these registers to a known state */
-    aty_st_le32(SRC_Y_X, 0, info);
-    aty_st_le32(SRC_HEIGHT1_WIDTH1, 1, info);
-    aty_st_le32(SRC_Y_X_START, 0, info);
-    aty_st_le32(SRC_HEIGHT2_WIDTH2, 1, info);
-
-    /* set source pixel retrieving attributes */
-    aty_st_le32(SRC_CNTL, SRC_LINE_X_LEFT_TO_RIGHT, info);
-
-    /* set host attributes */
-    wait_for_fifo(13, info);
-    aty_st_le32(HOST_CNTL, 0, info);
-
-    /* set pattern attributes */
-    aty_st_le32(PAT_REG0, 0, info);
-    aty_st_le32(PAT_REG1, 0, info);
-    aty_st_le32(PAT_CNTL, 0, info);
-
-    /* set scissors to modal size */
-    aty_st_le32(SC_LEFT, 0, info);
-    aty_st_le32(SC_TOP, 0, info);
-    aty_st_le32(SC_BOTTOM, par->crtc.vyres-1, info);
-    aty_st_le32(SC_RIGHT, pitch_value-1, info);
-
-    /* set background color to minimum value (usually BLACK) */
-    aty_st_le32(DP_BKGD_CLR, 0, info);
-
-    /* set foreground color to maximum value (usually WHITE) */
-    aty_st_le32(DP_FRGD_CLR, 0xFFFFFFFF, info);
-
-    /* set write mask to effect all pixel bits */
-    aty_st_le32(DP_WRITE_MASK, 0xFFFFFFFF, info);
-
-    /* set foreground mix to overpaint and background mix to */
-    /* no-effect */
-    aty_st_le32(DP_MIX, FRGD_MIX_S | BKGD_MIX_D, info);
-
-    /* set primary source pixel channel to foreground color */
-    /* register */
-    aty_st_le32(DP_SRC, FRGD_SRC_FRGD_CLR, info);
-
-    /* set compare functionality to false (no-effect on */
-    /* destination) */
-    wait_for_fifo(3, info);
-    aty_st_le32(CLR_CMP_CLR, 0, info);
-    aty_st_le32(CLR_CMP_MASK, 0xFFFFFFFF, info);
-    aty_st_le32(CLR_CMP_CNTL, 0, info);
-
-    /* set pixel depth */
-    wait_for_fifo(2, info);
-    aty_st_le32(DP_PIX_WIDTH, par->crtc.dp_pix_width, info);
-    aty_st_le32(DP_CHAIN_MASK, par->crtc.dp_chain_mask, info);
-
-    wait_for_fifo(5, info);
-    aty_st_le32(SCALE_3D_CNTL, 0, info);
-    aty_st_le32(Z_CNTL, 0, info);
-    aty_st_le32(CRTC_INT_CNTL, aty_ld_le32(CRTC_INT_CNTL, info) & ~0x20, info);
-    aty_st_le32(GUI_TRAJ_CNTL, 0x100023, info);
-
-    /* insure engine is idle before leaving */
-    wait_for_idle(info);
-}
-
-static void aty_st_514(int offset, u8 val, const struct fb_info_aty *info)
-{
-    aty_st_8(DAC_CNTL, 1, info);
-    /* right addr byte */
-    aty_st_8(DAC_W_INDEX, offset & 0xff, info);
-    /* left addr byte */
-    aty_st_8(DAC_DATA, (offset >> 8) & 0xff, info);
-    aty_st_8(DAC_MASK, val, info);
-    aty_st_8(DAC_CNTL, 0, info);
-}
-
-static void aty_st_pll(int offset, u8 val, const struct fb_info_aty *info)
-{
-    /* write addr byte */
-    aty_st_8(CLOCK_CNTL + 1, (offset << 2) | PLL_WR_EN, info);
-    /* write the register value */
-    aty_st_8(CLOCK_CNTL + 2, val, info);
-    aty_st_8(CLOCK_CNTL + 1, (offset << 2) & ~PLL_WR_EN, info);
-}
-
-static u8 aty_ld_pll(int offset, const struct fb_info_aty *info)
-{
-    u8 res;
-
-    /* write addr byte */
-    aty_st_8(CLOCK_CNTL + 1, (offset << 2), info);
-    /* read the register value */
-    res = aty_ld_8(CLOCK_CNTL + 2, info);
-    return res;
-}
-
-#if defined(CONFIG_PPC)
-
-    /*
-     *  Apple monitor sense
-     */
-
-static int read_aty_sense(const struct fb_info_aty *info)
-{
-    int sense, i;
-
-    aty_st_le32(GP_IO, 0x31003100, info);	/* drive outputs high */
-    __delay(200);
-    aty_st_le32(GP_IO, 0, info);		/* turn off outputs */
-    __delay(2000);
-    i = aty_ld_le32(GP_IO, info);		/* get primary sense value */
-    sense = ((i & 0x3000) >> 3) | (i & 0x100);
-
-    /* drive each sense line low in turn and collect the other 2 */
-    aty_st_le32(GP_IO, 0x20000000, info);	/* drive A low */
-    __delay(2000);
-    i = aty_ld_le32(GP_IO, info);
-    sense |= ((i & 0x1000) >> 7) | ((i & 0x100) >> 4);
-    aty_st_le32(GP_IO, 0x20002000, info);	/* drive A high again */
-    __delay(200);
-
-    aty_st_le32(GP_IO, 0x10000000, info);	/* drive B low */
-    __delay(2000);
-    i = aty_ld_le32(GP_IO, info);
-    sense |= ((i & 0x2000) >> 10) | ((i & 0x100) >> 6);
-    aty_st_le32(GP_IO, 0x10001000, info);	/* drive B high again */
-    __delay(200);
-
-    aty_st_le32(GP_IO, 0x01000000, info);	/* drive C low */
-    __delay(2000);
-    sense |= (aty_ld_le32(GP_IO, info) & 0x3000) >> 12;
-    aty_st_le32(GP_IO, 0, info);		/* turn off outputs */
-
-    return sense;
-}
-
-#endif /* defined(CONFIG_PPC) */
-
-/* ------------------------------------------------------------------------- */
-
-    /*
-     *  Hardware Cursor support.
-     */
-
-static u8 cursor_pixel_map[2] = { 0, 15 };
-static u8 cursor_color_map[2] = { 0, 0xff };
-
-static u8 cursor_bits_lookup[16] =
-{
-	0x00, 0x40, 0x10, 0x50, 0x04, 0x44, 0x14, 0x54,
-	0x01, 0x41, 0x11, 0x51, 0x05, 0x45, 0x15, 0x55
-};
-
-static u8 cursor_mask_lookup[16] =
-{
-	0xaa, 0x2a, 0x8a, 0x0a, 0xa2, 0x22, 0x82, 0x02,
-	0xa8, 0x28, 0x88, 0x08, 0xa0, 0x20, 0x80, 0x00
-};
-
-static void
-aty_set_cursor_color(struct fb_info_aty *fb, u8 *pixel,
-		     u8 *red, u8 *green, u8 *blue)
-{
-	struct aty_cursor *c = fb->cursor;
-	int i;
-
-	if (!c)
-		return;
-
-#ifdef __sparc__
-	if (fb->mmaped && (!fb->fb_info.display_fg
-	    || fb->fb_info.display_fg->vc_num == fb->vtconsole))
-		return;
-#endif
-
-	for (i = 0; i < 2; i++) {
-		c->color[i] =  (u32)red[i] << 24;
-		c->color[i] |= (u32)green[i] << 16;
- 		c->color[i] |= (u32)blue[i] <<  8;
- 		c->color[i] |= (u32)pixel[i];
-	}
-
-	wait_for_fifo(2, fb);
-	aty_st_le32(CUR_CLR0, c->color[0], fb);
-	aty_st_le32(CUR_CLR1, c->color[1], fb);
-}
-
-static void
-aty_set_cursor_shape(struct fb_info_aty *fb)
-{
-	struct aty_cursor *c = fb->cursor;
-	u8 *ram, m, b;
-	int x, y;
-
-	if (!c)
-		return;
-
-#ifdef __sparc__
-	if (fb->mmaped && (!fb->fb_info.display_fg
-	    || fb->fb_info.display_fg->vc_num == fb->vtconsole))
-		return;
-#endif
-
-	ram = c->ram;
-	for (y = 0; y < c->size.y; y++) {
-		for (x = 0; x < c->size.x >> 2; x++) {
-			m = c->mask[x][y];
-			b = c->bits[x][y];
-			fb_writeb (cursor_mask_lookup[m >> 4] |
-				   cursor_bits_lookup[(b & m) >> 4],
-				   ram++);
-			fb_writeb (cursor_mask_lookup[m & 0x0f] |
-				   cursor_bits_lookup[(b & m) & 0x0f],
-				   ram++);
-		}
-		for ( ; x < 8; x++) {
-			fb_writeb (0xaa, ram++);
-			fb_writeb (0xaa, ram++);
-		}
-	}
-	fb_memset (ram, 0xaa, (64 - c->size.y) * 16);
-}
-
-static void
-aty_set_cursor(struct fb_info_aty *fb, int on)
-{
-	struct atyfb_par *par = &fb->current_par;
-	struct aty_cursor *c = fb->cursor;
-	u16 xoff, yoff;
-	int x, y;
-
-	if (!c)
-		return;
-
-#ifdef __sparc__
-	if (fb->mmaped && (!fb->fb_info.display_fg
-	    || fb->fb_info.display_fg->vc_num == fb->vtconsole))
-		return;
-#endif
-
-	if (on) {
-		x = c->pos.x - c->hot.x - par->crtc.xoffset;
-		if (x < 0) {
-			xoff = -x;
-			x = 0;
-		} else {
-			xoff = 0;
-		}
-
-		y = c->pos.y - c->hot.y - par->crtc.yoffset;
-		if (y < 0) {
-			yoff = -y;
-			y = 0;
-		} else {
-			yoff = 0;
-		}
-
-		wait_for_fifo(4, fb);
-		aty_st_le32(CUR_OFFSET, (c->offset >> 3) + (yoff << 1), fb);
-		aty_st_le32(CUR_HORZ_VERT_OFF,
-			    ((u32)(64 - c->size.y + yoff) << 16) | xoff, fb);
-		aty_st_le32(CUR_HORZ_VERT_POSN, ((u32)y << 16) | x, fb);
-		aty_st_le32(GEN_TEST_CNTL, aty_ld_le32(GEN_TEST_CNTL, fb)
-						       | HWCURSOR_ENABLE, fb);
-	} else {
-		wait_for_fifo(1, fb);
-		aty_st_le32(GEN_TEST_CNTL,
-			    aty_ld_le32(GEN_TEST_CNTL, fb) & ~HWCURSOR_ENABLE,
-			    fb);
-	}
-	if (fb->blitter_may_be_busy)
-		wait_for_idle(fb);
-}
-
-static void
-aty_cursor_timer_handler(unsigned long dev_addr)
-{
-	struct fb_info_aty *fb = (struct fb_info_aty *)dev_addr;
-
-	if (!fb->cursor)
-		return;
-
-	if (!fb->cursor->enable)
-		goto out;
-
-	if (fb->cursor->vbl_cnt && --fb->cursor->vbl_cnt == 0) {
-		fb->cursor->on ^= 1;
-		aty_set_cursor(fb, fb->cursor->on);
-		fb->cursor->vbl_cnt = fb->cursor->blink_rate;
-	}
-
-out:
-	fb->cursor->timer->expires = jiffies + (HZ / 50);
-	add_timer(fb->cursor->timer);
-}
-
-static void
-atyfb_cursor(struct display *p, int mode, int x, int y)
-{
-	struct fb_info_aty *fb = (struct fb_info_aty *)p->fb_info;
-	struct aty_cursor *c = fb->cursor;
-
-	if (!c)
-		return;
-
-#ifdef __sparc__
-	if (fb->mmaped && (!fb->fb_info.display_fg
-	    || fb->fb_info.display_fg->vc_num == fb->vtconsole))
-		return;
-#endif
-
-	x *= fontwidth(p);
-	y *= fontheight(p);
-	if (c->pos.x == x && c->pos.y == y && (mode == CM_ERASE) == !c->enable)
-		return;
-
-	c->enable = 0;
-	if (c->on)
-		aty_set_cursor(fb, 0);
-	c->pos.x = x;
-	c->pos.y = y;
-
-	switch (mode) {
-	case CM_ERASE:
-		c->on = 0;
-		break;
-
-	case CM_DRAW:
-	case CM_MOVE:
-		if (c->on)
-			aty_set_cursor(fb, 1);
-		else
-			c->vbl_cnt = CURSOR_DRAW_DELAY;
-		c->enable = 1;
-		break;
-	}
-}
-
-static struct fb_info_aty *fb_list = NULL;
-
-static struct aty_cursor * __init
-aty_init_cursor(struct fb_info_aty *fb)
-{
-	struct aty_cursor *cursor;
-	unsigned long addr;
-
-	cursor = kmalloc(sizeof(struct aty_cursor), GFP_ATOMIC);
-	if (!cursor)
-		return 0;
-	memset(cursor, 0, sizeof(*cursor));
-
-	cursor->timer = kmalloc(sizeof(*cursor->timer), GFP_KERNEL);
-	if (!cursor->timer) {
-		kfree(cursor);
-		return 0;
-	}
-	memset(cursor->timer, 0, sizeof(*cursor->timer));
-
-	cursor->blink_rate = DEFAULT_CURSOR_BLINK_RATE;
-	fb->total_vram -= PAGE_SIZE;
-	cursor->offset = fb->total_vram;
-
-#ifdef __sparc__
-	addr = fb->frame_buffer - 0x800000 + cursor->offset;
-	cursor->ram = (u8 *)addr;
-#else
-#ifdef __BIG_ENDIAN
-	addr = fb->frame_buffer_phys - 0x800000 + cursor->offset;
-	cursor->ram = (u8 *)ioremap(addr, 1024);
-#else
-	addr = fb->frame_buffer + cursor->offset;
-	cursor->ram = (u8 *)addr;
-#endif
-#endif
-
-	if (! cursor->ram) {
-		kfree(cursor);
-		return NULL;
-	}
-
-	if (curblink) {
-		init_timer(cursor->timer);
-		cursor->timer->expires = jiffies + (HZ / 50);
-		cursor->timer->data = (unsigned long)fb;
-		cursor->timer->function = aty_cursor_timer_handler;
-		add_timer(cursor->timer);
-	}
-
-	return cursor;
-}
-
-static int
-atyfb_set_font(struct display *d, int width, int height)
-{
-    struct fb_info_aty *fb = (struct fb_info_aty *)d->fb_info;
-    struct aty_cursor *c = fb->cursor;
-    int i, j;
-
-    if (c) {
-	if (!width || !height) {
-	    width = 8;
-	    height = 16;
-	}
-
-	c->hot.x = 0;
-	c->hot.y = 0;
-	c->size.x = width;
-	c->size.y = height;
-
-	memset(c->bits, 0xff, sizeof(c->bits));
-	memset(c->mask, 0, sizeof(c->mask));
-
-	for (i = 0, j = width; j >= 0; j -= 8, i++) {
-	    c->mask[i][height-2] = (j >= 8) ? 0xff : (0xff << (8 - j));
-	    c->mask[i][height-1] = (j >= 8) ? 0xff : (0xff << (8 - j));
-	}
-
-	aty_set_cursor_color(fb, cursor_pixel_map, cursor_color_map,
-			     cursor_color_map, cursor_color_map);
-	aty_set_cursor_shape(fb);
-    }
-    return 1;
-}
-
-
-
-
-/* ------------------------------------------------------------------------- */
-
-    /*
-     *  CRTC programming
-     */
-
-static void aty_set_crtc(const struct fb_info_aty *info,
-			 const struct crtc *crtc)
-{
-    aty_st_le32(CRTC_H_TOTAL_DISP, crtc->h_tot_disp, info);
-    aty_st_le32(CRTC_H_SYNC_STRT_WID, crtc->h_sync_strt_wid, info);
-    aty_st_le32(CRTC_V_TOTAL_DISP, crtc->v_tot_disp, info);
-    aty_st_le32(CRTC_V_SYNC_STRT_WID, crtc->v_sync_strt_wid, info);
-    aty_st_le32(CRTC_VLINE_CRNT_VLINE, 0, info);
-    aty_st_le32(CRTC_OFF_PITCH, crtc->off_pitch, info);
-    aty_st_le32(CRTC_GEN_CNTL, crtc->gen_cntl, info);
-}
-
-static int aty_var_to_crtc(const struct fb_info_aty *info,
-			   const struct fb_var_screeninfo *var,
-			   struct crtc *crtc)
-{
-    u32 xres, yres, vxres, vyres, xoffset, yoffset, bpp;
-    u32 left, right, upper, lower, hslen, vslen, sync, vmode;
-    u32 h_total, h_disp, h_sync_strt, h_sync_dly, h_sync_wid, h_sync_pol;
-    u32 v_total, v_disp, v_sync_strt, v_sync_wid, v_sync_pol, c_sync;
-    u32 pix_width, dp_pix_width, dp_chain_mask;
-
-    /* input */
-    xres = var->xres;
-    yres = var->yres;
-    vxres = var->xres_virtual;
-    vyres = var->yres_virtual;
-    xoffset = var->xoffset;
-    yoffset = var->yoffset;
-    bpp = var->bits_per_pixel;
-    left = var->left_margin;
-    right = var->right_margin;
-    upper = var->upper_margin;
-    lower = var->lower_margin;
-    hslen = var->hsync_len;
-    vslen = var->vsync_len;
-    sync = var->sync;
-    vmode = var->vmode;
-
-    /* convert (and round up) and validate */
-    xres = (xres+7) & ~7;
-    xoffset = (xoffset+7) & ~7;
-    vxres = (vxres+7) & ~7;
-    if (vxres < xres+xoffset)
-	vxres = xres+xoffset;
-    h_disp = xres/8-1;
-    if (h_disp > 0xff)
-	FAIL("h_disp too large");
-    h_sync_strt = h_disp+(right/8);
-    if (h_sync_strt > 0x1ff)
-	FAIL("h_sync_start too large");
-    h_sync_dly = right & 7;
-    h_sync_wid = (hslen+7)/8;
-    if (h_sync_wid > 0x1f)
-	FAIL("h_sync_wid too large");
-    h_total = h_sync_strt+h_sync_wid+(h_sync_dly+left+7)/8;
-    if (h_total > 0x1ff)
-	FAIL("h_total too large");
-    h_sync_pol = sync & FB_SYNC_HOR_HIGH_ACT ? 0 : 1;
-
-    if (vyres < yres+yoffset)
-	vyres = yres+yoffset;
-    v_disp = yres-1;
-    if (v_disp > 0x7ff)
-	FAIL("v_disp too large");
-    v_sync_strt = v_disp+lower;
-    if (v_sync_strt > 0x7ff)
-	FAIL("v_sync_strt too large");
-    v_sync_wid = vslen;
-    if (v_sync_wid > 0x1f)
-	FAIL("v_sync_wid too large");
-    v_total = v_sync_strt+v_sync_wid+upper;
-    if (v_total > 0x7ff)
-	FAIL("v_total too large");
-    v_sync_pol = sync & FB_SYNC_VERT_HIGH_ACT ? 0 : 1;
-
-    c_sync = sync & FB_SYNC_COMP_HIGH_ACT ? CRTC_CSYNC_EN : 0;
-
-    if (bpp <= 8) {
-	bpp = 8;
-	pix_width = CRTC_PIX_WIDTH_8BPP;
-	dp_pix_width = HOST_8BPP | SRC_8BPP | DST_8BPP | BYTE_ORDER_LSB_TO_MSB;
-	dp_chain_mask = 0x8080;
-    } else if (bpp <= 16) {
-	bpp = 16;
-	pix_width = CRTC_PIX_WIDTH_15BPP;
-	dp_pix_width = HOST_15BPP | SRC_15BPP | DST_15BPP |
-		       BYTE_ORDER_LSB_TO_MSB;
-	dp_chain_mask = 0x4210;
-    } else if ((bpp <= 24) && (Gx != GX_CHIP_ID) && (Gx != CX_CHIP_ID)) {
-	bpp = 24;
-	pix_width = CRTC_PIX_WIDTH_24BPP;
-	dp_pix_width = HOST_8BPP | SRC_8BPP | DST_8BPP | BYTE_ORDER_LSB_TO_MSB;
-	dp_chain_mask = 0x8080;
-    } else if (bpp <= 32) {
-	bpp = 32;
-	pix_width = CRTC_PIX_WIDTH_32BPP;
-	dp_pix_width = HOST_32BPP | SRC_32BPP | DST_32BPP |
-		       BYTE_ORDER_LSB_TO_MSB;
-	dp_chain_mask = 0x8080;
-    } else
-	FAIL("invalid bpp");
-
-    if (vxres*vyres*bpp/8 > info->total_vram)
-	FAIL("not enough video RAM");
-
-    if ((vmode & FB_VMODE_MASK) != FB_VMODE_NONINTERLACED)
-	FAIL("invalid vmode");
-
-    /* output */
-    crtc->vxres = vxres;
-    crtc->vyres = vyres;
-    crtc->xoffset = xoffset;
-    crtc->yoffset = yoffset;
-    crtc->bpp = bpp;
-    crtc->h_tot_disp = h_total | (h_disp<<16);
-    crtc->h_sync_strt_wid = (h_sync_strt & 0xff) | (h_sync_dly<<8) |
-			    ((h_sync_strt & 0x100)<<4) | (h_sync_wid<<16) |
-			    (h_sync_pol<<21);
-    crtc->v_tot_disp = v_total | (v_disp<<16);
-    crtc->v_sync_strt_wid = v_sync_strt | (v_sync_wid<<16) | (v_sync_pol<<21);
-    crtc->off_pitch = ((yoffset*vxres+xoffset)*bpp/64) | (vxres<<19);
-    crtc->gen_cntl = pix_width | c_sync | CRTC_EXT_DISP_EN | CRTC_ENABLE;
-    if ((Gx == CT_CHIP_ID) || (Gx == ET_CHIP_ID) ||
-	((Gx == VT_CHIP_ID || Gx == GT_CHIP_ID) && !(Rev & 0x07))) {
-	/* Not VTB/GTB */
-	/* FIXME: magic FIFO values */
-	crtc->gen_cntl |= aty_ld_le32(CRTC_GEN_CNTL, info) & 0x000e0000;
-    }
-    crtc->dp_pix_width = dp_pix_width;
-    crtc->dp_chain_mask = dp_chain_mask;
-
-    return 0;
-}
-
-
-static int aty_set_dac_ATI68860_B(const struct fb_info_aty *info, u32 bpp,
-				  u32 AccelMode)
-{
-    u32 gModeReg, devSetupRegA, temp, mask;
-
-    gModeReg = 0;
-    devSetupRegA = 0;
-
-    switch (bpp) {
-	case 8:
-	    gModeReg = 0x83;
-	    devSetupRegA = 0x60 | 0x00 /*(info->mach64DAC8Bit ? 0x00 : 0x01) */;
-	    break;
-	case 15:
-	    gModeReg = 0xA0;
-	    devSetupRegA = 0x60;
-	    break;
-	case 16:
-	    gModeReg = 0xA1;
-	    devSetupRegA = 0x60;
-	    break;
-	case 24:
-	    gModeReg = 0xC0;
-	    devSetupRegA = 0x60;
-	    break;
-	case 32:
-	    gModeReg = 0xE3;
-	    devSetupRegA = 0x60;
-	    break;
-    }
-
-    if (!AccelMode) {
-	gModeReg = 0x80;
-	devSetupRegA = 0x61;
-    }
-
-    temp = aty_ld_8(DAC_CNTL, info);
-    aty_st_8(DAC_CNTL, (temp & ~DAC_EXT_SEL_RS2) | DAC_EXT_SEL_RS3, info);
-
-    aty_st_8(DAC_REGS + 2, 0x1D, info);
-    aty_st_8(DAC_REGS + 3, gModeReg, info);
-    aty_st_8(DAC_REGS, 0x02, info);
-
-    temp = aty_ld_8(DAC_CNTL, info);
-    aty_st_8(DAC_CNTL, temp | DAC_EXT_SEL_RS2 | DAC_EXT_SEL_RS3, info);
-
-    if (info->total_vram < MEM_SIZE_1M)
-	mask = 0x04;
-    else if (info->total_vram == MEM_SIZE_1M)
-	mask = 0x08;
-    else
-	mask = 0x0C;
-
-    /* The following assumes that the BIOS has correctly set R7 of the
-     * Device Setup Register A at boot time.
-     */
-#define A860_DELAY_L	0x80
-
-    temp = aty_ld_8(DAC_REGS, info);
-    aty_st_8(DAC_REGS, (devSetupRegA | mask) | (temp & A860_DELAY_L), info);
-    temp = aty_ld_8(DAC_CNTL, info);
-    aty_st_8(DAC_CNTL, (temp & ~(DAC_EXT_SEL_RS2 | DAC_EXT_SEL_RS3)), info);
-
-    return 0;
-}
-
-static int aty_set_dac_ATT21C498(const struct fb_info_aty *info,
-				 const struct pll_18818 *pll, u32 bpp)
-{
-    u32 dotClock;
-    int muxmode = 0;
-    int DACMask = 0;
-
-    dotClock = 100000000 / pll->period_in_ps;
-
-    switch (bpp) {
-	case 8:
-	    if (dotClock > 8000) {
-		DACMask = 0x24;
-		muxmode = 1;
-	    } else
-		DACMask = 0x04;
-	    break;
-	case 15:
-	    DACMask = 0x16;
-	    break;
-	case 16:
-	    DACMask = 0x36;
-	    break;
-	case 24:
-	    DACMask = 0xE6;
-	    break;
-	case 32:
-	    DACMask = 0xE6;
-	    break;
-    }
-
-    if (1 /* info->mach64DAC8Bit */)
-	DACMask |= 0x02;
-
-    aty_dac_waste4(info);
-    aty_st_8(DAC_REGS + 2, DACMask, info);
-
-    return muxmode;
-}
-
-void aty_dac_waste4(const struct fb_info_aty *info)
-{
-  (void)aty_ld_8(DAC_REGS, info);
-
-  (void)aty_ld_8(DAC_REGS + 2, info);
-  (void)aty_ld_8(DAC_REGS + 2, info);
-  (void)aty_ld_8(DAC_REGS + 2, info);
-  (void)aty_ld_8(DAC_REGS + 2, info);
-}
-
-
-static void aty_set_dac_514(const struct fb_info_aty *info, u32 bpp)
-{
-    static struct {
-	u8 pixel_dly;
-	u8 misc2_cntl;
-	u8 pixel_rep;
-	u8 pixel_cntl_index;
-	u8 pixel_cntl_v1;
-    } tab[3] = {
-	{ 0, 0x41, 0x03, 0x71, 0x45 },	/* 8 bpp */
-	{ 0, 0x45, 0x04, 0x0c, 0x01 },	/* 555 */
-	{ 0, 0x45, 0x06, 0x0e, 0x00 },	/* XRGB */
-    };
-    int i;
-
-    switch (bpp) {
-	case 8:
-	default:
-	    i = 0;
-	    break;
-	case 16:
-	    i = 1;
-	    break;
-	case 32:
-	    i = 2;
-	    break;
-    }
-    aty_st_514(0x90, 0x00, info);		/* VRAM Mask Low */
-    aty_st_514(0x04, tab[i].pixel_dly, info);	/* Horizontal Sync Control */
-    aty_st_514(0x05, 0x00, info);		/* Power Management */
-    aty_st_514(0x02, 0x01, info);		/* Misc Clock Control */
-    aty_st_514(0x71, tab[i].misc2_cntl, info);	/* Misc Control 2 */
-    aty_st_514(0x0a, tab[i].pixel_rep, info);	/* Pixel Format */
-    aty_st_514(tab[i].pixel_cntl_index, tab[i].pixel_cntl_v1, info);
-			/* Misc Control 2 / 16 BPP Control / 32 BPP Control */
-}
-
-static int aty_crtc_to_var(const struct crtc *crtc,
-			   struct fb_var_screeninfo *var)
-{
-    u32 xres, yres, bpp, left, right, upper, lower, hslen, vslen, sync;
-    u32 h_total, h_disp, h_sync_strt, h_sync_dly, h_sync_wid, h_sync_pol;
-    u32 v_total, v_disp, v_sync_strt, v_sync_wid, v_sync_pol, c_sync;
-    u32 pix_width;
-
-    /* input */
-    h_total = crtc->h_tot_disp & 0x1ff;
-    h_disp = (crtc->h_tot_disp>>16) & 0xff;
-    h_sync_strt = (crtc->h_sync_strt_wid & 0xff) |
-		  ((crtc->h_sync_strt_wid>>4) & 0x100);
-    h_sync_dly = (crtc->h_sync_strt_wid>>8) & 0x7;
-    h_sync_wid = (crtc->h_sync_strt_wid>>16) & 0x1f;
-    h_sync_pol = (crtc->h_sync_strt_wid>>21) & 0x1;
-    v_total = crtc->v_tot_disp & 0x7ff;
-    v_disp = (crtc->v_tot_disp>>16) & 0x7ff;
-    v_sync_strt = crtc->v_sync_strt_wid & 0x7ff;
-    v_sync_wid = (crtc->v_sync_strt_wid>>16) & 0x1f;
-    v_sync_pol = (crtc->v_sync_strt_wid>>21) & 0x1;
-    c_sync = crtc->gen_cntl & CRTC_CSYNC_EN ? 1 : 0;
-    pix_width = crtc->gen_cntl & CRTC_PIX_WIDTH_MASK;
-
-    /* convert */
-    xres = (h_disp+1)*8;
-    yres = v_disp+1;
-    left = (h_total-h_sync_strt-h_sync_wid)*8-h_sync_dly;
-    right = (h_sync_strt-h_disp)*8+h_sync_dly;
-    hslen = h_sync_wid*8;
-    upper = v_total-v_sync_strt-v_sync_wid;
-    lower = v_sync_strt-v_disp;
-    vslen = v_sync_wid;
-    sync = (h_sync_pol ? 0 : FB_SYNC_HOR_HIGH_ACT) |
-	   (v_sync_pol ? 0 : FB_SYNC_VERT_HIGH_ACT) |
-	   (c_sync ? FB_SYNC_COMP_HIGH_ACT : 0);
-
-    switch (pix_width) {
-#if 0
-	case CRTC_PIX_WIDTH_4BPP:
-	    bpp = 4;
-	    var->red.offset = 0;
-	    var->red.length = 8;
-	    var->green.offset = 0;
-	    var->green.length = 8;
-	    var->blue.offset = 0;
-	    var->blue.length = 8;
-	    var->transp.offset = 0;
-	    var->transp.length = 0;
-	    break;
-#endif
-	case CRTC_PIX_WIDTH_8BPP:
-	    bpp = 8;
-	    var->red.offset = 0;
-	    var->red.length = 8;
-	    var->green.offset = 0;
-	    var->green.length = 8;
-	    var->blue.offset = 0;
-	    var->blue.length = 8;
-	    var->transp.offset = 0;
-	    var->transp.length = 0;
-	    break;
-	case CRTC_PIX_WIDTH_15BPP:	/* RGB 555 */
-	    bpp = 16;
-	    var->red.offset = 10;
-	    var->red.length = 5;
-	    var->green.offset = 5;
-	    var->green.length = 5;
-	    var->blue.offset = 0;
-	    var->blue.length = 5;
-	    var->transp.offset = 0;
-	    var->transp.length = 0;
-	    break;
-#if 0
-	case CRTC_PIX_WIDTH_16BPP:	/* RGB 565 */
-	    bpp = 16;
-	    var->red.offset = 11;
-	    var->red.length = 5;
-	    var->green.offset = 5;
-	    var->green.length = 6;
-	    var->blue.offset = 0;
-	    var->blue.length = 5;
-	    var->transp.offset = 0;
-	    var->transp.length = 0;
-	    break;
-#endif
-	case CRTC_PIX_WIDTH_24BPP:	/* RGB 888 */
-	    bpp = 24;
-	    var->red.offset = 16;
-	    var->red.length = 8;
-	    var->green.offset = 8;
-	    var->green.length = 8;
-	    var->blue.offset = 0;
-	    var->blue.length = 8;
-	    var->transp.offset = 0;
-	    var->transp.length = 0;
-	    break;
-	case CRTC_PIX_WIDTH_32BPP:	/* ARGB 8888 */
-	    bpp = 32;
-	    var->red.offset = 16;
-	    var->red.length = 8;
-	    var->green.offset = 8;
-	    var->green.length = 8;
-	    var->blue.offset = 0;
-	    var->blue.length = 8;
-	    var->transp.offset = 24;
-	    var->transp.length = 8;
-	    break;
-	default:
-	    FAIL("Invalid pixel width");
-    }
-
-    /* output */
-    var->xres = xres;
-    var->yres = yres;
-    var->xres_virtual = crtc->vxres;
-    var->yres_virtual = crtc->vyres;
-    var->bits_per_pixel = bpp;
-    var->xoffset = crtc->xoffset;
-    var->yoffset = crtc->yoffset;
-    var->left_margin = left;
-    var->right_margin = right;
-    var->upper_margin = upper;
-    var->lower_margin = lower;
-    var->hsync_len = hslen;
-    var->vsync_len = vslen;
-    var->sync = sync;
-    var->vmode = FB_VMODE_NONINTERLACED;
-
-    return 0;
-}
-
-/* ------------------------------------------------------------------------- */
-
-    /*
-     *  PLL programming (Mach64 GX family)
-     *
-     *  FIXME: use function pointer tables instead of switch statements
-     */
-
-static void aty_set_pll_gx(const struct fb_info_aty *info,
-			   const struct pll_gx *pll)
-{
-    switch (info->clk_type) {
-	case CLK_ATI18818_1:
-	    aty_st_8(CLOCK_CNTL, pll->m, info);
-	    break;
-	case CLK_IBMRGB514:
-	    aty_st_514(0x06, 0x02, info);	/* DAC Operation */
-	    aty_st_514(0x10, 0x01, info);	/* PLL Control 1 */
-	    aty_st_514(0x70, 0x01, info);	/* Misc Control 1 */
-	    aty_st_514(0x8f, 0x1f, info);	/* PLL Ref. Divider Input */
-	    aty_st_514(0x03, 0x00, info);	/* Sync Control */
-	    aty_st_514(0x05, 0x00, info);	/* Power Management */
-	    aty_st_514(0x20, pll->m, info);	/* F0 / M0 */
-	    aty_st_514(0x21, pll->n, info);	/* F1 / N0 */
-	    break;
-    }
-}
-
-
-static int aty_var_to_pll_18818(u32 period_in_ps, struct pll_18818 *pll)
-{
-    u32 MHz100;		/* in 0.01 MHz */
-    u32 program_bits;
-    u32 post_divider;
-
-    /* Calculate the programming word */
-    MHz100 = 100000000 / period_in_ps;
-
-    program_bits = -1;
-    post_divider = 1;
-
-    if (MHz100 > MAX_FREQ_2595) {
-	MHz100 = MAX_FREQ_2595;
-	return -EINVAL;
-    } else if (MHz100 < ABS_MIN_FREQ_2595) {
-	program_bits = 0;	/* MHz100 = 257 */
-	return -EINVAL;
-    } else {
-	while (MHz100 < MIN_FREQ_2595) {
-	    MHz100 *= 2;
-	    post_divider *= 2;
-	}
-    }
-    MHz100 *= 1000;
-    MHz100 = (REF_DIV_2595 * MHz100) / REF_FREQ_2595;
-
-    MHz100 += 500;    /* + 0.5 round */
-    MHz100 /= 1000;
-
-    if (program_bits == -1) {
-	program_bits = MHz100 - N_ADJ_2595;
-	switch (post_divider) {
-	    case 1:
-		program_bits |= 0x0600;
-		break;
-	    case 2:
-		program_bits |= 0x0400;
-		break;
-	    case 4:
-		program_bits |= 0x0200;
-		break;
-	    case 8:
-	    default:
-		break;
-	}
-    }
-
-    program_bits |= STOP_BITS_2595;
-
-    pll->program_bits = program_bits;
-    pll->locationAddr = 0;
-    pll->post_divider = post_divider;
-    pll->period_in_ps = period_in_ps;
-
-    return 0;
-}
-
-static u32 aty_pll_18818_to_var(const struct pll_18818 *pll)
-{
-    return(pll->period_in_ps);  /* default for now */
-}
-
-static void aty_set_pll18818(const struct fb_info_aty *info,
-			     const struct pll_18818 *pll)
-{
-    u32 program_bits;
-    u32 locationAddr;
-
-    u32 i;
-
-    u8 old_clock_cntl;
-    u8 old_crtc_ext_disp;
-
-    old_clock_cntl = aty_ld_8(CLOCK_CNTL, info);
-    aty_st_8(CLOCK_CNTL + info->clk_wr_offset, 0, info);
-
-    old_crtc_ext_disp = aty_ld_8(CRTC_GEN_CNTL + 3, info);
-    aty_st_8(CRTC_GEN_CNTL + 3, old_crtc_ext_disp | (CRTC_EXT_DISP_EN >> 24),
-	     info);
-
-    mdelay(15); /* delay for 50 (15) ms */
-
-    program_bits = pll->program_bits;
-    locationAddr = pll->locationAddr;
-
-    /* Program the clock chip */
-    aty_st_8(CLOCK_CNTL + info->clk_wr_offset, 0, info);  /* Strobe = 0 */
-    aty_StrobeClock(info);
-    aty_st_8(CLOCK_CNTL + info->clk_wr_offset, 1, info);  /* Strobe = 0 */
-    aty_StrobeClock(info);
-
-    aty_ICS2595_put1bit(1, info);    /* Send start bits */
-    aty_ICS2595_put1bit(0, info);    /* Start bit */
-    aty_ICS2595_put1bit(0, info);    /* Read / ~Write */
-
-    for (i = 0; i < 5; i++) {	/* Location 0..4 */
-	aty_ICS2595_put1bit(locationAddr & 1, info);
-	locationAddr >>= 1;
-    }
-
-    for (i = 0; i < 8 + 1 + 2 + 2; i++) {
-	aty_ICS2595_put1bit(program_bits & 1, info);
-	program_bits >>= 1;
-    }
-
-    udelay(1000); /* delay for 1 ms */
-
-    (void)aty_ld_8(DAC_REGS, info); /* Clear DAC Counter */
-    aty_st_8(CRTC_GEN_CNTL + 3, old_crtc_ext_disp, info);
-    aty_st_8(CLOCK_CNTL + info->clk_wr_offset, old_clock_cntl | CLOCK_STROBE,
-	     info);
-
-    mdelay(50); /* delay for 50 (15) ms */
-    aty_st_8(CLOCK_CNTL + info->clk_wr_offset,
-	     ((pll->locationAddr & 0x0F) | CLOCK_STROBE), info);
-
-    return;
-}
-
-
-static int aty_var_to_pll_408(u32 period_in_ps, struct pll_18818 *pll)
-{
-    u32 mhz100;		/* in 0.01 MHz */
-    u32 program_bits;
-    /* u32 post_divider; */
-    u32 mach64MinFreq, mach64MaxFreq, mach64RefFreq;
-    u32 temp, tempB;
-    u16 remainder, preRemainder;
-    short divider = 0, tempA;
-
-    /* Calculate the programming word */
-    mhz100 = 100000000 / period_in_ps;
-    mach64MinFreq = MIN_FREQ_2595;
-    mach64MaxFreq = MAX_FREQ_2595;
-    mach64RefFreq = REF_FREQ_2595;	/* 14.32 MHz */
-
-    /* Calculate program word */
-    if (mhz100 == 0)
-	program_bits = 0xFF;
-    else {
-	if (mhz100 < mach64MinFreq)
-	    mhz100 = mach64MinFreq;
-	if (mhz100 > mach64MaxFreq)
-	    mhz100 = mach64MaxFreq;
-
-	while (mhz100 < (mach64MinFreq << 3)) {
-	    mhz100 <<= 1;
-	    divider += 0x40;
-	}
-
-	temp = (unsigned int)mhz100;
-	temp = (unsigned int)(temp * (MIN_N_408 + 2));
-	temp -= ((short)(mach64RefFreq << 1));
-
-	tempA = MIN_N_408;
-	preRemainder = 0xFFFF;
-
-	do {
-	    tempB = temp;
-	    remainder = tempB % mach64RefFreq;
-	    tempB = tempB / mach64RefFreq;
-	    if (((tempB & 0xFFFF) <= 255) && (remainder <= preRemainder)) {
-		preRemainder = remainder;
-		divider &= ~0x3f;
-		divider |= tempA;
-		divider = (divider & 0x00FF) + ((tempB & 0xFF) << 8);
-	    }
-	    temp += mhz100;
-	    tempA++;
-	} while(tempA <= 32);
-
-	program_bits = divider;
-    }
-
-    pll->program_bits = program_bits;
-    pll->locationAddr = 0;
-    pll->post_divider = divider;	/* fuer nix */
-    pll->period_in_ps = period_in_ps;
-
-    return 0;
-}
-
-static u32 aty_pll_408_to_var(const struct pll_18818 *pll)
-{
-    return(pll->period_in_ps);  /* default for now */
-}
-
-static void aty_set_pll_408(const struct fb_info_aty *info,
-			    const struct pll_18818 *pll)
-{
-    u32 program_bits;
-    u32 locationAddr;
-
-    u8 tmpA, tmpB, tmpC;
-    char old_crtc_ext_disp;
-
-    old_crtc_ext_disp = aty_ld_8(CRTC_GEN_CNTL + 3, info);
-    aty_st_8(CRTC_GEN_CNTL + 3, old_crtc_ext_disp | (CRTC_EXT_DISP_EN >> 24),
-	     info);
-
-    program_bits = pll->program_bits;
-    locationAddr = pll->locationAddr;
-
-    /* Program clock */
-    aty_dac_waste4(info);
-    tmpB = aty_ld_8(DAC_REGS + 2, info) | 1;
-    aty_dac_waste4(info);
-    aty_st_8(DAC_REGS + 2, tmpB, info);
-
-    tmpA = tmpB;
-    tmpC = tmpA;
-    tmpA |= 8;
-    tmpB = 1;
-
-    aty_st_8(DAC_REGS, tmpB, info);
-    aty_st_8(DAC_REGS + 2, tmpA, info);
-
-    udelay(400); /* delay for 400 us */
-
-    locationAddr = (locationAddr << 2) + 0x40;
-    tmpB = locationAddr;
-    tmpA = program_bits >> 8;
-
-    aty_st_8(DAC_REGS, tmpB, info);
-    aty_st_8(DAC_REGS + 2, tmpA, info);
-
-    tmpB = locationAddr + 1;
-    tmpA = (u8)program_bits;
-
-    aty_st_8(DAC_REGS, tmpB, info);
-    aty_st_8(DAC_REGS + 2, tmpA, info);
-
-    tmpB = locationAddr + 2;
-    tmpA = 0x77;
-
-    aty_st_8(DAC_REGS, tmpB, info);
-    aty_st_8(DAC_REGS + 2, tmpA, info);
-
-    udelay(400); /* delay for 400 us */
-    tmpA = tmpC & (~(1 | 8));
-    tmpB = 1;
-
-    aty_st_8(DAC_REGS, tmpB, info);
-    aty_st_8(DAC_REGS + 2, tmpA, info);
-
-    (void)aty_ld_8(DAC_REGS, info); /* Clear DAC Counter */
-    aty_st_8(CRTC_GEN_CNTL + 3, old_crtc_ext_disp, info);
-
-    return;
-}
-
-
-static int aty_var_to_pll_1703(u32 period_in_ps, struct pll_18818 *pll)
-{
-    u32 mhz100;			/* in 0.01 MHz */
-    u32 program_bits;
-    /* u32 post_divider; */
-    u32 mach64MinFreq, mach64MaxFreq, mach64RefFreq;
-    u32 temp, tempB;
-    u16 remainder, preRemainder;
-    short divider = 0, tempA;
-
-    /* Calculate the programming word */
-    mhz100 = 100000000 / period_in_ps;
-    mach64MinFreq = MIN_FREQ_2595;
-    mach64MaxFreq = MAX_FREQ_2595;
-    mach64RefFreq = REF_FREQ_2595;	/* 14.32 MHz */
-
-    /* Calculate program word */
-    if (mhz100 == 0)
-	program_bits = 0xE0;
-    else {
-	if (mhz100 < mach64MinFreq)
-	    mhz100 = mach64MinFreq;
-	if (mhz100 > mach64MaxFreq)
-	    mhz100 = mach64MaxFreq;
-
-	divider = 0;
-	while (mhz100 < (mach64MinFreq << 3)) {
-	    mhz100 <<= 1;
-	    divider += 0x20;
-	}
-
-	temp = (unsigned int)(mhz100);
-	temp = (unsigned int)(temp * (MIN_N_1703 + 2));
-	temp -= (short)(mach64RefFreq << 1);
-
-	tempA = MIN_N_1703;
-	preRemainder = 0xffff;
-
-	do {
-	    tempB = temp;
-	    remainder = tempB % mach64RefFreq;
-	    tempB = tempB / mach64RefFreq;
-
-	    if ((tempB & 0xffff) <= 127 && (remainder <= preRemainder)) {
-		preRemainder = remainder;
-		divider &= ~0x1f;
-		divider |= tempA;
-		divider = (divider & 0x00ff) + ((tempB & 0xff) << 8);
-	    }
-
-	    temp += mhz100;
-	    tempA++;
-	} while (tempA <= (MIN_N_1703 << 1));
-
-	program_bits = divider;
-    }
-
-      pll->program_bits = program_bits;
-      pll->locationAddr = 0;
-      pll->post_divider = divider;  /* fuer nix */
-      pll->period_in_ps = period_in_ps;
-
-      return 0;
-}
-
-static u32 aty_pll_1703_to_var(const struct pll_18818 *pll)
-{
-    return(pll->period_in_ps);  /* default for now */
-}
-
-static void aty_set_pll_1703(const struct fb_info_aty *info,
-			     const struct pll_18818 *pll)
-{
-    u32 program_bits;
-    u32 locationAddr;
-
-    char old_crtc_ext_disp;
-
-    old_crtc_ext_disp = aty_ld_8(CRTC_GEN_CNTL + 3, info);
-    aty_st_8(CRTC_GEN_CNTL + 3, old_crtc_ext_disp | (CRTC_EXT_DISP_EN >> 24),
-	     info);
-
-    program_bits = pll->program_bits;
-    locationAddr = pll->locationAddr;
-
-    /* Program clock */
-    aty_dac_waste4(info);
-
-    (void)aty_ld_8(DAC_REGS + 2, info);
-    aty_st_8(DAC_REGS+2, (locationAddr << 1) + 0x20, info);
-    aty_st_8(DAC_REGS+2, 0, info);
-    aty_st_8(DAC_REGS+2, (program_bits & 0xFF00) >> 8, info);
-    aty_st_8(DAC_REGS+2, (program_bits & 0xFF), info);
-
-    (void)aty_ld_8(DAC_REGS, info); /* Clear DAC Counter */
-    aty_st_8(CRTC_GEN_CNTL + 3, old_crtc_ext_disp, info);
-
-    return;
-}
-
-
-static int aty_var_to_pll_8398(u32 period_in_ps, struct pll_18818 *pll)
-{
-
-    u32 tempA, tempB, fOut, longMHz100, diff, preDiff;
-
-    u32 mhz100;				/* in 0.01 MHz */
-    u32 program_bits;
-    /* u32 post_divider; */
-    u32 mach64MinFreq, mach64MaxFreq, mach64RefFreq;
-    u16 m, n, k=0, save_m, save_n, twoToKth;
-
-    /* Calculate the programming word */
-    mhz100 = 100000000 / period_in_ps;
-    mach64MinFreq = MIN_FREQ_2595;
-    mach64MaxFreq = MAX_FREQ_2595;
-    mach64RefFreq = REF_FREQ_2595;	/* 14.32 MHz */
-
-    save_m = 0;
-    save_n = 0;
-
-    /* Calculate program word */
-    if (mhz100 == 0)
-	program_bits = 0xE0;
-    else
-    {
-	if (mhz100 < mach64MinFreq)
-	    mhz100 = mach64MinFreq;
-	if (mhz100 > mach64MaxFreq)
-	    mhz100 = mach64MaxFreq;
-
-	longMHz100 = mhz100 * 256 / 100;   /* 8 bit scale this */
-
-	while (mhz100 < (mach64MinFreq << 3))
-        {
-	    mhz100 <<= 1;
-	    k++;
-	}
-
-	twoToKth = 1 << k;
-	diff = 0;
-	preDiff = 0xFFFFFFFF;
-
-	for (m = MIN_M; m <= MAX_M; m++)
-        {
-	    for (n = MIN_N; n <= MAX_N; n++)
-            {
-		tempA = (14.31818 * 65536);
-		tempA *= (n + 8);  /* 43..256 */
-		tempB = twoToKth * 256;
-		tempB *= (m + 2);  /* 4..32 */
-		fOut = tempA / tempB;  /* 8 bit scale */
-
-		if (longMHz100 > fOut)
-		    diff = longMHz100 - fOut;
-		else
-		    diff = fOut - longMHz100;
-
-		if (diff < preDiff)
-                {
-		    save_m = m;
-		    save_n = n;
-		    preDiff = diff;
-		}
-	    }
-	}
-
-	program_bits = (k << 6) + (save_m) + (save_n << 8);
-    }
-
-    pll->program_bits = program_bits;
-    pll->locationAddr = 0;
-    pll->post_divider = 0;
-    pll->period_in_ps = period_in_ps;
-
-    return 0;
-}
-
-static u32 aty_pll_8398_to_var(const struct pll_18818 *pll)
-{
-    return(pll->period_in_ps);  /* default for now */
-}
-
-static void aty_set_pll_8398(const struct fb_info_aty *info,
-			     const struct pll_18818 *pll)
-{
-    u32 program_bits;
-    u32 locationAddr;
-
-    char old_crtc_ext_disp;
-    char tmp;
-
-    old_crtc_ext_disp = aty_ld_8(CRTC_GEN_CNTL + 3, info);
-    aty_st_8(CRTC_GEN_CNTL + 3, old_crtc_ext_disp | (CRTC_EXT_DISP_EN >> 24),
-	     info);
-
-    program_bits = pll->program_bits;
-    locationAddr = pll->locationAddr;
-
-    /* Program clock */
-    tmp = aty_ld_8(DAC_CNTL, info);
-    aty_st_8(DAC_CNTL, tmp | DAC_EXT_SEL_RS2 | DAC_EXT_SEL_RS3, info);
-
-    aty_st_8(DAC_REGS, locationAddr, info);
-    aty_st_8(DAC_REGS+1, (program_bits & 0xff00) >> 8, info);
-    aty_st_8(DAC_REGS+1, (program_bits & 0xff), info);
-
-    tmp = aty_ld_8(DAC_CNTL, info);
-    aty_st_8(DAC_CNTL, (tmp & ~DAC_EXT_SEL_RS2) | DAC_EXT_SEL_RS3, info);
-
-    (void)aty_ld_8(DAC_REGS, info); /* Clear DAC Counter */
-    aty_st_8(CRTC_GEN_CNTL + 3, old_crtc_ext_disp, info);
-
-    return;
-}
-
-
-static int aty_var_to_pll_514(u32 vclk_per, struct pll_gx *pll)
-{
-    /*
-     *  FIXME: use real calculations instead of using fixed values from the old
-     *	       driver
-     */
-    static struct {
-	u32 limit;	/* pixlock rounding limit (arbitrary) */
-	u8 m;		/* (df<<6) | vco_div_count */
-	u8 n;		/* ref_div_count */
-    } RGB514_clocks[7] = {
-	{  8000, (3<<6) | 20, 9 },	/*  7395 ps / 135.2273 MHz */
-	{ 10000, (1<<6) | 19, 3 },	/*  9977 ps / 100.2273 MHz */
-	{ 13000, (1<<6) |  2, 3 },	/* 12509 ps /  79.9432 MHz */
-	{ 14000, (2<<6) |  8, 7 },	/* 13394 ps /  74.6591 MHz */
-	{ 16000, (1<<6) | 44, 6 },	/* 15378 ps /  65.0284 MHz */
-	{ 25000, (1<<6) | 15, 5 },	/* 17460 ps /  57.2727 MHz */
-	{ 50000, (0<<6) | 53, 7 },	/* 33145 ps /  30.1705 MHz */
-    };
-    int i;
-
-    for (i = 0; i < sizeof(RGB514_clocks)/sizeof(*RGB514_clocks); i++)
-	if (vclk_per <= RGB514_clocks[i].limit) {
-	    pll->m = RGB514_clocks[i].m;
-	    pll->n = RGB514_clocks[i].n;
-	    return 0;
-	}
-    return -EINVAL;
-}
-
-
-static void aty_StrobeClock(const struct fb_info_aty *info)
-{
-    u8 tmp;
-
-    udelay(26);
-
-    tmp = aty_ld_8(CLOCK_CNTL, info);
-    aty_st_8(CLOCK_CNTL + info->clk_wr_offset, tmp | CLOCK_STROBE, info);
-
-    return;
-}
-
-
-static void aty_ICS2595_put1bit(u8 data, const struct fb_info_aty *info)
-{
-    u8 tmp;
-
-    data &= 0x01;
-    tmp = aty_ld_8(CLOCK_CNTL, info);
-    aty_st_8(CLOCK_CNTL + info->clk_wr_offset, (tmp & ~0x04) | (data << 2),
-	     info);
-
-    tmp = aty_ld_8(CLOCK_CNTL, info);
-    aty_st_8(CLOCK_CNTL + info->clk_wr_offset, (tmp & ~0x08) | (0 << 3), info);
-
-    aty_StrobeClock(info);
-
-    tmp = aty_ld_8(CLOCK_CNTL, info);
-    aty_st_8(CLOCK_CNTL + info->clk_wr_offset, (tmp & ~0x08) | (1 << 3), info);
-
-    aty_StrobeClock(info);
-
-    return;
-}
-
-
-static u32 aty_pll_gx_to_var(const struct pll_gx *pll,
-			     const struct fb_info_aty *info)
-{
-    u8 df, vco_div_count, ref_div_count;
-
-    df = pll->m >> 6;
-    vco_div_count = pll->m & 0x3f;
-    ref_div_count = pll->n;
-
-    return ((info->ref_clk_per*ref_div_count)<<(3-df))/(vco_div_count+65);
-}
-
-
-    /*
-     *  PLL programming (Mach64 CT family)
-     */
-
-static void aty_set_pll_ct(const struct fb_info_aty *info,
-			   const struct pll_ct *pll)
-{
-    aty_st_pll(PLL_REF_DIV, pll->pll_ref_div, info);
-    aty_st_pll(PLL_GEN_CNTL, pll->pll_gen_cntl, info);
-    aty_st_pll(MCLK_FB_DIV, pll->mclk_fb_div, info);
-    aty_st_pll(PLL_VCLK_CNTL, pll->pll_vclk_cntl, info);
-    aty_st_pll(VCLK_POST_DIV, pll->vclk_post_div, info);
-    aty_st_pll(VCLK0_FB_DIV, pll->vclk_fb_div, info);
-    aty_st_pll(PLL_EXT_CNTL, pll->pll_ext_cntl, info);
-
-    if (!(Gx == GX_CHIP_ID || Gx == CX_CHIP_ID || Gx == CT_CHIP_ID ||
-	  Gx == ET_CHIP_ID ||
-	  ((Gx == VT_CHIP_ID || Gx == GT_CHIP_ID) && !(Rev & 0x07)))) {
-	if (Gx == XL_CHIP_ID) {
-	    aty_st_pll(DLL_CNTL, 0x80, info);
-	} else {
-	    if (info->ram_type >= SDRAM)
-		aty_st_pll(DLL_CNTL, 0xa6, info);
-	    else
-		aty_st_pll(DLL_CNTL, 0xa0, info);
-	}
-	aty_st_pll(VFC_CNTL, 0x1b, info);
-	aty_st_le32(DSP_CONFIG, pll->dsp_config, info);
-	aty_st_le32(DSP_ON_OFF, pll->dsp_on_off, info);
-    }
-}
-
-static int aty_dsp_gt(const struct fb_info_aty *info, u8 bpp,
-		      struct pll_ct *pll)
-{
-    u32 dsp_xclks_per_row, dsp_loop_latency, dsp_precision, dsp_off, dsp_on;
-    u32 xclks_per_row, fifo_off, fifo_on, y, fifo_size, page_size;
-
-    /* xclocks_per_row<<11 */
-    xclks_per_row = (pll->mclk_fb_div*pll->vclk_post_div_real*64<<11)/
-		    (pll->vclk_fb_div*pll->mclk_post_div_real*bpp);
-    if (xclks_per_row < (1<<11))
-	FAIL("Dotclock to high");
-    if (Gx == GT_CHIP_ID || Gx == GU_CHIP_ID || Gx == VT_CHIP_ID ||
-	Gx == VU_CHIP_ID || Gx == GV_CHIP_ID || Gx == GW_CHIP_ID ||
-	Gx == GZ_CHIP_ID) {
-	fifo_size = 24;
-	dsp_loop_latency = 0;
-    } else {
-	fifo_size = 32;
-	dsp_loop_latency = 2;
-    }
-    dsp_precision = 0;
-    y = (xclks_per_row*fifo_size)>>11;
-    while (y) {
-	y >>= 1;
-	dsp_precision++;
-    }
-    dsp_precision -= 5;
-    /* fifo_off<<6 */
-    fifo_off = ((xclks_per_row*(fifo_size-1))>>5)+(3<<6);
-
-    if (info->total_vram > 1*1024*1024) {
-	if (info->ram_type >= SDRAM) {
-	    /* >1 MB SDRAM */
-	    dsp_loop_latency += 8;
-	    page_size = 8;
-	} else {
-	    /* >1 MB DRAM */
-	    dsp_loop_latency += 6;
-	    page_size = 9;
-	}
-    } else {
-	if (info->ram_type >= SDRAM) {
-	    /* <2 MB SDRAM */
-	    dsp_loop_latency += 9;
-	    page_size = 10;
-	} else {
-	    /* <2 MB DRAM */
-	    dsp_loop_latency += 8;
-	    page_size = 10;
-	}
-    }
-    /* fifo_on<<6 */
-    if (xclks_per_row >= (page_size<<11))
-	fifo_on = ((2*page_size+1)<<6)+(xclks_per_row>>5);
-    else
-	fifo_on = (3*page_size+2)<<6;
-
-    dsp_xclks_per_row = xclks_per_row>>dsp_precision;
-    dsp_on = fifo_on>>dsp_precision;
-    dsp_off = fifo_off>>dsp_precision;
-
-    pll->dsp_config = (dsp_xclks_per_row & 0x3fff) |
-		      ((dsp_loop_latency & 0xf)<<16) |
-		      ((dsp_precision & 7)<<20);
-    pll->dsp_on_off = (dsp_on & 0x7ff) | ((dsp_off & 0x7ff)<<16);
-    return 0;
-}
-
-static int aty_valid_pll_ct(const struct fb_info_aty *info, u32 vclk_per,
-			    struct pll_ct *pll)
-{
-    u32 q, x;			/* x is a workaround for sparc64-linux-gcc */
-    x = x;			/* x is a workaround for sparc64-linux-gcc */
-
-    pll->pll_ref_div = info->pll_per*2*255/info->ref_clk_per;
-
-    /* FIXME: use the VTB/GTB /3 post divider if it's better suited */
-    q = info->ref_clk_per*pll->pll_ref_div*4/info->mclk_per;	/* actually 8*q */
-    if (q < 16*8 || q > 255*8)
-	FAIL("mclk out of range");
-    else if (q < 32*8)
-	pll->mclk_post_div_real = 8;
-    else if (q < 64*8)
-	pll->mclk_post_div_real = 4;
-    else if (q < 128*8)
-	pll->mclk_post_div_real = 2;
-    else
-	pll->mclk_post_div_real = 1;
-    pll->mclk_fb_div = q*pll->mclk_post_div_real/8;
-
-    /* FIXME: use the VTB/GTB /{3,6,12} post dividers if they're better suited */
-    q = info->ref_clk_per*pll->pll_ref_div*4/vclk_per;	/* actually 8*q */
-    if (q < 16*8 || q > 255*8)
-	FAIL("vclk out of range");
-    else if (q < 32*8)
-	pll->vclk_post_div_real = 8;
-    else if (q < 64*8)
-	pll->vclk_post_div_real = 4;
-    else if (q < 128*8)
-	pll->vclk_post_div_real = 2;
-    else
-	pll->vclk_post_div_real = 1;
-    pll->vclk_fb_div = q*pll->vclk_post_div_real/8;
-    return 0;
-}
-
-static void aty_calc_pll_ct(const struct fb_info_aty *info, struct pll_ct *pll)
-{
-    u8 mpostdiv = 0;
-    u8 vpostdiv = 0;
-
-    if ((((Gx == GT_CHIP_ID) && (Rev & 0x03)) || (Gx == GU_CHIP_ID) ||
-	 (Gx == GV_CHIP_ID) || (Gx == GW_CHIP_ID) || (Gx == GZ_CHIP_ID) ||
-	 (Gx == LG_CHIP_ID) || (Gx == GB_CHIP_ID) || (Gx == GD_CHIP_ID) ||
-	 (Gx == GI_CHIP_ID) || (Gx == GP_CHIP_ID) || (Gx == GQ_CHIP_ID) ||
-	 (Gx == XL_CHIP_ID) ||
-	 (Gx == VU_CHIP_ID)) && (info->ram_type >= SDRAM))
-	pll->pll_gen_cntl = 0x04;
-    else
-	pll->pll_gen_cntl = 0x84;
-
-    switch (pll->mclk_post_div_real) {
-	case 1:
-	    mpostdiv = 0;
-	    break;
-	case 2:
-	    mpostdiv = 1;
-	    break;
-	case 3:
-	    mpostdiv = 4;
-	    break;
-	case 4:
-	    mpostdiv = 2;
-	    break;
-	case 8:
-	    mpostdiv = 3;
-	    break;
-    }
-    pll->pll_gen_cntl |= mpostdiv<<4;	/* mclk */
-
-    if (Gx == VT_CHIP_ID && (Rev == 0x40 || Rev == 0x48))
-	pll->pll_ext_cntl = 0;
-    else
-    	pll->pll_ext_cntl = mpostdiv;	/* xclk == mclk */
-
-    switch (pll->vclk_post_div_real) {
-	case 2:
-	    vpostdiv = 1;
-	    break;
-	case 3:
-	    pll->pll_ext_cntl |= 0x10;
-	case 1:
-	    vpostdiv = 0;
-	    break;
-	case 6:
-	    pll->pll_ext_cntl |= 0x10;
-	case 4:
-	    vpostdiv = 2;
-	    break;
-	case 12:
-	    pll->pll_ext_cntl |= 0x10;
-	case 8:
-	    vpostdiv = 3;
-	    break;
-    }
-
-    pll->pll_vclk_cntl = 0x03;	/* VCLK = PLL_VCLK/VCLKx_POST */
-    pll->vclk_post_div = vpostdiv;
-}
-
-static int aty_var_to_pll_ct(const struct fb_info_aty *info, u32 vclk_per,
-			     u8 bpp, struct pll_ct *pll)
-{
-    int err;
-
-    if ((err = aty_valid_pll_ct(info, vclk_per, pll)))
-	return err;
-    if (!(Gx == GX_CHIP_ID || Gx == CX_CHIP_ID || Gx == CT_CHIP_ID ||
-	  Gx == ET_CHIP_ID ||
-	  ((Gx == VT_CHIP_ID || Gx == GT_CHIP_ID) && !(Rev & 0x07)))) {
-	if ((err = aty_dsp_gt(info, bpp, pll)))
-	    return err;
-    }
-    aty_calc_pll_ct(info, pll);
-    return 0;
-}
-
-static u32 aty_pll_ct_to_var(const struct pll_ct *pll,
-			     const struct fb_info_aty *info)
-{
-    u32 ref_clk_per = info->ref_clk_per;
-    u8 pll_ref_div = pll->pll_ref_div;
-    u8 vclk_fb_div = pll->vclk_fb_div;
-    u8 vclk_post_div = pll->vclk_post_div_real;
-
-    return ref_clk_per*pll_ref_div*vclk_post_div/vclk_fb_div/2;
-}
-
-/* ------------------------------------------------------------------------- */
-
-static void atyfb_set_par(const struct atyfb_par *par,
-			  struct fb_info_aty *info)
-{
-    u32 i;
-    int accelmode;
-    int muxmode;
-    u8 tmp;
-
-    accelmode = par->accel_flags;  /* hack */
-
-    info->current_par = *par;
-
-    if (info->blitter_may_be_busy)
-	wait_for_idle(info);
-    tmp = aty_ld_8(CRTC_GEN_CNTL + 3, info);
-    aty_set_crtc(info, &par->crtc);
-    aty_st_8(CLOCK_CNTL + info->clk_wr_offset, 0, info);
-					/* better call aty_StrobeClock ?? */
-    aty_st_8(CLOCK_CNTL + info->clk_wr_offset, CLOCK_STROBE, info);
-
-    if ((Gx == GX_CHIP_ID) || (Gx == CX_CHIP_ID)) {
-	switch (info->dac_subtype) {
-	    case DAC_IBMRGB514:
-		aty_set_dac_514(info, par->crtc.bpp);
-		break;
-	    case DAC_ATI68860_B:
-	    case DAC_ATI68860_C:
-		muxmode = aty_set_dac_ATI68860_B(info, par->crtc.bpp,
-						 accelmode);
-		aty_st_le32(BUS_CNTL, 0x890e20f1, info);
-		aty_st_le32(DAC_CNTL, 0x47052100, info);
-		break;
-	    case DAC_ATT20C408:
-		muxmode = aty_set_dac_ATT21C498(info, &par->pll.ics2595,
-						par->crtc.bpp);
-		aty_st_le32(BUS_CNTL, 0x890e20f1, info);
-		aty_st_le32(DAC_CNTL, 0x00072000, info);
-		break;
-	    case DAC_ATT21C498:
-		muxmode = aty_set_dac_ATT21C498(info, &par->pll.ics2595,
-						par->crtc.bpp);
-		aty_st_le32(BUS_CNTL, 0x890e20f1, info);
-		aty_st_le32(DAC_CNTL, 0x00072000, info);
-		break;
-	    default:
-		printk(" atyfb_set_par: DAC type not implemented yet!\n");
-		aty_st_le32(BUS_CNTL, 0x890e20f1, info);
-		aty_st_le32(DAC_CNTL, 0x47052100, info);
-	/* new in 2.2.3p1 from Geert. ???????? */
-	aty_st_le32(BUS_CNTL, 0x590e10ff, info);
-	aty_st_le32(DAC_CNTL, 0x47012100, info);
-		break;
-	}
-
-	switch (info->clk_type) {
-	    case CLK_ATI18818_1:
-		aty_set_pll18818(info, &par->pll.ics2595);
-		break;
-	    case CLK_STG1703:
-		aty_set_pll_1703(info, &par->pll.ics2595);
-		break;
-	    case CLK_CH8398:
-		aty_set_pll_8398(info, &par->pll.ics2595);
-		break;
-	    case CLK_ATT20C408:
-		aty_set_pll_408(info, &par->pll.ics2595);
-		break;
-	    case CLK_IBMRGB514:
-		aty_set_pll_gx(info, &par->pll.gx);
-		break;
-	    default:
-		printk(" atyfb_set_par: CLK type not implemented yet!");
-		break;
-	}
-
-	/* Don't forget MEM_CNTL */
-	i = aty_ld_le32(MEM_CNTL, info) & 0xf0ffffff;
-	switch (par->crtc.bpp) {
-	    case 8:
-		i |= 0x02000000;
-		break;
-	    case 16:
-		i |= 0x03000000;
-		break;
-	    case 32:
-		i |= 0x06000000;
-		break;
-	}
-	aty_st_le32(MEM_CNTL, i, info);
-
-    } else {
-	aty_set_pll_ct(info, &par->pll.ct);
-	i = aty_ld_le32(MEM_CNTL, info) & 0xf00fffff;
-	if (!(Gx == VT_CHIP_ID && (Rev == 0x40 || Rev == 0x48)))
-	    i |= info->mem_refresh_rate << 20;
-	switch (par->crtc.bpp) {
-	    case 8:
-	    case 24:
-		i |= 0x00000000;
-		break;
-	    case 16:
-		i |= 0x04000000;
-		break;
-	    case 32:
-		i |= 0x08000000;
-		break;
-	}
-	if ((Gx == CT_CHIP_ID) || (Gx == ET_CHIP_ID)) {
-	    aty_st_le32(DAC_CNTL, 0x87010184, info);
-	    aty_st_le32(BUS_CNTL, 0x680000f9, info);
-	} else if ((Gx == VT_CHIP_ID) || (Gx == VU_CHIP_ID)) {
-	    aty_st_le32(DAC_CNTL, 0x87010184, info);
-	    aty_st_le32(BUS_CNTL, 0x680000f9, info);
-	}  else if ((Gx == LN_CHIP_ID) || (Gx == LM_CHIP_ID)) {
-	    aty_st_le32(DAC_CNTL, 0x80010102, info);
-	    aty_st_le32(BUS_CNTL, 0x7b33a040, info);
-	} else {
-	    /* GT */
-	    aty_st_le32(DAC_CNTL, 0x86010102, info);
-	    aty_st_le32(BUS_CNTL, 0x7b23a040, info);
-	    aty_st_le32(EXT_MEM_CNTL,
-			aty_ld_le32(EXT_MEM_CNTL, info) | 0x5000001, info);
-	}
-	aty_st_le32(MEM_CNTL, i, info);
-    }
-    aty_st_8(DAC_MASK, 0xff, info);
-
-    /* Initialize the graphics engine */
-    if (par->accel_flags & FB_ACCELF_TEXT)
-	init_engine(par, info);
-
-#ifdef CONFIG_FB_COMPAT_XPMAC
-    if (!console_fb_info || console_fb_info == &info->fb_info) {
-	struct fb_var_screeninfo var;
-	int vmode, cmode;
-	display_info.height = ((par->crtc.v_tot_disp>>16) & 0x7ff)+1;
-	display_info.width = (((par->crtc.h_tot_disp>>16) & 0xff)+1)*8;
-	display_info.depth = par->crtc.bpp;
-	display_info.pitch = par->crtc.vxres*par->crtc.bpp/8;
-	atyfb_encode_var(&var, par, info);
-	if (mac_var_to_vmode(&var, &vmode, &cmode))
-	    display_info.mode = 0;
-	else
-	    display_info.mode = vmode;
-	strcpy(display_info.name, atyfb_name);
-	display_info.fb_address = info->frame_buffer_phys;
-	display_info.cmap_adr_address = info->ati_regbase_phys+0xc0;
-	display_info.cmap_data_address = info->ati_regbase_phys+0xc1;
-	display_info.disp_reg_address = info->ati_regbase_phys;
-    }
-#endif /* CONFIG_FB_COMPAT_XPMAC */
-}
-
-static int atyfb_decode_var(const struct fb_var_screeninfo *var,
-			    struct atyfb_par *par,
-			    const struct fb_info_aty *info)
-{
-    int err;
-
-    if ((err = aty_var_to_crtc(info, var, &par->crtc)))
-	return err;
-    if ((Gx == GX_CHIP_ID) || (Gx == CX_CHIP_ID))
-	switch (info->clk_type) {
-	    case CLK_ATI18818_1:
-		err = aty_var_to_pll_18818(var->pixclock, &par->pll.ics2595);
-		break;
-	    case CLK_STG1703:
-		err = aty_var_to_pll_1703(var->pixclock, &par->pll.ics2595);
-		break;
-	    case CLK_CH8398:
-		err = aty_var_to_pll_8398(var->pixclock, &par->pll.ics2595);
-		break;
-	    case CLK_ATT20C408:
-		err = aty_var_to_pll_408(var->pixclock, &par->pll.ics2595);
-		break;
-	    case CLK_IBMRGB514:
-		err = aty_var_to_pll_514(var->pixclock, &par->pll.gx);
-		break;
-	}
-    else
-	err = aty_var_to_pll_ct(info, var->pixclock, par->crtc.bpp,
-				&par->pll.ct);
-    if (err)
-	return err;
-
-    if (var->accel_flags & FB_ACCELF_TEXT)
-	par->accel_flags = FB_ACCELF_TEXT;
-    else
-	par->accel_flags = 0;
-
-#if 0 /* fbmon is not done. uncomment for 2.5.x -brad */
-    if (!fbmon_valid_timings(var->pixclock, htotal, vtotal, info))
-	return -EINVAL;
-#endif
-
-    return 0;
-}
-
-static int atyfb_encode_var(struct fb_var_screeninfo *var,
-			    const struct atyfb_par *par,
-			    const struct fb_info_aty *info)
-{
-    int err;
-
-    memset(var, 0, sizeof(struct fb_var_screeninfo));
-
-    if ((err = aty_crtc_to_var(&par->crtc, var)))
-	return err;
-    if ((Gx == GX_CHIP_ID) || (Gx == CX_CHIP_ID))
-	switch (info->clk_type) {
-	    case CLK_ATI18818_1:
-		var->pixclock = aty_pll_18818_to_var(&par->pll.ics2595);
-		break;
-	    case CLK_STG1703:
-		var->pixclock = aty_pll_1703_to_var(&par->pll.ics2595);
-		break;
-	    case CLK_CH8398:
-		var->pixclock = aty_pll_8398_to_var(&par->pll.ics2595);
-		break;
-	    case CLK_ATT20C408:
-		var->pixclock = aty_pll_408_to_var(&par->pll.ics2595);
-		break;
-	    case CLK_IBMRGB514:
-	        var->pixclock = aty_pll_gx_to_var(&par->pll.gx, info);
-		break;
-	}
-    else
-	var->pixclock = aty_pll_ct_to_var(&par->pll.ct, info);
-
-    var->height = -1;
-    var->width = -1;
-    var->accel_flags = par->accel_flags;
-
-    return 0;
-}
-
-
-
-static void set_off_pitch(struct atyfb_par *par,
-			  const struct fb_info_aty *info)
-{
-    u32 xoffset = par->crtc.xoffset;
-    u32 yoffset = par->crtc.yoffset;
-    u32 vxres = par->crtc.vxres;
-    u32 bpp = par->crtc.bpp;
-
-    par->crtc.off_pitch = ((yoffset*vxres+xoffset)*bpp/64) | (vxres<<19);
-    aty_st_le32(CRTC_OFF_PITCH, par->crtc.off_pitch, info);
-}
-
-
-    /*
-     *  Open/Release the frame buffer device
-     */
-
-static int atyfb_open(struct fb_info *info, int user)
-
-{
-#ifdef __sparc__
-    struct fb_info_aty *fb = (struct fb_info_aty *)info;
-
-    if (user) {
-	fb->open++;
-	fb->mmaped = 0;
-	fb->vtconsole = -1;
-    } else {
-	fb->consolecnt++;
-    }
-#endif
-    return(0);
-}
-
-struct fb_var_screeninfo default_var = {
-    /* 640x480, 60 Hz, Non-Interlaced (25.175 MHz dotclock) */
-    640, 480, 640, 480, 0, 0, 8, 0,
-    {0, 8, 0}, {0, 8, 0}, {0, 8, 0}, {0, 0, 0},
-    0, 0, -1, -1, 0, 39722, 48, 16, 33, 10, 96, 2,
-    0, FB_VMODE_NONINTERLACED
-};
-
-static int atyfb_release(struct fb_info *info, int user)
-{
-#ifdef __sparc__
-    struct fb_info_aty *fb = (struct fb_info_aty *)info;
-
-    if (user) {
-	fb->open--;
-	udelay(1000);
-	wait_for_idle(fb);
-	if (!fb->open) {
-		int was_mmaped = fb->mmaped;
-
-		fb->mmaped = 0;
-		if (fb->vtconsole != -1)
-			vt_cons[fb->vtconsole]->vc_mode = KD_TEXT;
-		fb->vtconsole = -1;
-
-		if (was_mmaped) {
-			struct fb_var_screeninfo var;
-
-			/* Now reset the default display config, we have no
-			 * idea what the program(s) which mmap'd the chip did
-			 * to the configuration, nor whether it restored it
-			 * correctly.
-			 */
-			var = default_var;
-			if (noaccel)
-				var.accel_flags &= ~FB_ACCELF_TEXT;
-			else
-				var.accel_flags |= FB_ACCELF_TEXT;
-			if (var.yres == var.yres_virtual) {
-				u32 vram = (fb->total_vram - (PAGE_SIZE << 2));
-				var.yres_virtual = ((vram * 8) / var.bits_per_pixel) /
-					var.xres_virtual;
-				if (var.yres_virtual < var.yres)
-					var.yres_virtual = var.yres;
-			}
-			atyfb_set_var(&var, -1, &fb->fb_info);
-		}
-	}
-    } else {
-	fb->consolecnt--;
-    }
-#endif
-    return(0);
-}
-
-
-static int encode_fix(struct fb_fix_screeninfo *fix,
-		      const struct atyfb_par *par,
-		      const struct fb_info_aty *info)
-{
-    memset(fix, 0, sizeof(struct fb_fix_screeninfo));
-
-    strcpy(fix->id, atyfb_name);
-    fix->smem_start = info->frame_buffer_phys;
-    fix->smem_len = (u32)info->total_vram;
-
-    /*
-     *  Reg Block 0 (CT-compatible block) is at ati_regbase_phys
-     *  Reg Block 1 (multimedia extensions) is at ati_regbase_phys-0x400
-     */
-    if (Gx == GX_CHIP_ID || Gx == CX_CHIP_ID) {
-	fix->mmio_start = info->ati_regbase_phys;
-	fix->mmio_len = 0x400;
-	fix->accel = FB_ACCEL_ATI_MACH64GX;
-    } else if (Gx == CT_CHIP_ID || Gx == ET_CHIP_ID) {
-	fix->mmio_start = info->ati_regbase_phys;
-	fix->mmio_len = 0x400;
-	fix->accel = FB_ACCEL_ATI_MACH64CT;
-    } else if (Gx == VT_CHIP_ID || Gx == VU_CHIP_ID || Gx == VV_CHIP_ID) {
-	fix->mmio_start = info->ati_regbase_phys-0x400;
-	fix->mmio_len = 0x800;
-	fix->accel = FB_ACCEL_ATI_MACH64VT;
-    } else {
-	fix->mmio_start = info->ati_regbase_phys-0x400;
-	fix->mmio_len = 0x800;
-	fix->accel = FB_ACCEL_ATI_MACH64GT;
-    }
-    fix->type = FB_TYPE_PACKED_PIXELS;
-    fix->type_aux = 0;
-    fix->line_length = par->crtc.vxres*par->crtc.bpp/8;
-    fix->visual = par->crtc.bpp <= 8 ? FB_VISUAL_PSEUDOCOLOR
-				     : FB_VISUAL_DIRECTCOLOR;
-    fix->ywrapstep = 0;
-    fix->xpanstep = 8;
-    fix->ypanstep = 1;
-
-    return 0;
-}
-
-
-    /*
-     *  Get the Fixed Part of the Display
-     */
-
-static int atyfb_get_fix(struct fb_fix_screeninfo *fix, int con,
-			 struct fb_info *fb)
-{
-    const struct fb_info_aty *info = (struct fb_info_aty *)fb;
-    struct atyfb_par par;
-
-    if (con == -1)
-	par = info->default_par;
-    else
-	atyfb_decode_var(&fb_display[con].var, &par, info);
-    encode_fix(fix, &par, info);
-    return 0;
-}
-
-
-    /*
-     *  Get the User Defined Part of the Display
-     */
-
-static int atyfb_get_var(struct fb_var_screeninfo *var, int con,
-			 struct fb_info *fb)
-{
-    const struct fb_info_aty *info = (struct fb_info_aty *)fb;
-
-    if (con == -1)
-	atyfb_encode_var(var, &info->default_par, info);
-    else
-	*var = fb_display[con].var;
-    return 0;
-}
-
-
-static void atyfb_set_dispsw(struct display *disp, struct fb_info_aty *info,
-			     int bpp, int accel)
-{
-	    switch (bpp) {
-#ifdef FBCON_HAS_CFB8
-		case 8:
-		    info->dispsw = accel ? fbcon_aty8 : fbcon_cfb8;
-		    disp->dispsw = &info->dispsw;
-		    break;
-#endif
-#ifdef FBCON_HAS_CFB16
-		case 16:
-		    info->dispsw = accel ? fbcon_aty16 : fbcon_cfb16;
-		    disp->dispsw = &info->dispsw;
-		    disp->dispsw_data = info->fbcon_cmap.cfb16;
-		    break;
-#endif
-#ifdef FBCON_HAS_CFB24
-		case 24:
-		    info->dispsw = accel ? fbcon_aty24 : fbcon_cfb24;
-		    disp->dispsw = &info->dispsw;
-		    disp->dispsw_data = info->fbcon_cmap.cfb24;
-		    break;
-#endif
-#ifdef FBCON_HAS_CFB32
-		case 32:
-		    info->dispsw = accel ? fbcon_aty32 : fbcon_cfb32;
-		    disp->dispsw = &info->dispsw;
-		    disp->dispsw_data = info->fbcon_cmap.cfb32;
-		    break;
-#endif
-		default:
-		    disp->dispsw = &fbcon_dummy;
-	    }
-	    if (info->cursor) {
-		info->dispsw.cursor = atyfb_cursor;
-		info->dispsw.set_font = atyfb_set_font;
-	    }
-}
-
-
-    /*
-     *  Set the User Defined Part of the Display
-     */
-
-static int atyfb_set_var(struct fb_var_screeninfo *var, int con,
-			 struct fb_info *fb)
-{
-    struct fb_info_aty *info = (struct fb_info_aty *)fb;
-    struct atyfb_par par;
-    struct display *display;
-    int oldxres, oldyres, oldvxres, oldvyres, oldbpp, oldaccel, accel, err;
-    int activate = var->activate;
-
-    if (con >= 0)
-	display = &fb_display[con];
-    else
-	display = fb->disp;	/* used during initialization */
-
-    if ((err = atyfb_decode_var(var, &par, info)))
-	return err;
-
-    atyfb_encode_var(var, &par, (struct fb_info_aty *)info);
-
-    if ((activate & FB_ACTIVATE_MASK) == FB_ACTIVATE_NOW) {
-	oldxres = display->var.xres;
-	oldyres = display->var.yres;
-	oldvxres = display->var.xres_virtual;
-	oldvyres = display->var.yres_virtual;
-	oldbpp = display->var.bits_per_pixel;
-	oldaccel = display->var.accel_flags;
-	display->var = *var;
-	accel = var->accel_flags & FB_ACCELF_TEXT;
-	if (oldxres != var->xres || oldyres != var->yres ||
-	    oldvxres != var->xres_virtual || oldvyres != var->yres_virtual ||
-	    oldbpp != var->bits_per_pixel || oldaccel != var->accel_flags) {
-	    struct fb_fix_screeninfo fix;
-
-	    encode_fix(&fix, &par, info);
-	    display->screen_base = (char *)info->frame_buffer;
-	    display->visual = fix.visual;
-	    display->type = fix.type;
-	    display->type_aux = fix.type_aux;
-	    display->ypanstep = fix.ypanstep;
-	    display->ywrapstep = fix.ywrapstep;
-	    display->line_length = fix.line_length;
-	    display->can_soft_blank = 1;
-	    display->inverse = 0;
-	    if (accel)
-	    	display->scrollmode = (info->bus_type == PCI) ? SCROLL_YNOMOVE : 0;
-	    else
-	    	display->scrollmode = SCROLL_YREDRAW;
-	    if (info->fb_info.changevar)
-		(*info->fb_info.changevar)(con);
-	}
-	if (!info->fb_info.display_fg ||
-	    info->fb_info.display_fg->vc_num == con) {
-	    atyfb_set_par(&par, info);
-	    atyfb_set_dispsw(display, info, par.crtc.bpp, accel);
-	}
-	if (oldbpp != var->bits_per_pixel) {
-	    if ((err = fb_alloc_cmap(&display->cmap, 0, 0)))
-		return err;
-	    do_install_cmap(con, &info->fb_info);
-	}
-    }
-
-    return 0;
-}
-
-
-    /*
-     *  Pan or Wrap the Display
-     *
-     *  This call looks only at xoffset, yoffset and the FB_VMODE_YWRAP flag
-     */
-
-static int atyfb_pan_display(struct fb_var_screeninfo *var, int con,
-			     struct fb_info *fb)
-{
-    struct fb_info_aty *info = (struct fb_info_aty *)fb;
-    u32 xres, yres, xoffset, yoffset;
-    struct atyfb_par *par = &info->current_par;
-
-    xres = (((par->crtc.h_tot_disp>>16) & 0xff)+1)*8;
-    yres = ((par->crtc.v_tot_disp>>16) & 0x7ff)+1;
-    xoffset = (var->xoffset+7) & ~7;
-    yoffset = var->yoffset;
-    if (xoffset+xres > par->crtc.vxres || yoffset+yres > par->crtc.vyres)
-	return -EINVAL;
-    par->crtc.xoffset = xoffset;
-    par->crtc.yoffset = yoffset;
-    set_off_pitch(par, info);
-    return 0;
-}
-
-    /*
-     *  Get the Colormap
-     */
-
-static int atyfb_get_cmap(struct fb_cmap *cmap, int kspc, int con,
-			  struct fb_info *info)
-{
-    if (!info->display_fg || con == info->display_fg->vc_num) /* current console? */
-	return fb_get_cmap(cmap, kspc, atyfb_getcolreg, info);
-    else if (fb_display[con].cmap.len) /* non default colormap? */
-	fb_copy_cmap(&fb_display[con].cmap, cmap, kspc ? 0 : 2);
-    else {
-	int size = fb_display[con].var.bits_per_pixel == 16 ? 32 : 256;
-	fb_copy_cmap(fb_default_cmap(size), cmap, kspc ? 0 : 2);
-    }
-    return 0;
-}
-
-    /*
-     *  Set the Colormap
-     */
-
-static int atyfb_set_cmap(struct fb_cmap *cmap, int kspc, int con,
-			  struct fb_info *info)
-{
-    int err;
-    struct display *disp;
-
-    if (con >= 0)
-    	disp = &fb_display[con];
-    else
-        disp = info->disp;
-    if (!disp->cmap.len) {	/* no colormap allocated? */
-	int size = disp->var.bits_per_pixel == 16 ? 32 : 256;
-	if ((err = fb_alloc_cmap(&disp->cmap, size, 0)))
-	    return err;
-    }
-    if (!info->display_fg || con == info->display_fg->vc_num)			/* current console? */
-	return fb_set_cmap(cmap, kspc, atyfb_setcolreg, info);
-    else
-	fb_copy_cmap(cmap, &disp->cmap, kspc ? 0 : 1);
-    return 0;
-}
-
-
-#ifdef DEBUG
-#define ATYIO_CLKR		0x41545900	/* ATY\00 */
-#define ATYIO_CLKW		0x41545901	/* ATY\01 */
-
-struct atyclk {
-    u32 ref_clk_per;
-    u8 pll_ref_div;
-    u8 mclk_fb_div;
-    u8 mclk_post_div;		/* 1,2,3,4,8 */
-    u8 vclk_fb_div;
-    u8 vclk_post_div;		/* 1,2,3,4,6,8,12 */
-    u32 dsp_xclks_per_row;	/* 0-16383 */
-    u32 dsp_loop_latency;	/* 0-15 */
-    u32 dsp_precision;		/* 0-7 */
-    u32 dsp_on;			/* 0-2047 */
-    u32 dsp_off;		/* 0-2047 */
-};
-#endif
-
-static int atyfb_ioctl(struct inode *inode, struct file *file, u_int cmd,
-		       u_long arg, int con, struct fb_info *info2)
-{
-#if defined(__sparc__) || defined(DEBUG)
-    struct fb_info_aty *info = (struct fb_info_aty *)info2;
-#endif /* __sparc__ || DEBUG */
-#ifdef __sparc__
-    struct fbtype fbtyp;
-    struct display *disp;
-
-    if (con >= 0)
-    	disp = &fb_display[con];
-    else
-        disp = info2->disp;
-#endif
-
-    switch (cmd) {
-#ifdef __sparc__
-    case FBIOGTYPE:
-	fbtyp.fb_type = FBTYPE_PCI_GENERIC;
-	fbtyp.fb_width = info->current_par.crtc.vxres;
-	fbtyp.fb_height = info->current_par.crtc.vyres;
-	fbtyp.fb_depth = info->current_par.crtc.bpp;
-	fbtyp.fb_cmsize = disp->cmap.len;
-	fbtyp.fb_size = info->total_vram;
-	if (copy_to_user((struct fbtype *)arg, &fbtyp, sizeof(fbtyp)))
-		return -EFAULT;
-	break;
-#endif /* __sparc__ */
-#ifdef DEBUG
-    case ATYIO_CLKR:
-	if ((Gx != GX_CHIP_ID) && (Gx != CX_CHIP_ID)) {
-	    struct atyclk clk;
-	    struct pll_ct *pll = &info->current_par.pll.ct;
-	    u32 dsp_config = pll->dsp_config;
-	    u32 dsp_on_off = pll->dsp_on_off;
-	    clk.ref_clk_per = info->ref_clk_per;
-	    clk.pll_ref_div = pll->pll_ref_div;
-	    clk.mclk_fb_div = pll->mclk_fb_div;
-	    clk.mclk_post_div = pll->mclk_post_div_real;
-	    clk.vclk_fb_div = pll->vclk_fb_div;
-	    clk.vclk_post_div = pll->vclk_post_div_real;
-	    clk.dsp_xclks_per_row = dsp_config & 0x3fff;
-	    clk.dsp_loop_latency = (dsp_config>>16) & 0xf;
-	    clk.dsp_precision = (dsp_config>>20) & 7;
-	    clk.dsp_on = dsp_on_off & 0x7ff;
-	    clk.dsp_off = (dsp_on_off>>16) & 0x7ff;
-	    if (copy_to_user((struct atyclk *)arg, &clk, sizeof(clk)))
-		    return -EFAULT;
-	} else
-	    return -EINVAL;
-	break;
-    case ATYIO_CLKW:
-	if ((Gx != GX_CHIP_ID) && (Gx != CX_CHIP_ID)) {
-	    struct atyclk clk;
-	    struct pll_ct *pll = &info->current_par.pll.ct;
-	    if (copy_from_user(&clk, (struct atyclk *)arg, sizeof(clk)))
-		    return -EFAULT;
-	    info->ref_clk_per = clk.ref_clk_per;
-	    pll->pll_ref_div = clk.pll_ref_div;
-	    pll->mclk_fb_div = clk.mclk_fb_div;
-	    pll->mclk_post_div_real = clk.mclk_post_div;
-	    pll->vclk_fb_div = clk.vclk_fb_div;
-	    pll->vclk_post_div_real = clk.vclk_post_div;
-	    pll->dsp_config = (clk.dsp_xclks_per_row & 0x3fff) |
-			      ((clk.dsp_loop_latency & 0xf)<<16) |
-			      ((clk.dsp_precision & 7)<<20);
-	    pll->dsp_on_off = (clk.dsp_on & 0x7ff) |
-			      ((clk.dsp_off & 0x7ff)<<16);
-	    aty_calc_pll_ct(info, pll);
-	    aty_set_pll_ct(info, pll);
-	} else
-	    return -EINVAL;
-	break;
-#endif /* DEBUG */
-    default:
-	return -EINVAL;
-    }
-    return 0;
-}
-
-static int atyfb_rasterimg(struct fb_info *info, int start)
-{
-    struct fb_info_aty *fb = (struct fb_info_aty *)info;
-
-    if (fb->blitter_may_be_busy)
-	wait_for_idle(fb);
-    return 0;
-}
-
-#ifdef __sparc__
-static int atyfb_mmap(struct fb_info *info, struct file *file,
-		      struct vm_area_struct *vma)
-{
-	struct fb_info_aty *fb = (struct fb_info_aty *)info;
-	unsigned int size, page, map_size = 0;
-	unsigned long map_offset = 0;
-	unsigned long off;
-	int i;
-
-	if (!fb->mmap_map)
-		return -ENXIO;
-
-	if (vma->vm_pgoff > (~0UL >> PAGE_SHIFT))
-		return -EINVAL;
-
-	off = vma->vm_pgoff << PAGE_SHIFT;
-	size = vma->vm_end - vma->vm_start;
-
-	/* To stop the swapper from even considering these pages. */
-	vma->vm_flags |= (VM_SHM | VM_LOCKED);
-
-	if (((vma->vm_pgoff == 0) && (size == fb->total_vram)) ||
-	    ((off == fb->total_vram) && (size == PAGE_SIZE)))
-		off += 0x8000000000000000UL;
-
-	vma->vm_pgoff = off >> PAGE_SHIFT;	/* propagate off changes */
-
-	/* Each page, see which map applies */
-	for (page = 0; page < size; ) {
-		map_size = 0;
-		for (i = 0; fb->mmap_map[i].size; i++) {
-			unsigned long start = fb->mmap_map[i].voff;
-			unsigned long end = start + fb->mmap_map[i].size;
-			unsigned long offset = off + page;
-
-			if (start > offset)
-				continue;
-			if (offset >= end)
-				continue;
-
-			map_size = fb->mmap_map[i].size - (offset - start);
-			map_offset = fb->mmap_map[i].poff + (offset - start);
-			break;
-		}
-		if (!map_size) {
-			page += PAGE_SIZE;
-			continue;
-		}
-		if (page + map_size > size)
-			map_size = size - page;
-
-		pgprot_val(vma->vm_page_prot) &= ~(fb->mmap_map[i].prot_mask);
-		pgprot_val(vma->vm_page_prot) |= fb->mmap_map[i].prot_flag;
-
-		if (remap_page_range(vma->vm_start + page, map_offset,
-				     map_size, vma->vm_page_prot))
-			return -EAGAIN;
-
-		page += map_size;
-	}
-
-	if (!map_size)
-		return -EINVAL;
-
-	vma->vm_flags |= VM_IO;
-
-	if (!fb->mmaped) {
-		int lastconsole = 0;
-
-		if (info->display_fg)
-			lastconsole = info->display_fg->vc_num;
-		fb->mmaped = 1;
-		if (fb->consolecnt && fb_display[lastconsole].fb_info == info) {
-			fb->vtconsole = lastconsole;
-			vt_cons[lastconsole]->vc_mode = KD_GRAPHICS;
-		}
-	}
-	return 0;
-}
-
-static struct {
-	u32	yoffset;
-	u8	r[2][256];
-	u8	g[2][256];
-	u8	b[2][256];
-} atyfb_save;
-
-static void atyfb_save_palette(struct fb_info *fb, int enter)
-{
-	struct fb_info_aty *info = (struct fb_info_aty *)fb;
-	int i, tmp;
-
-	for (i = 0; i < 256; i++) {
-		tmp = aty_ld_8(DAC_CNTL, info) & 0xfc;
-		if (Gx == GT_CHIP_ID || Gx == GU_CHIP_ID || Gx == GV_CHIP_ID ||
-		    Gx == GW_CHIP_ID || Gx == GZ_CHIP_ID || Gx == LG_CHIP_ID ||
-		    Gx == GB_CHIP_ID || Gx == GD_CHIP_ID || Gx == GI_CHIP_ID ||
-		    Gx == GP_CHIP_ID || Gx == GQ_CHIP_ID || Gx == XL_CHIP_ID)
-			tmp |= 0x2;
-		aty_st_8(DAC_CNTL, tmp, info);
-		aty_st_8(DAC_MASK, 0xff, info);
-
-		writeb(i, &info->aty_cmap_regs->rindex);
-		atyfb_save.r[enter][i] = readb(&info->aty_cmap_regs->lut);
-		atyfb_save.g[enter][i] = readb(&info->aty_cmap_regs->lut);
-		atyfb_save.b[enter][i] = readb(&info->aty_cmap_regs->lut);
-		writeb(i, &info->aty_cmap_regs->windex);
-		writeb(atyfb_save.r[1-enter][i], &info->aty_cmap_regs->lut);
-		writeb(atyfb_save.g[1-enter][i], &info->aty_cmap_regs->lut);
-		writeb(atyfb_save.b[1-enter][i], &info->aty_cmap_regs->lut);
-	}
-}
-
-static void atyfb_palette(int enter)
-{
-	struct fb_info_aty *info;
-	struct atyfb_par *par;
-	struct display *d;
-	int i;
-
-	for (i = 0; i < MAX_NR_CONSOLES; i++) {
-		d = &fb_display[i];
-		if (d->fb_info &&
-		    d->fb_info->fbops == &atyfb_ops &&
-		    d->fb_info->display_fg &&
-		    d->fb_info->display_fg->vc_num == i) {
-			atyfb_save_palette(d->fb_info, enter);
-			info = (struct fb_info_aty *)d->fb_info;
-			par = &info->current_par;
-			if (enter) {
-				atyfb_save.yoffset = par->crtc.yoffset;
-				par->crtc.yoffset = 0;
-				set_off_pitch(par, info);
-			} else {
-				par->crtc.yoffset = atyfb_save.yoffset;
-				set_off_pitch(par, info);
-			}
-			break;
-		}
-	}
-}
-#endif /* __sparc__ */
-
-    /*
-     *  Initialisation
-     */
-
-static int __init aty_init(struct fb_info_aty *info, const char *name)
-{
-    u32 chip_id;
-    u32 i;
-    int j, k;
-    struct fb_var_screeninfo var;
-    struct display *disp;
-    const char *chipname = NULL, *ramname = NULL, *xtal;
-    int pll, mclk, gtb_memsize;
-#if defined(CONFIG_PPC)
-    int sense;
-#endif
-    u8 pll_ref_div;
-
-    info->aty_cmap_regs = (struct aty_cmap_regs *)(info->ati_regbase+0xc0);
-    chip_id = aty_ld_le32(CONFIG_CHIP_ID, info);
-    Gx = chip_id & CFG_CHIP_TYPE;
-    Rev = (chip_id & CFG_CHIP_REV)>>24;
-    for (j = 0; j < (sizeof(aty_features)/sizeof(*aty_features)); j++)
-	if (aty_features[j].chip_type == Gx) {
-	    chipname = aty_features[j].name;
-	    info->dac_type = (aty_ld_le32(DAC_CNTL, info) >> 16) & 0x07;
-	    break;
-	}
-    if (!chipname) {
-	printk("atyfb: Unknown mach64 0x%04x\n", Gx);
-	return 0;
-    } else
-	printk("atyfb: %s [0x%04x rev 0x%02x] ", chipname, Gx, Rev);
-    if ((Gx == GX_CHIP_ID) || (Gx == CX_CHIP_ID)) {
-	info->bus_type = (aty_ld_le32(CONFIG_STAT0, info) >> 0) & 0x07;
-	info->ram_type = (aty_ld_le32(CONFIG_STAT0, info) >> 3) & 0x07;
-	ramname = aty_gx_ram[info->ram_type];
-	/* FIXME: clockchip/RAMDAC probing? */
-#ifdef CONFIG_ATARI
-	info->clk_type = CLK_ATI18818_1;
-	info->dac_type = (aty_ld_le32(CONFIG_STAT0, info) >> 9) & 0x07;
-	if (info->dac_type == 0x07)
-	    info->dac_subtype = DAC_ATT20C408;
-	else
-	    info->dac_subtype = (aty_ld_8(SCRATCH_REG1 + 1, info) & 0xF0) |
-				info->dac_type;
-#else
-	info->dac_type = DAC_IBMRGB514;
-	info->dac_subtype = DAC_IBMRGB514;
-	info->clk_type = CLK_IBMRGB514;
-#endif
-	/* FIXME */
-	pll = 135;
-	mclk = 50;
-    } else {
-	info->bus_type = PCI;
-	info->ram_type = (aty_ld_le32(CONFIG_STAT0, info) & 0x07);
-	ramname = aty_ct_ram[info->ram_type];
-	info->dac_type = DAC_INTERNAL;
-	info->dac_subtype = DAC_INTERNAL;
-	info->clk_type = CLK_INTERNAL;
-	if ((Gx == CT_CHIP_ID) || (Gx == ET_CHIP_ID)) {
-	    pll = 135;
-	    mclk = 60;
-	} else {
-	    mclk = info->ram_type >= SDRAM ? 67 : 63;
-	    if ((Gx == VT_CHIP_ID) && (Rev == 0x08)) {
-		/* VTA3 */
-		pll = 170;
-	    } else if (((Gx == VT_CHIP_ID) && ((Rev == 0x40) ||
-					       (Rev == 0x48))) ||
-		       ((Gx == VT_CHIP_ID) && ((Rev == 0x01) ||
-					       (Rev == 0x9a))) ||
-		       Gx == VU_CHIP_ID) {
-		/* VTA4 or VTB */
-		pll = 200;
-	    } else if (Gx == VV_CHIP_ID) {
-		/* VT4 */
-		pll = 230;
-		mclk = 83;
-	    } else if (Gx == VT_CHIP_ID) {
-		/* other VT */
-		pll = 135;
-		mclk = 63;
-	    } else if ((Gx == GT_CHIP_ID) && (Rev & 0x01)) {
-		/* RAGE II */
-		pll = 170;
-	    } else if (((Gx == GT_CHIP_ID) && (Rev & 0x02)) ||
-		       (Gx == GU_CHIP_ID)) {
-		/* RAGE II+ */
-		pll = 200;
-	    } else if (Gx == GV_CHIP_ID || Gx == GW_CHIP_ID ||
-		       Gx == GZ_CHIP_ID) {
-		/* RAGE IIC */
-		pll = 230;
-		mclk = 83;
-	    } else if (Gx == GB_CHIP_ID || Gx == GD_CHIP_ID ||
-		       Gx == GI_CHIP_ID || Gx == GP_CHIP_ID ||
-		       Gx == GQ_CHIP_ID || Gx == LB_CHIP_ID ||
-		       Gx == LD_CHIP_ID ||
-		       Gx == LI_CHIP_ID || Gx == LP_CHIP_ID) {
-		/* RAGE PRO or LT PRO */
-		pll = 230;
-		mclk = 100;
-	    } else if (Gx == XL_CHIP_ID) {
-		pll = 230;
-		mclk = 120;
-	    } else if (Gx == LG_CHIP_ID) {
-		/* Rage LT */
-		pll = 230;
-		mclk = 63;
-	    } else if ((Gx == LN_CHIP_ID) || (Gx == LM_CHIP_ID)) {
-	    	/* Rage mobility M1 */
-	    	pll = 230;
-	    	mclk = 50;
-	    } else {
-		/* other RAGE */
-		pll = 135;
-		mclk = 63;
-	    }
-	}
-    }
-
-    info->ref_clk_per = 1000000000000ULL/14318180;
-    xtal = "14.31818";
-    if (!(Gx == GX_CHIP_ID || Gx == CX_CHIP_ID || Gx == CT_CHIP_ID ||
-	  Gx == ET_CHIP_ID ||
-	  ((Gx == VT_CHIP_ID || Gx == GT_CHIP_ID) && !(Rev & 0x07))) &&
-	(pll_ref_div = aty_ld_pll(PLL_REF_DIV, info))) {
-	int diff1, diff2;
-	diff1 = 510*14/pll_ref_div-pll;
-	diff2 = 510*29/pll_ref_div-pll;
-	if (diff1 < 0)
-	    diff1 = -diff1;
-	if (diff2 < 0)
-	    diff2 = -diff2;
-	if (diff2 < diff1) {
-	    info->ref_clk_per = 1000000000000ULL/29498928;
-	    xtal = "29.498928";
-	}
-    }
-
-    i = aty_ld_le32(MEM_CNTL, info);
-    gtb_memsize = !(Gx == GX_CHIP_ID || Gx == CX_CHIP_ID || Gx == CT_CHIP_ID ||
-		    Gx == ET_CHIP_ID ||
-		    ((Gx == VT_CHIP_ID || Gx == GT_CHIP_ID) && !(Rev & 0x07)));
-    if (gtb_memsize)
-	switch (i & 0xF) {	/* 0xF used instead of MEM_SIZE_ALIAS */
-	    case MEM_SIZE_512K:
-		info->total_vram = 0x80000;
-		break;
-	    case MEM_SIZE_1M:
-		info->total_vram = 0x100000;
-		break;
-	    case MEM_SIZE_2M_GTB:
-		info->total_vram = 0x200000;
-		break;
-	    case MEM_SIZE_4M_GTB:
-		info->total_vram = 0x400000;
-		break;
-	    case MEM_SIZE_6M_GTB:
-		info->total_vram = 0x600000;
-		break;
-	    case MEM_SIZE_8M_GTB:
-		info->total_vram = 0x800000;
-		break;
-	    default:
-		info->total_vram = 0x80000;
-	}
-    else
-	switch (i & MEM_SIZE_ALIAS) {
-	    case MEM_SIZE_512K:
-		info->total_vram = 0x80000;
-		break;
-	    case MEM_SIZE_1M:
-		info->total_vram = 0x100000;
-		break;
-	    case MEM_SIZE_2M:
-		info->total_vram = 0x200000;
-		break;
-	    case MEM_SIZE_4M:
-		info->total_vram = 0x400000;
-		break;
-	    case MEM_SIZE_6M:
-		info->total_vram = 0x600000;
-		break;
-	    case MEM_SIZE_8M:
-		info->total_vram = 0x800000;
-		break;
-	    default:
-		info->total_vram = 0x80000;
-	}
-
-    if (Gx == GI_CHIP_ID) {
-	if (aty_ld_le32(CONFIG_STAT1, info) & 0x40000000)
-	  info->total_vram += 0x400000;
-    }
-
-    if (default_vram) {
-	info->total_vram = default_vram*1024;
-	i = i & ~(gtb_memsize ? 0xF : MEM_SIZE_ALIAS);
-	if (info->total_vram <= 0x80000)
-	    i |= MEM_SIZE_512K;
-	else if (info->total_vram <= 0x100000)
-	    i |= MEM_SIZE_1M;
-	else if (info->total_vram <= 0x200000)
-	    i |= gtb_memsize ? MEM_SIZE_2M_GTB : MEM_SIZE_2M;
-	else if (info->total_vram <= 0x400000)
-	    i |= gtb_memsize ? MEM_SIZE_4M_GTB : MEM_SIZE_4M;
-	else if (info->total_vram <= 0x600000)
-	    i |= gtb_memsize ? MEM_SIZE_6M_GTB : MEM_SIZE_6M;
-	else
-	    i |= gtb_memsize ? MEM_SIZE_8M_GTB : MEM_SIZE_8M;
-	aty_st_le32(MEM_CNTL, i, info);
-    }
-    if (default_pll)
-	pll = default_pll;
-    if (default_mclk)
-	mclk = default_mclk;
-
-    printk("%d%c %s, %s MHz XTAL, %d MHz PLL, %d Mhz MCLK\n",
-    	   info->total_vram == 0x80000 ? 512 : (info->total_vram >> 20),
-    	   info->total_vram == 0x80000 ? 'K' : 'M', ramname, xtal, pll, mclk);
-
-    if (mclk < 44)
-	info->mem_refresh_rate = 0;	/* 000 = 10 Mhz - 43 Mhz */
-    else if (mclk < 50)
-	info->mem_refresh_rate = 1;	/* 001 = 44 Mhz - 49 Mhz */
-    else if (mclk < 55)
-	info->mem_refresh_rate = 2;	/* 010 = 50 Mhz - 54 Mhz */
-    else if (mclk < 66)
-	info->mem_refresh_rate = 3;	/* 011 = 55 Mhz - 65 Mhz */
-    else if (mclk < 75)
-	info->mem_refresh_rate = 4;	/* 100 = 66 Mhz - 74 Mhz */
-    else if (mclk < 80)
-	info->mem_refresh_rate = 5;	/* 101 = 75 Mhz - 79 Mhz */
-    else if (mclk < 100)
-	info->mem_refresh_rate = 6;	/* 110 = 80 Mhz - 100 Mhz */
-    else
-	info->mem_refresh_rate = 7;	/* 111 = 100 Mhz and above */
-    info->pll_per = 1000000/pll;
-    info->mclk_per = 1000000/mclk;
-
-#ifdef DEBUG
-    if ((Gx != GX_CHIP_ID) && (Gx != CX_CHIP_ID)) {
-	int i;
-	printk("BUS_CNTL DAC_CNTL MEM_CNTL EXT_MEM_CNTL CRTC_GEN_CNTL "
-	       "DSP_CONFIG DSP_ON_OFF\n"
-	       "%08x %08x %08x %08x     %08x      %08x   %08x\n"
-	       "PLL",
-	       aty_ld_le32(BUS_CNTL, info), aty_ld_le32(DAC_CNTL, info),
-	       aty_ld_le32(MEM_CNTL, info), aty_ld_le32(EXT_MEM_CNTL, info),
-	       aty_ld_le32(CRTC_GEN_CNTL, info), aty_ld_le32(DSP_CONFIG, info),
-	       aty_ld_le32(DSP_ON_OFF, info));
-	for (i = 0; i < 16; i++)
-	    printk(" %02x", aty_ld_pll(i, info));
-	printk("\n");
-    }
-#endif
-
-    /*
-     *  Last page of 8 MB (4 MB on ISA) aperture is MMIO
-     *  FIXME: we should use the auxiliary aperture instead so we can acces the
-     *  full 8 MB of video RAM on 8 MB boards
-     */
-    if (info->total_vram == 0x800000 ||
-	(info->bus_type == ISA && info->total_vram == 0x400000))
-	    info->total_vram -= GUI_RESERVE;
-
-    /* Clear the video memory */
-    fb_memset((void *)info->frame_buffer, 0, info->total_vram);
-
-    disp = &info->disp;
-
-    strcpy(info->fb_info.modename, atyfb_name);
-    info->fb_info.node = -1;
-    info->fb_info.fbops = &atyfb_ops;
-    info->fb_info.disp = disp;
-    strcpy(info->fb_info.fontname, fontname);
-    info->fb_info.changevar = NULL;
-    info->fb_info.switch_con = &atyfbcon_switch;
-    info->fb_info.updatevar = &atyfbcon_updatevar;
-    info->fb_info.blank = &atyfbcon_blank;
-    info->fb_info.flags = FBINFO_FLAG_DEFAULT;
-
-#ifdef CONFIG_PMAC_BACKLIGHT
-    if (Gx == LI_CHIP_ID && machine_is_compatible("PowerBook1,1")) {
-	/* these bits let the 101 powerbook wake up from sleep -- paulus */
-	aty_st_lcd(LCD_POWER_MANAGEMENT, aty_ld_lcd(LCD_POWER_MANAGEMENT, info)
-		| (USE_F32KHZ | TRISTATE_MEM_EN), info);
-    }
-    if ((Gx == LN_CHIP_ID) || (Gx == LM_CHIP_ID))
-	register_backlight_controller(&aty_backlight_controller, info, "ati");
-#endif /* CONFIG_PMAC_BACKLIGHT */
-
-#ifdef MODULE
-    var = default_var;
-#else /* !MODULE */
-    memset(&var, 0, sizeof(var));
-#ifdef CONFIG_PPC
-    if (_machine == _MACH_Pmac) {
-	    /*
-	     *  FIXME: The NVRAM stuff should be put in a Mac-specific file, as it
-	     *         applies to all Mac video cards
-	     */
-	    if (mode_option) {
-		if (!mac_find_mode(&var, &info->fb_info, mode_option, 8))
-		    var = default_var;
-	    } else {
-#ifdef CONFIG_NVRAM
-		if (default_vmode == VMODE_NVRAM) {
-		    default_vmode = nvram_read_byte(NV_VMODE);
-		    if (default_vmode <= 0 || default_vmode > VMODE_MAX)
-			default_vmode = VMODE_CHOOSE;
-		}
-#endif
-		if (default_vmode == VMODE_CHOOSE) {
-		    if (Gx == LG_CHIP_ID || Gx == LI_CHIP_ID)
-			/* G3 PowerBook with 1024x768 LCD */
-			default_vmode = VMODE_1024_768_60;
-		    else if (machine_is_compatible("iMac"))
-			default_vmode = VMODE_1024_768_75;
-		    else if (machine_is_compatible("PowerBook2,1"))
-			/* iBook with 800x600 LCD */
-			default_vmode = VMODE_800_600_60;
-		    else
-			default_vmode = VMODE_640_480_67;
-		    sense = read_aty_sense(info);
-		    printk(KERN_INFO "atyfb: monitor sense=%x, mode %d\n",
-			   sense, mac_map_monitor_sense(sense));
-		}
-		if (default_vmode <= 0 || default_vmode > VMODE_MAX)
-		    default_vmode = VMODE_640_480_60;
-#ifdef CONFIG_NVRAM
-		if (default_cmode == CMODE_NVRAM)
-		    default_cmode = nvram_read_byte(NV_CMODE);
-#endif
-		if (default_cmode < CMODE_8 || default_cmode > CMODE_32)
-		    default_cmode = CMODE_8;
-		if (mac_vmode_to_var(default_vmode, default_cmode, &var))
-		    var = default_var;
-	    }
-    }
-    else if (!fb_find_mode(&var, &info->fb_info, mode_option, NULL, 0, NULL, 8))
-	var = default_var;
-#else /* !CONFIG_PPC */
-#ifdef __sparc__
-    if (mode_option) {
-    	if (!fb_find_mode(&var, &info->fb_info, mode_option, NULL, 0, NULL, 8))
-	    var = default_var;
-    } else
-	var = default_var;
-#else
-    if (!fb_find_mode(&var, &info->fb_info, mode_option, NULL, 0, NULL, 8))
-	var = default_var;
-#endif /* !__sparc__ */
-#endif /* !CONFIG_PPC */
-#endif /* !MODULE */
-    if (noaccel)
-        var.accel_flags &= ~FB_ACCELF_TEXT;
-    else
-        var.accel_flags |= FB_ACCELF_TEXT;
-
-    if (var.yres == var.yres_virtual) {
-	u32 vram = (info->total_vram - (PAGE_SIZE << 2));
-	var.yres_virtual = ((vram * 8) / var.bits_per_pixel) / var.xres_virtual;
-	if (var.yres_virtual < var.yres)
-		var.yres_virtual = var.yres;
-    }
-
-    if (atyfb_decode_var(&var, &info->default_par, info)) {
-	printk("atyfb: can't set default video mode\n");
-	return 0;
-    }
-
-#ifdef __sparc__
-    atyfb_save_palette(&info->fb_info, 0);
-#endif
-    for (j = 0; j < 16; j++) {
-	k = color_table[j];
-	info->palette[j].red = default_red[k];
-	info->palette[j].green = default_grn[k];
-	info->palette[j].blue = default_blu[k];
-    }
-
-    if (Gx != GX_CHIP_ID && Gx != CX_CHIP_ID) {
-	info->cursor = aty_init_cursor(info);
-	if (info->cursor) {
-	    info->dispsw.cursor = atyfb_cursor;
-	    info->dispsw.set_font = atyfb_set_font;
-	}
-    }
-
-    atyfb_set_var(&var, -1, &info->fb_info);
-
-    if (register_framebuffer(&info->fb_info) < 0)
-	return 0;
-
-    info->next = fb_list;
-    fb_list = info;
-
-    printk("fb%d: %s frame buffer device on %s\n",
-	   GET_FB_IDX(info->fb_info.node), atyfb_name, name);
-    return 1;
-}
-
-int __init atyfb_init(void)
-{
-#if defined(CONFIG_PCI)
-    struct pci_dev *pdev = NULL;
-    struct fb_info_aty *info;
-    unsigned long addr, res_start, res_size;
-    int i;
-#ifdef __sparc__
-    extern void (*prom_palette) (int);
-    extern int con_is_present(void);
-    struct pcidev_cookie *pcp;
-    char prop[128];
-    int node, len, j;
-    u32 mem, chip_id;
-
-    /* Do not attach when we have a serial console. */
-    if (!con_is_present())
-	return -ENXIO;
-#else
-    u16 tmp;
-#endif
-
-    while ((pdev = pci_find_device(PCI_VENDOR_ID_ATI, PCI_ANY_ID, pdev))) {
-	if ((pdev->class >> 16) == PCI_BASE_CLASS_DISPLAY) {
-	    struct resource *rp;
-
-	    for (i = sizeof(aty_features)/sizeof(*aty_features)-1; i >= 0; i--)
-		if (pdev->device == aty_features[i].pci_id)
-		    break;
-	    if (i < 0)
-		continue;
-
-	    info = kmalloc(sizeof(struct fb_info_aty), GFP_ATOMIC);
-	    if (!info) {
-		printk("atyfb_init: can't alloc fb_info_aty\n");
-		return -ENXIO;
-	    }
-	    memset(info, 0, sizeof(struct fb_info_aty));
-
-	    rp = &pdev->resource[0];
-	    if (rp->flags & IORESOURCE_IO)
-		    rp = &pdev->resource[1];
-	    addr = rp->start;
-	    if (!addr)
-		continue;
-
-	    res_start = rp->start;
-	    res_size = rp->end-rp->start+1;
-	    if (!request_mem_region(res_start, res_size, "atyfb"))
-		continue;
-
-#ifdef __sparc__
-	    /*
-	     * Map memory-mapped registers.
-	     */
-	    info->ati_regbase = addr + 0x7ffc00UL;
-	    info->ati_regbase_phys = addr + 0x7ffc00UL;
-
-	    /*
-	     * Map in big-endian aperture.
-	     */
-	    info->frame_buffer = (unsigned long) addr + 0x800000UL;
-	    info->frame_buffer_phys = addr + 0x800000UL;
-
-	    /*
-	     * Figure mmap addresses from PCI config space.
-	     * Split Framebuffer in big- and little-endian halfs.
-	     */
-	    for (i = 0; i < 6 && pdev->resource[i].start; i++)
-		/* nothing */;
-	    j = i + 4;
-
-	    info->mmap_map = kmalloc(j * sizeof(*info->mmap_map), GFP_ATOMIC);
-	    if (!info->mmap_map) {
-		printk("atyfb_init: can't alloc mmap_map\n");
-		kfree(info);
-		release_mem_region(res_start, res_size);
-		return -ENXIO;
-	    }
-	    memset(info->mmap_map, 0, j * sizeof(*info->mmap_map));
-
-	    for (i = 0, j = 2; i < 6 && pdev->resource[i].start; i++) {
-		struct resource *rp = &pdev->resource[i];
-		int io, breg = PCI_BASE_ADDRESS_0 + (i << 2);
-		unsigned long base;
-		u32 size, pbase;
-
-		base = rp->start;
-
-		io = (rp->flags & IORESOURCE_IO);
-
-		size = rp->end - base + 1;
-
-		pci_read_config_dword(pdev, breg, &pbase);
-
-		if (io)
-			size &= ~1;
-
-		/*
-		 * Map the framebuffer a second time, this time without
-		 * the braindead _PAGE_IE setting. This is used by the
-		 * fixed Xserver, but we need to maintain the old mapping
-		 * to stay compatible with older ones...
-		 */
-		if (base == addr) {
-		    info->mmap_map[j].voff = (pbase + 0x10000000) & PAGE_MASK;
-		    info->mmap_map[j].poff = base & PAGE_MASK;
-		    info->mmap_map[j].size = (size + ~PAGE_MASK) & PAGE_MASK;
-		    info->mmap_map[j].prot_mask = _PAGE_CACHE;
-		    info->mmap_map[j].prot_flag = _PAGE_E;
-		    j++;
-		}
-
-		/*
-		 * Here comes the old framebuffer mapping with _PAGE_IE
-		 * set for the big endian half of the framebuffer...
-		 */
-		if (base == addr) {
-		    info->mmap_map[j].voff = (pbase + 0x800000) & PAGE_MASK;
-		    info->mmap_map[j].poff = (base+0x800000) & PAGE_MASK;
-		    info->mmap_map[j].size = 0x800000;
-		    info->mmap_map[j].prot_mask = _PAGE_CACHE;
-		    info->mmap_map[j].prot_flag = _PAGE_E|_PAGE_IE;
-		    size -= 0x800000;
-		    j++;
-		}
-
-		info->mmap_map[j].voff = pbase & PAGE_MASK;
-		info->mmap_map[j].poff = base & PAGE_MASK;
-		info->mmap_map[j].size = (size + ~PAGE_MASK) & PAGE_MASK;
-		info->mmap_map[j].prot_mask = _PAGE_CACHE;
-		info->mmap_map[j].prot_flag = _PAGE_E;
-		j++;
-	    }
-
-	    if (pdev->device != XL_CHIP_ID) {
-		    /*
-		     * Fix PROMs idea of MEM_CNTL settings...
-		     */
-		    mem = aty_ld_le32(MEM_CNTL, info);
-		    chip_id = aty_ld_le32(CONFIG_CHIP_ID, info);
-		    if (((chip_id & CFG_CHIP_TYPE) == VT_CHIP_ID) &&
-			!((chip_id >> 24) & 1)) {
-			    switch (mem & 0x0f) {
-			    case 3:
-				    mem = (mem & ~(0x0f)) | 2;
-				    break;
-			    case 7:
-				    mem = (mem & ~(0x0f)) | 3;
-				    break;
-			    case 9:
-				    mem = (mem & ~(0x0f)) | 4;
-				    break;
-			    case 11:
-				    mem = (mem & ~(0x0f)) | 5;
-				    break;
-			    default:
-				    break;
-			    }
-			    if ((aty_ld_le32(CONFIG_STAT0, info) & 7) >= SDRAM)
-				    mem &= ~(0x00700000);
-		    }
-		    mem &= ~(0xcf80e000);	/* Turn off all undocumented bits. */
-		    aty_st_le32(MEM_CNTL, mem, info);
-	    }
-
-	    /*
-	     * If this is the console device, we will set default video
-	     * settings to what the PROM left us with.
-	     */
-	    node = prom_getchild(prom_root_node);
-	    node = prom_searchsiblings(node, "aliases");
-	    if (node) {
-		len = prom_getproperty(node, "screen", prop, sizeof(prop));
-		if (len > 0) {
-		    prop[len] = '\0';
-		    node = prom_finddevice(prop);
-		} else {
-		    node = 0;
-		}
-	    }
-
-	    pcp = pdev->sysdata;
-	    if (node == pcp->prom_node) {
-
-		struct fb_var_screeninfo *var = &default_var;
-		unsigned int N, P, Q, M, T, R;
-		u32 v_total, h_total;
-		struct crtc crtc;
-		u8 pll_regs[16];
-		u8 clock_cntl;
-
-		crtc.vxres = prom_getintdefault(node, "width", 1024);
-		crtc.vyres = prom_getintdefault(node, "height", 768);
-		crtc.bpp = prom_getintdefault(node, "depth", 8);
-		crtc.xoffset = crtc.yoffset = 0;
-		crtc.h_tot_disp = aty_ld_le32(CRTC_H_TOTAL_DISP, info);
-		crtc.h_sync_strt_wid = aty_ld_le32(CRTC_H_SYNC_STRT_WID, info);
-		crtc.v_tot_disp = aty_ld_le32(CRTC_V_TOTAL_DISP, info);
-		crtc.v_sync_strt_wid = aty_ld_le32(CRTC_V_SYNC_STRT_WID, info);
-		crtc.gen_cntl = aty_ld_le32(CRTC_GEN_CNTL, info);
-		aty_crtc_to_var(&crtc, var);
-
-		h_total = var->xres + var->right_margin +
-			  var->hsync_len + var->left_margin;
-		v_total = var->yres + var->lower_margin +
-			  var->vsync_len + var->upper_margin;
-
-		/*
-		 * Read the PLL to figure actual Refresh Rate.
-		 */
-    		clock_cntl = aty_ld_8(CLOCK_CNTL, info);
-		/* printk("atyfb: CLOCK_CNTL: %02x\n", clock_cntl); */
-		for (i = 0; i < 16; i++)
-			pll_regs[i] = aty_ld_pll(i, info);
-
-		/*
-		 * PLL Reference Devider M:
-		 */
-		M = pll_regs[2];
-
-		/*
-		 * PLL Feedback Devider N (Dependant on CLOCK_CNTL):
-		 */
-		N = pll_regs[7 + (clock_cntl & 3)];
-
-		/*
-		 * PLL Post Divider P (Dependant on CLOCK_CNTL):
-		 */
-		P = 1 << (pll_regs[6] >> ((clock_cntl & 3) << 1));
-
-		/*
-		 * PLL Devider Q:
-		 */
-		Q = N / P;
-
-		/*
-		 * Target Frequency:
-		 *
-		 *      T * M
-		 * Q = -------
-		 *      2 * R
-		 *
-		 * where R is XTALIN (= 14318 or 29498 kHz).
-		 */
-		if (pdev->device == XL_CHIP_ID)
-			R = 29498;
-		else
-			R = 14318;
-
-		T = 2 * Q * R / M;
-
-		default_var.pixclock = 1000000000 / T;
-	    }
-#else /* __sparc__ */
-
-	    info->ati_regbase_phys = 0x7ff000 + addr;
-	    info->ati_regbase = (unsigned long)
-				ioremap(info->ati_regbase_phys, 0x1000);
-
-	    if(!info->ati_regbase) {
-		    kfree(info);
-		    release_mem_region(res_start, res_size);
-		    return -ENOMEM;
-	    }
-
-	    info->ati_regbase_phys += 0xc00;
-	    info->ati_regbase += 0xc00;
-
-	    /*
-	     * Enable memory-space accesses using config-space
-	     * command register.
-	     */
-	    pci_read_config_word(pdev, PCI_COMMAND, &tmp);
-	    if (!(tmp & PCI_COMMAND_MEMORY)) {
-		tmp |= PCI_COMMAND_MEMORY;
-		pci_write_config_word(pdev, PCI_COMMAND, tmp);
-	    }
-
-#ifdef __BIG_ENDIAN
-	    /* Use the big-endian aperture */
-	    addr += 0x800000;
-#endif
-
-	    /* Map in frame buffer */
-	    info->frame_buffer_phys = addr;
-	    info->frame_buffer = (unsigned long)ioremap(addr, 0x800000);
-
-	    if(!info->frame_buffer) {
-		    kfree(info);
-		    release_mem_region(res_start, res_size);
-		    return -ENXIO;
-	    }
-
-#endif /* __sparc__ */
-
-	    if (!aty_init(info, "PCI")) {
-		if (info->mmap_map)
-		    kfree(info->mmap_map);
-		kfree(info);
-		release_mem_region(res_start, res_size);
-		return -ENXIO;
-	    }
-
-#ifdef __sparc__
-	    if (!prom_palette)
-		prom_palette = atyfb_palette;
-
-	    /*
-	     * Add /dev/fb mmap values.
-	     */
-	    info->mmap_map[0].voff = 0x8000000000000000UL;
-	    info->mmap_map[0].poff = info->frame_buffer & PAGE_MASK;
-	    info->mmap_map[0].size = info->total_vram;
-	    info->mmap_map[0].prot_mask = _PAGE_CACHE;
-	    info->mmap_map[0].prot_flag = _PAGE_E;
-	    info->mmap_map[1].voff = info->mmap_map[0].voff + info->total_vram;
-	    info->mmap_map[1].poff = info->ati_regbase & PAGE_MASK;
-	    info->mmap_map[1].size = PAGE_SIZE;
-	    info->mmap_map[1].prot_mask = _PAGE_CACHE;
-	    info->mmap_map[1].prot_flag = _PAGE_E;
-#endif /* __sparc__ */
-
-#ifdef CONFIG_PMAC_PBOOK
-	    if (first_display == NULL)
-		pmu_register_sleep_notifier(&aty_sleep_notifier);
-	    info->next = first_display;
-	    first_display = info;
-#endif
-
-#ifdef CONFIG_FB_COMPAT_XPMAC
-	    if (!console_fb_info)
-		console_fb_info = &info->fb_info;
-#endif /* CONFIG_FB_COMPAT_XPMAC */
-	}
-    }
-
-#elif defined(CONFIG_ATARI)
-  u32   clock_r;
-    int m64_num;
-    struct fb_info_aty *info;
-
-    for (m64_num = 0; m64_num < mach64_count; m64_num++) {
-	if (!phys_vmembase[m64_num] || !phys_size[m64_num] ||
-	    !phys_guiregbase[m64_num]) {
-	    printk(" phys_*[%d] parameters not set => returning early. \n",
-		   m64_num);
-	    continue;
-	}
-
-	info = kmalloc(sizeof(struct fb_info_aty), GFP_ATOMIC);
-	if (!info) {
-	    printk("atyfb_init: can't alloc fb_info_aty\n");
-	    return -ENOMEM;
-	}
-	memset(info, 0, sizeof(struct fb_info_aty));
-
-	/*
-	 *  Map the video memory (physical address given) to somewhere in the
-	 *  kernel address space.
-	 */
-	info->frame_buffer = ioremap(phys_vmembase[m64_num], phys_size[m64_num]);
-	info->frame_buffer_phys = info->frame_buffer;  /* Fake! */
-	info->ati_regbase = ioremap(phys_guiregbase[m64_num], 0x10000)+0xFC00ul;
-	info->ati_regbase_phys = info->ati_regbase;  /* Fake! */
-
-	aty_st_le32(CLOCK_CNTL, 0x12345678, info);
-	clock_r = aty_ld_le32(CLOCK_CNTL, info);
-
-	switch (clock_r & 0x003F) {
-	    case 0x12:
-		info->clk_wr_offset = 3;  /*  */
-		break;
-	    case 0x34:
-		info->clk_wr_offset = 2;  /* Medusa ST-IO ISA Adapter etc. */
-		break;
-	    case 0x16:
-		info->clk_wr_offset = 1;  /*  */
-		break;
-	    case 0x38:
-		info->clk_wr_offset = 0;  /* Panther 1 ISA Adapter (Gerald) */
-		break;
-	}
-
-	if (!aty_init(info, "ISA bus")) {
-	    kfree(info);
-	    /* This is insufficient! kernel_map has added two large chunks!! */
-	    return -ENXIO;
-	}
-    }
-#endif /* CONFIG_ATARI */
-    return 0;
-}
-
-#ifndef MODULE
-int __init atyfb_setup(char *options)
-{
-    char *this_opt;
-
-    if (!options || !*options)
-	return 0;
-
-    for (this_opt = strtok(options, ","); this_opt;
-	 this_opt = strtok(NULL, ",")) {
-	if (!strncmp(this_opt, "font:", 5)) {
-		char *p;
-		int i;
-
-		p = this_opt + 5;
-		for (i = 0; i < sizeof(fontname) - 1; i++)
-			if (!*p || *p == ' ' || *p == ',')
-				break;
-		memcpy(fontname, this_opt + 5, i);
-		fontname[i] = 0;
-	} else if (!strncmp(this_opt, "noblink", 7)) {
-		curblink = 0;
-	} else if (!strncmp(this_opt, "noaccel", 7)) {
-		noaccel = 1;
-	} else if (!strncmp(this_opt, "vram:", 5))
-		default_vram = simple_strtoul(this_opt+5, NULL, 0);
-	else if (!strncmp(this_opt, "pll:", 4))
-		default_pll = simple_strtoul(this_opt+4, NULL, 0);
-	else if (!strncmp(this_opt, "mclk:", 5))
-		default_mclk = simple_strtoul(this_opt+5, NULL, 0);
-#ifdef CONFIG_PPC
-	else if (!strncmp(this_opt, "vmode:", 6)) {
-	    unsigned int vmode = simple_strtoul(this_opt+6, NULL, 0);
-	    if (vmode > 0 && vmode <= VMODE_MAX)
-		default_vmode = vmode;
-	} else if (!strncmp(this_opt, "cmode:", 6)) {
-	    unsigned int cmode = simple_strtoul(this_opt+6, NULL, 0);
-	    switch (cmode) {
-		case 0:
-		case 8:
-		    default_cmode = CMODE_8;
-		    break;
-		case 15:
-		case 16:
-		    default_cmode = CMODE_16;
-		    break;
-		case 24:
-		case 32:
-		    default_cmode = CMODE_32;
-		    break;
-	    }
-	}
-#endif
-#ifdef CONFIG_ATARI
-	/*
-	 * Why do we need this silly Mach64 argument?
-	 * We are already here because of mach64= so its redundant.
-	 */
-	else if (MACH_IS_ATARI && (!strncmp(this_opt, "Mach64:", 7))) {
-	    static unsigned char m64_num;
-	    static char mach64_str[80];
-	    strncpy(mach64_str, this_opt+7, 80);
-	    if (!store_video_par(mach64_str, m64_num)) {
-		m64_num++;
-		mach64_count = m64_num;
-	    }
-	}
-#endif
-	else
-	    mode_option = this_opt;
-    }
-    return 0;
-}
-#endif /* !MODULE */
-
-#ifdef CONFIG_ATARI
-static int __init store_video_par(char *video_str, unsigned char m64_num)
-{
-    char *p;
-    unsigned long vmembase, size, guiregbase;
-
-    printk("store_video_par() '%s' \n", video_str);
-
-    if (!(p = strtoke(video_str, ";")) || !*p)
-	goto mach64_invalid;
-    vmembase = simple_strtoul(p, NULL, 0);
-    if (!(p = strtoke(NULL, ";")) || !*p)
-	goto mach64_invalid;
-    size = simple_strtoul(p, NULL, 0);
-    if (!(p = strtoke(NULL, ";")) || !*p)
-	goto mach64_invalid;
-    guiregbase = simple_strtoul(p, NULL, 0);
-
-    phys_vmembase[m64_num] = vmembase;
-    phys_size[m64_num] = size;
-    phys_guiregbase[m64_num] = guiregbase;
-    printk(" stored them all: $%08lX $%08lX $%08lX \n", vmembase, size,
-	   guiregbase);
-    return 0;
-
-mach64_invalid:
-    phys_vmembase[m64_num]   = 0;
-    return -1;
-}
-
-static char __init *strtoke(char *s, const char *ct)
-{
-    static char *ssave = NULL;
-    char *sbegin, *send;
-
-    sbegin  = s ? s : ssave;
-    if (!sbegin)
-	return NULL;
-    if (*sbegin == '\0') {
-	ssave = NULL;
-	return NULL;
-    }
-    send = strpbrk(sbegin, ct);
-    if (send && *send != '\0')
-	*send++ = '\0';
-    ssave = send;
-    return sbegin;
-}
-#endif /* CONFIG_ATARI */
-
-static int atyfbcon_switch(int con, struct fb_info *fb)
-{
-    struct fb_info_aty *info = (struct fb_info_aty *)fb;
-    struct atyfb_par par;
-
-    /* Do we have to save the colormap? */
-    if (fb_display[currcon].cmap.len)
-	fb_get_cmap(&fb_display[currcon].cmap, 1, atyfb_getcolreg, fb);
-
-    /* Erase HW Cursor */
-    if (info->cursor)
-	atyfb_cursor(&fb_display[currcon], CM_ERASE,
-		     info->cursor->pos.x, info->cursor->pos.y);
-
-    currcon = con;
-
-    atyfb_decode_var(&fb_display[con].var, &par, info);
-    atyfb_set_par(&par, info);
-    atyfb_set_dispsw(&fb_display[con], info, par.crtc.bpp,
-		     par.accel_flags & FB_ACCELF_TEXT);
-
-    /* Install new colormap */
-    do_install_cmap(con, fb);
-
-    /* Install hw cursor */
-    if (info->cursor) {
-	aty_set_cursor_color(info, cursor_pixel_map, cursor_color_map,
-			     cursor_color_map, cursor_color_map);
-	aty_set_cursor_shape(info);
-    }
-    return 1;
-}
-
-    /*
-     *  Blank the display.
-     */
-
-static void atyfbcon_blank(int blank, struct fb_info *fb)
-{
-    struct fb_info_aty *info = (struct fb_info_aty *)fb;
-    u8 gen_cntl;
-
-#ifdef CONFIG_PMAC_BACKLIGHT
-    if ((_machine == _MACH_Pmac) && blank)
-    	set_backlight_enable(0);
-#endif /* CONFIG_PMAC_BACKLIGHT */
-
-    gen_cntl = aty_ld_8(CRTC_GEN_CNTL, info);
-    if (blank > 0)
-	switch (blank-1) {
-	    case VESA_NO_BLANKING:
-		gen_cntl |= 0x40;
-		break;
-	    case VESA_VSYNC_SUSPEND:
-		gen_cntl |= 0x8;
-		break;
-	    case VESA_HSYNC_SUSPEND:
-		gen_cntl |= 0x4;
-		break;
-	    case VESA_POWERDOWN:
-		gen_cntl |= 0x4c;
-		break;
-	}
-    else
-	gen_cntl &= ~(0x4c);
-    aty_st_8(CRTC_GEN_CNTL, gen_cntl, info);
-
-#ifdef CONFIG_PMAC_BACKLIGHT
-    if ((_machine == _MACH_Pmac) && !blank)
-    	set_backlight_enable(1);
-#endif /* CONFIG_PMAC_BACKLIGHT */
-}
-
-
-    /*
-     *  Read a single color register and split it into
-     *  colors/transparent. Return != 0 for invalid regno.
-     */
-
-static int atyfb_getcolreg(u_int regno, u_int *red, u_int *green, u_int *blue,
-			   u_int *transp, struct fb_info *fb)
-{
-    struct fb_info_aty *info = (struct fb_info_aty *)fb;
-
-    if (regno > 255)
-	return 1;
-    *red = (info->palette[regno].red<<8) | info->palette[regno].red;
-    *green = (info->palette[regno].green<<8) | info->palette[regno].green;
-    *blue = (info->palette[regno].blue<<8) | info->palette[regno].blue;
-    *transp = 0;
-    return 0;
-}
-
-
-    /*
-     *  Set a single color register. The values supplied are already
-     *  rounded down to the hardware's capabilities (according to the
-     *  entries in the var structure). Return != 0 for invalid regno.
-     */
-
-static int atyfb_setcolreg(u_int regno, u_int red, u_int green, u_int blue,
-			   u_int transp, struct fb_info *fb)
-{
-    struct fb_info_aty *info = (struct fb_info_aty *)fb;
-    int i, scale;
-
-    if (regno > 255)
-	return 1;
-    red >>= 8;
-    green >>= 8;
-    blue >>= 8;
-    info->palette[regno].red = red;
-    info->palette[regno].green = green;
-    info->palette[regno].blue = blue;
-    i = aty_ld_8(DAC_CNTL, info) & 0xfc;
-    if (Gx == GT_CHIP_ID || Gx == GU_CHIP_ID || Gx == GV_CHIP_ID ||
-	Gx == GW_CHIP_ID || Gx == GZ_CHIP_ID || Gx == LG_CHIP_ID ||
-	Gx == GB_CHIP_ID || Gx == GD_CHIP_ID || Gx == GI_CHIP_ID ||
-	Gx == GP_CHIP_ID || Gx == GQ_CHIP_ID || Gx == LI_CHIP_ID ||
-	Gx == XL_CHIP_ID)
-	i |= 0x2;	/*DAC_CNTL|0x2 turns off the extra brightness for gt*/
-    aty_st_8(DAC_CNTL, i, info);
-    aty_st_8(DAC_MASK, 0xff, info);
-    scale = ((Gx != GX_CHIP_ID) && (Gx != CX_CHIP_ID) &&
-	     (info->current_par.crtc.bpp == 16)) ? 3 : 0;
-    writeb(regno << scale, &info->aty_cmap_regs->windex);
-    writeb(red, &info->aty_cmap_regs->lut);
-    writeb(green, &info->aty_cmap_regs->lut);
-    writeb(blue, &info->aty_cmap_regs->lut);
-    if (regno < 16)
-	switch (info->current_par.crtc.bpp) {
-#ifdef FBCON_HAS_CFB16
-	    case 16:
-		info->fbcon_cmap.cfb16[regno] = (regno << 10) | (regno << 5) |
-						regno;
-		break;
-#endif
-#ifdef FBCON_HAS_CFB24
-	    case 24:
-		info->fbcon_cmap.cfb24[regno] = (regno << 16) | (regno << 8) |
-						regno;
-		break;
-#endif
-#ifdef FBCON_HAS_CFB32
-	    case 32:
-		i = (regno << 8) | regno;
-		info->fbcon_cmap.cfb32[regno] = (i << 16) | i;
-		break;
-#endif
-	    }
-    return 0;
-}
-
-
-static void do_install_cmap(int con, struct fb_info *info)
-{
-    if (con != currcon)
-	return;
-    if (fb_display[con].cmap.len)
-	fb_set_cmap(&fb_display[con].cmap, 1, atyfb_setcolreg, info);
-    else {
-	int size = fb_display[con].var.bits_per_pixel == 16 ? 32 : 256;
-	fb_set_cmap(fb_default_cmap(size), 1, atyfb_setcolreg, info);
-    }
-}
-
-
-    /*
-     *  Accelerated functions
-     */
-
-static inline void draw_rect(s16 x, s16 y, u16 width, u16 height,
-			     struct fb_info_aty *info)
-{
-    /* perform rectangle fill */
-    wait_for_fifo(2, info);
-    aty_st_le32(DST_Y_X, (x << 16) | y, info);
-    aty_st_le32(DST_HEIGHT_WIDTH, (width << 16) | height, info);
-    info->blitter_may_be_busy = 1;
-}
-
-static inline void aty_rectcopy(int srcx, int srcy, int dstx, int dsty,
-				u_int width, u_int height,
-				struct fb_info_aty *info)
-{
-    u32 direction = DST_LAST_PEL;
-    u32 pitch_value;
-
-    if (!width || !height)
-	return;
-
-    pitch_value = info->current_par.crtc.vxres;
-    if (info->current_par.crtc.bpp == 24) {
-	/* In 24 bpp, the engine is in 8 bpp - this requires that all */
-	/* horizontal coordinates and widths must be adjusted */
-	pitch_value *= 3;
-	srcx *= 3;
-	dstx *= 3;
-	width *= 3;
-    }
-
-    if (srcy < dsty) {
-	dsty += height - 1;
-	srcy += height - 1;
-    } else
-	direction |= DST_Y_TOP_TO_BOTTOM;
-
-    if (srcx < dstx) {
-	dstx += width - 1;
-	srcx += width - 1;
-    } else
-	direction |= DST_X_LEFT_TO_RIGHT;
-
-    wait_for_fifo(4, info);
-    aty_st_le32(DP_SRC, FRGD_SRC_BLIT, info);
-    aty_st_le32(SRC_Y_X, (srcx << 16) | srcy, info);
-    aty_st_le32(SRC_HEIGHT1_WIDTH1, (width << 16) | height, info);
-    aty_st_le32(DST_CNTL, direction, info);
-    draw_rect(dstx, dsty, width, height, info);
-}
-
-static inline void aty_rectfill(int dstx, int dsty, u_int width, u_int height,
-				u_int color, struct fb_info_aty *info)
-{
-    if (!width || !height)
-	return;
-
-    if (info->current_par.crtc.bpp == 24) {
-	/* In 24 bpp, the engine is in 8 bpp - this requires that all */
-	/* horizontal coordinates and widths must be adjusted */
-	dstx *= 3;
-	width *= 3;
-    }
-
-    wait_for_fifo(3, info);
-    aty_st_le32(DP_FRGD_CLR, color, info);
-    aty_st_le32(DP_SRC, BKGD_SRC_BKGD_CLR | FRGD_SRC_FRGD_CLR | MONO_SRC_ONE,
-		info);
-    aty_st_le32(DST_CNTL, DST_LAST_PEL | DST_Y_TOP_TO_BOTTOM |
-			  DST_X_LEFT_TO_RIGHT, info);
-    draw_rect(dstx, dsty, width, height, info);
-}
-
-    /*
-     *  Update the `var' structure (called by fbcon.c)
-     */
-
-static int atyfbcon_updatevar(int con, struct fb_info *fb)
-{
-    struct fb_info_aty *info = (struct fb_info_aty *)fb;
-    struct atyfb_par *par = &info->current_par;
-    struct display *p = &fb_display[con];
-    struct vc_data *conp = p->conp;
-    u32 yres, yoffset, sy, height;
-
-    yres = ((par->crtc.v_tot_disp >> 16) & 0x7ff) + 1;
-    yoffset = fb_display[con].var.yoffset;
-
-    sy = (conp->vc_rows + p->yscroll) * fontheight(p);
-    height = yres - conp->vc_rows * fontheight(p);
-
-    if (height && (yoffset + yres > sy)) {
-	u32 xres, xoffset;
-	u32 bgx;
-
-	xres = (((par->crtc.h_tot_disp >> 16) & 0xff) + 1) * 8;
-	xoffset = fb_display[con].var.xoffset;
-
-
-	bgx = attr_bgcol_ec(p, conp);
-	bgx |= (bgx << 8);
-	bgx |= (bgx << 16);
-
-	if (sy + height > par->crtc.vyres) {
-	    wait_for_fifo(1, info);
-	    aty_st_le32(SC_BOTTOM, sy + height - 1, info);
-	}
-	aty_rectfill(xoffset, sy, xres, height, bgx, info);
-    }
-
-    if (info->cursor && (yoffset + yres <= sy))
-	atyfb_cursor(p, CM_ERASE, info->cursor->pos.x, info->cursor->pos.y);
-
-    info->current_par.crtc.yoffset = yoffset;
-    set_off_pitch(&info->current_par, info);
-    return 0;
-}
-
-    /*
-     *  Text console acceleration
-     */
-
-static void fbcon_aty_bmove(struct display *p, int sy, int sx, int dy, int dx,
-			    int height, int width)
-{
-#ifdef __sparc__
-    struct fb_info_aty *fb = (struct fb_info_aty *)(p->fb_info);
-
-    if (fb->mmaped && (!fb->fb_info.display_fg
-	|| fb->fb_info.display_fg->vc_num == fb->vtconsole))
-	return;
-#endif
-
-    sx *= fontwidth(p);
-    sy *= fontheight(p);
-    dx *= fontwidth(p);
-    dy *= fontheight(p);
-    width *= fontwidth(p);
-    height *= fontheight(p);
-
-    aty_rectcopy(sx, sy, dx, dy, width, height,
-		 (struct fb_info_aty *)p->fb_info);
-}
-
-static void fbcon_aty_clear(struct vc_data *conp, struct display *p, int sy,
-			    int sx, int height, int width)
-{
-    u32 bgx;
-#ifdef __sparc__
-    struct fb_info_aty *fb = (struct fb_info_aty *)(p->fb_info);
-
-    if (fb->mmaped && (!fb->fb_info.display_fg
-	|| fb->fb_info.display_fg->vc_num == fb->vtconsole))
-	return;
-#endif
-
-    bgx = attr_bgcol_ec(p, conp);
-    bgx |= (bgx << 8);
-    bgx |= (bgx << 16);
-
-    sx *= fontwidth(p);
-    sy *= fontheight(p);
-    width *= fontwidth(p);
-    height *= fontheight(p);
-
-    aty_rectfill(sx, sy, width, height, bgx,
-		 (struct fb_info_aty *)p->fb_info);
-}
-
-#ifdef FBCON_HAS_CFB8
-static void fbcon_aty8_putc(struct vc_data *conp, struct display *p, int c,
-			    int yy, int xx)
-{
-    struct fb_info_aty *fb = (struct fb_info_aty *)(p->fb_info);
-
-#ifdef __sparc__
-    if (fb->mmaped && (!fb->fb_info.display_fg
-	|| fb->fb_info.display_fg->vc_num == fb->vtconsole))
-	return;
-#endif
-
-    if (fb->blitter_may_be_busy)
-	wait_for_idle((struct fb_info_aty *)p->fb_info);
-    fbcon_cfb8_putc(conp, p, c, yy, xx);
-}
-
-static void fbcon_aty8_putcs(struct vc_data *conp, struct display *p,
-			     const unsigned short *s, int count, int yy,
-			     int xx)
-{
-    struct fb_info_aty *fb = (struct fb_info_aty *)(p->fb_info);
-
-#ifdef __sparc__
-    if (fb->mmaped && (!fb->fb_info.display_fg
-	|| fb->fb_info.display_fg->vc_num == fb->vtconsole))
-	return;
-#endif
-
-    if (fb->blitter_may_be_busy)
-	wait_for_idle((struct fb_info_aty *)p->fb_info);
-    fbcon_cfb8_putcs(conp, p, s, count, yy, xx);
-}
-
-static void fbcon_aty8_clear_margins(struct vc_data *conp, struct display *p,
-				     int bottom_only)
-{
-    struct fb_info_aty *fb = (struct fb_info_aty *)(p->fb_info);
-
-#ifdef __sparc__
-    if (fb->mmaped && (!fb->fb_info.display_fg
-	|| fb->fb_info.display_fg->vc_num == fb->vtconsole))
-	return;
-#endif
-
-    if (fb->blitter_may_be_busy)
-	wait_for_idle((struct fb_info_aty *)p->fb_info);
-    fbcon_cfb8_clear_margins(conp, p, bottom_only);
-}
-
-static struct display_switch fbcon_aty8 = {
-    setup:		fbcon_cfb8_setup,
-    bmove:		fbcon_aty_bmove,
-    clear:		fbcon_aty_clear,
-    putc:		fbcon_aty8_putc,
-    putcs:		fbcon_aty8_putcs,
-    revc:		fbcon_cfb8_revc,
-    clear_margins:	fbcon_aty8_clear_margins,
-    fontwidthmask:	FONTWIDTH(4)|FONTWIDTH(8)|FONTWIDTH(12)|FONTWIDTH(16)
-};
-#endif
-
-#ifdef FBCON_HAS_CFB16
-static void fbcon_aty16_putc(struct vc_data *conp, struct display *p, int c,
-			     int yy, int xx)
-{
-    struct fb_info_aty *fb = (struct fb_info_aty *)(p->fb_info);
-
-#ifdef __sparc__
-    if (fb->mmaped && (!fb->fb_info.display_fg
-	|| fb->fb_info.display_fg->vc_num == fb->vtconsole))
-	return;
-#endif
-
-    if (fb->blitter_may_be_busy)
-	wait_for_idle((struct fb_info_aty *)p->fb_info);
-    fbcon_cfb16_putc(conp, p, c, yy, xx);
-}
-
-static void fbcon_aty16_putcs(struct vc_data *conp, struct display *p,
-			      const unsigned short *s, int count, int yy,
-			      int xx)
-{
-    struct fb_info_aty *fb = (struct fb_info_aty *)(p->fb_info);
-
-#ifdef __sparc__
-    if (fb->mmaped && (!fb->fb_info.display_fg
-	|| fb->fb_info.display_fg->vc_num == fb->vtconsole))
-	return;
-#endif
-
-    if (fb->blitter_may_be_busy)
-	wait_for_idle((struct fb_info_aty *)p->fb_info);
-    fbcon_cfb16_putcs(conp, p, s, count, yy, xx);
-}
-
-static void fbcon_aty16_clear_margins(struct vc_data *conp, struct display *p,
-				      int bottom_only)
-{
-    struct fb_info_aty *fb = (struct fb_info_aty *)(p->fb_info);
-
-#ifdef __sparc__
-    if (fb->mmaped && (!fb->fb_info.display_fg
-	|| fb->fb_info.display_fg->vc_num == fb->vtconsole))
-	return;
-#endif
-
-    if (fb->blitter_may_be_busy)
-	wait_for_idle((struct fb_info_aty *)p->fb_info);
-    fbcon_cfb16_clear_margins(conp, p, bottom_only);
-}
-
-static struct display_switch fbcon_aty16 = {
-    setup:		fbcon_cfb16_setup,
-    bmove:		fbcon_aty_bmove,
-    clear:		fbcon_aty_clear,
-    putc:		fbcon_aty16_putc,
-    putcs:		fbcon_aty16_putcs,
-    revc:		fbcon_cfb16_revc,
-    clear_margins:	fbcon_aty16_clear_margins,
-    fontwidthmask:	FONTWIDTH(4)|FONTWIDTH(8)|FONTWIDTH(12)|FONTWIDTH(16)
-};
-#endif
-
-#ifdef FBCON_HAS_CFB24
-static void fbcon_aty24_putc(struct vc_data *conp, struct display *p, int c,
-			     int yy, int xx)
-{
-    struct fb_info_aty *fb = (struct fb_info_aty *)(p->fb_info);
-
-#ifdef __sparc__
-    if (fb->mmaped && (!fb->fb_info.display_fg
-	|| fb->fb_info.display_fg->vc_num == fb->vtconsole))
-	return;
-#endif
-
-    if (fb->blitter_may_be_busy)
-	wait_for_idle((struct fb_info_aty *)p->fb_info);
-    fbcon_cfb24_putc(conp, p, c, yy, xx);
-}
-
-static void fbcon_aty24_putcs(struct vc_data *conp, struct display *p,
-			      const unsigned short *s, int count, int yy,
-			      int xx)
-{
-    struct fb_info_aty *fb = (struct fb_info_aty *)(p->fb_info);
-
-#ifdef __sparc__
-    if (fb->mmaped && (!fb->fb_info.display_fg
-	|| fb->fb_info.display_fg->vc_num == fb->vtconsole))
-	return;
-#endif
-
-    if (fb->blitter_may_be_busy)
-	wait_for_idle((struct fb_info_aty *)p->fb_info);
-    fbcon_cfb24_putcs(conp, p, s, count, yy, xx);
-}
-
-static void fbcon_aty24_clear_margins(struct vc_data *conp, struct display *p,
-				      int bottom_only)
-{
-    struct fb_info_aty *fb = (struct fb_info_aty *)(p->fb_info);
-
-#ifdef __sparc__
-    if (fb->mmaped && (!fb->fb_info.display_fg
-	|| fb->fb_info.display_fg->vc_num == fb->vtconsole))
-	return;
-#endif
-
-    if (fb->blitter_may_be_busy)
-	wait_for_idle((struct fb_info_aty *)p->fb_info);
-    fbcon_cfb24_clear_margins(conp, p, bottom_only);
-}
-
-static struct display_switch fbcon_aty24 = {
-    setup:		fbcon_cfb24_setup,
-    bmove:		fbcon_aty_bmove,
-    clear:		fbcon_aty_clear,
-    putc:		fbcon_aty24_putc,
-    putcs:		fbcon_aty24_putcs,
-    revc:		fbcon_cfb24_revc,
-    clear_margins:	fbcon_aty24_clear_margins,
-    fontwidthmask:	FONTWIDTH(4)|FONTWIDTH(8)|FONTWIDTH(12)|FONTWIDTH(16)
-};
-#endif
-
-#ifdef FBCON_HAS_CFB32
-static void fbcon_aty32_putc(struct vc_data *conp, struct display *p, int c,
-			     int yy, int xx)
-{
-    struct fb_info_aty *fb = (struct fb_info_aty *)(p->fb_info);
-
-#ifdef __sparc__
-    if (fb->mmaped && (!fb->fb_info.display_fg
-	|| fb->fb_info.display_fg->vc_num == fb->vtconsole))
-	return;
-#endif
-
-    if (fb->blitter_may_be_busy)
-	wait_for_idle((struct fb_info_aty *)p->fb_info);
-    fbcon_cfb32_putc(conp, p, c, yy, xx);
-}
-
-static void fbcon_aty32_putcs(struct vc_data *conp, struct display *p,
-			      const unsigned short *s, int count, int yy,
-			      int xx)
-{
-    struct fb_info_aty *fb = (struct fb_info_aty *)(p->fb_info);
-
-#ifdef __sparc__
-    if (fb->mmaped && (!fb->fb_info.display_fg
-	|| fb->fb_info.display_fg->vc_num == fb->vtconsole))
-	return;
-#endif
-
-    if (fb->blitter_may_be_busy)
-	wait_for_idle((struct fb_info_aty *)p->fb_info);
-    fbcon_cfb32_putcs(conp, p, s, count, yy, xx);
-}
-
-static void fbcon_aty32_clear_margins(struct vc_data *conp, struct display *p,
-				      int bottom_only)
-{
-    struct fb_info_aty *fb = (struct fb_info_aty *)(p->fb_info);
-
-#ifdef __sparc__
-    if (fb->mmaped && (!fb->fb_info.display_fg
-	|| fb->fb_info.display_fg->vc_num == fb->vtconsole))
-	return;
-#endif
-
-    if (fb->blitter_may_be_busy)
-	wait_for_idle((struct fb_info_aty *)p->fb_info);
-    fbcon_cfb32_clear_margins(conp, p, bottom_only);
-}
-
-static struct display_switch fbcon_aty32 = {
-    setup:		fbcon_cfb32_setup,
-    bmove:		fbcon_aty_bmove,
-    clear:		fbcon_aty_clear,
-    putc:		fbcon_aty32_putc,
-    putcs:		fbcon_aty32_putcs,
-    revc:		fbcon_cfb32_revc,
-    clear_margins:	fbcon_aty32_clear_margins,
-    fontwidthmask:	FONTWIDTH(4)|FONTWIDTH(8)|FONTWIDTH(12)|FONTWIDTH(16)
-};
-#endif
-
-#ifdef CONFIG_PMAC_PBOOK
-
-/* Power management routines. Those are used for PowerBook sleep.
- *
- * It appears that Rage LT and Rage LT Pro have different power
- * management registers. There's is some confusion about which
- * chipID is a Rage LT or LT pro :(
- */
-static int
-aty_power_mgmt_LT(int sleep, struct fb_info_aty *info)
-{
- 	unsigned int pm;
-	int timeout;
-	
-	pm = aty_ld_le32(POWER_MANAGEMENT_LG, info);
-	pm = (pm & ~PWR_MGT_MODE_MASK) | PWR_MGT_MODE_REG;
-	aty_st_le32(POWER_MANAGEMENT_LG, pm, info);
-	pm = aty_ld_le32(POWER_MANAGEMENT_LG, info);
-	
-	timeout = 200000;
-	if (sleep) {
-		/* Sleep */
-		pm &= ~PWR_MGT_ON;
-		aty_st_le32(POWER_MANAGEMENT_LG, pm, info);
-		pm = aty_ld_le32(POWER_MANAGEMENT_LG, info);
-		udelay(10);
-		pm &= ~(PWR_BLON | AUTO_PWR_UP);
-		pm |= SUSPEND_NOW;
-		aty_st_le32(POWER_MANAGEMENT_LG, pm, info);
-		pm = aty_ld_le32(POWER_MANAGEMENT_LG, info);
-		udelay(10);
-		pm |= PWR_MGT_ON;
-		aty_st_le32(POWER_MANAGEMENT_LG, pm, info);
-		do {
-			pm = aty_ld_le32(POWER_MANAGEMENT_LG, info);
-			udelay(10);
-			if ((--timeout) == 0)
-				break;
-		} while ((pm & PWR_MGT_STATUS_MASK) != PWR_MGT_STATUS_SUSPEND);
-	} else {
-		/* Wakeup */
-		pm &= ~PWR_MGT_ON;
-		aty_st_le32(POWER_MANAGEMENT_LG, pm, info);
-		pm = aty_ld_le32(POWER_MANAGEMENT_LG, info);
-		udelay(10);
-		pm |=  (PWR_BLON | AUTO_PWR_UP);
-		pm &= ~SUSPEND_NOW;
-		aty_st_le32(POWER_MANAGEMENT_LG, pm, info);
-		pm = aty_ld_le32(POWER_MANAGEMENT_LG, info);
-		udelay(10);
-		pm |= PWR_MGT_ON;
-		aty_st_le32(POWER_MANAGEMENT_LG, pm, info);
-		do {
-			pm = aty_ld_le32(POWER_MANAGEMENT_LG, info);
-			udelay(10);
-			if ((--timeout) == 0)
-				break;
-		} while ((pm & PWR_MGT_STATUS_MASK) != 0);
-	}
-	mdelay(500);
-
-	return timeout ? PBOOK_SLEEP_OK : PBOOK_SLEEP_REFUSE;
-}
-
-static int
-aty_power_mgmt_LTPro(int sleep, struct fb_info_aty *info)
-{
- 	unsigned int pm;
-	int timeout;
-	
-	pm = aty_ld_lcd(LCD_POWER_MANAGEMENT, info);
-	pm = (pm & ~PWR_MGT_MODE_MASK) | PWR_MGT_MODE_REG;
-	aty_st_lcd(LCD_POWER_MANAGEMENT, pm, info);
-	pm = aty_ld_lcd(LCD_POWER_MANAGEMENT, info);
-
-	timeout = 200;
-	if (sleep) {
-		/* Sleep */
-		pm &= ~PWR_MGT_ON;
-		aty_st_lcd(LCD_POWER_MANAGEMENT, pm, info);
-		pm = aty_ld_lcd(LCD_POWER_MANAGEMENT, info);
-		udelay(10);
-		pm &= ~(PWR_BLON | AUTO_PWR_UP);
-		pm |= SUSPEND_NOW;
-		aty_st_lcd(LCD_POWER_MANAGEMENT, pm, info);
-		pm = aty_ld_lcd(LCD_POWER_MANAGEMENT, info);
-		udelay(10);
-		pm |= PWR_MGT_ON;
-		aty_st_lcd(LCD_POWER_MANAGEMENT, pm, info);
-		do {
-			pm = aty_ld_lcd(LCD_POWER_MANAGEMENT, info);
-			udelay(1000);
-			if ((--timeout) == 0)
-				break;
-		} while ((pm & PWR_MGT_STATUS_MASK) != PWR_MGT_STATUS_SUSPEND);
-	} else {
-		/* Wakeup */
-		pm &= ~PWR_MGT_ON;
-		aty_st_lcd(LCD_POWER_MANAGEMENT, pm, info);
-		pm = aty_ld_lcd(LCD_POWER_MANAGEMENT, info);
-		udelay(10);
-		pm &= ~SUSPEND_NOW;
-		pm |= (PWR_BLON | AUTO_PWR_UP);
-		aty_st_lcd(LCD_POWER_MANAGEMENT, pm, info);
-		pm = aty_ld_lcd(LCD_POWER_MANAGEMENT, info);
-		udelay(10);
-		pm |= PWR_MGT_ON;
-		aty_st_lcd(LCD_POWER_MANAGEMENT, pm, info);
-		do {
-			pm = aty_ld_lcd(LCD_POWER_MANAGEMENT, info);			
-			udelay(1000);
-			if ((--timeout) == 0)
-				break;
-		} while ((pm & PWR_MGT_STATUS_MASK) != 0);
-	}
-
-	return timeout ? PBOOK_SLEEP_OK : PBOOK_SLEEP_REFUSE;
-}
-
-/*
- * Save the contents of the frame buffer when we go to sleep,
- * and restore it when we wake up again.
- */
-int
-aty_sleep_notify(struct pmu_sleep_notifier *self, int when)
-{
-	struct fb_info_aty *info;
- 	int result;
-
-	result = PBOOK_SLEEP_OK;
-
-	for (info = first_display; info != NULL; info = info->next) {
-		struct fb_fix_screeninfo fix;
-		int nb;
-
-		atyfb_get_fix(&fix, fg_console, (struct fb_info *)info);
-		nb = fb_display[fg_console].var.yres * fix.line_length;
-
-		switch (when) {
-		case PBOOK_SLEEP_REQUEST:
-			info->save_framebuffer = vmalloc(nb);
-			if (info->save_framebuffer == NULL)
-				return PBOOK_SLEEP_REFUSE;
-			break;
-		case PBOOK_SLEEP_REJECT:
-			if (info->save_framebuffer) {
-				vfree(info->save_framebuffer);
-				info->save_framebuffer = 0;
-			}
-			break;
-		case PBOOK_SLEEP_NOW:
-			if (info->blitter_may_be_busy)
-				wait_for_idle(info);
-			/* Stop accel engine (stop bus mastering) */
-			if (info->current_par.accel_flags & FB_ACCELF_TEXT)
-				reset_engine(info);
-
-			/* Backup fb content */	
-			if (info->save_framebuffer)
-				memcpy_fromio(info->save_framebuffer,
-				       (void *)info->frame_buffer, nb);
-
-			/* Blank display and LCD */
-			atyfbcon_blank(VESA_POWERDOWN+1, (struct fb_info *)info);
-
-			/* Set chip to "suspend" mode */
-			if (Gx == LG_CHIP_ID)
-				result = aty_power_mgmt_LT(1, info);
-			else
-				result = aty_power_mgmt_LTPro(1, info);
-			break;
-		case PBOOK_WAKE:
-			/* Wakeup chip */
-			if (Gx == LG_CHIP_ID)
-				result = aty_power_mgmt_LT(0, info);
-			else
-				result = aty_power_mgmt_LTPro(0, info);
-
-			/* Restore fb content */			
-			if (info->save_framebuffer) {
-				memcpy_toio((void *)info->frame_buffer,
-				       info->save_framebuffer, nb);
-				vfree(info->save_framebuffer);
-				info->save_framebuffer = 0;
-			}
-			/* Restore display */
-			atyfb_set_par(&info->current_par, info);
-			atyfbcon_blank(0, (struct fb_info *)info);
-			break;
-		}
-	}
-	return result;
-}
-#endif /* CONFIG_PMAC_PBOOK */
-
-#ifdef CONFIG_PMAC_BACKLIGHT
-static int backlight_conv[] = {
-	0x00, 0x3f, 0x4c, 0x59, 0x66, 0x73, 0x80, 0x8d,
-	0x9a, 0xa7, 0xb4, 0xc1, 0xcf, 0xdc, 0xe9, 0xff
-};
-
-static int
-aty_set_backlight_enable(int on, int level, void* data)
-{
-	struct fb_info_aty *info = (struct fb_info_aty *)data;
-	unsigned int reg = aty_ld_lcd(LCD_MISC_CNTL, info);
-	
-	reg |= (BLMOD_EN | BIASMOD_EN);
-	if (on && level > BACKLIGHT_OFF) {
-		reg &= ~BIAS_MOD_LEVEL_MASK;
-		reg |= (backlight_conv[level] << BIAS_MOD_LEVEL_SHIFT);
-	} else {
-		reg &= ~BIAS_MOD_LEVEL_MASK;
-		reg |= (backlight_conv[0] << BIAS_MOD_LEVEL_SHIFT);
-	}
-	aty_st_lcd(LCD_MISC_CNTL, reg, info);
-
-	return 0;
-}
-
-static int
-aty_set_backlight_level(int level, void* data)
-{
-	return aty_set_backlight_enable(1, level, data);
-}
-
-#endif /* CONFIG_PMAC_BACKLIGHT */
-
-
-#ifdef MODULE
-int __init init_module(void)
-{
-    atyfb_init();
-    return fb_list ? 0 : -ENXIO;
-}
-
-void cleanup_module(void)
-{
-    while (fb_list) {
-	struct fb_info_aty *info = fb_list;
-	fb_list = info->next;
-
-	unregister_framebuffer(&info->fb_info);
-
-#ifndef __sparc__
-	if (info->ati_regbase)
-	    iounmap((void *)info->ati_regbase);
-	if (info->frame_buffer)
-	    iounmap((void *)info->frame_buffer);
-#ifdef __BIG_ENDIAN
-	if (info->cursor && info->cursor->ram)
-	    iounmap(info->cursor->ram);
-#endif
-#endif
-
-	if (info->cursor) {
-	    if (info->cursor->timer)
-		kfree(info->cursor->timer);
-	    kfree(info->cursor);
-	}
-#ifdef __sparc__
-	if (info->mmap_map)
-	    kfree(info->mmap_map);
-#endif
-	kfree(info);
-    }
-}
-
-#endif
diff -u --recursive --new-file v2.4.7/linux/drivers/video/cgfourteenfb.c linux/drivers/video/cgfourteenfb.c
--- v2.4.7/linux/drivers/video/cgfourteenfb.c	Sun Feb 18 19:49:55 2001
+++ linux/drivers/video/cgfourteenfb.c	Sat Jul 28 12:12:38 2001
@@ -1,4 +1,4 @@
-/* $Id: cgfourteenfb.c,v 1.9 2001/02/13 01:17:14 davem Exp $
+/* $Id: cgfourteenfb.c,v 1.10 2001/07/27 09:44:00 davem Exp $
  * cgfourteenfb.c: CGfourteen frame buffer driver
  *
  * Copyright (C) 1996,1998 Jakub Jelinek (jj@ultra.linux.cz)
@@ -242,6 +242,11 @@
 		u8 tmp = sbus_readb(&cur->ccr);
 
 		tmp |= CG14_CCR_ENABLE;
+		sbus_writeb(tmp, &cur->ccr);
+	} else {
+		u8 tmp = sbus_readb(&cur->ccr);
+
+		tmp &= ~CG14_CCR_ENABLE;
 		sbus_writeb(tmp, &cur->ccr);
 	}
 	sbus_writew(((c->cpos.fbx - c->chot.fbx) & 0xfff), &cur->cursx);
diff -u --recursive --new-file v2.4.7/linux/fs/autofs/autofs_i.h linux/fs/autofs/autofs_i.h
--- v2.4.7/linux/fs/autofs/autofs_i.h	Tue Jul  3 17:08:21 2001
+++ linux/fs/autofs/autofs_i.h	Thu Jul 26 13:43:12 2001
@@ -107,7 +107,7 @@
 	unsigned long symlink_bitmap[AUTOFS_SYMLINK_BITMAP_LEN];
 };
 
-extern inline struct autofs_sb_info *autofs_sbi(struct super_block *sb)
+static inline struct autofs_sb_info *autofs_sbi(struct super_block *sb)
 {
 	return (struct autofs_sb_info *)(sb->u.generic_sbp);
 }
diff -u --recursive --new-file v2.4.7/linux/fs/buffer.c linux/fs/buffer.c
--- v2.4.7/linux/fs/buffer.c	Wed Jul 25 17:10:24 2001
+++ linux/fs/buffer.c	Tue Aug  7 00:27:41 2001
@@ -184,34 +184,30 @@
 /*
  * The buffers have been marked clean and locked.  Just submit the dang
  * things.. 
- *
- * We'll wait for the first one of them - "sync" is not exactly
- * performance-critical, and this makes us not hog the IO subsystem
- * completely, while still allowing for a fair amount of concurrent IO. 
  */
 static void write_locked_buffers(struct buffer_head **array, unsigned int count)
 {
-	struct buffer_head *wait = *array;
-	get_bh(wait);
 	do {
 		struct buffer_head * bh = *array++;
 		bh->b_end_io = end_buffer_io_sync;
 		submit_bh(WRITE, bh);
 	} while (--count);
-	wait_on_buffer(wait);
-	put_bh(wait);
 }
 
+/*
+ * Write some buffers from the head of the dirty queue.
+ *
+ * This must be called with the LRU lock held, and will
+ * return without it!
+ */
 #define NRSYNC (32)
-static void write_unlocked_buffers(kdev_t dev)
+static int write_some_buffers(kdev_t dev)
 {
 	struct buffer_head *next;
 	struct buffer_head *array[NRSYNC];
 	unsigned int count;
 	int nr;
 
-repeat:
-	spin_lock(&lru_list_lock);
 	next = lru_list[BUF_DIRTY];
 	nr = nr_buffers_type[BUF_DIRTY] * 2;
 	count = 0;
@@ -232,7 +228,7 @@
 
 			spin_unlock(&lru_list_lock);
 			write_locked_buffers(array, count);
-			goto repeat;
+			return -EAGAIN;
 		}
 		unlock_buffer(bh);
 		put_bh(bh);
@@ -241,6 +237,18 @@
 
 	if (count)
 		write_locked_buffers(array, count);
+	return 0;
+}
+
+/*
+ * Write out all buffers on the dirty list.
+ */
+static void write_unlocked_buffers(kdev_t dev)
+{
+	do {
+		spin_lock(&lru_list_lock);
+	} while (write_some_buffers(dev));
+	run_task_queue(&tq_disk);
 }
 
 static int wait_for_locked_buffers(kdev_t dev, int index, int refile)
@@ -310,11 +318,11 @@
 
 	lock_kernel();
 	sync_inodes_sb(sb);
+	DQUOT_SYNC(dev);
 	lock_super(sb);
 	if (sb->s_dirt && sb->s_op && sb->s_op->write_super)
 		sb->s_op->write_super(sb);
 	unlock_super(sb);
-	DQUOT_SYNC(dev);
 	unlock_kernel();
 
 	return sync_buffers(dev, 1);
@@ -325,9 +333,9 @@
 	sync_buffers(dev, 0);
 
 	lock_kernel();
-	sync_supers(dev);
 	sync_inodes(dev);
 	DQUOT_SYNC(dev);
+	sync_supers(dev);
 	unlock_kernel();
 
 	return sync_buffers(dev, 1);
@@ -775,7 +783,7 @@
 	if (free_shortage())
 		page_launder(GFP_NOFS, 0);
 	if (!grow_buffers(size)) {
-		wakeup_bdflush(1);
+		wakeup_bdflush();
 		current->policy |= SCHED_YIELD;
 		__set_current_state(TASK_RUNNING);
 		schedule();
@@ -1086,7 +1094,19 @@
 
 	if (state < 0)
 		return;
-	wakeup_bdflush(state);
+	wakeup_bdflush();
+
+	/*
+	 * If we're getting a lot out of balance, start some IO ourselves.
+	 *
+	 * This only queues it, and does not actually start it - we'll let
+	 * bdflush do that, or let it happen as a result of a lot of calls
+	 * to balance_dirty() filling up the request queues.
+	 */
+	if (state > 0) {
+		spin_lock(&lru_list_lock);
+		write_some_buffers(dev);
+	}
 }
 
 static __inline__ void __mark_dirty(struct buffer_head *bh)
@@ -2408,7 +2428,7 @@
 			loop = 1;
 			goto cleaned_buffers_try_again;
 		}
-		wakeup_bdflush(0);
+		wakeup_bdflush();
 	}
 	return 0;
 }
@@ -2532,69 +2552,11 @@
  * a limited number of buffers to the disks and then go back to sleep again.
  */
 
-/* This is the _only_ function that deals with flushing async writes
-   to disk.
-   NOTENOTENOTENOTE: we _only_ need to browse the DIRTY lru list
-   as all dirty buffers lives _only_ in the DIRTY lru list.
-   As we never browse the LOCKED and CLEAN lru lists they are infact
-   completly useless. */
-static int flush_dirty_buffers(int check_flushtime)
-{
-	struct buffer_head * bh, *next;
-	int flushed = 0, i;
-
- restart:
-	spin_lock(&lru_list_lock);
-	bh = lru_list[BUF_DIRTY];
-	if (!bh)
-		goto out_unlock;
-	for (i = nr_buffers_type[BUF_DIRTY]; i-- > 0; bh = next) {
-		next = bh->b_next_free;
-
-		if (!buffer_dirty(bh)) {
-			__refile_buffer(bh);
-			continue;
-		}
-		if (buffer_locked(bh))
-			continue;
-
-		if (check_flushtime) {
-			/* The dirty lru list is chronologically ordered so
-			   if the current bh is not yet timed out,
-			   then also all the following bhs
-			   will be too young. */
-			if (time_before(jiffies, bh->b_flushtime))
-				goto out_unlock;
-		} else {
-			if (++flushed > bdf_prm.b_un.ndirty)
-				goto out_unlock;
-		}
-
-		/* OK, now we are committed to write it out. */
-		get_bh(bh);
-		spin_unlock(&lru_list_lock);
-		ll_rw_block(WRITE, 1, &bh);
-		put_bh(bh);
-
-		if (current->need_resched)
-			schedule();
-		goto restart;
-	}
- out_unlock:
-	spin_unlock(&lru_list_lock);
-
-	return flushed;
-}
-
 DECLARE_WAIT_QUEUE_HEAD(bdflush_wait);
 
-void wakeup_bdflush(int block)
+void wakeup_bdflush(void)
 {
-	if (waitqueue_active(&bdflush_wait))
-		wake_up_interruptible(&bdflush_wait);
-
-	if (block)
-		flush_dirty_buffers(0);
+	wake_up_interruptible(&bdflush_wait);
 }
 
 /* 
@@ -2608,14 +2570,24 @@
 static int sync_old_buffers(void)
 {
 	lock_kernel();
-	sync_supers(0);
 	sync_unlocked_inodes();
+	sync_supers(0);
 	unlock_kernel();
 
-	flush_dirty_buffers(1);
-	/* must really sync all the active I/O request to disk here */
-	run_task_queue(&tq_disk);
-	return 0;
+	spin_lock(&lru_list_lock);
+	for (;;) {
+		if (write_some_buffers(NODEV)) {
+			struct buffer_head *bh;
+
+			spin_lock(&lru_list_lock);
+			bh = lru_list[BUF_DIRTY];
+			if (!time_before(jiffies, bh->b_flushtime))
+				continue;
+			spin_unlock(&lru_list_lock);
+		}
+		run_task_queue(&tq_disk);
+		return 0;
+	}
 }
 
 int block_sync_page(struct page *page)
@@ -2685,7 +2657,7 @@
 int bdflush(void *startup)
 {
 	struct task_struct *tsk = current;
-	int flushed;
+
 	/*
 	 *	We have a bare-bones task_struct, and really should fill
 	 *	in a few more things so "top" and /proc/2/{exe,root,cwd}
@@ -2708,14 +2680,8 @@
 	for (;;) {
 		CHECK_EMERGENCY_SYNC
 
-		flushed = flush_dirty_buffers(0);
-
-		/*
-		 * If there are still a lot of dirty buffers around,
-		 * skip the sleep and flush some more. Otherwise, we
-		 * go to sleep waiting a wakeup.
-		 */
-		if (!flushed || balance_dirty_state(NODEV) < 0) {
+		spin_lock(&lru_list_lock);
+		if (!write_some_buffers(NODEV) || balance_dirty_state(NODEV) < 0) {
 			run_task_queue(&tq_disk);
 			interruptible_sleep_on(&bdflush_wait);
 		}
diff -u --recursive --new-file v2.4.7/linux/fs/dcache.c linux/fs/dcache.c
--- v2.4.7/linux/fs/dcache.c	Wed Jul 25 17:10:24 2001
+++ linux/fs/dcache.c	Fri Aug  3 21:13:43 2001
@@ -547,7 +547,7 @@
  *  ...
  *   6 - base-level: try to shrink a bit.
  */
-void shrink_dcache_memory(int priority, unsigned int gfp_mask)
+int shrink_dcache_memory(int priority, unsigned int gfp_mask)
 {
 	int count = 0;
 
@@ -563,13 +563,13 @@
 	 * block allocations, but for now:
 	 */
 	if (!(gfp_mask & __GFP_FS))
-		return;
+		return 0;
 
-	if (priority)
-		count = dentry_stat.nr_unused / priority;
+	count = dentry_stat.nr_unused >> priority;
 
 	prune_dcache(count);
 	kmem_cache_shrink(dentry_cache);
+	return 0;
 }
 
 #define NAME_ALLOC_LEN(len)	((len+16) & ~15)
diff -u --recursive --new-file v2.4.7/linux/fs/fat/buffer.c linux/fs/fat/buffer.c
--- v2.4.7/linux/fs/fat/buffer.c	Thu May 24 15:36:33 2001
+++ linux/fs/fat/buffer.c	Tue Jul 24 14:23:53 2001
@@ -100,62 +100,3 @@
 {
 	ll_rw_block(opr,nbreq,bh);
 }
-
-struct buffer_head *bigblock_fat_bread(struct super_block *sb, int block)
-{
-	unsigned int hardsect = get_hardsect_size(sb->s_dev);
-	int rblock, roffset;
-	struct buffer_head *real, *dummy;
-
-	if (hardsect <= sb->s_blocksize)
-		BUG();
-
-	dummy = NULL;
-	rblock = block / (hardsect / sb->s_blocksize);
-	roffset = (block % (hardsect / sb->s_blocksize)) * sb->s_blocksize;
-	real = bread(sb->s_dev, rblock, hardsect);
-	if (real != NULL) {
-		dummy = kmalloc(sizeof(struct buffer_head), GFP_KERNEL);
-		if (dummy != NULL) {
-			memset(dummy, 0, sizeof(*dummy));
-			dummy->b_data = real->b_data + roffset;
-			dummy->b_next = real;
-		} else
-			brelse(real);
-	}
-
-	return dummy;
-}
-
-void bigblock_fat_brelse(struct super_block *sb, struct buffer_head *bh)
-{
-	brelse(bh->b_next);
-	kfree(bh);
-}
-
-void bigblock_fat_mark_buffer_dirty(struct super_block *sb, struct buffer_head *bh)
-{
-	mark_buffer_dirty(bh->b_next);
-}
-
-void bigblock_fat_set_uptodate(struct super_block *sb, struct buffer_head *bh,
-			       int val)
-{
-	mark_buffer_uptodate(bh->b_next, val);
-}
-
-int bigblock_fat_is_uptodate(struct super_block *sb, struct buffer_head *bh)
-{
-	return buffer_uptodate(bh->b_next);
-}
-
-void bigblock_fat_ll_rw_block (struct super_block *sb, int opr, int nbreq,
-			       struct buffer_head *bh[32])
-{
-	struct buffer_head *tmp[32];
-	int i;
-
-	for (i = 0; i < nbreq; i++)
-		tmp[i] = bh[i]->b_next;
-	ll_rw_block(opr, nbreq, tmp);
-}
diff -u --recursive --new-file v2.4.7/linux/fs/fat/cvf.c linux/fs/fat/cvf.c
--- v2.4.7/linux/fs/fat/cvf.c	Mon Oct 16 12:58:51 2000
+++ linux/fs/fat/cvf.c	Tue Jul 24 14:23:53 2001
@@ -23,79 +23,32 @@
 
 struct buffer_head *default_fat_bread(struct super_block *,int);
 struct buffer_head *default_fat_getblk(struct super_block *, int);
-struct buffer_head *bigblock_fat_bread(struct super_block *, int);
 void default_fat_brelse(struct super_block *, struct buffer_head *);
-void bigblock_fat_brelse(struct super_block *, struct buffer_head *);
-void default_fat_mark_buffer_dirty (struct super_block *,
-	struct buffer_head *);
-void bigblock_fat_mark_buffer_dirty (struct super_block *,
-	struct buffer_head *);
+void default_fat_mark_buffer_dirty (struct super_block *, struct buffer_head *);
 void default_fat_set_uptodate (struct super_block *, struct buffer_head *,int);
-void bigblock_fat_set_uptodate (struct super_block *, struct buffer_head *,int);
 int default_fat_is_uptodate(struct super_block *, struct buffer_head *);
-int bigblock_fat_is_uptodate(struct super_block *, struct buffer_head *);
 int default_fat_access(struct super_block *sb,int nr,int new_value);
-void default_fat_ll_rw_block (
-	struct super_block *sb,
-	int opr,
-	int nbreq,
-	struct buffer_head *bh[32]);
-void bigblock_fat_ll_rw_block (
-	struct super_block *sb,
-	int opr,
-	int nbreq,
-	struct buffer_head *bh[32]);
+void default_fat_ll_rw_block (struct super_block *sb, int opr, int nbreq,
+			      struct buffer_head *bh[32]);
 int default_fat_bmap(struct inode *inode,int block);
-ssize_t default_fat_file_write(
-	struct file *filp,
-	const char *buf,
-	size_t count,
-	loff_t *ppos);
+ssize_t default_fat_file_write(struct file *filp, const char *buf,
+			       size_t count, loff_t *ppos);
 
 struct cvf_format default_cvf = {
-	0,	/* version - who cares? */	
-	"plain",
-	0,	/* flags - who cares? */
-	NULL,
-	NULL,
-	NULL,
-	default_fat_bread,
-	default_fat_getblk,
-	default_fat_brelse,
-	default_fat_mark_buffer_dirty,
-	default_fat_set_uptodate,
-	default_fat_is_uptodate,
-	default_fat_ll_rw_block,
-	default_fat_access,
-	NULL,
-	default_fat_bmap,
-	generic_file_read,
-	default_fat_file_write,
-	NULL,
-	NULL
-};
-
-struct cvf_format bigblock_cvf = {
-	0,	/* version - who cares? */	
-	"big_blocks",
-	0,	/* flags - who cares? */
-	NULL,
-	NULL,
-	NULL,
-	bigblock_fat_bread,
-	bigblock_fat_bread,
-	bigblock_fat_brelse,
-	bigblock_fat_mark_buffer_dirty,
-	bigblock_fat_set_uptodate,
-	bigblock_fat_is_uptodate,
-	bigblock_fat_ll_rw_block,
-	default_fat_access,
-	NULL,
-	default_fat_bmap,
-	NULL,
-	default_fat_file_write,
-	NULL,
-	NULL
+	cvf_version: 		0,	/* version - who cares? */	
+	cvf_version_text: 	"plain",
+	flags:			0,	/* flags - who cares? */
+	cvf_bread:		default_fat_bread,
+	cvf_getblk:		default_fat_getblk,
+	cvf_brelse:		default_fat_brelse,
+	cvf_mark_buffer_dirty:	default_fat_mark_buffer_dirty,
+	cvf_set_uptodate:	default_fat_set_uptodate,
+	cvf_is_uptodate:	default_fat_is_uptodate,
+	cvf_ll_rw_block:	default_fat_ll_rw_block,
+	fat_access:		default_fat_access,
+	cvf_bmap:		default_fat_bmap,
+	cvf_file_read:		generic_file_read,
+	cvf_file_write:		default_fat_file_write,
 };
 
 struct cvf_format *cvf_formats[MAX_CVF_FORMATS];
diff -u --recursive --new-file v2.4.7/linux/fs/fat/inode.c linux/fs/fat/inode.c
--- v2.4.7/linux/fs/fat/inode.c	Tue Jul  3 17:08:21 2001
+++ linux/fs/fat/inode.c	Tue Jul 24 14:23:53 2001
@@ -36,7 +36,7 @@
 #include <asm/uaccess.h>
 #include <asm/unaligned.h>
 
-extern struct cvf_format default_cvf, bigblock_cvf;
+extern struct cvf_format default_cvf;
 
 /* #define FAT_PARANOIA 1 */
 #define DEBUG_LEVEL 0
@@ -448,8 +448,6 @@
 	hard_blksize = get_hardsect_size(sb->s_dev);
 	if (!hard_blksize)
 		hard_blksize = 512;
-	if (hard_blksize != 512)
-		printk("MSDOS: Hardware sector size is %d\n", hard_blksize);
 
 	opts.isvfat = sbi->options.isvfat;
 	if (!parse_options((char *) data, &fat, &debug, &opts,
@@ -464,8 +462,8 @@
 	set_blocksize(sb->s_dev, hard_blksize);
 	bh = bread(sb->s_dev, 0, sb->s_blocksize);
 	if (bh == NULL) {
-		brelse (bh);
-		goto out_no_bread;
+		printk("FAT: unable to read boot sector\n");
+		goto out_fail;
 	}
 
 /*
@@ -489,15 +487,23 @@
 		CF_LE_W(get_unaligned((unsigned short *) &b->sector_size));
 	if (!logical_sector_size
 	    || (logical_sector_size & (logical_sector_size - 1))) {
-		printk("fatfs: bogus logical sector size %d\n",
+		printk("FAT: bogus logical sector size %d\n",
 		       logical_sector_size);
 		brelse(bh);
 		goto out_invalid;
 	}
 
 	sbi->cluster_size = b->cluster_size;
-	if (!sbi->cluster_size || (sbi->cluster_size & (sbi->cluster_size - 1))) {
-		printk("fatfs: bogus cluster size %d\n", sbi->cluster_size);
+	if (!sbi->cluster_size
+	    || (sbi->cluster_size & (sbi->cluster_size - 1))) {
+		printk("FAT: bogus cluster size %d\n", sbi->cluster_size);
+		brelse(bh);
+		goto out_invalid;
+	}
+
+	if (logical_sector_size < hard_blksize) {
+		printk("FAT: logical sector size too small for device"
+		       " (logical sector size = %d)\n", logical_sector_size);
 		brelse(bh);
 		goto out_invalid;
 	}
@@ -528,8 +534,8 @@
 		if (bh->b_blocknr != fsinfo_block) {
 			fsinfo_bh = bread(sb->s_dev, fsinfo_block, hard_blksize);
 			if (fsinfo_bh == NULL) {
-				printk("FAT: bread failed, fsinfo block %d\n",
-				       fsinfo_block);
+				printk("FAT: bread failed, FSINFO block"
+				       " (blocknr = %d)\n", fsinfo_block);
 				brelse(bh);
 				goto out_invalid;
 			}
@@ -585,20 +591,14 @@
 
 	sb->s_blocksize = logical_sector_size;
 	sb->s_blocksize_bits = ffs(logical_sector_size) - 1;
-	if (sb->s_blocksize >= hard_blksize) {
-		set_blocksize(sb->s_dev, sb->s_blocksize);
-		sbi->cvf_format = &default_cvf;
-	} else {
-		set_blocksize(sb->s_dev, hard_blksize);
-		sbi->cvf_format = &bigblock_cvf;
-	}
-
-	if (!strcmp(cvf_format,"none"))
+	set_blocksize(sb->s_dev, sb->s_blocksize);
+	sbi->cvf_format = &default_cvf;
+	if (!strcmp(cvf_format, "none"))
 		i = -1;
 	else
 		i = detect_cvf(sb,cvf_format);
 	if (i >= 0)
-		error = cvf_formats[i]->mount_cvf(sb,cvf_options);
+		error = cvf_formats[i]->mount_cvf(sb, cvf_options);
 	if (error || debug) {
 		/* The MSDOS_CAN_BMAP is obsolete, but left just to remember */
 		printk("[MS-DOS FS Rel. 12,FAT %d,check=%c,conv=%c,"
@@ -607,16 +607,14 @@
 		       opts.conversion,opts.fs_uid,opts.fs_gid,opts.fs_umask,
 		       MSDOS_CAN_BMAP(sbi) ? ",bmap" : "");
 		printk("[me=0x%x,cs=%d,#f=%d,fs=%d,fl=%ld,ds=%ld,de=%d,data=%ld,"
-		       "se=%d,ts=%ld,ls=%d,rc=%ld,fc=%u]\n",
-		       b->media,sbi->cluster_size,
-		       sbi->fats,sbi->fat_start,
-		       sbi->fat_length,
-		       sbi->dir_start,sbi->dir_entries,
-		       sbi->data_start,
-		       CF_LE_W(*(unsigned short *) &b->sectors),
-		       (unsigned long)b->total_sect,logical_sector_size,
-		       sbi->root_cluster,sbi->free_clusters);
-		printk ("Transaction block size = %d\n", hard_blksize);
+		       "se=%u,ts=%u,ls=%d,rc=%ld,fc=%u]\n",
+		       b->media, sbi->cluster_size, sbi->fats,
+		       sbi->fat_start, sbi->fat_length, sbi->dir_start,
+		       sbi->dir_entries, sbi->data_start,
+		       CF_LE_W(get_unaligned((unsigned short *)&b->sectors)),
+		       CF_LE_L(b->total_sect), logical_sector_size,
+		       sbi->root_cluster, sbi->free_clusters);
+		printk ("hard sector size = %d\n", hard_blksize);
 	}
 	if (i < 0)
 		if (sbi->clusters + 2 > fat_clusters)
@@ -653,7 +651,7 @@
 	if (! sbi->nls_io)
 		sbi->nls_io = load_nls_default();
 
-	root_inode=new_inode(sb);
+	root_inode = new_inode(sb);
 	if (!root_inode)
 		goto out_unload_nls;
 	root_inode->i_ino = MSDOS_ROOT_INO;
@@ -662,29 +660,27 @@
 	sb->s_root = d_alloc_root(root_inode);
 	if (!sb->s_root)
 		goto out_no_root;
-	if(i>=0) {
+	if(i >= 0) {
 		sbi->cvf_format = cvf_formats[i];
 		++cvf_format_use_count[i];
 	}
 	return sb;
 
 out_no_root:
-	printk("get root inode failed\n");
+	printk("FAT: get root inode failed\n");
 	iput(root_inode);
 	unload_nls(sbi->nls_io);
 out_unload_nls:
 	unload_nls(sbi->nls_disk);
 	goto out_fail;
 out_invalid:
-	if (!silent)
-		printk("VFS: Can't find a valid MSDOS filesystem on dev %s.\n",
+	if (!silent) {
+		printk("VFS: Can't find a valid FAT filesystem on dev %s.\n",
 			kdevname(sb->s_dev));
-	goto out_fail;
-out_no_bread:
-	printk("FAT bread failed\n");
+	}
 out_fail:
 	if (opts.iocharset) {
-		printk("VFS: freeing iocharset=%s\n", opts.iocharset);
+		printk("FAT: freeing iocharset=%s\n", opts.iocharset);
 		kfree(opts.iocharset);
 	}
 	if(sbi->private_data)
diff -u --recursive --new-file v2.4.7/linux/fs/inode.c linux/fs/inode.c
--- v2.4.7/linux/fs/inode.c	Wed Jul 25 17:10:24 2001
+++ linux/fs/inode.c	Fri Aug  3 21:13:54 2001
@@ -681,7 +681,7 @@
 	goto free_unused;
 }
 
-void shrink_icache_memory(int priority, int gfp_mask)
+int shrink_icache_memory(int priority, int gfp_mask)
 {
 	int count = 0;
 
@@ -693,13 +693,13 @@
 	 * in clear_inode() and friends..
 	 */
 	if (!(gfp_mask & __GFP_FS))
-		return;
+		return 0;
 
-	if (priority)
-		count = inodes_stat.nr_unused / priority;
+	count = inodes_stat.nr_unused >> priority;
 
 	prune_icache(count);
 	kmem_cache_shrink(inode_cachep);
+	return 0;
 }
 
 /*
diff -u --recursive --new-file v2.4.7/linux/fs/ntfs/dir.c linux/fs/ntfs/dir.c
--- v2.4.7/linux/fs/ntfs/dir.c	Wed Jul 25 17:10:24 2001
+++ linux/fs/ntfs/dir.c	Mon Jul 23 16:23:58 2001
@@ -894,6 +894,11 @@
 		return -EIO;
 	}
 	attr = ntfs_find_attr(ino, vol->at_index_allocation, I30);
+	if (!attr) {
+		ntfs_free(buf);
+		ntfs_debug(DEBUG_DIR3, "unsorted 9.5\n");
+		return -EIO;
+	}
 	while (1) {
 		if ((__s64)*p_high << vol->cluster_size_bits > attr->size) {
 			/* No more index records. */
diff -u --recursive --new-file v2.4.7/linux/fs/ntfs/inode.c linux/fs/ntfs/inode.c
--- v2.4.7/linux/fs/ntfs/inode.c	Wed Jul 25 17:10:24 2001
+++ linux/fs/ntfs/inode.c	Mon Jul 23 16:23:58 2001
@@ -95,6 +95,8 @@
 	ntfs_io io;
 
 	mdata = ntfs_find_attr(vol->mft_ino, vol->at_data, 0);
+	if (!mdata)
+		return -EINVAL;
 	/* First check whether there is uninitialized space. */
 	if (mdata->allocated < mdata->size + vol->mft_record_size) {
 		size = (__s64)ntfs_get_free_cluster_count(vol->bitmap) <<
@@ -127,6 +129,8 @@
 	/* Now extend the bitmap if necessary. */
 	rcount = mdata->size >> vol->mft_record_size_bits;
 	bmp = ntfs_find_attr(vol->mft_ino, vol->at_bitmap, 0);
+	if (!bmp)
+		return -EINVAL;
 	if (bmp->size * 8 < rcount) { /* Less bits than MFT records. */
 		ntfs_u8 buf[1];
 		/* Extend bitmap by one byte. */
@@ -1305,6 +1309,8 @@
 	*result = 0;
 	/* Determine the number of mft records in the mft. */
 	data = ntfs_find_attr(vol->mft_ino, vol->at_data, 0);
+	if (!data)
+		return -EINVAL;
 	length = data->size >> vol->mft_record_size_bits;
 	/* Allocate sufficient space for the mft bitmap attribute value,
 	   inferring it from the number of mft records. */
diff -u --recursive --new-file v2.4.7/linux/fs/partitions/Config.in linux/fs/partitions/Config.in
--- v2.4.7/linux/fs/partitions/Config.in	Wed Jul 25 17:10:24 2001
+++ linux/fs/partitions/Config.in	Thu Jul 26 16:30:04 2001
@@ -25,6 +25,10 @@
       bool '    Solaris (x86) partition table support' CONFIG_SOLARIS_X86_PARTITION
       bool '    Unixware slices support' CONFIG_UNIXWARE_DISKLABEL
    fi
+   dep_bool '  Windows Logical Disk Manager (Dynamic Disk) support' CONFIG_LDM_PARTITION $CONFIG_EXPERIMENTAL
+   if [ "$CONFIG_LDM_PARTITION" = "y" ]; then
+      bool '    Windows LDM extra logging' CONFIG_LDM_DEBUG
+   fi
    bool '  SGI partition support' CONFIG_SGI_PARTITION
    bool '  Ultrix partition table support' CONFIG_ULTRIX_PARTITION
    bool '  Sun partition tables support' CONFIG_SUN_PARTITION
diff -u --recursive --new-file v2.4.7/linux/fs/partitions/Makefile linux/fs/partitions/Makefile
--- v2.4.7/linux/fs/partitions/Makefile	Fri Apr 13 20:26:07 2001
+++ linux/fs/partitions/Makefile	Thu Jul 26 16:30:04 2001
@@ -17,6 +17,7 @@
 obj-$(CONFIG_AMIGA_PARTITION) += amiga.o
 obj-$(CONFIG_ATARI_PARTITION) += atari.o
 obj-$(CONFIG_MAC_PARTITION) += mac.o
+obj-$(CONFIG_LDM_PARTITION) += ldm.o
 obj-$(CONFIG_MSDOS_PARTITION) += msdos.o
 obj-$(CONFIG_OSF_PARTITION) += osf.o
 obj-$(CONFIG_SGI_PARTITION) += sgi.o
diff -u --recursive --new-file v2.4.7/linux/fs/partitions/check.c linux/fs/partitions/check.c
--- v2.4.7/linux/fs/partitions/check.c	Wed Jul 25 17:10:24 2001
+++ linux/fs/partitions/check.c	Sun Aug  5 13:12:41 2001
@@ -25,6 +25,7 @@
 #include "acorn.h"
 #include "amiga.h"
 #include "atari.h"
+#include "ldm.h"
 #include "mac.h"
 #include "msdos.h"
 #include "osf.h"
@@ -42,6 +43,9 @@
 #ifdef CONFIG_ACORN_PARTITION
 	acorn_partition,
 #endif
+#ifdef CONFIG_LDM_PARTITION
+	ldm_partition,		/* this must come before msdos */
+#endif
 #ifdef CONFIG_MSDOS_PARTITION
 	msdos_partition,
 #endif
@@ -73,11 +77,23 @@
 };
 
 /*
+ *	This is ucking fugly but its probably the best thing for 2.4.x
+ *	Take it as a clear reminder than we should put the device name
+ *	generation in the object kdev_t points to in 2.5.
+ */
+ 
+#ifdef CONFIG_ARCH_S390
+int (*genhd_dasd_name)(char*,int,int,struct gendisk*) = NULL;
+EXPORT_SYMBOL(genhd_dasd_name);
+#endif
+
+/*
  * disk_name() is used by partition check code and the md driver.
  * It formats the devicename of the indicated disk into
  * the supplied buffer (of size at least 32), and returns
  * a pointer to that same buffer (for convenience).
  */
+
 char *disk_name (struct gendisk *hd, int minor, char *buf)
 {
 	unsigned int part;
@@ -92,6 +108,12 @@
 		if (pos >= 0)
 			return buf + pos;
 	}
+
+#ifdef CONFIG_ARCH_S390
+	if (genhd_dasd_name
+	    && genhd_dasd_name (buf, unit - 'a', part, hd) == 0)
+		return buf;
+#endif
 	/*
 	 * IDE devices use multiple major numbers, but the drives
 	 * are named as:  {hda,hdb}, {hdc,hdd}, {hde,hdf}, {hdg,hdh}..
diff -u --recursive --new-file v2.4.7/linux/fs/partitions/ibm.c linux/fs/partitions/ibm.c
--- v2.4.7/linux/fs/partitions/ibm.c	Sun May 20 12:11:39 2001
+++ linux/fs/partitions/ibm.c	Sun Aug  5 13:12:41 2001
@@ -10,14 +10,14 @@
  * 02/13/00 VTOC partition support added
  */
 
-#include <linux/module.h>
+#include <linux/config.h>
 #include <linux/fs.h>
 #include <linux/genhd.h>
 #include <linux/kernel.h>
 #include <linux/major.h>
 #include <linux/string.h>
 #include <linux/blk.h>
-#include <linux/malloc.h>
+#include <linux/slab.h>
 #include <linux/hdreg.h>
 #include <linux/ioctl.h>
 #include <linux/version.h>
@@ -29,14 +29,6 @@
 #include "check.h"
 #include <asm/vtoc.h>
 
-#if (LINUX_VERSION_CODE > KERNEL_VERSION(2,3,98))
-/* We hook in when DASD is a module... */
-int (*genhd_dasd_name)(char*,int,int,struct gendisk*) = NULL;
-int (*genhd_dasd_fillgeo)(int,struct hd_geometry *) = NULL;
-EXPORT_SYMBOL(genhd_dasd_fillgeo);
-EXPORT_SYMBOL(genhd_dasd_name);
-#endif /* LINUX_IS_24 */
-
 typedef enum {
   ibm_partition_lnx1 = 0,
   ibm_partition_vol1 = 1,
@@ -50,6 +42,73 @@
 			     [ibm_partition_none] = "(nonl)"
 };
 
+static int
+get_drive_geometry(int kdev,struct hd_geometry *geo) 
+{
+	int rc = 0;
+	mm_segment_t old_fs;
+	struct file *filp;
+	struct inode *inode;
+        /* find out offset of volume label (partn table) */
+        filp = (struct file *)kmalloc (sizeof(struct file),GFP_KERNEL);
+        if ( filp == NULL ) {
+                printk (KERN_WARNING __FILE__ " ibm_partition: kmalloc failed fo
+r filp\n");
+                return -ENOMEM;
+        }
+        memset(filp,0,sizeof(struct file));
+        filp ->f_mode = 1; /* read only */
+        inode = get_empty_inode();
+	if ( inode == NULL )
+		return -ENOMEM;
+        inode -> i_rdev = kdev;
+	inode -> i_bdev = bdget(kdev_t_to_nr(kdev));
+	rc = blkdev_open(inode,filp);
+        if ( rc == 0 ) {
+		old_fs=get_fs();
+		set_fs(KERNEL_DS);
+		rc = inode-> i_bdev -> bd_op->ioctl (inode, filp, HDIO_GETGEO, 
+						     (unsigned long)(geo))
+			;
+		set_fs(old_fs);
+	}
+	blkdev_put(inode->i_bdev,BDEV_FILE);
+	return rc;
+}
+
+static int
+get_drive_info(int kdev,dasd_information_t *info) 
+{
+	int rc = 0;
+	mm_segment_t old_fs;
+	struct file *filp;
+	struct inode *inode;
+        /* find out offset of volume label (partn table) */
+        filp = (struct file *)kmalloc (sizeof(struct file),GFP_KERNEL);
+        if ( filp == NULL ) {
+                printk (KERN_WARNING __FILE__ " ibm_partition: kmalloc failed fo
+r filp\n");
+                return -ENOMEM;
+        }
+        memset(filp,0,sizeof(struct file));
+        filp ->f_mode = 1; /* read only */
+        inode = get_empty_inode();
+	if ( inode == NULL )
+		return -ENOMEM;
+        inode -> i_rdev = kdev;
+	inode -> i_bdev = bdget(kdev_t_to_nr(kdev));
+        rc = blkdev_open(inode,filp);
+        if ( rc == 0 ) {
+		old_fs=get_fs();
+		set_fs(KERNEL_DS);
+		rc = inode-> i_bdev -> bd_op->ioctl (inode, filp, BIODASDINFO, 
+						     (unsigned long)(info));
+		set_fs(old_fs);
+	}
+	blkdev_put(inode->i_bdev,BDEV_FILE);
+	return rc;
+}
+
 static ibm_partition_t
 get_partition_type ( char * type )
 {
@@ -110,38 +169,52 @@
 	ibm_partition_t partition_type;
 	char type[5] = {0,};
 	char name[7] = {0,};
-	struct hd_geometry geo;
+	struct hd_geometry *geo;
 	int blocksize;
 	int offset=0, size=0, psize=0, counter=0;
 	unsigned int blk;
 	format1_label_t f1;
 	volume_label_t vlabel;
+	dasd_information_t *info;
 
 	if ( first_sector != 0 ) {
 		BUG();
 	}
-	if ( !genhd_dasd_fillgeo ) {
+	info = (struct dasd_information_t *)kmalloc(sizeof(dasd_information_t),
+						    GFP_KERNEL);
+	if ( info == NULL )
+		return 0;
+	if (get_drive_info (dev,info)) 
+		return 0;
+	geo = (struct hd_geometry *)kmalloc(sizeof(struct hd_geometry),
+					    GFP_KERNEL);
+	if ( geo == NULL )
+		return 0;
+	if (get_drive_geometry (dev,geo)) 
 		return 0;
-	}
-	genhd_dasd_fillgeo(dev,&geo);
 	blocksize = hardsect_size[MAJOR(dev)][MINOR(dev)];
 	if ( blocksize <= 0 ) {
 		return 0;
 	}
-
+	
 	set_blocksize(dev, blocksize);  /* OUCH !! */
-	if ( ( bh = bread( dev, geo.start, blocksize) ) != NULL ) {
+	if ( ( bh = bread( dev, info->label_block, blocksize) ) != NULL ) {
 		strncpy ( type,bh -> b_data + 0, 4);
-		strncpy ( name,bh -> b_data + 4, 6);
+		if ((!info->FBA_layout) && (!strcmp(info->type,"ECKD"))) {
+		        
+		        strncpy ( name,bh -> b_data + 8, 6);
+		} else {
+		        strncpy ( name,bh -> b_data + 4, 6);		  
+		}
 		memcpy (&vlabel, bh->b_data, sizeof(volume_label_t));
         } else {
 		return 0;
 	}
 	EBCASC(type,4);
 	EBCASC(name,6);
-
+	
 	partition_type = get_partition_type(type);
-	printk ( "%6s/%6s:",part_names[partition_type],name);
+	printk ( "%4s/%8s:",part_names[partition_type],name);
 	switch ( partition_type ) {
 	case ibm_partition_cms1:
 		if (* (((long *)bh->b_data) + 13) != 0) {
@@ -152,38 +225,37 @@
 			size = (label[7]-1)*(blocksize>>9); 
 			printk ("(MDSK)");
 		} else {
-			offset = (geo.start + 1);
+			offset = (info->label_block + 1);
 			size = hd -> sizes[MINOR(dev)]<<1;
 		}
-		two_partitions( hd, MINOR(dev), blocksize, 
-				offset, size);
+		two_partitions( hd, MINOR(dev), blocksize, offset, size);
 		break;
 	case ibm_partition_lnx1: 
 	case ibm_partition_none:
-		offset = (geo.start + 1);
+		offset = (info->label_block + 1);
 		size = hd -> sizes[MINOR(dev)]<<1;
-		two_partitions( hd, MINOR(dev), blocksize, 
-				offset, size);
+		two_partitions( hd, MINOR(dev), blocksize, offset, size);
 		break;
-	case ibm_partition_vol1:
+	case ibm_partition_vol1: 
+		size = hd -> sizes[MINOR(dev)]<<1;
 		add_gd_partition(hd, MINOR(dev), 0, size);
-
+		
 		/* get block number and read then first format1 label */
-		blk = cchhb2blk(&vlabel.vtoc, &geo) + 1;
+		blk = cchhb2blk(&vlabel.vtoc, geo) + 1;
 		if ((buf = bread( dev, blk, blocksize)) != NULL) {
 		        memcpy (&f1, buf->b_data, sizeof(format1_label_t));
 			bforget(buf);
 		}
-
+		
 		while (f1.DS1FMTID == _ascebc['1']) {
-		        offset = cchh2blk(&f1.DS1EXT1.llimit, &geo);
-			psize  = cchh2blk(&f1.DS1EXT1.ulimit, &geo) - 
-				offset + 1;
+		        offset = cchh2blk(&f1.DS1EXT1.llimit, geo);
+			psize  = cchh2blk(&f1.DS1EXT1.ulimit, geo) - 
+				offset + geo->sectors;
 			
 			counter++;
 			add_gd_partition(hd, MINOR(dev) + counter, 
-					  offset * (blocksize >> 9),
-					  psize * (blocksize >> 9));
+					 offset * (blocksize >> 9),
+					 psize * (blocksize >> 9));
 			
 			blk++;
 			if ((buf = bread( dev, blk, blocksize)) != NULL) {
@@ -197,9 +269,8 @@
 		add_gd_partition( hd, MINOR(dev), 0, 0);
 		add_gd_partition( hd, MINOR(dev) + 1, 0, 0);
 	}
-
+	
 	printk ( "\n" );
 	bforget(bh);
 	return 1;
 }
-
diff -u --recursive --new-file v2.4.7/linux/fs/partitions/ldm.c linux/fs/partitions/ldm.c
--- v2.4.7/linux/fs/partitions/ldm.c	Wed Dec 31 16:00:00 1969
+++ linux/fs/partitions/ldm.c	Thu Jul 26 16:30:04 2001
@@ -0,0 +1,980 @@
+/*
+ * $Id: ldm.c,v 1.25 2001/07/25 23:32:02 flatcap Exp $
+ *
+ * ldm - Part of the Linux-NTFS project.
+ *
+ * Copyright (C) 2001 Richard Russon <ntfs@flatcap.org>
+ * Copyright (C) 2001 Anton Altaparmakov <antona@users.sf.net>
+ *
+ * Documentation is available at http://linux-ntfs.sf.net/ldm
+ *
+ * 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 (in the main directory of the Linux-NTFS source
+ * in the file COPYING); if not, write to the Free Software Foundation,
+ * Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ */
+#include <asm/types.h>
+#include <asm/unaligned.h>
+#include <asm/byteorder.h>
+#include <linux/genhd.h>
+#include <linux/blkdev.h>
+#include <linux/slab.h>
+#include "check.h"
+#include "ldm.h"
+#include "msdos.h"
+
+#if 0 /* Fool kernel-doc since it doesn't do macros yet. */
+/**
+ * ldm_debug - output an error message if debugging was enabled at compile time
+ * @f:		a printf format string containing the message
+ * @...:	the variables to substitute into @f
+ *
+ * ldm_debug() writes a DEBUG level message to the syslog but only if the
+ * driver was compiled with debug enabled. Otherwise, the call turns into a NOP.
+ */
+static void ldm_debug(const char *f, ...);
+#endif
+#ifdef CONFIG_LDM_DEBUG
+#define ldm_debug(f, a...)						\
+	{								\
+		printk(LDM_DEBUG " DEBUG (%s, %d): %s: ",		\
+				__FILE__, __LINE__, __FUNCTION__);	\
+		printk(f, ##a);						\
+	}
+#else	/* !CONFIG_LDM_DEBUG */
+#define ldm_debug(f, a...)	do {} while (0)
+#endif	/* !CONFIG_LDM_DEBUG */
+
+/* Necessary forward declarations. */
+static int create_partition(struct gendisk *, int, int, int);
+static int parse_privhead(const u8 *, struct privhead *);
+static u64 get_vnum(const u8 *, int *);
+static int get_vstr(const u8 *, u8 *, const int);
+
+/**
+ * parse_vblk_part - parse a LDM database vblk partition record
+ * @buffer:	vblk partition record loaded from the LDM database
+ * @buf_size:	size of @buffer in bytes
+ * @vb:		in memory vblk structure to return parsed information in
+ *
+ * This parses the LDM database vblk record of type VBLK_PART, i.e. a partition
+ * record, supplied in @buffer and sets up the in memory vblk structure @vb
+ * with the obtained information.
+ *
+ * Return 1 on success and -1 on error, in which case @vb is undefined.
+ */
+static int parse_vblk_part(const u8 *buffer, const int buf_size,
+		struct vblk *vb)
+{
+	int err, rel_objid, rel_name, rel_size, rel_parent;
+
+	if (0x34 >= buf_size)
+		return -1;
+	/* Calculate relative offsets. */
+	rel_objid  = 1 + buffer[0x18];
+	if (0x18 + rel_objid >= buf_size)
+		return -1;
+	rel_name   = 1 + buffer[0x18 + rel_objid] + rel_objid;
+	if (0x34 + rel_name >= buf_size)
+		return -1;
+	rel_size   = 1 + buffer[0x34 + rel_name] + rel_name;
+	if (0x34 + rel_size >= buf_size)
+		return -1;
+	rel_parent = 1 + buffer[0x34 + rel_size] + rel_size;
+	if (0x34 + rel_parent >= buf_size)
+		return -1;
+	/* Setup @vb. */
+	vb->vblk_type    = VBLK_PART;
+	vb->obj_id       = get_vnum(buffer + 0x18, &err);
+	if (err || 0x34 + rel_parent + buffer[0x34 + rel_parent] >= buf_size)
+		return -1;
+	vb->disk_id      = get_vnum(buffer + 0x34 + rel_parent, &err);
+	if (err || 0x24 + rel_name + 8 > buf_size)
+		return -1;
+	vb->start_sector = BE64(buffer + 0x24 + rel_name);
+	if (0x34 + rel_name + buffer[0x34 + rel_name] >= buf_size)
+		return -1;
+	vb->num_sectors  = get_vnum(buffer + 0x34 + rel_name, &err);
+	if (err || 0x18 + rel_objid + buffer[0x18 + rel_objid] >= buf_size)
+		return -1;
+	err = get_vstr(buffer + 0x18 + rel_objid, vb->name, sizeof(vb->name));
+	if (err == -1)
+		return err;
+	ldm_debug("Parsed Partition VBLK successfully.\n");
+	return 1;
+}
+
+/**
+ * parse_vblk - parse a LDM database vblk record
+ * @buffer:	vblk record loaded from the LDM database
+ * @buf_size:	size of @buffer in bytes
+ * @vb:		in memory vblk structure to return parsed information in
+ *
+ * This parses the LDM database vblk record supplied in @buffer and sets up
+ * the in memory vblk structure @vb with the obtained information.
+ *
+ * Return 1 on success, 0 if successful but record not in use, and -1 on error.
+ * If the return value is 0 or -1, @vb is undefined.
+ *
+ * NOTE: Currently the only record type we handle is VBLK_PART, i.e. records
+ * describing a partition. For all others, we just set @vb->vblk_type to 0 and
+ * return success. This of course means that if @vb->vblk_type is zero, all
+ * other fields in @vb are undefined.
+ */
+static int parse_vblk(const u8 *buffer, const int buf_size, struct vblk *vb)
+{
+	int err = 1;
+
+	if (buf_size < 0x14)
+		return -1;
+	if (MAGIC_VBLK != BE32(buffer)) {
+		printk(LDM_CRIT "Cannot find VBLK, database may be corrupt.\n");
+		return -1;
+	}
+	if (BE16(buffer + 0x0E) == 0)	/* Record is not in use. */
+		return 0;
+	/* FIXME: What about extended VBLKs? */
+	switch (buffer[0x13]) {
+	case VBLK_PART:
+		err = parse_vblk_part(buffer, buf_size, vb);
+		break;
+	default:
+		vb->vblk_type = 0;
+	}
+	if (err != -1)
+		ldm_debug("Parsed VBLK successfully.\n");
+	return err;
+}
+
+/**
+ * create_data_partitions - create the data partition devices
+ * @hd:			gendisk structure in which to create the data partitions
+ * @first_sector:	first sector within the disk device
+ * @first_part_minor:	first minor number of data partition devices
+ * @dev:		partition device holding the LDM database
+ * @vm:			in memory vmdb structure of @dev
+ * @ph:			in memory privhead structure of the disk device
+ * @dk:			in memory ldmdisk structure of the disk device
+ *
+ * The database contains ALL the partitions for ALL the disks, so we need to
+ * filter out this specific disk. Using the disk's object id, we can find all
+ * the partitions in the database that belong to this disk.
+ *
+ * For each found partition, we create a corresponding partition device starting
+ * with minor number @first_part_minor.
+ *
+ * Return 1 on success and -1 on error.
+ */
+static int create_data_partitions(struct gendisk *hd,
+		const unsigned long first_sector, int first_part_minor,
+		const kdev_t dev, const struct vmdb *vm,
+		const struct privhead *ph, const struct ldmdisk *dk)
+{
+	struct buffer_head *bh;
+	struct vblk *vb;
+	int vblk;
+	int vsize;		/* VBLK size. */
+	int perbuf;		/* VBLKs per buffer. */
+	int buffer, lastbuf, lastofs, err;
+
+	vb = (struct vblk*)kmalloc(sizeof(struct vblk), GFP_KERNEL);
+	if (!vb)
+		goto no_mem;
+	vsize   = vm->vblk_size;
+	if (vsize < 1 || vsize > LDM_BLOCKSIZE)
+		goto err_out;
+	perbuf  = LDM_BLOCKSIZE / vsize;
+	if (perbuf < 1 || LDM_BLOCKSIZE % vsize)
+		goto err_out;
+					/* 512 == VMDB size */
+	lastbuf = (vm->last_vblk_seq - (512 / vsize)) / perbuf;
+	lastofs = (vm->last_vblk_seq - (512 / vsize)) % perbuf;
+	if (lastofs)
+		lastbuf++;
+	if (OFF_VBLK * LDM_BLOCKSIZE + vm->last_vblk_seq * vsize >
+			ph->config_size * 512)
+		goto err_out;
+	printk(" <");
+	for (buffer = 0; buffer < lastbuf; buffer++) {
+		if (!(bh = bread(dev, buffer + OFF_VBLK, LDM_BLOCKSIZE)))
+			goto read_err;
+		for (vblk = 0; vblk < perbuf; vblk++) {
+			u8 *block;
+			
+			if (lastofs && buffer == lastbuf - 1 && vblk >= lastofs)
+				break;
+			block = bh->b_data + vsize * vblk;
+			if (block + vsize > (u8*)bh->b_data + LDM_BLOCKSIZE)
+				goto brelse_out;
+			if (parse_vblk(block, LDM_BLOCKSIZE, vb) != 1)
+				continue;
+			if (vb->vblk_type != VBLK_PART)
+				continue;
+			if (dk->obj_id != vb->disk_id)
+				continue;
+			if (create_partition(hd, first_part_minor,
+					first_sector + vb->start_sector +
+					ph->logical_disk_start,
+					vb->num_sectors) == 1)
+				first_part_minor++;
+		}
+		brelse(bh);
+	}
+	printk(" >\n");
+	err = 1;
+out:
+	kfree(vb);
+	return err;
+brelse_out:
+	brelse(bh);
+	goto err_out;
+no_mem:
+	printk(LDM_CRIT "Not enough memory to allocate required buffers.\n");
+	goto err_out;
+read_err:
+	printk(LDM_CRIT "Disk read failed in create_partitions.\n");
+err_out:
+	err = -1;
+	goto out;
+}
+
+/**
+ * get_vnum - convert a variable-width, big endian number, to cpu u64 one
+ * @block:	pointer to the variable-width number to convert
+ * @err:	address of an integer into which to return the error code.
+ *
+ * This converts a variable-width, big endian number into a 64-bit, CPU format
+ * number and returns the result with err set to 0. If an error occurs return 0
+ * with err set to -1.
+ *
+ * The first byte of a variable-width number is the size of the number in bytes.
+ */
+static u64 get_vnum(const u8 *block, int *err)
+{
+	u64 tmp = 0ULL;
+	u8 length = *block++;
+
+	if (length && length <= 8) {
+		while (length--)
+			tmp = (tmp << 8) | *block++;
+		*err = 0;
+	} else {
+		printk(LDM_ERR "Illegal length in get_vnum(): %d.\n", length);
+		*err = 1;
+	}
+	return tmp;
+}
+
+/**
+ * get_vstr - convert a counted, non-null-terminated ASCII string to C-style one
+ * @block:	string to convert
+ * @buffer:	output buffer
+ * @buflen:	size of output buffer
+ *
+ * This converts @block, a counted, non-null-terminated ASCII string, into a
+ * C-style, null-terminated, ASCII string and returns this in @buffer. The
+ * maximum number of characters converted is given by @buflen.
+ *
+ * The first bytes of a counted string stores the length of the string in bytes.
+ *
+ * Return the number of characters written to @buffer, not including the
+ * terminating null character, on success, and -1 on error, in which case
+ * @buffer is not defined.
+ */
+static int get_vstr(const u8 *block, u8 *buffer, const int buflen)
+{
+	int length = block[0];
+
+	if (length < 1)
+		return -1;
+	if (length >= buflen) {
+		printk(LDM_ERR "String too long for buffer in get_vstr(): "
+				"(%d/%d). Truncating.\n", length, buflen);
+		length = buflen - 1;
+	}
+	memcpy(buffer, block + 1, length);
+	buffer[length] = (u8)'\0';
+	return length;
+}
+
+/**
+ * get_disk_objid - obtain the object id for the device we are working on
+ * @dev:	partition device holding the LDM database
+ * @vm:		in memory vmdb structure of the LDM database
+ * @ph:		in memory privhead structure of the device we are working on
+ * @dk:		in memory ldmdisk structure to return information into
+ *
+ * This obtains the object id for the device we are working on as defined by
+ * the private header @ph. The obtained object id, together with the disk's
+ * GUID from @ph are returned in the ldmdisk structure pointed to by @dk.
+ *
+ * A Disk has two Ids. The main one is a GUID in string format. The second,
+ * used internally for cross-referencing, is a small, sequentially allocated,
+ * number. The PRIVHEAD, just after the partition table, tells us the disk's
+ * GUID. To find the disk's object id, we have to look through the database.
+ *
+ * Return 1 on success and -1 on error, in which case @dk is undefined.
+ */
+static int get_disk_objid(const kdev_t dev, const struct vmdb *vm,
+		const struct privhead *ph, struct ldmdisk *dk)
+{
+	struct buffer_head *bh;
+	u8 *disk_id;
+	int vblk;
+	int vsize;		/* VBLK size. */
+	int perbuf;		/* VBLKs per buffer. */
+	int buffer, lastbuf, lastofs, err;
+
+	disk_id = (u8*)kmalloc(DISK_ID_SIZE, GFP_KERNEL);
+	if (!disk_id)
+		goto no_mem;
+	vsize   = vm->vblk_size;
+	if (vsize < 1 || vsize > LDM_BLOCKSIZE)
+		goto err_out;
+	perbuf  = LDM_BLOCKSIZE / vsize;
+	if (perbuf < 1 || LDM_BLOCKSIZE % vsize)
+		goto err_out;
+					/* 512 == VMDB size */
+	lastbuf = (vm->last_vblk_seq - (512 / vsize)) / perbuf;
+	lastofs = (vm->last_vblk_seq - (512 / vsize)) % perbuf;
+	if (lastofs)
+		lastbuf++;
+	if (OFF_VBLK * LDM_BLOCKSIZE + vm->last_vblk_seq * vsize >
+			ph->config_size * 512)
+		goto err_out;
+	for (buffer = 0; buffer < lastbuf; buffer++) {
+		if (!(bh = bread(dev, buffer + OFF_VBLK, LDM_BLOCKSIZE)))
+			goto read_err;
+		for (vblk = 0; vblk < perbuf; vblk++) {
+			int rel_objid, rel_name, delta;
+			u8 *block;
+
+			if (lastofs && buffer == lastbuf - 1 && vblk >= lastofs)
+				break;
+			block = bh->b_data + vblk * vsize;
+			delta = vblk * vsize + 0x18;
+			if (delta >= LDM_BLOCKSIZE)
+				goto brelse_out;
+			if (block[0x13] != VBLK_DISK)
+				continue;
+			/* Calculate relative offsets. */
+			rel_objid = 1 + block[0x18];
+			if (delta + rel_objid >= LDM_BLOCKSIZE)
+				goto brelse_out;
+			rel_name  = 1 + block[0x18 + rel_objid] + rel_objid;
+			if (delta + rel_name >= LDM_BLOCKSIZE ||
+			    delta + rel_name + block[0x18 + rel_name] >=
+					LDM_BLOCKSIZE)
+				goto brelse_out;
+			err = get_vstr(block + 0x18 + rel_name, disk_id,
+					DISK_ID_SIZE);
+			if (err == -1)
+				goto brelse_out;
+			if (!strncmp(disk_id, ph->disk_id, DISK_ID_SIZE)) {
+				dk->obj_id = get_vnum(block + 0x18, &err);
+				brelse(bh);
+				if (err)
+					goto out;
+				strncpy(dk->disk_id, ph->disk_id,
+						sizeof(dk->disk_id));
+				dk->disk_id[sizeof(dk->disk_id) - 1] = (u8)'\0';
+				err = 1;
+				goto out;
+			}
+		}
+		brelse(bh);
+	}
+	err = -1;
+out:
+	kfree(disk_id);
+	return err;
+brelse_out:
+	brelse(bh);
+	goto err_out;
+no_mem:
+	printk(LDM_CRIT "Not enough memory to allocate required buffers.\n");
+	goto err_out;
+read_err:
+	printk(LDM_CRIT "Disk read failed in get_disk_objid.\n");
+err_out:
+	err = -1;
+	goto out;
+}
+
+/**
+ * parse_vmdb - parse the LDM database vmdb structure
+ * @buffer:	LDM database vmdb structure loaded from the device
+ * @vm:		in memory vmdb structure to return parsed information in
+ *
+ * This parses the LDM database vmdb structure supplied in @buffer and sets up
+ * the in memory vmdb structure @vm with the obtained information.
+ *
+ * Return 1 on success and -1 on error, in which case @vm is undefined.
+ *
+ * NOTE: The *_start, *_size and *_seq values returned in @vm have not been
+ * checked for validity, so make sure to check them when using them.
+ */
+static int parse_vmdb(const u8 *buffer, struct vmdb *vm)
+{
+	if (MAGIC_VMDB != BE32(buffer)) {
+		printk(LDM_CRIT "Cannot find VMDB, database may be corrupt.\n");
+		return -1;
+	}
+	vm->ver_major = BE16(buffer + 0x12);
+	vm->ver_minor = BE16(buffer + 0x14);
+	if ((vm->ver_major != 4) || (vm->ver_minor != 10)) {
+		printk(LDM_ERR "Expected VMDB version %d.%d, got %d.%d. "
+				"Aborting.\n", 4, 10, vm->ver_major,
+				vm->ver_minor);
+		return -1;
+	}
+	vm->vblk_size	  = BE32(buffer + 0x08);
+	vm->vblk_offset   = BE32(buffer + 0x0C);
+	vm->last_vblk_seq = BE32(buffer + 0x04);
+
+	ldm_debug("Parsed VMDB successfully.\n");
+	return 1;
+}
+
+/**
+ * validate_vmdb - validate the vmdb
+ * @dev:	partition device holding the LDM database
+ * @vm:		in memory vmdb in which to return information
+ *
+ * Find the vmdb of the LDM database stored on @dev and return the parsed
+ * information into @vm.
+ *
+ * Return 1 on success and -1 on error, in which case @vm is undefined.
+ */
+static int validate_vmdb(const kdev_t dev, struct vmdb *vm)
+{
+	struct buffer_head *bh;
+	int ret;
+
+	if (!(bh = bread(dev, OFF_VMDB, LDM_BLOCKSIZE))) {
+		printk(LDM_CRIT "Disk read failed in validate_vmdb.\n");
+		return -1;
+	}
+	ret = parse_vmdb(bh->b_data + 0x200, vm);
+	brelse(bh);
+	return ret;
+}
+
+/**
+ * compare_tocblocks - compare two tables of contents
+ * @toc1:	first toc
+ * @toc2:	second toc
+ *
+ * This compares the two tables of contents @toc1 and @toc2.
+ *
+ * Return 1 if @toc1 and @toc2 are equal and -1 otherwise.
+ */
+static int compare_tocblocks(const struct tocblock *toc1,
+		const struct tocblock *toc2)
+{
+	if ((toc1->bitmap1_start == toc2->bitmap1_start)	&&
+	    (toc1->bitmap1_size  == toc2->bitmap1_size)		&&
+	    (toc1->bitmap2_start == toc2->bitmap2_start)	&&
+	    (toc1->bitmap2_size  == toc2->bitmap2_size)		&&
+	    !strncmp(toc1->bitmap1_name, toc2->bitmap1_name,
+			sizeof(toc1->bitmap1_name))		&&
+	    !strncmp(toc1->bitmap2_name, toc2->bitmap2_name,
+			sizeof(toc1->bitmap2_name)))
+		return 1;
+	return -1;
+}
+
+/**
+ * parse_tocblock - parse the LDM database table of contents structure
+ * @buffer:	LDM database toc structure loaded from the device
+ * @toc:	in memory toc structure to return parsed information in
+ *
+ * This parses the LDM database table of contents structure supplied in @buffer
+ * and sets up the in memory table of contents structure @toc with the obtained
+ * information.
+ *
+ * Return 1 on success and -1 on error, in which case @toc is undefined.
+ *
+ * FIXME: The *_start and *_size values returned in @toc are not been checked
+ * for validity but as we don't use the actual values for anything other than
+ * comparing between the toc and its backups, the values are not important.
+ */
+static int parse_tocblock(const u8 *buffer, struct tocblock *toc)
+{
+	if (MAGIC_TOCBLOCK != BE64(buffer)) {
+		printk(LDM_CRIT "Cannot find TOCBLOCK, database may be "
+				"corrupt.\n");
+		return -1;
+	}
+	strncpy(toc->bitmap1_name, buffer + 0x24, sizeof(toc->bitmap1_name));
+	toc->bitmap1_name[sizeof(toc->bitmap1_name) - 1] = (u8)'\0';
+	toc->bitmap1_start = BE64(buffer + 0x2E);
+	toc->bitmap1_size  = BE64(buffer + 0x36);
+	/*toc->bitmap1_flags = BE64(buffer + 0x3E);*/
+	if (strncmp(toc->bitmap1_name, TOC_BITMAP1,
+			sizeof(toc->bitmap1_name)) != 0) {
+		printk(LDM_CRIT "TOCBLOCK's first bitmap should be %s, but is "
+				"%s.\n", TOC_BITMAP1, toc->bitmap1_name);
+		return -1;
+	}
+	strncpy(toc->bitmap2_name, buffer + 0x46, sizeof(toc->bitmap2_name));
+	toc->bitmap2_name[sizeof(toc->bitmap2_name) - 1] = (u8)'\0';
+	toc->bitmap2_start = BE64(buffer + 0x50);
+	toc->bitmap2_size  = BE64(buffer + 0x58);
+	/*toc->bitmap2_flags = BE64(buffer + 0x60);*/
+	if (strncmp(toc->bitmap2_name, TOC_BITMAP2,
+			sizeof(toc->bitmap2_name)) != 0) {
+		printk(LDM_CRIT "TOCBLOCK's second bitmap should be %s, but is "
+				"%s.\n", TOC_BITMAP2, toc->bitmap2_name);
+		return -1;
+	}
+	ldm_debug("Parsed TOCBLOCK successfully.\n");
+	return 1;
+}
+
+/**
+ * validate_tocblocks - validate the table of contents and its backups
+ * @dev:	partition device holding the LDM database
+ * @toc1:	in memory table of contents in which to return information
+ *
+ * Find and compare the four tables of contents of the LDM database stored on
+ * @dev and return the parsed information into @toc1.
+ *
+ * Return 1 on success and -1 on error, in which case @toc1 is undefined.
+ */
+static int validate_tocblocks(const kdev_t devdb, struct tocblock *toc1)
+{
+	struct buffer_head *bh;
+	struct tocblock *toc2 = NULL, *toc3 = NULL, *toc4 = NULL;
+	int err;
+
+	toc2 = (struct tocblock*)kmalloc(sizeof(*toc2), GFP_KERNEL);
+	if (!toc2)
+		goto no_mem;
+	toc3 = (struct tocblock*)kmalloc(sizeof(*toc3), GFP_KERNEL);
+	if (!toc3)
+		goto no_mem;
+	toc4 = (struct tocblock*)kmalloc(sizeof(*toc4), GFP_KERNEL);
+	if (!toc4)
+		goto no_mem;
+	/* Read and parse first toc. */
+	if (!(bh = bread(devdb, OFF_TOCBLOCK1, LDM_BLOCKSIZE))) {
+		printk(LDM_CRIT "Disk read 1 failed in validate_tocblocks.\n");
+		goto err_out;
+	}
+	err = parse_tocblock(bh->b_data + 0x0200, toc1);
+	brelse(bh);
+	if (err != 1)
+		goto out;
+	/* Read and parse second toc. */
+	if (!(bh = bread(devdb, OFF_TOCBLOCK2, LDM_BLOCKSIZE))) {
+		printk(LDM_CRIT "Disk read 2 failed in validate_tocblocks.\n");
+		goto err_out;
+	}
+	err = parse_tocblock(bh->b_data, toc2);
+	brelse(bh);
+	if (err != 1)
+		goto out;
+	/* Read and parse third toc. */
+	if (!(bh = bread(devdb, OFF_TOCBLOCK3, LDM_BLOCKSIZE))) {
+		printk(LDM_CRIT "Disk read 3 failed in validate_tocblocks.\n");
+		goto err_out;
+	}
+	err = parse_tocblock(bh->b_data + 0x0200, toc3);
+	brelse(bh);
+	if (err != 1)
+		goto out;
+	/* Read and parse fourth toc. */
+	if (!(bh = bread(devdb, OFF_TOCBLOCK4, LDM_BLOCKSIZE))) {
+		printk(LDM_CRIT "Disk read 4 failed in validate_tocblocks.\n");
+		goto err_out;
+	}
+	err = parse_tocblock(bh->b_data, toc4);
+	brelse(bh);
+	if (err != 1)
+		goto out;
+	/* Compare all tocs. */
+	err = compare_tocblocks(toc1, toc2);
+	if (err != 1) {
+		printk(LDM_CRIT "First and second TOCBLOCKs don't match.\n");
+		goto out;
+	}
+	err = compare_tocblocks(toc3, toc4);
+	if (err != 1) {
+		printk(LDM_CRIT "Third and fourth TOCBLOCKs don't match.\n");
+		goto out;
+	}
+	err = compare_tocblocks(toc1, toc3);
+	if (err != 1)
+		printk(LDM_CRIT "First and third TOCBLOCKs don't match.\n");
+	else
+		ldm_debug("Validated TOCBLOCKs successfully.\n");
+out:
+	kfree(toc2);
+	kfree(toc3);
+	kfree(toc4);
+	return err;
+no_mem:
+	printk(LDM_CRIT "Not enough memory to allocate required buffers.\n");
+err_out:
+	err = -1;
+	goto out;
+}
+
+/**
+ * compare_privheads - compare two privheads
+ * @ph1:	first privhead
+ * @ph2:	second privhead
+ *
+ * This compares the two privheads @ph1 and @ph2.
+ *
+ * Return 1 if @ph1 and @ph2 are equal and -1 otherwise.
+ */
+static int compare_privheads(const struct privhead *ph1,
+		const struct privhead *ph2)
+{
+	if ((ph1->ver_major == ph2->ver_major)			 &&
+	    (ph1->ver_minor == ph2->ver_minor)			 &&
+	    (ph1->logical_disk_start == ph2->logical_disk_start) &&
+	    (ph1->logical_disk_size  == ph2->logical_disk_size)	 &&
+	    (ph1->config_start == ph2->config_start)		 &&
+	    (ph1->config_size  == ph2->config_size)		 &&
+	    !strncmp(ph1->disk_id, ph2->disk_id, sizeof(ph1->disk_id)))
+		return 1;
+	return -1;
+}
+
+/**
+ * validate_privheads - compare the privhead backups to the first one
+ * @dev:	partition device holding the LDM database
+ * @ph1:	first privhead which we have already validated before
+ *
+ * We already have one privhead from the beginning of the disk.
+ * Now we compare the two other copies for safety.
+ *
+ * Return 1 on succes and -1 on error.
+ */
+static int validate_privheads(const kdev_t dev, const struct privhead *ph1)
+{
+	struct buffer_head *bh;
+	struct privhead *ph2 = NULL, *ph3 = NULL;
+	int err;
+
+	ph2 = (struct privhead*)kmalloc(sizeof(*ph2), GFP_KERNEL);
+	if (!ph2)
+		goto no_mem;
+	ph3 = (struct privhead*)kmalloc(sizeof(*ph3), GFP_KERNEL);
+	if (!ph3)
+		goto no_mem;
+	if (!(bh = bread(dev, OFF_PRIVHEAD2, LDM_BLOCKSIZE))) {
+		printk(LDM_CRIT "Disk read 1 failed in validate_privheads.\n");
+		goto err_out;
+	}
+	err = parse_privhead(bh->b_data, ph2);
+	brelse(bh);
+	if (err != 1)
+		goto out;
+	if (!(bh = bread(dev, OFF_PRIVHEAD3, LDM_BLOCKSIZE))) {
+		printk(LDM_CRIT "Disk read 2 failed in validate_privheads.\n");
+		goto err_out;
+	}
+	err = parse_privhead(bh->b_data + 0x0200, ph3);
+	brelse(bh);
+	if (err != 1)
+		goto out;
+	err = compare_privheads(ph1, ph2);
+	if (err != 1) {
+		printk(LDM_CRIT "First and second PRIVHEADs don't match.\n");
+		goto out;
+	}
+	err = compare_privheads(ph1, ph3);
+	if (err != 1)
+		printk(LDM_CRIT "First and third PRIVHEADs don't match.\n");
+	else
+		/* We _could_ have checked more. */
+		ldm_debug("Validated PRIVHEADs successfully.\n");
+out:
+	kfree(ph2);
+	kfree(ph3);
+	return err;
+no_mem:
+	printk(LDM_CRIT "Not enough memory to allocate required buffers.\n");
+err_out:
+	err = -1;
+	goto out;
+}
+
+/**
+ * create_partition - validate input and create a kernel partition device
+ * @hd:		gendisk structure in which to create partition
+ * @minor:	minor number for device to create
+ * @start:	starting offset of the partition into the parent device
+ * @size:	size of the partition
+ *
+ * This validates the range, then puts an entry into the kernel's partition
+ * table.
+ *
+ * @start and @size are numbers of sectors.
+ *
+ * Return 1 on succes and -1 on error.
+ */
+static int create_partition(struct gendisk *hd, const int minor,
+		const int start, const int size)
+{
+	int disk_minor;
+
+	if (!hd->part)
+		return -1;
+	/*
+	 * Get the minor number of the parent device so we can check we don't
+	 * go beyond the end of the device.
+	 */
+	disk_minor = (minor >> hd->minor_shift) << hd->minor_shift;
+	if ((start < 1) || ((start + size) > hd->part[disk_minor].nr_sects)) {
+		printk(LDM_CRIT "LDM Partition exceeds physical disk. "
+				"Aborting.\n");
+		return -1;
+	}
+	add_gd_partition(hd, minor, start, size);
+	ldm_debug("Created partition successfully.\n");
+	return 1;
+}
+
+/**
+ * parse_privhead - parse the LDM database PRIVHEAD structure
+ * @buffer:	LDM database privhead structure loaded from the device
+ * @ph:		in memory privhead structure to return parsed information in
+ *
+ * This parses the LDM database PRIVHEAD structure supplied in @buffer and
+ * sets up the in memory privhead structure @ph with the obtained information.
+ *
+ * Return 1 on succes and -1 on error, in which case @ph is undefined.
+ */
+static int parse_privhead(const u8 *buffer, struct privhead *ph)
+{
+	if (MAGIC_PRIVHEAD != BE64(buffer)) {
+		printk(LDM_ERR "Cannot find PRIVHEAD structure. LDM database "
+				"is corrupt. Aborting.\n");
+		return -1;
+	}
+	ph->ver_major = BE16(buffer + 0x000C);
+	ph->ver_minor = BE16(buffer + 0x000E);
+	if ((ph->ver_major != 2) || (ph->ver_minor != 11)) {
+		printk(LDM_ERR "Expected PRIVHEAD version %d.%d, got %d.%d. "
+				"Aborting.\n", 2, 11, ph->ver_major,
+				ph->ver_minor);
+		return -1;
+	}
+	ph->config_start = BE64(buffer + 0x012B);
+	ph->config_size  = BE64(buffer + 0x0133);
+	if (ph->config_size != LDM_DB_SIZE) {	/* 1 MiB in sectors. */
+		printk(LDM_ERR "Database should be %u bytes, claims to be %Lu "
+				"bytes. Aborting.\n", LDM_DB_SIZE,
+				ph->config_size);
+		return -1;
+	}
+	ph->logical_disk_start = BE64(buffer + 0x011B);
+	ph->logical_disk_size  = BE64(buffer + 0x0123);
+	if (!ph->logical_disk_size ||
+	    ph->logical_disk_start + ph->logical_disk_size > ph->config_start)
+		return -1;
+
+	memcpy(ph->disk_id, buffer + 0x0030, sizeof(ph->disk_id));
+
+	ldm_debug("Parsed PRIVHEAD successfully.\n");
+	return 1;
+}
+
+/**
+ * create_db_partition - create a dedicated partition for our database
+ * @hd:		gendisk structure in which to create partition
+ * @dev:	device of which to create partition
+ * @ph:		@dev's LDM database private header
+ *
+ * Find the primary private header, locate the LDM database, then create a
+ * partition to wrap it.
+ *
+ * Return 1 on succes, 0 if device is not a dynamic disk and -1 on error.
+ */
+static int create_db_partition(struct gendisk *hd, const kdev_t dev,
+		const unsigned long first_sector, const int first_part_minor,
+		struct privhead *ph)
+{
+	struct buffer_head *bh;
+	int err;
+
+	if (!(bh = bread(dev, OFF_PRIVHEAD1, LDM_BLOCKSIZE))) {
+		printk(LDM_CRIT __FUNCTION__ "(): Device read failed.\n");
+		return -1;
+	}
+	if (BE64(bh->b_data) != MAGIC_PRIVHEAD) {
+		ldm_debug("Cannot find PRIVHEAD structure. Not a dynamic disk "
+				"or corrupt LDM database.\n");
+		return 0;
+	}
+	err = parse_privhead(bh->b_data, ph);
+	if (err == 1)
+		err = create_partition(hd, first_part_minor, first_sector +
+				ph->config_start, ph->config_size);
+	brelse(bh);
+	return err;
+}
+
+/**
+ * validate_patition_table - check whether @dev is a dynamic disk
+ * @dev:	device to test
+ *
+ * Check whether @dev is a dynamic disk by looking for an MS-DOS-style partition
+ * table with one or more entries of type 0x42 (the former Secure File System
+ * (Landis) partition type, now recycled by Microsoft for dynamic disks) in it.
+ * If this succeeds we assume we have a dynamic disk, and not otherwise.
+ *
+ * Return 1 if @dev is a dynamic disk, 0 if not and -1 on error.
+ */
+static int validate_partition_table(const kdev_t dev)
+{
+	struct buffer_head *bh;
+	struct partition *p;
+	int i, nr_sfs;
+
+	if (!(bh = bread(dev, 0, LDM_BLOCKSIZE))) {
+		if (warn_no_part)
+			printk(LDM_ERR "Unable to read partition table.\n");
+		return -1;
+	}
+	if (*(u16*)(bh->b_data + 0x01FE) != cpu_to_le16(MSDOS_LABEL_MAGIC)) {
+		ldm_debug("No MS-DOS partition found.\n");
+		goto no_msdos_partition;
+	}
+	nr_sfs = 0;
+	p = (struct partition*)(bh->b_data + 0x01BE);
+	for (i = 0; i < 4; i++) {
+		if (!SYS_IND(p+i) || SYS_IND(p+i) == WIN2K_EXTENDED_PARTITION)
+			continue;
+		if (SYS_IND(p+i) == WIN2K_DYNAMIC_PARTITION) {
+			nr_sfs++;
+			continue;
+		}
+		goto not_dynamic_disk;
+	}
+	if (!nr_sfs)
+		goto not_dynamic_disk;
+	ldm_debug("Parsed partition table successfully.\n");
+	brelse(bh);
+	return 1;
+not_dynamic_disk:
+	ldm_debug("Found basic MS-DOS partition, not a dynamic disk.\n");
+no_msdos_partition:
+	brelse(bh);
+	return 0;
+}
+
+/**
+ * ldm_partition - find out whether a device is a dynamic disk and handle it
+ * @hd:			gendisk structure in which to return the handled disk
+ * @dev:		device we need to look at
+ * @first_sector:	first sector within the device
+ * @first_part_minor:	first minor number of partitions for the device
+ *
+ * Description:
+ *
+ * This determines whether the device @dev is a dynamic disk and if so creates
+ * the partitions necessary in the gendisk structure pointed to by @hd.
+ *
+ * We create a dummy device 1, which contains the LDM database, we skip
+ * devices 2-4 and then create each partition described by the LDM database
+ * in sequence as devices 5 and following. For example, if the device is hda,
+ * we would have: hda1: LDM database, hda2-4: nothing, hda5-following: the
+ * actual data containing partitions.
+ *
+ * Return values:
+ *
+ *	 1 if @dev is a dynamic disk and we handled it,
+ *	 0 if @dev is not a dynamic disk,
+ *	-1 if an error occured.
+ */
+int ldm_partition(struct gendisk *hd, kdev_t dev, unsigned long first_sector,
+		int first_part_minor)
+{
+	kdev_t devdb;
+	struct privhead *ph  = NULL;
+	struct tocblock *toc = NULL;
+	struct vmdb     *vm  = NULL;
+	struct ldmdisk  *dk  = NULL;
+	int err;
+
+	if (!hd)
+		return 0;
+	err = (int)get_ptable_blocksize(dev);
+	if (err != LDM_BLOCKSIZE) {	/* 1024 bytes */
+		ldm_debug("Expected a blocksize of %d bytes, got %d instead.\n",
+				LDM_BLOCKSIZE, get_ptable_blocksize(dev));
+		return 0;
+	}
+	err = get_hardsect_size(dev); 
+	if (err != 512) {
+		ldm_debug("Expected a sector size of %d bytes, got %d "
+				"instead.\n", 512, get_hardsect_size(dev));
+		return 0;
+	}
+	/* Check the partition table. */
+	err = validate_partition_table(dev);
+	if (err != 1)
+		return err;
+	if (!(ph = (struct privhead*)kmalloc(sizeof(*ph), GFP_KERNEL)))
+		goto no_mem;
+	/* Create the LDM database device. */
+	err = create_db_partition(hd, dev, first_sector, first_part_minor, ph);
+	if (err != 1)
+		goto out;
+	/* For convenience, work with the LDM database device from now on. */
+	devdb = MKDEV(MAJOR(dev), first_part_minor);
+	/* Check the backup privheads. */
+	err = validate_privheads(devdb, ph);
+	if (err != 1)
+		goto out;
+	/* Check the table of contents and its backups. */
+	if (!(toc = (struct tocblock*)kmalloc(sizeof(*toc), GFP_KERNEL)))
+		goto no_mem;
+	err = validate_tocblocks(devdb, toc);
+	if (err != 1)
+		goto out;
+	/* Check the vmdb. */
+	if (!(vm = (struct vmdb*)kmalloc(sizeof(*vm), GFP_KERNEL)))
+		goto no_mem;
+	err = validate_vmdb(devdb, vm);
+	if (err != 1)
+		goto out;
+	/* Find the object id for @dev in the LDM database. */
+	if (!(dk = (struct ldmdisk*)kmalloc(sizeof(*dk), GFP_KERNEL)))
+		goto no_mem;
+	err = get_disk_objid(devdb, vm, ph, dk);
+	if (err != 1)
+		goto out;
+	/* Finally, create the data partition devices. */
+	err = create_data_partitions(hd, first_sector, first_part_minor +
+			LDM_FIRST_PART_OFFSET, devdb, vm, ph, dk);
+	if (err == 1)
+		ldm_debug("Parsed LDM database successfully.\n");
+out:
+	kfree(ph);
+	kfree(toc);
+	kfree(vm);
+	kfree(dk);
+	return err;
+no_mem:
+	printk(LDM_CRIT "Not enough memory to allocate required buffers.\n");
+	err = -1;
+	goto out;
+}
+
diff -u --recursive --new-file v2.4.7/linux/fs/partitions/ldm.h linux/fs/partitions/ldm.h
--- v2.4.7/linux/fs/partitions/ldm.h	Wed Dec 31 16:00:00 1969
+++ linux/fs/partitions/ldm.h	Mon Aug  6 22:28:22 2001
@@ -0,0 +1,150 @@
+#ifndef _FS_PT_LDM_H_
+#define _FS_PT_LDM_H_
+/*
+ * $Id: ldm.h,v 1.13 2001/07/23 19:49:49 antona Exp $
+ *
+ * ldm - Part of the Linux-NTFS project.
+ *
+ * Copyright (C) 2001 Richard Russon <ntfs@flatcap.org>
+ * Copyright (C) 2001 Anton Altaparmakov <antona@users.sf.net>
+ *
+ * Documentation is available at http://linux-ntfs.sf.net/ldm
+ *
+ * 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 (in the main directory of the Linux-NTFS source
+ * in the file COPYING); if not, write to the Free Software Foundation,
+ * Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ */
+#include <asm/types.h>
+#include <asm/unaligned.h>
+#include <asm/byteorder.h>
+#include <linux/genhd.h>
+
+/* Borrowed from kernel.h. */
+#define LDM_PREFIX	"LDM: "	   /* Prefix our error messages with this. */
+#define LDM_CRIT	KERN_CRIT	LDM_PREFIX /* critical conditions */
+#define LDM_ERR		KERN_ERR	LDM_PREFIX /* error conditions */
+#define LDM_DEBUG	KERN_DEBUG	LDM_PREFIX /* debug-level messages */
+
+/* Magic numbers in CPU format. */
+#define MAGIC_VMDB	0x564D4442		/* VMDB */
+#define MAGIC_VBLK	0x56424C4B		/* VBLK */
+#define MAGIC_PRIVHEAD	0x5052495648454144	/* PRIVHEAD */
+#define MAGIC_TOCBLOCK	0x544F43424C4F434B	/* TOCBLOCK */
+
+/* The defined vblk types. */
+#define VBLK_COMP		0x32		/* Component */
+#define VBLK_PART		0x33		/* Partition */
+#define VBLK_DISK		0x34		/* Disk */
+#define VBLK_DGRP		0x45		/* Disk Group */
+#define VBLK_VOLU		0x51		/* Volume */
+
+/* Other constants. */
+#define LDM_BLOCKSIZE		1024		/* Size of block in bytes. */
+#define LDM_DB_SIZE		2048		/* Size in sectors (= 1MiB). */
+#define LDM_FIRST_PART_OFFSET	4		/* Add this to first_part_minor
+						   to get to the first data
+						   partition device minor. */
+
+#define OFF_PRIVHEAD1		3		/* Offset of the first privhead
+						   relative to the start of the
+						   device in units of
+						   LDM_BLOCKSIZE. */
+
+/* Offsets to structures within the LDM Database in units of LDM_BLOCKSIZE. */
+#define OFF_PRIVHEAD2		928		/* Backup private headers. */
+#define OFF_PRIVHEAD3		1023
+
+#define OFF_TOCBLOCK1		0		/* Tables of contents. */
+#define OFF_TOCBLOCK2		1
+#define OFF_TOCBLOCK3		1022
+#define OFF_TOCBLOCK4		1023
+
+#define OFF_VMDB		8		/* List of partitions. */
+#define OFF_VBLK		9
+
+#define WIN2K_DYNAMIC_PARTITION		0x42	/* Formerly SFS (Landis). */
+#define WIN2K_EXTENDED_PARTITION	0x05	/* A standard extended
+						   partition. */
+
+#define TOC_BITMAP1		"config"	/* Names of the two defined */
+#define TOC_BITMAP2		"log"		/* bitmaps in the TOCBLOCK. */
+
+/* Borrowed from msdos.c */
+#define SYS_IND(p)		(get_unaligned(&p->sys_ind))
+#define NR_SECTS(p)		({ __typeof__(p->nr_sects) __a =	\
+					get_unaligned(&p->nr_sects);	\
+					le32_to_cpu(__a);		\
+				})
+#define START_SECT(p)		({ __typeof__(p->start_sect) __a =	\
+					get_unaligned(&p->start_sect);	\
+					le32_to_cpu(__a);		\
+				})
+
+/* Most numbers we deal with are big-endian and won't be aligned. */
+#define BE16(x)			((u16)be16_to_cpu(get_unaligned((u16*)(x))))
+#define BE32(x)			((u32)be32_to_cpu(get_unaligned((u32*)(x))))
+#define BE64(x)			((u64)be64_to_cpu(get_unaligned((u64*)(x))))
+
+/* In memory LDM database structures. */
+
+#define DISK_ID_SIZE		64	/* Size in bytes. */
+
+struct ldmdisk {
+	u64	obj_id;
+	u8	disk_id[DISK_ID_SIZE];
+};
+
+struct privhead	{			/* Offsets and sizes are in sectors. */
+	u16	ver_major;
+	u16	ver_minor;
+	u64	logical_disk_start;
+	u64	logical_disk_size;
+	u64	config_start;
+	u64	config_size;
+	u8	disk_id[DISK_ID_SIZE];
+};
+
+struct tocblock {			/* We have exactly two bitmaps. */
+	u8	bitmap1_name[16];
+	u64	bitmap1_start;
+	u64	bitmap1_size;
+	/*u64	bitmap1_flags;*/
+	u8	bitmap2_name[16];
+	u64	bitmap2_start;
+	u64	bitmap2_size;
+	/*u64	bitmap2_flags;*/
+};
+
+struct vmdb {
+	u16	ver_major;
+	u16	ver_minor;
+	u32	vblk_size;
+	u32	vblk_offset;
+	u32	last_vblk_seq;
+};
+
+struct vblk {
+	u8	name[64];
+	u8	vblk_type;
+	u64	obj_id;
+	u64	disk_id;
+	u64	start_sector;
+	u64	num_sectors;
+};
+
+int ldm_partition(struct gendisk *hd, kdev_t dev, unsigned long first_sector,
+		int first_part_minor);
+
+#endif /* _FS_PT_LDM_H_ */
+
diff -u --recursive --new-file v2.4.7/linux/fs/partitions/msdos.c linux/fs/partitions/msdos.c
--- v2.4.7/linux/fs/partitions/msdos.c	Fri Feb 16 16:02:37 2001
+++ linux/fs/partitions/msdos.c	Sat Jul 28 12:50:13 2001
@@ -84,6 +84,14 @@
 #endif
 }
 
+#define MSDOS_LABEL_MAGIC1	0x55
+#define MSDOS_LABEL_MAGIC2	0xAA
+
+static inline int
+msdos_magic_present(unsigned char *p) {
+	return (p[0] == MSDOS_LABEL_MAGIC1 && p[1] == MSDOS_LABEL_MAGIC2);
+}
+
 /*
  * Create devices for each logical partition in an extended partition.
  * The logical partitions form a linked list, with each entry being
@@ -118,10 +126,10 @@
 		if (!(bh = bread(dev,0,get_ptable_blocksize(dev))))
 			return;
 
-		if ((*(__u16 *) (bh->b_data+510)) != cpu_to_le16(MSDOS_LABEL_MAGIC))
+		if (!msdos_magic_present(bh->b_data + 510))
 			goto done;
 
-		p = (struct partition *) (0x1BE + bh->b_data);
+		p = (struct partition *) (bh->b_data + 0x1be);
 
 		this_size = hd->part[MINOR(dev)].nr_sects;
 
@@ -399,7 +407,7 @@
 	/* The first sector of a Minix partition can have either
 	 * a secondary MBR describing its subpartitions, or
 	 * the normal boot sector. */
-	if ((*(__u16 *) (bh->b_data + 510)) != cpu_to_le16(MSDOS_LABEL_MAGIC) &&
+	if (msdos_magic_present (bh->b_data + 510) &&
 	    SYS_IND(p) == MINIX_PARTITION) { /* subpartition table present */
 
 		printk(" %s: <minix:", partition_name(hd, minor, buf));
@@ -441,11 +449,11 @@
 check_table:
 #endif /* CONFIG_BLK_DEV_IDE */
 	/* Use bforget(), because we may have changed the disk geometry */
-	if (*(unsigned short *)  (0x1fe + data) != cpu_to_le16(MSDOS_LABEL_MAGIC)) {
+	if (!msdos_magic_present(data + 510)) {
 		bforget(bh);
 		return 0;
 	}
-	p = (struct partition *) (0x1be + data);
+	p = (struct partition *) (data + 0x1be);
 
 #ifdef CONFIG_BLK_DEV_IDE
 	if (!tested_for_xlate++) {	/* Do this only once per disk */
@@ -542,7 +550,7 @@
 	/*
 	 *  Check for old-style Disk Manager partition table
 	 */
-	if (*(unsigned short *) (data+0xfc) == cpu_to_le16(MSDOS_LABEL_MAGIC)) {
+	if (msdos_magic_present(data + 0xfc)) {
 		p = (struct partition *) (0x1be + data);
 		for (i = 4 ; i < 16 ; i++, current_minor++) {
 			p--;
diff -u --recursive --new-file v2.4.7/linux/fs/proc/array.c linux/fs/proc/array.c
--- v2.4.7/linux/fs/proc/array.c	Tue Jul  3 17:08:21 2001
+++ linux/fs/proc/array.c	Thu Jul 26 13:42:56 2001
@@ -258,7 +258,7 @@
 	return buffer;
 }
 
-extern inline char *task_cap(struct task_struct *p, char *buffer)
+static inline char *task_cap(struct task_struct *p, char *buffer)
 {
     return buffer + sprintf(buffer, "CapInh:\t%016x\n"
 			    "CapPrm:\t%016x\n"
diff -u --recursive --new-file v2.4.7/linux/fs/read_write.c linux/fs/read_write.c
--- v2.4.7/linux/fs/read_write.c	Tue Apr 17 14:36:44 2001
+++ linux/fs/read_write.c	Sun Aug  5 13:12:41 2001
@@ -15,6 +15,7 @@
 #include <asm/uaccess.h>
 
 struct file_operations generic_ro_fops = {
+	llseek:		generic_file_llseek,
 	read:		generic_file_read,
 	mmap:		generic_file_mmap,
 };
@@ -22,6 +23,34 @@
 ssize_t generic_read_dir(struct file *filp, char *buf, size_t siz, loff_t *ppos)
 {
 	return -EISDIR;
+}
+
+loff_t generic_file_llseek(struct file *file, loff_t offset, int origin)
+{
+	long long retval;
+
+	switch (origin) {
+		case 2:
+			offset += file->f_dentry->d_inode->i_size;
+			break;
+		case 1:
+			offset += file->f_pos;
+	}
+	retval = -EINVAL;
+	if (offset>=0 && offset<=file->f_dentry->d_inode->i_sb->s_maxbytes) {
+		if (offset != file->f_pos) {
+			file->f_pos = offset;
+			file->f_reada = 0;
+			file->f_version = ++event;
+		}
+		retval = offset;
+	}
+	return retval;
+}
+
+loff_t no_llseek(struct file *file, loff_t offset, int origin)
+{
+	return -ESPIPE;
 }
 
 loff_t default_llseek(struct file *file, loff_t offset, int origin)
diff -u --recursive --new-file v2.4.7/linux/include/asm-cris/atomic.h linux/include/asm-cris/atomic.h
--- v2.4.7/linux/include/asm-cris/atomic.h	Thu Feb  8 16:32:44 2001
+++ linux/include/asm-cris/atomic.h	Thu Jul 26 15:10:06 2001
@@ -1,4 +1,4 @@
-/* $Id: atomic.h,v 1.2 2000/07/13 16:51:57 bjornw Exp $ */
+/* $Id: atomic.h,v 1.3 2001/07/25 16:15:19 bjornw Exp $ */
 
 #ifndef __ASM_CRIS_ATOMIC__
 #define __ASM_CRIS_ATOMIC__
@@ -138,5 +138,11 @@
 	restore_flags(flags);
 	return retval;
 }
+
+/* Atomic operations are already serializing */
+#define smp_mb__before_atomic_dec()    barrier()
+#define smp_mb__after_atomic_dec()     barrier()
+#define smp_mb__before_atomic_inc()    barrier()
+#define smp_mb__after_atomic_inc()     barrier()
 
 #endif
diff -u --recursive --new-file v2.4.7/linux/include/asm-cris/axisflashmap.h linux/include/asm-cris/axisflashmap.h
--- v2.4.7/linux/include/asm-cris/axisflashmap.h	Wed Jul 25 17:10:25 2001
+++ linux/include/asm-cris/axisflashmap.h	Thu Jul 26 15:10:06 2001
@@ -15,7 +15,9 @@
  * tools/mkptable is used to generate the ptable. 
  */
 
-/* The partition table starts with code to "jump over" it: */
+/* The partition table starts with code to "jump over" it.  The ba
+   instruction and delay-slot is modified elsewhere (for example the
+   mkptable script); don't change this to fill the delay-slot.  */
 #define PARTITIONTABLE_CODE_START { \
  0x0f, 0x05, /* nop 0 */\
  0x25, 0xf0, /* di  2 */\
@@ -53,7 +55,7 @@
 #define PARTITIONTABLE_END_MARKER_SIZE 4
 
 /*#define PARTITION_TYPE_RESCUE 0x0000?*/  /* Not used, maybe it should? */
-#define PARTITION_TYPE_PARAM  0x0001 /* Hmm.. */
+#define PARTITION_TYPE_PARAM  0x0001
 #define PARTITION_TYPE_KERNEL 0x0002
 #define PARTITION_TYPE_JFFS   0x0003
 
diff -u --recursive --new-file v2.4.7/linux/include/asm-cris/checksum.h linux/include/asm-cris/checksum.h
--- v2.4.7/linux/include/asm-cris/checksum.h	Thu Feb  8 16:32:44 2001
+++ linux/include/asm-cris/checksum.h	Thu Jul 26 15:10:06 2001
@@ -1,4 +1,4 @@
-/* $Id: checksum.h,v 1.3 2000/11/15 17:35:16 bjornw Exp $ */
+/* $Id: checksum.h,v 1.4 2001/06/28 03:58:36 hp Exp $ */
 /* TODO: csum_tcpudp_magic could be speeded up, and csum_fold as well */
 
 #ifndef _CRIS_CHECKSUM_H
@@ -69,17 +69,9 @@
 	return res;
 }	
 
-
-/* TODO we need to write this properly to handle userland VM exceptions!! */
-
-#define csum_partial_copy_from_user(a,b,c,d,errptr) csum_partial_copy_nocheck(a,b,c,d)
-
-#if 0
-unsigned int csum_partial_copy_from_user(const char *src, char *dst,
-					int len, unsigned int sum);
-#endif
-
-
+extern unsigned int csum_partial_copy_from_user(const char *src, char *dst,
+						int len, unsigned int sum, 
+						int *errptr);
 
 /*
  *	This is a version of ip_compute_csum() optimized for IP headers,
diff -u --recursive --new-file v2.4.7/linux/include/asm-cris/delay.h linux/include/asm-cris/delay.h
--- v2.4.7/linux/include/asm-cris/delay.h	Wed Jul 25 17:10:25 2001
+++ linux/include/asm-cris/delay.h	Thu Jul 26 15:10:06 2001
@@ -1,10 +1,10 @@
-/* $Id: delay.h,v 1.4 2001/05/31 06:40:53 markusl Exp $ */
+/* $Id: delay.h,v 1.5 2001/06/28 04:59:25 hp Exp $ */
 
 #ifndef _CRIS_DELAY_H
 #define _CRIS_DELAY_H
 
 /*
- * Copyright (C) 1998, 1999, 2000 Axis Communications AB
+ * Copyright (C) 1998, 1999, 2000, 2001 Axis Communications AB
  *
  * Delay routines, using a pre-computed "loops_per_second" value.
  */
@@ -21,26 +21,18 @@
 extern __inline__ void __delay(int loops)
 {
 	__asm__ __volatile__ (
-			      "move.d %0,r0\n\t"
-			      "1:\n\t"
-			      "cmpq 0,r0\n\t"
+			      "move.d %0,r9\n\t"
 			      "beq 2f\n\t"
-			      "nop\n\t"
-			      "subq 1,r0\n\t"
-			      "ba 1b\n\t"
-			      "nop\n\t"
-			      "2:\n\t"
-			      : : "r" (loops) : "r0");
+			      "subq 1,r9\n\t"
+			      "1:\n\t"
+			      "bne 1b\n\t"
+			      "subq 1,r9\n"
+			      "2:"
+			      : : "g" (loops) : "r9");
 }
 
 
-/*
- * Use only for very small delays ( < 1 msec).  Should probably use a
- * lookup table, really, as the multiplications take much too long with
- * short delays.  This is a "reasonable" implementation, though (and the
- * first constant multiplications gets optimized away if the delay is
- * a constant)
- */
+/* Use only for very small delays ( < 1 msec).  */
 
 extern unsigned long loops_per_usec; /* arch/cris/mm/init.c */
 
diff -u --recursive --new-file v2.4.7/linux/include/asm-cris/hardirq.h linux/include/asm-cris/hardirq.h
--- v2.4.7/linux/include/asm-cris/hardirq.h	Thu Feb  8 16:32:44 2001
+++ linux/include/asm-cris/hardirq.h	Thu Jul 26 15:10:07 2001
@@ -7,11 +7,11 @@
 
 /* entry.S is sensitive to the offsets of these fields */
 typedef struct {
-	unsigned int __softirq_active;
-	unsigned int __softirq_mask;
+	unsigned int __softirq_pending;
 	unsigned int __local_irq_count;
 	unsigned int __local_bh_count;
 	unsigned int __syscall_count;
+	struct task_struct * __ksoftirqd_task; /* waitqueue is too large */
 } ____cacheline_aligned irq_cpustat_t;
 
 #include <linux/irq_cpustat.h> /* Standard mappings for irq_cpustat_t above */
diff -u --recursive --new-file v2.4.7/linux/include/asm-cris/io.h linux/include/asm-cris/io.h
--- v2.4.7/linux/include/asm-cris/io.h	Wed Jul 25 17:10:25 2001
+++ linux/include/asm-cris/io.h	Thu Jul 26 15:10:07 2001
@@ -9,8 +9,16 @@
    use will be evident. */
 #ifdef CONFIG_SVINTO_SIM
   /* Let's use the ucsim interface since it lets us do write(2, ...) */
-#define SIMCOUT(s,len) asm ("moveq 4,r1\n\tmoveq 2,r10\n\tmove.d %0,r11\n\tmove.d %1,r12\
-\n\tpush irp\n\t.word 0xae3f\n\t.dword 0f\n\tjump -6809\n0:\n\tpop irp" \
+#define SIMCOUT(s,len)							\
+  asm ("moveq 4,r1	\n\t"						\
+       "moveq 2,r10	\n\t"						\
+       "move.d %0,r11	\n\t"						\
+       "move.d %1,r12	\n\t"						\
+       "push irp	\n\t"						\
+       "move 0f,irp	\n\t"						\
+       "jump -6809	\n"						\
+       "0:		\n\t"						\
+       "pop irp"							\
        : : "rm" (s), "rm" (len) : "r1","r10","r11","r12","memory")
 #define TRACE_ON() __extension__ \
  ({ int _Foofoo; __asm__ volatile ("bmod [%0],%0" : "=r" (_Foofoo) : "0" \
@@ -113,7 +121,10 @@
 #define LED_ACTIVE_SET_R(x) \
          REG_SHADOW_SET(R_PORT_PA_DATA, port_pa_data_shadow, CONFIG_ETRAX_LED2R, !(x))
 #define LED_DISK_WRITE(x) \
-         REG_SHADOW_SET(R_PORT_PA_DATA, port_pa_data_shadow, CONFIG_ETRAX_LED3R, !(x))
+         do{\
+                REG_SHADOW_SET(R_PORT_PA_DATA, port_pa_data_shadow, CONFIG_ETRAX_LED3G, !(x));\
+                REG_SHADOW_SET(R_PORT_PA_DATA, port_pa_data_shadow, CONFIG_ETRAX_LED3R, !(x));\
+        }while(0)
 #define LED_DISK_READ(x) \
          REG_SHADOW_SET(R_PORT_PA_DATA, port_pa_data_shadow, CONFIG_ETRAX_LED3G, !(x)) 
 #endif
@@ -128,7 +139,10 @@
 #define LED_ACTIVE_SET_R(x) \
          REG_SHADOW_SET(R_PORT_PB_DATA, port_pb_data_shadow, CONFIG_ETRAX_LED2R, !(x))
 #define LED_DISK_WRITE(x) \
-         REG_SHADOW_SET(R_PORT_PB_DATA, port_pb_data_shadow, CONFIG_ETRAX_LED3R, !(x))
+        do{\
+                REG_SHADOW_SET(R_PORT_PB_DATA, port_pb_data_shadow, CONFIG_ETRAX_LED3G, !(x));\
+                REG_SHADOW_SET(R_PORT_PB_DATA, port_pb_data_shadow, CONFIG_ETRAX_LED3R, !(x));\
+        }while(0)
 #define LED_DISK_READ(x) \
          REG_SHADOW_SET(R_PORT_PB_DATA, port_pb_data_shadow, CONFIG_ETRAX_LED3G, !(x))     
 #endif
@@ -155,7 +169,10 @@
 #define LED_ACTIVE_SET_R(x) \
          REG_SHADOW_SET(port_csp0_addr, port_csp0_shadow, CONFIG_ETRAX_LED2R, !(x))
 #define LED_DISK_WRITE(x) \
-         REG_SHADOW_SET(port_csp0_addr, port_csp0_shadow, CONFIG_ETRAX_LED3R, !(x))
+        do{\
+                REG_SHADOW_SET(port_csp0_addr, port_csp0_shadow, CONFIG_ETRAX_LED3G, !(x));\
+                REG_SHADOW_SET(port_csp0_addr, port_csp0_shadow, CONFIG_ETRAX_LED3R, !(x));\
+        }while(0)
 #define LED_DISK_READ(x) \
          REG_SHADOW_SET(port_csp0_addr, port_csp0_shadow, CONFIG_ETRAX_LED3G, !(x))
 #define LED_BIT_SET(x)\
diff -u --recursive --new-file v2.4.7/linux/include/asm-cris/irq.h linux/include/asm-cris/irq.h
--- v2.4.7/linux/include/asm-cris/irq.h	Wed Jul 25 17:10:25 2001
+++ linux/include/asm-cris/irq.h	Thu Jul 26 15:10:07 2001
@@ -1,11 +1,11 @@
 /*
  * Interrupt handling assembler and defines for Linux/CRIS
  *
- * Copyright (c) 2000 Axis Communications AB
+ * Copyright (c) 2000, 2001 Axis Communications AB
  *
  * Authors:   Bjorn Wesen (bjornw@axis.com)
  *
- * $Id: irq.h,v 1.11 2001/06/01 14:57:17 starvik Exp $
+ * $Id: irq.h,v 1.13 2001/07/06 18:52:08 hp Exp $
  */
 
 #ifndef _ASM_IRQ_H
@@ -29,7 +29,7 @@
 /* par1, scsi1 on 5 */
 #define NETWORK_STATUS_IRQ_NBR IO_BITNR(R_VECT_MASK_RD, network) /* 6 */
 
-#define SERIAL_IRQ_NBR IO_BITNR(R_VECT_MASK_RD, network) /* 8 */
+#define SERIAL_IRQ_NBR IO_BITNR(R_VECT_MASK_RD, serial) /* 8 */
 #define PA_IRQ_NBR IO_BITNR(R_VECT_MASK_RD, pa) /* 11 */
 /* extdma0 and extdma1 is at irq 12 and 13 and/or same as dma5 and dma6 ? */
 #define EXTDMA0_IRQ_NBR IO_BITNR(R_VECT_MASK_RD, ext_dma0)
diff -u --recursive --new-file v2.4.7/linux/include/asm-cris/processor.h linux/include/asm-cris/processor.h
--- v2.4.7/linux/include/asm-cris/processor.h	Tue May  1 16:05:00 2001
+++ linux/include/asm-cris/processor.h	Thu Jul 26 15:10:07 2001
@@ -100,7 +100,7 @@
 #define start_thread(regs, ip, usp) do { \
 	set_fs(USER_DS);      \
 	regs->irp = ip;       \
-	regs->dccr |= 1 << 8; \
+	regs->dccr |= 1 << U_DCCR_BITNR; \
 	wrusp(usp);           \
 } while(0)
 
diff -u --recursive --new-file v2.4.7/linux/include/asm-cris/ptrace.h linux/include/asm-cris/ptrace.h
--- v2.4.7/linux/include/asm-cris/ptrace.h	Wed Jul 25 17:10:25 2001
+++ linux/include/asm-cris/ptrace.h	Thu Jul 26 15:10:07 2001
@@ -30,6 +30,20 @@
 #define PT_USP       23    /* special case - USP is not in the pt_regs */
 #define PT_MAX       23
 
+/* Condition code bit numbers.  The same numbers apply to CCR of course,
+   but we use DCCR everywhere else, so let's try and be consistent.  */
+#define C_DCCR_BITNR 0
+#define V_DCCR_BITNR 1
+#define Z_DCCR_BITNR 2
+#define N_DCCR_BITNR 3
+#define X_DCCR_BITNR 4
+#define I_DCCR_BITNR 5
+#define B_DCCR_BITNR 6
+#define M_DCCR_BITNR 7
+#define U_DCCR_BITNR 8
+#define P_DCCR_BITNR 9
+#define F_DCCR_BITNR 10
+
 /* Frame types */
 
 #define CRIS_FRAME_NORMAL   0 /* normal frame without SBFS stacking */
@@ -98,7 +112,7 @@
 #define PTRACE_SETREGS            13
 
 /* bit 8 is user-mode flag */
-#define user_mode(regs) ((regs)->dccr & 0x100)
+#define user_mode(regs) (((regs)->dccr & 0x100) != 0)
 #define instruction_pointer(regs) ((regs)->irp)
 extern void show_regs(struct pt_regs *);
 #endif
diff -u --recursive --new-file v2.4.7/linux/include/asm-cris/socket.h linux/include/asm-cris/socket.h
--- v2.4.7/linux/include/asm-cris/socket.h	Tue Jul  3 17:08:21 2001
+++ linux/include/asm-cris/socket.h	Thu Jul 26 15:10:07 2001
@@ -59,7 +59,7 @@
                                         /* level.  For writing rarp and */
                                         /* other similar things on the  */
                                         /* user level.                  */
-#define	SOCK_MAX	(SOCK_PACKET+1)
+#define        SOCK_MAX        (SOCK_PACKET+1)
 #endif
 
 #endif /* _ASM_SOCKET_H */
diff -u --recursive --new-file v2.4.7/linux/include/asm-cris/softirq.h linux/include/asm-cris/softirq.h
--- v2.4.7/linux/include/asm-cris/softirq.h	Thu Feb  8 16:32:44 2001
+++ linux/include/asm-cris/softirq.h	Thu Jul 26 15:10:07 2001
@@ -4,9 +4,29 @@
 #include <asm/atomic.h>
 #include <asm/hardirq.h>
 
-#define local_bh_disable()      (local_bh_count(smp_processor_id())++)
-#define local_bh_enable()       (local_bh_count(smp_processor_id())--)
+#define local_bh_disable()                      \
+do {                                            \
+        local_bh_count(smp_processor_id())++;   \
+        barrier();                              \
+} while (0)
+
+#define __local_bh_enable()                     \
+do {                                            \
+        barrier();                              \
+        local_bh_count(smp_processor_id())--;   \
+} while (0)
+
+#define local_bh_enable()                               \
+do {                                                    \
+        if (!--local_bh_count(smp_processor_id())       \
+            && softirq_pending(smp_processor_id())) {   \
+                do_softirq();                           \
+                __sti();                                \
+        }                                               \
+} while (0)
 
 #define in_softirq() (local_bh_count(smp_processor_id()) != 0)
+
+#define __cpu_raise_softirq(cpu,nr) set_bit((nr), &softirq_pending(cpu))
 
 #endif	/* __ASM_SOFTIRQ_H */
diff -u --recursive --new-file v2.4.7/linux/include/asm-i386/apic.h linux/include/asm-i386/apic.h
--- v2.4.7/linux/include/asm-i386/apic.h	Sat Jul 28 18:18:24 2001
+++ linux/include/asm-i386/apic.h	Mon Aug  6 21:40:18 2001
@@ -19,17 +19,17 @@
  * Basic functions accessing APICs.
  */
 
-extern __inline void apic_write(unsigned long reg, unsigned long v)
+static __inline void apic_write(unsigned long reg, unsigned long v)
 {
 	*((volatile unsigned long *)(APIC_BASE+reg)) = v;
 }
 
-extern __inline void apic_write_atomic(unsigned long reg, unsigned long v)
+static __inline void apic_write_atomic(unsigned long reg, unsigned long v)
 {
 	xchg((volatile unsigned long *)(APIC_BASE+reg), v);
 }
 
-extern __inline unsigned long apic_read(unsigned long reg)
+static __inline unsigned long apic_read(unsigned long reg)
 {
 	return *((volatile unsigned long *)(APIC_BASE+reg));
 }
@@ -51,7 +51,7 @@
 # define apic_write_around(x,y) apic_write_atomic((x),(y))
 #endif
 
-extern inline void ack_APIC_irq(void)
+static inline void ack_APIC_irq(void)
 {
 	/*
 	 * ack_APIC_irq() actually gets compiled as a single instruction:
diff -u --recursive --new-file v2.4.7/linux/include/asm-i386/checksum.h linux/include/asm-i386/checksum.h
--- v2.4.7/linux/include/asm-i386/checksum.h	Mon Jan 31 23:41:14 2000
+++ linux/include/asm-i386/checksum.h	Thu Jul 26 13:41:22 2001
@@ -34,14 +34,14 @@
  *	If you use these functions directly please don't forget the 
  *	verify_area().
  */
-extern __inline__
+static __inline__
 unsigned int csum_partial_copy_nocheck ( const char *src, char *dst,
 					int len, int sum)
 {
 	return csum_partial_copy_generic ( src, dst, len, sum, NULL, NULL);
 }
 
-extern __inline__
+static __inline__
 unsigned int csum_partial_copy_from_user ( const char *src, char *dst,
 						int len, int sum, int *err_ptr)
 {
diff -u --recursive --new-file v2.4.7/linux/include/asm-i386/cobalt.h linux/include/asm-i386/cobalt.h
--- v2.4.7/linux/include/asm-i386/cobalt.h	Mon Dec 11 13:11:58 2000
+++ linux/include/asm-i386/cobalt.h	Thu Jul 26 13:41:22 2001
@@ -86,22 +86,22 @@
 #define	CO_IRQ_8259	12
 
 #ifdef CONFIG_X86_VISWS_APIC
-extern __inline void co_cpu_write(unsigned long reg, unsigned long v)
+static __inline void co_cpu_write(unsigned long reg, unsigned long v)
 {
 	*((volatile unsigned long *)(CO_CPU_VADDR+reg))=v;
 }
 
-extern __inline unsigned long co_cpu_read(unsigned long reg)
+static __inline unsigned long co_cpu_read(unsigned long reg)
 {
 	return *((volatile unsigned long *)(CO_CPU_VADDR+reg));
 }            
              
-extern __inline void co_apic_write(unsigned long reg, unsigned long v)
+static __inline void co_apic_write(unsigned long reg, unsigned long v)
 {
 	*((volatile unsigned long *)(CO_APIC_VADDR+reg))=v;
 }            
              
-extern __inline unsigned long co_apic_read(unsigned long reg)
+static __inline unsigned long co_apic_read(unsigned long reg)
 {
 	return *((volatile unsigned long *)(CO_APIC_VADDR+reg));
 }
diff -u --recursive --new-file v2.4.7/linux/include/asm-i386/desc.h linux/include/asm-i386/desc.h
--- v2.4.7/linux/include/asm-i386/desc.h	Fri Dec 29 14:07:23 2000
+++ linux/include/asm-i386/desc.h	Thu Jul 26 13:40:32 2001
@@ -69,7 +69,7 @@
 extern void set_ldt_desc(unsigned int n, void *addr, unsigned int size);
 extern void set_tss_desc(unsigned int n, void *addr);
 
-extern inline void clear_LDT(void)
+static inline void clear_LDT(void)
 {
 	int cpu = smp_processor_id();
 	set_ldt_desc(cpu, &default_ldt[0], 5);
@@ -79,7 +79,7 @@
 /*
  * load one particular LDT into the current CPU
  */
-extern inline void load_LDT (struct mm_struct *mm)
+static inline void load_LDT (struct mm_struct *mm)
 {
 	int cpu = smp_processor_id();
 	void *segments = mm->context.segments;
diff -u --recursive --new-file v2.4.7/linux/include/asm-i386/fixmap.h linux/include/asm-i386/fixmap.h
--- v2.4.7/linux/include/asm-i386/fixmap.h	Sat Jul 28 18:18:24 2001
+++ linux/include/asm-i386/fixmap.h	Mon Aug  6 21:40:17 2001
@@ -98,7 +98,7 @@
  * directly without tranlation, we catch the bug with a NULL-deference
  * kernel oops. Illegal ranges of incoming indices are caught too.
  */
-extern inline unsigned long fix_to_virt(const unsigned int idx)
+static inline unsigned long fix_to_virt(const unsigned int idx)
 {
 	/*
 	 * this branch gets completely eliminated after inlining,
diff -u --recursive --new-file v2.4.7/linux/include/asm-i386/io.h linux/include/asm-i386/io.h
--- v2.4.7/linux/include/asm-i386/io.h	Sat Jul 28 18:18:42 2001
+++ linux/include/asm-i386/io.h	Mon Aug  6 22:24:42 2001
@@ -50,7 +50,7 @@
  * Talk about misusing macros..
  */
 #define __OUT1(s,x) \
-extern inline void out##s(unsigned x value, unsigned short port) {
+static inline void out##s(unsigned x value, unsigned short port) {
 
 #define __OUT2(s,s1,s2) \
 __asm__ __volatile__ ("out" #s " %" s1 "0,%" s2 "1"
@@ -60,7 +60,7 @@
 __OUT1(s##_p,x) __OUT2(s,s1,"w") __FULL_SLOW_DOWN_IO : : "a" (value), "Nd" (port));} \
 
 #define __IN1(s) \
-extern inline RETURN_TYPE in##s(unsigned short port) { RETURN_TYPE _v;
+static inline RETURN_TYPE in##s(unsigned short port) { RETURN_TYPE _v;
 
 #define __IN2(s,s1,s2) \
 __asm__ __volatile__ ("in" #s " %" s2 "1,%" s1 "0"
@@ -70,12 +70,12 @@
 __IN1(s##_p) __IN2(s,s1,"w") __FULL_SLOW_DOWN_IO : "=a" (_v) : "Nd" (port) ,##i ); return _v; } \
 
 #define __INS(s) \
-extern inline void ins##s(unsigned short port, void * addr, unsigned long count) \
+static inline void ins##s(unsigned short port, void * addr, unsigned long count) \
 { __asm__ __volatile__ ("rep ; ins" #s \
 : "=D" (addr), "=c" (count) : "d" (port),"0" (addr),"1" (count)); }
 
 #define __OUTS(s) \
-extern inline void outs##s(unsigned short port, const void * addr, unsigned long count) \
+static inline void outs##s(unsigned short port, const void * addr, unsigned long count) \
 { __asm__ __volatile__ ("rep ; outs" #s \
 : "=S" (addr), "=c" (count) : "d" (port),"0" (addr),"1" (count)); }
 
@@ -125,19 +125,19 @@
  * Change virtual addresses to physical addresses and vv.
  * These are pretty trivial
  */
-extern inline unsigned long virt_to_phys(volatile void * address)
+static inline unsigned long virt_to_phys(volatile void * address)
 {
 	return __pa(address);
 }
 
-extern inline void * phys_to_virt(unsigned long address)
+static inline void * phys_to_virt(unsigned long address)
 {
 	return __va(address);
 }
 
 extern void * __ioremap(unsigned long offset, unsigned long size, unsigned long flags);
 
-extern inline void * ioremap (unsigned long offset, unsigned long size)
+static inline void * ioremap (unsigned long offset, unsigned long size)
 {
 	return __ioremap(offset, size, 0);
 }
@@ -147,7 +147,7 @@
  * it's useful if some control registers are in such an area and write combining
  * or read caching is not desirable:
  */
-extern inline void * ioremap_nocache (unsigned long offset, unsigned long size)
+static inline void * ioremap_nocache (unsigned long offset, unsigned long size)
 {
         return __ioremap(offset, size, _PAGE_PCD);
 }
diff -u --recursive --new-file v2.4.7/linux/include/asm-i386/lithium.h linux/include/asm-i386/lithium.h
--- v2.4.7/linux/include/asm-i386/lithium.h	Mon Dec 11 13:34:19 2000
+++ linux/include/asm-i386/lithium.h	Thu Jul 26 13:40:32 2001
@@ -20,22 +20,22 @@
 
 #ifdef CONFIG_X86_VISWS_APIC
 /* More special purpose macros... */
-extern __inline void li_pcia_write16(unsigned long reg, unsigned short v)
+static __inline void li_pcia_write16(unsigned long reg, unsigned short v)
 {
 	*((volatile unsigned short *)(LI_PCIA_VADDR+reg))=v;
 }
 
-extern __inline unsigned short li_pcia_read16(unsigned long reg)
+static __inline unsigned short li_pcia_read16(unsigned long reg)
 {
 	 return *((volatile unsigned short *)(LI_PCIA_VADDR+reg));
 }
 
-extern __inline void li_pcib_write16(unsigned long reg, unsigned short v)
+static __inline void li_pcib_write16(unsigned long reg, unsigned short v)
 {
 	*((volatile unsigned short *)(LI_PCIB_VADDR+reg))=v;
 }
 
-extern __inline unsigned short li_pcib_read16(unsigned long reg)
+static __inline unsigned short li_pcib_read16(unsigned long reg)
 {
 	return *((volatile unsigned short *)(LI_PCIB_VADDR+reg));
 }
diff -u --recursive --new-file v2.4.7/linux/include/asm-i386/locks.h linux/include/asm-i386/locks.h
--- v2.4.7/linux/include/asm-i386/locks.h	Wed Jun  2 11:29:13 1999
+++ linux/include/asm-i386/locks.h	Thu Jul 26 13:40:32 2001
@@ -10,7 +10,7 @@
  *	to borrow for other processors if it was just assembler.
  */
 
-extern __inline__ void prim_spin_lock(struct spinlock *sp)
+static __inline__ void prim_spin_lock(struct spinlock *sp)
 {
 	int processor=smp_processor_id();
 	
@@ -56,7 +56,7 @@
  *	Release a spin lock
  */
  
-extern __inline__ int prim_spin_unlock(struct spinlock *sp)
+static __inline__ int prim_spin_unlock(struct spinlock *sp)
 {
 	/* This is safe. The decrement is still guarded by the lock. A multilock would
 	   not be safe this way */
@@ -73,7 +73,7 @@
  *	Non blocking lock grab
  */
  
-extern __inline__ int prim_spin_lock_nb(struct spinlock *sp)
+static __inline__ int prim_spin_lock_nb(struct spinlock *sp)
 {
 	if(lock_set_bit(0,&sp->lock))
 		return 0;		/* Locked already */
@@ -86,7 +86,7 @@
  *	These wrap the locking primitives up for usage
  */
  
-extern __inline__ void spinlock(struct spinlock *sp)
+static __inline__ void spinlock(struct spinlock *sp)
 {
 	if(sp->priority<current->lock_order)
 		panic("lock order violation: %s (%d)\n", sp->name, current->lock_order);
@@ -100,7 +100,7 @@
 	}
 }
 
-extern __inline__ void spinunlock(struct spinlock *sp)
+static __inline__ void spinunlock(struct spinlock *sp)
 {
 	int pri;
 	if(current->lock_order!=sp->priority)
@@ -116,7 +116,7 @@
 	}	
 }
 
-extern __inline__ void spintestlock(struct spinlock *sp)
+static __inline__ void spintestlock(struct spinlock *sp)
 {
 	/*
 	 *	We do no sanity checks, it's legal to optimistically
@@ -125,7 +125,7 @@
 	prim_spin_lock_nb(sp);
 }
 
-extern __inline__ void spintestunlock(struct spinlock *sp)
+static __inline__ void spintestunlock(struct spinlock *sp)
 {
 	/*
 	 *	A testlock doesn't update the lock chain so we
diff -u --recursive --new-file v2.4.7/linux/include/asm-i386/math_emu.h linux/include/asm-i386/math_emu.h
--- v2.4.7/linux/include/asm-i386/math_emu.h	Wed Jun 21 21:21:37 2000
+++ linux/include/asm-i386/math_emu.h	Sat Jul 28 12:53:05 2001
@@ -12,7 +12,6 @@
    */
 struct info {
 	long ___orig_eip;
-	long ___ret_from_system_call;
 	long ___ebx;
 	long ___ecx;
 	long ___edx;
diff -u --recursive --new-file v2.4.7/linux/include/asm-i386/mmu.h linux/include/asm-i386/mmu.h
--- v2.4.7/linux/include/asm-i386/mmu.h	Fri Dec 29 14:07:23 2000
+++ linux/include/asm-i386/mmu.h	Wed Jul 25 18:03:04 2001
@@ -7,6 +7,7 @@
  */
 typedef struct { 
 	void *segments;
+	unsigned long cpuvalid;
 } mm_context_t;
 
 #endif
diff -u --recursive --new-file v2.4.7/linux/include/asm-i386/mmu_context.h linux/include/asm-i386/mmu_context.h
--- v2.4.7/linux/include/asm-i386/mmu_context.h	Sat Jul 28 18:18:24 2001
+++ linux/include/asm-i386/mmu_context.h	Mon Aug  6 21:40:18 2001
@@ -40,6 +40,7 @@
 		cpu_tlbstate[cpu].active_mm = next;
 #endif
 		set_bit(cpu, &next->cpu_vm_mask);
+		set_bit(cpu, &next->context.cpuvalid);
 		/* Re-load page tables */
 		asm volatile("movl %0,%%cr3": :"r" (__pa(next->pgd)));
 	}
@@ -54,6 +55,8 @@
 			 */
 			local_flush_tlb();
 		}
+		if (!test_and_set_bit(cpu, &next->context.cpuvalid))
+			load_LDT(next);
 	}
 #endif
 }
diff -u --recursive --new-file v2.4.7/linux/include/asm-i386/page.h linux/include/asm-i386/page.h
--- v2.4.7/linux/include/asm-i386/page.h	Sat Jul 28 18:18:24 2001
+++ linux/include/asm-i386/page.h	Mon Aug  6 21:40:17 2001
@@ -96,7 +96,7 @@
 } while (0)
 
 /* Pure 2^n version of get_order */
-extern __inline__ int get_order(unsigned long size)
+static __inline__ int get_order(unsigned long size)
 {
 	int order;
 
diff -u --recursive --new-file v2.4.7/linux/include/asm-i386/pci.h linux/include/asm-i386/pci.h
--- v2.4.7/linux/include/asm-i386/pci.h	Sat Jul 28 18:19:16 2001
+++ linux/include/asm-i386/pci.h	Mon Aug  6 22:24:42 2001
@@ -61,7 +61,7 @@
  * Once the device is given the dma address, the device owns this memory
  * until either pci_unmap_single or pci_dma_sync_single is performed.
  */
-extern inline dma_addr_t pci_map_single(struct pci_dev *hwdev, void *ptr,
+static inline dma_addr_t pci_map_single(struct pci_dev *hwdev, void *ptr,
 					size_t size, int direction)
 {
 	if (direction == PCI_DMA_NONE)
@@ -76,7 +76,7 @@
  * After this call, reads by the cpu to the buffer are guarenteed to see
  * whatever the device wrote there.
  */
-extern inline void pci_unmap_single(struct pci_dev *hwdev, dma_addr_t dma_addr,
+static inline void pci_unmap_single(struct pci_dev *hwdev, dma_addr_t dma_addr,
 				    size_t size, int direction)
 {
 	if (direction == PCI_DMA_NONE)
@@ -99,7 +99,7 @@
  * Device ownership issues as mentioned above for pci_map_single are
  * the same here.
  */
-extern inline int pci_map_sg(struct pci_dev *hwdev, struct scatterlist *sg,
+static inline int pci_map_sg(struct pci_dev *hwdev, struct scatterlist *sg,
 			     int nents, int direction)
 {
 	if (direction == PCI_DMA_NONE)
@@ -111,7 +111,7 @@
  * Again, cpu read rules concerning calls here are the same as for
  * pci_unmap_single() above.
  */
-extern inline void pci_unmap_sg(struct pci_dev *hwdev, struct scatterlist *sg,
+static inline void pci_unmap_sg(struct pci_dev *hwdev, struct scatterlist *sg,
 				int nents, int direction)
 {
 	if (direction == PCI_DMA_NONE)
@@ -128,7 +128,7 @@
  * next point you give the PCI dma address back to the card, the
  * device again owns the buffer.
  */
-extern inline void pci_dma_sync_single(struct pci_dev *hwdev,
+static inline void pci_dma_sync_single(struct pci_dev *hwdev,
 				       dma_addr_t dma_handle,
 				       size_t size, int direction)
 {
@@ -143,7 +143,7 @@
  * The same as pci_dma_sync_single but for a scatter-gather list,
  * same rules and usage.
  */
-extern inline void pci_dma_sync_sg(struct pci_dev *hwdev,
+static inline void pci_dma_sync_sg(struct pci_dev *hwdev,
 				   struct scatterlist *sg,
 				   int nelems, int direction)
 {
@@ -157,7 +157,7 @@
  * only drive the low 24-bits during PCI bus mastering, then
  * you would pass 0x00ffffff as the mask to this function.
  */
-extern inline int pci_dma_supported(struct pci_dev *hwdev, dma_addr_t mask)
+static inline int pci_dma_supported(struct pci_dev *hwdev, dma_addr_t mask)
 {
         /*
          * we fall back to GFP_DMA when the mask isn't all 1s,
diff -u --recursive --new-file v2.4.7/linux/include/asm-i386/pgalloc.h linux/include/asm-i386/pgalloc.h
--- v2.4.7/linux/include/asm-i386/pgalloc.h	Sat Jul 28 18:18:24 2001
+++ linux/include/asm-i386/pgalloc.h	Mon Aug  6 21:40:18 2001
@@ -23,7 +23,7 @@
 extern void *kmalloc(size_t, int);
 extern void kfree(const void *);
 
-extern __inline__ pgd_t *get_pgd_slow(void)
+static __inline__ pgd_t *get_pgd_slow(void)
 {
 	int i;
 	pgd_t *pgd = kmalloc(PTRS_PER_PGD * sizeof(pgd_t), GFP_KERNEL);
@@ -48,7 +48,7 @@
 
 #else
 
-extern __inline__ pgd_t *get_pgd_slow(void)
+static __inline__ pgd_t *get_pgd_slow(void)
 {
 	pgd_t *pgd = (pgd_t *)__get_free_page(GFP_KERNEL);
 
@@ -61,7 +61,7 @@
 
 #endif
 
-extern __inline__ pgd_t *get_pgd_fast(void)
+static __inline__ pgd_t *get_pgd_fast(void)
 {
 	unsigned long *ret;
 
@@ -74,14 +74,14 @@
 	return (pgd_t *)ret;
 }
 
-extern __inline__ void free_pgd_fast(pgd_t *pgd)
+static __inline__ void free_pgd_fast(pgd_t *pgd)
 {
 	*(unsigned long *)pgd = (unsigned long) pgd_quicklist;
 	pgd_quicklist = (unsigned long *) pgd;
 	pgtable_cache_size++;
 }
 
-extern __inline__ void free_pgd_slow(pgd_t *pgd)
+static __inline__ void free_pgd_slow(pgd_t *pgd)
 {
 #if CONFIG_X86_PAE
 	int i;
@@ -116,14 +116,14 @@
 	return (pte_t *)ret;
 }
 
-extern __inline__ void pte_free_fast(pte_t *pte)
+static __inline__ void pte_free_fast(pte_t *pte)
 {
 	*(unsigned long *)pte = (unsigned long) pte_quicklist;
 	pte_quicklist = (unsigned long *) pte;
 	pgtable_cache_size++;
 }
 
-extern __inline__ void pte_free_slow(pte_t *pte)
+static __inline__ void pte_free_slow(pte_t *pte)
 {
 	free_page((unsigned long)pte);
 }
@@ -219,7 +219,7 @@
 
 #endif
 
-extern inline void flush_tlb_pgtables(struct mm_struct *mm,
+static inline void flush_tlb_pgtables(struct mm_struct *mm,
 				      unsigned long start, unsigned long end)
 {
 	/* i386 does not keep any page table caches in TLB */
diff -u --recursive --new-file v2.4.7/linux/include/asm-i386/pgtable-2level.h linux/include/asm-i386/pgtable-2level.h
--- v2.4.7/linux/include/asm-i386/pgtable-2level.h	Wed Oct 18 14:25:46 2000
+++ linux/include/asm-i386/pgtable-2level.h	Thu Jul 26 13:40:32 2001
@@ -29,9 +29,9 @@
  * setup: the pgd is never bad, and a pmd always exists (as it's folded
  * into the pgd entry)
  */
-extern inline int pgd_none(pgd_t pgd)		{ return 0; }
-extern inline int pgd_bad(pgd_t pgd)		{ return 0; }
-extern inline int pgd_present(pgd_t pgd)	{ return 1; }
+static inline int pgd_none(pgd_t pgd)		{ return 0; }
+static inline int pgd_bad(pgd_t pgd)		{ return 0; }
+static inline int pgd_present(pgd_t pgd)	{ return 1; }
 #define pgd_clear(xp)				do { } while (0)
 
 /*
@@ -50,7 +50,7 @@
 #define pgd_page(pgd) \
 ((unsigned long) __va(pgd_val(pgd) & PAGE_MASK))
 
-extern inline pmd_t * pmd_offset(pgd_t * dir, unsigned long address)
+static inline pmd_t * pmd_offset(pgd_t * dir, unsigned long address)
 {
 	return (pmd_t *) dir;
 }
diff -u --recursive --new-file v2.4.7/linux/include/asm-i386/pgtable-3level.h linux/include/asm-i386/pgtable-3level.h
--- v2.4.7/linux/include/asm-i386/pgtable-3level.h	Sun Mar 25 17:38:31 2001
+++ linux/include/asm-i386/pgtable-3level.h	Thu Jul 26 13:40:32 2001
@@ -33,9 +33,9 @@
 #define pgd_ERROR(e) \
 	printk("%s:%d: bad pgd %p(%016Lx).\n", __FILE__, __LINE__, &(e), pgd_val(e))
 
-extern inline int pgd_none(pgd_t pgd)		{ return 0; }
-extern inline int pgd_bad(pgd_t pgd)		{ return 0; }
-extern inline int pgd_present(pgd_t pgd)	{ return 1; }
+static inline int pgd_none(pgd_t pgd)		{ return 0; }
+static inline int pgd_bad(pgd_t pgd)		{ return 0; }
+static inline int pgd_present(pgd_t pgd)	{ return 1; }
 
 /* Rules for using set_pte: the pte being assigned *must* be
  * either not present or in a state where the hardware will
@@ -60,7 +60,7 @@
  * We do not let the generic code free and clear pgd entries due to
  * this erratum.
  */
-extern inline void pgd_clear (pgd_t * pgd) { }
+static inline void pgd_clear (pgd_t * pgd) { }
 
 #define pgd_page(pgd) \
 ((unsigned long) __va(pgd_val(pgd) & PAGE_MASK))
diff -u --recursive --new-file v2.4.7/linux/include/asm-i386/processor.h linux/include/asm-i386/processor.h
--- v2.4.7/linux/include/asm-i386/processor.h	Sat Jul 28 18:18:24 2001
+++ linux/include/asm-i386/processor.h	Mon Aug  6 21:40:18 2001
@@ -119,7 +119,7 @@
 /*
  * Generic CPUID function
  */
-extern inline void cpuid(int op, int *eax, int *ebx, int *ecx, int *edx)
+static inline void cpuid(int op, int *eax, int *ebx, int *ecx, int *edx)
 {
 	__asm__("cpuid"
 		: "=a" (*eax),
@@ -132,7 +132,7 @@
 /*
  * CPUID functions returning a single datum
  */
-extern inline unsigned int cpuid_eax(unsigned int op)
+static inline unsigned int cpuid_eax(unsigned int op)
 {
 	unsigned int eax;
 
@@ -142,7 +142,7 @@
 		: "bx", "cx", "dx");
 	return eax;
 }
-extern inline unsigned int cpuid_ebx(unsigned int op)
+static inline unsigned int cpuid_ebx(unsigned int op)
 {
 	unsigned int eax, ebx;
 
@@ -152,7 +152,7 @@
 		: "cx", "dx" );
 	return ebx;
 }
-extern inline unsigned int cpuid_ecx(unsigned int op)
+static inline unsigned int cpuid_ecx(unsigned int op)
 {
 	unsigned int eax, ecx;
 
@@ -162,7 +162,7 @@
 		: "bx", "dx" );
 	return ecx;
 }
-extern inline unsigned int cpuid_edx(unsigned int op)
+static inline unsigned int cpuid_edx(unsigned int op)
 {
 	unsigned int eax, edx;
 
@@ -439,7 +439,7 @@
 /*
  * Return saved PC of a blocked thread.
  */
-extern inline unsigned long thread_saved_pc(struct thread_struct *t)
+static inline unsigned long thread_saved_pc(struct thread_struct *t)
 {
 	return ((unsigned long *)t->esp)[3];
 }
@@ -472,7 +472,7 @@
 #define MICROCODE_IOCFREE	_IO('6',0)
 
 /* REP NOP (PAUSE) is a good thing to insert into busy-wait loops. */
-extern inline void rep_nop(void)
+static inline void rep_nop(void)
 {
 	__asm__ __volatile__("rep;nop");
 }
diff -u --recursive --new-file v2.4.7/linux/include/asm-i386/serial.h linux/include/asm-i386/serial.h
--- v2.4.7/linux/include/asm-i386/serial.h	Sat Jul 28 18:21:33 2001
+++ linux/include/asm-i386/serial.h	Mon Aug  6 21:43:24 2001
@@ -31,7 +31,9 @@
 #else
 #define RS_TABLE_SIZE
 #endif
-	
+
+#define MCA_COM_FLAGS	(STD_COM_FLAGS|ASYNC_BOOT_ONLYMCA)
+
 /*
  * The following define the access methods for the HUB6 card. All
  * access is through two ports for all 24 possible chips. The card is
@@ -113,12 +115,12 @@
 
 #ifdef CONFIG_MCA
 #define MCA_SERIAL_PORT_DFNS			\
-	{ 0, BASE_BAUD, 0x3220, 3, STD_COM_FLAGS },	\
-	{ 0, BASE_BAUD, 0x3228, 3, STD_COM_FLAGS },	\
-	{ 0, BASE_BAUD, 0x4220, 3, STD_COM_FLAGS },	\
-	{ 0, BASE_BAUD, 0x4228, 3, STD_COM_FLAGS },	\
-	{ 0, BASE_BAUD, 0x5220, 3, STD_COM_FLAGS },	\
-	{ 0, BASE_BAUD, 0x5228, 3, STD_COM_FLAGS },
+	{ 0, BASE_BAUD, 0x3220, 3, MCA_COM_FLAGS },	\
+	{ 0, BASE_BAUD, 0x3228, 3, MCA_COM_FLAGS },	\
+	{ 0, BASE_BAUD, 0x4220, 3, MCA_COM_FLAGS },	\
+	{ 0, BASE_BAUD, 0x4228, 3, MCA_COM_FLAGS },	\
+	{ 0, BASE_BAUD, 0x5220, 3, MCA_COM_FLAGS },	\
+	{ 0, BASE_BAUD, 0x5228, 3, MCA_COM_FLAGS },
 #else
 #define MCA_SERIAL_PORT_DFNS
 #endif
diff -u --recursive --new-file v2.4.7/linux/include/asm-i386/siginfo.h linux/include/asm-i386/siginfo.h
--- v2.4.7/linux/include/asm-i386/siginfo.h	Sat Jul 28 18:18:24 2001
+++ linux/include/asm-i386/siginfo.h	Mon Aug  6 21:40:18 2001
@@ -216,7 +216,7 @@
 #ifdef __KERNEL__
 #include <linux/string.h>
 
-extern inline void copy_siginfo(siginfo_t *to, siginfo_t *from)
+static inline void copy_siginfo(siginfo_t *to, siginfo_t *from)
 {
 	if (from->si_code < 0)
 		memcpy(to, from, sizeof(siginfo_t));
diff -u --recursive --new-file v2.4.7/linux/include/asm-i386/signal.h linux/include/asm-i386/signal.h
--- v2.4.7/linux/include/asm-i386/signal.h	Sat Jul 28 18:18:23 2001
+++ linux/include/asm-i386/signal.h	Mon Aug  6 21:40:17 2001
@@ -179,23 +179,23 @@
 
 #define __HAVE_ARCH_SIG_BITOPS
 
-extern __inline__ void sigaddset(sigset_t *set, int _sig)
+static __inline__ void sigaddset(sigset_t *set, int _sig)
 {
 	__asm__("btsl %1,%0" : "=m"(*set) : "Ir"(_sig - 1) : "cc");
 }
 
-extern __inline__ void sigdelset(sigset_t *set, int _sig)
+static __inline__ void sigdelset(sigset_t *set, int _sig)
 {
 	__asm__("btrl %1,%0" : "=m"(*set) : "Ir"(_sig - 1) : "cc");
 }
 
-extern __inline__ int __const_sigismember(sigset_t *set, int _sig)
+static __inline__ int __const_sigismember(sigset_t *set, int _sig)
 {
 	unsigned long sig = _sig - 1;
 	return 1 & (set->sig[sig / _NSIG_BPW] >> (sig % _NSIG_BPW));
 }
 
-extern __inline__ int __gen_sigismember(sigset_t *set, int _sig)
+static __inline__ int __gen_sigismember(sigset_t *set, int _sig)
 {
 	int ret;
 	__asm__("btl %2,%1\n\tsbbl %0,%0"
@@ -210,7 +210,7 @@
 
 #define sigmask(sig)	(1UL << ((sig) - 1))
 
-extern __inline__ int sigfindinword(unsigned long word)
+static __inline__ int sigfindinword(unsigned long word)
 {
 	__asm__("bsfl %1,%0" : "=r"(word) : "rm"(word) : "cc");
 	return word;
diff -u --recursive --new-file v2.4.7/linux/include/asm-i386/smp.h linux/include/asm-i386/smp.h
--- v2.4.7/linux/include/asm-i386/smp.h	Sat Jul 28 18:18:24 2001
+++ linux/include/asm-i386/smp.h	Mon Aug  6 21:40:18 2001
@@ -46,11 +46,11 @@
  * This simplifies scheduling and IPI sending and
  * compresses data structures.
  */
-extern inline int cpu_logical_map(int cpu)
+static inline int cpu_logical_map(int cpu)
 {
 	return cpu;
 }
-extern inline int cpu_number_map(int cpu)
+static inline int cpu_number_map(int cpu)
 {
 	return cpu;
 }
@@ -77,7 +77,7 @@
 
 #define smp_processor_id() (current->processor)
 
-extern __inline int hard_smp_processor_id(void)
+static __inline int hard_smp_processor_id(void)
 {
 	/* we don't want to mark this access volatile - bad code generation */
 	return GET_APIC_ID(*(unsigned long *)(APIC_BASE+APIC_ID));
diff -u --recursive --new-file v2.4.7/linux/include/asm-i386/smplock.h linux/include/asm-i386/smplock.h
--- v2.4.7/linux/include/asm-i386/smplock.h	Sat Jul 28 18:18:24 2001
+++ linux/include/asm-i386/smplock.h	Mon Aug  6 22:24:42 2001
@@ -40,7 +40,7 @@
  * so we only need to worry about other
  * CPU's.
  */
-extern __inline__ void lock_kernel(void)
+static __inline__ void lock_kernel(void)
 {
 #if 1
 	if (!++current->lock_depth)
@@ -56,7 +56,7 @@
 #endif
 }
 
-extern __inline__ void unlock_kernel(void)
+static __inline__ void unlock_kernel(void)
 {
 	if (current->lock_depth < 0)
 		BUG();
diff -u --recursive --new-file v2.4.7/linux/include/asm-i386/string.h linux/include/asm-i386/string.h
--- v2.4.7/linux/include/asm-i386/string.h	Sat Jul 28 18:18:24 2001
+++ linux/include/asm-i386/string.h	Mon Aug  6 21:40:17 2001
@@ -300,7 +300,7 @@
 	return _mmx_memcpy(to, from, len);
 }
 
-extern __inline__ void *__memcpy3d(void *to, const void *from, size_t len)
+static __inline__ void *__memcpy3d(void *to, const void *from, size_t len)
 {
 	if (len < 512)
 		return __memcpy(to, from, len);
diff -u --recursive --new-file v2.4.7/linux/include/asm-i386/system.h linux/include/asm-i386/system.h
--- v2.4.7/linux/include/asm-i386/system.h	Sat Jul 28 18:18:24 2001
+++ linux/include/asm-i386/system.h	Mon Aug  6 21:40:18 2001
@@ -141,7 +141,7 @@
  * might have an implicit FPU-save as a cost, so it's not
  * clear which path to go.)
  */
-extern inline void __set_64bit (unsigned long long * ptr,
+static inline void __set_64bit (unsigned long long * ptr,
 		unsigned int low, unsigned int high)
 {
 	__asm__ __volatile__ (
@@ -157,7 +157,7 @@
 		:	"ax","dx","memory");
 }
 
-extern void inline __set_64bit_constant (unsigned long long *ptr,
+static inline void __set_64bit_constant (unsigned long long *ptr,
 						 unsigned long long value)
 {
 	__set_64bit(ptr,(unsigned int)(value), (unsigned int)((value)>>32ULL));
@@ -165,7 +165,7 @@
 #define ll_low(x)	*(((unsigned int*)&(x))+0)
 #define ll_high(x)	*(((unsigned int*)&(x))+1)
 
-extern void inline __set_64bit_var (unsigned long long *ptr,
+static inline void __set_64bit_var (unsigned long long *ptr,
 			 unsigned long long value)
 {
 	__set_64bit(ptr,ll_low(value), ll_high(value));
diff -u --recursive --new-file v2.4.7/linux/include/asm-i386/uaccess.h linux/include/asm-i386/uaccess.h
--- v2.4.7/linux/include/asm-i386/uaccess.h	Sat Jul 28 18:18:24 2001
+++ linux/include/asm-i386/uaccess.h	Mon Aug  6 22:24:42 2001
@@ -58,7 +58,7 @@
 
 #endif
 
-extern inline int verify_area(int type, const void * addr, unsigned long size)
+static inline int verify_area(int type, const void * addr, unsigned long size)
 {
 	return access_ok(type,addr,size) ? 0 : -EFAULT;
 }
diff -u --recursive --new-file v2.4.7/linux/include/asm-ia64/a.out.h linux/include/asm-ia64/a.out.h
--- v2.4.7/linux/include/asm-ia64/a.out.h	Thu Apr  5 12:51:47 2001
+++ linux/include/asm-ia64/a.out.h	Tue Jul 31 10:30:09 2001
@@ -32,7 +32,7 @@
 #ifdef __KERNEL__
 # include <asm/page.h>
 # define STACK_TOP	(0x8000000000000000UL + (1UL << (4*PAGE_SHIFT - 12)) - PAGE_SIZE)
-# define IA64_RBS_BOT	(STACK_TOP - 0x80000000L)	/* bottom of register backing store */
+# define IA64_RBS_BOT	(STACK_TOP - 0x80000000L + PAGE_SIZE)	/* bottom of reg. backing store */
 #endif
 
 #endif /* _ASM_IA64_A_OUT_H */
diff -u --recursive --new-file v2.4.7/linux/include/asm-ia64/acpi-ext.h linux/include/asm-ia64/acpi-ext.h
--- v2.4.7/linux/include/asm-ia64/acpi-ext.h	Thu Jan  4 12:50:17 2001
+++ linux/include/asm-ia64/acpi-ext.h	Tue Jul 31 10:30:09 2001
@@ -5,12 +5,12 @@
  * Advanced Configuration and Power Infterface
  * Based on 'ACPI Specification 1.0b' Febryary 2, 1999
  * and 'IA-64 Extensions to the ACPI Specification' Rev 0.6
- * 
+ *
  * Copyright (C) 1999 VA Linux Systems
  * Copyright (C) 1999 Walt Drummond <drummond@valinux.com>
  * Copyright (C) 2000 Intel Corp.
  * Copyright (C) 2000 J.I. Lee <jung-ik.lee@intel.com>
- *	ACPI 2.0 specification 
+ *	ACPI 2.0 specification
  */
 
 #include <linux/types.h>
@@ -146,6 +146,9 @@
 	u32 lapic_address;
 	u32 flags;
 } acpi_madt_t;
+
+/* acpi 2.0 MADT flags */
+#define MADT_PCAT_COMPAT	(1<<0)
 
 /* acpi 2.0 MADT structure types */
 #define ACPI20_ENTRY_LOCAL_APIC                 0
diff -u --recursive --new-file v2.4.7/linux/include/asm-ia64/acpikcfg.h linux/include/asm-ia64/acpikcfg.h
--- v2.4.7/linux/include/asm-ia64/acpikcfg.h	Thu Apr  5 12:51:47 2001
+++ linux/include/asm-ia64/acpikcfg.h	Tue Jul 31 10:30:09 2001
@@ -1,6 +1,6 @@
-#include <linux/config.h>
+#ifndef _ASM_IA64_ACPIKCFG_H
+#define _ASM_IA64_ACPIKCFG_H
 
-#ifdef	CONFIG_ACPI_KERNEL_CONFIG
 /*
  *  acpikcfg.h - ACPI based Kernel Configuration Manager External Interfaces
  *
@@ -26,4 +26,5 @@
 	int				num_pci_vectors
 	);
 #endif
-#endif	/* CONFIG_ACPI_KERNEL_CONFIG */
+
+#endif /* _ASM_IA64_ACPIKCFG_H */
diff -u --recursive --new-file v2.4.7/linux/include/asm-ia64/bitops.h linux/include/asm-ia64/bitops.h
--- v2.4.7/linux/include/asm-ia64/bitops.h	Thu Apr  5 12:51:47 2001
+++ linux/include/asm-ia64/bitops.h	Tue Jul 31 10:30:09 2001
@@ -2,24 +2,29 @@
 #define _ASM_IA64_BITOPS_H
 
 /*
- * Copyright (C) 1998-2000 Hewlett-Packard Co
- * Copyright (C) 1998-2000 David Mosberger-Tang <davidm@hpl.hp.com>
- *
- * 02/04/00 D. Mosberger  Require 64-bit alignment for bitops, per suggestion from davem
+ * Copyright (C) 1998-2001 Hewlett-Packard Co
+ * Copyright (C) 1998-2001 David Mosberger-Tang <davidm@hpl.hp.com>
  */
 
 #include <asm/system.h>
 
-/*
- * These operations need to be atomic.  The address must be (at least)
- * 32-bit aligned.  Note that there are driver (e.g., eepro100) which
- * use these operations to operate on hw-defined data-structures, so
- * we can't easily change these operations to force a bigger
- * alignment.
+/**
+ * set_bit - Atomically set a bit in memory
+ * @nr: the bit to set
+ * @addr: the address to start counting from
+ *
+ * This function is atomic and may not be reordered.  See __set_bit()
+ * if you do not require the atomic guarantees.
+ * Note that @nr may be almost arbitrarily large; this function is not
+ * restricted to acting on a single-word quantity.
+ *
+ * The address must be (at least) "long" aligned.
+ * Note that there are driver (e.g., eepro100) which use these operations to operate on
+ * hw-defined data-structures, so we can't easily change these operations to force a
+ * bigger alignment.
  *
  * bit 0 is the LSB of addr; bit 32 is the LSB of (addr+1).
  */
-
 static __inline__ void
 set_bit (int nr, volatile void *addr)
 {
@@ -36,11 +41,37 @@
 	} while (cmpxchg_acq(m, old, new) != old);
 }
 
+/**
+ * __set_bit - Set a bit in memory
+ * @nr: the bit to set
+ * @addr: the address to start counting from
+ *
+ * Unlike set_bit(), this function is non-atomic and may be reordered.
+ * If it's called on the same region of memory simultaneously, the effect
+ * may be that only one operation succeeds.
+ */
+static __inline__ void
+__set_bit (int nr, volatile void *addr)
+{
+	*((__u32 *) addr + (nr >> 5)) |= (1 << (nr & 31));
+}
+
 /*
  * clear_bit() doesn't provide any barrier for the compiler.
  */
 #define smp_mb__before_clear_bit()	smp_mb()
 #define smp_mb__after_clear_bit()	smp_mb()
+
+/**
+ * clear_bit - Clears a bit in memory
+ * @nr: Bit to clear
+ * @addr: Address to start counting from
+ *
+ * clear_bit() is atomic and may not be reordered.  However, it does
+ * not contain a memory barrier, so if it is used for locking purposes,
+ * you should call smp_mb__before_clear_bit() and/or smp_mb__after_clear_bit()
+ * in order to ensure changes are visible on other processors.
+ */
 static __inline__ void
 clear_bit (int nr, volatile void *addr)
 {
@@ -57,6 +88,15 @@
 	} while (cmpxchg_acq(m, old, new) != old);
 }
 
+/**
+ * change_bit - Toggle a bit in memory
+ * @nr: Bit to clear
+ * @addr: Address to start counting from
+ *
+ * change_bit() is atomic and may not be reordered.
+ * Note that @nr may be almost arbitrarily large; this function is not
+ * restricted to acting on a single-word quantity.
+ */
 static __inline__ void
 change_bit (int nr, volatile void *addr)
 {
@@ -73,6 +113,29 @@
 	} while (cmpxchg_acq(m, old, new) != old);
 }
 
+/**
+ * __change_bit - Toggle a bit in memory
+ * @nr: the bit to set
+ * @addr: the address to start counting from
+ *
+ * Unlike change_bit(), this function is non-atomic and may be reordered.
+ * If it's called on the same region of memory simultaneously, the effect
+ * may be that only one operation succeeds.
+ */
+static __inline__ void
+__change_bit (int nr, volatile void *addr)
+{
+	*((__u32 *) addr + (nr >> 5)) ^= (1 << (nr & 31));
+}
+
+/**
+ * test_and_set_bit - Set a bit and return its old value
+ * @nr: Bit to set
+ * @addr: Address to count from
+ *
+ * This operation is atomic and cannot be reordered.  
+ * It also implies a memory barrier.
+ */
 static __inline__ int
 test_and_set_bit (int nr, volatile void *addr)
 {
@@ -90,6 +153,34 @@
 	return (old & bit) != 0;
 }
 
+/**
+ * __test_and_set_bit - Set a bit and return its old value
+ * @nr: Bit to set
+ * @addr: Address to count from
+ *
+ * This operation is non-atomic and can be reordered.  
+ * If two examples of this operation race, one can appear to succeed
+ * but actually fail.  You must protect multiple accesses with a lock.
+ */
+static __inline__ int
+__test_and_set_bit (int nr, volatile void *addr)
+{
+	__u32 *p = (__u32 *) addr + (nr >> 5);
+	__u32 m = 1 << (nr & 31);
+	int oldbitset = (*p & m) != 0;
+
+	*p |= m;
+	return oldbitset;
+}
+
+/**
+ * test_and_clear_bit - Clear a bit and return its old value
+ * @nr: Bit to set
+ * @addr: Address to count from
+ *
+ * This operation is atomic and cannot be reordered.  
+ * It also implies a memory barrier.
+ */
 static __inline__ int
 test_and_clear_bit (int nr, volatile void *addr)
 {
@@ -107,6 +198,34 @@
 	return (old & ~mask) != 0;
 }
 
+/**
+ * __test_and_clear_bit - Clear a bit and return its old value
+ * @nr: Bit to set
+ * @addr: Address to count from
+ *
+ * This operation is non-atomic and can be reordered.  
+ * If two examples of this operation race, one can appear to succeed
+ * but actually fail.  You must protect multiple accesses with a lock.
+ */
+static __inline__ int
+__test_and_clear_bit(int nr, volatile void * addr)
+{
+	__u32 *p = (__u32 *) addr + (nr >> 5);
+	__u32 m = 1 << (nr & 31);
+	int oldbitset = *p & m;
+
+	*p &= ~m;
+	return oldbitset;
+}
+
+/**
+ * test_and_change_bit - Change a bit and return its new value
+ * @nr: Bit to set
+ * @addr: Address to count from
+ *
+ * This operation is atomic and cannot be reordered.  
+ * It also implies a memory barrier.
+ */
 static __inline__ int
 test_and_change_bit (int nr, volatile void *addr)
 {
@@ -124,15 +243,33 @@
 	return (old & bit) != 0;
 }
 
+/*
+ * WARNING: non atomic version.
+ */
+static __inline__ int
+__test_and_change_bit (int nr, void *addr)
+{
+	__u32 old, bit = (1 << (nr & 31));
+	__u32 *m = (__u32 *) addr + (nr >> 5);
+
+	old = *m;
+	*m = old ^ bit;
+	return (old & bit) != 0;
+}
+
 static __inline__ int
 test_bit (int nr, volatile void *addr)
 {
 	return 1 & (((const volatile __u32 *) addr)[nr >> 5] >> (nr & 31));
 }
 
-/*
- * ffz = Find First Zero in word. Undefined if no zero exists,
- * so code should check against ~0UL first..
+/**
+ * ffz - find the first zero bit in a memory region
+ * @x: The address to start the search at
+ *
+ * Returns the bit-number (0..63) of the first (least significant) zero bit, not
+ * the number of the byte containing a bit.  Undefined if no zero exists, so
+ * code should check against ~0UL first...
  */
 static inline unsigned long
 ffz (unsigned long x)
@@ -146,8 +283,8 @@
 #ifdef __KERNEL__
 
 /*
- * Find the most significant bit that is set (undefined if no bit is
- * set).
+ * find_last_zero_bit - find the last zero bit in a 64 bit quantity
+ * @x: The value to search
  */
 static inline unsigned long
 ia64_fls (unsigned long x)
@@ -160,9 +297,10 @@
 }
 
 /*
- * ffs: find first bit set. This is defined the same way as
- * the libc and compiler builtin ffs routines, therefore
- * differs in spirit from the above ffz (man ffs).
+ * ffs: find first bit set. This is defined the same way as the libc and compiler builtin
+ * ffs routines, therefore differs in spirit from the above ffz (man ffs): it operates on
+ * "int" values only and the result value is the bit number + 1.  ffs(0) is defined to
+ * return zero.
  */
 #define ffs(x)	__builtin_ffs(x)
 
diff -u --recursive --new-file v2.4.7/linux/include/asm-ia64/efi.h linux/include/asm-ia64/efi.h
--- v2.4.7/linux/include/asm-ia64/efi.h	Thu Apr  5 12:51:47 2001
+++ linux/include/asm-ia64/efi.h	Tue Jul 31 10:30:09 2001
@@ -15,6 +15,7 @@
 #include <linux/string.h>
 #include <linux/time.h>
 #include <linux/types.h>
+#include <linux/proc_fs.h>
 
 #include <asm/page.h>
 #include <asm/system.h>
@@ -237,7 +238,7 @@
 extern void efi_memmap_walk (efi_freemem_callback_t callback, void *arg);
 extern void efi_gettimeofday (struct timeval *tv);
 extern void efi_enter_virtual_mode (void);	/* switch EFI to virtual mode, if possible */
-
+extern u64  efi_get_iobase (void);
 
 /*
  * Variable Attributes
@@ -245,5 +246,13 @@
 #define EFI_VARIABLE_NON_VOLATILE       0x0000000000000001
 #define EFI_VARIABLE_BOOTSERVICE_ACCESS 0x0000000000000002
 #define EFI_VARIABLE_RUNTIME_ACCESS     0x0000000000000004
+
+
+/*
+ * efi_dir is allocated in arch/ia64/kernel/efi.c.
+ */
+#ifdef CONFIG_PROC_FS
+extern struct proc_dir_entry *efi_dir;
+#endif
 
 #endif /* _ASM_IA64_EFI_H */
diff -u --recursive --new-file v2.4.7/linux/include/asm-ia64/fpswa.h linux/include/asm-ia64/fpswa.h
--- v2.4.7/linux/include/asm-ia64/fpswa.h	Sun Feb 13 10:30:50 2000
+++ linux/include/asm-ia64/fpswa.h	Tue Jul 31 10:30:09 2001
@@ -9,10 +9,6 @@
  * Copyright (C) 1999 Goutham Rao <goutham.rao@intel.com>
  */
 
-#if 1
-#define FPSWA_BUG
-#endif
-
 typedef struct {
 	/* 4 * 128 bits */
 	unsigned long fp_lp[4*2];
diff -u --recursive --new-file v2.4.7/linux/include/asm-ia64/hardirq.h linux/include/asm-ia64/hardirq.h
--- v2.4.7/linux/include/asm-ia64/hardirq.h	Thu Apr  5 12:51:47 2001
+++ linux/include/asm-ia64/hardirq.h	Tue Jul 31 10:30:09 2001
@@ -16,15 +16,15 @@
 /*
  * No irq_cpustat_t for IA-64.  The data is held in the per-CPU data structure.
  */
-#define softirq_active(cpu)		(cpu_data[cpu].softirq.active)
-#define softirq_mask(cpu)		(cpu_data[cpu].softirq.mask)
-#define irq_count(cpu)			(cpu_data[cpu].irq_stat.f.irq_count)
-#define bh_count(cpu)			(cpu_data[cpu].irq_stat.f.bh_count)
+#define softirq_pending(cpu)		(cpu_data(cpu)->softirq_pending)
+#define ksoftirqd_task(cpu)		(cpu_data(cpu)->ksoftirqd)
+#define irq_count(cpu)			(cpu_data(cpu)->irq_stat.f.irq_count)
+#define bh_count(cpu)			(cpu_data(cpu)->irq_stat.f.bh_count)
 #define syscall_count(cpu)		/* unused on IA-64 */
 #define nmi_count(cpu)			0
 
-#define local_softirq_active()		(local_cpu_data->softirq.active)
-#define local_softirq_mask()		(local_cpu_data->softirq.mask)
+#define local_softirq_pending()		(local_cpu_data->softirq_pending)
+#define local_ksoftirqd_task()		(local_cpu_data->ksoftirqd)
 #define local_irq_count()		(local_cpu_data->irq_stat.f.irq_count)
 #define local_bh_count()		(local_cpu_data->irq_stat.f.bh_count)
 #define local_syscall_count()		/* unused on IA-64 */
diff -u --recursive --new-file v2.4.7/linux/include/asm-ia64/hw_irq.h linux/include/asm-ia64/hw_irq.h
--- v2.4.7/linux/include/asm-ia64/hw_irq.h	Thu Apr  5 12:51:47 2001
+++ linux/include/asm-ia64/hw_irq.h	Tue Jul 31 10:30:09 2001
@@ -49,6 +49,7 @@
 #define IA64_PERFMON_VECTOR		0xee	/* performanc monitor interrupt vector */
 #define IA64_TIMER_VECTOR		0xef	/* use highest-prio group 15 interrupt for timer */
 #define	IA64_MCA_WAKEUP_VECTOR		0xf0	/* MCA wakeup (must be >MCA_RENDEZ_VECTOR) */
+#define IA64_IPI_RESCHEDULE		0xfd	/* SMP reschedule */
 #define IA64_IPI_VECTOR			0xfe	/* inter-processor interrupt vector */
 
 /* IA64 inter-cpu interrupt related definitions */
@@ -69,7 +70,7 @@
 
 extern unsigned long ipi_base_addr;
 
-extern struct hw_interrupt_type irq_type_ia64_sapic;	/* CPU-internal interrupt controller */
+extern struct hw_interrupt_type irq_type_ia64_lsapic;	/* CPU-internal interrupt controller */
 
 extern int ia64_alloc_irq (void);	/* allocate a free irq */
 extern void ia64_send_ipi (int cpu, int vector, int delivery_mode, int redirect);
diff -u --recursive --new-file v2.4.7/linux/include/asm-ia64/ia32.h linux/include/asm-ia64/ia32.h
--- v2.4.7/linux/include/asm-ia64/ia32.h	Fri Apr 13 20:26:07 2001
+++ linux/include/asm-ia64/ia32.h	Tue Jul 31 10:30:09 2001
@@ -108,7 +108,7 @@
 } sigset32_t;
 
 struct sigaction32 {
-       unsigned int  sa_handler;	/* Really a pointer, but need to deal 
+       unsigned int  sa_handler;	/* Really a pointer, but need to deal
 					     with 32 bits */
        unsigned int sa_flags;
        unsigned int sa_restorer;	/* Another 32 bit pointer */
@@ -118,7 +118,7 @@
 typedef unsigned int old_sigset32_t;	/* at least 32 bits */
 
 struct old_sigaction32 {
-       unsigned int  sa_handler;	/* Really a pointer, but need to deal 
+       unsigned int  sa_handler;	/* Really a pointer, but need to deal
 					     with 32 bits */
        old_sigset32_t sa_mask;		/* A 32 bit mask */
        unsigned int sa_flags;
@@ -133,7 +133,7 @@
 
 struct ucontext_ia32 {
 	unsigned int	  uc_flags;
-	unsigned int 	  uc_link;
+	unsigned int	  uc_link;
 	stack_ia32_t	  uc_stack;
 	struct sigcontext_ia32 uc_mcontext;
 	sigset_t	  uc_sigmask;	/* mask last for extensibility */
@@ -252,6 +252,15 @@
 #define ELF_ARCH	EM_386
 
 #define IA32_PAGE_OFFSET	0xc0000000
+#define IA32_STACK_TOP		((IA32_PAGE_OFFSET/3) * 2)
+
+/*
+ * The system segments (GDT, TSS, LDT) have to be mapped below 4GB so the IA-32 engine can
+ * access them.
+ */
+#define IA32_GDT_OFFSET		(IA32_PAGE_OFFSET)
+#define IA32_TSS_OFFSET		(IA32_PAGE_OFFSET + PAGE_SIZE)
+#define IA32_LDT_OFFSET		(IA32_PAGE_OFFSET + 2*PAGE_SIZE)
 
 #define USE_ELF_CORE_DUMP
 #define ELF_EXEC_PAGESIZE	IA32_PAGE_SIZE
@@ -287,7 +296,7 @@
 
 /* This macro yields a bitmask that programs can use to figure out
    what instruction set this CPU supports.  */
-#define ELF_HWCAP 	0
+#define ELF_HWCAP	0
 
 /* This macro yields a string that ld.so will use to load
    implementation specific libraries for optimization.  Not terribly
@@ -304,61 +313,64 @@
 /*
  * IA-32 ELF specific definitions for IA-64.
  */
- 
+
 #define __USER_CS      0x23
 #define __USER_DS      0x2B
 
-#define SEG_LIM     32
-#define SEG_TYPE    52
-#define SEG_SYS     56
-#define SEG_DPL     57
-#define SEG_P       59
-#define SEG_DB      62
-#define SEG_G       63
-
 #define FIRST_TSS_ENTRY 6
 #define FIRST_LDT_ENTRY (FIRST_TSS_ENTRY+1)
 #define _TSS(n) ((((unsigned long) n)<<4)+(FIRST_TSS_ENTRY<<3))
 #define _LDT(n) ((((unsigned long) n)<<4)+(FIRST_LDT_ENTRY<<3))
 
-#define IA64_SEG_DESCRIPTOR(base, limit, segtype, nonsysseg, dpl, segpresent, segdb, granularity) \
-	       ((base)			       |       \
-		(limit << SEG_LIM)	       |       \
-		(segtype << SEG_TYPE)	       |       \
-		(nonsysseg << SEG_SYS)	       |       \
-		(dpl << SEG_DPL)	       |       \
-		(segpresent << SEG_P)	       |       \
-		(segdb << SEG_DB)	       |       \
-		(granularity << SEG_G))
-
-#define IA32_SEG_BASE 16
-#define IA32_SEG_TYPE 40
-#define IA32_SEG_SYS  44
-#define IA32_SEG_DPL  45
-#define IA32_SEG_P    47
-#define IA32_SEG_HIGH_LIMIT    48
-#define IA32_SEG_AVL   52
-#define IA32_SEG_DB    54
-#define IA32_SEG_G     55
-#define IA32_SEG_HIGH_BASE 56
-
-#define IA32_SEG_DESCRIPTOR(base, limit, segtype, nonsysseg, dpl, segpresent, avl, segdb, granularity) \
-	       ((limit & 0xFFFF)			       |       \
-		 (base & 0xFFFFFF << IA32_SEG_BASE)	       |       \
-		(segtype << IA32_SEG_TYPE)		       |       \
-		(nonsysseg << IA32_SEG_SYS)		       |       \
-		(dpl << IA32_SEG_DPL)			       |       \
-		(segpresent << IA32_SEG_P)		       |       \
-		(((limit >> 16) & 0xF) << IA32_SEG_HIGH_LIMIT) |       \
-		(avl << IA32_SEG_AVL)			       |       \
-		(segdb << IA32_SEG_DB)			       |       \
-		(granularity << IA32_SEG_G)		       |       \
-		(((base >> 24) & 0xFF) << IA32_SEG_HIGH_BASE)) 
+#define IA32_SEG_BASE		16
+#define IA32_SEG_TYPE		40
+#define IA32_SEG_SYS		44
+#define IA32_SEG_DPL		45
+#define IA32_SEG_P		47
+#define IA32_SEG_HIGH_LIMIT	48
+#define IA32_SEG_AVL		52
+#define IA32_SEG_DB		54
+#define IA32_SEG_G		55
+#define IA32_SEG_HIGH_BASE	56
+
+#define IA32_SEG_DESCRIPTOR(base, limit, segtype, nonsysseg, dpl, segpresent, avl, segdb, gran)	\
+	       (((limit) & 0xffff)								\
+		| (((unsigned long) (base) & 0xffffff) << IA32_SEG_BASE)			\
+		| ((unsigned long) (segtype) << IA32_SEG_TYPE)					\
+		| ((unsigned long) (nonsysseg) << IA32_SEG_SYS)					\
+		| ((unsigned long) (dpl) << IA32_SEG_DPL)					\
+		| ((unsigned long) (segpresent) << IA32_SEG_P)					\
+		| ((((unsigned long) (limit) >> 16) & 0xf) << IA32_SEG_HIGH_LIMIT)		\
+		| ((unsigned long) (avl) << IA32_SEG_AVL)					\
+		| ((unsigned long) (segdb) << IA32_SEG_DB)					\
+		| ((unsigned long) (gran) << IA32_SEG_G)					\
+		| ((((unsigned long) (base) >> 24) & 0xff) << IA32_SEG_HIGH_BASE))
+
+#define SEG_LIM		32
+#define SEG_TYPE	52
+#define SEG_SYS		56
+#define SEG_DPL		57
+#define SEG_P		59
+#define SEG_AVL		60
+#define SEG_DB		62
+#define SEG_G		63
+
+/* Unscramble an IA-32 segment descriptor into the IA-64 format.  */
+#define IA32_SEG_UNSCRAMBLE(sd)									 \
+	(   (((sd) >> IA32_SEG_BASE) & 0xffffff) | ((((sd) >> IA32_SEG_HIGH_BASE) & 0xff) << 24) \
+	 | ((((sd) & 0xffff) | ((((sd) >> IA32_SEG_HIGH_LIMIT) & 0xf) << 16)) << SEG_LIM)	 \
+	 | ((((sd) >> IA32_SEG_TYPE) & 0xf) << SEG_TYPE)					 \
+	 | ((((sd) >> IA32_SEG_SYS) & 0x1) << SEG_SYS)						 \
+	 | ((((sd) >> IA32_SEG_DPL) & 0x3) << SEG_DPL)						 \
+	 | ((((sd) >> IA32_SEG_P) & 0x1) << SEG_P)						 \
+	 | ((((sd) >> IA32_SEG_AVL) & 0x1) << SEG_AVL)						 \
+	 | ((((sd) >> IA32_SEG_DB) & 0x1) << SEG_DB)						 \
+	 | ((((sd) >> IA32_SEG_G) & 0x1) << SEG_G))
 
-#define IA32_IOBASE    0x2000000000000000 /* Virtual address for I/O space */
+#define IA32_IOBASE	0x2000000000000000 /* Virtual address for I/O space */
 
-#define IA32_CR0       0x80000001      /* Enable PG and PE bits */
-#define IA32_CR4       0	       /* No architectural extensions */
+#define IA32_CR0	0x80000001	/* Enable PG and PE bits */
+#define IA32_CR4	0x600		/* MMXEX and FXSR on */
 
 /*
  *  IA32 floating point control registers starting values
@@ -384,6 +396,25 @@
 	regs->r12 = new_sp;							\
 } while (0)
 
+/*
+ * Local Descriptor Table (LDT) related declarations.
+ */
+
+#define IA32_LDT_ENTRIES	8192		/* Maximum number of LDT entries supported. */
+#define IA32_LDT_ENTRY_SIZE	8		/* The size of each LDT entry. */
+
+struct ia32_modify_ldt_ldt_s {
+	unsigned int entry_number;
+	unsigned int base_addr;
+	unsigned int limit;
+	unsigned int seg_32bit:1;
+	unsigned int contents:2;
+	unsigned int read_exec_only:1;
+	unsigned int limit_in_pages:1;
+	unsigned int seg_not_present:1;
+	unsigned int useable:1;
+};
+
 extern void ia32_gdt_init (void);
 extern int ia32_setup_frame1 (int sig, struct k_sigaction *ka, siginfo_t *info,
 			       sigset_t *set, struct pt_regs *regs);
@@ -392,5 +423,5 @@
 extern int ia32_exception (struct pt_regs *regs, unsigned long isr);
 
 #endif /* !CONFIG_IA32_SUPPORT */
- 
+
 #endif /* _ASM_IA64_IA32_H */
diff -u --recursive --new-file v2.4.7/linux/include/asm-ia64/io.h linux/include/asm-ia64/io.h
--- v2.4.7/linux/include/asm-ia64/io.h	Thu Apr  5 12:51:47 2001
+++ linux/include/asm-ia64/io.h	Tue Jul 31 10:30:09 2001
@@ -333,7 +333,7 @@
 #define readb(a)	__readb((void *)(a))
 #define readw(a)	__readw((void *)(a))
 #define readl(a)	__readl((void *)(a))
-#define readq(a)	__readqq((void *)(a))
+#define readq(a)	__readq((void *)(a))
 #define __raw_readb	readb
 #define __raw_readw	readw
 #define __raw_readl	readl
diff -u --recursive --new-file v2.4.7/linux/include/asm-ia64/iosapic.h linux/include/asm-ia64/iosapic.h
--- v2.4.7/linux/include/asm-ia64/iosapic.h	Thu Jan  4 15:25:55 2001
+++ linux/include/asm-ia64/iosapic.h	Tue Jul 31 10:30:09 2001
@@ -51,7 +51,8 @@
 
 #ifndef __ASSEMBLY__
 
-extern void __init iosapic_init (unsigned long address, unsigned int base_irq);
+extern void __init iosapic_init (unsigned long address, unsigned int base_irq,
+                                 int pcat_compat);
 extern void iosapic_register_legacy_irq (unsigned long irq, unsigned long pin,
 					 unsigned long polarity, unsigned long trigger);
 extern void iosapic_pci_fixup (int);
diff -u --recursive --new-file v2.4.7/linux/include/asm-ia64/mca_asm.h linux/include/asm-ia64/mca_asm.h
--- v2.4.7/linux/include/asm-ia64/mca_asm.h	Thu Apr  5 12:51:47 2001
+++ linux/include/asm-ia64/mca_asm.h	Tue Jul 31 10:30:09 2001
@@ -1,5 +1,5 @@
 /*
- * File: 	mca_asm.h
+ * File:	mca_asm.h
  *
  * Copyright (C) 1999 Silicon Graphics, Inc.
  * Copyright (C) Vijay Chander (vijay@engr.sgi.com)
@@ -16,23 +16,23 @@
 #define PSR_RT		27
 #define PSR_IT		36
 #define PSR_BN		44
-	
+
 /*
  * This macro converts a instruction virtual address to a physical address
  * Right now for simulation purposes the virtual addresses are
  * direct mapped to physical addresses.
- * 	1. Lop off bits 61 thru 63 in the virtual address
+ *	1. Lop off bits 61 thru 63 in the virtual address
  */
 #define INST_VA_TO_PA(addr)							\
-	dep 	addr	= 0, addr, 61, 3;
+	dep	addr	= 0, addr, 61, 3;
 /*
  * This macro converts a data virtual address to a physical address
  * Right now for simulation purposes the virtual addresses are
  * direct mapped to physical addresses.
- * 	1. Lop off bits 61 thru 63 in the virtual address
+ *	1. Lop off bits 61 thru 63 in the virtual address
  */
 #define DATA_VA_TO_PA(addr)							\
-	dep 	addr	= 0, addr, 61, 3;
+	dep	addr	= 0, addr, 61, 3;
 /*
  * This macro converts a data physical address to a virtual address
  * Right now for simulation purposes the virtual addresses are
@@ -40,7 +40,7 @@
  *	1. Put 0x7 in bits 61 thru 63.
  */
 #define DATA_PA_TO_VA(addr,temp)							\
-	mov	temp	= 0x7	;							\
+	mov	temp	= 0x7	;;							\
 	dep	addr	= temp, addr, 61, 3;
 
 /*
@@ -48,11 +48,11 @@
  * and starts execution in physical mode with all the address
  * translations turned off.
  *	1.	Save the current psr
- *	2. 	Make sure that all the upper 32 bits are off
+ *	2.	Make sure that all the upper 32 bits are off
  *
  *	3.	Clear the interrupt enable and interrupt state collection bits
  *		in the psr before updating the ipsr and iip.
- *	
+ *
  *	4.	Turn off the instruction, data and rse translation bits of the psr
  *		and store the new value into ipsr
  *		Also make sure that the interrupts are disabled.
@@ -71,7 +71,7 @@
 	mov	old_psr = psr;								\
 	;;										\
 	dep	old_psr = 0, old_psr, 32, 32;						\
-	                                                                                \
+											\
 	mov	ar.rsc = 0 ;								\
 	;;										\
 	mov	temp2 = ar.bspstore;							\
@@ -86,7 +86,7 @@
 	mov	temp1 = psr;								\
 	mov	temp2 = psr;								\
 	;;										\
-	                                                                                \
+											\
 	dep	temp2 = 0, temp2, PSR_IC, 2;						\
 	;;										\
 	mov	psr.l = temp2;								\
@@ -94,11 +94,11 @@
 	srlz.d;										\
 	dep	temp1 = 0, temp1, 32, 32;						\
 	;;										\
- 	dep	temp1 = 0, temp1, PSR_IT, 1;						\
+	dep	temp1 = 0, temp1, PSR_IT, 1;						\
 	;;										\
- 	dep	temp1 = 0, temp1, PSR_DT, 1;						\
+	dep	temp1 = 0, temp1, PSR_DT, 1;						\
 	;;										\
- 	dep	temp1 = 0, temp1, PSR_RT, 1;						\
+	dep	temp1 = 0, temp1, PSR_RT, 1;						\
 	;;										\
 	dep	temp1 = 0, temp1, PSR_I, 1;						\
 	;;										\
@@ -125,72 +125,73 @@
  * This macro jumps to the instruction at the given virtual address
  * and starts execution in virtual mode with all the address
  * translations turned on.
- *	1. 	Get the old saved psr
- *	
- *	2. 	Clear the interrupt enable and interrupt state collection bits
+ *	1.	Get the old saved psr
+ *
+ *	2.	Clear the interrupt enable and interrupt state collection bits
  *		in the current psr.
- *	
+ *
  *	3.	Set the instruction translation bit back in the old psr
  *		Note we have to do this since we are right now saving only the
  *		lower 32-bits of old psr.(Also the old psr has the data and
  *		rse translation bits on)
- *	
+ *
  *	4.	Set ipsr to this old_psr with "it" bit set and "bn" = 1.
  *
- *	5. 	Set iip to the virtual address of the next instruction bundle.
+ *	5.	Set iip to the virtual address of the next instruction bundle.
  *
  *	6.	Do an rfi to move ipsr to psr and iip to ip.
  */
 
-#define VIRTUAL_MODE_ENTER(temp1, temp2, start_addr, old_psr)				\
-	mov	temp2 = psr;								\
-	;;										\
-	dep	temp2 = 0, temp2, PSR_IC, 2;						\
-	;;										\
-	mov	psr.l = temp2;								\
-	mov	ar.rsc = 0;								\
-	;;										\
-	srlz.d;										\
-	mov	temp2 = ar.bspstore;							\
-	;;										\
-	DATA_PA_TO_VA(temp2,temp1);							\
-	;;										\
-	mov	temp1 = ar.rnat;							\
-	;;										\
-	mov	ar.bspstore = temp2;							\
-	;;										\
-	mov	ar.rnat = temp1;							\
-	;;										\
-	mov	temp1 = old_psr;							\
-	;;										\
-	mov	temp2 = 1	;							\
-	dep	temp1 = temp2, temp1, PSR_I,  1;					\
-	;;										\
- 	dep	temp1 = temp2, temp1, PSR_IC, 1;					\
-	;;										\
-	dep	temp1 = temp2, temp1, PSR_IT, 1;					\
-	;;										\
- 	dep	temp1 = temp2, temp1, PSR_DT, 1;					\
-	;;										\
- 	dep	temp1 = temp2, temp1, PSR_RT, 1;					\
-	;;										\
-	dep	temp1 = temp2, temp1, PSR_BN, 1;					\
-	;;										\
-	                                                                                \
-	mov     cr.ipsr = temp1;							\
-	movl	temp2 = start_addr;							\
-	;;										\
-	mov	cr.iip = temp2;								\
-	DATA_PA_TO_VA(sp, temp1);							\
-	DATA_PA_TO_VA(gp, temp2);							\
-	;;										\
-	nop	1;									\
-	nop	2;									\
-	nop	1;									\
-	rfi;										\
+#define VIRTUAL_MODE_ENTER(temp1, temp2, start_addr, old_psr)	\
+	mov	temp2 = psr;					\
+	;;							\
+	dep	temp2 = 0, temp2, PSR_IC, 2;			\
+	;;							\
+	mov	psr.l = temp2;					\
+	mov	ar.rsc = 0;					\
+	;;							\
+	srlz.d;							\
+	mov	temp2 = ar.bspstore;				\
+	;;							\
+	DATA_PA_TO_VA(temp2,temp1);				\
+	;;							\
+	mov	temp1 = ar.rnat;				\
+	;;							\
+	mov	ar.bspstore = temp2;				\
+	;;							\
+	mov	ar.rnat = temp1;				\
+	;;							\
+	mov	temp1 = old_psr;				\
+	;;							\
+	mov	temp2 = 1					\
+	;;							\
+	dep	temp1 = temp2, temp1, PSR_I,  1;		\
+	;;							\
+	dep	temp1 = temp2, temp1, PSR_IC, 1;		\
+	;;							\
+	dep	temp1 = temp2, temp1, PSR_IT, 1;		\
+	;;							\
+	dep	temp1 = temp2, temp1, PSR_DT, 1;		\
+	;;							\
+	dep	temp1 = temp2, temp1, PSR_RT, 1;		\
+	;;							\
+	dep	temp1 = temp2, temp1, PSR_BN, 1;		\
+	;;							\
+								\
+	mov     cr.ipsr = temp1;				\
+	movl	temp2 = start_addr;				\
+	;;							\
+	mov	cr.iip = temp2;					\
+	DATA_PA_TO_VA(sp, temp1);				\
+	DATA_PA_TO_VA(gp, temp2);				\
+	;;							\
+	nop	1;						\
+	nop	2;						\
+	nop	1;						\
+	rfi;							\
 	;;
 
-/* 
+/*
  * The following offsets capture the order in which the
  * RSE related registers from the old context are
  * saved onto the new stack frame.
@@ -198,15 +199,15 @@
  *	+-----------------------+
  *	|NDIRTY [BSP - BSPSTORE]|
  *	+-----------------------+
- *	| 	RNAT	      	|
+ *	|	RNAT		|
  *	+-----------------------+
- *	| 	BSPSTORE      	|
+ *	|	BSPSTORE	|
  *	+-----------------------+
- *	| 	IFS	      	|
+ *	|	IFS		|
  *	+-----------------------+
- *	| 	PFS	      	|
+ *	|	PFS		|
  *	+-----------------------+
- *	| 	RSC	      	|
+ *	|	RSC		|
  *	+-----------------------+ <-------- Bottom of new stack frame
  */
 #define  rse_rsc_offset		0
@@ -229,23 +230,23 @@
  *	8. Read and save the new BSP to calculate the #dirty registers
  * NOTE: Look at pages 11-10, 11-11 in PRM Vol 2
  */
-#define rse_switch_context(temp,p_stackframe,p_bspstore) 			\
-        ;; 									\
-        mov     temp=ar.rsc;; 							\
-        st8     [p_stackframe]=temp,8;; 					\
-        mov     temp=ar.pfs;; 							\
-        st8     [p_stackframe]=temp,8; 						\
-        cover ;;								\
-        mov     temp=cr.ifs;; 							\
-        st8     [p_stackframe]=temp,8;;	 					\
-        mov     temp=ar.bspstore;; 						\
-        st8     [p_stackframe]=temp,8;; 					\
-        mov     temp=ar.rnat;; 							\
-        st8     [p_stackframe]=temp,8; 						\
-        mov     ar.bspstore=p_bspstore;; 					\
-        mov     temp=ar.bsp;; 							\
-        sub     temp=temp,p_bspstore;;						\
-        st8     [p_stackframe]=temp,8
+#define rse_switch_context(temp,p_stackframe,p_bspstore)			\
+	;;									\
+	mov     temp=ar.rsc;;							\
+	st8     [p_stackframe]=temp,8;;					\
+	mov     temp=ar.pfs;;							\
+	st8     [p_stackframe]=temp,8;						\
+	cover ;;								\
+	mov     temp=cr.ifs;;							\
+	st8     [p_stackframe]=temp,8;;						\
+	mov     temp=ar.bspstore;;						\
+	st8     [p_stackframe]=temp,8;;					\
+	mov     temp=ar.rnat;;							\
+	st8     [p_stackframe]=temp,8;						\
+	mov     ar.bspstore=p_bspstore;;					\
+	mov     temp=ar.bsp;;							\
+	sub     temp=temp,p_bspstore;;						\
+	st8     [p_stackframe]=temp,8
 
 /*
  * rse_return_context
@@ -253,7 +254,7 @@
  *	2. Store the number of dirty registers RSC.loadrs field
  *	3. Issue a loadrs to insure that any registers from the interrupted
  *	   context which were saved on the new stack frame have been loaded
- * 	   back into the stacked registers
+ *	   back into the stacked registers
  *	4. Restore BSPSTORE
  *	5. Restore RNAT
  *	6. Restore PFS
@@ -261,44 +262,44 @@
  *	8. Restore RSC
  *	9. Issue an RFI
  */
-#define rse_return_context(psr_mask_reg,temp,p_stackframe) 			\
-        ;; 									\
-        alloc   temp=ar.pfs,0,0,0,0;						\
-        add     p_stackframe=rse_ndirty_offset,p_stackframe;;			\
-        ld8     temp=[p_stackframe];; 						\
-        shl     temp=temp,16;;							\
-        mov     ar.rsc=temp;; 							\
-        loadrs;;								\
-        add     p_stackframe=-rse_ndirty_offset+rse_bspstore_offset,p_stackframe;;\
-        ld8     temp=[p_stackframe];; 						\
-        mov     ar.bspstore=temp;; 						\
-        add     p_stackframe=-rse_bspstore_offset+rse_rnat_offset,p_stackframe;;\
-        ld8     temp=[p_stackframe];; 						\
-        mov     ar.rnat=temp;;							\
-        add     p_stackframe=-rse_rnat_offset+rse_pfs_offset,p_stackframe;;	\
-        ld8     temp=[p_stackframe];; 						\
-        mov     ar.pfs=temp;							\
-        add     p_stackframe=-rse_pfs_offset+rse_ifs_offset,p_stackframe;;	\
-        ld8     temp=[p_stackframe];; 						\
-        mov     cr.ifs=temp;							\
-        add     p_stackframe=-rse_ifs_offset+rse_rsc_offset,p_stackframe;;	\
-        ld8     temp=[p_stackframe];; 						\
-        mov     ar.rsc=temp ;							\
-        add     p_stackframe=-rse_rsc_offset,p_stackframe;			\
-        mov     temp=cr.ipsr;;							\
-        st8     [p_stackframe]=temp,8;						\
-        mov     temp=cr.iip;;							\
-        st8     [p_stackframe]=temp,-8;						\
-        mov     temp=psr;;							\
-        or      temp=temp,psr_mask_reg;;					\
-        mov     cr.ipsr=temp;;							\
-        mov     temp=ip;;							\
-        add     temp=0x30,temp;;						\
-        mov     cr.iip=temp;;							\
-        rfi;;									\
-        ld8     temp=[p_stackframe],8;;						\
-        mov     cr.ipsr=temp;;							\
-        ld8     temp=[p_stackframe];;						\
-        mov     cr.iip=temp
+#define rse_return_context(psr_mask_reg,temp,p_stackframe)			\
+	;;									\
+	alloc   temp=ar.pfs,0,0,0,0;						\
+	add     p_stackframe=rse_ndirty_offset,p_stackframe;;			\
+	ld8     temp=[p_stackframe];;						\
+	shl     temp=temp,16;;							\
+	mov     ar.rsc=temp;;							\
+	loadrs;;								\
+	add     p_stackframe=-rse_ndirty_offset+rse_bspstore_offset,p_stackframe;;\
+	ld8     temp=[p_stackframe];;						\
+	mov     ar.bspstore=temp;;						\
+	add     p_stackframe=-rse_bspstore_offset+rse_rnat_offset,p_stackframe;;\
+	ld8     temp=[p_stackframe];;						\
+	mov     ar.rnat=temp;;							\
+	add     p_stackframe=-rse_rnat_offset+rse_pfs_offset,p_stackframe;;	\
+	ld8     temp=[p_stackframe];;						\
+	mov     ar.pfs=temp;							\
+	add     p_stackframe=-rse_pfs_offset+rse_ifs_offset,p_stackframe;;	\
+	ld8     temp=[p_stackframe];;						\
+	mov     cr.ifs=temp;							\
+	add     p_stackframe=-rse_ifs_offset+rse_rsc_offset,p_stackframe;;	\
+	ld8     temp=[p_stackframe];;						\
+	mov     ar.rsc=temp ;							\
+	add     p_stackframe=-rse_rsc_offset,p_stackframe;			\
+	mov     temp=cr.ipsr;;							\
+	st8     [p_stackframe]=temp,8;						\
+	mov     temp=cr.iip;;							\
+	st8     [p_stackframe]=temp,-8;						\
+	mov     temp=psr;;							\
+	or      temp=temp,psr_mask_reg;;					\
+	mov     cr.ipsr=temp;;							\
+	mov     temp=ip;;							\
+	add     temp=0x30,temp;;						\
+	mov     cr.iip=temp;;							\
+	rfi;;									\
+	ld8     temp=[p_stackframe],8;;						\
+	mov     cr.ipsr=temp;;							\
+	ld8     temp=[p_stackframe];;						\
+	mov     cr.iip=temp
 
 #endif /* _ASM_IA64_MCA_ASM_H */
diff -u --recursive --new-file v2.4.7/linux/include/asm-ia64/offsets.h linux/include/asm-ia64/offsets.h
--- v2.4.7/linux/include/asm-ia64/offsets.h	Thu Apr  5 12:51:47 2001
+++ linux/include/asm-ia64/offsets.h	Tue Jul 31 10:30:09 2001
@@ -1,21 +1,19 @@
 #ifndef _ASM_IA64_OFFSETS_H
 #define _ASM_IA64_OFFSETS_H
-
 /*
  * DO NOT MODIFY
  *
- * This file was generated by arch/ia64/tools/print_offsets.
+ * This file was generated by arch/ia64/tools/print_offsets.awk.
  *
  */
-
-#define PT_PTRACED_BIT			0
-#define PT_TRACESYS_BIT			1
-
+#define PT_PTRACED_BIT		0
+#define PT_TRACESYS_BIT		1
 #define IA64_TASK_SIZE			3904	/* 0xf40 */
 #define IA64_PT_REGS_SIZE		400	/* 0x190 */
 #define IA64_SWITCH_STACK_SIZE		560	/* 0x230 */
 #define IA64_SIGINFO_SIZE		128	/* 0x80 */
 #define IA64_CPU_SIZE			16384	/* 0x4000 */
+#define SIGFRAME_SIZE			2832	/* 0xb10 */
 #define UNW_FRAME_INFO_SIZE		448	/* 0x1c0 */
 
 #define IA64_TASK_PTRACE_OFFSET		48	/* 0x30 */
@@ -24,8 +22,8 @@
 #define IA64_TASK_PROCESSOR_OFFSET	100	/* 0x64 */
 #define IA64_TASK_THREAD_OFFSET		1456	/* 0x5b0 */
 #define IA64_TASK_THREAD_KSP_OFFSET	1456	/* 0x5b0 */
-#define IA64_TASK_THREAD_SIGMASK_OFFSET	3752	/* 0xea8 */
-#define IA64_TASK_PFM_NOTIFY_OFFSET	3648	/* 0xe40 */
+#define IA64_TASK_THREAD_SIGMASK_OFFSET	1568	/* 0x620 */
+#define IA64_TASK_PFM_NOTIFY_OFFSET	2088	/* 0x828 */
 #define IA64_TASK_PID_OFFSET		196	/* 0xc4 */
 #define IA64_TASK_MM_OFFSET		88	/* 0x58 */
 #define IA64_PT_REGS_CR_IPSR_OFFSET	0	/* 0x0 */
@@ -75,7 +73,7 @@
 #define IA64_PT_REGS_F8_OFFSET		368	/* 0x170 */
 #define IA64_PT_REGS_F9_OFFSET		384	/* 0x180 */
 #define IA64_SWITCH_STACK_CALLER_UNAT_OFFSET 0	/* 0x0 */
-#define IA64_SWITCH_STACK_AR_FPSR_OFFSET	8	/* 0x8 */
+#define IA64_SWITCH_STACK_AR_FPSR_OFFSET 8	/* 0x8 */
 #define IA64_SWITCH_STACK_F2_OFFSET	16	/* 0x10 */
 #define IA64_SWITCH_STACK_F3_OFFSET	32	/* 0x20 */
 #define IA64_SWITCH_STACK_F4_OFFSET	48	/* 0x30 */
@@ -114,21 +112,30 @@
 #define IA64_SWITCH_STACK_B5_OFFSET	504	/* 0x1f8 */
 #define IA64_SWITCH_STACK_AR_PFS_OFFSET	512	/* 0x200 */
 #define IA64_SWITCH_STACK_AR_LC_OFFSET	520	/* 0x208 */
-#define IA64_SWITCH_STACK_AR_UNAT_OFFSET	528	/* 0x210 */
-#define IA64_SWITCH_STACK_AR_RNAT_OFFSET	536	/* 0x218 */
+#define IA64_SWITCH_STACK_AR_UNAT_OFFSET 528	/* 0x210 */
+#define IA64_SWITCH_STACK_AR_RNAT_OFFSET 536	/* 0x218 */
 #define IA64_SWITCH_STACK_AR_BSPSTORE_OFFSET 544	/* 0x220 */
 #define IA64_SWITCH_STACK_PR_OFFSET	552	/* 0x228 */
 #define IA64_SIGCONTEXT_AR_BSP_OFFSET	72	/* 0x48 */
+#define IA64_SIGCONTEXT_AR_FPSR_OFFSET	104	/* 0x68 */
 #define IA64_SIGCONTEXT_AR_RNAT_OFFSET	80	/* 0x50 */
-#define IA64_SIGCONTEXT_FLAGS_OFFSET	0	/* 0x0 */
+#define IA64_SIGCONTEXT_AR_UNAT_OFFSET	96	/* 0x60 */
+#define IA64_SIGCONTEXT_B0_OFFSET	136	/* 0x88 */
 #define IA64_SIGCONTEXT_CFM_OFFSET	48	/* 0x30 */
+#define IA64_SIGCONTEXT_FLAGS_OFFSET	0	/* 0x0 */
 #define IA64_SIGCONTEXT_FR6_OFFSET	560	/* 0x230 */
-#define IA64_CLONE_VFORK			16384	/* 0x4000 */
+#define IA64_SIGCONTEXT_PR_OFFSET	128	/* 0x80 */
+#define IA64_SIGCONTEXT_R12_OFFSET	296	/* 0x128 */
+#define IA64_SIGFRAME_ARG0_OFFSET	0	/* 0x0 */
+#define IA64_SIGFRAME_ARG1_OFFSET	8	/* 0x8 */
+#define IA64_SIGFRAME_ARG2_OFFSET	16	/* 0x10 */
+#define IA64_SIGFRAME_RBS_BASE_OFFSET	24	/* 0x18 */
+#define IA64_SIGFRAME_HANDLER_OFFSET	32	/* 0x20 */
+#define IA64_SIGFRAME_SIGCONTEXT_OFFSET	176	/* 0xb0 */
+#define IA64_CLONE_VFORK		16384	/* 0x4000 */
 #define IA64_CLONE_VM			256	/* 0x100 */
-#define IA64_CPU_IRQ_COUNT_OFFSET	8	/* 0x8 */
-#define IA64_CPU_BH_COUNT_OFFSET		12	/* 0xc */
-#define IA64_CPU_SOFTIRQ_ACTIVE_OFFSET	0	/* 0x0 */
-#define IA64_CPU_SOFTIRQ_MASK_OFFSET	4	/* 0x4 */
-#define IA64_CPU_PHYS_STACKED_SIZE_P8_OFFSET 16	/* 0x10 */
+#define IA64_CPU_IRQ_COUNT_OFFSET	0	/* 0x0 */
+#define IA64_CPU_BH_COUNT_OFFSET	4	/* 0x4 */
+#define IA64_CPU_PHYS_STACKED_SIZE_P8_OFFSET 12	/* 0xc */
 
 #endif /* _ASM_IA64_OFFSETS_H */
diff -u --recursive --new-file v2.4.7/linux/include/asm-ia64/pgalloc.h linux/include/asm-ia64/pgalloc.h
--- v2.4.7/linux/include/asm-ia64/pgalloc.h	Mon Apr 23 15:28:07 2001
+++ linux/include/asm-ia64/pgalloc.h	Tue Jul 31 10:30:09 2001
@@ -34,7 +34,7 @@
 #define pgtable_cache_size	(local_cpu_data->pgtable_cache_sz)
 
 static inline pgd_t*
-pgd_alloc_one_fast (void)
+pgd_alloc_one_fast (struct mm_struct *mm)
 {
 	unsigned long *ret = pgd_quicklist;
 
@@ -51,7 +51,7 @@
 pgd_alloc (struct mm_struct *mm)
 {
 	/* the VM system never calls pgd_alloc_one_fast(), so we do it here. */
-	pgd_t *pgd = pgd_alloc_one_fast();
+	pgd_t *pgd = pgd_alloc_one_fast(mm);
 
 	if (__builtin_expect(pgd == NULL, 0)) {
 		pgd = (pgd_t *)__get_free_page(GFP_KERNEL);
diff -u --recursive --new-file v2.4.7/linux/include/asm-ia64/pgtable.h linux/include/asm-ia64/pgtable.h
--- v2.4.7/linux/include/asm-ia64/pgtable.h	Thu Apr 12 12:16:36 2001
+++ linux/include/asm-ia64/pgtable.h	Tue Jul 31 10:30:09 2001
@@ -17,6 +17,7 @@
 #include <asm/mman.h>
 #include <asm/page.h>
 #include <asm/processor.h>
+#include <asm/system.h>
 #include <asm/types.h>
 
 #define IA64_MAX_PHYS_BITS	50	/* max. number of physical address bits (architected) */
@@ -125,7 +126,7 @@
 
 #include <asm/bitops.h>
 #include <asm/mmu_context.h>
-#include <asm/system.h>
+#include <asm/processor.h>
 
 /*
  * Next come the mappings that determine how mmap() protection bits
@@ -443,7 +444,7 @@
 
 #define SWP_TYPE(entry)			(((entry).val >> 1) & 0xff)
 #define SWP_OFFSET(entry)		(((entry).val << 1) >> 10)
-#define SWP_ENTRY(type,offset)		((swp_entry_t) { ((type) << 1) | ((offset) << 9) })
+#define SWP_ENTRY(type,offset)		((swp_entry_t) { ((type) << 1) | ((long) (offset) << 9) })
 #define pte_to_swp_entry(pte)		((swp_entry_t) { pte_val(pte) })
 #define swp_entry_to_pte(x)		((pte_t) { (x).val })
 
@@ -463,5 +464,13 @@
 #define HAVE_ARCH_UNMAPPED_AREA
 
 # endif /* !__ASSEMBLY__ */
+
+/*
+ * Identity-mapped regions use a large page size.  KERNEL_PG_NUM is the
+ * number of the (large) page frame that mapps the kernel.
+ */
+#define KERNEL_PG_SHIFT		_PAGE_SIZE_64M
+#define KERNEL_PG_SIZE		(1 << KERNEL_PG_SHIFT)
+#define KERNEL_PG_NUM		((KERNEL_START - PAGE_OFFSET) / KERNEL_PG_SIZE)
 
 #endif /* _ASM_IA64_PGTABLE_H */
diff -u --recursive --new-file v2.4.7/linux/include/asm-ia64/processor.h linux/include/asm-ia64/processor.h
--- v2.4.7/linux/include/asm-ia64/processor.h	Wed Jul 25 17:10:25 2001
+++ linux/include/asm-ia64/processor.h	Tue Jul 31 10:30:09 2001
@@ -235,11 +235,7 @@
  * state comes earlier:
  */
 struct cpuinfo_ia64 {
-	/* irq_stat and softirq should be 64-bit aligned */
-	struct {
-		__u32 active;
-		__u32 mask;
-	} softirq;
+	/* irq_stat must be 64-bit aligned */
 	union {
 		struct {
 			__u32 irq_count;
@@ -247,8 +243,8 @@
 		} f;
 		__u64 irq_and_bh_counts;
 	} irq_stat;
+	__u32 softirq_pending;
 	__u32 phys_stacked_size_p8;	/* size of physical stacked registers + 8 */
-	__u32 pad0;
 	__u64 itm_delta;	/* # of clock cycles between clock ticks */
 	__u64 itm_next;		/* interval timer mask value to use for next clock tick */
 	__u64 *pgd_quick;
@@ -273,6 +269,7 @@
 	__u64 ptce_base;
 	__u32 ptce_count[2];
 	__u32 ptce_stride[2];
+	struct task_struct *ksoftirqd;	/* kernel softirq daemon for this CPU */
 #ifdef CONFIG_SMP
 	__u64 loops_per_jiffy;
 	__u64 ipi_count;
@@ -280,6 +277,9 @@
 	__u64 prof_multiplier;
 	__u64 ipi_operation;
 #endif
+#ifdef CONFIG_NUMA
+	struct cpuinfo_ia64 *cpu_data[NR_CPUS];
+#endif
 } __attribute__ ((aligned (PAGE_SIZE))) ;
 
 /*
@@ -288,7 +288,22 @@
  */
 #define local_cpu_data		((struct cpuinfo_ia64 *) PERCPU_ADDR)
 
-extern struct cpuinfo_ia64 cpu_data[NR_CPUS];
+/*
+ * On NUMA systems, cpu_data for each cpu is allocated during cpu_init() & is allocated on
+ * the node that contains the cpu. This minimizes off-node memory references.  cpu_data
+ * for each cpu contains an array of pointers to the cpu_data structures of each of the
+ * other cpus.
+ *
+ * On non-NUMA systems, cpu_data is a static array allocated at compile time.  References
+ * to the cpu_data of another cpu is done by direct references to the appropriate entry of
+ * the array.
+ */
+#ifdef CONFIG_NUMA
+# define cpu_data(cpu)		local_cpu_data->cpu_data_ptrs[cpu]
+#else
+  extern struct cpuinfo_ia64 _cpu_data[NR_CPUS];
+# define cpu_data(cpu)		(&_cpu_data[cpu])
+#endif
 
 extern void identify_cpu (struct cpuinfo_ia64 *);
 extern void print_cpu_info (struct cpuinfo_ia64 *);
@@ -314,20 +329,10 @@
 struct thread_struct {
 	__u64 ksp;			/* kernel stack pointer */
 	unsigned long flags;		/* various flags */
-	struct ia64_fpreg fph[96];	/* saved/loaded on demand */
-	__u64 dbr[IA64_NUM_DBG_REGS];
-	__u64 ibr[IA64_NUM_DBG_REGS];
-#ifdef CONFIG_PERFMON
-	__u64 pmc[IA64_NUM_PMC_REGS];
-	__u64 pmd[IA64_NUM_PMD_REGS];
-	unsigned long pfm_pend_notify;	/* non-zero if we need to notify and block */
-	void *pfm_context;		/* pointer to detailed PMU context */
-# define INIT_THREAD_PM		{0, }, {0, }, 0, 0,
-#else
-# define INIT_THREAD_PM
-#endif
 	__u64 map_base;			/* base address for get_unmapped_area() */
 	__u64 task_size;		/* limit for task size */
+	struct siginfo *siginfo;	/* current siginfo struct for ptrace() */
+
 #ifdef CONFIG_IA32_SUPPORT
 	__u64 eflag;			/* IA32 EFLAGS reg */
 	__u64 fsr;			/* IA32 floating pt status reg */
@@ -345,7 +350,18 @@
 #else
 # define INIT_THREAD_IA32
 #endif /* CONFIG_IA32_SUPPORT */
-	struct siginfo *siginfo;	/* current siginfo struct for ptrace() */
+#ifdef CONFIG_PERFMON
+	__u64 pmc[IA64_NUM_PMC_REGS];
+	__u64 pmd[IA64_NUM_PMD_REGS];
+	unsigned long pfm_pend_notify;	/* non-zero if we need to notify and block */
+	void *pfm_context;		/* pointer to detailed PMU context */
+# define INIT_THREAD_PM		{0, }, {0, }, 0, 0,
+#else
+# define INIT_THREAD_PM
+#endif
+	__u64 dbr[IA64_NUM_DBG_REGS];
+	__u64 ibr[IA64_NUM_DBG_REGS];
+	struct ia64_fpreg fph[96];	/* saved/loaded on demand */
 };
 
 #define INIT_MMAP {								\
@@ -356,14 +372,14 @@
 #define INIT_THREAD {					\
 	0,				/* ksp */	\
 	0,				/* flags */	\
-	{{{{0}}}, },			/* fph */	\
-	{0, },				/* dbr */	\
-	{0, },				/* ibr */	\
-	INIT_THREAD_PM					\
 	DEFAULT_MAP_BASE,		/* map_base */	\
 	DEFAULT_TASK_SIZE,		/* task_size */	\
+	0,				/* siginfo */	\
 	INIT_THREAD_IA32				\
-	0				/* siginfo */	\
+	INIT_THREAD_PM					\
+	{0, },				/* dbr */	\
+	{0, },				/* ibr */	\
+	{{{{0}}}, }			/* fph */	\
 }
 
 #define start_thread(regs,new_ip,new_sp) do {							\
@@ -416,7 +432,7 @@
 /*
  * Free all resources held by a thread. This is called after the
  * parent of DEAD_TASK has collected the exist status of the task via
- * wait().  This is a no-op on IA-64.
+ * wait().
  */
 #ifdef CONFIG_PERFMON
   extern void release_thread (struct task_struct *task);
@@ -513,8 +529,8 @@
 extern void ia64_load_debug_regs (unsigned long *save_area);
 
 #ifdef CONFIG_IA32_SUPPORT
-extern void ia32_save_state (struct thread_struct *thread);
-extern void ia32_load_state (struct thread_struct *thread);
+extern void ia32_save_state (struct task_struct *task);
+extern void ia32_load_state (struct task_struct *task);
 #endif
 
 #ifdef CONFIG_PERFMON
diff -u --recursive --new-file v2.4.7/linux/include/asm-ia64/ptrace.h linux/include/asm-ia64/ptrace.h
--- v2.4.7/linux/include/asm-ia64/ptrace.h	Thu Apr  5 12:51:47 2001
+++ linux/include/asm-ia64/ptrace.h	Tue Jul 31 10:30:09 2001
@@ -220,11 +220,16 @@
   struct task_struct;			/* forward decl */
 
   extern void show_regs (struct pt_regs *);
-  extern unsigned long ia64_get_user_bsp (struct task_struct *, struct pt_regs *);
-  extern long ia64_peek (struct task_struct *, unsigned long, unsigned long, long *);
-  extern long ia64_poke (struct task_struct *, unsigned long, unsigned long, long);
+  extern unsigned long ia64_get_user_rbs_end (struct task_struct *, struct pt_regs *,
+					      unsigned long *);
+  extern long ia64_peek (struct task_struct *, struct switch_stack *, unsigned long,
+			 unsigned long, long *);
+  extern long ia64_poke (struct task_struct *, struct switch_stack *, unsigned long,
+			 unsigned long, long);
   extern void ia64_flush_fph (struct task_struct *);
   extern void ia64_sync_fph (struct task_struct *);
+  extern long ia64_sync_user_rbs (struct task_struct *, struct switch_stack *,
+				  unsigned long, unsigned long);
 
   /* get nat bits for scratch registers such that bit N==1 iff scratch register rN is a NaT */
   extern unsigned long ia64_get_scratch_nat_bits (struct pt_regs *pt, unsigned long scratch_unat);
diff -u --recursive --new-file v2.4.7/linux/include/asm-ia64/ptrace_offsets.h linux/include/asm-ia64/ptrace_offsets.h
--- v2.4.7/linux/include/asm-ia64/ptrace_offsets.h	Mon Oct  9 17:55:00 2000
+++ linux/include/asm-ia64/ptrace_offsets.h	Tue Jul 31 10:30:09 2001
@@ -173,7 +173,7 @@
 #define PT_AR_BSPSTORE		0x0868
 #define PT_PR			0x0870
 #define PT_B6			0x0878
-#define PT_AR_BSP		0x0880
+#define PT_AR_BSP		0x0880	/* note: this points to the *end* of the backing store! */
 #define PT_R1			0x0888
 #define PT_R2			0x0890
 #define PT_R3			0x0898
diff -u --recursive --new-file v2.4.7/linux/include/asm-ia64/sal.h linux/include/asm-ia64/sal.h
--- v2.4.7/linux/include/asm-ia64/sal.h	Thu Apr 12 12:16:36 2001
+++ linux/include/asm-ia64/sal.h	Tue Jul 31 10:30:09 2001
@@ -7,8 +7,8 @@
  * This is based on version 2.5 of the manual "IA-64 System
  * Abstraction Layer".
  *
- * Copyright (C) 1998, 1999 Hewlett-Packard Co
- * Copyright (C) 1998, 1999 David Mosberger-Tang <davidm@hpl.hp.com>
+ * Copyright (C) 1998, 1999, 2001 Hewlett-Packard Co
+ * Copyright (C) 1998, 1999, 2001 David Mosberger-Tang <davidm@hpl.hp.com>
  * Copyright (C) 1999 Srinivasa Prasad Thirumalachar <sprasad@sprasad.engr.sgi.com>
  *
  * 99/09/29 davidm	Updated for SAL 2.6.
diff -u --recursive --new-file v2.4.7/linux/include/asm-ia64/sigcontext.h linux/include/asm-ia64/sigcontext.h
--- v2.4.7/linux/include/asm-ia64/sigcontext.h	Thu Apr  5 12:51:47 2001
+++ linux/include/asm-ia64/sigcontext.h	Tue Jul 31 10:30:09 2001
@@ -40,6 +40,8 @@
 	unsigned long		sc_gr[32];	/* general registers (static partition) */
 	struct ia64_fpreg	sc_fr[128];	/* floating-point registers */
 
+	unsigned long		sc_rsvd[16];	/* reserved for future use */
+
 	/*
 	 * The mask must come last so we can increase _NSIG_WORDS
 	 * without breaking binary compatibility.
diff -u --recursive --new-file v2.4.7/linux/include/asm-ia64/signal.h linux/include/asm-ia64/signal.h
--- v2.4.7/linux/include/asm-ia64/signal.h	Wed Feb  9 19:45:43 2000
+++ linux/include/asm-ia64/signal.h	Tue Jul 31 10:30:09 2001
@@ -56,7 +56,7 @@
  * SA_FLAGS values:
  *
  * SA_ONSTACK indicates that a registered stack_t will be used.
- * SA_INTERRUPT is a no-op, but left due to historical reasons. Use the
+ * SA_INTERRUPT is a no-op, but left due to historical reasons.
  * SA_RESTART flag to get restarting signals (which were the default long ago)
  * SA_NOCLDSTOP flag to turn off SIGCHLD when children stop.
  * SA_RESETHAND clears the handler when the signal is delivered.
@@ -105,7 +105,6 @@
 #define SA_PROBE		SA_ONESHOT
 #define SA_SAMPLE_RANDOM	SA_RESTART
 #define SA_SHIRQ		0x04000000
-#define SA_LEGACY		0x02000000	/* installed via a legacy irq? */
 
 #endif /* __KERNEL__ */
 
diff -u --recursive --new-file v2.4.7/linux/include/asm-ia64/smp.h linux/include/asm-ia64/smp.h
--- v2.4.7/linux/include/asm-ia64/smp.h	Thu Apr  5 12:51:47 2001
+++ linux/include/asm-ia64/smp.h	Tue Jul 31 10:30:09 2001
@@ -1,7 +1,7 @@
 /*
  * SMP Support
  *
- * Copyright (C) 1999 VA Linux Systems 
+ * Copyright (C) 1999 VA Linux Systems
  * Copyright (C) 1999 Walt Drummond <drummond@valinux.com>
  * Copyright (C) 2001 Hewlett-Packard Co
  * Copyright (C) 2001 David Mosberger-Tang <davidm@hpl.hp.com>
@@ -35,14 +35,13 @@
 
 extern char no_int_routing __initdata;
 
-extern unsigned long cpu_present_map;
-extern unsigned long cpu_online_map;
+extern volatile unsigned long cpu_online_map;
 extern unsigned long ipi_base_addr;
-extern int __cpu_physical_id[NR_CPUS];
 extern unsigned char smp_int_redirect;
 extern int smp_num_cpus;
 
-#define cpu_physical_id(i)	__cpu_physical_id[i]
+extern volatile int ia64_cpu_to_sapicid[];
+#define cpu_physical_id(i)	ia64_cpu_to_sapicid[i]
 #define cpu_number_map(i)	(i)
 #define cpu_logical_map(i)	(i)
 
@@ -70,7 +69,7 @@
  *	max_xtp   : never deliver interrupts to this CPU.
  */
 
-static inline void 
+static inline void
 min_xtp (void)
 {
 	if (smp_int_redirect & SMP_IRQ_REDIRECTION)
@@ -85,13 +84,13 @@
 }
 
 static inline void
-max_xtp (void) 
+max_xtp (void)
 {
 	if (smp_int_redirect & SMP_IRQ_REDIRECTION)
 		writeb(0x0f, ipi_base_addr | XTP_OFFSET); /* Set XTP to max */
 }
 
-static inline unsigned int 
+static inline unsigned int
 hard_smp_processor_id (void)
 {
 	union {
diff -u --recursive --new-file v2.4.7/linux/include/asm-ia64/softirq.h linux/include/asm-ia64/softirq.h
--- v2.4.7/linux/include/asm-ia64/softirq.h	Thu Apr  5 12:51:47 2001
+++ linux/include/asm-ia64/softirq.h	Tue Jul 31 10:30:09 2001
@@ -7,8 +7,18 @@
  */
 #include <asm/hardirq.h>
 
+#define __local_bh_enable()	do { barrier(); local_bh_count()--; } while (0)
+
 #define local_bh_disable()	do { local_bh_count()++; barrier(); } while (0)
-#define local_bh_enable()	do { barrier(); local_bh_count()--; } while (0)
+#define local_bh_enable()								\
+do {											\
+	__local_bh_enable();								\
+	if (__builtin_expect(local_softirq_pending(), 0) && local_bh_count() == 0)	\
+		do_softirq();								\
+} while (0)
+
+
+#define __cpu_raise_softirq(cpu,nr)	set_bit((nr), &softirq_pending(cpu))
 
 #define in_softirq()		(local_bh_count() != 0)
 
diff -u --recursive --new-file v2.4.7/linux/include/asm-ia64/spinlock.h linux/include/asm-ia64/spinlock.h
--- v2.4.7/linux/include/asm-ia64/spinlock.h	Thu Jan  4 12:50:18 2001
+++ linux/include/asm-ia64/spinlock.h	Tue Jul 31 10:30:09 2001
@@ -19,12 +19,12 @@
 
 #ifdef NEW_LOCK
 
-typedef struct { 
+typedef struct {
 	volatile unsigned int lock;
 } spinlock_t;
 
 #define SPIN_LOCK_UNLOCKED			(spinlock_t) { 0 }
-#define spin_lock_init(x)			((x)->lock = 0) 
+#define spin_lock_init(x)			((x)->lock = 0)
 
 /*
  * Streamlined test_and_set_bit(0, (x)).  We use test-and-test-and-set
@@ -62,12 +62,12 @@
 })
 
 #define spin_is_locked(x)	((x)->lock != 0)
-#define spin_unlock(x)		do {((spinlock_t *) x)->lock = 0;} while (0)
-#define spin_unlock_wait(x)	do {} while ((x)->lock)
+#define spin_unlock(x)		do { barrier(); ((spinlock_t *) x)->lock = 0;} while (0)
+#define spin_unlock_wait(x)	do { barrier(); } while ((x)->lock)
 
 #else /* !NEW_LOCK */
 
-typedef struct { 
+typedef struct {
 	volatile unsigned int lock;
 } spinlock_t;
 
@@ -96,7 +96,7 @@
 	:: "r"(&(x)->lock) : "r2", "r29", "memory")
 
 #define spin_is_locked(x)	((x)->lock != 0)
-#define spin_unlock(x)		do {((spinlock_t *) x)->lock = 0; barrier(); } while (0)
+#define spin_unlock(x)		do { barrier(); ((spinlock_t *) x)->lock = 0; } while (0)
 #define spin_trylock(x)		(cmpxchg_acq(&(x)->lock, 0, 1) == 0)
 #define spin_unlock_wait(x)	do { barrier(); } while ((x)->lock)
 
diff -u --recursive --new-file v2.4.7/linux/include/asm-ia64/string.h linux/include/asm-ia64/string.h
--- v2.4.7/linux/include/asm-ia64/string.h	Mon Oct  9 17:55:00 2000
+++ linux/include/asm-ia64/string.h	Tue Jul 31 10:30:09 2001
@@ -10,7 +10,6 @@
  */
 
 #include <linux/config.h>	/* remove this once we remove the A-step workaround... */
-#ifndef CONFIG_ITANIUM_ASTEP_SPECIFIC
 
 #define __HAVE_ARCH_STRLEN	1 /* see arch/ia64/lib/strlen.S */
 #define __HAVE_ARCH_MEMSET	1 /* see arch/ia64/lib/memset.S */
@@ -20,7 +19,5 @@
 extern __kernel_size_t strlen (const char *);
 extern void *memset (void *, int, __kernel_size_t);
 extern void *memcpy (void *, const void *, __kernel_size_t);
-
-#endif /* CONFIG_ITANIUM_ASTEP_SPECIFIC */
 
 #endif /* _ASM_IA64_STRING_H */
diff -u --recursive --new-file v2.4.7/linux/include/asm-ia64/system.h linux/include/asm-ia64/system.h
--- v2.4.7/linux/include/asm-ia64/system.h	Thu Apr  5 12:51:47 2001
+++ linux/include/asm-ia64/system.h	Tue Jul 31 10:30:09 2001
@@ -29,8 +29,7 @@
 #define GATE_ADDR		(0xa000000000000000 + PAGE_SIZE)
 #define PERCPU_ADDR		(0xa000000000000000 + 2*PAGE_SIZE)
 
-#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)
   /* Workaround for Errata 97.  */
 # define IA64_SEMFIX_INSN	mf;
 # define IA64_SEMFIX	"mf;"
diff -u --recursive --new-file v2.4.7/linux/include/asm-ia64/unaligned.h linux/include/asm-ia64/unaligned.h
--- v2.4.7/linux/include/asm-ia64/unaligned.h	Mon Oct  9 17:55:00 2000
+++ linux/include/asm-ia64/unaligned.h	Tue Jul 31 10:30:09 2001
@@ -1,6 +1,8 @@
 #ifndef _ASM_IA64_UNALIGNED_H
 #define _ASM_IA64_UNALIGNED_H
 
+#include <linux/types.h>
+
 /*
  * The main single-value unaligned transfer routines.  Derived from
  * the Linux/Alpha version.
diff -u --recursive --new-file v2.4.7/linux/include/asm-ia64/unistd.h linux/include/asm-ia64/unistd.h
--- v2.4.7/linux/include/asm-ia64/unistd.h	Thu Jan  4 12:50:18 2001
+++ linux/include/asm-ia64/unistd.h	Tue Jul 31 10:30:09 2001
@@ -204,6 +204,7 @@
 #define __NR_fstat			1212
 #define __NR_clone2			1213
 #define __NR_getdents64			1214
+#define __NR_getunwind			1215
 
 #if !defined(__ASSEMBLY__) && !defined(ASSEMBLER)
 
diff -u --recursive --new-file v2.4.7/linux/include/asm-ia64/unwind.h linux/include/asm-ia64/unwind.h
--- v2.4.7/linux/include/asm-ia64/unwind.h	Thu Apr  5 12:51:47 2001
+++ linux/include/asm-ia64/unwind.h	Tue Jul 31 10:30:09 2001
@@ -94,9 +94,10 @@
  * Initialize unwind support.
  */
 extern void unw_init (void);
+extern void unw_create_gate_table (void);
 
 extern 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);
 
 extern void unw_remove_unwind_table (void *handle);
 
diff -u --recursive --new-file v2.4.7/linux/include/asm-s390/atomic.h linux/include/asm-s390/atomic.h
--- v2.4.7/linux/include/asm-s390/atomic.h	Wed Jul 25 17:10:25 2001
+++ linux/include/asm-s390/atomic.h	Wed Jul 25 14:12:02 2001
@@ -25,13 +25,13 @@
 
 #define atomic_eieio()          __asm__ __volatile__ ("BCR 15,0")
 
-#define __CS_LOOP(old, new, ptr, op_val, op_string)			\
+#define __CS_LOOP(old_val, new_val, ptr, op_val, op_string)		\
         __asm__ __volatile__("   l     %0,0(%2)\n"			\
                              "0: lr    %1,%0\n"				\
                              op_string "  %1,%3\n"			\
                              "   cs    %0,%1,0(%2)\n"			\
                              "   jl    0b"				\
-                             : "=&d" (old), "=&d" (new)			\
+                             : "=&d" (old_val), "=&d" (new_val)		\
 			     : "a" (ptr), "d" (op_val) : "cc" );
 
 static __inline__ int atomic_read(atomic_t *v)
@@ -52,80 +52,80 @@
 
 static __inline__ void atomic_add(int i, atomic_t *v)
 {
-	int old, new;
-	__CS_LOOP(old, new, v, i, "ar");
+	int old_val, new_val;
+	__CS_LOOP(old_val, new_val, v, i, "ar");
 }
 
 static __inline__ int atomic_add_return (int i, atomic_t *v)
 {
-	int old, new;
-	__CS_LOOP(old, new, v, i, "ar");
-	return new;
+	int old_val, new_val;
+	__CS_LOOP(old_val, new_val, v, i, "ar");
+	return new_val;
 }
 
 static __inline__ int atomic_add_negative(int i, atomic_t *v)
 {
-	int old, new;
-        __CS_LOOP(old, new, v, i, "ar");
-        return new < 0;
+	int old_val, new_val;
+        __CS_LOOP(old_val, new_val, v, i, "ar");
+        return new_val < 0;
 }
 
 static __inline__ void atomic_sub(int i, atomic_t *v)
 {
-	int old, new;
-	__CS_LOOP(old, new, v, i, "sr");
+	int old_val, new_val;
+	__CS_LOOP(old_val, new_val, v, i, "sr");
 }
 
 static __inline__ void atomic_inc(volatile atomic_t *v)
 {
-	int old, new;
-	__CS_LOOP(old, new, v, 1, "ar");
+	int old_val, new_val;
+	__CS_LOOP(old_val, new_val, v, 1, "ar");
 }
 
 static __inline__ int atomic_inc_return(volatile atomic_t *v)
 {
-	int old, new;
-	__CS_LOOP(old, new, v, 1, "ar");
-        return new;
+	int old_val, new_val;
+	__CS_LOOP(old_val, new_val, v, 1, "ar");
+        return new_val;
 }
 
 static __inline__ int atomic_inc_and_test(volatile atomic_t *v)
 {
-	int old, new;
-	__CS_LOOP(old, new, v, 1, "ar");
-	return new != 0;
+	int old_val, new_val;
+	__CS_LOOP(old_val, new_val, v, 1, "ar");
+	return new_val != 0;
 }
 
 static __inline__ void atomic_dec(volatile atomic_t *v)
 {
-	int old, new;
-	__CS_LOOP(old, new, v, 1, "sr");
+	int old_val, new_val;
+	__CS_LOOP(old_val, new_val, v, 1, "sr");
 }
 
 static __inline__ int atomic_dec_return(volatile atomic_t *v)
 {
-	int old, new;
-	__CS_LOOP(old, new, v, 1, "sr");
-        return new;
+	int old_val, new_val;
+	__CS_LOOP(old_val, new_val, v, 1, "sr");
+        return new_val;
 }
 
 static __inline__ int atomic_dec_and_test(volatile atomic_t *v)
 {
-	int old, new;
-	__CS_LOOP(old, new, v, 1, "sr");
-        return new == 0;
+	int old_val, new_val;
+	__CS_LOOP(old_val, new_val, v, 1, "sr");
+        return new_val == 0;
 }
 
 static __inline__ void atomic_clear_mask(unsigned long mask, atomic_t *v)
 {
-	int old, new;
-	__CS_LOOP(old, new, v, ~mask, "nr");
+	int old_val, new_val;
+	__CS_LOOP(old_val, new_val, v, ~mask, "nr");
 }
 
 static __inline__ void atomic_set_mask(unsigned long mask, atomic_t *v)
 {
-	int old, new;
-	__CS_LOOP(old, new, v, mask, "or");
+	int old_val, new_val;
+	__CS_LOOP(old_val, new_val, v, mask, "or");
 }
 
 /*
diff -u --recursive --new-file v2.4.7/linux/include/asm-s390/bitops.h linux/include/asm-s390/bitops.h
--- v2.4.7/linux/include/asm-s390/bitops.h	Wed Jul 25 17:10:25 2001
+++ linux/include/asm-s390/bitops.h	Wed Jul 25 14:12:02 2001
@@ -831,7 +831,7 @@
                         "   icm  %0,2,1(%1)\n"
                         "   icm  %0,4,2(%1)\n"
                         "   icm  %0,8,3(%1)"
-                        : "=&a" (word) : "a" (p) );
+                        : "=&a" (word) : "a" (p) : "cc" );
 		word >>= bit;
                 res = bit;
                 /* Look for zero in first longword */
diff -u --recursive --new-file v2.4.7/linux/include/asm-s390/byteorder.h linux/include/asm-s390/byteorder.h
--- v2.4.7/linux/include/asm-s390/byteorder.h	Fri May 12 11:41:44 2000
+++ linux/include/asm-s390/byteorder.h	Wed Jul 25 14:12:02 2001
@@ -23,7 +23,7 @@
           "        icm   %0,4,2(%1)\n"
           "        icm   %0,2,1(%1)\n"
           "        ic    %0,0(%1)"
-          : "+&d" (x) : "a" (&temp) : "memory" );
+          : "+&d" (x) : "a" (&temp) : "cc" );
   return x;
 }
 
@@ -36,7 +36,7 @@
           "        icm   %0,4,2(%1)\n"
           "        icm   %0,2,1(%1)\n"
           "        ic    %0,0(%1)"
-          : "=&d" (result) : "a" (x) );
+          : "=&d" (result) : "a" (x) : "cc" );
   return result;
 }
 
@@ -48,7 +48,7 @@
           "        icm   0,2,1(%0)\n"
           "        ic    0,0(%0)\n"
           "        st    0,0(%0)"
-          : : "a" (x) : "0", "memory");
+          : : "a" (x) : "0", "memory", "cc");
 }
 
 static __inline__ __const__ __u16 ___arch__swab16(__u16 x)
@@ -59,7 +59,7 @@
           "        sth   %0,0(%1)\n"
           "        icm   %0,2,1(%1)\n"
           "        ic    %0,0(%1)\n"
-          : "+&d" (x) : "a" (&temp) : "memory");
+          : "+&d" (x) : "a" (&temp) : "memory", "cc" );
   return x;
 }
 
@@ -71,7 +71,7 @@
           "        sr    %0,%0\n"
           "        icm   %0,2,1(%1)\n"
           "        ic    %0,0(%1)\n"
-          : "=&d" (result) : "a" (x) );
+          : "=&d" (result) : "a" (x) : "cc" );
   return result;
 }
 
@@ -81,7 +81,7 @@
           "        icm   0,2,1(%0)\n"
           "        ic    0,0(%0)\n"
           "        sth   0,0(%0)"
-          : : "a" (x) : "0", "memory");
+          : : "a" (x) : "0", "memory", "cc" );
 }
 
 #define __arch__swab32(x) ___arch__swab32(x)
diff -u --recursive --new-file v2.4.7/linux/include/asm-s390/cache.h linux/include/asm-s390/cache.h
--- v2.4.7/linux/include/asm-s390/cache.h	Fri May 12 11:41:44 2000
+++ linux/include/asm-s390/cache.h	Sun Aug  5 13:12:41 2001
@@ -11,6 +11,7 @@
 #ifndef __ARCH_S390_CACHE_H
 #define __ARCH_S390_CACHE_H
 
-#define L1_CACHE_BYTES     16
+#define L1_CACHE_BYTES     256
+#define L1_CACHE_SHIFT     8
 
 #endif
diff -u --recursive --new-file v2.4.7/linux/include/asm-s390/chandev.h linux/include/asm-s390/chandev.h
--- v2.4.7/linux/include/asm-s390/chandev.h	Wed Apr 11 19:02:28 2001
+++ linux/include/asm-s390/chandev.h	Wed Jul 25 14:12:02 2001
@@ -6,49 +6,86 @@
  * 
  *  Generic channel device initialisation support. 
  */
+#ifndef __S390_CHANDEV_H
+#define __S390_CHANDEV_H
 #include <linux/version.h>
 #include <asm/types.h>
 #include <linux/netdevice.h>
 
+
+/* Setting this flag to true causes a device name to be built based on the read_devno of the device */
+/* this is exported so external code can look at this flags setting */
+extern int chandev_use_devno_names;
+
+
 /* chandev_type is a bitmask for registering & describing device types. */
 typedef enum
 {
-	none=0x0,
-	ctc=0x1,
-	escon=0x2,
-	lcs=0x4,
-	osad=0x8,
-	qeth=0x10,
-	claw=0x20,
+	chandev_type_none=0x0,
+	chandev_type_ctc=0x1,
+	chandev_type_escon=0x2,
+	chandev_type_lcs=0x4,
+	chandev_type_osad=0x8,
+	chandev_type_qeth=0x10,
+	chandev_type_claw=0x20,
 } chandev_type;
 
 typedef enum
 {
-	no_category,
-	network_device,
-	serial_device,
+	chandev_category_none,
+	chandev_category_network_device,
+	chandev_category_serial_device,
 } chandev_category;
 
+
+
+typedef struct
+{
+	int     irq;
+	u16     devno;
+	u16     cu_type;      /* control unit type */
+	u8      cu_model;     /* control unit model */
+	u16     dev_type;     /* device type */
+	u8      dev_model;    /* device model */
+	u8      pim;          /* path installed mask */
+	u8      chpid[8];     /* CHPID 0-7 (if available) */
+} chandev_subchannel_info;
+
+#define CLAW_NAMELEN 9
+/* CLAW specific parameters other drivers should ignore these fields */
+typedef struct
+{
+	
+	char	 host_name[CLAW_NAMELEN];    /* local host name */
+	char	 adapter_name[CLAW_NAMELEN]; /* workstation adapter name */
+	char	 api_type[CLAW_NAMELEN];     /* API type either TCPIP or API */
+} chandev_claw_info;
+
 /*
  * The chandev_probeinfo structure is passed to the device driver with configuration
  * info for which irq's & ports to use when attempting to probe the device.
  */
 typedef struct
 {
-        int     read_irq;
-	int     write_irq;
-	u16     read_devno;
-	u16     write_devno;
-        s16     port_protocol_no; /* -1 don't care */
+	chandev_subchannel_info read;
+	chandev_subchannel_info write;
+	chandev_subchannel_info data;
+	/* memory_usage_in_k is the suggested memory the driver should attempt to use for io */
+	/* buffers -1 means use the driver default the driver should set this field to the */
+	/* amount of memory it actually uses when returning this probeinfo to the channel */
+	/* device layer with chandev_initdevice */
+	s32     memory_usage_in_k;
+	chandev_claw_info       claw;
+	u8      data_exists; /* whether this device has a data channel */
+	u8      cu_dev_info_inconsistent; /* either ctc or we possibly had a bad sense_id */
+	u8      chpid_info_inconsistent;  /* either ctc or schib info bad */
+        s16     port_protocol_no; /* 0 by default, set specifically when forcing */
 	u8      hint_port_no;   /* lcs specific */
-	u8      max_port_no;    /* lcs specific */
+	u8      max_port_no;    /* lcs/qeth specific */
 	chandev_type chan_type;
 	u8      checksum_received_ip_pkts;
 	u8      use_hw_stats; /* where available e.g. lcs */
-	u16     cu_type;      /* control unit type */
-	u8      cu_model;     /* control unit model */
-	u16     dev_type;     /* device type */
-	u8      dev_model;    /* device model */
+	u8      device_forced; /* indicates the device hasn't been autodetected */
 	char    *parmstr;       /* driver specific parameters added by add_parms keyword */
 	/* newdevice used internally by chandev.c */
 	struct  chandev_activelist *newdevice; 
@@ -75,19 +112,21 @@
 
 typedef enum
 {
-	good=0,
-	not_oper,
-	first_msck=not_oper,
-	no_path,
-	revalidate,
-	gone,
-	last_msck,
+	chandev_status_good,
+	chandev_status_not_oper,
+	chandev_status_first_msck=chandev_status_not_oper,
+	chandev_status_no_path,
+	chandev_status_revalidate,
+	chandev_status_gone,
+	chandev_status_last_msck,
+	chandev_status_all_chans_good /* pseudo machine check to indicate all channels are healthy */
 } chandev_msck_status;
 
 typedef int (*chandev_probefunc)(chandev_probeinfo *probeinfo);
-typedef void (*chandev_shutdownfunc)(void *device);
+typedef int (*chandev_shutdownfunc)(void *device);
 typedef void (*chandev_unregfunc)(void *device);
-typedef void (*chandev_reoperfunc)(void *device,int msck_for_read_chan,chandev_msck_status prevstatus);
+typedef void (*chandev_msck_notification_func)(void *device,int msck_irq,
+chandev_msck_status prevstatus,chandev_msck_status newstatus);
 
 
 
@@ -103,7 +142,7 @@
  */
 int chandev_register_and_probe(chandev_probefunc probefunc,
 			       chandev_shutdownfunc shutdownfunc,
-			       chandev_reoperfunc reoperfunc,
+			       chandev_msck_notification_func msck_notfunc,
 			       chandev_type chan_type);
 
 /* The chandev_unregister function is typically called when a module is being removed 
@@ -117,6 +156,33 @@
 int chandev_initdevice(chandev_probeinfo *probeinfo,void *dev_ptr,u8 port_no,char *devname,
 chandev_category category,chandev_unregfunc unreg_dev);
 
+/* This function builds a device name & copies it into destnamebuff suitable for calling 
+   init_trdev or whatever & it honours the use_devno_names flag, it is used by chandev_initnetdevice 
+   setting the buildfullname flag to TRUE will cause it to always build a full unique name based 
+   on basename either honouring the chandev_use_devno_names flag if set or starting at index 
+   0 & checking the namespace of the channel device layer itself for a free index, this
+   may be useful when one doesn't have control of the name an upper layer may choose.
+   It returns NULL on error.
+*/
+char *chandev_build_device_name(chandev_probeinfo *probeinfo,char *destnamebuff,char *basename,int buildfullname);
+
+
+
+
+/* chandev_init_netdev registers with the normal network device layer */
+/* it doesn't update any of the chandev internal structures. */
+/* i.e. it is optional */
+/* it was part of chandev_initnetdevice but I separated it as */
+/* chandev_initnetdevice may make too many assumptions for some users */
+/* chandev_initnetdevice = chandev_initdevice followed by chandev_init_netdev */
+#if LINUX_VERSION_CODE>=KERNEL_VERSION(2,3,0)
+struct net_device *chandev_init_netdev(chandev_probeinfo *probeinfo,char *basename,
+struct net_device *dev, int sizeof_priv,struct net_device *(*init_netdevfunc)(struct net_device *dev, int sizeof_priv));
+#else
+struct device *chandev_init_netdev(chandev_probeinfo *probeinfo,char *basename,
+struct device *dev, int sizeof_priv,struct device *(*init_netdevfunc)(struct device *dev, int sizeof_priv));
+#endif
+
 /* chandev_initnetdevice registers a network device with the channel layer. 
  * It returns the device structure if successful,if dev=NULL it kmallocs it, 
  * On device initialisation failure it will kfree it under ALL curcumstances
@@ -148,8 +214,18 @@
 				     void (*unreg_netdevfunc)(struct device *dev));
 #endif
 
-
-
+/* chandev_add & delete model shouldn't normally be needed by drivers except if */
+/* someone is developing a driver which the channel device layer doesn't know about */
+void chandev_add_model(chandev_type chan_type,s32 cu_type,s16 cu_model,
+		       s32 dev_type,s16 dev_model,u8 max_port_no,int auto_msck_recovery,
+		        u8 default_checksum_received_ip_pkts,u8 default_use_hw_stats);
+void chandev_del_model(s32 cu_type,s16 cu_model,s32 dev_type,s16 dev_model);
+
+/* modules should use chandev_persist to see if they should stay loaded */
+/* this is useful for debugging purposes where you may wish to examine */
+/* /proc/s390dbf/ entries */
+int chandev_persist(chandev_type chan_type);
+#endif /* __S390_CHANDEV_H */
 
 
 
diff -u --recursive --new-file v2.4.7/linux/include/asm-s390/checksum.h linux/include/asm-s390/checksum.h
--- v2.4.7/linux/include/asm-s390/checksum.h	Wed Apr 11 19:02:28 2001
+++ linux/include/asm-s390/checksum.h	Wed Jul 25 14:12:02 2001
@@ -67,19 +67,26 @@
  *
  * here even more important to align src and dst on a 32-bit (or even
  * better 64-bit) boundary
+ *
+ * Copy from userspace and compute checksum.  If we catch an exception
+ * then zero the rest of the buffer.
  */
-
 extern inline unsigned int 
-csum_partial_copy_from_user(const char *src, char *dst,
-                            int len, unsigned int sum, int *errp)
+csum_partial_copy_from_user (const char *src, char *dst,
+                                          int len, unsigned int sum,
+                                          int *err_ptr)
 {
-	if (copy_from_user(dst, src, len)) {
-		*errp = -EFAULT;
-		memset(dst, 0, len);
-		return sum;
-        }
-        return csum_partial(dst, len, sum);
+	int missing;
+
+	missing = copy_from_user(dst, src, len);
+	if (missing) {
+		memset(dst + len - missing, 0, missing);
+		*err_ptr = -EFAULT;
+	}
+		
+	return csum_partial(dst, len, sum);
 }
+
 
 extern inline unsigned int
 csum_partial_copy_nocheck (const char *src, char *dst, int len, unsigned int sum)
diff -u --recursive --new-file v2.4.7/linux/include/asm-s390/current.h linux/include/asm-s390/current.h
--- v2.4.7/linux/include/asm-s390/current.h	Tue Feb 13 14:13:44 2001
+++ linux/include/asm-s390/current.h	Wed Jul 25 14:12:02 2001
@@ -20,7 +20,7 @@
         struct task_struct *current;
         __asm__("lhi   %0,-8192\n\t"
                 "nr    %0,15"
-                : "=&r" (current) );
+                : "=&r" (current) : : "cc" );
         return current;
  }
 
diff -u --recursive --new-file v2.4.7/linux/include/asm-s390/dasd.h linux/include/asm-s390/dasd.h
--- v2.4.7/linux/include/asm-s390/dasd.h	Wed Apr 11 19:02:28 2001
+++ linux/include/asm-s390/dasd.h	Sun Aug  5 13:12:41 2001
@@ -4,43 +4,39 @@
  * Bugreports.to..: <Linux390@de.ibm.com>
  * (C) IBM Corporation, IBM Deutschland Entwicklung GmbH, 1999,2000
  *
+ * This file is the interface of the DASD device driver, which is exported to user space
+ * any future changes wrt the API will result in a change of the APIVERSION reported
+ * to userspace by the DASDAPIVER-ioctl
+ *
  * History of changes (starts July 2000)
- * 02/01/01 added dynamic registration of ioctls
+ * 05/04/01 created by moving the kernel interface to drivers/s390/block/dasd_int.h
  */
 
 #ifndef DASD_H
 #define DASD_H
-
-#undef ERP_DEBUG               /* enable debug messages */
-#undef ERP_FULL_ERP            /* enable full ERP - experimental code !!!! */
-#define CONFIG_DASD_DYNAMIC
-
 #include <linux/ioctl.h>
-#include <asm/irq.h>
 
-#define IOCTL_LETTER 'D'
-/* Disable the volume (for Linux) */
-#define BIODASDDISABLE _IO(IOCTL_LETTER,0) 
-/* Enable the volume (for Linux) */
-#define BIODASDENABLE  _IO(IOCTL_LETTER,1) 
-/* Issue a reserve/release command, rsp. */
-#define BIODASDRSRV    _IO(IOCTL_LETTER,2) /* reserve */
-#define BIODASDRLSE    _IO(IOCTL_LETTER,3) /* release */
-#define BIODASDSLCK    _IO(IOCTL_LETTER,4) /* steal lock */
-/* Read sense ID infpormation */
-#define BIODASDRSID    _IOR(IOCTL_LETTER,0,senseid_t)
-/* Format the volume or an extent */
-#define BIODASDFORMAT  _IOW(IOCTL_LETTER,0,format_data_t) 
-/* translate blocknumber of partition to absolute */
-#define BIODASDRWTB    _IOWR(IOCTL_LETTER,0,int)
+#define DASD_IOCTL_LETTER 'D'
 
-typedef int(*dasd_ioctl_fn_t) (struct inode *inp, int no, long args);
-int dasd_ioctl_no_register(int no, dasd_ioctl_fn_t handler);
-int dasd_ioctl_no_unregister(int no, dasd_ioctl_fn_t handler);
+#if (DASD_API_VERSION == 0)
 
-#define DASD_NAME "dasd"
 #define DASD_PARTN_BITS 2
-#define DASD_PER_MAJOR ( 1U<<(MINORBITS-DASD_PARTN_BITS))
+
+/* 
+ * struct profile_info_t
+ * holds the profinling information 
+ */
+typedef struct dasd_profile_info_t {
+        unsigned int dasd_io_reqs;	 /* number of requests processed at all */
+        unsigned int dasd_io_sects;	 /* number of sectors processed at all */
+        unsigned int dasd_io_secs[32];	 /* histogram of request's sizes */
+        unsigned int dasd_io_times[32];	 /* histogram of requests's times */
+        unsigned int dasd_io_timps[32];	 /* histogram of requests's times per sector */
+        unsigned int dasd_io_time1[32];	 /* histogram of time from build to start */
+        unsigned int dasd_io_time2[32];	 /* histogram of time from start to irq */
+        unsigned int dasd_io_time2ps[32]; /* histogram of time from start to irq */
+        unsigned int dasd_io_time3[32];	 /* histogram of time from irq to end */
+} dasd_profile_info_t;
 
 /* 
  * struct format_data_t
@@ -50,334 +46,65 @@
 	int start_unit; /* from track */
 	int stop_unit;  /* to track */
 	int blksize;    /* sectorsize */
-        int intensity;  /* 0: normal, 1:record zero, 3:home address, 4 invalidate tracks */
-} __attribute__ ((packed)) format_data_t;
-
-#define DASD_FORMAT_DEFAULT_START_UNIT 0
-#define DASD_FORMAT_DEFAULT_STOP_UNIT -1
-#define DASD_FORMAT_DEFAULT_BLOCKSIZE -1
-#define DASD_FORMAT_DEFAULT_INTENSITY -1
-
-#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/version.h>
-#include <linux/major.h>
-#include <linux/wait.h>
-#include <asm/ccwcache.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>
+        int intensity;  
+} format_data_t;
 
-#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,
-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;
-	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 IRQ0x%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;
+/*
+ * values to be used for format_data_t.intensity
+ * 0/8: normal format
+ * 1/9: also write record zero
+ * 3/11: also write home address
+ * 4/12: invalidate track
+ */
+#define DASD_FMT_INT_FMT_R0 1 /* write record zero */
+#define DASD_FMT_INT_FMT_HA 2 /* write home address, also set FMT_R0 ! */
+#define DASD_FMT_INT_INVAL  4 /* invalidate tracks */
+#define DASD_FMT_INT_COMPAT 8 /* use OS/390 compatible disk layout */
 
 /* 
- * 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 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 *);
-
-
-/*
- * 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++
+ * struct dasd_information_t
+ * represents any data about the data, which is visible to userspace
  */
-typedef struct dasd_discipline_t {
-	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_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;
-	
-	struct dasd_discipline_t *next;	/* used for list of disciplines */
-} dasd_discipline_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_profile_info_t {
-        unsigned long dasd_io_reqs;	/* number of requests processed at all */
-        unsigned long dasd_io_secs[32];	/* histogram of request's sizes */
-        unsigned long dasd_io_times[32];	/* histogram of requests's times */
-        unsigned long dasd_io_timps[32];	/* histogram of requests's times per sector */
-        unsigned long dasd_io_time1[32];	/* histogram of time from build to start */
-       unsigned  long dasd_io_time2[32];	/* histogram of time from start to irq */
-        unsigned long dasd_io_time2ps[32];	/* histogram of time from start to irq */
-        unsigned long dasd_io_time3[32];	/* histogram of time from irq to end */
-} dasd_profile_info_t;
-
-typedef struct dasd_device_t {
-	s390_dev_info_t devinfo;
-	dasd_discipline_t *discipline;
-	int level;
-        int 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;
-        struct proc_dir_entry *proc_dir; /* directory node */
-        struct proc_dir_entry *proc_info; /* information from dasd_device_t */
-        struct proc_dir_entry *proc_stats; /* statictics information */
-}  dasd_device_t;
-
-/* dasd_device_t.level can be: */
-#define DASD_DEVICE_LEVEL_UNKNOWN 0x00
-#define DASD_DEVICE_LEVEL_RECOGNIZED 0x01
-#define DASD_DEVICE_LEVEL_ANALYSIS_PENDING 0x02
-#define DASD_DEVICE_LEVEL_ANALYSIS_PREPARED 0x04
-#define DASD_DEVICE_LEVEL_ANALYSED 0x08
-#define DASD_DEVICE_LEVEL_ONLINE 0x10
-
-int dasd_init (void);
-void dasd_discipline_enq (dasd_discipline_t *);
-int dasd_discipline_deq(dasd_discipline_t *);
-int dasd_start_IO (ccw_req_t *);
-void dasd_int_handler (int , void *, struct pt_regs *);
-ccw_req_t *default_erp_action (ccw_req_t *);
-ccw_req_t *default_erp_postaction (ccw_req_t *);
-int dasd_chanq_deq (dasd_chanq_t *, ccw_req_t *);
-ccw_req_t *dasd_alloc_request (char *, int, int);
-void dasd_free_request (ccw_req_t *);
-extern int (*genhd_dasd_name) (char *, int, int, struct gendisk *);
-extern int (*genhd_dasd_fillgeo) (int, struct hd_geometry *);
-int dasd_oper_handler (int irq, devreg_t * devreg);
-void dasd_schedule_bh (dasd_device_t *);
-
-debug_info_t *dasd_debug_area;
-
-#endif /* __KERNEL__ */
+typedef struct dasd_information_t {
+        unsigned int devno; /* S/390 devno */
+        unsigned int real_devno; /* for aliases */
+        unsigned int schid; /* S/390 subchannel identifier */
+        unsigned int cu_type  : 16; /* from SenseID */
+        unsigned int cu_model :  8; /* from SenseID */
+        unsigned int dev_type : 16; /* from SenseID */
+        unsigned int dev_model : 8; /* from SenseID */
+        unsigned int open_count; 
+        unsigned int req_queue_len; 
+        unsigned int chanq_len;
+        char type[4]; /* from discipline.name, 'none' for unknown */
+        unsigned int status; /* current device level */
+        unsigned int label_block; /* where to find the VOLSER */
+        unsigned int FBA_layout; /* fixed block size (like AIXVOL) */
+        unsigned int characteristics_size;
+        unsigned int confdata_size;
+        char characteristics[64]; /* from read_device_characteristics */
+        char configuration_data[256]; /* from read_configuration_data */
+} dasd_information_t;
 
+/* Disable the volume (for Linux) */
+#define BIODASDDISABLE _IO(DASD_IOCTL_LETTER,0) 
+/* Enable the volume (for Linux) */
+#define BIODASDENABLE  _IO(DASD_IOCTL_LETTER,1)  
+/* Issue a reserve/release command, rsp. */
+#define BIODASDRSRV    _IO(DASD_IOCTL_LETTER,2) /* reserve */
+#define BIODASDRLSE    _IO(DASD_IOCTL_LETTER,3) /* release */
+#define BIODASDSLCK    _IO(DASD_IOCTL_LETTER,4) /* steal lock */
+/* reset profiling information of a device */
+#define BIODASDPRRST   _IO(DASD_IOCTL_LETTER,5)
+/* retrieve API version number */
+#define DASDAPIVER     _IOR(DASD_IOCTL_LETTER,0,int)
+/* Get information on a dasd device */
+#define BIODASDINFO    _IOR(DASD_IOCTL_LETTER,1,dasd_information_t)
+/* retrieve profiling information of a device */
+#define BIODASDPRRD    _IOR(DASD_IOCTL_LETTER,2,dasd_profile_info_t)
+/* #define BIODASDFORMAT  _IOW(IOCTL_LETTER,0,format_data_t) , deprecated */
+#define BIODASDFMT     _IOW(DASD_IOCTL_LETTER,1,format_data_t) 
+#endif /* DASD_API_VERSION */
 #endif				/* DASD_H */
 
 /*
diff -u --recursive --new-file v2.4.7/linux/include/asm-s390/debug.h linux/include/asm-s390/debug.h
--- v2.4.7/linux/include/asm-s390/debug.h	Wed Apr 11 19:02:28 2001
+++ linux/include/asm-s390/debug.h	Wed Jul 25 14:12:02 2001
@@ -53,7 +53,7 @@
 #define DEBUG_DATA(entry) (char*)(entry + 1) /* data is stored behind */
                                              /* the entry information */
 
-#define STCK(x)	asm volatile ("STCK %0":"=m" (x))
+#define STCK(x)	asm volatile ("STCK %0" : "=m" (x) : : "cc" )
 
 typedef struct __debug_entry debug_entry_t;
 
diff -u --recursive --new-file v2.4.7/linux/include/asm-s390/div64.h linux/include/asm-s390/div64.h
--- v2.4.7/linux/include/asm-s390/div64.h	Wed Apr 11 19:02:28 2001
+++ linux/include/asm-s390/div64.h	Wed Jul 25 14:12:02 2001
@@ -36,7 +36,7 @@
 	     "1: st   1,4+%1\n"					\
              "   lr   %0,0"					\
 	     : "=d" (__r), "+m" (__n)				\
-	     : "d" (base) : "0", "1", "2" );			\
+	     : "d" (base) : "0", "1", "2", "cc" );		\
 	(n) = (__n);						\
         __r;                                                    \
 })
diff -u --recursive --new-file v2.4.7/linux/include/asm-s390/hardirq.h linux/include/asm-s390/hardirq.h
--- v2.4.7/linux/include/asm-s390/hardirq.h	Tue Feb 13 14:13:44 2001
+++ linux/include/asm-s390/hardirq.h	Wed Jul 25 14:12:02 2001
@@ -17,44 +17,28 @@
 #include <asm/lowcore.h>
 #include <linux/sched.h>
 
-/* No irq_cpustat_t for s390, the data is held directly in S390_lowcore */
+/* entry.S is sensitive to the offsets of these fields */
+typedef struct {
+	unsigned int __softirq_pending;
+	unsigned int __local_irq_count;
+	unsigned int __local_bh_count;
+	unsigned int __syscall_count;
+	struct task_struct * __ksoftirqd_task; /* waitqueue is too large */
+} ____cacheline_aligned irq_cpustat_t;
 
-/*
- * Simple wrappers reducing source bloat.  S390 specific because each
- * cpu stores its data in S390_lowcore (PSA) instead of using a cache
- * aligned array element like most architectures.
- */
-
-#ifdef CONFIG_SMP
-
-#define softirq_active(cpu)	(safe_get_cpu_lowcore(cpu).__softirq_active)
-#define softirq_mask(cpu)	(safe_get_cpu_lowcore(cpu).__softirq_mask)
-#define local_irq_count(cpu)	(safe_get_cpu_lowcore(cpu).__local_irq_count)
-#define local_bh_count(cpu)	(safe_get_cpu_lowcore(cpu).__local_bh_count)
-#define syscall_count(cpu)	(safe_get_cpu_lowcore(cpu).__syscall_count)
-
-#else	/* CONFIG_SMP */
-
-/* Optimize away the cpu calculation, it is always current PSA */
-#define softirq_active(cpu)	((void)(cpu), S390_lowcore.__softirq_active)
-#define softirq_mask(cpu)	((void)(cpu), S390_lowcore.__softirq_mask)
-#define local_irq_count(cpu)	((void)(cpu), S390_lowcore.__local_irq_count)
-#define local_bh_count(cpu)	((void)(cpu), S390_lowcore.__local_bh_count)
-#define syscall_count(cpu)	((void)(cpu), S390_lowcore.__syscall_count)
-
-#endif	/* CONFIG_SMP */
+#include <linux/irq_cpustat.h>	/* Standard mappings for irq_cpustat_t above */
 
 /*
  * Are we in an interrupt context? Either doing bottom half
  * or hardware interrupt processing?
- * Special definitions for s390, always access current PSA.
  */
-#define in_interrupt() ((S390_lowcore.__local_irq_count + S390_lowcore.__local_bh_count) != 0)
-  
-#define in_irq() (S390_lowcore.__local_irq_count != 0)
+#define in_interrupt() ({ int __cpu = smp_processor_id(); \
+	(local_irq_count(__cpu) + local_bh_count(__cpu) != 0); })
+
+#define in_irq() (local_irq_count(smp_processor_id()) != 0)
   
 #ifndef CONFIG_SMP
-  
+
 #define hardirq_trylock(cpu)	(local_irq_count(cpu) == 0)
 #define hardirq_endlock(cpu)	do { } while (0)
   
@@ -63,7 +47,7 @@
 
 #define synchronize_irq()	do { } while (0)
 
-#else
+#else	/* CONFIG_SMP */
 
 #include <asm/atomic.h>
 #include <asm/smp.h>
@@ -77,7 +61,7 @@
 	/* if we didn't own the irq lock, just ignore.. */
 	if (atomic_read(&global_irq_holder) ==  cpu) {
 		atomic_set(&global_irq_holder,NO_PROC_ID);
-		clear_bit(0,&global_irq_lock);
+		atomic_set(&global_irq_lock,0);
 	}
 }
 
@@ -95,13 +79,14 @@
 
 static inline int hardirq_trylock(int cpu)
 {
-	return !atomic_read(&global_irq_count) && !test_bit(0,&global_irq_lock);
+	return !atomic_read(&global_irq_count) &&
+	       !atomic_read(&global_irq_lock);
 }
 
 #define hardirq_endlock(cpu)	do { } while (0)
 
 extern void synchronize_irq(void);
 
-#endif /* CONFIG_SMP */
+#endif	/* CONFIG_SMP */
 
 #endif /* __ASM_HARDIRQ_H */
diff -u --recursive --new-file v2.4.7/linux/include/asm-s390/idals.h linux/include/asm-s390/idals.h
--- v2.4.7/linux/include/asm-s390/idals.h	Tue Feb 13 14:13:44 2001
+++ linux/include/asm-s390/idals.h	Wed Jul 25 14:12:02 2001
@@ -10,36 +10,51 @@
 #include <linux/config.h>
 #include <asm/irq.h>
 
-typedef unsigned long idaw_t;
+#define IDA_SIZE_LOG 12 /* 11 for 2k , 12 for 4k */
+#define IDA_BLOCK_SIZE (1L<<IDA_SIZE_LOG)
 
-static inline idaw_t *
+static inline addr_t *
 idal_alloc ( int nridaws )
 {
 	if ( nridaws > 33 )
 		BUG();
-	return kmalloc(nridaws * sizeof(idaw_t), GFP_ATOMIC | GFP_DMA );
+	return kmalloc(nridaws * sizeof(addr_t), GFP_ATOMIC | GFP_DMA );
 }
 
 static inline void 
-idal_free ( idaw_t *idal )
+idal_free ( addr_t *idal )
 {
 	kfree (idal);
 }
 
+#if defined(CONFIG_ARCH_S390X)
+extern unsigned long __create_idal(unsigned long address, int count);
+#endif
+
 /*
  * Function: set_normalized_cda
  * sets the address of the data in CCW
  * if necessary it allocates an IDAL and sets sthe appropriate flags
  */
-#if defined (CONFIG_ARCH_S390X)
-extern void set_normalized_cda(ccw1_t * ccw, unsigned long address);
-#else
-static inline void
+static inline int
 set_normalized_cda(ccw1_t * ccw, unsigned long address)
 {
-	ccw->cda = address;
-}
+	int ret = 0;
+
+#if defined (CONFIG_ARCH_S390X)
+	if (((address + ccw->count) >> 31) != 0) {
+		if (ccw->flags & CCW_FLAG_IDA)
+			BUG();
+		address = __create_idal(address, ccw->count);
+		if (address)
+			ccw->flags |= CCW_FLAG_IDA;
+		else
+			ret = -ENOMEM;
+	}
 #endif
+	ccw->cda = (__u32) address;
+	return ret;
+}
 
 /*
  * Function: clear_normalized_cda
@@ -48,10 +63,12 @@
 static inline void
 clear_normalized_cda ( ccw1_t * ccw ) 
 {
+#if defined(CONFIG_ARCH_S390X)
 	if ( ccw -> flags & CCW_FLAG_IDA ) {
-		idal_free ( (idaw_t *) (ccw -> cda ));
+		idal_free ( (addr_t *)(unsigned long) (ccw -> cda ));
 		ccw -> flags &= ~CCW_FLAG_IDA;
 	}
+#endif
 	ccw -> cda = 0;
 }
 
diff -u --recursive --new-file v2.4.7/linux/include/asm-s390/init.h linux/include/asm-s390/init.h
--- v2.4.7/linux/include/asm-s390/init.h	Fri May 12 11:41:44 2000
+++ linux/include/asm-s390/init.h	Wed Jul 25 14:12:02 2001
@@ -23,7 +23,7 @@
 #define __INITDATA      .section        ".data.init",#alloc,#write
 */
 
-#define __cacheline_aligned __attribute__ ((__aligned__(16)))
+#define __cacheline_aligned __attribute__ ((__aligned__(256)))
 
 #endif
 
diff -u --recursive --new-file v2.4.7/linux/include/asm-s390/io.h linux/include/asm-s390/io.h
--- v2.4.7/linux/include/asm-s390/io.h	Tue Feb 13 14:13:44 2001
+++ linux/include/asm-s390/io.h	Wed Jul 25 14:12:02 2001
@@ -31,7 +31,7 @@
                  "   jz     0f\n"
                  "   sr     %0,%0\n"
                  "0:"
-                 : "=a" (real_address) : "a" (address) );
+                 : "=a" (real_address) : "a" (address) : "cc" );
         return real_address;
 }
 
diff -u --recursive --new-file v2.4.7/linux/include/asm-s390/irq.h linux/include/asm-s390/irq.h
--- v2.4.7/linux/include/asm-s390/irq.h	Wed Apr 11 19:02:28 2001
+++ linux/include/asm-s390/irq.h	Wed Jul 25 14:12:02 2001
@@ -572,6 +572,10 @@
 extern int set_cons_dev(int irq);
 extern int reset_cons_dev(int irq);
 extern int wait_cons_dev(int irq);
+extern schib_t *s390_get_schib( int irq );
+
+extern int s390_register_adapter_interrupt(adapter_int_handler_t handler);
+extern int s390_unregister_adapter_interrupt(adapter_int_handler_t handler);
 
 /*
  * Some S390 specific IO instructions as inline
diff -u --recursive --new-file v2.4.7/linux/include/asm-s390/lowcore.h linux/include/asm-s390/lowcore.h
--- v2.4.7/linux/include/asm-s390/lowcore.h	Fri Mar  2 11:12:06 2001
+++ linux/include/asm-s390/lowcore.h	Wed Jul 25 14:12:02 2001
@@ -42,12 +42,13 @@
 #define __LC_SAVE_AREA                  0xC00
 #define __LC_KERNEL_STACK               0xC40
 #define __LC_KERNEL_LEVEL               0xC44
-#define __LC_IRQ_STAT                   0xC48
 #define __LC_CPUID                      0xC60
 #define __LC_CPUADDR                    0xC68
 #define __LC_IPLDEV                     0xC7C
 #define __LC_PANIC_MAGIC                0xE00
 
+#define __LC_PFAULT_INTPARM             0x080
+
 /* interrupt handler start with all io, external and mcck interrupt disabled */
 
 #define _RESTART_PSW_MASK    0x00080000
@@ -148,13 +149,7 @@
 	__u32        kernel_stack;             /* 0xc40 */
 	__u32        kernel_level;             /* 0xc44 */
 	/* entry.S sensitive area start */
-	/* Next 6 words are the s390 equivalent of irq_stat */
-	__u32        __softirq_active;         /* 0xc48 */
-	__u32        __softirq_mask;           /* 0xc4c */
-	__u32        __local_irq_count;        /* 0xc50 */
-	__u32        __local_bh_count;         /* 0xc54 */
-	__u32        __syscall_count;          /* 0xc58 */
-	__u8         pad10[0xc60-0xc5c];       /* 0xc5c */
+	__u8         pad10[0xc60-0xc48];       /* 0xc5c */
 	struct       cpuinfo_S390 cpu_data;    /* 0xc60 */
 	__u32        ipl_device;               /* 0xc7c */
 	/* entry.S sensitive area end */
diff -u --recursive --new-file v2.4.7/linux/include/asm-s390/page.h linux/include/asm-s390/page.h
--- v2.4.7/linux/include/asm-s390/page.h	Wed Apr 11 19:02:28 2001
+++ linux/include/asm-s390/page.h	Wed Jul 25 14:12:02 2001
@@ -28,7 +28,7 @@
 	rp.subreg.odd = (unsigned long) 4096;
         asm volatile ("   slr  1,1\n"
 		      "   mvcl %0,0"
-		      : "+&a" (rp) : : "memory", "1" );
+		      : "+&a" (rp) : : "memory", "cc", "1" );
 }
 
 static inline void copy_page(void *to, void *from)
@@ -37,7 +37,7 @@
 		asm volatile ("   sr   0,0\n"
 			      "   mvpg %0,%1"
 			      : : "a" ((void *)(to)), "a" ((void *)(from))
-			      : "memory", "0" );
+			      : "memory", "cc", "0" );
 	else
 		asm volatile ("   mvc  0(256,%0),0(%1)\n"
 			      "   mvc  256(256,%0),256(%1)\n"
diff -u --recursive --new-file v2.4.7/linux/include/asm-s390/pgtable.h linux/include/asm-s390/pgtable.h
--- v2.4.7/linux/include/asm-s390/pgtable.h	Tue Feb 13 14:13:44 2001
+++ linux/include/asm-s390/pgtable.h	Wed Jul 25 14:12:02 2001
@@ -345,7 +345,7 @@
 
 extern inline pte_t pte_mkold(pte_t pte)
 {
-	asm volatile ("rrbe 0,%0" : : "a" (pte_val(pte)));
+	asm volatile ("rrbe 0,%0" : : "a" (pte_val(pte)) : "cc" );
 	return pte;
 }
 
@@ -364,7 +364,8 @@
 
 	asm volatile ("rrbe 0,%1\n\t"
 		      "ipm  %0\n\t"
-		      "srl  %0,28\n\t" : "=d" (ccode) : "a" (pte_val(*ptep)));
+		      "srl  %0,28\n\t" 
+                      : "=d" (ccode) : "a" (pte_val(*ptep)) : "cc" );
 	return ccode & 2;
 }
 
diff -u --recursive --new-file v2.4.7/linux/include/asm-s390/processor.h linux/include/asm-s390/processor.h
--- v2.4.7/linux/include/asm-s390/processor.h	Tue Feb 13 14:13:44 2001
+++ linux/include/asm-s390/processor.h	Wed Jul 25 14:12:02 2001
@@ -87,8 +87,10 @@
         /* perform syscall argument validation (get/set_fs) */
         mm_segment_t fs;
         per_struct per_info;/* Must be aligned on an 4 byte boundary*/
-	addr_t  ieee_instruction_pointer; 
 	/* Used to give failing instruction back to user for ieee exceptions */
+	addr_t  ieee_instruction_pointer; 
+        /* pfault_wait is used to block the process on a pfault event */
+	addr_t  pfault_wait;
 };
 
 typedef struct thread_struct thread_struct;
@@ -105,7 +107,8 @@
               (__pa((__u32) &swapper_pg_dir[0]) + _SEGMENT_TABLE),\
                      0,0,0,                                       \
                      (mm_segment_t) { 0,1},                       \
-                     (per_struct) {{{{0,}}},0,0,0,0,{{0,}}}       \
+                     (per_struct) {{{{0,}}},0,0,0,0,{{0,}}},      \
+                     0, 0                                         \
 }
 
 /* need to define ... */
@@ -196,7 +199,7 @@
                       "    stctl 0,15,0x1c0\n" /* store control registers */
                       "    oi    0(%1),0x10\n" /* fake protection bit */
                       "    lpsw 0(%0)"
-                      : : "a" (dw_psw), "a" (&ctl_buf));
+                      : : "a" (dw_psw), "a" (&ctl_buf) : "cc" );
 }
 
 #endif                                 /* __ASM_S390_PROCESSOR_H           */
diff -u --recursive --new-file v2.4.7/linux/include/asm-s390/queue.h linux/include/asm-s390/queue.h
--- v2.4.7/linux/include/asm-s390/queue.h	Wed Apr 11 19:02:28 2001
+++ linux/include/asm-s390/queue.h	Wed Jul 25 14:12:02 2001
@@ -7,7 +7,8 @@
  *
  *  A little set of queue utilies.
  */
-
+#ifndef __ASM_QUEUE_H
+#define __ASM_QUEUE_H
 #include <linux/stddef.h>
 
 typedef struct queue
@@ -29,12 +30,11 @@
 }
 
 static __inline__ void enqueue_tail(qheader *qhead,queue *member)
-{
-	queue *tail=qhead->tail;
-	member->next=NULL;
-	
+{	
 	if(member)
 	{
+		queue *tail=qhead->tail;
+
 		if(tail)
 			tail->next=member;
 		else
@@ -166,5 +166,5 @@
 	return(0);
 }
 
-
+#endif /* __ASM_QUEUE_H */
 
diff -u --recursive --new-file v2.4.7/linux/include/asm-s390/s390dyn.h linux/include/asm-s390/s390dyn.h
--- v2.4.7/linux/include/asm-s390/s390dyn.h	Wed Apr 11 19:02:28 2001
+++ linux/include/asm-s390/s390dyn.h	Wed Jul 25 14:12:02 2001
@@ -37,11 +37,14 @@
 	oper_handler_func_t  oper_func;
 } devreg_t;
 
-#define DEVREG_EXACT_MATCH      0x00000001
-#define DEVREG_MATCH_DEV_TYPE   0x00000002
-#define DEVREG_MATCH_CU_TYPE    0x00000004
-#define DEVREG_NO_CU_INFO       0x00000008
-#define DEVREG_NO_DEV_INFO      0x00000010
+#define DEVREG_MATCH_CU_TYPE    0x00000001
+#define DEVREG_MATCH_CU_MODEL   0x00000002
+#define DEVREG_MATCH_DEV_TYPE   0x00000004
+#define DEVREG_MATCH_DEV_MODEL  0x00000008
+
+#define DEVREG_EXACT_MATCH      (DEVREG_MATCH_CU_TYPE|DEVREG_MATCH_CU_MODEL|DEVREG_MATCH_DEV_TYPE|DEVREG_MATCH_DEV_MODEL)
+#define DEVREG_NO_CU_INFO       (DEVREG_MATCH_DEV_TYPE|DEVREG_MATCH_DEV_MODEL)
+#define DEVREG_NO_DEV_INFO      (DEVREG_MATCH_CU_TYPE|DEVREG_MATCH_CU_MODEL)
 
 #define DEVREG_TYPE_DEVNO       0x80000000
 #define DEVREG_TYPE_DEVCHARS    0x40000000
diff -u --recursive --new-file v2.4.7/linux/include/asm-s390/setup.h linux/include/asm-s390/setup.h
--- v2.4.7/linux/include/asm-s390/setup.h	Wed Apr 11 19:02:28 2001
+++ linux/include/asm-s390/setup.h	Wed Jul 25 14:12:02 2001
@@ -31,6 +31,22 @@
 #define MACHINE_HAS_CSP  (machine_flags & 8)
 #define MACHINE_HAS_MVPG (machine_flags & 16)
 
+#define MACHINE_HAS_HWC  (!MACHINE_IS_P390)
+
+/*
+ * Console mode. Override with conmode=
+ */
+extern unsigned int console_mode;
+extern unsigned int console_device;
+
+#define CONSOLE_IS_UNDEFINED	(console_mode == 0)
+#define CONSOLE_IS_HWC		(console_mode == 1)
+#define CONSOLE_IS_3215		(console_mode == 2)
+#define CONSOLE_IS_3270		(console_mode == 3)
+#define SET_CONSOLE_HWC		do { console_mode = 1; } while (0)
+#define SET_CONSOLE_3215	do { console_mode = 2; } while (0)
+#define SET_CONSOLE_3270	do { console_mode = 3; } while (0)
+
 #else 
 
 #define IPL_DEVICE        0x10404
diff -u --recursive --new-file v2.4.7/linux/include/asm-s390/softirq.h linux/include/asm-s390/softirq.h
--- v2.4.7/linux/include/asm-s390/softirq.h	Fri Aug  4 16:15:37 2000
+++ linux/include/asm-s390/softirq.h	Wed Jul 25 14:12:02 2001
@@ -17,11 +17,28 @@
 #include <asm/hardirq.h>
 #include <asm/lowcore.h>
 
-#define cpu_bh_disable(cpu)	do { local_bh_count(cpu)++; barrier(); } while (0)
-#define cpu_bh_enable(cpu)	do { barrier(); local_bh_count(cpu)--; } while (0)
+#define local_bh_disable()			\
+do {						\
+	local_bh_count(smp_processor_id())++;	\
+	barrier();				\
+} while (0)
 
-#define local_bh_disable()	cpu_bh_disable(smp_processor_id())
-#define local_bh_enable()	cpu_bh_enable(smp_processor_id())
+#define __local_bh_enable()			\
+do {						\
+	barrier();				\
+	local_bh_count(smp_processor_id())--;	\
+} while (0)
+
+#define local_bh_enable()				\
+do {							\
+	if (!--local_bh_count(smp_processor_id())	\
+	    && softirq_pending(smp_processor_id())) {	\
+		do_softirq();				\
+		__sti();				\
+	}						\
+} while (0)
+
+#define __cpu_raise_softirq(cpu, nr) (softirq_pending(cpu) |= (1<<nr))
 
 #define in_softirq() (local_bh_count(smp_processor_id()) != 0)
 
diff -u --recursive --new-file v2.4.7/linux/include/asm-s390/system.h linux/include/asm-s390/system.h
--- v2.4.7/linux/include/asm-s390/system.h	Wed Apr 11 19:02:28 2001
+++ linux/include/asm-s390/system.h	Wed Jul 25 14:12:02 2001
@@ -61,7 +61,7 @@
                                 "   jl    1b\n"
                                 "   ex    0,4(2)"     /* store *ptr to x */
                                 : "+a&" (ptr) : "a" (&x)
-                                : "memory", "0", "1", "2");
+                                : "memory", "cc", "0", "1", "2");
 			break;
                 case 2:
                         if(((__u32)ptr)&1)
@@ -84,7 +84,7 @@
                                 "   jl    1b\n"
                                 "   ex    0,4(2)"     /* store *ptr to x */
                                 : "+a&" (ptr) : "a" (&x)
-                                : "memory", "0", "1", "2");
+                                : "memory", "cc", "0", "1", "2");
                         break;
                 case 4:
                         if(((__u32)ptr)&3)
@@ -95,7 +95,7 @@
                                 "    jl  0b\n"
                                 "    lr  %0,0\n"
                                 : "+d&" (x) : "a" (ptr)
-                                : "memory", "0" );
+                                : "memory", "cc", "0" );
                         break;
                default:
                         abort();
@@ -149,7 +149,7 @@
         __asm__ __volatile__("ssm   %0" : : "m" (x) : "memory")
 
 #define __load_psw(psw) \
-	__asm__ __volatile__("lpsw %0" : : "m" (psw));
+	__asm__ __volatile__("lpsw %0" : : "m" (psw) : "cc" );
 
 #define __ctl_load(array, low, high) ({ \
 	__asm__ __volatile__ ( \
@@ -185,7 +185,7 @@
                 "    st    0,0(1)\n" \
                 "1:  ex    %1,4(2)"      /* execute lctl */ \
                 : "=m" (dummy) : "a" (cr*17), "a" (1<<(bit)) \
-                : "0", "1", "2"); \
+                : "cc", "0", "1", "2"); \
         })
 
 #define __ctl_clear_bit(cr, bit) ({ \
@@ -204,7 +204,7 @@
                 "    st    0,0(1)\n" \
                 "1:  ex    %1,4(2)"      /* execute lctl */ \
                 : "=m" (dummy) : "a" (cr*17), "a" (~(1<<(bit))) \
-                : "0", "1", "2"); \
+                : "cc", "0", "1", "2"); \
         })
 
 /* For spinlocks etc */
diff -u --recursive --new-file v2.4.7/linux/include/asm-s390/uaccess.h linux/include/asm-s390/uaccess.h
--- v2.4.7/linux/include/asm-s390/uaccess.h	Wed Apr 11 19:02:28 2001
+++ linux/include/asm-s390/uaccess.h	Wed Jul 25 14:12:02 2001
@@ -102,7 +102,7 @@
 				".previous"
                                 : "=m" (*((__u32*) ptr)) , "=&d" (err)
                                 : "d" (x), "K" (-EFAULT)
-                                : "4" );
+                                : "cc", "4" );
         return err;
 }
 
@@ -130,7 +130,7 @@
 				".previous"
                                 : "=m" (*((__u16*) ptr)) , "=&d" (err)
                                 : "d" (x), "K" (-EFAULT)
-                                : "4" );
+                                : "cc", "4" );
         return err;
 }
 
@@ -158,7 +158,7 @@
 				".previous"
                                 : "=m" (*((__u8*) ptr)) , "=&d" (err)
                                 : "d" (x), "K" (-EFAULT)
-                                : "4" );
+                                : "cc", "4" );
         return err;
 }
 
@@ -223,7 +223,7 @@
                                 ".previous"                                \
                                 : "=d" (x) , "=&d" (err)                   \
                                 : "m" (*(const __u32*)(ptr)),"K" (-EFAULT) \
-                                : "4" );                                   \
+                                : "cc", "4" );                             \
 })
 
 #define __get_user_asm_2(x, ptr, err)                                      \
@@ -248,7 +248,7 @@
                                 ".previous"                                \
                                 : "=d" (x) , "=&d" (err)                   \
                                 : "m" (*(const __u16*)(ptr)),"K" (-EFAULT) \
-                                : "4" );                                   \
+                                : "cc", "4" );                             \
 })
 
 #define __get_user_asm_1(x, ptr, err)                                     \
@@ -274,7 +274,7 @@
                                 ".previous"                               \
                                 : "=d" (x) , "=&d" (err)                  \
                                 : "m" (*(const __u8*)(ptr)),"K" (-EFAULT) \
-                                : "4" );                                  \
+                                : "cc", "4" );                            \
 })
 
 #define __get_user(x, ptr)                                      \
@@ -340,7 +340,7 @@
 				"   .long  0b,__copy_to_user_fixup\n"
 				".previous"
                                 : "+&d" (n) : "d" (to), "d" (from)
-                                : "2", "3", "4", "5" );
+                                : "cc", "2", "3", "4", "5" );
         return n;
 }
 
@@ -378,7 +378,7 @@
 				"   .long  0b,__copy_from_user_fixup\n"
 				".previous"
                                 : "+&d" (n) : "d" (to), "d" (from)
-                                : "2", "3", "4", "5" );
+                                : "cc", "2", "3", "4", "5" );
         return n;
 }
 
@@ -436,7 +436,7 @@
                                 : "=&a" (len)
                                 : "a" (dst), "d" (src), "d" (count),
                                   "K" (-EFAULT)
-                                : "2", "3", "4", "memory" );
+                                : "2", "3", "4", "memory", "cc" );
         return len;
 }
 
diff -u --recursive --new-file v2.4.7/linux/include/asm-s390/vtoc.h linux/include/asm-s390/vtoc.h
--- v2.4.7/linux/include/asm-s390/vtoc.h	Wed Apr 11 19:02:28 2001
+++ linux/include/asm-s390/vtoc.h	Sun Aug  5 13:12:41 2001
@@ -15,41 +15,188 @@
 #include <linux/types.h>
 #include <linux/hdreg.h>
 #include <linux/version.h>
-#endif
 #include <asm/dasd.h>
+#endif
+
+#define DASD_API_VERSION 0
 
 #define LINE_LENGTH 80
 #define VTOC_START_CC 0x0
 #define VTOC_START_HH 0x1
+#define FIRST_USABLE_CYL 1
+#define FIRST_USABLE_TRK 2
+
+#define DASD_3380_TYPE 13148
+#define DASD_3390_TYPE 13200
+#define DASD_9345_TYPE 37701
+
+#define DASD_3380_VALUE 0xbb60
+#define DASD_3390_VALUE 0xe5a2
+#define DASD_9345_VALUE 0xbc98
+
+#define VOLSER_LENGTH 6
+#define BIG_DISK_SIZE 0x10000
+
+#define VTOC_ERROR "VTOC error:"
 
 enum failure {unable_to_open,
 	      unable_to_seek,
 	      unable_to_write,
 	      unable_to_read};
 
-typedef struct ttr {
+unsigned char ASCtoEBC[256] =
+{
+  /*00  NL    SH    SX    EX    ET    NQ    AK    BL */
+  0x00, 0x01, 0x02, 0x03, 0x37, 0x2D, 0x2E, 0x2F,
+  /*08  BS    HT    LF    VT    FF    CR    SO    SI */
+  0x16, 0x05, 0x15, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F,
+  /*10  DL    D1    D2    D3    D4    NK    SN    EB */
+  0x10, 0x11, 0x12, 0x13, 0x3C, 0x15, 0x32, 0x26,
+  /*18  CN    EM    SB    EC    FS    GS    RS    US */
+  0x18, 0x19, 0x3F, 0x27, 0x1C, 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, 0xAD, 0xE0, 0xBD, 0x5F, 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,
+  0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F,
+  0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F,
+  0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F,
+  0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F,
+  0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F,
+  0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F,
+  0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F,
+  0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F,
+  0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F,
+  0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F,
+  0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F,
+  0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F,
+  0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F,
+  0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F,
+  0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F,
+  0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0xFF
+};
+
+
+unsigned char EBCtoASC[256] =
+{
+ /* 0x00   NUL   SOH   STX   ETX  *SEL    HT  *RNL   DEL */
+          0x00, 0x01, 0x02, 0x03, 0x07, 0x09, 0x07, 0x7F,
+ /* 0x08   -GE  -SPS  -RPT    VT    FF    CR    SO    SI */
+          0x07, 0x07, 0x07, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F,
+ /* 0x10   DLE   DC1   DC2   DC3  -RES   -NL    BS  -POC
+                                  -ENP  ->LF             */
+          0x10, 0x11, 0x12, 0x13, 0x07, 0x0A, 0x08, 0x07,
+ /* 0x18   CAN    EM  -UBS  -CU1  -IFS  -IGS  -IRS  -ITB
+                                                    -IUS */
+          0x18, 0x19, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07,
+ /* 0x20   -DS  -SOS    FS  -WUS  -BYP    LF   ETB   ESC
+                                  -INP                   */
+          0x07, 0x07, 0x1C, 0x07, 0x07, 0x0A, 0x17, 0x1B,
+ /* 0x28   -SA  -SFE   -SM  -CSP  -MFA   ENQ   ACK   BEL
+                       -SW                               */ 
+          0x07, 0x07, 0x07, 0x07, 0x07, 0x05, 0x06, 0x07,
+ /* 0x30  ----  ----   SYN   -IR   -PP  -TRN  -NBS   EOT */
+          0x07, 0x07, 0x16, 0x07, 0x07, 0x07, 0x07, 0x04,
+ /* 0x38  -SBS   -IT  -RFF  -CU3   DC4   NAK  ----   SUB */
+          0x07, 0x07, 0x07, 0x07, 0x14, 0x15, 0x07, 0x1A,
+ /* 0x40    SP   RSP           ä              ----       */
+          0x20, 0xFF, 0x83, 0x84, 0x85, 0xA0, 0x07, 0x86,
+ /* 0x48                       .     <     (     +     | */
+          0x87, 0xA4, 0x9B, 0x2E, 0x3C, 0x28, 0x2B, 0x7C,
+ /* 0x50     &                                      ---- */
+          0x26, 0x82, 0x88, 0x89, 0x8A, 0xA1, 0x8C, 0x07,
+ /* 0x58           ß     !     $     *     )     ;       */
+          0x8D, 0xE1, 0x21, 0x24, 0x2A, 0x29, 0x3B, 0xAA,
+ /* 0x60     -     /  ----     Ä  ----  ----  ----       */
+          0x2D, 0x2F, 0x07, 0x8E, 0x07, 0x07, 0x07, 0x8F,
+ /* 0x68              ----     ,     %     _     >     ? */ 
+          0x80, 0xA5, 0x07, 0x2C, 0x25, 0x5F, 0x3E, 0x3F,
+ /* 0x70  ----        ----  ----  ----  ----  ----  ---- */
+          0x07, 0x90, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07,
+ /* 0x78     *     `     :     #     @     '     =     " */
+          0x70, 0x60, 0x3A, 0x23, 0x40, 0x27, 0x3D, 0x22,
+ /* 0x80     *     a     b     c     d     e     f     g */
+          0x07, 0x61, 0x62, 0x63, 0x64, 0x65, 0x66, 0x67,
+ /* 0x88     h     i              ----  ----  ----       */
+          0x68, 0x69, 0xAE, 0xAF, 0x07, 0x07, 0x07, 0xF1,
+ /* 0x90     °     j     k     l     m     n     o     p */
+          0xF8, 0x6A, 0x6B, 0x6C, 0x6D, 0x6E, 0x6F, 0x70,
+ /* 0x98     q     r                    ----        ---- */
+          0x71, 0x72, 0xA6, 0xA7, 0x91, 0x07, 0x92, 0x07,
+ /* 0xA0           ~     s     t     u     v     w     x */
+          0xE6, 0x7E, 0x73, 0x74, 0x75, 0x76, 0x77, 0x78,
+ /* 0xA8     y     z              ----  ----  ----  ---- */
+          0x79, 0x7A, 0xAD, 0xAB, 0x07, 0x07, 0x07, 0x07,
+ /* 0xB0     ^                    ----     §  ----       */
+          0x5E, 0x9C, 0x9D, 0xFA, 0x07, 0x07, 0x07, 0xAC,
+ /* 0xB8        ----     [     ]  ----  ----  ----  ---- */
+          0xAB, 0x07, 0x5B, 0x5D, 0x07, 0x07, 0x07, 0x07,
+ /* 0xC0     {     A     B     C     D     E     F     G */
+          0x7B, 0x41, 0x42, 0x43, 0x44, 0x45, 0x46, 0x47,
+ /* 0xC8     H     I  ----           ö              ---- */
+          0x48, 0x49, 0x07, 0x93, 0x94, 0x95, 0xA2, 0x07,
+ /* 0xD0     }     J     K     L     M     N     O     P */
+          0x7D, 0x4A, 0x4B, 0x4C, 0x4D, 0x4E, 0x4F, 0x50,
+ /* 0xD8     Q     R  ----           ü                   */
+          0x51, 0x52, 0x07, 0x96, 0x81, 0x97, 0xA3, 0x98,
+ /* 0xE0     \           S     T     U     V     W     X */
+          0x5C, 0xF6, 0x53, 0x54, 0x55, 0x56, 0x57, 0x58,
+ /* 0xE8     Y     Z        ----     Ö  ----  ----  ---- */
+          0x59, 0x5A, 0xFD, 0x07, 0x99, 0x07, 0x07, 0x07,
+ /* 0xF0     0     1     2     3     4     5     6     7 */
+          0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37,
+ /* 0xF8     8     9  ----  ----     Ü  ----  ----  ---- */
+          0x38, 0x39, 0x07, 0x07, 0x9A, 0x07, 0x07, 0x07
+};
+
+typedef struct ttr 
+{
         __u16 tt;
         __u8  r;
 } __attribute__ ((packed)) ttr_t;
 
-typedef struct cchhb {
+typedef struct cchhb 
+{
         __u16 cc;
         __u16 hh;
         __u8 b;
 } __attribute__ ((packed)) cchhb_t;
 
-typedef struct cchh {
+typedef struct cchh 
+{
         __u16 cc;
         __u16 hh;
 } __attribute__ ((packed)) cchh_t;
 
-typedef struct labeldate {
+typedef struct labeldate 
+{
         __u8  year;
         __u16 day;
 } __attribute__ ((packed)) labeldate_t;
 
 
-typedef struct volume_label {
+typedef struct volume_label 
+{
         char volkey[4];         /* volume key = volume label                 */
 	char vollbl[4];	        /* volume label                              */
 	char volid[6];	        /* volume identifier                         */
@@ -66,7 +213,8 @@
 } __attribute__ ((packed)) volume_label_t;
 
 
-typedef struct extent {
+typedef struct extent 
+{
         __u8  typeind;          /* extent type indicator                     */
         __u8  seqno;            /* extent sequence number                    */
         cchh_t llimit;          /* starting point of this extent             */
@@ -74,7 +222,8 @@
 } __attribute__ ((packed)) extent_t;
 
 
-typedef struct dev_const {
+typedef struct dev_const 
+{
         __u16 DS4DSCYL;           /* number of logical cyls                  */
         __u16 DS4DSTRK;           /* number of tracks in a logical cylinder  */
         __u16 DS4DEVTK;           /* device track length                     */
@@ -88,7 +237,8 @@
 } __attribute__ ((packed)) dev_const_t;
 
 
-typedef struct format1_label {
+typedef struct format1_label 
+{
 	char  DS1DSNAM[44];       /* data set name                           */
 	__u8  DS1FMTID;           /* format identifier                       */
 	char  DS1DSSN[6];         /* data set serial number                  */
@@ -124,7 +274,8 @@
 } __attribute__ ((packed)) format1_label_t;
 
 
-typedef struct format4_label {
+typedef struct format4_label 
+{
 	char  DS4KEYCD[44];       /* key code for VTOC labels: 44 times 0x04 */
         __u8  DS4IDFMT;           /* format identifier                       */
 	cchhb_t DS4HPCHR;         /* highest address of a format 1 DSCB      */
@@ -153,6 +304,43 @@
 } __attribute__ ((packed)) format4_label_t;
 
 
+typedef struct ds5ext 
+{
+	__u16 t;                  /* RTA of the first track of free extent   */
+	__u16 fc;                 /* number of whole cylinders in free ext.  */
+	__u8  ft;                 /* number of remaining free tracks         */
+} __attribute__ ((packed)) ds5ext_t;
+
+
+typedef struct format5_label 
+{
+	char DS5KEYID[4];         /* key identifier                          */
+	ds5ext_t DS5AVEXT;        /* first available (free-space) extent.    */
+	ds5ext_t DS5EXTAV[7];     /* seven available extents                 */
+	__u8 DS5FMTID;            /* format identifier                       */
+	ds5ext_t DS5MAVET[18];    /* eighteen available extents              */
+	cchhb_t DS5PTRDS[5];      /* pointer to next format5 DSCB            */
+} __attribute__ ((packed)) format5_label_t;
+
+
+typedef struct ds7ext 
+{
+	__u32 a;                  /* starting RTA value                      */
+	__u32 b;                  /* ending RTA value + 1                    */
+} __attribute__ ((packed)) ds7ext_t;
+
+
+typedef struct format7_label 
+{
+	char DS7KEYID[4];         /* key identifier                          */
+	ds7ext_t DS7EXTNT[5];     /* space for 5 extent descriptions         */
+	__u8 DS7FMTID;            /* format identifier                       */
+	ds7ext_t DS7ADEXT[11];    /* space for 11 extent descriptions        */
+	char res1[2];             /* reserved                                */
+	cchhb_t DS7PTRDS;         /* pointer to next FMT7 DSCB               */
+} __attribute__ ((packed)) format7_label_t;
+
+
 char * vtoc_ebcdic_enc (
         unsigned char source[LINE_LENGTH],
         unsigned char target[LINE_LENGTH],
@@ -181,45 +369,126 @@
         __u8 year,
         __u16 day);
 
+void vtoc_volume_label_init (
+	volume_label_t *vlabel);
 
 int vtoc_read_volume_label (
         char * device,
         unsigned long vlabel_start,
         volume_label_t * vlabel);
+
 int vtoc_write_volume_label (
-        char * device,
+        char *device,
         unsigned long vlabel_start,
-        volume_label_t * vlabel);
+        volume_label_t *vlabel);
+
+void vtoc_volume_label_set_volser (
+	volume_label_t *vlabel,
+	char *volser);
+
+char *vtoc_volume_label_get_volser (
+	volume_label_t *vlabel,
+	char *volser);
+
+void vtoc_volume_label_set_key (
+        volume_label_t *vlabel,
+        char *key);     
+
+void vtoc_volume_label_set_label (
+	volume_label_t *vlabel,
+	char *lbl);
+
+char *vtoc_volume_label_get_label (
+	volume_label_t *vlabel,
+	char *lbl);
+
 void vtoc_read_label (
         char *device,
         unsigned long position,
+        format1_label_t *f1,
         format4_label_t *f4,
-        format1_label_t *f1);
+        format5_label_t *f5,
+        format7_label_t *f7);
+
 void vtoc_write_label (
         char *device,
         unsigned long position,
+        format1_label_t *f1,
 	format4_label_t *f4,
-	format1_label_t *f1);
-void vtoc_init_format4_label (
-        struct hd_geometry *geo,
-        format4_label_t *f4lbl,
-	unsigned int usable_partitions,
-	unsigned int cylinders,
-	unsigned int tracks,
-	unsigned int blocks);
+	format5_label_t *f5,
+	format7_label_t *f7);
+
+
 void vtoc_init_format1_label (
         char *volid,
         unsigned int blksize,
         extent_t *part_extent,
         format1_label_t *f1);
+
+
+void vtoc_init_format4_label (
+        format4_label_t *f4lbl,
+	unsigned int usable_partitions,
+	unsigned int cylinders,
+	unsigned int tracks,
+	unsigned int blocks,
+	unsigned int blksize,
+	__u16 dev_type);
+
 void vtoc_update_format4_label (
 	format4_label_t *f4,
 	cchhb_t *highest_f1,
-	__u8 unused_update,
-	__u16 freespace_update);
+	__u16 unused_update);
+
 
+void vtoc_init_format5_label (
+	format5_label_t *f5);
 
+void vtoc_update_format5_label_add (
+	format5_label_t *f5,
+	int verbose,
+	int cyl,
+	int trk,
+	__u16 a, 
+	__u16 b, 
+	__u8 c);
+ 
+void vtoc_update_format5_label_del (
+	format5_label_t *f5,
+	int verbose,
+	int cyl,
+	int trk,
+	__u16 a, 
+	__u16 b, 
+	__u8 c);
+
+
+void vtoc_init_format7_label (
+	format7_label_t *f7);
+
+void vtoc_update_format7_label_add (
+	format7_label_t *f7,
+	int verbose,
+	__u32 a, 
+	__u32 b);
+
+void vtoc_update_format7_label_del (
+	format7_label_t *f7, 
+	int verbose,
+	__u32 a, 
+	__u32 b);
 
+
+void vtoc_set_freespace(
+	format4_label_t *f4,
+	format5_label_t *f5,
+	format7_label_t *f7,
+	char ch,
+	int verbose,
+	__u32 start,
+	__u32 stop,
+	int cyl,
+	int trk);
 
 
 
diff -u --recursive --new-file v2.4.7/linux/include/asm-s390x/atomic.h linux/include/asm-s390x/atomic.h
--- v2.4.7/linux/include/asm-s390x/atomic.h	Wed Jul 25 17:10:25 2001
+++ linux/include/asm-s390x/atomic.h	Wed Jul 25 14:12:02 2001
@@ -25,13 +25,13 @@
 
 #define atomic_eieio()          __asm__ __volatile__ ("BCR 15,0")
 
-#define __CS_LOOP(old, new, ptr, op_val, op_string)			\
+#define __CS_LOOP(old_val, new_val, ptr, op_val, op_string)		\
         __asm__ __volatile__("   l     %0,0(%2)\n"			\
                              "0: lr    %1,%0\n"				\
                              op_string "  %1,%3\n"			\
                              "   cs    %0,%1,0(%2)\n"			\
                              "   jl    0b"				\
-                             : "=&d" (old), "=&d" (new)			\
+                             : "=&d" (old_val), "=&d" (new_val)		\
 			     : "a" (ptr), "d" (op_val) : "cc" );
 
 static __inline__ int atomic_read(atomic_t *v)
@@ -52,80 +52,80 @@
 
 static __inline__ void atomic_add(int i, atomic_t *v)
 {
-	int old, new;
-	__CS_LOOP(old, new, v, i, "ar");
+	int old_val, new_val;
+	__CS_LOOP(old_val, new_val, v, i, "ar");
 }
 
 static __inline__ int atomic_add_return (int i, atomic_t *v)
 {
-	int old, new;
-	__CS_LOOP(old, new, v, i, "ar");
-	return new;
+	int old_val, new_val;
+	__CS_LOOP(old_val, new_val, v, i, "ar");
+	return new_val;
 }
 
 static __inline__ int atomic_add_negative(int i, atomic_t *v)
 {
-	int old, new;
-        __CS_LOOP(old, new, v, i, "ar");
-        return new < 0;
+	int old_val, new_val;
+        __CS_LOOP(old_val, new_val, v, i, "ar");
+        return new_val < 0;
 }
 
 static __inline__ void atomic_sub(int i, atomic_t *v)
 {
-	int old, new;
-	__CS_LOOP(old, new, v, i, "sr");
+	int old_val, new_val;
+	__CS_LOOP(old_val, new_val, v, i, "sr");
 }
 
 static __inline__ void atomic_inc(volatile atomic_t *v)
 {
-	int old, new;
-	__CS_LOOP(old, new, v, 1, "ar");
+	int old_val, new_val;
+	__CS_LOOP(old_val, new_val, v, 1, "ar");
 }
 
 static __inline__ int atomic_inc_return(volatile atomic_t *v)
 {
-	int old, new;
-	__CS_LOOP(old, new, v, 1, "ar");
-        return new;
+	int old_val, new_val;
+	__CS_LOOP(old_val, new_val, v, 1, "ar");
+        return new_val;
 }
 
 static __inline__ int atomic_inc_and_test(volatile atomic_t *v)
 {
-	int old, new;
-	__CS_LOOP(old, new, v, 1, "ar");
-	return new != 0;
+	int old_val, new_val;
+	__CS_LOOP(old_val, new_val, v, 1, "ar");
+	return new_val != 0;
 }
 
 static __inline__ void atomic_dec(volatile atomic_t *v)
 {
-	int old, new;
-	__CS_LOOP(old, new, v, 1, "sr");
+	int old_val, new_val;
+	__CS_LOOP(old_val, new_val, v, 1, "sr");
 }
 
 static __inline__ int atomic_dec_return(volatile atomic_t *v)
 {
-	int old, new;
-	__CS_LOOP(old, new, v, 1, "sr");
-	return new;
+	int old_val, new_val;
+	__CS_LOOP(old_val, new_val, v, 1, "sr");
+	return new_val;
 }
 
 static __inline__ int atomic_dec_and_test(volatile atomic_t *v)
 {
-	int old, new;
-	__CS_LOOP(old, new, v, 1, "sr");
-        return new == 0;
+	int old_val, new_val;
+	__CS_LOOP(old_val, new_val, v, 1, "sr");
+        return new_val == 0;
 }
 
 static __inline__ void atomic_clear_mask(unsigned long mask, atomic_t *v)
 {
-	int old, new;
-	__CS_LOOP(old, new, v, ~mask, "nr");
+	int old_val, new_val;
+	__CS_LOOP(old_val, new_val, v, ~mask, "nr");
 }
 
 static __inline__ void atomic_set_mask(unsigned long mask, atomic_t *v)
 {
-	int old, new;
-	__CS_LOOP(old, new, v, mask, "or");
+	int old_val, new_val;
+	__CS_LOOP(old_val, new_val, v, mask, "or");
 }
 
 /*
diff -u --recursive --new-file v2.4.7/linux/include/asm-s390x/cache.h linux/include/asm-s390x/cache.h
--- v2.4.7/linux/include/asm-s390x/cache.h	Tue Feb 13 14:13:44 2001
+++ linux/include/asm-s390x/cache.h	Sun Aug  5 13:12:41 2001
@@ -11,6 +11,7 @@
 #ifndef __ARCH_S390_CACHE_H
 #define __ARCH_S390_CACHE_H
 
-#define L1_CACHE_BYTES     16
+#define L1_CACHE_BYTES     256
+#define L1_CACHE_SHIFT     8
 
 #endif
diff -u --recursive --new-file v2.4.7/linux/include/asm-s390x/chandev.h linux/include/asm-s390x/chandev.h
--- v2.4.7/linux/include/asm-s390x/chandev.h	Wed Apr 11 19:02:29 2001
+++ linux/include/asm-s390x/chandev.h	Wed Jul 25 14:12:02 2001
@@ -6,49 +6,86 @@
  * 
  *  Generic channel device initialisation support. 
  */
+#ifndef __S390_CHANDEV_H
+#define __S390_CHANDEV_H
 #include <linux/version.h>
 #include <asm/types.h>
 #include <linux/netdevice.h>
 
+
+/* Setting this flag to true causes a device name to be built based on the read_devno of the device */
+/* this is exported so external code can look at this flags setting */
+extern int chandev_use_devno_names;
+
+
 /* chandev_type is a bitmask for registering & describing device types. */
 typedef enum
 {
-	none=0x0,
-	ctc=0x1,
-	escon=0x2,
-	lcs=0x4,
-	osad=0x8,
-	qeth=0x10,
-	claw=0x20,
+	chandev_type_none=0x0,
+	chandev_type_ctc=0x1,
+	chandev_type_escon=0x2,
+	chandev_type_lcs=0x4,
+	chandev_type_osad=0x8,
+	chandev_type_qeth=0x10,
+	chandev_type_claw=0x20,
 } chandev_type;
 
 typedef enum
 {
-	no_category,
-	network_device,
-	serial_device,
+	chandev_category_none,
+	chandev_category_network_device,
+	chandev_category_serial_device,
 } chandev_category;
 
+
+
+typedef struct
+{
+	int     irq;
+	u16     devno;
+	u16     cu_type;      /* control unit type */
+	u8      cu_model;     /* control unit model */
+	u16     dev_type;     /* device type */
+	u8      dev_model;    /* device model */
+	u8      pim;          /* path installed mask */
+	u8      chpid[8];     /* CHPID 0-7 (if available) */
+} chandev_subchannel_info;
+
+#define CLAW_NAMELEN 9
+/* CLAW specific parameters other drivers should ignore these fields */
+typedef struct
+{
+	
+	char	 host_name[CLAW_NAMELEN];    /* local host name */
+	char	 adapter_name[CLAW_NAMELEN]; /* workstation adapter name */
+	char	 api_type[CLAW_NAMELEN];     /* API type either TCPIP or API */
+} chandev_claw_info;
+
 /*
  * The chandev_probeinfo structure is passed to the device driver with configuration
  * info for which irq's & ports to use when attempting to probe the device.
  */
 typedef struct
 {
-        int     read_irq;
-	int     write_irq;
-	u16     read_devno;
-	u16     write_devno;
-        s16     port_protocol_no; /* -1 don't care */
+	chandev_subchannel_info read;
+	chandev_subchannel_info write;
+	chandev_subchannel_info data;
+	/* memory_usage_in_k is the suggested memory the driver should attempt to use for io */
+	/* buffers -1 means use the driver default the driver should set this field to the */
+	/* amount of memory it actually uses when returning this probeinfo to the channel */
+	/* device layer with chandev_initdevice */
+	s32     memory_usage_in_k;
+	chandev_claw_info       claw;
+	u8      data_exists; /* whether this device has a data channel */
+	u8      cu_dev_info_inconsistent; /* either ctc or we possibly had a bad sense_id */
+	u8      chpid_info_inconsistent;  /* either ctc or schib info bad */
+        s16     port_protocol_no; /* 0 by default, set specifically when forcing */
 	u8      hint_port_no;   /* lcs specific */
-	u8      max_port_no;    /* lcs specific */
+	u8      max_port_no;    /* lcs/qeth specific */
 	chandev_type chan_type;
 	u8      checksum_received_ip_pkts;
 	u8      use_hw_stats; /* where available e.g. lcs */
-	u16     cu_type;      /* control unit type */
-	u8      cu_model;     /* control unit model */
-	u16     dev_type;     /* device type */
-	u8      dev_model;    /* device model */
+	u8      device_forced; /* indicates the device hasn't been autodetected */
 	char    *parmstr;       /* driver specific parameters added by add_parms keyword */
 	/* newdevice used internally by chandev.c */
 	struct  chandev_activelist *newdevice; 
@@ -75,19 +112,21 @@
 
 typedef enum
 {
-	good=0,
-	not_oper,
-	first_msck=not_oper,
-	no_path,
-	revalidate,
-	gone,
-	last_msck,
+	chandev_status_good,
+	chandev_status_not_oper,
+	chandev_status_first_msck=chandev_status_not_oper,
+	chandev_status_no_path,
+	chandev_status_revalidate,
+	chandev_status_gone,
+	chandev_status_last_msck,
+	chandev_status_all_chans_good /* pseudo machine check to indicate all channels are healthy */
 } chandev_msck_status;
 
 typedef int (*chandev_probefunc)(chandev_probeinfo *probeinfo);
-typedef void (*chandev_shutdownfunc)(void *device);
+typedef int (*chandev_shutdownfunc)(void *device);
 typedef void (*chandev_unregfunc)(void *device);
-typedef void (*chandev_reoperfunc)(void *device,int msck_for_read_chan,chandev_msck_status prevstatus);
+typedef void (*chandev_msck_notification_func)(void *device,int msck_irq,
+chandev_msck_status prevstatus,chandev_msck_status newstatus);
 
 
 
@@ -103,7 +142,7 @@
  */
 int chandev_register_and_probe(chandev_probefunc probefunc,
 			       chandev_shutdownfunc shutdownfunc,
-			       chandev_reoperfunc reoperfunc,
+			       chandev_msck_notification_func msck_notfunc,
 			       chandev_type chan_type);
 
 /* The chandev_unregister function is typically called when a module is being removed 
@@ -117,6 +156,33 @@
 int chandev_initdevice(chandev_probeinfo *probeinfo,void *dev_ptr,u8 port_no,char *devname,
 chandev_category category,chandev_unregfunc unreg_dev);
 
+/* This function builds a device name & copies it into destnamebuff suitable for calling 
+   init_trdev or whatever & it honours the use_devno_names flag, it is used by chandev_initnetdevice 
+   setting the buildfullname flag to TRUE will cause it to always build a full unique name based 
+   on basename either honouring the chandev_use_devno_names flag if set or starting at index 
+   0 & checking the namespace of the channel device layer itself for a free index, this
+   may be useful when one doesn't have control of the name an upper layer may choose.
+   It returns NULL on error.
+*/
+char *chandev_build_device_name(chandev_probeinfo *probeinfo,char *destnamebuff,char *basename,int buildfullname);
+
+
+
+
+/* chandev_init_netdev registers with the normal network device layer */
+/* it doesn't update any of the chandev internal structures. */
+/* i.e. it is optional */
+/* it was part of chandev_initnetdevice but I separated it as */
+/* chandev_initnetdevice may make too many assumptions for some users */
+/* chandev_initnetdevice = chandev_initdevice followed by chandev_init_netdev */
+#if LINUX_VERSION_CODE>=KERNEL_VERSION(2,3,0)
+struct net_device *chandev_init_netdev(chandev_probeinfo *probeinfo,char *basename,
+struct net_device *dev, int sizeof_priv,struct net_device *(*init_netdevfunc)(struct net_device *dev, int sizeof_priv));
+#else
+struct device *chandev_init_netdev(chandev_probeinfo *probeinfo,char *basename,
+struct device *dev, int sizeof_priv,struct device *(*init_netdevfunc)(struct device *dev, int sizeof_priv));
+#endif
+
 /* chandev_initnetdevice registers a network device with the channel layer. 
  * It returns the device structure if successful,if dev=NULL it kmallocs it, 
  * On device initialisation failure it will kfree it under ALL curcumstances
@@ -148,8 +214,18 @@
 				     void (*unreg_netdevfunc)(struct device *dev));
 #endif
 
-
-
+/* chandev_add & delete model shouldn't normally be needed by drivers except if */
+/* someone is developing a driver which the channel device layer doesn't know about */
+void chandev_add_model(chandev_type chan_type,s32 cu_type,s16 cu_model,
+		       s32 dev_type,s16 dev_model,u8 max_port_no,int auto_msck_recovery,
+		        u8 default_checksum_received_ip_pkts,u8 default_use_hw_stats);
+void chandev_del_model(s32 cu_type,s16 cu_model,s32 dev_type,s16 dev_model);
+
+/* modules should use chandev_persist to see if they should stay loaded */
+/* this is useful for debugging purposes where you may wish to examine */
+/* /proc/s390dbf/ entries */
+int chandev_persist(chandev_type chan_type);
+#endif /* __S390_CHANDEV_H */
 
 
 
diff -u --recursive --new-file v2.4.7/linux/include/asm-s390x/checksum.h linux/include/asm-s390x/checksum.h
--- v2.4.7/linux/include/asm-s390x/checksum.h	Tue Feb 13 14:13:44 2001
+++ linux/include/asm-s390x/checksum.h	Wed Jul 25 14:12:02 2001
@@ -67,18 +67,24 @@
  *
  * here even more important to align src and dst on a 32-bit (or even
  * better 64-bit) boundary
+ *
+ * Copy from userspace and compute checksum.  If we catch an exception
+ * then zero the rest of the buffer.
  */
-
 extern inline unsigned int 
-csum_partial_copy_from_user(const char *src, char *dst,
-                            int len, unsigned int sum, int *errp)
+csum_partial_copy_from_user (const char *src, char *dst,
+                                          int len, unsigned int sum,
+                                          int *err_ptr)
 {
-	if (copy_from_user(dst, src, len)) {
-		*errp = -EFAULT;
-		memset(dst, 0, len);
-		return sum;
-        }
-        return csum_partial_inline(dst, len, sum);
+	int missing;
+
+	missing = copy_from_user(dst, src, len);
+	if (missing) {
+		memset(dst + len - missing, 0, missing);
+		*err_ptr = -EFAULT;
+	}
+		
+	return csum_partial(dst, len, sum);
 }
 
 extern inline unsigned int
diff -u --recursive --new-file v2.4.7/linux/include/asm-s390x/current.h linux/include/asm-s390x/current.h
--- v2.4.7/linux/include/asm-s390x/current.h	Tue Feb 13 14:13:44 2001
+++ linux/include/asm-s390x/current.h	Wed Jul 25 14:12:02 2001
@@ -20,7 +20,7 @@
         struct task_struct *current;
         __asm__("lghi  %0,-16384\n\t"
                 "ngr   %0,15"
-                : "=&r" (current) );
+                : "=&r" (current) : : "cc" );
         return current;
  }
 
diff -u --recursive --new-file v2.4.7/linux/include/asm-s390x/dasd.h linux/include/asm-s390x/dasd.h
--- v2.4.7/linux/include/asm-s390x/dasd.h	Wed Apr 11 19:02:29 2001
+++ linux/include/asm-s390x/dasd.h	Sun Aug  5 13:12:41 2001
@@ -4,43 +4,39 @@
  * Bugreports.to..: <Linux390@de.ibm.com>
  * (C) IBM Corporation, IBM Deutschland Entwicklung GmbH, 1999,2000
  *
+ * This file is the interface of the DASD device driver, which is exported to user space
+ * any future changes wrt the API will result in a change of the APIVERSION reported
+ * to userspace by the DASDAPIVER-ioctl
+ *
  * History of changes (starts July 2000)
- * 02/01/01 added dynamic registration of ioctls
+ * 05/04/01 created by moving the kernel interface to drivers/s390/block/dasd_int.h
  */
 
 #ifndef DASD_H
 #define DASD_H
-
-#undef ERP_DEBUG               /* enable debug messages */
-#undef ERP_FULL_ERP            /* enable full ERP - experimental code !!!! */
-#define CONFIG_DASD_DYNAMIC
-
 #include <linux/ioctl.h>
-#include <asm/irq.h>
 
-#define IOCTL_LETTER 'D'
-/* Disable the volume (for Linux) */
-#define BIODASDDISABLE _IO(IOCTL_LETTER,0) 
-/* Enable the volume (for Linux) */
-#define BIODASDENABLE  _IO(IOCTL_LETTER,1) 
-/* Issue a reserve/release command, rsp. */
-#define BIODASDRSRV    _IO(IOCTL_LETTER,2) /* reserve */
-#define BIODASDRLSE    _IO(IOCTL_LETTER,3) /* release */
-#define BIODASDSLCK    _IO(IOCTL_LETTER,4) /* steal lock */
-/* Read sense ID infpormation */
-#define BIODASDRSID    _IOR(IOCTL_LETTER,0,senseid_t)
-/* Format the volume or an extent */
-#define BIODASDFORMAT  _IOW(IOCTL_LETTER,0,format_data_t) 
-/* translate blocknumber of partition to absolute */
-#define BIODASDRWTB    _IOWR(IOCTL_LETTER,0,int)
+#define DASD_IOCTL_LETTER 'D'
 
-typedef int(*dasd_ioctl_fn_t) (struct inode *inp, int no, long args);
-int dasd_ioctl_no_register(int no, dasd_ioctl_fn_t handler);
-int dasd_ioctl_no_unregister(int no, dasd_ioctl_fn_t handler);
+#if (DASD_API_VERSION == 0)
 
-#define DASD_NAME "dasd"
 #define DASD_PARTN_BITS 2
-#define DASD_PER_MAJOR ( 1U<<(MINORBITS-DASD_PARTN_BITS))
+
+/* 
+ * struct profile_info_t
+ * holds the profinling information 
+ */
+typedef struct dasd_profile_info_t {
+        unsigned int dasd_io_reqs;	 /* number of requests processed at all */
+        unsigned int dasd_io_sects;	 /* number of sectors processed at all */
+        unsigned int dasd_io_secs[32];	 /* histogram of request's sizes */
+        unsigned int dasd_io_times[32];	 /* histogram of requests's times */
+        unsigned int dasd_io_timps[32];	 /* histogram of requests's times per sector */
+        unsigned int dasd_io_time1[32];	 /* histogram of time from build to start */
+        unsigned int dasd_io_time2[32];	 /* histogram of time from start to irq */
+        unsigned int dasd_io_time2ps[32]; /* histogram of time from start to irq */
+        unsigned int dasd_io_time3[32];	 /* histogram of time from irq to end */
+} dasd_profile_info_t;
 
 /* 
  * struct format_data_t
@@ -50,334 +46,65 @@
 	int start_unit; /* from track */
 	int stop_unit;  /* to track */
 	int blksize;    /* sectorsize */
-        int intensity;  /* 0: normal, 1:record zero, 3:home address, 4 invalidate tracks */
-} __attribute__ ((packed)) format_data_t;
-
-#define DASD_FORMAT_DEFAULT_START_UNIT 0
-#define DASD_FORMAT_DEFAULT_STOP_UNIT -1
-#define DASD_FORMAT_DEFAULT_BLOCKSIZE -1
-#define DASD_FORMAT_DEFAULT_INTENSITY -1
-
-#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/version.h>
-#include <linux/major.h>
-#include <linux/wait.h>
-#include <asm/ccwcache.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>
+        int intensity;  
+} format_data_t;
 
-#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,
-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;
-	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 IRQ0x%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;
+/*
+ * values to be used for format_data_t.intensity
+ * 0/8: normal format
+ * 1/9: also write record zero
+ * 3/11: also write home address
+ * 4/12: invalidate track
+ */
+#define DASD_FMT_INT_FMT_R0 1 /* write record zero */
+#define DASD_FMT_INT_FMT_HA 2 /* write home address, also set FMT_R0 ! */
+#define DASD_FMT_INT_INVAL  4 /* invalidate tracks */
+#define DASD_FMT_INT_COMPAT 8 /* use OS/390 compatible disk layout */
 
 /* 
- * 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 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 *);
-
-
-/*
- * 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++
+ * struct dasd_information_t
+ * represents any data about the data, which is visible to userspace
  */
-typedef struct dasd_discipline_t {
-	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_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;
-	
-	struct dasd_discipline_t *next;	/* used for list of disciplines */
-} dasd_discipline_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_profile_info_t {
-        unsigned long dasd_io_reqs;	/* number of requests processed at all */
-        unsigned long dasd_io_secs[32];	/* histogram of request's sizes */
-        unsigned long dasd_io_times[32];	/* histogram of requests's times */
-        unsigned long dasd_io_timps[32];	/* histogram of requests's times per sector */
-        unsigned long dasd_io_time1[32];	/* histogram of time from build to start */
-       unsigned  long dasd_io_time2[32];	/* histogram of time from start to irq */
-        unsigned long dasd_io_time2ps[32];	/* histogram of time from start to irq */
-        unsigned long dasd_io_time3[32];	/* histogram of time from irq to end */
-} dasd_profile_info_t;
-
-typedef struct dasd_device_t {
-	s390_dev_info_t devinfo;
-	dasd_discipline_t *discipline;
-	int level;
-        int 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;
-        struct proc_dir_entry *proc_dir; /* directory node */
-        struct proc_dir_entry *proc_info; /* information from dasd_device_t */
-        struct proc_dir_entry *proc_stats; /* statictics information */
-}  dasd_device_t;
-
-/* dasd_device_t.level can be: */
-#define DASD_DEVICE_LEVEL_UNKNOWN 0x00
-#define DASD_DEVICE_LEVEL_RECOGNIZED 0x01
-#define DASD_DEVICE_LEVEL_ANALYSIS_PENDING 0x02
-#define DASD_DEVICE_LEVEL_ANALYSIS_PREPARED 0x04
-#define DASD_DEVICE_LEVEL_ANALYSED 0x08
-#define DASD_DEVICE_LEVEL_ONLINE 0x10
-
-int dasd_init (void);
-void dasd_discipline_enq (dasd_discipline_t *);
-int dasd_discipline_deq(dasd_discipline_t *);
-int dasd_start_IO (ccw_req_t *);
-void dasd_int_handler (int , void *, struct pt_regs *);
-ccw_req_t *default_erp_action (ccw_req_t *);
-ccw_req_t *default_erp_postaction (ccw_req_t *);
-int dasd_chanq_deq (dasd_chanq_t *, ccw_req_t *);
-ccw_req_t *dasd_alloc_request (char *, int, int);
-void dasd_free_request (ccw_req_t *);
-extern int (*genhd_dasd_name) (char *, int, int, struct gendisk *);
-extern int (*genhd_dasd_fillgeo) (int, struct hd_geometry *);
-int dasd_oper_handler (int irq, devreg_t * devreg);
-void dasd_schedule_bh (dasd_device_t *);
-
-debug_info_t *dasd_debug_area;
-
-#endif /* __KERNEL__ */
+typedef struct dasd_information_t {
+        unsigned int devno; /* S/390 devno */
+        unsigned int real_devno; /* for aliases */
+        unsigned int schid; /* S/390 subchannel identifier */
+        unsigned int cu_type  : 16; /* from SenseID */
+        unsigned int cu_model :  8; /* from SenseID */
+        unsigned int dev_type : 16; /* from SenseID */
+        unsigned int dev_model : 8; /* from SenseID */
+        unsigned int open_count; 
+        unsigned int req_queue_len; 
+        unsigned int chanq_len;
+        char type[4]; /* from discipline.name, 'none' for unknown */
+        unsigned int status; /* current device level */
+        unsigned int label_block; /* where to find the VOLSER */
+        unsigned int FBA_layout; /* fixed block size (like AIXVOL) */
+        unsigned int characteristics_size;
+        unsigned int confdata_size;
+        char characteristics[64]; /* from read_device_characteristics */
+        char configuration_data[256]; /* from read_configuration_data */
+} dasd_information_t;
 
+/* Disable the volume (for Linux) */
+#define BIODASDDISABLE _IO(DASD_IOCTL_LETTER,0) 
+/* Enable the volume (for Linux) */
+#define BIODASDENABLE  _IO(DASD_IOCTL_LETTER,1)  
+/* Issue a reserve/release command, rsp. */
+#define BIODASDRSRV    _IO(DASD_IOCTL_LETTER,2) /* reserve */
+#define BIODASDRLSE    _IO(DASD_IOCTL_LETTER,3) /* release */
+#define BIODASDSLCK    _IO(DASD_IOCTL_LETTER,4) /* steal lock */
+/* reset profiling information of a device */
+#define BIODASDPRRST   _IO(DASD_IOCTL_LETTER,5)
+/* retrieve API version number */
+#define DASDAPIVER     _IOR(DASD_IOCTL_LETTER,0,int)
+/* Get information on a dasd device */
+#define BIODASDINFO    _IOR(DASD_IOCTL_LETTER,1,dasd_information_t)
+/* retrieve profiling information of a device */
+#define BIODASDPRRD    _IOR(DASD_IOCTL_LETTER,2,dasd_profile_info_t)
+/* #define BIODASDFORMAT  _IOW(IOCTL_LETTER,0,format_data_t) , deprecated */
+#define BIODASDFMT     _IOW(DASD_IOCTL_LETTER,1,format_data_t) 
+#endif /* DASD_API_VERSION */
 #endif				/* DASD_H */
 
 /*
diff -u --recursive --new-file v2.4.7/linux/include/asm-s390x/debug.h linux/include/asm-s390x/debug.h
--- v2.4.7/linux/include/asm-s390x/debug.h	Wed Apr 11 19:02:29 2001
+++ linux/include/asm-s390x/debug.h	Wed Jul 25 14:12:02 2001
@@ -53,7 +53,7 @@
 #define DEBUG_DATA(entry) (char*)(entry + 1) /* data is stored behind */
                                              /* the entry information */
 
-#define STCK(x)	asm volatile ("STCK %0":"=m" (x))
+#define STCK(x)	asm volatile ("STCK %0" : "=m" (x) : : "cc" )
 
 typedef struct __debug_entry debug_entry_t;
 
diff -u --recursive --new-file v2.4.7/linux/include/asm-s390x/hardirq.h linux/include/asm-s390x/hardirq.h
--- v2.4.7/linux/include/asm-s390x/hardirq.h	Tue Feb 13 14:13:44 2001
+++ linux/include/asm-s390x/hardirq.h	Wed Jul 25 14:12:02 2001
@@ -17,42 +17,26 @@
 #include <asm/lowcore.h>
 #include <linux/sched.h>
 
-/* No irq_cpustat_t for s390, the data is held directly in S390_lowcore */
+/* entry.S is sensitive to the offsets of these fields */
+typedef struct {
+	unsigned int __softirq_pending;
+	unsigned int __local_irq_count;
+	unsigned int __local_bh_count;
+	unsigned int __syscall_count;
+	struct task_struct * __ksoftirqd_task; /* waitqueue is too large */
+} ____cacheline_aligned irq_cpustat_t;
 
-/*
- * Simple wrappers reducing source bloat.  S390 specific because each
- * cpu stores its data in S390_lowcore (PSA) instead of using a cache
- * aligned array element like most architectures.
- */
-
-#ifdef CONFIG_SMP
-
-#define softirq_active(cpu)	(safe_get_cpu_lowcore(cpu).__softirq_active)
-#define softirq_mask(cpu)	(safe_get_cpu_lowcore(cpu).__softirq_mask)
-#define local_irq_count(cpu)	(safe_get_cpu_lowcore(cpu).__local_irq_count)
-#define local_bh_count(cpu)	(safe_get_cpu_lowcore(cpu).__local_bh_count)
-#define syscall_count(cpu)	(safe_get_cpu_lowcore(cpu).__syscall_count)
-
-#else	/* CONFIG_SMP */
-
-/* Optimize away the cpu calculation, it is always current PSA */
-#define softirq_active(cpu)	((void)(cpu), S390_lowcore.__softirq_active)
-#define softirq_mask(cpu)	((void)(cpu), S390_lowcore.__softirq_mask)
-#define local_irq_count(cpu)	((void)(cpu), S390_lowcore.__local_irq_count)
-#define local_bh_count(cpu)	((void)(cpu), S390_lowcore.__local_bh_count)
-#define syscall_count(cpu)	((void)(cpu), S390_lowcore.__syscall_count)
-
-#endif	/* CONFIG_SMP */
+#include <linux/irq_cpustat.h>	/* Standard mappings for irq_cpustat_t above */
 
 /*
  * Are we in an interrupt context? Either doing bottom half
  * or hardware interrupt processing?
- * Special definitions for s390, always access current PSA.
  */
-#define in_interrupt() ((S390_lowcore.__local_irq_count + S390_lowcore.__local_bh_count) != 0)
-  
-#define in_irq() (S390_lowcore.__local_irq_count != 0)
-  
+#define in_interrupt() ({ int __cpu = smp_processor_id(); \
+	(local_irq_count(__cpu) + local_bh_count(__cpu) != 0); })
+
+#define in_irq() (local_irq_count(smp_processor_id()) != 0)
+
 #ifndef CONFIG_SMP
   
 #define hardirq_trylock(cpu)	(local_irq_count(cpu) == 0)
diff -u --recursive --new-file v2.4.7/linux/include/asm-s390x/idals.h linux/include/asm-s390x/idals.h
--- v2.4.7/linux/include/asm-s390x/idals.h	Tue Feb 13 14:13:44 2001
+++ linux/include/asm-s390x/idals.h	Wed Jul 25 14:12:02 2001
@@ -10,36 +10,51 @@
 #include <linux/config.h>
 #include <asm/irq.h>
 
-typedef unsigned long idaw_t;
+#define IDA_SIZE_LOG 12 /* 11 for 2k , 12 for 4k */
+#define IDA_BLOCK_SIZE (1L<<IDA_SIZE_LOG)
 
-static inline idaw_t *
+static inline addr_t *
 idal_alloc ( int nridaws )
 {
 	if ( nridaws > 33 )
 		BUG();
-	return kmalloc(nridaws * sizeof(idaw_t), GFP_ATOMIC | GFP_DMA );
+	return kmalloc(nridaws * sizeof(addr_t), GFP_ATOMIC | GFP_DMA );
 }
 
 static inline void 
-idal_free ( idaw_t *idal )
+idal_free ( addr_t *idal )
 {
 	kfree (idal);
 }
 
+#if defined(CONFIG_ARCH_S390X)
+extern unsigned long __create_idal(unsigned long address, int count);
+#endif
+
 /*
  * Function: set_normalized_cda
  * sets the address of the data in CCW
  * if necessary it allocates an IDAL and sets sthe appropriate flags
  */
-#if defined (CONFIG_ARCH_S390X)
-extern void set_normalized_cda(ccw1_t * ccw, unsigned long address);
-#else
-static inline void
+static inline int
 set_normalized_cda(ccw1_t * ccw, unsigned long address)
 {
-	ccw->cda = address;
-}
+	int ret = 0;
+
+#if defined (CONFIG_ARCH_S390X)
+	if (((address + ccw->count) >> 31) != 0) {
+		if (ccw->flags & CCW_FLAG_IDA)
+			BUG();
+		address = __create_idal(address, ccw->count);
+		if (address)
+			ccw->flags |= CCW_FLAG_IDA;
+		else
+			ret = -ENOMEM;
+	}
 #endif
+	ccw->cda = (__u32) address;
+	return ret;
+}
 
 /*
  * Function: clear_normalized_cda
@@ -48,10 +63,12 @@
 static inline void
 clear_normalized_cda ( ccw1_t * ccw ) 
 {
+#if defined(CONFIG_ARCH_S390X)
 	if ( ccw -> flags & CCW_FLAG_IDA ) {
-		idal_free ( (idaw_t *)(unsigned long) (ccw -> cda ));
+		idal_free ( (addr_t *)(unsigned long) (ccw -> cda ));
 		ccw -> flags &= ~CCW_FLAG_IDA;
 	}
+#endif
 	ccw -> cda = 0;
 }
 
diff -u --recursive --new-file v2.4.7/linux/include/asm-s390x/init.h linux/include/asm-s390x/init.h
--- v2.4.7/linux/include/asm-s390x/init.h	Tue Feb 13 14:13:44 2001
+++ linux/include/asm-s390x/init.h	Wed Jul 25 14:12:02 2001
@@ -23,7 +23,7 @@
 #define __INITDATA      .section        ".data.init",#alloc,#write
 */
 
-#define __cacheline_aligned __attribute__ ((__aligned__(16)))
+#define __cacheline_aligned __attribute__ ((__aligned__(256)))
 
 #endif
 
diff -u --recursive --new-file v2.4.7/linux/include/asm-s390x/io.h linux/include/asm-s390x/io.h
--- v2.4.7/linux/include/asm-s390x/io.h	Tue Feb 13 14:13:44 2001
+++ linux/include/asm-s390x/io.h	Wed Jul 25 14:12:02 2001
@@ -31,7 +31,7 @@
                  "   jz     0f\n"
                  "   slgr   %0,%0\n"
                  "0:"
-                 : "=a" (real_address) : "a" (address) );
+                 : "=a" (real_address) : "a" (address) : "cc" );
         return real_address;
 }
 
diff -u --recursive --new-file v2.4.7/linux/include/asm-s390x/irq.h linux/include/asm-s390x/irq.h
--- v2.4.7/linux/include/asm-s390x/irq.h	Wed Jul 25 17:10:25 2001
+++ linux/include/asm-s390x/irq.h	Wed Jul 25 14:12:02 2001
@@ -572,6 +572,10 @@
 extern int set_cons_dev(int irq);
 extern int reset_cons_dev(int irq);
 extern int wait_cons_dev(int irq);
+extern schib_t *s390_get_schib( int irq );
+
+extern int s390_register_adapter_interrupt(adapter_int_handler_t handler);
+extern int s390_unregister_adapter_interrupt(adapter_int_handler_t handler);
 
 /*
  * Some S390 specific IO instructions as inline
diff -u --recursive --new-file v2.4.7/linux/include/asm-s390x/lowcore.h linux/include/asm-s390x/lowcore.h
--- v2.4.7/linux/include/asm-s390x/lowcore.h	Fri Mar  2 11:12:06 2001
+++ linux/include/asm-s390x/lowcore.h	Wed Jul 25 14:12:02 2001
@@ -38,17 +38,18 @@
 #define __LC_MCCK_CODE                  0x0E8
 
 #define __LC_SAVE_AREA                  0xC00
-#define __LC_CREGS_SAVE_AREA            0xC80
-#define __LC_AREGS_SAVE_AREA            0xD00
 #define __LC_KERNEL_STACK               0xD40
 #define __LC_KERNEL_LEVEL               0xD48
-#define __LC_IRQ_STAT                   0xD50
 #define __LC_CPUID                      0xD90
 #define __LC_CPUADDR                    0xD98
 #define __LC_IPLDEV                     0xDB8
 
 #define __LC_PANIC_MAGIC                0xE00
 
+#define __LC_AREGS_SAVE_AREA            0x1340
+#define __LC_CREGS_SAVE_AREA            0x1380
+
+#define __LC_PFAULT_INTPARM             0x11B8
 
 /* interrupt handler start with all io, external and mcck interrupt disabled */
 
@@ -139,21 +140,14 @@
         __u8         pad8[0xc00-0x214];        /* 0x214 */
         /* System info area */
 	__u64        save_area[16];            /* 0xc00 */
-	__u64        cregs_save_area[16];      /* 0xc80 */
-	__u32        access_regs_save_area[16];/* 0xd00 */
+        __u8         pad9[0xd40-0xc80];        /* 0xc80 */
  	__u64        kernel_stack;             /* 0xd40 */
 	__u64        kernel_level;             /* 0xd48 */
 	/* entry.S sensitive area start */
-	/* Next 6 words are the s390 equivalent of irq_stat */
-	__u32        __softirq_active;         /* 0xd50 */
-	__u32        __softirq_mask;           /* 0xd54 */
-	__u32        __local_irq_count;        /* 0xd58 */
-	__u32        __local_bh_count;         /* 0xd5c */
-	__u32        __syscall_count;          /* 0xd60 */
-	__u8         pad10[0xd80-0xd64];       /* 0xd64 */
+	__u8         pad10[0xd80-0xd50];       /* 0xd64 */
 	struct       cpuinfo_S390 cpu_data;    /* 0xd80 */
 	__u32        ipl_device;               /* 0xdb8 */
-	__u32        pad13;                    /* 0xdbc was lsw word of ipl_device until a bug was found DJB */
+	__u32        pad11;                    /* 0xdbc was lsw word of ipl_device until a bug was found DJB */
 	/* entry.S sensitive area end */
 
         /* SMP info area: defined by DJB */
@@ -162,14 +156,33 @@
 	__u64        ext_call_queue;           /* 0xdd0 */
         __u64        ext_call_count;           /* 0xdd8 */
 
-        __u8         pad11[0xe00-0xde0];       /* 0xde0 */
+        __u8         pad12[0xe00-0xde0];       /* 0xde0 */
 
         /* 0xe00 is used as indicator for dump tools */
         /* whether the kernel died with panic() or not */
         __u32        panic_magic;              /* 0xe00 */
 
-        /* Align to the top 1k of prefix area */
-	__u8         pad12[0x1000-0xe04];      /* 0xe04 */
+	__u8         pad13[0x1200-0xe04];      /* 0xe04 */
+
+        /* System info area */ 
+
+	__u64        floating_pt_save_area[16]; /* 0x1200 */
+	__u64        gpregs_save_area[16];      /* 0x1280 */
+	__u32        st_status_fixed_logout[4]; /* 0x1300 */
+	__u8         pad14[0x1318-0x1310];      /* 0x1310 */
+	__u32        prefixreg_save_area;       /* 0x1318 */
+	__u32        fpt_creg_save_area;        /* 0x131c */
+	__u8         pad15[0x1324-0x1320];      /* 0x1320 */
+	__u32        tod_progreg_save_area;     /* 0x1324 */
+	__u32        cpu_timer_save_area[2];    /* 0x1328 */
+	__u32        clock_comp_save_area[2];   /* 0x1330 */
+	__u8         pad16[0x1340-0x1338];      /* 0x1338 */ 
+	__u32        access_regs_save_area[16]; /* 0x1340 */ 
+	__u64        cregs_save_area[16];       /* 0x1380 */
+
+	/* align to the top of the prefix area */
+
+	__u8         pad17[0x2000-0x1400];      /* 0x1400 */
 } __attribute__((packed)); /* End structure*/
 
 extern __inline__ void set_prefix(__u32 address)
diff -u --recursive --new-file v2.4.7/linux/include/asm-s390x/page.h linux/include/asm-s390x/page.h
--- v2.4.7/linux/include/asm-s390x/page.h	Wed Apr 11 19:02:29 2001
+++ linux/include/asm-s390x/page.h	Wed Jul 25 14:12:02 2001
@@ -26,7 +26,7 @@
                       "   slgr 1,1\n"
                       "   mvcl 2,0"
                       : : "a" ((void *) (page))
-		      : "memory", "1", "2", "3" );
+		      : "memory", "cc", "1", "2", "3" );
 }
 
 static inline void copy_page(void *to, void *from)
@@ -35,7 +35,7 @@
 		asm volatile ("   sgr  0,0\n"
 			      "   mvpg %0,%1"
 			      : : "a" ((void *)(to)), "a" ((void *)(from))
-			      : "memory", "0" );
+			      : "memory", "cc", "0" );
 	else
 		asm volatile ("   mvc  0(256,%0),0(%1)\n"
 			      "   mvc  256(256,%0),256(%1)\n"
diff -u --recursive --new-file v2.4.7/linux/include/asm-s390x/pci.h linux/include/asm-s390x/pci.h
--- v2.4.7/linux/include/asm-s390x/pci.h	Wed Dec 31 16:00:00 1969
+++ linux/include/asm-s390x/pci.h	Wed Jul 25 14:12:02 2001
@@ -0,0 +1,9 @@
+#ifndef __ASM_S390_PCI_H
+#define __ASM_S390_PCI_H
+
+/* S/390 systems don't have a PCI bus. This file is just here because some stupid .c code
+ * includes it even if CONFIG_PCI is not set.
+ */
+
+#endif /* __ASM_S390_PCI_H */
+
diff -u --recursive --new-file v2.4.7/linux/include/asm-s390x/pgalloc.h linux/include/asm-s390x/pgalloc.h
--- v2.4.7/linux/include/asm-s390x/pgalloc.h	Mon Apr 23 15:28:07 2001
+++ linux/include/asm-s390x/pgalloc.h	Wed Jul 25 14:12:02 2001
@@ -253,7 +253,7 @@
                 "    slr  2,2\n"
                 "    slr  3,3\n"
                 "    csp  2,4"
-                : : "a" (&dummy) : "2", "3", "4" );
+                : : "a" (&dummy) : "cc", "2", "3", "4" );
 }
 
 /*
diff -u --recursive --new-file v2.4.7/linux/include/asm-s390x/pgtable.h linux/include/asm-s390x/pgtable.h
--- v2.4.7/linux/include/asm-s390x/pgtable.h	Wed Apr 11 19:02:29 2001
+++ linux/include/asm-s390x/pgtable.h	Wed Jul 25 14:12:02 2001
@@ -180,7 +180,7 @@
  */
 #define _REGION_THIRD       0x4
 #define _REGION_THIRD_LEN   0x3 
-#define _REGION_TABLE       (_REGION_THIRD|_REGION_THIRD_LEN)
+#define _REGION_TABLE       (_REGION_THIRD|_REGION_THIRD_LEN|0x40)
 
 /* Bits in the storage key */
 #define _PAGE_CHANGED    0x02          /* HW changed bit                   */
@@ -363,7 +363,7 @@
 
 extern inline pte_t pte_mkold(pte_t pte)
 {
-	asm volatile ("rrbe 0,%0" : : "a" (pte_val(pte)));
+	asm volatile ("rrbe 0,%0" : : "a" (pte_val(pte)) : "cc" );
 	return pte;
 }
 
@@ -382,7 +382,8 @@
 
 	asm volatile ("rrbe 0,%1\n\t"
 		      "ipm  %0\n\t"
-		      "srl  %0,28\n\t" : "=d" (ccode) : "a" (pte_val(*ptep)));
+		      "srl  %0,28\n\t"
+		      : "=d" (ccode) : "a" (pte_val(*ptep)) : "cc" );
 	return ccode & 2;
 }
 
diff -u --recursive --new-file v2.4.7/linux/include/asm-s390x/processor.h linux/include/asm-s390x/processor.h
--- v2.4.7/linux/include/asm-s390x/processor.h	Tue Feb 13 14:13:44 2001
+++ linux/include/asm-s390x/processor.h	Wed Jul 25 14:12:02 2001
@@ -90,9 +90,11 @@
         __u32   error_code;            /* error-code of last prog-excep.   */
         __u32   trap_no;
         per_struct per_info;/* Must be aligned on an 4 byte boundary*/
-	addr_t  ieee_instruction_pointer; 
 	/* Used to give failing instruction back to user for ieee exceptions */
+	addr_t  ieee_instruction_pointer; 
 	unsigned long flags;            /* various flags */
+        /* pfault_wait is used to block the process on a pfault event */
+	addr_t  pfault_wait;
 };
 
 typedef struct thread_struct thread_struct;
@@ -109,7 +111,7 @@
               (__pa((addr_t) &swapper_pg_dir[0]) + _REGION_TABLE),\
                      0,0,0,                                       \
                      (per_struct) {{{{0,}}},0,0,0,0,{{0,}}},      \
-		     0					          \
+		     0, 0, 0				          \
 } 
 
 /* need to define ... */
@@ -220,7 +222,7 @@
                       "    stctg 0,15,0x380(1)\n" /* store control registers */
                       "    oi    0x384(1),0x10\n" /* fake protection bit */
                       "    lpswe 0(%0)"
-                      : : "a" (dw_psw), "a" (&ctl_buf) : "0", "1");
+                      : : "a" (dw_psw), "a" (&ctl_buf) : "cc", "0", "1");
 }
 
 #endif                                 /* __ASM_S390_PROCESSOR_H           */
diff -u --recursive --new-file v2.4.7/linux/include/asm-s390x/queue.h linux/include/asm-s390x/queue.h
--- v2.4.7/linux/include/asm-s390x/queue.h	Wed Apr 11 19:02:29 2001
+++ linux/include/asm-s390x/queue.h	Wed Jul 25 14:12:02 2001
@@ -7,7 +7,8 @@
  *
  *  A little set of queue utilies.
  */
-
+#ifndef __ASM_QUEUE_H
+#define __ASM_QUEUE_H
 #include <linux/stddef.h>
 
 typedef struct queue
@@ -29,12 +30,11 @@
 }
 
 static __inline__ void enqueue_tail(qheader *qhead,queue *member)
-{
-	queue *tail=qhead->tail;
-	member->next=NULL;
-	
+{	
 	if(member)
 	{
+		queue *tail=qhead->tail;
+
 		if(tail)
 			tail->next=member;
 		else
@@ -166,5 +166,5 @@
 	return(0);
 }
 
-
+#endif /* __ASM_QUEUE_H */
 
diff -u --recursive --new-file v2.4.7/linux/include/asm-s390x/s390dyn.h linux/include/asm-s390x/s390dyn.h
--- v2.4.7/linux/include/asm-s390x/s390dyn.h	Wed Apr 11 19:02:29 2001
+++ linux/include/asm-s390x/s390dyn.h	Wed Jul 25 14:12:02 2001
@@ -37,11 +37,14 @@
 	oper_handler_func_t  oper_func;
 } devreg_t;
 
-#define DEVREG_EXACT_MATCH      0x00000001
-#define DEVREG_MATCH_DEV_TYPE   0x00000002
-#define DEVREG_MATCH_CU_TYPE    0x00000004
-#define DEVREG_NO_CU_INFO       0x00000008
-#define DEVREG_NO_DEV_INFO      0x00000010
+#define DEVREG_MATCH_CU_TYPE    0x00000001
+#define DEVREG_MATCH_CU_MODEL   0x00000002
+#define DEVREG_MATCH_DEV_TYPE   0x00000004
+#define DEVREG_MATCH_DEV_MODEL  0x00000008
+
+#define DEVREG_EXACT_MATCH      (DEVREG_MATCH_CU_TYPE|DEVREG_MATCH_CU_MODEL|DEVREG_MATCH_DEV_TYPE|DEVREG_MATCH_DEV_MODEL)
+#define DEVREG_NO_CU_INFO       (DEVREG_MATCH_DEV_TYPE|DEVREG_MATCH_DEV_MODEL)
+#define DEVREG_NO_DEV_INFO      (DEVREG_MATCH_CU_TYPE|DEVREG_MATCH_CU_MODEL)
 
 #define DEVREG_TYPE_DEVNO       0x80000000
 #define DEVREG_TYPE_DEVCHARS    0x40000000
diff -u --recursive --new-file v2.4.7/linux/include/asm-s390x/setup.h linux/include/asm-s390x/setup.h
--- v2.4.7/linux/include/asm-s390x/setup.h	Wed Apr 11 19:02:29 2001
+++ linux/include/asm-s390x/setup.h	Wed Jul 25 14:12:02 2001
@@ -29,6 +29,22 @@
 #define MACHINE_IS_P390  (machine_flags & 4)
 #define MACHINE_HAS_MVPG (machine_flags & 16)
 
+#define MACHINE_HAS_HWC  (!MACHINE_IS_P390)
+
+/*
+ * Console mode. Override with conmode=
+ */
+extern unsigned int console_mode;
+extern unsigned int console_device;
+
+#define CONSOLE_IS_UNDEFINED	(console_mode == 0)
+#define CONSOLE_IS_HWC		(console_mode == 1)
+#define CONSOLE_IS_3215		(console_mode == 2)
+#define CONSOLE_IS_3270		(console_mode == 3)
+#define SET_CONSOLE_HWC		do { console_mode = 1; } while (0)
+#define SET_CONSOLE_3215	do { console_mode = 2; } while (0)
+#define SET_CONSOLE_3270	do { console_mode = 3; } while (0)
+
 #else 
 
 #define IPL_DEVICE        0x10400
diff -u --recursive --new-file v2.4.7/linux/include/asm-s390x/signal.h linux/include/asm-s390x/signal.h
--- v2.4.7/linux/include/asm-s390x/signal.h	Wed Apr 11 19:02:29 2001
+++ linux/include/asm-s390x/signal.h	Wed Jul 25 14:12:02 2001
@@ -166,9 +166,9 @@
           __sighandler_t _sa_handler;
           void (*_sa_sigaction)(int, struct siginfo *, void *);
         } _u;
-        sigset_t sa_mask;
         unsigned long sa_flags;
         void (*sa_restorer)(void);
+	sigset_t sa_mask;
 };
 
 #define sa_handler      _u._sa_handler
diff -u --recursive --new-file v2.4.7/linux/include/asm-s390x/softirq.h linux/include/asm-s390x/softirq.h
--- v2.4.7/linux/include/asm-s390x/softirq.h	Tue Feb 13 14:13:44 2001
+++ linux/include/asm-s390x/softirq.h	Wed Jul 25 14:12:02 2001
@@ -17,11 +17,28 @@
 #include <asm/hardirq.h>
 #include <asm/lowcore.h>
 
-#define cpu_bh_disable(cpu)	do { local_bh_count(cpu)++; barrier(); } while (0)
-#define cpu_bh_enable(cpu)	do { barrier(); local_bh_count(cpu)--; } while (0)
+#define local_bh_disable()			\
+do {						\
+	local_bh_count(smp_processor_id())++;	\
+	barrier();				\
+} while (0)
 
-#define local_bh_disable()	cpu_bh_disable(smp_processor_id())
-#define local_bh_enable()	cpu_bh_enable(smp_processor_id())
+#define __local_bh_enable()			\
+do {						\
+	barrier();				\
+	local_bh_count(smp_processor_id())--;	\
+} while (0)
+
+#define local_bh_enable()				\
+do {							\
+	if (!--local_bh_count(smp_processor_id())	\
+	    && softirq_pending(smp_processor_id())) {	\
+		do_softirq();				\
+		__sti();				\
+	}						\
+} while (0)
+
+#define __cpu_raise_softirq(cpu, nr) (softirq_pending(cpu) |= (1<<nr))
 
 #define in_softirq() (local_bh_count(smp_processor_id()) != 0)
 
diff -u --recursive --new-file v2.4.7/linux/include/asm-s390x/system.h linux/include/asm-s390x/system.h
--- v2.4.7/linux/include/asm-s390x/system.h	Wed Apr 11 19:02:29 2001
+++ linux/include/asm-s390x/system.h	Wed Jul 25 14:12:03 2001
@@ -63,7 +63,7 @@
                                 "   jl    1b\n"
                                 "   ex    0,4(2)"     /* store *ptr to x */
                                 : "+&a" (ptr) : "a" (&x)
-                                : "memory", "0", "1", "2");
+                                : "memory", "cc", "0", "1", "2");
 			break;
                 case 2:
                         if(((addr_t)ptr)&1)
@@ -86,7 +86,7 @@
                                 "   jl    1b\n"
                                 "   ex    0,4(2)"     /* store *ptr to x */
                                 : "+&a" (ptr) : "a" (&x)
-                                : "memory", "0", "1", "2");
+                                : "memory", "cc", "0", "1", "2");
                         break;
                 case 4:
                         if(((addr_t)ptr)&3)
@@ -97,7 +97,7 @@
                                 "    jl   0b\n"
                                 "    lgfr %0,0\n"
                                 : "+d" (x) : "a" (ptr)
-                                : "memory", "0" );
+                                : "memory", "cc", "0" );
                         break;
                 case 8:
                         if(((addr_t)ptr)&7)
@@ -108,7 +108,7 @@
                                 "    jl  0b\n"
                                 "    lgr %0,0\n"
                                 : "+d" (x) : "a" (ptr)
-                                : "memory", "0" );
+                                : "memory", "cc", "0" );
                         break;
                default:
                         abort();
@@ -161,7 +161,7 @@
         __asm__ __volatile__("ssm   %0" : : "m" (x) : "memory")
 
 #define __load_psw(psw) \
-        __asm__ __volatile__("lpswe %0" : : "m" (psw));
+        __asm__ __volatile__("lpswe %0" : : "m" (psw) : "cc" );
 
 #define __ctl_load(array, low, high) ({ \
 	__asm__ __volatile__ ( \
@@ -196,7 +196,7 @@
                 "    stg   0,0(1)\n" \
                 "1:  ex    %1,6(2)"      /* execute lctl */ \
                 : "=m" (dummy) : "a" (cr*17), "a" (1L<<(bit)) \
-                : "0", "1", "2"); \
+                : "cc", "0", "1", "2"); \
         })
 
 #define __ctl_clear_bit(cr, bit) ({ \
@@ -214,7 +214,7 @@
                 "    stg   0,0(1)\n" \
                 "1:  ex    %1,6(2)"      /* execute lctl */ \
                 : "=m" (dummy) : "a" (cr*17), "a" (~(1L<<(bit))) \
-                : "0", "1", "2"); \
+                : "cc", "0", "1", "2"); \
         })
 
 /* For spinlocks etc */
diff -u --recursive --new-file v2.4.7/linux/include/asm-s390x/termios.h linux/include/asm-s390x/termios.h
--- v2.4.7/linux/include/asm-s390x/termios.h	Tue Jul  3 17:08:21 2001
+++ linux/include/asm-s390x/termios.h	Wed Jul 25 14:12:03 2001
@@ -63,7 +63,7 @@
 #define N_IRDA		11	/* Linux IR - http://irda.sourceforge.net/ */
 #define N_SMSBLOCK	12	/* SMS block mode - for talking to GSM data cards about SMS messages */
 #define N_HDLC         13	/* synchronous HDLC */
-#define N_BT		15	/* bluetooth */
+#define N_HCI		15	/* Bluetooth HCI UART */
 
 #ifdef __KERNEL__
 
diff -u --recursive --new-file v2.4.7/linux/include/asm-s390x/uaccess.h linux/include/asm-s390x/uaccess.h
--- v2.4.7/linux/include/asm-s390x/uaccess.h	Wed Apr 11 19:02:29 2001
+++ linux/include/asm-s390x/uaccess.h	Wed Jul 25 14:12:03 2001
@@ -97,7 +97,7 @@
 				".previous"
                                 : "=m" (*((__u64*) ptr)) , "=&d" (err)
                                 : "d" (x), "K" (-EFAULT)
-                                : "4" );
+                                : "cc", "4" );
         return err;
 }
 extern inline int __put_user_asm_4(__u32 x, void *ptr)
@@ -119,7 +119,7 @@
 				".previous"
                                 : "=m" (*((__u32*) ptr)) , "=&d" (err)
                                 : "d" (x), "K" (-EFAULT)
-                                : "4" );
+                                : "cc", "4" );
         return err;
 }
 
@@ -142,7 +142,7 @@
 				".previous"
                                 : "=m" (*((__u16*) ptr)) , "=&d" (err)
                                 : "d" (x), "K" (-EFAULT)
-                                : "4" );
+                                : "cc", "4" );
         return err;
 }
 
@@ -165,7 +165,7 @@
 				".previous"
                                 : "=m" (*((__u8*) ptr)) , "=&d" (err)
                                 : "d" (x), "K" (-EFAULT)
-                                : "1", "4" );
+                                : "cc", "1", "4" );
         return err;
 }
 
@@ -228,7 +228,7 @@
                                 ".previous"                                \
                                 : "=d" (x) , "=&d" (err)                   \
                                 : "m" (*(const __u64*)(ptr)),"K" (-EFAULT) \
-                                : "4" );                                   \
+                                : "cc", "4" );                             \
 })
 #define __get_user_asm_4(x, ptr, err)                                      \
 ({                                                                         \
@@ -247,7 +247,7 @@
                                 ".previous"                                \
                                 : "=d" (x) , "=&d" (err)                   \
                                 : "m" (*(const __u32*)(ptr)),"K" (-EFAULT) \
-                                : "4" );                                   \
+                                : "cc", "4" );                             \
 })
 
 #define __get_user_asm_2(x, ptr, err)                                      \
@@ -267,7 +267,7 @@
                                 ".previous"                                \
                                 : "=d" (x) , "=&d" (err)                   \
                                 : "m" (*(const __u16*)(ptr)),"K" (-EFAULT) \
-                                : "4" );                                   \
+                                : "cc", "4" );                             \
 })
 
 #define __get_user_asm_1(x, ptr, err)                                     \
@@ -288,7 +288,7 @@
                                 ".previous"                               \
                                 : "=d" (x) , "=&d" (err)                  \
                                 : "m" (*(const __u8*)(ptr)),"K" (-EFAULT) \
-                                : "4" );                                  \
+                                : "cc", "4" );                            \
 })
 
 #define __get_user(x, ptr)                                      \
@@ -357,7 +357,7 @@
 				"   .quad  0b,__copy_to_user_fixup\n"
 				".previous"
                                 : "+&d" (n) : "d" (to), "d" (from)
-                                : "1", "2", "3", "4", "5" );
+                                : "cc", "1", "2", "3", "4", "5" );
         return n;
 }
 
@@ -395,7 +395,7 @@
 				"   .quad  0b,__copy_from_user_fixup\n"
 				".previous"
                                 : "+&d" (n) : "d" (to), "d" (from)
-                                : "1", "2", "3", "4", "5" );
+                                : "cc", "1", "2", "3", "4", "5" );
         return n;
 }
 
@@ -450,7 +450,7 @@
                                 : "=&a" (len)
                                 : "a"  (dst), "d" (src), "d" (count),
                                   "K" (-EFAULT)
-                                : "2" ,"3", "4" );
+                                : "cc", "2" ,"3", "4" );
         return len;
 }
 
diff -u --recursive --new-file v2.4.7/linux/include/asm-s390x/unistd.h linux/include/asm-s390x/unistd.h
--- v2.4.7/linux/include/asm-s390x/unistd.h	Fri Mar  2 11:12:06 2001
+++ linux/include/asm-s390x/unistd.h	Wed Jul 25 14:12:03 2001
@@ -179,7 +179,6 @@
 #define __NR_mincore            218
 #define __NR_madvise            219
 #define __NR_getdents64         220
-#define __NR_fcntl64            221
 
 
 /* user-visible error numbers are in the range -1 - -122: see <asm-s390/errno.h> */
diff -u --recursive --new-file v2.4.7/linux/include/asm-s390x/vtoc.h linux/include/asm-s390x/vtoc.h
--- v2.4.7/linux/include/asm-s390x/vtoc.h	Wed Apr 11 19:02:29 2001
+++ linux/include/asm-s390x/vtoc.h	Sun Aug  5 13:12:41 2001
@@ -15,41 +15,188 @@
 #include <linux/types.h>
 #include <linux/hdreg.h>
 #include <linux/version.h>
-#endif
 #include <asm/dasd.h>
+#endif
+
+#define DASD_API_VERSION 0
 
 #define LINE_LENGTH 80
 #define VTOC_START_CC 0x0
 #define VTOC_START_HH 0x1
+#define FIRST_USABLE_CYL 1
+#define FIRST_USABLE_TRK 2
+
+#define DASD_3380_TYPE 13148
+#define DASD_3390_TYPE 13200
+#define DASD_9345_TYPE 37701
+
+#define DASD_3380_VALUE 0xbb60
+#define DASD_3390_VALUE 0xe5a2
+#define DASD_9345_VALUE 0xbc98
+
+#define VOLSER_LENGTH 6
+#define BIG_DISK_SIZE 0x10000
+
+#define VTOC_ERROR "VTOC error:"
 
 enum failure {unable_to_open,
 	      unable_to_seek,
 	      unable_to_write,
 	      unable_to_read};
 
-typedef struct ttr {
+unsigned char ASCtoEBC[256] =
+{
+  /*00  NL    SH    SX    EX    ET    NQ    AK    BL */
+  0x00, 0x01, 0x02, 0x03, 0x37, 0x2D, 0x2E, 0x2F,
+  /*08  BS    HT    LF    VT    FF    CR    SO    SI */
+  0x16, 0x05, 0x15, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F,
+  /*10  DL    D1    D2    D3    D4    NK    SN    EB */
+  0x10, 0x11, 0x12, 0x13, 0x3C, 0x15, 0x32, 0x26,
+  /*18  CN    EM    SB    EC    FS    GS    RS    US */
+  0x18, 0x19, 0x3F, 0x27, 0x1C, 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, 0xAD, 0xE0, 0xBD, 0x5F, 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,
+  0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F,
+  0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F,
+  0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F,
+  0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F,
+  0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F,
+  0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F,
+  0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F,
+  0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F,
+  0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F,
+  0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F,
+  0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F,
+  0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F,
+  0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F,
+  0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F,
+  0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F,
+  0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0xFF
+};
+
+
+unsigned char EBCtoASC[256] =
+{
+ /* 0x00   NUL   SOH   STX   ETX  *SEL    HT  *RNL   DEL */
+          0x00, 0x01, 0x02, 0x03, 0x07, 0x09, 0x07, 0x7F,
+ /* 0x08   -GE  -SPS  -RPT    VT    FF    CR    SO    SI */
+          0x07, 0x07, 0x07, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F,
+ /* 0x10   DLE   DC1   DC2   DC3  -RES   -NL    BS  -POC
+                                  -ENP  ->LF             */
+          0x10, 0x11, 0x12, 0x13, 0x07, 0x0A, 0x08, 0x07,
+ /* 0x18   CAN    EM  -UBS  -CU1  -IFS  -IGS  -IRS  -ITB
+                                                    -IUS */
+          0x18, 0x19, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07,
+ /* 0x20   -DS  -SOS    FS  -WUS  -BYP    LF   ETB   ESC
+                                  -INP                   */
+          0x07, 0x07, 0x1C, 0x07, 0x07, 0x0A, 0x17, 0x1B,
+ /* 0x28   -SA  -SFE   -SM  -CSP  -MFA   ENQ   ACK   BEL
+                       -SW                               */ 
+          0x07, 0x07, 0x07, 0x07, 0x07, 0x05, 0x06, 0x07,
+ /* 0x30  ----  ----   SYN   -IR   -PP  -TRN  -NBS   EOT */
+          0x07, 0x07, 0x16, 0x07, 0x07, 0x07, 0x07, 0x04,
+ /* 0x38  -SBS   -IT  -RFF  -CU3   DC4   NAK  ----   SUB */
+          0x07, 0x07, 0x07, 0x07, 0x14, 0x15, 0x07, 0x1A,
+ /* 0x40    SP   RSP           ä              ----       */
+          0x20, 0xFF, 0x83, 0x84, 0x85, 0xA0, 0x07, 0x86,
+ /* 0x48                       .     <     (     +     | */
+          0x87, 0xA4, 0x9B, 0x2E, 0x3C, 0x28, 0x2B, 0x7C,
+ /* 0x50     &                                      ---- */
+          0x26, 0x82, 0x88, 0x89, 0x8A, 0xA1, 0x8C, 0x07,
+ /* 0x58           ß     !     $     *     )     ;       */
+          0x8D, 0xE1, 0x21, 0x24, 0x2A, 0x29, 0x3B, 0xAA,
+ /* 0x60     -     /  ----     Ä  ----  ----  ----       */
+          0x2D, 0x2F, 0x07, 0x8E, 0x07, 0x07, 0x07, 0x8F,
+ /* 0x68              ----     ,     %     _     >     ? */ 
+          0x80, 0xA5, 0x07, 0x2C, 0x25, 0x5F, 0x3E, 0x3F,
+ /* 0x70  ----        ----  ----  ----  ----  ----  ---- */
+          0x07, 0x90, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07,
+ /* 0x78     *     `     :     #     @     '     =     " */
+          0x70, 0x60, 0x3A, 0x23, 0x40, 0x27, 0x3D, 0x22,
+ /* 0x80     *     a     b     c     d     e     f     g */
+          0x07, 0x61, 0x62, 0x63, 0x64, 0x65, 0x66, 0x67,
+ /* 0x88     h     i              ----  ----  ----       */
+          0x68, 0x69, 0xAE, 0xAF, 0x07, 0x07, 0x07, 0xF1,
+ /* 0x90     °     j     k     l     m     n     o     p */
+          0xF8, 0x6A, 0x6B, 0x6C, 0x6D, 0x6E, 0x6F, 0x70,
+ /* 0x98     q     r                    ----        ---- */
+          0x71, 0x72, 0xA6, 0xA7, 0x91, 0x07, 0x92, 0x07,
+ /* 0xA0           ~     s     t     u     v     w     x */
+          0xE6, 0x7E, 0x73, 0x74, 0x75, 0x76, 0x77, 0x78,
+ /* 0xA8     y     z              ----  ----  ----  ---- */
+          0x79, 0x7A, 0xAD, 0xAB, 0x07, 0x07, 0x07, 0x07,
+ /* 0xB0     ^                    ----     §  ----       */
+          0x5E, 0x9C, 0x9D, 0xFA, 0x07, 0x07, 0x07, 0xAC,
+ /* 0xB8        ----     [     ]  ----  ----  ----  ---- */
+          0xAB, 0x07, 0x5B, 0x5D, 0x07, 0x07, 0x07, 0x07,
+ /* 0xC0     {     A     B     C     D     E     F     G */
+          0x7B, 0x41, 0x42, 0x43, 0x44, 0x45, 0x46, 0x47,
+ /* 0xC8     H     I  ----           ö              ---- */
+          0x48, 0x49, 0x07, 0x93, 0x94, 0x95, 0xA2, 0x07,
+ /* 0xD0     }     J     K     L     M     N     O     P */
+          0x7D, 0x4A, 0x4B, 0x4C, 0x4D, 0x4E, 0x4F, 0x50,
+ /* 0xD8     Q     R  ----           ü                   */
+          0x51, 0x52, 0x07, 0x96, 0x81, 0x97, 0xA3, 0x98,
+ /* 0xE0     \           S     T     U     V     W     X */
+          0x5C, 0xF6, 0x53, 0x54, 0x55, 0x56, 0x57, 0x58,
+ /* 0xE8     Y     Z        ----     Ö  ----  ----  ---- */
+          0x59, 0x5A, 0xFD, 0x07, 0x99, 0x07, 0x07, 0x07,
+ /* 0xF0     0     1     2     3     4     5     6     7 */
+          0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37,
+ /* 0xF8     8     9  ----  ----     Ü  ----  ----  ---- */
+          0x38, 0x39, 0x07, 0x07, 0x9A, 0x07, 0x07, 0x07
+};
+
+typedef struct ttr 
+{
         __u16 tt;
         __u8  r;
 } __attribute__ ((packed)) ttr_t;
 
-typedef struct cchhb {
+typedef struct cchhb 
+{
         __u16 cc;
         __u16 hh;
         __u8 b;
 } __attribute__ ((packed)) cchhb_t;
 
-typedef struct cchh {
+typedef struct cchh 
+{
         __u16 cc;
         __u16 hh;
 } __attribute__ ((packed)) cchh_t;
 
-typedef struct labeldate {
+typedef struct labeldate 
+{
         __u8  year;
         __u16 day;
 } __attribute__ ((packed)) labeldate_t;
 
 
-typedef struct volume_label {
+typedef struct volume_label 
+{
         char volkey[4];         /* volume key = volume label                 */
 	char vollbl[4];	        /* volume label                              */
 	char volid[6];	        /* volume identifier                         */
@@ -66,7 +213,8 @@
 } __attribute__ ((packed)) volume_label_t;
 
 
-typedef struct extent {
+typedef struct extent 
+{
         __u8  typeind;          /* extent type indicator                     */
         __u8  seqno;            /* extent sequence number                    */
         cchh_t llimit;          /* starting point of this extent             */
@@ -74,7 +222,8 @@
 } __attribute__ ((packed)) extent_t;
 
 
-typedef struct dev_const {
+typedef struct dev_const 
+{
         __u16 DS4DSCYL;           /* number of logical cyls                  */
         __u16 DS4DSTRK;           /* number of tracks in a logical cylinder  */
         __u16 DS4DEVTK;           /* device track length                     */
@@ -88,7 +237,8 @@
 } __attribute__ ((packed)) dev_const_t;
 
 
-typedef struct format1_label {
+typedef struct format1_label 
+{
 	char  DS1DSNAM[44];       /* data set name                           */
 	__u8  DS1FMTID;           /* format identifier                       */
 	char  DS1DSSN[6];         /* data set serial number                  */
@@ -124,7 +274,8 @@
 } __attribute__ ((packed)) format1_label_t;
 
 
-typedef struct format4_label {
+typedef struct format4_label 
+{
 	char  DS4KEYCD[44];       /* key code for VTOC labels: 44 times 0x04 */
         __u8  DS4IDFMT;           /* format identifier                       */
 	cchhb_t DS4HPCHR;         /* highest address of a format 1 DSCB      */
@@ -153,6 +304,43 @@
 } __attribute__ ((packed)) format4_label_t;
 
 
+typedef struct ds5ext 
+{
+	__u16 t;                  /* RTA of the first track of free extent   */
+	__u16 fc;                 /* number of whole cylinders in free ext.  */
+	__u8  ft;                 /* number of remaining free tracks         */
+} __attribute__ ((packed)) ds5ext_t;
+
+
+typedef struct format5_label 
+{
+	char DS5KEYID[4];         /* key identifier                          */
+	ds5ext_t DS5AVEXT;        /* first available (free-space) extent.    */
+	ds5ext_t DS5EXTAV[7];     /* seven available extents                 */
+	__u8 DS5FMTID;            /* format identifier                       */
+	ds5ext_t DS5MAVET[18];    /* eighteen available extents              */
+	cchhb_t DS5PTRDS[5];      /* pointer to next format5 DSCB            */
+} __attribute__ ((packed)) format5_label_t;
+
+
+typedef struct ds7ext 
+{
+	__u32 a;                  /* starting RTA value                      */
+	__u32 b;                  /* ending RTA value + 1                    */
+} __attribute__ ((packed)) ds7ext_t;
+
+
+typedef struct format7_label 
+{
+	char DS7KEYID[4];         /* key identifier                          */
+	ds7ext_t DS7EXTNT[5];     /* space for 5 extent descriptions         */
+	__u8 DS7FMTID;            /* format identifier                       */
+	ds7ext_t DS7ADEXT[11];    /* space for 11 extent descriptions        */
+	char res1[2];             /* reserved                                */
+	cchhb_t DS7PTRDS;         /* pointer to next FMT7 DSCB               */
+} __attribute__ ((packed)) format7_label_t;
+
+
 char * vtoc_ebcdic_enc (
         unsigned char source[LINE_LENGTH],
         unsigned char target[LINE_LENGTH],
@@ -181,45 +369,126 @@
         __u8 year,
         __u16 day);
 
+void vtoc_volume_label_init (
+	volume_label_t *vlabel);
 
 int vtoc_read_volume_label (
         char * device,
         unsigned long vlabel_start,
         volume_label_t * vlabel);
+
 int vtoc_write_volume_label (
-        char * device,
+        char *device,
         unsigned long vlabel_start,
-        volume_label_t * vlabel);
+        volume_label_t *vlabel);
+
+void vtoc_volume_label_set_volser (
+	volume_label_t *vlabel,
+	char *volser);
+
+char *vtoc_volume_label_get_volser (
+	volume_label_t *vlabel,
+	char *volser);
+
+void vtoc_volume_label_set_key (
+        volume_label_t *vlabel,
+        char *key);     
+
+void vtoc_volume_label_set_label (
+	volume_label_t *vlabel,
+	char *lbl);
+
+char *vtoc_volume_label_get_label (
+	volume_label_t *vlabel,
+	char *lbl);
+
 void vtoc_read_label (
         char *device,
         unsigned long position,
+        format1_label_t *f1,
         format4_label_t *f4,
-        format1_label_t *f1);
+        format5_label_t *f5,
+        format7_label_t *f7);
+
 void vtoc_write_label (
         char *device,
         unsigned long position,
+        format1_label_t *f1,
 	format4_label_t *f4,
-	format1_label_t *f1);
-void vtoc_init_format4_label (
-        struct hd_geometry *geo,
-        format4_label_t *f4lbl,
-	unsigned int usable_partitions,
-	unsigned int cylinders,
-	unsigned int tracks,
-	unsigned int blocks);
+	format5_label_t *f5,
+	format7_label_t *f7);
+
+
 void vtoc_init_format1_label (
         char *volid,
         unsigned int blksize,
         extent_t *part_extent,
         format1_label_t *f1);
+
+
+void vtoc_init_format4_label (
+        format4_label_t *f4lbl,
+	unsigned int usable_partitions,
+	unsigned int cylinders,
+	unsigned int tracks,
+	unsigned int blocks,
+	unsigned int blksize,
+	__u16 dev_type);
+
 void vtoc_update_format4_label (
 	format4_label_t *f4,
 	cchhb_t *highest_f1,
-	__u8 unused_update,
-	__u16 freespace_update);
+	__u16 unused_update);
+
 
+void vtoc_init_format5_label (
+	format5_label_t *f5);
 
+void vtoc_update_format5_label_add (
+	format5_label_t *f5,
+	int verbose,
+	int cyl,
+	int trk,
+	__u16 a, 
+	__u16 b, 
+	__u8 c);
+ 
+void vtoc_update_format5_label_del (
+	format5_label_t *f5,
+	int verbose,
+	int cyl,
+	int trk,
+	__u16 a, 
+	__u16 b, 
+	__u8 c);
+
+
+void vtoc_init_format7_label (
+	format7_label_t *f7);
+
+void vtoc_update_format7_label_add (
+	format7_label_t *f7,
+	int verbose,
+	__u32 a, 
+	__u32 b);
+
+void vtoc_update_format7_label_del (
+	format7_label_t *f7, 
+	int verbose,
+	__u32 a, 
+	__u32 b);
 
+
+void vtoc_set_freespace(
+	format4_label_t *f4,
+	format5_label_t *f5,
+	format7_label_t *f7,
+	char ch,
+	int verbose,
+	__u32 start,
+	__u32 stop,
+	int cyl,
+	int trk);
 
 
 
diff -u --recursive --new-file v2.4.7/linux/include/asm-sparc/bitops.h linux/include/asm-sparc/bitops.h
--- v2.4.7/linux/include/asm-sparc/bitops.h	Wed Jul 25 17:10:25 2001
+++ linux/include/asm-sparc/bitops.h	Sat Jul 28 12:12:38 2001
@@ -1,4 +1,4 @@
-/* $Id: bitops.h,v 1.63 2001/07/17 16:17:33 anton Exp $
+/* $Id: bitops.h,v 1.64 2001/07/18 13:48:23 anton Exp $
  * bitops.h: Bit string operations on the Sparc.
  *
  * Copyright 1995 David S. Miller (davem@caip.rutgers.edu)
@@ -25,22 +25,36 @@
 {
 	register unsigned long mask asm("g2");
 	register unsigned long *ADDR asm("g1");
+
 	ADDR = ((unsigned long *) addr) + (nr >> 5);
 	mask = 1 << (nr & 31);
+
 	__asm__ __volatile__("
 	mov	%%o7, %%g4
 	call	___set_bit
 	 add	%%o7, 8, %%o7
 "	: "=&r" (mask)
 	: "0" (mask), "r" (ADDR)
-	: "g3", "g4", "g5", "g7", "cc");
+	: "g3", "g4", "g5", "g7", "memory", "cc");
 
 	return mask != 0;
 }
 
 static __inline__ void set_bit(unsigned long nr, volatile void *addr)
 {
-	(void) test_and_set_bit(nr, addr);
+	register unsigned long mask asm("g2");
+	register unsigned long *ADDR asm("g1");
+
+	ADDR = ((unsigned long *) addr) + (nr >> 5);
+	mask = 1 << (nr & 31);
+
+	__asm__ __volatile__("
+	mov	%%o7, %%g4
+	call	___set_bit
+	 add	%%o7, 8, %%o7
+"	: "=&r" (mask)
+	: "0" (mask), "r" (ADDR)
+	: "g3", "g4", "g5", "g7", "cc");
 }
 
 static __inline__ int test_and_clear_bit(unsigned long nr, volatile void *addr)
@@ -50,20 +64,33 @@
 
 	ADDR = ((unsigned long *) addr) + (nr >> 5);
 	mask = 1 << (nr & 31);
+
 	__asm__ __volatile__("
 	mov	%%o7, %%g4
 	call	___clear_bit
 	 add	%%o7, 8, %%o7
 "	: "=&r" (mask)
 	: "0" (mask), "r" (ADDR)
-	: "g3", "g4", "g5", "g7", "cc");
+	: "g3", "g4", "g5", "g7", "memory", "cc");
 
 	return mask != 0;
 }
 
 static __inline__ void clear_bit(unsigned long nr, volatile void *addr)
 {
-	(void) test_and_clear_bit(nr, addr);
+	register unsigned long mask asm("g2");
+	register unsigned long *ADDR asm("g1");
+
+	ADDR = ((unsigned long *) addr) + (nr >> 5);
+	mask = 1 << (nr & 31);
+
+	__asm__ __volatile__("
+	mov	%%o7, %%g4
+	call	___clear_bit
+	 add	%%o7, 8, %%o7
+"	: "=&r" (mask)
+	: "0" (mask), "r" (ADDR)
+	: "g3", "g4", "g5", "g7", "cc");
 }
 
 static __inline__ int test_and_change_bit(unsigned long nr, volatile void *addr)
@@ -73,20 +100,33 @@
 
 	ADDR = ((unsigned long *) addr) + (nr >> 5);
 	mask = 1 << (nr & 31);
+
 	__asm__ __volatile__("
 	mov	%%o7, %%g4
 	call	___change_bit
 	 add	%%o7, 8, %%o7
 "	: "=&r" (mask)
 	: "0" (mask), "r" (ADDR)
-	: "g3", "g4", "g5", "g7", "cc");
+	: "g3", "g4", "g5", "g7", "memory", "cc");
 
 	return mask != 0;
 }
 
 static __inline__ void change_bit(unsigned long nr, volatile void *addr)
 {
-	(void) test_and_change_bit(nr, addr);
+	register unsigned long mask asm("g2");
+	register unsigned long *ADDR asm("g1");
+
+	ADDR = ((unsigned long *) addr) + (nr >> 5);
+	mask = 1 << (nr & 31);
+
+	__asm__ __volatile__("
+	mov	%%o7, %%g4
+	call	___change_bit
+	 add	%%o7, 8, %%o7
+"	: "=&r" (mask)
+	: "0" (mask), "r" (ADDR)
+	: "g3", "g4", "g5", "g7", "cc");
 }
 
 /*
diff -u --recursive --new-file v2.4.7/linux/include/linux/blkdev.h linux/include/linux/blkdev.h
--- v2.4.7/linux/include/linux/blkdev.h	Sat Jul 28 18:20:14 2001
+++ linux/include/linux/blkdev.h	Mon Aug  6 22:24:42 2001
@@ -14,9 +14,7 @@
 
 /*
  * Ok, this is an expanded form so that we can use the same
- * request for paging requests when that is implemented. In
- * paging, 'bh' is NULL, and the completion is used to wait
- * for the IO to be ready.
+ * request for paging requests.
  */
 struct request {
 	struct list_head queue;
@@ -176,8 +174,6 @@
 
 extern int * max_segments[MAX_BLKDEV];
 
-extern atomic_t queued_sectors;
-
 #define MAX_SEGMENTS 128
 #define MAX_SECTORS 255
 
@@ -205,14 +201,7 @@
 		return 512;
 }
 
-#define blk_finished_io(nsects)				\
-	atomic_sub(nsects, &queued_sectors);		\
-	if (atomic_read(&queued_sectors) < 0) {		\
-		printk("block: queued_sectors < 0\n");	\
-		atomic_set(&queued_sectors, 0);		\
-	}
-
-#define blk_started_io(nsects)				\
-	atomic_add(nsects, &queued_sectors);
+#define blk_finished_io(nsects)	do { } while (0)
+#define blk_started_io(nsects)	do { } while (0)
 
 #endif
diff -u --recursive --new-file v2.4.7/linux/include/linux/byteorder/swab.h linux/include/linux/byteorder/swab.h
--- v2.4.7/linux/include/linux/byteorder/swab.h	Mon Oct 16 13:36:08 2000
+++ linux/include/linux/byteorder/swab.h	Thu Jul 26 13:45:47 2001
@@ -128,34 +128,34 @@
 #endif /* OPTIMIZE */
 
 
-extern __inline__ __const__ __u16 __fswab16(__u16 x)
+static __inline__ __const__ __u16 __fswab16(__u16 x)
 {
 	return __arch__swab16(x);
 }
-extern __inline__ __u16 __swab16p(__u16 *x)
+static __inline__ __u16 __swab16p(__u16 *x)
 {
 	return __arch__swab16p(x);
 }
-extern __inline__ void __swab16s(__u16 *addr)
+static __inline__ void __swab16s(__u16 *addr)
 {
 	__arch__swab16s(addr);
 }
 
-extern __inline__ __const__ __u32 __fswab32(__u32 x)
+static __inline__ __const__ __u32 __fswab32(__u32 x)
 {
 	return __arch__swab32(x);
 }
-extern __inline__ __u32 __swab32p(__u32 *x)
+static __inline__ __u32 __swab32p(__u32 *x)
 {
 	return __arch__swab32p(x);
 }
-extern __inline__ void __swab32s(__u32 *addr)
+static __inline__ void __swab32s(__u32 *addr)
 {
 	__arch__swab32s(addr);
 }
 
 #ifdef __BYTEORDER_HAS_U64__
-extern __inline__ __const__ __u64 __fswab64(__u64 x)
+static __inline__ __const__ __u64 __fswab64(__u64 x)
 {
 #  ifdef __SWAB_64_THRU_32__
 	__u32 h = x >> 32;
@@ -165,11 +165,11 @@
 	return __arch__swab64(x);
 #  endif
 }
-extern __inline__ __u64 __swab64p(__u64 *x)
+static __inline__ __u64 __swab64p(__u64 *x)
 {
 	return __arch__swab64p(x);
 }
-extern __inline__ void __swab64s(__u64 *addr)
+static __inline__ void __swab64s(__u64 *addr)
 {
 	__arch__swab64s(addr);
 }
diff -u --recursive --new-file v2.4.7/linux/include/linux/byteorder/swabb.h linux/include/linux/byteorder/swabb.h
--- v2.4.7/linux/include/linux/byteorder/swabb.h	Fri Nov 17 21:31:50 2000
+++ linux/include/linux/byteorder/swabb.h	Thu Jul 26 13:47:44 2001
@@ -92,29 +92,29 @@
 #endif /* OPTIMIZE */
 
 
-extern __inline__ __const__ __u32 __fswahw32(__u32 x)
+static __inline__ __const__ __u32 __fswahw32(__u32 x)
 {
 	return __arch__swahw32(x);
 }
-extern __inline__ __u32 __swahw32p(__u32 *x)
+static __inline__ __u32 __swahw32p(__u32 *x)
 {
 	return __arch__swahw32p(x);
 }
-extern __inline__ void __swahw32s(__u32 *addr)
+static __inline__ void __swahw32s(__u32 *addr)
 {
 	__arch__swahw32s(addr);
 }
 
 
-extern __inline__ __const__ __u32 __fswahb32(__u32 x)
+static __inline__ __const__ __u32 __fswahb32(__u32 x)
 {
 	return __arch__swahb32(x);
 }
-extern __inline__ __u32 __swahb32p(__u32 *x)
+static __inline__ __u32 __swahb32p(__u32 *x)
 {
 	return __arch__swahb32p(x);
 }
-extern __inline__ void __swahb32s(__u32 *addr)
+static __inline__ void __swahb32s(__u32 *addr)
 {
 	__arch__swahb32s(addr);
 }
diff -u --recursive --new-file v2.4.7/linux/include/linux/dcache.h linux/include/linux/dcache.h
--- v2.4.7/linux/include/linux/dcache.h	Sat Jul 28 18:18:23 2001
+++ linux/include/linux/dcache.h	Mon Aug  6 21:40:17 2001
@@ -171,11 +171,11 @@
 #define shrink_dcache() prune_dcache(0)
 struct zone_struct;
 /* dcache memory management */
-extern void shrink_dcache_memory(int, unsigned int);
+extern int shrink_dcache_memory(int, unsigned int);
 extern void prune_dcache(int);
 
 /* icache memory management (defined in linux/fs/inode.c) */
-extern void shrink_icache_memory(int, int);
+extern int shrink_icache_memory(int, int);
 extern void prune_icache(int);
 
 /* only used at mount-time */
diff -u --recursive --new-file v2.4.7/linux/include/linux/fs.h linux/include/linux/fs.h
--- v2.4.7/linux/include/linux/fs.h	Sat Jul 28 18:18:24 2001
+++ linux/include/linux/fs.h	Tue Aug  7 00:17:49 2001
@@ -997,7 +997,7 @@
 	return 0;
 }
 
-extern inline int get_lease(struct inode *inode, unsigned int mode)
+static inline int get_lease(struct inode *inode, unsigned int mode)
 {
 	if (inode->i_flock && (inode->i_flock->fl_flags & FL_LEASE))
 		return __get_lease(inode, mode);
@@ -1316,7 +1316,7 @@
 }
 extern void set_blocksize(kdev_t, int);
 extern struct buffer_head * bread(kdev_t, int, int);
-extern void wakeup_bdflush(int wait);
+extern void wakeup_bdflush(void);
 
 extern int brw_page(int, struct page *, kdev_t, int [], int);
 
@@ -1342,7 +1342,7 @@
 extern ssize_t generic_file_read(struct file *, char *, size_t, loff_t *);
 extern ssize_t generic_file_write(struct file *, const char *, size_t, loff_t *);
 extern void do_generic_file_read(struct file *, loff_t *, read_descriptor_t *, read_actor_t);
-
+extern loff_t generic_file_llseek(struct file *file, loff_t offset, int origin);
 extern ssize_t generic_read_dir(struct file *, char *, size_t, loff_t *);
 
 extern struct file_operations generic_ro_fops;
diff -u --recursive --new-file v2.4.7/linux/include/linux/hdlc.h linux/include/linux/hdlc.h
--- v2.4.7/linux/include/linux/hdlc.h	Tue Mar  6 19:44:37 2001
+++ linux/include/linux/hdlc.h	Thu Jul 26 13:51:45 2001
@@ -210,43 +210,43 @@
 void hdlc_netif_rx(hdlc_device *hdlc, struct sk_buff *skb);
 
 
-extern __inline__ struct net_device* hdlc_to_dev(hdlc_device *hdlc)
+static __inline__ struct net_device* hdlc_to_dev(hdlc_device *hdlc)
 {
 	return &hdlc->netdev;
 }
 
 
-extern __inline__ hdlc_device* dev_to_hdlc(struct net_device *dev)
+static __inline__ hdlc_device* dev_to_hdlc(struct net_device *dev)
 {
 	return (hdlc_device*)dev;
 }
 
 
-extern __inline__ struct net_device* pvc_to_dev(pvc_device *pvc)
+static __inline__ struct net_device* pvc_to_dev(pvc_device *pvc)
 {
 	return &pvc->netdev;
 }
 
 
-extern __inline__ pvc_device* dev_to_pvc(struct net_device *dev)
+static __inline__ pvc_device* dev_to_pvc(struct net_device *dev)
 {
 	return (pvc_device*)dev;
 }
 
 
-extern __inline__ const char *hdlc_to_name(hdlc_device *hdlc)
+static __inline__ const char *hdlc_to_name(hdlc_device *hdlc)
 {
 	return hdlc_to_dev(hdlc)->name;
 }
 
 
-extern __inline__ const char *pvc_to_name(pvc_device *pvc)
+static __inline__ const char *pvc_to_name(pvc_device *pvc)
 {
 	return pvc_to_dev(pvc)->name;
 }
 
 
-extern __inline__ u16 status_to_dlci(hdlc_device *hdlc, u8 *status, u8 *state)
+static __inline__ u16 status_to_dlci(hdlc_device *hdlc, u8 *status, u8 *state)
 {
 	*state &= ~(PVC_STATE_ACTIVE | PVC_STATE_NEW);
 	if (status[2] & 0x08)
@@ -258,7 +258,7 @@
 }
 
 
-extern __inline__ void dlci_to_status(hdlc_device *hdlc, u16 dlci, u8 *status,
+static __inline__ void dlci_to_status(hdlc_device *hdlc, u16 dlci, u8 *status,
 				      u8 state)
 {
 	status[0] = (dlci>>4) & 0x3F;
@@ -273,21 +273,21 @@
 
 
 
-extern __inline__ u16 netdev_dlci(struct net_device *dev)
+static __inline__ u16 netdev_dlci(struct net_device *dev)
 {
 	return ntohs(*(u16*)dev->dev_addr);
 }
 
 
 
-extern __inline__ u16 q922_to_dlci(u8 *hdr)
+static __inline__ u16 q922_to_dlci(u8 *hdr)
 {
 	return ((hdr[0] & 0xFC)<<2) | ((hdr[1] & 0xF0)>>4);
 }
 
 
 
-extern __inline__ void dlci_to_q922(u8 *hdr, u16 dlci)
+static __inline__ void dlci_to_q922(u8 *hdr, u16 dlci)
 {
 	hdr[0] = (dlci>>2) & 0xFC;
 	hdr[1] = ((dlci<<4) & 0xF0) | 0x01;
@@ -295,14 +295,14 @@
 
 
 
-extern __inline__ int mode_is(hdlc_device *hdlc, int mask)
+static __inline__ int mode_is(hdlc_device *hdlc, int mask)
 {
 	return (hdlc->mode & mask) == mask;
 }
 
 
 
-extern __inline__ pvc_device* find_pvc(hdlc_device *hdlc, u16 dlci)
+static __inline__ pvc_device* find_pvc(hdlc_device *hdlc, u16 dlci)
 {
 	pvc_device *pvc=hdlc->first_pvc;
 	
@@ -317,7 +317,7 @@
 
 
 
-extern __inline__ void debug_frame(const struct sk_buff *skb)
+static __inline__ void debug_frame(const struct sk_buff *skb)
 {
 	int i;
 
diff -u --recursive --new-file v2.4.7/linux/include/linux/i2c-dev.h linux/include/linux/i2c-dev.h
--- v2.4.7/linux/include/linux/i2c-dev.h	Fri Dec 29 14:35:47 2000
+++ linux/include/linux/i2c-dev.h	Thu Jul 26 13:52:54 2001
@@ -49,7 +49,7 @@
 
 #include <sys/ioctl.h>
 
-extern inline __s32 i2c_smbus_access(int file, char read_write, __u8 command, 
+static inline __s32 i2c_smbus_access(int file, char read_write, __u8 command, 
                                      int size, union i2c_smbus_data *data)
 {
 	struct i2c_smbus_ioctl_data args;
@@ -62,12 +62,12 @@
 }
 
 
-extern inline __s32 i2c_smbus_write_quick(int file, __u8 value)
+static inline __s32 i2c_smbus_write_quick(int file, __u8 value)
 {
 	return i2c_smbus_access(file,value,0,I2C_SMBUS_QUICK,NULL);
 }
 	
-extern inline __s32 i2c_smbus_read_byte(int file)
+static inline __s32 i2c_smbus_read_byte(int file)
 {
 	union i2c_smbus_data data;
 	if (i2c_smbus_access(file,I2C_SMBUS_READ,0,I2C_SMBUS_BYTE,&data))
@@ -76,13 +76,13 @@
 		return 0x0FF & data.byte;
 }
 
-extern inline __s32 i2c_smbus_write_byte(int file, __u8 value)
+static inline __s32 i2c_smbus_write_byte(int file, __u8 value)
 {
 	return i2c_smbus_access(file,I2C_SMBUS_WRITE,value,
 	                        I2C_SMBUS_BYTE,NULL);
 }
 
-extern inline __s32 i2c_smbus_read_byte_data(int file, __u8 command)
+static inline __s32 i2c_smbus_read_byte_data(int file, __u8 command)
 {
 	union i2c_smbus_data data;
 	if (i2c_smbus_access(file,I2C_SMBUS_READ,command,
@@ -92,7 +92,7 @@
 		return 0x0FF & data.byte;
 }
 
-extern inline __s32 i2c_smbus_write_byte_data(int file, __u8 command, 
+static inline __s32 i2c_smbus_write_byte_data(int file, __u8 command, 
                                               __u8 value)
 {
 	union i2c_smbus_data data;
@@ -101,7 +101,7 @@
 	                        I2C_SMBUS_BYTE_DATA, &data);
 }
 
-extern inline __s32 i2c_smbus_read_word_data(int file, __u8 command)
+static inline __s32 i2c_smbus_read_word_data(int file, __u8 command)
 {
 	union i2c_smbus_data data;
 	if (i2c_smbus_access(file,I2C_SMBUS_READ,command,
@@ -111,7 +111,7 @@
 		return 0x0FFFF & data.word;
 }
 
-extern inline __s32 i2c_smbus_write_word_data(int file, __u8 command, 
+static inline __s32 i2c_smbus_write_word_data(int file, __u8 command, 
                                               __u16 value)
 {
 	union i2c_smbus_data data;
@@ -120,7 +120,7 @@
 	                        I2C_SMBUS_WORD_DATA, &data);
 }
 
-extern inline __s32 i2c_smbus_process_call(int file, __u8 command, __u16 value)
+static inline __s32 i2c_smbus_process_call(int file, __u8 command, __u16 value)
 {
 	union i2c_smbus_data data;
 	data.word = value;
@@ -133,7 +133,7 @@
 
 
 /* Returns the number of read bytes */
-extern inline __s32 i2c_smbus_read_block_data(int file, __u8 command, 
+static inline __s32 i2c_smbus_read_block_data(int file, __u8 command, 
                                               __u8 *values)
 {
 	union i2c_smbus_data data;
@@ -148,7 +148,7 @@
 	}
 }
 
-extern inline __s32 i2c_smbus_write_block_data(int file, __u8 command, 
+static inline __s32 i2c_smbus_write_block_data(int file, __u8 command, 
                                                __u8 length, __u8 *values)
 {
 	union i2c_smbus_data data;
@@ -162,7 +162,7 @@
 	                        I2C_SMBUS_BLOCK_DATA, &data);
 }
 
-extern inline __s32 i2c_smbus_write_i2c_block_data(int file, __u8 command,
+static inline __s32 i2c_smbus_write_i2c_block_data(int file, __u8 command,
                                                __u8 length, __u8 *values)
 {
 	union i2c_smbus_data data;
diff -u --recursive --new-file v2.4.7/linux/include/linux/i2o.h linux/include/linux/i2o.h
--- v2.4.7/linux/include/linux/i2o.h	Tue May  1 16:17:18 2001
+++ linux/include/linux/i2o.h	Thu Jul 26 13:53:55 2001
@@ -240,47 +240,47 @@
 /*
  *	Messenger inlines
  */
-extern inline u32 I2O_POST_READ32(struct i2o_controller *c)
+static inline u32 I2O_POST_READ32(struct i2o_controller *c)
 {
 	return *c->post_port;
 }
 
-extern inline void I2O_POST_WRITE32(struct i2o_controller *c, u32 Val)
+static inline void I2O_POST_WRITE32(struct i2o_controller *c, u32 Val)
 {
 	*c->post_port = Val;
 }
 
 
-extern inline u32 I2O_REPLY_READ32(struct i2o_controller *c)
+static inline u32 I2O_REPLY_READ32(struct i2o_controller *c)
 {
 	return *c->reply_port;
 }
 
-extern inline void I2O_REPLY_WRITE32(struct i2o_controller *c, u32 Val)
+static inline void I2O_REPLY_WRITE32(struct i2o_controller *c, u32 Val)
 {
 	*c->reply_port= Val;
 }
  
 
-extern inline u32 I2O_IRQ_READ32(struct i2o_controller *c)
+static inline u32 I2O_IRQ_READ32(struct i2o_controller *c)
 {
 	return *c->irq_mask;
 }
 
-extern inline void I2O_IRQ_WRITE32(struct i2o_controller *c, u32 Val)
+static inline void I2O_IRQ_WRITE32(struct i2o_controller *c, u32 Val)
 {
 	*c->irq_mask = Val;
 }
 
 
-extern inline void i2o_post_message(struct i2o_controller *c, u32 m)
+static inline void i2o_post_message(struct i2o_controller *c, u32 m)
 {
 	/* The second line isnt spurious - thats forcing PCI posting */
 	I2O_POST_WRITE32(c,m);
 	(void) I2O_IRQ_READ32(c);
 }
 
-extern inline void i2o_flush_reply(struct i2o_controller *c, u32 m)
+static inline void i2o_flush_reply(struct i2o_controller *c, u32 m)
 {
 	I2O_REPLY_WRITE32(c,m);
 }
diff -u --recursive --new-file v2.4.7/linux/include/linux/ibmtr.h linux/include/linux/ibmtr.h
--- v2.4.7/linux/include/linux/ibmtr.h	Wed Jul 25 17:10:26 2001
+++ linux/include/linux/ibmtr.h	Sun Aug  5 13:12:41 2001
@@ -169,7 +169,7 @@
 
 struct tok_info {
 	unsigned char irq;
-	__u32 mmio;
+	void *mmio;
 	unsigned char hw_address[32];
 	unsigned char adapter_type;
 	unsigned char data_rate;
diff -u --recursive --new-file v2.4.7/linux/include/linux/inetdevice.h linux/include/linux/inetdevice.h
--- v2.4.7/linux/include/linux/inetdevice.h	Wed May 16 10:21:45 2001
+++ linux/include/linux/inetdevice.h	Thu Jul 26 13:52:39 2001
@@ -85,7 +85,7 @@
 extern struct in_ifaddr *inet_ifa_byprefix(struct in_device *in_dev, u32 prefix, u32 mask);
 extern void		inet_forward_change(void);
 
-extern __inline__ int inet_ifa_match(u32 addr, struct in_ifaddr *ifa)
+static __inline__ int inet_ifa_match(u32 addr, struct in_ifaddr *ifa)
 {
 	return !((addr^ifa->ifa_address)&ifa->ifa_mask);
 }
@@ -94,7 +94,7 @@
  *	Check if a mask is acceptable.
  */
  
-extern __inline__ int bad_mask(u32 mask, u32 addr)
+static __inline__ int bad_mask(u32 mask, u32 addr)
 {
 	if (addr & (mask = ~mask))
 		return 1;
@@ -116,7 +116,7 @@
 extern rwlock_t inetdev_lock;
 
 
-extern __inline__ struct in_device *
+static __inline__ struct in_device *
 in_dev_get(const struct net_device *dev)
 {
 	struct in_device *in_dev;
@@ -129,7 +129,7 @@
 	return in_dev;
 }
 
-extern __inline__ struct in_device *
+static __inline__ struct in_device *
 __in_dev_get(const struct net_device *dev)
 {
 	return (struct in_device*)dev->ip_ptr;
@@ -137,7 +137,7 @@
 
 extern void in_dev_finish_destroy(struct in_device *idev);
 
-extern __inline__ void
+static __inline__ void
 in_dev_put(struct in_device *idev)
 {
 	if (atomic_dec_and_test(&idev->refcnt))
@@ -149,14 +149,14 @@
 
 #endif /* __KERNEL__ */
 
-extern __inline__ __u32 inet_make_mask(int logmask)
+static __inline__ __u32 inet_make_mask(int logmask)
 {
 	if (logmask)
 		return htonl(~((1<<(32-logmask))-1));
 	return 0;
 }
 
-extern __inline__ int inet_mask_len(__u32 mask)
+static __inline__ int inet_mask_len(__u32 mask)
 {
 	if (!(mask = ntohl(mask)))
 		return 0;
diff -u --recursive --new-file v2.4.7/linux/include/linux/init.h linux/include/linux/init.h
--- v2.4.7/linux/include/linux/init.h	Sat Jul 28 18:18:23 2001
+++ linux/include/linux/init.h	Mon Aug  6 21:40:17 2001
@@ -132,11 +132,11 @@
 typedef void (*__cleanup_module_func_t)(void);
 #define module_init(x) \
 	int init_module(void) __attribute__((alias(#x))); \
-	extern inline __init_module_func_t __init_module_inline(void) \
+	static inline __init_module_func_t __init_module_inline(void) \
 	{ return x; }
 #define module_exit(x) \
 	void cleanup_module(void) __attribute__((alias(#x))); \
-	extern inline __cleanup_module_func_t __cleanup_module_inline(void) \
+	static inline __cleanup_module_func_t __cleanup_module_inline(void) \
 	{ return x; }
 
 #define __setup(str,func) /* nothing */
diff -u --recursive --new-file v2.4.7/linux/include/linux/interrupt.h linux/include/linux/interrupt.h
--- v2.4.7/linux/include/linux/interrupt.h	Sat Jul 28 18:18:24 2001
+++ linux/include/linux/interrupt.h	Mon Aug  6 21:40:18 2001
@@ -118,7 +118,7 @@
 enum
 {
 	TASKLET_STATE_SCHED,	/* Tasklet is scheduled for execution */
-	TASKLET_STATE_RUN	/* Tasklet is running */
+	TASKLET_STATE_RUN	/* Tasklet is running (SMP only) */
 };
 
 struct tasklet_head
@@ -129,34 +129,68 @@
 extern struct tasklet_head tasklet_vec[NR_CPUS];
 extern struct tasklet_head tasklet_hi_vec[NR_CPUS];
 
-#define tasklet_trylock(t) (!test_and_set_bit(TASKLET_STATE_RUN, &(t)->state))
-#define tasklet_unlock(t) do { smp_mb__before_clear_bit(); clear_bit(TASKLET_STATE_RUN, &(t)->state); } while(0)
-#define tasklet_unlock_wait(t) while (test_bit(TASKLET_STATE_RUN, &(t)->state)) { barrier(); }
+#ifdef CONFIG_SMP
+static inline int tasklet_trylock(struct tasklet_struct *t)
+{
+	return !test_and_set_bit(TASKLET_STATE_RUN, &(t)->state);
+}
+
+static inline void tasklet_unlock(struct tasklet_struct *t)
+{
+	smp_mb__before_clear_bit(); 
+	clear_bit(TASKLET_STATE_RUN, &(t)->state);
+}
+
+static inline void tasklet_unlock_wait(struct tasklet_struct *t)
+{
+	while (test_bit(TASKLET_STATE_RUN, &(t)->state)) { barrier(); }
+}
+#else
+#define tasklet_trylock(t) 1
+#define tasklet_unlock_wait(t) do { } while (0)
+#define tasklet_unlock(t) do { } while (0)
+#endif
+
+extern void FASTCALL(__tasklet_schedule(struct tasklet_struct *t));
+
+static inline void tasklet_schedule(struct tasklet_struct *t)
+{
+	if (!test_and_set_bit(TASKLET_STATE_SCHED, &t->state))
+		__tasklet_schedule(t);
+}
+
+extern void FASTCALL(__tasklet_hi_schedule(struct tasklet_struct *t));
+
+static inline void tasklet_hi_schedule(struct tasklet_struct *t)
+{
+	if (!test_and_set_bit(TASKLET_STATE_SCHED, &t->state))
+		__tasklet_hi_schedule(t);
+}
 
-extern void tasklet_schedule(struct tasklet_struct *t);
-extern void tasklet_hi_schedule(struct tasklet_struct *t);
 
 static inline void tasklet_disable_nosync(struct tasklet_struct *t)
 {
 	atomic_inc(&t->count);
+	smp_mb__after_atomic_inc();
 }
 
 static inline void tasklet_disable(struct tasklet_struct *t)
 {
 	tasklet_disable_nosync(t);
 	tasklet_unlock_wait(t);
+	smp_mb();
 }
 
 static inline void tasklet_enable(struct tasklet_struct *t)
 {
-	if (atomic_dec_and_test(&t->count))
-		tasklet_schedule(t);
+	smp_mb__before_atomic_dec();
+	atomic_dec(&t->count);
 }
 
 static inline void tasklet_hi_enable(struct tasklet_struct *t)
 {
-	if (atomic_dec_and_test(&t->count))
-		tasklet_hi_schedule(t);
+	smp_mb__before_atomic_dec();
+	atomic_dec(&t->count);
 }
 
 extern void tasklet_kill(struct tasklet_struct *t);
diff -u --recursive --new-file v2.4.7/linux/include/linux/ipsec.h linux/include/linux/ipsec.h
--- v2.4.7/linux/include/linux/ipsec.h	Sat Jul 28 18:19:01 2001
+++ linux/include/linux/ipsec.h	Mon Aug  6 22:28:59 2001
@@ -49,7 +49,7 @@
  */
  
 #ifdef CONFIG_NET_SECURITY
-extern __inline__ int ipsec_sk_policy(struct sock *sk, struct sk_buff *skb)
+static __inline__ int ipsec_sk_policy(struct sock *sk, struct sk_buff *skb)
 {
 	return ((sk->authentication < IPSEC_LEVEL_REQUIRE) ||
 		(skb->security & RCV_AUTH)) &&
@@ -59,7 +59,7 @@
 
 #else
 
-extern __inline__ int ipsec_sk_policy(struct sock *sk, struct sk_buff *skb)
+static __inline__ int ipsec_sk_policy(struct sock *sk, struct sk_buff *skb)
 {
 	return 1;
 }
diff -u --recursive --new-file v2.4.7/linux/include/linux/isapnp.h linux/include/linux/isapnp.h
--- v2.4.7/linux/include/linux/isapnp.h	Sat Jul 28 18:21:14 2001
+++ linux/include/linux/isapnp.h	Mon Aug  6 22:24:42 2001
@@ -217,37 +217,37 @@
 #else /* !CONFIG_ISAPNP */
 
 /* lowlevel configuration */
-extern inline int isapnp_present(void) { return 0; }
-extern inline int isapnp_cfg_begin(int csn, int device) { return -ENODEV; }
-extern inline int isapnp_cfg_end(void) { return -ENODEV; }
-extern inline unsigned char isapnp_read_byte(unsigned char idx) { return 0xff; }
-extern inline unsigned short isapnp_read_word(unsigned char idx) { return 0xffff; }
-extern inline unsigned int isapnp_read_dword(unsigned char idx) { return 0xffffffff; }
-extern inline void isapnp_write_byte(unsigned char idx, unsigned char val) { ; }
-extern inline void isapnp_write_word(unsigned char idx, unsigned short val) { ; }
-extern inline void isapnp_write_dword(unsigned char idx, unsigned int val) { ; }
-extern inline void isapnp_wake(unsigned char csn) { ; }
-extern inline void isapnp_device(unsigned char device) { ; }
-extern inline void isapnp_activate(unsigned char device) { ; }
-extern inline void isapnp_deactivate(unsigned char device) { ; }
+static inline int isapnp_present(void) { return 0; }
+static inline int isapnp_cfg_begin(int csn, int device) { return -ENODEV; }
+static inline int isapnp_cfg_end(void) { return -ENODEV; }
+static inline unsigned char isapnp_read_byte(unsigned char idx) { return 0xff; }
+static inline unsigned short isapnp_read_word(unsigned char idx) { return 0xffff; }
+static inline unsigned int isapnp_read_dword(unsigned char idx) { return 0xffffffff; }
+static inline void isapnp_write_byte(unsigned char idx, unsigned char val) { ; }
+static inline void isapnp_write_word(unsigned char idx, unsigned short val) { ; }
+static inline void isapnp_write_dword(unsigned char idx, unsigned int val) { ; }
+static inline void isapnp_wake(unsigned char csn) { ; }
+static inline void isapnp_device(unsigned char device) { ; }
+static inline void isapnp_activate(unsigned char device) { ; }
+static inline void isapnp_deactivate(unsigned char device) { ; }
 /* manager */
-extern inline struct pci_bus *isapnp_find_card(unsigned short vendor,
+static inline struct pci_bus *isapnp_find_card(unsigned short vendor,
 					       unsigned short device,
 					       struct pci_bus *from) { return NULL; }
-extern inline struct pci_dev *isapnp_find_dev(struct pci_bus *card,
+static inline struct pci_dev *isapnp_find_dev(struct pci_bus *card,
 					      unsigned short vendor,
 					      unsigned short function,
 					      struct pci_dev *from) { return NULL; }
-extern inline int isapnp_probe_cards(const struct isapnp_card_id *ids,
+static inline int isapnp_probe_cards(const struct isapnp_card_id *ids,
 				     int (*probe)(struct pci_bus *card,
 						  const struct isapnp_card_id *id)) { return -ENODEV; }
-extern inline int isapnp_probe_devs(const struct isapnp_device_id *ids,
+static inline int isapnp_probe_devs(const struct isapnp_device_id *ids,
 				    int (*probe)(struct pci_dev *dev,
 						 const struct isapnp_device_id *id)) { return -ENODEV; }
-extern inline void isapnp_resource_change(struct resource *resource,
+static inline void isapnp_resource_change(struct resource *resource,
 					  unsigned long start,
 					  unsigned long size) { ; }
-extern inline int isapnp_activate_dev(struct pci_dev *dev, const char *name) { return -ENODEV; }
+static inline int isapnp_activate_dev(struct pci_dev *dev, const char *name) { return -ENODEV; }
 
 #endif /* CONFIG_ISAPNP */
 
diff -u --recursive --new-file v2.4.7/linux/include/linux/isicom.h linux/include/linux/isicom.h
--- v2.4.7/linux/include/linux/isicom.h	Thu Aug  5 14:34:01 1999
+++ linux/include/linux/isicom.h	Thu Jul 26 13:53:38 2001
@@ -169,7 +169,7 @@
  *  ISI Card specific ops ...
  */
  
-extern inline void raise_dtr(struct isi_port * port)
+static inline void raise_dtr(struct isi_port * port)
 {
 	struct isi_board * card = port->card;
 	unsigned short base = card->base;
@@ -189,7 +189,7 @@
 	port->status |= ISI_DTR;
 }
 
-extern inline void drop_dtr(struct isi_port * port)
+static inline void drop_dtr(struct isi_port * port)
 {	
 	struct isi_board * card = port->card;
 	unsigned short base = card->base;
@@ -208,7 +208,7 @@
 	InterruptTheCard(base);	
 	port->status &= ~ISI_DTR;
 }
-extern inline void raise_rts(struct isi_port * port)
+static inline void raise_rts(struct isi_port * port)
 {
 	struct isi_board * card = port->card;
 	unsigned short base = card->base;
@@ -227,7 +227,7 @@
 	InterruptTheCard(base);	
 	port->status |= ISI_RTS;
 }
-extern inline void drop_rts(struct isi_port * port)
+static inline void drop_rts(struct isi_port * port)
 {
 	struct isi_board * card = port->card;
 	unsigned short base = card->base;
@@ -246,7 +246,7 @@
 	InterruptTheCard(base);	
 	port->status &= ~ISI_RTS;
 }
-extern inline void raise_dtr_rts(struct isi_port * port)
+static inline void raise_dtr_rts(struct isi_port * port)
 {
 	struct isi_board * card = port->card;
 	unsigned short base = card->base;
@@ -265,7 +265,7 @@
 	InterruptTheCard(base);
 	port->status |= (ISI_DTR | ISI_RTS);
 }
-extern inline void drop_dtr_rts(struct isi_port * port)
+static inline void drop_dtr_rts(struct isi_port * port)
 {
 	struct isi_board * card = port->card;
 	unsigned short base = card->base;
@@ -285,7 +285,7 @@
 	port->status &= ~(ISI_RTS | ISI_DTR);
 }
 
-extern inline void kill_queue(struct isi_port * port, short queue)
+static inline void kill_queue(struct isi_port * port, short queue)
 {
 	struct isi_board * card = port->card;
 	unsigned short base = card->base;
diff -u --recursive --new-file v2.4.7/linux/include/linux/kbd_kern.h linux/include/linux/kbd_kern.h
--- v2.4.7/linux/include/linux/kbd_kern.h	Sat Jul 28 18:21:34 2001
+++ linux/include/linux/kbd_kern.h	Mon Aug  6 21:43:24 2001
@@ -75,69 +75,69 @@
 
 extern void (*kbd_ledfunc)(unsigned int led);
 
-extern inline void show_console(void)
+static inline void show_console(void)
 {
 	do_poke_blanked_console = 1;
 	tasklet_schedule(&console_tasklet);
 }
 
-extern inline void set_console(int nr)
+static inline void set_console(int nr)
 {
 	want_console = nr;
 	tasklet_schedule(&console_tasklet);
 }
 
-extern inline void set_leds(void)
+static inline void set_leds(void)
 {
 	tasklet_schedule(&keyboard_tasklet);
 }
 
-extern inline int vc_kbd_mode(struct kbd_struct * kbd, int flag)
+static inline int vc_kbd_mode(struct kbd_struct * kbd, int flag)
 {
 	return ((kbd->modeflags >> flag) & 1);
 }
 
-extern inline int vc_kbd_led(struct kbd_struct * kbd, int flag)
+static inline int vc_kbd_led(struct kbd_struct * kbd, int flag)
 {
 	return ((kbd->ledflagstate >> flag) & 1);
 }
 
-extern inline void set_vc_kbd_mode(struct kbd_struct * kbd, int flag)
+static inline void set_vc_kbd_mode(struct kbd_struct * kbd, int flag)
 {
 	kbd->modeflags |= 1 << flag;
 }
 
-extern inline void set_vc_kbd_led(struct kbd_struct * kbd, int flag)
+static inline void set_vc_kbd_led(struct kbd_struct * kbd, int flag)
 {
 	kbd->ledflagstate |= 1 << flag;
 }
 
-extern inline void clr_vc_kbd_mode(struct kbd_struct * kbd, int flag)
+static inline void clr_vc_kbd_mode(struct kbd_struct * kbd, int flag)
 {
 	kbd->modeflags &= ~(1 << flag);
 }
 
-extern inline void clr_vc_kbd_led(struct kbd_struct * kbd, int flag)
+static inline void clr_vc_kbd_led(struct kbd_struct * kbd, int flag)
 {
 	kbd->ledflagstate &= ~(1 << flag);
 }
 
-extern inline void chg_vc_kbd_lock(struct kbd_struct * kbd, int flag)
+static inline void chg_vc_kbd_lock(struct kbd_struct * kbd, int flag)
 {
 	kbd->lockstate ^= 1 << flag;
 }
 
-extern inline void chg_vc_kbd_slock(struct kbd_struct * kbd, int flag)
+static inline void chg_vc_kbd_slock(struct kbd_struct * kbd, int flag)
 {
 	kbd->slockstate ^= 1 << flag;
 }
 
-extern inline void chg_vc_kbd_mode(struct kbd_struct * kbd, int flag)
+static inline void chg_vc_kbd_mode(struct kbd_struct * kbd, int flag)
 {
 	kbd->modeflags ^= 1 << flag;
 }
 
-extern inline void chg_vc_kbd_led(struct kbd_struct * kbd, int flag)
+static inline void chg_vc_kbd_led(struct kbd_struct * kbd, int flag)
 {
 	kbd->ledflagstate ^= 1 << flag;
 }
@@ -161,7 +161,7 @@
 
 extern task_queue con_task_queue;
 
-extern inline void con_schedule_flip(struct tty_struct *t)
+static inline void con_schedule_flip(struct tty_struct *t)
 {
 	queue_task(&t->flip.tqueue, &con_task_queue);
 	tasklet_schedule(&console_tasklet);
diff -u --recursive --new-file v2.4.7/linux/include/linux/kernel_stat.h linux/include/linux/kernel_stat.h
--- v2.4.7/linux/include/linux/kernel_stat.h	Sat Jul 28 18:18:24 2001
+++ linux/include/linux/kernel_stat.h	Mon Aug  6 21:40:18 2001
@@ -41,7 +41,7 @@
 /*
  * Number of interrupts per specific IRQ source, since bootup
  */
-extern inline int kstat_irqs (int irq)
+static inline int kstat_irqs (int irq)
 {
 	int i, sum=0;
 
diff -u --recursive --new-file v2.4.7/linux/include/linux/lockd/lockd.h linux/include/linux/lockd/lockd.h
--- v2.4.7/linux/include/linux/lockd/lockd.h	Sat Jul 28 18:19:11 2001
+++ linux/include/linux/lockd/lockd.h	Mon Aug  6 22:27:55 2001
@@ -173,7 +173,7 @@
 void		  nlmsvc_mark_resources(void);
 void		  nlmsvc_free_host_resources(struct nlm_host *);
 
-extern __inline__ struct inode *
+static __inline__ struct inode *
 nlmsvc_file_inode(struct nlm_file *file)
 {
 	return file->f_file.f_dentry->d_inode;
@@ -182,7 +182,7 @@
 /*
  * Compare two host addresses (needs modifying for ipv6)
  */
-extern __inline__ int
+static __inline__ int
 nlm_cmp_addr(struct sockaddr_in *sin1, struct sockaddr_in *sin2)
 {
 	return sin1->sin_addr.s_addr == sin2->sin_addr.s_addr;
@@ -192,7 +192,7 @@
  * Compare two NLM locks.
  * When the second lock is of type F_UNLCK, this acts like a wildcard.
  */
-extern __inline__ int
+static __inline__ int
 nlm_compare_locks(struct file_lock *fl1, struct file_lock *fl2)
 {
 	return	fl1->fl_pid   == fl2->fl_pid
diff -u --recursive --new-file v2.4.7/linux/include/linux/locks.h linux/include/linux/locks.h
--- v2.4.7/linux/include/linux/locks.h	Sat Jul 28 18:19:11 2001
+++ linux/include/linux/locks.h	Mon Aug  6 22:24:42 2001
@@ -14,13 +14,13 @@
  */
 extern void __wait_on_buffer(struct buffer_head *);
 
-extern inline void wait_on_buffer(struct buffer_head * bh)
+static inline void wait_on_buffer(struct buffer_head * bh)
 {
 	if (test_bit(BH_Lock, &bh->b_state))
 		__wait_on_buffer(bh);
 }
 
-extern inline void lock_buffer(struct buffer_head * bh)
+static inline void lock_buffer(struct buffer_head * bh)
 {
 	while (test_and_set_bit(BH_Lock, &bh->b_state))
 		__wait_on_buffer(bh);
@@ -34,12 +34,12 @@
  * nfs may need it).
  */
 
-extern inline void lock_super(struct super_block * sb)
+static inline void lock_super(struct super_block * sb)
 {
 	down(&sb->s_lock);
 }
 
-extern inline void unlock_super(struct super_block * sb)
+static inline void unlock_super(struct super_block * sb)
 {
 	up(&sb->s_lock);
 }
diff -u --recursive --new-file v2.4.7/linux/include/linux/loop.h linux/include/linux/loop.h
--- v2.4.7/linux/include/linux/loop.h	Tue Mar  6 19:35:36 2001
+++ linux/include/linux/loop.h	Thu Jul 26 13:55:24 2001
@@ -62,7 +62,7 @@
 				char *raw_buf, char *loop_buf, int size,
 				int real_block);
 
-extern inline int lo_do_transfer(struct loop_device *lo, int cmd, char *rbuf,
+static inline int lo_do_transfer(struct loop_device *lo, int cmd, char *rbuf,
 				 char *lbuf, int size, int rblock)
 {
 	if (!lo->transfer)
diff -u --recursive --new-file v2.4.7/linux/include/linux/mii.h linux/include/linux/mii.h
--- v2.4.7/linux/include/linux/mii.h	Sat Jul 28 18:20:55 2001
+++ linux/include/linux/mii.h	Mon Aug  6 21:42:37 2001
@@ -2,7 +2,7 @@
  * linux/mii.h: definitions for MII-compatible transceivers
  * Originally drivers/net/sunhme.h.
  *
- * Copyright (C) 1996, 1999 David S. Miller (davem@redhat.com)
+ * Copyright (C) 1996, 1999, 2001 David S. Miller (davem@redhat.com)
  */
 
 #ifndef __LINUX_MII_H__
@@ -10,19 +10,8 @@
 
 #include <linux/types.h>
 
-/* Inside the Happy Meal transceiver is the physical layer, they use an
- * implementations for National Semiconductor, part number DP83840VCE.
- * You can retrieve the data sheets and programming docs for this beast
- * from http://www.national.com/
- *
- * The DP83840 is capable of both 10 and 100Mbps ethernet, in both
- * half and full duplex mode.  It also supports auto negotiation.
- *
- * But.... THIS THING IS A PAIN IN THE ASS TO PROGRAM!
- * Debugging eeprom burnt code is more fun than programming this chip!
- */
+/* Generic MII registers. */
 
-/* First, the MII register numbers (actually DP83840 register numbers). */
 #define MII_BMCR            0x00        /* Basic mode control register */
 #define MII_BMSR            0x01        /* Basic mode status register  */
 #define MII_PHYSID1         0x02        /* PHYS ID 1                   */
@@ -35,10 +24,10 @@
 #define MII_NWAYTEST        0x14        /* N-way auto-neg test reg     */
 #define MII_RERRCOUNTER     0x15        /* Receive error counter       */
 #define MII_SREVISION       0x16        /* Silicon revision            */
-#define MII_CSCONFIG        0x17        /* CS configuration            */
+#define MII_RESV1           0x17        /* Reserved...                 */
 #define MII_LBRERROR        0x18        /* Lpback, rx, bypass error    */
 #define MII_PHYADDR         0x19        /* PHY address                 */
-#define MII_RESERVED        0x1a        /* Unused...                   */
+#define MII_RESV2           0x1a        /* Reserved...                 */
 #define MII_TPISTATUS       0x1b        /* TPI status for 10mbps       */
 #define MII_NCONFIG         0x1c        /* Network interface config    */
 
@@ -111,23 +100,6 @@
 #define NWAYTEST_RESV1          0x00ff  /* Unused...                   */
 #define NWAYTEST_LOOPBACK       0x0100  /* Enable loopback for N-way   */
 #define NWAYTEST_RESV2          0xfe00  /* Unused...                   */
-
-/* The Carrier Sense config register. */
-#define CSCONFIG_RESV1          0x0001  /* Unused...                   */
-#define CSCONFIG_LED4           0x0002  /* Pin for full-dplx LED4      */
-#define CSCONFIG_LED1           0x0004  /* Pin for conn-status LED1    */
-#define CSCONFIG_RESV2          0x0008  /* Unused...                   */
-#define CSCONFIG_TCVDISAB       0x0010  /* Turns off the transceiver   */
-#define CSCONFIG_DFBYPASS       0x0020  /* Bypass disconnect function  */
-#define CSCONFIG_GLFORCE        0x0040  /* Good link force for 100mbps */
-#define CSCONFIG_CLKTRISTATE    0x0080  /* Tristate 25m clock          */
-#define CSCONFIG_RESV3          0x0700  /* Unused...                   */
-#define CSCONFIG_ENCODE         0x0800  /* 1=MLT-3, 0=binary           */
-#define CSCONFIG_RENABLE        0x1000  /* Repeater mode enable        */
-#define CSCONFIG_TCDISABLE      0x2000  /* Disable timeout counter     */
-#define CSCONFIG_RESV4          0x4000  /* Unused...                   */
-#define CSCONFIG_NDISABLE       0x8000  /* Disable NRZI                */
-
 
 /* This structure is used in all SIOCxMIIxxx ioctl calls */
 struct mii_ioctl_data {
diff -u --recursive --new-file v2.4.7/linux/include/linux/netdevice.h linux/include/linux/netdevice.h
--- v2.4.7/linux/include/linux/netdevice.h	Sat Jul 28 18:18:48 2001
+++ linux/include/linux/netdevice.h	Mon Aug  6 22:24:42 2001
@@ -298,7 +298,6 @@
 
 	/* Interface address info. */
 	unsigned char		broadcast[MAX_ADDR_LEN];	/* hw bcast add	*/
-	unsigned char		pad;		/* make dev_addr aligned to 8 bytes */
 	unsigned char		dev_addr[MAX_ADDR_LEN];	/* hw address	*/
 	unsigned char		addr_len;	/* hardware address length	*/
 
diff -u --recursive --new-file v2.4.7/linux/include/linux/netfilter_ipv4/ip_conntrack_tuple.h linux/include/linux/netfilter_ipv4/ip_conntrack_tuple.h
--- v2.4.7/linux/include/linux/netfilter_ipv4/ip_conntrack_tuple.h	Thu Aug 10 12:35:15 2000
+++ linux/include/linux/netfilter_ipv4/ip_conntrack_tuple.h	Thu Jul 26 13:58:26 2001
@@ -82,14 +82,14 @@
 	IP_CT_DIR_MAX
 };
 
-extern inline int ip_ct_tuple_src_equal(const struct ip_conntrack_tuple *t1,
+static inline int ip_ct_tuple_src_equal(const struct ip_conntrack_tuple *t1,
 				        const struct ip_conntrack_tuple *t2)
 {
 	return t1->src.ip == t2->src.ip
 		&& t1->src.u.all == t2->src.u.all;
 }
 
-extern inline int ip_ct_tuple_dst_equal(const struct ip_conntrack_tuple *t1,
+static inline int ip_ct_tuple_dst_equal(const struct ip_conntrack_tuple *t1,
 				        const struct ip_conntrack_tuple *t2)
 {
 	return t1->dst.ip == t2->dst.ip
@@ -97,13 +97,13 @@
 		&& t1->dst.protonum == t2->dst.protonum;
 }
 
-extern inline int ip_ct_tuple_equal(const struct ip_conntrack_tuple *t1,
+static inline int ip_ct_tuple_equal(const struct ip_conntrack_tuple *t1,
 				    const struct ip_conntrack_tuple *t2)
 {
 	return ip_ct_tuple_src_equal(t1, t2) && ip_ct_tuple_dst_equal(t1, t2);
 }
 
-extern inline int ip_ct_tuple_mask_cmp(const struct ip_conntrack_tuple *t,
+static inline int ip_ct_tuple_mask_cmp(const struct ip_conntrack_tuple *t,
 				       const struct ip_conntrack_tuple *tuple,
 				       const struct ip_conntrack_tuple *mask)
 {
diff -u --recursive --new-file v2.4.7/linux/include/linux/netfilter_ipv4/ip_tables.h linux/include/linux/netfilter_ipv4/ip_tables.h
--- v2.4.7/linux/include/linux/netfilter_ipv4/ip_tables.h	Tue Jul  3 17:08:22 2001
+++ linux/include/linux/netfilter_ipv4/ip_tables.h	Thu Jul 26 13:58:46 2001
@@ -289,7 +289,7 @@
 #define IPT_ERROR_TARGET "ERROR"
 
 /* Helper functions */
-extern __inline__ struct ipt_entry_target *
+static __inline__ struct ipt_entry_target *
 ipt_get_target(struct ipt_entry *e)
 {
 	return (void *)e + e->target_offset;
diff -u --recursive --new-file v2.4.7/linux/include/linux/netfilter_ipv4/listhelp.h linux/include/linux/netfilter_ipv4/listhelp.h
--- v2.4.7/linux/include/linux/netfilter_ipv4/listhelp.h	Mon Dec 11 13:31:23 2000
+++ linux/include/linux/netfilter_ipv4/listhelp.h	Thu Jul 26 13:52:12 2001
@@ -39,11 +39,11 @@
 	(type)__i;				\
 })
 
-extern inline int
+static inline int
 __list_cmp_same(const void *p1, const void *p2) { return p1 == p2; }
 
 /* Is this entry in the list? */
-extern inline int
+static inline int
 list_inlist(struct list_head *head, const void *entry)
 {
 	return LIST_FIND(head, __list_cmp_same, void *, entry) != NULL;
@@ -64,7 +64,7 @@
 #endif
 
 /* Append. */
-extern inline void
+static inline void
 list_append(struct list_head *head, void *new)
 {
 	ASSERT_WRITE_LOCK(head);
@@ -72,7 +72,7 @@
 }
 
 /* Prepend. */
-extern inline void
+static inline void
 list_prepend(struct list_head *head, void *new)
 {
 	ASSERT_WRITE_LOCK(head);
@@ -92,13 +92,13 @@
 
 /* If the field after the list_head is a nul-terminated string, you
    can use these functions. */
-extern inline int __list_cmp_name(const void *i, const char *name)
+static inline int __list_cmp_name(const void *i, const char *name)
 {
 	return strcmp(name, i+sizeof(struct list_head)) == 0;
 }
 
 /* Returns false if same name already in list, otherwise does insert. */
-extern inline int
+static inline int
 list_named_insert(struct list_head *head, void *new)
 {
 	if (LIST_FIND(head, __list_cmp_name, void *,
diff -u --recursive --new-file v2.4.7/linux/include/linux/netfilter_ipv6/ip6_tables.h linux/include/linux/netfilter_ipv6/ip6_tables.h
--- v2.4.7/linux/include/linux/netfilter_ipv6/ip6_tables.h	Mon Dec 11 13:32:07 2000
+++ linux/include/linux/netfilter_ipv6/ip6_tables.h	Thu Jul 26 13:59:06 2001
@@ -295,7 +295,7 @@
 #define IP6T_ERROR_TARGET "ERROR"
 
 /* Helper functions */
-extern __inline__ struct ip6t_entry_target *
+static __inline__ struct ip6t_entry_target *
 ip6t_get_target(struct ip6t_entry *e)
 {
 	return (void *)e + e->target_offset;
diff -u --recursive --new-file v2.4.7/linux/include/linux/netlink.h linux/include/linux/netlink.h
--- v2.4.7/linux/include/linux/netlink.h	Wed Jul 25 17:10:26 2001
+++ linux/include/linux/netlink.h	Thu Jul 26 14:00:17 2001
@@ -127,7 +127,7 @@
 	long		args[4];
 };
 
-extern __inline__ struct nlmsghdr *
+static __inline__ struct nlmsghdr *
 __nlmsg_put(struct sk_buff *skb, u32 pid, u32 seq, int type, int len)
 {
 	struct nlmsghdr *nlh;
diff -u --recursive --new-file v2.4.7/linux/include/linux/nfsd/nfsfh.h linux/include/linux/nfsd/nfsfh.h
--- v2.4.7/linux/include/linux/nfsd/nfsfh.h	Sat Jul 28 18:19:11 2001
+++ linux/include/linux/nfsd/nfsfh.h	Mon Aug  6 22:27:55 2001
@@ -120,22 +120,22 @@
 /*
  * Conversion macros for the filehandle fields.
  */
-extern inline __u32 kdev_t_to_u32(kdev_t dev)
+static inline __u32 kdev_t_to_u32(kdev_t dev)
 {
 	return (__u32) dev;
 }
 
-extern inline kdev_t u32_to_kdev_t(__u32 udev)
+static inline kdev_t u32_to_kdev_t(__u32 udev)
 {
 	return (kdev_t) udev;
 }
 
-extern inline __u32 ino_t_to_u32(ino_t ino)
+static inline __u32 ino_t_to_u32(ino_t ino)
 {
 	return (__u32) ino;
 }
 
-extern inline ino_t u32_to_ino_t(__u32 uino)
+static inline ino_t u32_to_ino_t(__u32 uino)
 {
 	return (ino_t) uino;
 }
diff -u --recursive --new-file v2.4.7/linux/include/linux/nubus.h linux/include/linux/nubus.h
--- v2.4.7/linux/include/linux/nubus.h	Tue Feb 13 14:13:45 2001
+++ linux/include/linux/nubus.h	Thu Jul 26 14:01:01 2001
@@ -314,7 +314,7 @@
 			int maxlen);
 
 /* We'd like to get rid of this eventually.  Only daynaport.c uses it now. */
-extern inline void *nubus_slot_addr(int slot)
+static inline void *nubus_slot_addr(int slot)
 {
 	return (void *)(0xF0000000|(slot<<24));
 }
diff -u --recursive --new-file v2.4.7/linux/include/linux/pagemap.h linux/include/linux/pagemap.h
--- v2.4.7/linux/include/linux/pagemap.h	Sat Jul 28 18:18:28 2001
+++ linux/include/linux/pagemap.h	Mon Aug  6 22:24:42 2001
@@ -60,7 +60,7 @@
  * For the time being it will work for struct address_space too (most of
  * them sitting inside the inodes). We might want to change it later.
  */
-extern inline unsigned long _page_hashfn(struct address_space * mapping, unsigned long index)
+static inline unsigned long _page_hashfn(struct address_space * mapping, unsigned long index)
 {
 #define i (((unsigned long) mapping)/(sizeof(struct inode) & ~ (sizeof(struct inode) - 1)))
 #define s(x) ((x)+((x)>>PAGE_HASH_BITS))
@@ -91,7 +91,7 @@
 
 extern void ___wait_on_page(struct page *);
 
-extern inline void wait_on_page(struct page * page)
+static inline void wait_on_page(struct page * page)
 {
 	if (PageLocked(page))
 		___wait_on_page(page);
diff -u --recursive --new-file v2.4.7/linux/include/linux/parport.h linux/include/linux/parport.h
--- v2.4.7/linux/include/linux/parport.h	Wed Jul 25 17:10:26 2001
+++ linux/include/linux/parport.h	Thu Jul 26 13:59:49 2001
@@ -415,7 +415,7 @@
  * timeslice is half a second, but it can be adjusted via the /proc
  * interface.
  **/
-extern __inline__ int parport_yield(struct pardevice *dev)
+static __inline__ int parport_yield(struct pardevice *dev)
 {
 	unsigned long int timeslip = (jiffies - dev->time);
 	if ((dev->port->waithead == NULL) || (timeslip < dev->timeslice))
@@ -433,7 +433,7 @@
  * parport_claim_or_block(), and the return value is the same as for
  * parport_claim_or_block().
  **/
-extern __inline__ int parport_yield_blocking(struct pardevice *dev)
+static __inline__ int parport_yield_blocking(struct pardevice *dev)
 {
 	unsigned long int timeslip = (jiffies - dev->time);
 	if ((dev->port->waithead == NULL) || (timeslip < dev->timeslice))
@@ -518,7 +518,7 @@
 extern int parport_find_class (parport_device_class cls, int from);
 
 /* Lowlevel drivers _can_ call this support function to handle irqs.  */
-extern __inline__ void parport_generic_irq(int irq, struct parport *port,
+static __inline__ void parport_generic_irq(int irq, struct parport *port,
 					   struct pt_regs *regs)
 {
 	parport_ieee1284_interrupt (irq, port, regs);
diff -u --recursive --new-file v2.4.7/linux/include/linux/pci_ids.h linux/include/linux/pci_ids.h
--- v2.4.7/linux/include/linux/pci_ids.h	Tue Jul  3 17:08:22 2001
+++ linux/include/linux/pci_ids.h	Mon Aug  6 10:11:58 2001
@@ -437,7 +437,15 @@
 #define PCI_DEVICE_ID_SI_601		0x0601
 #define PCI_DEVICE_ID_SI_620		0x0620
 #define PCI_DEVICE_ID_SI_630		0x0630
+#define PCI_DEVICE_ID_SI_635		0x0635
+#define PCI_DEVICE_ID_SI_640		0x0640
+#define PCI_DEVICE_ID_SI_645		0x0645
+#define PCI_DEVICE_ID_SI_650		0x0650
 #define PCI_DEVICE_ID_SI_730		0x0730
+#define PCI_DEVICE_ID_SI_735		0x0735
+#define PCI_DEVICE_ID_SI_740		0x0740
+#define PCI_DEVICE_ID_SI_745		0x0745
+#define PCI_DEVICE_ID_SI_750		0x0750
 #define PCI_DEVICE_ID_SI_630_VGA	0x6300
 #define PCI_DEVICE_ID_SI_730_VGA	0x7300
 #define PCI_DEVICE_ID_SI_900		0x0900
diff -u --recursive --new-file v2.4.7/linux/include/linux/pm.h linux/include/linux/pm.h
--- v2.4.7/linux/include/linux/pm.h	Sat Jul 28 18:18:24 2001
+++ linux/include/linux/pm.h	Mon Aug  6 21:40:17 2001
@@ -147,41 +147,41 @@
  */
 struct pm_dev *pm_find(pm_dev_t type, struct pm_dev *from);
 
-extern inline void pm_access(struct pm_dev *dev) {}
-extern inline void pm_dev_idle(struct pm_dev *dev) {}
+static inline void pm_access(struct pm_dev *dev) {}
+static inline void pm_dev_idle(struct pm_dev *dev) {}
 
 #else /* CONFIG_PM */
 
 #define PM_IS_ACTIVE() 0
 
-extern inline struct pm_dev *pm_register(pm_dev_t type,
+static inline struct pm_dev *pm_register(pm_dev_t type,
 					 unsigned long id,
 					 pm_callback callback)
 {
 	return 0;
 }
 
-extern inline void pm_unregister(struct pm_dev *dev) {}
+static inline void pm_unregister(struct pm_dev *dev) {}
 
-extern inline void pm_unregister_all(pm_callback callback) {}
+static inline void pm_unregister_all(pm_callback callback) {}
 
-extern inline int pm_send(struct pm_dev *dev, pm_request_t rqst, void *data)
+static inline int pm_send(struct pm_dev *dev, pm_request_t rqst, void *data)
 {
 	return 0;
 }
 
-extern inline int pm_send_all(pm_request_t rqst, void *data)
+static inline int pm_send_all(pm_request_t rqst, void *data)
 {
 	return 0;
 }
 
-extern inline struct pm_dev *pm_find(pm_dev_t type, struct pm_dev *from)
+static inline struct pm_dev *pm_find(pm_dev_t type, struct pm_dev *from)
 {
 	return 0;
 }
 
-extern inline void pm_access(struct pm_dev *dev) {}
-extern inline void pm_dev_idle(struct pm_dev *dev) {}
+static inline void pm_access(struct pm_dev *dev) {}
+static inline void pm_dev_idle(struct pm_dev *dev) {}
 
 #endif /* CONFIG_PM */
 
diff -u --recursive --new-file v2.4.7/linux/include/linux/poll.h linux/include/linux/poll.h
--- v2.4.7/linux/include/linux/poll.h	Sat Jul 28 18:18:38 2001
+++ linux/include/linux/poll.h	Mon Aug  6 22:24:42 2001
@@ -19,7 +19,7 @@
 
 extern void __pollwait(struct file * filp, wait_queue_head_t * wait_address, poll_table *p);
 
-extern inline void poll_wait(struct file * filp, wait_queue_head_t * wait_address, poll_table *p)
+static inline void poll_wait(struct file * filp, wait_queue_head_t * wait_address, poll_table *p)
 {
 	if (p && wait_address)
 		__pollwait(filp, wait_address, p);
diff -u --recursive --new-file v2.4.7/linux/include/linux/quotaops.h linux/include/linux/quotaops.h
--- v2.4.7/linux/include/linux/quotaops.h	Sat Jul 28 18:18:52 2001
+++ linux/include/linux/quotaops.h	Mon Aug  6 22:27:44 2001
@@ -35,13 +35,13 @@
 /*
  * Operations supported for diskquotas.
  */
-extern __inline__ void DQUOT_INIT(struct inode *inode)
+static __inline__ void DQUOT_INIT(struct inode *inode)
 {
 	if (inode->i_sb && inode->i_sb->dq_op)
 		inode->i_sb->dq_op->initialize(inode, -1);
 }
 
-extern __inline__ void DQUOT_DROP(struct inode *inode)
+static __inline__ void DQUOT_DROP(struct inode *inode)
 {
 	if (IS_QUOTAINIT(inode)) {
 		if (inode->i_sb && inode->i_sb->dq_op)
@@ -49,7 +49,7 @@
 	}
 }
 
-extern __inline__ int DQUOT_PREALLOC_BLOCK(struct super_block *sb, const struct inode *inode, int nr)
+static __inline__ int DQUOT_PREALLOC_BLOCK(struct super_block *sb, const struct inode *inode, int nr)
 {
 	if (sb->dq_op) {
 		if (sb->dq_op->alloc_block(inode, fs_to_dq_blocks(nr, sb->s_blocksize), 1) == NO_QUOTA)
@@ -58,7 +58,7 @@
 	return 0;
 }
 
-extern __inline__ int DQUOT_ALLOC_BLOCK(struct super_block *sb, const struct inode *inode, int nr)
+static __inline__ int DQUOT_ALLOC_BLOCK(struct super_block *sb, const struct inode *inode, int nr)
 {
 	if (sb->dq_op) {
 		if (sb->dq_op->alloc_block(inode, fs_to_dq_blocks(nr, sb->s_blocksize), 0) == NO_QUOTA)
@@ -67,7 +67,7 @@
 	return 0;
 }
 
-extern __inline__ int DQUOT_ALLOC_INODE(struct super_block *sb, struct inode *inode)
+static __inline__ int DQUOT_ALLOC_INODE(struct super_block *sb, struct inode *inode)
 {
 	if (sb->dq_op) {
 		sb->dq_op->initialize (inode, -1);
@@ -78,19 +78,19 @@
 	return 0;
 }
 
-extern __inline__ void DQUOT_FREE_BLOCK(struct super_block *sb, const struct inode *inode, int nr)
+static __inline__ void DQUOT_FREE_BLOCK(struct super_block *sb, const struct inode *inode, int nr)
 {
 	if (sb->dq_op)
 		sb->dq_op->free_block(inode, fs_to_dq_blocks(nr, sb->s_blocksize));
 }
 
-extern __inline__ void DQUOT_FREE_INODE(struct super_block *sb, struct inode *inode)
+static __inline__ void DQUOT_FREE_INODE(struct super_block *sb, struct inode *inode)
 {
 	if (sb->dq_op)
 		sb->dq_op->free_inode(inode, 1);
 }
 
-extern __inline__ int DQUOT_TRANSFER(struct dentry *dentry, struct iattr *iattr)
+static __inline__ int DQUOT_TRANSFER(struct dentry *dentry, struct iattr *iattr)
 {
 	int error = -EDQUOT;
 
diff -u --recursive --new-file v2.4.7/linux/include/linux/raid/md_compatible.h linux/include/linux/raid/md_compatible.h
--- v2.4.7/linux/include/linux/raid/md_compatible.h	Sat Jul 28 18:19:36 2001
+++ linux/include/linux/raid/md_compatible.h	Mon Aug  6 22:24:42 2001
@@ -29,7 +29,7 @@
 
 #ifdef __i386__
 /* 001 */
-extern __inline__ int md_cpu_has_mmx(void)
+static __inline__ int md_cpu_has_mmx(void)
 {
 	return test_bit(X86_FEATURE_MMX,  &boot_cpu_data.x86_capability);
 }
@@ -51,7 +51,7 @@
 #define md_put_user put_user
 
 /* 007 */
-extern inline int md_capable_admin(void)
+static inline int md_capable_admin(void)
 {
 	return capable(CAP_SYS_ADMIN);
 }
@@ -60,7 +60,7 @@
 #define MD_FILE_TO_INODE(file) ((file)->f_dentry->d_inode)
 
 /* 009 */
-extern inline void md_flush_signals (void)
+static inline void md_flush_signals (void)
 {
 	spin_lock(&current->sigmask_lock);
 	flush_signals(current);
@@ -68,7 +68,7 @@
 }
  
 /* 010 */
-extern inline void md_init_signals (void)
+static inline void md_init_signals (void)
 {
         current->exit_signal = SIGCHLD;
         siginitsetinv(&current->blocked, sigmask(SIGKILL));
diff -u --recursive --new-file v2.4.7/linux/include/linux/raid/md_k.h linux/include/linux/raid/md_k.h
--- v2.4.7/linux/include/linux/raid/md_k.h	Sun May 20 12:11:39 2001
+++ linux/include/linux/raid/md_k.h	Thu Jul 26 14:01:32 2001
@@ -39,7 +39,7 @@
 	return MD_RESERVED;
 }
 
-extern inline int level_to_pers (int level)
+static inline int level_to_pers (int level)
 {
 	switch (level) {
 		case -3: return HSM;
diff -u --recursive --new-file v2.4.7/linux/include/linux/reiserfs_fs.h linux/include/linux/reiserfs_fs.h
--- v2.4.7/linux/include/linux/reiserfs_fs.h	Wed Jul 25 17:10:26 2001
+++ linux/include/linux/reiserfs_fs.h	Mon Jul 30 13:01:08 2001
@@ -118,7 +118,7 @@
 #define REISERFS_SUPER_MAGIC_STRING "ReIsErFs"
 #define REISER2FS_SUPER_MAGIC_STRING "ReIsEr2Fs"
 
-extern inline int is_reiserfs_magic_string (struct reiserfs_super_block * rs)
+static inline int is_reiserfs_magic_string (struct reiserfs_super_block * rs)
 {
     return (!strncmp (rs->s_magic, REISERFS_SUPER_MAGIC_STRING, 
 		      strlen ( REISERFS_SUPER_MAGIC_STRING)) ||
@@ -434,7 +434,7 @@
 //
 // here are conversion routines
 //
-extern inline int uniqueness2type (__u32 uniqueness)
+static inline int uniqueness2type (__u32 uniqueness)
 {
     switch (uniqueness) {
     case V1_SD_UNIQUENESS: return TYPE_STAT_DATA;
@@ -451,7 +451,7 @@
     return TYPE_ANY;
 }
 
-extern inline __u32 type2uniqueness (int type)
+static inline __u32 type2uniqueness (int type)
 {
     switch (type) {
     case TYPE_STAT_DATA: return V1_SD_UNIQUENESS;
@@ -472,46 +472,46 @@
 // there is no way to get version of object from key, so, provide
 // version to these defines
 //
-extern inline loff_t le_key_k_offset (int version, struct key * key)
+static inline loff_t le_key_k_offset (int version, struct key * key)
 {
     return (version == ITEM_VERSION_1) ? key->u.k_offset_v1.k_offset :
 	le64_to_cpu (key->u.k_offset_v2.k_offset);
 }
-extern inline loff_t le_ih_k_offset (struct item_head * ih)
+static inline loff_t le_ih_k_offset (struct item_head * ih)
 {
     return le_key_k_offset (ih_version (ih), &(ih->ih_key));
 }
 
 
-extern inline loff_t le_key_k_type (int version, struct key * key)
+static inline loff_t le_key_k_type (int version, struct key * key)
 {
     return (version == ITEM_VERSION_1) ? uniqueness2type (key->u.k_offset_v1.k_uniqueness) :
 	le16_to_cpu (key->u.k_offset_v2.k_type);
 }
-extern inline loff_t le_ih_k_type (struct item_head * ih)
+static inline loff_t le_ih_k_type (struct item_head * ih)
 {
     return le_key_k_type (ih_version (ih), &(ih->ih_key));
 }
 
 
-extern inline void set_le_key_k_offset (int version, struct key * key, loff_t offset)
+static inline void set_le_key_k_offset (int version, struct key * key, loff_t offset)
 {
     (version == ITEM_VERSION_1) ? (key->u.k_offset_v1.k_offset = offset) :
 	(key->u.k_offset_v2.k_offset = cpu_to_le64 (offset));
 }
-extern inline void set_le_ih_k_offset (struct item_head * ih, loff_t offset)
+static inline void set_le_ih_k_offset (struct item_head * ih, loff_t offset)
 {
     set_le_key_k_offset (ih_version (ih), &(ih->ih_key), offset);
 }
 
 
 
-extern inline void set_le_key_k_type (int version, struct key * key, int type)
+static inline void set_le_key_k_type (int version, struct key * key, int type)
 {
     (version == ITEM_VERSION_1) ? (key->u.k_offset_v1.k_uniqueness = type2uniqueness (type)) :
 	(key->u.k_offset_v2.k_type = cpu_to_le16 (type));
 }
-extern inline void set_le_ih_k_type (struct item_head * ih, int type)
+static inline void set_le_ih_k_type (struct item_head * ih, int type)
 {
     set_le_key_k_type (ih_version (ih), &(ih->ih_key), type);
 }
@@ -535,32 +535,32 @@
 //
 // key is pointer to cpu key, result is cpu
 //
-extern inline loff_t cpu_key_k_offset (struct cpu_key * key)
+static inline loff_t cpu_key_k_offset (struct cpu_key * key)
 {
     return (key->version == ITEM_VERSION_1) ? key->on_disk_key.u.k_offset_v1.k_offset :
 	key->on_disk_key.u.k_offset_v2.k_offset;
 }
 
-extern inline loff_t cpu_key_k_type (struct cpu_key * key)
+static inline loff_t cpu_key_k_type (struct cpu_key * key)
 {
     return (key->version == ITEM_VERSION_1) ? uniqueness2type (key->on_disk_key.u.k_offset_v1.k_uniqueness) :
 	key->on_disk_key.u.k_offset_v2.k_type;
 }
 
-extern inline void set_cpu_key_k_offset (struct cpu_key * key, loff_t offset)
+static inline void set_cpu_key_k_offset (struct cpu_key * key, loff_t offset)
 {
     (key->version == ITEM_VERSION_1) ? (key->on_disk_key.u.k_offset_v1.k_offset = offset) :
 	(key->on_disk_key.u.k_offset_v2.k_offset = offset);
 }
 
 
-extern inline void set_cpu_key_k_type (struct cpu_key * key, int type)
+static inline void set_cpu_key_k_type (struct cpu_key * key, int type)
 {
     (key->version == ITEM_VERSION_1) ? (key->on_disk_key.u.k_offset_v1.k_uniqueness = type2uniqueness (type)) :
 	(key->on_disk_key.u.k_offset_v2.k_type = type);
 }
 
-extern inline void cpu_key_k_offset_dec (struct cpu_key * key)
+static inline void cpu_key_k_offset_dec (struct cpu_key * key)
 {
     if (key->version == ITEM_VERSION_1)
 	key->on_disk_key.u.k_offset_v1.k_offset --;
@@ -828,7 +828,7 @@
 
 /* compose directory item containing "." and ".." entries (entries are
    not aligned to 4 byte boundary) */
-extern inline void make_empty_dir_item_v1 (char * body, __u32 dirid, __u32 objid,
+static inline void make_empty_dir_item_v1 (char * body, __u32 dirid, __u32 objid,
 					   __u32 par_dirid, __u32 par_objid)
 {
     struct reiserfs_de_head * deh;
@@ -859,7 +859,7 @@
 }
 
 /* compose directory item containing "." and ".." entries */
-extern inline void make_empty_dir_item (char * body, __u32 dirid, __u32 objid,
+static inline void make_empty_dir_item (char * body, __u32 dirid, __u32 objid,
 					__u32 par_dirid, __u32 par_objid)
 {
     struct reiserfs_de_head * deh;
@@ -905,7 +905,7 @@
 #define I_DEH_N_ENTRY_LENGTH(ih,deh,i) \
 ((i) ? (((deh)-1)->deh_location - (deh)->deh_location) : ((ih)->ih_item_len) - (deh)->deh_location)
 */
-extern inline int entry_length (struct buffer_head * bh, struct item_head * ih,
+static inline int entry_length (struct buffer_head * bh, struct item_head * ih,
 				int pos_in_item)
 {
     struct reiserfs_de_head * deh;
@@ -1137,7 +1137,7 @@
 
 // reiserfs version 2 has max offset 60 bits. Version 1 - 32 bit offset
 #define U32_MAX (~(__u32)0)
-extern inline loff_t max_reiserfs_offset (struct inode * inode)
+static inline loff_t max_reiserfs_offset (struct inode * inode)
 {
     if (inode_items_version (inode) == ITEM_VERSION_1)
 	return (loff_t)U32_MAX;
@@ -1652,7 +1652,6 @@
 
 /* stree.c */
 int B_IS_IN_TREE(struct buffer_head *);
-extern inline void copy_key (void * to, void * from);
 extern inline void copy_short_key (void * to, void * from);
 extern inline void copy_item_head(void * p_v_to, void * p_v_from);
 
@@ -1673,7 +1672,7 @@
 //
 // get key version from on disk key - kludge
 //
-extern inline int le_key_version (struct key * key)
+static inline int le_key_version (struct key * key)
 {
     int type;
     
@@ -1686,7 +1685,7 @@
 }
 
 
-extern inline void copy_key (void * to, void * from)
+static inline void copy_key (void * to, void * from)
 {
   memcpy (to, from, KEY_SIZE);
 }
@@ -1963,7 +1962,7 @@
 
 #ifdef __i386__
 
-extern __inline__ int 
+static __inline__ int 
 find_first_nonzero_bit(void * addr, unsigned size) {
   int res;
   int __d0;
@@ -1992,7 +1991,7 @@
 
 #else /* __i386__ */
 
-extern __inline__ int find_next_nonzero_bit(void * addr, unsigned size, unsigned offset)
+static __inline__ int find_next_nonzero_bit(void * addr, unsigned size, unsigned offset)
 {
 	unsigned int * p = ((unsigned int *) addr) + (offset >> 5);
 	unsigned int result = offset & ~31UL;
@@ -2040,10 +2039,10 @@
    absolutely safe */
 #define SPARE_SPACE 500
 
-extern inline unsigned long reiserfs_get_journal_block(struct super_block *s) {
+static inline unsigned long reiserfs_get_journal_block(struct super_block *s) {
     return le32_to_cpu(SB_DISK_SUPER_BLOCK(s)->s_journal_block) ;
 }
-extern inline unsigned long reiserfs_get_journal_orig_size(struct super_block *s) {
+static inline unsigned long reiserfs_get_journal_orig_size(struct super_block *s) {
     return le32_to_cpu(SB_DISK_SUPER_BLOCK(s)->s_orig_journal_size) ;
 }
 
diff -u --recursive --new-file v2.4.7/linux/include/linux/rtnetlink.h linux/include/linux/rtnetlink.h
--- v2.4.7/linux/include/linux/rtnetlink.h	Sat Jul 28 18:18:21 2001
+++ linux/include/linux/rtnetlink.h	Thu Jul 26 14:01:13 2001
@@ -538,7 +538,7 @@
 
 #include <linux/config.h>
 
-extern __inline__ int rtattr_strcmp(struct rtattr *rta, char *str)
+static __inline__ int rtattr_strcmp(struct rtattr *rta, char *str)
 {
 	int len = strlen(str) + 1;
 	return len > rta->rta_len || memcmp(RTA_DATA(rta), str, len);
diff -u --recursive --new-file v2.4.7/linux/include/linux/serial.h linux/include/linux/serial.h
--- v2.4.7/linux/include/linux/serial.h	Sat Jul 28 18:18:24 2001
+++ linux/include/linux/serial.h	Mon Aug  6 21:40:17 2001
@@ -141,7 +141,8 @@
 					     --- no longer used */
 #define ASYNC_CONS_FLOW		0x00800000 /* flow control for console  */
 
-#define ASYNC_INTERNAL_FLAGS	0xFF800000 /* Internal flags */
+#define ASYNC_BOOT_ONLYMCA	0x00400000 /* Probe only if MCA bus */
+#define ASYNC_INTERNAL_FLAGS	0xFFC00000 /* Internal flags */
 
 /*
  * Multiport serial configuration structure --- external structure
diff -u --recursive --new-file v2.4.7/linux/include/linux/sockios.h linux/include/linux/sockios.h
--- v2.4.7/linux/include/linux/sockios.h	Tue Jul  3 17:08:22 2001
+++ linux/include/linux/sockios.h	Tue Jul 31 10:34:02 2001
@@ -109,6 +109,8 @@
  *	vector. Each device should include this file and redefine these names
  *	as their own. Because these are device dependent it is a good idea
  *	_NOT_ to issue them to random objects and hope.
+ *
+ *	THESE IOCTLS ARE _DEPRECATED_ AND WILL DISAPPEAR IN 2.5.X -DaveM
  */
  
 #define SIOCDEVPRIVATE	0x89F0	/* to 89FF */
diff -u --recursive --new-file v2.4.7/linux/include/linux/sunrpc/clnt.h linux/include/linux/sunrpc/clnt.h
--- v2.4.7/linux/include/linux/sunrpc/clnt.h	Sat Jul 28 18:19:11 2001
+++ linux/include/linux/sunrpc/clnt.h	Mon Aug  6 22:27:55 2001
@@ -130,7 +130,7 @@
 }
 		
 
-extern __inline__ void
+static __inline__ void
 rpc_set_timeout(struct rpc_clnt *clnt, unsigned int retr, unsigned long incr)
 {
 	xprt_set_timeout(&clnt->cl_timeout, retr, incr);
diff -u --recursive --new-file v2.4.7/linux/include/linux/sunrpc/sched.h linux/include/linux/sunrpc/sched.h
--- v2.4.7/linux/include/linux/sunrpc/sched.h	Sat Jul 28 18:18:24 2001
+++ linux/include/linux/sunrpc/sched.h	Mon Aug  6 21:40:18 2001
@@ -180,13 +180,13 @@
 void		rpc_show_tasks(void);
 #endif
 
-extern __inline__ void *
+static __inline__ void *
 rpc_malloc(struct rpc_task *task, unsigned int size)
 {
 	return rpc_allocate(task->tk_flags, size);
 }
 
-extern __inline__ void
+static __inline__ void
 rpc_exit(struct rpc_task *task, int status)
 {
 	task->tk_status = status;
@@ -194,7 +194,7 @@
 }
 
 #ifdef RPC_DEBUG
-extern __inline__ char *
+static __inline__ char *
 rpc_qname(struct rpc_wait_queue *q)
 {
 	return q->name? q->name : "unknown";
diff -u --recursive --new-file v2.4.7/linux/include/linux/sunrpc/stats.h linux/include/linux/sunrpc/stats.h
--- v2.4.7/linux/include/linux/sunrpc/stats.h	Sat Jul 28 18:19:11 2001
+++ linux/include/linux/sunrpc/stats.h	Mon Aug  6 22:27:55 2001
@@ -59,13 +59,13 @@
 
 #else
 
-extern inline void svc_proc_unregister(const char *p) {}
-extern inline struct proc_dir_entry*svc_proc_register(struct svc_stat *s)
+static inline void svc_proc_unregister(const char *p) {}
+static inline struct proc_dir_entry*svc_proc_register(struct svc_stat *s)
 {
 	return NULL;
 }
 
-extern inline int svc_proc_read(char *a, char **b, off_t c, int d, int *e, void *f)
+static inline int svc_proc_read(char *a, char **b, off_t c, int d, int *e, void *f)
 {
 	return 0;
 }
diff -u --recursive --new-file v2.4.7/linux/include/linux/sunrpc/types.h linux/include/linux/sunrpc/types.h
--- v2.4.7/linux/include/linux/sunrpc/types.h	Sat Jul 28 18:18:24 2001
+++ linux/include/linux/sunrpc/types.h	Mon Aug  6 21:40:18 2001
@@ -21,7 +21,7 @@
 	struct rpc_listitem *	next;
 };
 
-extern __inline__ void
+static __inline__ void
 __rpc_append_list(struct rpc_listitem **q, struct rpc_listitem *item)
 {
 	struct rpc_listitem	*next, *prev;
@@ -37,14 +37,14 @@
 	}
 }
 
-extern __inline__ void
+static __inline__ void
 __rpc_insert_list(struct rpc_listitem **q, struct rpc_listitem *item)
 {
 	__rpc_append_list(q, item);
 	*q = item;
 }
 
-extern __inline__ void
+static __inline__ void
 __rpc_remove_list(struct rpc_listitem **q, struct rpc_listitem *item)
 {
 	struct rpc_listitem	*prev = item->prev,
diff -u --recursive --new-file v2.4.7/linux/include/linux/swap.h linux/include/linux/swap.h
--- v2.4.7/linux/include/linux/swap.h	Sat Jul 28 18:18:24 2001
+++ linux/include/linux/swap.h	Mon Aug  6 21:40:18 2001
@@ -100,8 +100,6 @@
 
 /* linux/mm/swap.c */
 extern int memory_pressure;
-extern void age_page_up(struct page *);
-extern void age_page_up_nolock(struct page *);
 extern void age_page_down(struct page *);
 extern void age_page_down_nolock(struct page *);
 extern void age_page_down_ageonly(struct page *);
@@ -121,9 +119,15 @@
 extern wait_queue_head_t kreclaimd_wait;
 extern int page_launder(int, int);
 extern int free_shortage(void);
+extern int total_free_shortage(void);
 extern int inactive_shortage(void);
+extern int total_inactive_shortage(void);
 extern void wakeup_kswapd(void);
 extern int try_to_free_pages(unsigned int gfp_mask);
+
+extern unsigned int zone_free_shortage(zone_t *zone);
+extern unsigned int zone_inactive_shortage(zone_t *zone);
+extern unsigned int zone_inactive_plenty(zone_t *zone);
 
 /* linux/mm/page_io.c */
 extern void rw_swap_page(int, struct page *);
diff -u --recursive --new-file v2.4.7/linux/include/linux/sysv_fs.h linux/include/linux/sysv_fs.h
--- v2.4.7/linux/include/linux/sysv_fs.h	Tue Jul  3 17:08:22 2001
+++ linux/include/linux/sysv_fs.h	Thu Jul 26 13:56:31 2001
@@ -271,14 +271,14 @@
  */
 #define COH_KLUDGE_SYMLINK_MODE	(S_IFREG | S_ISVTX)
 #define COH_KLUDGE_NOT_SYMLINK	(S_IFREG | S_ISVTX | S_IRUSR) /* force read access */
-extern inline mode_t from_coh_imode(unsigned short mode)
+static inline mode_t from_coh_imode(unsigned short mode)
 {
 	if (mode == COH_KLUDGE_SYMLINK_MODE)
 		return (S_IFLNK | 0777);
 	else
 		return mode;
 }
-extern inline unsigned short to_coh_imode(mode_t mode)
+static inline unsigned short to_coh_imode(mode_t mode)
 {
 	if (S_ISLNK(mode))
 		return COH_KLUDGE_SYMLINK_MODE;
diff -u --recursive --new-file v2.4.7/linux/include/linux/tty_flip.h linux/include/linux/tty_flip.h
--- v2.4.7/linux/include/linux/tty_flip.h	Tue Sep  9 19:41:41 1997
+++ linux/include/linux/tty_flip.h	Thu Jul 26 13:57:42 2001
@@ -4,7 +4,7 @@
 #ifdef INCLUDE_INLINE_FUNCS
 #define _INLINE_ extern
 #else
-#define _INLINE_ extern __inline__
+#define _INLINE_ static __inline__
 #endif
 
 _INLINE_ void tty_insert_flip_char(struct tty_struct *tty,
diff -u --recursive --new-file v2.4.7/linux/include/linux/videodev.h linux/include/linux/videodev.h
--- v2.4.7/linux/include/linux/videodev.h	Wed Jul 25 17:10:26 2001
+++ linux/include/linux/videodev.h	Wed Jul 25 14:12:03 2001
@@ -376,6 +376,7 @@
 #define VID_HARDWARE_SE401	30	/* SE401 USB webcams */
 #define VID_HARDWARE_PWC	31	/* Philips webcams */
 #define VID_HARDWARE_MEYE	32	/* Sony Vaio MotionEye cameras */
+#define VID_HARDWARE_CPIA2	33
 
 /*
  *	Initialiser list
diff -u --recursive --new-file v2.4.7/linux/kernel/ksyms.c linux/kernel/ksyms.c
--- v2.4.7/linux/kernel/ksyms.c	Wed Jul 25 17:10:26 2001
+++ linux/kernel/ksyms.c	Sat Jul 28 13:01:25 2001
@@ -543,8 +543,8 @@
 EXPORT_SYMBOL(do_softirq);
 EXPORT_SYMBOL(raise_softirq);
 EXPORT_SYMBOL(cpu_raise_softirq);
-EXPORT_SYMBOL(tasklet_schedule);
-EXPORT_SYMBOL(tasklet_hi_schedule);
+EXPORT_SYMBOL(__tasklet_schedule);
+EXPORT_SYMBOL(__tasklet_hi_schedule);
 
 /* init task, for moving kthread roots - ought to export a function ?? */
 
diff -u --recursive --new-file v2.4.7/linux/kernel/softirq.c linux/kernel/softirq.c
--- v2.4.7/linux/kernel/softirq.c	Wed Jul 25 17:10:26 2001
+++ linux/kernel/softirq.c	Sat Jul 28 12:59:12 2001
@@ -40,10 +40,7 @@
    - Bottom halves: globally serialized, grr...
  */
 
-/* No separate irq_stat for s390, it is part of PSA */
-#if !defined(CONFIG_ARCH_S390)
 irq_cpustat_t irq_stat[NR_CPUS];
-#endif	/* CONFIG_ARCH_S390 */
 
 static struct softirq_action softirq_vec[32] __cacheline_aligned;
 
@@ -143,41 +140,29 @@
 /* Tasklets */
 
 struct tasklet_head tasklet_vec[NR_CPUS] __cacheline_aligned;
+struct tasklet_head tasklet_hi_vec[NR_CPUS] __cacheline_aligned;
 
-void tasklet_schedule(struct tasklet_struct *t)
+void __tasklet_schedule(struct tasklet_struct *t)
 {
+	int cpu = smp_processor_id();
 	unsigned long flags;
-	int cpu;
 
-	cpu = smp_processor_id();
 	local_irq_save(flags);
-	/*
-	 * If nobody is running it then add it to this CPU's
-	 * tasklet queue.
-	 */
-	if (!test_and_set_bit(TASKLET_STATE_SCHED, &t->state)) {
-		t->next = tasklet_vec[cpu].list;
-		tasklet_vec[cpu].list = t;
-		cpu_raise_softirq(cpu, TASKLET_SOFTIRQ);
-		tasklet_unlock(t);
-	}
+	t->next = tasklet_vec[cpu].list;
+	tasklet_vec[cpu].list = t;
+	cpu_raise_softirq(cpu, TASKLET_SOFTIRQ);
 	local_irq_restore(flags);
 }
 
-void tasklet_hi_schedule(struct tasklet_struct *t)
+void __tasklet_hi_schedule(struct tasklet_struct *t)
 {
+	int cpu = smp_processor_id();
 	unsigned long flags;
-	int cpu;
 
-	cpu = smp_processor_id();
 	local_irq_save(flags);
-
-	if (!test_and_set_bit(TASKLET_STATE_SCHED, &t->state)) {
-		t->next = tasklet_hi_vec[cpu].list;
-		tasklet_hi_vec[cpu].list = t;
-		cpu_raise_softirq(cpu, HI_SOFTIRQ);
-		tasklet_unlock(t);
-	}
+	t->next = tasklet_hi_vec[cpu].list;
+	tasklet_hi_vec[cpu].list = t;
+	cpu_raise_softirq(cpu, HI_SOFTIRQ);
 	local_irq_restore(flags);
 }
 
@@ -196,29 +181,25 @@
 
 		list = list->next;
 
-		if (!tasklet_trylock(t))
-			BUG();
-		if (!atomic_read(&t->count)) {
-			if (!test_and_clear_bit(TASKLET_STATE_SCHED, &t->state))
-				BUG();
-			t->func(t->data);
+		if (tasklet_trylock(t)) {
+			if (!atomic_read(&t->count)) {
+				if (!test_and_clear_bit(TASKLET_STATE_SCHED, &t->state))
+					BUG();
+				t->func(t->data);
+				tasklet_unlock(t);
+				continue;
+			}
 			tasklet_unlock(t);
-			continue;
 		}
-		tasklet_unlock(t);
 
 		local_irq_disable();
 		t->next = tasklet_vec[cpu].list;
 		tasklet_vec[cpu].list = t;
-		cpu_raise_softirq(cpu, TASKLET_SOFTIRQ);
 		local_irq_enable();
+		__cpu_raise_softirq(cpu, TASKLET_SOFTIRQ);
 	}
 }
 
-
-
-struct tasklet_head tasklet_hi_vec[NR_CPUS] __cacheline_aligned;
-
 static void tasklet_hi_action(struct softirq_action *a)
 {
 	int cpu = smp_processor_id();
@@ -234,22 +215,22 @@
 
 		list = list->next;
 
-		if (!tasklet_trylock(t))
-			BUG();
-		if (!atomic_read(&t->count)) {
-			if (!test_and_clear_bit(TASKLET_STATE_SCHED, &t->state))
-				BUG();
-			t->func(t->data);
+		if (tasklet_trylock(t)) {
+			if (!atomic_read(&t->count)) {
+				if (!test_and_clear_bit(TASKLET_STATE_SCHED, &t->state))
+					BUG();
+				t->func(t->data);
+				tasklet_unlock(t);
+				continue;
+			}
 			tasklet_unlock(t);
-			continue;
 		}
-		tasklet_unlock(t);
 
 		local_irq_disable();
 		t->next = tasklet_hi_vec[cpu].list;
 		tasklet_hi_vec[cpu].list = t;
-		cpu_raise_softirq(cpu, HI_SOFTIRQ);
 		local_irq_enable();
+		__cpu_raise_softirq(cpu, HI_SOFTIRQ);
 	}
 }
 
diff -u --recursive --new-file v2.4.7/linux/kernel/sys.c linux/kernel/sys.c
--- v2.4.7/linux/kernel/sys.c	Wed Jul 25 17:10:26 2001
+++ linux/kernel/sys.c	Thu Jul 26 13:43:33 2001
@@ -472,7 +472,7 @@
  * files..
  * Thanks to Olaf Kirch and Peter Benie for spotting this.
  */
-extern inline void cap_emulate_setxuid(int old_ruid, int old_euid, 
+static inline void cap_emulate_setxuid(int old_ruid, int old_euid, 
 				       int old_suid)
 {
 	if ((old_ruid == 0 || old_euid == 0 || old_suid == 0) &&
diff -u --recursive --new-file v2.4.7/linux/lib/vsprintf.c linux/lib/vsprintf.c
--- v2.4.7/linux/lib/vsprintf.c	Fri Apr 13 20:26:07 2001
+++ linux/lib/vsprintf.c	Sun Aug  5 13:12:41 2001
@@ -9,6 +9,11 @@
  * Wirzenius wrote this portably, Torvalds fucked it up :-)
  */
 
+/* 
+ * Fri Jul 13 2001 Crutcher Dunnavant <crutcher+kernel@datastacks.com>
+ * - changed to provide snprintf and vsnprintf functions
+ */
+
 #include <stdarg.h>
 #include <linux/types.h>
 #include <linux/string.h>
@@ -121,14 +126,15 @@
 #define SPECIAL	32		/* 0x */
 #define LARGE	64		/* use 'ABCDEF' instead of 'abcdef' */
 
-static char * number(char * str, long long num, int base, int size, int precision, int type)
+static char * number(char * buf, char * end, long long num, int base, int size, int precision, int type)
 {
 	char c,sign,tmp[66];
-	const char *digits="0123456789abcdefghijklmnopqrstuvwxyz";
+	const char *digits;
+	const char small_digits[] = "0123456789abcdefghijklmnopqrstuvwxyz";
+	const char large_digits[] = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ";
 	int i;
 
-	if (type & LARGE)
-		digits = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ";
+	digits = (type & LARGE) ? large_digits : small_digits;
 	if (type & LEFT)
 		type &= ~ZEROPAD;
 	if (base < 2 || base > 36)
@@ -162,46 +168,73 @@
 	if (i > precision)
 		precision = i;
 	size -= precision;
-	if (!(type&(ZEROPAD+LEFT)))
-		while(size-->0)
-			*str++ = ' ';
-	if (sign)
-		*str++ = sign;
+	if (!(type&(ZEROPAD+LEFT))) {
+		while(size-->0) {
+			if (buf <= end)
+				*buf = ' ';
+			++buf;
+		}
+	}
+	if (sign) {
+		if (buf <= end)
+			*buf = sign;
+		++buf;
+	}
 	if (type & SPECIAL) {
-		if (base==8)
-			*str++ = '0';
-		else if (base==16) {
-			*str++ = '0';
-			*str++ = digits[33];
-		}
-	}
-	if (!(type & LEFT))
-		while (size-- > 0)
-			*str++ = c;
-	while (i < precision--)
-		*str++ = '0';
-	while (i-- > 0)
-		*str++ = tmp[i];
-	while (size-- > 0)
-		*str++ = ' ';
-	return str;
+		if (base==8) {
+			if (buf <= end)
+				*buf = '0';
+			++buf;
+		} else if (base==16) {
+			if (buf <= end)
+				*buf = '0';
+			++buf;
+			if (buf <= end)
+				*buf = digits[33];
+			++buf;
+		}
+	}
+	if (!(type & LEFT)) {
+		while (size-- > 0) {
+			if (buf <= end)
+				*buf = c;
+			++buf;
+		}
+	}
+	while (i < precision--) {
+		if (buf <= end)
+			*buf = '0';
+		++buf;
+	}
+	while (i-- > 0) {
+		if (buf <= end)
+			*buf = tmp[i];
+		++buf;
+	}
+	while (size-- > 0) {
+		if (buf <= end)
+			*buf = ' ';
+		++buf;
+	}
+	return buf;
 }
 
 /**
- * vsprintf - Format a string and place it in a buffer
- * @buf: The buffer to place the result into
- * @fmt: The format string to use
- * @args: Arguments for the format string
- *
- * Call this function if you are already dealing with a va_list.
- * You probably want sprintf instead.
+* vsnprintf - Format a string and place it in a buffer
+* @buf: The buffer to place the result into
+* @size: The size of the buffer, including the trailing null space
+* @fmt: The format string to use
+* @args: Arguments for the format string
+*
+* Call this function if you are already dealing with a va_list.
+* You probably want snprintf instead.
  */
-int vsprintf(char *buf, const char *fmt, va_list args)
+int vsnprintf(char *buf, size_t size, const char *fmt, va_list args)
 {
 	int len;
 	unsigned long long num;
 	int i, base;
-	char * str;
+	char *str, *end, c;
 	const char *s;
 
 	int flags;		/* flags to number() */
@@ -210,16 +243,25 @@
 	int precision;		/* min. # of digits for integers; max
 				   number of chars for from string */
 	int qualifier;		/* 'h', 'l', or 'L' for integer fields */
-	                        /* 'z' support added 23/7/1999 S.H.    */
+				/* 'z' support added 23/7/1999 S.H.    */
 				/* 'z' changed to 'Z' --davidm 1/25/99 */
 
-	
-	for (str=buf ; *fmt ; ++fmt) {
+	str = buf;
+	end = buf + size - 1;
+
+	if (end < buf - 1) {
+		end = ((void *) -1);
+		size = end - buf + 1;
+	}
+
+	for (; *fmt ; ++fmt) {
 		if (*fmt != '%') {
-			*str++ = *fmt;
+			if (str <= end)
+				*str = *fmt;
+			++str;
 			continue;
 		}
-			
+
 		/* process flags */
 		flags = 0;
 		repeat:
@@ -230,8 +272,8 @@
 				case ' ': flags |= SPACE; goto repeat;
 				case '#': flags |= SPECIAL; goto repeat;
 				case '0': flags |= ZEROPAD; goto repeat;
-				}
-		
+			}
+
 		/* get field width */
 		field_width = -1;
 		if (isdigit(*fmt))
@@ -272,83 +314,112 @@
 		base = 10;
 
 		switch (*fmt) {
-		case 'c':
-			if (!(flags & LEFT))
-				while (--field_width > 0)
-					*str++ = ' ';
-			*str++ = (unsigned char) va_arg(args, int);
-			while (--field_width > 0)
-				*str++ = ' ';
-			continue;
-
-		case 's':
-			s = va_arg(args, char *);
-			if (!s)
-				s = "<NULL>";
-
-			len = strnlen(s, precision);
-
-			if (!(flags & LEFT))
-				while (len < field_width--)
-					*str++ = ' ';
-			for (i = 0; i < len; ++i)
-				*str++ = *s++;
-			while (len < field_width--)
-				*str++ = ' ';
-			continue;
-
-		case 'p':
-			if (field_width == -1) {
-				field_width = 2*sizeof(void *);
-				flags |= ZEROPAD;
-			}
-			str = number(str,
-				(unsigned long) va_arg(args, void *), 16,
-				field_width, precision, flags);
-			continue;
-
+			case 'c':
+				if (!(flags & LEFT)) {
+					while (--field_width > 0) {
+						if (str <= end)
+							*str = ' ';
+						++str;
+					}
+				}
+				c = (unsigned char) va_arg(args, int);
+				if (str <= end)
+					*str = c;
+				++str;
+				while (--field_width > 0) {
+					if (str <= end)
+						*str = ' ';
+					++str;
+				}
+				continue;
 
-		case 'n':
-			if (qualifier == 'l') {
-				long * ip = va_arg(args, long *);
-				*ip = (str - buf);
-			} else if (qualifier == 'Z') {
-				size_t * ip = va_arg(args, size_t *);
-				*ip = (str - buf);
-			} else {
-				int * ip = va_arg(args, int *);
-				*ip = (str - buf);
-			}
-			continue;
+			case 's':
+				s = va_arg(args, char *);
+				if (!s)
+					s = "<NULL>";
+
+				len = strnlen(s, precision);
+
+				if (!(flags & LEFT)) {
+					while (len < field_width--) {
+						if (str <= end)
+							*str = ' ';
+						++str;
+					}
+				}
+				for (i = 0; i < len; ++i) {
+					if (str <= end)
+						*str = *s;
+					++str; ++s;
+				}
+				while (len < field_width--) {
+					if (str <= end)
+						*str = ' ';
+					++str;
+				}
+				continue;
 
-		case '%':
-			*str++ = '%';
-			continue;
+			case 'p':
+				if (field_width == -1) {
+					field_width = 2*sizeof(void *);
+					flags |= ZEROPAD;
+				}
+				str = number(str, end,
+						(unsigned long) va_arg(args, void *),
+						16, field_width, precision, flags);
+				continue;
+
+
+			case 'n':
+				/* FIXME:
+				* What does C99 say about the overflow case here? */
+				if (qualifier == 'l') {
+					long * ip = va_arg(args, long *);
+					*ip = (str - buf);
+				} else if (qualifier == 'Z') {
+					size_t * ip = va_arg(args, size_t *);
+					*ip = (str - buf);
+				} else {
+					int * ip = va_arg(args, int *);
+					*ip = (str - buf);
+				}
+				continue;
 
-		/* integer number formats - set up the flags and "break" */
-		case 'o':
-			base = 8;
-			break;
+			case '%':
+				if (str <= end)
+					*str = '%';
+				++str;
+				continue;
+
+				/* integer number formats - set up the flags and "break" */
+			case 'o':
+				base = 8;
+				break;
+
+			case 'X':
+				flags |= LARGE;
+			case 'x':
+				base = 16;
+				break;
 
-		case 'X':
-			flags |= LARGE;
-		case 'x':
-			base = 16;
-			break;
-
-		case 'd':
-		case 'i':
-			flags |= SIGN;
-		case 'u':
-			break;
-
-		default:
-			*str++ = '%';
-			if (*fmt)
-				*str++ = *fmt;
-			else
-				--fmt;
-			continue;
+			case 'd':
+			case 'i':
+				flags |= SIGN;
+			case 'u':
+				break;
+
+			default:
+				if (str <= end)
+					*str = '%';
+				++str;
+				if (*fmt) {
+					if (str <= end)
+						*str = *fmt;
+					++str;
+				} else {
+					--fmt;
+				}
+				continue;
 		}
 		if (qualifier == 'L')
 			num = va_arg(args, long long);
@@ -367,13 +438,54 @@
 			if (flags & SIGN)
 				num = (signed int) num;
 		}
-		str = number(str, num, base, field_width, precision, flags);
+		str = number(str, end, num, base,
+				field_width, precision, flags);
 	}
-	*str = '\0';
+	if (str <= end)
+		*str = '\0';
+	else if (size > 0)
+		/* don't write out a null byte if the buf size is zero */
+		*end = '\0';
+	/* the trailing null byte doesn't count towards the total
+	* ++str;
+	*/
 	return str-buf;
 }
 
 /**
+ * snprintf - Format a string and place it in a buffer
+ * @buf: The buffer to place the result into
+ * @size: The size of the buffer, including the trailing null space
+ * @fmt: The format string to use
+ * @...: Arguments for the format string
+ */
+int snprintf(char * buf, size_t size, const char *fmt, ...)
+{
+	va_list args;
+	int i;
+
+	va_start(args, fmt);
+	i=vsnprintf(buf,size,fmt,args);
+	va_end(args);
+	return i;
+}
+
+/**
+ * vsprintf - Format a string and place it in a buffer
+ * @buf: The buffer to place the result into
+ * @fmt: The format string to use
+ * @args: Arguments for the format string
+ *
+ * Call this function if you are already dealing with a va_list.
+ * You probably want sprintf instead.
+ */
+int vsprintf(char *buf, const char *fmt, va_list args)
+{
+	return vsnprintf(buf, 0xFFFFFFFFUL, fmt, args);
+}
+
+
+/**
  * sprintf - Format a string and place it in a buffer
  * @buf: The buffer to place the result into
  * @fmt: The format string to use
@@ -389,3 +501,4 @@
 	va_end(args);
 	return i;
 }
+
diff -u --recursive --new-file v2.4.7/linux/mm/filemap.c linux/mm/filemap.c
--- v2.4.7/linux/mm/filemap.c	Wed Jul 25 17:10:26 2001
+++ linux/mm/filemap.c	Thu Jul 26 14:19:50 2001
@@ -293,34 +293,6 @@
 	spin_unlock(&pagecache_lock);
 }
 
-/*
- * This function is pretty much like __find_page_nolock(), but it only
- * requires 2 arguments and doesn't mark the page as touched, making it
- * ideal for ->writepage() clustering and other places where you don't
- * want to mark the page referenced.
- *
- * The caller needs to hold the pagecache_lock.
- */
-static struct page * FASTCALL(__find_page_simple(struct address_space *, unsigned long));
-static struct page * __find_page_simple(struct address_space *mapping, unsigned long index)
-{
-	struct page **next = page_hash(mapping, index);;
-
-	for (;;) {
-		struct page *page = *next;
-		if (!page)
-			break;
-		next = &page->next_hash;
-		if (page->mapping != mapping)
-			continue;
-		if (page->index != index)
-			continue;
-		return page;
-	}
-
-	return NULL;
-}
-
 static inline struct page * __find_page_nolock(struct address_space *mapping, unsigned long offset, struct page *page)
 {
 	goto inside;
@@ -778,51 +750,6 @@
 #endif
 
 /*
- * We combine this with read-ahead to deactivate pages when we
- * think there's sequential IO going on. Note that this is
- * harmless since we don't actually evict the pages from memory
- * but just move them to the inactive list.
- *
- * TODO:
- * - make the readahead code smarter
- * - move readahead to the VMA level so we can do the same
- *   trick with mmap()
- *
- * Rik van Riel, 2000
- */
-static void drop_behind(struct file * file, unsigned long index)
-{
-	struct inode *inode = file->f_dentry->d_inode;
-	struct address_space *mapping = inode->i_mapping;
-	struct page *page;
-	unsigned long start;
-
-	/* Nothing to drop-behind if we're on the first page. */
-	if (!index)
-		return;
-
-	if (index > file->f_rawin)
-		start = index - file->f_rawin;
-	else
-		start = 0;
-
-	/*
-	 * Go backwards from index-1 and drop all pages in the
-	 * readahead window. Since the readahead window may have
-	 * been increased since the last time we were called, we
-	 * stop when the page isn't there.
-	 */
-	spin_lock(&pagecache_lock);
-	while (--index >= start) {
-		page = __find_page_simple(mapping, index);
-		if (!page)
-			break;
-		deactivate_page(page);
-	}
-	spin_unlock(&pagecache_lock);
-}
-
-/*
  * Read-ahead profiling information
  * --------------------------------
  * Every PROFILE_MAXREADCOUNT, the following information is written 
@@ -1041,12 +968,6 @@
 		if (filp->f_ramax > max_readahead)
 			filp->f_ramax = max_readahead;
 
-		/*
-		 * Move the pages that have already been passed
-		 * to the inactive list.
-		 */
-		drop_behind(filp, index);
-
 #ifdef PROFILE_READAHEAD
 		profile_readahead((reada_ok == 2), filp);
 #endif
@@ -1056,6 +977,14 @@
 }
 
 
+static inline void check_used_once (struct page *page)
+{
+	if (!page->age) {
+		page->age = PAGE_AGE_START;
+		ClearPageReferenced(page);
+	}
+}
+
 /*
  * This is a generic file read routine, and uses the
  * inode->i_op->readpage() function for the actual low-level
@@ -1171,7 +1100,8 @@
 		offset += ret;
 		index += offset >> PAGE_CACHE_SHIFT;
 		offset &= ~PAGE_CACHE_MASK;
-	
+
+		check_used_once (page);
 		page_cache_release(page);
 		if (ret == nr && desc->count)
 			continue;
@@ -2608,7 +2538,6 @@
 	while (count) {
 		unsigned long index, offset;
 		char *kaddr;
-		int deactivate = 1;
 
 		/*
 		 * Try to find the page in the cache. If it isn't there,
@@ -2617,10 +2546,8 @@
 		offset = (pos & (PAGE_CACHE_SIZE -1)); /* Within page */
 		index = pos >> PAGE_CACHE_SHIFT;
 		bytes = PAGE_CACHE_SIZE - offset;
-		if (bytes > count) {
+		if (bytes > count)
 			bytes = count;
-			deactivate = 0;
-		}
 
 		/*
 		 * Bring in the user page that we will copy from _first_.
@@ -2664,8 +2591,7 @@
 unlock:
 		/* Mark it unlocked again and drop the page.. */
 		UnlockPage(page);
-		if (deactivate)
-			deactivate_page(page);
+		check_used_once(page);
 		page_cache_release(page);
 
 		if (status < 0)
diff -u --recursive --new-file v2.4.7/linux/mm/highmem.c linux/mm/highmem.c
--- v2.4.7/linux/mm/highmem.c	Tue Jul  3 17:08:22 2001
+++ linux/mm/highmem.c	Tue Aug  7 00:18:00 2001
@@ -309,7 +309,7 @@
 	 * No luck. First, kick the VM so it doesnt idle around while
 	 * we are using up our emergency rations.
 	 */
-	wakeup_bdflush(0);
+	wakeup_bdflush();
 
 	/*
 	 * Try to allocate from the emergency pool.
@@ -347,7 +347,7 @@
 	 * No luck. First, kick the VM so it doesnt idle around while
 	 * we are using up our emergency rations.
 	 */
-	wakeup_bdflush(0);
+	wakeup_bdflush();
 
 	/*
 	 * Try to allocate from the emergency pool.
diff -u --recursive --new-file v2.4.7/linux/mm/memory.c linux/mm/memory.c
--- v2.4.7/linux/mm/memory.c	Wed Jul 25 17:10:26 2001
+++ linux/mm/memory.c	Sun Jul 29 22:13:58 2001
@@ -619,9 +619,9 @@
 			
 			if (TryLockPage(page)) {
 				while (j--) {
-					page = *(--ppage);
-					if (page)
-						UnlockPage(page);
+					struct page *tmp = *--ppage;
+					if (tmp)
+						UnlockPage(tmp);
 				}
 				goto retry;
 			}
@@ -862,10 +862,9 @@
 /*
  * We hold the mm semaphore for reading and vma->vm_mm->page_table_lock
  */
-static inline void break_cow(struct vm_area_struct * vma, struct page *	old_page, struct page * new_page, unsigned long address, 
+static inline void break_cow(struct vm_area_struct * vma, struct page * new_page, unsigned long address, 
 		pte_t *page_table)
 {
-	copy_cow_page(old_page,new_page,address);
 	flush_page_to_ram(new_page);
 	flush_cache_page(vma, address);
 	establish_pte(vma, address, page_table, pte_mkwrite(pte_mkdirty(mk_pte(new_page, vma->vm_page_prot))));
@@ -936,19 +935,23 @@
 	/*
 	 * Ok, we need to copy. Oh, well..
 	 */
+	page_cache_get(old_page);
 	spin_unlock(&mm->page_table_lock);
+
 	new_page = alloc_page(GFP_HIGHUSER);
-	spin_lock(&mm->page_table_lock);
 	if (!new_page)
-		return -1;
+		goto no_mem;
+	copy_cow_page(old_page,new_page,address);
+	page_cache_release(old_page);
 
 	/*
 	 * Re-check the pte - we dropped the lock
 	 */
+	spin_lock(&mm->page_table_lock);
 	if (pte_same(*page_table, pte)) {
 		if (PageReserved(old_page))
 			++mm->rss;
-		break_cow(vma, old_page, new_page, address, page_table);
+		break_cow(vma, new_page, address, page_table);
 
 		/* Free the old page.. */
 		new_page = old_page;
@@ -959,6 +962,10 @@
 bad_wp_page:
 	printk("do_wp_page: bogus page at address %08lx (page 0x%lx)\n",address,(unsigned long)old_page);
 	return -1;
+no_mem:
+	page_cache_release(old_page);
+	spin_lock(&mm->page_table_lock);
+	return -1;
 }
 
 static void vmtruncate_list(struct vm_area_struct *mpnt, unsigned long pgoff)
@@ -1163,16 +1170,18 @@
 
 		/* Allocate our own private page. */
 		spin_unlock(&mm->page_table_lock);
+
 		page = alloc_page(GFP_HIGHUSER);
-		spin_lock(&mm->page_table_lock);
 		if (!page)
-			return -1;
+			goto no_mem;
+		clear_user_highpage(page, addr);
+
+		spin_lock(&mm->page_table_lock);
 		if (!pte_none(*page_table)) {
 			page_cache_release(page);
 			return 1;
 		}
 		mm->rss++;
-		clear_user_highpage(page, addr);
 		flush_page_to_ram(page);
 		entry = pte_mkwrite(pte_mkdirty(mk_pte(page, vma->vm_page_prot)));
 	}
@@ -1182,6 +1191,10 @@
 	/* No need to invalidate - it was non-present before */
 	update_mmu_cache(vma, addr, entry);
 	return 1;	/* Minor fault */
+
+no_mem:
+	spin_lock(&mm->page_table_lock);
+	return -1;
 }
 
 /*
diff -u --recursive --new-file v2.4.7/linux/mm/page_alloc.c linux/mm/page_alloc.c
--- v2.4.7/linux/mm/page_alloc.c	Tue Jul  3 17:08:22 2001
+++ linux/mm/page_alloc.c	Fri Aug  3 23:09:17 2001
@@ -448,7 +448,7 @@
 		 * to give up than to deadlock the kernel looping here.
 		 */
 		if (gfp_mask & __GFP_WAIT) {
-			if (!order || free_shortage()) {
+			if (!order || total_free_shortage()) {
 				int progress = try_to_free_pages(gfp_mask);
 				if (progress || (gfp_mask & __GFP_FS))
 					goto try_again;
@@ -622,6 +622,53 @@
 }
 #endif
 
+unsigned int zone_free_shortage(zone_t *zone)
+{
+	int sum = 0;
+
+	if (!zone->size)
+		goto ret;
+
+	if (zone->inactive_clean_pages + zone->free_pages
+			< zone->pages_high) {
+		sum += zone->pages_high;
+		sum -= zone->free_pages;
+		sum -= zone->inactive_clean_pages;
+	}
+ret:
+	return sum;
+}
+
+unsigned int zone_inactive_plenty(zone_t *zone)
+{
+	int inactive;
+
+	if (!zone->size)
+		return 0;
+		
+	inactive = zone->inactive_dirty_pages;
+	inactive += zone->inactive_clean_pages;
+	inactive += zone->free_pages;
+
+	return (inactive > (zone->size / 3));
+
+}
+unsigned int zone_inactive_shortage(zone_t *zone) 
+{
+	int sum = 0;
+
+	if (!zone->size)
+		goto ret;
+
+	sum = zone->pages_high;
+	sum -= zone->inactive_dirty_pages;
+	sum -= zone->inactive_clean_pages;
+	sum -= zone->free_pages;
+
+ret:
+     return (sum > 0 ? sum : 0);
+}
+
 /*
  * Show free area list (used inside shift_scroll-lock stuff)
  * We also calculate the percentage fragmentation. We do this by counting the
@@ -856,7 +903,6 @@
 		}
 
 		offset += size;
-		mask = -1;
 		for (i = 0; ; i++) {
 			unsigned long bitmap_size;
 
@@ -865,11 +911,32 @@
 				zone->free_area[i].map = NULL;
 				break;
 			}
-			mask += mask;
-			size = (size + ~mask) & mask;
-			bitmap_size = size >> (i+1);
-			bitmap_size = (bitmap_size + 7) >> 3;
-			bitmap_size = LONG_ALIGN(bitmap_size);
+
+			/*
+			 * Page buddy system uses "index >> (i+1)",
+			 * where "index" is at most "size-1".
+			 *
+			 * The extra "+3" is to round down to byte
+			 * size (8 bits per byte assumption). Thus
+			 * we get "(size-1) >> (i+4)" as the last byte
+			 * we can access.
+			 *
+			 * The "+1" is because we want to round the
+			 * byte allocation up rather than down. So
+			 * we should have had a "+7" before we shifted
+			 * down by three. Also, we have to add one as
+			 * we actually _use_ the last bit (it's [0,n]
+			 * inclusive, not [0,n[).
+			 *
+			 * So we actually had +7+1 before we shift
+			 * down by 3. But (n+8) >> 3 == (n >> 3) + 1
+			 * (modulo overflows, which we do not have).
+			 *
+			 * Finally, we LONG_ALIGN because all bitmap
+			 * operations are on longs.
+			 */
+			bitmap_size = (size-1) >> (i+4);
+			bitmap_size = LONG_ALIGN(bitmap_size+1);
 			zone->free_area[i].map = 
 			  (unsigned long *) alloc_bootmem_node(pgdat, bitmap_size);
 		}
diff -u --recursive --new-file v2.4.7/linux/mm/shmem.c linux/mm/shmem.c
--- v2.4.7/linux/mm/shmem.c	Wed Jul 25 17:10:26 2001
+++ linux/mm/shmem.c	Mon Aug  6 10:46:56 2001
@@ -754,18 +754,8 @@
 	buf->f_type = TMPFS_MAGIC;
 	buf->f_bsize = PAGE_CACHE_SIZE;
 	spin_lock (&sb->u.shmem_sb.stat_lock);
-	if (sb->u.shmem_sb.max_blocks == ULONG_MAX) {
-		/*
-		 * This is only a guestimate and not honoured.
-		 * We need it to make some programs happy which like to
-		 * test the free space of a file system.
-		 */
-		buf->f_bavail = buf->f_bfree = nr_free_pages() + nr_swap_pages + atomic_read(&buffermem_pages);
-		buf->f_blocks = buf->f_bfree + ULONG_MAX - sb->u.shmem_sb.free_blocks;
-	} else {
-		buf->f_blocks = sb->u.shmem_sb.max_blocks;
-		buf->f_bavail = buf->f_bfree = sb->u.shmem_sb.free_blocks;
-	}
+	buf->f_blocks = sb->u.shmem_sb.max_blocks;
+	buf->f_bavail = buf->f_bfree = sb->u.shmem_sb.free_blocks;
 	buf->f_files = sb->u.shmem_sb.max_inodes;
 	buf->f_ffree = sb->u.shmem_sb.free_inodes;
 	spin_unlock (&sb->u.shmem_sb.stat_lock);
@@ -1013,17 +1003,11 @@
 	return 0;
 }
 
-static int shmem_remount_fs (struct super_block *sb, int *flags, char *data)
+static int shmem_set_size(struct shmem_sb_info *info,
+			  unsigned long max_blocks, unsigned long max_inodes)
 {
 	int error;
-	unsigned long max_blocks, blocks;
-	unsigned long max_inodes, inodes;
-	struct shmem_sb_info *info = &sb->u.shmem_sb;
-
-	max_blocks = info->max_blocks;
-	max_inodes = info->max_inodes;
-	if (shmem_parse_options (data, NULL, &max_blocks, &max_inodes))
-		return -EINVAL;
+	unsigned long blocks, inodes;
 
 	spin_lock(&info->stat_lock);
 	blocks = info->max_blocks - info->free_blocks;
@@ -1043,6 +1027,17 @@
 	return error;
 }
 
+static int shmem_remount_fs (struct super_block *sb, int *flags, char *data)
+{
+	struct shmem_sb_info *info = &sb->u.shmem_sb;
+	unsigned long max_blocks = info->max_blocks;
+	unsigned long max_inodes = info->max_inodes;
+
+	if (shmem_parse_options (data, NULL, &max_blocks, &max_inodes))
+		return -EINVAL;
+	return shmem_set_size(info, max_blocks, max_inodes);
+}
+
 int shmem_sync_file(struct file * file, struct dentry *dentry, int datasync)
 {
 	return 0;
@@ -1053,9 +1048,16 @@
 {
 	struct inode * inode;
 	struct dentry * root;
-	unsigned long blocks = ULONG_MAX;	/* unlimited */
-	unsigned long inodes = ULONG_MAX;	/* unlimited */
+	unsigned long blocks, inodes;
 	int mode   = S_IRWXUGO | S_ISVTX;
+	struct sysinfo si;
+
+	/*
+	 * Per default we only allow half of the physical ram per
+	 * tmpfs instance
+	 */
+	si_meminfo(&si);
+	blocks = inodes = si.totalram / 2;
 
 #ifdef CONFIG_TMPFS
 	if (shmem_parse_options (data, &mode, &blocks, &inodes)) {
@@ -1179,6 +1181,10 @@
 		unregister_filesystem(&tmpfs_fs_type);
 		return PTR_ERR(res);
 	}
+
+	/* The internal instance should not do size checking */
+	if ((error = shmem_set_size(&res->mnt_sb->u.shmem_sb, ULONG_MAX, ULONG_MAX)))
+		printk (KERN_ERR "could not set limits on internal tmpfs\n");
 
 	return 0;
 }
diff -u --recursive --new-file v2.4.7/linux/mm/swap.c linux/mm/swap.c
--- v2.4.7/linux/mm/swap.c	Mon Jan 22 13:30:21 2001
+++ linux/mm/swap.c	Sun Jul 29 09:07:56 2001
@@ -74,31 +74,6 @@
 	8,	/* do swap I/O in clusters of this size */
 };
 
-/**
- * age_page_{up,down} -	page aging helper functions
- * @page - the page we want to age
- * @nolock - are we already holding the pagelist_lru_lock?
- *
- * If the page is on one of the lists (active, inactive_dirty or
- * inactive_clean), we will grab the pagelist_lru_lock as needed.
- * If you're already holding the lock, call this function with the
- * nolock argument non-zero.
- */
-void age_page_up_nolock(struct page * page)
-{
-	/*
-	 * We're dealing with an inactive page, move the page
-	 * to the active list.
-	 */
-	if (!page->age)
-		activate_page_nolock(page);
-
-	/* The actual page aging bit */
-	page->age += PAGE_AGE_ADV;
-	if (page->age > PAGE_AGE_MAX)
-		page->age = PAGE_AGE_MAX;
-}
-
 /*
  * We use this (minimal) function in the case where we
  * know we can't deactivate the page (yet).
@@ -121,21 +96,6 @@
 	       deactivate_page_nolock(page);
 }
 
-void age_page_up(struct page * page)
-{
-	/*
-	 * We're dealing with an inactive page, move the page
-	 * to the active list.
-	 */
-	if (!page->age)
-		activate_page(page);
-
-	/* The actual page aging bit */
-	page->age += PAGE_AGE_ADV;
-	if (page->age > PAGE_AGE_MAX)
-		page->age = PAGE_AGE_MAX;
-}
-
 void age_page_down(struct page * page)
 {
 	/* The actual page aging bit */
@@ -231,11 +191,8 @@
 	spin_lock(&pagemap_lru_lock);
 	if (!PageLocked(page))
 		BUG();
-	DEBUG_ADD_PAGE
-	add_page_to_active_list(page);
-	/* This should be relatively rare */
-	if (!page->age)
-		deactivate_page_nolock(page);
+	add_page_to_inactive_dirty_list(page);
+	page->age = 0;
 	spin_unlock(&pagemap_lru_lock);
 }
 
diff -u --recursive --new-file v2.4.7/linux/mm/vmscan.c linux/mm/vmscan.c
--- v2.4.7/linux/mm/vmscan.c	Wed Jul 25 17:10:26 2001
+++ linux/mm/vmscan.c	Tue Aug  7 00:19:28 2001
@@ -41,6 +41,14 @@
 	pte_t pte;
 	swp_entry_t entry;
 
+	/* 
+	 * If we are doing a zone-specific scan, do not
+	 * touch pages from zones which don't have a 
+	 * shortage.
+	 */
+	if (zone_inactive_plenty(page->zone))
+		return;
+
 	/* Don't look at this pte if it's been accessed recently. */
 	if (ptep_test_and_clear_young(page_table)) {
 		page->age += PAGE_AGE_ADV;
@@ -355,10 +363,10 @@
 		}
 
 		/* Page is or was in use?  Move it to the active list. */
-		if (PageReferenced(page) || page->age > 0 ||
-				(!page->buffers && page_count(page) > 1)) {
+		if (PageReferenced(page) || (!page->buffers && page_count(page) > 1)) {
 			del_page_from_inactive_clean_list(page);
 			add_page_to_active_list(page);
+			page->age = PAGE_AGE_START;
 			continue;
 		}
 
@@ -426,7 +434,7 @@
 #define MAX_LAUNDER 		(4 * (1 << page_cluster))
 #define CAN_DO_FS		(gfp_mask & __GFP_FS)
 #define CAN_DO_IO		(gfp_mask & __GFP_IO)
-int page_launder(int gfp_mask, int sync)
+int do_page_launder(zone_t *zone, int gfp_mask, int sync)
 {
 	int launder_loop, maxscan, cleaned_pages, maxlaunder;
 	struct list_head * page_lru;
@@ -453,11 +461,22 @@
 		}
 
 		/* Page is or was in use?  Move it to the active list. */
-		if (PageReferenced(page) || page->age > 0 ||
-				(!page->buffers && page_count(page) > 1) ||
+		if (PageReferenced(page) || (!page->buffers && page_count(page) > 1) ||
 				page_ramdisk(page)) {
 			del_page_from_inactive_dirty_list(page);
 			add_page_to_active_list(page);
+			page->age = PAGE_AGE_START;
+			continue;
+		}
+
+		/* 
+		 * If we are doing zone-specific laundering, 
+		 * avoid touching pages from zones which do 
+		 * not have a free shortage.
+		 */
+		if (zone && !zone_free_shortage(page->zone)) {
+			list_del(page_lru);
+			list_add(page_lru, &inactive_dirty_list);
 			continue;
 		}
 
@@ -574,8 +593,9 @@
 			 * If we're freeing buffer cache pages, stop when
 			 * we've got enough free memory.
 			 */
-			if (freed_page && !free_shortage())
+			if (freed_page && !total_free_shortage())
 				break;
+
 			continue;
 		} else if (page->mapping && !PageDirty(page)) {
 			/*
@@ -613,7 +633,7 @@
 	 * loads, flush out the dirty pages before we have to wait on
 	 * IO.
 	 */
-	if (CAN_DO_IO && !launder_loop && free_shortage()) {
+	if (CAN_DO_IO && !launder_loop && total_free_shortage()) {
 		launder_loop = 1;
 		/* If we cleaned pages, never do synchronous IO. */
 		if (cleaned_pages)
@@ -621,7 +641,7 @@
 		/* We only do a few "out of order" flushes. */
 		maxlaunder = MAX_LAUNDER;
 		/* Kflushd takes care of the rest. */
-		wakeup_bdflush(0);
+		wakeup_bdflush();
 		goto dirty_page_rescan;
 	}
 
@@ -629,6 +649,40 @@
 	return cleaned_pages;
 }
 
+int page_launder(int gfp_mask, int sync)
+{
+	int type = 0, ret = 0;
+	pg_data_t *pgdat = pgdat_list;
+	/*
+	 * First do a global scan if there is a 
+	 * global shortage.
+	 */
+	if (free_shortage())
+		ret += do_page_launder(NULL, gfp_mask, sync);
+
+	/*
+	 * Then check if there is any specific zone 
+	 * needs laundering.
+	 */
+	for (type = 0; type < MAX_NR_ZONES; type++) {
+		zone_t *zone = pgdat->node_zones + type;
+		
+		if (zone_free_shortage(zone)) 
+			ret += do_page_launder(zone, gfp_mask, sync);
+	} 
+
+	return ret;
+}
+
+static inline void age_page_up(struct page *page)
+{
+	unsigned age = page->age + PAGE_AGE_ADV;
+	if (age > PAGE_AGE_MAX)
+		age = PAGE_AGE_MAX;
+	page->age = age;
+}
+
+
 /**
  * refill_inactive_scan - scan the active list and find pages to deactivate
  * @priority: the priority at which to scan
@@ -637,7 +691,7 @@
  * This function will scan a portion of the active list to find
  * unused pages, those pages will then be moved to the inactive list.
  */
-int refill_inactive_scan(unsigned int priority, int target)
+int refill_inactive_scan(zone_t *zone, unsigned int priority, int target)
 {
 	struct list_head * page_lru;
 	struct page * page;
@@ -665,9 +719,19 @@
 			continue;
 		}
 
+		/*
+		 * Do not deactivate pages from zones which 
+		 * have plenty inactive pages.
+		 */
+
+		if (zone_inactive_plenty(page->zone)) {
+			page_active = 1;
+			goto skip_page;
+		}
+
 		/* Do aging on the pages. */
 		if (PageTestandClearReferenced(page)) {
-			age_page_up_nolock(page);
+			age_page_up(page);
 			page_active = 1;
 		} else {
 			age_page_down_ageonly(page);
@@ -695,10 +759,12 @@
 		 * we have done enough work.
 		 */
 		if (page_active || PageActive(page)) {
+skip_page:
 			list_del(page_lru);
 			list_add(page_lru, &active_list);
 		} else {
-			nr_deactivated++;
+			if (!zone || (zone && (zone == page->zone)))
+				nr_deactivated++;
 			if (target && nr_deactivated >= target)
 				break;
 		}
@@ -709,19 +775,32 @@
 }
 
 /*
- * Check if there are zones with a severe shortage of free pages,
- * or if all zones have a minor shortage.
+ * Check if we have are low on free pages globally.
  */
 int free_shortage(void)
 {
-	pg_data_t *pgdat = pgdat_list;
-	int sum = 0;
 	int freeable = nr_free_pages() + nr_inactive_clean_pages();
 	int freetarget = freepages.high;
 
 	/* Are we low on free pages globally? */
 	if (freeable < freetarget)
 		return freetarget - freeable;
+	return 0;
+}
+
+/*
+ *
+ * Check if there are zones with a severe shortage of free pages,
+ * or if all zones have a minor shortage.
+ */
+int total_free_shortage(void)
+{
+	int sum = 0;
+	pg_data_t *pgdat = pgdat_list;
+
+	/* Do we have a global free shortage? */
+	if((sum = free_shortage()))
+		return sum;
 
 	/* If not, are we very low on any particular zone? */
 	do {
@@ -739,15 +818,15 @@
 	} while (pgdat);
 
 	return sum;
+
 }
 
 /*
- * How many inactive pages are we short?
+ * How many inactive pages are we short globally?
  */
 int inactive_shortage(void)
 {
 	int shortage = 0;
-	pg_data_t *pgdat = pgdat_list;
 
 	/* Is the inactive dirty list too small? */
 
@@ -759,10 +838,20 @@
 
 	if (shortage > 0)
 		return shortage;
+	return 0;
+}
+/*
+ * Are we low on inactive pages globally or in any zone?
+ */
+int total_inactive_shortage(void)
+{
+	int shortage = 0;
+	pg_data_t *pgdat = pgdat_list;
 
-	/* If not, do we have enough per-zone pages on the inactive list? */
+	if((shortage = inactive_shortage()))
+		return shortage;
 
-	shortage = 0;
+	shortage = 0;	
 
 	do {
 		int i;
@@ -802,7 +891,7 @@
  * when called from a user process.
  */
 #define DEF_PRIORITY (6)
-static int refill_inactive(unsigned int gfp_mask, int user)
+static int refill_inactive_global(unsigned int gfp_mask, int user)
 {
 	int count, start_count, maxtry;
 
@@ -826,7 +915,7 @@
 		/* Walk the VM space for a bit.. */
 		swap_out(DEF_PRIORITY, gfp_mask);
 
-		count -= refill_inactive_scan(DEF_PRIORITY, count);
+		count -= refill_inactive_scan(NULL, DEF_PRIORITY, count);
 		if (count <= 0)
 			goto done;
 
@@ -839,6 +928,59 @@
 	return (count < start_count);
 }
 
+static int refill_inactive_zone(zone_t *zone, unsigned int gfp_mask, int user) 
+{
+	int count, start_count, maxtry; 
+	
+	count = start_count = zone_inactive_shortage(zone);
+
+	maxtry = (1 << DEF_PRIORITY);
+
+	do {
+		swap_out(DEF_PRIORITY, gfp_mask);
+
+		count -= refill_inactive_scan(zone, DEF_PRIORITY, count);
+
+		if (count <= 0)
+			goto done;
+
+		if (--maxtry <= 0)
+			return 0;
+
+	} while(zone_inactive_shortage(zone));
+done:
+	return (count < start_count);
+}
+
+
+static int refill_inactive(unsigned int gfp_mask, int user) 
+{
+	int type = 0, ret = 0;
+	pg_data_t *pgdat = pgdat_list;
+	/*
+	 * First do a global scan if there is a 
+	 * global shortage.
+	 */
+	if (inactive_shortage())
+		ret += refill_inactive_global(gfp_mask, user);
+
+	/*
+	 * Then check if there is any specific zone 
+	 * with a shortage and try to refill it if
+	 * so.
+	 */
+	for (type = 0; type < MAX_NR_ZONES; type++) {
+		zone_t *zone = pgdat->node_zones + type;
+		
+		if (zone_inactive_shortage(zone)) 
+			ret += refill_inactive_zone(zone, gfp_mask, user);
+	} 
+
+	return ret;
+}
+
+#define DEF_PRIORITY (6)
+
 static int do_try_to_free_pages(unsigned int gfp_mask, int user)
 {
 	int ret = 0;
@@ -851,18 +993,17 @@
 	 * before we get around to moving them to the other
 	 * list, so this is a relatively cheap operation.
 	 */
-	if (free_shortage()) {
-		ret += page_launder(gfp_mask, user);
-		shrink_dcache_memory(DEF_PRIORITY, gfp_mask);
-		shrink_icache_memory(DEF_PRIORITY, gfp_mask);
-	}
+
+	ret += page_launder(gfp_mask, user);
+
+	ret += shrink_dcache_memory(DEF_PRIORITY, gfp_mask);
+	ret += shrink_icache_memory(DEF_PRIORITY, gfp_mask);
 
 	/*
 	 * If needed, we move pages from the active list
 	 * to the inactive list.
 	 */
-	if (inactive_shortage())
-		ret += refill_inactive(gfp_mask, user);
+	ret += refill_inactive(gfp_mask, user);
 
 	/* 	
 	 * Reclaim unused slab cache if memory is low.
@@ -917,7 +1058,7 @@
 		static long recalc = 0;
 
 		/* If needed, try to free some memory. */
-		if (inactive_shortage() || free_shortage()) 
+		if (total_inactive_shortage() || total_free_shortage()) 
 			do_try_to_free_pages(GFP_KSWAPD, 0);
 
 		/* Once a second ... */
@@ -928,7 +1069,7 @@
 			recalculate_vm_stats();
 
 			/* Do background page aging. */
-			refill_inactive_scan(DEF_PRIORITY, 0);
+			refill_inactive_scan(NULL, DEF_PRIORITY, 0);
 		}
 
 		run_task_queue(&tq_disk);
@@ -944,7 +1085,7 @@
 		 * We go to sleep for one second, but if it's needed
 		 * we'll be woken up earlier...
 		 */
-		if (!free_shortage() || !inactive_shortage()) {
+		if (!total_free_shortage() || !total_inactive_shortage()) {
 			interruptible_sleep_on_timeout(&kswapd_wait, HZ);
 		/*
 		 * If we couldn't free enough memory, we see if it was
diff -u --recursive --new-file v2.4.7/linux/net/atm/common.c linux/net/atm/common.c
--- v2.4.7/linux/net/atm/common.c	Tue Jul  3 17:08:22 2001
+++ linux/net/atm/common.c	Sun Aug  5 13:12:41 2001
@@ -210,7 +210,7 @@
 
 	if ((vpi != ATM_VPI_UNSPEC && vpi != ATM_VPI_ANY &&
 	    vpi >> dev->ci_range.vpi_bits) || (vci != ATM_VCI_UNSPEC &&
-	    vci != ATM_VCI_ANY && vci >> dev->ci_range.vci_bits))
+	    vci != ATM_VCI_ANY && vci > dev->ci_range.vci_bits))
 		return -EINVAL;
 	if (vci > 0 && vci < ATM_NOT_RSV_VCI && !capable(CAP_NET_BIND_SERVICE))
 		return -EPERM;
diff -u --recursive --new-file v2.4.7/linux/net/core/dev.c linux/net/core/dev.c
--- v2.4.7/linux/net/core/dev.c	Wed Jul 25 17:10:26 2001
+++ linux/net/core/dev.c	Tue Jul 31 10:34:02 2001
@@ -1217,10 +1217,10 @@
 enqueue:
 			dev_hold(skb->dev);
 			__skb_queue_tail(&queue->input_pkt_queue,skb);
+			local_irq_restore(flags);
 
 			/* Runs from irqs or BH's, no need to wake BH */
 			__cpu_raise_softirq(this_cpu, NET_RX_SOFTIRQ);
-			local_irq_restore(flags);
 #ifndef OFFLINE_SAMPLE
 			get_sample_stats(this_cpu);
 #endif
@@ -1529,10 +1529,10 @@
 
 	local_irq_disable();
 	netdev_rx_stat[this_cpu].time_squeeze++;
+	local_irq_enable();
 
 	/* This already runs in BH context, no need to wake up BH's */
 	__cpu_raise_softirq(this_cpu, NET_RX_SOFTIRQ);
-	local_irq_enable();
 
 	NET_PROFILE_LEAVE(softnet_process);
 	return;
@@ -2169,7 +2169,10 @@
 		default:
 			if ((cmd >= SIOCDEVPRIVATE &&
 			    cmd <= SIOCDEVPRIVATE + 15) ||
-			    cmd == SIOCETHTOOL) {
+			    cmd == SIOCETHTOOL ||
+			    cmd == SIOCGMIIPHY ||
+			    cmd == SIOCGMIIREG ||
+			    cmd == SIOCSMIIREG) {
 				if (dev->do_ioctl) {
 					if (!netif_device_present(dev))
 						return -ENODEV;
@@ -2291,6 +2294,9 @@
 		case SIOCSIFTXQLEN:
 		case SIOCSIFNAME:
 		case SIOCETHTOOL:
+		case SIOCGMIIPHY:
+		case SIOCGMIIREG:
+		case SIOCSMIIREG:
 			if (!capable(CAP_NET_ADMIN))
 				return -EPERM;
 			dev_load(ifr.ifr_name);
diff -u --recursive --new-file v2.4.7/linux/net/core/rtnetlink.c linux/net/core/rtnetlink.c
--- v2.4.7/linux/net/core/rtnetlink.c	Sun Feb 27 18:45:10 2000
+++ linux/net/core/rtnetlink.c	Sun Aug  5 13:12:41 2001
@@ -274,7 +274,7 @@
 
 /* Process one rtnetlink message. */
 
-extern __inline__ int
+static __inline__ int
 rtnetlink_rcv_msg(struct sk_buff *skb, struct nlmsghdr *nlh, int *errp)
 {
 	struct rtnetlink_link *link;
diff -u --recursive --new-file v2.4.7/linux/net/core/sock.c linux/net/core/sock.c
--- v2.4.7/linux/net/core/sock.c	Tue Jul  3 17:08:22 2001
+++ linux/net/core/sock.c	Sat Jul 28 12:12:38 2001
@@ -7,7 +7,7 @@
  *		handler for protocols to use and generic option handler.
  *
  *
- * Version:	$Id: sock.c,v 1.111 2001/06/26 23:29:17 davem Exp $
+ * Version:	$Id: sock.c,v 1.112 2001/07/27 09:54:48 davem Exp $
  *
  * Authors:	Ross Biro, <bir7@leland.Stanford.Edu>
  *		Fred N. van Kempen, <waltje@uWalt.NL.Mugnet.ORG>
@@ -131,8 +131,6 @@
 #include <linux/filter.h>
 #endif
 
-#define min(a,b)	((a)<(b)?(a):(b))
-
 /* Run time adjustable parameters. */
 __u32 sysctl_wmem_max = SK_WMEM_MAX;
 __u32 sysctl_rmem_max = SK_RMEM_MAX;
@@ -232,7 +230,10 @@
 				val = sysctl_wmem_max;
 
 			sk->userlocks |= SOCK_SNDBUF_LOCK;
-			sk->sndbuf = max(val*2,SOCK_MIN_SNDBUF);
+			if ((val * 2) < SOCK_MIN_SNDBUF)
+				sk->sndbuf = SOCK_MIN_SNDBUF;
+			else
+				sk->sndbuf = (val * 2);
 
 			/*
 			 *	Wake up sending tasks if we
@@ -252,7 +253,10 @@
 
 			sk->userlocks |= SOCK_RCVBUF_LOCK;
 			/* FIXME: is this lower bound the right one? */
-			sk->rcvbuf = max(val*2,SOCK_MIN_RCVBUF);
+			if ((val * 2) < SOCK_MIN_RCVBUF)
+				sk->rcvbuf = SOCK_MIN_RCVBUF;
+			else
+				sk->rcvbuf = (val * 2);
 			break;
 
 		case SO_KEEPALIVE:
@@ -533,9 +537,9 @@
 			break;
 
 		case SO_PEERCRED:
-			lv=sizeof(sk->peercred);
-			len=min(len, lv);
-			if(copy_to_user((void*)optval, &sk->peercred, len))
+			if (len > sizeof(sk->peercred))
+				len = sizeof(sk->peercred);
+			if (copy_to_user(optval, &sk->peercred, len))
 				return -EFAULT;
 			goto lenout;
 
@@ -562,11 +566,12 @@
 		default:
 			return(-ENOPROTOOPT);
 	}
-	len=min(len,lv);
-	if(copy_to_user(optval,&v,len))
+	if (len > lv)
+		len = lv;
+	if (copy_to_user(optval, &v, len))
 		return -EFAULT;
 lenout:
-  	if(put_user(len, optlen))
+  	if (put_user(len, optlen))
   		return -EFAULT;
   	return 0;
 }
diff -u --recursive --new-file v2.4.7/linux/net/ipv4/igmp.c linux/net/ipv4/igmp.c
--- v2.4.7/linux/net/ipv4/igmp.c	Thu Apr 12 12:11:39 2001
+++ linux/net/ipv4/igmp.c	Sat Jul 28 12:12:38 2001
@@ -8,7 +8,7 @@
  *	the older version didn't come out right using gcc 2.5.8, the newer one
  *	seems to fall out with gcc 2.6.2.
  *
- *	Version: $Id: igmp.c,v 1.45 2001/02/23 06:32:11 davem Exp $
+ *	Version: $Id: igmp.c,v 1.46 2001/07/27 09:27:29 davem Exp $
  *
  *	Authors:
  *		Alan Cox <Alan.Cox@linux.org>
@@ -112,7 +112,7 @@
 #define IGMP_Unsolicited_Report_Count		2
 
 
-#define IGMP_Initial_Report_Delay		(1*HZ)
+#define IGMP_Initial_Report_Delay		(1)
 
 /* IGMP_Initial_Report_Delay is not from IGMP specs!
  * IGMP specs require to report membership immediately after
diff -u --recursive --new-file v2.4.7/linux/net/irda/ircomm/ircomm_tty.c linux/net/irda/ircomm/ircomm_tty.c
--- v2.4.7/linux/net/irda/ircomm/ircomm_tty.c	Fri Mar  2 11:12:12 2001
+++ linux/net/irda/ircomm/ircomm_tty.c	Wed Jul 25 14:12:03 2001
@@ -468,7 +468,8 @@
 	/* Check if this is a "normal" ircomm device, or an irlpt device */
 	if (line < 0x10) {
 		self->service_type = IRCOMM_3_WIRE | IRCOMM_9_WIRE;
-		self->settings.service_type = IRCOMM_9_WIRE; /* Default */
+		self->settings.service_type = IRCOMM_9_WIRE; /* 9 wire as default */
+		self->settings.dce = IRCOMM_CTS | IRCOMM_CD; /* Default line settings */
 		IRDA_DEBUG(2, __FUNCTION__ "(), IrCOMM device\n");
 	} else {
 		IRDA_DEBUG(2, __FUNCTION__ "(), IrLPT device\n");
diff -u --recursive --new-file v2.4.7/linux/net/irda/ircomm/ircomm_tty_attach.c linux/net/irda/ircomm/ircomm_tty_attach.c
--- v2.4.7/linux/net/irda/ircomm/ircomm_tty_attach.c	Sat Nov 11 18:11:23 2000
+++ linux/net/irda/ircomm/ircomm_tty_attach.c	Wed Jul 25 14:12:03 2001
@@ -505,7 +505,7 @@
 	 * will have to wait for the peer device (DCE) to raise the CTS
 	 * line.  
 	 */
-	if (self->flags & ASYNC_CTS_FLOW) {
+	if ((self->flags & ASYNC_CTS_FLOW) && ((self->settings.dce & IRCOMM_CTS) == 0)) {
 		IRDA_DEBUG(0, __FUNCTION__ "(), waiting for CTS ...\n");
 		return;
 	} else {
diff -u --recursive --new-file v2.4.7/linux/net/unix/af_unix.c linux/net/unix/af_unix.c
--- v2.4.7/linux/net/unix/af_unix.c	Wed Jul 25 17:10:27 2001
+++ linux/net/unix/af_unix.c	Sat Jul 28 12:12:38 2001
@@ -8,7 +8,7 @@
  *		as published by the Free Software Foundation; either version
  *		2 of the License, or (at your option) any later version.
  *
- * Version:	$Id: af_unix.c,v 1.117 2001/07/01 06:59:10 davem Exp $
+ * Version:	$Id: af_unix.c,v 1.118 2001/07/18 07:52:37 davem Exp $
  *
  * Fixes:
  *		Linus Torvalds	:	Assorted bug cures.
diff -u --recursive --new-file v2.4.7/linux/scripts/Menuconfig linux/scripts/Menuconfig
--- v2.4.7/linux/scripts/Menuconfig	Tue Jul  3 17:08:22 2001
+++ linux/scripts/Menuconfig	Sun Aug  5 13:12:41 2001
@@ -1335,7 +1335,7 @@
 	then
 		echo -e "\n\007Your display is too small to run Menuconfig!"
 		echo "It must be at least 19 lines by 80 columns."
-		exit 0
+		exit 1
 	fi 
 
 	ROWS=$((ROWS-4))  COLS=$((COLS-5))
